mirror of
https://github.com/brues-code/pfUI.git
synced 2026-09-22 07:36:56 +00:00
75c4657ab9
* nameplates: source totem icons from UnitCreatedBySpell
Read the totem's icon from the totem-drop spell (UnitCreatedBySpell +
GetSpellTexture) instead of the self-aura at index 1 plus a
UNIT_SPELLCAST_SUCCEEDED capture for active totems. The drop spell is a
broadcast descriptor field present for every summoned unit in range, so
it resolves immediately for passive and active totems alike and gives the
totem's own icon rather than the attack-spell proxy. Drops the
UNIT_SPELLCAST_SUCCEEDED registration and handler.
Re-read the spell each render and key the cached texture on the spell id
so an in-place totem swap (same unit, new drop spell -- no plate re-add)
refreshes the icon without needing the plate to leave and re-enter view.
* CAPI min bumped to 1.13.1
* Gracefully disable pfUI when ClassicAPI is missing
Add API_Check.lua as the first TOC entry. When the ClassicAPI DLL is
absent or below the minimum version it sets pfUI_disabled and stands up
an inert stub so the rest of the addon no-ops instead of flooding load
errors: modules and skins register their bodies into no-ops, and the
setfenv'd api/lib files run inside an environment where CreateFrame and
any missing global resolve to a null object -- so no real frames or live
handlers are created and missing API calls just return null. pfUI.lua
bails early on pfUI_disabled.
* auras: scan through GetAuraSlots instead of by-index loops
Every aura scan loop (unit frame buffs/debuffs, dispel indicators, buff and
custom indicators, player buff frame, buffwatch bars, tooltip buff row) now
enumerates a unit's auras once with C_UnitAuras.GetAuraSlots and reads each
aura by slot id via the positional C_UnitAuras.UnitAuraBySlot. The by-index
getters re-walk the aura array from slot 0 on every call, so a per-button
loop over them was quadratic in the aura count; one enumeration plus a
by-slot read per aura is linear.
pfUI.api.ScanAuraSlots(unit, filter, buf, max) wraps GetAuraSlots' fill-a-
table form (table as the 5th argument) so no vararg Lua frame is involved:
Lua 5.0 allocates an `arg` table for every vararg call, which showed up as
nameplate OnUpdate/OnEvent memory growth in the first cut of this change.
Single by-index reads in tooltip and click handlers are unchanged (one call
each, and SetUnitAura takes the same index).
Requires the ClassicAPI build that adds GetAuraSlots' fill form; on an older
DLL the 5th argument is ignored and ScanAuraSlots would read the first slot
id as the count.
* Show Faction/Race icons in chat
* Load pfUI through ClassicAPI's flavor TOCs
ClassicAPI redirects the read of pfUI\pfUI.toc to a flavored file whenever
the DLL is installed, so which TOC the client opens already answers whether
ClassicAPI is there. Split the manifest three ways and let that do the work:
pfUI.toc fallback, reached only when ClassicAPI is missing;
loads API_Check.lua and nothing else
pfUI_ClassicAPI.toc full addon, every non-Turtle client
pfUI_Turtle.toc full addon plus init\turtle.xml, on Turtle
The fallback TOC declares no SavedVariables. It used to, while API_Check.lua
reset pfUI_profiles to an empty table on the disabled path -- which truncated
the player's profiles on logout.
With the missing-DLL case handled by TOC selection, API_Check.lua drops the
null object stub that kept the other ~140 files quiet, along with
pfUI_disabled and the now unreachable early return in pfUI.lua. It keeps the
version gate, which still matters: the flavor redirect landed in ClassicAPI
v1.11.0, below the v1.13.1 pfUI needs, so an old DLL still gets served a
flavor TOC. pfUI.lua also loses a verbatim duplicate of the whole check.
Turtle-only files move to init\turtle.xml: modules\turtle-wow.lua (its
TURTLE_WOW_VERSION guard is now redundant) and the lft, turtle_shop,
barbershop, transmog and ebc skins. turtle-wow registers last instead of
75th of 84; the only ordering it relies on is pfUI.chat, registered 8th.
pfSellData moves to env\selldata.lua, listed only in pfUI_ClassicAPI.toc,
since turtle-wow.lua replaces the table wholesale on Turtle. env\tables.lua
keeps an empty declaration so sellvalue.lua has something to index when the
turtle-wow module is disabled.
The release workflow pinned PFUI_CLASSIC_API_LATEST in pfUI.lua, which has
not held that constant since it moved to API_Check.lua, so the pin was
silently doing nothing. It also switches to brues-code/packager@vCAPI, which
recognizes the _ClassicAPI and _Turtle suffixes and applies the TOC build
type filters to them.
* Split the vendor price tables into their own manifests
Turtle's pfSellData moves out of modules\turtle-wow.lua into
env\selldata_turtle.lua, matching env\selldata.lua for the stock list, and
each is pulled in by the manifest for its client: init\stock.xml from
pfUI_ClassicAPI.toc, init\turtle.xml from pfUI_Turtle.toc. Either way it
loads after init\env.xml and replaces the empty pfSellData declared there.
Turtle's prices used to be assigned inside the turtle-wow module body, which
put them on pfUI.env and skipped them entirely when that module was
disabled. At file scope they land on _G and apply either way.
* Drop the vanilla compat layer
compat\vanilla.lua named the handful of things that differed between clients
back when pfUI targeted several. Only one client remains, so every constant
had exactly one value. Inline each at its use site and delete the file,
init\compat.xml, and both TOC entries.
COOLDOWN_FRAME_TYPE -> "Model"
LOOT_BUTTON_FRAME_TYPE -> "LootButton"
MINIMAP_TRACKING_FRAME -> _G.MiniMapTrackingFrame
FRIENDS_NAME_LOCATION -> "ButtonTextNameLocation"
EVENTS_MINIMAP_ZONE_UPDATE -> the event list, in panel.lua
MICRO_BUTTONS -> a local in panel.lua
NAMEPLATE_OBJECTORDER -> a local in nameplates.lua
ACTIONBAR_SECURE_TEMPLATE_BAR/_BUTTON -> nil, so the argument goes away
NAMEPLATE_FRAMETYPE and PLAYER_BUFF_START_ID had no readers left.
RunMacroText moves to pfUI.lua. compat\vanilla.lua was setfenv'd into the
pfUI environment, so the function only ever existed on pfUI.env; at file
scope it lands on _G as a real export instead. Nothing in pfUI calls it, and
ClassicAPI neither defines nor looks for a RunMacroText global -- it does
the same throwaway edit box natively in src/macro/Execute.cpp and only
defers to a global RunMacro.
* bump CAPI min to 11303
* auras: uncap the self-debuff tooltip lookup
With selfdebuff on, the displayed debuff list is PLAYER-filtered while
GameTooltip:SetUnitAura indexes the unfiltered HARMFUL list, so both
handlers map one to the other by matching name + sourceGUID. That mapping
scanned slots 1..16 only.
The unfiltered harmful list is not capped at 16. Once a unit's 16 debuff
slots are full the server parks further debuffs in buff slots, and
C_UnitAuras classifies by the aura's polarity flag rather than its slot
range, so it reports those as harmful too -- verified live at 18 harmful on
a 20-aura target. Past the sixteenth the lookup found nothing and fell
through to the raw filtered index, opening the wrong tooltip or none.
Both now enumerate however many harmful auras the unit actually has, via
ScanAuraSlots, which also drops the per-index rescan the by-index accessor
was doing. Each handler gets its own slot buffer: OnEnter can fire while a
refresh is showing/hiding frames under the cursor, so sharing the refresh
buffer could clobber a scan mid-walk.
The nameplate module still collects at most 16 debuffs per plate. That one
is a display cap matching its 16 configured icon frames, not an aura-count
assumption, so it is left alone.
* bump CAPI min to 11304
953 lines
36 KiB
Lua
953 lines
36 KiB
Lua
pfUI:RegisterModule("chat", function ()
|
|
local panelfont = C.panel.use_unitfonts == "1" and pfUI.font_unit or pfUI.font_default
|
|
local panelfont_size = C.panel.use_unitfonts == "1" and C.global.font_unit_size or C.global.font_size
|
|
local rawborder, default_border = GetBorderSize("chat")
|
|
|
|
-- The 'GetChatWindowInfo' function returns shown as 'false' while the UIParent is hidden (Alt+Z).
|
|
-- Based on that return value, the 'FloatingChatFrame_Update' would remove every chat frame,
|
|
-- that isn't tabbed while the interface is hidden. With this hook we prevent the original
|
|
-- 'FloatingChatFrame_Update' function from being called during that time.
|
|
|
|
local HookFloatingChatFrame_Update = _G.FloatingChatFrame_Update
|
|
_G.FloatingChatFrame_Update = function(id, onUpdateEvent)
|
|
if not UIParent:IsShown() then return end
|
|
HookFloatingChatFrame_Update(id, onUpdateEvent)
|
|
end
|
|
|
|
_G.CHAT_FONT_HEIGHTS = { 8, 10, 12, 14, 16, 18, 20 }
|
|
|
|
-- add dropdown menu button to ignore player
|
|
UnitPopupButtons["IGNORE_PLAYER"] = { text = IGNORE_PLAYER, dist = 0 }
|
|
for index,value in ipairs(UnitPopupMenus["FRIEND"]) do
|
|
if value == "GUILD_LEAVE" then
|
|
table.insert(UnitPopupMenus["FRIEND"], index+1, "IGNORE_PLAYER")
|
|
end
|
|
end
|
|
|
|
hooksecurefunc("UnitPopup_OnClick", function(self)
|
|
if this.value == "IGNORE_PLAYER" then
|
|
AddIgnore(_G[UIDROPDOWNMENU_INIT_MENU].name)
|
|
end
|
|
end)
|
|
|
|
local realm = GetRealmName()
|
|
local player = UnitName("player")
|
|
local history
|
|
local function SaveChatHistory(id, msg, r, g, b)
|
|
-- create cache tables if not existing
|
|
pfUI_cache = pfUI_cache or {}
|
|
pfUI_cache["chathistory"] = pfUI_cache["chathistory"] or {}
|
|
pfUI_cache["chathistory"][realm] = pfUI_cache["chathistory"][realm] or {}
|
|
pfUI_cache["chathistory"][realm][player] = pfUI_cache["chathistory"][realm][player] or {}
|
|
pfUI_cache["chathistory"][realm][player][id] = pfUI_cache["chathistory"][realm][player][id] or {}
|
|
|
|
if r and g and b then
|
|
local color = rgbhex(r*.5+.2, g*.5+.2, b*.5+.2)
|
|
msg = string.gsub(msg, "^", color)
|
|
msg = string.gsub(msg, "|r", "|r" .. color)
|
|
end
|
|
|
|
history = pfUI_cache["chathistory"][realm][player][id]
|
|
table.insert(history, 1, msg)
|
|
if history[30] then table.remove(history, 30) end
|
|
end
|
|
|
|
local function GetChatHistory(id)
|
|
-- create cache tables if not existing
|
|
pfUI_cache = pfUI_cache or {}
|
|
pfUI_cache["chathistory"] = pfUI_cache["chathistory"] or {}
|
|
pfUI_cache["chathistory"][realm] = pfUI_cache["chathistory"][realm] or {}
|
|
pfUI_cache["chathistory"][realm][player] = pfUI_cache["chathistory"][realm][player] or {}
|
|
pfUI_cache["chathistory"][realm][player][id] = pfUI_cache["chathistory"][realm][player][id] or {}
|
|
|
|
return pfUI_cache["chathistory"][realm][player][id]
|
|
end
|
|
|
|
-- [ Chat Panel Colors ]
|
|
-- The panels normally inherit pfUI's global appearance theme; custom colors let chat
|
|
-- deviate from it. CreateBackdrop is re-run first to restore the theme, so toggling
|
|
-- custom colors back off doesn't leave the previous override behind.
|
|
local function ApplyPanelColors(panel)
|
|
if not panel then return end
|
|
|
|
CreateBackdrop(panel, default_border, nil, .8)
|
|
if C.chat.global.custombg ~= "1" then return end
|
|
|
|
local r, g, b, a = GetStringColor(C.chat.global.background)
|
|
panel.backdrop:SetBackdropColor(tonumber(r), tonumber(g), tonumber(b), tonumber(a))
|
|
|
|
local r, g, b, a = GetStringColor(C.chat.global.border)
|
|
panel.backdrop:SetBackdropBorderColor(tonumber(r), tonumber(g), tonumber(b), tonumber(a))
|
|
end
|
|
|
|
pfUI.chat = CreateFrame("Frame",nil,UIParent)
|
|
|
|
pfUI.chat.left = CreateFrame("Frame", "pfChatLeft", UIParent)
|
|
pfUI.chat.left.OnMove = function()
|
|
pfUI.chat:RefreshChat()
|
|
end
|
|
|
|
pfUI.chat.left:SetFrameStrata("BACKGROUND")
|
|
pfUI.chat.left:SetWidth(C.chat.left.width)
|
|
pfUI.chat.left:SetHeight(C.chat.left.height)
|
|
pfUI.chat.left:SetPoint("BOTTOMLEFT", 2*default_border,2*default_border)
|
|
pfUI.chat.left:SetScript("OnShow", function() pfUI.chat:RefreshChat() end)
|
|
UpdateMovable(pfUI.chat.left)
|
|
ApplyPanelColors(pfUI.chat.left)
|
|
if C.chat.global.frameshadow == "1" then
|
|
CreateBackdropShadow(pfUI.chat.left)
|
|
end
|
|
|
|
pfUI.chat.left.panelTop = CreateFrame("Frame", "leftChatPanelTop", pfUI.chat.left)
|
|
pfUI.chat.left.panelTop:ClearAllPoints()
|
|
pfUI.chat.left.panelTop:SetHeight(C.global.font_size+default_border*2)
|
|
pfUI.chat.left.panelTop:SetPoint("TOPLEFT", pfUI.chat.left, "TOPLEFT", default_border, -default_border)
|
|
pfUI.chat.left.panelTop:SetPoint("TOPRIGHT", pfUI.chat.left, "TOPRIGHT", -default_border, -default_border)
|
|
if C.chat.global.tabdock == "1" then
|
|
CreateBackdrop(pfUI.chat.left.panelTop, default_border, nil, .8)
|
|
end
|
|
|
|
pfUI.chat.URLPattern = {
|
|
WWW = {
|
|
["rx"]=" (www%d-)%.([_A-Za-z0-9-]+)%.(%S+)%s?",
|
|
["fm"]="%s.%s.%s"},
|
|
PROTOCOL = {
|
|
["rx"]=" (%a+)://(%S+)%s?",
|
|
["fm"]="%s://%s"},
|
|
EMAIL = {
|
|
["rx"]=" ([_A-Za-z0-9-%.:]+)@([_A-Za-z0-9-]+)(%.)([_A-Za-z0-9-]+%.?[_A-Za-z0-9-]*)%s?",
|
|
["fm"]="%s@%s%s%s"},
|
|
PORTIP = {
|
|
["rx"]=" (%d%d?%d?)%.(%d%d?%d?)%.(%d%d?%d?)%.(%d%d?%d?):(%d%d?%d?%d?%d?)%s?",
|
|
["fm"]="%s.%s.%s.%s:%s"},
|
|
IP = {
|
|
["rx"]=" (%d%d?%d?)%.(%d%d?%d?)%.(%d%d?%d?)%.(%d%d?%d?)%s?",
|
|
["fm"]="%s.%s.%s.%s"},
|
|
SHORTURL = {
|
|
["rx"]=" (%a+)%.(%a+)/(%S+)%s?",
|
|
["fm"]="%s.%s/%s"},
|
|
URLIP = {
|
|
["rx"]=" ([_A-Za-z0-9-]+)%.([_A-Za-z0-9-]+)%.(%S+)%:([_0-9-]+)%s?",
|
|
["fm"]="%s.%s.%s:%s"},
|
|
URL = {
|
|
["rx"]=" ([_A-Za-z0-9-]+)%.([_A-Za-z0-9-]+)%.(%S+)%s?",
|
|
["fm"]="%s.%s.%s"},
|
|
}
|
|
|
|
pfUI.chat.URLFuncs = {
|
|
["WWW"] = function(a1,a2,a3) return pfUI.chat:FormatLink(pfUI.chat.URLPattern.WWW.fm,a1,a2,a3) end,
|
|
["PROTOCOL"] = function(a1,a2) return pfUI.chat:FormatLink(pfUI.chat.URLPattern.PROTOCOL.fm,a1,a2) end,
|
|
["EMAIL"] = function(a1,a2,a3,a4) return pfUI.chat:FormatLink(pfUI.chat.URLPattern.EMAIL.fm,a1,a2,a3,a4) end,
|
|
["PORTIP"] = function(a1,a2,a3,a4,a5) return pfUI.chat:FormatLink(pfUI.chat.URLPattern.PORTIP.fm,a1,a2,a3,a4,a5) end,
|
|
["IP"] = function(a1,a2,a3,a4) return pfUI.chat:FormatLink(pfUI.chat.URLPattern.IP.fm,a1,a2,a3,a4) end,
|
|
["SHORTURL"] = function(a1,a2,a3) return pfUI.chat:FormatLink(pfUI.chat.URLPattern.SHORTURL.fm,a1,a2,a3) end,
|
|
["URLIP"] = function(a1,a2,a3,a4) return pfUI.chat:FormatLink(pfUI.chat.URLPattern.URLIP.fm,a1,a2,a3,a4) end,
|
|
["URL"] = function(a1,a2,a3) return pfUI.chat:FormatLink(pfUI.chat.URLPattern.URL.fm,a1,a2,a3) end,
|
|
}
|
|
|
|
-- url copy dialog
|
|
function pfUI.chat:FormatLink(formatter,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
|
|
if not (formatter and a1) then return end
|
|
local newtext = string.format(formatter,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
|
|
|
|
-- check the last capture index for consecutive trailing dots (invalid top level domain)
|
|
local invalidtld
|
|
for _, arg in pairs({a10,a9,a8,a7,a6,a5,a4,a3,a2,a1}) do
|
|
if arg then
|
|
invalidtld = string.find(arg, "(%.%.)$")
|
|
break
|
|
end
|
|
end
|
|
|
|
if (invalidtld) then return newtext end
|
|
if formatter == self.URLPattern.EMAIL.fm then -- email parser
|
|
local colon = string.find(a1,":")
|
|
if (colon) and string.len(a1) > colon then
|
|
if not (string.sub(a1,1,6) == "mailto") then
|
|
local prefix,address = string.sub(newtext,1,colon),string.sub(newtext,colon+1)
|
|
return string.format(" %s|cffccccff|Hurl:%s|h[%s]|h|r ",prefix,address,address)
|
|
end
|
|
end
|
|
end
|
|
return " |cffccccff|Hurl:" .. newtext .. "|h[" .. newtext .. "]|h|r "
|
|
end
|
|
|
|
function pfUI.chat:HandleLink(text)
|
|
local URLPattern = pfUI.chat.URLPattern
|
|
text = string.gsub (text, URLPattern.WWW.rx, pfUI.chat.URLFuncs.WWW)
|
|
text = string.gsub (text, URLPattern.PROTOCOL.rx, pfUI.chat.URLFuncs.PROTOCOL)
|
|
text = string.gsub (text, URLPattern.EMAIL.rx, pfUI.chat.URLFuncs.EMAIL)
|
|
text = string.gsub (text, URLPattern.PORTIP.rx, pfUI.chat.URLFuncs.PORTIP)
|
|
text = string.gsub (text, URLPattern.IP.rx, pfUI.chat.URLFuncs.IP)
|
|
text = string.gsub (text, URLPattern.SHORTURL.rx, pfUI.chat.URLFuncs.SHORTURL)
|
|
text = string.gsub (text, URLPattern.URLIP.rx, pfUI.chat.URLFuncs.URLIP)
|
|
text = string.gsub (text, URLPattern.URL.rx, pfUI.chat.URLFuncs.URL)
|
|
return text
|
|
end
|
|
|
|
pfUI.chat.urlcopy = CreateFrame("Frame", "pfURLCopy", UIParent)
|
|
pfUI.chat.urlcopy:Hide()
|
|
pfUI.chat.urlcopy:SetWidth(270)
|
|
pfUI.chat.urlcopy:SetHeight(65)
|
|
pfUI.chat.urlcopy:SetFrameStrata("FULLSCREEN")
|
|
pfUI.chat.urlcopy:SetPoint("CENTER", 0, 0)
|
|
CreateBackdrop(pfUI.chat.urlcopy, nil, nil, 0.8)
|
|
|
|
pfUI.chat.urlcopy:SetMovable(true)
|
|
pfUI.chat.urlcopy:EnableMouse(true)
|
|
pfUI.chat.urlcopy:RegisterForDrag("LeftButton")
|
|
pfUI.chat.urlcopy:SetScript("OnDragStart",function()
|
|
this:StartMoving()
|
|
end)
|
|
|
|
pfUI.chat.urlcopy:SetScript("OnDragStop",function()
|
|
this:StopMovingOrSizing()
|
|
end)
|
|
|
|
pfUI.chat.urlcopy:SetScript("OnShow", function()
|
|
this.text:HighlightText()
|
|
end)
|
|
|
|
pfUI.chat.urlcopy.text = CreateFrame("EditBox", "pfURLCopyEditBox", pfUI.chat.urlcopy)
|
|
pfUI.chat.urlcopy.text:SetTextColor(.2,1,.8,1)
|
|
pfUI.chat.urlcopy.text:SetJustifyH("CENTER")
|
|
|
|
pfUI.chat.urlcopy.text:SetWidth(250)
|
|
pfUI.chat.urlcopy.text:SetHeight(20)
|
|
pfUI.chat.urlcopy.text:SetPoint("TOP", pfUI.chat.urlcopy, "TOP", 0, -10)
|
|
pfUI.chat.urlcopy.text:SetFontObject(GameFontNormal)
|
|
CreateBackdrop(pfUI.chat.urlcopy.text)
|
|
|
|
pfUI.chat.urlcopy.text:SetScript("OnEscapePressed", function(self)
|
|
pfUI.chat.urlcopy:Hide()
|
|
end)
|
|
|
|
pfUI.chat.urlcopy.text:SetScript("OnEditFocusLost", function(self)
|
|
pfUI.chat.urlcopy:Hide()
|
|
end)
|
|
|
|
pfUI.chat.urlcopy.close = CreateFrame("Button", "pfURLCopyClose", pfUI.chat.urlcopy, "UIPanelButtonTemplate")
|
|
pfUI.api.SkinButton(pfUI.chat.urlcopy.close)
|
|
pfUI.chat.urlcopy.close:SetWidth(70)
|
|
pfUI.chat.urlcopy.close:SetHeight(18)
|
|
pfUI.chat.urlcopy.close:SetPoint("BOTTOMRIGHT", pfUI.chat.urlcopy, "BOTTOMRIGHT", -10, 10)
|
|
|
|
pfUI.chat.urlcopy.close:SetText(T["Close"])
|
|
pfUI.chat.urlcopy.close:SetScript("OnClick", function()
|
|
pfUI.chat.urlcopy:Hide()
|
|
end)
|
|
|
|
pfUI.chat.urlcopy.SetItemRef = SetItemRef
|
|
pfUI.chat.urlcopy.CopyText = function(text)
|
|
pfUI.chat.urlcopy.text:SetText(text)
|
|
pfUI.chat.urlcopy:Show()
|
|
end
|
|
|
|
function _G.SetItemRef(link, text, button)
|
|
if (strsub(link, 1, 3) == "url") then
|
|
if string.len(link) > 4 and string.sub(link,1,4) == "url:" then
|
|
pfUI.chat.urlcopy.CopyText(string.sub(link,5, string.len(link)))
|
|
end
|
|
return
|
|
end
|
|
pfUI.chat.urlcopy.SetItemRef(link, text, button)
|
|
end
|
|
|
|
pfUI.chat.right = CreateFrame("Frame", "pfChatRight", UIParent)
|
|
pfUI.chat.right:SetFrameStrata("BACKGROUND")
|
|
pfUI.chat.right:SetWidth(C.chat.right.width)
|
|
pfUI.chat.right:SetHeight(C.chat.right.height)
|
|
pfUI.chat.right:SetPoint("BOTTOMRIGHT", -2*default_border,2*default_border)
|
|
pfUI.chat.right:SetScript("OnShow", function() pfUI.chat:RefreshChat() end)
|
|
UpdateMovable(pfUI.chat.right)
|
|
ApplyPanelColors(pfUI.chat.right)
|
|
if C.chat.global.frameshadow == "1" then
|
|
CreateBackdropShadow(pfUI.chat.right)
|
|
end
|
|
|
|
pfUI.chat.right.panelTop = CreateFrame("Frame", "rightChatPanelTop", pfUI.chat.right)
|
|
pfUI.chat.right.panelTop:ClearAllPoints()
|
|
pfUI.chat.right.panelTop:SetHeight(C.global.font_size+default_border*2)
|
|
pfUI.chat.right.panelTop:SetPoint("TOPLEFT", pfUI.chat.right, "TOPLEFT", default_border, -default_border)
|
|
pfUI.chat.right.panelTop:SetPoint("TOPRIGHT", pfUI.chat.right, "TOPRIGHT", -default_border, -default_border)
|
|
if C.chat.global.tabdock == "1" then
|
|
CreateBackdrop(pfUI.chat.right.panelTop, default_border, nil, .8)
|
|
end
|
|
|
|
pfUI.chat:RegisterEvent("PLAYER_ENTERING_WORLD")
|
|
pfUI.chat:RegisterEvent("UI_SCALE_CHANGED")
|
|
|
|
local function ChatOnMouseWheel()
|
|
if (arg1 > 0) then
|
|
if IsShiftKeyDown() then
|
|
this:ScrollToTop()
|
|
else
|
|
for i=1, C.chat.global.scrollspeed do
|
|
this:ScrollUp()
|
|
end
|
|
end
|
|
elseif (arg1 < 0) then
|
|
if IsShiftKeyDown() then
|
|
this:ScrollToBottom()
|
|
else
|
|
for i=1, C.chat.global.scrollspeed do
|
|
this:ScrollDown()
|
|
end
|
|
end
|
|
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.
|
|
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()
|
|
-- Custom colors own the alpha. C.chat.global.background carries its own alpha, is
|
|
-- set by profiles and is shared with the meter skins, so the native slider must not
|
|
-- overwrite it -- doing so reverted the configured opacity on every refresh. The
|
|
-- slider only drives the panel when the user hasn't opted into pfUI's chat colors.
|
|
if C.chat.global.custombg == "1" then return end
|
|
|
|
-- 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
|
|
|
|
-- live config apply, resolved by the gui as U["chat"]. Lets the color pickers
|
|
-- take effect on the spot instead of waiting for a /reload.
|
|
function pfUI.chat:UpdateConfig()
|
|
ApplyPanelColors(pfUI.chat.left)
|
|
ApplyPanelColors(pfUI.chat.right)
|
|
pfUI.chat:RefreshBackgroundAlpha()
|
|
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
|
|
|
|
if C.chat.global.sticky == "1" then
|
|
ChatTypeInfo.WHISPER.sticky = 1
|
|
ChatTypeInfo.OFFICER.sticky = 1
|
|
ChatTypeInfo.RAID_WARNING.sticky = 1
|
|
ChatTypeInfo.CHANNEL.sticky = 1
|
|
end
|
|
|
|
ChatFrameMenuButton:Hide()
|
|
ChatMenu:SetClampedToScreen(true)
|
|
CreateBackdrop(ChatMenu)
|
|
CreateBackdrop(EmoteMenu)
|
|
CreateBackdrop(LanguageMenu)
|
|
CreateBackdrop(VoiceMacroMenu)
|
|
|
|
local combatlogpanel = (CombatLogQuickButtonFrame_Custom and CombatLogQuickButtonFrame_Custom:GetHeight() or 0)
|
|
|
|
for i=1, NUM_CHAT_WINDOWS do
|
|
local frame = _G["ChatFrame"..i]
|
|
local tab = _G["ChatFrame"..i.."Tab"]
|
|
|
|
local combat = 0
|
|
for _, msg in pairs(_G["ChatFrame"..i].messageTypeList) do
|
|
if strfind(msg, "SPELL", 1) or strfind(msg, "COMBAT", 1) then
|
|
combat = combat + 1
|
|
end
|
|
end
|
|
|
|
if combat > 5 then
|
|
frame.pfCombatLog = true
|
|
else
|
|
frame.pfCombatLog = nil
|
|
end
|
|
|
|
|
|
if not frame.pfStartMoving then
|
|
frame.pfStartMoving = frame.StartMoving
|
|
frame.StartMoving = function(a1)
|
|
pfUI.chat.hideLock = true
|
|
frame.pfStartMoving(a1)
|
|
end
|
|
end
|
|
|
|
if not frame.pfStopMovingOrSizing then
|
|
frame.pfStopMovingOrSizing = frame.StopMovingOrSizing
|
|
frame.StopMovingOrSizing = function(a1)
|
|
frame.pfStopMovingOrSizing(a1)
|
|
pfUI.chat.RefreshChat()
|
|
pfUI.chat.hideLock = false
|
|
end
|
|
end
|
|
|
|
if C.chat.global.fadeout == "1" then
|
|
frame:SetFading(true)
|
|
frame:SetTimeVisible(tonumber(C.chat.global.fadetime))
|
|
else
|
|
frame:SetFading(false)
|
|
end
|
|
|
|
if i == 3 and C.chat.right.enable == "1" then
|
|
-- Loot & Spam
|
|
local bottompadding = pfUI.panel and pfUI.panel.right:IsShown() and not pfUI_config.position["pfPanelRight"] and panelheight or default_border
|
|
tab:SetParent(pfUI.chat.right.panelTop)
|
|
frame:SetParent(pfUI.chat.right)
|
|
frame:ClearAllPoints()
|
|
frame:SetPoint("TOPLEFT", pfUI.chat.right ,"TOPLEFT", default_border, -panelheight)
|
|
frame:SetPoint("BOTTOMRIGHT", pfUI.chat.right ,"BOTTOMRIGHT", -default_border, bottompadding)
|
|
frame:Show()
|
|
elseif frame.isDocked then
|
|
-- Left Chat
|
|
local bottompadding = pfUI.panel and pfUI.panel.left:IsShown() and not pfUI_config.position["pfPanelLeft"] and panelheight or default_border
|
|
FCF_DockFrame(frame)
|
|
tab:SetParent(pfUI.chat.left.panelTop)
|
|
frame:SetParent(pfUI.chat.left)
|
|
frame:ClearAllPoints()
|
|
if i == 2 then
|
|
frame:SetPoint("TOPLEFT", pfUI.chat.left ,"TOPLEFT", default_border, -panelheight - combatlogpanel)
|
|
else
|
|
frame:SetPoint("TOPLEFT", pfUI.chat.left ,"TOPLEFT", default_border, -panelheight)
|
|
end
|
|
frame:SetPoint("BOTTOMRIGHT", pfUI.chat.left ,"BOTTOMRIGHT", -default_border, bottompadding)
|
|
else
|
|
FCF_UnDockFrame(frame)
|
|
frame:SetParent(UIParent)
|
|
tab:SetParent(UIParent)
|
|
end
|
|
|
|
-- Combat Log
|
|
if C.chat.global.combathide == "1" and frame.pfCombatLog then
|
|
FCF_UnDockFrame(frame)
|
|
FCF_Close(frame)
|
|
end
|
|
|
|
-- hide textures
|
|
for j,v in ipairs({tab:GetRegions()}) do
|
|
if j==5 then v:SetTexture(0,0,0,0) end
|
|
v:SetHeight(C.global.font_size+default_border*2)
|
|
end
|
|
|
|
-- remove background on docked frames
|
|
for _, tex in pairs(CHAT_FRAME_TEXTURES) do
|
|
local texture = _G["ChatFrame"..i..tex]
|
|
if tex == "Background" then
|
|
texture.oldTexture = texture.oldTexture or texture:GetTexture()
|
|
if frame:GetParent() == pfUI.chat.left or frame:GetParent() == pfUI.chat.right then
|
|
texture:SetTexture()
|
|
texture:Hide()
|
|
else
|
|
texture:SetTexture(texture.oldTexture)
|
|
texture:Show()
|
|
end
|
|
else
|
|
texture:SetTexture()
|
|
texture:Hide()
|
|
end
|
|
end
|
|
|
|
_G["ChatFrame" .. i .. "ResizeBottom"]:Hide()
|
|
_G["ChatFrame" .. i .. "TabText"]:SetJustifyV("CENTER")
|
|
_G["ChatFrame" .. i .. "TabText"]:SetHeight(C.global.font_size+default_border*2)
|
|
_G["ChatFrame" .. i .. "TabText"]:SetPoint("BOTTOM", 0, default_border)
|
|
_G["ChatFrame" .. i .. "TabLeft"]:SetAlpha(0)
|
|
_G["ChatFrame" .. i .. "TabMiddle"]:SetAlpha(0)
|
|
_G["ChatFrame" .. i .. "TabRight"]:SetAlpha(0)
|
|
|
|
if C.chat.global.chatflash == "1" then
|
|
_G["ChatFrame" .. i .. "TabFlash"]:SetAllPoints(_G["ChatFrame" .. i .. "TabText"])
|
|
else
|
|
_G["ChatFrame" .. i .. "TabFlash"].Show = function() return end
|
|
end
|
|
|
|
local class = UnitClassBase("player")
|
|
local classColor = PFUI_CLASS_COLORS[class]
|
|
_G["ChatFrame" .. i .. "TabText"]:SetTextColor((classColor.r + .3) * .5, (classColor.g + .3) * .5, (classColor.b + .3) * .5, 1)
|
|
_G["ChatFrame" .. i .. "TabText"]:SetFont(panelfont,panelfont_size, "OUTLINE")
|
|
|
|
if _G["ChatFrame" .. i].isDocked or _G["ChatFrame" .. i]:IsVisible() then
|
|
_G["ChatFrame" .. i .. "Tab"]:Show()
|
|
end
|
|
|
|
frame:EnableMouseWheel(true)
|
|
frame:SetScript("OnMouseWheel", ChatOnMouseWheel)
|
|
end
|
|
|
|
|
|
-- update dock frame for all windows
|
|
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")
|
|
pfUI.chat.mouseovertab:SetScript("OnUpdate", function()
|
|
-- throttle
|
|
if ( this.tick or .1) > GetTime() then return else this.tick = GetTime() + pfUI.throttle:Get("chat_tab") end -- Default: Normal (10 FPS)
|
|
|
|
if pfUI.chat.hideLock then return end
|
|
|
|
if MouseIsOver(pfUI.chat.left, 10, -10, -10, 10) then
|
|
pfUI.chat.left.panelTop:Show()
|
|
FCF_DockUpdate()
|
|
elseif MouseIsOver(pfUI.chat.right, 10, -10, -10, 10) then
|
|
-- disable while dock is active
|
|
if pfUI.chat.right:GetAlpha() == 0 then return end
|
|
|
|
pfUI.chat.right.panelTop:Show()
|
|
FCF_DockUpdate()
|
|
else
|
|
pfUI.chat.left.panelTop:Hide()
|
|
pfUI.chat.right.panelTop:Hide()
|
|
end
|
|
end)
|
|
end
|
|
|
|
function pfUI.chat.SetupRightChat(state)
|
|
if state then
|
|
C.chat.right.enable = "1"
|
|
pfUI.chat.right:Show()
|
|
else
|
|
C.chat.right.enable = "0"
|
|
pfUI.chat.right:Hide()
|
|
end
|
|
end
|
|
|
|
function pfUI.chat.SetupPositions()
|
|
-- close all chat windows
|
|
for i=1, NUM_CHAT_WINDOWS do
|
|
FCF_Close(_G["ChatFrame"..i])
|
|
FCF_DockUpdate()
|
|
end
|
|
|
|
-- Main Window
|
|
ChatFrame1:ClearAllPoints()
|
|
ChatFrame1:SetPoint("TOPLEFT", pfUI.chat.left ,"TOPLEFT", 5, -25)
|
|
ChatFrame1:SetPoint("BOTTOMRIGHT", pfUI.chat.left ,"BOTTOMRIGHT", -5, 25)
|
|
|
|
FCF_SetLocked(ChatFrame1, 1)
|
|
FCF_SetWindowName(ChatFrame1, GENERAL)
|
|
FCF_SetWindowColor(ChatFrame1, 0, 0, 0)
|
|
FCF_SetWindowAlpha(ChatFrame1, 0.8)
|
|
FCF_SetChatWindowFontSize(ChatFrame1, 12)
|
|
ChatFrame1:SetUserPlaced(1)
|
|
|
|
-- Combat Log
|
|
FCF_SetLocked(ChatFrame2, 1)
|
|
FCF_SetWindowName(ChatFrame2, COMBAT_LOG)
|
|
FCF_SetWindowColor(ChatFrame2, 0, 0, 0)
|
|
FCF_SetWindowAlpha(ChatFrame2, 0.8)
|
|
FCF_SetChatWindowFontSize(ChatFrame2, 12)
|
|
ChatFrame2:SetUserPlaced(1)
|
|
|
|
-- Loot & Spam
|
|
if C.chat.right.enable == "1" then
|
|
-- set position of Loot & Spam
|
|
FCF_SetLocked(ChatFrame3, 1)
|
|
FCF_SetWindowName(ChatFrame3, T["Loot & Spam"])
|
|
FCF_SetWindowColor(ChatFrame3, 0, 0, 0)
|
|
FCF_SetWindowAlpha(ChatFrame3, 0.8)
|
|
FCF_SetChatWindowFontSize(ChatFrame3, 12)
|
|
FCF_UnDockFrame(ChatFrame3)
|
|
FCF_SetTabPosition(ChatFrame3, 0)
|
|
ChatFrame3:ClearAllPoints()
|
|
ChatFrame3:SetPoint("TOPLEFT", pfUI.chat.right ,"TOPLEFT", 5, -25)
|
|
ChatFrame3:SetPoint("BOTTOMRIGHT", pfUI.chat.right ,"BOTTOMRIGHT", -5, 25)
|
|
ChatFrame3:SetUserPlaced(1)
|
|
end
|
|
|
|
pfUI.chat:RefreshChat()
|
|
FCF_DockUpdate()
|
|
end
|
|
|
|
function pfUI.chat.SetupChannels()
|
|
ChatFrame_RemoveAllMessageGroups(ChatFrame1)
|
|
ChatFrame_RemoveAllMessageGroups(ChatFrame2)
|
|
ChatFrame_RemoveAllMessageGroups(ChatFrame3)
|
|
|
|
ChatFrame_RemoveAllChannels(ChatFrame1)
|
|
ChatFrame_RemoveAllChannels(ChatFrame2)
|
|
ChatFrame_RemoveAllChannels(ChatFrame3)
|
|
|
|
local normalg = { "SYSTEM", "SAY", "YELL", "WHISPER", "PARTY", "GUILD", "GUILD_OFFICER", "CREATURE", "CHANNEL", "EMOTE", "RAID", "RAID_LEADER", "RAID_WARNING", "BATTLEGROUND", "BATTLEGROUND_LEADER", "MONSTER_SAY", "MONSTER_EMOTE", "MONSTER_YELL", "MONSTER_WHISPER", "MONSTER_BOSS_EMOTE", "MONSTER_BOSS_WHISPER" }
|
|
for _,group in pairs(normalg) do
|
|
ChatFrame_AddMessageGroup(ChatFrame1, group)
|
|
end
|
|
|
|
ChatFrame_ActivateCombatMessages(ChatFrame2)
|
|
|
|
if C.chat.right.enable == "1" then
|
|
local spamg = { "COMBAT_XP_GAIN", "COMBAT_HONOR_GAIN", "COMBAT_FACTION_CHANGE", "SKILL", "LOOT" }
|
|
for _,group in pairs(spamg) do
|
|
ChatFrame_AddMessageGroup(ChatFrame3, group)
|
|
end
|
|
|
|
for _, chan in pairs({EnumerateServerChannels()}) do
|
|
ChatFrame_AddChannel(ChatFrame3, chan)
|
|
ChatFrame_RemoveChannel(ChatFrame1, chan)
|
|
end
|
|
|
|
JoinChannelByName("World")
|
|
ChatFrame_AddChannel(ChatFrame3, "World")
|
|
end
|
|
pfUI.chat:RefreshChat()
|
|
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)
|
|
|
|
-- update all chat settings
|
|
pfUI.chat:RefreshChat()
|
|
FCF_DockUpdate()
|
|
if C.chat.right.enable == "0" then
|
|
pfUI.chat.right:Hide()
|
|
end
|
|
end)
|
|
|
|
local function SkipFading(self, alpha)
|
|
UIFrameFadeRemoveFrame(self)
|
|
if SELECTED_CHAT_FRAME:GetID() == self:GetID() then
|
|
self:_SetAlpha(1)
|
|
else
|
|
self:_SetAlpha(0.5)
|
|
end
|
|
end
|
|
|
|
for i=1, NUM_CHAT_WINDOWS do
|
|
_G["ChatFrame" .. i .. "UpButton"]:Hide()
|
|
_G["ChatFrame" .. i .. "UpButton"].Show = function() return end
|
|
_G["ChatFrame" .. i .. "DownButton"]:Hide()
|
|
_G["ChatFrame" .. i .. "DownButton"].Show = function() return end
|
|
_G["ChatFrame" .. i .. "BottomButton"]:Hide()
|
|
_G["ChatFrame" .. i .. "BottomButton"].Show = function() return end
|
|
_G["ChatFrame" .. i .. "Tab"]._SetAlpha = _G["ChatFrame" .. i .. "Tab"].SetAlpha
|
|
_G["ChatFrame" .. i .. "Tab"].SetAlpha = SkipFading
|
|
end
|
|
|
|
pfUI.chat.editbox = CreateFrame("Frame", "pfChatInputBox", UIParent)
|
|
pfUI.chat.editbox:SetFrameStrata("DIALOG")
|
|
if C.chat.text.input_height == "0" then
|
|
pfUI.chat.editbox:SetHeight(22)
|
|
|
|
if ChatFrameEditBoxLanguage then
|
|
SkinButton(ChatFrameEditBoxLanguage)
|
|
ChatFrameEditBoxLanguage:SetWidth(22)
|
|
ChatFrameEditBoxLanguage:SetHeight(22)
|
|
end
|
|
else
|
|
pfUI.chat.editbox:SetHeight(C.chat.text.input_height)
|
|
|
|
if ChatFrameEditBoxLanguage then
|
|
SkinButton(ChatFrameEditBoxLanguage)
|
|
ChatFrameEditBoxLanguage:SetWidth(C.chat.text.input_height)
|
|
ChatFrameEditBoxLanguage:SetHeight(C.chat.text.input_height)
|
|
end
|
|
end
|
|
|
|
-- to make sure the bars are set up properly, we need to wait.
|
|
local pfChatArrangeFrame = CreateFrame("Frame", "pfChatArrange", UIParent)
|
|
pfChatArrangeFrame:RegisterEvent("CVAR_UPDATE")
|
|
pfChatArrangeFrame:RegisterEvent("PLAYER_ENTERING_WORLD")
|
|
pfChatArrangeFrame:SetScript("OnEvent", function()
|
|
pfUI.chat.editbox:ClearAllPoints()
|
|
|
|
local anchor = pfUI.chat.left
|
|
if pfUI.bars and pfUI.bars[6]:IsShown() then
|
|
anchor = pfUI.bars[6]
|
|
elseif pfUI.bars and pfUI.bars[1]:IsShown() then
|
|
anchor = pfUI.bars[1]
|
|
end
|
|
|
|
if C.chat.text.input_width ~= "0" then
|
|
pfUI.chat.editbox:SetPoint("BOTTOM", anchor, "TOP", 0, default_border*3)
|
|
pfUI.chat.editbox:SetWidth(C.chat.text.input_width)
|
|
else
|
|
pfUI.chat.editbox:SetWidth(anchor:GetWidth())
|
|
pfUI.chat.editbox:SetPoint("BOTTOMLEFT", anchor, "TOPLEFT", 0, default_border*3)
|
|
pfUI.chat.editbox:SetPoint("BOTTOMRIGHT", anchor, "TOPRIGHT", 0, default_border*3)
|
|
end
|
|
|
|
UpdateMovable(pfUI.chat.editbox)
|
|
end)
|
|
|
|
|
|
ChatFrameEditBox:SetParent(pfUI.chat.editbox)
|
|
ChatFrameEditBox:SetAllPoints(pfUI.chat.editbox)
|
|
CreateBackdrop(ChatFrameEditBox, default_border)
|
|
|
|
for i,v in ipairs({ChatFrameEditBox:GetRegions()}) do
|
|
if i==6 or i==7 or i==8 then v:Hide() end
|
|
if v.SetFont then
|
|
v:SetFont(pfUI.font_default, C.global.font_size + 1, "OUTLINE")
|
|
end
|
|
end
|
|
ChatFrameEditBox:SetAltArrowKeyMode(false)
|
|
|
|
if C.chat.text.mouseover == "1" then
|
|
for i=1, NUM_CHAT_WINDOWS do
|
|
local frame = _G["ChatFrame" .. i]
|
|
frame:SetScript("OnHyperlinkEnter", function()
|
|
local _, _, linktype = string.find(arg1, "^(.-):(.+)$")
|
|
if linktype == "item" then
|
|
GameTooltip:SetOwner(this, "ANCHOR_CURSOR")
|
|
GameTooltip:SetHyperlink(arg1)
|
|
GameTooltip:Show()
|
|
end
|
|
end)
|
|
|
|
frame:SetScript("OnHyperlinkLeave", function()
|
|
GameTooltip:Hide()
|
|
end)
|
|
end
|
|
end
|
|
|
|
-- read and parse whisper color settings
|
|
local cr, cg, cb, ca = GetStringColor(C.chat.global.whisper)
|
|
cr, cg, cb = tonumber(cr), tonumber(cg), tonumber(cb)
|
|
local wcol = rgbhex(cr, cg, cb)
|
|
|
|
-- read and parse chat bracket settings
|
|
local left = "|r" .. string.sub(C.chat.text.bracket, 1, 1)
|
|
local right = string.sub(C.chat.text.bracket, 2, 2) .. "|r"
|
|
|
|
-- read and parse chat time bracket settings
|
|
local tleft = string.sub(C.chat.text.timebracket, 1, 1)
|
|
local tright = string.sub(C.chat.text.timebracket, 2, 2)
|
|
|
|
-- shorten chat channel indicators
|
|
local default = " " .. "%s" .. "|r:" .. "\32"
|
|
_G.CHAT_CHANNEL_GET = "%s" .. "|r:" .. "\32"
|
|
_G.CHAT_GUILD_GET = left .. "G" .. right .. default
|
|
_G.CHAT_OFFICER_GET = left .. "O" .. right .. default
|
|
_G.CHAT_PARTY_GET = left .. "P" .. right .. default
|
|
_G.CHAT_RAID_GET = left .. "R" .. right .. default
|
|
_G.CHAT_RAID_LEADER_GET = left .. "RL" .. right .. default
|
|
_G.CHAT_RAID_WARNING_GET = left .. "RW" .. right .. default
|
|
_G.CHAT_BATTLEGROUND_GET = left .. "BG" .. right .. default
|
|
_G.CHAT_BATTLEGROUND_LEADER_GET = left .. "BL" .. right .. default
|
|
_G.CHAT_SAY_GET = left .. "S" .. right .. default
|
|
_G.CHAT_YELL_GET = left .. "Y" .. right ..default
|
|
|
|
if C.chat.global.whispermod == "1" then
|
|
_G.CHAT_WHISPER_GET = wcol .. '[W]' .. default
|
|
_G.CHAT_WHISPER_INFORM_GET = '[W]' .. default
|
|
end
|
|
|
|
local r,g,b,a = GetStringColor(C.chat.text.timecolor)
|
|
local timecolorhex = rgbhex(r,g,b,a)
|
|
|
|
local r,g,b = GetStringColor(C.chat.text.unknowncolor)
|
|
local unknowncolorhex = rgbhex(r,g,b)
|
|
|
|
-- Suppress FriendsFrame's WHO_LIST_UPDATE handling for our DLL-issued
|
|
-- name lookups so they don't pop the friends panel. User-issued /who
|
|
-- still works because IsWhoQueryPending only reports true for queries
|
|
-- issued via C_FriendList.SendWhoQueryByName.
|
|
local original_FriendsFrame_OnEvent = FriendsFrame_OnEvent
|
|
_G.FriendsFrame_OnEvent = function()
|
|
if _G.event == "WHO_LIST_UPDATE" and C_FriendList.IsWhoQueryPending() then return end
|
|
return original_FriendsFrame_OnEvent()
|
|
end
|
|
|
|
local function GetPlayerLevel(name)
|
|
if not pfUI_playerDB then return nil end
|
|
if not pfUI_playerDB[name] then return nil end
|
|
return pfUI_playerDB[name].level
|
|
end
|
|
|
|
local function AddMessage(frame, text, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17)
|
|
if not text then return end
|
|
|
|
-- skip chat parsing on combat log
|
|
if frame.pfCombatLog then
|
|
return frame:HookAddMessage(text, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17)
|
|
end
|
|
|
|
-- Remove prat CLINKs
|
|
text = gsub(text, "{CLINK:(%x+):([%d-]-:[%d-]-:[%d-]-:[%d-]-:[%d-]-:[%d-]-:[%d-]-:[%d-]-):([^}]-)}", "|c%1|Hitem:%2|h[%3]|h|r") -- tbc
|
|
text = gsub(text, "{CLINK:(%x+):([%d-]-:[%d-]-:[%d-]-:[%d-]-):([^}]-)}", "|c%1|Hitem:%2|h[%3]|h|r") -- vanilla
|
|
|
|
-- Remove chatter CLINKs
|
|
text = gsub(text, "{CLINK:item:(%x+):([%d-]-:[%d-]-:[%d-]-:[%d-]-:[%d-]-:[%d-]-:[%d-]-:[%d-]-):([^}]-)}", "|c%1|Hitem:%2|h[%3]|h|r")
|
|
text = gsub(text, "{CLINK:enchant:(%x+):([%d-]-):([^}]-)}", "|c%1|Henchant:%2|h[%3]|h|r")
|
|
text = gsub(text, "{CLINK:spell:(%x+):([%d-]-):([^}]-)}", "|c%1|Hspell:%2|h[%3]|h|r")
|
|
text = gsub(text, "{CLINK:quest:(%x+):([%d-]-):([%d-]-):([^}]-)}", "|c%1|Hquest:%2:%3|h[%4]|h|r")
|
|
|
|
-- detect urls
|
|
if C.chat.text.detecturl == "1" then
|
|
text = pfUI.chat:HandleLink(text)
|
|
end
|
|
|
|
-- display class colors if already indexed
|
|
if C.chat.text.classcolor == "1" then
|
|
for name in gfind(text, "|Hplayer:(.-)|h") do
|
|
local real, _ = strsplit(":", name)
|
|
local color = unknowncolorhex
|
|
local match = false
|
|
local _, class, _, raceKey, sex = C_PlayerCache.GetPlayerInfoByName(real)
|
|
-- local guid = GetCurrentChatGUID()
|
|
-- if guid then
|
|
-- _, class = GetPlayerInfoByGUID(guid)
|
|
-- end
|
|
if not class then
|
|
class = GetUnitInfo(real)
|
|
end
|
|
if class then
|
|
if class ~= UNKNOWN then
|
|
color = "|c" .. PFUI_CLASS_COLORS[class].colorStr
|
|
match = true
|
|
end
|
|
elseif C.chat.text.whosearchunknown == "1" then
|
|
C_FriendList.SendWhoQueryByName(name) -- cooldown + state managed by DLL
|
|
end
|
|
|
|
if C.chat.text.tintunknown == "1" or match then
|
|
local icon = ""
|
|
if match and C.chat.text.playericons == "1" then
|
|
icon = GetFactionIcon(raceKey) .. GetRaceIcon(raceKey, sex)
|
|
end
|
|
text = string.gsub(text, "|Hplayer:"..name.."|h%["..real.."%]|h(.-:-)",
|
|
left..icon..color.."|Hplayer:"..name.."|h" .. color .. real .. "|h|r"..right.."%1")
|
|
end
|
|
end
|
|
end
|
|
|
|
-- display player levels if available
|
|
if C.chat.text.playerlevel == "1" then
|
|
for name in gfind(text, "|Hplayer:(.-)|h") do
|
|
local real, _ = strsplit(":", name)
|
|
local level = GetPlayerLevel(real)
|
|
|
|
if level and level > 0 then
|
|
local levelcolor = rgbhex(GetDifficultyColor(level))
|
|
-- Add level after the player name, before the closing bracket
|
|
text = string.gsub(text, "(|Hplayer:" .. name .. "|h.-|h|r)" .. right,
|
|
"%1 " .. levelcolor .. level .. "|r" .. right)
|
|
elseif level and level <= 0 then
|
|
-- Show ?? for unknown levels (e.g. -1 from UnitLevel)
|
|
text = string.gsub(text, "(|Hplayer:" .. name .. "|h.-|h|r)" .. right,
|
|
"%1 |cffff0000??|r" .. right)
|
|
end
|
|
end
|
|
end
|
|
|
|
-- reduce channel name to number
|
|
if C.chat.text.channelnumonly == "1" then
|
|
local channel = string.gsub(text, ".*%[(.-)%]%s+(.*|Hplayer).+", "%1")
|
|
if string.find(channel, "%d+%. ") then
|
|
channel = string.gsub(channel, "(%d+)%..*", "channel%1")
|
|
channel = string.gsub(channel, "channel", "")
|
|
text = string.gsub(text, "%[%d+%..-%]%s+(.*|Hplayer)", left .. channel .. right .. " %1")
|
|
end
|
|
end
|
|
|
|
-- detect the whisper prefix BEFORE prepending a timestamp; the timestamp
|
|
-- pushes the whisper colour code off position 1 and the find below fails
|
|
local isWhisper = C.chat.global.whispermod == "1" and string.find(text, wcol, 1) == 1
|
|
|
|
-- show timestamp in chat
|
|
if C.chat.text.time == "1" then
|
|
text = timecolorhex .. tleft .. date(C.chat.text.timeformat) .. tright .. "|r " .. text
|
|
end
|
|
|
|
-- save chat history
|
|
if isWhisper then
|
|
SaveChatHistory(frame:GetID(), string.gsub(text, wcol, ""), cr, cg, cb)
|
|
else
|
|
SaveChatHistory(frame:GetID(), text, a1, a2, a3)
|
|
end
|
|
|
|
if isWhisper then
|
|
-- patch incoming whisper string to match the colors
|
|
text = string.gsub(text, "|r", "|r" .. wcol)
|
|
end
|
|
|
|
frame:HookAddMessage(text, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17)
|
|
end
|
|
|
|
for i=1,NUM_CHAT_WINDOWS do
|
|
if C.chat.global.maxlines ~= "128" then
|
|
_G["ChatFrame"..i]:SetMaxLines(tonumber(C.chat.global.maxlines) or 128)
|
|
end
|
|
|
|
if not _G["ChatFrame"..i].HookAddMessage then
|
|
if C.chat.text.history == "1" then
|
|
-- write history to chat
|
|
local history = GetChatHistory(i)
|
|
for j=30,0,-1 do
|
|
if history[j] then
|
|
_G["ChatFrame"..i]:AddMessage(history[j], .7,.7,.7)
|
|
end
|
|
end
|
|
end
|
|
|
|
-- add chat parse and history hooks
|
|
_G["ChatFrame"..i].HookAddMessage = _G["ChatFrame"..i].AddMessage
|
|
_G["ChatFrame"..i].AddMessage = AddMessage
|
|
end
|
|
end
|
|
|
|
-- create playerlinks on shift-click
|
|
if C.chat.text.playerlinks == "1" then
|
|
local pfHookSetItemRef = SetItemRef
|
|
_G.SetItemRef = function(link, text, button)
|
|
if ( strsub(link, 1, 6) == "player" ) then
|
|
local name = strsub(link, 8)
|
|
if ( name and (strlen(name) > 0) ) then
|
|
local name, _ = strsplit(":", name)
|
|
name = gsub(name, "([^%s]*)%s+([^%s]*)%s+([^%s]*)", "%3")
|
|
name = gsub(name, "([^%s]*)%s+([^%s]*)", "%2")
|
|
if IsShiftKeyDown() and ChatFrameEditBox:IsVisible() then
|
|
ChatFrameEditBox:Insert("|cffffffff|Hplayer:"..name.."|h["..name.."]|h|r")
|
|
return
|
|
end
|
|
end
|
|
end
|
|
pfHookSetItemRef(link, text, button)
|
|
end
|
|
end
|
|
end)
|