Quantcast

add chat plus

rawoil [12-07-21 - 10:56]
add chat plus
Filename
rChatPlus/core.lua
rChatPlus/init.lua
rChatPlus/medias/Copy.tga
rChatPlus/rChatPlus.toc
rChatPlus/setup.lua
rChatPlus/utils.lua
rSkin/init.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 0000000..d04ad68
Binary files /dev/null and b/rChatPlus/medias/Copy.tga differ
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