340 lines
10 KiB
Lua
340 lines
10 KiB
Lua
-- ------------------------------------------------------------------------------ --
|
|
-- TradeSkillMaster --
|
|
-- https://tradeskillmaster.com --
|
|
-- All Rights Reserved - Detailed license information included with addon. --
|
|
-- ------------------------------------------------------------------------------ --
|
|
|
|
--- FrameStack Functions
|
|
-- @module FrameStack
|
|
|
|
local _, TSM = ...
|
|
local FrameStack = TSM.UI:NewPackage("FrameStack")
|
|
local Math = TSM.Include("Util.Math")
|
|
local Theme = TSM.Include("Util.Theme")
|
|
local Table = TSM.Include("Util.Table")
|
|
local Vararg = TSM.Include("Util.Vararg")
|
|
local ScriptWrapper = TSM.Include("Util.ScriptWrapper")
|
|
local UIElements = TSM.Include("UI.UIElements")
|
|
local private = {}
|
|
local STRATA_ORDER = {"TOOLTIP", "FULLSCREEN_DIALOG", "FULLSCREEN", "DIALOG", "HIGH", "MEDIUM", "LOW", "BACKGROUND", "WORLD"}
|
|
local framesByStrata = {
|
|
WORLD = {},
|
|
BACKGROUND = {},
|
|
LOW = {},
|
|
MEDIUM = {},
|
|
HIGH = {},
|
|
DIALOG = {},
|
|
FULLSCREEN = {},
|
|
FULLSCREEN_DIALOG = {},
|
|
TOOLTIP = {},
|
|
}
|
|
local ELEMENT_ATTR_KEYS = {
|
|
"_hScrollbar",
|
|
"_vScrollbar",
|
|
"_hScrollFrame",
|
|
"_hContent",
|
|
"_vScrollFrame",
|
|
"_content",
|
|
"_header",
|
|
"_frame",
|
|
"_rows",
|
|
}
|
|
local COLOR_KEYS = {
|
|
FRAME_BG = true,
|
|
PRIMARY_BG = true,
|
|
PRIMARY_BG_ALT = true,
|
|
ACTIVE_BG = true,
|
|
ACTIVE_BG_ALT = true,
|
|
INDICATOR = true,
|
|
INDICATOR_ALT = true,
|
|
INDICATOR_DISABLED = true,
|
|
TEXT = true,
|
|
TEXT_ALT = true,
|
|
TEXT_DISABLED = true,
|
|
}
|
|
local FEEDBACK_COLOR_KEYS = {
|
|
RED = true,
|
|
YELLOW = true,
|
|
GREEN = true,
|
|
BLUE = true,
|
|
ORANGE = true,
|
|
}
|
|
local FONT_KEYS = {
|
|
HEADING_H5 = true,
|
|
BODY_BODY1 = true,
|
|
BODY_BODY1_BOLD = true,
|
|
BODY_BODY2 = true,
|
|
BODY_BODY2_MEDIUM = true,
|
|
BODY_BODY2_BOLD = true,
|
|
BODY_BODY3 = true,
|
|
BODY_BODY3_MEDIUM = true,
|
|
ITEM_BODY1 = true,
|
|
ITEM_BODY2 = true,
|
|
ITEM_BODY3 = true,
|
|
TABLE_TABLE1 = true,
|
|
}
|
|
local ELEMENT_STYLE_KEYS = {
|
|
"_background",
|
|
"_texture",
|
|
"_backgroundColor",
|
|
"_borderColor",
|
|
"_textStr",
|
|
"_textColor",
|
|
"_font",
|
|
"_roundedCorners",
|
|
"_borderSize",
|
|
}
|
|
|
|
|
|
|
|
-- ============================================================================
|
|
-- Module Functions
|
|
-- ============================================================================
|
|
|
|
function FrameStack.Toggle()
|
|
if not TSMFrameStackTooltip then
|
|
CreateFrame("GameTooltip", "TSMFrameStackTooltip", UIParent, "GameTooltipTemplate")
|
|
TSMFrameStackTooltip.highlightFrame = CreateFrame("Frame", nil, nil, TSM.IsShadowlands() and "BackdropTemplate" or nil)
|
|
TSMFrameStackTooltip.highlightFrame:SetBackdrop({ bgFile = "Interface\\Buttons\\WHITE8X8" })
|
|
TSMFrameStackTooltip.highlightFrame:SetBackdropColor(1, 0, 0, 0.3)
|
|
TSMFrameStackTooltip:Hide()
|
|
ScriptWrapper.Set(TSMFrameStackTooltip, "OnUpdate", private.OnUpdate)
|
|
end
|
|
if TSMFrameStackTooltip:IsVisible() then
|
|
TSMFrameStackTooltip:Hide()
|
|
TSMFrameStackTooltip.highlightFrame:Hide()
|
|
else
|
|
TSMFrameStackTooltip.lastUpdate = 0
|
|
TSMFrameStackTooltip.altDown = nil
|
|
TSMFrameStackTooltip.index = 1
|
|
TSMFrameStackTooltip.numFrames = 0
|
|
TSMFrameStackTooltip:SetOwner(UIParent, "ANCHOR_NONE")
|
|
TSMFrameStackTooltip:SetPoint("TOPLEFT", 0, 0)
|
|
TSMFrameStackTooltip:AddLine("Loading...")
|
|
TSMFrameStackTooltip:Show()
|
|
TSMFrameStackTooltip.highlightFrame:Show()
|
|
end
|
|
end
|
|
|
|
|
|
|
|
-- ============================================================================
|
|
-- Private Helper Functions
|
|
-- ============================================================================
|
|
|
|
function private.OnUpdate(self)
|
|
if self.lastUpdate + 0.05 >= GetTime() then
|
|
return
|
|
end
|
|
self.lastUpdate = GetTime()
|
|
|
|
local numFrames = 0
|
|
for _, strata in ipairs(STRATA_ORDER) do
|
|
for _, strataFrame in ipairs(framesByStrata[strata]) do
|
|
local name = private.GetFrameName(strataFrame)
|
|
if not strmatch(name, "innerBorderFrame") then
|
|
numFrames = numFrames + 1
|
|
end
|
|
end
|
|
end
|
|
if numFrames ~= TSMFrameStackTooltip.numFrames then
|
|
TSMFrameStackTooltip.index = 1
|
|
TSMFrameStackTooltip.numFrames = numFrames
|
|
end
|
|
|
|
local leftAltDown = IsKeyDown("LALT")
|
|
local rightAltDown = IsKeyDown("RALT")
|
|
if not self.altDown and leftAltDown and not rightAltDown then
|
|
self.altDown = "LEFT"
|
|
if TSMFrameStackTooltip.index == TSMFrameStackTooltip.numFrames then
|
|
TSMFrameStackTooltip.index = 1
|
|
else
|
|
TSMFrameStackTooltip.index = TSMFrameStackTooltip.index + 1
|
|
end
|
|
elseif not self.altDown and not leftAltDown and rightAltDown then
|
|
self.altDown = "RIGHT"
|
|
if TSMFrameStackTooltip.index == 1 then
|
|
TSMFrameStackTooltip.index = TSMFrameStackTooltip.numFrames
|
|
else
|
|
TSMFrameStackTooltip.index = TSMFrameStackTooltip.index - 1
|
|
end
|
|
elseif self.altDown == "LEFT" and not leftAltDown then
|
|
self.altDown = nil
|
|
elseif self.altDown == "RIGHT" and not rightAltDown then
|
|
self.altDown = nil
|
|
end
|
|
|
|
for _, strata in ipairs(STRATA_ORDER) do
|
|
wipe(framesByStrata[strata])
|
|
end
|
|
|
|
local frame = EnumerateFrames()
|
|
while frame do
|
|
if frame ~= self.highlightFrame and not frame:IsForbidden() and frame:IsVisible() and MouseIsOver(frame) then
|
|
tinsert(framesByStrata[frame:GetFrameStrata()], frame)
|
|
for _, region in Vararg.Iterator(frame:GetRegions()) do
|
|
if region:IsObjectType("Texture") and not region:IsForbidden() and region:IsVisible() and MouseIsOver(region) and UIElements.GetByFrame(region) then
|
|
tinsert(framesByStrata[frame:GetFrameStrata()], region)
|
|
end
|
|
end
|
|
end
|
|
frame = EnumerateFrames(frame)
|
|
end
|
|
|
|
self:ClearLines()
|
|
self:AddDoubleLine("TSM Frame Stack", format("%0.2f, %0.2f", GetCursorPosition()))
|
|
local currentIndex = 1
|
|
local topFrame = nil
|
|
for _, strata in ipairs(STRATA_ORDER) do
|
|
if #framesByStrata[strata] > 0 then
|
|
sort(framesByStrata[strata], private.FrameLevelSortFunction)
|
|
self:AddLine(strata, 0.6, 0.6, 1)
|
|
for _, strataFrame in ipairs(framesByStrata[strata]) do
|
|
local isTexture = strataFrame:IsObjectType("Texture")
|
|
local level = (isTexture and strataFrame:GetParent() or strataFrame):GetFrameLevel()
|
|
local width = strataFrame:GetWidth()
|
|
local height = strataFrame:GetHeight()
|
|
local mouseEnabled = not isTexture and strataFrame:IsMouseEnabled()
|
|
local name = private.GetFrameName(strataFrame)
|
|
local isIndexedFrame = false
|
|
if not strmatch(name, "innerBorderFrame") then
|
|
if not topFrame and currentIndex == self.index then
|
|
topFrame = strataFrame
|
|
isIndexedFrame = true
|
|
end
|
|
currentIndex = currentIndex + 1
|
|
end
|
|
local text = format(" <%d%s> %s (%d, %d)", level, isTexture and "+" or "", name, Math.Round(width), Math.Round(height))
|
|
if isIndexedFrame then
|
|
self:AddLine(text, 0.9, 0.9, 0.5)
|
|
local element = UIElements.GetByFrame(strataFrame)
|
|
if element then
|
|
for _, k in ipairs(ELEMENT_STYLE_KEYS) do
|
|
local v = element[k]
|
|
if v ~= nil then
|
|
local vStr = private.GetStyleValueStr(v)
|
|
if vStr then
|
|
self:AddLine(format(" %s = %s", tostring(k), vStr), 0.7, 0.7, 0.7)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
elseif mouseEnabled then
|
|
self:AddLine(text, 0.6, 1, 1)
|
|
else
|
|
self:AddLine(text, 0.9, 0.9, 0.9)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
self.highlightFrame:ClearAllPoints()
|
|
self.highlightFrame:SetAllPoints(topFrame)
|
|
self.highlightFrame:SetFrameStrata("TOOLTIP")
|
|
self:Show()
|
|
end
|
|
|
|
function private.FrameLevelSortFunction(a, b)
|
|
local aLevel = a:IsObjectType("Texture") and (a:GetParent():GetFrameLevel() + 0.1) or a:GetFrameLevel()
|
|
local bLevel = b:IsObjectType("Texture") and (b:GetParent():GetFrameLevel() + 0.1) or b:GetFrameLevel()
|
|
return aLevel > bLevel
|
|
end
|
|
|
|
function private.TableValueSearch(tbl, searchValue, currentKey, visited)
|
|
visited = visited or {}
|
|
for key, value in pairs(tbl) do
|
|
if value == searchValue then
|
|
return (currentKey and (currentKey..".") or "")..key
|
|
elseif type(value) == "table" and (not value.__isa or value:__isa(TSM.UI.Element)) and not visited[value] then
|
|
visited[value] = true
|
|
local result = private.TableValueSearch(value, searchValue, (currentKey and (currentKey..".") or "")..key, visited)
|
|
if result then
|
|
return result
|
|
end
|
|
end
|
|
end
|
|
for _, key in ipairs(ELEMENT_ATTR_KEYS) do
|
|
local value = tbl[key]
|
|
if value == searchValue then
|
|
return (currentKey and (currentKey..".") or "")..key
|
|
elseif type(value) == "table" and (not value.__isa or value:__isa(TSM.UI.Element)) and not visited[value] then
|
|
visited[value] = true
|
|
local result = private.TableValueSearch(value, searchValue, (currentKey and (currentKey..".") or "")..key, visited)
|
|
if result then
|
|
return result
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function private.GetFrameNodeInfo(frame)
|
|
local globalName = not frame:IsObjectType("Texture") and frame:GetName()
|
|
if globalName and not strmatch(globalName, "^TSM_UI_ELEMENT:") then
|
|
return globalName, frame:GetParent()
|
|
end
|
|
|
|
local parent = frame:GetParent()
|
|
local element = UIElements.GetByFrame(frame)
|
|
if element then
|
|
return element._id, parent
|
|
end
|
|
|
|
if parent then
|
|
-- check if this exists as an attribute of the parent table
|
|
local parentKey = Table.KeyByValue(parent, frame)
|
|
if parentKey then
|
|
return tostring(parentKey), parent
|
|
end
|
|
|
|
-- find the nearest element to which this frame belongs
|
|
local parentElement = nil
|
|
local testFrame = parent
|
|
while testFrame and not parentElement do
|
|
parentElement = UIElements.GetByFrame(testFrame)
|
|
testFrame = testFrame:GetParent()
|
|
end
|
|
if parentElement then
|
|
-- check if this exists as an attribute of this element
|
|
local tableKey = private.TableValueSearch(parentElement, frame)
|
|
if tableKey then
|
|
return tableKey, parentElement._frame
|
|
end
|
|
end
|
|
end
|
|
|
|
return nil, parent
|
|
end
|
|
|
|
function private.GetFrameName(frame)
|
|
local name, parent = private.GetFrameNodeInfo(frame)
|
|
local parentName = parent and (private.GetFrameName(parent)..".") or ""
|
|
name = name or gsub(tostring(frame), ": ?0*", ":")
|
|
return parentName..name
|
|
end
|
|
|
|
function private.GetStyleValueStr(value)
|
|
for key in pairs(COLOR_KEYS) do
|
|
if value == Theme.GetColor(key) then
|
|
return "ThemeColor<"..key..">"
|
|
end
|
|
end
|
|
for key in pairs(FEEDBACK_COLOR_KEYS) do
|
|
if value == Theme.GetFeedbackColor(key) then
|
|
return "ThemeColor<"..key..">"
|
|
end
|
|
end
|
|
if value == Theme.GetBlizzardColor() then
|
|
return "ThemeColor<BLIZZARD>"
|
|
end
|
|
for key in pairs(FONT_KEYS) do
|
|
if value == Theme.GetFont(key) then
|
|
return "ThemeFont<"..key..">"
|
|
end
|
|
end
|
|
if type(value) == "string" then
|
|
return "\""..value.."\""
|
|
elseif value ~= false then
|
|
return tostring(value)
|
|
end
|
|
return nil
|
|
end
|