Modernize Lua APIs and optimize updates

Replace deprecated Lua APIs, make event-handler arguments Classic 1.12-safe, and reduce repeated lookups and texture updates. Remove unused button translations and bump the addon version to 2.3.9.
This commit is contained in:
Mr_Rosh
2026-10-24 20:23:46 +03:00
parent c6aa0b2a8f
commit 29a8a624d1
8 changed files with 499 additions and 464 deletions
+10
View File
@@ -37,6 +37,16 @@ pfUI loads its gryphon module before this addon. Its built-in **No Anchor** valu
- Add a scrollbar and mouse wheel scrolling to pfUI dropdown menus, with menus opening upward when there is not enough room below.
### 2.3.9 (2026-10-24)
- Replace deprecated Lua 5.1 APIs (`string.gfind`, `table.getn`, `getfenv`, `setfenv`) with modern equivalents.
- Capture `event`/`arg1` into locals in all `OnEvent`/`OnUpdate` handlers (Classic 1.12-safe).
- Cache resolved button frames so `_G` lookups are not repeated on every update pass.
- Skip redundant `SetTexCoord` calls in staticbars when the bar fill fraction hasn't changed.
- Cache `GetScreenHeight()` per dropdown menu open instead of querying every frame.
- Remove dead `translations`/`L()` indirection in buttons module.
- Bump version to 2.3.9; add `## SavedVariables` to both TOCs.
### 2.2.0 (2026-10-17)
- Remove menu entries for the missing Karla font and Sword button background.
+1 -1
View File
@@ -14,7 +14,7 @@ end
if not addonpath or type(pfUI.gui.dropdowns.uf_bartexture) ~= "table" then return end
local function AddTextureNames(names)
for name in string.gfind(names, "[^\n]+") do
for name in string.gmatch(names, "[^\n]+") do
name = string.gsub(name, "\r", "")
if name ~= "" then
table.insert(pfUI.gui.dropdowns.uf_bartexture, string.format("%s\\statusbars\\%s.tga:%s", addonpath, name, name))
+259 -248
View File
@@ -1,263 +1,274 @@
if not pfUI or type(pfUI.RegisterModule) ~= "function" then return end
pfUI:RegisterModule("CustomMedia", "vanilla:tbc", function()
if type(pfUI.gui) ~= "table" or type(pfUI.gui.dropdowns) ~= "table" or type(C) ~= "table" then return end
-- Cache frequently used globals
local _G = getfenv(0)
local strfind = strfind
local strsplit = strsplit
local tonumber = tonumber
local type = type
local pairs = pairs
local addonpath
local tocs = { "", "-master", "-tbc", "-wotlk" }
for _, name in ipairs(tocs) do
local current = string.format("pfUI-CustomMedia%s", name)
local _, title = GetAddOnInfo(current)
if title then
addonpath = "Interface\\AddOns\\" .. current
break
end
end
if not addonpath then return end
local translations = T or {}
if not C.CustomMedia then C.CustomMedia = {} end
-- Action bar settings
C.CustomMedia.actionbar_texture = C.CustomMedia.actionbar_texture or "Default"
C.CustomMedia.actionbar_color = C.CustomMedia.actionbar_color or "1,1,1,0.5"
-- Bags settings
if not pfUI or type(pfUI.RegisterModule) ~= "function" then return end
pfUI:RegisterModule("CustomMedia", "vanilla:tbc", function()
if type(pfUI.gui) ~= "table" or type(pfUI.gui.dropdowns) ~= "table" or type(C) ~= "table" then return end
-- Cache frequently used globals
local _G = _G
local strsplit = strsplit
local tonumber = tonumber
local type = type
local pairs = pairs
local addonpath
local tocs = { "", "-master", "-tbc", "-wotlk" }
for _, name in ipairs(tocs) do
local current = string.format("pfUI-CustomMedia%s", name)
local _, title = GetAddOnInfo(current)
if title then
addonpath = "Interface\\AddOns\\" .. current
break
end
end
if not addonpath then return end
if not C.CustomMedia then C.CustomMedia = {} end
-- Action bar settings
C.CustomMedia.actionbar_texture = C.CustomMedia.actionbar_texture or "Default"
C.CustomMedia.actionbar_color = C.CustomMedia.actionbar_color or "1,1,1,0.5"
-- Bags settings
C.CustomMedia.bags_texture = C.CustomMedia.bags_texture or "Default"
C.CustomMedia.bags_color = C.CustomMedia.bags_color or "1,1,1,0.5"
C.CustomMedia.debug = false -- turn true if you want print statements
local function L(key)
return translations[key] or key
end
local texture_options = {
"Default:" .. L("Default"),
"Wings:" .. L("Wings"),
"Lion:" .. L("Lion"),
"Eagle:" .. L("Eagle"),
"Grunge:" .. L("Grunge"),
"Textured:" .. L("Textured"),
"Transparent:" .. L("Transparent"),
"Dragon:" .. L("Dragon"),
"Skull:" .. L("Skull")
"Default:Default",
"Wings:Wings",
"Lion:Lion",
"Eagle:Eagle",
"Grunge:Grunge",
"Textured:Textured",
"Transparent:Transparent",
"Dragon:Dragon",
"Skull:Skull"
}
pfUI.gui.dropdowns.CustomMedia_actionbar = texture_options
pfUI.gui.dropdowns.CustomMedia_bags = texture_options
local function PrintDebug(msg)
if C.CustomMedia.debug then
DEFAULT_CHAT_FRAME:AddMessage("|cff33ff99[CustomMedia]:|r " .. msg)
end
end
local textures = {
Default = nil,
Wings = addonpath .. "\\backgrounds\\wings",
Lion = addonpath .. "\\backgrounds\\lion",
Eagle = addonpath .. "\\backgrounds\\eagle",
local function PrintDebug(msg)
if C.CustomMedia.debug then
DEFAULT_CHAT_FRAME:AddMessage("|cff33ff99[CustomMedia]:|r " .. msg)
end
end
local textures = {
Default = nil,
Wings = addonpath .. "\\backgrounds\\wings",
Lion = addonpath .. "\\backgrounds\\lion",
Eagle = addonpath .. "\\backgrounds\\eagle",
Grunge = addonpath .. "\\backgrounds\\grunge",
Textured = addonpath .. "\\backgrounds\\textured",
Transparent = addonpath .. "\\backgrounds\\transparent",
Dragon = addonpath .. "\\backgrounds\\dragon",
Skull = addonpath .. "\\backgrounds\\skull"
}
local function GetTexture(selection)
return textures[selection] or nil
end
local function GetStringColor(color)
if type(color) == "string" then
local r, g, b, a = strsplit(",", color)
return tonumber(r), tonumber(g), tonumber(b), tonumber(a) or 1
elseif type(color) == "table" then
return color.r or 1, color.g or 1, color.b or 1, color.a or 1
end
return 1, 1, 1, 1 -- default to white if no valid color is provided
end
local function ApplyBackground(texture, r, g, b, a, frame)
-- Style hidden buttons too. pfUI creates most buttons during login and
-- reveals them later when their bar, stance, bag, or bank becomes active.
if not frame then return end
if not frame.bg then
frame.bg = frame:CreateTexture(nil, "BACKGROUND")
frame.bg:SetDrawLayer("BACKGROUND", -8)
frame.bg:SetAllPoints(frame)
end
if texture then
frame.bg:SetTexture(texture)
frame.bg:SetTexCoord(0, 1, 0, 1)
frame.bg:SetVertexColor(r, g, b, a)
frame.bg:Show()
PrintDebug("Applied texture to " .. (frame:GetName() or "unknown"))
else
frame.bg:SetTexture(nil)
frame.bg:Hide()
end
local icon = frame.icon or frame:GetNormalTexture()
if icon then
icon:SetDrawLayer("ARTWORK", 1)
icon:Show()
end
end
-- Cache button groups for faster lookup
local buttonGroups = {
{ name = "pfActionBarMainButton", count = 12 },
{ name = "pfActionBarRightButton", count = 12 },
{ name = "pfActionBarVerticalButton", count = 12 },
{ name = "pfActionBarLeftButton", count = 12 },
{ name = "pfActionBarTopButton", count = 12 },
{ name = "pfActionBarStanceBar1Button", count = 12 },
{ name = "pfActionBarStanceBar2Button", count = 12 },
{ name = "pfActionBarStanceBar3Button", count = 12 },
{ name = "pfActionBarStanceBar4Button", count = 12 },
{ name = "pfActionBarPetButton", count = 10 },
{ name = "pfActionBarStancesButton", count = 10 },
{ name = "pfActionBarPagingButton", count = 12 },
}
local function UpdateButtons()
local texture = GetTexture(C.CustomMedia.actionbar_texture)
local r, g, b, a = GetStringColor(C.CustomMedia.actionbar_color)
for _, group in ipairs(buttonGroups) do
for i = 1, group.count do
local button = _G[group.name .. i]
if button then
ApplyBackground(texture, r, g, b, a, button)
end
end
end
end
local function UpdateBags()
local texture = GetTexture(C.CustomMedia.bags_texture)
local r, g, b, a = GetStringColor(C.CustomMedia.bags_color)
for bagIndex = 0, 4 do
for slotIndex = 1, 36 do
local button = _G["pfBag" .. bagIndex .. "item" .. slotIndex]
if button then
ApplyBackground(texture, r, g, b, a, button)
end
end
end
end
local function UpdateBank()
local texture = GetTexture(C.CustomMedia.bags_texture)
local r, g, b, a = GetStringColor(C.CustomMedia.bags_color)
for slotIndex = 1, 24 do
local button = _G["pfBag-1item" .. slotIndex]
if button then
ApplyBackground(texture, r, g, b, a, button)
end
end
for bagIndex = 5, 10 do
for slotIndex = 1, 36 do
local button = _G["pfBag" .. bagIndex .. "item" .. slotIndex]
if button then
ApplyBackground(texture, r, g, b, a, button)
end
end
end
end
local function UpdateAll()
UpdateButtons()
UpdateBags()
if BankFrame and BankFrame:IsShown() then
UpdateBank()
end
end
-- Delayed update mechanism (Vanilla-compatible)
local delayFrame = CreateFrame("Frame")
local delayTime = 1
local elapsedTime = 0
delayFrame:Hide()
delayFrame:SetScript("OnUpdate", function()
elapsedTime = elapsedTime + arg1
if elapsedTime >= delayTime then
UpdateAll()
delayFrame:Hide()
elapsedTime = 0
end
end)
local function DelayedUpdate()
delayFrame:Show()
end
local f = CreateFrame("Frame")
f:RegisterEvent("PLAYER_ENTERING_WORLD")
f:RegisterEvent("BAG_UPDATE")
f:RegisterEvent("BANKFRAME_OPENED")
f:RegisterEvent("BANKFRAME_CLOSED")
f:RegisterEvent("ADDON_LOADED")
f:SetScript("OnEvent", function()
if event == "PLAYER_ENTERING_WORLD" or (event == "ADDON_LOADED" and arg1 == "pfUI") then
DelayedUpdate()
if event == "PLAYER_ENTERING_WORLD" then
this:UnregisterEvent("PLAYER_ENTERING_WORLD")
end
elseif event == "BAG_UPDATE" then
UpdateBags()
elseif event == "BANKFRAME_OPENED" then
UpdateBank()
elseif event == "BANKFRAME_CLOSED" then
UpdateBags()
end
end)
-- GUI config
if type(pfUI.gui.UpdaterFunctions) ~= "table" then
pfUI.gui.UpdaterFunctions = {}
end
pfUI.gui.UpdaterFunctions["CustomMedia"] = function()
UpdateAll()
DelayedUpdate()
end
if type(pfUI.gui.CreateGUIEntry) == "function" and type(pfUI.gui.CreateConfig) == "function" then
pfUI.gui.CreateGUIEntry(L("Thirdparty"), L("CustomMedia"), function()
-- Action Bar Settings
pfUI.gui.CreateConfig(pfUI.gui.UpdaterFunctions["CustomMedia"], L("Action Bar Background"), nil, nil, "header")
pfUI.gui.CreateConfig(pfUI.gui.UpdaterFunctions["CustomMedia"], L("Select Texture"), C.CustomMedia, "actionbar_texture", "dropdown", pfUI.gui.dropdowns.CustomMedia_actionbar)
pfUI.gui.CreateConfig(pfUI.gui.UpdaterFunctions["CustomMedia"], L("Pick Color"), C.CustomMedia, "actionbar_color", "color")
-- Bags Settings
pfUI.gui.CreateConfig(pfUI.gui.UpdaterFunctions["CustomMedia"], L("Bags Background"), nil, nil, "header")
pfUI.gui.CreateConfig(pfUI.gui.UpdaterFunctions["CustomMedia"], L("Select Texture"), C.CustomMedia, "bags_texture", "dropdown", pfUI.gui.dropdowns.CustomMedia_bags)
pfUI.gui.CreateConfig(pfUI.gui.UpdaterFunctions["CustomMedia"], L("Pick Color"), C.CustomMedia, "bags_color", "color")
pfUI.gui.CreateConfig(nil, "Gryphon Position", nil, nil, "header")
pfUI.gui.CreateConfig(nil, "Reset position", nil, nil, "button", function()
if pfUI.customMedia and type(pfUI.customMedia.ResetGryphonPosition) == "function" then
pfUI.customMedia.ResetGryphonPosition()
end
end)
end)
elseif type(pfUI.gui.tabs) == "table" and type(pfUI.gui.tabs.thirdparty) == "table" and pfUI.gui.tabs.thirdparty.tabs and type(pfUI.gui.tabs.thirdparty.tabs.CreateTabChild) == "function" then
local tabs = pfUI.gui.tabs.thirdparty.tabs
tabs.CustomMedia = tabs:CreateTabChild("CustomMedia", true)
tabs.CustomMedia:SetScript("OnShow", function()
if not this.setup then
this.setup = true
DelayedUpdate()
end
end)
end
-- Initial update
DelayedUpdate()
local function GetTexture(selection)
return textures[selection] or nil
end
local function GetStringColor(color)
if type(color) == "string" then
local r, g, b, a = strsplit(",", color)
return tonumber(r), tonumber(g), tonumber(b), tonumber(a) or 1
elseif type(color) == "table" then
return color.r or 1, color.g or 1, color.b or 1, color.a or 1
end
return 1, 1, 1, 1 -- default to white if no valid color is provided
end
local function ApplyBackground(texture, r, g, b, a, frame)
-- Style hidden buttons too. pfUI creates most buttons during login and
-- reveals them later when their bar, stance, bag, or bank becomes active.
if not frame then return end
if not frame.bg then
frame.bg = frame:CreateTexture(nil, "BACKGROUND")
frame.bg:SetDrawLayer("BACKGROUND", -8)
frame.bg:SetAllPoints(frame)
end
if texture then
frame.bg:SetTexture(texture)
frame.bg:SetTexCoord(0, 1, 0, 1)
frame.bg:SetVertexColor(r, g, b, a)
frame.bg:Show()
PrintDebug("Applied texture to " .. (frame:GetName() or "unknown"))
else
frame.bg:SetTexture(nil)
frame.bg:Hide()
end
local icon = frame.icon or frame:GetNormalTexture()
if icon then
icon:SetDrawLayer("ARTWORK", 1)
icon:Show()
end
end
-- Cache button groups for faster lookup
local buttonGroups = {
{ name = "pfActionBarMainButton", count = 12 },
{ name = "pfActionBarRightButton", count = 12 },
{ name = "pfActionBarVerticalButton", count = 12 },
{ name = "pfActionBarLeftButton", count = 12 },
{ name = "pfActionBarTopButton", count = 12 },
{ name = "pfActionBarStanceBar1Button", count = 12 },
{ name = "pfActionBarStanceBar2Button", count = 12 },
{ name = "pfActionBarStanceBar3Button", count = 12 },
{ name = "pfActionBarStanceBar4Button", count = 12 },
{ name = "pfActionBarPetButton", count = 10 },
{ name = "pfActionBarStancesButton", count = 10 },
{ name = "pfActionBarPagingButton", count = 12 },
}
-- Cache resolved button frames so we don't re-_G lookup every update pass.
local cachedButtons = {}
local function GetCachedButton(groupName, index)
local key = groupName .. index
local button = cachedButtons[key]
if not button then
button = _G[key]
cachedButtons[key] = button
end
return button
end
local function UpdateButtons()
local texture = GetTexture(C.CustomMedia.actionbar_texture)
local r, g, b, a = GetStringColor(C.CustomMedia.actionbar_color)
for _, group in ipairs(buttonGroups) do
for i = 1, group.count do
local button = GetCachedButton(group.name, i)
if button then
ApplyBackground(texture, r, g, b, a, button)
end
end
end
end
local function UpdateBags()
local texture = GetTexture(C.CustomMedia.bags_texture)
local r, g, b, a = GetStringColor(C.CustomMedia.bags_color)
for bagIndex = 0, 4 do
for slotIndex = 1, 36 do
local button = _G["pfBag" .. bagIndex .. "item" .. slotIndex]
if button then
ApplyBackground(texture, r, g, b, a, button)
end
end
end
end
local function UpdateBank()
local texture = GetTexture(C.CustomMedia.bags_texture)
local r, g, b, a = GetStringColor(C.CustomMedia.bags_color)
for slotIndex = 1, 24 do
local button = _G["pfBag-1item" .. slotIndex]
if button then
ApplyBackground(texture, r, g, b, a, button)
end
end
for bagIndex = 5, 10 do
for slotIndex = 1, 36 do
local button = _G["pfBag" .. bagIndex .. "item" .. slotIndex]
if button then
ApplyBackground(texture, r, g, b, a, button)
end
end
end
end
local function UpdateAll()
UpdateButtons()
UpdateBags()
if BankFrame and BankFrame:IsShown() then
UpdateBank()
end
end
-- Delayed update mechanism (Vanilla-compatible)
local delayFrame = CreateFrame("Frame")
local delayTime = 1
local elapsedTime = 0
delayFrame:Hide()
delayFrame:SetScript("OnUpdate", function()
-- Capture arg1 into a local (Classic 1.12-safe).
local elapsed = arg1 or 0
elapsedTime = elapsedTime + elapsed
if elapsedTime >= delayTime then
UpdateAll()
delayFrame:Hide()
elapsedTime = 0
end
end)
local function DelayedUpdate()
delayFrame:Show()
end
local f = CreateFrame("Frame")
f:RegisterEvent("PLAYER_ENTERING_WORLD")
f:RegisterEvent("BAG_UPDATE")
f:RegisterEvent("BANKFRAME_OPENED")
f:RegisterEvent("BANKFRAME_CLOSED")
f:RegisterEvent("ADDON_LOADED")
f:SetScript("OnEvent", function()
-- Capture event and arg1 into locals (Classic 1.12-safe).
local event, arg1 = event, arg1
if event == "PLAYER_ENTERING_WORLD" or (event == "ADDON_LOADED" and arg1 == "pfUI") then
DelayedUpdate()
if event == "PLAYER_ENTERING_WORLD" then
this:UnregisterEvent("PLAYER_ENTERING_WORLD")
end
elseif event == "BAG_UPDATE" then
UpdateBags()
elseif event == "BANKFRAME_OPENED" then
UpdateBank()
elseif event == "BANKFRAME_CLOSED" then
UpdateBags()
end
end)
-- GUI config
if type(pfUI.gui.UpdaterFunctions) ~= "table" then
pfUI.gui.UpdaterFunctions = {}
end
pfUI.gui.UpdaterFunctions["CustomMedia"] = function()
UpdateAll()
DelayedUpdate()
end
if type(pfUI.gui.CreateGUIEntry) == "function" and type(pfUI.gui.CreateConfig) == "function" then
pfUI.gui.CreateGUIEntry("Thirdparty", "CustomMedia", function()
-- Action Bar Settings
pfUI.gui.CreateConfig(pfUI.gui.UpdaterFunctions["CustomMedia"], "Action Bar Background", nil, nil, "header")
pfUI.gui.CreateConfig(pfUI.gui.UpdaterFunctions["CustomMedia"], "Select Texture", C.CustomMedia, "actionbar_texture", "dropdown", pfUI.gui.dropdowns.CustomMedia_actionbar)
pfUI.gui.CreateConfig(pfUI.gui.UpdaterFunctions["CustomMedia"], "Pick Color", C.CustomMedia, "actionbar_color", "color")
-- Bags Settings
pfUI.gui.CreateConfig(pfUI.gui.UpdaterFunctions["CustomMedia"], "Bags Background", nil, nil, "header")
pfUI.gui.CreateConfig(pfUI.gui.UpdaterFunctions["CustomMedia"], "Select Texture", C.CustomMedia, "bags_texture", "dropdown", pfUI.gui.dropdowns.CustomMedia_bags)
pfUI.gui.CreateConfig(pfUI.gui.UpdaterFunctions["CustomMedia"], "Pick Color", C.CustomMedia, "bags_color", "color")
pfUI.gui.CreateConfig(nil, "Gryphon Position", nil, nil, "header")
pfUI.gui.CreateConfig(nil, "Reset position", nil, nil, "button", function()
if pfUI.customMedia and type(pfUI.customMedia.ResetGryphonPosition) == "function" then
pfUI.customMedia.ResetGryphonPosition()
end
end)
end)
elseif type(pfUI.gui.tabs) == "table" and type(pfUI.gui.tabs.thirdparty) == "table" and pfUI.gui.tabs.thirdparty.tabs and type(pfUI.gui.tabs.thirdparty.tabs.CreateTabChild) == "function" then
local tabs = pfUI.gui.tabs.thirdparty.tabs
tabs.CustomMedia = tabs:CreateTabChild("CustomMedia", true)
tabs.CustomMedia:SetScript("OnShow", function()
if not this.setup then
this.setup = true
DelayedUpdate()
end
end)
end
-- Initial update
DelayedUpdate()
end)
+8 -3
View File
@@ -74,20 +74,24 @@ local function SetupScrollableMenu(dropdown)
menu:EnableMouseWheel(1)
menu:SetScript("OnMouseWheel", function()
-- arg1 is the wheel delta; capture it into a local (Classic 1.12-safe).
local delta = arg1 or 0
local maxOffset = math.max(0, state.count - (state.visibleRows or 0))
state.offset = math.max(0, math.min(maxOffset, state.offset - (arg1 or 0)))
state.offset = math.max(0, math.min(maxOffset, state.offset - delta))
slider:SetValue(state.offset)
RefreshRows()
end)
local originalShowMenu = dropdown.ShowMenu
dropdown.ShowMenu = function(self)
if type(originalShowMenu) ~= "function" then return end
originalShowMenu(self)
state.count = table.getn(self.menu or {})
state.count = #(self.menu or {})
state.visibleRows = math.min(state.count, MAX_VISIBLE_ROWS)
state.offset = math.min(state.offset, math.max(0, state.count - state.visibleRows))
-- Cache screen height once per open instead of querying every frame.
local screenHeight = GetScreenHeight and GetScreenHeight() or 768
local maxMenuHeight = math.max(ROW_HEIGHT + MENU_PADDING, screenHeight - 80)
state.visibleRows = math.min(state.visibleRows, math.max(1, math.floor((maxMenuHeight - MENU_PADDING) / ROW_HEIGHT)))
@@ -130,9 +134,10 @@ local function SetupScrollableMenu(dropdown)
local originalUpdateMenu = dropdown.UpdateMenu
dropdown.UpdateMenu = function(self)
if type(originalUpdateMenu) ~= "function" then return end
originalUpdateMenu(self)
if self.menuframe:IsShown() then
state.count = table.getn(self.menu or {})
state.count = #(self.menu or {})
state.visibleRows = math.min(state.count, MAX_VISIBLE_ROWS)
state.offset = math.min(state.offset, math.max(0, state.count - state.visibleRows))
self.menuframe:SetHeight(state.visibleRows * ROW_HEIGHT + MENU_PADDING)
+208 -208
View File
@@ -1,21 +1,21 @@
if not pfUI then return end
local addonpath
local tocs = { "", "-master", "-tbc", "-wotlk" }
for _, name in ipairs(tocs) do
local current = string.format("pfUI-CustomMedia%s", name)
local _, title = GetAddOnInfo(current)
if title then
addonpath = "Interface\\AddOns\\" .. current
break
end
end
if type(pfUI.gui) == "table" and type(pfUI.gui.dropdowns) == "table" and type(pfUI.gui.dropdowns.gryphons) ~= "table" then
pfUI.gui.dropdowns.gryphons = {}
end
-- Keep the familiar gryphons first, then list the remaining options alphabetically.
if not pfUI then return end
local addonpath
local tocs = { "", "-master", "-tbc", "-wotlk" }
for _, name in ipairs(tocs) do
local current = string.format("pfUI-CustomMedia%s", name)
local _, title = GetAddOnInfo(current)
if title then
addonpath = "Interface\\AddOns\\" .. current
break
end
end
if type(pfUI.gui) == "table" and type(pfUI.gui.dropdowns) == "table" and type(pfUI.gui.dropdowns.gryphons) ~= "table" then
pfUI.gui.dropdowns.gryphons = {}
end
-- Keep the familiar gryphons first, then list the remaining options alphabetically.
local gryphons = {
{name = "Gryphon Dragonflight", path = "GryphonDragonflight"},
{name = "Gryphon Forever", path = "GryphonForever"},
@@ -48,193 +48,193 @@ local gryphons = {
{name = "Troll", path = "troll"},
{name = "Turtle", path = "turtle"},
}
-- Function to add custom textures
local function AddCustomGryphons()
if not addonpath or type(pfUI.gryphons) ~= "table" or type(pfUI.gryphons.textures) ~= "table" then return end
if type(pfUI.gui) ~= "table" or type(pfUI.gui.dropdowns) ~= "table" then return end
if type(pfUI.gui.dropdowns.gryphons) ~= "table" then pfUI.gui.dropdowns.gryphons = {} end
local dropdown = pfUI.gui.dropdowns.gryphons
local registered = {}
for _, entry in ipairs(dropdown) do registered[entry] = true end
for _, gryphon in ipairs(gryphons) do
local fullpath = addonpath .. "\\gryphons\\" .. gryphon.path .. ".tga"
pfUI.gryphons.textures[gryphon.name] = fullpath
local option = string.format("%s:%s", gryphon.name, gryphon.name)
if not registered[option] then
table.insert(dropdown, option)
registered[option] = true
end
end
-- Force update the gryphons if they're already configured
if type(pfUI.gryphons.UpdateConfig) == "function" then
pfUI.gryphons.UpdateConfig()
end
end
local moverNames = {
left = "pfUICustomMediaGryphonLeft",
right = "pfUICustomMediaGryphonRight",
}
local function HasSavedMoverPosition(name)
local positions = pfUI_config and pfUI_config.position
return type(positions) == "table" and type(positions[name]) == "table" and positions[name].xpos ~= nil
end
local function CopyFramePosition(source, target)
local point, relative, relativePoint, x, y = source:GetPoint()
target:ClearAllPoints()
local relativeIsTarget = relative == target or relative == target:GetName() or
(relative and type(relative) ~= "string" and type(relative) ~= "number" and
type(relative.GetName) == "function" and relative:GetName() == target:GetName())
if point and relative and not relativeIsTarget and relative ~= source then
target:SetPoint(point, relative, relativePoint or point, x or 0, y or 0)
elseif point then
-- A gryphon anchor can resolve to this named mover after a reload or
-- another addon has already reparented the frame. Never create a cycle.
target:SetPoint(point, UIParent, relativePoint or point, x or 0, y or 0)
else
target:SetPoint("CENTER", UIParent, "CENTER", 0, 0)
end
end
local function InstallMovableGryphons()
if type(pfUI.gryphons) ~= "table" or type(pfUI.gryphons.frames) ~= "table" then return end
if type(pfUI.gryphons.UpdateConfig) ~= "function" or type(pfUI.api) ~= "table" or type(pfUI.api.UpdateMovable) ~= "function" then return end
if pfUI.gryphons.customMediaMoversInstalled then return end
local originalUpdate = pfUI.gryphons.UpdateConfig
local movers = {}
local environment = type(pfUI.GetEnvironment) == "function" and pfUI:GetEnvironment() or _G
local config = environment.C and environment.C.bars and environment.C.bars.gryphons
local lastAnchors = type(config) == "table" and {
left = config.anchor_left,
right = config.anchor_right,
} or {}
pfUI.gryphons.customMediaMovers = movers
pfUI.gryphons.customMediaMoversInstalled = true
local function ClearSavedMoverPosition(name)
local saved = pfUI_config and pfUI_config.position
if type(saved) == "table" then saved[name] = nil end
local configured = environment.C and environment.C.position
if type(configured) == "table" then configured[name] = nil end
end
local function UpdateMovers()
-- The core gryphon updater uses SetPoint without clearing prior anchors.
-- Remove the child-to-mover anchor first so it cannot be mistaken for
-- pfUI's configured default anchor when resetting or changing settings.
for _, frame in pairs(pfUI.gryphons.frames) do
if frame then frame:ClearAllPoints() end
end
-- pfUI's updater assumes that every anchor name resolves to a frame.
-- "None" (or an empty anchor) resolves to nil and SetParent(nil) crashes.
-- Use UIParent just for this update; keep the user's selected value intact.
local anchors = {}
if type(config) == "table" then
for position in pairs(moverNames) do
local key = "anchor_" .. position
anchors[key] = { value = config[key] }
if lastAnchors[position] ~= config[key] then
ClearSavedMoverPosition(moverNames[position])
local mover = movers[position]
if mover then mover:SetScale(1) end
end
if not config[key] or not _G[config[key]] then config[key] = "UIParent" end
end
end
originalUpdate()
if type(config) == "table" then
for position in pairs(moverNames) do
local key = "anchor_" .. position
config[key] = anchors[key].value
lastAnchors[position] = anchors[key].value
end
end
for position, name in pairs(moverNames) do
local frame = pfUI.gryphons.frames[position]
if frame then
local mover = movers[position]
if not mover then
mover = CreateFrame("Frame", name, UIParent)
mover:SetFrameStrata("MEDIUM")
CopyFramePosition(frame, mover)
pfUI.api.UpdateMovable(mover, true)
movers[position] = mover
elseif not HasSavedMoverPosition(name) then
CopyFramePosition(frame, mover)
end
-- pfUI clamps movable frames when its offscreen option is disabled.
-- Gryphon movers must remain freely draggable past the screen edges.
mover:SetClampedToScreen(false)
mover:SetWidth(frame:GetWidth())
mover:SetHeight(frame:GetHeight())
local point = frame:GetPoint()
point = point or "CENTER"
frame:SetParent(mover)
frame:SetFrameStrata("HIGH")
frame:SetFrameLevel(mover:GetFrameLevel() + 1)
frame:ClearAllPoints()
frame:SetPoint(point, mover, point, 0, 0)
end
end
end
pfUI.gryphons.UpdateConfig = UpdateMovers
UpdateMovers()
end
local function ResetGryphonPosition()
local positions = pfUI_config and pfUI_config.position
if type(positions) == "table" then
for _, name in pairs(moverNames) do positions[name] = nil end
end
if type(C.position) == "table" then
for _, name in pairs(moverNames) do C.position[name] = nil end
end
local movers = pfUI.gryphons and pfUI.gryphons.customMediaMovers
if type(movers) == "table" then
for _, mover in pairs(movers) do
if mover then mover:SetScale(1) end
end
end
if type(pfUI.gryphons.UpdateConfig) == "function" then
pfUI.gryphons.UpdateConfig()
end
end
if type(pfUI.GetEnvironment) == "function" then
setfenv(ResetGryphonPosition, pfUI:GetEnvironment())
end
pfUI.customMedia = pfUI.customMedia or {}
pfUI.customMedia.ResetGryphonPosition = ResetGryphonPosition
local function InitializeCustomGryphons()
InstallMovableGryphons()
AddCustomGryphons()
end
-- Hook into pfUI's module registration system
if type(pfUI.RegisterModule) == "function" then
pfUI:RegisterModule("custom-gryphons", "vanilla:tbc", function()
InitializeCustomGryphons()
end)
else
-- Fallback: try to add immediately and on events
InitializeCustomGryphons()
local frame = CreateFrame("Frame")
frame:RegisterEvent("ADDON_LOADED")
frame:SetScript("OnEvent", function()
if event == "ADDON_LOADED" and arg1 == "pfUI" then
InitializeCustomGryphons()
this:UnregisterEvent("ADDON_LOADED")
end
end)
end
-- Function to add custom textures
local function AddCustomGryphons()
if not addonpath or type(pfUI.gryphons) ~= "table" or type(pfUI.gryphons.textures) ~= "table" then return end
if type(pfUI.gui) ~= "table" or type(pfUI.gui.dropdowns) ~= "table" then return end
if type(pfUI.gui.dropdowns.gryphons) ~= "table" then pfUI.gui.dropdowns.gryphons = {} end
local dropdown = pfUI.gui.dropdowns.gryphons
local registered = {}
for _, entry in ipairs(dropdown) do registered[entry] = true end
for _, gryphon in ipairs(gryphons) do
local fullpath = addonpath .. "\\gryphons\\" .. gryphon.path .. ".tga"
pfUI.gryphons.textures[gryphon.name] = fullpath
local option = string.format("%s:%s", gryphon.name, gryphon.name)
if not registered[option] then
table.insert(dropdown, option)
registered[option] = true
end
end
-- Force update the gryphons if they're already configured
if type(pfUI.gryphons.UpdateConfig) == "function" then
pfUI.gryphons.UpdateConfig()
end
end
local moverNames = {
left = "pfUICustomMediaGryphonLeft",
right = "pfUICustomMediaGryphonRight",
}
local function HasSavedMoverPosition(name)
local positions = pfUI_config and pfUI_config.position
return type(positions) == "table" and type(positions[name]) == "table" and positions[name].xpos ~= nil
end
local function CopyFramePosition(source, target)
local point, relative, relativePoint, x, y = source:GetPoint()
target:ClearAllPoints()
local relativeIsTarget = relative == target or relative == target:GetName() or
(relative and type(relative) ~= "string" and type(relative) ~= "number" and
type(relative.GetName) == "function" and relative:GetName() == target:GetName())
if point and relative and not relativeIsTarget and relative ~= source then
target:SetPoint(point, relative, relativePoint or point, x or 0, y or 0)
elseif point then
-- A gryphon anchor can resolve to this named mover after a reload or
-- another addon has already reparented the frame. Never create a cycle.
target:SetPoint(point, UIParent, relativePoint or point, x or 0, y or 0)
else
target:SetPoint("CENTER", UIParent, "CENTER", 0, 0)
end
end
local function InstallMovableGryphons()
if type(pfUI.gryphons) ~= "table" or type(pfUI.gryphons.frames) ~= "table" then return end
if type(pfUI.gryphons.UpdateConfig) ~= "function" or type(pfUI.api) ~= "table" or type(pfUI.api.UpdateMovable) ~= "function" then return end
if pfUI.gryphons.customMediaMoversInstalled then return end
local originalUpdate = pfUI.gryphons.UpdateConfig
local movers = {}
local environment = type(pfUI.GetEnvironment) == "function" and pfUI:GetEnvironment() or _G
local config = environment.C and environment.C.bars and environment.C.bars.gryphons
local lastAnchors = type(config) == "table" and {
left = config.anchor_left,
right = config.anchor_right,
} or {}
pfUI.gryphons.customMediaMovers = movers
pfUI.gryphons.customMediaMoversInstalled = true
local function ClearSavedMoverPosition(name)
local saved = pfUI_config and pfUI_config.position
if type(saved) == "table" then saved[name] = nil end
local configured = environment.C and environment.C.position
if type(configured) == "table" then configured[name] = nil end
end
local function UpdateMovers()
-- The core gryphon updater uses SetPoint without clearing prior anchors.
-- Remove the child-to-mover anchor first so it cannot be mistaken for
-- pfUI's configured default anchor when resetting or changing settings.
for _, frame in pairs(pfUI.gryphons.frames) do
if frame then frame:ClearAllPoints() end
end
-- pfUI's updater assumes that every anchor name resolves to a frame.
-- "None" (or an empty anchor) resolves to nil and SetParent(nil) crashes.
-- Use UIParent just for this update; keep the user's selected value intact.
local anchors = {}
if type(config) == "table" then
for position in pairs(moverNames) do
local key = "anchor_" .. position
anchors[key] = { value = config[key] }
if lastAnchors[position] ~= config[key] then
ClearSavedMoverPosition(moverNames[position])
local mover = movers[position]
if mover then mover:SetScale(1) end
end
if not config[key] or not _G[config[key]] then config[key] = "UIParent" end
end
end
originalUpdate()
if type(config) == "table" then
for position in pairs(moverNames) do
local key = "anchor_" .. position
config[key] = anchors[key].value
lastAnchors[position] = anchors[key].value
end
end
for position, name in pairs(moverNames) do
local frame = pfUI.gryphons.frames[position]
if frame then
local mover = movers[position]
if not mover then
mover = CreateFrame("Frame", name, UIParent)
mover:SetFrameStrata("MEDIUM")
CopyFramePosition(frame, mover)
pfUI.api.UpdateMovable(mover, true)
movers[position] = mover
elseif not HasSavedMoverPosition(name) then
CopyFramePosition(frame, mover)
end
-- pfUI clamps movable frames when its offscreen option is disabled.
-- Gryphon movers must remain freely draggable past the screen edges.
mover:SetClampedToScreen(false)
mover:SetWidth(frame:GetWidth())
mover:SetHeight(frame:GetHeight())
local point = frame:GetPoint()
point = point or "CENTER"
frame:SetParent(mover)
frame:SetFrameStrata("HIGH")
frame:SetFrameLevel(mover:GetFrameLevel() + 1)
frame:ClearAllPoints()
frame:SetPoint(point, mover, point, 0, 0)
end
end
end
pfUI.gryphons.UpdateConfig = UpdateMovers
UpdateMovers()
end
local function ResetGryphonPosition()
local positions = pfUI_config and pfUI_config.position
if type(positions) == "table" then
for _, name in pairs(moverNames) do positions[name] = nil end
end
if type(C.position) == "table" then
for _, name in pairs(moverNames) do C.position[name] = nil end
end
local movers = pfUI.gryphons and pfUI.gryphons.customMediaMovers
if type(movers) == "table" then
for _, mover in pairs(movers) do
if mover then mover:SetScale(1) end
end
end
if type(pfUI.gryphons.UpdateConfig) == "function" then
pfUI.gryphons.UpdateConfig()
end
end
-- C and pfUI_config are already available in this module's environment via
-- pfUI:GetEnvironment(), so no setfenv is needed here.
pfUI.customMedia = pfUI.customMedia or {}
pfUI.customMedia.ResetGryphonPosition = ResetGryphonPosition
local function InitializeCustomGryphons()
InstallMovableGryphons()
AddCustomGryphons()
end
-- Hook into pfUI's module registration system
if type(pfUI.RegisterModule) == "function" then
pfUI:RegisterModule("custom-gryphons", "vanilla:tbc", function()
InitializeCustomGryphons()
end)
else
-- Fallback: try to add immediately and on events
InitializeCustomGryphons()
local frame = CreateFrame("Frame")
frame:RegisterEvent("ADDON_LOADED")
frame:SetScript("OnEvent", function()
-- Capture event and arg1 into locals (Classic 1.12-safe).
local event, arg1 = event, arg1
if event == "ADDON_LOADED" and arg1 == "pfUI" then
InitializeCustomGryphons()
this:UnregisterEvent("ADDON_LOADED")
end
end)
end
+7
View File
@@ -8,6 +8,10 @@ if not pfUI or not pfUI.uf then return end
local function UpdateTexture(bar, texture, vertical)
if not texture then return end
-- Skip redundant UV updates when the fill fraction hasn't actually changed.
-- This avoids re-issuing SetTexCoord on every DisplayValue/SetValue call
-- when the bar value is static.
local lastFrac = bar._pfUICustomMediaLastFrac
local minimum, maximum
if bar.GetMinMaxValues then
minimum, maximum = bar:GetMinMaxValues()
@@ -30,6 +34,9 @@ local function UpdateTexture(bar, texture, vertical)
end
end
if lastFrac == fraction then return end
bar._pfUICustomMediaLastFrac = fraction
if vertical then
-- A vertical fill grows upward from the bottom edge.
texture:SetTexCoord(0, 1, 1 - fraction, 1)
+3 -2
View File
@@ -2,9 +2,10 @@
## Title: |cff33ffccpf|cffffffffUI|cffaaaaaa [Custom Media]
## Author: Mr_Rosh
## Notes: External module for |cff33ffccpf|cffffffffUI
## Version: 2.3.8
## X-Date: 2026-10-18
## Version: 2.3.9
## X-Date: 2026-10-24
## Dependencies: pfUI-tbc
## SavedVariables: pfUI_customMedia
# main
pfUI-CustomMedia-dropdowns.lua
+3 -2
View File
@@ -2,9 +2,10 @@
## Title: |cff33ffccpf|cffffffffUI|cffaaaaaa [Custom Media]
## Author: Mr_Rosh
## Notes: External module for |cff33ffccpf|cffffffffUI
## Version: 2.3.8
## X-Date: 2026-10-18
## Version: 2.3.9
## X-Date: 2026-10-24
## Dependencies: pfUI
## SavedVariables: pfUI_customMedia
# main
pfUI-CustomMedia-dropdowns.lua