--[[--------------------------------------------------------------------------------- Clique by Cladhaire <cladhaire@gmail.com> ----------------------------------------------------------------------------------]] Clique = {Locals = {}} DongleStub("Dongle"):New("Clique", Clique) local L = Clique.Locals local oocClicks = {} function Clique:Enable() -- Grab the localisation header L = Clique.Locals self.ooc = oocClicks self.defaults = { profile = { clicksets = { [L.CLICKSET_DEFAULT] = {}, [L.CLICKSET_HARMFUL] = {}, [L.CLICKSET_HELPFUL] = {}, [L.CLICKSET_OOC] = {}, }, blacklist = { }, } } self.db = self:InitializeDB("CliqueDB", self.defaults) self.profile = self.db.profile self.clicksets = self.profile.clicksets self.editSet = self.clicksets[L.CLICKSET_DEFAULT] ClickCastFrames = ClickCastFrames or {} self.ccframes = ClickCastFrames local newindex = function(t,k,v) if v == nil then Clique:UnregisterFrame(k) rawset(self.ccframes, k, nil) else Clique:RegisterFrame(k) rawset(self.ccframes, k, v) end end ClickCastFrames = setmetatable({}, {__newindex=newindex}) -- Register all frames that snuck in before we did =) Clique:OptionsOnLoad() Clique:EnableFrames() for frame in pairs(self.ccframes) do self:RegisterFrame(frame) end -- Define a state header for forms self.stateheader = CreateFrame("Frame", "CliqueStateHeader", UIParent, "SecureStateDriverTemplate") self.stateheader:SetAttribute("statemap-stance-0", "s0") self.stateheader:SetAttribute("statemap-stance-1", "s1") self.stateheader:SetAttribute("statemap-stance-2", "s2") self.stateheader:SetAttribute("statemap-stance-3", "s3") self.stateheader:SetAttribute("statemap-stance-4", "s4") self.stateheader:SetAttribute("statemap-stance-5", "s5") --PlayerFrame:SetAttribute("shift-statebutton1", "s0:s0;s1:s1;s2:s2;s3:s3;s4:s4;s5:s5") --[[ PlayerFrame:SetAttribute("shift-unit-s1", "player") PlayerFrame:SetAttribute("shift-type-s1", "spell") PlayerFrame:SetAttribute("shift-spell-s1", "Enrage") PlayerFrame:SetAttribute("shift-unit1", "player") PlayerFrame:SetAttribute("shift-type1", "spell") PlayerFrame:SetAttribute("shift-spell1", "Rejuvenation") PlayerFrame:SetAttribute("alt-type1", "spell") PlayerFrame:SetAttribute("alt-spell1", "Attack") --]] -- Register for LEARNED_SPELL_IN_TAB self:RegisterEvent("LEARNED_SPELL_IN_TAB") self:RegisterEvent("PLAYER_ENTERING_WORLD") self:LEARNED_SPELL_IN_TAB() -- Register for dongle events self:RegisterEvent("DONGLE_PROFILE_CHANGED") self:RegisterEvent("DONGLE_PROFILE_DELETED") -- Run the OOC script if we need to self:UpdateClicks() self:PLAYER_ENTERING_WORLD() -- Securehook CreateFrame to catch any new raid frames local raidFunc = function(type, name, parent, template) if template == "RaidPulloutButtonTemplate" then ClickCastFrames[getglobal(name.."ClearButton")] = true end end hooksecurefunc("CreateFrame", raidFunc) end function Clique:LEARNED_SPELL_IN_TAB() local forms = { [L.DIRE_BEAR_FORM] = L.CLICKSET_BEARFORM, [L.BEAR_FORM] = L.CLICKSET_BEARFORM, [L.AQUATIC_FORM] = L.CLICKSET_AQUATICFORM, [L.CAT_FORM] = L.CLICKSET_CATFORM, [L.TRAVEL_FORM] = L.CLICKSET_TRAVELFORM, [L.MOONKIN_FORM] = L.CLICKSET_MOONKINFORM, [L.TREEOFLIFE] = L.CLICKSET_TREEOFLIFE, [L.STEALTH] = L.CLICKSET_STEALTHED, [L.BATTLESTANCE] = L.CLICKSET_BATTLESTANCE, [L.DEFENSIVESTANCE] = L.CLICKSET_DEFENSIVESTANCE, [L.BERSERKERSTANCE] = L.CLICKSET_BERSERKERSTANCE, [L.SHADOWFORM] = L.CLICKSET_SHADOWFORM, } self.forms = forms local profile = self.defaults.profile local offset,num = select(3, GetSpellTabInfo(GetNumSpellTabs())) local num = num + offset for i=1,num do local name = GetSpellName(i, BOOKTYPE_SPELL) if forms[name] then --profile[name] = profile[name] or {} --self.profile[name] = self.profile[name] or {} end end end function Clique:PLAYER_ENTERING_WORLD() self:Print("PLAYER_ENTERING_WORLD") if InCombatLockdown() then self:CombatLockdown() else self:CombatUnlock() end end function Clique:EnableFrames() local tbl = { PlayerFrame, PetFrame, PartyMemberFrame1, PartyMemberFrame2, PartyMemberFrame3, PartyMemberFrame4, PartyMemberFrame1PetFrame, PartyMemberFrame2PetFrame, PartyMemberFrame3PetFrame, PartyMemberFrame4PetFrame, TargetFrame, TargetofTargetFrame, } for i,frame in pairs(tbl) do ClickCastFrames[frame] = true end end function Clique:SpellBookButtonPressed() local id = SpellBook_GetSpellID(this:GetParent():GetID()); local texture = GetSpellTexture(id, SpellBookFrame.bookType) local name, rank = GetSpellName(id, SpellBookFrame.bookType) if rank == L.RACIAL_PASSIVE or rank == L.PASSIVE then StaticPopup_Show("CLIQUE_PASSIVE_SKILL") return else rank = select(3, string.find(rank, L.RANK_PATTERN)) if rank then rank = tonumber(rank) end end local type = "spell" local button if self.editSet == self.clicksets[L.CLICKSET_HARMFUL] then button = string.format("%s%d", "harmbutton", self:GetButtonNumber()) elseif self.editSet == self.clicksets[L.CLICKSET_HELPFUL] then button = string.format("%s%d", "helpbutton", self:GetButtonNumber()) else button = self:GetButtonNumber() end -- Build the structure local t = { ["button"] = button, ["modifier"] = self:GetModifierText(), ["texture"] = GetSpellTexture(id, SpellBookFrame.bookType), ["type"] = type, ["arg1"] = name, ["arg2"] = rank, } local key = t.modifier .. t.button if self:CheckBinding(key) then StaticPopup_Show("CLIQUE_BINDING_PROBLEM") return end self.editSet[key] = t self:UpdateClicks() self:ListScrollUpdate() end function Clique:CombatLockdown(frame) -- Remove all OOC clicks if not frame then self:Print("Going into combat lockdown", event) end self:RemoveClickSet(oocClicks, frame) self:ApplyClickSet(L.CLICKSET_DEFAULT, frame) self:ApplyClickSet(L.CLICKSET_HARMFUL, frame) self:ApplyClickSet(L.CLICKSET_HELPFUL, frame) end function Clique:CombatUnlock(frame) if not frame then self:Print("Coming out of lockdown, applying ooc stuff", event) end self:ApplyClickSet(L.CLICKSET_DEFAULT, frame) self:RemoveClickSet(L.CLICKSET_HARMFUL, frame) self:RemoveClickSet(L.CLICKSET_HELPFUL, frame) self:ApplyClickSet(oocClicks, frame) end function Clique:UpdateClicks() self:Print("Updating clicks") local ooc = self.clicksets[L.CLICKSET_OOC] local harm = self.clicksets[L.CLICKSET_HARMFUL] local help = self.clicksets[L.CLICKSET_HELPFUL] oocClicks = {} for modifier,entry in pairs(harm) do local button = string.gsub(entry.button, "harmbutton", "") button = string.gsub(button, "helpbutton", "") button = tonumber(button) local mask = false for k,v in pairs(ooc) do if button == v.button then mask = true end end if not mask then table.insert(oocClicks, entry) self:Print("Adding", entry.type, entry.arg1, " to ooc clicks") else self:Print("* Masking", entry.type, entry.arg1, " to ooc clicks") end end for modifier,entry in pairs(help) do local button = string.gsub(entry.button, "harmbutton", "") button = string.gsub(button, "helpbutton", "") button = tonumber(button) local mask = false for k,v in pairs(ooc) do if button == v.button then mask = true end end if not mask then table.insert(oocClicks, entry) self:Print("Adding", entry.type, entry.arg1, " to ooc clicks") else self:Print("* Masking", entry.type, entry.arg1, " to ooc clicks") end end for modifier,entry in pairs(ooc) do table.insert(oocClicks, entry) self:Print("Adding", entry.type, entry.arg1, " to ooc clicks") end self:CombatUnlock() end function Clique:RegisterFrame(frame) local name = frame:GetName() -- Check to see if we can register this frame at this time if InCombatLockdown() and not frame:CanChangeProtectedState() then self:PrintF("Cannot register frame %s. The addon which attempted to register this frame is doing so while in-combat.", tostring(name)) end if self.profile.blacklist[name] then rawset(self.ccframes, frame, false) return end if not ClickCastFrames[frame] then rawset(self.ccframes, frame, true) if CliqueTextListFrame then Clique:TextListScrollUpdate() end end frame:RegisterForClicks("AnyUp") if InCombatLockdown() then self:CombatLockdown(frame) else self:CombatUnlock(frame) end end function Clique:ApplyClickSet(name, frame) local set = self.clicksets[name] or name if frame then for modifier,entry in pairs(set) do self:SetAttribute(entry, frame) end else for modifier,entry in pairs(set) do self:SetAction(entry) end end end function Clique:RemoveClickSet(name, frame) local set = self.clicksets[name] or name if frame then for modifier,entry in pairs(set) do self:DeleteAttribute(entry, frame) end else for modifier,entry in pairs(set) do self:DeleteAction(entry) end end end function Clique:UnregisterFrame(frame) for name,set in pairs(self.clicksets) do for modifier,entry in pairs(set) do self:DeleteAttribute(entry, frame) end end end function Clique:DONGLE_PROFILE_CHANGED(event, db, parent, svname, profileKey) if db == self.db then self:PrintF(L.PROFILE_CHANGED, profileKey) for name,set in pairs(self.clicksets) do for modifier,entry in pairs(set) do self:DeleteAction(entry) end end self.profile = self.db.profile self.clicksets = self.profile.clicksets self.editSet = self.clicksets[L.CLICKSET_DEFAULT] self.profileKey = profileKey -- Refresh the profile editor if it exists self.textlistSelected = nil self:TextListScrollUpdate() self:ListScrollUpdate() for frame in pairs(self.ccframes) do self:RegisterFrame(frame) end end end function Clique:DONGLE_PROFILE_DELETED(event, db, parent, svname, profileKey) if db == self.db then self:PrintF(L.PROFILE_DELETED, profileKey) self.textlistSelected = nil self:TextListScrollUpdate() self:ListScrollUpdate() end end function Clique:SetAttribute(entry, frame) local name = frame:GetName() if self.profile.blacklist and self.profile.blacklist[name] then return end -- Set up any special attributes local type,button,value if not tonumber(entry.button) then type,button = select(3, string.find(entry.button, "(%a+)button(%d+)")) frame:SetAttribute(entry.modifier..entry.button, type..button) button = string.format("-%s%s", type, button) end button = button or entry.button if entry.type == "actionbar" then frame:SetAttribute(entry.modifier.."type"..button, entry.type) frame:SetAttribute(entry.modifier.."action"..button, entry.arg1) elseif entry.type == "action" then frame:SetAttribute(entry.modifier.."type"..button, entry.type) frame:SetAttribute(entry.modifier.."action"..button, entry.arg1) frame:SetAttribute(entry.modifier.."unit"..button, entry.arg2) elseif entry.type == "pet" then frame:SetAttribute(entry.modifier.."type"..button, entry.type) frame:SetAttribute(entry.modifier.."action"..button, entry.arg1) frame:SetAttribute(entry.modifier.."unit"..button, entry.arg2) elseif entry.type == "spell" then local rank = tonumber(entry.arg2) local cast = string.format(rank and L.CAST_FORMAT or "%s", entry.arg1, rank) frame:SetAttribute(entry.modifier.."type"..button, entry.type) frame:SetAttribute(entry.modifier.."spell"..button, cast) frame:SetAttribute(entry.modifier.."bag"..button, entry.arg2) frame:SetAttribute(entry.modifier.."slot"..button, entry.arg3) frame:SetAttribute(entry.modifier.."item"..button, entry.arg4) frame:SetAttribute(entry.modifier.."unit"..button, entry.arg5) elseif entry.type == "item" then frame:SetAttribute(entry.modifier.."type"..button, entry.type) frame:SetAttribute(entry.modifier.."bag"..button, entry.arg1) frame:SetAttribute(entry.modifier.."slot"..button, entry.arg2) frame:SetAttribute(entry.modifier.."item"..button, entry.arg3) frame:SetAttribute(entry.modifier.."unit"..button, entry.arg4) elseif entry.type == "macro" then frame:SetAttribute(entry.modifier.."type"..button, entry.type) frame:SetAttribute(entry.modifier.."macro"..button, entry.arg1) frame:SetAttribute(entry.modifier.."macrotext"..button, entry.arg2) elseif entry.type == "stop" then frame:SetAttribute(entry.modifier.."type"..button, entry.type) elseif entry.type == "target" then frame:SetAttribute(entry.modifier.."type"..button, entry.type) frame:SetAttribute(entry.modifier.."unit"..button, entry.arg1) elseif entry.type == "focus" then frame:SetAttribute(entry.modifier.."type"..button, entry.type) frame:SetAttribute(entry.modifier.."unit"..button, entry.arg1) elseif entry.type == "assist" then frame:SetAttribute(entry.modifier.."type"..button, entry.type) frame:SetAttribute(entry.modifier.."unit"..button, entry.arg1) elseif entry.type == "click" then frame:SetAttribute(entry.modifier.."type"..button, entry.type) frame:SetAttribute(entry.modifier.."clickbutton"..button, getglobal(entry.arg1)) elseif entry.type == "menu" then frame:SetAttribute(entry.modifier.."type"..button, entry.type) end end function Clique:DeleteAttribute(entry, frame) local name = frame:GetName() if self.profile.blacklist and self.profile.blacklist[name] then return end local type,button,value if not tonumber(entry.button) then type,button = select(3, string.find(entry.button, "(%a+)button(%d+)")) for frame in pairs(self.ccframes) do frame:SetAttribute(entry.modifier..entry.button, nil) end button = string.format("-%s%s", type, button) end button = button or entry.button entry.delete = true frame:SetAttribute(entry.modifier.."type"..button, nil) frame:SetAttribute(entry.modifier..entry.type..button, nil) end function Clique:SetAction(entry) for frame,enabled in pairs(self.ccframes) do if enabled then self:SetAttribute(entry, frame) end end end function Clique:DeleteAction(entry) for frame in pairs(self.ccframes) do self:DeleteAttribute(entry, frame) end end local mods = {"Shift", "Ctrl", "Alt"} local buttonsraw = {1,2,3,4,5} local buttonmods = {"-help", "-harm"} local buttons = {} for idx,button in pairs(buttonsraw) do for k,v in pairs(buttonmods) do table.insert(buttons, v..button) end end for k,v in pairs(buttonsraw) do table.insert(buttons, v) end function dump(frame) for k,v in pairs(buttons) do local attr = frame:GetAttribute("type"..v) if attr then local val = frame:GetAttribute(attr..v) Clique:Print("type"..v, attr, val) end end for k,v in pairs(buttons) do for i,mod in ipairs(mods) do local attr = frame:GetAttribute(mod.."-type"..v) if attr then local val = frame:GetAttribute(mod.."-"..attr..v) Clique:Print(mod.."-type"..v,attr, val) end end end end