575c3eb819
Check in UnitGroupRolesAssigned checked for function existence. The function exists in TBC, but returns NONE for everyone. Changed check for IsTimewalkWoW
4547 lines
142 KiB
Lua
4547 lines
142 KiB
Lua
|
|
|
|
local dversion = 313
|
|
local major, minor = "DetailsFramework-1.0", dversion
|
|
local DF, oldminor = LibStub:NewLibrary (major, minor)
|
|
|
|
if (not DF) then
|
|
DetailsFrameworkCanLoad = false
|
|
return
|
|
end
|
|
|
|
DetailsFrameworkCanLoad = true
|
|
local SharedMedia = LibStub:GetLibrary ("LibSharedMedia-3.0")
|
|
|
|
local _
|
|
local _type = type
|
|
local _unpack = unpack
|
|
local upper = string.upper
|
|
local string_match = string.match
|
|
local tinsert = _G.tinsert
|
|
local abs = _G.abs
|
|
local tremove = _G.tremove
|
|
|
|
local IS_WOW_PROJECT_MAINLINE = WOW_PROJECT_ID == WOW_PROJECT_MAINLINE
|
|
local IS_WOW_PROJECT_NOT_MAINLINE = WOW_PROJECT_ID ~= WOW_PROJECT_MAINLINE
|
|
|
|
local UnitPlayerControlled = UnitPlayerControlled
|
|
local UnitIsTapDenied = UnitIsTapDenied
|
|
|
|
SMALL_NUMBER = 0.000001
|
|
ALPHA_BLEND_AMOUNT = 0.8400251
|
|
|
|
DF.dversion = dversion
|
|
|
|
DF.AuthorInfo = {
|
|
Name = "Terciob",
|
|
Discord = "https://discord.gg/AGSzAZX",
|
|
}
|
|
|
|
local PixelUtil = PixelUtil or DFPixelUtil
|
|
if (not PixelUtil) then
|
|
--check if is in classic or TBC wow, if it is, build a replacement for PixelUtil
|
|
local gameVersion = GetBuildInfo()
|
|
if (gameVersion:match("%d") == "1" or gameVersion:match("%d") == "2") then
|
|
PixelUtil = {
|
|
SetWidth = function (self, width) self:SetWidth (width) end,
|
|
SetHeight = function (self, height) self:SetHeight (height) end,
|
|
SetSize = function (self, width, height) self:SetSize (width, height) end,
|
|
SetPoint = function (self, ...) self:SetPoint (...) end,
|
|
}
|
|
end
|
|
end
|
|
|
|
function DF.IsTimewalkWoW()
|
|
return DF.IsClassicWow() or DF.IsTBCWow()
|
|
end
|
|
|
|
function DF.IsClassicWow()
|
|
local gameVersion = GetBuildInfo()
|
|
if (gameVersion:match ("%d") == "1") then
|
|
return true
|
|
end
|
|
return false
|
|
end
|
|
|
|
function DF.IsTBCWow()
|
|
local gameVersion = GetBuildInfo()
|
|
if (gameVersion:match ("%d") == "2") then
|
|
return true
|
|
end
|
|
return false
|
|
end
|
|
|
|
function DF.UnitGroupRolesAssigned (unitId)
|
|
if (not DF.IsTimewalkWoW()) then --Was function exist check. TBC has function, returns NONE. -Flamanis 5/16/2022
|
|
return UnitGroupRolesAssigned (unitId)
|
|
else
|
|
--attempt to guess the role by the player spec
|
|
local classLoc, className = UnitClass(unitId)
|
|
if (className == "MAGE" or className == "ROGUE" or className == "HUNTER" or className == "WARLOCK") then
|
|
return "DAMAGER"
|
|
end
|
|
|
|
if (Details) then
|
|
--attempt to get the role from Details! Damage Meter
|
|
local guid = UnitGUID(unitId)
|
|
if (guid) then
|
|
local role = Details.cached_roles[guid]
|
|
if (role) then
|
|
return role
|
|
end
|
|
end
|
|
end
|
|
|
|
return "NONE"
|
|
end
|
|
end
|
|
|
|
--return the specialization of the player it self
|
|
function DF.GetSpecialization()
|
|
if (GetSpecialization) then
|
|
return GetSpecialization()
|
|
end
|
|
|
|
return nil
|
|
end
|
|
|
|
function DF.GetSpecializationInfoByID (...)
|
|
if (GetSpecializationInfoByID) then
|
|
return GetSpecializationInfoByID (...)
|
|
end
|
|
|
|
return nil
|
|
end
|
|
|
|
function DF.GetSpecializationInfo (...)
|
|
if (GetSpecializationInfo) then
|
|
return GetSpecializationInfo (...)
|
|
end
|
|
|
|
return nil
|
|
end
|
|
|
|
function DF.GetSpecializationRole (...)
|
|
if (GetSpecializationRole) then
|
|
return GetSpecializationRole (...)
|
|
end
|
|
|
|
return nil
|
|
end
|
|
|
|
--build dummy encounter journal functions if they doesn't exists
|
|
--this is done for compatibility with classic and if in the future EJ_ functions are moved to C_
|
|
DF.EncounterJournal = {
|
|
EJ_GetCurrentInstance = EJ_GetCurrentInstance or function() return nil end,
|
|
EJ_GetInstanceForMap = EJ_GetInstanceForMap or function() return nil end,
|
|
EJ_GetInstanceInfo = EJ_GetInstanceInfo or function() return nil end,
|
|
EJ_SelectInstance = EJ_SelectInstance or function() return nil end,
|
|
|
|
EJ_GetEncounterInfoByIndex = EJ_GetEncounterInfoByIndex or function() return nil end,
|
|
EJ_GetEncounterInfo = EJ_GetEncounterInfo or function() return nil end,
|
|
EJ_SelectEncounter = EJ_SelectEncounter or function() return nil end,
|
|
|
|
EJ_GetSectionInfo = EJ_GetSectionInfo or function() return nil end,
|
|
EJ_GetCreatureInfo = EJ_GetCreatureInfo or function() return nil end,
|
|
EJ_SetDifficulty = EJ_SetDifficulty or function() return nil end,
|
|
EJ_GetNumLoot = EJ_GetNumLoot or function() return 0 end,
|
|
EJ_GetLootInfoByIndex = EJ_GetLootInfoByIndex or function() return nil end,
|
|
}
|
|
|
|
if (not EJ_GetCurrentInstance) then
|
|
|
|
end
|
|
|
|
--> will always give a very random name for our widgets
|
|
local init_counter = math.random (1, 1000000)
|
|
|
|
DF.LabelNameCounter = DF.LabelNameCounter or init_counter
|
|
DF.PictureNameCounter = DF.PictureNameCounter or init_counter
|
|
DF.BarNameCounter = DF.BarNameCounter or init_counter
|
|
DF.DropDownCounter = DF.DropDownCounter or init_counter
|
|
DF.PanelCounter = DF.PanelCounter or init_counter
|
|
DF.SimplePanelCounter = DF.SimplePanelCounter or init_counter
|
|
DF.ButtonCounter = DF.ButtonCounter or init_counter
|
|
DF.SliderCounter = DF.SliderCounter or init_counter
|
|
DF.SwitchCounter = DF.SwitchCounter or init_counter
|
|
DF.SplitBarCounter = DF.SplitBarCounter or init_counter
|
|
|
|
DF.FRAMELEVEL_OVERLAY = 750
|
|
DF.FRAMELEVEL_BACKGROUND = 150
|
|
|
|
--/dump DetailsFramework:PrintVersion()
|
|
|
|
DF.FrameWorkVersion = tostring (dversion)
|
|
function DF:PrintVersion()
|
|
print ("Details! Framework Version:", DF.FrameWorkVersion)
|
|
end
|
|
|
|
LibStub:GetLibrary("AceTimer-3.0"):Embed (DF)
|
|
|
|
--> get the working folder
|
|
do
|
|
local path = string.match (debugstack (1, 1, 0), "AddOns\\(.+)fw.lua")
|
|
if (path) then
|
|
DF.folder = "Interface\\AddOns\\" .. path
|
|
else
|
|
--> if not found, try to use the last valid one
|
|
DF.folder = DF.folder or ""
|
|
end
|
|
end
|
|
|
|
DF.debug = false
|
|
|
|
_G ["DetailsFramework"] = DF
|
|
|
|
DF.embeds = DF.embeds or {}
|
|
local embed_functions = {
|
|
"RemoveRealName",
|
|
"table",
|
|
"BuildDropDownFontList",
|
|
"SetFontSize",
|
|
"SetFontFace",
|
|
"SetFontColor",
|
|
"GetFontSize",
|
|
"GetFontFace",
|
|
"SetFontOutline",
|
|
"trim",
|
|
"Msg",
|
|
"CreateFlashAnimation",
|
|
"Fade",
|
|
"NewColor",
|
|
"IsHtmlColor",
|
|
"ParseColors",
|
|
"BuildMenu",
|
|
"ShowTutorialAlertFrame",
|
|
"GetNpcIdFromGuid",
|
|
"ShowFeedbackPanel",
|
|
"SetAsOptionsPanel",
|
|
"GetPlayerRole",
|
|
"GetCharacterTalents",
|
|
"GetCharacterPvPTalents",
|
|
|
|
"CreateDropDown",
|
|
"CreateButton",
|
|
"CreateColorPickButton",
|
|
"CreateLabel",
|
|
"CreateBar",
|
|
"CreatePanel",
|
|
"CreateFillPanel",
|
|
"ColorPick",
|
|
"IconPick",
|
|
"CreateSimplePanel",
|
|
"CreateChartPanel",
|
|
"CreateImage",
|
|
"CreateScrollBar",
|
|
"CreateSwitch",
|
|
"CreateSlider",
|
|
"CreateSplitBar",
|
|
"CreateTextEntry",
|
|
"Create1PxPanel",
|
|
"CreateFeedbackButton",
|
|
"CreateOptionsFrame",
|
|
"NewSpecialLuaEditorEntry",
|
|
"ShowPromptPanel",
|
|
"ShowTextPromptPanel",
|
|
"www_icons",
|
|
"GetTemplate",
|
|
"InstallTemplate",
|
|
"GetFrameworkFolder",
|
|
"ShowPanicWarning",
|
|
"SetFrameworkDebugState",
|
|
"FindHighestParent",
|
|
"OpenInterfaceProfile",
|
|
"CreateInCombatTexture",
|
|
"CreateAnimationHub",
|
|
"CreateAnimation",
|
|
"CreateScrollBox",
|
|
"CreateBorder",
|
|
"FormatNumber",
|
|
"IntegerToTimer",
|
|
"QuickDispatch",
|
|
"Dispatch",
|
|
"CommaValue",
|
|
"RemoveRealmName",
|
|
"Trim",
|
|
"CreateGlowOverlay",
|
|
"CreateAnts",
|
|
"CreateFrameShake",
|
|
"RegisterScriptComm",
|
|
"SendScriptComm",
|
|
}
|
|
|
|
DF.WidgetFunctions = {
|
|
GetCapsule = function (self)
|
|
return self.MyObject
|
|
end,
|
|
}
|
|
|
|
DF.table = {}
|
|
|
|
function DF:GetFrameworkFolder()
|
|
return DF.folder
|
|
end
|
|
|
|
function DF:SetFrameworkDebugState (state)
|
|
DF.debug = state
|
|
end
|
|
|
|
function DF:FadeFrame (frame, t)
|
|
if (t == 0) then
|
|
frame.hidden = false
|
|
frame.faded = false
|
|
frame.fading_out = false
|
|
frame.fading_in = false
|
|
frame:Show()
|
|
frame:SetAlpha (1)
|
|
|
|
elseif (t == 1) then
|
|
frame.hidden = true
|
|
frame.faded = true
|
|
frame.fading_out = false
|
|
frame.fading_in = false
|
|
frame:SetAlpha (0)
|
|
frame:Hide()
|
|
end
|
|
end
|
|
|
|
function DF.table.find (t, value)
|
|
for i = 1, #t do
|
|
if (t[i] == value) then
|
|
return i
|
|
end
|
|
end
|
|
end
|
|
|
|
function DF.table.addunique (t, index, value)
|
|
if (not value) then
|
|
value = index
|
|
index = #t + 1
|
|
end
|
|
|
|
for i = 1, #t do
|
|
if (t[i] == value) then
|
|
return false
|
|
end
|
|
end
|
|
|
|
tinsert (t, index, value)
|
|
return true
|
|
end
|
|
|
|
function DF.table.reverse (t)
|
|
local new = {}
|
|
local index = 1
|
|
for i = #t, 1, -1 do
|
|
new [index] = t[i]
|
|
index = index + 1
|
|
end
|
|
return new
|
|
end
|
|
|
|
--> copy from table2 to table1 overwriting values
|
|
function DF.table.copy(t1, t2)
|
|
for key, value in pairs(t2) do
|
|
if (key ~= "__index" and key ~= "__newindex") then
|
|
if (type (value) == "table") then
|
|
t1[key] = t1[key] or {}
|
|
DF.table.copy(t1[key], t2[key])
|
|
else
|
|
t1[key] = value
|
|
end
|
|
end
|
|
end
|
|
return t1
|
|
end
|
|
|
|
--> copy from table2 to table1 overwriting values but do not copy data that cannot be compressed
|
|
function DF.table.copytocompress(t1, t2)
|
|
for key, value in pairs(t2) do
|
|
if (key ~= "__index" and type(value) ~= "function") then
|
|
if (type(value) == "table") then
|
|
if (not value.GetObjectType) then
|
|
t1[key] = t1[key] or {}
|
|
DF.table.copytocompress(t1[key], t2[key])
|
|
end
|
|
else
|
|
t1 [key] = value
|
|
end
|
|
end
|
|
end
|
|
return t1
|
|
end
|
|
|
|
--> copy values that does exist on table2 but not on table1
|
|
function DF.table.deploy (t1, t2)
|
|
for key, value in pairs (t2) do
|
|
if (type (value) == "table") then
|
|
t1 [key] = t1 [key] or {}
|
|
DF.table.deploy (t1 [key], t2 [key])
|
|
elseif (t1 [key] == nil) then
|
|
t1 [key] = value
|
|
end
|
|
end
|
|
return t1
|
|
end
|
|
|
|
function DF.table.dump (t, s, deep)
|
|
s = s or ""
|
|
deep = deep or 0
|
|
local space = ""
|
|
for i = 1, deep do
|
|
space = space .. " "
|
|
end
|
|
|
|
for key, value in pairs (t) do
|
|
local tpe = _type (value)
|
|
|
|
if (type (key) == "function") then
|
|
key = "#function#"
|
|
elseif (type (key) == "table") then
|
|
key = "#table#"
|
|
end
|
|
|
|
if (type (key) ~= "string" and type (key) ~= "number") then
|
|
key = "unknown?"
|
|
end
|
|
|
|
if (tpe == "table") then
|
|
if (type (key) == "number") then
|
|
s = s .. space .. "[" .. key .. "] = |cFFa9ffa9 {|r\n"
|
|
else
|
|
s = s .. space .. "[\"" .. key .. "\"] = |cFFa9ffa9 {|r\n"
|
|
end
|
|
s = s .. DF.table.dump (value, nil, deep+1)
|
|
s = s .. space .. "|cFFa9ffa9},|r\n"
|
|
|
|
elseif (tpe == "string") then
|
|
s = s .. space .. "[\"" .. key .. "\"] = \"|cFFfff1c1" .. value .. "|r\",\n"
|
|
|
|
elseif (tpe == "number") then
|
|
s = s .. space .. "[\"" .. key .. "\"] = |cFFffc1f4" .. value .. "|r,\n"
|
|
|
|
elseif (tpe == "function") then
|
|
s = s .. space .. "[\"" .. key .. "\"] = function()end,\n"
|
|
|
|
elseif (tpe == "boolean") then
|
|
s = s .. space .. "[\"" .. key .. "\"] = |cFF99d0ff" .. (value and "true" or "false") .. "|r,\n"
|
|
end
|
|
end
|
|
|
|
return s
|
|
end
|
|
|
|
--grab a text and split it into lines adding each line to a indexed table
|
|
function DF:SplitTextInLines(text)
|
|
local lines = {}
|
|
local position = 1
|
|
local startScope, endScope = text:find("\n", position, true)
|
|
|
|
while (startScope) do
|
|
if (startScope ~= 1) then
|
|
tinsert(lines, text:sub(position, startScope-1))
|
|
end
|
|
position = endScope + 1
|
|
startScope, endScope = text:find("\n", position, true)
|
|
end
|
|
|
|
if (position <= #text) then
|
|
tinsert(lines, text:sub(position))
|
|
end
|
|
|
|
return lines
|
|
end
|
|
|
|
|
|
DF.www_icons = {
|
|
texture = "feedback_sites",
|
|
wowi = {0, 0.7890625, 0, 37/128},
|
|
curse = {0, 0.7890625, 38/123, 79/128},
|
|
mmoc = {0, 0.7890625, 80/123, 123/128},
|
|
}
|
|
|
|
local symbol_1K, symbol_10K, symbol_1B
|
|
if (GetLocale() == "koKR") then
|
|
symbol_1K, symbol_10K, symbol_1B = "천", "만", "억"
|
|
elseif (GetLocale() == "zhCN") then
|
|
symbol_1K, symbol_10K, symbol_1B = "千", "万", "亿"
|
|
elseif (GetLocale() == "zhTW") then
|
|
symbol_1K, symbol_10K, symbol_1B = "千", "萬", "億"
|
|
end
|
|
|
|
function DF:GetAsianNumberSymbols()
|
|
if (GetLocale() == "koKR") then
|
|
return "천", "만", "억"
|
|
elseif (GetLocale() == "zhCN") then
|
|
return "千", "万", "亿"
|
|
elseif (GetLocale() == "zhTW") then
|
|
return "千", "萬", "億"
|
|
else
|
|
--> return korean as default (if the language is western)
|
|
return "천", "만", "억"
|
|
end
|
|
end
|
|
|
|
if (symbol_1K) then
|
|
function DF.FormatNumber (numero)
|
|
if (numero > 99999999) then
|
|
return format ("%.2f", numero/100000000) .. symbol_1B
|
|
elseif (numero > 999999) then
|
|
return format ("%.2f", numero/10000) .. symbol_10K
|
|
elseif (numero > 99999) then
|
|
return floor (numero/10000) .. symbol_10K
|
|
elseif (numero > 9999) then
|
|
return format ("%.1f", (numero/10000)) .. symbol_10K
|
|
elseif (numero > 999) then
|
|
return format ("%.1f", (numero/1000)) .. symbol_1K
|
|
end
|
|
return format ("%.1f", numero)
|
|
end
|
|
else
|
|
function DF.FormatNumber (numero)
|
|
if (numero > 999999999) then
|
|
return format ("%.2f", numero/1000000000) .. "B"
|
|
elseif (numero > 999999) then
|
|
return format ("%.2f", numero/1000000) .. "M"
|
|
elseif (numero > 99999) then
|
|
return floor (numero/1000) .. "K"
|
|
elseif (numero > 999) then
|
|
return format ("%.1f", (numero/1000)) .. "K"
|
|
end
|
|
return floor (numero)
|
|
end
|
|
end
|
|
|
|
function DF:CommaValue (value)
|
|
if (not value) then
|
|
return "0"
|
|
end
|
|
|
|
value = floor (value)
|
|
|
|
if (value == 0) then
|
|
return "0"
|
|
end
|
|
|
|
--source http://richard.warburton.it
|
|
local left, num, right = string_match (value, '^([^%d]*%d)(%d*)(.-)$')
|
|
return left .. (num:reverse():gsub ('(%d%d%d)','%1,'):reverse()) .. right
|
|
end
|
|
|
|
function DF:GroupIterator (func, ...)
|
|
if (IsInRaid()) then
|
|
for i = 1, GetNumGroupMembers() do
|
|
DF:QuickDispatch (func, "raid" .. i, ...)
|
|
end
|
|
|
|
elseif (IsInGroup()) then
|
|
for i = 1, GetNumGroupMembers() - 1 do
|
|
DF:QuickDispatch (func, "party" .. i, ...)
|
|
end
|
|
DF:QuickDispatch (func, "player", ...)
|
|
|
|
else
|
|
DF:QuickDispatch (func, "player", ...)
|
|
end
|
|
end
|
|
|
|
function DF:IntegerToTimer (value)
|
|
return "" .. floor (value/60) .. ":" .. format ("%02.f", value%60)
|
|
end
|
|
|
|
function DF:Embed (target)
|
|
for k, v in pairs (embed_functions) do
|
|
target[v] = self[v]
|
|
end
|
|
self.embeds [target] = true
|
|
return target
|
|
end
|
|
|
|
function DF:RemoveRealmName (name)
|
|
return name:gsub (("%-.*"), "")
|
|
end
|
|
|
|
function DF:RemoveRealName (name)
|
|
return name:gsub (("%-.*"), "")
|
|
end
|
|
|
|
function DF:SetFontSize (fontString, ...)
|
|
local fonte, _, flags = fontString:GetFont()
|
|
fontString:SetFont (fonte, max (...), flags)
|
|
end
|
|
function DF:SetFontFace (fontString, fontface)
|
|
local font = SharedMedia:Fetch ("font", fontface, true)
|
|
if (font) then
|
|
fontface = font
|
|
end
|
|
|
|
local _, size, flags = fontString:GetFont()
|
|
fontString:SetFont (fontface, size, flags)
|
|
end
|
|
function DF:SetFontColor (fontString, r, g, b, a)
|
|
r, g, b, a = DF:ParseColors (r, g, b, a)
|
|
fontString:SetTextColor (r, g, b, a)
|
|
end
|
|
|
|
function DF:SetFontShadow (fontString, r, g, b, a, x, y)
|
|
r, g, b, a = DF:ParseColors (r, g, b, a)
|
|
fontString:SetShadowColor (r, g, b, a)
|
|
|
|
local offSetX, offSetY = fontString:GetShadowOffset()
|
|
x = x or offSetX
|
|
y = y or offSetY
|
|
|
|
fontString:SetShadowOffset (x, y)
|
|
end
|
|
|
|
function DF:AddClassColorToText (text, class)
|
|
if (type (class) ~= "string") then
|
|
return DF:RemoveRealName (text)
|
|
|
|
elseif (class == "UNKNOW" or class == "PET") then
|
|
return DF:RemoveRealName (text)
|
|
end
|
|
|
|
local color = RAID_CLASS_COLORS [class]
|
|
if (color) then
|
|
text = "|c" .. color.colorStr .. DF:RemoveRealName (text) .. "|r"
|
|
else
|
|
return DF:RemoveRealName (text)
|
|
end
|
|
|
|
return text
|
|
end
|
|
|
|
function DF:GetClassTCoordsAndTexture(class)
|
|
local l, r, t, b = unpack(CLASS_ICON_TCOORDS[class])
|
|
return l, r, t, b, [[Interface\WORLDSTATEFRAME\Icons-Classes]]
|
|
--return l, r, t, b, "Interface\\TargetingFrame\\UI-Classes-Circles"
|
|
end
|
|
|
|
function DF:AddClassIconToText(text, playerName, class, useSpec, iconSize)
|
|
local size = iconSize or 16
|
|
|
|
local iconToUse, spec
|
|
if (useSpec) then
|
|
if (Details) then
|
|
local guid = UnitGUID(playerName)
|
|
if (guid) then
|
|
local spec = Details.cached_specs[guid]
|
|
if (spec) then
|
|
spec = spec
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
if (spec) then --if spec is valid, the user has Details! installed
|
|
local specString = ""
|
|
local L, R, T, B = unpack (Details.class_specs_coords[spec])
|
|
if (L) then
|
|
specString = "|TInterface\\AddOns\\Details\\images\\spec_icons_normal:" .. size .. ":" .. size .. ":0:0:512:512:" .. (L * 512) .. ":" .. (R * 512) .. ":" .. (T * 512) .. ":" .. (B * 512) .. "|t"
|
|
return specString .. " " .. text
|
|
end
|
|
end
|
|
|
|
if (class) then
|
|
local classString = ""
|
|
local L, R, T, B = unpack (Details.class_coords[class])
|
|
if (L) then
|
|
local imageSize = 128
|
|
classString = "|TInterface\\AddOns\\Details\\images\\classes_small:" .. size .. ":" .. size .. ":0:0:" .. imageSize .. ":" .. imageSize .. ":" .. (L * imageSize) .. ":" .. (R * imageSize) .. ":" .. (T * imageSize) .. ":" .. (B * imageSize) .. "|t"
|
|
return classString .. " " .. text
|
|
end
|
|
end
|
|
|
|
return text
|
|
end
|
|
|
|
function DF:GetFontSize (fontString)
|
|
local _, size = fontString:GetFont()
|
|
return size
|
|
end
|
|
function DF:GetFontFace (fontString)
|
|
local fontface = fontString:GetFont()
|
|
return fontface
|
|
end
|
|
|
|
local ValidOutlines = {
|
|
["NONE"] = true,
|
|
["MONOCHROME"] = true,
|
|
["OUTLINE"] = true,
|
|
["THICKOUTLINE"] = true,
|
|
}
|
|
function DF:SetFontOutline (fontString, outline)
|
|
local fonte, size = fontString:GetFont()
|
|
if (outline) then
|
|
if (ValidOutlines [outline]) then
|
|
outline = outline
|
|
elseif (_type (outline) == "boolean" and outline) then
|
|
outline = "OUTLINE"
|
|
elseif (outline == 1) then
|
|
outline = "OUTLINE"
|
|
elseif (outline == 2) then
|
|
outline = "THICKOUTLINE"
|
|
end
|
|
end
|
|
|
|
fontString:SetFont (fonte, size, outline)
|
|
end
|
|
|
|
function DF:Trim (s) --hello name conventions!
|
|
return DF:trim (s)
|
|
end
|
|
|
|
function DF:trim (s)
|
|
local from = s:match"^%s*()"
|
|
return from > #s and "" or s:match(".*%S", from)
|
|
end
|
|
|
|
function DF:TruncateText (fontString, maxWidth)
|
|
local text = fontString:GetText()
|
|
|
|
while (fontString:GetStringWidth() > maxWidth) do
|
|
text = strsub (text, 1, #text - 1)
|
|
fontString:SetText (text)
|
|
if (string.len (text) <= 1) then
|
|
break
|
|
end
|
|
end
|
|
|
|
text = DF:CleanTruncateUTF8String(text)
|
|
fontString:SetText (text)
|
|
end
|
|
|
|
function DF:CleanTruncateUTF8String(text)
|
|
if type(text) == "string" and text ~= "" then
|
|
local b1 = (#text > 0) and strbyte(strsub(text, #text, #text)) or nil
|
|
local b2 = (#text > 1) and strbyte(strsub(text, #text-1, #text)) or nil
|
|
local b3 = (#text > 2) and strbyte(strsub(text, #text-2, #text)) or nil
|
|
if b1 and b1 >= 194 and b1 <= 244 then
|
|
text = strsub (text, 1, #text - 1)
|
|
elseif b2 and b2 >= 224 and b2 <= 244 then
|
|
text = strsub (text, 1, #text - 2)
|
|
elseif b3 and b3 >= 240 and b3 <= 244 then
|
|
text = strsub (text, 1, #text - 3)
|
|
end
|
|
end
|
|
return text
|
|
end
|
|
|
|
function DF:Msg (msg, ...)
|
|
print ("|cFFFFFFAA" .. (self.__name or "FW Msg:") .. "|r ", msg, ...)
|
|
end
|
|
|
|
function DF:GetNpcIdFromGuid (guid)
|
|
local NpcId = select ( 6, strsplit ( "-", guid ) )
|
|
if (NpcId) then
|
|
return tonumber ( NpcId )
|
|
end
|
|
return 0
|
|
end
|
|
|
|
function DF.SortOrder1 (t1, t2)
|
|
return t1[1] > t2[1]
|
|
end
|
|
function DF.SortOrder2 (t1, t2)
|
|
return t1[2] > t2[2]
|
|
end
|
|
function DF.SortOrder3 (t1, t2)
|
|
return t1[3] > t2[3]
|
|
end
|
|
function DF.SortOrder1R (t1, t2)
|
|
return t1[1] < t2[1]
|
|
end
|
|
function DF.SortOrder2R (t1, t2)
|
|
return t1[2] < t2[2]
|
|
end
|
|
function DF.SortOrder3R (t1, t2)
|
|
return t1[3] < t2[3]
|
|
end
|
|
|
|
--return a list of spells from the player spellbook
|
|
function DF:GetSpellBookSpells()
|
|
local spellNamesInSpellBook = {}
|
|
|
|
for i = 1, GetNumSpellTabs() do
|
|
local tabName, tabTexture, offset, numSpells, isGuild, offspecId = GetSpellTabInfo(i)
|
|
|
|
if (offspecId == 0) then
|
|
offset = offset + 1
|
|
local tabEnd = offset + numSpells
|
|
|
|
for j = offset, tabEnd - 1 do
|
|
local spellType, spellId = GetSpellBookItemInfo(j, "player")
|
|
|
|
if (spellId) then
|
|
if (spellType ~= "FLYOUT") then
|
|
local spellName = GetSpellInfo(spellId)
|
|
if (spellName) then
|
|
spellNamesInSpellBook[spellName] = true
|
|
end
|
|
else
|
|
local _, _, numSlots, isKnown = GetFlyoutInfo(spellId)
|
|
if (isKnown and numSlots > 0) then
|
|
for k = 1, numSlots do
|
|
local spellID, overrideSpellID, isKnown = GetFlyoutSlotInfo(spellId, k)
|
|
if (isKnown) then
|
|
local spellName = GetSpellInfo(spellID)
|
|
spellNamesInSpellBook[spellName] = true
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
return spellNamesInSpellBook
|
|
end
|
|
|
|
------------------------------
|
|
--flash animation
|
|
local onFinish = function (self)
|
|
if (self.showWhenDone) then
|
|
self.frame:SetAlpha (1)
|
|
else
|
|
self.frame:SetAlpha (0)
|
|
self.frame:Hide()
|
|
end
|
|
|
|
if (self.onFinishFunc) then
|
|
self:onFinishFunc (self.frame)
|
|
end
|
|
end
|
|
|
|
local stop = function (self)
|
|
local FlashAnimation = self.FlashAnimation
|
|
FlashAnimation:Stop()
|
|
end
|
|
|
|
local flash = function (self, fadeInTime, fadeOutTime, flashDuration, showWhenDone, flashInHoldTime, flashOutHoldTime, loopType)
|
|
|
|
local FlashAnimation = self.FlashAnimation
|
|
|
|
local fadeIn = FlashAnimation.fadeIn
|
|
local fadeOut = FlashAnimation.fadeOut
|
|
|
|
fadeIn:Stop()
|
|
fadeOut:Stop()
|
|
|
|
fadeIn:SetDuration (fadeInTime or 1)
|
|
fadeIn:SetEndDelay (flashInHoldTime or 0)
|
|
|
|
fadeOut:SetDuration (fadeOutTime or 1)
|
|
fadeOut:SetEndDelay (flashOutHoldTime or 0)
|
|
|
|
FlashAnimation.duration = flashDuration
|
|
FlashAnimation.loopTime = FlashAnimation:GetDuration()
|
|
FlashAnimation.finishAt = GetTime() + flashDuration
|
|
FlashAnimation.showWhenDone = showWhenDone
|
|
|
|
FlashAnimation:SetLooping (loopType or "REPEAT")
|
|
|
|
self:Show()
|
|
self:SetAlpha (0)
|
|
FlashAnimation:Play()
|
|
end
|
|
|
|
function DF:CreateFlashAnimation (frame, onFinishFunc, onLoopFunc)
|
|
local FlashAnimation = frame:CreateAnimationGroup()
|
|
|
|
FlashAnimation.fadeOut = FlashAnimation:CreateAnimation ("Alpha") --> fade out anime
|
|
FlashAnimation.fadeOut:SetOrder (1)
|
|
FlashAnimation.fadeOut:SetFromAlpha (0)
|
|
FlashAnimation.fadeOut:SetToAlpha (1)
|
|
|
|
FlashAnimation.fadeIn = FlashAnimation:CreateAnimation ("Alpha") --> fade in anime
|
|
FlashAnimation.fadeIn:SetOrder (2)
|
|
FlashAnimation.fadeIn:SetFromAlpha (1)
|
|
FlashAnimation.fadeIn:SetToAlpha (0)
|
|
|
|
frame.FlashAnimation = FlashAnimation
|
|
FlashAnimation.frame = frame
|
|
FlashAnimation.onFinishFunc = onFinishFunc
|
|
|
|
FlashAnimation:SetScript ("OnLoop", onLoopFunc)
|
|
FlashAnimation:SetScript ("OnFinished", onFinish)
|
|
|
|
frame.Flash = flash
|
|
frame.Stop = stop
|
|
end
|
|
|
|
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
--> points
|
|
|
|
function DF:CheckPoints (v1, v2, v3, v4, v5, object)
|
|
|
|
if (not v1 and not v2) then
|
|
return "topleft", object.widget:GetParent(), "topleft", 0, 0
|
|
end
|
|
|
|
if (_type (v1) == "string") then
|
|
local frameGlobal = _G [v1]
|
|
if (frameGlobal and type (frameGlobal) == "table" and frameGlobal.GetObjectType) then
|
|
return DF:CheckPoints (frameGlobal, v2, v3, v4, v5, object)
|
|
end
|
|
|
|
elseif (_type (v2) == "string") then
|
|
local frameGlobal = _G [v2]
|
|
if (frameGlobal and type (frameGlobal) == "table" and frameGlobal.GetObjectType) then
|
|
return DF:CheckPoints (v1, frameGlobal, v3, v4, v5, object)
|
|
end
|
|
end
|
|
|
|
if (_type (v1) == "string" and _type (v2) == "table") then --> :setpoint ("left", frame, _, _, _)
|
|
if (not v3 or _type (v3) == "number") then --> :setpoint ("left", frame, 10, 10)
|
|
v1, v2, v3, v4, v5 = v1, v2, v1, v3, v4
|
|
end
|
|
|
|
elseif (_type (v1) == "string" and _type (v2) == "number") then --> :setpoint ("topleft", x, y)
|
|
v1, v2, v3, v4, v5 = v1, object.widget:GetParent(), v1, v2, v3
|
|
|
|
elseif (_type (v1) == "number") then --> :setpoint (x, y)
|
|
v1, v2, v3, v4, v5 = "topleft", object.widget:GetParent(), "topleft", v1, v2
|
|
|
|
elseif (_type (v1) == "table") then --> :setpoint (frame, x, y)
|
|
v1, v2, v3, v4, v5 = "topleft", v1, "topleft", v2, v3
|
|
|
|
end
|
|
|
|
if (not v2) then
|
|
v2 = object.widget:GetParent()
|
|
elseif (v2.dframework) then
|
|
v2 = v2.widget
|
|
end
|
|
|
|
return v1 or "topleft", v2, v3 or "topleft", v4 or 0, v5 or 0
|
|
end
|
|
|
|
local anchoring_functions = {
|
|
function (frame, anchorTo, offSetX, offSetY) --> 1 TOP LEFT
|
|
frame:ClearAllPoints()
|
|
frame:SetPoint ("bottomleft", anchorTo, "topleft", offSetX, offSetY)
|
|
end,
|
|
|
|
function (frame, anchorTo, offSetX, offSetY) --> 2 LEFT
|
|
frame:ClearAllPoints()
|
|
frame:SetPoint ("right", anchorTo, "left", offSetX, offSetY)
|
|
end,
|
|
|
|
function (frame, anchorTo, offSetX, offSetY) --> 3 BOTTOM LEFT
|
|
frame:ClearAllPoints()
|
|
frame:SetPoint ("topleft", anchorTo, "bottomleft", offSetX, offSetY)
|
|
end,
|
|
|
|
function (frame, anchorTo, offSetX, offSetY) --> 4 BOTTOM
|
|
frame:ClearAllPoints()
|
|
frame:SetPoint ("top", anchorTo, "bottom", offSetX, offSetY)
|
|
end,
|
|
|
|
function (frame, anchorTo, offSetX, offSetY) --> 5 BOTTOM RIGHT
|
|
frame:ClearAllPoints()
|
|
frame:SetPoint ("topright", anchorTo, "bottomright", offSetX, offSetY)
|
|
end,
|
|
|
|
function (frame, anchorTo, offSetX, offSetY) --> 6 RIGHT
|
|
frame:ClearAllPoints()
|
|
frame:SetPoint ("left", anchorTo, "right", offSetX, offSetY)
|
|
end,
|
|
|
|
function (frame, anchorTo, offSetX, offSetY) --> 7 TOP RIGHT
|
|
frame:ClearAllPoints()
|
|
frame:SetPoint ("bottomright", anchorTo, "topright", offSetX, offSetY)
|
|
end,
|
|
|
|
function (frame, anchorTo, offSetX, offSetY) --> 8 TOP
|
|
frame:ClearAllPoints()
|
|
frame:SetPoint ("bottom", anchorTo, "top", offSetX, offSetY)
|
|
end,
|
|
|
|
function (frame, anchorTo, offSetX, offSetY) --> 9 CENTER
|
|
frame:ClearAllPoints()
|
|
frame:SetPoint ("center", anchorTo, "center", offSetX, offSetY)
|
|
end,
|
|
|
|
function (frame, anchorTo, offSetX, offSetY) --> 10
|
|
frame:ClearAllPoints()
|
|
frame:SetPoint ("left", anchorTo, "left", offSetX, offSetY)
|
|
end,
|
|
|
|
function (frame, anchorTo, offSetX, offSetY) --> 11
|
|
frame:ClearAllPoints()
|
|
frame:SetPoint ("right", anchorTo, "right", offSetX, offSetY)
|
|
end,
|
|
|
|
function (frame, anchorTo, offSetX, offSetY) --> 12
|
|
frame:ClearAllPoints()
|
|
frame:SetPoint ("top", anchorTo, "top", offSetX, offSetY)
|
|
end,
|
|
|
|
function (frame, anchorTo, offSetX, offSetY) --> 13
|
|
frame:ClearAllPoints()
|
|
frame:SetPoint ("bottom", anchorTo, "bottom", offSetX, offSetY)
|
|
end
|
|
}
|
|
|
|
function DF:SetAnchor (widget, config, anchorTo)
|
|
anchorTo = anchorTo or widget:GetParent()
|
|
anchoring_functions [config.side] (widget, anchorTo, config.x, config.y)
|
|
end
|
|
|
|
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
--> colors
|
|
|
|
function DF:NewColor (_colorname, _colortable, _green, _blue, _alpha)
|
|
assert (_type (_colorname) == "string", "NewColor: colorname must be a string.")
|
|
assert (not DF.alias_text_colors [_colorname], "NewColor: colorname already exists.")
|
|
|
|
if (_type (_colortable) == "table") then
|
|
if (_colortable[1] and _colortable[2] and _colortable[3]) then
|
|
_colortable[4] = _colortable[4] or 1
|
|
DF.alias_text_colors [_colorname] = _colortable
|
|
else
|
|
error ("invalid color table.")
|
|
end
|
|
elseif (_colortable and _green and _blue) then
|
|
_alpha = _alpha or 1
|
|
DF.alias_text_colors [_colorname] = {_colortable, _green, _blue, _alpha}
|
|
else
|
|
error ("invalid parameter.")
|
|
end
|
|
|
|
return true
|
|
end
|
|
|
|
local colorTableMixin = {
|
|
GetColor = function (self)
|
|
return self.r, self.g, self.b, self.a
|
|
end,
|
|
|
|
SetColor = function (self, r, g, b, a)
|
|
r, g, b, a = DF:ParseColors (r, g, b, a)
|
|
self.r = r or self.r
|
|
self.g = g or self.g
|
|
self.b = b or self.b
|
|
self.a = a or self.a
|
|
end,
|
|
|
|
IsColorTable = true,
|
|
}
|
|
|
|
function DF:CreateColorTable (r, g, b, a)
|
|
local t = {
|
|
r = r or 1,
|
|
g = g or 1,
|
|
b = b or 1,
|
|
a = a or 1,
|
|
}
|
|
DF:Mixin (t, colorTableMixin)
|
|
return t
|
|
end
|
|
|
|
function DF:IsHtmlColor (color)
|
|
return DF.alias_text_colors [color]
|
|
end
|
|
|
|
local tn = tonumber
|
|
function DF:ParseColors (_arg1, _arg2, _arg3, _arg4)
|
|
if (_type (_arg1) == "table") then
|
|
if (_arg1.IsColorTable) then
|
|
return _arg1:GetColor()
|
|
|
|
elseif (not _arg1[1] and _arg1.r) then
|
|
_arg1, _arg2, _arg3, _arg4 = _arg1.r, _arg1.g, _arg1.b, _arg1.a
|
|
|
|
else
|
|
_arg1, _arg2, _arg3, _arg4 = _unpack (_arg1)
|
|
end
|
|
|
|
elseif (_type (_arg1) == "string") then
|
|
|
|
if (string.find (_arg1, "#")) then
|
|
_arg1 = _arg1:gsub ("#","")
|
|
if (string.len (_arg1) == 8) then --alpha
|
|
_arg1, _arg2, _arg3, _arg4 = tn ("0x" .. _arg1:sub (3, 4))/255, tn ("0x" .. _arg1:sub (5, 6))/255, tn ("0x" .. _arg1:sub (7, 8))/255, tn ("0x" .. _arg1:sub (1, 2))/255
|
|
else
|
|
_arg1, _arg2, _arg3, _arg4 = tn ("0x" .. _arg1:sub (1, 2))/255, tn ("0x" .. _arg1:sub (3, 4))/255, tn ("0x" .. _arg1:sub (5, 6))/255, 1
|
|
end
|
|
|
|
else
|
|
local color = DF.alias_text_colors [_arg1]
|
|
if (color) then
|
|
_arg1, _arg2, _arg3, _arg4 = _unpack (color)
|
|
else
|
|
_arg1, _arg2, _arg3, _arg4 = _unpack (DF.alias_text_colors.none)
|
|
end
|
|
end
|
|
end
|
|
|
|
if (not _arg1) then
|
|
_arg1 = 1
|
|
end
|
|
if (not _arg2) then
|
|
_arg2 = 1
|
|
end
|
|
if (not _arg3) then
|
|
_arg3 = 1
|
|
end
|
|
if (not _arg4) then
|
|
_arg4 = 1
|
|
end
|
|
|
|
return _arg1, _arg2, _arg3, _arg4
|
|
end
|
|
|
|
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
--> menus
|
|
|
|
local disable_on_combat = {}
|
|
|
|
local getMenuWidgetVolative = function(parent, widgetType, indexTable)
|
|
|
|
local widget
|
|
|
|
if (widgetType == "label") then
|
|
widget = parent.widget_list_by_type[widgetType][indexTable[widgetType]]
|
|
if (not widget) then
|
|
widget = DF:CreateLabel (parent, "", 10, "white", "", nil, "$parentWidget" .. widgetType .. indexTable[widgetType], "overlay")
|
|
tinsert(parent.widget_list, widget)
|
|
tinsert(parent.widget_list_by_type[widgetType], widget)
|
|
end
|
|
|
|
indexTable[widgetType] = indexTable[widgetType] + 1
|
|
|
|
elseif (widgetType == "dropdown") then
|
|
widget = parent.widget_list_by_type[widgetType][indexTable[widgetType]]
|
|
|
|
if (not widget) then
|
|
widget = DF:CreateDropDown (parent, function() return {} end, nil, 140, 18, nil, "$parentWidget" .. widgetType .. indexTable[widgetType])
|
|
widget.hasLabel = DF:CreateLabel (parent, "", 10, "white", "", nil, "$parentWidget" .. widgetType .. indexTable[widgetType] .. "label", "overlay")
|
|
tinsert(parent.widget_list, widget)
|
|
tinsert(parent.widget_list_by_type[widgetType], widget)
|
|
|
|
else
|
|
widget:ClearHooks()
|
|
widget.hasLabel.text = ""
|
|
end
|
|
|
|
indexTable[widgetType] = indexTable[widgetType] + 1
|
|
|
|
elseif (widgetType == "switch") then
|
|
widget = parent.widget_list_by_type[widgetType][indexTable[widgetType]]
|
|
|
|
if (not widget) then
|
|
widget = DF:CreateSwitch (parent, nil, true, 20, 20, nil, nil, nil, "$parentWidget" .. widgetType .. indexTable[widgetType])
|
|
widget.hasLabel = DF:CreateLabel (parent, "", 10, "white", "", nil, "$parentWidget" .. widgetType .. indexTable[widgetType] .. "label", "overlay")
|
|
|
|
tinsert(parent.widget_list, widget)
|
|
tinsert(parent.widget_list_by_type[widgetType], widget)
|
|
else
|
|
widget:ClearHooks()
|
|
end
|
|
|
|
indexTable[widgetType] = indexTable[widgetType] + 1
|
|
|
|
elseif (widgetType == "slider") then
|
|
widget = parent.widget_list_by_type[widgetType][indexTable[widgetType]]
|
|
|
|
if (not widget) then
|
|
widget = DF:CreateSlider (parent, 140, 20, 1, 2, 1, 1, false, nil, "$parentWidget" .. widgetType .. indexTable[widgetType])
|
|
widget.hasLabel = DF:CreateLabel (parent, "", 10, "white", "", nil, "$parentWidget" .. widgetType .. indexTable[widgetType] .. "label", "overlay")
|
|
|
|
tinsert(parent.widget_list, widget)
|
|
tinsert(parent.widget_list_by_type[widgetType], widget)
|
|
else
|
|
widget:ClearHooks()
|
|
end
|
|
|
|
indexTable[widgetType] = indexTable[widgetType] + 1
|
|
|
|
elseif (widgetType == "color") then
|
|
widget = parent.widget_list_by_type[widgetType][indexTable[widgetType]]
|
|
|
|
if (not widget) then
|
|
widget = DF:CreateColorPickButton (parent, "$parentWidget" .. widgetType .. indexTable[widgetType], nil, function()end, 1)
|
|
widget.hasLabel = DF:CreateLabel (parent, "", 10, "white", "", nil, "$parentWidget" .. widgetType .. indexTable[widgetType] .. "label", "overlay")
|
|
|
|
tinsert(parent.widget_list, widget)
|
|
tinsert(parent.widget_list_by_type[widgetType], widget)
|
|
else
|
|
widget:ClearHooks()
|
|
end
|
|
|
|
indexTable[widgetType] = indexTable[widgetType] + 1
|
|
|
|
elseif (widgetType == "button") then
|
|
widget = parent.widget_list_by_type[widgetType][indexTable[widgetType]]
|
|
|
|
if (not widget) then
|
|
widget = DF:CreateButton (parent, function()end, 120, 18, "", nil, nil, nil, nil, "$parentWidget" .. widgetType .. indexTable[widgetType])
|
|
widget.hasLabel = DF:CreateLabel (parent, "", 10, "white", "", nil, "$parentWidget" .. widgetType .. indexTable[widgetType] .. "label", "overlay")
|
|
|
|
tinsert(parent.widget_list, widget)
|
|
tinsert(parent.widget_list_by_type[widgetType], widget)
|
|
else
|
|
widget:ClearHooks()
|
|
end
|
|
|
|
indexTable[widgetType] = indexTable[widgetType] + 1
|
|
|
|
elseif (widgetType == "textentry") then
|
|
widget = parent.widget_list_by_type[widgetType][indexTable[widgetType]]
|
|
|
|
if (not widget) then
|
|
widget = DF:CreateTextEntry (parent, function()end, 120, 18, nil, "$parentWidget" .. widgetType .. indexTable[widgetType])
|
|
widget.hasLabel = DF:CreateLabel (parent, "", 10, "white", "", nil, "$parentWidget" .. widgetType .. indexTable[widgetType] .. "label", "overlay")
|
|
|
|
tinsert(parent.widget_list, widget)
|
|
tinsert(parent.widget_list_by_type[widgetType], widget)
|
|
else
|
|
widget:ClearHooks()
|
|
end
|
|
|
|
indexTable[widgetType] = indexTable[widgetType] + 1
|
|
end
|
|
|
|
--if the widget is inside the no combat table, remove it
|
|
for i = 1, #disable_on_combat do
|
|
if (disable_on_combat[i] == widget) then
|
|
tremove(disable_on_combat, i)
|
|
break
|
|
end
|
|
end
|
|
|
|
return widget
|
|
end
|
|
|
|
--volatile menu can be called several times, each time all settings are reset and a new menu is built using the same widgets
|
|
function DF:BuildMenuVolatile (parent, menu, x_offset, y_offset, height, use_two_points, text_template, dropdown_template, switch_template, switch_is_box, slider_template, button_template, value_change_hook)
|
|
|
|
if (not parent.widget_list) then
|
|
DF:SetAsOptionsPanel (parent)
|
|
end
|
|
DF:ClearOptionsPanel(parent)
|
|
|
|
local cur_x = x_offset
|
|
local cur_y = y_offset
|
|
local max_x = 0
|
|
|
|
local latestInlineWidget
|
|
|
|
local widgetIndexes = {
|
|
label = 1,
|
|
dropdown = 1,
|
|
switch = 1,
|
|
slider = 1,
|
|
color = 1,
|
|
button = 1,
|
|
textentry = 1,
|
|
}
|
|
|
|
height = abs ((height or parent:GetHeight()) - abs (y_offset) + 20)
|
|
height = height*-1
|
|
|
|
for index, widget_table in ipairs(menu) do
|
|
if (not widget_table.hidden) then
|
|
|
|
local widget_created
|
|
if (latestInlineWidget) then
|
|
if (not widget_table.inline) then
|
|
latestInlineWidget = nil
|
|
cur_y = cur_y - 20
|
|
end
|
|
end
|
|
|
|
if (not widget_table.novolatile) then
|
|
|
|
--step a line
|
|
if (widget_table.type == "blank" or widget_table.type == "space") then
|
|
-- do nothing
|
|
|
|
elseif (widget_table.type == "label" or widget_table.type == "text") then
|
|
|
|
local label = getMenuWidgetVolative(parent, "label", widgetIndexes)
|
|
widget_created = label
|
|
|
|
label.text = widget_table.get() or widget_table.text or ""
|
|
label.color = widget_table.color
|
|
|
|
if (widget_table.font) then
|
|
label.fontface = widget_table.font
|
|
end
|
|
|
|
if (widget_table.text_template or text_template) then
|
|
label:SetTemplate(widget_table.text_template or text_template)
|
|
else
|
|
label.fontsize = widget_table.size or 10
|
|
end
|
|
|
|
label._get = widget_table.get
|
|
label.widget_type = "label"
|
|
label:ClearAllPoints()
|
|
label:SetPoint (cur_x, cur_y)
|
|
|
|
if (widget_table.id) then
|
|
parent.widgetids [widget_table.id] = label
|
|
end
|
|
|
|
--dropdowns
|
|
elseif (widget_table.type == "select" or widget_table.type == "dropdown") then
|
|
|
|
local dropdown = getMenuWidgetVolative(parent, "dropdown", widgetIndexes)
|
|
widget_created = dropdown
|
|
|
|
dropdown:SetFunction(widget_table.values)
|
|
dropdown:Refresh()
|
|
dropdown:Select (widget_table.get())
|
|
dropdown:SetTemplate (dropdown_template)
|
|
|
|
dropdown.tooltip = widget_table.desc
|
|
dropdown._get = widget_table.get
|
|
dropdown.widget_type = "select"
|
|
|
|
|
|
dropdown.hasLabel.text = widget_table.name .. (use_two_points and ": " or "")
|
|
dropdown.hasLabel:SetTemplate(widget_table.text_template or text_template)
|
|
dropdown:ClearAllPoints()
|
|
dropdown:SetPoint ("left", dropdown.hasLabel, "right", 2)
|
|
dropdown.hasLabel:ClearAllPoints()
|
|
dropdown.hasLabel:SetPoint (cur_x, cur_y)
|
|
|
|
--> global callback
|
|
if (value_change_hook) then
|
|
dropdown:SetHook ("OnOptionSelected", value_change_hook)
|
|
end
|
|
|
|
--> hook list (hook list is wiped when getting the widget)
|
|
if (widget_table.hooks) then
|
|
for hookName, hookFunc in pairs (widget_table.hooks) do
|
|
dropdown:SetHook (hookName, hookFunc)
|
|
end
|
|
end
|
|
|
|
if (widget_table.id) then
|
|
parent.widgetids [widget_table.id] = dropdown
|
|
end
|
|
|
|
local size = dropdown.hasLabel.widget:GetStringWidth() + 140 + 4
|
|
if (size > max_x) then
|
|
max_x = size
|
|
end
|
|
|
|
--switchs
|
|
elseif (widget_table.type == "toggle" or widget_table.type == "switch") then
|
|
|
|
local switch = getMenuWidgetVolative(parent, "switch", widgetIndexes)
|
|
widget_created = switch
|
|
|
|
switch:SetValue(widget_table.get())
|
|
switch:SetTemplate(switch_template)
|
|
switch:SetAsCheckBox() --it's always a checkbox on volatile menu
|
|
|
|
switch.tooltip = widget_table.desc
|
|
switch._get = widget_table.get
|
|
switch.widget_type = "toggle"
|
|
switch.OnSwitch = widget_table.set
|
|
|
|
if (value_change_hook) then
|
|
switch:SetHook ("OnSwitch", value_change_hook)
|
|
end
|
|
|
|
--> hook list
|
|
if (widget_table.hooks) then
|
|
for hookName, hookFunc in pairs (widget_table.hooks) do
|
|
switch:SetHook (hookName, hookFunc)
|
|
end
|
|
end
|
|
|
|
if (widget_table.width) then
|
|
switch:SetWidth(widget_table.width)
|
|
end
|
|
if (widget_table.height) then
|
|
switch:SetHeight(widget_table.height)
|
|
end
|
|
|
|
switch.hasLabel.text = widget_table.name .. (use_two_points and ": " or "")
|
|
switch.hasLabel:SetTemplate(widget_table.text_template or text_template)
|
|
|
|
switch:ClearAllPoints()
|
|
switch.hasLabel:ClearAllPoints()
|
|
|
|
if (widget_table.boxfirst) then
|
|
switch:SetPoint (cur_x, cur_y)
|
|
switch.hasLabel:SetPoint ("left", switch, "right", 2)
|
|
else
|
|
switch.hasLabel:SetPoint (cur_x, cur_y)
|
|
switch:SetPoint ("left", switch.hasLabel, "right", 2)
|
|
end
|
|
|
|
if (widget_table.id) then
|
|
parent.widgetids [widget_table.id] = switch
|
|
end
|
|
|
|
local size = switch.hasLabel:GetStringWidth() + 60 + 4
|
|
if (size > max_x) then
|
|
max_x = size
|
|
end
|
|
|
|
--slider
|
|
elseif (widget_table.type == "range" or widget_table.type == "slider") then
|
|
|
|
local slider = getMenuWidgetVolative(parent, "slider", widgetIndexes)
|
|
widget_created = slider
|
|
|
|
if (widget_table.usedecimals) then
|
|
slider.slider:SetValueStep (0.01)
|
|
else
|
|
slider.slider:SetValueStep (widget_table.step)
|
|
end
|
|
slider.useDecimals = widget_table.usedecimals
|
|
|
|
slider.slider:SetMinMaxValues (widget_table.min, widget_table.max)
|
|
slider.slider:SetValue (widget_table.get())
|
|
slider.ivalue = slider.slider:GetValue()
|
|
|
|
slider:SetTemplate(slider_template)
|
|
|
|
slider.tooltip = widget_table.desc
|
|
slider._get = widget_table.get
|
|
slider.widget_type = "range"
|
|
slider:SetHook ("OnValueChange", widget_table.set)
|
|
|
|
if (value_change_hook) then
|
|
slider:SetHook ("OnValueChange", value_change_hook)
|
|
end
|
|
|
|
if (widget_table.thumbscale) then
|
|
slider:SetThumbSize (slider.thumb.originalWidth * widget_table.thumbscale, nil)
|
|
else
|
|
slider:SetThumbSize (slider.thumb.originalWidth * 1.3, nil)
|
|
end
|
|
|
|
--> hook list
|
|
if (widget_table.hooks) then
|
|
for hookName, hookFunc in pairs (widget_table.hooks) do
|
|
slider:SetHook (hookName, hookFunc)
|
|
end
|
|
end
|
|
|
|
slider.hasLabel.text = widget_table.name .. (use_two_points and ": " or "")
|
|
slider.hasLabel:SetTemplate(widget_table.text_template or text_template)
|
|
|
|
slider:SetPoint ("left", slider.hasLabel, "right", 2)
|
|
slider.hasLabel:SetPoint (cur_x, cur_y)
|
|
|
|
if (widget_table.id) then
|
|
parent.widgetids [widget_table.id] = slider
|
|
end
|
|
|
|
local size = slider.hasLabel:GetStringWidth() + 140 + 6
|
|
if (size > max_x) then
|
|
max_x = size
|
|
end
|
|
|
|
--color
|
|
elseif (widget_table.type == "color" or widget_table.type == "color") then
|
|
|
|
local colorpick = getMenuWidgetVolative(parent, "color", widgetIndexes)
|
|
widget_created = colorpick
|
|
|
|
colorpick.color_callback = widget_table.set --callback
|
|
colorpick:SetTemplate(button_template)
|
|
|
|
colorpick.tooltip = widget_table.desc
|
|
colorpick._get = widget_table.get
|
|
colorpick.widget_type = "color"
|
|
|
|
local default_value, g, b, a = widget_table.get()
|
|
if (type (default_value) == "table") then
|
|
colorpick:SetColor (unpack (default_value))
|
|
else
|
|
colorpick:SetColor (default_value, g, b, a)
|
|
end
|
|
|
|
if (value_change_hook) then
|
|
colorpick:SetHook ("OnColorChanged", value_change_hook)
|
|
end
|
|
|
|
--> hook list
|
|
if (widget_table.hooks) then
|
|
for hookName, hookFunc in pairs (widget_table.hooks) do
|
|
colorpick:SetHook (hookName, hookFunc)
|
|
end
|
|
end
|
|
|
|
colorpick.hasLabel.text = widget_table.name .. (use_two_points and ": " or "")
|
|
colorpick.hasLabel:SetTemplate(widget_table.text_template or text_template)
|
|
|
|
colorpick:SetPoint ("left", colorpick.hasLabel, "right", 2)
|
|
colorpick.hasLabel:SetPoint (cur_x, cur_y)
|
|
|
|
if (widget_table.id) then
|
|
parent.widgetids [widget_table.id] = colorpick
|
|
end
|
|
|
|
local size = colorpick.hasLabel:GetStringWidth() + 60 + 4
|
|
if (size > max_x) then
|
|
max_x = size
|
|
end
|
|
|
|
--button
|
|
elseif (widget_table.type == "execute" or widget_table.type == "button") then
|
|
|
|
local button = getMenuWidgetVolative(parent, "button", widgetIndexes)
|
|
widget_created = button
|
|
|
|
button:SetTemplate(button_template)
|
|
button:SetSize(widget_table.width or 120, widget_table.height or 18)
|
|
button:SetClickFunction(widget_table.func, widget_table.param1, widget_table.param2)
|
|
|
|
local textTemplate = widget_table.text_template or text_template or DF.font_templates ["ORANGE_FONT_TEMPLATE"]
|
|
button.textcolor = textTemplate.color
|
|
button.textfont = textTemplate.font
|
|
button.textsize = textTemplate.size
|
|
button.text = widget_table.name
|
|
|
|
if (widget_table.inline) then
|
|
if (latestInlineWidget) then
|
|
button:SetPoint ("left", latestInlineWidget, "right", 2, 0)
|
|
latestInlineWidget = button
|
|
else
|
|
button:SetPoint (cur_x, cur_y)
|
|
latestInlineWidget = button
|
|
end
|
|
else
|
|
button:SetPoint (cur_x, cur_y)
|
|
end
|
|
|
|
button.tooltip = widget_table.desc
|
|
button.widget_type = "execute"
|
|
|
|
--> execute doesn't trigger global callback
|
|
|
|
--> hook list
|
|
if (widget_table.hooks) then
|
|
for hookName, hookFunc in pairs (widget_table.hooks) do
|
|
button:SetHook (hookName, hookFunc)
|
|
end
|
|
end
|
|
|
|
if (widget_table.width) then
|
|
button:SetWidth(widget_table.width)
|
|
end
|
|
if (widget_table.height) then
|
|
button:SetHeight(widget_table.height)
|
|
end
|
|
|
|
if (widget_table.id) then
|
|
parent.widgetids [widget_table.id] = button
|
|
end
|
|
|
|
local size = button:GetWidth() + 4
|
|
if (size > max_x) then
|
|
max_x = size
|
|
end
|
|
|
|
--textentry
|
|
elseif (widget_table.type == "textentry") then
|
|
|
|
local textentry = getMenuWidgetVolative(parent, "textentry", widgetIndexes)
|
|
widget_created = textentry
|
|
|
|
textentry:SetCommitFunction(widget_table.func or widget_table.set)
|
|
textentry:SetTemplate(widget_table.template or widget_table.button_template or button_template)
|
|
textentry:SetSize(widget_table.width or 120, widget_table.height or 18)
|
|
|
|
textentry.tooltip = widget_table.desc
|
|
textentry.text = widget_table.get()
|
|
textentry._get = widget_table.get
|
|
textentry.widget_type = "textentry"
|
|
textentry:SetHook ("OnEnterPressed", widget_table.func or widget_table.set)
|
|
textentry:SetHook ("OnEditFocusLost", widget_table.func or widget_table.set)
|
|
|
|
textentry.hasLabel.text = widget_table.name .. (use_two_points and ": " or "")
|
|
textentry.hasLabel:SetTemplate(widget_table.text_template or text_template)
|
|
textentry:SetPoint ("left", textentry.hasLabel, "right", 2)
|
|
textentry.hasLabel:SetPoint (cur_x, cur_y)
|
|
|
|
--> text entry doesn't trigger global callback
|
|
|
|
--> hook list
|
|
if (widget_table.hooks) then
|
|
for hookName, hookFunc in pairs (widget_table.hooks) do
|
|
textentry:SetHook (hookName, hookFunc)
|
|
end
|
|
end
|
|
|
|
if (widget_table.id) then
|
|
parent.widgetids [widget_table.id] = textentry
|
|
end
|
|
|
|
local size = textentry.hasLabel:GetStringWidth() + 60 + 4
|
|
if (size > max_x) then
|
|
max_x = size
|
|
end
|
|
|
|
end --end loop
|
|
|
|
if (widget_table.nocombat) then
|
|
tinsert (disable_on_combat, widget_created)
|
|
end
|
|
|
|
if (not widget_table.inline) then
|
|
if (widget_table.spacement) then
|
|
cur_y = cur_y - 30
|
|
else
|
|
cur_y = cur_y - 20
|
|
end
|
|
end
|
|
|
|
if (widget_table.type == "breakline" or cur_y < height) then
|
|
cur_y = y_offset
|
|
cur_x = cur_x + max_x + 30
|
|
line_widgets_created = 0
|
|
max_x = 0
|
|
end
|
|
|
|
if widget_created then
|
|
widget_created:Show()
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
DF.RefreshUnsafeOptionsWidgets()
|
|
end
|
|
|
|
function DF:BuildMenu (parent, menu, x_offset, y_offset, height, use_two_points, text_template, dropdown_template, switch_template, switch_is_box, slider_template, button_template, value_change_hook)
|
|
|
|
if (not parent.widget_list) then
|
|
DF:SetAsOptionsPanel (parent)
|
|
end
|
|
|
|
local cur_x = x_offset
|
|
local cur_y = y_offset
|
|
local max_x = 0
|
|
local line_widgets_created = 0 --how many widgets has been created on this line loop pass
|
|
|
|
local latestInlineWidget
|
|
|
|
height = abs ((height or parent:GetHeight()) - abs (y_offset) + 20)
|
|
height = height*-1
|
|
|
|
for index, widget_table in ipairs (menu) do
|
|
if (not widget_table.hidden) then
|
|
|
|
local widget_created
|
|
if (latestInlineWidget) then
|
|
if (not widget_table.inline) then
|
|
latestInlineWidget = nil
|
|
cur_y = cur_y - 28
|
|
end
|
|
end
|
|
|
|
if (widget_table.type == "blank" or widget_table.type == "space") then
|
|
-- do nothing
|
|
|
|
elseif (widget_table.type == "label" or widget_table.type == "text") then
|
|
local label = DF:CreateLabel (parent, widget_table.get() or widget_table.text, widget_table.text_template or text_template or widget_table.size, widget_table.color, widget_table.font, nil, "$parentWidget" .. index, "overlay")
|
|
label._get = widget_table.get
|
|
label.widget_type = "label"
|
|
label:SetPoint (cur_x, cur_y)
|
|
|
|
--store the widget created into the overall table and the widget by type
|
|
tinsert (parent.widget_list, label)
|
|
tinsert (parent.widget_list_by_type.label, label)
|
|
|
|
line_widgets_created = line_widgets_created + 1
|
|
|
|
if (widget_table.id) then
|
|
parent.widgetids [widget_table.id] = label
|
|
end
|
|
|
|
elseif (widget_table.type == "select" or widget_table.type == "dropdown") then
|
|
local dropdown = DF:NewDropDown (parent, nil, "$parentWidget" .. index, nil, 140, 18, widget_table.values, widget_table.get(), dropdown_template)
|
|
dropdown.tooltip = widget_table.desc
|
|
dropdown._get = widget_table.get
|
|
dropdown.widget_type = "select"
|
|
|
|
local label = DF:NewLabel (parent, nil, "$parentLabel" .. index, nil, widget_table.name .. (use_two_points and ": " or ""), "GameFontNormal", widget_table.text_template or text_template or 12)
|
|
dropdown:SetPoint ("left", label, "right", 2)
|
|
label:SetPoint (cur_x, cur_y)
|
|
dropdown.hasLabel = label
|
|
|
|
--> global callback
|
|
if (value_change_hook) then
|
|
dropdown:SetHook ("OnOptionSelected", value_change_hook)
|
|
end
|
|
|
|
--> hook list
|
|
if (widget_table.hooks) then
|
|
for hookName, hookFunc in pairs (widget_table.hooks) do
|
|
dropdown:SetHook (hookName, hookFunc)
|
|
end
|
|
end
|
|
|
|
if (widget_table.id) then
|
|
parent.widgetids [widget_table.id] = dropdown
|
|
end
|
|
|
|
local size = label.widget:GetStringWidth() + 140 + 4
|
|
if (size > max_x) then
|
|
max_x = size
|
|
end
|
|
|
|
--store the widget created into the overall table and the widget by type
|
|
tinsert (parent.widget_list, dropdown)
|
|
tinsert (parent.widget_list_by_type.dropdown, dropdown)
|
|
|
|
widget_created = dropdown
|
|
line_widgets_created = line_widgets_created + 1
|
|
|
|
elseif (widget_table.type == "toggle" or widget_table.type == "switch") then
|
|
local switch = DF:NewSwitch (parent, nil, "$parentWidget" .. index, nil, 60, 20, nil, nil, widget_table.get(), nil, nil, nil, nil, switch_template)
|
|
switch.tooltip = widget_table.desc
|
|
switch._get = widget_table.get
|
|
switch.widget_type = "toggle"
|
|
switch.OnSwitch = widget_table.set
|
|
|
|
if (switch_is_box) then
|
|
switch:SetAsCheckBox()
|
|
end
|
|
|
|
if (value_change_hook) then
|
|
switch:SetHook ("OnSwitch", value_change_hook)
|
|
end
|
|
|
|
--> hook list
|
|
if (widget_table.hooks) then
|
|
for hookName, hookFunc in pairs (widget_table.hooks) do
|
|
switch:SetHook (hookName, hookFunc)
|
|
end
|
|
end
|
|
|
|
if (widget_table.width) then
|
|
switch:SetWidth(widget_table.width)
|
|
end
|
|
if (widget_table.height) then
|
|
switch:SetHeight(widget_table.height)
|
|
end
|
|
|
|
local label = DF:NewLabel (parent, nil, "$parentLabel" .. index, nil, widget_table.name .. (use_two_points and ": " or ""), "GameFontNormal", widget_table.text_template or text_template or 12)
|
|
if (widget_table.boxfirst) then
|
|
switch:SetPoint (cur_x, cur_y)
|
|
label:SetPoint ("left", switch, "right", 2)
|
|
else
|
|
label:SetPoint (cur_x, cur_y)
|
|
switch:SetPoint ("left", label, "right", 2)
|
|
end
|
|
switch.hasLabel = label
|
|
|
|
if (widget_table.id) then
|
|
parent.widgetids [widget_table.id] = switch
|
|
end
|
|
|
|
local size = label.widget:GetStringWidth() + 60 + 4
|
|
if (size > max_x) then
|
|
max_x = size
|
|
end
|
|
|
|
--store the widget created into the overall table and the widget by type
|
|
tinsert (parent.widget_list, switch)
|
|
tinsert (parent.widget_list_by_type.switch, switch)
|
|
|
|
widget_created = switch
|
|
line_widgets_created = line_widgets_created + 1
|
|
|
|
elseif (widget_table.type == "range" or widget_table.type == "slider") then
|
|
local is_decimanls = widget_table.usedecimals
|
|
local slider = DF:NewSlider (parent, nil, "$parentWidget" .. index, nil, 140, 20, widget_table.min, widget_table.max, widget_table.step, widget_table.get(), is_decimanls, nil, nil, slider_template)
|
|
slider.tooltip = widget_table.desc
|
|
slider._get = widget_table.get
|
|
slider.widget_type = "range"
|
|
slider:SetHook ("OnValueChange", widget_table.set)
|
|
|
|
if (widget_table.thumbscale) then
|
|
slider:SetThumbSize (slider.thumb:GetWidth()*widget_table.thumbscale, nil)
|
|
else
|
|
slider:SetThumbSize (slider.thumb:GetWidth()*1.3, nil)
|
|
end
|
|
|
|
if (value_change_hook) then
|
|
slider:SetHook ("OnValueChange", value_change_hook)
|
|
end
|
|
|
|
--> hook list
|
|
if (widget_table.hooks) then
|
|
for hookName, hookFunc in pairs (widget_table.hooks) do
|
|
slider:SetHook (hookName, hookFunc)
|
|
end
|
|
end
|
|
|
|
local label = DF:NewLabel (parent, nil, "$parentLabel" .. index, nil, widget_table.name .. (use_two_points and ": " or ""), "GameFontNormal", widget_table.text_template or text_template or 12)
|
|
slider:SetPoint ("left", label, "right", 2)
|
|
label:SetPoint (cur_x, cur_y)
|
|
slider.hasLabel = label
|
|
|
|
if (widget_table.id) then
|
|
parent.widgetids [widget_table.id] = slider
|
|
end
|
|
|
|
local size = label.widget:GetStringWidth() + 140 + 6
|
|
if (size > max_x) then
|
|
max_x = size
|
|
end
|
|
|
|
--store the widget created into the overall table and the widget by type
|
|
tinsert (parent.widget_list, slider)
|
|
tinsert (parent.widget_list_by_type.slider, slider)
|
|
|
|
widget_created = slider
|
|
line_widgets_created = line_widgets_created + 1
|
|
|
|
elseif (widget_table.type == "color" or widget_table.type == "color") then
|
|
local colorpick = DF:NewColorPickButton (parent, "$parentWidget" .. index, nil, widget_table.set, nil, button_template)
|
|
colorpick.tooltip = widget_table.desc
|
|
colorpick._get = widget_table.get
|
|
colorpick.widget_type = "color"
|
|
|
|
local default_value, g, b, a = widget_table.get()
|
|
if (type (default_value) == "table") then
|
|
colorpick:SetColor (unpack (default_value))
|
|
else
|
|
colorpick:SetColor (default_value, g, b, a)
|
|
end
|
|
|
|
if (value_change_hook) then
|
|
colorpick:SetHook ("OnColorChanged", value_change_hook)
|
|
end
|
|
|
|
--> hook list
|
|
if (widget_table.hooks) then
|
|
for hookName, hookFunc in pairs (widget_table.hooks) do
|
|
colorpick:SetHook (hookName, hookFunc)
|
|
end
|
|
end
|
|
|
|
local label = DF:NewLabel (parent, nil, "$parentLabel" .. index, nil, widget_table.name .. (use_two_points and ": " or ""), "GameFontNormal", widget_table.text_template or text_template or 12)
|
|
colorpick:SetPoint ("left", label, "right", 2)
|
|
label:SetPoint (cur_x, cur_y)
|
|
colorpick.hasLabel = label
|
|
|
|
if (widget_table.id) then
|
|
parent.widgetids [widget_table.id] = colorpick
|
|
end
|
|
|
|
local size = label.widget:GetStringWidth() + 60 + 4
|
|
if (size > max_x) then
|
|
max_x = size
|
|
end
|
|
|
|
--store the widget created into the overall table and the widget by type
|
|
tinsert (parent.widget_list, colorpick)
|
|
tinsert (parent.widget_list_by_type.color, colorpick)
|
|
|
|
widget_created = colorpick
|
|
line_widgets_created = line_widgets_created + 1
|
|
|
|
elseif (widget_table.type == "execute" or widget_table.type == "button") then
|
|
|
|
local button = DF:NewButton (parent, nil, "$parentWidget" .. index, nil, 120, 18, widget_table.func, widget_table.param1, widget_table.param2, nil, widget_table.name, nil, button_template, text_template)
|
|
if (not button_template) then
|
|
button:InstallCustomTexture()
|
|
end
|
|
|
|
if (widget_table.inline) then
|
|
if (latestInlineWidget) then
|
|
button:SetPoint ("left", latestInlineWidget, "right", 2, 0)
|
|
latestInlineWidget = button
|
|
else
|
|
button:SetPoint (cur_x, cur_y)
|
|
latestInlineWidget = button
|
|
end
|
|
else
|
|
button:SetPoint (cur_x, cur_y)
|
|
end
|
|
|
|
button.tooltip = widget_table.desc
|
|
button.widget_type = "execute"
|
|
|
|
--notice: execute doesn't trigger global callback
|
|
|
|
--button icon
|
|
if (widget_table.icontexture) then
|
|
button:SetIcon(widget_table.icontexture, nil, nil, nil, widget_table.icontexcoords, nil, nil, 2)
|
|
end
|
|
|
|
--hook list
|
|
if (widget_table.hooks) then
|
|
for hookName, hookFunc in pairs (widget_table.hooks) do
|
|
button:SetHook (hookName, hookFunc)
|
|
end
|
|
end
|
|
|
|
if (widget_table.id) then
|
|
parent.widgetids [widget_table.id] = button
|
|
end
|
|
|
|
if (widget_table.width) then
|
|
button:SetWidth(widget_table.width)
|
|
end
|
|
if (widget_table.height) then
|
|
button:SetHeight(widget_table.height)
|
|
end
|
|
|
|
local size = button:GetWidth() + 4
|
|
if (size > max_x) then
|
|
max_x = size
|
|
end
|
|
|
|
--store the widget created into the overall table and the widget by type
|
|
tinsert (parent.widget_list, button)
|
|
tinsert (parent.widget_list_by_type.button, button)
|
|
|
|
widget_created = button
|
|
line_widgets_created = line_widgets_created + 1
|
|
|
|
elseif (widget_table.type == "textentry") then
|
|
local textentry = DF:CreateTextEntry (parent, widget_table.func or widget_table.set, 120, 18, nil, "$parentWidget" .. index, nil, button_template)
|
|
textentry.tooltip = widget_table.desc
|
|
textentry.text = widget_table.get()
|
|
textentry._get = widget_table.get
|
|
textentry.widget_type = "textentry"
|
|
textentry:SetHook ("OnEnterPressed", widget_table.func or widget_table.set)
|
|
textentry:SetHook ("OnEditFocusLost", widget_table.func or widget_table.set)
|
|
|
|
local label = DF:NewLabel (parent, nil, "$parentLabel" .. index, nil, widget_table.name .. (use_two_points and ": " or ""), "GameFontNormal", widget_table.text_template or text_template or 12)
|
|
textentry:SetPoint ("left", label, "right", 2)
|
|
label:SetPoint (cur_x, cur_y)
|
|
textentry.hasLabel = label
|
|
|
|
--> text entry doesn't trigger global callback
|
|
|
|
--> hook list
|
|
if (widget_table.hooks) then
|
|
for hookName, hookFunc in pairs (widget_table.hooks) do
|
|
textentry:SetHook (hookName, hookFunc)
|
|
end
|
|
end
|
|
|
|
if (widget_table.id) then
|
|
parent.widgetids [widget_table.id] = textentry
|
|
end
|
|
|
|
local size = label.widget:GetStringWidth() + 60 + 4
|
|
if (size > max_x) then
|
|
max_x = size
|
|
end
|
|
|
|
--store the widget created into the overall table and the widget by type
|
|
tinsert (parent.widget_list, textentry)
|
|
tinsert (parent.widget_list_by_type.textentry, textentry)
|
|
|
|
widget_created = textentry
|
|
line_widgets_created = line_widgets_created + 1
|
|
|
|
end
|
|
|
|
if (widget_table.nocombat) then
|
|
tinsert (disable_on_combat, widget_created)
|
|
end
|
|
|
|
if (not widget_table.inline) then
|
|
if (widget_table.spacement) then
|
|
cur_y = cur_y - 30
|
|
else
|
|
cur_y = cur_y - 20
|
|
end
|
|
end
|
|
|
|
if (widget_table.type == "breakline" or cur_y < height) then
|
|
cur_y = y_offset
|
|
cur_x = cur_x + max_x + 30
|
|
line_widgets_created = 0
|
|
max_x = 0
|
|
end
|
|
end
|
|
end
|
|
|
|
DF.RefreshUnsafeOptionsWidgets()
|
|
|
|
end
|
|
|
|
local lock_notsafe_widgets = function()
|
|
for _, widget in ipairs (disable_on_combat) do
|
|
widget:Disable()
|
|
end
|
|
end
|
|
local unlock_notsafe_widgets = function()
|
|
for _, widget in ipairs (disable_on_combat) do
|
|
widget:Enable()
|
|
end
|
|
end
|
|
function DF.RefreshUnsafeOptionsWidgets()
|
|
if (DF.PlayerHasCombatFlag) then
|
|
lock_notsafe_widgets()
|
|
else
|
|
unlock_notsafe_widgets()
|
|
end
|
|
end
|
|
DF.PlayerHasCombatFlag = false
|
|
local ProtectCombatFrame = CreateFrame ("frame")
|
|
ProtectCombatFrame:RegisterEvent ("PLAYER_REGEN_ENABLED")
|
|
ProtectCombatFrame:RegisterEvent ("PLAYER_REGEN_DISABLED")
|
|
ProtectCombatFrame:RegisterEvent ("PLAYER_ENTERING_WORLD")
|
|
ProtectCombatFrame:SetScript ("OnEvent", function (self, event)
|
|
if (event == "PLAYER_ENTERING_WORLD") then
|
|
if (InCombatLockdown()) then
|
|
DF.PlayerHasCombatFlag = true
|
|
else
|
|
DF.PlayerHasCombatFlag = false
|
|
end
|
|
DF.RefreshUnsafeOptionsWidgets()
|
|
|
|
elseif (event == "PLAYER_REGEN_ENABLED") then
|
|
DF.PlayerHasCombatFlag = false
|
|
DF.RefreshUnsafeOptionsWidgets()
|
|
|
|
elseif (event == "PLAYER_REGEN_DISABLED") then
|
|
DF.PlayerHasCombatFlag = true
|
|
DF.RefreshUnsafeOptionsWidgets()
|
|
|
|
end
|
|
end)
|
|
|
|
function DF:CreateInCombatTexture (frame)
|
|
if (DF.debug and not frame) then
|
|
error ("Details! Framework: CreateInCombatTexture invalid frame on parameter 1.")
|
|
end
|
|
|
|
local in_combat_background = DF:CreateImage (frame)
|
|
in_combat_background:SetColorTexture (.6, 0, 0, .1)
|
|
in_combat_background:Hide()
|
|
|
|
local in_combat_label = Plater:CreateLabel (frame, "you are in combat", 24, "silver")
|
|
in_combat_label:SetPoint ("right", in_combat_background, "right", -10, 0)
|
|
in_combat_label:Hide()
|
|
|
|
frame:RegisterEvent ("PLAYER_REGEN_DISABLED")
|
|
frame:RegisterEvent ("PLAYER_REGEN_ENABLED")
|
|
frame:SetScript ("OnEvent", function (self, event)
|
|
if (event == "PLAYER_REGEN_DISABLED") then
|
|
in_combat_background:Show()
|
|
in_combat_label:Show()
|
|
elseif (event == "PLAYER_REGEN_ENABLED") then
|
|
in_combat_background:Hide()
|
|
in_combat_label:Hide()
|
|
end
|
|
end)
|
|
|
|
return in_combat_background
|
|
end
|
|
|
|
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
--> tutorials
|
|
|
|
function DF:ShowTutorialAlertFrame (maintext, desctext, clickfunc)
|
|
|
|
local TutorialAlertFrame = _G.DetailsFrameworkAlertFrame
|
|
|
|
if (not TutorialAlertFrame) then
|
|
|
|
TutorialAlertFrame = CreateFrame ("frame", "DetailsFrameworkAlertFrame", UIParent, "MicroButtonAlertTemplate")
|
|
TutorialAlertFrame.isFirst = true
|
|
TutorialAlertFrame:SetPoint ("left", UIParent, "left", -20, 100)
|
|
TutorialAlertFrame:SetFrameStrata ("TOOLTIP")
|
|
TutorialAlertFrame:Hide()
|
|
|
|
TutorialAlertFrame:SetScript ("OnMouseUp", function (self)
|
|
if (self.clickfunc and type (self.clickfunc) == "function") then
|
|
self.clickfunc()
|
|
end
|
|
self:Hide()
|
|
end)
|
|
TutorialAlertFrame:Hide()
|
|
end
|
|
|
|
--
|
|
TutorialAlertFrame.label = type (maintext) == "string" and maintext or type (desctext) == "string" and desctext or ""
|
|
MicroButtonAlert_SetText (TutorialAlertFrame, alert.label)
|
|
--
|
|
|
|
TutorialAlertFrame.clickfunc = clickfunc
|
|
TutorialAlertFrame:Show()
|
|
end
|
|
|
|
local refresh_options = function (self)
|
|
for _, widget in ipairs (self.widget_list) do
|
|
if (widget._get) then
|
|
if (widget.widget_type == "label") then
|
|
if (widget._get()) then
|
|
widget:SetText (widget._get())
|
|
end
|
|
elseif (widget.widget_type == "select") then
|
|
widget:Select (widget._get())
|
|
elseif (widget.widget_type == "toggle" or widget.widget_type == "range") then
|
|
widget:SetValue (widget._get())
|
|
elseif (widget.widget_type == "textentry") then
|
|
widget:SetText (widget._get())
|
|
elseif (widget.widget_type == "color") then
|
|
local default_value, g, b, a = widget._get()
|
|
if (type (default_value) == "table") then
|
|
widget:SetColor (unpack (default_value))
|
|
else
|
|
widget:SetColor (default_value, g, b, a)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
local get_frame_by_id = function (self, id)
|
|
return self.widgetids [id]
|
|
end
|
|
|
|
function DF:ClearOptionsPanel(frame)
|
|
for i = 1, #frame.widget_list do
|
|
frame.widget_list[i]:Hide()
|
|
if (frame.widget_list[i].hasLabel) then
|
|
frame.widget_list[i].hasLabel:SetText("")
|
|
end
|
|
end
|
|
|
|
table.wipe(frame.widgetids)
|
|
end
|
|
|
|
function DF:SetAsOptionsPanel (frame)
|
|
frame.RefreshOptions = refresh_options
|
|
frame.widget_list = {}
|
|
frame.widget_list_by_type = {
|
|
["dropdown"] = {}, -- "select"
|
|
["switch"] = {}, -- "toggle"
|
|
["slider"] = {}, -- "range"
|
|
["color"] = {}, --
|
|
["button"] = {}, -- "execute"
|
|
["textentry"] = {}, --
|
|
["label"] = {}, --"text"
|
|
}
|
|
frame.widgetids = {}
|
|
frame.GetWidgetById = get_frame_by_id
|
|
end
|
|
|
|
function DF:CreateOptionsFrame (name, title, template)
|
|
|
|
template = template or 1
|
|
|
|
if (template == 2) then
|
|
local options_frame = CreateFrame ("frame", name, UIParent, "ButtonFrameTemplate")
|
|
tinsert (UISpecialFrames, name)
|
|
options_frame:SetSize (500, 200)
|
|
options_frame.RefreshOptions = refresh_options
|
|
options_frame.widget_list = {}
|
|
|
|
options_frame:SetScript ("OnMouseDown", function(self, button)
|
|
if (button == "RightButton") then
|
|
if (self.moving) then
|
|
self.moving = false
|
|
self:StopMovingOrSizing()
|
|
end
|
|
return options_frame:Hide()
|
|
elseif (button == "LeftButton" and not self.moving) then
|
|
self.moving = true
|
|
self:StartMoving()
|
|
end
|
|
end)
|
|
options_frame:SetScript ("OnMouseUp", function(self)
|
|
if (self.moving) then
|
|
self.moving = false
|
|
self:StopMovingOrSizing()
|
|
end
|
|
end)
|
|
|
|
options_frame:SetMovable (true)
|
|
options_frame:EnableMouse (true)
|
|
options_frame:SetFrameStrata ("DIALOG")
|
|
options_frame:SetToplevel (true)
|
|
|
|
options_frame:Hide()
|
|
|
|
options_frame:SetPoint ("center", UIParent, "center")
|
|
options_frame.TitleText:SetText (title)
|
|
options_frame.portrait:SetTexture ([[Interface\CHARACTERFRAME\TEMPORARYPORTRAIT-FEMALE-BLOODELF]])
|
|
|
|
return options_frame
|
|
|
|
elseif (template == 1) then
|
|
|
|
local options_frame = CreateFrame ("frame", name, UIParent)
|
|
tinsert (UISpecialFrames, name)
|
|
options_frame:SetSize (500, 200)
|
|
options_frame.RefreshOptions = refresh_options
|
|
options_frame.widget_list = {}
|
|
|
|
options_frame:SetScript ("OnMouseDown", function(self, button)
|
|
if (button == "RightButton") then
|
|
if (self.moving) then
|
|
self.moving = false
|
|
self:StopMovingOrSizing()
|
|
end
|
|
return options_frame:Hide()
|
|
elseif (button == "LeftButton" and not self.moving) then
|
|
self.moving = true
|
|
self:StartMoving()
|
|
end
|
|
end)
|
|
options_frame:SetScript ("OnMouseUp", function(self)
|
|
if (self.moving) then
|
|
self.moving = false
|
|
self:StopMovingOrSizing()
|
|
end
|
|
end)
|
|
|
|
options_frame:SetMovable (true)
|
|
options_frame:EnableMouse (true)
|
|
options_frame:SetFrameStrata ("DIALOG")
|
|
options_frame:SetToplevel (true)
|
|
|
|
options_frame:Hide()
|
|
|
|
options_frame:SetPoint ("center", UIParent, "center")
|
|
|
|
options_frame:SetBackdrop ({bgFile = "Interface\\Tooltips\\UI-Tooltip-Background", tile = true, tileSize = 16,
|
|
edgeFile = [[Interface\Buttons\WHITE8X8]], edgeSize = 1,
|
|
insets = {left = 1, right = 1, top = 1, bottom = 1}})
|
|
options_frame:SetBackdropColor (0, 0, 0, .7)
|
|
|
|
local texturetitle = options_frame:CreateTexture (nil, "artwork")
|
|
texturetitle:SetTexture ([[Interface\CURSOR\Interact]])
|
|
texturetitle:SetTexCoord (0, 1, 0, 1)
|
|
texturetitle:SetVertexColor (1, 1, 1, 1)
|
|
texturetitle:SetPoint ("topleft", options_frame, "topleft", 2, -3)
|
|
texturetitle:SetWidth (36)
|
|
texturetitle:SetHeight (36)
|
|
|
|
local title = DF:NewLabel (options_frame, nil, "$parentTitle", nil, title, nil, 20, "yellow")
|
|
title:SetPoint ("left", texturetitle, "right", 2, -1)
|
|
DF:SetFontOutline (title, true)
|
|
|
|
local c = CreateFrame ("Button", nil, options_frame, "UIPanelCloseButton")
|
|
c:SetWidth (32)
|
|
c:SetHeight (32)
|
|
c:SetPoint ("TOPRIGHT", options_frame, "TOPRIGHT", -3, -3)
|
|
c:SetFrameLevel (options_frame:GetFrameLevel()+1)
|
|
|
|
return options_frame
|
|
end
|
|
end
|
|
|
|
------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
--> ~templates
|
|
|
|
--fonts
|
|
|
|
DF.font_templates = DF.font_templates or {}
|
|
|
|
--> detect which language is the client and select the font accordingly
|
|
local clientLanguage = GetLocale()
|
|
if (clientLanguage == "enGB") then
|
|
clientLanguage = "enUS"
|
|
end
|
|
|
|
DF.ClientLanguage = clientLanguage
|
|
|
|
--> returns which region the language the client is running, return "western", "russia" or "asia"
|
|
function DF:GetClientRegion()
|
|
if (clientLanguage == "zhCN" or clientLanguage == "koKR" or clientLanguage == "zhTW") then
|
|
return "asia"
|
|
elseif (clientLanguage == "ruRU") then
|
|
return "russia"
|
|
else
|
|
return "western"
|
|
end
|
|
end
|
|
|
|
--> return the best font to use for the client language
|
|
function DF:GetBestFontForLanguage (language, western, cyrillic, china, korean, taiwan)
|
|
if (not language) then
|
|
language = DF.ClientLanguage
|
|
end
|
|
|
|
if (language == "enUS" or language == "deDE" or language == "esES" or language == "esMX" or language == "frFR" or language == "itIT" or language == "ptBR") then
|
|
return western or "Accidental Presidency"
|
|
|
|
elseif (language == "ruRU") then
|
|
return cyrillic or "Arial Narrow"
|
|
|
|
elseif (language == "zhCN") then
|
|
return china or "AR CrystalzcuheiGBK Demibold"
|
|
|
|
elseif (language == "koKR") then
|
|
return korean or "2002"
|
|
|
|
elseif (language == "zhTW") then
|
|
return taiwan or "AR CrystalzcuheiGBK Demibold"
|
|
|
|
end
|
|
end
|
|
|
|
--DF.font_templates ["ORANGE_FONT_TEMPLATE"] = {color = "orange", size = 11, font = "Accidental Presidency"}
|
|
--DF.font_templates ["OPTIONS_FONT_TEMPLATE"] = {color = "yellow", size = 12, font = "Accidental Presidency"}
|
|
DF.font_templates ["ORANGE_FONT_TEMPLATE"] = {color = "orange", size = 11, font = DF:GetBestFontForLanguage()}
|
|
DF.font_templates ["OPTIONS_FONT_TEMPLATE"] = {color = "yellow", size = 12, font = DF:GetBestFontForLanguage()}
|
|
|
|
-- dropdowns
|
|
|
|
DF.dropdown_templates = DF.dropdown_templates or {}
|
|
DF.dropdown_templates ["OPTIONS_DROPDOWN_TEMPLATE"] = {
|
|
backdrop = {
|
|
edgeFile = [[Interface\Buttons\WHITE8X8]],
|
|
edgeSize = 1,
|
|
bgFile = [[Interface\Tooltips\UI-Tooltip-Background]],
|
|
tileSize = 64,
|
|
tile = true
|
|
},
|
|
|
|
backdropcolor = {1, 1, 1, .7},
|
|
backdropbordercolor = {0, 0, 0, 1},
|
|
onentercolor = {1, 1, 1, .9},
|
|
onenterbordercolor = {1, 1, 1, 1},
|
|
|
|
dropicon = "Interface\\BUTTONS\\arrow-Down-Down",
|
|
dropiconsize = {16, 16},
|
|
dropiconpoints = {-2, -3},
|
|
}
|
|
|
|
-- switches
|
|
|
|
DF.switch_templates = DF.switch_templates or {}
|
|
DF.switch_templates ["OPTIONS_CHECKBOX_TEMPLATE"] = {
|
|
backdrop = {edgeFile = [[Interface\Buttons\WHITE8X8]], edgeSize = 1, bgFile = [[Interface\Tooltips\UI-Tooltip-Background]], tileSize = 64, tile = true},
|
|
backdropcolor = {1, 1, 1, .5},
|
|
backdropbordercolor = {0, 0, 0, 1},
|
|
width = 18,
|
|
height = 18,
|
|
enabled_backdropcolor = {1, 1, 1, .5},
|
|
disabled_backdropcolor = {1, 1, 1, .2},
|
|
onenterbordercolor = {1, 1, 1, 1},
|
|
}
|
|
DF.switch_templates ["OPTIONS_CHECKBOX_BRIGHT_TEMPLATE"] = {
|
|
backdrop = {edgeFile = [[Interface\Buttons\WHITE8X8]], edgeSize = 1, bgFile = [[Interface\Tooltips\UI-Tooltip-Background]], tileSize = 64, tile = true},
|
|
backdropcolor = {1, 1, 1, .5},
|
|
backdropbordercolor = {0, 0, 0, 1},
|
|
width = 18,
|
|
height = 18,
|
|
enabled_backdropcolor = {1, 1, 1, .5},
|
|
disabled_backdropcolor = {1, 1, 1, .5},
|
|
onenterbordercolor = {1, 1, 1, 1},
|
|
}
|
|
|
|
-- buttons
|
|
|
|
DF.button_templates = DF.button_templates or {}
|
|
DF.button_templates ["OPTIONS_BUTTON_TEMPLATE"] = {
|
|
backdrop = {edgeFile = [[Interface\Buttons\WHITE8X8]], edgeSize = 1, bgFile = [[Interface\Tooltips\UI-Tooltip-Background]], tileSize = 64, tile = true},
|
|
backdropcolor = {1, 1, 1, .5},
|
|
backdropbordercolor = {0, 0, 0, 1},
|
|
}
|
|
|
|
-- sliders
|
|
|
|
DF.slider_templates = DF.slider_templates or {}
|
|
DF.slider_templates ["OPTIONS_SLIDER_TEMPLATE"] = {
|
|
backdrop = {edgeFile = [[Interface\Buttons\WHITE8X8]], edgeSize = 1, bgFile = [[Interface\Tooltips\UI-Tooltip-Background]], tileSize = 64, tile = true},
|
|
backdropcolor = {1, 1, 1, .5},
|
|
backdropbordercolor = {0, 0, 0, 1},
|
|
onentercolor = {1, 1, 1, .5},
|
|
onenterbordercolor = {1, 1, 1, 1},
|
|
thumbtexture = [[Interface\Tooltips\UI-Tooltip-Background]],
|
|
thumbwidth = 16,
|
|
thumbheight = 14,
|
|
thumbcolor = {0, 0, 0, 0.5},
|
|
}
|
|
|
|
function DF:InstallTemplate (widget_type, template_name, template, parent_name)
|
|
|
|
local newTemplate = {}
|
|
|
|
--if has a parent, just copy the parent to the new template
|
|
if (parent_name and type (parent_name) == "string") then
|
|
local parentTemplate = DF:GetTemplate (widget_type, parent_name)
|
|
if (parentTemplate) then
|
|
DF.table.copy (newTemplate, parentTemplate)
|
|
end
|
|
end
|
|
|
|
--copy the template passed into the new template
|
|
DF.table.copy (newTemplate, template)
|
|
|
|
widget_type = string.lower (widget_type)
|
|
|
|
local template_table
|
|
if (widget_type == "font") then
|
|
template_table = DF.font_templates
|
|
|
|
local font = template.font
|
|
if (font) then
|
|
--> fonts passed into the template has default to western
|
|
--> the framework will get the game client language and change the font if needed
|
|
font = DF:GetBestFontForLanguage (nil, font)
|
|
end
|
|
|
|
elseif (widget_type == "dropdown") then
|
|
template_table = DF.dropdown_templates
|
|
elseif (widget_type == "button") then
|
|
template_table = DF.button_templates
|
|
elseif (widget_type == "switch") then
|
|
template_table = DF.switch_templates
|
|
elseif (widget_type == "slider") then
|
|
template_table = DF.slider_templates
|
|
end
|
|
|
|
template_table [template_name] = newTemplate
|
|
|
|
return newTemplate
|
|
end
|
|
|
|
function DF:GetTemplate (widget_type, template_name)
|
|
widget_type = string.lower (widget_type)
|
|
|
|
local template_table
|
|
if (widget_type == "font") then
|
|
template_table = DF.font_templates
|
|
elseif (widget_type == "dropdown") then
|
|
template_table = DF.dropdown_templates
|
|
elseif (widget_type == "button") then
|
|
template_table = DF.button_templates
|
|
elseif (widget_type == "switch") then
|
|
template_table = DF.switch_templates
|
|
elseif (widget_type == "slider") then
|
|
template_table = DF.slider_templates
|
|
end
|
|
return template_table [template_name]
|
|
end
|
|
|
|
function DF.GetParentName (frame)
|
|
local parentName = frame:GetName()
|
|
if (not parentName) then
|
|
error ("Details! FrameWork: called $parent but parent was no name.", 2)
|
|
end
|
|
return parentName
|
|
end
|
|
|
|
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
--> widget scripts and hooks
|
|
|
|
function DF:RunHooksForWidget (event, ...)
|
|
local hooks = self.HookList [event]
|
|
|
|
if (not hooks) then
|
|
print (self.widget:GetName(), "no hooks for", event)
|
|
return
|
|
end
|
|
|
|
for i, func in ipairs (hooks) do
|
|
local success, canInterrupt = pcall (func, ...)
|
|
if (not success) then
|
|
error ("Details! Framework: " .. event .. " hook for " .. self:GetName() .. ": " .. canInterrupt)
|
|
elseif (canInterrupt) then
|
|
return true
|
|
end
|
|
end
|
|
end
|
|
|
|
function DF:SetHook (hookType, func)
|
|
if (self.HookList [hookType]) then
|
|
if (type (func) == "function") then
|
|
local isRemoval = false
|
|
for i = #self.HookList [hookType], 1, -1 do
|
|
if (self.HookList [hookType] [i] == func) then
|
|
tremove (self.HookList [hookType], i)
|
|
isRemoval = true
|
|
break
|
|
end
|
|
end
|
|
if (not isRemoval) then
|
|
tinsert (self.HookList [hookType], func)
|
|
end
|
|
else
|
|
if (DF.debug) then
|
|
print (debugstack())
|
|
error ("Details! Framework: invalid function for widget " .. self.WidgetType .. ".")
|
|
end
|
|
end
|
|
else
|
|
if (DF.debug) then
|
|
error ("Details! Framework: unknown hook type for widget " .. self.WidgetType .. ": '" .. hookType .. "'.")
|
|
end
|
|
end
|
|
end
|
|
|
|
function DF:HasHook (hookType, func)
|
|
if (self.HookList [hookType]) then
|
|
if (type (func) == "function") then
|
|
for i = #self.HookList [hookType], 1, -1 do
|
|
if (self.HookList [hookType] [i] == func) then
|
|
return true
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function DF:ClearHooks()
|
|
for hookType, hookTable in pairs(self.HookList) do
|
|
table.wipe(hookTable)
|
|
end
|
|
end
|
|
|
|
function DF:Error (errortext)
|
|
print ("|cFFFF2222Details! Framework Error|r:", errortext, self.GetName and self:GetName(), self.WidgetType, debugstack (2, 3, 0))
|
|
end
|
|
|
|
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
--> members
|
|
|
|
DF.GlobalWidgetControlNames = {
|
|
textentry = "DF_TextEntryMetaFunctions",
|
|
button = "DF_ButtonMetaFunctions",
|
|
panel = "DF_PanelMetaFunctions",
|
|
dropdown = "DF_DropdownMetaFunctions",
|
|
label = "DF_LabelMetaFunctions",
|
|
normal_bar = "DF_NormalBarMetaFunctions",
|
|
image = "DF_ImageMetaFunctions",
|
|
slider = "DF_SliderMetaFunctions",
|
|
split_bar = "DF_SplitBarMetaFunctions",
|
|
aura_tracker = "DF_AuraTracker",
|
|
healthBar = "DF_healthBarMetaFunctions",
|
|
timebar = "DF_TimeBarMetaFunctions",
|
|
}
|
|
|
|
function DF:AddMemberForWidget (widgetName, memberType, memberName, func)
|
|
if (DF.GlobalWidgetControlNames [widgetName]) then
|
|
if (type (memberName) == "string" and (memberType == "SET" or memberType == "GET")) then
|
|
if (func) then
|
|
local widgetControlObject = _G [DF.GlobalWidgetControlNames [widgetName]]
|
|
|
|
if (memberType == "SET") then
|
|
widgetControlObject ["SetMembers"] [memberName] = func
|
|
elseif (memberType == "GET") then
|
|
widgetControlObject ["GetMembers"] [memberName] = func
|
|
end
|
|
else
|
|
if (DF.debug) then
|
|
error ("Details! Framework: AddMemberForWidget invalid function.")
|
|
end
|
|
end
|
|
else
|
|
if (DF.debug) then
|
|
error ("Details! Framework: AddMemberForWidget unknown memberName or memberType.")
|
|
end
|
|
end
|
|
else
|
|
if (DF.debug) then
|
|
error ("Details! Framework: AddMemberForWidget unknown widget type: " .. (widgetName or "") .. ".")
|
|
end
|
|
end
|
|
end
|
|
|
|
-----------------------------
|
|
|
|
function DF:OpenInterfaceProfile()
|
|
-- OptionsFrame1/2 should be registered if created with DF:CreateAddOn, so open to them directly
|
|
if self.OptionsFrame1 then
|
|
InterfaceOptionsFrame_OpenToCategory (self.OptionsFrame1)
|
|
if self.OptionsFrame2 then
|
|
InterfaceOptionsFrame_OpenToCategory (self.OptionsFrame2)
|
|
end
|
|
return
|
|
end
|
|
|
|
-- fallback (broken as of ElvUI Skins in version 12.18+... maybe fix/change will come)
|
|
InterfaceOptionsFrame_OpenToCategory (self.__name)
|
|
InterfaceOptionsFrame_OpenToCategory (self.__name)
|
|
for i = 1, 100 do
|
|
local button = _G ["InterfaceOptionsFrameAddOnsButton" .. i]
|
|
if (button) then
|
|
local text = _G ["InterfaceOptionsFrameAddOnsButton" .. i .. "Text"]
|
|
if (text) then
|
|
text = text:GetText()
|
|
if (text == self.__name) then
|
|
local toggle = _G ["InterfaceOptionsFrameAddOnsButton" .. i .. "Toggle"]
|
|
if (toggle) then
|
|
if (toggle:GetNormalTexture():GetTexture():find ("PlusButton")) then
|
|
--is minimized, need expand
|
|
toggle:Click()
|
|
_G ["InterfaceOptionsFrameAddOnsButton" .. i+1]:Click()
|
|
elseif (toggle:GetNormalTexture():GetTexture():find ("MinusButton")) then
|
|
--isn't minimized
|
|
_G ["InterfaceOptionsFrameAddOnsButton" .. i+1]:Click()
|
|
end
|
|
end
|
|
break
|
|
end
|
|
end
|
|
else
|
|
self:Msg ("Couldn't not find the profile panel.")
|
|
break
|
|
end
|
|
end
|
|
end
|
|
|
|
-----------------------------
|
|
--safe copy from blizz api
|
|
function DF:Mixin (object, ...)
|
|
for i = 1, select("#", ...) do
|
|
local mixin = select(i, ...);
|
|
for k, v in pairs(mixin) do
|
|
object[k] = v;
|
|
end
|
|
end
|
|
|
|
return object;
|
|
end
|
|
|
|
-----------------------------
|
|
--> animations
|
|
|
|
function DF:CreateAnimationHub (parent, onPlay, onFinished)
|
|
local newAnimation = parent:CreateAnimationGroup()
|
|
newAnimation:SetScript ("OnPlay", onPlay)
|
|
newAnimation:SetScript ("OnFinished", onFinished)
|
|
newAnimation:SetScript ("OnStop", onFinished)
|
|
newAnimation.NextAnimation = 1
|
|
return newAnimation
|
|
end
|
|
|
|
function DF:CreateAnimation (animation, type, order, duration, arg1, arg2, arg3, arg4, arg5, arg6, arg7)
|
|
local anim = animation:CreateAnimation (type)
|
|
|
|
anim:SetOrder (order or animation.NextAnimation)
|
|
anim:SetDuration (duration)
|
|
|
|
type = string.upper (type)
|
|
|
|
if (type == "ALPHA") then
|
|
anim:SetFromAlpha (arg1)
|
|
anim:SetToAlpha (arg2)
|
|
|
|
elseif (type == "SCALE") then
|
|
anim:SetFromScale (arg1, arg2)
|
|
anim:SetToScale (arg3, arg4)
|
|
anim:SetOrigin (arg5 or "center", arg6 or 0, arg7 or 0) --point, x, y
|
|
|
|
elseif (type == "ROTATION") then
|
|
anim:SetDegrees (arg1) --degree
|
|
anim:SetOrigin (arg2 or "center", arg3 or 0, arg4 or 0) --point, x, y
|
|
|
|
elseif (type == "TRANSLATION") then
|
|
anim:SetOffset (arg1, arg2)
|
|
|
|
end
|
|
|
|
animation.NextAnimation = animation.NextAnimation + 1
|
|
return anim
|
|
end
|
|
|
|
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
--> frame shakes
|
|
|
|
--> frame shakes rely on OnUpdate scripts, we are using a built-in OnUpdate so is guarantee it'll run
|
|
local FrameshakeUpdateFrame = DetailsFrameworkFrameshakeControl or CreateFrame ("frame", "DetailsFrameworkFrameshakeControl", UIParent)
|
|
--> store the frame which has frame shakes registered
|
|
FrameshakeUpdateFrame.RegisteredFrames = FrameshakeUpdateFrame.RegisteredFrames or {}
|
|
|
|
FrameshakeUpdateFrame.RegisterFrame = function (newFrame)
|
|
--> add the frame into the registered frames to update
|
|
DF.table.addunique (FrameshakeUpdateFrame.RegisteredFrames, newFrame)
|
|
end
|
|
|
|
--forward declared
|
|
local frameshake_do_update
|
|
|
|
FrameshakeUpdateFrame:SetScript ("OnUpdate", function (self, deltaTime)
|
|
for i = 1, #FrameshakeUpdateFrame.RegisteredFrames do
|
|
local parent = FrameshakeUpdateFrame.RegisteredFrames [i]
|
|
--> check if there's a shake running
|
|
if (parent.__frameshakes.enabled > 0) then
|
|
--update all shakes for this frame
|
|
for i = 1, #parent.__frameshakes do
|
|
local shakeObject = parent.__frameshakes [i]
|
|
if (shakeObject.IsPlaying) then
|
|
frameshake_do_update (parent, shakeObject, deltaTime)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end)
|
|
|
|
|
|
local frameshake_shake_finished = function (parent, shakeObject)
|
|
if (shakeObject.IsPlaying) then
|
|
shakeObject.IsPlaying = false
|
|
shakeObject.TimeLeft = 0
|
|
shakeObject.IsFadingOut = false
|
|
shakeObject.IsFadingIn = false
|
|
|
|
--> update the amount of shake running on this frame
|
|
parent.__frameshakes.enabled = parent.__frameshakes.enabled - 1
|
|
|
|
--> restore the default anchors, in case where deltaTime was too small that didn't triggered an update
|
|
for i = 1, #shakeObject.Anchors do
|
|
local anchor = shakeObject.Anchors [i]
|
|
|
|
--> automatic anchoring and reanching needs to the reviwed in the future
|
|
if (#anchor == 1) then
|
|
local anchorTo = unpack (anchor)
|
|
parent:ClearAllPoints()
|
|
parent:SetPoint (anchorTo)
|
|
|
|
elseif (#anchor == 2) then
|
|
local anchorTo, point1 = unpack (anchor)
|
|
parent:ClearAllPoints()
|
|
parent:SetPoint (anchorTo, point1)
|
|
|
|
elseif (#anchor == 3) then
|
|
local anchorTo, point1, point2 = unpack (anchor)
|
|
parent:SetPoint (anchorTo, point1, point2)
|
|
|
|
elseif (#anchor == 5) then
|
|
local anchorName1, anchorTo, anchorName2, point1, point2 = unpack (anchor)
|
|
parent:SetPoint (anchorName1, anchorTo, anchorName2, point1, point2)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
--already declared above the update function
|
|
frameshake_do_update = function (parent, shakeObject, deltaTime)
|
|
|
|
--> check delta time
|
|
deltaTime = deltaTime or 0
|
|
|
|
--> update time left
|
|
shakeObject.TimeLeft = max (shakeObject.TimeLeft - deltaTime, 0)
|
|
|
|
if (shakeObject.TimeLeft > 0) then
|
|
--> update fade in and out
|
|
if (shakeObject.IsFadingIn) then
|
|
shakeObject.IsFadingInTime = shakeObject.IsFadingInTime + deltaTime
|
|
end
|
|
if (shakeObject.IsFadingOut) then
|
|
shakeObject.IsFadingOutTime = shakeObject.IsFadingOutTime + deltaTime
|
|
end
|
|
|
|
--> check if can disable fade in
|
|
if (shakeObject.IsFadingIn and shakeObject.IsFadingInTime > shakeObject.FadeInTime) then
|
|
shakeObject.IsFadingIn = false
|
|
end
|
|
|
|
--> check if can enable fade out
|
|
if (not shakeObject.IsFadingOut and shakeObject.TimeLeft < shakeObject.FadeOutTime) then
|
|
shakeObject.IsFadingOut = true
|
|
shakeObject.IsFadingOutTime = shakeObject.FadeOutTime - shakeObject.TimeLeft
|
|
end
|
|
|
|
--> update position
|
|
local scaleShake = min (shakeObject.IsFadingIn and (shakeObject.IsFadingInTime / shakeObject.FadeInTime) or 1, shakeObject.IsFadingOut and (1 - shakeObject.IsFadingOutTime / shakeObject.FadeOutTime) or 1)
|
|
|
|
if (scaleShake > 0) then
|
|
|
|
--> delate the time by the frequency on both X and Y offsets
|
|
shakeObject.XSineOffset = shakeObject.XSineOffset + (deltaTime * shakeObject.Frequency)
|
|
shakeObject.YSineOffset = shakeObject.YSineOffset + (deltaTime * shakeObject.Frequency)
|
|
|
|
--> calc the new position
|
|
local newX, newY
|
|
if (shakeObject.AbsoluteSineX) then
|
|
--absoluting only the sine wave, passing a negative scale will reverse the absolute direction
|
|
newX = shakeObject.Amplitude * abs (math.sin (shakeObject.XSineOffset)) * scaleShake * shakeObject.ScaleX
|
|
else
|
|
newX = shakeObject.Amplitude * math.sin (shakeObject.XSineOffset) * scaleShake * shakeObject.ScaleX
|
|
end
|
|
|
|
if (shakeObject.AbsoluteSineY) then
|
|
newY = shakeObject.Amplitude * abs (math.sin (shakeObject.YSineOffset)) * scaleShake * shakeObject.ScaleY
|
|
else
|
|
newY = shakeObject.Amplitude * math.sin (shakeObject.YSineOffset) * scaleShake * shakeObject.ScaleY
|
|
end
|
|
|
|
--> apply the offset to the frame anchors
|
|
for i = 1, #shakeObject.Anchors do
|
|
local anchor = shakeObject.Anchors [i]
|
|
|
|
if (#anchor == 1 or #anchor == 3) then
|
|
local anchorTo, point1, point2 = unpack (anchor)
|
|
point1 = point1 or 0
|
|
point2 = point2 or 0
|
|
parent:SetPoint (anchorTo, point1 + newX, point2 + newY)
|
|
|
|
elseif (#anchor == 5) then
|
|
local anchorName1, anchorTo, anchorName2, point1, point2 = unpack (anchor)
|
|
--parent:ClearAllPoints()
|
|
|
|
parent:SetPoint (anchorName1, anchorTo, anchorName2, point1 + newX, point2 + newY)
|
|
end
|
|
end
|
|
|
|
end
|
|
else
|
|
frameshake_shake_finished (parent, shakeObject)
|
|
end
|
|
end
|
|
|
|
local frameshake_stop = function (parent, shakeObject)
|
|
frameshake_shake_finished (parent, shakeObject)
|
|
end
|
|
|
|
--> scale direction scales the X and Y coordinates, scale strength scales the amplitude and frequency
|
|
local frameshake_play = function (parent, shakeObject, scaleDirection, scaleAmplitude, scaleFrequency, scaleDuration)
|
|
|
|
--> check if is already playing
|
|
if (shakeObject.TimeLeft > 0) then
|
|
--> reset the time left
|
|
shakeObject.TimeLeft = shakeObject.Duration
|
|
|
|
if (shakeObject.IsFadingOut) then
|
|
if (shakeObject.FadeInTime > 0) then
|
|
shakeObject.IsFadingIn = true
|
|
--> scale the current fade out into fade in, so it starts the fade in at the point where it was fading out
|
|
shakeObject.IsFadingInTime = shakeObject.FadeInTime * (1 - shakeObject.IsFadingOutTime / shakeObject.FadeOutTime)
|
|
else
|
|
shakeObject.IsFadingIn = false
|
|
shakeObject.IsFadingInTime = 0
|
|
end
|
|
|
|
--> disable fade out and enable fade in
|
|
shakeObject.IsFadingOut = false
|
|
shakeObject.IsFadingOutTime = 0
|
|
end
|
|
else
|
|
--> create a new random offset
|
|
shakeObject.XSineOffset = math.pi * 2 * math.random()
|
|
shakeObject.YSineOffset = math.pi * 2 * math.random()
|
|
|
|
--> store the initial position if case it needs a reset
|
|
shakeObject.StartedXSineOffset = shakeObject.XSineOffset
|
|
shakeObject.StartedYSineOffset = shakeObject.YSineOffset
|
|
|
|
--> check if there's a fade in time
|
|
if (shakeObject.FadeInTime > 0) then
|
|
shakeObject.IsFadingIn = true
|
|
else
|
|
shakeObject.IsFadingIn = false
|
|
end
|
|
|
|
shakeObject.IsFadingInTime = 0
|
|
shakeObject.IsFadingOut = false
|
|
shakeObject.IsFadingOutTime = 0
|
|
|
|
--> apply custom scale
|
|
shakeObject.ScaleX = (scaleDirection or 1) * shakeObject.OriginalScaleX
|
|
shakeObject.ScaleY = (scaleDirection or 1) * shakeObject.OriginalScaleY
|
|
shakeObject.Frequency = (scaleFrequency or 1) * shakeObject.OriginalFrequency
|
|
shakeObject.Amplitude = (scaleAmplitude or 1) * shakeObject.OriginalAmplitude
|
|
shakeObject.Duration = (scaleDuration or 1) * shakeObject.OriginalDuration
|
|
|
|
--> update the time left
|
|
shakeObject.TimeLeft = shakeObject.Duration
|
|
|
|
--> check if is dynamic points
|
|
if (shakeObject.IsDynamicAnchor) then
|
|
wipe (shakeObject.Anchors)
|
|
for i = 1, parent:GetNumPoints() do
|
|
local p1, p2, p3, p4, p5 = parent:GetPoint (i)
|
|
shakeObject.Anchors [#shakeObject.Anchors+1] = {p1, p2, p3, p4, p5}
|
|
end
|
|
end
|
|
|
|
--> update the amount of shake running on this frame
|
|
parent.__frameshakes.enabled = parent.__frameshakes.enabled + 1
|
|
|
|
if (not parent:GetScript ("OnUpdate")) then
|
|
parent:SetScript ("OnUpdate", function()end)
|
|
end
|
|
end
|
|
|
|
shakeObject.IsPlaying = true
|
|
|
|
frameshake_do_update (parent, shakeObject)
|
|
end
|
|
|
|
local frameshake_set_config = function (parent, shakeObject, duration, amplitude, frequency, absoluteSineX, absoluteSineY, scaleX, scaleY, fadeInTime, fadeOutTime, anchorPoints)
|
|
shakeObject.Amplitude = amplitude or shakeObject.Amplitude
|
|
shakeObject.Frequency = frequency or shakeObject.Frequency
|
|
shakeObject.Duration = duration or shakeObject.Duration
|
|
shakeObject.FadeInTime = fadeInTime or shakeObject.FadeInTime
|
|
shakeObject.FadeOutTime = fadeOutTime or shakeObject.FadeOutTime
|
|
shakeObject.ScaleX = scaleX or shakeObject.ScaleX
|
|
shakeObject.ScaleY = scaleY or shakeObject.ScaleY
|
|
|
|
if (absoluteSineX ~= nil) then
|
|
shakeObject.AbsoluteSineX = absoluteSineX
|
|
end
|
|
if (absoluteSineY ~= nil) then
|
|
shakeObject.AbsoluteSineY = absoluteSineY
|
|
end
|
|
|
|
shakeObject.OriginalScaleX = shakeObject.ScaleX
|
|
shakeObject.OriginalScaleY = shakeObject.ScaleY
|
|
shakeObject.OriginalFrequency = shakeObject.Frequency
|
|
shakeObject.OriginalAmplitude = shakeObject.Amplitude
|
|
shakeObject.OriginalDuration = shakeObject.Duration
|
|
end
|
|
|
|
function DF:CreateFrameShake (parent, duration, amplitude, frequency, absoluteSineX, absoluteSineY, scaleX, scaleY, fadeInTime, fadeOutTime, anchorPoints)
|
|
|
|
--> create the shake table
|
|
local frameShake = {
|
|
Amplitude = amplitude or 2,
|
|
Frequency = frequency or 5,
|
|
Duration = duration or 0.3,
|
|
FadeInTime = fadeInTime or 0.01,
|
|
FadeOutTime = fadeOutTime or 0.01,
|
|
ScaleX = scaleX or 0.2,
|
|
ScaleY = scaleY or 1,
|
|
AbsoluteSineX = absoluteSineX,
|
|
AbsoluteSineY = absoluteSineY,
|
|
--
|
|
IsPlaying = false,
|
|
TimeLeft = 0,
|
|
}
|
|
|
|
frameShake.OriginalScaleX = frameShake.ScaleX
|
|
frameShake.OriginalScaleY = frameShake.ScaleY
|
|
frameShake.OriginalFrequency = frameShake.Frequency
|
|
frameShake.OriginalAmplitude = frameShake.Amplitude
|
|
frameShake.OriginalDuration = frameShake.Duration
|
|
|
|
if (type (anchorPoints) ~= "table") then
|
|
frameShake.IsDynamicAnchor = true
|
|
frameShake.Anchors = {}
|
|
else
|
|
frameShake.Anchors = anchorPoints
|
|
end
|
|
|
|
--> inject frame shake table into the frame
|
|
if (not parent.__frameshakes) then
|
|
parent.__frameshakes = {
|
|
enabled = 0,
|
|
}
|
|
parent.PlayFrameShake = frameshake_play
|
|
parent.StopFrameShake = frameshake_stop
|
|
parent.UpdateFrameShake = frameshake_do_update
|
|
parent.SetFrameShakeSettings = frameshake_set_config
|
|
|
|
--> register the frame within the frame shake updater
|
|
FrameshakeUpdateFrame.RegisterFrame (parent)
|
|
end
|
|
|
|
tinsert (parent.__frameshakes, frameShake)
|
|
|
|
return frameShake
|
|
end
|
|
|
|
|
|
-----------------------------
|
|
--> glow overlay
|
|
|
|
local glow_overlay_play = function (self)
|
|
if (not self:IsShown()) then
|
|
self:Show()
|
|
end
|
|
if (self.animOut:IsPlaying()) then
|
|
self.animOut:Stop()
|
|
end
|
|
if (not self.animIn:IsPlaying()) then
|
|
self.animIn:Stop()
|
|
self.animIn:Play()
|
|
end
|
|
end
|
|
|
|
local glow_overlay_stop = function (self)
|
|
if (self.animOut:IsPlaying()) then
|
|
self.animOut:Stop()
|
|
end
|
|
if (self.animIn:IsPlaying()) then
|
|
self.animIn:Stop()
|
|
end
|
|
if (self:IsShown()) then
|
|
self:Hide()
|
|
end
|
|
end
|
|
|
|
local glow_overlay_setcolor = function (self, antsColor, glowColor)
|
|
if (antsColor) then
|
|
local r, g, b, a = DF:ParseColors (antsColor)
|
|
self.ants:SetVertexColor (r, g, b, a)
|
|
self.AntsColor.r = r
|
|
self.AntsColor.g = g
|
|
self.AntsColor.b = b
|
|
self.AntsColor.a = a
|
|
end
|
|
|
|
if (glowColor) then
|
|
local r, g, b, a = DF:ParseColors (glowColor)
|
|
self.outerGlow:SetVertexColor (r, g, b, a)
|
|
self.GlowColor.r = r
|
|
self.GlowColor.g = g
|
|
self.GlowColor.b = b
|
|
self.GlowColor.a = a
|
|
end
|
|
end
|
|
|
|
local glow_overlay_onshow = function (self)
|
|
glow_overlay_play (self)
|
|
end
|
|
|
|
local glow_overlay_onhide = function (self)
|
|
glow_overlay_stop (self)
|
|
end
|
|
|
|
--this is most copied from the wow client code, few changes applied to customize it
|
|
function DF:CreateGlowOverlay (parent, antsColor, glowColor)
|
|
local glowFrame = CreateFrame ("frame", parent:GetName() and "$parentGlow2" or "OverlayActionGlow" .. math.random (1, 10000000), parent, "ActionBarButtonSpellActivationAlert")
|
|
glowFrame:HookScript ("OnShow", glow_overlay_onshow)
|
|
glowFrame:HookScript ("OnHide", glow_overlay_onhide)
|
|
|
|
glowFrame.Play = glow_overlay_play
|
|
glowFrame.Stop = glow_overlay_stop
|
|
glowFrame.SetColor = glow_overlay_setcolor
|
|
|
|
glowFrame:Hide()
|
|
|
|
parent.overlay = glowFrame
|
|
local frameWidth, frameHeight = parent:GetSize()
|
|
|
|
local scale = 1.4
|
|
|
|
--Make the height/width available before the next frame:
|
|
parent.overlay:SetSize(frameWidth * scale, frameHeight * scale)
|
|
parent.overlay:SetPoint("TOPLEFT", parent, "TOPLEFT", -frameWidth * 0.32, frameHeight * 0.36)
|
|
parent.overlay:SetPoint("BOTTOMRIGHT", parent, "BOTTOMRIGHT", frameWidth * 0.32, -frameHeight * 0.36)
|
|
|
|
local r, g, b, a = DF:ParseColors (antsColor or defaultColor)
|
|
glowFrame.ants:SetVertexColor (r, g, b, a)
|
|
glowFrame.AntsColor = {r, g, b, a}
|
|
|
|
local r, g, b, a = DF:ParseColors (glowColor or defaultColor)
|
|
glowFrame.outerGlow:SetVertexColor (r, g, b, a)
|
|
glowFrame.GlowColor = {r, g, b, a}
|
|
|
|
glowFrame.outerGlow:SetScale (1.2)
|
|
return glowFrame
|
|
end
|
|
|
|
--> custom glow with ants animation
|
|
local ants_set_texture_offset = function (self, leftOffset, rightOffset, topOffset, bottomOffset)
|
|
leftOffset = leftOffset or 0
|
|
rightOffset = rightOffset or 0
|
|
topOffset = topOffset or 0
|
|
bottomOffset = bottomOffset or 0
|
|
|
|
self:ClearAllPoints()
|
|
self:SetPoint ("topleft", leftOffset, topOffset)
|
|
self:SetPoint ("bottomright", rightOffset, bottomOffset)
|
|
end
|
|
|
|
function DF:CreateAnts (parent, antTable, leftOffset, rightOffset, topOffset, bottomOffset, antTexture)
|
|
leftOffset = leftOffset or 0
|
|
rightOffset = rightOffset or 0
|
|
topOffset = topOffset or 0
|
|
bottomOffset = bottomOffset or 0
|
|
|
|
local f = CreateFrame ("frame", nil, parent)
|
|
f:SetPoint ("topleft", leftOffset, topOffset)
|
|
f:SetPoint ("bottomright", rightOffset, bottomOffset)
|
|
|
|
f.SetOffset = ants_set_texture_offset
|
|
|
|
local t = f:CreateTexture (nil, "overlay")
|
|
t:SetAllPoints()
|
|
t:SetTexture (antTable.Texture)
|
|
t:SetBlendMode (antTable.BlendMode or "ADD")
|
|
t:SetVertexColor (DF:ParseColors (antTable.Color or "white"))
|
|
f.Texture = t
|
|
|
|
f.AntTable = antTable
|
|
|
|
f:SetScript ("OnUpdate", function (self, deltaTime)
|
|
AnimateTexCoords (t, self.AntTable.TextureWidth, self.AntTable.TextureHeight, self.AntTable.TexturePartsWidth, self.AntTable.TexturePartsHeight, self.AntTable.AmountParts, deltaTime, self.AntTable.Throttle or 0.025)
|
|
end)
|
|
|
|
return f
|
|
end
|
|
|
|
--[=[ --test ants
|
|
do
|
|
local f = DF:CreateAnts (UIParent)
|
|
end
|
|
--]=]
|
|
|
|
-----------------------------
|
|
--> borders
|
|
|
|
local default_border_color1 = .5
|
|
local default_border_color2 = .3
|
|
local default_border_color3 = .1
|
|
|
|
local SetBorderAlpha = function (self, alpha1, alpha2, alpha3)
|
|
self.Borders.Alpha1 = alpha1 or self.Borders.Alpha1
|
|
self.Borders.Alpha2 = alpha2 or self.Borders.Alpha2
|
|
self.Borders.Alpha3 = alpha3 or self.Borders.Alpha3
|
|
|
|
for _, texture in ipairs (self.Borders.Layer1) do
|
|
texture:SetAlpha (self.Borders.Alpha1)
|
|
end
|
|
for _, texture in ipairs (self.Borders.Layer2) do
|
|
texture:SetAlpha (self.Borders.Alpha2)
|
|
end
|
|
for _, texture in ipairs (self.Borders.Layer3) do
|
|
texture:SetAlpha (self.Borders.Alpha3)
|
|
end
|
|
end
|
|
|
|
local SetBorderColor = function (self, r, g, b)
|
|
for _, texture in ipairs (self.Borders.Layer1) do
|
|
texture:SetColorTexture (r, g, b)
|
|
end
|
|
for _, texture in ipairs (self.Borders.Layer2) do
|
|
texture:SetColorTexture (r, g, b)
|
|
end
|
|
for _, texture in ipairs (self.Borders.Layer3) do
|
|
texture:SetColorTexture (r, g, b)
|
|
end
|
|
end
|
|
|
|
local SetLayerVisibility = function (self, layer1Shown, layer2Shown, layer3Shown)
|
|
|
|
for _, texture in ipairs (self.Borders.Layer1) do
|
|
texture:SetShown (layer1Shown)
|
|
end
|
|
|
|
for _, texture in ipairs (self.Borders.Layer2) do
|
|
texture:SetShown (layer2Shown)
|
|
end
|
|
|
|
for _, texture in ipairs (self.Borders.Layer3) do
|
|
texture:SetShown (layer3Shown)
|
|
end
|
|
|
|
end
|
|
|
|
function DF:CreateBorder (parent, alpha1, alpha2, alpha3)
|
|
|
|
parent.Borders = {
|
|
Layer1 = {},
|
|
Layer2 = {},
|
|
Layer3 = {},
|
|
Alpha1 = alpha1 or default_border_color1,
|
|
Alpha2 = alpha2 or default_border_color2,
|
|
Alpha3 = alpha3 or default_border_color3,
|
|
}
|
|
|
|
parent.SetBorderAlpha = SetBorderAlpha
|
|
parent.SetBorderColor = SetBorderColor
|
|
parent.SetLayerVisibility = SetLayerVisibility
|
|
|
|
local border1 = parent:CreateTexture (nil, "background")
|
|
PixelUtil.SetPoint (border1, "topleft", parent, "topleft", -1, 1)
|
|
PixelUtil.SetPoint (border1, "bottomleft", parent, "bottomleft", -1, -1)
|
|
border1:SetColorTexture (0, 0, 0, alpha1 or default_border_color1)
|
|
local border2 = parent:CreateTexture (nil, "background")
|
|
PixelUtil.SetPoint (border2, "topleft", parent, "topleft", -2, 2)
|
|
PixelUtil.SetPoint (border2, "bottomleft", parent, "bottomleft", -2, -2)
|
|
border2:SetColorTexture (0, 0, 0, alpha2 or default_border_color2)
|
|
local border3 = parent:CreateTexture (nil, "background")
|
|
PixelUtil.SetPoint (border3, "topleft", parent, "topleft", -3, 3)
|
|
PixelUtil.SetPoint (border3, "bottomleft", parent, "bottomleft", -3, -3)
|
|
border3:SetColorTexture (0, 0, 0, alpha3 or default_border_color3)
|
|
|
|
tinsert (parent.Borders.Layer1, border1)
|
|
tinsert (parent.Borders.Layer2, border2)
|
|
tinsert (parent.Borders.Layer3, border3)
|
|
|
|
local border1 = parent:CreateTexture (nil, "background")
|
|
PixelUtil.SetPoint (border1, "topleft", parent, "topleft", 0, 1)
|
|
PixelUtil.SetPoint (border1, "topright", parent, "topright", 1, 1)
|
|
border1:SetColorTexture (0, 0, 0, alpha1 or default_border_color1)
|
|
local border2 = parent:CreateTexture (nil, "background")
|
|
PixelUtil.SetPoint (border2, "topleft", parent, "topleft", -1, 2)
|
|
PixelUtil.SetPoint (border2, "topright", parent, "topright", 2, 2)
|
|
border2:SetColorTexture (0, 0, 0, alpha2 or default_border_color2)
|
|
local border3 = parent:CreateTexture (nil, "background")
|
|
PixelUtil.SetPoint (border3, "topleft", parent, "topleft", -2, 3)
|
|
PixelUtil.SetPoint (border3, "topright", parent, "topright", 3, 3)
|
|
border3:SetColorTexture (0, 0, 0, alpha3 or default_border_color3)
|
|
|
|
tinsert (parent.Borders.Layer1, border1)
|
|
tinsert (parent.Borders.Layer2, border2)
|
|
tinsert (parent.Borders.Layer3, border3)
|
|
|
|
local border1 = parent:CreateTexture (nil, "background")
|
|
PixelUtil.SetPoint (border1, "topright", parent, "topright", 1, 0)
|
|
PixelUtil.SetPoint (border1, "bottomright", parent, "bottomright", 1, -1)
|
|
border1:SetColorTexture (0, 0, 0, alpha1 or default_border_color1)
|
|
local border2 = parent:CreateTexture (nil, "background")
|
|
PixelUtil.SetPoint (border2, "topright", parent, "topright", 2, 1)
|
|
PixelUtil.SetPoint (border2, "bottomright", parent, "bottomright", 2, -2)
|
|
border2:SetColorTexture (0, 0, 0, alpha2 or default_border_color2)
|
|
local border3 = parent:CreateTexture (nil, "background")
|
|
PixelUtil.SetPoint (border3, "topright", parent, "topright", 3, 2)
|
|
PixelUtil.SetPoint (border3, "bottomright", parent, "bottomright", 3, -3)
|
|
border3:SetColorTexture (0, 0, 0, alpha3 or default_border_color3)
|
|
|
|
tinsert (parent.Borders.Layer1, border1)
|
|
tinsert (parent.Borders.Layer2, border2)
|
|
tinsert (parent.Borders.Layer3, border3)
|
|
|
|
local border1 = parent:CreateTexture (nil, "background")
|
|
PixelUtil.SetPoint (border1, "bottomleft", parent, "bottomleft", 0, -1)
|
|
PixelUtil.SetPoint (border1, "bottomright", parent, "bottomright", 0, -1)
|
|
border1:SetColorTexture (0, 0, 0, alpha1 or default_border_color1)
|
|
local border2 = parent:CreateTexture (nil, "background")
|
|
PixelUtil.SetPoint (border2, "bottomleft", parent, "bottomleft", -1, -2)
|
|
PixelUtil.SetPoint (border2, "bottomright", parent, "bottomright", 1, -2)
|
|
border2:SetColorTexture (0, 0, 0, alpha2 or default_border_color2)
|
|
local border3 = parent:CreateTexture (nil, "background")
|
|
PixelUtil.SetPoint (border3, "bottomleft", parent, "bottomleft", -2, -3)
|
|
PixelUtil.SetPoint (border3, "bottomright", parent, "bottomright", 2, -3)
|
|
border3:SetColorTexture (0, 0, 0, alpha3 or default_border_color3)
|
|
|
|
tinsert (parent.Borders.Layer1, border1)
|
|
tinsert (parent.Borders.Layer2, border2)
|
|
tinsert (parent.Borders.Layer3, border3)
|
|
|
|
end
|
|
|
|
--DFNamePlateBorder as copy from "NameplateFullBorderTemplate" -> DF:CreateFullBorder (name, parent)
|
|
local DFNamePlateBorderTemplateMixin = {};
|
|
|
|
function DFNamePlateBorderTemplateMixin:SetVertexColor(r, g, b, a)
|
|
for i, texture in ipairs(self.Textures) do
|
|
texture:SetVertexColor(r, g, b, a);
|
|
end
|
|
end
|
|
|
|
function DFNamePlateBorderTemplateMixin:SetBorderSizes(borderSize, borderSizeMinPixels, upwardExtendHeightPixels, upwardExtendHeightMinPixels)
|
|
self.borderSize = borderSize;
|
|
self.borderSizeMinPixels = borderSizeMinPixels;
|
|
self.upwardExtendHeightPixels = upwardExtendHeightPixels;
|
|
self.upwardExtendHeightMinPixels = upwardExtendHeightMinPixels;
|
|
end
|
|
|
|
function DFNamePlateBorderTemplateMixin:UpdateSizes()
|
|
local borderSize = self.borderSize or 1;
|
|
local minPixels = self.borderSizeMinPixels or 2;
|
|
|
|
local upwardExtendHeightPixels = self.upwardExtendHeightPixels or borderSize;
|
|
local upwardExtendHeightMinPixels = self.upwardExtendHeightMinPixels or minPixels;
|
|
|
|
PixelUtil.SetWidth(self.Left, borderSize, minPixels);
|
|
PixelUtil.SetPoint(self.Left, "TOPRIGHT", self, "TOPLEFT", 0, upwardExtendHeightPixels, 0, upwardExtendHeightMinPixels);
|
|
PixelUtil.SetPoint(self.Left, "BOTTOMRIGHT", self, "BOTTOMLEFT", 0, -borderSize, 0, minPixels);
|
|
|
|
PixelUtil.SetWidth(self.Right, borderSize, minPixels);
|
|
PixelUtil.SetPoint(self.Right, "TOPLEFT", self, "TOPRIGHT", 0, upwardExtendHeightPixels, 0, upwardExtendHeightMinPixels);
|
|
PixelUtil.SetPoint(self.Right, "BOTTOMLEFT", self, "BOTTOMRIGHT", 0, -borderSize, 0, minPixels);
|
|
|
|
PixelUtil.SetHeight(self.Bottom, borderSize, minPixels);
|
|
PixelUtil.SetPoint(self.Bottom, "TOPLEFT", self, "BOTTOMLEFT", 0, 0);
|
|
PixelUtil.SetPoint(self.Bottom, "TOPRIGHT", self, "BOTTOMRIGHT", 0, 0);
|
|
|
|
if self.Top then
|
|
PixelUtil.SetHeight(self.Top, borderSize, minPixels);
|
|
PixelUtil.SetPoint(self.Top, "BOTTOMLEFT", self, "TOPLEFT", 0, 0);
|
|
PixelUtil.SetPoint(self.Top, "BOTTOMRIGHT", self, "TOPRIGHT", 0, 0);
|
|
end
|
|
end
|
|
|
|
function DF:CreateFullBorder (name, parent)
|
|
local border = CreateFrame("Frame", name, parent)
|
|
border:SetAllPoints()
|
|
border:SetIgnoreParentScale(true)
|
|
border:SetFrameLevel(border:GetParent():GetFrameLevel())
|
|
border.Textures = {}
|
|
Mixin(border, DFNamePlateBorderTemplateMixin)
|
|
|
|
local left = border:CreateTexture("$parentLeft", "BACKGROUND", nil, -8)
|
|
--left:SetDrawLayer("BACKGROUND", -8)
|
|
left:SetColorTexture(1, 1, 1, 1)
|
|
left:SetWidth(1.0)
|
|
left:SetPoint("TOPRIGHT", border, "TOPLEFT", 0, 1.0)
|
|
left:SetPoint("BOTTOMRIGHT", border, "BOTTOMLEFT", 0, -1.0)
|
|
border.Left = left
|
|
tinsert(border.Textures, left)
|
|
|
|
local right = border:CreateTexture("$parentRight", "BACKGROUND", nil, -8)
|
|
--right:SetDrawLayer("BACKGROUND", -8)
|
|
right:SetColorTexture(1, 1, 1, 1)
|
|
right:SetWidth(1.0)
|
|
right:SetPoint("TOPLEFT", border, "TOPRIGHT", 0, 1.0)
|
|
right:SetPoint("BOTTOMLEFT", border, "BOTTOMRIGHT", 0, -1.0)
|
|
border.Right = right
|
|
tinsert(border.Textures, right)
|
|
|
|
local bottom = border:CreateTexture("$parentBottom", "BACKGROUND", nil, -8)
|
|
--bottom:SetDrawLayer("BACKGROUND", -8)
|
|
bottom:SetColorTexture(1, 1, 1, 1)
|
|
bottom:SetHeight(1.0)
|
|
bottom:SetPoint("TOPLEFT", border, "BOTTOMLEFT", 0, 0)
|
|
bottom:SetPoint("TOPRIGHT", border, "BOTTOMRIGHT", 0, 0)
|
|
border.Bottom = bottom
|
|
tinsert(border.Textures, bottom)
|
|
|
|
local top = border:CreateTexture("$parentTop", "BACKGROUND", nil, -8)
|
|
--top:SetDrawLayer("BACKGROUND", -8)
|
|
top:SetColorTexture(1, 1, 1, 1)
|
|
top:SetHeight(1.0)
|
|
top:SetPoint("BOTTOMLEFT", border, "TOPLEFT", 0, 0)
|
|
top:SetPoint("BOTTOMRIGHT", border, "TOPRIGHT", 0, 0)
|
|
border.Top = top
|
|
tinsert(border.Textures, top)
|
|
|
|
return border
|
|
end
|
|
|
|
function DF:CreateBorderSolid (parent, size)
|
|
|
|
end
|
|
|
|
function DF:CreateBorderWithSpread (parent, alpha1, alpha2, alpha3, size, spread)
|
|
|
|
parent.Borders = {
|
|
Layer1 = {},
|
|
Layer2 = {},
|
|
Layer3 = {},
|
|
Alpha1 = alpha1 or default_border_color1,
|
|
Alpha2 = alpha2 or default_border_color2,
|
|
Alpha3 = alpha3 or default_border_color3,
|
|
}
|
|
|
|
parent.SetBorderAlpha = SetBorderAlpha
|
|
parent.SetBorderColor = SetBorderColor
|
|
parent.SetLayerVisibility = SetLayerVisibility
|
|
|
|
size = size or 1
|
|
local minPixels = 1
|
|
local spread = 0
|
|
|
|
--left
|
|
local border1 = parent:CreateTexture (nil, "background")
|
|
border1:SetColorTexture (0, 0, 0, alpha1 or default_border_color1)
|
|
PixelUtil.SetPoint (border1, "topleft", parent, "topleft", -1 + spread, 1 + (-spread), 0, 0)
|
|
PixelUtil.SetPoint (border1, "bottomleft", parent, "bottomleft", -1 + spread, -1 + spread, 0, 0)
|
|
PixelUtil.SetWidth (border1, size, minPixels)
|
|
|
|
local border2 = parent:CreateTexture (nil, "background")
|
|
PixelUtil.SetPoint (border2, "topleft", parent, "topleft", -2 + spread, 2 + (-spread))
|
|
PixelUtil.SetPoint (border2, "bottomleft", parent, "bottomleft", -2 + spread, -2 + spread)
|
|
border2:SetColorTexture (0, 0, 0, alpha2 or default_border_color2)
|
|
PixelUtil.SetWidth (border2, size, minPixels)
|
|
|
|
local border3 = parent:CreateTexture (nil, "background")
|
|
PixelUtil.SetPoint (border3, "topleft", parent, "topleft", -3 + spread, 3 + (-spread))
|
|
PixelUtil.SetPoint (border3, "bottomleft", parent, "bottomleft", -3 + spread, -3 + spread)
|
|
border3:SetColorTexture (0, 0, 0, alpha3 or default_border_color3)
|
|
PixelUtil.SetWidth (border3, size, minPixels)
|
|
|
|
tinsert (parent.Borders.Layer1, border1)
|
|
tinsert (parent.Borders.Layer2, border2)
|
|
tinsert (parent.Borders.Layer3, border3)
|
|
|
|
--top
|
|
local border1 = parent:CreateTexture (nil, "background")
|
|
PixelUtil.SetPoint (border1, "topleft", parent, "topleft", 0 + spread, 1 + (-spread))
|
|
PixelUtil.SetPoint (border1, "topright", parent, "topright", 1 + (-spread), 1 + (-spread))
|
|
border1:SetColorTexture (0, 0, 0, alpha1 or default_border_color1)
|
|
PixelUtil.SetHeight (border1, size, minPixels)
|
|
|
|
local border2 = parent:CreateTexture (nil, "background")
|
|
PixelUtil.SetPoint (border2, "topleft", parent, "topleft", -1 + spread, 2 + (-spread))
|
|
PixelUtil.SetPoint (border2, "topright", parent, "topright", 2 + (-spread), 2 + (-spread))
|
|
border2:SetColorTexture (0, 0, 0, alpha2 or default_border_color2)
|
|
PixelUtil.SetHeight (border2, size, minPixels)
|
|
|
|
local border3 = parent:CreateTexture (nil, "background")
|
|
PixelUtil.SetPoint (border3, "topleft", parent, "topleft", -2 + spread, 3 + (-spread))
|
|
PixelUtil.SetPoint (border3, "topright", parent, "topright", 3 + (-spread), 3 + (-spread))
|
|
border3:SetColorTexture (0, 0, 0, alpha3 or default_border_color3)
|
|
PixelUtil.SetHeight (border3, size, minPixels)
|
|
|
|
tinsert (parent.Borders.Layer1, border1)
|
|
tinsert (parent.Borders.Layer2, border2)
|
|
tinsert (parent.Borders.Layer3, border3)
|
|
|
|
--right
|
|
local border1 = parent:CreateTexture (nil, "background")
|
|
PixelUtil.SetPoint (border1, "topright", parent, "topright", 1 + (-spread), 0 + (-spread))
|
|
PixelUtil.SetPoint (border1, "bottomright", parent, "bottomright", 1 + (-spread), -1 + spread)
|
|
border1:SetColorTexture (0, 0, 0, alpha1 or default_border_color1)
|
|
PixelUtil.SetWidth (border1, size, minPixels)
|
|
|
|
local border2 = parent:CreateTexture (nil, "background")
|
|
PixelUtil.SetPoint (border2, "topright", parent, "topright", 2 + (-spread), 1 + (-spread))
|
|
PixelUtil.SetPoint (border2, "bottomright", parent, "bottomright", 2 + (-spread), -2 + spread)
|
|
border2:SetColorTexture (0, 0, 0, alpha2 or default_border_color2)
|
|
PixelUtil.SetWidth (border2, size, minPixels)
|
|
|
|
local border3 = parent:CreateTexture (nil, "background")
|
|
PixelUtil.SetPoint (border3, "topright", parent, "topright", 3 + (-spread), 2 + (-spread))
|
|
PixelUtil.SetPoint (border3, "bottomright", parent, "bottomright", 3 + (-spread), -3 + spread)
|
|
border3:SetColorTexture (0, 0, 0, alpha3 or default_border_color3)
|
|
PixelUtil.SetWidth (border3, size, minPixels)
|
|
|
|
tinsert (parent.Borders.Layer1, border1)
|
|
tinsert (parent.Borders.Layer2, border2)
|
|
tinsert (parent.Borders.Layer3, border3)
|
|
|
|
local border1 = parent:CreateTexture (nil, "background")
|
|
PixelUtil.SetPoint (border1, "bottomleft", parent, "bottomleft", 0 + spread, -1 + spread)
|
|
PixelUtil.SetPoint (border1, "bottomright", parent, "bottomright", 0 + (-spread), -1 + spread)
|
|
border1:SetColorTexture (0, 0, 0, alpha1 or default_border_color1)
|
|
PixelUtil.SetHeight (border1, size, minPixels)
|
|
|
|
local border2 = parent:CreateTexture (nil, "background")
|
|
PixelUtil.SetPoint (border2, "bottomleft", parent, "bottomleft", -1 + spread, -2 + spread)
|
|
PixelUtil.SetPoint (border2, "bottomright", parent, "bottomright", 1 + (-spread), -2 + spread)
|
|
border2:SetColorTexture (0, 0, 0, alpha2 or default_border_color2)
|
|
PixelUtil.SetHeight (border2, size, minPixels)
|
|
|
|
local border3 = parent:CreateTexture (nil, "background")
|
|
PixelUtil.SetPoint (border3, "bottomleft", parent, "bottomleft", -2 + spread, -3 + spread)
|
|
PixelUtil.SetPoint (border3, "bottomright", parent, "bottomright", 2 + (-spread), -3 + spread)
|
|
border3:SetColorTexture (0, 0, 0, alpha3 or default_border_color3)
|
|
PixelUtil.SetHeight (border3, size, minPixels)
|
|
|
|
tinsert (parent.Borders.Layer1, border1)
|
|
tinsert (parent.Borders.Layer2, border2)
|
|
tinsert (parent.Borders.Layer3, border3)
|
|
|
|
end
|
|
|
|
function DF:ReskinSlider (slider, heightOffset)
|
|
if (slider.slider) then
|
|
slider.cima:SetNormalTexture ([[Interface\Buttons\Arrow-Up-Up]])
|
|
slider.cima:SetPushedTexture ([[Interface\Buttons\Arrow-Up-Down]])
|
|
slider.cima:SetDisabledTexture ([[Interface\Buttons\Arrow-Up-Disabled]])
|
|
slider.cima:GetNormalTexture():ClearAllPoints()
|
|
slider.cima:GetPushedTexture():ClearAllPoints()
|
|
slider.cima:GetDisabledTexture():ClearAllPoints()
|
|
slider.cima:GetNormalTexture():SetPoint ("center", slider.cima, "center", 1, 1)
|
|
slider.cima:GetPushedTexture():SetPoint ("center", slider.cima, "center", 1, 1)
|
|
slider.cima:GetDisabledTexture():SetPoint ("center", slider.cima, "center", 1, 1)
|
|
slider.cima:SetSize (16, 16)
|
|
--[=[
|
|
slider.cima:SetBackdrop ({edgeFile = [[Interface\Buttons\WHITE8X8]], edgeSize = 1, bgFile = [[Interface\AddOns\Details\images\background]]})
|
|
slider.cima:SetBackdropColor (0, 0, 0, 0.3)
|
|
slider.cima:SetBackdropBorderColor (0, 0, 0, 1)
|
|
]=]
|
|
|
|
slider.baixo:SetNormalTexture ([[Interface\Buttons\Arrow-Down-Up]])
|
|
slider.baixo:SetPushedTexture ([[Interface\Buttons\Arrow-Down-Down]])
|
|
slider.baixo:SetDisabledTexture ([[Interface\Buttons\Arrow-Down-Disabled]])
|
|
slider.baixo:GetNormalTexture():ClearAllPoints()
|
|
slider.baixo:GetPushedTexture():ClearAllPoints()
|
|
slider.baixo:GetDisabledTexture():ClearAllPoints()
|
|
slider.baixo:GetNormalTexture():SetPoint ("center", slider.baixo, "center", 1, -5)
|
|
slider.baixo:GetPushedTexture():SetPoint ("center", slider.baixo, "center", 1, -5)
|
|
slider.baixo:GetDisabledTexture():SetPoint ("center", slider.baixo, "center", 1, -5)
|
|
slider.baixo:SetSize (16, 16)
|
|
--[=[
|
|
slider.baixo:SetBackdrop ({edgeFile = [[Interface\Buttons\WHITE8X8]], edgeSize = 1, bgFile = [[Interface\AddOns\Details\images\background]]})
|
|
slider.baixo:SetBackdropColor (0, 0, 0, 0.35)
|
|
slider.baixo:SetBackdropBorderColor (0, 0, 0, 1)
|
|
|
|
slider.slider:SetBackdrop ({edgeFile = [[Interface\Buttons\WHITE8X8]], edgeSize = 1, bgFile = [[Interface\AddOns\Details\images\background]]})
|
|
slider.slider:SetBackdropColor (0, 0, 0, 0.35)
|
|
slider.slider:SetBackdropBorderColor (0, 0, 0, 1)
|
|
]=]
|
|
|
|
--slider.slider:Altura (164)
|
|
slider.slider:cimaPoint (0, 13)
|
|
slider.slider:baixoPoint (0, -13)
|
|
slider.slider.thumb:SetTexture ([[Interface\AddOns\Details\images\icons2]])
|
|
slider.slider.thumb:SetTexCoord (482/512, 492/512, 104/512, 120/512)
|
|
slider.slider.thumb:SetSize (12, 12)
|
|
slider.slider.thumb:SetVertexColor (0.6, 0.6, 0.6, 0.95)
|
|
|
|
else
|
|
--up button
|
|
|
|
local offset = 1 --space between the scrollbox and the scrollar
|
|
|
|
do
|
|
local normalTexture = slider.ScrollBar.ScrollUpButton.Normal
|
|
normalTexture:SetTexture ([[Interface\Buttons\Arrow-Up-Up]])
|
|
normalTexture:SetTexCoord (0, 1, .2, 1)
|
|
|
|
normalTexture:SetPoint ("topleft", slider.ScrollBar.ScrollUpButton, "topleft", offset, 0)
|
|
normalTexture:SetPoint ("bottomright", slider.ScrollBar.ScrollUpButton, "bottomright", offset, 0)
|
|
|
|
local pushedTexture = slider.ScrollBar.ScrollUpButton.Pushed
|
|
pushedTexture:SetTexture ([[Interface\Buttons\Arrow-Up-Down]])
|
|
pushedTexture:SetTexCoord (0, 1, .2, 1)
|
|
|
|
pushedTexture:SetPoint ("topleft", slider.ScrollBar.ScrollUpButton, "topleft", offset, 0)
|
|
pushedTexture:SetPoint ("bottomright", slider.ScrollBar.ScrollUpButton, "bottomright", offset, 0)
|
|
|
|
local disabledTexture = slider.ScrollBar.ScrollUpButton.Disabled
|
|
disabledTexture:SetTexture ([[Interface\Buttons\Arrow-Up-Disabled]])
|
|
disabledTexture:SetTexCoord (0, 1, .2, 1)
|
|
disabledTexture:SetAlpha (.5)
|
|
|
|
disabledTexture:SetPoint ("topleft", slider.ScrollBar.ScrollUpButton, "topleft", offset, 0)
|
|
disabledTexture:SetPoint ("bottomright", slider.ScrollBar.ScrollUpButton, "bottomright", offset, 0)
|
|
|
|
slider.ScrollBar.ScrollUpButton:SetSize (16, 16)
|
|
--[=[
|
|
slider.ScrollBar.ScrollUpButton:SetBackdrop ({edgeFile = [[Interface\Buttons\WHITE8X8]], edgeSize = 1, bgFile = "Interface\\Tooltips\\UI-Tooltip-Background"})
|
|
slider.ScrollBar.ScrollUpButton:SetBackdropColor (0, 0, 0, 0.3)
|
|
slider.ScrollBar.ScrollUpButton:SetBackdropBorderColor (0, 0, 0, 1)
|
|
]=]
|
|
--it was having problems with the texture anchor when calling ClearAllPoints() and setting new points different from the original
|
|
--now it is using the same points from the original with small offsets tp align correctly
|
|
end
|
|
|
|
--down button
|
|
do
|
|
local normalTexture = slider.ScrollBar.ScrollDownButton.Normal
|
|
normalTexture:SetTexture ([[Interface\Buttons\Arrow-Down-Up]])
|
|
normalTexture:SetTexCoord (0, 1, 0, .8)
|
|
|
|
normalTexture:SetPoint ("topleft", slider.ScrollBar.ScrollDownButton, "topleft", offset, -4)
|
|
normalTexture:SetPoint ("bottomright", slider.ScrollBar.ScrollDownButton, "bottomright", offset, -4)
|
|
|
|
local pushedTexture = slider.ScrollBar.ScrollDownButton.Pushed
|
|
pushedTexture:SetTexture ([[Interface\Buttons\Arrow-Down-Down]])
|
|
pushedTexture:SetTexCoord (0, 1, 0, .8)
|
|
|
|
pushedTexture:SetPoint ("topleft", slider.ScrollBar.ScrollDownButton, "topleft", offset, -4)
|
|
pushedTexture:SetPoint ("bottomright", slider.ScrollBar.ScrollDownButton, "bottomright", offset, -4)
|
|
|
|
local disabledTexture = slider.ScrollBar.ScrollDownButton.Disabled
|
|
disabledTexture:SetTexture ([[Interface\Buttons\Arrow-Down-Disabled]])
|
|
disabledTexture:SetTexCoord (0, 1, 0, .8)
|
|
disabledTexture:SetAlpha (.5)
|
|
|
|
disabledTexture:SetPoint ("topleft", slider.ScrollBar.ScrollDownButton, "topleft", offset, -4)
|
|
disabledTexture:SetPoint ("bottomright", slider.ScrollBar.ScrollDownButton, "bottomright", offset, -4)
|
|
|
|
slider.ScrollBar.ScrollDownButton:SetSize (16, 16)
|
|
--[=[
|
|
slider.ScrollBar.ScrollDownButton:SetBackdrop ({edgeFile = [[Interface\Buttons\WHITE8X8]], edgeSize = 1, bgFile = "Interface\\Tooltips\\UI-Tooltip-Background"})
|
|
slider.ScrollBar.ScrollDownButton:SetBackdropColor (0, 0, 0, 0.3)
|
|
slider.ScrollBar.ScrollDownButton:SetBackdropBorderColor (0, 0, 0, 1)
|
|
]=]
|
|
|
|
--<Anchor point="TOP" relativePoint="BOTTOM"/>
|
|
--slider.ScrollBar.ScrollDownButton:SetPoint ("top", slider.ScrollBar, "bottom", 0, 0)
|
|
end
|
|
|
|
--if the parent has a editbox, this is a code editor
|
|
if (slider:GetParent().editbox) then
|
|
slider.ScrollBar:SetPoint ("TOPLEFT", slider, "TOPRIGHT", 12 + offset, -6)
|
|
slider.ScrollBar:SetPoint ("BOTTOMLEFT", slider, "BOTTOMRIGHT", 12 + offset, 6 + (heightOffset and heightOffset*-1 or 0))
|
|
|
|
else
|
|
slider.ScrollBar:SetPoint ("TOPLEFT", slider, "TOPRIGHT", 6, -16)
|
|
slider.ScrollBar:SetPoint ("BOTTOMLEFT", slider, "BOTTOMRIGHT", 6, 16 + (heightOffset and heightOffset*-1 or 0))
|
|
end
|
|
|
|
slider.ScrollBar.ThumbTexture:SetColorTexture (.5, .5, .5, .3)
|
|
slider.ScrollBar.ThumbTexture:SetSize (12, 8)
|
|
|
|
--
|
|
--[=[
|
|
slider.ScrollBar:SetBackdrop ({edgeFile = [[Interface\Buttons\WHITE8X8]], edgeSize = 1, bgFile = "Interface\\Tooltips\\UI-Tooltip-Background"})
|
|
slider.ScrollBar:SetBackdropColor (0, 0, 0, 0.35)
|
|
slider.ScrollBar:SetBackdropBorderColor (0, 0, 0, 1)
|
|
]=]
|
|
end
|
|
end
|
|
|
|
function DF:GetCurrentSpec()
|
|
local specIndex = DF.GetSpecialization()
|
|
if (specIndex) then
|
|
local specID = DF.GetSpecializationInfo (specIndex)
|
|
if (specID and specID ~= 0) then
|
|
return specID
|
|
end
|
|
end
|
|
end
|
|
|
|
local specs_per_class = {
|
|
["DEMONHUNTER"] = {577, 581},
|
|
["DEATHKNIGHT"] = {250, 251, 252},
|
|
["WARRIOR"] = {71, 72, 73},
|
|
["MAGE"] = {62, 63, 64},
|
|
["ROGUE"] = {259, 260, 261},
|
|
["DRUID"] = {102, 103, 104, 105},
|
|
["HUNTER"] = {253, 254, 255},
|
|
["SHAMAN"] = {262, 263, 254},
|
|
["PRIEST"] = {256, 257, 258},
|
|
["WARLOCK"] = {265, 266, 267},
|
|
["PALADIN"] = {65, 66, 70},
|
|
["MONK"] = {268, 269, 270},
|
|
}
|
|
|
|
function DF:GetClassSpecIDs (class)
|
|
return specs_per_class [class]
|
|
end
|
|
|
|
local dispatch_error = function (context, errortext)
|
|
DF:Msg ( (context or "<no context>") .. " |cFFFF9900error|r: " .. (errortext or "<no error given>"))
|
|
end
|
|
|
|
--> safe call an external func with payload and without telling who is calling
|
|
function DF:QuickDispatch (func, ...)
|
|
if (type (func) ~= "function") then
|
|
return
|
|
end
|
|
|
|
local okay, errortext = pcall (func, ...)
|
|
|
|
if (not okay) then
|
|
--> trigger an error msg
|
|
dispatch_error (_, errortext)
|
|
return
|
|
end
|
|
|
|
return true
|
|
end
|
|
|
|
function DF:Dispatch (func, ...)
|
|
if (type (func) ~= "function") then
|
|
return dispatch_error (_, "Dispatch required a function.")
|
|
end
|
|
|
|
local okay, result1, result2, result3, result4 = xpcall (func, geterrorhandler(), ...)
|
|
|
|
if (not okay) then
|
|
return nil
|
|
end
|
|
|
|
return result1, result2, result3, result4
|
|
end
|
|
|
|
--[=[
|
|
DF:CoreDispatch (func, context, ...)
|
|
safe call a function making a error window with what caused, the context and traceback of the error
|
|
this func is only used inside the framework for sensitive calls where the func must run without errors
|
|
@func = the function which will be called
|
|
@context = what made the function be called
|
|
... parameters to pass in the function call
|
|
--]=]
|
|
function DF:CoreDispatch (context, func, ...)
|
|
if (type (func) ~= "function") then
|
|
local stack = debugstack(2)
|
|
local errortext = "D!Framework " .. context .. " error: invalid function to call\n====================\n" .. stack .. "\n====================\n"
|
|
error (errortext)
|
|
end
|
|
|
|
local okay, result1, result2, result3, result4 = xpcall(func, geterrorhandler(), ...)
|
|
|
|
--if (not okay) then --when using pcall
|
|
--local stack = debugstack(2)
|
|
--local errortext = "D!Framework (" .. context .. ") error: " .. result1 .. "\n====================\n" .. stack .. "\n====================\n"
|
|
--error (errortext)
|
|
--end
|
|
|
|
return result1, result2, result3, result4
|
|
end
|
|
|
|
|
|
--/run local a, b =32,3; local f=function(c,d) return c+d, 2, 3;end; print (xpcall(f,geterrorhandler(),a,b))
|
|
function DF_CALC_PERFORMANCE()
|
|
local F = CreateFrame ("frame")
|
|
local T = GetTime()
|
|
local J = false
|
|
F:SetScript ("OnUpdate", function (self, deltaTime)
|
|
if (not J) then
|
|
J = true
|
|
return
|
|
end
|
|
print ("Elapsed Time:", deltaTime)
|
|
F:SetScript ("OnUpdate", nil)
|
|
end)
|
|
end
|
|
|
|
DF.ClassIndexToFileName = {
|
|
[6] = "DEATHKNIGHT",
|
|
[1] = "WARRIOR",
|
|
[4] = "ROGUE",
|
|
[8] = "MAGE",
|
|
[5] = "PRIEST",
|
|
[3] = "HUNTER",
|
|
[9] = "WARLOCK",
|
|
[12] = "DEMONHUNTER",
|
|
[7] = "SHAMAN",
|
|
[11] = "DRUID",
|
|
[10] = "MONK",
|
|
[2] = "PALADIN",
|
|
}
|
|
|
|
|
|
DF.ClassFileNameToIndex = {
|
|
["DEATHKNIGHT"] = 6,
|
|
["WARRIOR"] = 1,
|
|
["ROGUE"] = 4,
|
|
["MAGE"] = 8,
|
|
["PRIEST"] = 5,
|
|
["HUNTER"] = 3,
|
|
["WARLOCK"] = 9,
|
|
["DEMONHUNTER"] = 12,
|
|
["SHAMAN"] = 7,
|
|
["DRUID"] = 11,
|
|
["MONK"] = 10,
|
|
["PALADIN"] = 2,
|
|
}
|
|
DF.ClassCache = {}
|
|
|
|
function DF:GetClassList()
|
|
|
|
if (next (DF.ClassCache)) then
|
|
return DF.ClassCache
|
|
end
|
|
|
|
for className, classIndex in pairs (DF.ClassFileNameToIndex) do
|
|
local classTable = C_CreatureInfo.GetClassInfo (classIndex)
|
|
if classTable then
|
|
local t = {
|
|
ID = classIndex,
|
|
Name = classTable.className,
|
|
Texture = [[Interface\GLUES\CHARACTERCREATE\UI-CharacterCreate-Classes]],
|
|
TexCoord = CLASS_ICON_TCOORDS [className],
|
|
FileString = className,
|
|
}
|
|
tinsert (DF.ClassCache, t)
|
|
end
|
|
end
|
|
|
|
return DF.ClassCache
|
|
|
|
end
|
|
|
|
--hardcoded race list
|
|
DF.RaceList = {
|
|
[1] = "Human",
|
|
[2] = "Orc",
|
|
[3] = "Dwarf",
|
|
[4] = "NightElf",
|
|
[5] = "Scourge",
|
|
[6] = "Tauren",
|
|
[7] = "Gnome",
|
|
[8] = "Troll",
|
|
[9] = "Goblin",
|
|
[10] = "BloodElf",
|
|
[11] = "Draenei",
|
|
[22] = "Worgen",
|
|
[24] = "Pandaren",
|
|
}
|
|
|
|
DF.AlliedRaceList = {
|
|
[27] = "Nightborne",
|
|
[29] = "HighmountainTauren",
|
|
[31] = "VoidElf",
|
|
[33] = "LightforgedDraenei",
|
|
[35] = "ZandalariTroll",
|
|
[36] = "KulTiran",
|
|
[38] = "DarkIronDwarf",
|
|
[40] = "Vulpera",
|
|
[41] = "MagharOrc",
|
|
}
|
|
|
|
local slotIdToIcon = {
|
|
[1] = "Interface\\ICONS\\" .. "INV_Helmet_29", --head
|
|
[2] = "Interface\\ICONS\\" .. "INV_Jewelry_Necklace_07", --neck
|
|
[3] = "Interface\\ICONS\\" .. "INV_Shoulder_25", --shoulder
|
|
[5] = "Interface\\ICONS\\" .. "INV_Chest_Cloth_08", --chest
|
|
[6] = "Interface\\ICONS\\" .. "INV_Belt_15", --waist
|
|
[7] = "Interface\\ICONS\\" .. "INV_Pants_08", --legs
|
|
[8] = "Interface\\ICONS\\" .. "INV_Boots_Cloth_03", --feet
|
|
[9] = "Interface\\ICONS\\" .. "INV_Bracer_07", --wrist
|
|
[10] = "Interface\\ICONS\\" .. "INV_Gauntlets_17", --hands
|
|
[11] = "Interface\\ICONS\\" .. "INV_Jewelry_Ring_22", --finger 1
|
|
[12] = "Interface\\ICONS\\" .. "INV_Jewelry_Ring_22", --finger 2
|
|
[13] = "Interface\\ICONS\\" .. "INV_Jewelry_Talisman_07", --trinket 1
|
|
[14] = "Interface\\ICONS\\" .. "INV_Jewelry_Talisman_07", --trinket 2
|
|
[15] = "Interface\\ICONS\\" .. "INV_Misc_Cape_19", --back
|
|
[16] = "Interface\\ICONS\\" .. "INV_Sword_39", --main hand
|
|
[17] = "Interface\\ICONS\\" .. "INV_Sword_39", --off hand
|
|
}
|
|
|
|
function DF:GetArmorIconByArmorSlot(equipSlotId)
|
|
return slotIdToIcon[equipSlotId] or ""
|
|
end
|
|
|
|
|
|
--> store and return a list of character races, always return the non-localized value
|
|
DF.RaceCache = {}
|
|
function DF:GetCharacterRaceList (fullList)
|
|
if (next (DF.RaceCache)) then
|
|
return DF.RaceCache
|
|
end
|
|
|
|
for i = 1, 100 do
|
|
local raceInfo = C_CreatureInfo.GetRaceInfo (i)
|
|
if (raceInfo and DF.RaceList [raceInfo.raceID]) then
|
|
tinsert (DF.RaceCache, {Name = raceInfo.raceName, FileString = raceInfo.clientFileString})
|
|
end
|
|
|
|
if IS_WOW_PROJECT_MAINLINE then
|
|
local alliedRaceInfo = C_AlliedRaces.GetRaceInfoByID (i)
|
|
if (alliedRaceInfo and DF.AlliedRaceList [alliedRaceInfo.raceID]) then
|
|
tinsert (DF.RaceCache, {Name = alliedRaceInfo.maleName, FileString = alliedRaceInfo.raceFileString})
|
|
end
|
|
end
|
|
end
|
|
|
|
return DF.RaceCache
|
|
end
|
|
|
|
--get a list of talents for the current spec the player is using
|
|
--if onlySelected return an index table with only the talents the character has selected
|
|
--if onlySelectedHash return a hash table with [spelID] = true
|
|
function DF:GetCharacterTalents (onlySelected, onlySelectedHash)
|
|
local talentList = {}
|
|
|
|
for i = 1, 7 do
|
|
for o = 1, 3 do
|
|
local talentID, name, texture, selected, available = GetTalentInfo (i, o, 1)
|
|
if (onlySelectedHash) then
|
|
if (selected) then
|
|
talentList [talentID] = true
|
|
break
|
|
end
|
|
elseif (onlySelected) then
|
|
if (selected) then
|
|
tinsert (talentList, {Name = name, ID = talentID, Texture = texture, IsSelected = selected})
|
|
break
|
|
end
|
|
else
|
|
tinsert (talentList, {Name = name, ID = talentID, Texture = texture, IsSelected = selected})
|
|
end
|
|
end
|
|
end
|
|
|
|
return talentList
|
|
end
|
|
|
|
function DF:GetCharacterPvPTalents (onlySelected, onlySelectedHash)
|
|
if (onlySelected or onlySelectedHash) then
|
|
local talentsSelected = C_SpecializationInfo.GetAllSelectedPvpTalentIDs()
|
|
local talentList = {}
|
|
for _, talentID in ipairs (talentsSelected) do
|
|
local _, talentName, texture = GetPvpTalentInfoByID (talentID)
|
|
if (onlySelectedHash) then
|
|
talentList [talentID] = true
|
|
else
|
|
tinsert (talentList, {Name = talentName, ID = talentID, Texture = texture, IsSelected = true})
|
|
end
|
|
end
|
|
return talentList
|
|
|
|
else
|
|
local alreadyAdded = {}
|
|
local talentList = {}
|
|
for i = 1, 4 do --4 slots - get talents available in each one
|
|
local slotInfo = C_SpecializationInfo.GetPvpTalentSlotInfo (i)
|
|
if (slotInfo) then
|
|
for _, talentID in ipairs (slotInfo.availableTalentIDs) do
|
|
if (not alreadyAdded [talentID]) then
|
|
local _, talentName, texture, selected = GetPvpTalentInfoByID (talentID)
|
|
tinsert (talentList, {Name = talentName, ID = talentID, Texture = texture, IsSelected = selected})
|
|
alreadyAdded [talentID] = true
|
|
end
|
|
end
|
|
end
|
|
end
|
|
return talentList
|
|
end
|
|
end
|
|
|
|
DF.GroupTypes = {
|
|
{Name = "Arena", ID = "arena"},
|
|
{Name = "Battleground", ID = "pvp"},
|
|
{Name = "Raid", ID = "raid"},
|
|
{Name = "Dungeon", ID = "party"},
|
|
{Name = "Scenario", ID = "scenario"},
|
|
{Name = "Open World", ID = "none"},
|
|
}
|
|
function DF:GetGroupTypes()
|
|
return DF.GroupTypes
|
|
end
|
|
|
|
DF.RoleTypes = {
|
|
{Name = _G.DAMAGER, ID = "DAMAGER", Texture = _G.INLINE_DAMAGER_ICON},
|
|
{Name = _G.HEALER, ID = "HEALER", Texture = _G.INLINE_HEALER_ICON},
|
|
{Name = _G.TANK, ID = "TANK", Texture = _G.INLINE_TANK_ICON},
|
|
}
|
|
function DF:GetRoleTypes()
|
|
return DF.RoleTypes
|
|
end
|
|
|
|
local roleTexcoord = {
|
|
DAMAGER = "72:130:69:127",
|
|
HEALER = "72:130:2:60",
|
|
TANK = "5:63:69:127",
|
|
NONE = "139:196:69:127",
|
|
}
|
|
|
|
local roleTextures = {
|
|
DAMAGER = "Interface\\LFGFRAME\\UI-LFG-ICON-ROLES",
|
|
TANK = "Interface\\LFGFRAME\\UI-LFG-ICON-ROLES",
|
|
HEALER = "Interface\\LFGFRAME\\UI-LFG-ICON-ROLES",
|
|
NONE = "Interface\\LFGFRAME\\UI-LFG-ICON-ROLES",
|
|
}
|
|
|
|
local roleTexcoord2 = {
|
|
DAMAGER = {72/256, 130/256, 69/256, 127/256},
|
|
HEALER = {72/256, 130/256, 2/256, 60/256},
|
|
TANK = {5/256, 63/256, 69/256, 127/256},
|
|
NONE = {139/256, 196/256, 69/256, 127/256},
|
|
}
|
|
|
|
function DF:GetRoleIconAndCoords(role)
|
|
local texture = roleTextures[role]
|
|
local coords = roleTexcoord2[role]
|
|
return texture, unpack(coords)
|
|
end
|
|
|
|
function DF:AddRoleIconToText(text, role, size)
|
|
if (role and type(role) == "string") then
|
|
local coords = GetTexCoordsForRole(role)
|
|
if (coords) then
|
|
if (type (text) == "string" and role ~= "NONE") then
|
|
size = size or 14
|
|
text = "|TInterface\\LFGFRAME\\UI-LFG-ICON-ROLES:" .. size .. ":" .. size .. ":0:0:256:256:" .. roleTexcoord[role] .. "|t " .. text
|
|
return text
|
|
end
|
|
end
|
|
end
|
|
|
|
return text
|
|
end
|
|
|
|
-- TODO: maybe make this auto-generaded some day?...
|
|
DF.CLEncounterID = {
|
|
{ID = 2423, Name = "The Tarragrue"},
|
|
{ID = 2433, Name = "The Eye of the Jailer"},
|
|
{ID = 2429, Name = "The Nine"},
|
|
{ID = 2432, Name = "Remnant of Ner'zhul"},
|
|
{ID = 2434, Name = "Soulrender Dormazain"},
|
|
{ID = 2430, Name = "Painsmith Raznal"},
|
|
{ID = 2436, Name = "Guardian of the First Ones"},
|
|
{ID = 2431, Name = "Fatescribe Roh-Kalo"},
|
|
{ID = 2422, Name = "Kel'Thuzad"},
|
|
{ID = 2435, Name = "Sylvanas Windrunner"},
|
|
}
|
|
|
|
function DF:GetPlayerRole()
|
|
local assignedRole = DF.UnitGroupRolesAssigned ("player")
|
|
if (assignedRole == "NONE") then
|
|
local spec = DF.GetSpecialization()
|
|
return spec and DF.GetSpecializationRole (spec) or "NONE"
|
|
end
|
|
return assignedRole
|
|
end
|
|
|
|
function DF:GetCLEncounterIDs()
|
|
return DF.CLEncounterID
|
|
end
|
|
|
|
DF.ClassSpecs = {
|
|
["DEMONHUNTER"] = {
|
|
[577] = true,
|
|
[581] = true,
|
|
},
|
|
["DEATHKNIGHT"] = {
|
|
[250] = true,
|
|
[251] = true,
|
|
[252] = true,
|
|
},
|
|
["WARRIOR"] = {
|
|
[71] = true,
|
|
[72] = true,
|
|
[73] = true,
|
|
},
|
|
["MAGE"] = {
|
|
[62] = true,
|
|
[63] = true,
|
|
[64] = true,
|
|
},
|
|
["ROGUE"] = {
|
|
[259] = true,
|
|
[260] = true,
|
|
[261] = true,
|
|
},
|
|
["DRUID"] = {
|
|
[102] = true,
|
|
[103] = true,
|
|
[104] = true,
|
|
[105] = true,
|
|
},
|
|
["HUNTER"] = {
|
|
[253] = true,
|
|
[254] = true,
|
|
[255] = true,
|
|
},
|
|
["SHAMAN"] = {
|
|
[262] = true,
|
|
[263] = true,
|
|
[264] = true,
|
|
},
|
|
["PRIEST"] = {
|
|
[256] = true,
|
|
[257] = true,
|
|
[258] = true,
|
|
},
|
|
["WARLOCK"] = {
|
|
[265] = true,
|
|
[266] = true,
|
|
[267] = true,
|
|
},
|
|
["PALADIN"] = {
|
|
[65] = true,
|
|
[66] = true,
|
|
[70] = true,
|
|
},
|
|
["MONK"] = {
|
|
[268] = true,
|
|
[269] = true,
|
|
[270] = true,
|
|
},
|
|
}
|
|
|
|
DF.SpecListByClass = {
|
|
["DEMONHUNTER"] = {
|
|
577,
|
|
581,
|
|
},
|
|
["DEATHKNIGHT"] = {
|
|
250,
|
|
251,
|
|
252,
|
|
},
|
|
["WARRIOR"] = {
|
|
71,
|
|
72,
|
|
73,
|
|
},
|
|
["MAGE"] = {
|
|
62,
|
|
63,
|
|
64,
|
|
},
|
|
["ROGUE"] = {
|
|
259,
|
|
260,
|
|
261,
|
|
},
|
|
["DRUID"] = {
|
|
102,
|
|
103,
|
|
104,
|
|
105,
|
|
},
|
|
["HUNTER"] = {
|
|
253,
|
|
254,
|
|
255,
|
|
},
|
|
["SHAMAN"] = {
|
|
262,
|
|
263,
|
|
264,
|
|
},
|
|
["PRIEST"] = {
|
|
256,
|
|
257,
|
|
258,
|
|
},
|
|
["WARLOCK"] = {
|
|
265,
|
|
266,
|
|
267,
|
|
},
|
|
["PALADIN"] = {
|
|
65,
|
|
66,
|
|
70,
|
|
},
|
|
["MONK"] = {
|
|
268,
|
|
269,
|
|
270,
|
|
},
|
|
}
|
|
|
|
--given a class and a specId, return if the specId is a spec from the class passed
|
|
function DF:IsSpecFromClass(class, specId)
|
|
return DF.ClassSpecs[class] and DF.ClassSpecs[class][specId]
|
|
end
|
|
|
|
--return a has table where specid is the key and 'true' is the value
|
|
function DF:GetClassSpecs(class)
|
|
return DF.ClassSpecs [class]
|
|
end
|
|
|
|
--return a numeric table with spec ids
|
|
function DF:GetSpecListFromClass(class)
|
|
return DF.SpecListByClass [class]
|
|
end
|
|
|
|
--return a list with specIds as keys and spellId as value
|
|
function DF:GetSpellsForRangeCheck()
|
|
return SpellRangeCheckListBySpec
|
|
end
|
|
|
|
--return a list with specIds as keys and spellId as value
|
|
function DF:GetRangeCheckSpellForSpec(specId)
|
|
return SpellRangeCheckListBySpec[specId]
|
|
end
|
|
|
|
|
|
--key is instanceId from GetInstanceInfo()
|
|
-- /dump GetInstanceInfo()
|
|
DF.BattlegroundSizes = {
|
|
[2245] = 15, --Deepwind Gorge
|
|
[2106] = 10, --Warsong Gulch
|
|
[2107] = 15, --Arathi Basin
|
|
[566] = 15, --Eye of the Storm
|
|
[30] = 40, --Alterac Valley
|
|
[628] = 40, --Isle of Conquest
|
|
[761] = 10, --The Battle for Gilneas
|
|
[726] = 10, --Twin Peaks
|
|
[727] = 10, --Silvershard Mines
|
|
[998] = 10, --Temple of Kotmogu
|
|
[2118] = 40, --Battle for Wintergrasp
|
|
[1191] = 25, --Ashran
|
|
[1803] = 10, --Seething Shore
|
|
}
|
|
|
|
------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
--> execute range
|
|
|
|
function DF.GetExecuteRange(unitId)
|
|
unitId = unitId or "player"
|
|
|
|
local classLoc, class = UnitClass(unitId)
|
|
local spec = GetSpecialization()
|
|
|
|
if (spec and class) then
|
|
--prist
|
|
if (class == "PRIEST") then
|
|
--playing as shadow?
|
|
local specID = GetSpecializationInfo(spec)
|
|
if (specID and specID ~= 0) then
|
|
if (specID == 258) then --shadow
|
|
local _, _, _, using_SWDeath = GetTalentInfo(5, 2, 1)
|
|
if (using_SWDeath) then
|
|
return 0.20
|
|
end
|
|
end
|
|
end
|
|
|
|
elseif (class == "MAGE") then
|
|
--playing fire mage?
|
|
local specID = GetSpecializationInfo(spec)
|
|
if (specID and specID ~= 0) then
|
|
if (specID == 63) then --fire
|
|
local _, _, _, using_SearingTouch = GetTalentInfo(1, 3, 1)
|
|
if (using_SearingTouch) then
|
|
return 0.30
|
|
end
|
|
end
|
|
end
|
|
|
|
elseif (class == "WARRIOR") then
|
|
--is playing as a Arms warrior?
|
|
local specID = GetSpecializationInfo(spec)
|
|
if (specID and specID ~= 0) then
|
|
|
|
if (specID == 71) then --arms
|
|
local _, _, _, using_Massacre = GetTalentInfo(3, 1, 1)
|
|
if (using_Massacre) then
|
|
--if using massacre, execute can be used at 35% health in Arms spec
|
|
return 0.35
|
|
end
|
|
end
|
|
|
|
if (specID == 71 or specID == 72) then --arms or fury
|
|
return 0.20
|
|
end
|
|
end
|
|
|
|
elseif (class == "HUNTER") then
|
|
local specID = GetSpecializationInfo(spec)
|
|
if (specID and specID ~= 0) then
|
|
if (specID == 253) then --beast mastery
|
|
--> is using killer instinct?
|
|
local _, _, _, using_KillerInstinct = GetTalentInfo(1, 1, 1)
|
|
if (using_KillerInstinct) then
|
|
return 0.35
|
|
end
|
|
end
|
|
end
|
|
|
|
elseif (class == "PALADIN") then
|
|
local specID = GetSpecializationInfo(spec)
|
|
if (specID and specID ~= 0) then
|
|
if (specID == 70) then --retribution paladin
|
|
--> is using hammer of wrath?
|
|
local _, _, _, using_HammerOfWrath = GetTalentInfo(2, 3, 1)
|
|
if (using_HammerOfWrath) then
|
|
return 0.20
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
--> delta seconds reader
|
|
|
|
if (not DetailsFrameworkDeltaTimeFrame) then
|
|
CreateFrame ("frame", "DetailsFrameworkDeltaTimeFrame", UIParent)
|
|
end
|
|
|
|
local deltaTimeFrame = DetailsFrameworkDeltaTimeFrame
|
|
deltaTimeFrame:SetScript ("OnUpdate", function (self, deltaTime)
|
|
self.deltaTime = deltaTime
|
|
end)
|
|
|
|
function GetWorldDeltaSeconds()
|
|
return deltaTimeFrame.deltaTime
|
|
end
|
|
|
|
------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
--> build the global script channel for scripts communication
|
|
--send and retrieve data sent by othe users in scripts
|
|
--Usage:
|
|
--DetailsFramework:RegisterScriptComm (ID, function(sourcePlayerName, ...) end)
|
|
--DetailsFramework:SendScriptComm (ID, ...)
|
|
|
|
local aceComm = LibStub:GetLibrary ("AceComm-3.0")
|
|
local LibAceSerializer = LibStub:GetLibrary ("AceSerializer-3.0")
|
|
local LibDeflate = LibStub:GetLibrary ("LibDeflate")
|
|
|
|
DF.RegisteredScriptsComm = DF.RegisteredScriptsComm or {}
|
|
|
|
function DF.OnReceiveScriptComm (...)
|
|
local prefix, encodedString, channel, commSource = ...
|
|
|
|
local decodedString = LibDeflate:DecodeForWoWAddonChannel (encodedString)
|
|
if (decodedString) then
|
|
local uncompressedString = LibDeflate:DecompressDeflate (decodedString)
|
|
if (uncompressedString) then
|
|
local data = {LibAceSerializer:Deserialize (uncompressedString)}
|
|
if (data[1]) then
|
|
local ID = data[2]
|
|
if (ID) then
|
|
local sourceName = data[4]
|
|
if (Ambiguate (sourceName, "none") == commSource) then
|
|
local func = DF.RegisteredScriptsComm [ID]
|
|
if (func) then
|
|
DF:Dispatch (func, commSource, select (5, unpack (data))) --this use xpcall
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function DF:RegisterScriptComm (ID, func)
|
|
if (ID) then
|
|
if (type (func) == "function") then
|
|
DF.RegisteredScriptsComm [ID] = func
|
|
else
|
|
DF.RegisteredScriptsComm [ID] = nil
|
|
end
|
|
end
|
|
end
|
|
|
|
function DF:SendScriptComm (ID, ...)
|
|
if (DF.RegisteredScriptsComm [ID]) then
|
|
local sourceName = UnitName ("player") .. "-" .. GetRealmName()
|
|
local data = LibAceSerializer:Serialize (ID, UnitGUID ("player"), sourceName, ...)
|
|
data = LibDeflate:CompressDeflate (data, {level = 9})
|
|
data = LibDeflate:EncodeForWoWAddonChannel (data)
|
|
aceComm:SendCommMessage ("_GSC", data, "PARTY")
|
|
end
|
|
end
|
|
|
|
if (aceComm and LibAceSerializer and LibDeflate) then
|
|
aceComm:RegisterComm ("_GSC", DF.OnReceiveScriptComm)
|
|
end
|
|
|
|
------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
--> debug
|
|
|
|
DF.DebugMixin = {
|
|
|
|
debug = true,
|
|
|
|
CheckPoint = function (self, checkPointName, ...)
|
|
print (self:GetName(), checkPointName, ...)
|
|
end,
|
|
|
|
CheckVisibilityState = function (self, widget)
|
|
|
|
self = widget or self
|
|
|
|
local width, height = self:GetSize()
|
|
width = floor (width)
|
|
height = floor (height)
|
|
|
|
local numPoints = self:GetNumPoints()
|
|
|
|
print ("shown:", self:IsShown(), "visible:", self:IsVisible(), "alpha:", self:GetAlpha(), "size:", width, height, "points:", numPoints)
|
|
end,
|
|
|
|
CheckStack = function (self)
|
|
local stack = debugstack()
|
|
Details:Dump (stack)
|
|
end,
|
|
|
|
}
|
|
|
|
-----------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
--> returns if the unit is tapped (gray health color when another player hit the unit first)
|
|
function DF:IsUnitTapDenied (unitId)
|
|
return unitId and not UnitPlayerControlled (unitId) and UnitIsTapDenied (unitId)
|
|
end
|
|
|
|
|
|
-----------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
--> pool
|
|
|
|
do
|
|
local get = function(self)
|
|
local object = tremove(self.notUse, #self.notUse)
|
|
if (object) then
|
|
tinsert(self.inUse, object)
|
|
if (self.onAcquire) then
|
|
local result, errortext = pcall(self.onAcquire, object)
|
|
end
|
|
return object, false
|
|
else
|
|
--need to create the new object
|
|
local newObject = self.newObjectFunc(self, unpack(self.payload))
|
|
if (newObject) then
|
|
tinsert(self.inUse, newObject)
|
|
if (self.onAcquire) then
|
|
local result, errortext = pcall(self.onAcquire, object)
|
|
end
|
|
return newObject, true
|
|
end
|
|
end
|
|
end
|
|
|
|
local get_all_inuse = function(self)
|
|
return self.inUse;
|
|
end
|
|
|
|
local release = function(self, object)
|
|
for i = #self.inUse, 1, -1 do
|
|
if (self.inUse[i] == object) then
|
|
tremove(self.inUse, i)
|
|
tinsert(self.notUse, object)
|
|
break
|
|
end
|
|
end
|
|
end
|
|
|
|
local reset = function(self)
|
|
for i = #self.inUse, 1, -1 do
|
|
local object = tremove(self.inUse, i)
|
|
tinsert(self.notUse, object)
|
|
|
|
if (self.onReset) then
|
|
local result, errortext = pcall(self.onReset, object)
|
|
end
|
|
end
|
|
end
|
|
|
|
--only hide objects in use, do not disable them
|
|
local hide = function(self)
|
|
for i = #self.inUse, 1, -1 do
|
|
self.inUse[i]:Hide()
|
|
end
|
|
end
|
|
|
|
--only show objects in use, do not enable them
|
|
local show = function(self)
|
|
for i = #self.inUse, 1, -1 do
|
|
self.inUse[i]:Show()
|
|
end
|
|
end
|
|
|
|
--return the amount of objects
|
|
local getamount = function(self)
|
|
return #self.notUse + #self.inUse, #self.notUse, #self.inUse
|
|
end
|
|
|
|
local poolMixin = {
|
|
Get = get,
|
|
GetAllInUse = get_all_inuse,
|
|
Acquire = get,
|
|
Release = release,
|
|
Reset = reset,
|
|
ReleaseAll = reset,
|
|
Hide = hide,
|
|
Show = show,
|
|
GetAmount = getamount,
|
|
SetOnReset = function(self, func)
|
|
self.onReset = func
|
|
end,
|
|
SetOnAcquire = function(self, func)
|
|
self.onAcquire = func
|
|
end,
|
|
}
|
|
|
|
function DF:CreatePool(func, ...)
|
|
local t = {}
|
|
DetailsFramework:Mixin(t, poolMixin)
|
|
|
|
t.inUse = {}
|
|
t.notUse = {}
|
|
t.newObjectFunc = func
|
|
t.payload = {...}
|
|
|
|
return t
|
|
end
|
|
|
|
--alias
|
|
function DF:CreateObjectPool(func, ...)
|
|
return DF:CreatePool(func, ...)
|
|
end
|
|
end
|
|
|
|
|
|
-----------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
--> forbidden functions on scripts
|
|
|
|
--these are functions which scripts cannot run due to security issues
|
|
local forbiddenFunction = {
|
|
--block mail, trades, action house, banks
|
|
["C_AuctionHouse"] = true,
|
|
["C_Bank"] = true,
|
|
["C_GuildBank"] = true,
|
|
["SetSendMailMoney"] = true,
|
|
["SendMail"] = true,
|
|
["SetTradeMoney"] = true,
|
|
["AddTradeMoney"] = true,
|
|
["PickupTradeMoney"] = true,
|
|
["PickupPlayerMoney"] = true,
|
|
["AcceptTrade"] = true,
|
|
|
|
--frames
|
|
["BankFrame"] = true,
|
|
["TradeFrame"] = true,
|
|
["GuildBankFrame"] = true,
|
|
["MailFrame"] = true,
|
|
["EnumerateFrames"] = true,
|
|
|
|
--block run code inside code
|
|
["RunScript"] = true,
|
|
["securecall"] = true,
|
|
["getfenv"] = true,
|
|
["getfenv"] = true,
|
|
["loadstring"] = true,
|
|
["pcall"] = true,
|
|
["xpcall"] = true,
|
|
["getglobal"] = true,
|
|
["setmetatable"] = true,
|
|
["DevTools_DumpCommand"] = true,
|
|
|
|
--avoid creating macros
|
|
["SetBindingMacro"] = true,
|
|
["CreateMacro"] = true,
|
|
["EditMacro"] = true,
|
|
["hash_SlashCmdList"] = true,
|
|
["SlashCmdList"] = true,
|
|
|
|
--block guild commands
|
|
["GuildDisband"] = true,
|
|
["GuildUninvite"] = true,
|
|
|
|
--other things
|
|
["C_GMTicketInfo"] = true,
|
|
|
|
--deny messing addons with script support
|
|
["PlaterDB"] = true,
|
|
["_detalhes_global"] = true,
|
|
["WeakAurasSaved"] = true,
|
|
}
|
|
|
|
local C_RestrictedSubFunctions = {
|
|
["C_GuildInfo"] = {
|
|
["RemoveFromGuild"] = true,
|
|
},
|
|
}
|
|
|
|
--not in use, can't find a way to check within the environment handle
|
|
local addonRestrictedFunctions = {
|
|
["DetailsFramework"] = {
|
|
["SetEnvironment"] = true,
|
|
},
|
|
|
|
["Plater"] = {
|
|
["ImportScriptString"] = true,
|
|
["db"] = true,
|
|
},
|
|
|
|
["WeakAuras"] = {
|
|
["Add"] = true,
|
|
["AddMany"] = true,
|
|
["Delete"] = true,
|
|
["NewAura"] = true,
|
|
},
|
|
}
|
|
|
|
local C_SubFunctionsTable = {}
|
|
for globalTableName, functionTable in pairs(C_RestrictedSubFunctions) do
|
|
C_SubFunctionsTable [globalTableName] = {}
|
|
for functionName, functionObject in pairs(_G[globalTableName]) do
|
|
if (not functionTable[functionName]) then
|
|
C_SubFunctionsTable [globalTableName][functionName] = functionObject
|
|
end
|
|
end
|
|
end
|
|
|
|
DF.DefaultSecureScriptEnvironmentHandle = {
|
|
__index = function (env, key)
|
|
|
|
if (forbiddenFunction[key]) then
|
|
return nil
|
|
|
|
elseif (key == "_G") then
|
|
return env
|
|
|
|
elseif (C_SubFunctionsTable[key]) then
|
|
return C_SubFunctionsTable[key]
|
|
end
|
|
|
|
return _G[key]
|
|
end
|
|
}
|
|
|
|
function DF:SetEnvironment(func, environmentHandle, newEnvironment)
|
|
environmentHandle = environmentHandle or DF.DefaultSecureScriptEnvironmentHandle
|
|
newEnvironment = newEnvironment or {}
|
|
|
|
setmetatable(newEnvironment, environmentHandle)
|
|
_G.setfenv(func, newEnvironment)
|
|
end
|
|
|
|
|
|
-----------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
|