mirror of
https://github.com/brues-code/pfUI.git
synced 2026-10-25 05:20:49 +00:00
Compare commits
4
Commits
65fcba6698
...
6144a32cab
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6144a32cab | ||
|
|
463563c9a9 | ||
|
|
3e551ed3c4 | ||
|
|
8eee766652 |
+104
@@ -0,0 +1,104 @@
|
||||
do
|
||||
-- ClassicAPI dependency check.
|
||||
-- pfUI relies pervasively on the modern C_* / SuperWoW / nameplate / focus
|
||||
-- API surface that ClassicAPI polyfills, so presence is required.
|
||||
local PFUI_CLASSIC_API_MIN = 11301 -- (X*10000 + Y*100 + Z)
|
||||
local PFUI_CLASSIC_API_LATEST = PFUI_CLASSIC_API_MIN
|
||||
local PFUI_CLASSIC_API_WEBSITE = "https://github.com/brues-code/ClassicAPI"
|
||||
local PFUI_CLASSIC_API_LATEST_URL = PFUI_CLASSIC_API_WEBSITE .. "/releases/latest"
|
||||
local function FormatVersion(packed)
|
||||
local x = math.floor(packed / 10000)
|
||||
local y = math.floor(math.mod(packed, 10000) / 100)
|
||||
local z = math.mod(packed, 100)
|
||||
return string.format("v%d.%d.%d", x, y, z)
|
||||
end
|
||||
if not CLASSIC_API_VERSION or CLASSIC_API_VERSION < PFUI_CLASSIC_API_MIN then
|
||||
local minVersion = FormatVersion(PFUI_CLASSIC_API_MIN)
|
||||
pfUI_disabled = true
|
||||
pfUI_locale = {}
|
||||
pfUI_profiles = {}
|
||||
pfUI_translation = {}
|
||||
|
||||
-- ClassicAPI is required. Rather than let the ~140 files that follow flood
|
||||
-- errors as they load, stand up an inert stub so everything no-ops:
|
||||
-- * modules/skins register their body into a no-op, so it never runs;
|
||||
-- * the setfenv'd api/lib files run inside `env`, where CreateFrame and
|
||||
-- any missing global (C_*, SuperWoW, ...) resolve to a null object --
|
||||
-- so no real frames or live OnUpdate/OnEvent handlers get created and
|
||||
-- missing API calls just return null instead of erroring.
|
||||
local null -- forward declaration so the metamethods can return it
|
||||
local nullmt = {
|
||||
__index = function() return null end,
|
||||
__newindex = function() end,
|
||||
__call = function() return null end,
|
||||
__concat = function() return "" end,
|
||||
__tostring = function() return "" end,
|
||||
}
|
||||
for _, op in ipairs({ "__add","__sub","__mul","__div","__mod","__pow","__unm" }) do
|
||||
nullmt[op] = function() return null end
|
||||
end
|
||||
for _, op in ipairs({ "__lt","__le","__eq" }) do nullmt[op] = function() return false end end
|
||||
null = setmetatable({}, nullmt)
|
||||
|
||||
local realG = getfenv(0)
|
||||
pfUI = setmetatable({}, { __index = function() return null end })
|
||||
pfUI.env = setmetatable({}, {
|
||||
__index = function(_, k)
|
||||
if k == "CreateFrame" then return function() return null end end
|
||||
local v = realG[k]
|
||||
if v ~= nil then return v end
|
||||
return null
|
||||
end,
|
||||
})
|
||||
function pfUI:RegisterModule(_, _, _) end
|
||||
function pfUI:RegisterSkin(_, _, _) end
|
||||
function pfUI:GetEnvironment() return pfUI.env end
|
||||
local detail
|
||||
if not CLASSIC_API_VERSION then
|
||||
detail = "The ClassicAPI DLL isn't loaded. The |cff33ffcc!!!ClassicAPI|r addon ships bundled with it -- delete your |cff33ffcc!!!ClassicAPI|r folder and install the latest release from:"
|
||||
else
|
||||
detail = "ClassicAPI " .. minVersion .. " or newer is required. Delete your |cff33ffcc!!!ClassicAPI|r folder and reinstall the latest release from:"
|
||||
end
|
||||
|
||||
local function ShowRequiredPopup()
|
||||
StaticPopupDialogs["PFUI_CLASSICAPI_REQUIRED"] = {
|
||||
text = "|cff33ffccpf|cffffffffUI|r has been disabled.\n\n" .. detail,
|
||||
button1 = OKAY,
|
||||
hasEditBox = 1,
|
||||
editBoxWidth = 280,
|
||||
timeout = 0,
|
||||
whileDead = 1,
|
||||
hideOnEscape = 1,
|
||||
preferredIndex = 3,
|
||||
OnShow = function()
|
||||
local editBox = getglobal(this:GetName().."EditBox")
|
||||
if editBox then
|
||||
editBox:SetText(PFUI_CLASSIC_API_LATEST_URL)
|
||||
editBox:HighlightText()
|
||||
editBox:SetFocus()
|
||||
end
|
||||
end,
|
||||
}
|
||||
StaticPopup_Show("PFUI_CLASSICAPI_REQUIRED")
|
||||
DEFAULT_CHAT_FRAME:AddMessage(
|
||||
"|cff33ffccpf|cffffffffUI|r disabled: " .. detail .. " " .. PFUI_CLASSIC_API_LATEST_URL,
|
||||
1, 0.3, 0.3
|
||||
)
|
||||
end
|
||||
local loginFrame = CreateFrame("Frame")
|
||||
loginFrame:RegisterEvent("PLAYER_ENTERING_WORLD")
|
||||
loginFrame:SetScript("OnEvent", function()
|
||||
loginFrame:UnregisterEvent("PLAYER_ENTERING_WORLD")
|
||||
ShowRequiredPopup()
|
||||
end)
|
||||
elseif CLASSIC_API_VERSION < PFUI_CLASSIC_API_LATEST then
|
||||
EventUtil.ContinueOnPlayerLogin(function()
|
||||
C_Timer.After(8, function()
|
||||
DEFAULT_CHAT_FRAME:AddMessage(
|
||||
"|cff33ffccpf|rUI: ClassicAPI " .. FormatVersion(PFUI_CLASSIC_API_LATEST) .. " is available — " .. PFUI_CLASSIC_API_LATEST_URL,
|
||||
1, 0.85, 0.3
|
||||
)
|
||||
end)
|
||||
end)
|
||||
end
|
||||
end
|
||||
+58
-3
@@ -296,6 +296,54 @@ pfUI:RegisterModule("chat", function ()
|
||||
end
|
||||
end
|
||||
|
||||
-- [ Chat Background Alpha ]
|
||||
-- Blizzard's per-window transparency slider drives FCF_SetWindowAlpha, which only
|
||||
-- touches the ChatFrame*Background textures that pfUI hides on docked frames. Mirror
|
||||
-- the window's stored alpha onto the visible pfUI backdrop so the native slider
|
||||
-- controls it directly. The slider is authoritative for the panel's alpha.
|
||||
local function ApplyChatBackgroundAlpha(panel, frame)
|
||||
if not (panel and panel.backdrop and frame) then return end
|
||||
local _, _, _, _, _, alpha = GetChatWindowInfo(frame:GetID())
|
||||
alpha = tonumber(alpha)
|
||||
if not alpha then return end
|
||||
local r, g, b = panel.backdrop:GetBackdropColor()
|
||||
panel.backdrop:SetBackdropColor(r, g, b, alpha)
|
||||
end
|
||||
|
||||
function pfUI.chat:RefreshBackgroundAlpha()
|
||||
-- left panel follows the currently selected docked tab
|
||||
local selected = SELECTED_CHAT_FRAME
|
||||
if not (selected and selected:GetParent() == pfUI.chat.left) then
|
||||
selected = ChatFrame1
|
||||
end
|
||||
ApplyChatBackgroundAlpha(pfUI.chat.left, selected)
|
||||
|
||||
if C.chat.right.enable == "1" then
|
||||
ApplyChatBackgroundAlpha(pfUI.chat.right, ChatFrame3)
|
||||
end
|
||||
end
|
||||
|
||||
function pfUI.chat:MigrateBackgroundAlpha()
|
||||
-- Runs once per character. The previous SetupPositions default stored a hard 0 window
|
||||
-- alpha, which now renders the pfUI backdrop fully transparent. Restore the historical
|
||||
-- 0.8 look for any pfUI-managed window still sitting at 0. Only existing installs that
|
||||
-- already ran chat setup carry that legacy 0; fresh installs get 0.8 from SetupPositions.
|
||||
if pfUI_init.chatbgalpha then return end
|
||||
if not pfUI_init["chat_position"] then return end
|
||||
pfUI_init.chatbgalpha = true
|
||||
|
||||
local frames = { ChatFrame1, ChatFrame2 }
|
||||
if C.chat.right.enable == "1" then table.insert(frames, ChatFrame3) end
|
||||
|
||||
for _, frame in ipairs(frames) do
|
||||
local _, _, _, _, _, alpha = GetChatWindowInfo(frame:GetID())
|
||||
alpha = tonumber(alpha)
|
||||
if alpha and alpha <= 0 then
|
||||
FCF_SetWindowAlpha(frame, 0.8)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function pfUI.chat:RefreshChat()
|
||||
local panelheight = C.global.font_size*1.5 + default_border*2 + 2
|
||||
|
||||
@@ -447,9 +495,13 @@ pfUI:RegisterModule("chat", function ()
|
||||
for index, value in pairs(DOCKED_CHAT_FRAMES) do
|
||||
FCF_UpdateButtonSide(value)
|
||||
end
|
||||
|
||||
pfUI.chat:RefreshBackgroundAlpha()
|
||||
end
|
||||
|
||||
hooksecurefunc("FCF_SaveDock", pfUI.chat.RefreshChat)
|
||||
hooksecurefunc("FCF_SetWindowAlpha", function() pfUI.chat:RefreshBackgroundAlpha() end)
|
||||
hooksecurefunc("FCF_SelectDockFrame", function() pfUI.chat:RefreshBackgroundAlpha() end)
|
||||
|
||||
if C.chat.global.tabmouse == "1" then
|
||||
pfUI.chat.mouseovertab = CreateFrame("Frame")
|
||||
@@ -500,7 +552,7 @@ pfUI:RegisterModule("chat", function ()
|
||||
FCF_SetLocked(ChatFrame1, 1)
|
||||
FCF_SetWindowName(ChatFrame1, GENERAL)
|
||||
FCF_SetWindowColor(ChatFrame1, 0, 0, 0)
|
||||
FCF_SetWindowAlpha(ChatFrame1, 0)
|
||||
FCF_SetWindowAlpha(ChatFrame1, 0.8)
|
||||
FCF_SetChatWindowFontSize(ChatFrame1, 12)
|
||||
ChatFrame1:SetUserPlaced(1)
|
||||
|
||||
@@ -508,7 +560,7 @@ pfUI:RegisterModule("chat", function ()
|
||||
FCF_SetLocked(ChatFrame2, 1)
|
||||
FCF_SetWindowName(ChatFrame2, COMBAT_LOG)
|
||||
FCF_SetWindowColor(ChatFrame2, 0, 0, 0)
|
||||
FCF_SetWindowAlpha(ChatFrame2, 0)
|
||||
FCF_SetWindowAlpha(ChatFrame2, 0.8)
|
||||
FCF_SetChatWindowFontSize(ChatFrame2, 12)
|
||||
ChatFrame2:SetUserPlaced(1)
|
||||
|
||||
@@ -518,7 +570,7 @@ pfUI:RegisterModule("chat", function ()
|
||||
FCF_SetLocked(ChatFrame3, 1)
|
||||
FCF_SetWindowName(ChatFrame3, T["Loot & Spam"])
|
||||
FCF_SetWindowColor(ChatFrame3, 0, 0, 0)
|
||||
FCF_SetWindowAlpha(ChatFrame3, 0)
|
||||
FCF_SetWindowAlpha(ChatFrame3, 0.8)
|
||||
FCF_SetChatWindowFontSize(ChatFrame3, 12)
|
||||
FCF_UnDockFrame(ChatFrame3)
|
||||
FCF_SetTabPosition(ChatFrame3, 0)
|
||||
@@ -566,6 +618,9 @@ pfUI:RegisterModule("chat", function ()
|
||||
end
|
||||
|
||||
pfUI.chat:SetScript("OnEvent", function()
|
||||
-- restore legacy chat windows stuck at 0 alpha before anything reads it
|
||||
pfUI.chat:MigrateBackgroundAlpha()
|
||||
|
||||
-- set the default chat
|
||||
FCF_SelectDockFrame(SELECTED_CHAT_FRAME)
|
||||
|
||||
|
||||
+16
-27
@@ -296,18 +296,23 @@ pfUI:RegisterModule("nameplates", function ()
|
||||
return plate.creatureType
|
||||
end
|
||||
|
||||
-- Totem icon, read straight from the game:
|
||||
-- * Passive totems self-cast their provided buff, so they carry exactly one
|
||||
-- aura whose icon IS the totem's icon (Totem::Summon TOTEM_PASSIVE).
|
||||
-- * Active totems (Searing/Magma/Fire Nova) cast at enemies and hold no
|
||||
-- self-aura, so their icon arrives via UNIT_SPELLCAST_SUCCEEDED (cached
|
||||
-- into plate.totemIcon by the event handler); nil here until then.
|
||||
-- Totem icon: UnitCreatedBySpell returns the totem-drop spell, whose icon IS
|
||||
-- the totem's icon. It's a broadcast descriptor field the client has for every
|
||||
-- summoned unit in range, so it resolves immediately for passive and active
|
||||
-- totems alike -- no self-aura read or attack-cast capture needed.
|
||||
--
|
||||
-- Re-read the spell every call rather than caching the icon outright: a shaman
|
||||
-- can swap the totem in place (same unit, new drop spell) with no plate re-add
|
||||
-- to invalidate a cache, so key the cached texture on the spell id and refresh
|
||||
-- it only when the spell changes.
|
||||
local function TotemPlate(plate)
|
||||
if C.nameplates.totemicons ~= "1" then return nil end
|
||||
if CreatureType(plate) ~= 11 then return nil end
|
||||
if plate.totemIcon then return plate.totemIcon end
|
||||
local aura = C_UnitAuras.GetBuffDataByIndex(plate.cachedGuid, 1)
|
||||
if aura then plate.totemIcon = aura.icon end
|
||||
local spellId = UnitCreatedBySpell(plate.cachedGuid)
|
||||
if spellId ~= plate.totemSpell then
|
||||
plate.totemSpell = spellId
|
||||
plate.totemIcon = spellId and C_Spell.GetSpellTexture(spellId) or nil
|
||||
end
|
||||
return plate.totemIcon
|
||||
end
|
||||
|
||||
@@ -499,7 +504,6 @@ nameplates:RegisterEvent("UNIT_SPELLCAST_START")
|
||||
nameplates:RegisterEvent("UNIT_SPELLCAST_CHANNEL_START")
|
||||
nameplates:RegisterEvent("UNIT_SPELLCAST_STOP")
|
||||
nameplates:RegisterEvent("UNIT_SPELLCAST_CHANNEL_STOP")
|
||||
nameplates:RegisterEvent("UNIT_SPELLCAST_SUCCEEDED")
|
||||
nameplates:RegisterEvent("PLAYER_GUILD_UPDATE")
|
||||
|
||||
nameplates:SetScript("OnEvent", function()
|
||||
@@ -588,6 +592,7 @@ nameplates:RegisterEvent("PLAYER_GUILD_UPDATE")
|
||||
plate.nameplate.unit = arg1
|
||||
plate.nameplate.creatureType = nil -- recompute for the new unit
|
||||
plate.nameplate.totemIcon = nil
|
||||
plate.nameplate.totemSpell = nil
|
||||
if guid then
|
||||
plateByGuid[guid] = plate.nameplate
|
||||
-- Seed: the unit may already be mid-cast (its UNIT_SPELLCAST_START
|
||||
@@ -665,22 +670,6 @@ nameplates:RegisterEvent("PLAYER_GUILD_UPDATE")
|
||||
end
|
||||
end
|
||||
|
||||
elseif event == "UNIT_SPELLCAST_SUCCEEDED" then
|
||||
-- Active totems (Searing/Magma/Fire Nova) carry no self-aura, so their
|
||||
-- attack cast is the only icon source. Capture it once per totem, gated on
|
||||
-- creature type so a normal caster's spell never styles it as a totem.
|
||||
if arg1 and strfind(arg1, "^nameplate") then
|
||||
local guid = UnitGUID(arg1)
|
||||
local plate = guid and plateByGuid[guid]
|
||||
if plate and not plate.totemIcon and arg3 and CreatureType(plate) == 11 then
|
||||
local tex = C_Spell.GetSpellTexture(arg3)
|
||||
if tex then
|
||||
plate.totemIcon = tex
|
||||
plate.castUpdate = true -- re-render now so the icon shows
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
elseif event == "UNIT_AURA" then
|
||||
-- ClassicAPI: fires with arg1 == "nameplateN" when a unit's aura set
|
||||
-- changes (add/remove/modify). Flag the matching plate so OnUpdate does a
|
||||
@@ -1116,7 +1105,7 @@ nameplates:RegisterEvent("PLAYER_GUILD_UPDATE")
|
||||
local TotemIcon = TotemPlate(plate)
|
||||
|
||||
if TotemIcon then
|
||||
-- icon resolved from the totem's aura / attack cast (already a full path)
|
||||
-- icon resolved from the totem-drop spell (already a full path)
|
||||
plate.totem.icon:SetTexture(TotemIcon)
|
||||
|
||||
plate.glow:Hide()
|
||||
|
||||
@@ -3,6 +3,10 @@ function SlashCmdList.RELOAD(msg, editbox)
|
||||
ReloadUI()
|
||||
end
|
||||
|
||||
if pfUI_disabled then return end
|
||||
|
||||
local addonName = ...
|
||||
|
||||
SLASH_PFUI1 = '/pfui'
|
||||
function SlashCmdList.PFUI(msg, editbox)
|
||||
pfUI.gui:SetShown(not pfUI.gui:IsShown())
|
||||
@@ -13,7 +17,7 @@ function SlashCmdList.GM(msg, editbox)
|
||||
ToggleHelpFrame(1)
|
||||
end
|
||||
|
||||
pfUI = CreateFrame("Frame", nil, UIParent)
|
||||
local pfUI = CreateFrame("Frame", addonName, UIParent)
|
||||
pfUI:RegisterEvent("ADDON_LOADED")
|
||||
|
||||
-- setup bootvar
|
||||
@@ -23,7 +27,7 @@ do
|
||||
-- ClassicAPI dependency check.
|
||||
-- pfUI relies pervasively on the modern C_* / SuperWoW / nameplate / focus
|
||||
-- API surface that ClassicAPI polyfills, so presence is required.
|
||||
local PFUI_CLASSIC_API_MIN = 11204 -- (X*10000 + Y*100 + Z)
|
||||
local PFUI_CLASSIC_API_MIN = 11301 -- (X*10000 + Y*100 + Z)
|
||||
local PFUI_CLASSIC_API_LATEST = PFUI_CLASSIC_API_MIN
|
||||
local PFUI_CLASSIC_API_WEBSITE = "https://github.com/brues-code/ClassicAPI"
|
||||
local PFUI_CLASSIC_API_LATEST_URL = PFUI_CLASSIC_API_WEBSITE .. "/releases/latest"
|
||||
@@ -117,35 +121,24 @@ pfUI.env = {}
|
||||
-- the flag; one that lacks it should drop the flag and get the safe fallback.
|
||||
pfUI.handlesHookScript = true
|
||||
|
||||
if not pfUI.disabled then
|
||||
pfUI.events = Mixin({}, CallbackRegistryMixin)
|
||||
pfUI.events:OnLoad()
|
||||
pfUI.events:SetUndefinedEventsAllowed(true)
|
||||
end
|
||||
pfUI.events = Mixin({}, CallbackRegistryMixin)
|
||||
pfUI.events:OnLoad()
|
||||
pfUI.events:SetUndefinedEventsAllowed(true)
|
||||
|
||||
-- check if macro addons are loaded (disables macrotweak/macroscan)
|
||||
function pfUI:MacroAddonsLoaded()
|
||||
return IsAddOnLoaded("Supermacro") or IsAddOnLoaded("SuperCleveRoidMacros") or IsAddOnLoaded("UltimaMacros")
|
||||
end
|
||||
|
||||
-- detect current addon path
|
||||
local tocs = { "", "-master", "-tbc", "-wotlk" }
|
||||
for _, name in pairs(tocs) do
|
||||
local current = string.format("pfUI%s", name)
|
||||
local title = C_AddOns.GetAddOnName(current)
|
||||
if title then
|
||||
pfUI.name = current
|
||||
pfUI.path = "Interface\\AddOns\\" .. current
|
||||
break
|
||||
end
|
||||
end
|
||||
pfUI.name = addonName
|
||||
pfUI.path = "Interface\\AddOns\\" .. addonName
|
||||
|
||||
-- handle/convert media dir paths
|
||||
pfUI.media = setmetatable({}, { __index = function(tab,key)
|
||||
local value = tostring(key)
|
||||
if strfind(value, "img:") then
|
||||
if value:find("img:") then
|
||||
value = string.gsub(value, "img:", pfUI.path .. "\\img\\")
|
||||
elseif strfind(value, "font:") then
|
||||
elseif value:find("font:") then
|
||||
value = string.gsub(value, "font:", pfUI.path .. "\\fonts\\")
|
||||
else
|
||||
value = string.gsub(value, "Interface\\AddOns\\pfUI\\", pfUI.path .. "\\")
|
||||
@@ -154,9 +147,7 @@ pfUI.media = setmetatable({}, { __index = function(tab,key)
|
||||
return value
|
||||
end})
|
||||
|
||||
-- cache client version
|
||||
local _, _, _, client = GetBuildInfo()
|
||||
pfUI.client = client or 11200
|
||||
pfUI.client = INTERFACE_VERSION
|
||||
|
||||
-- setup pfUI namespace
|
||||
setmetatable(pfUI.env, {__index = getfenv(0)})
|
||||
@@ -390,14 +381,13 @@ function pfUI:CheckNewModules()
|
||||
end
|
||||
|
||||
local function BackwardsCompatRegister(func, arg3)
|
||||
if arg3 and type(func) == "string" and type(arg3) == "function" and string.find(func, "vanilla") then
|
||||
if arg3 and type(func) == "string" and type(arg3) == "function" and func:find("vanilla") then
|
||||
return arg3
|
||||
end
|
||||
return func
|
||||
end
|
||||
|
||||
function pfUI:RegisterModule(name, func, arg3)
|
||||
if pfUI.disabled then return end
|
||||
if pfUI.module[name] then return end
|
||||
func = BackwardsCompatRegister(func, arg3)
|
||||
pfUI.module[name] = func
|
||||
@@ -408,7 +398,6 @@ function pfUI:RegisterModule(name, func, arg3)
|
||||
end
|
||||
|
||||
function pfUI:RegisterSkin(name, func, arg3)
|
||||
if pfUI.disabled then return end
|
||||
if pfUI.skin[name] then return end
|
||||
func = BackwardsCompatRegister(func, arg3)
|
||||
pfUI.skin[name] = func
|
||||
@@ -429,7 +418,6 @@ function pfUI:LoadSkin(s)
|
||||
end
|
||||
|
||||
pfUI:SetScript("OnEvent", function()
|
||||
if pfUI.disabled then return end
|
||||
|
||||
-- make sure to initialize and set our fonts
|
||||
-- each time an addon got loaded but only
|
||||
@@ -443,7 +431,7 @@ pfUI:SetScript("OnEvent", function()
|
||||
-- "@project-version@" until release tooling substitutes it — mark those
|
||||
-- explicitly as "dev" instead of pretending they're a real numbered build.
|
||||
local raw = tostring(GetAddOnMetadata(pfUI.name, "Version"))
|
||||
if strfind(raw, "@") then
|
||||
if raw:find("@") then
|
||||
pfUI.version.major, pfUI.version.minor, pfUI.version.fix = 0, 0, 0
|
||||
pfUI.version.string = "dev"
|
||||
else
|
||||
|
||||
Reference in New Issue
Block a user