Files
2026-10-30 16:27:05 +00:00

419 lines
12 KiB
Lua

PTGuiComponent = {}
PTUtil.SetEnvironment(PTGuiComponent)
local _G = getfenv(0)
PTGuiComponent.__index = PTGuiComponent
-- A static flag to verify if this is a gui component
PTGuiComponent.IsPuppeteerGui = true
PTGuiComponent.TypeName = "BASE_COMPONENT"
-- The primary frame associated with the set of components
PTGuiComponent.Primary = nil
-- The raw frame associated with the component
PTGuiComponent.Frame = nil
-- All gui component instances associated with the component, including itself(named "Frame")
PTGuiComponent.Components = {}
-- Permanent frames cannot be recycled
PTGuiComponent.Permanent = false
PTGuiComponent.FrameCount = 0
function PTGuiComponent:Extend(typeName)
local obj = {}
setmetatable(obj, self)
obj.TypeName = typeName
obj.super = self
obj.__index = obj
return obj
end
-- Called when a component is acquired
function PTGuiComponent:OnAcquire()
self:Show()
end
-- Responsible for cleaning up a component, putting it in a default state
function PTGuiComponent:OnDispose()
self:Hide()
self:ClearAllPoints()
self:SetSize(0, 0)
self:SetParent(nil)
if self.HasScript and self:HasScript("OnClick") then
self:OnClick(nil)
end
if self.DisposeHandler then
self:DisposeHandler()
self.DisposeHandler = nil
end
end
function PTGuiComponent:Dispose()
if not self:IsPermanent() then -- Permanent components aren't recycled, but can try to hide themselves
PTGuiLib.Recycle(self)
end
self:OnDispose()
end
-- Set a special handler that is called when this component is being disposed.
-- Should be used for cleaning up things components don't normally clean up.
function PTGuiComponent:SetDisposeHandler(handler)
self.DisposeHandler = handler
return self
end
function PTGuiComponent:SetPermanent()
self.Permanent = true
return self
end
function PTGuiComponent:IsPermanent()
return self.Permanent
end
function PTGuiComponent:Type()
return self.TypeName
end
function PTGuiComponent:GenerateName()
self.FrameCount = self.FrameCount + 1
return "PTGui_"..self:Type()..self.FrameCount
end
function PTGuiComponent:SetHandle(frame)
self.Frame = frame
self:AddComponent("Frame", self)
frame.GuiInstance = self
self:SetPrimary()
return self
end
function PTGuiComponent:GetHandle()
return self.Frame
end
function PTGuiComponent:IsInstance()
return self.Frame ~= nil
end
function PTGuiComponent:IsPrimary()
return self.Primary == self.Frame
end
function PTGuiComponent:GetPrimary()
return self.Primary
end
-- Sets this component as the primary for all associated components
function PTGuiComponent:SetPrimary()
for _, component in pairs(self.Components) do
component.Primary = self
end
end
function PTGuiComponent:Import(returnSelf, ...)
self:ImportComponent(nil, returnSelf, arg)
end
function PTGuiComponent:ImportComponent(frameName, returnSelf, ...)
frameName = frameName or "Frame"
for _, import in ipairs(arg) do
if type(import) == "table" then
for _, import in ipairs(import) do
self:DoImport(frameName, returnSelf, import)
end
else
self:DoImport(frameName, returnSelf, import)
end
end
end
-- Instance imports are faster and static imports consume less memory.
-- Instance importing must be done after the component is added.
function PTGuiComponent:DoImport(frameName, returnSelf, import)
if self:IsInstance() then -- Prefer an instance import
local frame = self:GetComponent(frameName):GetHandle()
local func = frame[import]
if returnSelf then
self[import] = function(self, a1, a2, a3, a4, a5)
func(frame, a1, a2, a3, a4, a5)
return self
end
else
self[import] = function(self, a1, a2, a3, a4, a5)
return func(frame, a1, a2, a3, a4, a5)
end
end
elseif frameName == "Frame" then -- Optimized static import for the handle
if returnSelf then
self[import] = function(self, a1, a2, a3, a4, a5)
local frame = self.Frame
frame[import](frame, a1, a2, a3, a4, a5)
return self
end
else
self[import] = function(self, a1, a2, a3, a4, a5)
local frame = self.Frame
return frame[import](frame, a1, a2, a3, a4, a5)
end
end
else -- Static import for other components
if returnSelf then
self[import] = function(self, a1, a2, a3, a4, a5)
local frame = self.Components[frameName]:GetHandle()
frame[import](frame, a1, a2, a3, a4, a5)
return self
end
else
self[import] = function(self, a1, a2, a3, a4, a5)
local frame = self.Components[frameName]:GetHandle()
return frame[import](frame, a1, a2, a3, a4, a5)
end
end
end
end
function PTGuiComponent:CreateGetter(componentName, funcName)
self[funcName or ("Get"..componentName)] = function(self)
return self:GetComponent(componentName)
end
end
function PTGuiComponent:GetContainer()
return self.Frame
end
function PTGuiComponent:GetAnchor()
return self.Frame
end
function PTGuiComponent:AddComponent(name, component)
if self.Components == PTGuiComponent.Components then
self.Components = {}
end
self.Components[name] = component
end
function PTGuiComponent:GetComponent(name)
return self.Components[name]
end
function PTGuiComponent:GetComponents()
return self.Components
end
function PTGuiComponent:SetParent(obj)
if obj and obj.IsPuppeteerGui then
obj = obj:GetContainer()
end
self:GetHandle():SetParent(obj)
PTUtil.FixFrameLevels(self:GetHandle())
return self
end
function PTGuiComponent:SetSize(width, height)
self:SetWidth(width)
self:SetHeight(height)
return self
end
function PTGuiComponent:SetScript(scriptName, script, noSelf)
self:GetHandle():SetScript(scriptName, script and (noSelf and script or function() script(self) end) or nil)
return self
end
function PTGuiComponent:HookScript(scriptName, script)
local prevScript = self:GetScript(scriptName)
self:GetHandle():SetScript(scriptName, function()
if prevScript then
prevScript(self)
end
script(self)
end)
return self
end
function PTGuiComponent:OnClick(script, noSelf)
return self:SetScript("OnClick", script, noSelf)
end
function PTGuiComponent:SetPoint(point, relativeFrame, relativePoint, xOffset, yOffset)
if type(relativeFrame) == "table" and relativeFrame.IsPuppeteerGui then
relativeFrame = relativeFrame:GetAnchor()
end
self:GetHandle():SetPoint(point, relativeFrame, relativePoint, xOffset, yOffset)
return self
end
PTGuiComponent.BACKGROUND_TOOLTIP = 1
PTGuiComponent.BACKGROUND_DIALOG = 2
function PTGuiComponent:SetSimpleBackground(type, diff)
type = type or PTGuiComponent.BACKGROUND_TOOLTIP
local background
if type == PTGuiComponent.BACKGROUND_TOOLTIP then
background = {
frameBackdrop = {
bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
edgeSize = 11,
tile = true
},
frameBackdropColor = {0.09, 0.09, 0.19},
frameBorderColor = nil,
borderBackdrop = {
edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
edgeSize = 11,
tileSize = 11,
tile = true
},
borderBackdropColor = nil,
borderBorderColor = {0.8, 0.8, 0.8},
borderPadding = 2
}
elseif type == PTGuiComponent.BACKGROUND_DIALOG then
background = {
frameBackdrop = {
bgFile = "Interface\\DialogFrame\\UI-DialogBox-Background",
edgeSize = 32,
tile = true,
tileSize = 32
},
borderBackdrop = {
edgeFile = "Interface\\DialogFrame\\UI-DialogBox-Border",
edgeSize = 32,
tile = true,
tileSize = 32
},
borderPadding = 11
}
end
if diff then
for k, v in pairs(diff) do
background[k] = v
end
end
return self:SetBackground(background)
end
function PTGuiComponent:SetBackground(params)
local frame = self:GetHandle()
frame:SetBackdrop(nil)
frame:SetBackdropColor()
frame:SetBackdropBorderColor()
if frame.guiBorder then
frame.guiBorder:Hide()
frame.guiBorder:SetBackdrop(nil)
frame.guiBorder:SetBackdropColor()
frame.guiBorder:SetBackdropBorderColor()
end
if not params then
return self
end
if params.frameBackdrop then
frame:SetBackdrop(params.frameBackdrop)
if params.frameBackdropColor then
frame:SetBackdropColor(unpack(params.frameBackdropColor))
end
if params.frameBorderColor then
frame:SetBackdropColor(unpack(params.frameBorderColor))
end
end
if params.borderBackdrop then
local border = frame.guiBorder or CreateFrame("Frame", nil, frame)
frame.guiBorder = border
frame.guiBorder:Show()
local padding = params.borderPadding or 0
border:SetPoint("TOPLEFT", frame, "TOPLEFT", -padding, padding)
border:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", padding, -padding)
border:SetBackdrop(params.borderBackdrop)
border:SetFrameLevel(frame:GetFrameLevel())
if params.borderBackdropColor then
border:SetBackdropColor(unpack(params.borderBackdropColor))
end
if params.borderBorderColor then
border:SetBackdropBorderColor(unpack(params.borderBorderColor))
end
end
return self
end
-- TODO: Handle cleanup of tooltips for disposed components
local infoTooltip = CreateFrame("GameTooltip", "PTGuiInfoTooltip", UIParent, "GameTooltipTemplate")
local singleTextArray = {}
local function ShowTooltip(attachTo, texts)
infoTooltip:SetOwner(attachTo, "ANCHOR_RIGHT")
infoTooltip:SetPoint("RIGHT", attachTo, "LEFT", 0, 0)
if type(texts) == "string" then
singleTextArray[1] = texts
texts = singleTextArray
end
for i, text in ipairs(texts) do
if i ~= 1 then
text = PTUtil.Colorize(text, 1.0, 0.88, 0.3)
end
infoTooltip:AddLine(text)
_G["PTGuiInfoTooltipTextLeft"..i]:SetFont("Fonts\\FRIZQT__.TTF", i == 1 and 14 or 12, "OUTLINE")
end
infoTooltip:Show()
end
function PTGuiComponent:ApplyTooltip(...)
self:ApplyTooltipToAll(arg)
return self
end
function PTGuiComponent:ApplyTooltipTo(component, texts)
local primary = component:GetPrimary():GetHandle()
local frame = component:GetHandle()
frame:EnableMouse(true)
frame:SetScript("OnEnter", function()
ShowTooltip(primary, texts)
end)
frame:SetScript("OnLeave", function()
infoTooltip:Hide()
end)
end
local function flattenTexts(element, t)
if type(element) == "table" then
for _, e in ipairs(element) do
flattenTexts(e, t)
end
elseif type(element) == "string" then
table.insert(t, element)
end
return t
end
function PTGuiComponent:ApplyTooltipToAll(texts)
local primary = self:GetPrimary():GetHandle()
local texts = flattenTexts(texts, {})
local onEnter = function()
ShowTooltip(primary, texts)
end
local onLeave = function()
infoTooltip:Hide()
end
for _, component in pairs(self:GetComponents()) do
local frame = component:GetHandle()
if frame.EnableMouse and frame.HasScript and frame:HasScript("OnEnter") then
frame:EnableMouse(true)
frame:SetScript("OnEnter", onEnter)
frame:SetScript("OnLeave", onLeave)
end
end
end
PTGuiComponent:Import(true, "ClearAllPoints", "SetAllPoints", "SetWidth", "SetHeight", "Show", "Hide", "SetFrameLevel")
PTGuiComponent:Import(false, "GetWidth", "GetHeight", "GetName", "HasScript", "GetScript", "GetParent", "GetFrameLevel", "IsVisible", "IsShown")