diff --git a/BagSync.lua b/BagSync.lua index fd80b90..96be191 100644 --- a/BagSync.lua +++ b/BagSync.lua @@ -9,16 +9,17 @@ --]] -local ADDON_NAME, addon = ... +local BSYC = select(2, ...) --grab the addon namespace +BSYC = LibStub("AceAddon-3.0"):NewAddon(BSYC, "BagSync", "AceEvent-3.0", "AceConsole-3.0") local L = LibStub("AceLocale-3.0"):GetLocale("BagSync", true) + local lastItem local lastDisplayed = {} local currentPlayer local currentRealm local playerClass local playerFaction -local crossRealmNames = {} local NUM_EQUIPMENT_SLOTS = 19 local BS_DB local BS_GD @@ -41,10 +42,12 @@ local select, pairs, next, type = select, pairs, next, type local error, assert = error, assert local debugf = tekDebug and tekDebug:GetFrame("BagSync") -local function Debug(...) + +function BSYC:Debug(...) if debugf then debugf:AddMessage(string.join(", ", tostringall(...))) end end + --sometimes I just want to debug some BagSync DB data someone gives me lol local debugging = false @@ -82,24 +85,6 @@ local dataobj = ldb:NewDataObject("BagSyncLDB", { end }) ------------------------------- --- MAIN OBJ -- ------------------------------- - -local BagSync = CreateFrame("Frame", "BagSync", UIParent) - -BagSync:SetScript("OnEvent", function(self, event, ...) - if self[event] then - self[event](self, event, ...) - end -end) - -function BagSync:Debug(...) - Debug(...) -end - -if IsLoggedIn() then BagSync:PLAYER_LOGIN() else BagSync:RegisterEvent("PLAYER_LOGIN") end - ---------------------- -- Local -- ---------------------- @@ -124,13 +109,44 @@ local function ToShortLink(link) return link:match("item:(%d+):") or nil end +local function IsInBG() + if (GetNumBattlefieldScores() > 0) then + return true + end + return false +end + +local function IsInArena() + local a,b = IsActiveBattlefieldArena() + if not a then + return false + end + return true +end + +--sort by key element rather then value +local function pairsByKeys (t, f) + local a = {} + for n in pairs(t) do table.insert(a, n) end + table.sort(a, f) + local i = 0 -- iterator variable + local iter = function () -- iterator function + i = i + 1 + if a[i] == nil then return nil + else return a[i], t[a[i]] + end + end + return iter +end + ---------------------- -- DB Functions -- ---------------------- -local function StartupDB() +function BSYC:StartupDB() BagSyncOpt = BagSyncOpt or {} + if BagSyncOpt.showTotal == nil then BagSyncOpt.showTotal = true end if BagSyncOpt.showGuildNames == nil then BagSyncOpt.showGuildNames = false end if BagSyncOpt.enableGuild == nil then BagSyncOpt.enableGuild = true end @@ -158,7 +174,7 @@ local function StartupDB() if not BagSyncOpt.dbversion or not tonumber(BagSyncOpt.dbversion) or tonumber(BagSyncOpt.dbversion) < 7 then BagSyncDB = {} BagSyncGUILD_DB = {} - print("|cFFFF0000BagSync: You have been updated to latest database version! You will need to rescan all your characters again!|r") + self:Print(L["You have been updated to latest database version! You will need to rescan all your characters again!|r"]) end BagSyncDB = BagSyncDB or {} @@ -189,7 +205,7 @@ local function StartupDB() end -function BagSync:FixDB_Data(onlyChkGuild) +function BSYC:FixDB_Data(onlyChkGuild) --Removes obsolete character information --Removes obsolete guild information --Removes obsolete characters from tokens db @@ -307,11 +323,11 @@ function BagSync:FixDB_Data(onlyChkGuild) end end - DEFAULT_CHAT_FRAME:AddMessage("|cFF99CC33BagSync:|r |cFFFF9900"..L["A FixDB has been performed on BagSync! The database is now optimized!"].."|r") + self:Print("|cFFFF9900"..L["A FixDB has been performed on BagSync! The database is now optimized!"].."|r") end end -function BagSync:getFilteredDB() +function BSYC:getFilteredDB() local xIndex = {} @@ -325,7 +341,7 @@ function BagSync:getFilteredDB() end elseif BagSyncOpt.enableCrossRealmsItems then for k, v in pairs(BagSyncDB) do - if k == currentRealm or crossRealmNames[k] then + if k == currentRealm or self.crossRealmNames[k] then for q, r in pairs(v) do ----we do this incase there are multiple characters with same name xIndex[q.."^"..k] = r @@ -339,7 +355,7 @@ function BagSync:getFilteredDB() return xIndex end -function BagSync:getCharacterRealmInfo(charName, charRealm) +function BSYC:getCharacterRealmInfo(charName, charRealm) local yName, yRealm = strsplit("^", charName) local realmFullName = charRealm @@ -349,7 +365,7 @@ function BagSync:getCharacterRealmInfo(charName, charRealm) --add Cross-Realm and BNet identifiers to Characters not on same realm if BagSyncOpt.enableBNetAccountItems then if charRealm and charRealm ~= currentRealm then - if not crossRealmNames[charRealm] then + if not self.crossRealmNames[charRealm] then charName = yName.." "..rgbhex(BagSyncOpt.colors.bnet).."[BNet-"..realmFullName.."]|r" else charName = yName.." "..rgbhex(BagSyncOpt.colors.cross).."[XR-"..realmFullName.."]|r" @@ -371,7 +387,7 @@ function BagSync:getCharacterRealmInfo(charName, charRealm) return charName end -function BagSync:getGuildRealmInfo(guildName, guildRealm) +function BSYC:getGuildRealmInfo(guildName, guildRealm) local realmFullName = guildRealm @@ -380,7 +396,7 @@ function BagSync:getGuildRealmInfo(guildName, guildRealm) --add Cross-Realm and BNet identifiers to Guilds not on same realm if BagSyncOpt.enableBNetAccountItems then if guildRealm and guildRealm ~= currentRealm then - if not crossRealmNames[guildRealm] then + if not self.crossRealmNames[guildRealm] then guildName = guildName.." "..rgbhex(BagSyncOpt.colors.bnet).."[BNet-"..realmFullName.."]|r" else guildName = guildName.." "..rgbhex(BagSyncOpt.colors.cross).."[XR-"..realmFullName.."]|r" @@ -406,10 +422,10 @@ end -- Bag Functions -- ---------------------- -local function SaveBag(bagname, bagid) +function BSYC:SaveBag(bagname, bagid) if debugging then return end if not bagname or not bagid then return nil end - if not BS_DB then StartupDB() end + if not BS_DB then self:StartupDB() end BS_DB[bagname] = BS_DB[bagname] or {} --reset our tooltip data since we scanned new items (we want current data not old) @@ -435,13 +451,13 @@ local function SaveBag(bagname, bagid) end end -local function SaveEquipment() +function BSYC:SaveEquipment() if debugging then return end --reset our tooltip data since we scanned new items (we want current data not old) lastItem = nil lastDisplayed = {} - if not BS_DB then StartupDB() end + if not BS_DB then self:StartupDB() end BS_DB["equip"] = BS_DB["equip"] or {} local slotItems = {} @@ -461,20 +477,20 @@ local function SaveEquipment() BS_DB["equip"][0] = slotItems end -local function ScanEntireBank() +function BSYC:ScanEntireBank() --force scan of bank bag -1, since blizzard never sends updates for it - SaveBag("bank", BANK_CONTAINER) + self:SaveBag("bank", BANK_CONTAINER) for i = NUM_BAG_SLOTS + 1, NUM_BAG_SLOTS + NUM_BANKBAGSLOTS do - SaveBag("bank", i) + self:SaveBag("bank", i) end if IsReagentBankUnlocked() then - SaveBag("reagentbank", REAGENTBANK_CONTAINER) + self:SaveBag("reagentbank", REAGENTBANK_CONTAINER) end end -local function ScanVoidBank() +function BSYC:ScanVoidBank() if VoidStorageFrame and VoidStorageFrame:IsShown() then - if not BS_DB then StartupDB() end + if not BS_DB then self:StartupDB() end BS_DB["void"] = BS_DB["void"] or {} --reset our tooltip data since we scanned new items (we want current data not old) @@ -499,11 +515,11 @@ local function ScanVoidBank() end end -local function ScanGuildBank() +function BSYC:ScanGuildBank() --GetCurrentGuildBankTab() if not IsInGuild() then return end - if not BS_GD then StartupDB() end + if not BS_GD then self:StartupDB() end BS_GD[BS_DB.guild] = BS_GD[BS_DB.guild] or {} --reset our tooltip data since we scanned new items (we want current data not old) @@ -541,7 +557,7 @@ local function ScanGuildBank() end -local function ScanMailbox() +function BSYC:ScanMailbox() --this is to prevent buffer overflow from the CheckInbox() function calling ScanMailbox too much :) if isCheckingMail then return end isCheckingMail = true @@ -550,7 +566,7 @@ local function ScanMailbox() --even though the user has mail in the mailbox. This can be attributed to lag. CheckInbox() - if not BS_DB then StartupDB() end + if not BS_DB then self:StartupDB() end BS_DB["mailbox"] = BS_DB["mailbox"] or {} local slotItems = {} @@ -585,8 +601,8 @@ local function ScanMailbox() isCheckingMail = false end -local function ScanAuctionHouse() - if not BS_DB then StartupDB() end +function BSYC:ScanAuctionHouse() + if not BS_DB then self:StartupDB() end BS_DB["auction"] = BS_DB["auction"] or {} local slotItems = {} @@ -618,7 +634,7 @@ local function ScanAuctionHouse() end --this method is global for all toons, removes expired auctions on login -local function RemoveExpiredAuctions() +function BSYC:RemoveExpiredAuctions() if debugging then return end local timestampChk = { 30*60, 2*60*60, 12*60*60, 48*60*60 } @@ -665,7 +681,7 @@ end -- Money Tooltip -- ------------------------ -local function buildMoneyString(money, color) +function BSYC:buildMoneyString(money, color) local iconSize = 14 local goldicon = string.format("\124TInterface\\MoneyFrame\\UI-GoldIcon:%d:%d:1:0\124t ", iconSize, iconSize) @@ -700,7 +716,7 @@ local function buildMoneyString(money, color) return moneystring end -function BagSync:ShowMoneyTooltip() +function BSYC:ShowMoneyTooltip() local tooltip = _G["BagSyncMoneyTooltip"] or nil if (not tooltip) then @@ -737,11 +753,11 @@ function BagSync:ShowMoneyTooltip() tooltip:AddLine(" ") --loop through our characters - local xDB = BagSync:getFilteredDB() + local xDB = self:getFilteredDB() for k, v in pairs(xDB) do if v.gold then - k = BagSync:getCharacterRealmInfo(k, v.realm) + k = self:getCharacterRealmInfo(k, v.realm) table.insert(usrData, { name=k, gold=v.gold } ) end end @@ -750,12 +766,12 @@ function BagSync:ShowMoneyTooltip() local gldTotal = 0 for i=1, table.getn(usrData) do - tooltip:AddDoubleLine(usrData[i].name, buildMoneyString(usrData[i].gold, false), 1, 1, 1, 1, 1, 1) + tooltip:AddDoubleLine(usrData[i].name, self:buildMoneyString(usrData[i].gold, false), 1, 1, 1, 1, 1, 1) gldTotal = gldTotal + usrData[i].gold end if BagSyncOpt.showTotal and gldTotal > 0 then tooltip:AddLine(" ") - tooltip:AddDoubleLine(tooltipColor(BagSyncOpt.colors.total, buildMoneyString(gldTotal, false)), 1, 1, 1, 1, 1, 1) + tooltip:AddDoubleLine(tooltipColor(BagSyncOpt.colors.total, L["Total:"]), self:buildMoneyString(gldTotal, false), 1, 1, 1, 1, 1, 1) end tooltip:AddLine(" ") @@ -765,29 +781,16 @@ end ------------------------ -- Tokens -- ------------------------ -local function IsInBG() - if (GetNumBattlefieldScores() > 0) then - return true - end - return false -end - -local function IsInArena() - local a,b = IsActiveBattlefieldArena() - if not a then - return false - end - return true -end -local function ScanTokens() +function BSYC:ScanTokens() +self:Print("tokens") if debugging then return end --LETS AVOID TOKEN SPAM AS MUCH AS POSSIBLE if doTokenUpdate == 1 then return end if IsInBG() or IsInArena() or InCombatLockdown() or UnitAffectingCombat("player") then --avoid (Honor point spam), avoid (arena point spam), if it's world PVP...well then it sucks to be you doTokenUpdate = 1 - BagSync:RegisterEvent("PLAYER_REGEN_ENABLED") + BSYC:RegisterEvent("PLAYER_REGEN_ENABLED") return end @@ -821,20 +824,18 @@ local function ScanTokens() --we don't want to overwrite tokens, because some characters may have currency that the others dont have end -hooksecurefunc("BackpackTokenFrame_Update", ScanTokens) - ------------------------ -- Tooltip! -- -- (Special thanks to tuller) ------------------------ --a function call to reset these local variables outside the scope ;) -function BagSync:resetTooltip() +function BSYC:resetTooltip() lastDisplayed = {} lastItem = nil end -local function CountsToInfoString(countTable) +function BSYC:CountsToInfoString(countTable) local info local total = 0 @@ -932,22 +933,7 @@ local function CountsToInfoString(countTable) end end ---sort by key element rather then value -local function pairsByKeys (t, f) - local a = {} - for n in pairs(t) do table.insert(a, n) end - table.sort(a, f) - local i = 0 -- iterator variable - local iter = function () -- iterator function - i = i + 1 - if a[i] == nil then return nil - else return a[i], t[a[i]] - end - end - return iter -end - -local function getNameColor(sName, sClass) +function BSYC:getNameColor(sName, sClass) if not BagSyncOpt.enableUnitClass then return tooltipColor(BagSyncOpt.colors.first, sName) else @@ -958,29 +944,29 @@ local function getNameColor(sName, sClass) return tooltipColor(BagSyncOpt.colors.first, sName) end -local function getPlayerNameColor(sName) +function BSYC:getPlayerNameColor(sName) if BagSyncDB[currentRealm][sName] then local sClass = BagSyncDB[currentRealm][sName].class - return getNameColor(sName, sClass) + return self:getNameColor(sName, sClass) end return tooltipColor(BagSyncOpt.colors.first, sName) end -local function AddCurrencyToTooltip(frame, currencyName) +function BSYC:AddCurrencyToTooltip(frame, currencyName) if BS_TD and currencyName and BS_TD[currencyName] then if BagSyncOpt.enableTooltipSeperator then frame:AddLine(" ") end for charName, count in pairsByKeys(BS_TD[currencyName]) do if charName ~= "icon" and charName ~= "header" and count > 0 then - frame:AddDoubleLine(getPlayerNameColor(charName), count) + frame:AddDoubleLine(self:getPlayerNameColor(charName), count) end end frame:Show() end end -local function AddItemToTooltip(frame, link) --workaround +function BSYC:AddItemToTooltip(frame, link) --workaround --if we can't convert the item link then lets just ignore it altogether local itemLink = ToShortLink(link) @@ -996,10 +982,10 @@ local function AddItemToTooltip(frame, link) --workaround end --ignore the hearthstone and blacklisted items - if itemLink and tonumber(itemLink) and (tonumber(itemLink) == 6948 or tonumber(itemLink) == 110560 or tonumber(itemLink) == 140192 or BS_BL[tonumber(itemLink)]) then - frame:Show() - return - end + -- if itemLink and tonumber(itemLink) and (tonumber(itemLink) == 6948 or tonumber(itemLink) == 110560 or tonumber(itemLink) == 140192 or BS_BL[tonumber(itemLink)]) then + -- frame:Show() + -- return + -- end --lag check (check for previously displayed data) if so then display it if lastItem and itemLink and itemLink == lastItem then @@ -1024,7 +1010,7 @@ local function AddItemToTooltip(frame, link) --workaround local grandTotal = 0 local first = true - local xDB = BagSync:getFilteredDB() + local xDB = BSYC:getFilteredDB() --loop through our characters --k = player, v = stored data for player @@ -1075,7 +1061,7 @@ local function AddItemToTooltip(frame, link) --workaround if BagSyncGUILD_DB and guildN and BagSyncGUILD_DB[v.realm][guildN] then --check to see if this guild has already been done through this run (so we don't do it multiple times) --check for XR/B.Net support - local gName = BagSync:getGuildRealmInfo(guildN, v.realm) + local gName = BSYC:getGuildRealmInfo(guildN, v.realm) if not previousGuilds[gName] then --we only really need to see this information once per guild @@ -1095,11 +1081,11 @@ local function AddItemToTooltip(frame, link) --workaround --get class for the unit if there is one local pClass = v.class or nil - infoString = CountsToInfoString(allowList) + infoString = self:CountsToInfoString(allowList) if infoString and infoString ~= "" then - k = BagSync:getCharacterRealmInfo(k, v.realm) - table.insert(lastDisplayed, getNameColor(k or "Unknown", pClass).."@"..(infoString or "unknown")) + k = BSYC:getCharacterRealmInfo(k, v.realm) + table.insert(lastDisplayed, self:getNameColor(k or "Unknown", pClass).."@"..(infoString or "unknown")) end end @@ -1147,37 +1133,38 @@ end --Honestly we aren't going to care about throttleing or anything like that anymore. The lastdisplay array token should take care of that --Special thanks to Tuller for tooltip hook function -local function hookTip(tooltip) - local modified = false +function BSYC:hookTip(tooltip) + + tooltip.isModified = false tooltip:HookScript("OnHide", function(self) - modified = false + self.isModified = false self.lastHyperLink = nil end) tooltip:HookScript("OnTooltipCleared", function(self) - modified = false + self.isModified = false end) tooltip:HookScript("OnTooltipSetItem", function(self) - if modified or not BagSyncOpt.enableTooltips then return end + if self.isModified or not BagSyncOpt.enableTooltips then return end local name, link = self:GetItem() if link and ToShortLink(link) then - modified = true - AddItemToTooltip(self, link) + self.isModified = true + BSYC:AddItemToTooltip(self, link) return end --sometimes we have a tooltip but no link because GetItem() returns nil, this is the case for recipes --so lets try something else to see if we can get the link. Doesn't always work! Thanks for breaking GetItem() Blizzard... you ROCK! :P - if not modified and self.lastHyperLink then + if not self.isModified and self.lastHyperLink then local xName, xLink = GetItemInfo(self.lastHyperLink) --local title = _G[tooltip:GetName().."TextLeft1"] -- if xName and xLink and title and title:GetText() and title:GetText() == xName and ToShortLink(xLink) then --only show info if the tooltip text matches the link - -- modified = true - -- AddItemToTooltip(self, xLink) + -- self.isModified = true + -- BSYC:AddItemToTooltip(self, xLink) -- end if xLink and ToShortLink(xLink) then --only show info if the tooltip text matches the link - modified = true - AddItemToTooltip(self, xLink) + self.isModified = true + BSYC:AddItemToTooltip(self, xLink) end end end) @@ -1205,93 +1192,92 @@ local function hookTip(tooltip) end end) hooksecurefunc(tooltip, "SetHyperlink", function(self, link) - if modified or not BagSyncOpt.enableTooltips then return end + if self.isModified or not BagSyncOpt.enableTooltips then return end if link and ToShortLink(link) then --I'm pretty sure there is a better way to do this but since Recipes fire OnTooltipSetItem with empty/nil GetItem(). There is really no way to my knowledge to grab the current itemID --without storing the ItemLink from the bag parsing or at least grabbing the current SetHyperLink. - if tooltip:IsVisible() then modified = true end --only do the modifier if the tooltip is showing, because this interferes with ItemRefTooltip if someone clicks it twice in chat - AddItemToTooltip(self, link) + if tooltip:IsVisible() then self.isModified = true end --only do the modifier if the tooltip is showing, because this interferes with ItemRefTooltip if someone clicks it twice in chat + self.isModified = true + BSYC:AddItemToTooltip(self, link) end end) --------------------------------- --lets hook other frames so we can show tooltips there as well hooksecurefunc(tooltip, "SetRecipeReagentItem", function(self, recipeID, reagentIndex) - if modified or not BagSyncOpt.enableTooltips then return end + if self.isModified or not BagSyncOpt.enableTooltips then return end local link = C_TradeSkillUI.GetRecipeReagentItemLink(recipeID, reagentIndex) if link and ToShortLink(link) then - modified = true - AddItemToTooltip(self, link) + self.isModified = true + BSYC:AddItemToTooltip(self, link) end end) hooksecurefunc(tooltip, "SetRecipeResultItem", function(self, recipeID) - if modified or not BagSyncOpt.enableTooltips then return end + if self.isModified or not BagSyncOpt.enableTooltips then return end local link = C_TradeSkillUI.GetRecipeItemLink(recipeID) if link and ToShortLink(link) then - modified = true - AddItemToTooltip(self, link) + self.isModified = true + BSYC:AddItemToTooltip(self, link) end end) hooksecurefunc(tooltip, "SetQuestLogItem", function(self, itemType, index) - if modified or not BagSyncOpt.enableTooltips then return end + if self.isModified or not BagSyncOpt.enableTooltips then return end local link = GetQuestLogItemLink(itemType, index) if link and ToShortLink(link) then - modified = true + self.isModified = true AddItemToTooltip(self, link) end end) hooksecurefunc(tooltip, "SetQuestItem", function(self, itemType, index) - if modified or not BagSyncOpt.enableTooltips then return end + if self.isModified or not BagSyncOpt.enableTooltips then return end local link = GetQuestItemLink(itemType, index) if link and ToShortLink(link) then - modified = true - AddItemToTooltip(self, link) + self.isModified = true + BSYC:AddItemToTooltip(self, link) end end) -- hooksecurefunc(tooltip, 'SetItemByID', function(self, link) - -- if modified or not BagSyncOpt.enableTooltips then return end + -- if self.isModified or not BagSyncOpt.enableTooltips then return end -- if link and ToShortLink(link) then - -- modified = true - -- AddItemToTooltip(self, link) + -- self.isModified = true + -- BSYC:AddItemToTooltip(self, link) -- end -- end) -------------------------------------------------- hooksecurefunc(tooltip, "SetCurrencyToken", function(self, index) - if modified or not BagSyncOpt.enableTooltips then return end - modified = true + if self.isModified or not BagSyncOpt.enableTooltips then return end + self.isModified = true local currencyName = GetCurrencyListInfo(index) - AddCurrencyToTooltip(self, currencyName) + BSYC:AddCurrencyToTooltip(self, currencyName) end) hooksecurefunc(tooltip, "SetCurrencyByID", function(self, id) - if modified or not BagSyncOpt.enableTooltips then return end - modified = true + if self.isModified or not BagSyncOpt.enableTooltips then return end + self.isModified = true local currencyName = GetCurrencyInfo(id) - AddCurrencyToTooltip(self, currencyName) + BSYC:AddCurrencyToTooltip(self, currencyName) end) hooksecurefunc(tooltip, "SetBackpackToken", function(self, index) - if modified or not BagSyncOpt.enableTooltips then return end - modified = true + if self.isModified or not BagSyncOpt.enableTooltips then return end + self.isModified = true local currencyName = GetBackpackCurrencyInfo(index) - AddCurrencyToTooltip(self, currencyName) + BSYC:AddCurrencyToTooltip(self, currencyName) end) -- hooksecurefunc(tooltip, 'SetTradeSkillReagentInfo', function(self, index) - -- if modified or not BagSyncOpt.enableTooltips then return end - -- modified = true + -- if self.isModified or not BagSyncOpt.enableTooltips then return end + -- self.isModified = true -- local currencyName = GetTradeSkillReagentInfo(index,1) - -- AddCurrencyToTooltip(self, currencyName) + -- BSYC:AddCurrencyToTooltip(self, currencyName) -- end) end -hookTip(GameTooltip) -hookTip(ItemRefTooltip) - ------------------------------ -- LOGIN HANDLER -- ------------------------------ -function BagSync:PLAYER_LOGIN() +function BSYC:OnEnable() + --NOTE: Using OnEnable() instead of OnInitialize() because not all the SavedVarables are loaded and UnitFullName() will return nil for realm BINDING_HEADER_BAGSYNC = "BagSync" BINDING_NAME_BAGSYNCTOGGLESEARCH = L["Toggle Search"] @@ -1310,14 +1296,15 @@ function BagSync:PLAYER_LOGIN() local autoCompleteRealms = GetAutoCompleteRealms() or { currentRealm } + self.crossRealmNames = {} for k, v in pairs(autoCompleteRealms) do if v ~= currentRealm then - crossRealmNames[v] = true + self.crossRealmNames[v] = true end end --initiate the db - StartupDB() + self:StartupDB() --do DB cleanup check by version number if not BagSyncOpt.dbversion or BagSyncOpt.dbversion ~= ver then @@ -1348,17 +1335,18 @@ function BagSync:PLAYER_LOGIN() --save all inventory data, including backpack(0) for i = BACKPACK_CONTAINER, BACKPACK_CONTAINER + NUM_BAG_SLOTS do - SaveBag("bag", i) + self:SaveBag("bag", i) end --force an equipment scan - SaveEquipment() + self:SaveEquipment() --force token scan - ScanTokens() + hooksecurefunc("BackpackTokenFrame_Update", function(self) BSYC:ScanTokens() end) + self:ScanTokens() --clean up old auctions - RemoveExpiredAuctions() + self:RemoveExpiredAuctions() --check for minimap toggle if BagSyncOpt.enableMinimap and BagSync_MinimapButton and not BagSync_MinimapButton:IsVisible() then @@ -1396,6 +1384,10 @@ function BagSync:PLAYER_LOGIN() --this will be used for getting the tradeskill link self:RegisterEvent("TRADE_SKILL_SHOW") + --hook the tooltips + self:hookTip(GameTooltip) + self:hookTip(ItemRefTooltip) + SLASH_BAGSYNC1 = "/bagsync" SLASH_BAGSYNC2 = "/bgs" SlashCmdList["BAGSYNC"] = function(msg) @@ -1445,8 +1437,7 @@ function BagSync:PLAYER_LOGIN() self:FixDB_Data() return true elseif c and c:lower() == L["config"] then - InterfaceOptionsFrame_OpenToCategory("BagSync") - InterfaceOptionsFrame_OpenToCategory("BagSync") --calling it twice because sometimes it doesn't always work, it's a bug with blizzard + LibStub("AceConfigDialog-3.0"):Open("BagSync") return true elseif c and c:lower() ~= "" then --do an item search @@ -1459,47 +1450,42 @@ function BagSync:PLAYER_LOGIN() end end - DEFAULT_CHAT_FRAME:AddMessage("BAGSYNC") - DEFAULT_CHAT_FRAME:AddMessage(L["/bgs [itemname] - Does a quick search for an item"]) - DEFAULT_CHAT_FRAME:AddMessage(L["/bgs search - Opens the search window"]) - DEFAULT_CHAT_FRAME:AddMessage(L["/bgs gold - Displays a tooltip with the amount of gold on each character."]) - DEFAULT_CHAT_FRAME:AddMessage(L["/bgs tokens - Opens the tokens/currency window."]) - DEFAULT_CHAT_FRAME:AddMessage(L["/bgs profiles - Opens the profiles window."]) - DEFAULT_CHAT_FRAME:AddMessage(L["/bgs professions - Opens the professions window."]) - DEFAULT_CHAT_FRAME:AddMessage(L["/bgs blacklist - Opens the blacklist window."]) - DEFAULT_CHAT_FRAME:AddMessage(L["/bgs fixdb - Runs the database fix (FixDB) on BagSync."]) - DEFAULT_CHAT_FRAME:AddMessage(L["/bgs config - Opens the BagSync Config Window"] ) + self:Print(L["/bgs [itemname] - Does a quick search for an item"]) + self:Print(L["/bgs search - Opens the search window"]) + self:Print(L["/bgs gold - Displays a tooltip with the amount of gold on each character."]) + self:Print(L["/bgs tokens - Opens the tokens/currency window."]) + self:Print(L["/bgs profiles - Opens the profiles window."]) + self:Print(L["/bgs professions - Opens the professions window."]) + self:Print(L["/bgs blacklist - Opens the blacklist window."]) + self:Print(L["/bgs fixdb - Runs the database fix (FixDB) on BagSync."]) + self:Print(L["/bgs config - Opens the BagSync Config Window"] ) end - DEFAULT_CHAT_FRAME:AddMessage("|cFF99CC33BagSync|r [v|cFFDF2B2B"..ver.."|r] /bgs, /bagsync") - - self:UnregisterEvent("PLAYER_LOGIN") - self.PLAYER_LOGIN = nil - + self:Print("[v|cFFDF2B2B"..ver.."|r] /bgs, /bagsync") end ------------------------------ -- Event Handlers -- ------------------------------ -function BagSync:CURRENCY_DISPLAY_UPDATE() +function BSYC:CURRENCY_DISPLAY_UPDATE() if debugging then return end if IsInBG() or IsInArena() or InCombatLockdown() or UnitAffectingCombat("player") then return end doTokenUpdate = 0 - ScanTokens() + self:ScanTokens() end -function BagSync:PLAYER_REGEN_ENABLED() +function BSYC:PLAYER_REGEN_ENABLED() if debugging then return end if IsInBG() or IsInArena() or InCombatLockdown() or UnitAffectingCombat("player") then return end self:UnregisterEvent("PLAYER_REGEN_ENABLED") --were out of an arena or battleground scan the points doTokenUpdate = 0 - ScanTokens() + self:ScanTokens() end -function BagSync:GUILD_ROSTER_UPDATE() +function BSYC:GUILD_ROSTER_UPDATE() if debugging then return end if not IsInGuild() and BS_DB.guild then BS_DB.guild = nil @@ -1515,7 +1501,7 @@ function BagSync:GUILD_ROSTER_UPDATE() end end -function BagSync:PLAYER_MONEY() +function BSYC:PLAYER_MONEY() if debugging then return end BS_DB.gold = GetMoney() end @@ -1524,7 +1510,7 @@ end -- BAG UPDATES -- ------------------------------ -function BagSync:BAG_UPDATE(event, bagid) +function BSYC:BAG_UPDATE(event, bagid) if debugging then return end -- -1 happens to be the primary bank slot ;) if (bagid > BANK_CONTAINER) then @@ -1544,15 +1530,15 @@ function BagSync:BAG_UPDATE(event, bagid) if bagname == "bank" and not atBank then return; end --now save the item information in the bag from bagupdate, this could be bag or bank - SaveBag(bagname, bagid) + self:SaveBag(bagname, bagid) end end -function BagSync:UNIT_INVENTORY_CHANGED(event, unit) +function BSYC:UNIT_INVENTORY_CHANGED(event, unit) if debugging then return end if unit == "player" then - SaveEquipment() + self:SaveEquipment() end end @@ -1560,22 +1546,22 @@ end -- BANK -- ------------------------------ -function BagSync:BANKFRAME_OPENED() +function BSYC:BANKFRAME_OPENED() if debugging then return end atBank = true - ScanEntireBank() + self:ScanEntireBank() end -function BagSync:BANKFRAME_CLOSED() +function BSYC:BANKFRAME_CLOSED() if debugging then return end atBank = false end -function BagSync:PLAYERBANKSLOTS_CHANGED(event, slotid) +function BSYC:PLAYERBANKSLOTS_CHANGED(event, slotid) if debugging then return end --Remove atBank when/if Blizzard allows Bank access without being at the bank if atBank then - SaveBag("bank", BANK_CONTAINER) + self:SaveBag("bank", BANK_CONTAINER) end end @@ -1583,46 +1569,46 @@ end -- REAGENT BANK -- ------------------------------ -function BagSync:PLAYERREAGENTBANKSLOTS_CHANGED() +function BSYC:PLAYERREAGENTBANKSLOTS_CHANGED() if debugging then return end - SaveBag("reagentbank", REAGENTBANK_CONTAINER) + self:SaveBag("reagentbank", REAGENTBANK_CONTAINER) end ------------------------------ -- VOID BANK -- ------------------------------ -function BagSync:VOID_STORAGE_OPEN() +function BSYC:VOID_STORAGE_OPEN() if debugging then return end atVoidBank = true - ScanVoidBank() + self:ScanVoidBank() end -function BagSync:VOID_STORAGE_CLOSE() +function BSYC:VOID_STORAGE_CLOSE() if debugging then return end atVoidBank = false end -function BagSync:VOID_STORAGE_UPDATE() +function BSYC:VOID_STORAGE_UPDATE() if debugging then return end - ScanVoidBank() + self:ScanVoidBank() end -function BagSync:VOID_STORAGE_CONTENTS_UPDATE() +function BSYC:VOID_STORAGE_CONTENTS_UPDATE() if debugging then return end - ScanVoidBank() + self:ScanVoidBank() end -function BagSync:VOID_TRANSFER_DONE() +function BSYC:VOID_TRANSFER_DONE() if debugging then return end - ScanVoidBank() + self:ScanVoidBank() end ------------------------------ -- GUILD BANK -- ------------------------------ -function BagSync:GUILDBANKFRAME_OPENED() +function BSYC:GUILDBANKFRAME_OPENED() if debugging then return end atGuildBank = true if not BagSyncOpt.enableGuild then return end @@ -1637,12 +1623,12 @@ function BagSync:GUILDBANKFRAME_OPENED() end end -function BagSync:GUILDBANKFRAME_CLOSED() +function BSYC:GUILDBANKFRAME_CLOSED() if debugging then return end atGuildBank = false end -function BagSync:GUILDBANKBAGSLOTS_CHANGED() +function BSYC:GUILDBANKBAGSLOTS_CHANGED() if debugging then return end if not BagSyncOpt.enableGuild then return end @@ -1654,7 +1640,7 @@ function BagSync:GUILDBANKBAGSLOTS_CHANGED() guildTabQueryQueue[tab] = nil else -- the bank is ready for reading - ScanGuildBank() + self:ScanGuildBank() end end end @@ -1663,49 +1649,49 @@ end -- MAILBOX -- ------------------------------ -function BagSync:MAIL_SHOW() +function BSYC:MAIL_SHOW() if debugging then return end if isCheckingMail then return end if not BagSyncOpt.enableMailbox then return end - ScanMailbox() + self:ScanMailbox() end -function BagSync:MAIL_INBOX_UPDATE() +function BSYC:MAIL_INBOX_UPDATE() if debugging then return end if isCheckingMail then return end if not BagSyncOpt.enableMailbox then return end - ScanMailbox() + self:ScanMailbox() end ------------------------------ -- AUCTION HOUSE -- ------------------------------ -function BagSync:AUCTION_HOUSE_SHOW() +function BSYC:AUCTION_HOUSE_SHOW() if debugging then return end if not BagSyncOpt.enableAuction then return end - ScanAuctionHouse() + self:ScanAuctionHouse() end -function BagSync:AUCTION_OWNED_LIST_UPDATE() +function BSYC:AUCTION_OWNED_LIST_UPDATE() if debugging then return end if not BagSyncOpt.enableAuction then return end BS_DB.AH_LastScan = time() - ScanAuctionHouse() + self:ScanAuctionHouse() end ------------------------------ -- PROFESSION -- ------------------------------ -local function doRegularTradeSkill(numIndex, dbIdx) +function BSYC:doRegularTradeSkill(numIndex, dbIdx) local name, icon, skillLevel, maxSkillLevel, numAbilities, spelloffset, skillLine, skillModifier = GetProfessionInfo(numIndex) if name and skillLevel then BS_CD[dbIdx] = format("%s,%s", name, skillLevel) end end -function BagSync:TRADE_SKILL_SHOW() +function BSYC:TRADE_SKILL_SHOW() if debugging then return end --IsTradeSkillLinked() returns true only if trade window was opened from chat link (meaning another player) @@ -1730,7 +1716,7 @@ function BagSync:TRADE_SKILL_SHOW() BS_CD[1] = { tradename, C_TradeSkillUI.GetTradeSkillListLink(), skill } elseif prof1 and iconProf1 and noLinkTS[iconProf1] then --only store if it's herbalism, skinning, or mining - doRegularTradeSkill(prof1, 1) + self:doRegularTradeSkill(prof1, 1) elseif not prof1 and BS_CD[1] then --they removed a profession BS_CD[1] = nil @@ -1742,7 +1728,7 @@ function BagSync:TRADE_SKILL_SHOW() BS_CD[2] = { tradename, C_TradeSkillUI.GetTradeSkillListLink(), skill } elseif prof2 and iconProf2 and noLinkTS[iconProf2] then --only store if it's herbalism, skinning, or mining - doRegularTradeSkill(prof2, 2) + self:doRegularTradeSkill(prof2, 2) elseif not prof2 and BS_CD[2] then --they removed a profession BS_CD[2] = nil @@ -1750,7 +1736,7 @@ function BagSync:TRADE_SKILL_SHOW() --archaeology if archaeology then - doRegularTradeSkill(archaeology, 3) + self:doRegularTradeSkill(archaeology, 3) elseif not archaeology and BS_CD[3] then --they removed a profession BS_CD[3] = nil @@ -1758,7 +1744,7 @@ function BagSync:TRADE_SKILL_SHOW() --fishing if fishing then - doRegularTradeSkill(fishing, 4) + self:doRegularTradeSkill(fishing, 4) elseif not fishing and BS_CD[4] then --they removed a profession BS_CD[4] = nil diff --git a/BagSync.toc b/BagSync.toc index a63a92c..78f6430 100644 --- a/BagSync.toc +++ b/BagSync.toc @@ -8,9 +8,12 @@ libs\LibStub\LibStub.lua libs\CallbackHandler-1.0\CallbackHandler-1.0.xml +libs\AceAddon-3.0\AceAddon-3.0.xml libs\AceGUI-3.0\AceGUI-3.0.xml libs\AceConfig-3.0\AceConfig-3.0.xml libs\AceLocale-3.0\AceLocale-3.0.xml +libs\AceConsole-3.0\AceConsole-3.0.xml +libs\AceEvent-3.0\AceEvent-3.0.xml libs\Unfit-1.0\Unfit-1.0.lua libs\CustomSearch-1.0\CustomSearch-1.0.lua libs\LibItemSearch-1.2\LibItemSearch-1.2.lua diff --git a/libs/AceAddon-3.0/AceAddon-3.0.lua b/libs/AceAddon-3.0/AceAddon-3.0.lua new file mode 100644 index 0000000..a7f7279 --- /dev/null +++ b/libs/AceAddon-3.0/AceAddon-3.0.lua @@ -0,0 +1,674 @@ +--- **AceAddon-3.0** provides a template for creating addon objects. +-- It'll provide you with a set of callback functions that allow you to simplify the loading +-- process of your addon.\\ +-- Callbacks provided are:\\ +-- * **OnInitialize**, which is called directly after the addon is fully loaded. +-- * **OnEnable** which gets called during the PLAYER_LOGIN event, when most of the data provided by the game is already present. +-- * **OnDisable**, which is only called when your addon is manually being disabled. +-- @usage +-- -- A small (but complete) addon, that doesn't do anything, +-- -- but shows usage of the callbacks. +-- local MyAddon = LibStub("AceAddon-3.0"):NewAddon("MyAddon") +-- +-- function MyAddon:OnInitialize() +-- -- do init tasks here, like loading the Saved Variables, +-- -- or setting up slash commands. +-- end +-- +-- function MyAddon:OnEnable() +-- -- Do more initialization here, that really enables the use of your addon. +-- -- Register Events, Hook functions, Create Frames, Get information from +-- -- the game that wasn't available in OnInitialize +-- end +-- +-- function MyAddon:OnDisable() +-- -- Unhook, Unregister Events, Hide frames that you created. +-- -- You would probably only use an OnDisable if you want to +-- -- build a "standby" mode, or be able to toggle modules on/off. +-- end +-- @class file +-- @name AceAddon-3.0.lua +-- @release $Id: AceAddon-3.0.lua 1084 2013-04-27 20:14:11Z nevcairiel $ + +local MAJOR, MINOR = "AceAddon-3.0", 12 +local AceAddon, oldminor = LibStub:NewLibrary(MAJOR, MINOR) + +if not AceAddon then return end -- No Upgrade needed. + +AceAddon.frame = AceAddon.frame or CreateFrame("Frame", "AceAddon30Frame") -- Our very own frame +AceAddon.addons = AceAddon.addons or {} -- addons in general +AceAddon.statuses = AceAddon.statuses or {} -- statuses of addon. +AceAddon.initializequeue = AceAddon.initializequeue or {} -- addons that are new and not initialized +AceAddon.enablequeue = AceAddon.enablequeue or {} -- addons that are initialized and waiting to be enabled +AceAddon.embeds = AceAddon.embeds or setmetatable({}, {__index = function(tbl, key) tbl[key] = {} return tbl[key] end }) -- contains a list of libraries embedded in an addon + +-- Lua APIs +local tinsert, tconcat, tremove = table.insert, table.concat, table.remove +local fmt, tostring = string.format, tostring +local select, pairs, next, type, unpack = select, pairs, next, type, unpack +local loadstring, assert, error = loadstring, assert, error +local setmetatable, getmetatable, rawset, rawget = setmetatable, getmetatable, rawset, rawget + +-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded +-- List them here for Mikk's FindGlobals script +-- GLOBALS: LibStub, IsLoggedIn, geterrorhandler + +--[[ + xpcall safecall implementation +]] +local xpcall = xpcall + +local function errorhandler(err) + return geterrorhandler()(err) +end + +local function CreateDispatcher(argCount) + local code = [[ + local xpcall, eh = ... + local method, ARGS + local function call() return method(ARGS) end + + local function dispatch(func, ...) + method = func + if not method then return end + ARGS = ... + return xpcall(call, eh) + end + + return dispatch + ]] + + local ARGS = {} + for i = 1, argCount do ARGS[i] = "arg"..i end + code = code:gsub("ARGS", tconcat(ARGS, ", ")) + return assert(loadstring(code, "safecall Dispatcher["..argCount.."]"))(xpcall, errorhandler) +end + +local Dispatchers = setmetatable({}, {__index=function(self, argCount) + local dispatcher = CreateDispatcher(argCount) + rawset(self, argCount, dispatcher) + return dispatcher +end}) +Dispatchers[0] = function(func) + return xpcall(func, errorhandler) +end + +local function safecall(func, ...) + -- we check to see if the func is passed is actually a function here and don't error when it isn't + -- this safecall is used for optional functions like OnInitialize OnEnable etc. When they are not + -- present execution should continue without hinderance + if type(func) == "function" then + return Dispatchers[select('#', ...)](func, ...) + end +end + +-- local functions that will be implemented further down +local Enable, Disable, EnableModule, DisableModule, Embed, NewModule, GetModule, GetName, SetDefaultModuleState, SetDefaultModuleLibraries, SetEnabledState, SetDefaultModulePrototype + +-- used in the addon metatable +local function addontostring( self ) return self.name end + +-- Check if the addon is queued for initialization +local function queuedForInitialization(addon) + for i = 1, #AceAddon.initializequeue do + if AceAddon.initializequeue[i] == addon then + return true + end + end + return false +end + +--- Create a new AceAddon-3.0 addon. +-- Any libraries you specified will be embeded, and the addon will be scheduled for +-- its OnInitialize and OnEnable callbacks. +-- The final addon object, with all libraries embeded, will be returned. +-- @paramsig [object ,]name[, lib, ...] +-- @param object Table to use as a base for the addon (optional) +-- @param name Name of the addon object to create +-- @param lib List of libraries to embed into the addon +-- @usage +-- -- Create a simple addon object +-- MyAddon = LibStub("AceAddon-3.0"):NewAddon("MyAddon", "AceEvent-3.0") +-- +-- -- Create a Addon object based on the table of a frame +-- local MyFrame = CreateFrame("Frame") +-- MyAddon = LibStub("AceAddon-3.0"):NewAddon(MyFrame, "MyAddon", "AceEvent-3.0") +function AceAddon:NewAddon(objectorname, ...) + local object,name + local i=1 + if type(objectorname)=="table" then + object=objectorname + name=... + i=2 + else + name=objectorname + end + if type(name)~="string" then + error(("Usage: NewAddon([object,] name, [lib, lib, lib, ...]): 'name' - string expected got '%s'."):format(type(name)), 2) + end + if self.addons[name] then + error(("Usage: NewAddon([object,] name, [lib, lib, lib, ...]): 'name' - Addon '%s' already exists."):format(name), 2) + end + + object = object or {} + object.name = name + + local addonmeta = {} + local oldmeta = getmetatable(object) + if oldmeta then + for k, v in pairs(oldmeta) do addonmeta[k] = v end + end + addonmeta.__tostring = addontostring + + setmetatable( object, addonmeta ) + self.addons[name] = object + object.modules = {} + object.orderedModules = {} + object.defaultModuleLibraries = {} + Embed( object ) -- embed NewModule, GetModule methods + self:EmbedLibraries(object, select(i,...)) + + -- add to queue of addons to be initialized upon ADDON_LOADED + tinsert(self.initializequeue, object) + return object +end + + +--- Get the addon object by its name from the internal AceAddon registry. +-- Throws an error if the addon object cannot be found (except if silent is set). +-- @param name unique name of the addon object +-- @param silent if true, the addon is optional, silently return nil if its not found +-- @usage +-- -- Get the Addon +-- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon") +function AceAddon:GetAddon(name, silent) + if not silent and not self.addons[name] then + error(("Usage: GetAddon(name): 'name' - Cannot find an AceAddon '%s'."):format(tostring(name)), 2) + end + return self.addons[name] +end + +-- - Embed a list of libraries into the specified addon. +-- This function will try to embed all of the listed libraries into the addon +-- and error if a single one fails. +-- +-- **Note:** This function is for internal use by :NewAddon/:NewModule +-- @paramsig addon, [lib, ...] +-- @param addon addon object to embed the libs in +-- @param lib List of libraries to embed into the addon +function AceAddon:EmbedLibraries(addon, ...) + for i=1,select("#", ... ) do + local libname = select(i, ...) + self:EmbedLibrary(addon, libname, false, 4) + end +end + +-- - Embed a library into the addon object. +-- This function will check if the specified library is registered with LibStub +-- and if it has a :Embed function to call. It'll error if any of those conditions +-- fails. +-- +-- **Note:** This function is for internal use by :EmbedLibraries +-- @paramsig addon, libname[, silent[, offset]] +-- @param addon addon object to embed the library in +-- @param libname name of the library to embed +-- @param silent marks an embed to fail silently if the library doesn't exist (optional) +-- @param offset will push the error messages back to said offset, defaults to 2 (optional) +function AceAddon:EmbedLibrary(addon, libname, silent, offset) + local lib = LibStub:GetLibrary(libname, true) + if not lib and not silent then + error(("Usage: EmbedLibrary(addon, libname, silent, offset): 'libname' - Cannot find a library instance of %q."):format(tostring(libname)), offset or 2) + elseif lib and type(lib.Embed) == "function" then + lib:Embed(addon) + tinsert(self.embeds[addon], libname) + return true + elseif lib then + error(("Usage: EmbedLibrary(addon, libname, silent, offset): 'libname' - Library '%s' is not Embed capable"):format(libname), offset or 2) + end +end + +--- Return the specified module from an addon object. +-- Throws an error if the addon object cannot be found (except if silent is set) +-- @name //addon//:GetModule +-- @paramsig name[, silent] +-- @param name unique name of the module +-- @param silent if true, the module is optional, silently return nil if its not found (optional) +-- @usage +-- -- Get the Addon +-- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon") +-- -- Get the Module +-- MyModule = MyAddon:GetModule("MyModule") +function GetModule(self, name, silent) + if not self.modules[name] and not silent then + error(("Usage: GetModule(name, silent): 'name' - Cannot find module '%s'."):format(tostring(name)), 2) + end + return self.modules[name] +end + +local function IsModuleTrue(self) return true end + +--- Create a new module for the addon. +-- The new module can have its own embeded libraries and/or use a module prototype to be mixed into the module.\\ +-- A module has the same functionality as a real addon, it can have modules of its own, and has the same API as +-- an addon object. +-- @name //addon//:NewModule +-- @paramsig name[, prototype|lib[, lib, ...]] +-- @param name unique name of the module +-- @param prototype object to derive this module from, methods and values from this table will be mixed into the module (optional) +-- @param lib List of libraries to embed into the addon +-- @usage +-- -- Create a module with some embeded libraries +-- MyModule = MyAddon:NewModule("MyModule", "AceEvent-3.0", "AceHook-3.0") +-- +-- -- Create a module with a prototype +-- local prototype = { OnEnable = function(self) print("OnEnable called!") end } +-- MyModule = MyAddon:NewModule("MyModule", prototype, "AceEvent-3.0", "AceHook-3.0") +function NewModule(self, name, prototype, ...) + if type(name) ~= "string" then error(("Usage: NewModule(name, [prototype, [lib, lib, lib, ...]): 'name' - string expected got '%s'."):format(type(name)), 2) end + if type(prototype) ~= "string" and type(prototype) ~= "table" and type(prototype) ~= "nil" then error(("Usage: NewModule(name, [prototype, [lib, lib, lib, ...]): 'prototype' - table (prototype), string (lib) or nil expected got '%s'."):format(type(prototype)), 2) end + + if self.modules[name] then error(("Usage: NewModule(name, [prototype, [lib, lib, lib, ...]): 'name' - Module '%s' already exists."):format(name), 2) end + + -- modules are basically addons. We treat them as such. They will be added to the initializequeue properly as well. + -- NewModule can only be called after the parent addon is present thus the modules will be initialized after their parent is. + local module = AceAddon:NewAddon(fmt("%s_%s", self.name or tostring(self), name)) + + module.IsModule = IsModuleTrue + module:SetEnabledState(self.defaultModuleState) + module.moduleName = name + + if type(prototype) == "string" then + AceAddon:EmbedLibraries(module, prototype, ...) + else + AceAddon:EmbedLibraries(module, ...) + end + AceAddon:EmbedLibraries(module, unpack(self.defaultModuleLibraries)) + + if not prototype or type(prototype) == "string" then + prototype = self.defaultModulePrototype or nil + end + + if type(prototype) == "table" then + local mt = getmetatable(module) + mt.__index = prototype + setmetatable(module, mt) -- More of a Base class type feel. + end + + safecall(self.OnModuleCreated, self, module) -- Was in Ace2 and I think it could be a cool thing to have handy. + self.modules[name] = module + tinsert(self.orderedModules, module) + + return module +end + +--- Returns the real name of the addon or module, without any prefix. +-- @name //addon//:GetName +-- @paramsig +-- @usage +-- print(MyAddon:GetName()) +-- -- prints "MyAddon" +function GetName(self) + return self.moduleName or self.name +end + +--- Enables the Addon, if possible, return true or false depending on success. +-- This internally calls AceAddon:EnableAddon(), thus dispatching a OnEnable callback +-- and enabling all modules of the addon (unless explicitly disabled).\\ +-- :Enable() also sets the internal `enableState` variable to true +-- @name //addon//:Enable +-- @paramsig +-- @usage +-- -- Enable MyModule +-- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon") +-- MyModule = MyAddon:GetModule("MyModule") +-- MyModule:Enable() +function Enable(self) + self:SetEnabledState(true) + + -- nevcairiel 2013-04-27: don't enable an addon/module if its queued for init still + -- it'll be enabled after the init process + if not queuedForInitialization(self) then + return AceAddon:EnableAddon(self) + end +end + +--- Disables the Addon, if possible, return true or false depending on success. +-- This internally calls AceAddon:DisableAddon(), thus dispatching a OnDisable callback +-- and disabling all modules of the addon.\\ +-- :Disable() also sets the internal `enableState` variable to false +-- @name //addon//:Disable +-- @paramsig +-- @usage +-- -- Disable MyAddon +-- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon") +-- MyAddon:Disable() +function Disable(self) + self:SetEnabledState(false) + return AceAddon:DisableAddon(self) +end + +--- Enables the Module, if possible, return true or false depending on success. +-- Short-hand function that retrieves the module via `:GetModule` and calls `:Enable` on the module object. +-- @name //addon//:EnableModule +-- @paramsig name +-- @usage +-- -- Enable MyModule using :GetModule +-- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon") +-- MyModule = MyAddon:GetModule("MyModule") +-- MyModule:Enable() +-- +-- -- Enable MyModule using the short-hand +-- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon") +-- MyAddon:EnableModule("MyModule") +function EnableModule(self, name) + local module = self:GetModule( name ) + return module:Enable() +end + +--- Disables the Module, if possible, return true or false depending on success. +-- Short-hand function that retrieves the module via `:GetModule` and calls `:Disable` on the module object. +-- @name //addon//:DisableModule +-- @paramsig name +-- @usage +-- -- Disable MyModule using :GetModule +-- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon") +-- MyModule = MyAddon:GetModule("MyModule") +-- MyModule:Disable() +-- +-- -- Disable MyModule using the short-hand +-- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon") +-- MyAddon:DisableModule("MyModule") +function DisableModule(self, name) + local module = self:GetModule( name ) + return module:Disable() +end + +--- Set the default libraries to be mixed into all modules created by this object. +-- Note that you can only change the default module libraries before any module is created. +-- @name //addon//:SetDefaultModuleLibraries +-- @paramsig lib[, lib, ...] +-- @param lib List of libraries to embed into the addon +-- @usage +-- -- Create the addon object +-- MyAddon = LibStub("AceAddon-3.0"):NewAddon("MyAddon") +-- -- Configure default libraries for modules (all modules need AceEvent-3.0) +-- MyAddon:SetDefaultModuleLibraries("AceEvent-3.0") +-- -- Create a module +-- MyModule = MyAddon:NewModule("MyModule") +function SetDefaultModuleLibraries(self, ...) + if next(self.modules) then + error("Usage: SetDefaultModuleLibraries(...): cannot change the module defaults after a module has been registered.", 2) + end + self.defaultModuleLibraries = {...} +end + +--- Set the default state in which new modules are being created. +-- Note that you can only change the default state before any module is created. +-- @name //addon//:SetDefaultModuleState +-- @paramsig state +-- @param state Default state for new modules, true for enabled, false for disabled +-- @usage +-- -- Create the addon object +-- MyAddon = LibStub("AceAddon-3.0"):NewAddon("MyAddon") +-- -- Set the default state to "disabled" +-- MyAddon:SetDefaultModuleState(false) +-- -- Create a module and explicilty enable it +-- MyModule = MyAddon:NewModule("MyModule") +-- MyModule:Enable() +function SetDefaultModuleState(self, state) + if next(self.modules) then + error("Usage: SetDefaultModuleState(state): cannot change the module defaults after a module has been registered.", 2) + end + self.defaultModuleState = state +end + +--- Set the default prototype to use for new modules on creation. +-- Note that you can only change the default prototype before any module is created. +-- @name //addon//:SetDefaultModulePrototype +-- @paramsig prototype +-- @param prototype Default prototype for the new modules (table) +-- @usage +-- -- Define a prototype +-- local prototype = { OnEnable = function(self) print("OnEnable called!") end } +-- -- Set the default prototype +-- MyAddon:SetDefaultModulePrototype(prototype) +-- -- Create a module and explicitly Enable it +-- MyModule = MyAddon:NewModule("MyModule") +-- MyModule:Enable() +-- -- should print "OnEnable called!" now +-- @see NewModule +function SetDefaultModulePrototype(self, prototype) + if next(self.modules) then + error("Usage: SetDefaultModulePrototype(prototype): cannot change the module defaults after a module has been registered.", 2) + end + if type(prototype) ~= "table" then + error(("Usage: SetDefaultModulePrototype(prototype): 'prototype' - table expected got '%s'."):format(type(prototype)), 2) + end + self.defaultModulePrototype = prototype +end + +--- Set the state of an addon or module +-- This should only be called before any enabling actually happend, e.g. in/before OnInitialize. +-- @name //addon//:SetEnabledState +-- @paramsig state +-- @param state the state of an addon or module (enabled=true, disabled=false) +function SetEnabledState(self, state) + self.enabledState = state +end + + +--- Return an iterator of all modules associated to the addon. +-- @name //addon//:IterateModules +-- @paramsig +-- @usage +-- -- Enable all modules +-- for name, module in MyAddon:IterateModules() do +-- module:Enable() +-- end +local function IterateModules(self) return pairs(self.modules) end + +-- Returns an iterator of all embeds in the addon +-- @name //addon//:IterateEmbeds +-- @paramsig +local function IterateEmbeds(self) return pairs(AceAddon.embeds[self]) end + +--- Query the enabledState of an addon. +-- @name //addon//:IsEnabled +-- @paramsig +-- @usage +-- if MyAddon:IsEnabled() then +-- MyAddon:Disable() +-- end +local function IsEnabled(self) return self.enabledState end +local mixins = { + NewModule = NewModule, + GetModule = GetModule, + Enable = Enable, + Disable = Disable, + EnableModule = EnableModule, + DisableModule = DisableModule, + IsEnabled = IsEnabled, + SetDefaultModuleLibraries = SetDefaultModuleLibraries, + SetDefaultModuleState = SetDefaultModuleState, + SetDefaultModulePrototype = SetDefaultModulePrototype, + SetEnabledState = SetEnabledState, + IterateModules = IterateModules, + IterateEmbeds = IterateEmbeds, + GetName = GetName, +} +local function IsModule(self) return false end +local pmixins = { + defaultModuleState = true, + enabledState = true, + IsModule = IsModule, +} +-- Embed( target ) +-- target (object) - target object to embed aceaddon in +-- +-- this is a local function specifically since it's meant to be only called internally +function Embed(target, skipPMixins) + for k, v in pairs(mixins) do + target[k] = v + end + if not skipPMixins then + for k, v in pairs(pmixins) do + target[k] = target[k] or v + end + end +end + + +-- - Initialize the addon after creation. +-- This function is only used internally during the ADDON_LOADED event +-- It will call the **OnInitialize** function on the addon object (if present), +-- and the **OnEmbedInitialize** function on all embeded libraries. +-- +-- **Note:** Do not call this function manually, unless you're absolutely sure that you know what you are doing. +-- @param addon addon object to intialize +function AceAddon:InitializeAddon(addon) + safecall(addon.OnInitialize, addon) + + local embeds = self.embeds[addon] + for i = 1, #embeds do + local lib = LibStub:GetLibrary(embeds[i], true) + if lib then safecall(lib.OnEmbedInitialize, lib, addon) end + end + + -- we don't call InitializeAddon on modules specifically, this is handled + -- from the event handler and only done _once_ +end + +-- - Enable the addon after creation. +-- Note: This function is only used internally during the PLAYER_LOGIN event, or during ADDON_LOADED, +-- if IsLoggedIn() already returns true at that point, e.g. for LoD Addons. +-- It will call the **OnEnable** function on the addon object (if present), +-- and the **OnEmbedEnable** function on all embeded libraries.\\ +-- This function does not toggle the enable state of the addon itself, and will return early if the addon is disabled. +-- +-- **Note:** Do not call this function manually, unless you're absolutely sure that you know what you are doing. +-- Use :Enable on the addon itself instead. +-- @param addon addon object to enable +function AceAddon:EnableAddon(addon) + if type(addon) == "string" then addon = AceAddon:GetAddon(addon) end + if self.statuses[addon.name] or not addon.enabledState then return false end + + -- set the statuses first, before calling the OnEnable. this allows for Disabling of the addon in OnEnable. + self.statuses[addon.name] = true + + safecall(addon.OnEnable, addon) + + -- make sure we're still enabled before continueing + if self.statuses[addon.name] then + local embeds = self.embeds[addon] + for i = 1, #embeds do + local lib = LibStub:GetLibrary(embeds[i], true) + if lib then safecall(lib.OnEmbedEnable, lib, addon) end + end + + -- enable possible modules. + local modules = addon.orderedModules + for i = 1, #modules do + self:EnableAddon(modules[i]) + end + end + return self.statuses[addon.name] -- return true if we're disabled +end + +-- - Disable the addon +-- Note: This function is only used internally. +-- It will call the **OnDisable** function on the addon object (if present), +-- and the **OnEmbedDisable** function on all embeded libraries.\\ +-- This function does not toggle the enable state of the addon itself, and will return early if the addon is still enabled. +-- +-- **Note:** Do not call this function manually, unless you're absolutely sure that you know what you are doing. +-- Use :Disable on the addon itself instead. +-- @param addon addon object to enable +function AceAddon:DisableAddon(addon) + if type(addon) == "string" then addon = AceAddon:GetAddon(addon) end + if not self.statuses[addon.name] then return false end + + -- set statuses first before calling OnDisable, this allows for aborting the disable in OnDisable. + self.statuses[addon.name] = false + + safecall( addon.OnDisable, addon ) + + -- make sure we're still disabling... + if not self.statuses[addon.name] then + local embeds = self.embeds[addon] + for i = 1, #embeds do + local lib = LibStub:GetLibrary(embeds[i], true) + if lib then safecall(lib.OnEmbedDisable, lib, addon) end + end + -- disable possible modules. + local modules = addon.orderedModules + for i = 1, #modules do + self:DisableAddon(modules[i]) + end + end + + return not self.statuses[addon.name] -- return true if we're disabled +end + +--- Get an iterator over all registered addons. +-- @usage +-- -- Print a list of all installed AceAddon's +-- for name, addon in AceAddon:IterateAddons() do +-- print("Addon: " .. name) +-- end +function AceAddon:IterateAddons() return pairs(self.addons) end + +--- Get an iterator over the internal status registry. +-- @usage +-- -- Print a list of all enabled addons +-- for name, status in AceAddon:IterateAddonStatus() do +-- if status then +-- print("EnabledAddon: " .. name) +-- end +-- end +function AceAddon:IterateAddonStatus() return pairs(self.statuses) end + +-- Following Iterators are deprecated, and their addon specific versions should be used +-- e.g. addon:IterateEmbeds() instead of :IterateEmbedsOnAddon(addon) +function AceAddon:IterateEmbedsOnAddon(addon) return pairs(self.embeds[addon]) end +function AceAddon:IterateModulesOfAddon(addon) return pairs(addon.modules) end + +-- Event Handling +local function onEvent(this, event, arg1) + -- 2011-08-17 nevcairiel - ignore the load event of Blizzard_DebugTools, so a potential startup error isn't swallowed up + if (event == "ADDON_LOADED" and arg1 ~= "Blizzard_DebugTools") or event == "PLAYER_LOGIN" then + -- if a addon loads another addon, recursion could happen here, so we need to validate the table on every iteration + while(#AceAddon.initializequeue > 0) do + local addon = tremove(AceAddon.initializequeue, 1) + -- this might be an issue with recursion - TODO: validate + if event == "ADDON_LOADED" then addon.baseName = arg1 end + AceAddon:InitializeAddon(addon) + tinsert(AceAddon.enablequeue, addon) + end + + if IsLoggedIn() then + while(#AceAddon.enablequeue > 0) do + local addon = tremove(AceAddon.enablequeue, 1) + AceAddon:EnableAddon(addon) + end + end + end +end + +AceAddon.frame:RegisterEvent("ADDON_LOADED") +AceAddon.frame:RegisterEvent("PLAYER_LOGIN") +AceAddon.frame:SetScript("OnEvent", onEvent) + +-- upgrade embeded +for name, addon in pairs(AceAddon.addons) do + Embed(addon, true) +end + +-- 2010-10-27 nevcairiel - add new "orderedModules" table +if oldminor and oldminor < 10 then + for name, addon in pairs(AceAddon.addons) do + addon.orderedModules = {} + for module_name, module in pairs(addon.modules) do + tinsert(addon.orderedModules, module) + end + end +end diff --git a/libs/AceAddon-3.0/AceAddon-3.0.xml b/libs/AceAddon-3.0/AceAddon-3.0.xml new file mode 100644 index 0000000..e6ad639 --- /dev/null +++ b/libs/AceAddon-3.0/AceAddon-3.0.xml @@ -0,0 +1,4 @@ +<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/ +..\FrameXML\UI.xsd"> + <Script file="AceAddon-3.0.lua"/> +</Ui> \ No newline at end of file diff --git a/libs/AceConsole-3.0/AceConsole-3.0.lua b/libs/AceConsole-3.0/AceConsole-3.0.lua new file mode 100644 index 0000000..0567a65 --- /dev/null +++ b/libs/AceConsole-3.0/AceConsole-3.0.lua @@ -0,0 +1,250 @@ +--- **AceConsole-3.0** provides registration facilities for slash commands. +-- You can register slash commands to your custom functions and use the `GetArgs` function to parse them +-- to your addons individual needs. +-- +-- **AceConsole-3.0** can be embeded into your addon, either explicitly by calling AceConsole:Embed(MyAddon) or by +-- specifying it as an embeded library in your AceAddon. All functions will be available on your addon object +-- and can be accessed directly, without having to explicitly call AceConsole itself.\\ +-- It is recommended to embed AceConsole, otherwise you'll have to specify a custom `self` on all calls you +-- make into AceConsole. +-- @class file +-- @name AceConsole-3.0 +-- @release $Id: AceConsole-3.0.lua 1143 2016-07-11 08:52:03Z nevcairiel $ +local MAJOR,MINOR = "AceConsole-3.0", 7 + +local AceConsole, oldminor = LibStub:NewLibrary(MAJOR, MINOR) + +if not AceConsole then return end -- No upgrade needed + +AceConsole.embeds = AceConsole.embeds or {} -- table containing objects AceConsole is embedded in. +AceConsole.commands = AceConsole.commands or {} -- table containing commands registered +AceConsole.weakcommands = AceConsole.weakcommands or {} -- table containing self, command => func references for weak commands that don't persist through enable/disable + +-- Lua APIs +local tconcat, tostring, select = table.concat, tostring, select +local type, pairs, error = type, pairs, error +local format, strfind, strsub = string.format, string.find, string.sub +local max = math.max + +-- WoW APIs +local _G = _G + +-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded +-- List them here for Mikk's FindGlobals script +-- GLOBALS: DEFAULT_CHAT_FRAME, SlashCmdList, hash_SlashCmdList + +local tmp={} +local function Print(self,frame,...) + local n=0 + if self ~= AceConsole then + n=n+1 + tmp[n] = "|cff33ff99"..tostring( self ).."|r:" + end + for i=1, select("#", ...) do + n=n+1 + tmp[n] = tostring(select(i, ...)) + end + frame:AddMessage( tconcat(tmp," ",1,n) ) +end + +--- Print to DEFAULT_CHAT_FRAME or given ChatFrame (anything with an .AddMessage function) +-- @paramsig [chatframe ,] ... +-- @param chatframe Custom ChatFrame to print to (or any frame with an .AddMessage function) +-- @param ... List of any values to be printed +function AceConsole:Print(...) + local frame = ... + if type(frame) == "table" and frame.AddMessage then -- Is first argument something with an .AddMessage member? + return Print(self, frame, select(2,...)) + else + return Print(self, DEFAULT_CHAT_FRAME, ...) + end +end + + +--- Formatted (using format()) print to DEFAULT_CHAT_FRAME or given ChatFrame (anything with an .AddMessage function) +-- @paramsig [chatframe ,] "format"[, ...] +-- @param chatframe Custom ChatFrame to print to (or any frame with an .AddMessage function) +-- @param format Format string - same syntax as standard Lua format() +-- @param ... Arguments to the format string +function AceConsole:Printf(...) + local frame = ... + if type(frame) == "table" and frame.AddMessage then -- Is first argument something with an .AddMessage member? + return Print(self, frame, format(select(2,...))) + else + return Print(self, DEFAULT_CHAT_FRAME, format(...)) + end +end + + + + +--- Register a simple chat command +-- @param command Chat command to be registered WITHOUT leading "/" +-- @param func Function to call when the slash command is being used (funcref or methodname) +-- @param persist if false, the command will be soft disabled/enabled when aceconsole is used as a mixin (default: true) +function AceConsole:RegisterChatCommand( command, func, persist ) + if type(command)~="string" then error([[Usage: AceConsole:RegisterChatCommand( "command", func[, persist ]): 'command' - expected a string]], 2) end + + if persist==nil then persist=true end -- I'd rather have my addon's "/addon enable" around if the author screws up. Having some extra slash regged when it shouldnt be isn't as destructive. True is a better default. /Mikk + + local name = "ACECONSOLE_"..command:upper() + + if type( func ) == "string" then + SlashCmdList[name] = function(input, editBox) + self[func](self, input, editBox) + end + else + SlashCmdList[name] = func + end + _G["SLASH_"..name.."1"] = "/"..command:lower() + AceConsole.commands[command] = name + -- non-persisting commands are registered for enabling disabling + if not persist then + if not AceConsole.weakcommands[self] then AceConsole.weakcommands[self] = {} end + AceConsole.weakcommands[self][command] = func + end + return true +end + +--- Unregister a chatcommand +-- @param command Chat command to be unregistered WITHOUT leading "/" +function AceConsole:UnregisterChatCommand( command ) + local name = AceConsole.commands[command] + if name then + SlashCmdList[name] = nil + _G["SLASH_" .. name .. "1"] = nil + hash_SlashCmdList["/" .. command:upper()] = nil + AceConsole.commands[command] = nil + end +end + +--- Get an iterator over all Chat Commands registered with AceConsole +-- @return Iterator (pairs) over all commands +function AceConsole:IterateChatCommands() return pairs(AceConsole.commands) end + + +local function nils(n, ...) + if n>1 then + return nil, nils(n-1, ...) + elseif n==1 then + return nil, ... + else + return ... + end +end + + +--- Retreive one or more space-separated arguments from a string. +-- Treats quoted strings and itemlinks as non-spaced. +-- @param str The raw argument string +-- @param numargs How many arguments to get (default 1) +-- @param startpos Where in the string to start scanning (default 1) +-- @return Returns arg1, arg2, ..., nextposition\\ +-- Missing arguments will be returned as nils. 'nextposition' is returned as 1e9 at the end of the string. +function AceConsole:GetArgs(str, numargs, startpos) + numargs = numargs or 1 + startpos = max(startpos or 1, 1) + + local pos=startpos + + -- find start of new arg + pos = strfind(str, "[^ ]", pos) + if not pos then -- whoops, end of string + return nils(numargs, 1e9) + end + + if numargs<1 then + return pos + end + + -- quoted or space separated? find out which pattern to use + local delim_or_pipe + local ch = strsub(str, pos, pos) + if ch=='"' then + pos = pos + 1 + delim_or_pipe='([|"])' + elseif ch=="'" then + pos = pos + 1 + delim_or_pipe="([|'])" + else + delim_or_pipe="([| ])" + end + + startpos = pos + + while true do + -- find delimiter or hyperlink + local ch,_ + pos,_,ch = strfind(str, delim_or_pipe, pos) + + if not pos then break end + + if ch=="|" then + -- some kind of escape + + if strsub(str,pos,pos+1)=="|H" then + -- It's a |H....|hhyper link!|h + pos=strfind(str, "|h", pos+2) -- first |h + if not pos then break end + + pos=strfind(str, "|h", pos+2) -- second |h + if not pos then break end + elseif strsub(str,pos, pos+1) == "|T" then + -- It's a |T....|t texture + pos=strfind(str, "|t", pos+2) + if not pos then break end + end + + pos=pos+2 -- skip past this escape (last |h if it was a hyperlink) + + else + -- found delimiter, done with this arg + return strsub(str, startpos, pos-1), AceConsole:GetArgs(str, numargs-1, pos+1) + end + + end + + -- search aborted, we hit end of string. return it all as one argument. (yes, even if it's an unterminated quote or hyperlink) + return strsub(str, startpos), nils(numargs-1, 1e9) +end + + +--- embedding and embed handling + +local mixins = { + "Print", + "Printf", + "RegisterChatCommand", + "UnregisterChatCommand", + "GetArgs", +} + +-- Embeds AceConsole into the target object making the functions from the mixins list available on target:.. +-- @param target target object to embed AceBucket in +function AceConsole:Embed( target ) + for k, v in pairs( mixins ) do + target[v] = self[v] + end + self.embeds[target] = true + return target +end + +function AceConsole:OnEmbedEnable( target ) + if AceConsole.weakcommands[target] then + for command, func in pairs( AceConsole.weakcommands[target] ) do + target:RegisterChatCommand( command, func, false, true ) -- nonpersisting and silent registry + end + end +end + +function AceConsole:OnEmbedDisable( target ) + if AceConsole.weakcommands[target] then + for command, func in pairs( AceConsole.weakcommands[target] ) do + target:UnregisterChatCommand( command ) -- TODO: this could potentially unregister a command from another application in case of command conflicts. Do we care? + end + end +end + +for addon in pairs(AceConsole.embeds) do + AceConsole:Embed(addon) +end diff --git a/libs/AceConsole-3.0/AceConsole-3.0.xml b/libs/AceConsole-3.0/AceConsole-3.0.xml new file mode 100644 index 0000000..be9f47c --- /dev/null +++ b/libs/AceConsole-3.0/AceConsole-3.0.xml @@ -0,0 +1,4 @@ +<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/ +..\FrameXML\UI.xsd"> + <Script file="AceConsole-3.0.lua"/> +</Ui> \ No newline at end of file diff --git a/libs/AceEvent-3.0/AceEvent-3.0.lua b/libs/AceEvent-3.0/AceEvent-3.0.lua new file mode 100644 index 0000000..578ae25 --- /dev/null +++ b/libs/AceEvent-3.0/AceEvent-3.0.lua @@ -0,0 +1,126 @@ +--- AceEvent-3.0 provides event registration and secure dispatching. +-- All dispatching is done using **CallbackHandler-1.0**. AceEvent is a simple wrapper around +-- CallbackHandler, and dispatches all game events or addon message to the registrees. +-- +-- **AceEvent-3.0** can be embeded into your addon, either explicitly by calling AceEvent:Embed(MyAddon) or by +-- specifying it as an embeded library in your AceAddon. All functions will be available on your addon object +-- and can be accessed directly, without having to explicitly call AceEvent itself.\\ +-- It is recommended to embed AceEvent, otherwise you'll have to specify a custom `self` on all calls you +-- make into AceEvent. +-- @class file +-- @name AceEvent-3.0 +-- @release $Id: AceEvent-3.0.lua 975 2010-10-23 11:26:18Z nevcairiel $ +local MAJOR, MINOR = "AceEvent-3.0", 3 +local AceEvent = LibStub:NewLibrary(MAJOR, MINOR) + +if not AceEvent then return end + +-- Lua APIs +local pairs = pairs + +local CallbackHandler = LibStub:GetLibrary("CallbackHandler-1.0") + +AceEvent.frame = AceEvent.frame or CreateFrame("Frame", "AceEvent30Frame") -- our event frame +AceEvent.embeds = AceEvent.embeds or {} -- what objects embed this lib + +-- APIs and registry for blizzard events, using CallbackHandler lib +if not AceEvent.events then + AceEvent.events = CallbackHandler:New(AceEvent, + "RegisterEvent", "UnregisterEvent", "UnregisterAllEvents") +end + +function AceEvent.events:OnUsed(target, eventname) + AceEvent.frame:RegisterEvent(eventname) +end + +function AceEvent.events:OnUnused(target, eventname) + AceEvent.frame:UnregisterEvent(eventname) +end + + +-- APIs and registry for IPC messages, using CallbackHandler lib +if not AceEvent.messages then + AceEvent.messages = CallbackHandler:New(AceEvent, + "RegisterMessage", "UnregisterMessage", "UnregisterAllMessages" + ) + AceEvent.SendMessage = AceEvent.messages.Fire +end + +--- embedding and embed handling +local mixins = { + "RegisterEvent", "UnregisterEvent", + "RegisterMessage", "UnregisterMessage", + "SendMessage", + "UnregisterAllEvents", "UnregisterAllMessages", +} + +--- Register for a Blizzard Event. +-- The callback will be called with the optional `arg` as the first argument (if supplied), and the event name as the second (or first, if no arg was supplied) +-- Any arguments to the event will be passed on after that. +-- @name AceEvent:RegisterEvent +-- @class function +-- @paramsig event[, callback [, arg]] +-- @param event The event to register for +-- @param callback The callback function to call when the event is triggered (funcref or method, defaults to a method with the event name) +-- @param arg An optional argument to pass to the callback function + +--- Unregister an event. +-- @name AceEvent:UnregisterEvent +-- @class function +-- @paramsig event +-- @param event The event to unregister + +--- Register for a custom AceEvent-internal message. +-- The callback will be called with the optional `arg` as the first argument (if supplied), and the event name as the second (or first, if no arg was supplied) +-- Any arguments to the event will be passed on after that. +-- @name AceEvent:RegisterMessage +-- @class function +-- @paramsig message[, callback [, arg]] +-- @param message The message to register for +-- @param callback The callback function to call when the message is triggered (funcref or method, defaults to a method with the event name) +-- @param arg An optional argument to pass to the callback function + +--- Unregister a message +-- @name AceEvent:UnregisterMessage +-- @class function +-- @paramsig message +-- @param message The message to unregister + +--- Send a message over the AceEvent-3.0 internal message system to other addons registered for this message. +-- @name AceEvent:SendMessage +-- @class function +-- @paramsig message, ... +-- @param message The message to send +-- @param ... Any arguments to the message + + +-- Embeds AceEvent into the target object making the functions from the mixins list available on target:.. +-- @param target target object to embed AceEvent in +function AceEvent:Embed(target) + for k, v in pairs(mixins) do + target[v] = self[v] + end + self.embeds[target] = true + return target +end + +-- AceEvent:OnEmbedDisable( target ) +-- target (object) - target object that is being disabled +-- +-- Unregister all events messages etc when the target disables. +-- this method should be called by the target manually or by an addon framework +function AceEvent:OnEmbedDisable(target) + target:UnregisterAllEvents() + target:UnregisterAllMessages() +end + +-- Script to fire blizzard events into the event listeners +local events = AceEvent.events +AceEvent.frame:SetScript("OnEvent", function(this, event, ...) + events:Fire(event, ...) +end) + +--- Finally: upgrade our old embeds +for target, v in pairs(AceEvent.embeds) do + AceEvent:Embed(target) +end diff --git a/libs/AceEvent-3.0/AceEvent-3.0.xml b/libs/AceEvent-3.0/AceEvent-3.0.xml new file mode 100644 index 0000000..313ef4d --- /dev/null +++ b/libs/AceEvent-3.0/AceEvent-3.0.xml @@ -0,0 +1,4 @@ +<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/ +..\FrameXML\UI.xsd"> + <Script file="AceEvent-3.0.lua"/> +</Ui> \ No newline at end of file diff --git a/locale/enUS.lua b/locale/enUS.lua index ff50251..b057a88 100644 --- a/locale/enUS.lua +++ b/locale/enUS.lua @@ -45,6 +45,7 @@ L["Remove ItemID"] = true L["[itemname]"] = true L["search"] = true L["gold"] = true +L["config"] = true L["tokens"] = true L["fixdb"] = true L["profiles"] = true @@ -79,7 +80,7 @@ L["BagSync [Total] tooltip color."] = true L["BagSync [Guild] tooltip color."] = true L["BagSync [Cross-Realms] tooltip color."] = true L["BagSync [Battle.Net] tooltip color."] = true -L["Settings for various BagSync features"] = true +L["Settings for various BagSync features."] = true L["Display"] = true L["Settings for the displayed BagSync tooltip information."] = true L["Color"] = true @@ -87,3 +88,4 @@ L["Color settings for BagSync tooltip information."] = true L["Main"] = true L["Main settings for BagSync."] = true L["WARNING: A total of [%d] items were not searched!\nBagSync is still waiting for the server/cache to respond.\nPress the Search button again to retry."] = true +L["You have been updated to latest database version! You will need to rescan all your characters again!|r"] = true diff --git a/modules/test.lua b/modules/test.lua index 3d0217e..da12e03 100644 --- a/modules/test.lua +++ b/modules/test.lua @@ -207,7 +207,7 @@ frame:AddChild(OKbutton) --lets create the warning frame. -local warning = AceGUI:Create("Frame") +--local warning = AceGUI:Create("Frame") --f.statusbg:Hide() --f:SetWidth(400) f:SetHeight(320)