Guest User

Cellular (Shadowlands) - core.lua

a guest
Oct 18th, 2020
151
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 45.46 KB | None | 0 0
  1. local Cellular = CreateFrame("Frame", "Cellular", UIParent, BackdropTemplateMixin and "BackdropTemplate")
  2. local a = Cellular
  3. local smed = LibStub("LibSharedMedia-3.0")
  4.  
  5. local _G = getfenv(0)
  6. local format, gsub, strmatch, gmatch = format, gsub, strmatch, gmatch
  7. local cfeb, ChatFrame_GetMessageEventFilters = ChatFrame10EditBox or ChatFrame1EditBox, ChatFrame_GetMessageEventFilters
  8.  
  9. local db, svar
  10. local you, attached, lastwindow, currenttab, eb
  11. local nwin = 0
  12. local base, tabs, usedtabs, recentw, taborder = {}, {}, {}, {}, {}
  13. local l_p, l_rt, l_rp, l_x, l_y, r_p, r_rt, r_rp, r_x, r_y
  14.  
  15. local MinimizeWindow, GetWindow, CloseWindow, ShowOptions
  16. local realmName = GetRealmName()
  17.  
  18.  
  19. a:SetScript("OnEvent", function(this, event, ...)
  20.     a[event](a, ...)
  21. end)
  22. a:RegisterEvent("ADDON_LOADED")
  23.  
  24. function a:ADDON_LOADED(a1)
  25.     if a1 ~= "Cellular" then return end
  26.     a:UnregisterEvent("ADDON_LOADED")
  27.     a.ADDON_LOADED = nil
  28.    
  29.     CellularDB = CellularDB or {}
  30.     if CellularDB.char then
  31.         CellularCharDB = CellularCharDB or (CellularDB.profiles and CellularDB.profiles.Default) or CellularDB
  32.         db = CellularCharDB
  33.     else
  34.         db = (CellularDB.profiles and CellularDB.profiles.Default) or CellularDB
  35.     end
  36.    
  37.     if db.dbinit ~= 2 then
  38.         db.dbinit = 2
  39.         for k, v in pairs({
  40.             width = 340, height = 160,
  41.             pos = { },
  42.             alpha = 0.9,
  43.             bg = "Tooltip",
  44.             bgcolor = { 0, 0, 0, 1, },
  45.             border = "Blizzard Tooltip",
  46.             bordercolor = { 0.7, 0.7, 0.7, 1, },
  47.             incolor = { 1, 0, 1, 1, },
  48.             outcolor = { 0, 1, 1, 1, },
  49.             busymessage = "Sorry, I'm busy right now...I'll chat with you later.",
  50.             history = true, enabletabs = false, char = false,
  51.             maxwindows = 8,
  52.             fade = true,
  53.             automin = false, autominalways = false,
  54.             showname = true, showtime = true, showside = true,
  55.             fontmsg = "Arial Narrow", fonttitle = "Arial Narrow", fontsize = 12,
  56.         }) do
  57.             db[k] = (db[k] ~= nil and db[k]) or v
  58.         end
  59.     end
  60.     db.border = (type(db.border) == "string" and db.border) or (db.border and "Blizzard Tooltip") or "None"
  61.     a:SetAlpha(db.alpha)
  62.    
  63.     Cellular_History = Cellular_History or { }  -- saved history per char
  64.     svar = Cellular_History
  65.    
  66.     SlashCmdList.CELLULAR = ShowOptions
  67.     SLASH_CELLULAR1, SLASH_CELLULAR2 = "/cellular", "/cell"
  68.     local panel = CreateFrame("Frame", BackdropTemplateMixin and "BackdropTemplate")
  69.     panel.name = "Cellular"
  70.     panel:SetScript("OnShow", function(this)
  71.         local t1 = this:CreateFontString(nil, "ARTWORK", "GameFontNormalLarge")
  72.         t1:SetJustifyH("LEFT")
  73.         t1:SetJustifyV("TOP")
  74.         t1:SetPoint("TOPLEFT", 16, -16)
  75.         t1:SetText(this.name)
  76.        
  77.         local t2 = this:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
  78.         t2:SetJustifyH("LEFT")
  79.         t2:SetJustifyV("TOP")
  80.         t2:SetHeight(43)
  81.         t2:SetPoint("TOPLEFT", t1, "BOTTOMLEFT", 0, -8)
  82.         t2:SetPoint("RIGHT", this, "RIGHT", -32, 0)
  83.         t2:SetNonSpaceWrap(true)
  84.         t2:SetFormattedText( "Notes: %s\nAuthor: %s\nVersion: %s",
  85.                 GetAddOnMetadata("Cellular", "Notes"),
  86.                 GetAddOnMetadata("Cellular", "Author"),
  87.                 GetAddOnMetadata("Cellular", "Version") )
  88.    
  89.         local b = CreateFrame("Button", nil, this, "UIPanelButtonTemplate")
  90.         b:SetWidth(120)
  91.         b:SetHeight(20)
  92.         b:SetText("Options Menu")
  93.         b:SetScript("OnClick", ShowOptions)
  94.         b:SetPoint("TOPLEFT", t2, "BOTTOMLEFT", -2, -8)
  95.         this:SetScript("OnShow", nil)
  96.     end)
  97.     InterfaceOptions_AddCategory(panel)
  98.    
  99.     local cevents = { "CHAT_MSG_WHISPER", "CHAT_MSG_WHISPER_INFORM", "CHAT_MSG_AFK", "CHAT_MSG_DND", "CHAT_MSG_IGNORED", }
  100.     if not db.nobn then
  101.         tinsert(cevents, "CHAT_MSG_BN_WHISPER")
  102.         tinsert(cevents, "CHAT_MSG_BN_WHISPER_INFORM")
  103.     end
  104.     for _, v in ipairs(cevents) do
  105.         a:RegisterEvent(v)
  106.     end
  107.     you = UnitName("player")
  108.     a.pratloaded = select(4, GetAddOnInfo("Prat-3.0"))
  109.    
  110.     CONFIGMODE_CALLBACKS = CONFIGMODE_CALLBACKS or {}
  111.     CONFIGMODE_CALLBACKS.Cellular = function(action, mode)
  112.         if action == "ON" then
  113.             SendChatMessage("Hey self, entering cheap config mode.", "WHISPER", nil, you)
  114.         end
  115.     end
  116.  
  117.     if not db.chatshow then  -- don't display some messages to the chat frame
  118.         local _G = getfenv(0)
  119.         local function Unreg(frame)
  120.             if type(frame) ~= "table" then return end
  121.             for _, v in ipairs(cevents) do
  122.                 frame:UnregisterEvent(v)
  123.             end
  124.         end
  125.         for i = 1, NUM_CHAT_WINDOWS, 1 do
  126.             Unreg(_G["ChatFrame"..i])
  127.         end
  128.         hooksecurefunc("ChatFrame_AddMessageGroup", Unreg)
  129.         hooksecurefunc("ChatFrame_RegisterForMessages", Unreg)
  130.     end
  131. end
  132.  
  133. --- EVENTS
  134. local function Filter(event, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14)
  135.     local cfilter = ChatFrame_GetMessageEventFilters(event)
  136.     if cfilter then  -- filter
  137.         for _, filterFunc in next, cfilter do
  138.             local filter, n1,n2,n3,n4,n5,n6,n7,n8,n9,n10,n11,n12,n13,n14 = filterFunc(a, event, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14)
  139.             if filter then
  140.                 return true
  141.             elseif n1 and n2 then
  142.                 a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14 = n1,n2,n3,n4,n5,n6,n7,n8,n9,n10,n11,n12,n13,n14
  143.             end
  144.         end
  145.     end
  146.     if a7 < 1 or (a7 >= 1 and _G.CHAT_SHOW_ICONS ~= "0") then  -- chat icons
  147.         for tag in gmatch(a1, "%b{}") do
  148.             local termlist = ICON_TAG_LIST[ strlower(gsub(tag, "[{}]", "")) ]
  149.             local icon = termlist and ICON_LIST[termlist]
  150.             if icon then
  151.                 a1 = gsub(a1, tag, icon.."0|t")
  152.             end
  153.         end
  154.     end
  155.     return a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14
  156. end
  157.  
  158. function a:CHAT_MSG_WHISPER(...)
  159.     local a1,a2,_,_,_,a6,_,_,_,_,a11,a12 = Filter("CHAT_MSG_WHISPER", ...)
  160.     if a2 and a6 ~= "GM" then
  161.         a:IncomingMessage(a2, a1, a6, nil, a11, a12)
  162.     end
  163. end
  164.    
  165. function a:CHAT_MSG_BN_WHISPER(...)  -- battle.net incoming whisper
  166.     local a1,a2,_,_,_,a6,_,_,_,_,a11,a12,a13,a14,a15 = Filter("CHAT_MSG_BN_WHISPER", ...)
  167.     if a2 then
  168.         a:IncomingMessage(a2, a1, a6, nil, a11, a12, a13)
  169.     end
  170. end
  171.  
  172. function a:CHAT_MSG_WHISPER_INFORM(...)
  173.     local a1, a2 = Filter("CHAT_MSG_WHISPER_INFORM", ...)
  174.     if a2 and (not GMChatFrame_IsGM or not GMChatFrame_IsGM(a2)) then  -- don't handle GM whispers
  175.         a:OutgoingMessage(a2, a1)
  176.     end
  177. end
  178.  
  179. function a:CHAT_MSG_BN_WHISPER_INFORM(...)  -- battle.net outgoing whisper
  180.     local a1,a2,_,_,_,_,_,_,_,_,_,_,a13,a14,a15 = Filter("CHAT_MSG_BN_WHISPER_INFORM", ...)
  181.     if a2 then
  182.         a:OutgoingMessage(a2, a1, a13)
  183.     end
  184. end
  185.  
  186. function a:CHAT_MSG_AFK(a1, a2)
  187.     a:IncomingMessage(a2, a2.." is AFK: "..a1, nil, 2)
  188. end
  189.  
  190. function a:CHAT_MSG_DND(a1, a2)
  191.     a:IncomingMessage(a2, a2.." is DND: "..a1, nil, 3)
  192. end
  193.  
  194. function a:CHAT_MSG_IGNORED(_, a2)
  195.     a:IncomingMessage(a2, a2.." is ignoring you.", nil, 4)
  196. end
  197.  
  198. -- parse some important system messages when chatting to someone
  199. local parstrings
  200. function a:CHAT_MSG_SYSTEM(text)
  201.     if not taborder[1] or not text then return end
  202.     if not parstrings then
  203.         parstrings = {
  204.             "|Hplayer:(.+)|h%[(.+)%]|h(.+)", ERR_FRIEND_OFFLINE_S,
  205.             JOINED_PARTY, LEFT_PARTY, ERR_DECLINE_GROUP_S,
  206.             ERR_RAID_MEMBER_ADDED_S, ERR_RAID_MEMBER_REMOVED_S,
  207.             ERR_GUILD_JOIN_S, ERR_GUILD_DECLINE_S, ERR_GUILD_LEAVE_S,
  208.             ERR_PETITION_DECLINED_S, ERR_PETITION_SIGNED_S,
  209.         }
  210.         for index, s in ipairs(parstrings) do
  211.             parstrings[index] = gsub(s, "%%s", "(.+)")
  212.         end
  213.     end
  214.     for index, s in ipairs(parstrings) do
  215.         local name = strmatch(text, s)
  216.         if name then
  217.             return a:IncomingMessage(name, text, nil, 1)
  218.         end
  219.     end
  220. end
  221. function a:CHAT_MSG_TEXT_EMOTE(emote, sender)
  222.     if taborder[1] and strfind(emote, " you") then
  223.         a:IncomingMessage(sender, emote, nil, 1)
  224.     end
  225. end
  226.  
  227. --- TAB ORGANIZATION
  228. local function UpdateTabOrder(id)  -- update tab order and set positions
  229.     if not db.enabletabs then return end
  230.     currenttab = id or currenttab or 1
  231.     base[1].tab = currenttab
  232.     local n = #taborder + 0.4
  233.     local tabsize = (db.width - (2*n + 48)) / n
  234.     local i = 0
  235.     for _, tid in ipairs(taborder) do
  236.         i = i + 1
  237.         local t = tabs[tid]
  238.         t:SetPoint("TOPLEFT", base[1], "TOPLEFT", ((i-1)*tabsize) + (2*i) + 8, -6)
  239.         if tid == currenttab then
  240.             if not t:GetParent().mini then
  241.                 t.mininew = 0
  242.                 t.text:SetText(t.name)
  243.                 t.msg:Show()
  244.             end
  245.             t:SetBackdropColor(0, 0, 0, 0)
  246.             t.text:SetTextColor(t.text.r or 1, t.text.g or 1, t.text.b or 1, 1)
  247.             i = i + 0.4 -- makes active tab 40% wider
  248.         else
  249.             t.msg:Hide()
  250.             t:SetBackdropColor(0.7, 0.7, 0.7, 0.7)
  251.             t.text:SetTextColor(0.8, 0.8, 0.8, 0.8)
  252.         end
  253.         t:SetPoint("BOTTOMRIGHT", base[1], "TOPLEFT", (i*tabsize) + (2*i) + 8, -20)
  254.     end
  255.     if #taborder < 1 then
  256.         CloseWindow(tabs[1])
  257.     end
  258. end
  259. local function RemoveTab(id, activeid)  -- remove a tab and reorganize
  260.     if not id then return end
  261.     for index, tid in pairs(taborder) do
  262.         if tid == id or id == "a" then
  263.             local tab = tabs[tid]
  264.             usedtabs[tab.name] = nil
  265.             tab:Hide()
  266.             tab.text.r, tab.text.g, tab.text.b = nil, nil, nil
  267.             tremove(taborder, index)
  268.             if IsControlKeyDown() then
  269.                 svar[tabs[(id == "a" and activeid) or tid].name] = nil
  270.             end
  271.         end
  272.     end
  273.     currenttab = (id == currenttab and taborder[1]) or currenttab
  274.     if attached == id and cfeb:IsShown() then
  275.         ChatEdit_DeactivateChat(cfeb)
  276.     end
  277.     UpdateTabOrder()
  278. end
  279.  
  280. --- EDITBOX
  281. local function ResetEditBox()  -- reset the editbox to it's normal position
  282.     if not attached then return end
  283.     cfeb:ClearAllPoints()
  284.     cfeb:SetParent(l_rt)
  285.     cfeb:SetPoint(l_p, l_rt, l_rp, l_x, l_y)
  286.     if r_p then cfeb:SetPoint(r_p, r_rt, r_rp, r_x, r_y) end
  287.     attached = nil
  288. end
  289. local skipupdate
  290. local sw = _G.SLASH_SMART_WHISPER1.." "
  291. local function AttachEditBox(id, skiptext, skipset)  -- attach the main chat editbox to the current person you're whispering
  292.     local tab = tabs[id]
  293.     if not tab:IsShown() then return end
  294.     if not db.noattach then
  295.         ChatEdit_ActivateChat(cfeb)
  296.         cfeb.setText = 1
  297.         cfeb.text = sw..tab.name.." "
  298.         ChatEdit_UpdateHeader(cfeb)
  299.         ChatEdit_ParseText(cfeb, 0)
  300.         if not attached then
  301.             l_p, l_rt, l_rp, l_x, l_y = cfeb:GetPoint(1)
  302.             r_p, r_rt, r_rp, r_x, r_y = cfeb:GetPoint(2)
  303.         end
  304.         cfeb:SetParent(tab:GetParent())
  305.         cfeb:ClearAllPoints()
  306.         if db.showtop then
  307.             cfeb:SetPoint("BOTTOMLEFT", tab:GetParent(), "TOPLEFT", 0, -6)
  308.             cfeb:SetPoint("BOTTOMRIGHT", tab:GetParent(), "TOPRIGHT", 0, -6)
  309.         else
  310.             cfeb:SetPoint("TOPLEFT", tab:GetParent(), "BOTTOMLEFT", 0, 6)
  311.             cfeb:SetPoint("TOPRIGHT", tab:GetParent(), "BOTTOMRIGHT", 0, 6)
  312.         end
  313.         attached = id
  314.         cfeb:SetFocus()
  315.     else
  316.         if tab.name and tab.name ~= "" then
  317.             local editBox = ChatEdit_ChooseBoxForSend()
  318.             local lastTell, lastTellType = ChatEdit_GetLastTellTarget();
  319.             if lastTell then
  320.                 editBox:SetAttribute("chatType", lastTellType)
  321.                 editBox:SetAttribute("tellTarget", tab.name)
  322.                 ChatEdit_UpdateHeader(editBox)
  323.                 if editBox ~= ChatEdit_GetActiveWindow() then
  324.                     ChatFrame_OpenChat("")
  325.                 end
  326.             end
  327.         end
  328.     end
  329. end
  330. local function ToggleEditBox(id, hidediff)
  331.     if not db.noattach and (attached == id or (attached and hidediff)) then
  332.         ChatEdit_DeactivateChat(cfeb)
  333.     elseif not hidediff and id then
  334.         AttachEditBox(id)
  335.     end
  336. end
  337.  
  338. --- MESSAGE HANDLERS
  339. GetWindow = function(name, isSpecial, showmore, battleTag)  -- retrieve window
  340.     local id = usedtabs[name]
  341.     if (not id or not tabs[id] or not tabs[id]:IsShown()) and not isSpecial then
  342.         local t
  343.         for _, tab in ipairs(tabs) do  -- assumes if a window is hidden, it's unused
  344.             if not tab:IsShown() then
  345.                 t = tab
  346.                 break
  347.             end
  348.         end
  349.         t = t or a:CreateWindow()  -- if no windows are available, make a new one
  350.         if t then  -- still no windows, you probably hit maximum allowed
  351.             t.name = name
  352.             t.lastspecial = nil
  353.             t.tag = nil
  354.            
  355.             t.msg:Clear()
  356.             t.msg:ScrollToBottom()
  357.             local history = svar[battleTag or name]
  358.             if history then  -- show recent history if available
  359.                 local n = #history
  360.                 local numlines = (showmore and 50) or 15
  361.                 if n > numlines then
  362.                     t.msg:AddMessage("**See ..\\WTF \\Account \\<Account Name> \\<Server> \\<Character> \\SavedVariables \\Cellular.lua for more**", 1, 1, 0)
  363.                 end
  364.                 for i = max(1, n-numlines), n, 1 do
  365.                     t.msg:AddMessage(history[i], 0.6, 0.6, 0.6)
  366.                 end
  367.                 if not a.memchecked and (not db.memcheck or db.memcheck + 21600 < time()) then  -- quick memory check
  368.                     db.memcheck = time()
  369.                     UpdateAddOnMemoryUsage()
  370.                     local mem = GetAddOnMemoryUsage("Cellular")
  371.                     if mem and mem > 490 then
  372.                         t.msg:AddMessage(format("History usage is high ( +%d KB ). Consider cleaning it.", mem - 85), 0.7, 0.5, 0.5)
  373.                     end
  374.                 end
  375.                 a.memchecked = true
  376.             end
  377.             id = t.id
  378.             usedtabs[name] = id
  379.             tinsert(taborder, id)
  380.             t:GetParent():Show()
  381.             t:Show()
  382.             t.mininew = 0
  383.             t.text:SetText(t.name)
  384.             t.msg:Show()
  385.             t:EnableMouse(db.enabletabs)
  386.             UpdateTabOrder(currenttab or taborder[1])
  387.             if id  and  (db.autominalways or (db.automin and InCombatLockdown()))  and  (not db.enabletabs or #taborder == 1) then
  388.                 MinimizeWindow(t:GetParent().Minimize)
  389.             end
  390.         end
  391.     end
  392.     return id
  393. end
  394.  
  395. do
  396.     local ChatEdit_SetLastTellTarget, GetTime = ChatEdit_SetLastTellTarget, GetTime
  397.     local function HandleHistory(name, dname, text, battleTag)  -- history tracking
  398.         recentw[name] = true
  399.         if not db.history then return end
  400.  
  401.         local t = svar[battleTag or name]
  402.         if not t then
  403.             svar[battleTag or name] = {}
  404.             t = svar[battleTag or name]
  405.         end
  406.         t[#t + 1] = format("<%s>[%s] %s", date("%m-%d-%y %H:%M"), dname, text)
  407.         if eb and eb:IsShown() and eb.name == name then
  408.             eb.max = #t
  409.         end
  410.     end
  411.     local function HandleWindow(name, special, text, battleTag)  -- window check
  412.         if not name then return end
  413.         local id = GetWindow(name, special, nil, battleTag)
  414.         if not id then
  415.             if not special then
  416.                 print(format("|cff88ff88Cellular|r: Max windows reached - [%s] %s", name, text))
  417.             end
  418.             return
  419.         end
  420.         lastwindow = id
  421.         return tabs[id]
  422.     end
  423.     local function addmsg(fmsg, out, form, ...)
  424.         local c = (out and db.outcolor) or db.incolor
  425.         fmsg:AddMessage(format(form, ...), c[1], c[2], c[3], c[4])
  426.     end
  427.     local lastTell = 0
  428.  
  429.     function a:IncomingMessage(name, text, status, special, cid, guid, isbn)  -- handles the displaying of all incoming whisper messages
  430.         local battleTag, presenceName, _, toonName
  431.         name = gsub(name, "-" .. realmName, "")
  432.         if isbn then
  433.             _, presenceName, battleTag, _, toonName = C_BattleNet.GetAccountInfoByID(isbn)
  434.         end
  435.         local f = HandleWindow(name, special, text, battleTag)
  436.         if not f then return end
  437.        
  438.         local ctime = GetTime()
  439.         if special then  -- handle special messages (system, afk, dnd, etc) and reduces the spam
  440.             if special == 1 then
  441.                 f.msg:AddMessage(format("[%s] %s", date("%H:%M:%S"), text), 1, 1, 0)
  442.             else
  443.                 if not f.lastspecial or ctime > f.lastspecial + 90 or f.tag ~= special then
  444.                     f.lastspecial = ctime
  445.                     f.tag = special
  446.                     f.msg:AddMessage(format("[%s] %s", date("%H:%M:%S"), text), 1, 0, 0)
  447.                 end
  448.             end
  449.             return
  450.         end
  451.        
  452.         -- handles the status flags (GM, AFK, DND)
  453.         status, cid = status or "", cid or ""
  454.         if status ~= "" then
  455.             status = ((status == "GM" or status == "DEV") and " |TInterface\\ChatFrame\\UI-ChatIcon-Blizz.blp:0:2:0:-3|t") or format(" (%s)", status)
  456.         end
  457.         local tname = gsub(name, "-(.+)", "")  -- remove realm name
  458.         if isbn then
  459.             if db.showname and db.showtime then  -- finally add the message to whisper window
  460.                 addmsg(f.msg, nil, "|HBNplayer:%s:%s:%s:BN_WHISPER:%s|h[%s %s|h%s] %s", name, isbn, cid, name, gsub(date("%I:%M:%S"), "^0", ""), tname, status, text)
  461.             elseif db.showtime then
  462.                 addmsg(f.msg, nil, "|HBNplayer:%s:%s:%s:BN_WHISPER:%s|h[%s|h%s] %s", name, isbn, cid, name, gsub(date("%I:%M:%S"), "^0", ""), status, text)
  463.             elseif db.showname then
  464.                 addmsg(f.msg, nil, "|HBNplayer:%s:%s:%s:BN_WHISPER:%s|h[%s|h%s] %s", name, isbn, cid, name, tname, status, text)
  465.             else
  466.                 addmsg(f.msg, nil, "|HBNplayer:%s:%s:%s:BN_WHISPER:%s|h[>|h%s] %s", name, isbn, cid, name, status, text)
  467.             end
  468.         else
  469.             if db.showname and db.showtime then  -- finally add the message to whisper window
  470.                 addmsg(f.msg, nil, "|Hplayer:%s:%s:WHISPER:%s|h[%s %s|h%s] %s", name, cid, strupper(name), gsub(date("%I:%M:%S"), "^0", ""), tname, status, text)
  471.             elseif db.showtime then
  472.                 addmsg(f.msg, nil, "|Hplayer:%s:%s:WHISPER:%s|h[%s|h%s] %s", name, cid, strupper(name), gsub(date("%I:%M:%S"), "^0", ""), status, text)
  473.             elseif db.showname then
  474.                 addmsg(f.msg, nil, "|Hplayer:%s:%s:WHISPER:%s|h[%s|h%s] %s", name, cid, strupper(name), tname, status, text)
  475.             else
  476.                 addmsg(f.msg, nil, "|Hplayer:%s:%s:WHISPER:%s|h[>|h%s] %s", name, cid, strupper(name), status, text)
  477.             end
  478.         end
  479.        
  480.         local r, g, b
  481.         if ChatTypeInfo.WHISPER and ChatTypeInfo.WHISPER.colorNameByClass and guid and guid ~= "" then
  482.             local _, englishClass, _, _, _ = GetPlayerInfoByGUID(guid)
  483.             local cc = englishClass and (CUSTOM_CLASS_COLORS or RAID_CLASS_COLORS)[englishClass]
  484.             r, g, b = cc and cc.r or 1, cc and cc.g or 1, cc and cc.b or 1
  485.             f.text.r, f.text.g, f.text.b = r, g, b
  486.         else
  487.             f.text.r, f.text.g, f.text.b = nil, nil, nil
  488.         end
  489.         if not f.msg:IsVisible() then  -- update number of whispers received if minimized
  490.             f.mininew = f.mininew + 1
  491.             r, g, b = 0.8, 0, 0
  492.             f.text:SetFormattedText("%s (%d)", f.name, f.mininew)
  493.         end
  494.         f.text:SetTextColor(r or 1, g or 1, b or 1, 1)
  495.  
  496.         ChatEdit_SetLastTellTarget(name, isbn and "BN_WHISPER" or "WHISPER")
  497.         HandleHistory(name, tname, text, battleTag)  -- add entry to history
  498.  
  499.         if ctime > lastTell + 2 then  -- support for whisper sound alerts
  500.             if a.pratloaded and Prat.Addon:GetModule("Sounds", true) then
  501.                 a.PLAYERLINK = name
  502.                 Prat.Addon:GetModule("Sounds", true):Prat_PostAddMessage(nil, a, nil, "CHAT_MSG_WHISPER")
  503.             elseif ChatSounds_InitConfig then
  504.                 ChatSounds_PlaySound(ChatSounds_Config[ChatSounds_Player].Incoming["WHISPER"])
  505.             elseif not ChatSoundsDB then
  506.                 --PlaySound("TellMessage")
  507.             end
  508.             lastTell = ctime
  509.         end
  510.     end
  511.  
  512.     function a:OutgoingMessage(name, text, isbn) -- handles the displaying of all outgoing whisper messages
  513.         local battleTag, presenceName, _, toonName
  514.         name = gsub(name, "-" .. realmName, "")
  515.         if isbn then
  516.             _, presenceName, battleTag, _, toonName = C_BattleNet.GetAccountInfoByID(isbn)
  517.         end
  518.         local f = HandleWindow(name, nil, text, battleTag)
  519.         if not f then return end
  520.         if db.showname and db.showtime then
  521.             addmsg(f.msg, true, "[%s %s] %s", gsub(date("%I:%M:%S"), "^0", ""), you, text)
  522.         elseif db.showtime then
  523.             addmsg(f.msg, true, "[%s] %s", gsub(date("%I:%M:%S"), "^0", ""), text)
  524.         elseif db.showname then
  525.             addmsg(f.msg, true, "[%s] %s", you, text)
  526.         else
  527.             addmsg(f.msg, true, "[<] %s", text)
  528.         end
  529.        
  530.         HandleHistory(name, you, text, battleTag)
  531.         if a.pratloaded and Prat.Addon:GetModule("Sounds", true) then
  532.             a.PLAYERLINK = you
  533.             Prat.Addon:GetModule("Sounds", true):Prat_PostAddMessage(nil, a, nil, "CHAT_MSG_WHISPER_INFORM")
  534.         elseif ChatSounds_InitConfig then
  535.             ChatSounds_PlaySound(ChatSounds_Config[ChatSounds_Player].Outgoing["WHISPER"])
  536.         end
  537.     end
  538. end
  539.  
  540. --- FRAME/VISUAL STUFF
  541. -- button functions
  542. local buttons
  543. local function ApplyFont(t, font, fontsize, fontstyle)
  544.     if fontstyle == "Shadow" then
  545.         t:SetFont(smed:Fetch("font", font), fontsize)
  546.         t:SetShadowColor(0, 0, 0, 0.7)
  547.         t:SetShadowOffset(1, -1)
  548.     else
  549.         t:SetFont(smed:Fetch("font", font), fontsize, fontstyle ~= "None" and fontstyle)
  550.         t:SetShadowOffset(0, 0)
  551.     end
  552. end
  553. do
  554.     local function Who(this)
  555.         C_FriendList.SendWho(tabs[this:GetParent().tab].name)
  556.     end
  557.     local function Busy(this)
  558.         local bm = db.busymessage
  559.         if bm and bm ~= "" then
  560.             SendChatMessage(bm, "WHISPER", nil, tabs[this:GetParent().tab].name)
  561.         end
  562.     end
  563.     local function Social(this)
  564.         if not IsShiftKeyDown() then return end
  565.         local b, n = this.text, tabs[this:GetParent().tab].name
  566.         if b == _G.CHAT_INVITE_SEND then
  567.             InviteUnit(n)
  568.         elseif b == _G.ADD_FRIEND then
  569.             AddFriend(n)
  570.         elseif b == _G.IGNORE_PLAYER then
  571.             AddIgnore(n)
  572.         end
  573.     end
  574.     local function Scroll(this)
  575.         local f = tabs[this:GetParent().tab].msg
  576.         f[this.text](f)
  577.     end
  578.     MinimizeWindow = function(this)
  579.         local p = this:GetParent()
  580.         local t = tabs[p.tab]
  581.         if not p.mini then
  582.             p.mini = 1
  583.             p:SetHeight(28)
  584.             for b, k in pairs(buttons) do
  585.                 if not k.dontmin then
  586.                     p[b]:Hide()
  587.                 end
  588.             end
  589.             p.resizer:Hide()
  590.             p.mininew = 0
  591.             t.msg:Hide()
  592.         else
  593.             p.mini = nil
  594.             p:SetHeight(db.height)
  595.             for b, k in pairs(buttons) do
  596.                 if db.showside or not k.side then
  597.                     p[b]:Show()
  598.                 end
  599.             end
  600.             p.resizer:Show()
  601.             t.mininew = 0
  602.             t.text:SetText(t.name)
  603.             t.text:SetTextColor(t.text.r or 1, t.text.g or 1, t.text.b or 1, 1)
  604.             t.msg:Show()
  605.         end
  606.         if eb and eb:IsShown() then eb:Hide() end
  607.     end
  608.     CloseWindow = function(this)
  609.         local p = this:GetParent()
  610.         if p.mini then MinimizeWindow(p.Minimize) end
  611.         if attached == p.tab then ChatEdit_DeactivateChat(cfeb) end
  612.         if eb and eb:IsShown() then eb:Hide() end
  613.         if db.enabletabs then
  614.             for i = 1, #taborder, 1 do
  615.                 RemoveTab("a", p.tab)
  616.             end
  617.             currenttab = 1
  618.         else
  619.             RemoveTab(p.tab)
  620.         end
  621.         p:Hide()
  622.     end
  623.     local EButtonClick
  624.     local function CreateEButton(texture, left, close)
  625.         local f = CreateFrame("Button", nil, eb)
  626.         f:SetWidth(16)
  627.         f:SetHeight(16)
  628.         f:SetNormalTexture(texture)
  629.         f:SetHighlightTexture("Interface\\Minimap\\UI-Minimap-ZoomButton-Highlight")
  630.         EButtonClick = EButtonClick or function(this)
  631.             local p = this:GetParent()
  632.             p.i = (this.back and max(p.i-1, 1)) or min(p.max, p.i + 1)
  633.             p:SetText(svar[p.name][p.i])
  634.             p:HighlightText()
  635.             p:SetFocus()
  636.         end
  637.         f:SetScript("OnClick", (not close and EButtonClick) or function(this) this:GetParent():Hide() end)
  638.         f:SetPoint("BOTTOMLEFT", left, "BOTTOMRIGHT", -1, 0)
  639.         return f
  640.     end
  641.     local function Copy(this)
  642.         local p = this:GetParent()
  643.         local t = tabs[p.tab]
  644.         local h = svar[t.name]
  645.         if not h or not h[1] then return end
  646.         if not eb then
  647.             eb = CreateFrame("EditBox", "CellularEB", UIParent)
  648.             ApplyFont(eb, db.fontmsg, db.fontsize, db.fontmsgstyle)
  649.             eb:SetMaxLetters(600)
  650.             eb.back = CreateEButton("Interface\\Buttons\\UI-SpellbookIcon-PrevPage-Up", eb)
  651.             eb.forward = CreateEButton("Interface\\Buttons\\UI-SpellbookIcon-NextPage-Up", eb.back)
  652.             eb.close = CreateEButton("Interface\\Buttons\\UI-Panel-MinimizeButton-Up", eb.forward, true)
  653.             eb.back.back = true
  654.             eb:Hide()
  655.             eb:SetHeight(16)
  656.             eb:SetScript("OnEscapePressed", function(this) this:Hide() this:ClearFocus() end)
  657.             eb:SetScript("OnEditFocusLost", function(this) this:Hide() end)
  658.         end
  659.         if eb:IsShown() and eb.name == t.name then
  660.             eb:Hide()
  661.         else
  662.             eb.name = t.name
  663.             eb.max = #h
  664.             eb.i = eb.max
  665.             eb:SetText(h[eb.i])
  666.             eb:ClearAllPoints()
  667.             if db.showtop then
  668.                 eb:SetPoint("LEFT", p, "BOTTOMLEFT", -4, -5)
  669.                 eb:SetPoint("RIGHT", p, "BOTTOMRIGHT", -40, -5)
  670.             else
  671.                 eb:SetPoint("LEFT", p, "TOPLEFT", -4, 5)
  672.                 eb:SetPoint("RIGHT", p, "TOPRIGHT", -40, 5)
  673.             end
  674.             eb:Show()
  675.             eb:HighlightText()
  676.             eb:SetFocus()
  677.         end
  678.     end
  679.  
  680.     buttons = {
  681.         [_G.WHO] = { p="TOPLEFT", x=6, y=-22, tt=1, path="Interface\\Icons\\INV_Misc_QuestionMark", func=Who, side=true, },
  682.         ["\"I'm Busy!\""] = { p="TOPLEFT", x=6, y=-42, tt=1, path="Interface\\Icons\\Spell_Holy_Silence", func=Busy, side=true, },
  683.         [_G.CHAT_INVITE_SEND] = { p="TOPLEFT", x=6, y=-59, tt=2, path="Interface\\Icons\\Spell_Holy_PrayerofSpirit", func=Social, side=true, },
  684.         [_G.ADD_FRIEND] = { p="TOPLEFT", x=6, y=-76, tt=2, path="Interface\\Icons\\Spell_ChargePositive", func=Social, side=true, },
  685.         [_G.IGNORE_PLAYER] = { p="TOPLEFT", x=6, y=-95, tt=2, path="Interface\\Icons\\Spell_ChargeNegative", func=Social, side=true, },
  686.         [_G.CALENDAR_COPY_EVENT] = { p="BOTTOMLEFT", x=6, y=6, tt=3, path="Interface\\Icons\\INV_Scroll_01", func=Copy, side=true, },
  687.         ScrollUp = { p="BOTTOMRIGHT", x=-6, y=42, path="Interface\\ChatFrame\\UI-ChatIcon-ScrollUp-Up", func=Scroll, },
  688.         ScrollDown = { p="BOTTOMRIGHT", x=-6, y=26, path="Interface\\ChatFrame\\UI-ChatIcon-ScrollDown-Up", func=Scroll, },
  689.         ScrollToBottom = { p="BOTTOMRIGHT", x=-6, y=10, path="Interface\\ChatFrame\\UI-ChatIcon-ScrollEnd-Up", func=Scroll, },
  690.         [_G.CLOSE] = { p="TOPRIGHT", x=-6, y=-6, tt=1, tpl="UIPanelButtonTemplate", func=CloseWindow, bt = "x", dontmin = true, },
  691.         Minimize = { p="TOPRIGHT", x=-22, y=-6, tt=1, tpl="UIPanelButtonTemplate", func=MinimizeWindow, bt = "-", dontmin = true, },
  692.     }
  693. end
  694.  
  695. -- backdrop table
  696. local bdt = { tileSize = 16, edgeSize = 16, insets = { left = 4, right = 4, top = 4, bottom = 4, }, }
  697. local bdt2 = { bgFile = "Interface\\Tooltips\\UI-Tooltip-Background", tile = true, tileSize = 16, }
  698.  
  699. local function UpdateBaseVars(f)  -- updates main window's variable settings
  700.     bdt.bgFile = smed:Fetch(db.bglist or "statusbar", db.bg)
  701.     bdt.tile = (db.bg == "Tooltip")
  702.     bdt.edgeFile = smed:Fetch("border", db.border)
  703.     f:SetBackdrop(bdt)
  704.     f:SetBackdropColor(unpack(db.bgcolor))
  705.     f:SetBackdropBorderColor(unpack(db.bordercolor))
  706.     if db.strata then f:SetFrameStrata(db.strata) end
  707.     for b, k in pairs(buttons) do
  708.         if k.side and db.showside then
  709.             f[b]:Show()
  710.         elseif k.side then
  711.             f[b]:Hide()
  712.         end
  713.     end
  714. end
  715.  
  716. local function UpdateTabVars(f)  -- updates tab's variable settings
  717.     ApplyFont(f.text, db.fonttitle, 12, db.fonttitlestyle)
  718.     ApplyFont(f.msg, db.fontmsg, db.fontsize, db.fontmsgstyle)
  719.     f.msg:SetFading(db.fade)
  720.     f.msg:SetPoint("TOPLEFT", f:GetParent(), "TOPLEFT", db.showside and 24 or 8, -18)
  721.     f.msg:SetPoint("BOTTOMRIGHT", f:GetParent(), "BOTTOMRIGHT", -20, 8)
  722. end
  723.  
  724. local function UpdateSizes(reset)
  725.     if reset then
  726.         db.width, db.height = 340, 160
  727.     end
  728.     for _, f in pairs(base) do
  729.         f:SetWidth(db.width)
  730.         f:SetHeight(db.height)
  731.     end
  732. end
  733.  
  734. local function UpdatePosition(this, reset)
  735.     db.pos[this.id] = db.pos[this.id] or {}
  736.    
  737.     local t = db.pos[this.id]
  738.    
  739.     if reset then
  740.         this:ClearAllPoints()
  741.         this:SetPoint("TOPLEFT", UIParent, "CENTER", (this.id - 1) * 20 + 100, -(this.id - 1) * 20)
  742.         t.p, t.rp, t.x, t.y = "TOPLEFT", "BOTTOMLEFT", this:GetLeft(), this:GetTop()
  743.     elseif (this:GetTop() - db.height/2) > (GetScreenHeight()/2) then
  744.         t.p, t.rp, t.x, t.y = "TOPLEFT", "BOTTOMLEFT", this:GetLeft(), this:GetTop()
  745.     else
  746.         t.p, t.rp, t.x, t.y = "BOTTOMLEFT", "BOTTOMLEFT", this:GetLeft(), this:GetBottom()
  747.     end
  748.     this:ClearAllPoints()
  749.     this:SetPoint(t.p, UIParent, t.rp, t.x, t.y)
  750. end
  751.  
  752. do  -- button creation and layout handler
  753.     local gtt = GameTooltip
  754.    
  755.     local function BOnEnter(this)
  756.         gtt:SetOwner(this, "ANCHOR_BOTTOMLEFT")
  757.         gtt:SetText(this.text, 1, 1, 1)
  758.         if this.tt then
  759.             if this.tt == 2 then
  760.                 gtt:AddLine(" Shift-click to execute", 0, 1, 0)
  761.             elseif not db.history and this.tt == 3 then
  762.                 gtt:AddLine(" History must be enabled", 0, 1, 0)
  763.             end
  764.         end
  765.         gtt:Show()
  766.     end
  767.    
  768.     local function GttHide() gtt:Hide() end
  769.     local function BDown(this) this:SetAlpha(0.3) end
  770.     local function BUp(this) this:SetAlpha(0.6) end
  771.    
  772.     local function ResizeStart(this)
  773.         if not IsShiftKeyDown() then
  774.             if not a.shiftsaid2 then
  775.                 print("|cff00ff00Cellular|r: Hold shift and drag to resize.")
  776.                 a.shiftsaid2 = true
  777.             end
  778.             return
  779.         end
  780.         this:GetParent():StartSizing("BOTTOMRIGHT")
  781.     end
  782.    
  783.     local function ResizeEnd(this)
  784.         local p = this:GetParent()
  785.         p:StopMovingOrSizing()
  786.         db.height, db.width = floor(p:GetHeight() + 0.5), floor(p:GetWidth() + 0.5)
  787.         UpdateSizes()
  788.         UpdateTabOrder()
  789.         UpdatePosition(p)
  790.     end
  791.    
  792.     local function DragStart(this)
  793.         if not IsShiftKeyDown() then
  794.             if not a.shiftsaid then
  795.                 print("|cff00ff00Cellular|r: Hold shift and drag to move.")
  796.                 a.shiftsaid = true
  797.             end
  798.             return
  799.         end
  800.         this = this.msg and this:GetParent() or this
  801.         this:StartMoving()
  802.     end
  803.    
  804.     local function DragStop(this)
  805.         this = this.msg and this:GetParent() or this
  806.         this:StopMovingOrSizing()
  807.         UpdatePosition(this)
  808.     end
  809.    
  810.     local function Wheel(this, a1)
  811.         if not a1 then return end
  812.         local t = tabs[this.tab].msg
  813.         if a1 > 0 then
  814.             t:ScrollUp()
  815.             t:ScrollUp()
  816.         else
  817.             t:ScrollDown()
  818.             t:ScrollDown()
  819.         end
  820.     end
  821.    
  822.     local function MainClick(this, a1)
  823.         if a1 == "RightButton" then
  824.             ShowOptions()
  825.         else
  826.             ToggleEditBox(this.tab)
  827.         end
  828.     end
  829.    
  830.     local function TabOnClick(this, a1)
  831.         if a1 == "LeftButton" then
  832.             local id = this.id
  833.             ToggleEditBox(id, currenttab ~= id)
  834.             if currenttab ~= id then
  835.                 UpdateTabOrder(id)
  836.             end
  837.         elseif a1 == "RightButton" then
  838.             ShowOptions(nil, this.id)
  839.         elseif a1 == "MiddleButton" then
  840.             RemoveTab(this.id)
  841.         end
  842.     end
  843.    
  844.     local function TabOnEnter(this)
  845.         gtt:SetOwner(this, "ANCHOR_TOPLEFT")
  846.         gtt:SetText(this.text:GetText(), 1, 1, 1)
  847.         gtt:Show()
  848.     end
  849.  
  850.     function a:CreateBase(id)
  851.         if base[id] then return base[id] end
  852.        
  853.         local f = CreateFrame("Button", "CellularWindow"..id, a, BackdropTemplateMixin and "BackdropTemplate")
  854.         f:SetWidth(db.width)
  855.         f:SetHeight(db.height)
  856.         local pos = db.pos[id]
  857.         if pos then
  858.             f:SetPoint(pos.p or "TOPLEFT", UIParent, pos.rp or "TOPLEFT", pos.x, pos.y)
  859.         else
  860.             f:SetPoint("TOPLEFT", UIParent, "CENTER", (id-1)*20 + 100, -(id-1)*20)
  861.         end
  862.         f.id = id
  863.         f:SetMovable(true)
  864.         f:SetResizable(true)
  865.         f:EnableMouseWheel(true)
  866.         f:RegisterForClicks("LeftButtonUp", "RightButtonUp")
  867.         f:RegisterForDrag("LeftButton")
  868.         f:SetScript("OnDragStart", DragStart)
  869.         f:SetScript("OnDragStop", DragStop)
  870.         f:SetScript("OnClick", MainClick)
  871.         f:SetScript("OnMouseWheel", Wheel)
  872.         f:SetClampedToScreen(true)
  873.         f:SetClampRectInsets(10, -10, -10, 10)
  874.        
  875.         -- resizing button
  876.         f:SetMinResize(120, 80)
  877.         local resize = CreateFrame("Button", nil, f, "UIPanelButtonGrayTemplate")
  878.         resize:SetWidth(8)
  879.         resize:SetHeight(8)
  880.         resize:SetPoint("BOTTOMRIGHT", f, "BOTTOMRIGHT", -4, 4)
  881.         resize:SetScript("OnMouseDown", ResizeStart)
  882.         resize:SetScript("OnMouseUp", ResizeEnd)
  883.         if ChatFrame1ResizeButton then
  884.             resize:SetNormalTexture("Interface\\ChatFrame\\UI-ChatIM-SizeGrabber-Up")
  885.             resize:SetHighlightTexture("Interface\\ChatFrame\\UI-ChatIM-SizeGrabber-Highlight")
  886.             resize:SetWidth(14)
  887.             resize:SetHeight(14)
  888.         end
  889.         f.resizer = resize
  890.        
  891.         -- all the buttons
  892.         for bn, t in pairs(buttons) do
  893.             local b = CreateFrame("Button", nil, f, t.tpl)
  894.             b:SetWidth(16)
  895.             b:SetHeight(16)
  896.             b.text = bn
  897.             b:SetPoint(t.p, f, t.p, t.x, t.y)
  898.             if t.path then
  899.                 b:SetNormalTexture(t.path)
  900.                 b:SetHighlightTexture("Interface\\Minimap\\UI-Minimap-ZoomButton-Highlight")
  901.             end
  902.             b:SetScript("OnMouseDown", BDown)
  903.             b:SetScript("OnMouseUp", BUp)
  904.             b:SetScript("OnClick", t.func)
  905.             if t.tt then
  906.                 b:SetScript("OnEnter", BOnEnter)
  907.                 b:SetScript("OnLeave", GttHide)
  908.                 b.tt = t.tt
  909.             end
  910.             b:SetText(t.bt)
  911.             b:SetAlpha(0.6)
  912.             f[bn] = b
  913.         end
  914.        
  915.         UpdateBaseVars(f)
  916.         UpdatePosition(f)
  917.         base[id] = f
  918.         return f
  919.     end
  920.  
  921.     function a:CreateTab(id, parent)
  922.         if tabs[id] then return tabs[id] end
  923.        
  924.         local t = CreateFrame("Button", nil, parent, BackdropTemplateMixin and "BackdropTemplate")
  925.         t:SetPoint("TOPLEFT", parent, "TOPLEFT", 8, -6)
  926.         t:SetPoint("BOTTOMRIGHT", parent, "TOPRIGHT", -8, -20)
  927.         t:RegisterForClicks("LeftButtonUp", "RightButtonUp", "MiddleButtonUp")
  928.         t:RegisterForDrag("LeftButton")
  929.         t:SetScript("OnClick", TabOnClick)
  930.         t:SetScript("OnEnter", TabOnEnter)
  931.         t:SetScript("OnLeave", GttHide)
  932.         t:SetScript("OnDragStart", DragStart)
  933.         t:SetScript("OnDragStop", DragStop)
  934.         t:SetBackdrop(bdt2)
  935.         t:SetBackdropColor(0,0,0,0)
  936.         t.id = id
  937.        
  938.         -- button text (not needed if someone tells me how to justify button text)
  939.         t.text = t:CreateFontString(nil, "ARTWORK")
  940.         t.text:SetJustifyH("LEFT")
  941.         t.text:SetJustifyV("TOP")
  942.         t.text:SetAllPoints(t)
  943.        
  944.         -- scrolling text
  945.         local m = CreateFrame("ScrollingMessageFrame", nil, t)
  946.         m:SetHyperlinksEnabled(true)
  947.         m:UnregisterAllEvents()
  948.         m:SetJustifyH("LEFT")
  949.         m:SetTimeVisible(120)
  950.         m:SetMaxLines(100)
  951.         m:SetScript("OnHyperlinkClick", ChatFrame_OnHyperlinkShow)
  952.         m:SetScript("OnHyperlinkEnter", ChatFrame1:GetScript("OnHyperlinkEnter"))
  953.         m:SetScript("OnHyperlinkLeave", GttHide)
  954.         m:Hide()
  955.         t.msg = m
  956.        
  957.         UpdateTabVars(t)
  958.         tabs[id] = t
  959.         return t
  960.     end
  961.  
  962.     function a:CreateWindow()
  963.         if nwin >= db.maxwindows then return end
  964.         nwin = nwin + 1
  965.         if nwin == 1 then  -- setup system events and hooks
  966.             a:RegisterEvent("CHAT_MSG_SYSTEM")
  967.             a:RegisterEvent("CHAT_MSG_TEXT_EMOTE")
  968.  
  969.             hooksecurefunc("ChatFrame_ReplyTell", function(chatframe)
  970.                 local lastTell = ChatEdit_GetLastTellTarget()
  971.                 if not lastTell or lastTell == "" then return end
  972.                 local id = GetWindow(lastTell)
  973.                 if id then
  974.                     AttachEditBox(id)
  975.                     UpdateTabOrder(id)
  976.                 end
  977.             end)
  978.             hooksecurefunc("ChatEdit_DeactivateChat", ResetEditBox)
  979.         end
  980.         if not db.enabletabs or (db.enabletabs and nwin == 1) then  -- create full windows
  981.             local f = a:CreateBase(nwin)
  982.             f.tab = nwin
  983.             return a:CreateTab(nwin, f)
  984.         else  -- create tabs
  985.             return a:CreateTab(nwin, base[1])
  986.         end
  987.     end
  988. end
  989.  
  990. local CellularDD
  991. local info, list = { }, { }
  992. local offsetvalue, offsetcount, lastb, showid
  993. ShowOptions = function(a1, id)
  994.     showid = type(id) == "number" and id
  995.     if not CellularDD then
  996.         CellularDD = CreateFrame("Frame", "CellularDD", Cellular, BackdropTemplateMixin and "BackdropTemplate")
  997.         CellularDD.displayMode = "MENU"
  998.        
  999.         hooksecurefunc("ToggleDropDownMenu", function(...) lastb = select(8, ...) end)
  1000.         local function UpdateSettings()
  1001.             Cellular:SetAlpha(db.alpha)
  1002.             for _, f in pairs(base) do
  1003.                 UpdateBaseVars(f)
  1004.             end
  1005.             for _, t in pairs(tabs) do
  1006.                 UpdateTabVars(t)
  1007.             end
  1008.         end
  1009.        
  1010.         local function HideCheck(b)
  1011.             if b and b.GetName and _G[b:GetName().."Check"] then
  1012.                 _G[b:GetName().."Check"]:Hide()
  1013.             end
  1014.         end
  1015.        
  1016.         local function CloseMenu(b)
  1017.             if not b or not b:GetParent() then return end
  1018.             CloseDropDownMenus(b:GetParent():GetID())
  1019.         end
  1020.        
  1021.         local function RefreshMenu(b)
  1022.             local tb = _G[gsub(lastb:GetName(), "ExpandArrow", "")]
  1023.             CloseMenu(b)
  1024.             ToggleDropDownMenu(b:GetParent():GetID(), tb.value, nil, nil, nil, nil, tb.menuList, tb)
  1025.         end
  1026.        
  1027.         local function Exec(b, k, value)
  1028.             HideCheck(b)
  1029.             if (k == "less" or k == "more") and lastb then
  1030.                 local off = (k == "less" and -8) or 8
  1031.                 if offsetvalue == value then
  1032.                     offsetcount = offsetcount + off
  1033.                 else
  1034.                     offsetvalue, offsetcount = value, off
  1035.                 end
  1036.                 RefreshMenu(b)
  1037.                
  1038.             elseif k == "showtab" then
  1039.                 CloseMenu(b)
  1040.                 ToggleEditBox(value, currenttab ~= value)
  1041.                 if currenttab ~= value then
  1042.                     UpdateTabOrder(value)
  1043.                 end
  1044.            
  1045.             elseif k == "removetab" then
  1046.                 CloseMenu(b)
  1047.                 RemoveTab(value)
  1048.            
  1049.             elseif k == "showoptions" then
  1050.                 CloseMenu(b)
  1051.                 ShowOptions()
  1052.            
  1053.             elseif k == "resetsizes" then
  1054.                 UpdateSizes(true)
  1055.                 for id, f in pairs(base) do
  1056.                     UpdatePosition(f, true)
  1057.                 end
  1058.            
  1059.             elseif k == "movehelp" then
  1060.                 print("|cff00ff00Cellular|r: Hold shift and drag empty space to move or bottom-right corner to resize windows.")
  1061.            
  1062.             elseif k == "busymessage" then
  1063.                 StaticPopupDialogs["CellularBusy"] = StaticPopupDialogs["CellularBusy"] or {
  1064.                     text = "Set your busy message.",
  1065.                     button1 = ACCEPT, button2 = CANCEL,
  1066.                     hasEditBox = 1, maxLetters = 60, editBoxWidth = 350,
  1067.                     OnAccept = function(this)
  1068.                         db.busymessage = this.editBox:GetText() or ""
  1069.                     end,
  1070.                     EditBoxOnEnterPressed = function(this)
  1071.                         db.busymessage = this:GetParent().editBox:GetText() or ""
  1072.                         this:GetParent():Hide()
  1073.                     end,
  1074.                     EditBoxOnEscapePressed = function(this)
  1075.                         this:GetParent():Hide()
  1076.                     end,
  1077.                     OnShow = function(this)
  1078.                         this.editBox:SetText(db.busymessage or "")
  1079.                         this.editBox:SetFocus()
  1080.                     end,
  1081.                     OnHide = function(this)
  1082.                         this.editBox:SetText("")
  1083.                     end,
  1084.                     timeout = 0, exclusive = 1, whileDead = 1, hideOnEscape = 1,
  1085.                 }
  1086.                 StaticPopup_Show("CellularBusy")
  1087.            
  1088.             elseif k == "clearall" and IsShiftKeyDown() then
  1089.                 for name in pairs(svar) do
  1090.                     svar[name] = nil
  1091.                 end
  1092.                 print("|cff00ff00Cellular|r: History cleared.")
  1093.            
  1094.             elseif k == "clearold" and IsShiftKeyDown() then
  1095.                 local cdays = tonumber(date("%y")) * 365.25 + tonumber(date("%m")) * 30.4 + tonumber(date("%d"))
  1096.                 local cleared = 0
  1097.                 for name, t in pairs(svar) do
  1098.                     while true do
  1099.                         if #t < 1 then
  1100.                             svar[name] = nil
  1101.                             break
  1102.                         end
  1103.                         local m, d, y = strmatch(t[1], "<(%d+)-(%d+)-(%d+) ")
  1104.                         if m and d and y then
  1105.                             local days = tonumber(y) * 365.25 + tonumber(m) * 30.4 + tonumber(d)
  1106.                             if days + 42 < cdays then
  1107.                                 cleared = cleared + 1
  1108.                                 tremove(t, 1)
  1109.                             else
  1110.                                 break
  1111.                             end
  1112.                         else
  1113.                             break
  1114.                         end
  1115.                     end
  1116.                 end
  1117.                 print("|cff00ff00Cellular|r: "..cleared.." history entries removed.")
  1118.             end
  1119.         end
  1120.        
  1121.         local function Set(b, k)
  1122.             if not k then return end
  1123.             db[k] = not db[k]
  1124.             if k == "enabletabs" then
  1125.                 if nwin < 1 then return end
  1126.                
  1127.                 local v = db.enabletabs
  1128.                
  1129.                 for i, tab in pairs(tabs) do
  1130.                     local p = base[(v and 1) or i] or a:CreateBase((v and 1) or i)
  1131.                     tab:GetParent():Hide()
  1132.                     tab:SetParent(p)
  1133.                     tab:EnableMouse(db.enabletabs)
  1134.                     tab.msg:SetPoint("TOPLEFT", p, "TOPLEFT", db.showside and 24 or 8, -18)
  1135.                     tab.msg:SetPoint("BOTTOMRIGHT", p, "BOTTOMRIGHT", -20, 8)
  1136.                     if not v then
  1137.                         if not tab:GetParent().mini then
  1138.                             tab.mininew = 0
  1139.                             tab.text:SetText(tab.name)
  1140.                             tab.msg:Show()
  1141.                         end
  1142.                         tab:ClearAllPoints()
  1143.                         tab:SetPoint("TOPLEFT", p, "TOPLEFT", 8, -6)
  1144.                         tab:SetPoint("BOTTOMRIGHT", p, "TOPRIGHT", -8, -20)
  1145.                         tab:SetBackdropColor(0, 0, 0, 0)
  1146.                         tab.text:SetTextColor(tab.text.r or 1, tab.text.g or 1, tab.text.b or 1, 1)
  1147.                         p.tab = tab.id
  1148.                     end
  1149.                     tab:GetParent():Hide()
  1150.                 end
  1151.                
  1152.                 for _, id in pairs(usedtabs) do
  1153.                     tabs[id]:GetParent():Show()
  1154.                     tabs[id]:Show()
  1155.                 end
  1156.                
  1157.                 UpdateTabOrder(lastwindow or taborder[1])
  1158.                 ChatEdit_DeactivateChat(cfeb)
  1159.                
  1160.             elseif k == "char" or k == "chatshow" or k == "nobn" then
  1161.                 print("|cff00ff00Cellular|r: This setting requires a reload and will effect all characters.")
  1162.            
  1163.             else
  1164.                 UpdateSettings()
  1165.             end
  1166.         end
  1167.        
  1168.         local function SetSelect(b, a1)
  1169.             HideCheck(b)
  1170.            
  1171.             if a1 == "show" or a1 == "recent" then
  1172.                 GetWindow(b.value, nil, true)
  1173.            
  1174.             elseif a1 == "clear" then
  1175.                 if IsShiftKeyDown() then
  1176.                     svar[b.value] = nil
  1177.                     RefreshMenu(b)
  1178.                 end
  1179.            
  1180.             else
  1181.                 db[a1] = tonumber(b.value) or b.value
  1182.                 local level, num = strmatch(b:GetName(), "DropDownList(%d+)Button(%d+)")
  1183.                 level, num = tonumber(level) or 0, tonumber(num) or 0
  1184.                 for i = 1, UIDROPDOWNMENU_MAXBUTTONS, 1 do
  1185.                     local b = _G["DropDownList"..level.."Button"..i.."Check"]
  1186.                     if b then
  1187.                         b[i == num and "Show" or "Hide"](b)
  1188.                     end
  1189.                 end
  1190.                 UpdateSettings()
  1191.             end
  1192.         end
  1193.        
  1194.         local function SetColor(a1)
  1195.             local dbc = db[UIDROPDOWNMENU_MENU_VALUE]
  1196.             if not dbc then return end
  1197.             if a1 then
  1198.                 local pv = ColorPickerFrame.previousValues
  1199.                 dbc[1], dbc[2], dbc[3], dbc[4] = pv.r, pv.g, pv.b, 1 - pv.opacity
  1200.             else
  1201.                 dbc[1], dbc[2], dbc[3] = ColorPickerFrame:GetColorRGB()
  1202.                 dbc[4] = 1 - OpacitySliderFrame:GetValue()
  1203.             end
  1204.             UpdateSettings()
  1205.         end
  1206.        
  1207.         local function AddButton(lvl, text, keepshown)
  1208.             info.text = text
  1209.             info.keepShownOnClick = keepshown
  1210.             UIDropDownMenu_AddButton(info, lvl)
  1211.             wipe(info)
  1212.         end
  1213.        
  1214.         local function AddToggle(lvl, text, value)
  1215.             info.arg1 = value
  1216.             info.func = Set
  1217.             info.checked = db[value]
  1218.             info.isNotRadio = true
  1219.             AddButton(lvl, text, 1)
  1220.         end
  1221.        
  1222.         local function AddExecute(lvl, text, arg1, arg2)
  1223.             info.arg1 = arg1
  1224.             info.arg2 = arg2
  1225.             info.func = Exec
  1226.             info.notCheckable = 1
  1227.             AddButton(lvl, text, 1)
  1228.         end
  1229.        
  1230.         local function AddColor(lvl, text, value)
  1231.             local dbc = db[value]
  1232.             if not dbc then return end
  1233.             info.hasColorSwatch = true
  1234.             info.hasOpacity = 1
  1235.             info.r, info.g, info.b, info.opacity = dbc[1], dbc[2], dbc[3], 1 - (dbc[4] or 1)
  1236.             info.swatchFunc, info.opacityFunc, info.cancelFunc = SetColor, SetColor, SetColor
  1237.             info.value = value
  1238.             info.notCheckable = 1
  1239.             info.func = UIDropDownMenuButton_OpenColorPicker
  1240.             AddButton(lvl, text, nil)
  1241.         end
  1242.        
  1243.         local function AddList(lvl, text, value)
  1244.             info.value = value
  1245.             info.hasArrow = true
  1246.             info.func = HideCheck
  1247.             info.notCheckable = 1
  1248.             AddButton(lvl, text, 1)
  1249.         end
  1250.        
  1251.         local function AddSelect(lvl, text, arg1, value)
  1252.             info.arg1 = arg1
  1253.             info.func = SetSelect
  1254.             info.value = value
  1255.             if tonumber(value) and tonumber(db[arg1] or "blah") then
  1256.                 if floor(100 * tonumber(value)) == floor(100 * tonumber(db[arg1])) then
  1257.                     info.checked = true
  1258.                 end
  1259.             else
  1260.                 info.checked = (db[arg1] == value)
  1261.             end
  1262.             AddButton(lvl, text, 1)
  1263.         end
  1264.        
  1265.         local function AddFakeSlider(lvl, value, minv, maxv, step, tbl)
  1266.             local cvalue = 0
  1267.             local dbv = db[value]
  1268.             if type(dbv) == "string" and tbl then
  1269.                 for i, v in ipairs(tbl) do
  1270.                     if dbv == v then
  1271.                         cvalue = i
  1272.                         break
  1273.                     end
  1274.                 end
  1275.             else
  1276.                 cvalue = dbv or floor((maxv - minv) / 2)
  1277.             end
  1278.             local adj = (offsetvalue == value and offsetcount) or 0
  1279.             local starti = max(minv, cvalue - (7 - adj) * step)
  1280.             local endi = min(maxv, cvalue + (8 + adj) * step)
  1281.             if starti == minv then
  1282.                 endi = min(maxv, starti + 16 * step)
  1283.             elseif endi == maxv then
  1284.                 starti = max(minv, endi - 16 * step)
  1285.             end
  1286.             if starti > minv then
  1287.                 AddExecute(lvl, "--", "less", value)
  1288.             end
  1289.             if tbl then
  1290.                 for i = starti, endi, step do
  1291.                     AddSelect(lvl, tbl[i], value, tbl[i])
  1292.                 end
  1293.             else
  1294.                 local fstring = (step >= 1 and "%d") or (step >= 0.1 and "%.1f") or "%.2f"
  1295.                 for i = starti, endi, step do
  1296.                     AddSelect(lvl, format(fstring, i), value, i)
  1297.                 end
  1298.             end
  1299.             if endi < maxv then
  1300.                 AddExecute(lvl, "++", "more", value)
  1301.             end
  1302.         end
  1303.         CellularDD.initialize = function(self, lvl)
  1304.             if lvl == 1 then
  1305.                 if showid then
  1306.                     AddExecute(lvl, "Show Message (or left-click)", "showtab", showid)
  1307.                     AddExecute(lvl, "Close Tab (or middle-click)", "removetab", showid)
  1308.                     info.isTitle = true
  1309.                     AddButton(lvl, " ")
  1310.                     AddExecute(lvl, "Options", "showoptions")
  1311.                 else
  1312.                     info.isTitle = true
  1313.                     info.notCheckable = 1
  1314.                     AddButton(lvl, "|cff5555ffCellular|r")
  1315.                     AddList(lvl, "Frame", "frame")
  1316.                     AddList(lvl, "Text", "text")
  1317.                     AddList(lvl, "Behavior", "behave")
  1318.                     AddList(lvl, "History", "history")
  1319.                 end
  1320.             elseif lvl == 2 then
  1321.                 local sub = UIDROPDOWNMENU_MENU_VALUE
  1322.                 if sub == "frame" then
  1323.                     AddList(lvl, "Texture Group", "bglist")
  1324.                     AddList(lvl, "Background Texture", "bg")
  1325.                     AddColor(lvl, "Background Color", "bgcolor")
  1326.                     AddList(lvl, "Border", "border")
  1327.                     AddColor(lvl, "Border Color", "bordercolor")
  1328.                     AddToggle(lvl, "Show Side Buttons", "showside")
  1329.                     AddList(lvl, "Frame Opacity", "alpha")
  1330.                     AddList(lvl, "Frame Strata", "strata")
  1331.                     AddExecute(lvl, "Reset Size and Position", "resetsizes")
  1332.                     AddExecute(lvl, "How to Move/Resize", "movehelp")
  1333.                 elseif sub == "text" then
  1334.                     AddToggle(lvl, "Show Name", "showname")
  1335.                     AddToggle(lvl, "Show Timestamp", "showtime")
  1336.                     AddToggle(lvl, "Fade Old Messages", "fade")
  1337.                     AddList(lvl, "Title Font", "fonttitle")
  1338.                     AddList(lvl, "Title Style", "fonttitlestyle")
  1339.                     AddList(lvl, "Message Font", "fontmsg")
  1340.                     AddList(lvl, "Message Style", "fontmsgstyle")
  1341.                     AddList(lvl, "Message Font Size", "fontsize")
  1342.                     AddColor(lvl, "Incoming Font Color", "incolor")
  1343.                     AddColor(lvl, "Outgoing Font Color", "outcolor")
  1344.                 elseif sub == "behave" then
  1345.                     AddToggle(lvl, "Use Tabs", "enabletabs")
  1346.                     AddToggle(lvl, "No battle.net", "nobn")
  1347.                     AddToggle(lvl, "Combat Auto-Minimize", "automin")
  1348.                     AddToggle(lvl, "Always Auto-Minimize", "autominalways")
  1349.                     AddToggle(lvl, "Editbox Top Anchor", "showtop")
  1350.                     AddToggle(lvl, "Disable EditBox Move", "noattach")
  1351.                     AddToggle(lvl, "Disable Block to Default", "chatshow")
  1352.                     AddList(lvl, "Maximum Windows/Tabs", "maxwindows")
  1353.                     AddExecute(lvl, "Set Busy Message", "busymessage")
  1354.                     AddToggle(lvl, "Save Settings Per Character", "char")
  1355.                 elseif sub == "history" then
  1356.                     AddToggle(lvl, "Enable History", "history")
  1357.                     AddList(lvl, "Show Recent", "recent")
  1358.                     AddList(lvl, "Show Entry", "show")
  1359.                     AddList(lvl, "Clear Entry (hold shift)", "clear")
  1360.                     AddExecute(lvl, "Clear +6 Weeks (hold shift)", "clearold")
  1361.                     AddExecute(lvl, "Clear All (hold shift)", "clearall")
  1362.                 end
  1363.             elseif lvl == 3 then
  1364.                 local sub = UIDROPDOWNMENU_MENU_VALUE
  1365.                 if sub == "bglist" then
  1366.                     AddSelect(lvl, "background", sub, "background")
  1367.                     AddSelect(lvl, "statusbar", sub, "statusbar")
  1368.                 elseif sub == "bg" then
  1369.                     local t = smed:List(db.bglist or "statusbar")
  1370.                     AddFakeSlider(lvl, sub, 1, #t, 1, t)
  1371.                 elseif sub == "fonttitle" or sub == "fontmsg" then
  1372.                     local t = smed:List("font")
  1373.                     AddFakeSlider(lvl, sub, 1, #t, 1, t)
  1374.                 elseif sub == "border" then
  1375.                     local t = smed:List("border")
  1376.                     AddFakeSlider(lvl, sub, 1, #t, 1, t)
  1377.                 elseif sub == "fontsize" then
  1378.                     AddFakeSlider(lvl, sub, 4, 30, 1)
  1379.                 elseif sub == "fonttitlestyle" or sub == "fontmsgstyle" then
  1380.                     AddSelect(lvl, "None", sub, "None")
  1381.                     AddSelect(lvl, "Shadow", sub, "Shadow")
  1382.                     AddSelect(lvl, "Outline", sub, "OUTLINE")
  1383.                     AddSelect(lvl, "Thick Outline", sub, "THICKOUTLINE")
  1384.                     AddSelect(lvl, "Monochrome", sub, "MONOCHROME")
  1385.                 elseif sub == "alpha" then
  1386.                     AddFakeSlider(lvl, sub, 0, 1, 0.1)
  1387.                 elseif sub == "strata" then
  1388.                     AddSelect(lvl, "BACKGROUND", sub, "BACKGROUND")
  1389.                     AddSelect(lvl, "LOW", sub, "LOW")
  1390.                     AddSelect(lvl, "MEDIUM", sub, "MEDIUM")
  1391.                     AddSelect(lvl, "HIGH", sub, "HIGH")
  1392.                     AddSelect(lvl, "DIALOG", sub, "DIALOG")
  1393.                 elseif sub == "maxwindows" then
  1394.                     AddFakeSlider(lvl, sub, 4, 20, 1)
  1395.                 elseif sub == "recent" or sub == "show" or sub == "clear" then
  1396.                     wipe(list)
  1397.                     for name in pairs(sub == "recent" and recentw or svar) do
  1398.                         tinsert(list, name)
  1399.                     end
  1400.                     table.sort(list)
  1401.                     AddFakeSlider(lvl, sub, 1, #list, 1, list)
  1402.                 end
  1403.             end
  1404.         end
  1405.     end
  1406.     ToggleDropDownMenu(1, nil, CellularDD, "cursor")
  1407. end
Add Comment
Please, Sign In to add comment