From 29a8a624d1f44e93f6f4738390c2e3e155ee5cec Mon Sep 17 00:00:00 2001 From: Mr_Rosh Date: Sat, 24 Oct 2026 20:23:46 +0300 Subject: [PATCH] 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. --- README.md | 10 + pfUI-CustomMedia-bars.lua | 2 +- pfUI-CustomMedia-buttons.lua | 507 ++++++++++++++++---------------- pfUI-CustomMedia-dropdowns.lua | 11 +- pfUI-CustomMedia-gryphons.lua | 416 +++++++++++++------------- pfUI-CustomMedia-staticbars.lua | 7 + pfUI-CustomMedia-tbc.toc | 5 +- pfUI-CustomMedia.toc | 5 +- 8 files changed, 499 insertions(+), 464 deletions(-) diff --git a/README.md b/README.md index ef803f0..d17efc4 100644 --- a/README.md +++ b/README.md @@ -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. diff --git a/pfUI-CustomMedia-bars.lua b/pfUI-CustomMedia-bars.lua index 5acbc2d..45419aa 100644 --- a/pfUI-CustomMedia-bars.lua +++ b/pfUI-CustomMedia-bars.lua @@ -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)) diff --git a/pfUI-CustomMedia-buttons.lua b/pfUI-CustomMedia-buttons.lua index 14d328f..9f5f0a1 100644 --- a/pfUI-CustomMedia-buttons.lua +++ b/pfUI-CustomMedia-buttons.lua @@ -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) diff --git a/pfUI-CustomMedia-dropdowns.lua b/pfUI-CustomMedia-dropdowns.lua index 2f696de..7d152a5 100644 --- a/pfUI-CustomMedia-dropdowns.lua +++ b/pfUI-CustomMedia-dropdowns.lua @@ -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) diff --git a/pfUI-CustomMedia-gryphons.lua b/pfUI-CustomMedia-gryphons.lua index 0101aeb..a140a2a 100644 --- a/pfUI-CustomMedia-gryphons.lua +++ b/pfUI-CustomMedia-gryphons.lua @@ -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 diff --git a/pfUI-CustomMedia-staticbars.lua b/pfUI-CustomMedia-staticbars.lua index 6c53ea3..5a6536f 100644 --- a/pfUI-CustomMedia-staticbars.lua +++ b/pfUI-CustomMedia-staticbars.lua @@ -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) diff --git a/pfUI-CustomMedia-tbc.toc b/pfUI-CustomMedia-tbc.toc index baaa6dc..80940ca 100644 --- a/pfUI-CustomMedia-tbc.toc +++ b/pfUI-CustomMedia-tbc.toc @@ -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 diff --git a/pfUI-CustomMedia.toc b/pfUI-CustomMedia.toc index 5672c4c..69c9308 100644 --- a/pfUI-CustomMedia.toc +++ b/pfUI-CustomMedia.toc @@ -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