From 69eff45596549a91af4f596fcf2004561b94407c Mon Sep 17 00:00:00 2001 From: rawoil Date: Tue, 7 Dec 2021 18:56:35 +0800 Subject: [PATCH] add chat plus --- rChatPlus/core.lua | 869 +++++++++++++++++++++++++++++++++++++++++++++ rChatPlus/init.lua | 64 ++++ rChatPlus/medias/Copy.tga | Bin 0 -> 715 bytes rChatPlus/rChatPlus.toc | 10 + rChatPlus/setup.lua | 19 + rChatPlus/utils.lua | 101 ++++++ rSkin/init.lua | 2 +- 7 files changed, 1064 insertions(+), 1 deletion(-) create mode 100644 rChatPlus/core.lua create mode 100644 rChatPlus/init.lua create mode 100644 rChatPlus/medias/Copy.tga create mode 100644 rChatPlus/rChatPlus.toc create mode 100644 rChatPlus/setup.lua create mode 100644 rChatPlus/utils.lua diff --git a/rChatPlus/core.lua b/rChatPlus/core.lua new file mode 100644 index 0000000..c2d2f41 --- /dev/null +++ b/rChatPlus/core.lua @@ -0,0 +1,869 @@ +local A, L = ... +local options = L.C + +-------------------------------------- +-- grab from elvui chat module +local _G = _G +local gsub, strfind, gmatch, format, max = gsub, strfind, gmatch, format, max +local ipairs, sort, wipe, time, difftime = ipairs, sort, wipe, time, difftime +local pairs, unpack, select, tostring, pcall, next, tonumber, type = pairs, unpack, select, tostring, pcall, next, tonumber, type +local strlower, strsub, strlen, strupper, strtrim, strmatch = strlower, strsub, strlen, strupper, strtrim, strmatch +local tinsert, tremove, tconcat = tinsert, tremove, table.concat + +local Ambiguate = Ambiguate +local BetterDate = BetterDate +local BNGetFriendInfo = BNGetFriendInfo +local BNGetFriendInfoByID = BNGetFriendInfoByID +local BNGetNumFriendInvites = BNGetNumFriendInvites +local BNGetNumFriends = BNGetNumFriends +local CreateFrame = CreateFrame +local FlashClientIcon = FlashClientIcon +local GetBNPlayerCommunityLink = GetBNPlayerCommunityLink +local GetBNPlayerLink = GetBNPlayerLink +local GetChannelName = GetChannelName +local GetChatWindowInfo = GetChatWindowInfo +local GetCursorPosition = GetCursorPosition +local GetCVar, GetCVarBool = GetCVar, GetCVarBool +local GetGuildRosterMOTD = GetGuildRosterMOTD +local GetInstanceInfo = GetInstanceInfo +local GetMouseFocus = GetMouseFocus +local GetNumGroupMembers = GetNumGroupMembers +local GetPlayerCommunityLink = GetPlayerCommunityLink +local GetPlayerInfoByGUID = GetPlayerInfoByGUID +local GetPlayerLink = GetPlayerLink +local GetRaidRosterInfo = GetRaidRosterInfo +local GMChatFrame_IsGM = GMChatFrame_IsGM +local GMError = GMError +local hooksecurefunc = hooksecurefunc +local InCombatLockdown = InCombatLockdown +local IsAltKeyDown = IsAltKeyDown +local IsInRaid, IsInGroup = IsInRaid, IsInGroup +local IsShiftKeyDown = IsShiftKeyDown +local PlaySoundFile = PlaySoundFile +local RemoveExtraSpaces = RemoveExtraSpaces +local RemoveNewlines = RemoveNewlines +local ToggleFrame = ToggleFrame +local UnitName = UnitName + +local C_DateAndTime_GetCurrentCalendarTime = C_DateAndTime.GetCurrentCalendarTime +local C_Club_GetInfoFromLastCommunityChatLine = C_Club.GetInfoFromLastCommunityChatLine +local Chat_GetChatCategory = Chat_GetChatCategory +local ChatHistory_GetAccessID = ChatHistory_GetAccessID +local ChatFrame_ResolvePrefixedChannelName = ChatFrame_ResolvePrefixedChannelName +local BNet_GetValidatedCharacterName = BNet_GetValidatedCharacterName +local BNet_GetClientEmbeddedTexture = BNet_GetClientEmbeddedTexture +local BNET_CLIENT_WOW = BNET_CLIENT_WOW + +local tabTexs = { + '', + 'Selected', + 'Highlight' +} + +local function GetDockerParent(docker, chat) + if not docker then return end + + local _, relativeTo = chat:GetPoint() + if relativeTo == docker then + return docker:GetParent() + end +end + +local function UpdateEditboxAnchors(self) + local cvar = (type(self) == 'string' and self) or GetCVar('chatStyle') + + local classic = cvar == 'classic' + local leftChat = classic and _G.LeftChatPanel + local panel = 22 + + for _, name in ipairs(_G.CHAT_FRAMES) do + local frame = _G[name] + local editbox = frame and frame.editBox + if not editbox then return end + editbox.chatStyle = cvar + editbox:ClearAllPoints() + + local anchorTo = leftChat or frame + local below, belowInside = options.editBoxPosition == 'BELOW_CHAT', options.editBoxPosition == 'BELOW_CHAT_INSIDE' + if below or belowInside then + -- local showLeftPanel = E.db.datatexts.panels.LeftChatDataPanel.enable + editbox:SetPoint('TOPLEFT', anchorTo, 'BOTTOMLEFT', classic and 0 or -2, (classic and (belowInside and 1 or 0) or -5)) + editbox:SetPoint('BOTTOMRIGHT', anchorTo, 'BOTTOMRIGHT', classic and 0 or -2, (classic and (belowInside and 1 or 0) or -5) + (belowInside and panel or -panel)) + else + local aboveInside = options.editBoxPosition == 'ABOVE_CHAT_INSIDE' + editbox:SetPoint('BOTTOMLEFT', anchorTo, 'TOPLEFT', classic and (aboveInside and 1 or 0) or -2, (classic and (aboveInside and -1 or 0) or 2)) + editbox:SetPoint('TOPRIGHT', anchorTo, 'TOPRIGHT', classic and (aboveInside and -1 or 0) or 2, (classic and (aboveInside and -1 or 0) or 2) + (aboveInside and -panel or panel)) + end + end +end + +local function RepositionOverflowButton() + _G.GeneralDockManagerOverflowButton:ClearAllPoints() + _G.GeneralDockManagerOverflowButton:SetPoint('RIGHT', _G.ChatFrameChannelButton, 'LEFT', -4, 0) +end + +local function CreateChatVoicePanel() + local Holder = CreateFrame('Frame', 'ChatButtonHolder', UIParent) + Holder:ClearAllPoints() + Holder:SetPoint('BOTTOMLEFT', _G.LeftChatPanel, 'TOPLEFT', 0, 1) + Holder:SetSize(30, 86) + Holder.backdrop = L.CreateBackdrop(Holder) + Holder.backdrop:SetBackdropColor(options.panelColor.r, options.panelColor.g, options.panelColor.b, options.panelColor.a) + --create drag frame + rLib:CreateDragFrame(Holder, L.dragFrames, -2, true) + + _G.ChatFrameChannelButton:ClearAllPoints() + _G.ChatFrameChannelButton:SetPoint('TOP', Holder, 'TOP', 0, -2) + + _G.ChatFrameChannelButton.Icon:SetParent(_G.ChatFrameChannelButton) + _G.ChatFrameChannelButton.Icon:SetDesaturated(options.desaturateVoiceIcons) + _G.ChatFrameChannelButton:SetParent(Holder) + + _G.ChatAlertFrame:ClearAllPoints() + _G.ChatAlertFrame:SetPoint('BOTTOM', _G.ChatFrameChannelButton, 'TOP', 1, 3) +end + +local function HandleChatVoiceIcons() + if options.hideVoiceButtons then + _G.ChatFrameChannelButton:Hide() + elseif options.pinVoiceButtons then + _G.ChatFrameChannelButton.Icon:SetDesaturated(options.desaturateVoiceIcons) + _G.ChatFrameChannelButton:ClearAllPoints() + _G.ChatFrameChannelButton:SetPoint('RIGHT', _G.GeneralDockManager, 'RIGHT', 2, 0) + + RepositionOverflowButton() + else + CreateChatVoicePanel() + end + + if not options.hideVoiceButtons then + _G.GeneralDockManagerOverflowButtonList:SetFrameStrata('LOW') + _G.GeneralDockManagerOverflowButtonList:SetFrameLevel(5) + end + + if not options.pinVoiceButtons then + _G.GeneralDockManagerOverflowButton:ClearAllPoints() + _G.GeneralDockManagerOverflowButton:SetPoint('RIGHT', _G.GeneralDockManager, 'RIGHT', -4, 0) + end +end + +local function UpdateFading() + for _, frameName in ipairs(_G.CHAT_FRAMES) do + local frame = _G[frameName] + if frame then + frame:SetTimeVisible(options.inactivityTimer) + frame:SetFading(options.fade) + end + end +end + +local canChangeMessage = function(arg1, id) + if id and arg1 == '' then return id end +end + +local function MessageIsProtected(message) + return message and (message ~= gsub(message, '(:?|?)|K(.-)|k', canChangeMessage)) +end + +local function GetOwner(tab) + if not tab.owner then + tab.owner = _G[format('ChatFrame%s', tab:GetID())] + end + + return tab.owner +end + +local function GetTab(chat) + if not chat.tab then + chat.tab = _G[format('ChatFrame%sTab', chat:GetID())] + end + + return chat.tab +end + +local function ChatFrameTab_SetAlpha(self, _, skip) + if skip then return end + local chat = GetOwner(self) + self:SetAlpha((not chat.isDocked or self.selected) and 1 or 0.6, true) +end + +local function ShowBackground(background, show) + if not background then return end + + if show then + background.Show = nil + background:Show() + else + L.Kill(background) + end +end + +local function TabOnEnter(tab) + tab.Text:Show() + + if tab.conversationIcon then + tab.conversationIcon:Show() + end + + if not options.hideCopyButton then + local chat = GetOwner(tab) + if chat and chat.copyButton and GetMouseFocus() ~= chat.copyButton then + chat.copyButton:SetAlpha(0.35) + end + end +end + +local function TabOnLeave(tab) + tab.Text:Hide() + + if tab.conversationIcon then + tab.conversationIcon:Hide() + end + + if not options.hideCopyButton then + local chat = GetOwner(tab) + if chat and chat.copyButton and GetMouseFocus() ~= chat.copyButton then + chat.copyButton:SetAlpha(0) + end + end +end + +local function ChatOnEnter(chat) + TabOnEnter(GetTab(chat)) +end + +local function ChatOnLeave(chat) + TabOnLeave(GetTab(chat)) +end + +local function IsUndocked(chat, docker) + if not docker then docker = _G.GeneralDockManager.primary end + + local primaryUndocked = docker ~= rChatPlus.LeftChatWindow and docker ~= rChatPlus.RightChatWindow + return not chat.isDocked or (primaryUndocked and ((chat == docker) or GetDockerParent(docker, chat))) +end + +local function HandleFadeTabs(chat, hook) + local tab = GetTab(chat) + + if hook then + chat:SetScript('OnEnter', ChatOnEnter) + chat:SetScript('OnLeave', ChatOnLeave) + + tab:SetScript('OnEnter', TabOnEnter) + tab:SetScript('OnLeave', TabOnLeave) + else + chat:SetScript('OnEnter', nil) + chat:SetScript('OnLeave', nil) + + tab:SetScript('OnEnter', nil) + tab:SetScript('OnLeave', nil) + end + + local focus = GetMouseFocus() + if not hook then + TabOnEnter(tab) + elseif focus ~= tab and focus ~= chat then + TabOnLeave(tab) + end +end + +local function UpdateChatTab(chat) + local fadeLeft, fadeRight + if options.fadeTabsNoBackdrop then + local both = options.panelBackdrop == 'HIDEBOTH' + fadeLeft = (both or options.panelBackdrop == 'RIGHT') + fadeRight = (both or options.panelBackdrop == 'LEFT') + end + + if chat == rChatPlus.LeftChatWindow then + GetTab(chat):SetParent(_G.LeftChatPanel or _G.UIParent) + chat:SetParent(_G.LeftChatPanel or _G.UIParent) + + HandleFadeTabs(chat, fadeLeft) + elseif chat == rChatPlus.RightChatWindow then + GetTab(chat):SetParent(_G.RightChatPanel or _G.UIParent) + chat:SetParent(_G.RightChatPanel or _G.UIParent) + + HandleFadeTabs(chat, fadeRight) + else + local docker = _G.GeneralDockManager.primary + local parent = GetDockerParent(docker, chat) + + -- we need to update the tab parent to mimic the docker + GetTab(chat):SetParent(parent or _G.UIParent) + chat:SetParent(parent or _G.UIParent) + + if parent and docker == rChatPlus.LeftChatWindow then + HandleFadeTabs(chat, fadeLeft) + elseif parent and docker == rChatPlus.RightChatWindow then + HandleFadeTabs(chat, fadeRight) + else + HandleFadeTabs(chat, options.fadeUndockedTabs and IsUndocked(chat, docker)) + end + end +end + +local function UpdateChatTabs() + for _, name in ipairs(_G.CHAT_FRAMES) do + UpdateChatTab(_G[name]) + end +end + +local function GetAnchorParents(chat) + local Left = (chat == rChatPlus.LeftChatWindow and _G.LeftChatPanel) + local Right = (chat == rChatPlus.RightChatWindow and _G.RightChatPanel) + local Chat, TabPanel = Left or Right or _G.UIParent + + return TabPanel or Chat, Chat +end + +local function ReparentVoiceChatIcon(parent) + if not parent then + parent = GetAnchorParents(_G.GeneralDockManager.primary) + end + + _G.ChatFrameChannelButton:SetParent(parent) +end + +local function FindChatWindows() + if not options.panelSnapping then return end + + local left, right = rChatPlus.LeftChatWindow, rChatPlus.RightChatWindow + + -- they already exist just return them :) + if left and right then + return left, right + end + + local docker = _G.GeneralDockManager.primary + for _, name in ipairs(_G.CHAT_FRAMES) do + local chat = _G[name] + if (chat.isDocked and docker) or chat:IsShown() then + if not left and L.FramesOverlap(chat, _G.LeftChatPanel) then + left = chat + elseif not right and L.FramesOverlap(chat, _G.RightChatPanel) then + right = chat + end + + -- if both are found just return now, don't wait + if left and right then + return left, right + end + end + end + + -- none or one was found + return left, right +end + +local function PositionChat(chat) + rChatPlus.LeftChatWindow, rChatPlus.RightChatWindow = FindChatWindows() + + local docker = _G.GeneralDockManager.primary + if chat == docker then + local iconParent, chatParent = GetAnchorParents(chat) + _G.GeneralDockManager:SetParent(chatParent) + + if options.pinVoiceButtons and not options.hideVoiceButtons then + ReparentVoiceChatIcon(iconParent or chatParent) + end + end + + UpdateChatTab(chat) + + if chat:IsMovable() then + chat:SetUserPlaced(true) + end + + if chat.FontStringContainer then + chat.FontStringContainer:ClearAllPoints() + chat.FontStringContainer:SetPoint('TOPLEFT', chat, 'TOPLEFT', -1, 1) + chat.FontStringContainer:SetPoint('BOTTOMRIGHT', chat, 'BOTTOMRIGHT', 1, -1) + end + + if chat:IsShown() then + -- that chat font container leaks outside of its frame + -- we cant clip it, so lets force that leak sooner so + -- i can position it properly, patch: 8.3.0 ~Simpy + chat:Hide() + chat:Show() + end + + local BASE_OFFSET = 32 + if chat == rChatPlus.LeftChatWindow then + local LOG_OFFSET = chat:GetID() == 2 and (_G.LeftChatTab:GetHeight() + 4) or 0 + + chat:ClearAllPoints() + chat:SetPoint('BOTTOMLEFT', _G.LeftChatPanel, 'BOTTOMLEFT', 5, 5) + chat:SetSize(options.panelWidth - 10, options.panelHeight - BASE_OFFSET - LOG_OFFSET) + + ShowBackground(chat.Background, false) + elseif chat == rChatPlus.RightChatWindow then + local LOG_OFFSET = chat:GetID() == 2 and (_G.LeftChatTab:GetHeight() + 4) or 0 + + chat:ClearAllPoints() + chat:SetPoint('BOTTOMLEFT', _G.RightChatPanel, 'BOTTOMLEFT', 5, 5) + chat:SetSize((options.separateSizes and options.panelWidthRight or options.panelWidth) - 10, (options.separateSizes and options.panelHeightRight or options.panelHeight) - BASE_OFFSET - LOG_OFFSET) + + ShowBackground(chat.Background, false) + else -- show if: not docked, or ChatFrame1, or attached to ChatFrame1 + ShowBackground(chat.Background, IsUndocked(chat, docker)) + end +end + +local function PositionChats() + for _, name in ipairs(_G.CHAT_FRAMES) do + PositionChat(_G[name]) + end +end + +local copyLines = {} +function GetLines(frame) + local index = 1 + for i = 1, frame:GetNumMessages() do + local message, r, g, b = frame:GetMessageInfo(i) + if message and not MessageIsProtected(message) then + --Set fallback color values + r, g, b = r or 1, g or 1, b or 1 + + copyLines[index] = message + index = index + 1 + end + end + + return index - 1 +end + +local function CopyChat(frame) + if not _G.CopyChatFrame:IsShown() then + local _, fontSize = _G.FCF_GetChatWindowInfo(frame:GetID()) + if fontSize < 10 then fontSize = 12 end + _G.FCF_SetChatWindowFontSize(frame, frame, 0.01) + _G.CopyChatFrame:Show() + local lineCt = GetLines(frame) + local text = tconcat(copyLines, ' \n', 1, lineCt) + _G.FCF_SetChatWindowFontSize(frame, frame, fontSize) + _G.CopyChatFrameEditBox:SetText(text) + else + _G.CopyChatFrame:Hide() + end +end + +local function CopyButtonOnMouseUp(self, btn) + local chat = self:GetParent() + if btn == 'RightButton' and chat:GetID() == 1 then + ToggleFrame(_G.ChatMenu) + else + CopyChat(chat) + end +end + +local function CopyButtonOnEnter(self) + self:SetAlpha(1) +end + +local function CopyButtonOnLeave(self) + local chat = self:GetParent() + if _G[chat:GetName()..'TabText']:IsShown() then + self:SetAlpha(0.35) + else + self:SetAlpha(0) + end +end + +local function ToggleChatButton(button) + if button then + button:SetShown(not options.hideCopyButton) + end +end + +local function Panels_ColorUpdate() + local panelColor = options.panelColor + _G.LeftChatPanel.backdrop:SetBackdropColor(panelColor.r, panelColor.g, panelColor.b, panelColor.a) + + if _G.ChatButtonHolder then + _G.ChatButtonHolder:SetBackdropColor(panelColor.r, panelColor.g, panelColor.b, panelColor.a) + end +end + +local function StyleChat(frame) + local name = frame:GetName() + local tab = GetTab(frame) + + frame:SetTimeVisible(options.inactivityTimer) + frame:SetMaxLines(options.maxLines) + frame:SetFading(options.fade) + + if frame.styled then return end + + frame:SetFrameLevel(4) + frame:SetClampRectInsets(0,0,0,0) + frame:SetClampedToScreen(false) + L.StripTextures(frame, true) + + L.Kill(_G[name..'ButtonFrame']) + + local editbox = frame.editBox + + for _, texName in pairs(tabTexs) do + _G[name..'Tab'..texName..'Left']:SetTexture() + _G[name..'Tab'..texName..'Middle']:SetTexture() + _G[name..'Tab'..texName..'Right']:SetTexture() + end + + hooksecurefunc(tab, 'SetAlpha', ChatFrameTab_SetAlpha) + + if not tab.left then tab.left = _G[name..'TabLeft'] end + tab.Text:ClearAllPoints() + tab.Text:SetPoint('LEFT', tab, 'LEFT', tab.left:GetWidth(), 0) + tab:SetHeight(22) + + if tab.conversationIcon then + tab.conversationIcon:ClearAllPoints() + tab.conversationIcon:SetPoint('RIGHT', tab.Text, 'LEFT', -1, 0) + end + + --local a, b, c = select(6, editbox:GetRegions()); a:Kill(); b:Kill(); c:Kill() + L.Kill(_G[name..'EditBoxLeft']) + L.Kill(_G[name..'EditBoxMid']) + L.Kill(_G[name..'EditBoxRight']) + + editbox:SetAltArrowKeyMode(options.useAltKey) + + --copy chat button + local copyButton = CreateFrame('Frame', format('%sCopyChatButton%d', A, id), frame) + copyButton:EnableMouse(true) + copyButton:SetAlpha(0.35) + copyButton:SetSize(20, 22) + copyButton:SetPoint('TOPRIGHT', 0, -4) + copyButton:SetFrameLevel(frame:GetFrameLevel() + 5) + frame.copyButton = copyButton + + local copyTexture = L.CreateIcon(frame.copyButton, 'OVERLAY') + copyTexture:SetTexture(options.mediapath .. "Copy.tga") + copyButton.texture = copyTexture + + copyButton:SetScript('OnMouseUp', CopyButtonOnMouseUp) + copyButton:SetScript('OnEnter', CopyButtonOnEnter) + copyButton:SetScript('OnLeave', CopyButtonOnLeave) + ToggleChatButton(copyButton) + + frame.styled = true +end + +local function SetupChat() + for _, frameName in ipairs(_G.CHAT_FRAMES) do + local frame = _G[frameName] + local id = frame:GetID() + StyleChat(frame) + + _G.FCFTab_UpdateAlpha(frame) + end + + local chat = _G.GeneralDockManager.primary + _G.GeneralDockManager:ClearAllPoints() + _G.GeneralDockManager:SetPoint('BOTTOMLEFT', chat, 'TOPLEFT', 0, 3) + _G.GeneralDockManager:SetPoint('BOTTOMRIGHT', chat, 'TOPRIGHT', 0, 3) + _G.GeneralDockManager:SetHeight(22) + _G.GeneralDockManagerScrollFrame:SetHeight(22) + _G.GeneralDockManagerScrollFrameChild:SetHeight(22) + + PositionChats() + + if not rChatPlus.HookSecured then + hooksecurefunc("FCF_OpenTemporaryWindow", SetupChat) + rChatPlus.HookSecured = true + end +end + +local function UpdateEditboxFont(chatFrame) + local style = GetCVar('chatStyle') + if style == 'classic' and rChatPlus.LeftChatWindow then + chatFrame = rChatPlus.LeftChatWindow + end + + if chatFrame == _G.GeneralDockManager.primary then + chatFrame = _G.GeneralDockManager.selected + end + + local editbox = _G.ChatEdit_ChooseBoxForSend(chatFrame) + -- the header and text will not update the placement without focus + if editbox and editbox:IsShown() then + editbox:SetFocus() + end +end + +local function ChatEdit_SetLastActiveWindow(editbox) + local style = editbox.chatStyle or GetCVar('chatStyle') + if style == 'im' then editbox:SetAlpha(0.5) end +end + +local function ChatEdit_DeactivateChat(editbox) + local style = editbox.chatStyle or GetCVar('chatStyle') + if style == 'im' then editbox:Hide() end +end + +local function ChatEdit_ActivateChat(editbox) + if editbox and editbox.chatFrame then + UpdateEditboxFont(editbox.chatFrame) + end +end + +local function ChatEdit_OnEnterPressed(editBox) + -- editBox:ClearHistory() -- we will use our own editbox history so keeping them populated on blizzards end is pointless + + local chatType = editBox:GetAttribute('chatType') + local chatFrame = chatType and editBox:GetParent() + if chatFrame and (not chatFrame.isTemporary) and (_G.ChatTypeInfo[chatType].sticky == 1) then + if not options.sticky then chatType = 'SAY' end + editBox:SetAttribute('chatType', chatType) + end +end + +local function GetCombatLog() + local LOG = _G.ChatFrame2 -- ChatFrame2 + if LOG then return LOG, GetTab(LOG) end +end + +local function FCFDock_UpdateTabs(dock) + if dock == _G.GeneralDockManager then + local logchat, logchattab = GetCombatLog() + dock.scrollFrame:ClearAllPoints() + dock.scrollFrame:SetPoint('RIGHT', dock.overflowButton, 'LEFT') + dock.scrollFrame:SetPoint('TOPLEFT', (logchat.isDocked and logchattab) or GetTab(dock.primary), 'TOPRIGHT') + end +end + +local function FCF_Close(chat) + -- clear these off when it's closed, used by FCFTab_UpdateColors + local tab = GetTab(chat) + tab.whisperName = nil + tab.classColor = nil +end + +local function FCF_SetWindowAlpha(frame, alpha) + frame.oldAlpha = alpha or 1 +end + +local function FCFTab_UpdateColors(tab, selected) + if not tab then return end + + if tab:GetParent() == _G.ChatConfigFrameChatTabManager then + if selected then + tab.Text:SetTextColor(1, 1, 1) + end + + local name = GetChatWindowInfo(tab:GetID()) + if name then + tab.Text:SetText(name) + end + + tab:SetAlpha(1) -- for some reason blizzard likes to change the alpha here? idk + else -- actual chat tab and other + local chat = GetOwner(tab) + if not chat then return end + + tab.selected = selected + + local whisper = tab.conversationIcon and chat.chatTarget + local name = chat.name or UNKNOWN + + if whisper and not tab.whisperName then + tab.whisperName = gsub(name, '([%S]-)%-[%S]+', '%1|cFF999999*|r') + end + + if selected then + if options.tabSelector == 'NONE' then + tab:SetFormattedText(rChatPlus.TabStyles.NONE, tab.whisperName or name) + else + local color = options.tabSelectorColor + local hexColor = L.RGBToHex(color.r, color.g, color.b) + tab:SetFormattedText(rChatPlus.TabStyles[options.tabSelector] or rChatPlus.TabStyles.ARROW1, hexColor, tab.whisperName or name, hexColor) + end + + if options.tabSelectedTextEnabled then + local color = options.tabSelectedTextColor + tab.Text:SetTextColor(color.r, color.g, color.b) + return -- using selected text color + end + end + + if whisper then + if not selected then + tab:SetText(tab.whisperName or name) + end + else + if not selected then + tab:SetText(name) + end + end + end +end + +local function FCFDock_SelectWindow(_, chatFrame) + if chatFrame then + UpdateEditboxFont(chatFrame) + end +end + +local function Unsnapped(chat) + if chat == rChatPlus.LeftChatWindow then + rChatPlus.LeftChatWindow = nil + elseif chat == rChatPlus.RightChatWindow then + rChatPlus.RightChatWindow = nil + end +end + +local function ClearSnapping() + rChatPlus.LeftChatWindow = nil + rChatPlus.RightChatWindow = nil +end + +local function SnappingChanged(chat) + Unsnapped(chat) + + if chat == _G.GeneralDockManager.primary then + for _, frame in ipairs(_G.GeneralDockManager.DOCKED_CHAT_FRAMES) do + PositionChat(frame) + end + else + PositionChat(chat) + end +end + +local function BuildCopyChatFrame() + local frame = CreateFrame('Frame', 'CopyChatFrame', UIParent, 'BackdropTemplate') + tinsert(_G.UISpecialFrames, 'CopyChatFrame') + frame.backdrop = L.CreateBackdrop(frame) + frame:SetSize(700, 200) + frame:SetPoint('CENTER', UIParent, 'CENTER') + frame:Hide() + frame:SetMovable(true) + frame:EnableMouse(true) + frame:SetResizable(true) + frame:SetMinResize(350, 100) + frame:SetScript('OnMouseDown', function(copyChat, button) + if button == 'LeftButton' and not copyChat.isMoving then + copyChat:StartMoving() + copyChat.isMoving = true + elseif button == 'RightButton' and not copyChat.isSizing then + copyChat:StartSizing() + copyChat.isSizing = true + end + end) + frame:SetScript('OnMouseUp', function(copyChat, button) + if button == 'LeftButton' and copyChat.isMoving then + copyChat:StopMovingOrSizing() + copyChat.isMoving = false + elseif button == 'RightButton' and copyChat.isSizing then + copyChat:StopMovingOrSizing() + copyChat.isSizing = false + end + end) + frame:SetScript('OnHide', function(copyChat) + if copyChat.isMoving or copyChat.isSizing then + copyChat:StopMovingOrSizing() + copyChat.isMoving = false + copyChat.isSizing = false + end + end) + frame:SetFrameStrata('DIALOG') + + local scrollArea = CreateFrame('ScrollFrame', 'CopyChatScrollFrame', frame, 'UIPanelScrollFrameTemplate') + scrollArea:SetPoint('TOPLEFT', frame, 'TOPLEFT', 8, -30) + scrollArea:SetPoint('BOTTOMRIGHT', frame, 'BOTTOMRIGHT', -30, 8) + scrollArea:SetScript('OnSizeChanged', function(scroll) + _G.CopyChatFrameEditBox:SetWidth(scroll:GetWidth()) + _G.CopyChatFrameEditBox:SetHeight(scroll:GetHeight()) + end) + scrollArea:SetScript('OnVerticalScroll', function(scroll, offset) + _G.CopyChatFrameEditBox:SetHitRectInsets(0, 0, offset, (_G.CopyChatFrameEditBox:GetHeight() - offset - scroll:GetHeight())) + end) + + local editBox = CreateFrame('EditBox', 'CopyChatFrameEditBox', frame) + editBox:SetMultiLine(true) + editBox:SetMaxLetters(99999) + editBox:EnableMouse(true) + editBox:SetAutoFocus(false) + editBox:SetFontObject(_G.ChatFontNormal) + editBox:SetWidth(scrollArea:GetWidth()) + editBox:SetHeight(200) + editBox:SetScript('OnEscapePressed', function() _G.CopyChatFrame:Hide() end) + scrollArea:SetScrollChild(editBox) + _G.CopyChatFrameEditBox:SetScript('OnTextChanged', function(_, userInput) + if userInput then return end + local _, Max = _G.CopyChatScrollFrameScrollBar:GetMinMaxValues() + for _ = 1, Max do + _G.ScrollFrameTemplate_OnMouseWheel(_G.CopyChatScrollFrame, -1) + end + end) + + local close = CreateFrame('Button', 'CopyChatFrameCloseButton', frame, 'UIPanelCloseButton, BackdropTemplate') + close:SetPoint('TOPRIGHT') + close:SetFrameLevel(close:GetFrameLevel() + 1) + close:EnableMouse(true) +end + +function rChatPlus:Initialize() + SetupChat() + UpdateFading() + Panels_ColorUpdate() + HandleChatVoiceIcons() + UpdateEditboxAnchors() + + hooksecurefunc("ChatEdit_SetLastActiveWindow", ChatEdit_SetLastActiveWindow) + hooksecurefunc("ChatEdit_DeactivateChat", ChatEdit_DeactivateChat) + hooksecurefunc("ChatEdit_ActivateChat", ChatEdit_ActivateChat) + hooksecurefunc("ChatEdit_OnEnterPressed", ChatEdit_OnEnterPressed) + hooksecurefunc("FCFDock_UpdateTabs", FCFDock_UpdateTabs) + hooksecurefunc("FCF_Close", FCF_Close) + hooksecurefunc("FCF_SetWindowAlpha", FCF_SetWindowAlpha) + hooksecurefunc("FCFTab_UpdateColors", FCFTab_UpdateColors) + hooksecurefunc('FCFDock_SelectWindow', FCFDock_SelectWindow) + hooksecurefunc('FCF_SavePositionAndDimensions', SnappingChanged) + hooksecurefunc('FCF_UnDockFrame', SnappingChanged) + hooksecurefunc('FCF_DockFrame', SnappingChanged) + hooksecurefunc('FCF_ResetChatWindows', ClearSnapping) + hooksecurefunc('RedockChatWindows', ClearSnapping) + + self:RegisterEvent('UPDATE_CHAT_WINDOWS') + self:RegisterEvent('UPDATE_FLOATING_CHAT_WINDOWS') + self:SetScript('OnEvent', function(self, event) + if event == 'UPDATE_CHAT_WINDOWS' or event == 'UPDATE_FLOATING_CHAT_WINDOWS' then + SetupChat() + end + end) + + BuildCopyChatFrame() + + -- Editbox Backdrop Color + hooksecurefunc('ChatEdit_UpdateHeader', function(editbox) + local chatType = editbox:GetAttribute('chatType') + if not chatType then return end + + local ChatTypeInfo = _G.ChatTypeInfo + local info = ChatTypeInfo[chatType] + local chanTarget = editbox:GetAttribute('channelTarget') + local chanName = chanTarget and GetChannelName(chanTarget) + + --Increase inset on right side to make room for character count text + local insetLeft, insetRight, insetTop, insetBottom = editbox:GetTextInsets() + editbox:SetTextInsets(insetLeft, insetRight + 30, insetTop, insetBottom) + + if not editbox.backdrop then + editbox.backdrop = L.CreateBackdrop(editbox) + end + + if chanName and (chatType == 'CHANNEL') then + if chanName == 0 then + editbox.backdrop:SetBackdropBorderColor(unpack(options.backdrop.edgeColor)) + else + info = ChatTypeInfo[chatType..chanName] + editbox.backdrop:SetBackdropBorderColor(info.r, info.g, info.b) + end + else + editbox.backdrop:SetBackdropBorderColor(info.r, info.g, info.b) + end + end) +end \ No newline at end of file diff --git a/rChatPlus/init.lua b/rChatPlus/init.lua new file mode 100644 index 0000000..1a0a0ba --- /dev/null +++ b/rChatPlus/init.lua @@ -0,0 +1,64 @@ +local A, L = ... + +L.dragFrames = {} +L.addonName = A +L.addonColor = "ff27c400" +L.addonShortcut = "rchat" + +----------------------------- +-- rChatPlus Global +----------------------------- + +rChatPlus = CreateFrame("frame") +rChatPlus.addonName = A +rChatPlus.TabStyles = { + NONE = '%s', + ARROW = '%s>|r%s%s<|r', + ARROW1 = '%s>|r %s %s<|r', + ARROW2 = '%s<|r%s%s>|r', + ARROW3 = '%s<|r %s %s>|r', + BOX = '%s[|r%s%s]|r', + BOX1 = '%s[|r %s %s]|r', + CURLY = '%s{|r%s%s}|r', + CURLY1 = '%s{|r %s %s}|r', + CURVE = '%s(|r%s%s)|r', + CURVE1 = '%s(|r %s %s)|r', +} + +----------------------------- +-- Configs +----------------------------- + +L.C = { + mediapath = "interface\\addons\\"..A.."\\medias\\", + backdrop = rLib.CopyTable(oUF_SimpleConfig.backdrop), + panelSnapping = true, + fade = true, + inactivityTimer = 100, + fontOutline = 'NONE', + sticky = true, + maxLines = 100, + tabSelector = 'ARROW1', + tabSelectedTextEnabled = true, + tabSelectedTextColor = { r = 1, g = 1, b = 1 }, + tabSelectorColor = { r = .3, g = 1, b = .3 }, + separateSizes = false, + panelWidth = 412, + panelHeight = 180, + panelWidthRight = 412, + panelHeightRight = 180, + panelBackdrop = 'SHOWBOTH', + editBoxPosition = 'ABOVE_CHAT_INSIDE', + fadeUndockedTabs = false, + fadeTabsNoBackdrop = true, + hideCopyButton = false, + useAltKey = false, + panelColor = {r = .06, g = .06, b = .06, a = 0.5}, + pinVoiceButtons = true, + hideVoiceButtons = false, + desaturateVoiceIcons = true, +} + +L.C.backdrop.edgeSize = 2 +L.C.backdrop.inset = 2 +L.C.backdrop.insets = {left=2,right=2,top=2,bottom=2} \ No newline at end of file diff --git a/rChatPlus/medias/Copy.tga b/rChatPlus/medias/Copy.tga new file mode 100644 index 0000000000000000000000000000000000000000..d04ad687ddbe7cce7cf804a2a4d7ea8e55d03356 GIT binary patch literal 715 zcmZ{iv5JF06h+4jyTw-dgnUd2t!#w^3&H$HW|w8Vt@9IU>{6smz%G!^O0)@rmD;|| znbib^SPYkY-+lMZ8C?xI-q2{q%0q6mw8?{+(JKrmL< z=wTRI9r@|sBE560*XxIlyX!h>+g41|G@?N;L*J)wwOWmQbzMtURbpG{8U%xn&aZPWmrI`m8r9o9Oy@eE&vLz9#Zaz6 zFe9J6&vbvslr9m)6Qejv6Zx}k#hb%*l2EkBF Hg*E&E!QLb7 literal 0 HcmV?d00001 diff --git a/rChatPlus/rChatPlus.toc b/rChatPlus/rChatPlus.toc new file mode 100644 index 0000000..7b80b3f --- /dev/null +++ b/rChatPlus/rChatPlus.toc @@ -0,0 +1,10 @@ +## Interface: 20502 +## Author: rawoil +## Title: rChat|cff27c400Plus|r |cff1a9fc0BCC|r +## Notes: Chat enhancements advanced +## RequiredDeps: rLib, oUF_SimpleConfig + +init.lua +utils.lua +core.lua +setup.lua \ No newline at end of file diff --git a/rChatPlus/setup.lua b/rChatPlus/setup.lua new file mode 100644 index 0000000..fcb1cae --- /dev/null +++ b/rChatPlus/setup.lua @@ -0,0 +1,19 @@ +local A, L = ... + +local options = L.C +local chatPanel = CreateFrame('Frame', 'LeftChatPanel', UIParent) +chatPanel:SetFrameStrata('BACKGROUND') +chatPanel:SetFrameLevel(300) +chatPanel:SetSize(options.panelWidth, options.panelHeight) +chatPanel:SetPoint('BOTTOMLEFT', UIParent, 4, 4) +chatPanel.backdrop = L.CreateBackdrop(chatPanel) + +--Left Chat Tab +local chatTab = CreateFrame('Frame', 'LeftChatTab', chatPanel, 'BackdropTemplate') + +rChatPlus:Initialize() + +--create drag frame +rLib:CreateDragFrame(chatPanel, L.dragFrames, -2, true) +--create slash commands +rLib:CreateSlashCmd(L.addonName, L.addonShortcut, L.dragFrames, L.addonColor) \ No newline at end of file diff --git a/rChatPlus/utils.lua b/rChatPlus/utils.lua new file mode 100644 index 0000000..7732904 --- /dev/null +++ b/rChatPlus/utils.lua @@ -0,0 +1,101 @@ +local A, L = ... + +L.HiddenFrame = CreateFrame('Frame') +L.HiddenFrame:Hide() + +--CreateBackdrop +local function CreateBackdrop(self, relativeTo, anotherBackdrop) + local backdrop = anotherBackdrop or L.C.backdrop + local parent = self.IsObjectType and self:IsObjectType('Texture') and self:GetParent() or self + local bd = CreateFrame("Frame", nil, parent, BackdropTemplateMixin and "BackdropTemplate") + if (parent:GetFrameLevel() - 1) >= 0 then + bd:SetFrameLevel(parent:GetFrameLevel() - 1) + else + bd:SetFrameLevel(0) + end + + bd:SetPoint("TOPLEFT", relativeTo or self, "TOPLEFT", -backdrop.inset, backdrop.inset) + bd:SetPoint("BOTTOMRIGHT", relativeTo or self, "BOTTOMRIGHT", backdrop.inset, -backdrop.inset) + bd:SetBackdrop(backdrop) + bd:SetBackdropColor(unpack(backdrop.bgColor)) + bd:SetBackdropBorderColor(unpack(backdrop.edgeColor)) + return bd +end +L.CreateBackdrop = CreateBackdrop + +--From http://wow.gamepedia.com/UI_coordinates +local function FramesOverlap(frameA, frameB) + if not frameA or not frameB then return end + + local sA, sB = frameA:GetEffectiveScale(), frameB:GetEffectiveScale() + if not sA or not sB then return end + + local frameALeft, frameARight, frameABottom, frameATop = frameA:GetLeft(), frameA:GetRight(), frameA:GetBottom(), frameA:GetTop() + local frameBLeft, frameBRight, frameBBottom, frameBTop = frameB:GetLeft(), frameB:GetRight(), frameB:GetBottom(), frameB:GetTop() + if not (frameALeft and frameARight and frameABottom and frameATop) then return end + if not (frameBLeft and frameBRight and frameBBottom and frameBTop) then return end + + return ((frameALeft*sA) < (frameBRight*sB)) and ((frameBLeft*sB) < (frameARight*sA)) and ((frameABottom*sA) < (frameBTop*sB)) and ((frameBBottom*sB) < (frameATop*sA)) +end +L.FramesOverlap = FramesOverlap + +local function Kill(object) + if object.UnregisterAllEvents then + object:UnregisterAllEvents() + object:SetParent(L.HiddenFrame) + else + object.Show = object.Hide + end + + object:Hide() +end +L.Kill = Kill + +--SetPoint +local function SetPoint(self,relativeTo,point) + --adjut the setpoint function to make it possible to reference a relativeTo object that is set on runtime and it not available on config init + local a,b,c,d,e = unpack(point) + if not b then + self:SetPoint(a) + elseif b and type(b) == "string" and not _G[b] then + self:SetPoint(a,relativeTo,b,c,d) + else + self:SetPoint(a,b,c,d,e) + end +end +L.SetPoint = SetPoint + +--CreateIcon +local function CreateIcon(self,layer) + local icon = self:CreateTexture(nil,layer) + icon:SetAllPoints() + return icon +end +L.CreateIcon = CreateIcon + +local function StripTextures(self, kill) + for i = 1, self:GetNumRegions() do + local Region = select(i, self:GetRegions()) + if (Region and Region:GetObjectType() == "Texture") then + if (kill and type(kill) == "boolean") then + L.Kill(Region) + elseif (Region:GetDrawLayer() == kill) then + Region:SetTexture(nil) + elseif (kill and type(kill) == "string" and Region:GetTexture() ~= kill) then + Region:SetTexture(nil) + else + Region:SetTexture(nil) + end + end + end +end +L.StripTextures = StripTextures + +--RGB to Hex +local function RGBToHex(r, g, b, header, ending) + r = r <= 1 and r >= 0 and r or 1 + g = g <= 1 and g >= 0 and g or 1 + b = b <= 1 and b >= 0 and b or 1 + return format('%s%02x%02x%02x%s', header or '|cff', r*255, g*255, b*255, ending or '') +end +L.RGBToHex = RGBToHex \ No newline at end of file diff --git a/rSkin/init.lua b/rSkin/init.lua index 35a3a20..1214ee5 100644 --- a/rSkin/init.lua +++ b/rSkin/init.lua @@ -9,7 +9,7 @@ rSkin.addonName = A rSkin.skins = {} L.C = { - style = "ZrokUI", + style = "ZorkUI", backdrop = rLib.CopyTable(oUF_SimpleConfig.backdrop), -- default bd font = oUF_SimpleConfig.fonts.expressway, -- font scale = oUF_SimpleConfig.globalscale, -- scale -- 1.7.9.5