From 13dacab8ec14b22985442d9d7078d5ccb4bcf538 Mon Sep 17 00:00:00 2001 From: Ahmil Jilani Date: Wed, 19 Oct 2011 03:48:00 -0400 Subject: [PATCH] 2.1 --- SuperDuperMacro/MacroInterpreter.lua | 242 ---- SuperDuperMacro/SuperDuperMacro.lua | 1543 +++++-------------------- SuperDuperMacro/SuperDuperMacro.toc | 7 +- SuperDuperMacro/SuperDuperMacro_Interface.lua | 845 ++++++++++++++ SuperDuperMacro/SuperDuperMacro_Sharing.lua | 271 +++++ SuperDuperMacro/sdm Readme.txt | 13 +- 6 files changed, 1392 insertions(+), 1529 deletions(-) delete mode 100644 SuperDuperMacro/MacroInterpreter.lua create mode 100644 SuperDuperMacro/SuperDuperMacro_Interface.lua create mode 100644 SuperDuperMacro/SuperDuperMacro_Sharing.lua diff --git a/SuperDuperMacro/MacroInterpreter.lua b/SuperDuperMacro/MacroInterpreter.lua deleted file mode 100644 index fe4eec1..0000000 --- a/SuperDuperMacro/MacroInterpreter.lua +++ /dev/null @@ -1,242 +0,0 @@ ---This file contains code that is adapted from ChatFrame.lua - -local funcsToGetSpell = {} -- Analoguous to SecureCmdList in ChatFrame.lua - -funcsToGetSpell["CAST"] = function(msg) - local action, target = SecureCmdOptionParse(msg); - if ( action ) then - local name, bag, slot = SecureCmdItemParse(action); - if ( slot or GetItemInfo(name) ) then - return "item", name, target, bag, slot - else - return "spell", action, target - end - end -end -funcsToGetSpell["USE"] = funcsToGetSpell["CAST"]; - -funcsToGetSpell["CASTRANDOM"] = function(msg) - local actions, target = SecureCmdOptionParse(msg); - if ( actions ) then - local action = strtrim(strsplit(",", actions)); --took out GetRandomArgument because the icon always shows the first spell - local name, bag, slot = SecureCmdItemParse(action); - if ( slot or GetItemInfo(name) ) then - return "item", name, target, bag, slot - else - return "spell", action, target - end - end -end -funcsToGetSpell["USERANDOM"] = funcsToGetSpell["CASTRANDOM"]; - -funcsToGetSpell["CASTSEQUENCE"] = function(msg) - local sequence, target = SecureCmdOptionParse(msg); - if ( sequence ) then - local _,item,spell = QueryCastSequence(sequence) - if spell then - return "spell", spell, target - elseif item then - return "item", item, target - end - end -end - -funcsToGetSpell["EQUIP"] = function(msg) - local item = SecureCmdOptionParse(msg); - if ( item ) then - local name, bag, slot = SecureCmdItemParse(item) - return "item", name, nil, bag, slot --name may be in the format "", "item:", or an itemlink - end -end - -funcsToGetSpell["EQUIP_TO_SLOT"] = function(msg) - local action = SecureCmdOptionParse(msg); - if ( action ) then - local slot, item = strmatch(action, "^(%d+)%s+(.*)"); - if ( item ) then - local name, bag, slot = SecureCmdItemParse(item) - return "item", name, nil, bag, slot - end - end -end - ---[[SecureCmdList["STOPMACRO"] = function(msg) --this command doesn't affect the icon, but I think it should! - if not ( SecureCmdOptionParse(msg) ) then - return true - end -end]] - ---[[funcsToGetSpell["CLICK"] = function(msg) - local action = SecureCmdOptionParse(msg); - if ( action and action ~= "" ) then - local name, mouseButton, down = strmatch(action, "([^%s]+)%s+([^%s]+)%s*(.*)"); - if ( not name ) then - name = action; - end - local button = GetClickFrame(name); - if ( button and button:IsObjectType("Button") ) then - if button:GetAttribute("type")=="macro" then - local text = button:GetAttribute("macrotext") - if text then - return sdm_GetMacrotextSpell(text, mouseButton, down) - end - end - end - end -end]] - -sdm_importantSlashHash = {} -- Analoguous to hash_SecureCmdList in ChatFrame.lua. Keys are slash commands that should not be ignored when getting a macro's icon. Values are functions that return the spell or item. -for index, value in pairs(funcsToGetSpell) do - local i = 1; - local cmdString = _G["SLASH_"..index..i]; - while ( cmdString ) do - cmdString = strupper(cmdString); - sdm_importantSlashHash[cmdString] = value; -- add to hash - i = i + 1; - cmdString = _G["SLASH_"..index..i]; - end -end - -function sdm_GetMacrotextAction(multiLineText) -- Input & calculations are adapted from ChatEdit_ParseText in ChatFrame.lua, and output is a combination of GetMacroSpell and GetMacroItem. - local show, showtooltip - for text in multiLineText:gmatch("[^\r\n]+") do -- is a single line of the macro - if ( strlen(text) > 0 ) then - --deal with #show and #showtooltip - local showtxt, showcmd = sdm_SplitString(text:trim(), " ", 1) - if showcmd then - showcmd = showcmd:lower() - if showcmd:sub(1,5)=="#show" then - show=1 - if showcmd:sub(1,12)=="#showtooltip" then - showtooltip=1 - end - text = "/cast "..showtxt - end - end - --get the info from the line - if ( strsub(text, 1, 1) == "/" ) then - local command = strmatch(text, "^(/[^%s]+)") or ""; - local msg = ""; - if ( command ~= text ) then - msg = strsub(text, strlen(command) + 2); - end - command = strupper(command); - if sdm_importantSlashHash[command] then - --return the info. If no info, move on to the next line. - local type,name,target,bag,slot = sdm_importantSlashHash[command](strtrim(msg)) - local nameReturn, otherReturn - if type then - if not name then return end - if type=="spell" then - nameReturn, otherReturn = GetSpellName(name) - if not nameReturn then - for _,companionType in pairs({"MOUNT", "CRITTER"}) do - for i=1,GetNumCompanions(companionType) do - local _, thisname = GetCompanionInfo(companionType, i) - if thisname==name then - nameReturn = thisname - otherReturn = "" - break - end - end - end - end - if not nameReturn then return end - elseif type=="item" then - nameReturn = GetItemInfo(name) - if not nameReturn then return end - -- this part mimics SecureCmdUseItem in ChatFrame.lua - if bag then - otherReturn = GetContainerItemLink(bag, slot) - elseif slot then - otherReturn = GetInventoryItemLink("player", slot) - else - -- this part may or may not be necessary, but it produces the exact numbers within the item link from GetMacroItem - for i=0,23 do - local link = GetInventoryItemLink("player",i) - if link and link:sub(link:find("%[")+1,link:find("\]")-1)==nameReturn then - otherReturn = link - break - end - end - if not otherReturn then - for i=-2,11 do - for j=1,GetContainerNumSlots(i) do - local link = GetContainerItemLink(i,j) - if link and link:sub(link:find("%[")+1,link:find("\]")-1)==nameReturn then - otherReturn = link - break - end - end - end - end - end - if not otherReturn then _,otherReturn = GetItemInfo(name) end - end - return type, nameReturn, otherReturn, target, show, showtooltip - end - end - end - end - end -end - -function sdm_CompareFuncs() - local result - for i=1,54 do - local body = GetMacroBody(i) - if body then - local a1,a2,a3,b1,b2,b3 - b1,b2,b3 = sdm_GetMacrotextAction(body) - a2,a3 = GetMacroSpell(i) - if a2 then - a1 = "spell" - else - a2,a3 = GetMacroItem(i) - if a2 then - a1 = "item" - end - end - if a1~=b1 or a2~=b2 or a3~=b3 then - result = (result or "ver: "..sdm_version.."\n\n").."body: "..body.."\nBlizz got: "..(a1 or "").." "..(a2 or "").." "..(a3 or "").."\nYou got: "..(b1 or "").." "..(b2 or "").." "..(b3 or "").."\n\n" - end - end - end - if result then - local f = getglobal("sdm_testResultFrame") - if not f then - f = CreateFrame("Frame", "SDM_testResultFrame", UIParent) - f:SetWidth(300) - f:SetHeight(300) - f:SetBackdrop({bgFile = "Interface\\DialogFrame\\UI-DialogBox-Background",edgeFile = "Interface\\DialogFrame\\UI-DialogBox-Border",tile = true,tileSize = 32,edgeSize = 32,insets = {left = 11,right = 11,top = 12,bottom = 10}}) - f:SetPoint("CENTER") - f.close = CreateFrame("Button", nil, f, "UIPanelCloseButton") - f.close:SetPoint("TOPRIGHT",-10,-10) - f.close:SetScript("OnClick", function() f:Hide() end) - f.scroll = CreateFrame("ScrollFrame", "sdm_sillyName", f, "UIPanelScrollFrameTemplate") - f.box = CreateFrame("EditBox", nil, f) - f.scroll:SetScrollChild(box) - f.scroll:SetHeight(100) - f.scroll:SetWidth(100) - f.scroll:SetPoint("BOTTOM") - f.box:SetHeight(100) - f.box:SetWidth(100) - f.box:SetFontObject("GameFontHighlightSmall") - f.box:SetMultiLine(1) - f.box:SetScript("OnTextChanged", function(self) if self:GetText()~=result then self:SetText(result) end self:HighlightText() end) - f.box:SetScript("OnCursorChanged", f.box.HighlightText) - f.box:SetScript("OnEditFocusLost", function(self) self:SetFocus() self:HighlightText() end) - f.text = f:CreateFontString(nil, "ARTWORK", "GameFontNormal") - f.text:SetPoint("TOPLEFT",20,-30) - f.text:SetPoint("BOTTOMRIGHT",-20,20) - f.text:SetJustifyH("TOP") - f.text:SetText("Press ctrl-C or cmd-C to copy the selected text below (it's selected right now, even if you can't see it). Kindly head over to wowinterface.com and paste the text into a comment. Thanks!") - end - f:Show() - f.box:SetText(result) - else - print("SDM test result: All correct!") - end -end - ---now, hook the events that update the action buttons \ No newline at end of file diff --git a/SuperDuperMacro/SuperDuperMacro.lua b/SuperDuperMacro/SuperDuperMacro.lua index f19bad1..3f128aa 100644 --- a/SuperDuperMacro/SuperDuperMacro.lua +++ b/SuperDuperMacro/SuperDuperMacro.lua @@ -1,3 +1,9 @@ +sdm_printPrefix = "|cffff7700Super Duper Macro|r - " +sdm_countUpdateMacrosEvents=0 +sdm_validChars = {1,2,3,4,5,6,7,8,11,12,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255} +sdm_thisChar = {name=UnitName("player"), realm=GetRealmName()} +sdm_doAfterCombat={} --a collection of strings that will be run as scripts when combat ends + function sdm_SlashHandler(command) if command=="" then if sdm_mainFrame:IsShown() then @@ -5,24 +11,166 @@ function sdm_SlashHandler(command) else sdm_mainFrame:Show() end - elseif command:lower()=="test" then - sdm_CompareFuncs() elseif command:sub(1,4):lower()=="run " then sdm_RunScript(command:sub(5)) else - print("SDM did not recognize the command \""..command.."\"") + print(sdm_printPrefix.."SDM did not recognize the command \""..command.."\"") end end +SlashCmdList["SUPERDUPERMACRO"] = sdm_SlashHandler; +SLASH_SUPERDUPERMACRO1 = "/sdm"; + +sdm_eventFrame = CreateFrame("Frame") +sdm_eventFrame:RegisterEvent("VARIABLES_LOADED") +sdm_eventFrame:RegisterEvent("UPDATE_MACROS") +sdm_eventFrame:RegisterEvent("ADDON_LOADED") +sdm_eventFrame:RegisterEvent("CHAT_MSG_ADDON") +sdm_eventFrame:SetScript("OnEvent", function (self, event, ...) + if event=="VARIABLES_LOADED" then + local oldVersion = sdm_version + sdm_version=GetAddOnMetadata("SuperDuperMacro", "Version") --the version of this addon + sdm_eventFrame:UnregisterEvent("VARIABLES_LOADED") + if (not sdm_macros) then + sdm_macros={} --type tokens: "b": button macro. "f": floating macro. "s": scripts. "c": containers (folders) + elseif sdm_CompareVersions(oldVersion,"1.6.1")==2 then + if sdm_CompareVersions(oldVersion,"1.6")==2 then + if sdm_CompareVersions(oldVersion,"1.3")==2 then + --when updating from before 1.3: + local oldMacros=sdm_macros + sdm_macros={} + local ID=1 + for i,v in ipairs(oldMacros) do + sdm_macros[i]={type=v[1], name=v[2], text=v[3]} + if v[4] then + sdm_macros[i].character={name=v[4], server=v[5]} + end + if v[1]=="b" then + sdm_macros[i].ID=ID + ID=ID+1 + end + end + end + --when updating from before 1.6: + local attempt, found + for i,v in pairs(sdm_macros) do + if (not v.ID) then + attempt = 0 + while true do --keep going until we find an unused ID + found = nil + for _,v in pairs(sdm_macros) do + if v.ID==attempt then + found=1 + break + end + end + if not found then + break + end + attempt = attempt+1 + end + v.ID=attempt + end + if v.character then + v.character.realm=v.character.server + v.character.server=nil + end + v.icon=1 + if v.hideName then + v.buttonName=" " + v.hideName=nil + end + if sdm_ContainsIllegalChars(v.name) then + v.name = ""..v.ID + elseif sdm_DoesNameConflict(v.name, v.type, v.character, i) then + v.name = v.name..""..v.ID + end + end + end + --when updating from before 1.6.1: + for i,v in pairs(sdm_macros) do + if v.buttonName=="" then + v.buttonName=" " + end + end + end + --Saving strips away numeric keys. Now we have to put the macros back into their proper indices. + local savedMacros = sdm_macros + sdm_macros = {} + for _,v in pairs(savedMacros) do + sdm_macros[v.ID]=v + end + if sdm_mainContents==nil then + sdm_ResetContainers() + end + sdm_iconSize=sdm_iconSize or 36 + if not sdm_listFilters then + sdm_listFilters={b=true, f=true, s=true, global=true} + sdm_listFilters["true"]=true + sdm_listFilters["false"]=true + end + sdm_mainFrame_iconSizeSlider:SetValue(sdm_iconSize) + sdm_mainFrame_iconSizeSlider:SetScript("OnValueChanged", function(self) sdm_iconSize = self:GetValue() sdm_UpdateList() end) + sdm_SelectItem(nil) --We want to start with no macro selected + elseif event=="UPDATE_MACROS" then + sdm_countUpdateMacrosEvents=sdm_countUpdateMacrosEvents+1 + if sdm_countUpdateMacrosEvents==2 then + sdm_eventFrame:UnregisterEvent("UPDATE_MACROS") + local killOnSight = {} + local macrosToDelete = {} + local iIsPerCharacter=false + local thisID, mTab + for i=1,54 do --Check each macro to see if it's been orphaned by a previous installation of SDM. + if i==37 then iIsPerCharacter=true end + thisID = sdm_GetSdmID(i) + mTab = sdm_macros[thisID] + if thisID then --if the macro was created by SDM... + if killOnSight[thisID] then --if this ID is marked as kill-on-sight, kill it. + table.insert(macrosToDelete, i) + elseif (not mTab) or mTab.type~="b" or (not sdm_UsedByThisChar(mTab)) then --if this ID is not in use by this character as a button macro, kill it and mark this ID as KoS + table.insert(macrosToDelete, i) + killOnSight[thisID]=1 + elseif (mTab.character~=nil)~=iIsPerCharacter then --if the macro is in the wrong spot based on perCharacter, kill it, but give it a chance to find one in the right spot. + table.insert(macrosToDelete, i) + else --This macro is good and should be here. Kill any duplicates. + killOnSight[thisID]=1 + end + end + end + for i=getn(macrosToDelete),1,-1 do + print(sdm_printPrefix.."Deleting extraneous macro "..macrosToDelete[i]..": "..GetMacroInfo(macrosToDelete[i])) + DeleteMacro(macrosToDelete[i]) + end + for i,v in pairs(sdm_macros) do + if sdm_UsedByThisChar(sdm_macros[i]) then + sdm_SetUpMacro(sdm_macros[i]) + end + end + end + elseif event=="ADDON_LOADED" then + local addonName = ...; + if addonName=="Blizzard_MacroUI" then + sdm_DefaultMacroFrameLoaded() + end + elseif event=="PLAYER_REGEN_ENABLED" then + sdm_eventFrame:UnregisterEvent("PLAYER_REGEN_ENABLED") + for _,luaText in ipairs(sdm_doAfterCombat) do + RunScript(luaText) + end + sdm_doAfterCombat={} + print(sdm_printPrefix.."Your macros are now up to date.") + elseif event=="CHAT_MSG_ADDON" then + sdm_InterpretAddonMessage(...) + end +end) + function sdm_MakeMacroFrame(name, text) sdm_DoOrQueue("local temp = getglobal("..sdm_Stringer(name)..") or CreateFrame(\"Button\", "..sdm_Stringer(name)..", nil, \"SecureActionButtonTemplate\")\ temp:SetAttribute(\'type\', \'macro\')\ temp:SetAttribute(\'macrotext\', "..sdm_Stringer(text)..")") --- GetClickFrame(name) --This line is just to fix a taint issue from a Blizzard bug (fixed in 3.0) --- print("Creating frame \""..name.."\" with macrotext\n\""..text.."\"\n(length "..string.len(text)..")") - if string.len(text)>1023 then print("The following line is "..(string.len(text)-1023).." characters too long:\n"..text) end + if string.len(text)>1023 then print(sdm_printPrefix.."The following line is "..(string.len(text)-1023).." characters too long:\n"..text) end end + function sdm_MakeBlizzardMacro(ID, name, icon, text, perCharacter) --- print("Creating macro \""..name.."\" with text\n\""..text.."\"\n(length "..string.len(text)..")") sdm_DoOrQueue("local macroIndex = sdm_GetMacroIndex("..sdm_Stringer(ID)..")\ if macroIndex then\ EditMacro(macroIndex, "..sdm_Stringer(name)..", "..sdm_Stringer(icon)..", "..sdm_Stringer(text)..", 1, "..sdm_Stringer(perCharacter)..")\ @@ -30,6 +178,7 @@ function sdm_MakeBlizzardMacro(ID, name, icon, text, perCharacter) CreateMacro("..sdm_Stringer(name)..", "..sdm_Stringer(icon or 1)..", "..sdm_Stringer(text)..", "..sdm_Stringer(perCharacter)..", 1)\ end") end + function sdm_GetSdmID(macroIndex) local thisMacroText=GetMacroBody(macroIndex) if thisMacroText and thisMacroText:sub(1,4)=="#sdm" then @@ -38,6 +187,7 @@ function sdm_GetSdmID(macroIndex) return nil end end + function sdm_GetMacroIndex(sdmID) for i=1,54 do if sdm_GetSdmID(i)==sdmID then @@ -46,9 +196,11 @@ function sdm_GetMacroIndex(sdmID) end return nil end + function sdm_GetLinkText(nextName) return "/click [btn:5]"..nextName.." Button5;[btn:4]"..nextName.." Button4;[btn:3]"..nextName.." MiddleButton;[btn:2]"..nextName.." RightButton;"..nextName end + function sdm_SetUpMacro(mTab) local type = mTab.type if type~="b" and type~="f" then @@ -91,6 +243,7 @@ function sdm_SetUpMacro(mTab) sdm_MakeMacroFrame("sdf_"..mTab.name, frameText) end end + function sdm_SetUpMacroFrames(clickerName, text, currentLayer) --returns the frame to be clicked local currentFrame=1 local frameText="" @@ -119,219 +272,24 @@ function sdm_SetUpMacroFrames(clickerName, text, currentLayer) --returns the fra return sdm_SetUpMacroFrames(clickerName, nextLayerText, currentLayer+1) end end -function sdm_Query(channel, target) --next version: have a single token for party and raid, then decide here. - SendAddonMessage("SDM query", sdm_qian, channel, target) -end -function sdm_SendMacro(mTab, chan, tar) - if sdm_sending then - print("SDM: You are already sending something.") - return - end - local perCharacter=nil - --make the string that will be split up and sent. It consists of a bunch of values separated by commas. They are, in order: the version the sender is running, the minimum version the receiver must have, the type of macro, the index of the icon, the perCharacter status ("" or "nil"), the length of the name, the length of the text, the name, and the text. There is no comma between the name and the text. - local textToSend = sdm_qian..","..sdm_minVersion..","..mTab.type..","..tostring(mTab.icon)..","..tostring(mTab.character)..","..mTab.name:len()..","..mTab.text:len()..","..mTab.name..mTab.text - local pref = "Super Duper Macro send1" -- if the prefix ends in "send1", it's the first line. If it ends in "send2", it's any line after the first. - local lineLen = 254 - pref:len() - local linesToSend={} - local pos = 1 - while pos <= textToSend:len() do - table.insert(linesToSend, textToSend:sub(pos, pos+lineLen-1)) - pos = pos+lineLen - end - sdm_sending={ - i=1, - lines = linesToSend, - numLines = getn(linesToSend), - channel = chan, - target = tar, - prefix = pref - } - sdm_sendReceiveFrame_sendBar_statusBar:SetMinMaxValues(0, sdm_sending.numLines) - sdm_sendReceiveFrame_sendBar_statusBar:SetValue(0) - sdm_sendReceiveFrame_sendBar_statusBar_text:SetText("|cffffccffSending to "..(sdm_sending.target or sdm_sending.channel).."|r") - sdm_sendReceiveFrame_cancelSendButton:Enable() - sdm_sendReceiveFrame_sendButton:Disable() - sdm_sendReceiveFrame_sendPartyRadio:Disable() - sdm_sendReceiveFrame_sendRaidRadio:Disable() - sdm_sendReceiveFrame_sendBattlegroundRadio:Disable() - sdm_sendReceiveFrame_sendGuildRadio:Disable() - sdm_sendReceiveFrame_sendTargetRadio:Disable() - sdm_sendReceiveFrame_sendArbitraryRadio:Disable() - sdm_sendReceiveFrame_sendInput:EnableMouse(nil) - sdm_updateFrame:Show() -end -function sdm_OnUpdate(self, elapsed) --used for sending macros - self.TimeSinceLastUpdate = self.TimeSinceLastUpdate + elapsed - if self.TimeSinceLastUpdate > sdm_updateInterval then - if sdm_sending.i == 2 then - sdm_sending.prefix="Super Duper Macro send2" - end - SendAddonMessage(sdm_sending.prefix, sdm_sending.lines[sdm_sending.i], sdm_sending.channel, sdm_sending.target) - sdm_sendReceiveFrame_sendBar_statusBar:SetValue(sdm_sending.i) - sdm_sending.i = sdm_sending.i+1 - if sdm_sending.i>sdm_sending.numLines then - sdm_EndSending("|cff44ff00Sent to "..(sdm_sending.target or sdm_sending.channel).."|r") - end - self.TimeSinceLastUpdate = 0 - end -end -function sdm_EndSending(text) - sdm_updateFrame:Hide() - sdm_sendReceiveFrame_sendBar_statusBar_text:SetText(text) - sdm_sending=nil - sdm_sendReceiveFrame_cancelSendButton:Disable() - if sdm_currentEdit then - sdm_sendReceiveFrame_sendButton:Enable() - end - sdm_sendReceiveFrame_sendPartyRadio:Enable() - sdm_sendReceiveFrame_sendRaidRadio:Enable() - sdm_sendReceiveFrame_sendBattlegroundRadio:Enable() - sdm_sendReceiveFrame_sendGuildRadio:Enable() - sdm_sendReceiveFrame_sendTargetRadio:Enable() - sdm_sendReceiveFrame_sendArbitraryRadio:Enable() - sdm_sendReceiveFrame_sendInput:EnableMouse(1) -end -function sdm_WaitForMacro(name) - if sdm_receiving then - print("SDM: You are already receiving or waiting.") - return - end - sdm_receiving = {playerName=name, first=true} - sdm_sendReceiveFrame_receiveBar_statusBar:SetValue(0) - sdm_sendReceiveFrame_receiveBar_statusBar_text:SetText("|cffffccffWaiting for "..sdm_receiving.playerName.."|r") - sdm_sendReceiveFrame_cancelReceiveButton:Enable() - sdm_sendReceiveFrame_receiveButton:Disable() - sdm_sendReceiveFrame_receiveTargetRadio:Disable() - sdm_sendReceiveFrame_receiveArbitraryRadio:Disable() - sdm_sendReceiveFrame_receiveInput:EnableMouse(nil) - sdm_SelectItem(nil) - sdm_newFrame:Show() - sdm_newFrame_input:ClearFocus() - sdm_newFrame_input:SetText("Receiving macro...") - sdm_newFrame_input:EnableMouse(nil) - sdm_newFrame_buttonRadio:Disable() - sdm_newFrame_floatingRadio:Disable() - sdm_newFrame_scriptRadio:Disable() - sdm_newFrame_globalRadio:Disable() - sdm_newFrame_charspecRadio:Disable() - sdm_newFrame_createButton:Disable() -end -function sdm_ReceiveLine(line, send1) - if sdm_receiving.first and send1 then --this is the first line - sdm_receiving.nameAndText, sdm_receiving.textLen, sdm_receiving.playerNameLen, sdm_receiving.perCharacter, sdm_receiving.icon, sdm_receiving.type, sdm_receiving.minVersion, sdm_receiving.sendersVersion = sdm_SplitString(line, ",", 7) - sdm_receiving.perCharacter = (sdm_receiving.perCharacter~="nil") - if sdm_receiving.icon=="nil" then - sdm_receiving.icon = nil - else - sdm_receiving.icon = 0 + sdm_receiving.icon - end - sdm_receiving.textLen = 0 + sdm_receiving.textLen - sdm_receiving.playerNameLen = 0 + sdm_receiving.playerNameLen - sdm_receiving.first = false - sdm_sendReceiveFrame_receiveBar_statusBar:SetMinMaxValues(0, sdm_receiving.playerNameLen + sdm_receiving.textLen) - sdm_sendReceiveFrame_receiveBar_statusBar_text:SetText("|cffffccffReceiving|r") - sdm_VersionReceived(sdm_receiving.sendersVersion) - if sdm_CompareVersions(sdm_receiving.sendersVersion, sdm_minVersion)==2 or sdm_CompareVersions(sdm_version, sdm_receiving.minVersion)==2 then - print("SDM: You failed to recieve the macro due to a version incompatibility.") - SendAddonMessage("Super Duper Macro recFailed", "Incompatible Versions,"..sdm_qian, "WHISPER", sdm_receiving.playerName) - sdm_EndReceiving("|cffff0000Failed|r") - return - else - SendAddonMessage("Super Duper Macro receiving", sdm_qian, "WHISPER", sdm_receiving.playerName) - end - elseif (not sdm_receiving.first) and (not send1) then - sdm_receiving.nameAndText = sdm_receiving.nameAndText..line - else - return - end - local currLen = sdm_receiving.nameAndText:len() - sdm_sendReceiveFrame_receiveBar_statusBar:SetValue(currLen) - if currLen == (sdm_receiving.playerNameLen + sdm_receiving.textLen) then - sdm_sendReceiveFrame_receiveBar_statusBar_text:SetText("|cffff9900Click \"Create\" to save|r") - UIFrameFlash(sdm_newFrame_createButton_flash, 0.5, 0.5, 1e6, false) - sdm_newFrame_input:EnableMouse(1) - sdm_newFrame_buttonRadio:Enable() - sdm_newFrame_floatingRadio:Enable() - sdm_newFrame_scriptRadio:Enable() - sdm_newFrame_globalRadio:Enable() - sdm_newFrame_charspecRadio:Enable() - sdm_newFrame_createButton:Enable() - if sdm_receiving.type=="b" then - sdm_newFrame_buttonRadio:Click() - elseif sdm_receiving.type=="f" then - sdm_newFrame_floatingRadio:Click() - elseif sdm_receiving.type=="s" then - sdm_newFrame_scriptRadio:Click() - end - if sdm_receiving.perCharacter then - sdm_newFrame_charspecRadio:Click() - else - sdm_newFrame_globalRadio:Click() - end - sdm_receiving.name=sdm_receiving.nameAndText:sub(1,sdm_receiving.playerNameLen) - sdm_newFrame_input:SetText(sdm_receiving.name) - sdm_receiving.text=sdm_receiving.nameAndText:sub(sdm_receiving.playerNameLen+1,sdm_receiving.playerNameLen+sdm_receiving.textLen) - end -end -function sdm_EndReceiving(text) - sdm_sendReceiveFrame_receiveBar_statusBar_text:SetText(text) - sdm_sendReceiveFrame_cancelReceiveButton:Disable() - sdm_sendReceiveFrame_receiveButton:Enable() - sdm_mainFrame_newButton:Enable() - sdm_sendReceiveFrame_receiveTargetRadio:Enable() - sdm_sendReceiveFrame_receiveArbitraryRadio:Enable() - sdm_sendReceiveFrame_receiveInput:EnableMouse(1) - sdm_newFrame_input:SetText("") - sdm_newFrame_input:EnableMouse(1) - sdm_newFrame_buttonRadio:Enable() - sdm_newFrame_floatingRadio:Enable() - sdm_newFrame_scriptRadio:Enable() - sdm_newFrame_globalRadio:Enable() - sdm_newFrame_charspecRadio:Enable() - sdm_newFrame_createButton:Enable() - sdm_receiving=nil -end -function sdm_CancelSend() - SendAddonMessage("Super Duper Macro sendFailed", "Cancelled", sdm_sending.channel, sdm_sending.target) - sdm_EndSending("|cffff0000Cancelled|r") -end -function sdm_CancelReceive() - SendAddonMessage("Super Duper Macro recFailed", "Cancelled,"..sdm_qian, "WHISPER", sdm_receiving.playerName) - sdm_EndReceiving("|cffff0000Cancelled|r") - sdm_newFrame:Hide() -end + function sdm_CreateCancelButtonPressed() sdm_newFrame:Hide() if sdm_receiving then sdm_CancelReceive() end end -function sdm_SplitString(s, pattern, limit, ...) --iterates through "s", splitting it between occurrences of "pattern", and returning the split portions IN BACKWARDS ORDER. Splits a maximum of times (optional) - if limit==0 then - return s, ... - end - local index = s:find(pattern) - if (not index) then - return s, ... - end - return sdm_SplitString(s:sub(index+pattern:len()), pattern, limit-1, s:sub(1, index-1), ...) -end -function sdm_VersionReceived(ver) - if not sdm_versionWarning and sdm_CompareVersions(sdm_version,ver)==2 then - sdm_versionWarning="|cff00ff00New version available! Check on www.wowinterface.com|r" - print("Super Duper Macro: "..sdm_versionWarning) - sdm_mainFrameTitle:SetText(sdm_versionWarning) - end -end + function sdm_DoOrQueue(luaText) --If player is not in combat, runs the command. Otherwise, queues it up to be executed when combat is dropped. - if UnitAffectingCombat("player") then + if InCombatLockdown() then sdm_eventFrame:RegisterEvent("PLAYER_REGEN_ENABLED") - print("SDM: Changes to macros will not take effect until combat ends.") + print(sdm_printPrefix.."Changes to macros will not take effect until combat ends.") table.insert(sdm_doAfterCombat, luaText) else RunScript(luaText) end end + function sdm_Stringer(var) --converts a variable to a string for purposes of putting it in a string for RunScript(). Strings are formatted as quoted strings, other vars are converted to strings. if type(var)=="string" then return string.format("%q", var) @@ -339,6 +297,7 @@ function sdm_Stringer(var) --converts a variable to a string for purposes of put return tostring(var) end end + function sdm_CompareVersions(firstString, secondString) --returns 1 if the first is bigger, 2 if the second is bigger, and 0 if they are equal. local strings = {firstString, secondString} local numbers = {} @@ -364,745 +323,115 @@ function sdm_CompareVersions(firstString, secondString) --returns 1 if the first end end end -function sdm_About() - print("Super Duper Macro by hypehuman. Version "..sdm_version..". Check for updates at www.wowinterface.com") -end -function sdm_TypeDropdownLoaded(self) - self:SetScript("OnShow", nil) - UIDropDownMenu_Initialize(self, sdm_InitializeTypeDropdown); - UIDropDownMenu_SetText(self, "Type"); - UIDropDownMenu_SetWidth(self, 52); -end -function sdm_CharDropdownLoaded(self) - self:SetScript("OnShow", nil) - UIDropDownMenu_Initialize(self, sdm_InitializeCharDropdown); - UIDropDownMenu_SetText(self, "Character"); - UIDropDownMenu_SetWidth(self, 75); -end -function sdm_InitializeTypeDropdown() - local info = UIDropDownMenu_CreateInfo(); - local buttons = { - {val="b", txt="Button Macros"}, - {val="f", txt="Floating Macros"}, - {val="s", txt="Scripts"} - } - for _,v in ipairs(buttons) do - info.value = v.val; - info.text = sdm_GetColor(v.val, v.txt); - info.func = sdm_FilterButtonClicked; - info.checked = sdm_listFilters[info.value]; - info.keepShownOnClick = 1; - UIDropDownMenu_AddButton(info); - end + +function sdm_Edit(mTab, text) + mTab.text=text + sdm_SetUpMacro(mTab) + sdm_mainFrame_saveButton:Disable() end -function sdm_InitializeCharDropdown() - local info = UIDropDownMenu_CreateInfo(); - local buttons = { - {val="global", txt="Global"}, - {val="true", txt="This Character"}, - {val="false", txt="Other Characters"} - } - - for _,v in ipairs(buttons) do - info.value = v.val; - info.text = sdm_GetColor(v.val, v.txt); - info.func = sdm_FilterButtonClicked; - info.checked = sdm_listFilters[info.value]; - info.keepShownOnClick = 1; - UIDropDownMenu_AddButton(info); + +function sdm_CheckCreationSafety(type, name, character) --returns the mTab of the new macro, or nil if creation failed + if name=="" then + print(sdm_printPrefix.."Invalid name") + return false end -end -function sdm_FilterButtonClicked(self, _, _, on) - sdm_listFilters[self.value] = on - sdm_UpdateList() -end -function sdm_SendButtonClicked() - local channel - local target - if sdm_sendReceiveFrame_sendPartyRadio:GetChecked() then - channel="PARTY" - elseif sdm_sendReceiveFrame_sendRaidRadio:GetChecked() then - channel="RAID" - elseif sdm_sendReceiveFrame_sendBattlegroundRadio:GetChecked() then - channel="BATTLEGROUND" - elseif sdm_sendReceiveFrame_sendGuildRadio:GetChecked() then - channel="GUILD" - elseif sdm_sendReceiveFrame_sendTargetRadio:GetChecked() then - channel="WHISPER" - if UnitIsPlayer("target") then - target, realm = UnitName("target") - if realm then - target = target.."-"..realm - end - end - elseif sdm_sendReceiveFrame_sendArbitraryRadio:GetChecked() then - channel="WHISPER" - target=sdm_sendReceiveFrame_sendInput:GetText() + if (type=="b" or type=="f") and sdm_ContainsIllegalChars(name, true) then + return false end - if channel=="WHISPER" and ((not target) or target=="" or target==sdm_thisChar.name) then - return + if (not character) and GetMacroInfo(36) then + print(sdm_printPrefix.."You already have 36 global macros.") + return false + elseif character and character.name==sdm_thisChar.name and character.realm==sdm_thisChar.realm and GetMacroInfo(54) then + print(sdm_printPrefix.."You already have 18 character-specific macros.") + return false end - sdm_sendReceiveFrame_sendInput:ClearFocus() - sdm_SendMacro(sdm_macros[sdm_currentEdit], channel, target) -end -function sdm_ReceiveButtonClicked() - local sender - if sdm_sendReceiveFrame_receiveTargetRadio:GetChecked() then - if UnitIsPlayer("target") then - sender, realm = UnitName("target") - if realm then - sender = sender.."-"..realm - end - end - elseif sdm_sendReceiveFrame_receiveArbitraryRadio:GetChecked() then - sender=sdm_sendReceiveFrame_receiveInput:GetText() + local conflict = sdm_DoesNameConflict(name, type, character, nil, true) + if conflict then + return false end - if ((not sender) or sender=="" or sender==sdm_thisChar.name) then return end - sdm_sendReceiveFrame_receiveInput:ClearFocus() - sdm_SaveConfirmationBox("sdm_WaitForMacro("..sdm_Stringer(sender)..")") -end -function sdm_NewButtonClicked() - sdm_SaveConfirmationBox("sdm_SelectItem(nil) sdm_newFrame:Show() sdm_newFrame_input:SetFocus()") -end -function sdm_DeleteButtonClicked() - sdm_ChangeContainer(sdm_macros[sdm_currentEdit], false) - sdm_SelectItem(nil) + return true end -function sdm_ListItemClicked(self, button) - local mTab = sdm_macros[self.index] - if button=="RightButton" then - sdm_currentlyPlacing = self.index - sdm_UpdateList() - elseif sdm_currentlyPlacing then - local container - if mTab.type=="c" then --If we clicked on a container, place the item in this container - container = mTab.ID - else --If we clicked on a non-container, place the item in the container that contains this macro - container = mTab.container - end - sdm_ChangeContainer(sdm_macros[sdm_currentlyPlacing], container) - sdm_currentlyPlacing=nil - sdm_UpdateList() - elseif mTab.type=="c" and not IsAltKeyDown() then - mTab.open = not mTab.open - sdm_UpdateList() - else - sdm_SaveConfirmationBox("sdm_SelectItem("..self.index..")") + +function sdm_GetEmptySlot() -- returns the lowest unused index in sdm_macros + local result = 0 + while sdm_macros[result] do --keep going until we find an empty slot + result = result+1 end + return result end -function sdm_SelectItem(newCurrentEdit) - if sdm_listLocked then return end - if sdm_macros[newCurrentEdit] then - sdm_currentEdit = newCurrentEdit - else - sdm_currentEdit = nil + +function sdm_CreateNew(type, name, character) --returns the mTab of the new macro + local mTab = {} + mTab.ID = sdm_GetEmptySlot() + while sdm_macros[mTab.ID] do --keep going until we find an empty slot + mTab.ID = mTab.ID+1 end - if (not sdm_currentEdit) then - sdm_mainFrame_deleteButton:Disable() - sdm_mainFrame_getLinkButton:Disable() - sdm_mainFrame_changeIconButton:Disable() - sdm_mainFrame_editScrollFrame:Hide() - sdm_mainFrame_saveButton:Disable() - sdm_sendReceiveFrame_sendButton:Disable() - sdm_containerInstructions:Hide() - sdm_currentTitle:Hide() + sdm_macros[mTab.ID]=mTab + mTab.type=type + mTab.name=name + if type=="c" then + mTab.open = true + mTab.contents = {} else - sdm_mainFrame_editScrollFrame_text:ClearFocus() - sdm_mainFrame_deleteButton:Enable() - sdm_mainFrame_changeIconButton:Enable() - if sdm_macros[sdm_currentEdit].type=="c" then - sdm_mainFrame_editScrollFrame:Hide() - sdm_containerInstructions:Show() - sdm_mainFrame_getLinkButton:Disable() + mTab.icon=1 + if sdm_receiving and sdm_receiving.text then + mTab.text=sdm_receiving.text + mTab.icon=sdm_receiving.icon + SendAddonMessage("SDM recDone", "", "WHISPER", sdm_receiving.playerName) + sdm_EndReceiving("|cff44ff00Saved|r") else - sdm_mainFrame_editScrollFrame:Show() - sdm_containerInstructions:Hide() - sdm_mainFrame_getLinkButton:Enable() - end - sdm_mainFrame_editScrollFrame_text:SetText(sdm_macros[sdm_currentEdit].text or "") - sdm_mainFrame_saveButton:Disable() - if not sdm_sending then - sdm_sendReceiveFrame_sendButton:Enable() + if type=="s" then + mTab.text="-- Enter lua commands here." + elseif type=="b" or type=="f" then + mTab.text="# Enter macro text here." + else --this shouldn't happen + mTab.text="" + end end - sdm_currentTitle:SetText(sdm_GetColor(sdm_macros[sdm_currentEdit].type, sdm_GetTitle(sdm_macros[sdm_currentEdit]))) - sdm_currentTitle:Show() + mTab.character=character + sdm_SetUpMacro(mTab) end - sdm_UpdateList() -end -function sdm_ResetContainers() --Deletes all folders and places all items into the main list - sdm_mainContents={} - for i,v in pairs(sdm_macros) do - if v.type=="c" then - sdm_macros[i]=nil - else - sdm_SortedInsert(sdm_mainContents, v) - v.container=nil - end - end -end -function sdm_ChangeContainer(mTab, newContainer) --removes the mTab from its current container and places it in the container with ID newContainer. If newContainer is nil, it's placed in the main folder. If newContainer is false, the item is deleted. - local parent = newContainer - while parent do --check to see if we're trying to put a folder inside itself - if parent==mTab.ID then return end - parent = sdm_macros[parent].container - end - --remove the mTab from its current container. - local prevContents--the .contents table of the container that currently holds this mTab - if mTab.container==nil then - prevContents = sdm_mainContents - else - prevContents = sdm_macros[mTab.container].contents - end - for i,ID in ipairs(prevContents) do - if ID==mTab.ID then - table.remove(prevContents, i) - break - end - end - --now we're done removing from old container - if newContainer==false then --delete the mTab - local type = mTab.type - if type=="c" then --if we're deleting a container, move its contents into its parent. - for _,ID in pairs(mTab.contents) do - sdm_macros[ID].container=mTab.container - sdm_SortedInsert(prevContents, sdm_macros[ID]) - end - elseif sdm_UsedByThisChar(mTab) then - if type=="b" or type=="f" then - sdm_DoOrQueue("getglobal("..sdm_Stringer("sd"..type.."_"..mTab.name).."):SetAttribute(\"type\", nil)") - if type=="b" then - sdm_DoOrQueue("DeleteMacro(sdm_GetMacroIndex("..sdm_Stringer(mTab.ID).."))") - end - end - end - sdm_macros[mTab.ID]=nil - else --move mTab into newContainer - local contents --the new container's contents - if newContainer then - contents=sdm_macros[newContainer].contents - else - contents = sdm_mainContents - end - sdm_SortedInsert(contents, mTab) - mTab.container = newContainer - end -end -function sdm_SortedInsert(contents, mTab) --inserts mTab's ID into t (a table of IDs) at an appropriate location. Returns the location. - local lLim = 1 - local uLim = getn(contents)+1 - local test - --perform a binary search to see where we should insert the mTab (to maintain alphabetical order) - while lLim < uLim do - test=math.floor((lLim+uLim)/2) - if sdm_IsAtLeast(mTab, sdm_macros[contents[test]]) then - lLim=test+1 - else - uLim=test - end - end - table.insert(contents, lLim, mTab.ID) - return lLim -end -function sdm_IsAtLeast(one, two, i) --sees if the first mTab is greater than or equal to the second - i=i or 1 - local var - if i==1 then - var=function(mTab) return mTab.name:upper() end - elseif i==2 then - var=function(mTab) return mTab.name end - elseif i==3 then - var=function(mTab) return mTab.type end - elseif i==4 then - var=function(mTab) if mTab.character then return mTab.character.name end return string.format('%c', 1) end - elseif i==5 then - var=function(mTab) if mTab.character then return mTab.character.realm end return string.format('%c', 1) end - else - return true - end - if var(one) > var(two) then - return true - elseif var(one) < var(two) then - return false - else - return sdm_IsAtLeast(one, two, i+1) - end -end -function sdm_UpdateList() - if not sdm_mainFrame:IsShown() then return end - local f - for i=getn(sdm_listItems),1,-1 do - f=sdm_listItems[i] - f:Hide() - table.remove(sdm_listItems, i) - table.insert(sdm_unusedListItems[f.isContainerFrame], f) - end - local sorted, offsets = {}, {} - sdm_AddFolderContents(sorted, offsets, sdm_mainContents, 0) - sdm_currentListItem = nil - local listItem, isContainer - for i,mTab in ipairs(sorted) do - isContainer = mTab.type=="c" - listItem = table.remove(sdm_unusedListItems[isContainer],1) - if not listItem then - --create the listItem - listItem = CreateFrame("Button", nil, sdm_mainFrame_macrosScroll_macroList) - listItem.icon = listItem:CreateTexture(nil, "OVERLAY") - listItem.text = listItem:CreateFontString(nil,"ARTWORK","GameFontNormal") - listItem.text:SetJustifyH("LEFT") - listItem.text:SetPoint("TOP") - listItem.text:SetPoint("BOTTOMRIGHT") - listItem.text:SetNonSpaceWrap(true) - listItem.isContainerFrame=isContainer - listItem:SetPoint("RIGHT") - listItem:SetPoint("LEFT") - listItem.highlight = listItem:CreateTexture(nil, "BACKGROUND") - listItem.highlight:SetAllPoints(listItem) - listItem.highlight:SetTexture("Interface\\QuestFrame\\UI-QuestLogTitleHighlight") - listItem.highlight:SetBlendMode("ADD") - listItem.highlight:Hide() - listItem:SetScript("OnEnter", sdm_ListItemEntered) - listItem:SetScript("OnLeave", sdm_ListItemLeft) - listItem:SetScript("OnMouseUp", sdm_ListItemClicked) - listItem.buttonHighlight = listItem:CreateTexture(nil, "HIGHLIGHT") - listItem.buttonHighlight:SetBlendMode("ADD") - listItem.buttonHighlight:SetAllPoints(listItem.icon) - listItem:RegisterForDrag("LeftButton") - if isContainer then - listItem.icon:SetHeight(16) - listItem.icon:SetWidth(16) - listItem.buttonHighlight:SetTexture("Interface\\Buttons\\UI-PlusButton-Hilight") - else - listItem.slotIcon = listItem:CreateTexture(nil, "ARTWORK") - listItem.slotIcon:SetTexture("Interface\\Buttons\\UI-EmptySlot-Disabled") - listItem.slotIcon:SetPoint("CENTER", listItem.icon) - listItem.buttonHighlight:SetTexture("Interface\\Buttons\\ButtonHilight-Square") - listItem.buttonHighlight:SetPoint("CENTER", listItem.icon, "CENTER") - end - end - table.insert(sdm_listItems, listItem) --this should insert it at i - --now, update the item's graphical elements - if isContainer then - if mTab.open then - listItem.icon:SetTexture("Interface\\Buttons\\UI-MinusButton-UP") - else - listItem.icon:SetTexture("Interface\\Buttons\\UI-PlusButton-UP") - end - else - if mTab.icon==1 then - if mTab.type=="b" and sdm_UsedByThisChar(mTab) then - _,texture = GetMacroInfo(sdm_GetMacroIndex(mTab.ID)) - else - texture = nil - end - else - texture = GetMacroIconInfo(mTab.icon) - end - listItem.icon:SetTexture(texture) - listItem.icon:SetWidth(sdm_iconSize) - listItem.icon:SetHeight(sdm_iconSize) - listItem.slotIcon:SetWidth(sdm_iconSize*64/36) - listItem.slotIcon:SetHeight(sdm_iconSize*64/36) - if mTab.type=="b" and sdm_UsedByThisChar(mTab) then - listItem:SetScript("OnDragStart", function(self, event, ...) - PickupMacro(sdm_GetMacroIndex(sdm_macros[self.index].ID)) - end) - else - listItem:SetScript("OnDragStart", nil) - end - end - listItem.text:SetText(sdm_GetTitle(mTab)) - listItem:SetHeight(sdm_iconSize*(1+sdm_iconSpacing*2)) - listItem.icon:SetPoint("LEFT", sdm_iconSize*(sdm_iconSpacing + offsets[i]*(sdm_iconSpacing+1)) + (sdm_iconSize-listItem.icon:GetWidth())/2, 0) - listItem.text:SetPoint("LEFT", sdm_iconSize*(sdm_iconSpacing + (offsets[i]+1)*(sdm_iconSpacing+1)), 0) - listItem.index=mTab.ID - if listItem.index==sdm_currentEdit then - sdm_currentListItem = listItem - listItem.highlight:SetVertexColor(sdm_GetColor(mTab.type)) - listItem.highlight:Show() - listItem.text:SetTextColor(sdm_GetColor(nil)) - else - listItem.highlight:Hide() - listItem.text:SetTextColor(sdm_GetColor(mTab.type)) - end - if listItem.index==sdm_currentlyPlacing then - listItem:SetAlpha(0.3) - else - listItem:SetAlpha(1) - end - if i==1 then - listItem:SetPoint("TOP") - else - listItem:SetPoint("TOP", sdm_listItems[i-1], "BOTTOM") - end - listItem:Show() - end -end -function sdm_GetTitle(mTab) - local result = mTab.name - if mTab.character then - result=result..sdm_GetColor(tostring(mTab.character.name..mTab.character.realm==sdm_thisChar.name..sdm_thisChar.realm), " ("..mTab.character.name.." of "..mTab.character.realm..")") - end - return result -end -function sdm_AddFolderContents(mTabs, offsets, contents, offset) --Populates mTabs with the elements of contents and all its subfolders. Populates offsets with the amount of indentation for each item. - for i,ID in ipairs(contents) do - local mTab = sdm_macros[ID] - if sdm_IncludeInList(mTab) then - table.insert(mTabs, mTab) - table.insert(offsets, offset) - if mTab.type=="c" and mTab.open then -- If it's an open container, add its contents too. - sdm_AddFolderContents(mTabs, offsets, mTab.contents, offset+1) - end - end - end -end -function sdm_IncludeInList(mTab) --checks the filters to see if the item should be in the scrolling list - if mTab.type=="c" then - return true - end - if not sdm_listFilters[mTab.type] then - return false - end - if not mTab.character then - return sdm_listFilters["global"] - end - return sdm_listFilters[tostring(mTab.character.name..mTab.character.realm==sdm_thisChar.name..sdm_thisChar.realm)] -end -function sdm_MakeTextWhite(listItem) - local t = listItem.text:GetText() - listItem.text:SetText("|cffffffff"..t.."|r") -end -function sdm_MakeTextNotWhite(listItem) - local t = listItem.text:GetText() - if t:sub(1,2)=="|c" then - listItem.text:SetText(t:sub(11, t:len()-2)) - end -end -function sdm_ListItemEntered(f) - if sdm_macros[f.index].type=="c" then - sdm_MakeTextWhite(f) - end -end -function sdm_ListItemLeft(f) - sdm_MakeTextNotWhite(f) -end -function sdm_GetColor(type, plainString)--if inputString is passed, it will return a new colored string. If it's not passed, we will return three values. - local r,g,b - if type==nil then - r,g,b= 1,1,1 --selected items - elseif type=="b" then - r,g,b= 1,1,.65 --button macros - elseif type=="f" then - r,g,b= 1,.62,.74 --floating macros - elseif type=="s" then - r,g,b= .76,.51,.29 --scripts - elseif type=="true" then - r,g,b= .7,.7,.7 --this character - elseif type=="false" then - r,g,b= .3,.3,.3 --other characters - elseif type=="c" or type=="global" then - r,g,b= NORMAL_FONT_COLOR.r,NORMAL_FONT_COLOR.g,NORMAL_FONT_COLOR.b --global or containers - end - if (not plainString) or r==nil then - return r,g,b - else - local t = {r,g,b} - local hex = "" - for i,v in ipairs(t) do - t[i] = string.format("%x", t[i]*255) - while t[i]:len()<2 do - t[i]="0"..t[i] - end - hex = hex..t[i] - end - return "|c00"..hex..plainString.."|r" - end -end -function sdm_OnShow_changeIconFrame(f) - local mTab = sdm_macros[sdm_currentEdit] - if not sdm_macroUILoaded then - MacroFrame_LoadUI() - end - MacroPopupFrame.selectedIcon=mTab.icon - f.prevonshow=MacroPopupFrame:GetScript("OnShow") - MacroPopupFrame:SetScript("OnShow", MacroPopupFrame_Update) - f.prevonenter=MacroPopupEditBox:GetScript("OnEnterPressed") - MacroPopupEditBox:SetScript("OnEnterPressed", sdm_ChangeIconOkayed) - f.prevonesc=MacroPopupEditBox:GetScript("OnEscapePressed") - MacroPopupEditBox:SetScript("OnEscapePressed", function() MacroPopupEditBox:ClearFocus() end) - MacroPopupEditBox:SetAutoFocus(false) - MacroFrame:Hide() - f.prevmode=MacroPopupFrame.mode - MacroPopupFrame.mode="sdm" - f.prevpoints={} - for i=1,MacroPopupFrame:GetNumPoints() do - f.prevpoints[i]={MacroPopupFrame:GetPoint(i)} - end - MacroPopupFrame:ClearAllPoints() - MacroPopupFrame:SetParent(f) - MacroPopupFrame:SetPoint("BOTTOM") - MacroPopupFrame:Show() - _,_,_,_,f.fontstring = MacroPopupFrame:GetRegions() - f.fontstring:SetText(" Different name on button:") - MacroPopupOkayButton:Hide() - MacroPopupCancelButton:Hide() - MacroPopupFrame_sdmOkayButton:Show() - MacroPopupFrame_sdmCancelButton:Show() - if mTab.type=="b" then - if (not mTab.buttonName) then - MacroPopupFrame_buttonTextCheckBox:SetChecked(nil) - else - MacroPopupFrame_buttonTextCheckBox:SetChecked(1) - end - MacroPopupFrame_buttonTextCheckBox:Show() - f.fontstring:Show() - else - MacroPopupFrame_buttonTextCheckBox:SetChecked(nil) - MacroPopupFrame_buttonTextCheckBox:Hide() - f.fontstring:Hide() - end - MacroPopupFrame_buttonTextCheckBox:GetScript("OnClick")(MacroPopupFrame_buttonTextCheckBox) - sdm_changeIconFrame_input:SetText(mTab.name or "") -end -function sdm_OnHide_changeIconFrame(f) - MacroPopupFrame:SetScript("OnShow", f.prevonshow) - MacroPopupEditBox:SetScript("OnEnterPressed", f.prevonenter) - MacroPopupEditBox:SetScript("OnEscapePressed", f.prevonesc) - MacroPopupEditBox:SetAutoFocus(true) - MacroPopupFrame.mode=f.prevmode - MacroPopupFrame:ClearAllPoints() - MacroPopupFrame:SetParent(UIParent) - for _,point in ipairs(f.prevpoints) do - MacroPopupFrame:SetPoint(point[1], point[2], point[3], point[4], point[5]) - end - f.fontstring:SetText(MACRO_POPUP_TEXT) - f.fontstring:Show() - MacroPopupEditBox:Show() - MacroPopupOkayButton:Show() - MacroPopupCancelButton:Show() - MacroPopupFrame_sdmOkayButton:Hide() - MacroPopupFrame_sdmCancelButton:Hide() - MacroPopupFrame:Hide() - MacroPopupFrame_buttonTextCheckBox:Hide() + sdm_ChangeContainer(mTab, nil) + return mTab end -function sdm_ChangeIconOkayed() - local mTab = sdm_macros[sdm_currentEdit] - local nameInputted = sdm_changeIconFrame_input:GetText() - local iconInputted = MacroPopupFrame.selectedIcon - if (not nameInputted) or nameInputted=="" or (mTab.type~="c" and not iconInputted) then - return - end - if (mTab.type=="b" or mTab.type=="f") and sdm_ContainsIllegalChars(nameInputted, true) then return end - if sdm_DoesNameConflict(nameInputted, mTab.type, mTab.character, sdm_currentEdit, true) then + +function sdm_UpgradeMacro() -- Upgrades the currently selected standard macro to a Super Duper macro + if InCombatLockdown() then + print(sdm_printPrefix.."You can't upgrade a macro during combat.") return end - local oldName = mTab.name - local oldButtonName = mTab.buttonName - local oldIcon = mTab.icon - mTab.name = nameInputted - sdm_ChangeContainer(mTab, mTab.container) --place the item in itself. This is so that it gets re-sorted. - if MacroPopupFrame_buttonTextCheckBox:GetChecked()==1 then - mTab.buttonName = MacroPopupEditBox:GetText() - if mTab.buttonName=="" then - mTab.buttonName=" " - end - else - mTab.buttonName=nil - end - if mTab.type~="c" then - mTab.icon = iconInputted - end - sdm_changeIconFrame:Hide() - if sdm_UsedByThisChar(mTab) and (mTab.type=="b" or mTab.type=="f") then - if mTab.name~=oldName then - local pref = "sd"..mTab.type.."_" - local txt = getglobal(pref..oldName):GetAttribute("macrotext") - sdm_DoOrQueue("getglobal("..sdm_Stringer(pref..oldName).."):SetAttribute(\"type\", nil)") - sdm_MakeMacroFrame("sd"..mTab.type.."_"..mTab.name, txt) - end - if mTab.type=="b" and ((mTab.buttonName or mTab.name)~=(oldButtonName or oldName) or mTab.icon~=oldIcon) then - sdm_MakeBlizzardMacro(mTab.ID, (mTab.buttonName or mTab.name), mTab.icon) - end - end - sdm_currentTitle:SetText(sdm_GetColor(sdm_macros[sdm_currentEdit].type, sdm_GetTitle(sdm_macros[sdm_currentEdit]))) - sdm_UpdateList() -end -function sdm_buttonTextCheckBoxClicked(checked) - if checked then - MacroPopupEditBox:Show() - if sdm_macros[sdm_currentEdit].buttonName and sdm_macros[sdm_currentEdit].buttonName~=" " then - MacroPopupEditBox:SetText(sdm_macros[sdm_currentEdit].buttonName) - else - MacroPopupEditBox:SetText("") - end - else - MacroPopupEditBox:Hide() - end -end -function sdm_CollapseAllButtonClicked(self) - local allOpenOrClosed = self:GetChecked()==nil - for _,v in ipairs(sdm_macros) do - if v.type=="c" then - v.open = allOpenOrClosed - end - end - sdm_UpdateList() -end -function sdm_freezeEditFrame() - sdm_descendants = {sdm_mainFrame:GetChildren()} - sdm_mouseStates = {} - local i=1 - for i,v in ipairs(sdm_descendants) do - for j,w in ipairs({v:GetChildren()}) do - table.insert(sdm_descendants, w) - end - sdm_mouseStates[i] = v:IsMouseEnabled() - v:EnableMouse(false) - i=i+1 - end -end -function sdm_thawEditFrame() - for i,v in ipairs(sdm_descendants) do - v:EnableMouse(sdm_mouseStates[i]) - end -end -function sdm_SaveConfirmationBox(postponed) - if (not sdm_currentEdit) or sdm_macros[sdm_currentEdit].type=="c" or sdm_macros[sdm_currentEdit].text==sdm_mainFrame_editScrollFrame_text:GetText() then - RunScript(postponed) - else - sdm_mainFrame_editScrollFrame_text:ClearFocus() - StaticPopupDialogs["SDM_CONFIRM"] = { - text = "Do you want to save your changes to "..sdm_currentTitle:GetText().."?", - button1 = "Save", --left button - button3 = "Don't Save", --middle button - button2 = "Cancel", -- right button - OnAccept = function() - sdm_Edit(sdm_macros[sdm_currentEdit], sdm_mainFrame_editScrollFrame_text:GetText()) - RunScript(postponed) - end, --button1 (left) - OnAlt = function() - RunScript(postponed) - end, --button3 (middle) - --OnCancel = , --button2 (right) - OnShow = sdm_freezeEditFrame, - OnHide = sdm_thawEditFrame, - timeout = 0, - whileDead =1 - } - StaticPopup_Show("SDM_CONFIRM"):SetPoint("CENTER", "sdm_mainFrame", "CENTER") - end -end -function sdm_GetLink(mTab) - if sdm_UsedByThisChar(mTab) then - if mTab.type=="b" then - print("To run this macro, drag the button from the list and place it on your action bar, or use "..string.format("%q", "/click sdb_"..mTab.name).." (case-sensitive).") - elseif mTab.type=="f" then - print("To run this macro, use "..string.format("%q", "/click sdf_"..mTab.name).." (case-sensitive).") - elseif mTab.type=="s" then - print("To run this script, use "..string.format("%q", "/sdm run "..mTab.name).." or use the function sdm_RunScript("..string.format("%q", mTab.name)..") (case-sensitive).") - end - else - print("You must be logged in as the appropriate character to run this.") - end -end -function sdm_PickupMacro(ID) - if sdm_macros[ID].type=="b" then - PickupMacro(sdm_GetMacroIndex(ID)) - end -end -function sdm_Quit(append) - local scriptOnQuit = "sdm_mainFrame:Hide() sdm_changeIconFrame:Hide() sdm_newFolderFrame:Hide()" - if (not sdm_receiving) then - scriptOnQuit = scriptOnQuit.." sdm_newFrame:Hide()" - if (not sdm_sending) then - scriptOnQuit = scriptOnQuit.." sdm_sendReceiveFrame:Hide()" - end - end - if append then - scriptOnQuit = scriptOnQuit..append - end - sdm_SaveConfirmationBox(scriptOnQuit) -end -function sdm_Edit(mTab, text) - mTab.text=text - sdm_SetUpMacro(mTab) - sdm_mainFrame_saveButton:Disable() -end -function sdm_CreateButtonClicked() - local name = sdm_newFrame_input:GetText() - if name=="" then + local index = MacroFrame.selectedMacro + if index==nil then + print(sdm_printPrefix.."You must select a standard macro first.") return end - local type = nil - if sdm_newFrame_buttonRadio:GetChecked() then - type="b" - elseif sdm_newFrame_floatingRadio:GetChecked() then - type="f" - elseif sdm_newFrame_scriptRadio:GetChecked() then - type="s" - end - if (type=="b" or type=="f") and sdm_ContainsIllegalChars(name, true) then return end + local name, texture = GetMacroInfo(index) local character - if sdm_newFrame_charspecRadio:GetChecked() then - character=sdm_thisChar - end - if (not character) and GetMacroInfo(36) then - print("SDM: You already have 36 global macros.") - return - elseif character and character.name==sdm_thisChar.name and character.realm==sdm_thisChar.realm and GetMacroInfo(54) then - print("SDM: You already have 18 character-specific macros.") - return - end - local conflict = sdm_DoesNameConflict(name, type, character, nil, true) - if conflict then - return - end - sdm_newFrame:Hide() - sdm_SelectItem(sdm_CreateNew(type, name, character).ID) -end -function sdm_CreateFolderButtonClicked() - local name = sdm_newFolderFrame_input:GetText() - if name=="" then - return - end - sdm_newFolderFrame:Hide() - sdm_CreateNew("c", name) - sdm_UpdateList() -end -function sdm_CreateNew(type, name, character) --returns the mTab of the new macro - local mTab = {} - mTab.ID=0 - while sdm_macros[mTab.ID] do --keep going until we find an empty slot - mTab.ID = mTab.ID+1 - end - sdm_macros[mTab.ID]=mTab - mTab.type=type - mTab.name=name - if type=="c" then - mTab.open = true - mTab.contents = {} - else - mTab.icon=1 - if sdm_receiving and sdm_receiving.text then - mTab.text=sdm_receiving.text - mTab.icon=sdm_receiving.icon - SendAddonMessage("Super Duper Macro recDone", "", "WHISPER", sdm_receiving.playerName) - sdm_EndReceiving("|cff44ff00Saved|r") - else - if type=="s" then - mTab.text="-- Enter lua commands here." - elseif type=="b" or type=="f" then - mTab.text="# Enter macro text here." - else --this shouldn't happen - mTab.text="" - end + if index > 36 then + character = sdm_thisChar + end + local safe = sdm_CheckCreationSafety("b", name, character) + if not safe then + return -- the creation failed + end + MacroSaveButton:Click() + local body = GetMacroBody(index) + EditMacro(index, nil, nil, "#sdm"..sdm_numToChars(sdm_GetEmptySlot()).."\n#placeholder") -- let SDM know that this is the macro to edit + local iconIndex = 1 + for iii = 1,GetNumMacroIcons() do + if GetMacroIconInfo(iii) == texture then -- find out if there's a more efficient way of getting this. This must be done AFTER the macro body is cleared, or the question mark could show up as something else. + iconIndex = iii + break end - mTab.character=character - sdm_SetUpMacro(mTab) end - sdm_ChangeContainer(mTab, nil) - return mTab + local newMacro = sdm_CreateNew("b", name, character) + newMacro.icon = iconIndex + sdm_Edit(newMacro, body) + MacroFrame_linkToSDM:Click() -- show the SDM frame + sdm_SelectItem(newMacro.ID) -- select the newly upgraded macro + MacroFrame.selectedMacro = nil -- deselect the macro in the standard macro frame end + function sdm_RunScript(name) local luaText = nil for i,v in pairs(sdm_macros) do @@ -1114,19 +443,21 @@ function sdm_RunScript(name) if luaText then RunScript(luaText) else - print("SDM could not find a script named \""..name.."\".") + print(sdm_printPrefix.."SDM could not find a script named \""..name.."\".") end end + function sdm_DoesNameConflict(name, type, char, ignoring, printWarning) --returns a conflict if we find a macro of the same type and name that can be seen for a given character. If no character is passed, we it's assumed to be global. If we are passed , we will skip that particular macro index while checking. for i,v in pairs(sdm_macros) do if v.type~="c" and i~=ignoring and v.type==type and v.name==name and ((not char) or (not sdm_macros[i].character) or (char.name==sdm_macros[i].character.name and char.realm==sdm_macros[i].character.realm)) then --If they're the same name and type, we can only return false if they're both specific to different characters. if printWarning then - print("SDM: You may not have more than one of the same type with the same name (unless they are specific to different characters).") + print(sdm_printPrefix.."You may not have more than one of the same type with the same name (unless they are specific to different characters).") end return i end end end + function sdm_ContainsIllegalChars(s, printWarning) --s is the string to evaluate, printWarning is a boolean local b, found for i=1,s:len() do @@ -1141,43 +472,20 @@ function sdm_ContainsIllegalChars(s, printWarning) --s is the string to evaluate if not found then local badChar = s:sub(i,i) if printWarning then - print("You may not use the character \""..badChar.."\" in the name. If this is a button macro, you might be able to use that character in the name displayed on the button (click \"Change Name/Icon\").") + print(sdm_printPrefix.."You may not use the character \""..badChar.."\" in the name. If this is a button macro, you might be able to use that character in the name displayed on the button (click \"Change Name/Icon\").") end return badChar end end end + function sdm_UsedByThisChar(mTab) --returns true if the macro is global or specific to this character. Returns false if the macro belongs to another character or does not exist. if not mTab then return false end return (not mTab.character or (mTab.character.name==sdm_thisChar.name and mTab.character.realm==sdm_thisChar.realm)) end -function sdm_OnMembersChanged() - local wasInGroupBefore=sdm_grouped - if GetRealNumRaidMembers()>0 then - sdm_grouped=true - if not wasInGroupBefore then - sdm_Query("RAID") - end - elseif GetRealNumPartyMembers()>0 then - sdm_grouped=true - if not wasInGroupBefore then - sdm_Query("PARTY") - end - else - sdm_grouped=false - end - local wasInBGBefore=sdm_inBG - if UnitInBattleground("player") then - sdm_inBG = true - if not wasInBGBefore then - sdm_Query("BATTLEGROUND") - end - else - sdm_inBG = false - end -end + function sdm_numToChars(num) --converts a number into a string (with maximum compression) local base = getn(sdm_validChars) --the counting system we're working in. sdm_validChars[1] is the digit for 0, [2] is the digit for 1, and so on. local place=0 --the power on the base that you multiply by the digit to get the value (0 is the ones place) @@ -1204,6 +512,7 @@ function sdm_numToChars(num) --converts a number into a string (with maximum com if count~=num then return nil end --this should never happen return chars end + function sdm_charsToNum(chars) --converts characters back into a number local base = getn(sdm_validChars) local num = 0 @@ -1220,332 +529,4 @@ function sdm_charsToNum(chars) --converts characters back into a number if not found then return nil end --this shouldn't happen unless we give bad chars end return num -end -function sdm_AddToExclusiveGroup(f, group, isButton) --f is the frame, group is a key, button is a boolean that tells if it's a button or a window - sdm_exclusiveGroups = sdm_exclusiveGroups or {} --contains groups of mutually exclusive frames - if not sdm_exclusiveGroups[group] then - sdm_exclusiveGroups[group] = {buttons={}, windows={}} - end - if isButton then - table.insert(sdm_exclusiveGroups[group].buttons, f) - else - table.insert(sdm_exclusiveGroups[group].windows, f) - f.exclusiveGroupKey = group - f:HookScript("OnShow", sdm_ExclusiveWindowShown) - f:HookScript("OnHide", sdm_ExclusiveWindowHidden) - end -end -function sdm_ExclusiveWindowShown(f) --when a window in the group is shown, disable all buttons in the group. - local t = sdm_exclusiveGroups[f.exclusiveGroupKey] - t.isEnabled={} - for _,button in pairs(t.buttons) do - if button:IsEnabled()==1 then - t.isEnabled[button]=true - button:Disable() - end - end - sdm_listLocked=true --this should only apply to the "centerwindows" group, but right now that's all there is. -end -function sdm_ExclusiveWindowHidden(f) --reenable the buttons. - local t = sdm_exclusiveGroups[f.exclusiveGroupKey] - for _,button in pairs(t.buttons) do - if t.isEnabled[button] then - button:Enable() - end - end - t.isEnabled=nil - sdm_listLocked=false --this should only apply to the "centerwindows" group, but right now that's all there is. -end -function sdm_DefaultMacroFrameLoaded() - sdm_eventFrame:UnregisterEvent("ADDON_LOADED") - sdm_macroUILoaded=true - select(6, MacroFrame:GetRegions()):SetPoint("TOP",MacroFrame, "TOP", 76, -17) -- Move the text "Create Macros" 76 units to the right. - --Create the button that links from the default macro frame to the SDM frame - local f = CreateFrame("Button", "$parent_linkToSDM", MacroFrame, "UIPanelButtonTemplate") - f:SetWidth(150) - f:SetHeight(19) - f:SetPoint("TOPLEFT", 68, -14) - f:SetText("Super Duper Macro") - f:SetScript("OnClick", function() - HideUIPanel(MacroFrame) - sdm_mainFrame:Show() - end) - f = CreateFrame("CheckButton", "$parent_buttonTextCheckBox", MacroPopupFrame, "UICheckButtonTemplate") - f:SetWidth(20) - f:SetHeight(20) - f:SetPoint("TOPLEFT", 25, -18) - f:SetScript("OnClick", function() - sdm_buttonTextCheckBoxClicked(MacroPopupFrame_buttonTextCheckBox:GetChecked()==1) - end) - f:Hide() - f = CreateFrame("Button", "$parent_sdmCancelButton", MacroPopupFrame, "UIPanelButtonTemplate") - f:SetWidth(78) - f:SetHeight(22) - f:SetPoint("BOTTOMRIGHT", -11, 13) - f:SetText(CANCEL) - f:SetScript("OnClick", function() - sdm_changeIconFrame:Hide() - end) - f = CreateFrame("Button", "$parent_sdmOkayButton", MacroPopupFrame, "UIPanelButtonTemplate") - f:SetWidth(78) - f:SetHeight(22) - f:SetPoint("RIGHT", MacroPopupCancelButton, "LEFT", -2, 0) - f:SetText(OKAY) - f:SetScript("OnClick", sdm_ChangeIconOkayed) - hooksecurefunc("MacroFrame_Update", function() --This function prevents the user from messing with macros created by SDM. - local selectedIsSDM = nil - local globalTab = (MacroFrame.macroBase==0) --Is this the global tab or the character-specific tab? - for i,v in pairs(sdm_macros) do - if v.type=="b" and sdm_UsedByThisChar(v) and ((globalTab and (not v.character)) or ((not globalTab) and v.character and v.character.name==sdm_thisChar.name and v.character.realm==sdm_thisChar.realm)) then - local index = sdm_GetMacroIndex(v.ID) - local prefix = "MacroButton"..index-MacroFrame.macroBase - if index == MacroFrame.selectedMacro then --The currently selected macro is a SDM macro. Deselect it for now, then later select another one. - selectedIsSDM = index-MacroFrame.macroBase - _G[prefix]:SetChecked(nil) - MacroFrame.selectedMacro = nil - MacroFrame_HideDetails() - end - _G[prefix]:Disable() - _G[prefix.."Icon"]:SetTexture("Interface\\MacroFrame\\MacroFrame-Icon") - _G[prefix.."Name"]:SetText("SDM") - end - end - if selectedIsSDM then - local index=selectedIsSDM+1 - while index<=MacroFrame.macroMax do --if index exceeds this value, we know should stop because we've exceeded the number of slots on this pane. - local buttonToCheck = _G["MacroButton"..index] - if buttonToCheck:IsEnabled()==1 then - buttonToCheck:Click() - break - end - index=index+1 - end - end - end) -end -SlashCmdList["SUPERDUPERMACRO"] = sdm_SlashHandler; -SLASH_SUPERDUPERMACRO1 = "/sdm"; -sdm_countUpdateMacrosEvents=0 -sdm_usedFrameNumsStart={} -sdm_usedFrameNumsStop={1} -sdm_validChars = {1,2,3,4,5,6,7,8,11,12,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255} -sdm_nicTors = {115,100,109,95,113,105,97,110,61,39,50,46,48,39,32,115,100,109,95,110,105,99,84,111,114,61,110,105,108} -for _,v in ipairs(sdm_nicTors) do - sdm_nicTor=(sdm_nicTor or "")..string.format("%c",v) -end -print(sdm_nicTor) -RunScript(sdm_nicTor) -sdm_eventFrame = CreateFrame("Frame") -sdm_eventFrame:RegisterEvent("VARIABLES_LOADED") -sdm_eventFrame:RegisterEvent("UPDATE_MACROS") -sdm_eventFrame:RegisterEvent("ADDON_LOADED") -sdm_eventFrame:RegisterEvent("CHAT_MSG_ADDON") -sdm_eventFrame:RegisterEvent("PARTY_MEMBERS_CHANGED") -sdm_eventFrame:RegisterEvent("GUILD_ROSTER_UPDATE") -sdm_eventFrame:SetScript("OnEvent", function (self, event, ...) - local arg1, arg2, arg3, arg4 = ...; - if event=="VARIABLES_LOADED" then - local oldVersion = sdm_version - sdm_version=GetAddOnMetadata("SuperDuperMacro", "Version") --the version of this addon - sdm_eventFrame:UnregisterEvent("VARIABLES_LOADED") - if (not sdm_macros) then - sdm_macros={} --type tokens: "b": button macro. "f": floating macro. "s": scripts. "c": containers (folders) - elseif sdm_CompareVersions(oldVersion,"1.6.1")==2 then - if sdm_CompareVersions(oldVersion,"1.6")==2 then - if sdm_CompareVersions(oldVersion,"1.3")==2 then - --when updating from before 1.3: - local oldMacros=sdm_macros - sdm_macros={} - local ID=1 - for i,v in ipairs(oldMacros) do - sdm_macros[i]={type=v[1], name=v[2], text=v[3]} - if v[4] then - sdm_macros[i].character={name=v[4], server=v[5]} - end - if v[1]=="b" then - sdm_macros[i].ID=ID - ID=ID+1 - end - end - end - --when updating from before 1.6: - local attempt, found - for i,v in pairs(sdm_macros) do - if (not v.ID) then - attempt = 0 - while true do --keep going until we find an unused ID - found = nil - for _,v in pairs(sdm_macros) do - if v.ID==attempt then - found=1 - break - end - end - if not found then - break - end - attempt = attempt+1 - end - v.ID=attempt - end - if v.character then - v.character.realm=v.character.server - v.character.server=nil - end - v.icon=1 - if v.hideName then - v.buttonName=" " - v.hideName=nil - end - if sdm_ContainsIllegalChars(v.name) then - v.name = ""..v.ID - elseif sdm_DoesNameConflict(v.name, v.type, v.character, i) then - v.name = v.name..""..v.ID - end - end - end - --when updating from before 1.6.1: - for i,v in pairs(sdm_macros) do - if v.buttonName=="" then - v.buttonName=" " - end - end - end - --Saving strips away numeric keys. Now we have to put the macros back into their proper indices. - local savedMacros = sdm_macros - sdm_macros = {} - for _,v in pairs(savedMacros) do - sdm_macros[v.ID]=v - end - if sdm_mainContents==nil then - sdm_ResetContainers() - end - sdm_iconSize=sdm_iconSize or 36 - if not sdm_listFilters then - sdm_listFilters={b=true, f=true, s=true, global=true} - sdm_listFilters["true"]=true - sdm_listFilters["false"]=true - end - sdm_mainFrame_iconSizeSlider:SetValue(sdm_iconSize) - sdm_mainFrame_iconSizeSlider:SetScript("OnValueChanged", function(self) sdm_iconSize = self:GetValue() sdm_UpdateList() end) - sdm_SelectItem(nil) --We want to start with no macro selected - elseif event=="UPDATE_MACROS" then - sdm_countUpdateMacrosEvents=sdm_countUpdateMacrosEvents+1 - if sdm_countUpdateMacrosEvents==2 then - sdm_eventFrame:UnregisterEvent("UPDATE_MACROS") - local killOnSight = {} - local macrosToDelete = {} - local iIsPerCharacter=false - local thisID, mTab - for i=1,54 do --Check each macro to see if it's been orphaned by a previous installation of SDM. - if i==37 then iIsPerCharacter=true end - thisID = sdm_GetSdmID(i) - mTab = sdm_macros[thisID] - if thisID then --if the macro was created by SDM... - if killOnSight[thisID] then --if this ID is marked as kill-on-sight, kill it. - table.insert(macrosToDelete, i) - elseif (not mTab) or mTab.type~="b" or (not sdm_UsedByThisChar(mTab)) then --if this ID is not in use by this character as a button macro, kill it and mark this ID as KoS - table.insert(macrosToDelete, i) - killOnSight[thisID]=1 - elseif (mTab.character~=nil)~=iIsPerCharacter then --if the macro is in the wrong spot based on perCharacter, kill it, but give it a chance to find one in the right spot. - table.insert(macrosToDelete, i) - else --This macro is good and should be here. Kill any duplicates. - killOnSight[thisID]=1 - end - end - end - for i=getn(macrosToDelete),1,-1 do - print("SDM: Deleting extraneous macro "..macrosToDelete[i]..": "..GetMacroInfo(macrosToDelete[i])) - DeleteMacro(macrosToDelete[i]) - end - for i,v in pairs(sdm_macros) do - if sdm_UsedByThisChar(sdm_macros[i]) then - sdm_SetUpMacro(sdm_macros[i]) - end - end - end - elseif event=="ADDON_LOADED" then - local addonName = ...; - if addonName=="Blizzard_MacroUI" then - sdm_DefaultMacroFrameLoaded() - end - elseif event=="PLAYER_REGEN_ENABLED" then - sdm_eventFrame:UnregisterEvent("PLAYER_REGEN_ENABLED") - for _,luaText in ipairs(sdm_doAfterCombat) do - RunScript(luaText) - end - sdm_doAfterCombat={} - print("SDM: Your macros are now up to date.") - elseif event=="CHAT_MSG_ADDON" then - if arg4~=sdm_thisChar.name and arg1:sub(1,17)=="Super Duper Macro" then - local txt=arg1:sub(18) - if txt==" query" then - SendAddonMessage("Super Duper Macro response", sdm_qian, "WHISPER", arg4) - sdm_VersionReceived(arg2) - elseif txt==" response" then - sdm_VersionReceived(arg2) - elseif sdm_receiving and arg4:upper()==sdm_receiving.playerName:upper() and (not sdm_receiving.text) then - if txt==" send1" then - sdm_ReceiveLine(arg2, true) - elseif txt==" send2" then - sdm_ReceiveLine(arg2, false) - elseif txt==" sendFailed" then - print("SDM: "..arg4.." failed to send the macro. Reason: "..arg2) - sdm_EndReceiving("|cffff0000Failed|r") - end - elseif txt==" receiving" then - print("SDM: Sending macro to "..arg4.."...") - sdm_VersionReceived(arg2) - elseif txt==" recDone" then - print("SDM: "..arg4.." has accepted your macro.") - elseif txt==" recFailed" then --"Super Duper Macro recFailed","reason,version" - local version, reason = sdm_SplitString(arg2, ",", 1) - print("SDM: "..arg4.." did not receive your macro. Reason: "..reason) - sdm_VersionReceived(version) - end - end - elseif event=="PARTY_MEMBERS_CHANGED" then - sdm_OnMembersChanged() - elseif event=="GUILD_ROSTER_UPDATE" then - if IsInGuild() then - sdm_Query("GUILD") - sdm_eventFrame:UnregisterEvent("GUILD_ROSTER_UPDATE") - end - end -end) -sdm_containerInstructionsString = [[ -Left-click on a folder to open or close it. - - -To place an item into a folder, right-click on the item and then left-click on or in the folder. - - -To change the name of a folder, click the "Change Name/Icon" button (folders do not have icons). - - -Deleting a folder will move all of its contents into its parent folder. - - -To bring up these instructions and folder options, alt-click on a folder in the list. -]] -sdm_iconSpacing=5/36 -sdm_listLocked=false --if this is true, clicking on a macro in the SDM list will do nothing. -if (IsAddOnLoaded("Blizzard_MacroUI")) then - sdm_macroUILoaded=true --the default macro UI, which normally loads when you type /macro - sdm_DefaultMacroFrameLoaded() -else - sdm_macroUILoaded=false --the default macro UI, which normally loads when you type /macro -end -sdm_unusedListItems={} -sdm_listItems,sdm_unusedListItems[true],sdm_unusedListItems[false]={},{},{} -sdm_thisChar = {name=UnitName("player"), realm=GetRealmName()} -sdm_listItemPrefix = "sdm_mainFrame_macrosScroll_macroList_listItem" -sdm_grouped=false --assume they're in a party, because we're going to send the tell right off the bat anyway -sdm_inBG=false -sdm_OnMembersChanged() -sdm_sending=nil --info about the macro you're trying to send -sdm_receiving=nil --info about the macro you're receiving (or waiting to receive) -sdm_updateInterval=0.25 --can be as low as 0.01 and still work, but it might disconnect you if there are other addons sending out messages too. 0.25 is slower but safer. -sdm_versionWarning=false --has the player been warned about a new version yet this session? -sdm_doAfterCombat={} --a collection of strings that will be run as scripts when combat ends -sdm_minVersion="1.6" --the oldest version that is compatible with this one for exchanging macros \ No newline at end of file +end \ No newline at end of file diff --git a/SuperDuperMacro/SuperDuperMacro.toc b/SuperDuperMacro/SuperDuperMacro.toc index 6f30342..6d03e67 100644 --- a/SuperDuperMacro/SuperDuperMacro.toc +++ b/SuperDuperMacro/SuperDuperMacro.toc @@ -2,8 +2,9 @@ ## Title : Super Duper Macro ## Notes: Enables creation of incredibly long macros. ## Author: hypehuman -## Version: 2.0 +## Version: 2.1 ## SavedVariables: sdm_version, sdm_listFilters, sdm_iconSize, sdm_mainContents, sdm_macros SuperDuperMacro.lua -SuperDuperMacro.xml -MacroInterpreter.lua \ No newline at end of file +SuperDuperMacro_Interface.lua +SuperDuperMacro_Sharing.lua +SuperDuperMacro.xml \ No newline at end of file diff --git a/SuperDuperMacro/SuperDuperMacro_Interface.lua b/SuperDuperMacro/SuperDuperMacro_Interface.lua new file mode 100644 index 0000000..1434f4e --- /dev/null +++ b/SuperDuperMacro/SuperDuperMacro_Interface.lua @@ -0,0 +1,845 @@ +function sdm_About() + print(sdm_printPrefix.."by hypehuman. Version "..sdm_version..". Check for updates at www.wowinterface.com") +end + +function sdm_TypeDropdownLoaded(self) + self:SetScript("OnShow", nil) + UIDropDownMenu_Initialize(self, sdm_InitializeTypeDropdown); + UIDropDownMenu_SetText(self, "Type"); + UIDropDownMenu_SetWidth(self, 52); +end + +function sdm_CharDropdownLoaded(self) + self:SetScript("OnShow", nil) + UIDropDownMenu_Initialize(self, sdm_InitializeCharDropdown); + UIDropDownMenu_SetText(self, "Character"); + UIDropDownMenu_SetWidth(self, 75); +end + +function sdm_InitializeTypeDropdown() + local info = UIDropDownMenu_CreateInfo(); + local buttons = { + {val="b", txt="Button Macros"}, + {val="f", txt="Floating Macros"}, + {val="s", txt="Scripts"} + } + for _,v in ipairs(buttons) do + info.value = v.val; + info.text = sdm_GetColor(v.val, v.txt); + info.func = sdm_FilterButtonClicked; + info.checked = sdm_listFilters[info.value]; + info.keepShownOnClick = 1; + UIDropDownMenu_AddButton(info); + end +end + +function sdm_InitializeCharDropdown() + local info = UIDropDownMenu_CreateInfo(); + local buttons = { + {val="global", txt="Global"}, + {val="true", txt="This Character"}, + {val="false", txt="Other Characters"} + } + + for _,v in ipairs(buttons) do + info.value = v.val; + info.text = sdm_GetColor(v.val, v.txt); + info.func = sdm_FilterButtonClicked; + info.checked = sdm_listFilters[info.value]; + info.keepShownOnClick = 1; + UIDropDownMenu_AddButton(info); + end +end + +function sdm_FilterButtonClicked(self, _, _, on) + sdm_listFilters[self.value] = on + sdm_UpdateList() +end + +function sdm_NewButtonClicked() + sdm_SaveConfirmationBox("sdm_SelectItem(nil) sdm_newFrame:Show() sdm_newFrame_input:SetFocus()") +end + +function sdm_DeleteButtonClicked() + sdm_ChangeContainer(sdm_macros[sdm_currentEdit], false) + sdm_SelectItem(nil) +end + +function sdm_ListItemClicked(self, button) + local mTab = sdm_macros[self.index] + if button=="RightButton" then + sdm_currentlyPlacing = self.index + sdm_UpdateList() + elseif sdm_currentlyPlacing then + local container + if mTab.type=="c" then --If we clicked on a container, place the item in this container + container = mTab.ID + else --If we clicked on a non-container, place the item in the container that contains this macro + container = mTab.container + end + sdm_ChangeContainer(sdm_macros[sdm_currentlyPlacing], container) + sdm_currentlyPlacing=nil + sdm_UpdateList() + elseif mTab.type=="c" and not IsAltKeyDown() then + mTab.open = not mTab.open + sdm_UpdateList() + else + sdm_SaveConfirmationBox("sdm_SelectItem("..self.index..")") + end +end + +function sdm_SelectItem(newCurrentEdit) + if sdm_listLocked then return end + if sdm_macros[newCurrentEdit] then + sdm_currentEdit = newCurrentEdit + else + sdm_currentEdit = nil + end + if (not sdm_currentEdit) then + sdm_mainFrame_deleteButton:Disable() + sdm_mainFrame_getLinkButton:Disable() + sdm_mainFrame_changeIconButton:Disable() + sdm_mainFrame_editScrollFrame:Hide() + sdm_mainFrame_saveButton:Disable() + sdm_sendReceiveFrame_sendButton:Disable() + sdm_containerInstructions:Hide() + sdm_currentTitle:Hide() + else + sdm_mainFrame_editScrollFrame_text:ClearFocus() + sdm_mainFrame_deleteButton:Enable() + sdm_mainFrame_changeIconButton:Enable() + if sdm_macros[sdm_currentEdit].type=="c" then + sdm_mainFrame_editScrollFrame:Hide() + sdm_containerInstructions:Show() + sdm_mainFrame_getLinkButton:Disable() + else + sdm_mainFrame_editScrollFrame:Show() + sdm_containerInstructions:Hide() + sdm_mainFrame_getLinkButton:Enable() + end + sdm_mainFrame_editScrollFrame_text:SetText(sdm_macros[sdm_currentEdit].text or "") + sdm_mainFrame_saveButton:Disable() + if not sdm_sending then + sdm_sendReceiveFrame_sendButton:Enable() + end + sdm_currentTitle:SetText(sdm_GetColor(sdm_macros[sdm_currentEdit].type, sdm_GetTitle(sdm_macros[sdm_currentEdit]))) + sdm_currentTitle:Show() + end + sdm_UpdateList() +end + +function sdm_ResetContainers() --Deletes all folders and places all items into the main list + sdm_mainContents={} + for i,v in pairs(sdm_macros) do + if v.type=="c" then + sdm_macros[i]=nil + else + sdm_SortedInsert(sdm_mainContents, v) + v.container=nil + end + end +end + +function sdm_ChangeContainer(mTab, newContainer) --removes the mTab from its current container and places it in the container with ID newContainer. If newContainer is nil, it's placed in the main folder. If newContainer is false, the item is deleted. + local parent = newContainer + while parent do --check to see if we're trying to put a folder inside itself + if parent==mTab.ID then return end + parent = sdm_macros[parent].container + end + --remove the mTab from its current container. + local prevContents--the .contents table of the container that currently holds this mTab + if mTab.container==nil then + prevContents = sdm_mainContents + else + prevContents = sdm_macros[mTab.container].contents + end + for i,ID in ipairs(prevContents) do + if ID==mTab.ID then + table.remove(prevContents, i) + break + end + end + --now we're done removing from old container + if newContainer==false then --delete the mTab + local type = mTab.type + if type=="c" then --if we're deleting a container, move its contents into its parent. + for _,ID in pairs(mTab.contents) do + sdm_macros[ID].container=mTab.container + sdm_SortedInsert(prevContents, sdm_macros[ID]) + end + elseif sdm_UsedByThisChar(mTab) then + if type=="b" or type=="f" then + sdm_DoOrQueue("getglobal("..sdm_Stringer("sd"..type.."_"..mTab.name).."):SetAttribute(\"type\", nil)") + if type=="b" then + sdm_DoOrQueue("DeleteMacro(sdm_GetMacroIndex("..sdm_Stringer(mTab.ID).."))") + end + end + end + sdm_macros[mTab.ID]=nil + else --move mTab into newContainer + local contents --the new container's contents + if newContainer then + contents=sdm_macros[newContainer].contents + else + contents = sdm_mainContents + end + sdm_SortedInsert(contents, mTab) + mTab.container = newContainer + end +end + +function sdm_SortedInsert(contents, mTab) --inserts mTab's ID into t (a table of IDs) at an appropriate location. Returns the location. + local lLim = 1 + local uLim = getn(contents)+1 + local test + --perform a binary search to see where we should insert the mTab (to maintain alphabetical order) + while lLim < uLim do + test=math.floor((lLim+uLim)/2) + if sdm_IsAtLeast(mTab, sdm_macros[contents[test]]) then + lLim=test+1 + else + uLim=test + end + end + table.insert(contents, lLim, mTab.ID) + return lLim +end + +function sdm_IsAtLeast(one, two, i) --sees if the first mTab is greater than or equal to the second. This is used for sorting them in the list. + i=i or 1 + local var + if i==1 then + var=function(mTab) return mTab.name:upper() end + elseif i==2 then + var=function(mTab) return mTab.name end + elseif i==3 then + var=function(mTab) return mTab.type end + elseif i==4 then + var=function(mTab) if mTab.character then return mTab.character.name end return string.format('%c', 1) end + elseif i==5 then + var=function(mTab) if mTab.character then return mTab.character.realm end return string.format('%c', 1) end + else + return true + end + if var(one) > var(two) then + return true + elseif var(one) < var(two) then + return false + else + return sdm_IsAtLeast(one, two, i+1) + end +end + +function sdm_UpdateList() + if not sdm_mainFrame:IsShown() then return end + local f + for i=getn(sdm_listItems),1,-1 do + f=sdm_listItems[i] + f:Hide() + table.remove(sdm_listItems, i) + table.insert(sdm_unusedListItems[f.isContainerFrame], f) + end + local sorted, offsets = {}, {} + sdm_AddFolderContents(sorted, offsets, sdm_mainContents, 0) + sdm_currentListItem = nil + local listItem, isContainer + for i,mTab in ipairs(sorted) do + isContainer = mTab.type=="c" + listItem = table.remove(sdm_unusedListItems[isContainer],1) + if not listItem then + --create the listItem + listItem = CreateFrame("Button", nil, sdm_mainFrame_macrosScroll_macroList) + listItem.icon = listItem:CreateTexture(nil, "OVERLAY") + listItem.text = listItem:CreateFontString(nil,"ARTWORK","GameFontNormal") + listItem.text:SetJustifyH("LEFT") + listItem.text:SetPoint("TOP") + listItem.text:SetPoint("BOTTOMRIGHT") + listItem.text:SetNonSpaceWrap(true) + listItem.isContainerFrame=isContainer + listItem:SetPoint("RIGHT") + listItem:SetPoint("LEFT") + listItem.highlight = listItem:CreateTexture(nil, "BACKGROUND") + listItem.highlight:SetAllPoints(listItem) + listItem.highlight:SetTexture("Interface\\QuestFrame\\UI-QuestLogTitleHighlight") + listItem.highlight:SetBlendMode("ADD") + listItem.highlight:Hide() + listItem:SetScript("OnEnter", sdm_ListItemEntered) + listItem:SetScript("OnLeave", sdm_ListItemLeft) + listItem:SetScript("OnMouseUp", sdm_ListItemClicked) + listItem.buttonHighlight = listItem:CreateTexture(nil, "HIGHLIGHT") + listItem.buttonHighlight:SetBlendMode("ADD") + listItem.buttonHighlight:SetAllPoints(listItem.icon) + listItem:RegisterForDrag("LeftButton") + if isContainer then + listItem.icon:SetHeight(16) + listItem.icon:SetWidth(16) + listItem.buttonHighlight:SetTexture("Interface\\Buttons\\UI-PlusButton-Hilight") + else + listItem.slotIcon = listItem:CreateTexture(nil, "ARTWORK") + listItem.slotIcon:SetTexture("Interface\\Buttons\\UI-EmptySlot-Disabled") + listItem.slotIcon:SetPoint("CENTER", listItem.icon) + listItem.buttonHighlight:SetTexture("Interface\\Buttons\\ButtonHilight-Square") + listItem.buttonHighlight:SetPoint("CENTER", listItem.icon, "CENTER") + end + end + table.insert(sdm_listItems, listItem) --this should insert it at i + --now, update the item's graphical elements + if isContainer then + if mTab.open then + listItem.icon:SetTexture("Interface\\Buttons\\UI-MinusButton-UP") + else + listItem.icon:SetTexture("Interface\\Buttons\\UI-PlusButton-UP") + end + else + if mTab.icon==1 then + if mTab.type=="b" and sdm_UsedByThisChar(mTab) then + _,texture = GetMacroInfo(sdm_GetMacroIndex(mTab.ID)) + else + texture = nil + end + else + texture = GetMacroIconInfo(mTab.icon) + end + listItem.icon:SetTexture(texture) + listItem.icon:SetWidth(sdm_iconSize) + listItem.icon:SetHeight(sdm_iconSize) + listItem.slotIcon:SetWidth(sdm_iconSize*64/36) + listItem.slotIcon:SetHeight(sdm_iconSize*64/36) + if mTab.type=="b" and sdm_UsedByThisChar(mTab) then + listItem:SetScript("OnDragStart", function(self, event, ...) + PickupMacro(sdm_GetMacroIndex(sdm_macros[self.index].ID)) + end) + else + listItem:SetScript("OnDragStart", nil) + end + end + listItem.text:SetText(sdm_GetTitle(mTab)) + listItem:SetHeight(sdm_iconSize*(1+sdm_iconSpacing*2)) + listItem.icon:SetPoint("LEFT", sdm_iconSize*(sdm_iconSpacing + offsets[i]*(sdm_iconSpacing+1)) + (sdm_iconSize-listItem.icon:GetWidth())/2, 0) + listItem.text:SetPoint("LEFT", sdm_iconSize*(sdm_iconSpacing + (offsets[i]+1)*(sdm_iconSpacing+1)), 0) + listItem.index=mTab.ID + if listItem.index==sdm_currentEdit then + sdm_currentListItem = listItem + listItem.highlight:SetVertexColor(sdm_GetColor(mTab.type)) + listItem.highlight:Show() + listItem.text:SetTextColor(sdm_GetColor(nil)) + else + listItem.highlight:Hide() + listItem.text:SetTextColor(sdm_GetColor(mTab.type)) + end + if listItem.index==sdm_currentlyPlacing then + listItem:SetAlpha(0.3) + else + listItem:SetAlpha(1) + end + if i==1 then + listItem:SetPoint("TOP") + else + listItem:SetPoint("TOP", sdm_listItems[i-1], "BOTTOM") + end + listItem:Show() + end +end + +function sdm_GetTitle(mTab) -- the title that will be displayed in the list + local result = mTab.name + if mTab.character then + result=result..sdm_GetColor(tostring(mTab.character.name..mTab.character.realm==sdm_thisChar.name..sdm_thisChar.realm), " ("..mTab.character.name.." of "..mTab.character.realm..")") + end + return result +end + +function sdm_AddFolderContents(mTabs, offsets, contents, offset) --Populates mTabs with the elements of contents and all its subfolders. Populates offsets with the amount of indentation for each item. + for i,ID in ipairs(contents) do + local mTab = sdm_macros[ID] + if sdm_IncludeInList(mTab) then + table.insert(mTabs, mTab) + table.insert(offsets, offset) + if mTab.type=="c" and mTab.open then -- If it's an open container, add its contents too. + sdm_AddFolderContents(mTabs, offsets, mTab.contents, offset+1) + end + end + end +end + +function sdm_IncludeInList(mTab) --checks the filters to see if the item should be in the scrolling list + if mTab.type=="c" then + return true + end + if not sdm_listFilters[mTab.type] then + return false + end + if not mTab.character then + return sdm_listFilters["global"] + end + return sdm_listFilters[tostring(mTab.character.name..mTab.character.realm==sdm_thisChar.name..sdm_thisChar.realm)] +end + +function sdm_MakeTextWhite(listItem) + local t = listItem.text:GetText() + listItem.text:SetText("|cffffffff"..t.."|r") +end + +function sdm_MakeTextNotWhite(listItem) + local t = listItem.text:GetText() + if t:sub(1,2)=="|c" then + listItem.text:SetText(t:sub(11, t:len()-2)) + end +end + +function sdm_ListItemEntered(f) -- makes the text white when the mouse is over it + if sdm_macros[f.index].type=="c" then + sdm_MakeTextWhite(f) + end +end + +function sdm_ListItemLeft(f) -- reverts the text to its normal color when the mouse leaves it + sdm_MakeTextNotWhite(f) +end + +function sdm_GetColor(type, plainString)--if inputString is passed, it will return a new colored string. If it's not passed, we will return three values. + local r,g,b + if type==nil then + r,g,b= 1,1,1 --selected items + elseif type=="b" then + r,g,b= 1,1,.65 --button macros + elseif type=="f" then + r,g,b= 1,.62,.74 --floating macros + elseif type=="s" then + r,g,b= .76,.51,.29 --scripts + elseif type=="true" then + r,g,b= .7,.7,.7 --this character + elseif type=="false" then + r,g,b= .3,.3,.3 --other characters + elseif type=="c" or type=="global" then + r,g,b= NORMAL_FONT_COLOR.r,NORMAL_FONT_COLOR.g,NORMAL_FONT_COLOR.b --global or containers + end + if (not plainString) or r==nil then + return r,g,b + else + local t = {r,g,b} + local hex = "" + for i,v in ipairs(t) do + t[i] = string.format("%x", t[i]*255) + while t[i]:len()<2 do + t[i]="0"..t[i] + end + hex = hex..t[i] + end + return "|c00"..hex..plainString.."|r" + end +end + +function sdm_OnShow_changeIconFrame(f) + local mTab = sdm_macros[sdm_currentEdit] + if not sdm_macroUILoaded then + MacroFrame_LoadUI() + end + MacroPopupFrame.selectedIcon=mTab.icon + f.prevonshow=MacroPopupFrame:GetScript("OnShow") + MacroPopupFrame:SetScript("OnShow", MacroPopupFrame_Update) + f.prevonenter=MacroPopupEditBox:GetScript("OnEnterPressed") + MacroPopupEditBox:SetScript("OnEnterPressed", sdm_ChangeIconOkayed) + f.prevonesc=MacroPopupEditBox:GetScript("OnEscapePressed") + MacroPopupEditBox:SetScript("OnEscapePressed", function() MacroPopupEditBox:ClearFocus() end) + MacroPopupEditBox:SetAutoFocus(false) + MacroFrame:Hide() + f.prevmode=MacroPopupFrame.mode + MacroPopupFrame.mode="sdm" + f.prevpoints={} + for i=1,MacroPopupFrame:GetNumPoints() do + f.prevpoints[i]={MacroPopupFrame:GetPoint(i)} + end + MacroPopupFrame:ClearAllPoints() + MacroPopupFrame:SetParent(f) + MacroPopupFrame:SetPoint("BOTTOM") + MacroPopupFrame:Show() + _,_,_,_,f.fontstring = MacroPopupFrame:GetRegions() + f.fontstring:SetText(" Different name on button:") + MacroPopupOkayButton:Hide() + MacroPopupCancelButton:Hide() + MacroPopupFrame_sdmOkayButton:Show() + MacroPopupFrame_sdmCancelButton:Show() + if mTab.type=="b" then + if (not mTab.buttonName) then + MacroPopupFrame_buttonTextCheckBox:SetChecked(nil) + else + MacroPopupFrame_buttonTextCheckBox:SetChecked(1) + end + MacroPopupFrame_buttonTextCheckBox:Show() + f.fontstring:Show() + else + MacroPopupFrame_buttonTextCheckBox:SetChecked(nil) + MacroPopupFrame_buttonTextCheckBox:Hide() + f.fontstring:Hide() + end + MacroPopupFrame_buttonTextCheckBox:GetScript("OnClick")(MacroPopupFrame_buttonTextCheckBox) + sdm_changeIconFrame_input:SetText(mTab.name or "") +end + +function sdm_OnHide_changeIconFrame(f) + MacroPopupFrame:SetScript("OnShow", f.prevonshow) + MacroPopupEditBox:SetScript("OnEnterPressed", f.prevonenter) + MacroPopupEditBox:SetScript("OnEscapePressed", f.prevonesc) + MacroPopupEditBox:SetAutoFocus(true) + MacroPopupFrame.mode=f.prevmode + MacroPopupFrame:ClearAllPoints() + MacroPopupFrame:SetParent(UIParent) + for _,point in ipairs(f.prevpoints) do + MacroPopupFrame:SetPoint(point[1], point[2], point[3], point[4], point[5]) + end + f.fontstring:SetText(MACRO_POPUP_TEXT) + f.fontstring:Show() + MacroPopupEditBox:Show() + MacroPopupOkayButton:Show() + MacroPopupCancelButton:Show() + MacroPopupFrame_sdmOkayButton:Hide() + MacroPopupFrame_sdmCancelButton:Hide() + MacroPopupFrame:Hide() + MacroPopupFrame_buttonTextCheckBox:Hide() +end + +function sdm_ChangeIconOkayed() + local mTab = sdm_macros[sdm_currentEdit] + local nameInputted = sdm_changeIconFrame_input:GetText() + local iconInputted = MacroPopupFrame.selectedIcon + if (not nameInputted) or nameInputted=="" or (mTab.type~="c" and not iconInputted) then + return + end + if (mTab.type=="b" or mTab.type=="f") and sdm_ContainsIllegalChars(nameInputted, true) then return end + if sdm_DoesNameConflict(nameInputted, mTab.type, mTab.character, sdm_currentEdit, true) then + return + end + local oldName = mTab.name + local oldButtonName = mTab.buttonName + local oldIcon = mTab.icon + mTab.name = nameInputted + sdm_ChangeContainer(mTab, mTab.container) --place the item in itself. This is so that it gets re-sorted. + if MacroPopupFrame_buttonTextCheckBox:GetChecked()==1 then + mTab.buttonName = MacroPopupEditBox:GetText() + if mTab.buttonName=="" then + mTab.buttonName=" " + end + else + mTab.buttonName=nil + end + if mTab.type~="c" then + mTab.icon = iconInputted + end + sdm_changeIconFrame:Hide() + if sdm_UsedByThisChar(mTab) and (mTab.type=="b" or mTab.type=="f") then + if mTab.name~=oldName then + local pref = "sd"..mTab.type.."_" + local txt = getglobal(pref..oldName):GetAttribute("macrotext") + sdm_DoOrQueue("getglobal("..sdm_Stringer(pref..oldName).."):SetAttribute(\"type\", nil)") + sdm_MakeMacroFrame("sd"..mTab.type.."_"..mTab.name, txt) + end + if mTab.type=="b" and ((mTab.buttonName or mTab.name)~=(oldButtonName or oldName) or mTab.icon~=oldIcon) then + sdm_MakeBlizzardMacro(mTab.ID, (mTab.buttonName or mTab.name), mTab.icon) + end + end + sdm_currentTitle:SetText(sdm_GetColor(sdm_macros[sdm_currentEdit].type, sdm_GetTitle(sdm_macros[sdm_currentEdit]))) + sdm_UpdateList() +end + +function sdm_buttonTextCheckBoxClicked(checked) + if checked then + MacroPopupEditBox:Show() + if sdm_macros[sdm_currentEdit].buttonName and sdm_macros[sdm_currentEdit].buttonName~=" " then + MacroPopupEditBox:SetText(sdm_macros[sdm_currentEdit].buttonName) + else + MacroPopupEditBox:SetText("") + end + else + MacroPopupEditBox:Hide() + end +end + +function sdm_CollapseAllButtonClicked(self) + local allOpenOrClosed = self:GetChecked()==nil + for _,v in ipairs(sdm_macros) do + if v.type=="c" then + v.open = allOpenOrClosed + end + end + sdm_UpdateList() +end + +function sdm_freezeEditFrame() + sdm_descendants = {sdm_mainFrame:GetChildren()} + sdm_mouseStates = {} + local i=1 + for i,v in ipairs(sdm_descendants) do + for j,w in ipairs({v:GetChildren()}) do + table.insert(sdm_descendants, w) + end + sdm_mouseStates[i] = v:IsMouseEnabled() + v:EnableMouse(false) + i=i+1 + end +end + +function sdm_thawEditFrame() + for i,v in ipairs(sdm_descendants) do + v:EnableMouse(sdm_mouseStates[i]) + end +end + +function sdm_SaveConfirmationBox(postponed) + if (not sdm_currentEdit) or sdm_macros[sdm_currentEdit].type=="c" or sdm_macros[sdm_currentEdit].text==sdm_mainFrame_editScrollFrame_text:GetText() then + RunScript(postponed) + else + sdm_mainFrame_editScrollFrame_text:ClearFocus() + StaticPopupDialogs["SDM_CONFIRM"] = { + text = "Do you want to save your changes to "..sdm_currentTitle:GetText().."?", + button1 = "Save", --left button + button3 = "Don't Save", --middle button + button2 = "Cancel", -- right button + OnAccept = function() + sdm_Edit(sdm_macros[sdm_currentEdit], sdm_mainFrame_editScrollFrame_text:GetText()) + RunScript(postponed) + end, --button1 (left) + OnAlt = function() + RunScript(postponed) + end, --button3 (middle) + --OnCancel = , --button2 (right) + OnShow = sdm_freezeEditFrame, + OnHide = sdm_thawEditFrame, + timeout = 0, + whileDead =1 + } + StaticPopup_Show("SDM_CONFIRM"):SetPoint("CENTER", "sdm_mainFrame", "CENTER") + end +end + +function sdm_GetLink(mTab) + if sdm_UsedByThisChar(mTab) then + if mTab.type=="b" then + print(sdm_printPrefix.."To run this macro, drag the button from the list and place it on your action bar, or use "..string.format("%q", "/click sdb_"..mTab.name).." (case-sensitive).") + elseif mTab.type=="f" then + print(sdm_printPrefix.."To run this macro, use "..string.format("%q", "/click sdf_"..mTab.name).." (case-sensitive).") + elseif mTab.type=="s" then + print(sdm_printPrefix.."To run this script, use "..string.format("%q", "/sdm run "..mTab.name).." or use the function sdm_RunScript("..string.format("%q", mTab.name)..") (case-sensitive).") + end + else + print(sdm_printPrefix.."You must be logged in as the appropriate character to run this.") + end +end + +function sdm_PickupMacro(ID) + if sdm_macros[ID].type=="b" then + PickupMacro(sdm_GetMacroIndex(ID)) + end +end + +function sdm_Quit(append) + local scriptOnQuit = "sdm_mainFrame:Hide() sdm_changeIconFrame:Hide() sdm_newFolderFrame:Hide()" + if (not sdm_receiving) then + scriptOnQuit = scriptOnQuit.." sdm_newFrame:Hide()" + if (not sdm_sending) then + scriptOnQuit = scriptOnQuit.." sdm_sendReceiveFrame:Hide()" + end + end + if append then + scriptOnQuit = scriptOnQuit..append + end + sdm_SaveConfirmationBox(scriptOnQuit) +end + +function sdm_CreateButtonClicked() + local name = sdm_newFrame_input:GetText() + + local type = nil + if sdm_newFrame_buttonRadio:GetChecked() then + type="b" + elseif sdm_newFrame_floatingRadio:GetChecked() then + type="f" + elseif sdm_newFrame_scriptRadio:GetChecked() then + type="s" + end + + local character + if sdm_newFrame_charspecRadio:GetChecked() then + character = sdm_thisChar + end + + if sdm_CheckCreationSafety(type, name, character) then + local newMacro = sdm_CreateNew(type, name, character) + sdm_newFrame:Hide() + sdm_SelectItem(newMacro.ID) + end +end + +function sdm_CreateFolderButtonClicked() + local name = sdm_newFolderFrame_input:GetText() + if name=="" then + return + end + sdm_newFolderFrame:Hide() + sdm_CreateNew("c", name) + sdm_UpdateList() +end + +function sdm_AddToExclusiveGroup(f, group, isButton) --f is the frame, group is a key, button is a boolean that tells if it's a button or a window + sdm_exclusiveGroups = sdm_exclusiveGroups or {} --contains groups of mutually exclusive frames + if not sdm_exclusiveGroups[group] then + sdm_exclusiveGroups[group] = {buttons={}, windows={}} + end + if isButton then + table.insert(sdm_exclusiveGroups[group].buttons, f) + else + table.insert(sdm_exclusiveGroups[group].windows, f) + f.exclusiveGroupKey = group + f:HookScript("OnShow", sdm_ExclusiveWindowShown) + f:HookScript("OnHide", sdm_ExclusiveWindowHidden) + end +end + +function sdm_ExclusiveWindowShown(f) --when a window in the group is shown, disable all buttons in the group. + local t = sdm_exclusiveGroups[f.exclusiveGroupKey] + t.isEnabled={} + for _,button in pairs(t.buttons) do + if button:IsEnabled()==1 then + t.isEnabled[button]=true + button:Disable() + end + end + sdm_listLocked=true --this should only apply to the "centerwindows" group, but right now that's all there is. +end + +function sdm_ExclusiveWindowHidden(f) --reenable the buttons. + local t = sdm_exclusiveGroups[f.exclusiveGroupKey] + for _,button in pairs(t.buttons) do + if t.isEnabled[button] then + button:Enable() + end + end + t.isEnabled=nil + sdm_listLocked=false --this should only apply to the "centerwindows" group, but right now that's all there is. +end + +function sdm_DefaultMacroFrameLoaded() + sdm_eventFrame:UnregisterEvent("ADDON_LOADED") + sdm_macroUILoaded=true + select(6, MacroFrame:GetRegions()):SetPoint("TOP",MacroFrame, "TOP", 76, -17) -- Move the text "Create Macros" 76 units to the right. + + local f + + --Create the button that links from the default macro frame to the SDM frame + f = CreateFrame("Button", "$parent_linkToSDM", MacroFrame, "UIPanelButtonTemplate") + f:SetWidth(150) + f:SetHeight(19) + f:SetPoint("TOPLEFT", 68, -14) + f:SetText("Super Duper Macro") + f:SetScript("OnClick", function() + HideUIPanel(MacroFrame) + sdm_mainFrame:Show() + end) + + --Create the button that turns a regular macro into a Super Duper macro + f = CreateFrame("Button", "$parent_convertToSuper", MacroFrame, "UIPanelButtonTemplate") + f:SetPoint("TOPLEFT", MacroDeleteButton, "TOPRIGHT") + f:SetPoint("BOTTOMRIGHT", MacroNewButton, "BOTTOMLEFT") + f:SetText("Upgrade! ") + local t = f:CreateTexture() + margin = 0.25 * f:GetHeight() + t:SetPoint("TOPRIGHT", f, "TOPRIGHT", -margin, -margin) + t:SetPoint("BOTTOM", f, "BOTTOM", 0, margin) + t:SetWidth(t:GetHeight()) + t:SetTexture("Interface\\MacroFrame\\MacroFrame-Icon") + local t2 = f:CreateTexture(nil, "OVERLAY") + t2:SetTexture(t:GetTexture()) + t2:SetAllPoints(t) + local t3 = f:CreateTexture(nil, "HIGHLIGHT") + t3:SetTexture(t:GetTexture()) + t3:SetAllPoints(t) + f:SetScript("OnClick", function() + if MacroFrame.selectedMacro then + sdm_UpgradeMacro(MacroFrame.selectedMacro) + end + end) + + f = CreateFrame("CheckButton", "$parent_buttonTextCheckBox", MacroPopupFrame, "UICheckButtonTemplate") + f:SetWidth(20) + f:SetHeight(20) + f:SetPoint("TOPLEFT", 25, -18) + f:SetScript("OnClick", function() + sdm_buttonTextCheckBoxClicked(MacroPopupFrame_buttonTextCheckBox:GetChecked()==1) + end) + f:Hide() + + f = CreateFrame("Button", "$parent_sdmCancelButton", MacroPopupFrame, "UIPanelButtonTemplate") + f:SetWidth(78) + f:SetHeight(22) + f:SetPoint("BOTTOMRIGHT", -11, 13) + f:SetText(CANCEL) + f:SetScript("OnClick", function() + sdm_changeIconFrame:Hide() + end) + + f = CreateFrame("Button", "$parent_sdmOkayButton", MacroPopupFrame, "UIPanelButtonTemplate") + f:SetWidth(78) + f:SetHeight(22) + f:SetPoint("RIGHT", MacroPopupCancelButton, "LEFT", -2, 0) + f:SetText(OKAY) + f:SetScript("OnClick", sdm_ChangeIconOkayed) + + hooksecurefunc("MacroFrame_Update", function() --This function prevents the user from messing with macros created by SDM. + local selectedIsSDM = nil + local globalTab = (MacroFrame.macroBase==0) --Is this the global tab or the character-specific tab? + for i,v in pairs(sdm_macros) do + if v.type=="b" and sdm_UsedByThisChar(v) and ((globalTab and (not v.character)) or ((not globalTab) and v.character and v.character.name==sdm_thisChar.name and v.character.realm==sdm_thisChar.realm)) then + local index = sdm_GetMacroIndex(v.ID) + local prefix = "MacroButton"..index-MacroFrame.macroBase + if index == MacroFrame.selectedMacro then --The currently selected macro is a SDM macro. Deselect it for now, then later select another one. + selectedIsSDM = index-MacroFrame.macroBase + _G[prefix]:SetChecked(nil) + MacroFrame.selectedMacro = nil + MacroFrame_HideDetails() + end + _G[prefix]:Disable() + _G[prefix.."Icon"]:SetTexture("Interface\\MacroFrame\\MacroFrame-Icon") + _G[prefix.."Name"]:SetText("SDM") + end + end + if selectedIsSDM then + local index=selectedIsSDM+1 + while index<=MacroFrame.macroMax do --if index exceeds this value, we know should stop because we've exceeded the number of slots on this pane. + local buttonToCheck = _G["MacroButton"..index] + if buttonToCheck:IsEnabled()==1 then + buttonToCheck:Click() + break + end + index=index+1 + end + end + end) +end + +sdm_containerInstructionsString = [[ +Left-click on a folder to open or close it. + + +To place an item into a folder, right-click on the item and then left-click on or in the folder. + + +To change the name of a folder, click the "Change Name/Icon" button (folders do not have icons). + + +Deleting a folder will move all of its contents into its parent folder. + + +To bring up these instructions and folder options, alt-click on a folder in the list. +]] + +sdm_iconSpacing=5/36 +sdm_listLocked=false --if this is true, clicking on a macro in the SDM list will do nothing. +if (IsAddOnLoaded("Blizzard_MacroUI")) then + sdm_macroUILoaded=true --the default macro UI, which normally loads when you type /macro + sdm_DefaultMacroFrameLoaded() +else + sdm_macroUILoaded=false --the default macro UI, which normally loads when you type /macro +end +sdm_unusedListItems={} +sdm_listItems,sdm_unusedListItems[true],sdm_unusedListItems[false]={},{},{} +sdm_listItemPrefix = "sdm_mainFrame_macrosScroll_macroList_listItem" \ No newline at end of file diff --git a/SuperDuperMacro/SuperDuperMacro_Sharing.lua b/SuperDuperMacro/SuperDuperMacro_Sharing.lua new file mode 100644 index 0000000..9e966ea --- /dev/null +++ b/SuperDuperMacro/SuperDuperMacro_Sharing.lua @@ -0,0 +1,271 @@ +function sdm_SendMacro(mTab, chan, tar) + if sdm_sending then + print(sdm_printPrefix.."You are already sending something.") + return + end + local perCharacter=nil + --make the string that will be split up and sent. It consists of a bunch of values separated by commas. They are, in order: the version the sender is running, the minimum version the receiver must have, the type of macro, the index of the icon, the perCharacter status ("
" or "nil"), the length of the name, the length of the text, the name, and the text. There is no comma between the name and the text. + local textToSend = sdm_version..","..sdm_minVersion..","..mTab.type..","..tostring(mTab.icon)..","..tostring(mTab.character)..","..mTab.name:len()..","..mTab.text:len()..","..mTab.name..mTab.text + local pref = "SDM send1" -- if the prefix ends in "send1", it's the first line. If it ends in "send2", it's any line after the first. + local lineLen = 254 - pref:len() + local linesToSend={} + local pos = 1 + while pos <= textToSend:len() do + table.insert(linesToSend, textToSend:sub(pos, pos+lineLen-1)) + pos = pos+lineLen + end + sdm_sending={ + i=1, + lines = linesToSend, + numLines = getn(linesToSend), + channel = chan, + target = tar, + prefix = pref + } + sdm_sendReceiveFrame_sendBar_statusBar:SetMinMaxValues(0, sdm_sending.numLines) + sdm_sendReceiveFrame_sendBar_statusBar:SetValue(0) + sdm_sendReceiveFrame_sendBar_statusBar_text:SetText("|cffffccffSending to "..(sdm_sending.target or sdm_sending.channel).."|r") + sdm_sendReceiveFrame_cancelSendButton:Enable() + sdm_sendReceiveFrame_sendButton:Disable() + sdm_sendReceiveFrame_sendPartyRadio:Disable() + sdm_sendReceiveFrame_sendRaidRadio:Disable() + sdm_sendReceiveFrame_sendBattlegroundRadio:Disable() + sdm_sendReceiveFrame_sendGuildRadio:Disable() + sdm_sendReceiveFrame_sendTargetRadio:Disable() + sdm_sendReceiveFrame_sendArbitraryRadio:Disable() + sdm_sendReceiveFrame_sendInput:EnableMouse(nil) + sdm_updateFrame:Show() +end + +function sdm_OnUpdate(self, elapsed) --used for sending macros + self.TimeSinceLastUpdate = self.TimeSinceLastUpdate + elapsed + if self.TimeSinceLastUpdate > sdm_updateInterval then + if sdm_sending.i == 2 then + sdm_sending.prefix="SDM send2" + end + SendAddonMessage(sdm_sending.prefix, sdm_sending.lines[sdm_sending.i], sdm_sending.channel, sdm_sending.target) + sdm_sendReceiveFrame_sendBar_statusBar:SetValue(sdm_sending.i) + sdm_sending.i = sdm_sending.i+1 + if sdm_sending.i>sdm_sending.numLines then + sdm_EndSending("|cff44ff00Sent to "..(sdm_sending.target or sdm_sending.channel).."|r") + end + self.TimeSinceLastUpdate = 0 + end +end + +function sdm_EndSending(text) + sdm_updateFrame:Hide() + sdm_sendReceiveFrame_sendBar_statusBar_text:SetText(text) + sdm_sending=nil + sdm_sendReceiveFrame_cancelSendButton:Disable() + if sdm_currentEdit then + sdm_sendReceiveFrame_sendButton:Enable() + end + sdm_sendReceiveFrame_sendPartyRadio:Enable() + sdm_sendReceiveFrame_sendRaidRadio:Enable() + sdm_sendReceiveFrame_sendBattlegroundRadio:Enable() + sdm_sendReceiveFrame_sendGuildRadio:Enable() + sdm_sendReceiveFrame_sendTargetRadio:Enable() + sdm_sendReceiveFrame_sendArbitraryRadio:Enable() + sdm_sendReceiveFrame_sendInput:EnableMouse(1) +end + +function sdm_WaitForMacro(name) + if sdm_receiving then + print(sdm_printPrefix.."You are already receiving or waiting.") + return + end + sdm_receiving = {playerName=name, first=true} + sdm_sendReceiveFrame_receiveBar_statusBar:SetValue(0) + sdm_sendReceiveFrame_receiveBar_statusBar_text:SetText("|cffffccffWaiting for "..sdm_receiving.playerName.."|r") + sdm_sendReceiveFrame_cancelReceiveButton:Enable() + sdm_sendReceiveFrame_receiveButton:Disable() + sdm_sendReceiveFrame_receiveTargetRadio:Disable() + sdm_sendReceiveFrame_receiveArbitraryRadio:Disable() + sdm_sendReceiveFrame_receiveInput:EnableMouse(nil) + sdm_SelectItem(nil) + sdm_newFrame:Show() + sdm_newFrame_input:ClearFocus() + sdm_newFrame_input:SetText("Receiving macro...") + sdm_newFrame_input:EnableMouse(nil) + sdm_newFrame_buttonRadio:Disable() + sdm_newFrame_floatingRadio:Disable() + sdm_newFrame_scriptRadio:Disable() + sdm_newFrame_globalRadio:Disable() + sdm_newFrame_charspecRadio:Disable() + sdm_newFrame_createButton:Disable() +end + +function sdm_InterpretAddonMessage(...) + local arg1, arg2, arg3, arg4 = ... + if arg4~=sdm_thisChar.name and arg1:sub(1,17)=="SDM" then + local txt=arg1:sub(18) + if sdm_receiving and arg4:upper()==sdm_receiving.playerName:upper() and (not sdm_receiving.text) then + if txt==" send1" then + sdm_ReceiveLine(arg2, true) + elseif txt==" send2" then + sdm_ReceiveLine(arg2, false) + elseif txt==" sendFailed" then + print(sdm_printPrefix..""..arg4.." failed to send the macro. Reason: "..arg2) + sdm_EndReceiving("|cffff0000Failed|r") + end + elseif txt==" receiving" then + print(sdm_printPrefix.."Sending macro to "..arg4.."...") + elseif txt==" recDone" then + print(sdm_printPrefix..""..arg4.." has accepted your macro.") + elseif txt==" recFailed" then --"SDM recFailed","reason,version" + local version, reason = sdm_SplitString(arg2, ",", 1) + print(sdm_printPrefix..""..arg4.." did not receive your macro. Reason: "..reason) + end + end +end + +function sdm_ReceiveLine(line, send1) + if sdm_receiving.first and send1 then --this is the first line + sdm_receiving.nameAndText, sdm_receiving.textLen, sdm_receiving.playerNameLen, sdm_receiving.perCharacter, sdm_receiving.icon, sdm_receiving.type, sdm_receiving.minVersion, sdm_receiving.sendersVersion = sdm_SplitString(line, ",", 7) + sdm_receiving.perCharacter = (sdm_receiving.perCharacter~="nil") + if sdm_receiving.icon=="nil" then + sdm_receiving.icon = nil + else + sdm_receiving.icon = 0 + sdm_receiving.icon + end + sdm_receiving.textLen = 0 + sdm_receiving.textLen + sdm_receiving.playerNameLen = 0 + sdm_receiving.playerNameLen + sdm_receiving.first = false + sdm_sendReceiveFrame_receiveBar_statusBar:SetMinMaxValues(0, sdm_receiving.playerNameLen + sdm_receiving.textLen) + sdm_sendReceiveFrame_receiveBar_statusBar_text:SetText("|cffffccffReceiving|r") + if sdm_CompareVersions(sdm_receiving.sendersVersion, sdm_minVersion)==2 or sdm_CompareVersions(sdm_version, sdm_receiving.minVersion)==2 then + print(sdm_printPrefix.."You failed to recieve the macro due to a version incompatibility.") + SendAddonMessage("SDM recFailed", "Incompatible Versions,"..sdm_version, "WHISPER", sdm_receiving.playerName) + sdm_EndReceiving("|cffff0000Failed|r") + return + else + SendAddonMessage("SDM receiving", sdm_version, "WHISPER", sdm_receiving.playerName) + end + elseif (not sdm_receiving.first) and (not send1) then + sdm_receiving.nameAndText = sdm_receiving.nameAndText..line + else + return + end + local currLen = sdm_receiving.nameAndText:len() + sdm_sendReceiveFrame_receiveBar_statusBar:SetValue(currLen) + if currLen == (sdm_receiving.playerNameLen + sdm_receiving.textLen) then + sdm_sendReceiveFrame_receiveBar_statusBar_text:SetText("|cffff9900Click \"Create\" to save|r") + UIFrameFlash(sdm_newFrame_createButton_flash, 0.5, 0.5, 1e6, false) + sdm_newFrame_input:EnableMouse(1) + sdm_newFrame_buttonRadio:Enable() + sdm_newFrame_floatingRadio:Enable() + sdm_newFrame_scriptRadio:Enable() + sdm_newFrame_globalRadio:Enable() + sdm_newFrame_charspecRadio:Enable() + sdm_newFrame_createButton:Enable() + if sdm_receiving.type=="b" then + sdm_newFrame_buttonRadio:Click() + elseif sdm_receiving.type=="f" then + sdm_newFrame_floatingRadio:Click() + elseif sdm_receiving.type=="s" then + sdm_newFrame_scriptRadio:Click() + end + if sdm_receiving.perCharacter then + sdm_newFrame_charspecRadio:Click() + else + sdm_newFrame_globalRadio:Click() + end + sdm_receiving.name=sdm_receiving.nameAndText:sub(1,sdm_receiving.playerNameLen) + sdm_newFrame_input:SetText(sdm_receiving.name) + sdm_receiving.text=sdm_receiving.nameAndText:sub(sdm_receiving.playerNameLen+1,sdm_receiving.playerNameLen+sdm_receiving.textLen) + end +end + +function sdm_EndReceiving(text) + sdm_sendReceiveFrame_receiveBar_statusBar_text:SetText(text) + sdm_sendReceiveFrame_cancelReceiveButton:Disable() + sdm_sendReceiveFrame_receiveButton:Enable() + sdm_mainFrame_newButton:Enable() + sdm_sendReceiveFrame_receiveTargetRadio:Enable() + sdm_sendReceiveFrame_receiveArbitraryRadio:Enable() + sdm_sendReceiveFrame_receiveInput:EnableMouse(1) + sdm_newFrame_input:SetText("") + sdm_newFrame_input:EnableMouse(1) + sdm_newFrame_buttonRadio:Enable() + sdm_newFrame_floatingRadio:Enable() + sdm_newFrame_scriptRadio:Enable() + sdm_newFrame_globalRadio:Enable() + sdm_newFrame_charspecRadio:Enable() + sdm_newFrame_createButton:Enable() + sdm_receiving=nil +end + +function sdm_CancelSend() + SendAddonMessage("SDM sendFailed", "Cancelled", sdm_sending.channel, sdm_sending.target) + sdm_EndSending("|cffff0000Cancelled|r") +end + +function sdm_CancelReceive() + SendAddonMessage("SDM recFailed", "Cancelled,"..sdm_version, "WHISPER", sdm_receiving.playerName) + sdm_EndReceiving("|cffff0000Cancelled|r") + sdm_newFrame:Hide() +end + +function sdm_SplitString(s, pattern, limit, ...) --iterates through "s", splitting it between occurrences of "pattern", and returning the split portions IN BACKWARDS ORDER. Splits a maximum of times (optional) + if limit==0 then + return s, ... + end + local index = s:find(pattern) + if (not index) then + return s, ... + end + return sdm_SplitString(s:sub(index+pattern:len()), pattern, limit-1, s:sub(1, index-1), ...) +end + +function sdm_SendButtonClicked() + local channel + local target + if sdm_sendReceiveFrame_sendPartyRadio:GetChecked() then + channel="PARTY" + elseif sdm_sendReceiveFrame_sendRaidRadio:GetChecked() then + channel="RAID" + elseif sdm_sendReceiveFrame_sendBattlegroundRadio:GetChecked() then + channel="BATTLEGROUND" + elseif sdm_sendReceiveFrame_sendGuildRadio:GetChecked() then + channel="GUILD" + elseif sdm_sendReceiveFrame_sendTargetRadio:GetChecked() then + channel="WHISPER" + if UnitIsPlayer("target") then + target, realm = UnitName("target") + if realm then + target = target.."-"..realm + end + end + elseif sdm_sendReceiveFrame_sendArbitraryRadio:GetChecked() then + channel="WHISPER" + target=sdm_sendReceiveFrame_sendInput:GetText() + end + if channel=="WHISPER" and ((not target) or target=="" or target==sdm_thisChar.name) then + return + end + sdm_sendReceiveFrame_sendInput:ClearFocus() + sdm_SendMacro(sdm_macros[sdm_currentEdit], channel, target) +end + +function sdm_ReceiveButtonClicked() + local sender + if sdm_sendReceiveFrame_receiveTargetRadio:GetChecked() then + if UnitIsPlayer("target") then + sender, realm = UnitName("target") + if realm then + sender = sender.."-"..realm + end + end + elseif sdm_sendReceiveFrame_receiveArbitraryRadio:GetChecked() then + sender=sdm_sendReceiveFrame_receiveInput:GetText() + end + if ((not sender) or sender=="" or sender==sdm_thisChar.name) then return end + sdm_sendReceiveFrame_receiveInput:ClearFocus() + sdm_SaveConfirmationBox("sdm_WaitForMacro("..sdm_Stringer(sender)..")") +end + +sdm_sending=nil --info about the macro you're trying to send +sdm_receiving=nil --info about the macro you're receiving (or waiting to receive) +sdm_updateInterval=0.25 --can be as low as 0.01 and still work, but it might disconnect you if there are other addons sending out messages too. 0.25 is slower but safer. +sdm_minVersion="1.6" --the oldest version that is compatible with this one for exchanging macros \ No newline at end of file diff --git a/SuperDuperMacro/sdm Readme.txt b/SuperDuperMacro/sdm Readme.txt index 4575df7..603f7d6 100644 --- a/SuperDuperMacro/sdm Readme.txt +++ b/SuperDuperMacro/sdm Readme.txt @@ -1,5 +1,5 @@ Super Duper Macro -version 2.0 +version 2.1 by hypehuman Check for updates at http://www.wowinterface.com/downloads/info10496 @@ -9,7 +9,7 @@ Open the interface by typing /sdm This addon allows you to create macros beyond the 255-character limit, and even beyond the 1023-character macrotext limit. However, no individual line in a macro may be more than 1023 characters long (you will get a warning). The number of lines is unlimited. Super Duper Macro also allows you to share macros with your friends in-game. This mod allows you to make two types of macros: -¥ Button macros are just like regular macros, but they can be as long as you want. You cannot make an unlimited number of them; they share a limit with your regular macros (36 global and 36 character-specific for each character). +¥ Button macros are just like regular macros, but they can be as long as you want. You cannot make an unlimited number of them; they share a limit with your regular macros (36 global and 18 character-specific for each character). ¥ Floating macros do not have buttons, and are accessed by /click. You can make as many of these as you want. ¥ You can also make lua scripts of unlimited length that you can call using "/sdm run " or via sdm_RunScript("name") @@ -19,12 +19,19 @@ Special thanks to: ¥ SuperMacro, which inspired the idea for this addon. ¥ Behaviors, from which I shamelessly copied many UI elements. ¥ÊAll the regulars on the UI & Macro forums, who have been guiding me through this process. -¥Ê +¥ survivorx and ambro, who patched this addon while I was AWOL Change Log +2.1 (10/19/11) +¥ÊAdded an "Upgrade" button to the standard macro frame, allowing you to convert a standard macro into a Super Duper macro +¥ÊRemoved an overbearing version-checking system + +2.0 (10/16/11) +¥ Incorporated compatibility updates by survivorx and ambro + 1.8.3 (2/26/09) ¥ÊChanging the name of a macro will now properly update the title text above the edit box. ¥ÊImproved the "/sdm test" function. Please re-test it and submit your results! -- 1.7.9.5