initial commit, update of grennon mail (postal), speedup for opening all mail and fixed the unread mail minimap icon issue
This commit is contained in:
+961
@@ -0,0 +1,961 @@
|
||||
Postal = AceLibrary("AceAddon-2.0"):new("AceEvent-2.0", "AceHook-2.0")
|
||||
|
||||
function Postal:OnInitialize()
|
||||
tinsert(UISpecialFrames, "PostalInboxOpenAll")
|
||||
|
||||
-- Allows the mail frame to be pushed
|
||||
if UIPanelWindows["MailFrame"] then
|
||||
UIPanelWindows["MailFrame"].pushable = 1
|
||||
else
|
||||
UIPanelWindows["MailFrame"] = { area = "left", pushable = 1 }
|
||||
end
|
||||
|
||||
-- Close FriendsFrame will close if you try to open a mail with mailframe+friendsframe open
|
||||
if UIPanelWindows["FriendsFrame"] then
|
||||
UIPanelWindows["FriendsFrame"].pushable = 2
|
||||
else
|
||||
UIPanelWindows["FriendsFrame"] = { area = "left", pushable = 2 }
|
||||
end
|
||||
|
||||
MailItem1:SetPoint("TOPLEFT", "InboxFrame", "TOPLEFT", 48, -80)
|
||||
for i = 1, 7 do
|
||||
getglobal("MailItem" .. i .. "ExpireTime"):SetPoint("TOPRIGHT", "MailItem" .. i, "TOPRIGHT", 10, -4)
|
||||
getglobal("MailItem" .. i):SetWidth(280)
|
||||
end
|
||||
|
||||
POSTAL_NUMITEMBUTTONS = 21
|
||||
Postal_BagLinks = {}
|
||||
Postal_ScheduledStack = {}
|
||||
Postal_SelectedItems = {}
|
||||
Postal_PICKDELAY = 0.2
|
||||
Postal_DELETEDELAY = 0.2
|
||||
Postal_DELETEEVENTDELAY = 0.2
|
||||
|
||||
PostalFrame.num = 0
|
||||
PanelTemplates_SetNumTabs(MailFrame, 3)
|
||||
|
||||
PostalForwardFrame.pickItem = {}
|
||||
PostalForwardFrame.process = 0
|
||||
|
||||
PostalGlobalFrame.queue = {}
|
||||
PostalGlobalFrame.update = 0
|
||||
PostalGlobalFrame.total = 0
|
||||
PostalGlobalFrame.sendmail = 0
|
||||
PostalGlobalFrame.latency = 2.25
|
||||
|
||||
PostalTooltip:SetOwner(WorldFrame, "ANCHOR_NONE")
|
||||
|
||||
PostalInboxFrame.eventFunc = {}
|
||||
end
|
||||
|
||||
function Postal:OnEnable()
|
||||
self:RegisterEvent("MAIL_INBOX_UPDATE")
|
||||
self:RegisterEvent("UI_ERROR_MESSAGE")
|
||||
self:RegisterEvent("MAIL_SEND_SUCCESS")
|
||||
self:RegisterEvent("MAIL_SEND_INFO_UPDATE")
|
||||
self:RegisterEvent("MAIL_CLOSED")
|
||||
self:RegisterEvent("BAG_UPDATE")
|
||||
|
||||
self:Hook("ContainerFrameItemButton_OnClick")
|
||||
self:Hook("PickupContainerItem")
|
||||
self:Hook("ContainerFrame_Update")
|
||||
self:Hook("ClickSendMailItemButton")
|
||||
self:HookScript(TradeFrame, "OnShow", "TF_Show")
|
||||
self:Hook("InboxFrameItem_OnEnter")
|
||||
self:Hook("MailFrameTab_OnClick")
|
||||
self:Hook("InboxFrame_OnClick")
|
||||
self:Hook("InboxFrame_Update")
|
||||
self:Hook("CloseMail")
|
||||
self:Hook("TakeInboxItem")
|
||||
self:Hook("OpenMail_Reply")
|
||||
oldTakeInboxMoney = OpenMailMoneyButton:GetScript("OnClick")
|
||||
end
|
||||
|
||||
function Postal:MAIL_CLOSED()
|
||||
Postal:ClearItems()
|
||||
PostalGlobalFrame.total = 0
|
||||
PostalGlobalFrame.queue = {}
|
||||
-- Hides the minimap unread mail button if there are no unread mail on closing the mailbox.
|
||||
-- Does not scan past the first 50 items since only the first 50 are viewable.
|
||||
for i = 1, GetInboxNumItems() do
|
||||
_, _, _, _, _, _, _, _, wasRead = GetInboxHeaderInfo(i)
|
||||
if not wasRead then
|
||||
return
|
||||
end
|
||||
end
|
||||
MiniMapMailFrame:Hide()
|
||||
end
|
||||
|
||||
function Postal:MAIL_SEND_SUCCESS()
|
||||
POSTAL_CANSENDNEXT = 1
|
||||
end
|
||||
|
||||
function Postal:ContainerFrameItemButton_OnClick(btn, ignore)
|
||||
if self:GetItemFrame(this:GetParent():GetID(), this:GetID()) then
|
||||
return
|
||||
end
|
||||
self.hooks["ContainerFrameItemButton_OnClick"].orig(btn, ignore)
|
||||
self:UpdateItemButtons()
|
||||
end
|
||||
|
||||
function Postal:PickupContainerItem(bag, item, special)
|
||||
if (self:GetItemFrame(bag, item) or (Postal_addItem and Postal_addItem[1] == bag and Postal_addItem[2] == item)) and not special then
|
||||
return
|
||||
end
|
||||
if not CursorHasItem() then
|
||||
PostalFrame.bag = bag
|
||||
PostalFrame.item = item
|
||||
end
|
||||
if IsAltKeyDown() and PostalFrame:IsVisible() and not CursorHasItem() then
|
||||
local i
|
||||
for i = 1, POSTAL_NUMITEMBUTTONS do
|
||||
if not getglobal("PostalButton" .. i).item then
|
||||
|
||||
if self:ItemIsMailable(bag, item) then
|
||||
Postal:Print("Postal: Cannot attach item.", 1, 0.5, 0)
|
||||
return
|
||||
end
|
||||
|
||||
self.hooks["PickupContainerItem"].orig(bag, item)
|
||||
self:MailButton_OnClick(getglobal("PostalButton" .. i))
|
||||
self:UpdateItemButtons()
|
||||
return
|
||||
end
|
||||
end
|
||||
elseif IsAltKeyDown() and SendMailFrame:IsVisible() and not CursorHasItem() then
|
||||
self.hooks["PickupContainerItem"].orig(bag, item)
|
||||
ClickSendMailItemButton()
|
||||
return
|
||||
elseif IsAltKeyDown() and TradeFrame:IsVisible() and not CursorHasItem() then
|
||||
for i = 1, 6 do
|
||||
if not GetTradePlayerItemLink(i) then
|
||||
self.hooks["PickupContainerItem"].orig(bag, item)
|
||||
ClickTradeButton(i)
|
||||
return
|
||||
end
|
||||
end
|
||||
elseif IsAltKeyDown() and not CursorHasItem() and (not TradeFrame or not TradeFrame:IsVisible()) and (not AuctionFrame or not AuctionFrame:IsVisible()) and UnitExists("target") and CheckInteractDistance("target", 2) and UnitIsFriend("player", "target") and UnitIsPlayer("target") then
|
||||
InitiateTrade("target")
|
||||
Postal_addItem = { bag, item, UnitName("target"), 2 }
|
||||
for i = 1, NUM_CONTAINER_FRAMES do
|
||||
if getglobal("ContainerFrame" .. i):IsVisible() then
|
||||
ContainerFrame_Update(getglobal("ContainerFrame" .. i))
|
||||
end
|
||||
end
|
||||
return
|
||||
end
|
||||
self.hooks["PickupContainerItem"].orig(bag, item)
|
||||
self:UpdateItemButtons()
|
||||
end
|
||||
|
||||
function Postal:MailFrameTab_OnClick(tab)
|
||||
if not tab then
|
||||
tab = this:GetID()
|
||||
end
|
||||
|
||||
if tab == 3 then
|
||||
PanelTemplates_SetTab(MailFrame, 3)
|
||||
InboxFrame:Hide()
|
||||
SendMailFrame:Hide()
|
||||
PostalFrame:Show()
|
||||
SendMailFrame.sendMode = "massmail"
|
||||
MailFrameTopLeft:SetTexture("Interface\\ClassTrainerFrame\\UI-ClassTrainer-TopLeft")
|
||||
MailFrameTopRight:SetTexture("Interface\\ClassTrainerFrame\\UI-ClassTrainer-TopRight")
|
||||
MailFrameBotLeft:SetTexture("Interface\\ClassTrainerFrame\\UI-ClassTrainer-BotLeft")
|
||||
MailFrameBotRight:SetTexture("Interface\\ClassTrainerFrame\\UI-ClassTrainer-BotRight")
|
||||
MailFrameTopLeft:SetPoint("TOPLEFT", "MailFrame", "TOPLEFT", 2, -1)
|
||||
return
|
||||
else
|
||||
PostalFrame:Hide()
|
||||
end
|
||||
self.hooks["MailFrameTab_OnClick"].orig(tab)
|
||||
self:Forward_EnableForward()
|
||||
end
|
||||
|
||||
function Postal:ClickSendMailItemButton()
|
||||
if not GetSendMailItem() then
|
||||
PostalFrame.mailbag = PostalFrame.bag
|
||||
PostalFrame.mailitem = PostalFrame.item
|
||||
end
|
||||
self.hooks["ClickSendMailItemButton"].orig()
|
||||
end
|
||||
|
||||
-- Handle the dragging of items
|
||||
function Postal:MailButton_OnClick(button)
|
||||
if not button then button = this end
|
||||
if CursorHasItem() then
|
||||
local bag = PostalFrame.bag
|
||||
local item = PostalFrame.item
|
||||
if not bag or not item then return end
|
||||
if self:ItemIsMailable(bag, item) then
|
||||
Postal:Print("Postal: Cannot attach item.", 1, 0.5, 0)
|
||||
self.hooks["PickupContainerItem"].orig(bag, item)
|
||||
return
|
||||
end
|
||||
self.hooks["PickupContainerItem"].orig(bag, item)
|
||||
if this.bag and this.item then
|
||||
-- There's already an item there
|
||||
-- Pickup that item to replicate Send Mail's behaviour
|
||||
self.hooks["PickupContainerItem"].orig(button.bag, button.item)
|
||||
PostalFrame.bag = button.bag
|
||||
PostalFrame.item = button.item
|
||||
else
|
||||
PostalFrame.bag = nil
|
||||
PostalFrame.item = nil
|
||||
end
|
||||
local texture, count = GetContainerItemInfo(bag, item)
|
||||
getglobal(button:GetName() .. "IconTexture"):Show()
|
||||
getglobal(button:GetName() .. "IconTexture"):SetTexture(texture)
|
||||
if count > 1 then
|
||||
getglobal(button:GetName() .. "Count"):SetText(count)
|
||||
getglobal(button:GetName() .. "Count"):Show()
|
||||
else
|
||||
getglobal(button:GetName() .. "Count"):Hide()
|
||||
end
|
||||
button.bag = bag
|
||||
button.item = item
|
||||
button.texture = texture
|
||||
button.count = count
|
||||
elseif button.item and button.bag then
|
||||
self.hooks["PickupContainerItem"].orig(button.bag, button.item)
|
||||
getglobal(button:GetName() .. "IconTexture"):Hide()
|
||||
getglobal(button:GetName() .. "Count"):Hide()
|
||||
PostalFrame.bag = button.bag
|
||||
PostalFrame.item = button.item
|
||||
button.item = nil
|
||||
button.bag = nil
|
||||
button.count = nil
|
||||
button.texture = nil
|
||||
end
|
||||
local num = self:GetNumMails()
|
||||
PostalFrame.num = num
|
||||
self:CanSend(PostalNameEditBox)
|
||||
if num == 0 then num = 1 end
|
||||
MoneyFrame_Update("PostalCostMoneyFrame", GetSendMailPrice()*num)
|
||||
for i = 1, NUM_CONTAINER_FRAMES do
|
||||
if getglobal("ContainerFrame" .. i):IsVisible() then
|
||||
ContainerFrame_Update(getglobal("ContainerFrame" .. i))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function Postal:ItemIsMailable(bag, item)
|
||||
-- Make sure tooltip is cleared
|
||||
for i = 1, 29 do
|
||||
getglobal("PostalTooltipTextLeft" .. i):SetText("")
|
||||
end
|
||||
|
||||
PostalTooltip:SetBagItem(bag, item)
|
||||
for i = 1, PostalTooltip:NumLines() do
|
||||
local text = getglobal("PostalTooltipTextLeft" .. i):GetText()
|
||||
if text == ITEM_SOULBOUND or text == ITEM_BIND_QUEST or text == ITEM_CONJURED or text == ITEM_BIND_ON_PICKUP then
|
||||
return 1
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
|
||||
function Postal:UpdateItemButtons(frame)
|
||||
local i
|
||||
for i = 1, POSTAL_NUMITEMBUTTONS do
|
||||
local btn = getglobal("PostalButton" .. i)
|
||||
if not frame or btn ~= frame then
|
||||
local texture, count
|
||||
if btn.item and btn.bag then
|
||||
texture, count = GetContainerItemInfo(btn.bag, btn.item)
|
||||
end
|
||||
if not texture then
|
||||
getglobal(btn:GetName() .. "IconTexture"):Hide()
|
||||
getglobal(btn:GetName() .. "Count"):Hide()
|
||||
btn.item = nil
|
||||
btn.bag = nil
|
||||
btn.count = nil
|
||||
btn.texture = nil
|
||||
else
|
||||
btn.count = count
|
||||
btn.texture = texture
|
||||
getglobal(btn:GetName() .. "IconTexture"):Show()
|
||||
getglobal(btn:GetName() .. "IconTexture"):SetTexture(texture)
|
||||
if count > 1 then
|
||||
getglobal(btn:GetName() .. "Count"):Show()
|
||||
getglobal(btn:GetName() .. "Count"):SetText(count)
|
||||
else
|
||||
getglobal(btn:GetName() .. "Count"):Hide()
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function Postal:GetItemFrame(bag, item)
|
||||
local i
|
||||
for i = 1, POSTAL_NUMITEMBUTTONS do
|
||||
local btn = getglobal("PostalButton" .. i)
|
||||
if btn.item == item and btn.bag == bag then
|
||||
return btn
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
function Postal:GetNumMails()
|
||||
local i
|
||||
local num = 0
|
||||
for i = 1, POSTAL_NUMITEMBUTTONS do
|
||||
local btn = getglobal("PostalButton" .. i)
|
||||
if btn.item and btn.bag then
|
||||
num = num + 1
|
||||
end
|
||||
end
|
||||
return num
|
||||
end
|
||||
|
||||
function Postal:ClearItems()
|
||||
local i
|
||||
local num = 0
|
||||
for i = 1, POSTAL_NUMITEMBUTTONS do
|
||||
local btn = getglobal("PostalButton" .. i)
|
||||
btn.item = nil
|
||||
btn.count = nil
|
||||
btn.bag = nil
|
||||
btn.texture = nil
|
||||
end
|
||||
self:UpdateItemButtons()
|
||||
PostalMailButton:Disable()
|
||||
PostalNameEditBox:SetText("")
|
||||
PostalSubjectEditBox:SetText("")
|
||||
PostalStatusText:SetText("")
|
||||
PostalAbortButton:Hide()
|
||||
PostalAcceptSendFrame:Hide()
|
||||
end
|
||||
|
||||
function Postal:CanSend(eb)
|
||||
if not eb then eb = this end
|
||||
if strlen(eb:GetText()) > 0 and PostalFrame.num > 0 and GetSendMailPrice()*PostalFrame.num <= GetMoney() then
|
||||
PostalMailButton:Enable()
|
||||
else
|
||||
PostalMailButton:Disable()
|
||||
end
|
||||
end
|
||||
|
||||
function Postal:SendMail()
|
||||
for key, val in this.queue do
|
||||
PostalStatusText:SetText(format(POSTAL_SENDING, key, this.total))
|
||||
PostalAbortButton:Show()
|
||||
|
||||
if GetSendMailItem() and PostalFrame.mailbag and PostalFrame.mailitem then
|
||||
-- There's already an item in the slot
|
||||
ClickSendMailItemButton()
|
||||
self.hooks["PickupContainerItem"].orig(PostalFrame.mailbag, PostalFrame.mailitem)
|
||||
PostalFrame.mailbag = nil
|
||||
PostalFrame.mailitem = nil
|
||||
elseif CursorHasItem() and PostalFrame.bag and PostalFrame.item then
|
||||
PickupContainerItem(PostalFrame.bag, PostalFrame.item)
|
||||
PostalFrame.bag = nil
|
||||
PostalFrame.item = nil
|
||||
end
|
||||
|
||||
self.hooks["PickupContainerItem"].orig(val.bag, val.item)
|
||||
|
||||
ClickSendMailItemButton()
|
||||
|
||||
local name, useless, count = GetSendMailItem()
|
||||
|
||||
if not name then
|
||||
Postal:Print("Postal: " .. POSTAL_ERROR, 1, 0, 0)
|
||||
else
|
||||
local subjectstr = PostalSubjectEditBox:GetText()
|
||||
if strlen(subjectstr) > 0 then
|
||||
subjectstr = subjectstr .. " "
|
||||
end
|
||||
|
||||
if count > 1 then
|
||||
subjectstr = subjectstr .. "[" .. name .. " x" .. count .. "]"
|
||||
else
|
||||
subjectstr = subjectstr .. "[" .. name .. "]"
|
||||
end
|
||||
|
||||
SendMail(val.to, subjectstr, format(POSTAL_ITEMNUM, key, this.total))
|
||||
end
|
||||
|
||||
PostalGlobalFrame.queue[key] = nil
|
||||
return
|
||||
end
|
||||
PostalStatusText:SetText(format(POSTAL_DONESENDING, this.total))
|
||||
PostalAbortButton:Hide()
|
||||
PostalGlobalFrame:Hide()
|
||||
|
||||
PostalGlobalFrame.total = 0
|
||||
PostalGlobalFrame.queue = {}
|
||||
end
|
||||
|
||||
function Postal:FillItemTable()
|
||||
local arr = {}
|
||||
for i = 1, POSTAL_NUMITEMBUTTONS do
|
||||
local btn = getglobal("PostalButton" .. i)
|
||||
if btn.item and btn.bag then
|
||||
tinsert(arr, { ["item"] = btn.item, ["bag"] = btn.bag, ["to"] = PostalNameEditBox:GetText() })
|
||||
end
|
||||
end
|
||||
return arr
|
||||
end
|
||||
|
||||
function Postal:ProcessQueue(elapsed)
|
||||
if not POSTAL_CANSENDNEXT then
|
||||
return
|
||||
end
|
||||
this.sendmail = this.sendmail + elapsed
|
||||
if this.sendmail > 0.5 then
|
||||
this.sendmail = 0
|
||||
if this.total > 0 then
|
||||
self:SendMail()
|
||||
POSTAL_CANSENDNEXT = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function Postal:ContainerFrame_Update(frame)
|
||||
self.hooks["ContainerFrame_Update"].orig(frame)
|
||||
local id = frame:GetID()
|
||||
if PostalFrame:IsVisible() then
|
||||
local i
|
||||
for i = 1, POSTAL_NUMITEMBUTTONS do
|
||||
local btn = getglobal("PostalButton" .. i)
|
||||
if btn.item and btn.bag then
|
||||
if btn.bag == frame:GetID() then
|
||||
SetItemButtonDesaturated(getglobal(frame:GetName() .. "Item" .. (frame.size-btn.item)+1), 1, 0.5, 0.5, 0.5)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if Postal_addItem and Postal_addItem[1] == frame:GetID() then
|
||||
SetItemButtonDesaturated(getglobal(frame:GetName() .. "Item" .. (frame.size-Postal_addItem[2])+1), 1, 0.5, 0.5, 0.5)
|
||||
end
|
||||
end
|
||||
|
||||
function Postal:MAIL_SEND_INFO_UPDATE()
|
||||
if not SendMailFrame:IsVisible() then return end
|
||||
local name, useless, count = GetSendMailItem()
|
||||
|
||||
if name and strlen(SendMailSubjectEditBox:GetText()) == 0 then
|
||||
if count > 1 then
|
||||
name = name .. " x" .. count
|
||||
end
|
||||
SendMailSubjectEditBox:SetText(name)
|
||||
end
|
||||
end
|
||||
|
||||
function Postal:InboxFrameItem_OnEnter()
|
||||
local didSetTooltip
|
||||
if this.index then
|
||||
if GetInboxItem(this.index) then
|
||||
GameTooltip:SetOwner(this, "ANCHOR_RIGHT")
|
||||
GameTooltip:SetInboxItem(this.index)
|
||||
didSetTooltip = 1
|
||||
end
|
||||
end
|
||||
if not didSetTooltip then
|
||||
GameTooltip:SetOwner(this, "ANCHOR_RIGHT")
|
||||
end
|
||||
if this.money then
|
||||
GameTooltip:AddLine(ENCLOSED_MONEY, "", 1, 1, 1)
|
||||
SetTooltipMoney(GameTooltip, this.money)
|
||||
SetMoneyFrameColor("GameTooltipMoneyFrame", HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b)
|
||||
elseif this.cod then
|
||||
GameTooltip:AddLine(COD_AMOUNT, "", 1, 1, 1)
|
||||
SetTooltipMoney(GameTooltip, this.cod)
|
||||
if this.cod > GetMoney() then
|
||||
SetMoneyFrameColor("GameTooltipMoneyFrame", RED_FONT_COLOR.r, RED_FONT_COLOR.g, RED_FONT_COLOR.b)
|
||||
else
|
||||
SetMoneyFrameColor("GameTooltipMoneyFrame", HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b)
|
||||
end
|
||||
end
|
||||
if didSetTooltip and (this.money or this.cod) then
|
||||
GameTooltip:SetHeight(GameTooltip:GetHeight()+getglobal("GameTooltipTextLeft" .. GameTooltip:NumLines()):GetHeight())
|
||||
if GameTooltipMoneyFrame:IsVisible() then
|
||||
GameTooltip:SetHeight(GameTooltip:GetHeight()+GameTooltipMoneyFrame:GetHeight())
|
||||
end
|
||||
end
|
||||
GameTooltip:Show()
|
||||
end
|
||||
|
||||
function Postal:TF_Show()
|
||||
self.hooks[TradeFrame].OnShow.orig()
|
||||
if Postal_addItem and not CursorHasItem() and UnitName("NPC") == Postal_addItem[3] then
|
||||
self.hooks["PickupContainerItem"].orig(Postal_addItem[1], Postal_addItem[2])
|
||||
|
||||
ClickTradeButton(1)
|
||||
end
|
||||
Postal_addItem = nil
|
||||
end
|
||||
|
||||
function Postal:Inbox_OnUpdate(elapsed)
|
||||
if Postal_addItem then
|
||||
Postal_addItem[4] = Postal_addItem[4] - elapsed
|
||||
if Postal_addItem[4] <= 0 then
|
||||
Postal_addItem = nil
|
||||
for i = 1, NUM_CONTAINER_FRAMES do
|
||||
if getglobal("ContainerFrame" .. i):IsVisible() then
|
||||
ContainerFrame_Update(getglobal("ContainerFrame" .. i))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if this.num and this.timeout then
|
||||
this.timeout = this.timeout - elapsed
|
||||
if this.timeout <= 0 then
|
||||
this.timeout = nil
|
||||
if this.id[1] then
|
||||
local val = this.id[1]
|
||||
local success = Postal:PickMail(val, this.openSelected)
|
||||
if success ~= 2 then
|
||||
tremove(this.id, 1)
|
||||
this.num = this.num - 1
|
||||
end
|
||||
if success == 1 then
|
||||
for key, va in this.id do
|
||||
if va > val then
|
||||
this.id[key] = va - 1
|
||||
end
|
||||
end
|
||||
this.lastVal = val
|
||||
InboxFrame_Update()
|
||||
else
|
||||
this.timeout = Postal_PICKDELAY
|
||||
this.lastVal = nil
|
||||
end
|
||||
if this.num == 0 then
|
||||
this.num = nil
|
||||
Postal:Inbox_DisableClicks(nil)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if this.delete then
|
||||
this.delete[1] = this.delete[1] - elapsed
|
||||
if this.delete[1] <= 0 then
|
||||
local _, _, _, _, money, _, _, itemID, _, _, _ = GetInboxHeaderInfo(this.delete[2])
|
||||
if money == 0 and not itemID then
|
||||
GetInboxText(this.delete[2])
|
||||
DeleteInboxItem(this.delete[2])
|
||||
end
|
||||
this.delete = nil
|
||||
this.timeout = Postal_PICKDELAY
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function Postal:MAIL_INBOX_UPDATE()
|
||||
if PostalInboxFrame.eventDelete then
|
||||
PostalInboxFrame.delete = { Postal_DELETEEVENTDELAY, PostalInboxFrame.eventDelete }
|
||||
PostalInboxFrame.eventDelete = nil
|
||||
end
|
||||
end
|
||||
|
||||
function Postal:UI_ERROR_MESSAGE()
|
||||
if event == "UI_ERROR_MESSAGE" and (arg1 == ERR_INV_FULL or arg1 == ERR_ITEM_MAX_COUNT) then
|
||||
if this.num then
|
||||
if arg1 == ERR_INV_FULL then
|
||||
Postal:Inbox_Abort()
|
||||
Postal:Print("Postal: Inventory full. Aborting.", 1, 0, 0)
|
||||
elseif arg1 == ERR_ITEM_MAX_COUNT then
|
||||
Postal:Print("Postal: You already have the maximum amount of that item. Skipping.", 1, 0, 0)
|
||||
this.timeout = Postal_DELETEDELAY
|
||||
if this.lastVal then
|
||||
for key, va in this.id do
|
||||
if va >= this.lastVal then
|
||||
this.id[key] = va + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function Postal:Print(msg, r, g, b)
|
||||
DEFAULT_CHAT_FRAME:AddMessage(msg, r, g, b)
|
||||
end
|
||||
|
||||
function Postal:PickMail(id, openSelected)
|
||||
if not id then
|
||||
return 0
|
||||
end
|
||||
local _, _, sender, subject, money, CODAmount, _, hasItem = GetInboxHeaderInfo(id)
|
||||
if CODAmount > 0 then
|
||||
Postal:Print("Postal: Mail |c00FFFFFF" .. this.numMails - (this.num - 1) .. "|r/|c00FFFFFF" .. this.numMails .. "|r is Cash on Delivery, skipping.", 1, 0, 0)
|
||||
return 0
|
||||
elseif not hasItem and money == 0 and not openSelected then
|
||||
Postal:Print("Postal: Mail |c00FFFFFF" .. this.numMails - (this.num - 1) .. "|r/|c00FFFFFF" .. this.numMails .. "|r has no money or items, skipping.", 1, 1, 0)
|
||||
return 0
|
||||
end
|
||||
Postal:Print("Postal: Opening mail |c00FFFFFF" .. this.numMails - (this.num - 1) .. "|r/|c00FFFFFF" .. this.numMails .. "|r: \"|c00FFFFFF" .. ( subject or "<No Subject>" ) .. "|r\" from |c00FFFFFF" .. ( sender or "<Unknown Sender>" ) .. "|r.", 1, 1, 0)
|
||||
local eventDelete
|
||||
if hasItem then
|
||||
self.hooks["TakeInboxItem"].orig(id)
|
||||
eventDelete = 1
|
||||
if money > 0 then
|
||||
return 2
|
||||
end
|
||||
end
|
||||
if money > 0 then
|
||||
TakeInboxMoney(id)
|
||||
eventDelete = 1
|
||||
end
|
||||
if eventDelete then
|
||||
PostalInboxFrame.eventDelete = id
|
||||
else
|
||||
PostalInboxFrame.delete = { Postal_DELETEDELAY, id }
|
||||
end
|
||||
return 1
|
||||
end
|
||||
|
||||
function Postal_Inbox_SetSelected()
|
||||
local id = this:GetID() + (InboxFrame.pageNum - 1) * 7
|
||||
if not this:GetChecked() then
|
||||
for k, v in Postal_SelectedItems do
|
||||
if v == id then
|
||||
tremove(Postal_SelectedItems, k)
|
||||
break
|
||||
end
|
||||
end
|
||||
else
|
||||
tinsert(Postal_SelectedItems, id)
|
||||
end
|
||||
end
|
||||
|
||||
function Postal_Inbox_OpenSelected(openAll)
|
||||
Postal:Inbox_DisableClicks(1)
|
||||
PostalInboxFrame.num = 0
|
||||
PostalInboxFrame.timeout = Postal_PICKDELAY
|
||||
PostalInboxFrame.id = {}
|
||||
PostalInboxFrame.openSelected = not openAll
|
||||
if openAll then
|
||||
for i = 1, GetInboxNumItems() do
|
||||
PostalInboxFrame.num = PostalInboxFrame.num + 1
|
||||
tinsert(PostalInboxFrame.id, i)
|
||||
end
|
||||
else
|
||||
for k, v in Postal_SelectedItems do
|
||||
PostalInboxFrame.num = PostalInboxFrame.num + 1
|
||||
tinsert(PostalInboxFrame.id, v)
|
||||
end
|
||||
end
|
||||
PostalInboxFrame.numMails = PostalInboxFrame.num
|
||||
Postal_SelectedItems = {}
|
||||
end
|
||||
|
||||
function Postal:InboxFrame_Update()
|
||||
self.hooks["InboxFrame_Update"].orig()
|
||||
for i = 1, 7 do
|
||||
local index = (i + (InboxFrame.pageNum - 1) * 7)
|
||||
if index > GetInboxNumItems() then
|
||||
getglobal("PostalBoxItem" .. i .. "CB"):Hide()
|
||||
else
|
||||
getglobal("PostalBoxItem" .. i .. "CB"):Show()
|
||||
getglobal("PostalBoxItem" .. i .. "CB"):SetChecked(nil)
|
||||
for k, v in Postal_SelectedItems do
|
||||
if v == index then
|
||||
getglobal("PostalBoxItem" .. i .. "CB"):SetChecked(1)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if PostalInboxFrame.num then
|
||||
Postal:Inbox_DisableClicks(1, 1)
|
||||
end
|
||||
end
|
||||
|
||||
function Postal:Inbox_DisableClicks(disable, loopPrevention)
|
||||
if disable then
|
||||
for i = 1, 7 do
|
||||
getglobal("MailItem" .. i .. "ButtonIcon"):SetDesaturated(1)
|
||||
end
|
||||
if not self:IsHooked("InboxFrame_OnClick") then self:Hook("InboxFrame_OnClick", "DummyFunction") end
|
||||
else
|
||||
for i = 1, 7 do
|
||||
getglobal("MailItem" .. i .. "ButtonIcon"):SetDesaturated(nil)
|
||||
end
|
||||
if not loopPrevention then
|
||||
InboxFrame_Update()
|
||||
end
|
||||
if self:IsHooked("InboxFrame_OnClick") then self:Unhook("InboxFrame_OnClick") end
|
||||
end
|
||||
end
|
||||
|
||||
function Postal:InboxFrame_OnClick()
|
||||
this:SetChecked(nil)
|
||||
end
|
||||
|
||||
function Postal:Inbox_Abort()
|
||||
PostalInboxFrame.num = nil
|
||||
PostalInboxFrame.timeout = nil
|
||||
PostalInboxFrame.id = {}
|
||||
Postal_SelectedItems = {}
|
||||
Postal:Inbox_DisableClicks()
|
||||
HideUIPanel(PostalInboxOpenAll)
|
||||
end
|
||||
|
||||
function Postal:CloseMail()
|
||||
self.hooks["CloseMail"].orig()
|
||||
Postal:Inbox_Abort()
|
||||
end
|
||||
|
||||
function Postal:TakeInboxItem(id)
|
||||
self.hooks["TakeInboxItem"].orig(id)
|
||||
local name = GetInboxItem(id)
|
||||
tinsert(PostalForwardFrame.pickItem, name)
|
||||
end
|
||||
|
||||
-- Mail Forwarding
|
||||
function Postal:DisableAttachments(disable)
|
||||
if disable then
|
||||
OpenMailMoneyButtonIconTexture:SetDesaturated(1)
|
||||
OpenMailPackageButtonIconTexture:SetDesaturated(1)
|
||||
if not self:IsHooked(OpenMailMoneyButton, "OnClick") then self:HookScript(OpenMailMoneyButton, "OnClick", "DummyFunction") end
|
||||
if not self:IsHooked(OpenMailPackageButton, "OnClick") then self:HookScript(OpenMailPackageButton, "OnClick", "DummyFunction") end
|
||||
else
|
||||
OpenMailMoneyButtonIconTexture:SetDesaturated(nil)
|
||||
OpenMailPackageButtonIconTexture:SetDesaturated(nil)
|
||||
if self:IsHooked(OpenMailMoneyButton, "OnClick") then self:Unhook(OpenMailMoneyButton, "OnClick") end
|
||||
if self:IsHooked(OpenMailPackageButton, "OnClick") then self:Unhook(OpenMailPackageButton, "OnClick") end
|
||||
end
|
||||
end
|
||||
|
||||
function Postal:DummyFunction()
|
||||
end
|
||||
|
||||
function Postal:OpenMail_Reply()
|
||||
self.hooks["OpenMail_Reply"].orig()
|
||||
SendMailMoneyCopper:SetText("")
|
||||
SendMailMoneySilver:SetText("")
|
||||
SendMailMoneyGold:SetText("")
|
||||
end
|
||||
|
||||
|
||||
function Postal:OpenReply()
|
||||
OpenMail_Reply()
|
||||
local _, _, _, subject, money = GetInboxHeaderInfo(InboxFrame.openMailID)
|
||||
|
||||
-- Money
|
||||
local gold, silver, copper = "", "", ""
|
||||
if money and money > 0 then
|
||||
gold = floor(money / (COPPER_PER_SILVER * SILVER_PER_GOLD))
|
||||
silver = floor((money - (gold * COPPER_PER_SILVER * SILVER_PER_GOLD)) / COPPER_PER_SILVER)
|
||||
copper = mod(money, COPPER_PER_SILVER)
|
||||
end
|
||||
SendMailMoneyCopper:SetText(copper)
|
||||
SendMailMoneySilver:SetText(silver)
|
||||
SendMailMoneyGold:SetText(gold)
|
||||
|
||||
-- Items
|
||||
local _, itemTexture, count = GetInboxItem(InboxFrame.openMailID)
|
||||
SendMailPackageButton:SetNormalTexture(itemTexture)
|
||||
if count > 1 then
|
||||
SendMailPackageButtonCount:SetText(count)
|
||||
else
|
||||
SendMailPackageButtonCount:SetText("")
|
||||
end
|
||||
|
||||
-- Text fields
|
||||
SendMailNameEditBox:SetText("")
|
||||
local subject = OpenMailSubject:GetText()
|
||||
local prefix = "FW:".." "
|
||||
if strsub(subject, 1, strlen(prefix)) ~= prefix then
|
||||
subject = prefix..subject
|
||||
end
|
||||
SendMailSubjectEditBox:SetText(subject or "")
|
||||
SendMailBodyEditBox:SetText(string.gsub(OpenMailBodyText:GetText() or "", "\n", "\n>"))
|
||||
SendMailNameEditBox:SetFocus()
|
||||
|
||||
-- Set the send mode so the work flow can change accordingly
|
||||
SendMailFrame.sendMode = "reply"
|
||||
|
||||
self:Forward_EnableForward(1)
|
||||
end
|
||||
|
||||
function Postal:SendMailMailButton_OnClick()
|
||||
local name = GetInboxItem(InboxFrame.openMailID)
|
||||
local _, _, _, _, money = GetInboxHeaderInfo(InboxFrame.openMailID)
|
||||
if name then
|
||||
PostalForwardFrame.searchItem = name
|
||||
PostalForwardFrame.forwardStep = 1
|
||||
self.hooks["TakeInboxItem"].orig(InboxFrame.openMailID)
|
||||
else
|
||||
PostalForwardFrame.forwardStep = 2
|
||||
if money and money > 0 then
|
||||
SetSendMailMoney(money)
|
||||
PostalForwardFrame.countDown = 2
|
||||
oldTakeInboxMoney(InboxFrame.openMailID)
|
||||
else
|
||||
PostalForwardFrame.countDown = 0.5
|
||||
end
|
||||
end
|
||||
SendMailMailButton:Disable()
|
||||
end
|
||||
|
||||
function Postal:Forward_OnUpdate(elapsed)
|
||||
if this.forwardStep and this.forwardStep > 1 then
|
||||
if this.countDown then
|
||||
this.countDown = this.countDown - elapsed
|
||||
if this.countDown <= 0 then
|
||||
if this.forwardStep == 2 then
|
||||
this.countDown = 0.5
|
||||
this.forwardStep = 3
|
||||
-- Send the mail
|
||||
SendMail(SendMailNameEditBox:GetText(), SendMailSubjectEditBox:GetText(), SendMailBodyEditBox:GetText())
|
||||
SendMailMailButton:Disable()
|
||||
elseif this.forwardStep == 3 then
|
||||
-- Delete the old one
|
||||
local _, _, _, _, money, _, _, itemID = GetInboxHeaderInfo(InboxFrame.openMailID)
|
||||
if money == 0 and not itemID then
|
||||
DeleteInboxItem(InboxFrame.openMailID)
|
||||
end
|
||||
self:MailFrameTab_OnClick(1)
|
||||
HideUIPanel(OpenMailFrame)
|
||||
this.countDown = nil
|
||||
this.forwardStep = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
this.process = this.process - elapsed
|
||||
if this.process <= 0 then
|
||||
this.process = 3
|
||||
if getn(Postal_ScheduledStack) > 0 then
|
||||
self:ProcessStack()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function Postal:InboxFrame_OnClick(id)
|
||||
self.hooks["InboxFrame_OnClick"].orig(id)
|
||||
local _, _, _, _, _, CODAmount = GetInboxHeaderInfo(id)
|
||||
if CODAmount and CODAmount > 0 then
|
||||
OpenMailForwardButton:Disable()
|
||||
else
|
||||
OpenMailForwardButton:Enable()
|
||||
end
|
||||
end
|
||||
|
||||
function Postal:Forward_EnableForward(enable)
|
||||
if enable then
|
||||
OpenMailForwardButton:Disable()
|
||||
if not self:IsHooked(SendMailPackageButton, "OnEnter") then self:HookScript(SendMailPackageButton, "OnEnter", "SMPBOE") end
|
||||
SendMailCODButton:Disable()
|
||||
self:DisableAttachments(1)
|
||||
if not self:IsHooked("SendMailMailButton_OnClick") then self:Hook("SendMailMailButton_OnClick") end
|
||||
if not self:IsHooked("SendMailPackageButton_OnClick") then self:Hook("SendMailPackageButton_OnClick") end
|
||||
else
|
||||
OpenMailForwardButton:Enable()
|
||||
if self:IsHooked(SendMailPackageButton, "OnEnter") then self:Unhook(SendMailPackageButton, "OnEnter") end
|
||||
SendMailCODButton:Enable()
|
||||
self:DisableAttachments(nil)
|
||||
if self:IsHooked("SendMailMailButton_OnClick") then self:Unhook("SendMailMailButton_OnClick") end
|
||||
if self:IsHooked("SendMailPackageButton_OnClick") then self:Unhook("SendMailPackageButton_OnClick") end
|
||||
end
|
||||
end
|
||||
|
||||
function Postal:SMPBOE()
|
||||
GameTooltip:SetOwner(SendMailPackageButton, "ANCHOR_RIGHT")
|
||||
GameTooltip:SetInboxItem(InboxFrame.openMailID)
|
||||
end
|
||||
|
||||
function Postal:SendMailPackageButton_OnClick()
|
||||
end
|
||||
|
||||
function Postal:Forward_AttachSlot(container, item)
|
||||
PickupContainerItem(container, item)
|
||||
ClickSendMailItemButton()
|
||||
PostalForwardFrame.searchItem = nil
|
||||
PostalForwardFrame.forwardStep = 2
|
||||
PostalForwardFrame.countDown = 1.5
|
||||
end
|
||||
|
||||
function Postal:BAG_UPDATE()
|
||||
local old = {}
|
||||
for k, v in Postal_BagLinks do
|
||||
if type(v) == "table" then
|
||||
old[k] = { }
|
||||
for key, val in v do
|
||||
old[k][key] = val
|
||||
end
|
||||
end
|
||||
end
|
||||
Postal_BagLinks = {}
|
||||
for i = 0, 4 do
|
||||
Postal_BagLinks[i] = {}
|
||||
for y = 1, GetContainerNumSlots(i) do
|
||||
local curr = GetContainerItemLink(i, y)
|
||||
local _, _, name = string.find(( curr or "" ), "%[(.+)%]")
|
||||
if name then
|
||||
if PostalForwardFrame.searchItem then
|
||||
if name and name == PostalForwardFrame.searchItem and not old[i][y] then
|
||||
self:Forward_AttachSlot(i, y)
|
||||
end
|
||||
else
|
||||
local _, _, name = string.find(( curr or "" ), "%[(.+)%]")
|
||||
if name and name == PostalForwardFrame.pickItem[1] and not old[i][y] then
|
||||
tremove(PostalForwardFrame.pickItem, 1)
|
||||
for k, v in old do
|
||||
local hasFound
|
||||
for key, val in v do
|
||||
if val == name and ( k ~= i or key ~= y ) then
|
||||
local _,_, link = string.find((GetContainerItemLink(k, key) or ""), "(item:[%d:]+)")
|
||||
if link then
|
||||
local texture, itemCount = GetContainerItemInfo(k,key)
|
||||
local tex, iC = GetContainerItemInfo(i, y)
|
||||
local sName, sLink, iQuality, iLevel, sType, sSubType, iCount = GetItemInfo(link)
|
||||
if sName and itemCount and iCount and iC then
|
||||
if iCount >= (itemCount+iC) then
|
||||
if getn(Postal_ScheduledStack) == 0 then
|
||||
PostalForwardFrame.process = 2
|
||||
end
|
||||
tinsert(Postal_ScheduledStack, { i, y, k, key })
|
||||
hasFound = 1
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if hasFound then
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
Postal_BagLinks[i][y] = name
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function Postal:ProcessStack()
|
||||
local val = tremove(Postal_ScheduledStack, 1)
|
||||
PickupContainerItem(val[1], val[2])
|
||||
PickupContainerItem(val[3], val[4])
|
||||
end
|
||||
|
||||
local oldSMMFfunc = SendMailMoneyFrame.onvalueChangedFunc
|
||||
SendMailMoneyFrame.onvalueChangedFunc = function()
|
||||
if oldSMMFfunc then
|
||||
oldSMMFfunc()
|
||||
end
|
||||
local subject = SendMailSubjectEditBox:GetText()
|
||||
if subject == "" or string.find(subject, "%[%d+G, %d+S, %d+C%]") then
|
||||
local copper, silver, gold = SendMailMoneyFrameCopper:GetText(), SendMailMoneyFrameSilver:GetText(), SendMailMoneyFrameGold:GetText()
|
||||
if not tonumber(copper) then
|
||||
copper = 0
|
||||
end
|
||||
if not tonumber(silver) then
|
||||
silver = 0
|
||||
end
|
||||
if not tonumber(gold) then
|
||||
gold = 0
|
||||
end
|
||||
SendMailSubjectEditBox:SetText(format("[%sG, %sS, %sC]", gold, silver, copper))
|
||||
end
|
||||
end
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
## Interface: 11200
|
||||
## Version: 1.0
|
||||
## Title: Postal |cff7fff7f -Ace2-|r
|
||||
## Notes: Postal
|
||||
## Notes-zhCN: 批量邮件收取发送
|
||||
## Author: Grennon
|
||||
## X-Category: Interface
|
||||
## OptionalDeps: Ace2
|
||||
libs\AceLibrary\AceLibrary.lua
|
||||
libs\AceOO\AceOO-2.0.lua
|
||||
libs\AceEvent\AceEvent-2.0.lua
|
||||
libs\AceAddon\AceAddon-2.0.lua
|
||||
libs\AceHook\AceHook-2.0.lua
|
||||
Postal.xml
|
||||
+936
@@ -0,0 +1,936 @@
|
||||
<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/
|
||||
C:\Projects\WoW\Bin\Interface\FrameXML\UI.xsd">
|
||||
<Script file="localization.lua"/>
|
||||
<Script file="localization.ge.lua"/>
|
||||
<Script file="localization.fr.lua"/>
|
||||
<Script file="localization.cn.lua"/>
|
||||
<Script file="Postal.lua"/>
|
||||
<Button name="PostalButtonTemplate" virtual="true">
|
||||
<Size>
|
||||
<AbsDimension x="37" y="37"/>
|
||||
</Size>
|
||||
<Layers>
|
||||
<Layer level="BACKGROUND">
|
||||
<Texture file="Interface\Buttons\UI-Slot-Background">
|
||||
<Size>
|
||||
<AbsDimension x="39" y="39"/>
|
||||
</Size>
|
||||
<Anchors>
|
||||
<Anchor point="TOPLEFT">
|
||||
<Offset>
|
||||
<AbsDimension x="-2" y="2"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
<TexCoords left="0" right="0.640625" top="0" bottom="0.640625"/>
|
||||
</Texture>
|
||||
</Layer>
|
||||
<Layer level="ARTWORK">
|
||||
<FontString name="$parentCount" inherits="NumberFontNormal" justifyH="RIGHT">
|
||||
<Anchors>
|
||||
<Anchor point="BOTTOMRIGHT">
|
||||
<Offset>
|
||||
<AbsDimension x="-5" y="2"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
</FontString>
|
||||
</Layer>
|
||||
<Layer level="BORDER">
|
||||
<Texture name="$parentIconTexture"/>
|
||||
</Layer>
|
||||
</Layers>
|
||||
<Scripts>
|
||||
<OnLoad>
|
||||
this:RegisterForDrag("LeftButton")
|
||||
</OnLoad>
|
||||
<OnReceiveDrag>
|
||||
Postal:MailButton_OnClick()
|
||||
</OnReceiveDrag>
|
||||
<OnDragStart>
|
||||
Postal:MailButton_OnClick()
|
||||
</OnDragStart>
|
||||
<OnClick>
|
||||
Postal:MailButton_OnClick()
|
||||
</OnClick>
|
||||
<OnEnter>
|
||||
GameTooltip:SetOwner(this, "ANCHOR_RIGHT");
|
||||
if ( this.item and this.bag ) then
|
||||
GameTooltip:SetBagItem(this.bag,this.item);
|
||||
else
|
||||
GameTooltip:SetText(ATTACHMENT_TEXT, 1.0, 1.0, 1.0);
|
||||
end
|
||||
</OnEnter>
|
||||
<OnLeave>
|
||||
GameTooltip:Hide()
|
||||
</OnLeave>
|
||||
</Scripts>
|
||||
<HighlightTexture alphaMode="ADD" file="Interface\Buttons\ButtonHilight-Square"/>
|
||||
</Button>
|
||||
<Frame name="PostalFrame" parent="MailFrame" hidden="true">
|
||||
<Size>
|
||||
<AbsDimension x="384" y="512"/>
|
||||
</Size>
|
||||
<Anchors>
|
||||
<Anchor point="TOPLEFT"/>
|
||||
</Anchors>
|
||||
<Layers>
|
||||
<Layer level="BACKGROUND">
|
||||
<FontString name="PostalTitleText" inherits="GameFontNormal" text="POSTAL_SEND">
|
||||
<Size>
|
||||
<AbsDimension x="224" y="14"/>
|
||||
</Size>
|
||||
<Anchors>
|
||||
<Anchor point="CENTER">
|
||||
<Offset>
|
||||
<AbsDimension x="6" y="230"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
</FontString>
|
||||
<FontString name="PostalStatusText" inherits="GameFontNormal">
|
||||
<Size>
|
||||
<AbsDimension x="224" y="14"/>
|
||||
</Size>
|
||||
<Anchors>
|
||||
<Anchor point="BOTTOM" relativePoint="BOTTOM">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="125"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
</FontString>
|
||||
<FontString justifyH="left" justifyV="top" name="PostalHelpText" inherits="GameFontNormal" text="POSTAL_HELP">
|
||||
<Size>
|
||||
<AbsDimension x="300" y="150"/>
|
||||
</Size>
|
||||
<Anchors>
|
||||
<Anchor point="TOPLEFT">
|
||||
<Offset>
|
||||
<AbsDimension x="30" y="-105"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
</FontString>
|
||||
<Texture name="PostalHorizontalBarLeft" file="Interface\ClassTrainerFrame\UI-ClassTrainer-HorizontalBar">
|
||||
<Size>
|
||||
<AbsDimension x="256" y="16"/>
|
||||
</Size>
|
||||
<Anchors>
|
||||
<Anchor point="TOPLEFT">
|
||||
<Offset>
|
||||
<AbsDimension x="15" y="-350"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
<TexCoords left="0" right="1.0" top="0" bottom="0.25"/>
|
||||
</Texture>
|
||||
<Texture file="Interface\ClassTrainerFrame\UI-ClassTrainer-HorizontalBar">
|
||||
<Size>
|
||||
<AbsDimension x="75" y="16"/>
|
||||
</Size>
|
||||
<Anchors>
|
||||
<Anchor point="LEFT" relativeTo="PostalHorizontalBarLeft" relativePoint="RIGHT">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="0"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
<TexCoords left="0" right="0.29296875" top="0.25" bottom="0.5"/>
|
||||
</Texture>
|
||||
</Layer>
|
||||
</Layers>
|
||||
<Frames>
|
||||
<EditBox name="PostalNameEditBox" letters="12" historyLines="0" autoFocus="false">
|
||||
<Size>
|
||||
<AbsDimension x="122" y="20"/>
|
||||
</Size>
|
||||
<Anchors>
|
||||
<Anchor point="TOPLEFT">
|
||||
<Offset>
|
||||
<AbsDimension x="105" y="-46"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
<Layers>
|
||||
<Layer level="BACKGROUND">
|
||||
<FontString inherits="GameFontNormal" text="MAIL_TO_LABEL" justifyH="RIGHT">
|
||||
<Anchors>
|
||||
<Anchor point="RIGHT" relativePoint="LEFT">
|
||||
<Offset>
|
||||
<AbsDimension x="-12" y="0"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
</FontString>
|
||||
<Texture name="$parentLeft" file="Interface\Common\Common-Input-Border">
|
||||
<Size>
|
||||
<AbsDimension x="8" y="20"/>
|
||||
</Size>
|
||||
<Anchors>
|
||||
<Anchor point="TOPLEFT">
|
||||
<Offset>
|
||||
<AbsDimension x="-8" y="0"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
<TexCoords left="0" right="0.0625" top="0" bottom="0.625"/>
|
||||
</Texture>
|
||||
<Texture name="$parentMiddle" file="Interface\Common\Common-Input-Border">
|
||||
<Size>
|
||||
<AbsDimension x="100" y="20"/>
|
||||
</Size>
|
||||
<Anchors>
|
||||
<Anchor point="LEFT" relativeTo="$parentLeft" relativePoint="RIGHT"/>
|
||||
</Anchors>
|
||||
<TexCoords left="0.0625" right="0.9375" top="0" bottom="0.625"/>
|
||||
</Texture>
|
||||
<Texture name="$parentRight" file="Interface\Common\Common-Input-Border">
|
||||
<Size>
|
||||
<AbsDimension x="8" y="20"/>
|
||||
</Size>
|
||||
<Anchors>
|
||||
<Anchor point="LEFT" relativeTo="$parentMiddle" relativePoint="RIGHT"/>
|
||||
</Anchors>
|
||||
<TexCoords left="0.9375" right="1.0" top="0" bottom="0.625"/>
|
||||
</Texture>
|
||||
</Layer>
|
||||
</Layers>
|
||||
<Scripts>
|
||||
<OnTabPressed>
|
||||
PostalSubjectEditBox:SetFocus()
|
||||
</OnTabPressed>
|
||||
<OnEditFocusLost>
|
||||
this:HighlightText(0, 0)
|
||||
</OnEditFocusLost>
|
||||
<OnChar>
|
||||
SendMailFrame_SendeeAutocomplete()
|
||||
</OnChar>
|
||||
<OnEnterPressed>
|
||||
PostalSubjectEditBox:SetFocus()
|
||||
</OnEnterPressed>
|
||||
<OnEscapePressed>
|
||||
PostalNameEditBox:ClearFocus()
|
||||
</OnEscapePressed>
|
||||
<OnTextChanged>
|
||||
Postal:CanSend()
|
||||
</OnTextChanged>
|
||||
</Scripts>
|
||||
<FontString inherits="ChatFontNormal"/>
|
||||
</EditBox>
|
||||
<Frame name="PostalCostMoneyFrame" inherits="SmallMoneyFrameTemplate">
|
||||
<Anchors>
|
||||
<Anchor point="TOPRIGHT">
|
||||
<Offset>
|
||||
<AbsDimension x="-46" y="-48"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
<Layers>
|
||||
<Layer level="BACKGROUND">
|
||||
<FontString inherits="GameFontNormal" text="SEND_MAIL_COST">
|
||||
<Anchors>
|
||||
<Anchor point="RIGHT" relativePoint="LEFT">
|
||||
<Offset>
|
||||
<AbsDimension x="-3" y="0"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
</FontString>
|
||||
</Layer>
|
||||
</Layers>
|
||||
<Scripts>
|
||||
<OnLoad>
|
||||
SmallMoneyFrame_OnLoad()
|
||||
MoneyFrame_SetType("STATIC")
|
||||
MoneyFrame_Update("PostalCostMoneyFrame", GetSendMailPrice())
|
||||
</OnLoad>
|
||||
</Scripts>
|
||||
</Frame>
|
||||
<EditBox name="PostalSubjectEditBox" letters="64" historyLines="0" autoFocus="false">
|
||||
<Size>
|
||||
<AbsDimension x="237" y="20"/>
|
||||
</Size>
|
||||
<Anchors>
|
||||
<Anchor point="TOPLEFT" relativeTo="PostalNameEditBox" relativePoint="BOTTOMLEFT">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="-3"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
<Layers>
|
||||
<Layer level="BACKGROUND">
|
||||
<FontString inherits="GameFontNormal" text="MAIL_SUBJECT_LABEL" justifyH="RIGHT">
|
||||
<Anchors>
|
||||
<Anchor point="RIGHT" relativePoint="LEFT">
|
||||
<Offset>
|
||||
<AbsDimension x="-12" y="0"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
</FontString>
|
||||
<Texture name="$parentLeft" file="Interface\Common\Common-Input-Border">
|
||||
<Size>
|
||||
<AbsDimension x="8" y="20"/>
|
||||
</Size>
|
||||
<Anchors>
|
||||
<Anchor point="TOPLEFT">
|
||||
<Offset>
|
||||
<AbsDimension x="-8" y="0"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
<TexCoords left="0" right="0.0625" top="0" bottom="0.625"/>
|
||||
</Texture>
|
||||
<Texture name="$parentMiddle" file="Interface\Common\Common-Input-Border">
|
||||
<Size>
|
||||
<AbsDimension x="221" y="20"/>
|
||||
</Size>
|
||||
<Anchors>
|
||||
<Anchor point="LEFT" relativeTo="$parentLeft" relativePoint="RIGHT"/>
|
||||
</Anchors>
|
||||
<TexCoords left="0.0625" right="0.9375" top="0" bottom="0.625"/>
|
||||
</Texture>
|
||||
<Texture name="$parentRight" file="Interface\Common\Common-Input-Border">
|
||||
<Size>
|
||||
<AbsDimension x="8" y="20"/>
|
||||
</Size>
|
||||
<Anchors>
|
||||
<Anchor point="LEFT" relativeTo="$parentMiddle" relativePoint="RIGHT"/>
|
||||
</Anchors>
|
||||
<TexCoords left="0.9375" right="1.0" top="0" bottom="0.625"/>
|
||||
</Texture>
|
||||
</Layer>
|
||||
</Layers>
|
||||
<Scripts>
|
||||
<OnTabPressed>
|
||||
PostalNameEditBox:SetFocus()
|
||||
</OnTabPressed>
|
||||
<OnEscapePressed>
|
||||
PostalSubjectEditBox:ClearFocus()
|
||||
</OnEscapePressed>
|
||||
</Scripts>
|
||||
<FontString inherits="ChatFontNormal"/>
|
||||
</EditBox>
|
||||
<Frame name="PostalMoneyFrame" inherits="SmallMoneyFrameTemplate">
|
||||
<Anchors>
|
||||
<Anchor point="BOTTOMRIGHT" relativePoint="BOTTOMLEFT">
|
||||
<Offset>
|
||||
<AbsDimension x="183" y="84"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
</Frame>
|
||||
<Button name="PostalCancelButton" inherits="UIPanelButtonTemplate" text="CANCEL">
|
||||
<Size>
|
||||
<AbsDimension x="80" y="22"/>
|
||||
</Size>
|
||||
<Anchors>
|
||||
<Anchor point="BOTTOMRIGHT" relativePoint="BOTTOMRIGHT">
|
||||
<Offset>
|
||||
<AbsDimension x="-39" y="80"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
<Scripts>
|
||||
<OnClick>
|
||||
HideUIPanel(MailFrame)
|
||||
</OnClick>
|
||||
</Scripts>
|
||||
</Button>
|
||||
<Button name="PostalMailButton" inherits="UIPanelButtonTemplate" text="SEND_LABEL">
|
||||
<Size>
|
||||
<AbsDimension x="80" y="22"/>
|
||||
</Size>
|
||||
<Anchors>
|
||||
<Anchor point="RIGHT" relativeTo="SendMailCancelButton" relativePoint="LEFT">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="0"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
<Scripts>
|
||||
<OnClick>
|
||||
PostalAcceptSendFrame:Show()
|
||||
</OnClick>
|
||||
</Scripts>
|
||||
</Button>
|
||||
|
||||
<Button name="PostalAbortButton" hidden="true" inherits="UIPanelButtonTemplate" text="POSTAL_ABORT">
|
||||
<Size>
|
||||
<AbsDimension x="80" y="22"/>
|
||||
</Size>
|
||||
<Anchors>
|
||||
<Anchor point="BOTTOM" relativePoint="BOTTOM">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="105"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
<Scripts>
|
||||
<OnClick>
|
||||
PostalStatusText:SetText(format(POSTAL_ABORTED, PostalGlobalFrame.total-(getn(PostalGlobalFrame.queue)-1), PostalGlobalFrame.total));
|
||||
PostalGlobalFrame.queue = { };
|
||||
PostalGlobalFrame.total = 0;
|
||||
PostalGlobalFrame:Hide();
|
||||
</OnClick>
|
||||
</Scripts>
|
||||
</Button>
|
||||
|
||||
<Button name="PostalButton1" inherits="PostalButtonTemplate" id="1" hidden="false">
|
||||
<Anchors>
|
||||
<Anchor point="TOPLEFT">
|
||||
<Offset>
|
||||
<AbsDimension x="30" y="-222"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
</Button>
|
||||
<Button name="PostalButton2" inherits="PostalButtonTemplate" id="2" hidden="false">
|
||||
<Anchors>
|
||||
<Anchor point="LEFT" relativePoint="RIGHT" relativeTo="PostalButton1">
|
||||
<Offset>
|
||||
<AbsDimension x="8" y="0"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
</Button>
|
||||
<Button name="PostalButton3" inherits="PostalButtonTemplate" id="3" hidden="false">
|
||||
<Anchors>
|
||||
<Anchor point="LEFT" relativePoint="RIGHT" relativeTo="PostalButton2">
|
||||
<Offset>
|
||||
<AbsDimension x="8" y="0"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
</Button>
|
||||
<Button name="PostalButton4" inherits="PostalButtonTemplate" id="4" hidden="false">
|
||||
<Anchors>
|
||||
<Anchor point="LEFT" relativePoint="RIGHT" relativeTo="PostalButton3">
|
||||
<Offset>
|
||||
<AbsDimension x="8" y="0"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
</Button>
|
||||
<Button name="PostalButton5" inherits="PostalButtonTemplate" id="5" hidden="false">
|
||||
<Anchors>
|
||||
<Anchor point="LEFT" relativePoint="RIGHT" relativeTo="PostalButton4">
|
||||
<Offset>
|
||||
<AbsDimension x="8" y="0"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
</Button>
|
||||
<Button name="PostalButton6" inherits="PostalButtonTemplate" id="6" hidden="false">
|
||||
<Anchors>
|
||||
<Anchor point="LEFT" relativePoint="RIGHT" relativeTo="PostalButton5">
|
||||
<Offset>
|
||||
<AbsDimension x="8" y="0"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
</Button>
|
||||
<Button name="PostalButton7" inherits="PostalButtonTemplate" id="7" hidden="false">
|
||||
<Anchors>
|
||||
<Anchor point="LEFT" relativePoint="RIGHT" relativeTo="PostalButton6">
|
||||
<Offset>
|
||||
<AbsDimension x="8" y="0"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
</Button>
|
||||
|
||||
|
||||
|
||||
<Button name="PostalButton8" inherits="PostalButtonTemplate" id="8" hidden="false">
|
||||
<Anchors>
|
||||
<Anchor point="TOP" relativePoint="BOTTOM" relativeTo="PostalButton1">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="-8"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
</Button>
|
||||
<Button name="PostalButton9" inherits="PostalButtonTemplate" id="9" hidden="false">
|
||||
<Anchors>
|
||||
<Anchor point="LEFT" relativePoint="RIGHT" relativeTo="PostalButton8">
|
||||
<Offset>
|
||||
<AbsDimension x="8" y="0"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
</Button>
|
||||
<Button name="PostalButton10" inherits="PostalButtonTemplate" id="10" hidden="false">
|
||||
<Anchors>
|
||||
<Anchor point="LEFT" relativePoint="RIGHT" relativeTo="PostalButton9">
|
||||
<Offset>
|
||||
<AbsDimension x="8" y="0"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
</Button>
|
||||
<Button name="PostalButton11" inherits="PostalButtonTemplate" id="11" hidden="false">
|
||||
<Anchors>
|
||||
<Anchor point="LEFT" relativePoint="RIGHT" relativeTo="PostalButton10">
|
||||
<Offset>
|
||||
<AbsDimension x="8" y="0"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
</Button>
|
||||
<Button name="PostalButton12" inherits="PostalButtonTemplate" id="12" hidden="false">
|
||||
<Anchors>
|
||||
<Anchor point="LEFT" relativePoint="RIGHT" relativeTo="PostalButton11">
|
||||
<Offset>
|
||||
<AbsDimension x="8" y="0"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
</Button>
|
||||
<Button name="PostalButton13" inherits="PostalButtonTemplate" id="13" hidden="false">
|
||||
<Anchors>
|
||||
<Anchor point="LEFT" relativePoint="RIGHT" relativeTo="PostalButton12">
|
||||
<Offset>
|
||||
<AbsDimension x="8" y="0"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
</Button>
|
||||
<Button name="PostalButton14" inherits="PostalButtonTemplate" id="14" hidden="false">
|
||||
<Anchors>
|
||||
<Anchor point="LEFT" relativePoint="RIGHT" relativeTo="PostalButton13">
|
||||
<Offset>
|
||||
<AbsDimension x="8" y="0"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
</Button>
|
||||
|
||||
|
||||
<Button name="PostalButton15" inherits="PostalButtonTemplate" id="15" hidden="false">
|
||||
<Anchors>
|
||||
<Anchor point="TOP" relativePoint="BOTTOM" relativeTo="PostalButton8">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="-8"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
</Button>
|
||||
<Button name="PostalButton16" inherits="PostalButtonTemplate" id="16" hidden="false">
|
||||
<Anchors>
|
||||
<Anchor point="LEFT" relativePoint="RIGHT" relativeTo="PostalButton15">
|
||||
<Offset>
|
||||
<AbsDimension x="8" y="0"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
</Button>
|
||||
<Button name="PostalButton17" inherits="PostalButtonTemplate" id="17" hidden="false">
|
||||
<Anchors>
|
||||
<Anchor point="LEFT" relativePoint="RIGHT" relativeTo="PostalButton16">
|
||||
<Offset>
|
||||
<AbsDimension x="8" y="0"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
</Button>
|
||||
<Button name="PostalButton18" inherits="PostalButtonTemplate" id="18" hidden="false">
|
||||
<Anchors>
|
||||
<Anchor point="LEFT" relativePoint="RIGHT" relativeTo="PostalButton17">
|
||||
<Offset>
|
||||
<AbsDimension x="8" y="0"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
</Button>
|
||||
<Button name="PostalButton19" inherits="PostalButtonTemplate" id="19" hidden="false">
|
||||
<Anchors>
|
||||
<Anchor point="LEFT" relativePoint="RIGHT" relativeTo="PostalButton18">
|
||||
<Offset>
|
||||
<AbsDimension x="8" y="0"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
</Button>
|
||||
<Button name="PostalButton20" inherits="PostalButtonTemplate" id="20" hidden="false">
|
||||
<Anchors>
|
||||
<Anchor point="LEFT" relativePoint="RIGHT" relativeTo="PostalButton19">
|
||||
<Offset>
|
||||
<AbsDimension x="8" y="0"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
</Button>
|
||||
<Button name="PostalButton21" inherits="PostalButtonTemplate" id="21" hidden="false">
|
||||
<Anchors>
|
||||
<Anchor point="LEFT" relativePoint="RIGHT" relativeTo="PostalButton20">
|
||||
<Offset>
|
||||
<AbsDimension x="8" y="0"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
</Button>
|
||||
</Frames>
|
||||
<Scripts>
|
||||
<OnShow>
|
||||
PostalNameEditBox:SetFocus()
|
||||
</OnShow>
|
||||
</Scripts>
|
||||
</Frame>
|
||||
|
||||
<Button name="MailFrameTab3" inherits="FriendsFrameTabTemplate" id="3" parent="MailFrame" text="Mass Mail">
|
||||
<Anchors>
|
||||
<Anchor point="LEFT" relativeTo="MailFrameTab2" relativePoint="RIGHT">
|
||||
<Offset>
|
||||
<AbsDimension x="-8" y="0"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
<Scripts>
|
||||
<OnClick>
|
||||
Postal:MailFrameTab_OnClick()
|
||||
</OnClick>
|
||||
</Scripts>
|
||||
</Button>
|
||||
|
||||
<Frame name="PostalAcceptSendFrame" toplevel="true" frameStrata="DIALOG" movable="true" enableMouse="true" hidden="true" parent="PostalFrame">
|
||||
<Size>
|
||||
<AbsDimension x="400" y="150"/>
|
||||
</Size>
|
||||
<Anchors>
|
||||
<Anchor point="CENTER" relativeTo="UIParent"/>
|
||||
</Anchors>
|
||||
<Backdrop bgFile="Interface\DialogFrame\UI-DialogBox-Background" edgeFile="Interface\DialogFrame\UI-DialogBox-Border" tile="true">
|
||||
<BackgroundInsets>
|
||||
<AbsInset left="11" right="12" top="12" bottom="11"/>
|
||||
</BackgroundInsets>
|
||||
<TileSize>
|
||||
<AbsValue val="32"/>
|
||||
</TileSize>
|
||||
<EdgeSize>
|
||||
<AbsValue val="32"/>
|
||||
</EdgeSize>
|
||||
</Backdrop>
|
||||
<Layers>
|
||||
<Layer level="ARTWORK">
|
||||
<Texture name="$parentHeaderTexture" file="Interface\DialogFrame\UI-DialogBox-Header">
|
||||
<Size>
|
||||
<AbsDimension x="256" y="64"/>
|
||||
</Size>
|
||||
<Anchors>
|
||||
<Anchor point="TOP">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="12"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
</Texture>
|
||||
<FontString inherits="GameFontNormal" text="POSTAL_SEND">
|
||||
<Anchors>
|
||||
<Anchor point="TOP" relativeTo="$parentHeaderTexture">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="-14"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
</FontString>
|
||||
<FontString name="$parentInfo" justifyV="top" inherits="GameFontNormal" text="POSTAL_SENDINFO">
|
||||
<Size>
|
||||
<AbsDimension x="350" y="32"/>
|
||||
</Size>
|
||||
<Anchors>
|
||||
<Anchor point="TOP">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="-78"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
</FontString>
|
||||
<FontString name="$parentInfoString" justifyV="top" inherits="GameFontNormal" text="POSTAL_SENDINFO2">
|
||||
<Size>
|
||||
<AbsDimension x="350" y="12"/>
|
||||
</Size>
|
||||
<Anchors>
|
||||
<Anchor point="TOP">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="-30"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
</FontString>
|
||||
<FontString name="$parentInfoItems" justifyV="top" inherits="GameFontNormal" text="">
|
||||
<Size>
|
||||
<AbsDimension x="350" y="12"/>
|
||||
</Size>
|
||||
<Anchors>
|
||||
<Anchor point="TOP" relativeTo="$parentInfoString" relativePoint="BOTTOM">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="-2"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
</FontString>
|
||||
</Layer>
|
||||
</Layers>
|
||||
<Frames>
|
||||
<Frame name="$parentMoneyFrame" inherits="SmallMoneyFrameTemplate">
|
||||
<Anchors>
|
||||
<Anchor point="TOP" relativePoint="BOTTOM" relativeTo="$parentInfo">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="5"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
<Scripts>
|
||||
<OnLoad>
|
||||
SmallMoneyFrame_OnLoad();
|
||||
MoneyFrame_SetType("STATIC");
|
||||
MoneyFrame_Update(this:GetName(), GetSendMailPrice())
|
||||
</OnLoad>
|
||||
</Scripts>
|
||||
</Frame>
|
||||
<Button name="$parentSendButton" hidden="false" inherits="GameMenuButtonTemplate" text="POSTAL_SENDBUTTON">
|
||||
<Size>
|
||||
<AbsDimension x="60" y="21"/>
|
||||
</Size>
|
||||
<Anchors>
|
||||
<Anchor point="BOTTOM" relativePoint="BOTTOM">
|
||||
<Offset>
|
||||
<AbsDimension x="-32" y="8"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
<Scripts>
|
||||
<OnClick>
|
||||
PostalGlobalFrame.queue = Postal:FillItemTable();
|
||||
PostalGlobalFrame.total = getn(PostalGlobalFrame.queue);
|
||||
Postal:ClearItems();
|
||||
PostalGlobalFrame:Show();
|
||||
this:GetParent():Hide();
|
||||
POSTAL_CANSENDNEXT = 1
|
||||
</OnClick>
|
||||
</Scripts>
|
||||
</Button>
|
||||
<Button name="$parentCancelButton" hidden="false" inherits="GameMenuButtonTemplate" text="POSTAL_CANCELBUTTON">
|
||||
<Size>
|
||||
<AbsDimension x="60" y="21"/>
|
||||
</Size>
|
||||
<Anchors>
|
||||
<Anchor point="BOTTOM" relativePoint="BOTTOM">
|
||||
<Offset>
|
||||
<AbsDimension x="32" y="8"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
<Scripts>
|
||||
<OnClick>
|
||||
this:GetParent():Hide()
|
||||
</OnClick>
|
||||
</Scripts>
|
||||
</Button>
|
||||
</Frames>
|
||||
<Scripts>
|
||||
<OnShow>
|
||||
getglobal(this:GetName() .. "InfoItems"):SetText(PostalFrame.num .. " " .. POSTAL_ITEMS);
|
||||
MoneyFrame_Update(this:GetName() .. "MoneyFrame", PostalFrame.num*GetSendMailPrice())
|
||||
</OnShow>
|
||||
</Scripts>
|
||||
</Frame>
|
||||
<Frame name="PostalInboxFrame" parent="UIParent">
|
||||
<Scripts>
|
||||
<OnUpdate>
|
||||
Postal:Inbox_OnUpdate(arg1)
|
||||
</OnUpdate>
|
||||
</Scripts>
|
||||
</Frame>
|
||||
<CheckButton name="PostalBoxItemCBTemplate" hidden="true" virtual="true" inherits="OptionsCheckButtonTemplate">
|
||||
<HitRectInsets>
|
||||
<AbsInset left="0" right="0" top="0" bottom="0"/>
|
||||
</HitRectInsets>
|
||||
<Size>
|
||||
<AbsDimension x="24" y="24"/>
|
||||
</Size>
|
||||
<Anchors>
|
||||
<Anchor point="RIGHT" relativePoint="LEFT">
|
||||
<Offset>
|
||||
<AbsDimension x="1" y="0"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
<Scripts>
|
||||
<OnClick>
|
||||
Postal_Inbox_SetSelected()
|
||||
</OnClick>
|
||||
</Scripts>
|
||||
</CheckButton>
|
||||
<CheckButton name="PostalBoxItem1CB" id="1" hidden="false" parent="MailItem1" inherits="PostalBoxItemCBTemplate"/>
|
||||
<CheckButton name="PostalBoxItem2CB" id="2" hidden="false" parent="MailItem2" inherits="PostalBoxItemCBTemplate"/>
|
||||
<CheckButton name="PostalBoxItem3CB" id="3" hidden="false" parent="MailItem3" inherits="PostalBoxItemCBTemplate"/>
|
||||
<CheckButton name="PostalBoxItem4CB" id="4" hidden="false" parent="MailItem4" inherits="PostalBoxItemCBTemplate"/>
|
||||
<CheckButton name="PostalBoxItem5CB" id="5" hidden="false" parent="MailItem5" inherits="PostalBoxItemCBTemplate"/>
|
||||
<CheckButton name="PostalBoxItem6CB" id="6" hidden="false" parent="MailItem6" inherits="PostalBoxItemCBTemplate"/>
|
||||
<CheckButton name="PostalBoxItem7CB" id="7" hidden="false" parent="MailItem7" inherits="PostalBoxItemCBTemplate"/>
|
||||
<Button name="PostalInboxOpenSelected" parent="InboxFrame" inherits="UIPanelButtonTemplate" text="POSTAL_INBOX_OPENSELECTED">
|
||||
<Size>
|
||||
<AbsDimension x="120" y="25"/>
|
||||
</Size>
|
||||
<Anchors>
|
||||
<Anchor relativePoint="TOP" point="RIGHT">
|
||||
<Offset>
|
||||
<AbsDimension x="5" y="-53"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
<Scripts>
|
||||
<OnClick>
|
||||
Postal_Inbox_OpenSelected()
|
||||
</OnClick>
|
||||
</Scripts>
|
||||
</Button>
|
||||
<Button name="PostalInboxOpenAllButton" parent="InboxFrame" inherits="UIPanelButtonTemplate" text="POSTAL_INBOX_OPENALL">
|
||||
<Size>
|
||||
<AbsDimension x="120" y="25"/>
|
||||
</Size>
|
||||
<Anchors>
|
||||
<Anchor relativePoint="TOP" point="LEFT">
|
||||
<Offset>
|
||||
<AbsDimension x="10" y="-53"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
<Scripts>
|
||||
<OnClick>
|
||||
ShowUIPanel(PostalInboxOpenAll)
|
||||
</OnClick>
|
||||
</Scripts>
|
||||
</Button>
|
||||
<Frame name="PostalInboxOpenAll" toplevel="true" frameStrata="DIALOG" movable="true" enableMouse="true" hidden="true" parent="MailFrame">
|
||||
<Size>
|
||||
<AbsDimension x="400" y="100"/>
|
||||
</Size>
|
||||
<Anchors>
|
||||
<Anchor point="CENTER" relativeTo="UIParent"/>
|
||||
</Anchors>
|
||||
<Backdrop bgFile="Interface\DialogFrame\UI-DialogBox-Background" edgeFile="Interface\DialogFrame\UI-DialogBox-Border" tile="true">
|
||||
<BackgroundInsets>
|
||||
<AbsInset left="11" right="12" top="12" bottom="11"/>
|
||||
</BackgroundInsets>
|
||||
<TileSize>
|
||||
<AbsValue val="32"/>
|
||||
</TileSize>
|
||||
<EdgeSize>
|
||||
<AbsValue val="32"/>
|
||||
</EdgeSize>
|
||||
</Backdrop>
|
||||
<Layers>
|
||||
<Layer level="ARTWORK">
|
||||
<Texture name="$parentHeaderTexture" file="Interface\DialogFrame\UI-DialogBox-Header">
|
||||
<Size>
|
||||
<AbsDimension x="256" y="64"/>
|
||||
</Size>
|
||||
<Anchors>
|
||||
<Anchor point="TOP">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="12"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
</Texture>
|
||||
<FontString inherits="GameFontNormal" text="POSTAL_INBOX_OPENALLTITLE">
|
||||
<Anchors>
|
||||
<Anchor point="TOP" relativeTo="$parentHeaderTexture">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="-14"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
</FontString>
|
||||
<FontString name="$parentInfo" justifyV="top" inherits="GameFontNormal" text="POSTAL_INBOX_OPENALLCONFIRMATION">
|
||||
<Size>
|
||||
<AbsDimension x="350" y="32"/>
|
||||
</Size>
|
||||
<Anchors>
|
||||
<Anchor point="CENTER">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="4"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
</FontString>
|
||||
</Layer>
|
||||
</Layers>
|
||||
<Frames>
|
||||
<Button name="$parentOpenButton" hidden="false" inherits="GameMenuButtonTemplate" text="POSTAL_INBOX_OPENALL">
|
||||
<Size>
|
||||
<AbsDimension x="125" y="32"/>
|
||||
</Size>
|
||||
<Anchors>
|
||||
<Anchor point="BOTTOMRIGHT" relativePoint="BOTTOM">
|
||||
<Offset>
|
||||
<AbsDimension x="-8" y="16"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
<Scripts>
|
||||
<OnClick>
|
||||
Postal_Inbox_OpenSelected(1);
|
||||
HideUIPanel(this:GetParent())
|
||||
</OnClick>
|
||||
</Scripts>
|
||||
</Button>
|
||||
<Button name="$parentCancelButton" hidden="false" inherits="GameMenuButtonTemplate" text="POSTAL_CANCELBUTTON">
|
||||
<Size>
|
||||
<AbsDimension x="125" y="32"/>
|
||||
</Size>
|
||||
<Anchors>
|
||||
<Anchor point="BOTTOMLEFT" relativePoint="BOTTOM">
|
||||
<Offset>
|
||||
<AbsDimension x="8" y="16"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
<Scripts>
|
||||
<OnClick>
|
||||
HideUIPanel(this:GetParent())
|
||||
</OnClick>
|
||||
</Scripts>
|
||||
</Button>
|
||||
</Frames>
|
||||
</Frame>
|
||||
|
||||
<!-- Mail forwarding -->
|
||||
<Button name="OpenMailForwardButton" parent="OpenMailFrame" inherits="UIPanelButtonTemplate" text="Forward">
|
||||
<Size>
|
||||
<AbsDimension x="82" y="22"/>
|
||||
</Size>
|
||||
<Anchors>
|
||||
<Anchor point="RIGHT" relativeTo="OpenMailReplyButton" relativePoint="LEFT">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="0"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
<Scripts>
|
||||
<OnClick>
|
||||
Postal:OpenReply()
|
||||
</OnClick>
|
||||
</Scripts>
|
||||
</Button>
|
||||
<Frame name="PostalForwardFrame" parent="UIParent">
|
||||
<Scripts>
|
||||
<OnUpdate>
|
||||
Postal:Forward_OnUpdate(arg1)
|
||||
</OnUpdate>
|
||||
</Scripts>
|
||||
</Frame>
|
||||
|
||||
<Frame name="PostalGlobalFrame" parent="UIParent" hidden="true">
|
||||
<Scripts>
|
||||
<OnUpdate>
|
||||
Postal:ProcessQueue(arg1)
|
||||
</OnUpdate>
|
||||
</Scripts>
|
||||
</Frame>
|
||||
<GameTooltip name="PostalTooltip" inherits="GameTooltipTemplate"></GameTooltip>
|
||||
</Ui>
|
||||
@@ -0,0 +1,728 @@
|
||||
--[[
|
||||
Name: AceAddon-2.0
|
||||
Revision: $Rev: 10447 $
|
||||
Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team)
|
||||
Inspired By: Ace 1.x by Turan (turan@gryphon.com)
|
||||
Website: http://www.wowace.com/
|
||||
Documentation: http://www.wowace.com/index.php/AceAddon-2.0
|
||||
SVN: http://svn.wowace.com/root/trunk/Ace2/AceAddon-2.0
|
||||
Description: Base for all Ace addons to inherit from.
|
||||
Dependencies: AceLibrary, AceOO-2.0, AceEvent-2.0, (optional) AceConsole-2.0
|
||||
]]
|
||||
|
||||
local MAJOR_VERSION = "AceAddon-2.0"
|
||||
local MINOR_VERSION = "$Revision: 10447 $"
|
||||
|
||||
-- This ensures the code is only executed if the libary doesn't already exist, or is a newer version
|
||||
if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary.") end
|
||||
if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end
|
||||
|
||||
if not AceLibrary:HasInstance("AceOO-2.0") then error(MAJOR_VERSION .. " requires AceOO-2.0.") end
|
||||
|
||||
-- Localization
|
||||
local STANDBY, TITLE, NOTES, VERSION, AUTHOR, DATE, CATEGORY, EMAIL, WEBSITE, CATEGORIES, ABOUT, PRINT_ADDON_INFO
|
||||
if false then -- GetLocale() == "deDE"
|
||||
else -- enUS
|
||||
STANDBY = "|cffff5050(standby)|r"
|
||||
|
||||
TITLE = "Title"
|
||||
NOTES = "Notes"
|
||||
VERSION = "Version"
|
||||
AUTHOR = "Author"
|
||||
DATE = "Date"
|
||||
CATEGORY = "Category"
|
||||
EMAIL = "E-mail"
|
||||
WEBSITE = "Website"
|
||||
|
||||
ABOUT = "About"
|
||||
PRINT_ADDON_INFO = "Print out addon info"
|
||||
|
||||
CATEGORIES = {
|
||||
["Action Bars"] = "Action Bars",
|
||||
["Auction"] = "Auction",
|
||||
["Audio"] = "Audio",
|
||||
["Battlegrounds/PvP"] = "Battlegrounds/PvP",
|
||||
["Buffs"] = "Buffs",
|
||||
["Chat/Communication"] = "Chat/Communication",
|
||||
["Druid"] = "Druid",
|
||||
["Hunter"] = "Hunter",
|
||||
["Mage"] = "Mage",
|
||||
["Paladin"] = "Paladin",
|
||||
["Priest"] = "Priest",
|
||||
["Rogue"] = "Rogue",
|
||||
["Shaman"] = "Shaman",
|
||||
["Warlock"] = "Warlock",
|
||||
["Warrior"] = "Warrior",
|
||||
["Healer"] = "Healer",
|
||||
["Tank"] = "Tank",
|
||||
["Caster"] = "Caster",
|
||||
["Combat"] = "Combat",
|
||||
["Compilations"] = "Compilations",
|
||||
["Data Export"] = "Data Export",
|
||||
["Development Tools "] = "Development Tools ",
|
||||
["Guild"] = "Guild",
|
||||
["Frame Modification"] = "Frame Modification",
|
||||
["Interface Enhancements"] = "Interface Enhancements",
|
||||
["Inventory"] = "Inventory",
|
||||
["Library"] = "Library",
|
||||
["Map"] = "Map",
|
||||
["Mail"] = "Mail",
|
||||
["Miscellaneous"] = "Miscellaneous",
|
||||
["Quest"] = "Quest",
|
||||
["Raid"] = "Raid",
|
||||
["Tradeskill"] = "Tradeskill",
|
||||
["UnitFrame"] = "UnitFrame",
|
||||
}
|
||||
end
|
||||
|
||||
setmetatable(CATEGORIES, { __index = function(self, key) -- case-insensitive
|
||||
local lowerKey = string.lower(key)
|
||||
for k,v in CATEGORIES do
|
||||
if string.lower(k) == lowerKey then
|
||||
return v
|
||||
end
|
||||
end
|
||||
end })
|
||||
|
||||
-- Create the library object
|
||||
|
||||
local AceOO = AceLibrary("AceOO-2.0")
|
||||
local AceAddon = AceOO.Class()
|
||||
local AceEvent
|
||||
local AceConsole
|
||||
local AceModuleCore
|
||||
|
||||
function AceAddon:ToString()
|
||||
return "AceAddon"
|
||||
end
|
||||
|
||||
local function print(text)
|
||||
DEFAULT_CHAT_FRAME:AddMessage(text)
|
||||
end
|
||||
|
||||
function AceAddon:ADDON_LOADED(name)
|
||||
while table.getn(self.nextAddon) > 0 do
|
||||
local addon = table.remove(self.nextAddon, 1)
|
||||
table.insert(self.addons, addon)
|
||||
if not self.addons[name] then
|
||||
self.addons[name] = addon
|
||||
end
|
||||
self:InitializeAddon(addon, name)
|
||||
end
|
||||
end
|
||||
|
||||
local function RegisterOnEnable(self)
|
||||
if DEFAULT_CHAT_FRAME and DEFAULT_CHAT_FRAME.defaultLanguage then -- HACK
|
||||
AceAddon.playerLoginFired = true
|
||||
end
|
||||
if AceAddon.playerLoginFired then
|
||||
AceAddon.addonsStarted[self] = true
|
||||
if (type(self.IsActive) ~= "function" or self:IsActive()) and (not AceModuleCore or not AceModuleCore:IsModule(self) or AceModuleCore:IsModuleActive(self)) then
|
||||
local current = self.class
|
||||
while true do
|
||||
if current == AceOO.Class then
|
||||
break
|
||||
end
|
||||
if current.mixins then
|
||||
for mixin in pairs(current.mixins) do
|
||||
if type(mixin.OnEmbedEnable) == "function" then
|
||||
mixin:OnEmbedEnable(self)
|
||||
end
|
||||
end
|
||||
end
|
||||
current = current.super
|
||||
end
|
||||
if type(self.OnEnable) == "function" then
|
||||
self:OnEnable()
|
||||
end
|
||||
end
|
||||
else
|
||||
if not AceAddon.addonsToOnEnable then
|
||||
AceAddon.addonsToOnEnable = {}
|
||||
end
|
||||
table.insert(AceAddon.addonsToOnEnable, self)
|
||||
end
|
||||
end
|
||||
|
||||
local function stripSpaces(text)
|
||||
if type(text) == "string" then
|
||||
return (string.gsub(string.gsub(text, "^%s*(.-)%s*$", "%1"), "%s%s+", " "))
|
||||
end
|
||||
return text
|
||||
end
|
||||
|
||||
function AceAddon:InitializeAddon(addon, name)
|
||||
if addon.name == nil then
|
||||
addon.name = name
|
||||
end
|
||||
if GetAddOnMetadata then
|
||||
-- TOC checks
|
||||
if addon.title == nil then
|
||||
addon.title = GetAddOnMetadata(name, "Title")
|
||||
if addon.title then
|
||||
local num = string.find(addon.title, " |cff7fff7f %-Ace2%-|r$")
|
||||
if num then
|
||||
addon.title = string.sub(addon.title, 1, num - 1)
|
||||
end
|
||||
addon.title = stripSpaces(addon.title)
|
||||
end
|
||||
end
|
||||
if addon.notes == nil then
|
||||
addon.notes = GetAddOnMetadata(name, "Notes")
|
||||
addon.notes = stripSpaces(addon.notes)
|
||||
end
|
||||
if addon.version == nil then
|
||||
addon.version = GetAddOnMetadata(name, "Version")
|
||||
if addon.version then
|
||||
if string.find(addon.version, "%$Revision: (%d+) %$") then
|
||||
addon.version = string.gsub(addon.version, "%$Revision: (%d+) %$", "%1")
|
||||
elseif string.find(addon.version, "%$Rev: (%d+) %$") then
|
||||
addon.version = string.gsub(addon.version, "%$Rev: (%d+) %$", "%1")
|
||||
elseif string.find(addon.version, "%$LastChangedRevision: (%d+) %$") then
|
||||
addon.version = string.gsub(addon.version, "%$LastChangedRevision: (%d+) %$", "%1")
|
||||
end
|
||||
end
|
||||
addon.version = stripSpaces(addon.version)
|
||||
end
|
||||
if addon.author == nil then
|
||||
addon.author = GetAddOnMetadata(name, "Author")
|
||||
addon.author = stripSpaces(addon.author)
|
||||
end
|
||||
if addon.date == nil then
|
||||
addon.date = GetAddOnMetadata(name, "X-Date") or GetAddOnMetadata(name, "X-ReleaseDate")
|
||||
if addon.date then
|
||||
if string.find(addon.date, "%$Date: (.-) %$") then
|
||||
addon.date = string.gsub(addon.date, "%$Date: (.-) %$", "%1")
|
||||
elseif string.find(addon.date, "%$LastChangedDate: (.-) %$") then
|
||||
addon.date = string.gsub(addon.date, "%$LastChangedDate: (.-) %$", "%1")
|
||||
end
|
||||
end
|
||||
addon.date = stripSpaces(addon.date)
|
||||
end
|
||||
if addon.category == nil then
|
||||
addon.category = GetAddOnMetadata(name, "X-Category")
|
||||
addon.category = stripSpaces(addon.category)
|
||||
end
|
||||
if addon.email == nil then
|
||||
addon.email = GetAddOnMetadata(name, "X-eMail") or GetAddOnMetadata(name, "X-Email")
|
||||
addon.email = stripSpaces(addon.email)
|
||||
end
|
||||
if addon.website == nil then
|
||||
addon.website = GetAddOnMetadata(name, "X-Website")
|
||||
addon.website = stripSpaces(addon.website)
|
||||
end
|
||||
end
|
||||
local current = addon.class
|
||||
while true do
|
||||
if current == AceOO.Class then
|
||||
break
|
||||
end
|
||||
if current.mixins then
|
||||
for mixin in pairs(current.mixins) do
|
||||
if type(mixin.OnEmbedInitialize) == "function" then
|
||||
mixin:OnEmbedInitialize(addon, name)
|
||||
end
|
||||
end
|
||||
end
|
||||
current = current.super
|
||||
end
|
||||
if type(addon.OnInitialize) == "function" then
|
||||
addon:OnInitialize(name)
|
||||
end
|
||||
RegisterOnEnable(addon)
|
||||
end
|
||||
|
||||
function AceAddon.prototype:PrintAddonInfo()
|
||||
local x
|
||||
if self.title then
|
||||
x = "|cffffff7f" .. tostring(self.title) .. "|r"
|
||||
elseif self.name then
|
||||
x = "|cffffff7f" .. tostring(self.name) .. "|r"
|
||||
else
|
||||
x = "|cffffff7f<" .. tostring(self.class) .. " instance>|r"
|
||||
end
|
||||
if type(self.IsActive) == "function" then
|
||||
if not self:IsActive() then
|
||||
x = x .. " " .. STANDBY
|
||||
end
|
||||
end
|
||||
if self.version then
|
||||
x = x .. " - |cffffff7f" .. tostring(self.version) .. "|r"
|
||||
end
|
||||
if self.notes then
|
||||
x = x .. " - " .. tostring(self.notes)
|
||||
end
|
||||
print(x)
|
||||
if self.author then
|
||||
print(" - |cffffff7f" .. AUTHOR .. ":|r " .. tostring(self.author))
|
||||
end
|
||||
if self.date then
|
||||
print(" - |cffffff7f" .. DATE .. ":|r " .. tostring(self.date))
|
||||
end
|
||||
if self.category then
|
||||
local category = CATEGORIES[self.category]
|
||||
if category then
|
||||
print(" - |cffffff7f" .. CATEGORY .. ":|r " .. category)
|
||||
end
|
||||
end
|
||||
if self.email then
|
||||
print(" - |cffffff7f" .. EMAIL .. ":|r " .. tostring(self.email))
|
||||
end
|
||||
if self.website then
|
||||
print(" - |cffffff7f" .. WEBSITE .. ":|r " .. tostring(self.website))
|
||||
end
|
||||
end
|
||||
|
||||
local options
|
||||
function AceAddon:GetAceOptionsDataTable(target)
|
||||
if not options then
|
||||
options = {
|
||||
about = {
|
||||
name = ABOUT,
|
||||
desc = PRINT_ADDON_INFO,
|
||||
type = "execute",
|
||||
func = "PrintAddonInfo",
|
||||
order = -1,
|
||||
}
|
||||
}
|
||||
end
|
||||
return options
|
||||
end
|
||||
|
||||
function AceAddon:PLAYER_LOGIN()
|
||||
self.playerLoginFired = true
|
||||
if self.addonsToOnEnable then
|
||||
while table.getn(self.addonsToOnEnable) > 0 do
|
||||
local addon = table.remove(self.addonsToOnEnable, 1)
|
||||
self.addonsStarted[addon] = true
|
||||
if (type(addon.IsActive) ~= "function" or addon:IsActive()) and (not AceModuleCore or not AceModuleCore:IsModule(addon) or AceModuleCore:IsModuleActive(addon)) then
|
||||
local current = addon.class
|
||||
while true do
|
||||
if current == AceOO.Class then
|
||||
break
|
||||
end
|
||||
if current.mixins then
|
||||
for mixin in pairs(current.mixins) do
|
||||
if type(mixin.OnEmbedEnable) == "function" then
|
||||
mixin:OnEmbedEnable(addon)
|
||||
end
|
||||
end
|
||||
end
|
||||
current = current.super
|
||||
end
|
||||
if type(addon.OnEnable) == "function" then
|
||||
addon:OnEnable()
|
||||
end
|
||||
end
|
||||
end
|
||||
self.addonsToOnEnable = nil
|
||||
end
|
||||
end
|
||||
|
||||
function AceAddon.prototype:Inject(t)
|
||||
AceAddon:argCheck(t, 2, "table")
|
||||
for k,v in pairs(t) do
|
||||
self[k] = v
|
||||
end
|
||||
end
|
||||
|
||||
function AceAddon.prototype:init()
|
||||
if not AceEvent then
|
||||
error(MAJOR_VERSION .. " requires AceEvent-2.0", 4)
|
||||
end
|
||||
AceAddon.super.prototype.init(self)
|
||||
|
||||
self.super = self.class.prototype
|
||||
|
||||
AceAddon:RegisterEvent("ADDON_LOADED", "ADDON_LOADED", true)
|
||||
table.insert(AceAddon.nextAddon, self)
|
||||
end
|
||||
|
||||
function AceAddon.prototype:ToString()
|
||||
local x
|
||||
if type(self.title) == "string" then
|
||||
x = self.title
|
||||
elseif type(self.name) == "string" then
|
||||
x = self.name
|
||||
else
|
||||
x = "<" .. tostring(self.class) .. " instance>"
|
||||
end
|
||||
if (type(self.IsActive) == "function" and not self:IsActive()) or (AceModuleCore and AceModuleCore:IsModule(addon) and AceModuleCore:IsModuleActive(addon)) then
|
||||
x = x .. " " .. STANDBY
|
||||
end
|
||||
return x
|
||||
end
|
||||
|
||||
AceAddon.new = function(self, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12, m13, m14, m15, m16, m17, m18, m19, m20)
|
||||
local class = AceAddon:pcall(AceOO.Classpool, self, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12, m13, m14, m15, m16, m17, m18, m19, m20)
|
||||
return class:new()
|
||||
end
|
||||
|
||||
local function external(self, major, instance)
|
||||
if major == "AceEvent-2.0" then
|
||||
AceEvent = instance
|
||||
|
||||
AceEvent:embed(self)
|
||||
|
||||
self:RegisterEvent("PLAYER_LOGIN", "PLAYER_LOGIN", true)
|
||||
elseif major == "AceConsole-2.0" then
|
||||
AceConsole = instance
|
||||
|
||||
local slashCommands = { "/ace2" }
|
||||
local _,_,_,enabled,loadable = GetAddOnInfo("Ace")
|
||||
if not enabled or not loadable then
|
||||
table.insert(slashCommands, "/ace")
|
||||
end
|
||||
local function listAddon(addon, depth)
|
||||
if not depth then
|
||||
depth = 0
|
||||
end
|
||||
|
||||
local s = string.rep(" ", depth) .. " - " .. tostring(addon)
|
||||
if addon.version then
|
||||
s = s .. " - |cffffff7f" .. tostring(addon.version) .. "|r"
|
||||
end
|
||||
if addon.slashCommand then
|
||||
s = s .. " |cffffff7f(" .. tostring(addon.slashCommand) .. ")|r"
|
||||
end
|
||||
print(s)
|
||||
if type(addon.modules) == "table" then
|
||||
local i = 0
|
||||
for k,v in pairs(addon.modules) do
|
||||
i = i + 1
|
||||
if i == 6 then
|
||||
print(string.rep(" ", depth + 1) .. " - more...")
|
||||
break
|
||||
else
|
||||
listAddon(v, depth + 1)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
local function listNormalAddon(i)
|
||||
local name,_,_,enabled,loadable = GetAddOnInfo(i)
|
||||
if not loadable then
|
||||
enabled = false
|
||||
end
|
||||
if self.addons[name] then
|
||||
local addon = self.addons[name]
|
||||
if not AceCoreAddon or not AceCoreAddon:IsModule(addon) then
|
||||
listAddon(addon)
|
||||
end
|
||||
else
|
||||
local s = " - " .. tostring(GetAddOnMetadata(i, "Title") or name)
|
||||
local version = GetAddOnMetadata(i, "Version")
|
||||
if version then
|
||||
if string.find(version, "%$Revision: (%d+) %$") then
|
||||
version = string.gsub(version, "%$Revision: (%d+) %$", "%1")
|
||||
elseif string.find(version, "%$Rev: (%d+) %$") then
|
||||
version = string.gsub(version, "%$Rev: (%d+) %$", "%1")
|
||||
elseif string.find(version, "%$LastChangedRevision: (%d+) %$") then
|
||||
version = string.gsub(version, "%$LastChangedRevision: (%d+) %$", "%1")
|
||||
end
|
||||
s = s .. " - |cffffff7f" .. version .. "|r"
|
||||
end
|
||||
if not enabled then
|
||||
s = s .. " |cffff0000(disabled)|r"
|
||||
end
|
||||
if IsAddOnLoadOnDemand(i) then
|
||||
s = s .. " |cff00ff00[LoD]|r"
|
||||
end
|
||||
print(s)
|
||||
end
|
||||
end
|
||||
local function mySort(alpha, bravo)
|
||||
return tostring(alpha) < tostring(bravo)
|
||||
end
|
||||
AceConsole.RegisterChatCommand(self, slashCommands, {
|
||||
desc = "AddOn development framework",
|
||||
name = "Ace2",
|
||||
type = "group",
|
||||
args = {
|
||||
about = {
|
||||
desc = "Get information about Ace2",
|
||||
name = "About",
|
||||
type = "execute",
|
||||
func = function()
|
||||
print("|cffffff7fAce2|r - |cffffff7f2.0." .. string.gsub(MINOR_VERSION, "%$Revision: (%d+) %$", "%1") .. "|r - AddOn development framework")
|
||||
print(" - |cffffff7f" .. AUTHOR .. ":|r Ace Development Team")
|
||||
print(" - |cffffff7f" .. WEBSITE .. ":|r http://www.wowace.com/")
|
||||
end
|
||||
},
|
||||
list = {
|
||||
desc = "List addons",
|
||||
name = "List",
|
||||
type = "group",
|
||||
args = {
|
||||
ace2 = {
|
||||
desc = "List addons using Ace2",
|
||||
name = "Ace2",
|
||||
type = "execute",
|
||||
func = function()
|
||||
print("|cffffff7fAddon list:|r")
|
||||
local AceCoreAddon = AceLibrary:HasInstance("AceCoreAddon-2.0") and AceLibrary("AceCoreAddon-2.0")
|
||||
table.sort(self.addons, mySort)
|
||||
for _,v in ipairs(self.addons) do
|
||||
if not AceCoreAddon or not AceCoreAddon:IsModule(v) then
|
||||
listAddon(v)
|
||||
end
|
||||
end
|
||||
end
|
||||
},
|
||||
all = {
|
||||
desc = "List all addons",
|
||||
name = "All",
|
||||
type = "execute",
|
||||
func = function()
|
||||
print("|cffffff7fAddon list:|r")
|
||||
local AceCoreAddon = AceLibrary:HasInstance("AceCoreAddon-2.0") and AceLibrary("AceCoreAddon-2.0")
|
||||
local count = GetNumAddOns()
|
||||
for i = 1, count do
|
||||
listNormalAddon(i)
|
||||
end
|
||||
end
|
||||
},
|
||||
enabled = {
|
||||
desc = "List all enabled addons",
|
||||
name = "Enabled",
|
||||
type = "execute",
|
||||
func = function()
|
||||
print("|cffffff7fAddon list:|r")
|
||||
local AceCoreAddon = AceLibrary:HasInstance("AceCoreAddon-2.0") and AceLibrary("AceCoreAddon-2.0")
|
||||
local count = GetNumAddOns()
|
||||
for i = 1, count do
|
||||
local _,_,_,enabled,loadable = GetAddOnInfo(i)
|
||||
if enabled and loadable then
|
||||
listNormalAddon(i)
|
||||
end
|
||||
end
|
||||
end
|
||||
},
|
||||
disabled = {
|
||||
desc = "List all disabled addons",
|
||||
name = "Disabled",
|
||||
type = "execute",
|
||||
func = function()
|
||||
print("|cffffff7fAddon list:|r")
|
||||
local AceCoreAddon = AceLibrary:HasInstance("AceCoreAddon-2.0") and AceLibrary("AceCoreAddon-2.0")
|
||||
local count = GetNumAddOns()
|
||||
for i = 1, count do
|
||||
local _,_,_,enabled,loadable = GetAddOnInfo(i)
|
||||
if not enabled or not loadable then
|
||||
listNormalAddon(i)
|
||||
end
|
||||
end
|
||||
end
|
||||
},
|
||||
lod = {
|
||||
desc = "List all LoadOnDemand addons",
|
||||
name = "LoadOnDemand",
|
||||
type = "execute",
|
||||
func = function()
|
||||
print("|cffffff7fAddon list:|r")
|
||||
local AceCoreAddon = AceLibrary:HasInstance("AceCoreAddon-2.0") and AceLibrary("AceCoreAddon-2.0")
|
||||
local count = GetNumAddOns()
|
||||
for i = 1, count do
|
||||
if IsAddOnLoadOnDemand(i) then
|
||||
listNormalAddon(i)
|
||||
end
|
||||
end
|
||||
end
|
||||
},
|
||||
ace1 = {
|
||||
desc = "List all addons using Ace1",
|
||||
name = "Ace 1.x",
|
||||
type = "execute",
|
||||
func = function()
|
||||
print("|cffffff7fAddon list:|r")
|
||||
local count = GetNumAddOns()
|
||||
for i = 1, count do
|
||||
local dep1, dep2, dep3, dep4 = GetAddOnDependencies(i)
|
||||
if dep1 == "Ace" or dep2 == "Ace" or dep3 == "Ace" or dep4 == "Ace" then
|
||||
listNormalAddon(i)
|
||||
end
|
||||
end
|
||||
end
|
||||
},
|
||||
libs = {
|
||||
desc = "List all libraries using AceLibrary",
|
||||
name = "Libraries",
|
||||
type = "execute",
|
||||
func = function()
|
||||
if type(AceLibrary) == "table" and type(AceLibrary.libs) == "table" then
|
||||
print("|cffffff7fLibrary list:|r")
|
||||
for name, data in pairs(AceLibrary.libs) do
|
||||
local s
|
||||
if data.minor then
|
||||
s = " - " .. tostring(name) .. "." .. tostring(data.minor)
|
||||
else
|
||||
s = " - " .. tostring(name)
|
||||
end
|
||||
if AceLibrary(name).slashCommand then
|
||||
s = s .. " |cffffff7f(" .. tostring(AceLibrary(name).slashCommand) .. "|cffffff7f)"
|
||||
end
|
||||
print(s)
|
||||
end
|
||||
end
|
||||
end
|
||||
},
|
||||
search = {
|
||||
desc = "Search by name",
|
||||
name = "Search",
|
||||
type = "text",
|
||||
usage = "<keyword>",
|
||||
input = true,
|
||||
get = false,
|
||||
set = function(...)
|
||||
for i,v in ipairs(arg) do
|
||||
arg[i] = string.lower(string.gsub(string.gsub(v, '%*', '.*'), '%%', '%%%%'))
|
||||
end
|
||||
local count = GetNumAddOns()
|
||||
for i = 1, count do
|
||||
local name = GetAddOnInfo(i)
|
||||
local good = true
|
||||
for _,v in ipairs(arg) do
|
||||
if not string.find(string.lower(name), v) then
|
||||
good = false
|
||||
break
|
||||
end
|
||||
end
|
||||
if good then
|
||||
listNormalAddon(i)
|
||||
end
|
||||
end
|
||||
end
|
||||
}
|
||||
},
|
||||
},
|
||||
enable = {
|
||||
desc = "Enable addon",
|
||||
name = "Enable",
|
||||
type = "text",
|
||||
usage = "<addon>",
|
||||
get = false,
|
||||
set = function(text)
|
||||
local name,title,_,_,_,reason = GetAddOnInfo(text)
|
||||
if reason == "MISSING" then
|
||||
print(string.format("|cffffff7fAce2:|r AddOn %q does not exist", text))
|
||||
else
|
||||
EnableAddOn(text)
|
||||
print(string.format("|cffffff7fAce2:|r %s is now enabled", title or name))
|
||||
end
|
||||
end,
|
||||
},
|
||||
disable = {
|
||||
desc = "Disable addon",
|
||||
name = "Disable",
|
||||
type = "text",
|
||||
usage = "<addon>",
|
||||
get = false,
|
||||
set = function(text)
|
||||
local name,title,_,_,_,reason = GetAddOnInfo(text)
|
||||
if reason == "MISSING" then
|
||||
print(string.format("|cffffff7fAce2:|r AddOn %q does not exist", text))
|
||||
else
|
||||
DisableAddOn(text)
|
||||
print(string.format("|cffffff7fAce2:|r %s is now disabled", title or name))
|
||||
end
|
||||
end,
|
||||
},
|
||||
load = {
|
||||
desc = "Load addon",
|
||||
name = "Load",
|
||||
type = "text",
|
||||
usage = "<addon>",
|
||||
get = false,
|
||||
set = function(text)
|
||||
local name,title,_,_,loadable,reason = GetAddOnInfo(text)
|
||||
if reason == "MISSING" then
|
||||
print(string.format("|cffffff7fAce2:|r AddOn %q does not exist.", text))
|
||||
elseif not loadable then
|
||||
print(string.format("|cffffff7fAce2:|r AddOn %q is not loadable. Reason: %s", text, reason))
|
||||
else
|
||||
LoadAddOn(text)
|
||||
print(string.format("|cffffff7fAce2:|r %s is now loaded", title or name))
|
||||
end
|
||||
end
|
||||
},
|
||||
info = {
|
||||
desc = "Display information",
|
||||
name = "Information",
|
||||
type = "execute",
|
||||
func = function()
|
||||
local mem, threshold = gcinfo()
|
||||
print(string.format(" - |cffffff7fMemory usage [|r%.3f MiB|cffffff7f]|r", mem / 1024))
|
||||
print(string.format(" - |cffffff7fThreshold [|r%.3f MiB|cffffff7f]|r", threshold / 1024))
|
||||
print(string.format(" - |cffffff7fFramerate [|r%.0f fps|cffffff7f]|r", GetFramerate()))
|
||||
local bandwidthIn, bandwidthOut, latency = GetNetStats()
|
||||
bandwidthIn, bandwidthOut = floor(bandwidthIn * 1024), floor(bandwidthOut * 1024)
|
||||
print(string.format(" - |cffffff7fLatency [|r%.0f ms|cffffff7f]|r", latency))
|
||||
print(string.format(" - |cffffff7fBandwidth in [|r%.0f B/s|cffffff7f]|r", bandwidthIn))
|
||||
print(string.format(" - |cffffff7fBandwidth out [|r%.0f B/s|cffffff7f]|r", bandwidthOut))
|
||||
print(string.format(" - |cffffff7fTotal addons [|r%d|cffffff7f]|r", GetNumAddOns()))
|
||||
print(string.format(" - |cffffff7fAce2 addons [|r%d|cffffff7f]|r", table.getn(self.addons)))
|
||||
local ace = 0
|
||||
local enabled = 0
|
||||
local disabled = 0
|
||||
local lod = 0
|
||||
for i = 1, GetNumAddOns() do
|
||||
local dep1, dep2, dep3, dep4 = GetAddOnDependencies(i)
|
||||
if dep1 == "Ace" or dep2 == "Ace" or dep3 == "Ace" or dep4 == "Ace" then
|
||||
ace = ace + 1
|
||||
end
|
||||
if IsAddOnLoadOnDemand(i) then
|
||||
lod = lod + 1
|
||||
end
|
||||
local _,_,_,IsActive,loadable = GetAddOnInfo(i)
|
||||
if not IsActive or not loadable then
|
||||
disabled = disabled + 1
|
||||
else
|
||||
enabled = enabled + 1
|
||||
end
|
||||
end
|
||||
print(string.format(" - |cffffff7fAce 1.x addons [|r%d|cffffff7f]|r", ace))
|
||||
print(string.format(" - |cffffff7fLoadOnDemand addons [|r%d|cffffff7f]|r", lod))
|
||||
print(string.format(" - |cffffff7fenabled addons [|r%d|cffffff7f]|r", enabled))
|
||||
print(string.format(" - |cffffff7fdisabled addons [|r%d|cffffff7f]|r", disabled))
|
||||
local libs = 0
|
||||
if type(AceLibrary) == "table" and type(AceLibrary.libs) == "table" then
|
||||
for _ in pairs(AceLibrary.libs) do
|
||||
libs = libs + 1
|
||||
end
|
||||
end
|
||||
print(string.format(" - |cffffff7fAceLibrary instances [|r%d|cffffff7f]|r", libs))
|
||||
end
|
||||
}
|
||||
}
|
||||
})
|
||||
elseif major == "AceModuleCore-2.0" then
|
||||
AceModuleCore = instance
|
||||
end
|
||||
end
|
||||
|
||||
local function activate(self, oldLib, oldDeactivate)
|
||||
AceAddon = self
|
||||
|
||||
if oldLib then
|
||||
self.playerLoginFired = oldLib.playerLoginFired or DEFAULT_CHAT_FRAME and DEFAULT_CHAT_FRAME.defaultLanguage
|
||||
self.addonsToOnEnable = oldLib.addonsToOnEnable
|
||||
self.addons = oldLib.addons
|
||||
self.nextAddon = oldLib.nextAddon
|
||||
self.addonsStarted = oldLib.addonsStarted
|
||||
end
|
||||
if not self.addons then
|
||||
self.addons = {}
|
||||
end
|
||||
if not self.nextAddon then
|
||||
self.nextAddon = {}
|
||||
end
|
||||
if not self.addonsStarted then
|
||||
self.addonsStarted = {}
|
||||
end
|
||||
if oldDeactivate then
|
||||
oldDeactivate(oldLib)
|
||||
end
|
||||
end
|
||||
|
||||
AceLibrary:Register(AceAddon, MAJOR_VERSION, MINOR_VERSION, activate, nil, external)
|
||||
AceAddon = AceLibrary(MAJOR_VERSION)
|
||||
@@ -0,0 +1,956 @@
|
||||
--[[
|
||||
Name: AceEvent-2.0
|
||||
Revision: $Rev: 11577 $
|
||||
Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team)
|
||||
Inspired By: Ace 1.x by Turan (turan@gryphon.com)
|
||||
Website: http://www.wowace.com/
|
||||
Documentation: http://www.wowace.com/index.php/AceEvent-2.0
|
||||
SVN: http://svn.wowace.com/root/trunk/Ace2/AceEvent-2.0
|
||||
Description: Mixin to allow for event handling, scheduling, and inter-addon
|
||||
communication.
|
||||
Dependencies: AceLibrary, AceOO-2.0
|
||||
]]
|
||||
|
||||
local MAJOR_VERSION = "AceEvent-2.0"
|
||||
local MINOR_VERSION = "$Revision: 11577 $"
|
||||
|
||||
if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary") end
|
||||
if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end
|
||||
|
||||
if not AceLibrary:HasInstance("AceOO-2.0") then error(MAJOR_VERSION .. " requires AceOO-2.0") end
|
||||
|
||||
local AceOO = AceLibrary:GetInstance("AceOO-2.0")
|
||||
local Mixin = AceOO.Mixin
|
||||
local AceEvent = Mixin {
|
||||
"RegisterEvent",
|
||||
"RegisterAllEvents",
|
||||
"UnregisterEvent",
|
||||
"UnregisterAllEvents",
|
||||
"TriggerEvent",
|
||||
"ScheduleEvent",
|
||||
"ScheduleRepeatingEvent",
|
||||
"CancelScheduledEvent",
|
||||
"CancelAllScheduledEvents",
|
||||
"IsEventRegistered",
|
||||
"IsEventScheduled",
|
||||
"RegisterBucketEvent",
|
||||
"UnregisterBucketEvent",
|
||||
"UnregisterAllBucketEvents",
|
||||
"IsBucketEventRegistered",
|
||||
}
|
||||
|
||||
local table_setn
|
||||
do
|
||||
local version = GetBuildInfo()
|
||||
if string.find(version, "^2%.") then
|
||||
-- 2.0.0
|
||||
table_setn = function() end
|
||||
else
|
||||
table_setn = table.setn
|
||||
end
|
||||
end
|
||||
|
||||
local weakKey = {__mode="k"}
|
||||
local new, del
|
||||
do
|
||||
local list = setmetatable({}, weakKey)
|
||||
function new()
|
||||
local t = next(list)
|
||||
if t then
|
||||
list[t] = nil
|
||||
return t
|
||||
else
|
||||
return {}
|
||||
end
|
||||
end
|
||||
|
||||
function del(t)
|
||||
setmetatable(t, nil)
|
||||
for k in pairs(t) do
|
||||
t[k] = nil
|
||||
end
|
||||
list[t] = true
|
||||
end
|
||||
end
|
||||
|
||||
local FAKE_NIL
|
||||
local RATE
|
||||
|
||||
local eventsWhichHappenOnce = {
|
||||
PLAYER_LOGIN = true,
|
||||
AceEvent_FullyInitialized = true,
|
||||
VARIABLES_LOADED = true,
|
||||
PLAYER_LOGOUT = true,
|
||||
}
|
||||
|
||||
local registeringFromAceEvent
|
||||
function AceEvent:RegisterEvent(event, method, once)
|
||||
AceEvent:argCheck(event, 2, "string")
|
||||
if self == AceEvent and not registeringFromAceEvent then
|
||||
AceEvent:argCheck(method, 3, "function")
|
||||
self = method
|
||||
else
|
||||
AceEvent:argCheck(method, 3, "string", "function", "nil", "boolean", "number")
|
||||
if type(method) == "boolean" or type(method) == "number" then
|
||||
AceEvent:argCheck(once, 4, "nil")
|
||||
once, method = method, event
|
||||
end
|
||||
end
|
||||
AceEvent:argCheck(once, 4, "number", "boolean", "nil")
|
||||
if eventsWhichHappenOnce[event] then
|
||||
once = true
|
||||
end
|
||||
local throttleRate
|
||||
if type(once) == "number" then
|
||||
throttleRate, once = once
|
||||
end
|
||||
if not method then
|
||||
method = event
|
||||
end
|
||||
if type(method) == "string" and type(self[method]) ~= "function" then
|
||||
AceEvent:error("Cannot register event %q to method %q, it does not exist", event, method)
|
||||
else
|
||||
assert(type(method) == "function" or type(method) == "string")
|
||||
end
|
||||
|
||||
local AceEvent_registry = AceEvent.registry
|
||||
if not AceEvent_registry[event] then
|
||||
AceEvent_registry[event] = new()
|
||||
AceEvent.frame:RegisterEvent(event)
|
||||
end
|
||||
|
||||
local remember = true
|
||||
if AceEvent_registry[event][self] then
|
||||
remember = false
|
||||
end
|
||||
AceEvent_registry[event][self] = method
|
||||
|
||||
local AceEvent_onceRegistry = AceEvent.onceRegistry
|
||||
if once then
|
||||
if not AceEvent_onceRegistry then
|
||||
AceEvent.onceRegistry = new()
|
||||
AceEvent_onceRegistry = AceEvent.onceRegistry
|
||||
end
|
||||
if not AceEvent_onceRegistry[event] then
|
||||
AceEvent_onceRegistry[event] = new()
|
||||
end
|
||||
AceEvent_onceRegistry[event][self] = true
|
||||
else
|
||||
if AceEvent_onceRegistry and AceEvent_onceRegistry[event] then
|
||||
AceEvent_onceRegistry[event][self] = nil
|
||||
if not next(AceEvent_onceRegistry[event]) then
|
||||
AceEvent_onceRegistry[event] = del(AceEvent_onceRegistry[event])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local AceEvent_throttleRegistry = AceEvent.throttleRegistry
|
||||
if throttleRate then
|
||||
if not AceEvent_throttleRegistry then
|
||||
AceEvent.throttleRegistry = new()
|
||||
AceEvent_throttleRegistry = AceEvent.throttleRegistry
|
||||
end
|
||||
if not AceEvent_throttleRegistry[event] then
|
||||
AceEvent_throttleRegistry[event] = new()
|
||||
end
|
||||
if AceEvent_throttleRegistry[event][self] then
|
||||
AceEvent_throttleRegistry[event][self] = del(AceEvent_throttleRegistry[event][self])
|
||||
end
|
||||
AceEvent_throttleRegistry[event][self] = setmetatable(new(), weakKey)
|
||||
local t = AceEvent_throttleRegistry[event][self]
|
||||
t[RATE] = throttleRate
|
||||
else
|
||||
if AceEvent_throttleRegistry and AceEvent_throttleRegistry[event] then
|
||||
if AceEvent_throttleRegistry[event][self] then
|
||||
AceEvent_throttleRegistry[event][self] = del(AceEvent_throttleRegistry[event][self])
|
||||
end
|
||||
if not next(AceEvent_throttleRegistry[event]) then
|
||||
AceEvent_throttleRegistry[event] = del(AceEvent_throttleRegistry[event])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if remember then
|
||||
AceEvent:TriggerEvent("AceEvent_EventRegistered", self, event)
|
||||
end
|
||||
end
|
||||
|
||||
local ALL_EVENTS
|
||||
|
||||
function AceEvent:RegisterAllEvents(method)
|
||||
if self == AceEvent then
|
||||
AceEvent:argCheck(method, 1, "function")
|
||||
self = method
|
||||
else
|
||||
AceEvent:argCheck(method, 1, "string", "function")
|
||||
if type(method) == "string" and type(self[method]) ~= "function" then
|
||||
AceEvent:error("Cannot register all events to method %q, it does not exist", method)
|
||||
end
|
||||
end
|
||||
|
||||
local AceEvent_registry = AceEvent.registry
|
||||
if not AceEvent_registry[ALL_EVENTS] then
|
||||
AceEvent_registry[ALL_EVENTS] = new()
|
||||
AceEvent.frame:RegisterAllEvents()
|
||||
end
|
||||
|
||||
AceEvent_registry[ALL_EVENTS][self] = method
|
||||
end
|
||||
|
||||
local _G = getfenv(0)
|
||||
local memstack, timestack = {}, {}
|
||||
local memdiff, timediff
|
||||
function AceEvent:TriggerEvent(event, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
|
||||
AceEvent:argCheck(event, 2, "string")
|
||||
local AceEvent_registry = AceEvent.registry
|
||||
if (not AceEvent_registry[event] or not next(AceEvent_registry[event])) and (not AceEvent_registry[ALL_EVENTS] or not next(AceEvent_registry[ALL_EVENTS])) then
|
||||
return
|
||||
end
|
||||
local _G_event = _G.event
|
||||
_G.event = event
|
||||
|
||||
local AceEvent_onceRegistry = AceEvent.onceRegistry
|
||||
local AceEvent_debugTable = AceEvent.debugTable
|
||||
if AceEvent_onceRegistry and AceEvent_onceRegistry[event] then
|
||||
local tmp = new()
|
||||
for obj, method in pairs(AceEvent_onceRegistry[event]) do
|
||||
tmp[obj] = AceEvent_registry[event] and AceEvent_registry[event][obj] or nil
|
||||
end
|
||||
local obj = next(tmp)
|
||||
while obj do
|
||||
local mem, time
|
||||
if AceEvent_debugTable then
|
||||
if not AceEvent_debugTable[event] then
|
||||
AceEvent_debugTable[event] = new()
|
||||
end
|
||||
if not AceEvent_debugTable[event][obj] then
|
||||
AceEvent_debugTable[event][obj] = new()
|
||||
AceEvent_debugTable[event][obj].mem = 0
|
||||
AceEvent_debugTable[event][obj].time = 0
|
||||
AceEvent_debugTable[event][obj].count = 0
|
||||
end
|
||||
if memdiff then
|
||||
table.insert(memstack, memdiff)
|
||||
table.insert(timestack, timediff)
|
||||
end
|
||||
memdiff, timediff = 0, 0
|
||||
mem, time = gcinfo(), GetTime()
|
||||
end
|
||||
local method = tmp[obj]
|
||||
AceEvent.UnregisterEvent(obj, event)
|
||||
if type(method) == "string" then
|
||||
local obj_method = obj[method]
|
||||
if obj_method then
|
||||
obj_method(obj, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
|
||||
end
|
||||
elseif method then -- function
|
||||
method(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
|
||||
end
|
||||
if AceEvent_debugTable then
|
||||
local dmem, dtime = memdiff, timediff
|
||||
mem, time = gcinfo() - mem - memdiff, GetTime() - time - timediff
|
||||
AceEvent_debugTable[event][obj].mem = AceEvent_debugTable[event][obj].mem + mem
|
||||
AceEvent_debugTable[event][obj].time = AceEvent_debugTable[event][obj].time + time
|
||||
AceEvent_debugTable[event][obj].count = AceEvent_debugTable[event][obj].count + 1
|
||||
|
||||
memdiff, timediff = table.remove(memstack), table.remove(timestack)
|
||||
if memdiff then
|
||||
memdiff = memdiff + mem + dmem
|
||||
timediff = timediff + time + dtime
|
||||
end
|
||||
end
|
||||
tmp[obj] = nil
|
||||
obj = next(tmp)
|
||||
end
|
||||
del(tmp)
|
||||
end
|
||||
|
||||
local AceEvent_throttleRegistry = AceEvent.throttleRegistry
|
||||
local throttleTable = AceEvent_throttleRegistry and AceEvent_throttleRegistry[event]
|
||||
if AceEvent_registry[event] then
|
||||
local tmp = new()
|
||||
for obj, method in pairs(AceEvent_registry[event]) do
|
||||
tmp[obj] = method
|
||||
end
|
||||
local obj = next(tmp)
|
||||
while obj do
|
||||
local method = tmp[obj]
|
||||
local continue = false
|
||||
if throttleTable and throttleTable[obj] then
|
||||
local a1 = a1
|
||||
if a1 == nil then
|
||||
a1 = FAKE_NIL
|
||||
end
|
||||
if not throttleTable[obj][a1] or GetTime() - throttleTable[obj][a1] >= throttleTable[obj][RATE] then
|
||||
throttleTable[obj][a1] = GetTime()
|
||||
else
|
||||
continue = true
|
||||
end
|
||||
end
|
||||
if not continue then
|
||||
local mem, time
|
||||
if AceEvent_debugTable then
|
||||
if not AceEvent_debugTable[event] then
|
||||
AceEvent_debugTable[event] = new()
|
||||
end
|
||||
if not AceEvent_debugTable[event][obj] then
|
||||
AceEvent_debugTable[event][obj] = new()
|
||||
AceEvent_debugTable[event][obj].mem = 0
|
||||
AceEvent_debugTable[event][obj].time = 0
|
||||
AceEvent_debugTable[event][obj].count = 0
|
||||
end
|
||||
if memdiff then
|
||||
table.insert(memstack, memdiff)
|
||||
table.insert(timestack, timediff)
|
||||
end
|
||||
memdiff, timediff = 0, 0
|
||||
mem, time = gcinfo(), GetTime()
|
||||
end
|
||||
if type(method) == "string" then
|
||||
local obj_method = obj[method]
|
||||
if obj_method then
|
||||
obj_method(obj, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
|
||||
end
|
||||
elseif method then -- function
|
||||
method(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
|
||||
end
|
||||
if AceEvent_debugTable then
|
||||
local dmem, dtime = memdiff, timediff
|
||||
mem, time = gcinfo() - mem - memdiff, GetTime() - time - timediff
|
||||
AceEvent_debugTable[event][obj].mem = AceEvent_debugTable[event][obj].mem + mem
|
||||
AceEvent_debugTable[event][obj].time = AceEvent_debugTable[event][obj].time + time
|
||||
AceEvent_debugTable[event][obj].count = AceEvent_debugTable[event][obj].count + 1
|
||||
|
||||
memdiff, timediff = table.remove(memstack), table.remove(timestack)
|
||||
if memdiff then
|
||||
memdiff = memdiff + mem + dmem
|
||||
timediff = timediff + time + dtime
|
||||
end
|
||||
end
|
||||
end
|
||||
tmp[obj] = nil
|
||||
obj = next(tmp)
|
||||
end
|
||||
del(tmp)
|
||||
end
|
||||
if AceEvent_registry[ALL_EVENTS] then
|
||||
local tmp = new()
|
||||
for obj, method in pairs(AceEvent_registry[ALL_EVENTS]) do
|
||||
tmp[obj] = method
|
||||
end
|
||||
local obj = next(tmp)
|
||||
while obj do
|
||||
local method = tmp[obj]
|
||||
local mem, time
|
||||
if AceEvent_debugTable then
|
||||
if not AceEvent_debugTable[event] then
|
||||
AceEvent_debugTable[event] = new()
|
||||
end
|
||||
if not AceEvent_debugTable[event][obj] then
|
||||
AceEvent_debugTable[event][obj] = new()
|
||||
AceEvent_debugTable[event][obj].mem = 0
|
||||
AceEvent_debugTable[event][obj].time = 0
|
||||
AceEvent_debugTable[event][obj].count = 0
|
||||
end
|
||||
if memdiff then
|
||||
table.insert(memstack, memdiff)
|
||||
table.insert(timestack, timediff)
|
||||
end
|
||||
memdiff, timediff = 0, 0
|
||||
mem, time = gcinfo(), GetTime()
|
||||
end
|
||||
if type(method) == "string" then
|
||||
local obj_method = obj[method]
|
||||
if obj_method then
|
||||
obj_method(obj, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
|
||||
end
|
||||
elseif method then -- function
|
||||
method(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
|
||||
end
|
||||
if AceEvent_debugTable then
|
||||
local dmem, dtime = memdiff, timediff
|
||||
mem, time = gcinfo() - mem - memdiff, GetTime() - time - timediff
|
||||
AceEvent_debugTable[event][obj].mem = AceEvent_debugTable[event][obj].mem + mem
|
||||
AceEvent_debugTable[event][obj].time = AceEvent_debugTable[event][obj].time + time
|
||||
AceEvent_debugTable[event][obj].count = AceEvent_debugTable[event][obj].count + 1
|
||||
|
||||
memdiff, timediff = table.remove(memstack), table.remove(timestack)
|
||||
if memdiff then
|
||||
memdiff = memdiff + mem + dmem
|
||||
timediff = timediff + time + dtime
|
||||
end
|
||||
end
|
||||
tmp[obj] = nil
|
||||
obj = next(tmp)
|
||||
end
|
||||
del(tmp)
|
||||
end
|
||||
_G.event = _G_event
|
||||
end
|
||||
|
||||
-- local accessors
|
||||
local getn = table.getn
|
||||
local tinsert = table.insert
|
||||
local tremove = table.remove
|
||||
local floor = math.floor
|
||||
local GetTime = GetTime
|
||||
local next = next
|
||||
local pairs = pairs
|
||||
local unpack = unpack
|
||||
|
||||
local delayRegistry
|
||||
local function OnUpdate()
|
||||
local t = GetTime()
|
||||
local k,v = next(delayRegistry)
|
||||
local last = nil
|
||||
while k do
|
||||
local v_time = v.time
|
||||
if not v_time then
|
||||
delayRegistry[k] = del(v)
|
||||
elseif v_time <= t then
|
||||
local v_repeatDelay = v.repeatDelay
|
||||
if v_repeatDelay then
|
||||
-- use the event time, not the current time, else timing inaccuracies add up over time
|
||||
v.time = v_time + v_repeatDelay
|
||||
end
|
||||
local event = v.event
|
||||
local mem, time
|
||||
if AceEvent_debugTable then
|
||||
mem, time = gcinfo(), GetTime()
|
||||
end
|
||||
if type(event) == "function" then
|
||||
event(unpack(v))
|
||||
else
|
||||
AceEvent:TriggerEvent(event, unpack(v))
|
||||
end
|
||||
if AceEvent_debugTable then
|
||||
mem, time = gcinfo() - mem, GetTime() - time
|
||||
v.mem = v.mem + mem
|
||||
v.timeSpent = v.timeSpent + time
|
||||
v.count = v.count + 1
|
||||
end
|
||||
if not v_repeatDelay then
|
||||
local x = delayRegistry[k]
|
||||
if x and x.time == v_time then -- check if it was manually reset
|
||||
delayRegistry[k] = del(v)
|
||||
end
|
||||
end
|
||||
end
|
||||
if delayRegistry[k] then
|
||||
last = k
|
||||
end
|
||||
k,v = next(delayRegistry, last)
|
||||
end
|
||||
if not next(delayRegistry) then
|
||||
AceEvent.frame:Hide()
|
||||
end
|
||||
end
|
||||
|
||||
local function ScheduleEvent(self, repeating, event, delay, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
|
||||
local id
|
||||
if type(event) == "string" or type(event) == "table" then
|
||||
if type(event) == "table" then
|
||||
if not delayRegistry or not delayRegistry[event] then
|
||||
AceEvent:error("Bad argument #2 to `ScheduleEvent'. Improper id table fed in.")
|
||||
end
|
||||
end
|
||||
if type(delay) ~= "number" then
|
||||
id, event, delay, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20 = event, delay, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20
|
||||
AceEvent:argCheck(event, 3, "string", "function", --[[ so message is right ]] "number")
|
||||
AceEvent:argCheck(delay, 4, "number")
|
||||
self:CancelScheduledEvent(id)
|
||||
end
|
||||
else
|
||||
AceEvent:argCheck(event, 2, "string", "function")
|
||||
AceEvent:argCheck(delay, 3, "number")
|
||||
end
|
||||
|
||||
if not delayRegistry then
|
||||
AceEvent.delayRegistry = new()
|
||||
delayRegistry = AceEvent.delayRegistry
|
||||
AceEvent.frame:SetScript("OnUpdate", OnUpdate)
|
||||
end
|
||||
local t
|
||||
if type(id) == "table" then
|
||||
for k in pairs(id) do
|
||||
id[k] = nil
|
||||
end
|
||||
t = id
|
||||
else
|
||||
t = new()
|
||||
end
|
||||
t[1] = a1
|
||||
t[2] = a2
|
||||
t[3] = a3
|
||||
t[4] = a4
|
||||
t[5] = a5
|
||||
t[6] = a6
|
||||
t[7] = a7
|
||||
t[8] = a8
|
||||
t[9] = a9
|
||||
t[10] = a10
|
||||
t[11] = a11
|
||||
t[12] = a12
|
||||
t[13] = a13
|
||||
t[14] = a14
|
||||
t[15] = a15
|
||||
t[16] = a16
|
||||
t[17] = a17
|
||||
t[18] = a18
|
||||
t[19] = a19
|
||||
t[20] = a20
|
||||
table_setn(t, 20)
|
||||
t.event = event
|
||||
t.time = GetTime() + delay
|
||||
t.self = self
|
||||
t.id = id or t
|
||||
t.repeatDelay = repeating and delay
|
||||
if AceEvent_debugTable then
|
||||
t.mem = 0
|
||||
t.count = 0
|
||||
t.timeSpent = 0
|
||||
end
|
||||
delayRegistry[t.id] = t
|
||||
AceEvent.frame:Show()
|
||||
return t.id
|
||||
end
|
||||
|
||||
function AceEvent:ScheduleEvent(event, delay, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
|
||||
if type(event) == "string" or type(event) == "table" then
|
||||
if type(event) == "table" then
|
||||
if not delayRegistry or not delayRegistry[event] then
|
||||
AceEvent:error("Bad argument #2 to `ScheduleEvent'. Improper id table fed in.")
|
||||
end
|
||||
end
|
||||
if type(delay) ~= "number" then
|
||||
AceEvent:argCheck(delay, 3, "string", "function", --[[ so message is right ]] "number")
|
||||
AceEvent:argCheck(a1, 4, "number")
|
||||
end
|
||||
else
|
||||
AceEvent:argCheck(event, 2, "string", "function")
|
||||
AceEvent:argCheck(delay, 3, "number")
|
||||
end
|
||||
|
||||
return ScheduleEvent(self, false, event, delay, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
|
||||
end
|
||||
|
||||
function AceEvent:ScheduleRepeatingEvent(event, delay, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
|
||||
if type(event) == "string" or type(event) == "table" then
|
||||
if type(event) == "table" then
|
||||
if not delayRegistry or not delayRegistry[event] then
|
||||
AceEvent:error("Bad argument #2 to `ScheduleEvent'. Improper id table fed in.")
|
||||
end
|
||||
end
|
||||
if type(delay) ~= "number" then
|
||||
AceEvent:argCheck(delay, 3, "string", "function", --[[ so message is right ]] "number")
|
||||
AceEvent:argCheck(a1, 4, "number")
|
||||
end
|
||||
else
|
||||
AceEvent:argCheck(event, 2, "string", "function")
|
||||
AceEvent:argCheck(delay, 3, "number")
|
||||
end
|
||||
|
||||
return ScheduleEvent(self, true, event, delay, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
|
||||
end
|
||||
|
||||
function AceEvent:CancelScheduledEvent(t)
|
||||
AceEvent:argCheck(t, 2, "string", "table")
|
||||
if delayRegistry then
|
||||
local v = delayRegistry[t]
|
||||
if v then
|
||||
delayRegistry[t] = del(v)
|
||||
if not next(delayRegistry) then
|
||||
AceEvent.frame:Hide()
|
||||
end
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function AceEvent:IsEventScheduled(t)
|
||||
AceEvent:argCheck(t, 2, "string", "table")
|
||||
if delayRegistry then
|
||||
local v = delayRegistry[t]
|
||||
if v then
|
||||
return true, v.time - GetTime()
|
||||
end
|
||||
end
|
||||
return false, nil
|
||||
end
|
||||
|
||||
function AceEvent:UnregisterEvent(event)
|
||||
AceEvent:argCheck(event, 2, "string")
|
||||
local AceEvent_registry = AceEvent.registry
|
||||
if AceEvent_registry[event] and AceEvent_registry[event][self] then
|
||||
AceEvent_registry[event][self] = nil
|
||||
local AceEvent_onceRegistry = AceEvent.onceRegistry
|
||||
if AceEvent_onceRegistry and AceEvent_onceRegistry[event] and AceEvent_onceRegistry[event][self] then
|
||||
AceEvent_onceRegistry[event][self] = nil
|
||||
if not next(AceEvent_onceRegistry[event]) then
|
||||
AceEvent_onceRegistry[event] = del(AceEvent_onceRegistry[event])
|
||||
end
|
||||
end
|
||||
local AceEvent_throttleRegistry = AceEvent.throttleRegistry
|
||||
if AceEvent_throttleRegistry and AceEvent_throttleRegistry[event] and AceEvent_throttleRegistry[event][self] then
|
||||
AceEvent_throttleRegistry[event][self] = del(AceEvent_throttleRegistry[event][self])
|
||||
if not next(AceEvent_throttleRegistry[event]) then
|
||||
AceEvent_throttleRegistry[event] = del(AceEvent_throttleRegistry[event])
|
||||
end
|
||||
end
|
||||
if not next(AceEvent_registry[event]) then
|
||||
AceEvent_registry[event] = del(AceEvent_registry[event])
|
||||
if not AceEvent_registry[ALL_EVENTS] or not next(AceEvent_registry[ALL_EVENTS]) then
|
||||
AceEvent.frame:UnregisterEvent(event)
|
||||
end
|
||||
end
|
||||
else
|
||||
if self == AceEvent then
|
||||
error(string.format("Cannot unregister event %q. Improperly unregistering from AceEvent-2.0.", event), 2)
|
||||
else
|
||||
AceEvent:error("Cannot unregister event %q. %q is not registered with it.", event, self)
|
||||
end
|
||||
end
|
||||
AceEvent:TriggerEvent("AceEvent_EventUnregistered", self, event)
|
||||
end
|
||||
|
||||
function AceEvent:UnregisterAllEvents()
|
||||
local AceEvent_registry = AceEvent.registry
|
||||
if AceEvent_registry[ALL_EVENTS] and AceEvent_registry[ALL_EVENTS][self] then
|
||||
AceEvent_registry[ALL_EVENTS][self] = nil
|
||||
if not next(AceEvent_registry[ALL_EVENTS]) then
|
||||
del(AceEvent_registry[ALL_EVENTS])
|
||||
AceEvent.frame:UnregisterAllEvents()
|
||||
for k,v in pairs(AceEvent_registry) do
|
||||
if k ~= ALL_EVENTS then
|
||||
AceEvent.frame:RegisterEvent(k)
|
||||
end
|
||||
end
|
||||
AceEvent_registry[event] = nil
|
||||
end
|
||||
end
|
||||
local first = true
|
||||
for event, data in pairs(AceEvent_registry) do
|
||||
if first then
|
||||
if AceEvent_registry.AceEvent_EventUnregistered then
|
||||
event = "AceEvent_EventUnregistered"
|
||||
else
|
||||
first = false
|
||||
end
|
||||
end
|
||||
local x = data[self]
|
||||
data[self] = nil
|
||||
if x and event ~= ALL_EVENTS then
|
||||
if not next(data) then
|
||||
del(data)
|
||||
if not AceEvent_registry[ALL_EVENTS] or not next(AceEvent_registry[ALL_EVENTS]) then
|
||||
AceEvent.frame:UnregisterEvent(event)
|
||||
end
|
||||
AceEvent_registry[event] = nil
|
||||
end
|
||||
AceEvent:TriggerEvent("AceEvent_EventUnregistered", self, event)
|
||||
end
|
||||
if first then
|
||||
event = nil
|
||||
end
|
||||
end
|
||||
if AceEvent.onceRegistry then
|
||||
for event, data in pairs(AceEvent.onceRegistry) do
|
||||
data[self] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function AceEvent:CancelAllScheduledEvents()
|
||||
if delayRegistry then
|
||||
for k,v in pairs(delayRegistry) do
|
||||
if v.self == self then
|
||||
delayRegistry[k] = del(v)
|
||||
end
|
||||
end
|
||||
if not next(delayRegistry) then
|
||||
AceEvent.frame:Hide()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function AceEvent:IsEventRegistered(event)
|
||||
AceEvent:argCheck(event, 2, "string")
|
||||
local AceEvent_registry = AceEvent.registry
|
||||
if self == AceEvent then
|
||||
return AceEvent_registry[event] and next(AceEvent_registry[event]) and true or false
|
||||
end
|
||||
if AceEvent_registry[event] and AceEvent_registry[event][self] then
|
||||
return true, AceEvent_registry[event][self]
|
||||
end
|
||||
return false, nil
|
||||
end
|
||||
|
||||
local bucketfunc
|
||||
function AceEvent:RegisterBucketEvent(event, delay, method)
|
||||
AceEvent:argCheck(event, 2, "string", "table")
|
||||
if type(event) == "table" then
|
||||
for k,v in pairs(event) do
|
||||
if type(k) ~= "number" then
|
||||
AceEvent:error("All keys to argument #2 to `RegisterBucketEvent' must be numbers.")
|
||||
elseif type(v) ~= "string" then
|
||||
AceEvent:error("All values to argument #2 to `RegisterBucketEvent' must be strings.")
|
||||
end
|
||||
end
|
||||
end
|
||||
AceEvent:argCheck(delay, 3, "number")
|
||||
if AceEvent == self then
|
||||
AceEvent:argCheck(method, 4, "function")
|
||||
self = method
|
||||
else
|
||||
if type(event) == "string" then
|
||||
AceEvent:argCheck(method, 4, "string", "function", "nil")
|
||||
if not method then
|
||||
method = event
|
||||
end
|
||||
else
|
||||
AceEvent:argCheck(method, 4, "string", "function")
|
||||
end
|
||||
|
||||
if type(method) == "string" and type(self[method]) ~= "function" then
|
||||
AceEvent:error("Cannot register event %q to method %q, it does not exist", event, method)
|
||||
end
|
||||
end
|
||||
if not AceEvent.buckets then
|
||||
AceEvent.buckets = new()
|
||||
end
|
||||
if not AceEvent.buckets[event] then
|
||||
AceEvent.buckets[event] = new()
|
||||
end
|
||||
if not AceEvent.buckets[event][self] then
|
||||
AceEvent.buckets[event][self] = new()
|
||||
AceEvent.buckets[event][self].current = new()
|
||||
AceEvent.buckets[event][self].self = self
|
||||
else
|
||||
AceEvent.CancelScheduledEvent(self, AceEvent.buckets[event][self].id)
|
||||
end
|
||||
local bucket = AceEvent.buckets[event][self]
|
||||
bucket.method = method
|
||||
|
||||
local func = function(arg1)
|
||||
bucket.run = true
|
||||
if arg1 then
|
||||
bucket.current[arg1] = true
|
||||
end
|
||||
end
|
||||
AceEvent.buckets[event][self].func = func
|
||||
if type(event) == "string" then
|
||||
AceEvent.RegisterEvent(self, event, func)
|
||||
else
|
||||
for _,v in ipairs(event) do
|
||||
AceEvent.RegisterEvent(self, v, func)
|
||||
end
|
||||
end
|
||||
if not bucketfunc then
|
||||
bucketfunc = function(bucket)
|
||||
local current = bucket.current
|
||||
local method = bucket.method
|
||||
local self = bucket.self
|
||||
if bucket.run then
|
||||
if type(method) == "string" then
|
||||
self[method](self, current)
|
||||
elseif method then -- function
|
||||
method(current)
|
||||
end
|
||||
for k in pairs(current) do
|
||||
current[k] = nil
|
||||
k = nil
|
||||
end
|
||||
bucket.run = false
|
||||
end
|
||||
end
|
||||
end
|
||||
bucket.id = AceEvent.ScheduleRepeatingEvent(self, bucketfunc, delay, bucket)
|
||||
end
|
||||
|
||||
function AceEvent:IsBucketEventRegistered(event)
|
||||
AceEvent:argCheck(event, 2, "string", "table")
|
||||
return AceEvent.buckets and AceEvent.buckets[event] and AceEvent.buckets[event][self]
|
||||
end
|
||||
|
||||
function AceEvent:UnregisterBucketEvent(event)
|
||||
AceEvent:argCheck(event, 2, "string", "table")
|
||||
if not AceEvent.buckets or not AceEvent.buckets[event] or not AceEvent.buckets[event][self] then
|
||||
AceEvent:error("Cannot unregister bucket event %q. %q is not registered with it.", event, self)
|
||||
end
|
||||
|
||||
local bucket = AceEvent.buckets[event][self]
|
||||
|
||||
if type(event) == "string" then
|
||||
AceEvent.UnregisterEvent(bucket.func, event)
|
||||
else
|
||||
for _,v in ipairs(event) do
|
||||
AceEvent.UnregisterEvent(bucket.func, v)
|
||||
end
|
||||
end
|
||||
AceEvent:CancelScheduledEvent(bucket.id)
|
||||
|
||||
del(bucket.current)
|
||||
AceEvent.buckets[event][self] = del(AceEvent.buckets[event][self])
|
||||
if not next(AceEvent.buckets[event]) then
|
||||
AceEvent.buckets[event] = del(AceEvent.buckets[event])
|
||||
end
|
||||
end
|
||||
|
||||
function AceEvent:UnregisterAllBucketEvents()
|
||||
if not AceEvent.buckets or not next(AceEvent.buckets) then
|
||||
return
|
||||
end
|
||||
for k,v in pairs(AceEvent.buckets) do
|
||||
if v == self then
|
||||
AceEvent.UnregisterBucketEvent(self, k)
|
||||
k = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function AceEvent:OnEmbedDisable(target)
|
||||
self.UnregisterAllEvents(target)
|
||||
|
||||
self.CancelAllScheduledEvents(target)
|
||||
|
||||
self.UnregisterAllBucketEvents(target)
|
||||
end
|
||||
|
||||
function AceEvent:EnableDebugging()
|
||||
if not self.debugTable then
|
||||
self.debugTable = new()
|
||||
|
||||
if delayRegistry then
|
||||
for k,v in pairs(self.delayRegistry) do
|
||||
if not v.mem then
|
||||
v.mem = 0
|
||||
v.count = 0
|
||||
v.timeSpent = 0
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function AceEvent:IsFullyInitialized()
|
||||
return self.postInit or false
|
||||
end
|
||||
|
||||
function AceEvent:IsPostPlayerLogin()
|
||||
return self.playerLogin or false
|
||||
end
|
||||
|
||||
function AceEvent:activate(oldLib, oldDeactivate)
|
||||
AceEvent = self
|
||||
|
||||
if oldLib then
|
||||
self.onceRegistry = oldLib.onceRegistry
|
||||
self.throttleRegistry = oldLib.throttleRegistry
|
||||
self.delayRegistry = oldLib.delayRegistry
|
||||
self.buckets = oldLib.buckets
|
||||
self.registry = oldLib.registry
|
||||
self.frame = oldLib.frame
|
||||
self.debugTable = oldLib.debugTable
|
||||
self.playerLogin = oldLib.pew or DEFAULT_CHAT_FRAME and DEFAULT_CHAT_FRAME.defaultLanguage and true
|
||||
self.postInit = oldLib.postInit or self.playerLogin and ChatTypeInfo and ChatTypeInfo.WHISPER and ChatTypeInfo.WHISPER.r and true
|
||||
self.ALL_EVENTS = oldLib.ALL_EVENTS
|
||||
self.FAKE_NIL = oldLib.FAKE_NIL
|
||||
self.RATE = oldLib.RATE
|
||||
end
|
||||
if not self.registry then
|
||||
self.registry = {}
|
||||
end
|
||||
if not self.frame then
|
||||
self.frame = CreateFrame("Frame", "AceEvent20Frame")
|
||||
end
|
||||
if not self.ALL_EVENTS then
|
||||
self.ALL_EVENTS = {}
|
||||
end
|
||||
if not self.FAKE_NIL then
|
||||
self.FAKE_NIL = {}
|
||||
end
|
||||
if not self.RATE then
|
||||
self.RATE = {}
|
||||
end
|
||||
ALL_EVENTS = self.ALL_EVENTS
|
||||
FAKE_NIL = self.FAKE_NIL
|
||||
RATE = self.RATE
|
||||
local inPlw = false
|
||||
local blacklist = {
|
||||
UNIT_INVENTORY_CHANGED = true,
|
||||
BAG_UPDATE = true,
|
||||
ITEM_LOCK_CHANGED = true,
|
||||
ACTIONBAR_SLOT_CHANGED = true,
|
||||
}
|
||||
self.frame:SetScript("OnEvent", function()
|
||||
local event = event
|
||||
if event == "PLAYER_ENTERING_WORLD" then
|
||||
inPlw = false
|
||||
elseif event == "PLAYER_LEAVING_WORLD" then
|
||||
inPlw = true
|
||||
end
|
||||
if event and (not inPlw or not blacklist[event]) then
|
||||
self:TriggerEvent(event, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9)
|
||||
end
|
||||
end)
|
||||
if self.delayRegistry then
|
||||
delayRegistry = self.delayRegistry
|
||||
self.frame:SetScript("OnUpdate", OnUpdate)
|
||||
end
|
||||
|
||||
self:UnregisterAllEvents()
|
||||
self:CancelAllScheduledEvents()
|
||||
|
||||
if not self.playerLogin then
|
||||
registeringFromAceEvent = true
|
||||
self:RegisterEvent("PLAYER_LOGIN", function()
|
||||
self.playerLogin = true
|
||||
end, true)
|
||||
registeringFromAceEvent = nil
|
||||
end
|
||||
|
||||
if not self.postInit then
|
||||
local isReload = true
|
||||
local function func()
|
||||
self.postInit = true
|
||||
self:TriggerEvent("AceEvent_FullyInitialized")
|
||||
if self.registry["CHAT_MSG_CHANNEL_NOTICE"] and self.registry["CHAT_MSG_CHANNEL_NOTICE"][self] then
|
||||
self:UnregisterEvent("CHAT_MSG_CHANNEL_NOTICE")
|
||||
end
|
||||
if self.registry["MEETINGSTONE_CHANGED"] and self.registry["MEETINGSTONE_CHANGED"][self] then
|
||||
self:UnregisterEvent("MEETINGSTONE_CHANGED")
|
||||
end
|
||||
if self.registry["MINIMAP_ZONE_CHANGED"] and self.registry["MINIMAP_ZONE_CHANGED"][self] then
|
||||
self:UnregisterEvent("MINIMAP_ZONE_CHANGED")
|
||||
end
|
||||
if self.registry["LANGUAGE_LIST_CHANGED"] and self.registry["LANGUAGE_LIST_CHANGED"][self] then
|
||||
self:UnregisterEvent("LANGUAGE_LIST_CHANGED")
|
||||
end
|
||||
end
|
||||
registeringFromAceEvent = true
|
||||
local f = function()
|
||||
self.playerLogin = true
|
||||
self:ScheduleEvent("AceEvent_FullyInitialized", func, 1)
|
||||
end
|
||||
self:RegisterEvent("MEETINGSTONE_CHANGED", f, true)
|
||||
self:RegisterEvent("CHAT_MSG_CHANNEL_NOTICE", function()
|
||||
self:ScheduleEvent("AceEvent_FullyInitialized", func, 0.05)
|
||||
end)
|
||||
self:RegisterEvent("LANGUAGE_LIST_CHANGED", function()
|
||||
if self.registry["MEETINGSTONE_CHANGED"] and self.registry["MEETINGSTONE_CHANGED"][self] then
|
||||
self:UnregisterEvent("MEETINGSTONE_CHANGED")
|
||||
self:RegisterEvent("MINIMAP_ZONE_CHANGED", f, true)
|
||||
end
|
||||
end)
|
||||
registeringFromAceEvent = nil
|
||||
end
|
||||
|
||||
self.super.activate(self, oldLib, oldDeactivate)
|
||||
if oldLib then
|
||||
oldDeactivate(oldLib)
|
||||
end
|
||||
end
|
||||
|
||||
AceLibrary:Register(AceEvent, MAJOR_VERSION, MINOR_VERSION, AceEvent.activate)
|
||||
AceEvent = AceLibrary(MAJOR_VERSION)
|
||||
@@ -0,0 +1,572 @@
|
||||
--[[
|
||||
Name: AceHook-2.0
|
||||
Revision: $Rev: 11577 $
|
||||
Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team)
|
||||
Inspired By: Ace 1.x by Turan (turan@gryphon.com)
|
||||
Website: http://www.wowace.com/
|
||||
Documentation: http://www.wowace.com/index.php/AceHook-2.0
|
||||
SVN: http://svn.wowace.com/root/trunk/Ace2/AceHook-2.0
|
||||
Description: Mixin to allow for safe hooking of functions, methods, and scripts.
|
||||
Dependencies: AceLibrary, AceOO-2.0
|
||||
]]
|
||||
|
||||
local MAJOR_VERSION = "AceHook-2.0"
|
||||
local MINOR_VERSION = "$Revision: 11577 $"
|
||||
|
||||
-- This ensures the code is only executed if the libary doesn't already exist, or is a newer version
|
||||
if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary.") end
|
||||
if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end
|
||||
|
||||
if not AceLibrary:HasInstance("AceOO-2.0") then error(MAJOR_VERSION .. " requires AceOO-2.0") end
|
||||
|
||||
--[[---------------------------------------------------------------------------------
|
||||
Create the library object
|
||||
----------------------------------------------------------------------------------]]
|
||||
|
||||
local AceOO = AceLibrary:GetInstance("AceOO-2.0")
|
||||
local AceHook = AceOO.Mixin {
|
||||
"Hook",
|
||||
"Unhook",
|
||||
"UnhookAll",
|
||||
"HookReport",
|
||||
"IsHooked",
|
||||
"HookScript",
|
||||
}
|
||||
|
||||
local table_setn
|
||||
do
|
||||
local version = GetBuildInfo()
|
||||
if string.find(version, "^2%.") then
|
||||
-- 2.0.0
|
||||
table_setn = function() end
|
||||
else
|
||||
table_setn = table.setn
|
||||
end
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------------------------------
|
||||
Library Definitions
|
||||
----------------------------------------------------------------------------------]]
|
||||
|
||||
local protFuncs = {
|
||||
CameraOrSelectOrMoveStart = true, CameraOrSelectOrMoveStop = true,
|
||||
TurnOrActionStart = true, TurnOrActionStop = true,
|
||||
PitchUpStart = true, PitchUpStop = true,
|
||||
PitchDownStart = true, PitchDownStop = true,
|
||||
MoveBackwardStart = true, MoveBackwardStop = true,
|
||||
MoveForwardStart = true, MoveForwardStop = true,
|
||||
Jump = true, StrafeLeftStart = true,
|
||||
StrafeLeftStop = true, StrafeRightStart = true,
|
||||
StrafeRightStop = true, ToggleMouseMove = true,
|
||||
ToggleRun = true, TurnLeftStart = true,
|
||||
TurnLeftStop = true, TurnRightStart = true,
|
||||
TurnRightStop = true,
|
||||
}
|
||||
|
||||
local _G = getfenv(0)
|
||||
|
||||
local handlers, funcs, scripts, actives
|
||||
|
||||
--[[---------------------------------------------------------------------------------
|
||||
Private definitions (Not exposed)
|
||||
----------------------------------------------------------------------------------]]
|
||||
|
||||
--[[----------------------------------------------------------------------
|
||||
_debug - Internal Method
|
||||
-------------------------------------------------------------------------]]
|
||||
local function print(text)
|
||||
DEFAULT_CHAT_FRAME:AddMessage(text)
|
||||
end
|
||||
|
||||
local function _debug(self, msg)
|
||||
local name = self.hooks.name
|
||||
if name then
|
||||
print(string.format("[%s]: %s", name, msg))
|
||||
else
|
||||
print(msg)
|
||||
end
|
||||
end
|
||||
|
||||
local new, del
|
||||
do
|
||||
local list = setmetatable({}, {__mode = "k"})
|
||||
function new()
|
||||
local t = next(list)
|
||||
if not t then
|
||||
return {}
|
||||
end
|
||||
list[t] = nil
|
||||
return t
|
||||
end
|
||||
|
||||
function del(t)
|
||||
setmetatable(t, nil)
|
||||
table_setn(t, 0)
|
||||
for k in pairs(t) do
|
||||
t[k] = nil
|
||||
end
|
||||
list[t] = true
|
||||
end
|
||||
end
|
||||
|
||||
local origMetatable = {
|
||||
__call = function(self, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
|
||||
return self.orig(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
|
||||
end
|
||||
}
|
||||
|
||||
--[[----------------------------------------------------------------------
|
||||
AceHook:_getFunctionHook- internal method
|
||||
-------------------------------------------------------------------------]]
|
||||
|
||||
local function _getFunctionHook(self, func, handler, orig)
|
||||
if type(handler) == "string" then
|
||||
-- The handler is a method, need to self it
|
||||
return function(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
|
||||
if actives[orig] then
|
||||
return self[handler](self, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
|
||||
else
|
||||
return orig(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
|
||||
end
|
||||
end
|
||||
else
|
||||
-- The handler is a function, just call it
|
||||
return function(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
|
||||
if actives[orig] then
|
||||
return handler(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
|
||||
else
|
||||
return orig(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--[[----------------------------------------------------------------------
|
||||
AceHook:_getMethodHook - Internal Method
|
||||
-------------------------------------------------------------------------]]
|
||||
local function _getMethodHook(self, object, method, handler, orig, script)
|
||||
if type(handler) == "string" then
|
||||
-- The handler is a method, need to self it
|
||||
if script then
|
||||
return function()
|
||||
if actives[orig] then
|
||||
return self[handler](self, object)
|
||||
else
|
||||
return orig()
|
||||
end
|
||||
end
|
||||
else
|
||||
return function(obj,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
|
||||
if actives[orig] then
|
||||
return self[handler](self, obj, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
|
||||
else
|
||||
return orig(obj, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
-- The handler is a function, just call it
|
||||
if script then
|
||||
return function()
|
||||
if actives[orig] then
|
||||
return handler(object)
|
||||
else
|
||||
return orig()
|
||||
end
|
||||
end
|
||||
else
|
||||
return function(obj,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
|
||||
if actives[orig] then
|
||||
return handler(obj,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
|
||||
else
|
||||
return orig(obj, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--[[----------------------------------------------------------------------
|
||||
AceHook:HookFunc - internal method.
|
||||
o You can only hook each function once from each source.
|
||||
o If there is an inactive hook for this func/handler pair, we reactivate it
|
||||
o If there is an inactive hook for another handler, we error out.
|
||||
o Looks for handler as a method of the calling class, error if not available
|
||||
o If handler is a function, it just uses it directly through the wrapper
|
||||
-------------------------------------------------------------------------]]
|
||||
local function _hookFunc(self, func, handler)
|
||||
local orig = _G[func]
|
||||
|
||||
if not orig or type(orig) ~= "function" then
|
||||
_debug(self, string.format("Attempt to hook a non-existant function %q", func),3)
|
||||
return
|
||||
end
|
||||
|
||||
if not handler then handler = func end
|
||||
|
||||
if self.hooks[func] then
|
||||
local orig = self.hooks[func].orig
|
||||
-- We have an active hook from this source. Don't multi-hook
|
||||
if actives[orig] then
|
||||
_debug(self, string.format("%q already has an active hook from this source.", func))
|
||||
return
|
||||
end
|
||||
-- The hook is inactive, so reactivate it
|
||||
if handlers[orig] == handler then
|
||||
actives[orig] = true
|
||||
return
|
||||
else
|
||||
AceHook:error("There is a stale hook for %q can't hook or reactivate.", func)
|
||||
end
|
||||
end
|
||||
|
||||
if type(handler) == "string" then
|
||||
if type(self[handler]) ~= "function" then
|
||||
AceHook:error("Could not find the the handler %q when hooking function %q", handler, func)
|
||||
end
|
||||
elseif type(handler) ~= "function" then
|
||||
AceHook:error("Could not find the handler you supplied when hooking %q", func)
|
||||
end
|
||||
|
||||
local t = setmetatable(new(), origMetatable)
|
||||
self.hooks[func] = t
|
||||
t.orig = orig
|
||||
|
||||
actives[orig] = true
|
||||
handlers[orig] = handler
|
||||
local newFunc = _getFunctionHook(self, func, handler, orig)
|
||||
funcs[orig] = newFunc
|
||||
|
||||
_G[func] = newFunc
|
||||
end
|
||||
|
||||
--[[----------------------------------------------------------------------
|
||||
AceHook:UnhookFunc - internal method
|
||||
o If you attempt to unhook a function that has never been hooked, or to unhook in a
|
||||
system that has never had a hook before, the system will error with a stack trace
|
||||
o If we own the global function, then put the original back in its place and remove
|
||||
all references to the Hooks[func] structure.
|
||||
o If we don't own the global function (we've been hooked) we deactivate the hook,
|
||||
forcing the handler to passthrough.
|
||||
-------------------------------------------------------------------------]]
|
||||
local function _unhookFunc(self, func)
|
||||
if not self.hooks[func] or not funcs[self.hooks[func].orig] then
|
||||
_debug(self, string.format("Tried to unhook %q which is not currently hooked.", func))
|
||||
return
|
||||
end
|
||||
|
||||
local orig = self.hooks[func].orig
|
||||
|
||||
if actives[orig] then
|
||||
-- See if we own the global function
|
||||
if _G[func] == funcs[orig] then
|
||||
_G[func] = orig
|
||||
self.hooks[func] = del(self.hooks[func])
|
||||
handlers[orig] = nil
|
||||
funcs[orig] = nil
|
||||
scripts[orig] = nil
|
||||
actives[orig] = nil
|
||||
-- Magically all-done
|
||||
else
|
||||
actives[orig] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--[[----------------------------------------------------------------------
|
||||
AceHook:HookMeth - Takes an optional fourth argument
|
||||
o script - Signifies whether this is a script hook or not
|
||||
-------------------------------------------------------------------------]]
|
||||
|
||||
local function _hookMeth(self, obj, method, handler, script)
|
||||
if not handler then handler = method end
|
||||
if (not obj or type(obj) ~= "table") then
|
||||
AceHook:error("The object you supplied could not be found, or isn't a table.")
|
||||
end
|
||||
|
||||
if self.hooks[obj] and self.hooks[obj][method] then
|
||||
local orig = self.hooks[obj][method].orig
|
||||
-- We have an active hook from this source. Don't multi-hook
|
||||
if actives[orig] then
|
||||
_debug(self, string.format("%q already has an active hook from this source.", method))
|
||||
return
|
||||
end
|
||||
-- The hook is inactive, so reactivate it.
|
||||
if handlers[orig] == handler then
|
||||
actives[orig] = true
|
||||
return
|
||||
else
|
||||
AceHook:error("There is a stale hook for %q can't hook or reactivate.", method)
|
||||
end
|
||||
end
|
||||
-- We're clear to try the hook, let's make some checks first
|
||||
if type(handler) == "string" then
|
||||
if type(self[handler]) ~= "function" then
|
||||
AceHook:error("Could not find the handler %q you supplied when hooking method %q", handler, method)
|
||||
end
|
||||
elseif type(handler) ~= "function" then
|
||||
AceHook:error("Could not find the handler you supplied when hooking method %q", method)
|
||||
end
|
||||
-- Handler has been found, so now try to find the method we're trying to hook
|
||||
local orig
|
||||
-- Script
|
||||
if script then
|
||||
if not obj.GetScript then
|
||||
AceHook:error("The object you supplied does not have a GetScript method.")
|
||||
end
|
||||
if not obj:HasScript(method) then
|
||||
AceHook:error("The object you supplied doesn't allow the %q method.", method)
|
||||
end
|
||||
-- Sometimes there is not a original function for a script.
|
||||
orig = obj:GetScript(method)
|
||||
if not orig then
|
||||
orig = function() end
|
||||
end
|
||||
-- Method
|
||||
else
|
||||
orig = obj[method]
|
||||
end
|
||||
if not orig then
|
||||
AceHook:error("Could not find the method or script %q you are trying to hook.", method)
|
||||
end
|
||||
if not self.hooks[obj] then
|
||||
self.hooks[obj] = new()
|
||||
end
|
||||
local t = setmetatable(new(), origMetatable)
|
||||
self.hooks[obj][method] = t
|
||||
t.orig = orig
|
||||
|
||||
actives[orig] = true
|
||||
handlers[orig] = handler
|
||||
scripts[orig] = script and true or nil
|
||||
local newFunc = _getMethodHook(self, obj, method, handler, orig, script)
|
||||
funcs[orig] = newFunc
|
||||
|
||||
if script then
|
||||
obj:SetScript(method, newFunc)
|
||||
else
|
||||
obj[method] = newFunc
|
||||
end
|
||||
end
|
||||
|
||||
--[[----------------------------------------------------------------------
|
||||
AceHook:UnhookMeth - Internal method
|
||||
o If you attempt to unhook a method that has never been hooked, or to unhook in a
|
||||
system that has never had a hook before, the system will error with a stack trace
|
||||
o If we own the global method, then put the original back in its place and remove
|
||||
all references to the Hooks[obj][method] structure.
|
||||
o If we don't own the global method (we've been hooked) we deactivate the hook,
|
||||
forcing the handler to passthrough.
|
||||
-------------------------------------------------------------------------]]
|
||||
local function _unhookMeth(self, obj, method)
|
||||
if not self.hooks[obj] or not self.hooks[obj][method] or not funcs[self.hooks[obj][method].orig] then
|
||||
_debug(self, string.format("Attempt to unhook a method %q that is not currently hooked.", method))
|
||||
return
|
||||
end
|
||||
|
||||
local orig = self.hooks[obj][method].orig
|
||||
|
||||
if actives[orig] then
|
||||
-- If this is a script
|
||||
if scripts[orig] then
|
||||
if obj:GetScript(method) == funcs[orig] then
|
||||
-- We own the script. Kill it.
|
||||
obj:SetScript(method, orig)
|
||||
self.hooks[obj][method] = del(self.hooks[obj][method])
|
||||
handlers[orig] = nil
|
||||
funcs[orig] = nil
|
||||
scripts[orig] = nil
|
||||
actives[orig] = nil
|
||||
else
|
||||
actives[orig] = nil
|
||||
end
|
||||
else
|
||||
if obj[method] == funcs[orig] then
|
||||
-- We own the method. Kill it.
|
||||
obj[method] = orig
|
||||
self.hooks[obj][method] = del(self.hooks[obj][method])
|
||||
handlers[orig] = nil
|
||||
funcs[orig] = nil
|
||||
scripts[orig] = nil
|
||||
actives[orig] = nil
|
||||
else
|
||||
actives[orig] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
if not next(self.hooks[obj]) then
|
||||
-- Spank the table
|
||||
self.hooks[obj] = del(self.hooks[obj])
|
||||
end
|
||||
end
|
||||
|
||||
function AceHook:OnInstanceInit(object)
|
||||
if not object.hooks then
|
||||
object.hooks = new()
|
||||
end
|
||||
|
||||
local name
|
||||
|
||||
if type(rawget(object, 'GetLibraryVersion')) == "function" then
|
||||
name = object:GetLibraryVersion()
|
||||
end
|
||||
if not name and type(object.GetName) == "function" then
|
||||
name = object:GetName()
|
||||
end
|
||||
if not name and type(object.name) == "string" then
|
||||
name = object.name
|
||||
end
|
||||
if not name then
|
||||
for k,v in pairs(_G) do
|
||||
if v == object then
|
||||
name = tostring(k)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
object.hooks.name = name
|
||||
end
|
||||
|
||||
AceHook.OnManualEmbed = AceHook.OnInstanceInit
|
||||
|
||||
--[[----------------------------------------------------------------------
|
||||
AceHook:Hook
|
||||
self:Hook("functionName", ["handlerName" | handler])
|
||||
self:Hook(ObjectName, "Method", ["Handler" | handler])
|
||||
-------------------------------------------------------------------------]]
|
||||
function AceHook:Hook(arg1, arg2, arg3)
|
||||
if type(arg1)== "string" then
|
||||
if protFuncs[arg1] then
|
||||
if self.hooks.name then
|
||||
AceHook:error("%s tried to hook %q, which is a Blizzard protected function.", self.hooks.name, arg1)
|
||||
else
|
||||
_debug(self, string.format("An Addon tried to hook %q, which is a Blizzard protected function.", arg1))
|
||||
end
|
||||
else
|
||||
_hookFunc(self, arg1, arg2)
|
||||
end
|
||||
else
|
||||
_hookMeth(self, arg1, arg2, arg3)
|
||||
end
|
||||
end
|
||||
|
||||
function AceHook:HookScript(arg1, arg2, arg3)
|
||||
_hookMeth(self, arg1, arg2, arg3, true)
|
||||
end
|
||||
|
||||
--[[----------------------------------------------------------------------
|
||||
AceHook:IsHooked()
|
||||
self:Hook("functionName")
|
||||
self:Hook(ObjectName, "Method")
|
||||
|
||||
Returns whether or not the given function is hooked in the current
|
||||
namespace. A hooked, but inactive function is considered NOT
|
||||
hooked in this context.
|
||||
-------------------------------------------------------------------------]]
|
||||
function AceHook:IsHooked(obj, method)
|
||||
if method and obj then
|
||||
if self.hooks and self.hooks[obj] and self.hooks[obj][method] and actives[self.hooks[obj][method].orig] then
|
||||
return true, handlers[self.hooks[obj][method].orig]
|
||||
end
|
||||
else
|
||||
if self.hooks and self.hooks[obj] and actives[self.hooks[obj].orig] then
|
||||
return true, handlers[self.hooks[obj].orig]
|
||||
end
|
||||
end
|
||||
|
||||
return false, nil
|
||||
end
|
||||
|
||||
--[[----------------------------------------------------------------------
|
||||
AceHook:Unhook
|
||||
self:Unhook("functionName")
|
||||
self:Unhook(ObjectName, "Method")
|
||||
-------------------------------------------------------------------------]]
|
||||
function AceHook:Unhook(arg1, arg2)
|
||||
if type(arg1) == "string" then
|
||||
_unhookFunc(self, arg1)
|
||||
else
|
||||
_unhookMeth(self, arg1, arg2)
|
||||
end
|
||||
end
|
||||
|
||||
--[[----------------------------------------------------------------------
|
||||
AceHook:UnhookAll - Unhooks all active hooks from the calling source
|
||||
-------------------------------------------------------------------------]]
|
||||
function AceHook:UnhookAll()
|
||||
for key, value in pairs(self.hooks) do
|
||||
if type(key) == "table" then
|
||||
for method in pairs(value) do
|
||||
self:Unhook(key, method)
|
||||
end
|
||||
else
|
||||
self:Unhook(key)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function AceHook:OnEmbedDisable(target)
|
||||
self.UnhookAll(target)
|
||||
end
|
||||
|
||||
--[[----------------------------------------------------------------------
|
||||
AceHook:HookReport - Lists registered hooks from this source
|
||||
-------------------------------------------------------------------------]]
|
||||
|
||||
function AceHook:HookReport()
|
||||
_debug(self, "This is a list of all active hooks for this object:")
|
||||
if not self.hooks then _debug(self, "No registered hooks.") return end
|
||||
|
||||
for key, value in pairs(self.hooks) do
|
||||
if type(value) == "table" then
|
||||
for method in pairs(value) do
|
||||
_debug(self, string.format("key: %s method: %q |cff%s|r", tostring(key), method, self.hooks[key][method].active and "00ff00Active" or "ffff00Inactive"))
|
||||
end
|
||||
else
|
||||
_debug(self, string.format("key: %s value: %q |cff%s|r", tostring(key), tostring(value), self.hooks[key].active and "00ff00Active" or "ffff00Inactive"))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------------------------------
|
||||
Stub and Library registration
|
||||
----------------------------------------------------------------------------------]]
|
||||
|
||||
local function activate(self, oldLib, oldDeactivate)
|
||||
AceHook = self
|
||||
|
||||
AceHook.super.activate(self, oldLib, oldDeactivate)
|
||||
|
||||
if oldLib then
|
||||
self.handlers = oldLib.handlers
|
||||
self.funcs = oldLib.funcs
|
||||
self.scripts = oldLib.scripts
|
||||
self.actives = oldLib.actives
|
||||
end
|
||||
|
||||
if not self.handlers then
|
||||
self.handlers = {}
|
||||
end
|
||||
if not self.funcs then
|
||||
self.funcs = {}
|
||||
end
|
||||
if not self.scripts then
|
||||
self.scripts = {}
|
||||
end
|
||||
if not self.actives then
|
||||
self.actives = {}
|
||||
end
|
||||
|
||||
handlers = self.handlers
|
||||
funcs = self.funcs
|
||||
scripts = self.scripts
|
||||
actives = self.actives
|
||||
|
||||
if oldDeactivate then
|
||||
oldDeactivate(oldLib)
|
||||
end
|
||||
end
|
||||
|
||||
AceLibrary:Register(AceHook, MAJOR_VERSION, MINOR_VERSION, activate)
|
||||
@@ -0,0 +1,568 @@
|
||||
--[[
|
||||
Name: AceHook-2.1
|
||||
Revision: $Rev: 15485 $
|
||||
Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team)
|
||||
Inspired By: Ace 1.x by Turan (turan@gryphon.com)
|
||||
Website: http://www.wowace.com/
|
||||
Documentation: http://www.wowace.com/index.php/AceHook-2.1
|
||||
SVN: http://svn.wowace.com/root/trunk/Ace2/AceHook-2.1
|
||||
Description: Mixin to allow for safe hooking of functions, methods, and scripts.
|
||||
Dependencies: AceLibrary, AceOO-2.0
|
||||
]]
|
||||
|
||||
local MAJOR_VERSION = "AceHook-2.1"
|
||||
local MINOR_VERSION = "$Revision: 15485 $"
|
||||
|
||||
-- This ensures the code is only executed if the libary doesn't already exist, or is a newer version
|
||||
if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary.") end
|
||||
if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end
|
||||
|
||||
if not AceLibrary:HasInstance("AceOO-2.0") then error(MAJOR_VERSION .. " requires AceOO-2.0") end
|
||||
|
||||
--[[---------------------------------------------------------------------------------
|
||||
Create the library object
|
||||
----------------------------------------------------------------------------------]]
|
||||
|
||||
local AceOO = AceLibrary:GetInstance("AceOO-2.0")
|
||||
local AceHook = AceOO.Mixin {
|
||||
"Hook",
|
||||
"HookScript",
|
||||
"SecureHook",
|
||||
"Unhook",
|
||||
"UnhookAll",
|
||||
"HookReport",
|
||||
"IsHooked",
|
||||
}
|
||||
|
||||
--[[---------------------------------------------------------------------------------
|
||||
Library Definitions
|
||||
----------------------------------------------------------------------------------]]
|
||||
|
||||
local protFuncs = {
|
||||
CameraOrSelectOrMoveStart = true, CameraOrSelectOrMoveStop = true,
|
||||
TurnOrActionStart = true, TurnOrActionStop = true,
|
||||
PitchUpStart = true, PitchUpStop = true,
|
||||
PitchDownStart = true, PitchDownStop = true,
|
||||
MoveBackwardStart = true, MoveBackwardStop = true,
|
||||
MoveForwardStart = true, MoveForwardStop = true,
|
||||
Jump = true, StrafeLeftStart = true,
|
||||
StrafeLeftStop = true, StrafeRightStart = true,
|
||||
StrafeRightStop = true, ToggleMouseMove = true,
|
||||
ToggleRun = true, TurnLeftStart = true,
|
||||
TurnLeftStop = true, TurnRightStart = true,
|
||||
TurnRightStop = true,
|
||||
}
|
||||
|
||||
local function issecurevariable(x)
|
||||
if protFuncs[x] then
|
||||
return 1
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
local _G = getfenv(0)
|
||||
|
||||
local function hooksecurefunc(arg1, arg2, arg3)
|
||||
if type(arg1) == "string" then
|
||||
arg1, arg2, arg3 = _G, arg1, arg2
|
||||
end
|
||||
local orig = arg1[arg2]
|
||||
arg1[arg2] = function(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
|
||||
local x1,x2,x3,x4,x5,x6,x7,x8,x9,x10,x11,x12,x13,x14,x15,x16,x17,x18,x19,x20 = orig(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
|
||||
|
||||
arg3(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
|
||||
|
||||
return x1,x2,x3,x4,x5,x6,x7,x8,x9,x10,x11,x12,x13,x14,x15,x16,x17,x18,x19,x20
|
||||
end
|
||||
end
|
||||
|
||||
local protectedScripts = {
|
||||
OnClick = true,
|
||||
}
|
||||
|
||||
|
||||
local handlers, scripts, actives, registry
|
||||
|
||||
--[[---------------------------------------------------------------------------------
|
||||
Private definitions (Not exposed)
|
||||
----------------------------------------------------------------------------------]]
|
||||
|
||||
local new, del
|
||||
do
|
||||
local list = setmetatable({}, {__mode = "k"})
|
||||
function new()
|
||||
local t = next(list)
|
||||
if not t then
|
||||
return {}
|
||||
end
|
||||
list[t] = nil
|
||||
return t
|
||||
end
|
||||
|
||||
function del(t)
|
||||
setmetatable(t, nil)
|
||||
for k in pairs(t) do
|
||||
t[k] = nil
|
||||
end
|
||||
list[t] = true
|
||||
end
|
||||
end
|
||||
|
||||
local function createFunctionHook(self, func, handler, orig, secure)
|
||||
if not secure then
|
||||
if type(handler) == "string" then
|
||||
-- The handler is a method, need to self it
|
||||
local uid
|
||||
uid = function(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
|
||||
if actives[uid] then
|
||||
return self[handler](self, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
|
||||
else
|
||||
return orig(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
|
||||
end
|
||||
end
|
||||
return uid
|
||||
else
|
||||
-- The handler is a function, just call it
|
||||
local uid
|
||||
uid = function(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
|
||||
if actives[uid] then
|
||||
return handler(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
|
||||
else
|
||||
return orig(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
|
||||
end
|
||||
end
|
||||
return uid
|
||||
end
|
||||
else
|
||||
-- secure hooks don't call the original method
|
||||
if type(handler) == "string" then
|
||||
-- The handler is a method, need to self it
|
||||
local uid
|
||||
uid = function(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
|
||||
if actives[uid] then
|
||||
return self[handler](self, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
|
||||
end
|
||||
end
|
||||
return uid
|
||||
else
|
||||
-- The handler is a function, just call it
|
||||
local uid
|
||||
uid = function(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
|
||||
if actives[uid] then
|
||||
return handler(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
|
||||
end
|
||||
end
|
||||
return uid
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function createMethodHook(self, object, method, handler, orig, secure, script)
|
||||
if script then
|
||||
if type(handler) == "string" then
|
||||
local uid
|
||||
uid = function()
|
||||
if actives[uid] then
|
||||
return self[handler](self, object)
|
||||
else
|
||||
return orig()
|
||||
end
|
||||
end
|
||||
return uid
|
||||
else
|
||||
-- The handler is a function, just call it
|
||||
local uid
|
||||
uid = function()
|
||||
if actives[uid] then
|
||||
return handler(object)
|
||||
else
|
||||
return orig()
|
||||
end
|
||||
end
|
||||
return uid
|
||||
end
|
||||
elseif not secure then
|
||||
if type(handler) == "string" then
|
||||
local uid
|
||||
uid = function(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
|
||||
if actives[uid] then
|
||||
return self[handler](self, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
|
||||
else
|
||||
return orig(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
|
||||
end
|
||||
end
|
||||
return uid
|
||||
else
|
||||
-- The handler is a function, just call it
|
||||
local uid
|
||||
uid = function(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
|
||||
if actives[uid] then
|
||||
return handler(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
|
||||
else
|
||||
return orig(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
|
||||
end
|
||||
end
|
||||
return uid
|
||||
end
|
||||
else
|
||||
-- secure hooks don't call the original method
|
||||
if type(handler) == "string" then
|
||||
local uid
|
||||
uid = function(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
|
||||
if actives[uid] then
|
||||
return self[handler](self, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
|
||||
end
|
||||
end
|
||||
return uid
|
||||
else
|
||||
-- The handler is a function, just call it
|
||||
local uid
|
||||
uid = function(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
|
||||
if actives[uid] then
|
||||
return handler(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
|
||||
end
|
||||
end
|
||||
return uid
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function hookFunction(self, func, handler, secure)
|
||||
local orig = _G[func]
|
||||
|
||||
if not orig or type(orig) ~= "function" then
|
||||
AceHook:error("Attempt to hook a non-existant function %q", func)
|
||||
end
|
||||
|
||||
if not handler then
|
||||
handler = func
|
||||
end
|
||||
|
||||
if registry[self][func] then
|
||||
local uid = registry[self][func]
|
||||
|
||||
if actives[uid] then
|
||||
-- We have an active hook from this source. Don't multi-hook
|
||||
AceHook:error("%q already has an active hook from this source.", func)
|
||||
end
|
||||
|
||||
if handlers[uid] == handler then
|
||||
-- The hook is inactive, so reactivate it
|
||||
actives[uid] = true
|
||||
return
|
||||
else
|
||||
AceHook:error("There is a stale hook for %q can't hook or reactivate.", func)
|
||||
end
|
||||
end
|
||||
|
||||
if type(handler) == "string" then
|
||||
if type(self[handler]) ~= "function" then
|
||||
AceHook:error("Could not find the the handler %q when hooking function %q", handler, func)
|
||||
end
|
||||
elseif type(handler) ~= "function" then
|
||||
AceHook:error("Could not find the handler you supplied when hooking %q", func)
|
||||
end
|
||||
|
||||
local uid = createFunctionHook(self, func, handler, orig, secure)
|
||||
registry[self][func] = uid
|
||||
actives[uid] = true
|
||||
handlers[uid] = handler
|
||||
|
||||
if not secure then
|
||||
_G[func] = uid
|
||||
self.hooks[func] = orig
|
||||
else
|
||||
hooksecurefunc(func, uid)
|
||||
end
|
||||
end
|
||||
|
||||
local function unhookFunction(self, func)
|
||||
if not registry[self][func] then
|
||||
AceHook:error("Tried to unhook %q which is not currently hooked.", func)
|
||||
end
|
||||
|
||||
local uid = registry[self][func]
|
||||
|
||||
if actives[uid] then
|
||||
-- See if we own the global function
|
||||
if self.hooks[func] and _G[func] == uid then
|
||||
_G[func] = self.hooks[func]
|
||||
self.hooks[func] = nil
|
||||
registry[self][func] = nil
|
||||
handlers[uid] = nil
|
||||
scripts[uid] = nil
|
||||
actives[uid] = nil
|
||||
-- Magically all-done
|
||||
else
|
||||
actives[uid] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function hookMethod(self, obj, method, handler, script, secure)
|
||||
if not handler then
|
||||
handler = method
|
||||
end
|
||||
|
||||
if not obj or type(obj) ~= "table" then
|
||||
AceHook:error("The object you supplied could not be found, or isn't a table.")
|
||||
end
|
||||
|
||||
local uid = registry[self][obj] and registry[self][obj][method]
|
||||
if uid then
|
||||
if actives[uid] then
|
||||
-- We have an active hook from this source. Don't multi-hook
|
||||
AceHook:error("%q already has an active hook from this source.", method)
|
||||
end
|
||||
|
||||
if handlers[uid] == handler then
|
||||
-- The hook is inactive, reactivate it.
|
||||
actives[uid] = true
|
||||
return
|
||||
else
|
||||
AceHook:error("There is a stale hook for %q can't hook or reactivate.", method)
|
||||
end
|
||||
end
|
||||
|
||||
if type(handler) == "string" then
|
||||
if type(self[handler]) ~= "function" then
|
||||
AceHook:error("Could not find the handler %q you supplied when hooking method %q", handler, method)
|
||||
end
|
||||
elseif type(handler) ~= "function" then
|
||||
AceHook:error("Could not find the handler you supplied when hooking method %q", method)
|
||||
end
|
||||
|
||||
local orig
|
||||
if script then
|
||||
if not obj.GetScript then
|
||||
AceHook:error("The object you supplied does not have a GetScript method.")
|
||||
end
|
||||
if not obj:HasScript(method) then
|
||||
AceHook:error("The object you supplied doesn't allow the %q method.", method)
|
||||
end
|
||||
|
||||
orig = obj:GetScript(method)
|
||||
if type(orig) ~= "function" then
|
||||
-- Sometimes there is not a original function for a script.
|
||||
orig = function() end
|
||||
end
|
||||
else
|
||||
orig = obj[method]
|
||||
end
|
||||
if not orig then
|
||||
AceHook:error("Could not find the method or script %q you are trying to hook.", method)
|
||||
end
|
||||
|
||||
if not registry[self][obj] then
|
||||
registry[self][obj] = new()
|
||||
end
|
||||
|
||||
if not self.hooks[obj] then
|
||||
self.hooks[obj] = new()
|
||||
end
|
||||
|
||||
local uid = createMethodHook(self, obj, method, handler, orig, secure, script)
|
||||
registry[self][obj][method] = uid
|
||||
actives[uid] = true
|
||||
handlers[uid] = handler
|
||||
scripts[uid] = script and true or nil
|
||||
|
||||
if script then
|
||||
obj:SetScript(method, uid)
|
||||
self.hooks[obj][method] = orig
|
||||
elseif not secure then
|
||||
obj[method] = uid
|
||||
self.hooks[obj][method] = orig
|
||||
else
|
||||
hooksecurefunc(obj, method, uid)
|
||||
end
|
||||
end
|
||||
|
||||
local function unhookMethod(self, obj, method)
|
||||
if not registry[self][obj] or not registry[self][obj][method] then
|
||||
AceHook:error("Attempt to unhook a method %q that is not currently hooked.", method)
|
||||
return
|
||||
end
|
||||
|
||||
local uid = registry[self][obj][method]
|
||||
|
||||
if actives[uid] then
|
||||
if scripts[uid] then -- If this is a script
|
||||
if obj:GetScript(method) == uid then
|
||||
-- We own the script. Revert to normal.
|
||||
obj:SetScript(method, self.hooks[obj][method])
|
||||
self.hooks[obj][method] = nil
|
||||
registry[self][obj][method] = nil
|
||||
handlers[uid] = nil
|
||||
scripts[uid] = nil
|
||||
actives[uid] = nil
|
||||
else
|
||||
actives[uid] = nil
|
||||
end
|
||||
else
|
||||
if self.hooks[obj][method] and obj[method] == uid then
|
||||
-- We own the method. Revert to normal.
|
||||
obj[method] = self.hooks[obj][method]
|
||||
self.hooks[obj][method] = nil
|
||||
registry[self][obj][method] = nil
|
||||
handlers[uid] = nil
|
||||
actives[uid] = nil
|
||||
else
|
||||
actives[uid] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
if not next(self.hooks[obj]) then
|
||||
self.hooks[obj] = del(self.hooks[obj])
|
||||
end
|
||||
if not next(registry[self][obj]) then
|
||||
registry[self][obj] = del(registry[self][obj])
|
||||
end
|
||||
end
|
||||
|
||||
-- ("function" [, handler] [, hookSecure]) or (object, "method" [, handler] [, hookSecure])
|
||||
function AceHook:Hook(object, method, handler, hookSecure)
|
||||
if type(object) == "string" then
|
||||
method, handler, hookSecure = object, method, handler
|
||||
if handler == true then
|
||||
handler, hookSecure = nil, true
|
||||
end
|
||||
if not hookSecure and issecurevariable(method) then
|
||||
AceHook:error("Attempt to hook secure function %q. Use `SecureHook' or add `true' to the argument list to override.", method)
|
||||
end
|
||||
AceHook:argCheck(handler, 3, "function", "string", "nil")
|
||||
AceHook:argCheck(hookSecure, 4, "boolean", "nil")
|
||||
hookFunction(self, method, handler, false)
|
||||
else
|
||||
if handler == true then
|
||||
handler, hookSecure = nil, true
|
||||
end
|
||||
if not hookSecure and issecurevariable(object, method) then
|
||||
AceHook:error("Attempt to hook secure method %q. Use `SecureHook' or add `true' to the argument list to override.", method)
|
||||
end
|
||||
AceHook:argCheck(object, 2, "table")
|
||||
AceHook:argCheck(method, 3, "string")
|
||||
AceHook:argCheck(handler, 4, "function", "string", "nil")
|
||||
AceHook:argCheck(hookSecure, 5, "boolean", "nil")
|
||||
hookMethod(self, object, method, handler, false, false)
|
||||
end
|
||||
end
|
||||
|
||||
-- ("function", handler) or (object, "method", handler)
|
||||
function AceHook:SecureHook(object, method, handler)
|
||||
if type(object) == "string" then
|
||||
method, handler = object, method
|
||||
AceHook:argCheck(handler, 3, "function", "string", "nil")
|
||||
hookFunction(self, method, handler, true)
|
||||
else
|
||||
AceHook:argCheck(object, 2, "table")
|
||||
AceHook:argCheck(method, 3, "string")
|
||||
AceHook:argCheck(handler, 4, "function", "string", "nil")
|
||||
hookMethod(self, object, method, handler, false, true)
|
||||
end
|
||||
end
|
||||
|
||||
function AceHook:HookScript(frame, script, handler)
|
||||
AceHook:argCheck(frame, 2, "table")
|
||||
if not frame[0] or type(frame.IsFrameType) ~= "function" then
|
||||
AceHook:error("Bad argument #2 to `HookScript'. Expected frame.")
|
||||
end
|
||||
AceHook:argCheck(script, 3, "string")
|
||||
AceHook:argCheck(handler, 4, "function", "string", "nil")
|
||||
hookMethod(self, frame, script, handler, true, false)
|
||||
end
|
||||
|
||||
-- ("function") or (object, "method")
|
||||
function AceHook:IsHooked(obj, method)
|
||||
if type(obj) == "string" then
|
||||
if registry[self][obj] and actives[registry[self][obj]] then
|
||||
return true, handlers[registry[self][obj]]
|
||||
end
|
||||
else
|
||||
AceHook:argCheck(obj, 2, "string", "table")
|
||||
AceHook:argCheck(method, 3, "string")
|
||||
if registry[self][obj] and registry[self][obj][method] and actives[registry[self][obj][method]] then
|
||||
return true, handlers[registry[self][obj][method]]
|
||||
end
|
||||
end
|
||||
|
||||
return false, nil
|
||||
end
|
||||
|
||||
-- ("function") or (object, "method")
|
||||
function AceHook:Unhook(obj, method)
|
||||
if type(obj) == "string" then
|
||||
unhookFunction(self, obj)
|
||||
else
|
||||
AceHook:argCheck(obj, 2, "string", "table")
|
||||
AceHook:argCheck(method, 3, "string")
|
||||
unhookMethod(self, obj, method)
|
||||
end
|
||||
end
|
||||
|
||||
function AceHook:UnhookAll()
|
||||
for key, value in pairs(self.hooks) do
|
||||
if type(key) == "table" then
|
||||
for method in pairs(value) do
|
||||
self:Unhook(key, method)
|
||||
end
|
||||
else
|
||||
self:Unhook(key)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function AceHook:HookReport()
|
||||
DEFAULT_CHAT_FRAME:AddMessage("This is a list of all active hooks for this object:")
|
||||
if not next(registry[self]) then
|
||||
DEFAULT_CHAT_FRAME:AddMessage("No hooks")
|
||||
end
|
||||
|
||||
for key, value in pairs(registry[self]) do
|
||||
if type(value) == "table" then
|
||||
for method, uid in pairs(value) do
|
||||
DEFAULT_CHAT_FRAME:AddMessage(string.format("object: %s method: %q |cff%s|r%s", tostring(key), method, actives[uid] and "00ff00Active" or "ffff00Inactive", not self.hooks[key][method] and " |cff7f7fff-Secure-|r" or ""))
|
||||
end
|
||||
else
|
||||
DEFAULT_CHAT_FRAME:AddMessage(string.format("function: %q |cff%s|r%s", tostring(key), actives[value] and "00ff00Active" or "ffff00Inactive", not self.hooks[key] and " |cff7f7fff-Secure-|r" or ""))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function AceHook:OnInstanceInit(object)
|
||||
if not object.hooks then
|
||||
object.hooks = new()
|
||||
end
|
||||
if not registry[object] then
|
||||
registry[object] = new()
|
||||
end
|
||||
end
|
||||
|
||||
AceHook.OnManualEmbed = AceHook.OnInstanceInit
|
||||
|
||||
function AceHook:OnEmbedDisable(target)
|
||||
self.UnhookAll(target)
|
||||
end
|
||||
|
||||
local function activate(self, oldLib, oldDeactivate)
|
||||
AceHook = self
|
||||
|
||||
self.handlers = oldLib and oldLib.handlers or {}
|
||||
self.registry = oldLib and oldLib.registry or {}
|
||||
self.scripts = oldLib and oldLib.scripts or {}
|
||||
self.actives = oldLib and oldLib.actives or {}
|
||||
|
||||
handlers = self.handlers
|
||||
registry = self.registry
|
||||
scripts = self.scripts
|
||||
actives = self.actives
|
||||
|
||||
AceHook.super.activate(self, oldLib, oldDeactivate)
|
||||
|
||||
if oldDeactivate then
|
||||
oldDeactivate(oldLib)
|
||||
end
|
||||
end
|
||||
|
||||
AceLibrary:Register(AceHook, MAJOR_VERSION, MINOR_VERSION, activate)
|
||||
@@ -0,0 +1,723 @@
|
||||
--[[
|
||||
Name: AceLibrary
|
||||
Revision: $Rev: 11612 $
|
||||
Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team)
|
||||
Inspired By: Iriel (iriel@vigilance-committee.org)
|
||||
Tekkub (tekkub@gmail.com)
|
||||
Revision: $Rev: 11612 $
|
||||
Website: http://www.wowace.com/
|
||||
Documentation: http://www.wowace.com/index.php/AceLibrary
|
||||
SVN: http://svn.wowace.com/root/trunk/Ace2/AceLibrary
|
||||
Description: Versioning library to handle other library instances, upgrading,
|
||||
and proper access.
|
||||
It also provides a base for libraries to work off of, providing
|
||||
proper error tools. It is handy because all the errors occur in the
|
||||
file that called it, not in the library file itself.
|
||||
Dependencies: None
|
||||
]]
|
||||
|
||||
local ACELIBRARY_MAJOR = "AceLibrary"
|
||||
local ACELIBRARY_MINOR = "$Revision: 11612 $"
|
||||
|
||||
-- CHANGE DEBUG TO ``false`` ON RELEASE -------------------
|
||||
local DEBUG = true
|
||||
-- CHANGE DEBUG TO ``false`` ON RELEASE -------------------
|
||||
|
||||
local table_setn
|
||||
do
|
||||
local version = GetBuildInfo()
|
||||
if string.find(version, "^2%.") then
|
||||
-- 2.0.0
|
||||
table_setn = function() end
|
||||
else
|
||||
table_setn = table.setn
|
||||
end
|
||||
end
|
||||
|
||||
local string_gfind = string.gmatch or string.gfind
|
||||
|
||||
local _G = getfenv(0)
|
||||
local previous = _G[ACELIBRARY_MAJOR]
|
||||
if previous and not previous:IsNewVersion(ACELIBRARY_MAJOR, ACELIBRARY_MINOR) then return end
|
||||
|
||||
-- @table AceLibrary
|
||||
-- @brief System to handle all versioning of libraries.
|
||||
local AceLibrary = {}
|
||||
local AceLibrary_mt = {}
|
||||
setmetatable(AceLibrary, AceLibrary_mt)
|
||||
|
||||
local tmp
|
||||
local function error(self, message, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
|
||||
if type(self) ~= "table" then
|
||||
_G.error(string.format("Bad argument #1 to `error' (table expected, got %s)", type(self)), 2)
|
||||
end
|
||||
if not tmp then
|
||||
tmp = {}
|
||||
else
|
||||
for k in pairs(tmp) do tmp[k] = nil end
|
||||
table_setn(tmp, 0)
|
||||
end
|
||||
|
||||
table.insert(tmp, a1)
|
||||
table.insert(tmp, a2)
|
||||
table.insert(tmp, a3)
|
||||
table.insert(tmp, a4)
|
||||
table.insert(tmp, a5)
|
||||
table.insert(tmp, a6)
|
||||
table.insert(tmp, a7)
|
||||
table.insert(tmp, a8)
|
||||
table.insert(tmp, a9)
|
||||
table.insert(tmp, a10)
|
||||
table.insert(tmp, a11)
|
||||
table.insert(tmp, a12)
|
||||
table.insert(tmp, a13)
|
||||
table.insert(tmp, a14)
|
||||
table.insert(tmp, a15)
|
||||
table.insert(tmp, a16)
|
||||
table.insert(tmp, a17)
|
||||
table.insert(tmp, a18)
|
||||
table.insert(tmp, a19)
|
||||
table.insert(tmp, a20)
|
||||
|
||||
local stack = debugstack()
|
||||
if not message then
|
||||
local _,_,second = string.find(stack, "\n(.-)\n")
|
||||
message = "error raised! " .. second
|
||||
else
|
||||
for i = 1,table.getn(tmp) do
|
||||
tmp[i] = tostring(tmp[i])
|
||||
end
|
||||
for i = 1,10 do
|
||||
table.insert(tmp, "nil")
|
||||
end
|
||||
message = string.format(message, unpack(tmp))
|
||||
end
|
||||
|
||||
if getmetatable(self) and getmetatable(self).__tostring then
|
||||
message = string.format("%s: %s", tostring(self), message)
|
||||
elseif type(rawget(self, 'GetLibraryVersion')) == "function" and AceLibrary:HasInstance(self:GetLibraryVersion()) then
|
||||
message = string.format("%s: %s", self:GetLibraryVersion(), message)
|
||||
elseif type(rawget(self, 'class')) == "table" and type(rawget(self.class, 'GetLibraryVersion')) == "function" and AceLibrary:HasInstance(self.class:GetLibraryVersion()) then
|
||||
message = string.format("%s: %s", self.class:GetLibraryVersion(), message)
|
||||
end
|
||||
|
||||
local first = string.gsub(stack, "\n.*", "")
|
||||
local file = string.gsub(first, ".*\\(.*).lua:%d+: .*", "%1")
|
||||
file = string.gsub(file, "([%(%)%.%*%+%-%[%]%?%^%$%%])", "%%%1")
|
||||
|
||||
local i = 0
|
||||
for s in string_gfind(stack, "\n([^\n]*)") do
|
||||
i = i + 1
|
||||
if not string.find(s, file .. "%.lua:%d+:") then
|
||||
file = string.gsub(s, "^.*\\(.*).lua:%d+: .*", "%1")
|
||||
file = string.gsub(file, "([%(%)%.%*%+%-%[%]%?%^%$%%])", "%%%1")
|
||||
break
|
||||
end
|
||||
end
|
||||
local j = 0
|
||||
for s in string_gfind(stack, "\n([^\n]*)") do
|
||||
j = j + 1
|
||||
if j > i and not string.find(s, file .. "%.lua:%d+:") then
|
||||
_G.error(message, j + 1)
|
||||
return
|
||||
end
|
||||
end
|
||||
_G.error(message, 2)
|
||||
return
|
||||
end
|
||||
|
||||
local function assert(self, condition, message, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
|
||||
if not condition then
|
||||
if not message then
|
||||
local stack = debugstack()
|
||||
local _,_,second = string.find(stack, "\n(.-)\n")
|
||||
message = "assertion failed! " .. second
|
||||
end
|
||||
error(self, message, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
|
||||
return
|
||||
end
|
||||
return condition
|
||||
end
|
||||
|
||||
local function argCheck(self, arg, num, kind, kind2, kind3, kind4, kind5)
|
||||
if type(num) ~= "number" then
|
||||
error(self, "Bad argument #3 to `argCheck' (number expected, got %s)", type(num))
|
||||
elseif type(kind) ~= "string" then
|
||||
error(self, "Bad argument #4 to `argCheck' (string expected, got %s)", type(kind))
|
||||
end
|
||||
local errored = false
|
||||
arg = type(arg)
|
||||
if arg ~= kind and arg ~= kind2 and arg ~= kind3 and arg ~= kind4 and arg ~= kind5 then
|
||||
local _,_,func = string.find(debugstack(), "`argCheck'.-([`<].-['>])")
|
||||
if not func then
|
||||
_,_,func = string.find(debugstack(), "([`<].-['>])")
|
||||
end
|
||||
if kind5 then
|
||||
error(self, "Bad argument #%s to %s (%s, %s, %s, %s, or %s expected, got %s)", tonumber(num) or 0/0, func, kind, kind2, kind3, kind4, kind5, arg)
|
||||
elseif kind4 then
|
||||
error(self, "Bad argument #%s to %s (%s, %s, %s, or %s expected, got %s)", tonumber(num) or 0/0, func, kind, kind2, kind3, kind4, arg)
|
||||
elseif kind3 then
|
||||
error(self, "Bad argument #%s to %s (%s, %s, or %s expected, got %s)", tonumber(num) or 0/0, func, kind, kind2, kind3, arg)
|
||||
elseif kind2 then
|
||||
error(self, "Bad argument #%s to %s (%s or %s expected, got %s)", tonumber(num) or 0/0, func, kind, kind2, arg)
|
||||
else
|
||||
error(self, "Bad argument #%s to %s (%s expected, got %s)", tonumber(num) or 0/0, func, kind, arg)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function pcall(self, func, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
|
||||
a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20 = _G.pcall(func, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
|
||||
if not a1 then
|
||||
error(self, string.gsub(a2, ".-%.lua:%d-: ", ""))
|
||||
else
|
||||
return a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20
|
||||
end
|
||||
end
|
||||
|
||||
local recurse = {}
|
||||
local function addToPositions(t, major)
|
||||
if not AceLibrary.positions[t] or AceLibrary.positions[t] == major then
|
||||
rawset(t, recurse, true)
|
||||
AceLibrary.positions[t] = major
|
||||
for k,v in pairs(t) do
|
||||
if type(v) == "table" and not rawget(v, recurse) then
|
||||
addToPositions(v, major)
|
||||
end
|
||||
if type(k) == "table" and not rawget(k, recurse) then
|
||||
addToPositions(k, major)
|
||||
end
|
||||
end
|
||||
local mt = getmetatable(t)
|
||||
if mt and not rawget(mt, recurse) then
|
||||
addToPositions(mt, major)
|
||||
end
|
||||
rawset(t, recurse, nil)
|
||||
end
|
||||
end
|
||||
|
||||
local function svnRevisionToNumber(text)
|
||||
if type(text) == "string" then
|
||||
if string.find(text, "^%$Revision: (%d+) %$$") then
|
||||
return tonumber((string.gsub(text, "^%$Revision: (%d+) %$$", "%1")))
|
||||
elseif string.find(text, "^%$Rev: (%d+) %$$") then
|
||||
return tonumber((string.gsub(text, "^%$Rev: (%d+) %$$", "%1")))
|
||||
elseif string.find(text, "^%$LastChangedRevision: (%d+) %$$") then
|
||||
return tonumber((string.gsub(text, "^%$LastChangedRevision: (%d+) %$$", "%1")))
|
||||
end
|
||||
elseif type(text) == "number" then
|
||||
return text
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
local crawlReplace
|
||||
do
|
||||
local recurse = {}
|
||||
local function func(t, to, from)
|
||||
if recurse[t] then
|
||||
return
|
||||
end
|
||||
recurse[t] = true
|
||||
local mt = getmetatable(t)
|
||||
setmetatable(t, nil)
|
||||
rawset(t, to, rawget(t, from))
|
||||
rawset(t, from, nil)
|
||||
for k,v in pairs(t) do
|
||||
if v == from then
|
||||
t[k] = to
|
||||
elseif type(v) == "table" then
|
||||
if not recurse[v] then
|
||||
func(v, to, from)
|
||||
end
|
||||
end
|
||||
|
||||
if type(k) == "table" then
|
||||
if not recurse[k] then
|
||||
func(k, to, from)
|
||||
end
|
||||
end
|
||||
end
|
||||
setmetatable(t, mt)
|
||||
if mt then
|
||||
if mt == from then
|
||||
setmetatable(t, to)
|
||||
elseif not recurse[mt] then
|
||||
func(mt, to, from)
|
||||
end
|
||||
end
|
||||
end
|
||||
function crawlReplace(t, to, from)
|
||||
func(t, to, from)
|
||||
for k in pairs(recurse) do
|
||||
recurse[k] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- @function destroyTable
|
||||
-- @brief remove all the contents of a table
|
||||
-- @param t table to destroy
|
||||
local function destroyTable(t)
|
||||
setmetatable(t, nil)
|
||||
for k,v in pairs(t) do t[k] = nil end
|
||||
table_setn(t, 0)
|
||||
end
|
||||
|
||||
local function isFrame(frame)
|
||||
return type(frame) == "table" and type(rawget(frame, 0)) == "userdata" and type(rawget(frame, 'IsFrameType')) == "function" and getmetatable(frame) and type(rawget(getmetatable(frame), '__index')) == "function"
|
||||
end
|
||||
|
||||
local new, del
|
||||
do
|
||||
local tables = setmetatable({}, {__mode = "k"})
|
||||
|
||||
function new()
|
||||
local t = next(tables)
|
||||
if t then
|
||||
tables[t] = nil
|
||||
return t
|
||||
else
|
||||
return {}
|
||||
end
|
||||
end
|
||||
|
||||
function del(t, depth)
|
||||
if depth and depth > 0 then
|
||||
for k,v in pairs(t) do
|
||||
if type(v) == "table" and not isFrame(v) then
|
||||
del(v, depth - 1)
|
||||
end
|
||||
end
|
||||
end
|
||||
destroyTable(t)
|
||||
tables[t] = true
|
||||
end
|
||||
end
|
||||
|
||||
-- @function copyTable
|
||||
-- @brief Create a shallow copy of a table and return it.
|
||||
-- @param from The table to copy from
|
||||
-- @return A shallow copy of the table
|
||||
local function copyTable(from)
|
||||
local to = new()
|
||||
for k,v in pairs(from) do to[k] = v end
|
||||
table_setn(to, table.getn(from))
|
||||
setmetatable(to, getmetatable(from))
|
||||
return to
|
||||
end
|
||||
|
||||
-- @function deepTransfer
|
||||
-- @brief Fully transfer all data, keeping proper previous table
|
||||
-- backreferences stable.
|
||||
-- @param to The table with which data is to be injected into
|
||||
-- @param from The table whose data will be injected into the first
|
||||
-- @param saveFields If available, a shallow copy of the basic data is saved
|
||||
-- in here.
|
||||
-- @param list The account of table references
|
||||
-- @param list2 The current status on which tables have been traversed.
|
||||
local deepTransfer
|
||||
do
|
||||
-- @function examine
|
||||
-- @brief Take account of all the table references to be shared
|
||||
-- between the to and from tables.
|
||||
-- @param to The table with which data is to be injected into
|
||||
-- @param from The table whose data will be injected into the first
|
||||
-- @param list An account of the table references
|
||||
local function examine(to, from, list, major)
|
||||
list[from] = to
|
||||
for k,v in pairs(from) do
|
||||
if rawget(to, k) and type(from[k]) == "table" and type(to[k]) == "table" and not list[from[k]] then
|
||||
if from[k] == to[k] then
|
||||
list[from[k]] = to[k]
|
||||
elseif AceLibrary.positions[from[v]] ~= major and AceLibrary.positions[from[v]] then
|
||||
list[from[k]] = from[k]
|
||||
elseif not list[from[k]] then
|
||||
examine(to[k], from[k], list, major)
|
||||
end
|
||||
end
|
||||
end
|
||||
return list
|
||||
end
|
||||
|
||||
function deepTransfer(to, from, saveFields, major, list, list2)
|
||||
setmetatable(to, nil)
|
||||
local createdList
|
||||
if not list then
|
||||
createdList = true
|
||||
list = new()
|
||||
list2 = new()
|
||||
examine(to, from, list, major)
|
||||
end
|
||||
list2[to] = to
|
||||
for k,v in pairs(to) do
|
||||
if type(rawget(from, k)) ~= "table" or type(v) ~= "table" or isFrame(v) then
|
||||
if saveFields then
|
||||
saveFields[k] = v
|
||||
end
|
||||
to[k] = nil
|
||||
elseif v ~= _G then
|
||||
if saveFields then
|
||||
saveFields[k] = copyTable(v)
|
||||
end
|
||||
end
|
||||
end
|
||||
for k in pairs(from) do
|
||||
if rawget(to, k) and to[k] ~= from[k] and AceLibrary.positions[to[k]] == major and from[k] ~= _G then
|
||||
if not list2[to[k]] then
|
||||
deepTransfer(to[k], from[k], nil, major, list, list2)
|
||||
end
|
||||
to[k] = list[to[k]] or list2[to[k]]
|
||||
else
|
||||
rawset(to, k, from[k])
|
||||
end
|
||||
end
|
||||
table_setn(to, table.getn(from))
|
||||
setmetatable(to, getmetatable(from))
|
||||
local mt = getmetatable(to)
|
||||
if mt then
|
||||
if list[mt] then
|
||||
setmetatable(to, list[mt])
|
||||
elseif mt.__index and list[mt.__index] then
|
||||
mt.__index = list[mt.__index]
|
||||
end
|
||||
end
|
||||
destroyTable(from)
|
||||
if createdList then
|
||||
del(list)
|
||||
del(list2)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- @method IsNewVersion
|
||||
-- @brief Obtain whether the supplied version would be an upgrade to the
|
||||
-- current version. This allows for bypass code in library
|
||||
-- declaration.
|
||||
-- @param major A string representing the major version
|
||||
-- @param minor An integer or an svn revision string representing the minor version
|
||||
-- @return whether the supplied version would be newer than what is
|
||||
-- currently available.
|
||||
function AceLibrary:IsNewVersion(major, minor)
|
||||
argCheck(self, major, 2, "string")
|
||||
if type(minor) == "string" then
|
||||
local m = svnRevisionToNumber(minor)
|
||||
if m then
|
||||
minor = m
|
||||
else
|
||||
_G.error(string.format("Bad argument #3 to `IsNewVersion'. Must be a number or SVN revision string. %q is not appropriate", minor), 2)
|
||||
end
|
||||
end
|
||||
argCheck(self, minor, 3, "number")
|
||||
local data = self.libs[major]
|
||||
if not data then
|
||||
return true
|
||||
end
|
||||
return data.minor < minor
|
||||
end
|
||||
|
||||
-- @method HasInstance
|
||||
-- @brief Returns whether an instance exists. This allows for optional support of a library.
|
||||
-- @param major A string representing the major version.
|
||||
-- @param minor (optional) An integer or an svn revision string representing the minor version.
|
||||
-- @return Whether an instance exists.
|
||||
function AceLibrary:HasInstance(major, minor)
|
||||
argCheck(self, major, 2, "string")
|
||||
if minor then
|
||||
if type(minor) == "string" then
|
||||
local m = svnRevisionToNumber(minor)
|
||||
if m then
|
||||
minor = m
|
||||
else
|
||||
_G.error(string.format("Bad argument #3 to `HasInstance'. Must be a number or SVN revision string. %q is not appropriate", minor), 2)
|
||||
end
|
||||
end
|
||||
argCheck(self, minor, 3, "number")
|
||||
if not self.libs[major] then
|
||||
return
|
||||
end
|
||||
return self.libs[major].minor == minor
|
||||
end
|
||||
return self.libs[major] and true
|
||||
end
|
||||
|
||||
-- @method GetInstance
|
||||
-- @brief Returns the library with the given major/minor version.
|
||||
-- @param major A string representing the major version.
|
||||
-- @param minor (optional) An integer or an svn revision string representing the minor version.
|
||||
-- @return The library with the given major/minor version.
|
||||
function AceLibrary:GetInstance(major, minor)
|
||||
argCheck(self, major, 2, "string")
|
||||
|
||||
local data = self.libs[major]
|
||||
if not data then
|
||||
_G.error(string.format("Cannot find a library instance of %s.", major), 2)
|
||||
return
|
||||
end
|
||||
if minor then
|
||||
if type(minor) == "string" then
|
||||
local m = svnRevisionToNumber(minor)
|
||||
if m then
|
||||
minor = m
|
||||
else
|
||||
_G.error(string.format("Bad argument #3 to `GetInstance'. Must be a number or SVN revision string. %q is not appropriate", minor), 2)
|
||||
end
|
||||
end
|
||||
argCheck(self, minor, 2, "number")
|
||||
if data.minor ~= minor then
|
||||
_G.error(string.format("Cannot find a library instance of %s, minor version %d.", major, minor), 2)
|
||||
return
|
||||
end
|
||||
end
|
||||
return data.instance
|
||||
end
|
||||
|
||||
-- Syntax sugar. AceLibrary("FooBar-1.0")
|
||||
AceLibrary_mt.__call = AceLibrary.GetInstance
|
||||
|
||||
local donothing
|
||||
|
||||
local AceEvent
|
||||
|
||||
-- @method Register
|
||||
-- @brief Registers a new version of a given library.
|
||||
-- @param newInstance the library to register
|
||||
-- @param major the major version of the library
|
||||
-- @param minor the minor version of the library
|
||||
-- @param activateFunc (optional) A function to be called when the library is
|
||||
-- fully activated. Takes the arguments
|
||||
-- (newInstance [, oldInstance, oldDeactivateFunc]). If
|
||||
-- oldInstance is given, you should probably call
|
||||
-- oldDeactivateFunc(oldInstance).
|
||||
-- @param deactivateFunc (optional) A function to be called by a newer library's
|
||||
-- activateFunc.
|
||||
-- @param externalFunc (optional) A function to be called whenever a new
|
||||
-- library is registered.
|
||||
function AceLibrary:Register(newInstance, major, minor, activateFunc, deactivateFunc, externalFunc)
|
||||
argCheck(self, newInstance, 2, "table")
|
||||
argCheck(self, major, 3, "string")
|
||||
if type(minor) == "string" then
|
||||
local m = svnRevisionToNumber(minor)
|
||||
if m then
|
||||
minor = m
|
||||
else
|
||||
_G.error(string.format("Bad argument #4 to `Register'. Must be a number or SVN revision string. %q is not appropriate", minor), 2)
|
||||
end
|
||||
end
|
||||
argCheck(self, minor, 4, "number")
|
||||
if math.floor(minor) ~= minor or minor < 0 then
|
||||
error(self, "Bad argument #4 to `Register' (integer >= 0 expected, got %s)", minor)
|
||||
end
|
||||
argCheck(self, activateFunc, 5, "function", "nil")
|
||||
argCheck(self, deactivateFunc, 6, "function", "nil")
|
||||
argCheck(self, externalFunc, 7, "function", "nil")
|
||||
if not deactivateFunc then
|
||||
if not donothing then
|
||||
donothing = function() end
|
||||
end
|
||||
deactivateFunc = donothing
|
||||
end
|
||||
local data = self.libs[major]
|
||||
if not data then
|
||||
-- This is new
|
||||
local instance = copyTable(newInstance)
|
||||
crawlReplace(instance, instance, newInstance)
|
||||
destroyTable(newInstance)
|
||||
if AceLibrary == newInstance then
|
||||
self = instance
|
||||
AceLibrary = instance
|
||||
end
|
||||
self.libs[major] = {
|
||||
instance = instance,
|
||||
minor = minor,
|
||||
deactivateFunc = deactivateFunc,
|
||||
externalFunc = externalFunc,
|
||||
}
|
||||
rawset(instance, 'GetLibraryVersion', function(self)
|
||||
return major, minor
|
||||
end)
|
||||
if not rawget(instance, 'error') then
|
||||
rawset(instance, 'error', error)
|
||||
end
|
||||
if not rawget(instance, 'assert') then
|
||||
rawset(instance, 'assert', assert)
|
||||
end
|
||||
if not rawget(instance, 'argCheck') then
|
||||
rawset(instance, 'argCheck', argCheck)
|
||||
end
|
||||
if not rawget(instance, 'pcall') then
|
||||
rawset(instance, 'pcall', pcall)
|
||||
end
|
||||
addToPositions(instance, major)
|
||||
if activateFunc then
|
||||
activateFunc(instance, nil, nil) -- no old version, so explicit nil
|
||||
end
|
||||
|
||||
if externalFunc then
|
||||
for k,data in pairs(self.libs) do
|
||||
if k ~= major then
|
||||
externalFunc(instance, k, data.instance)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for k,data in pairs(self.libs) do
|
||||
if k ~= major and data.externalFunc then
|
||||
data.externalFunc(data.instance, major, instance)
|
||||
end
|
||||
end
|
||||
if major == "AceEvent-2.0" then
|
||||
AceEvent = instance
|
||||
end
|
||||
if AceEvent then
|
||||
AceEvent.TriggerEvent(self, "AceLibrary_Register", major, instance)
|
||||
end
|
||||
|
||||
return instance
|
||||
end
|
||||
local instance = data.instance
|
||||
if minor <= data.minor then
|
||||
if DEBUG then
|
||||
-- This one is already obsolete, raise an error.
|
||||
error(string.format("Obsolete library registered. %s is already registered at version %d. You are trying to register version %d. Hint: if not AceLibrary:IsNewVersion(%q, %d) then return end", major, data.minor, minor, major, minor), 2)
|
||||
return
|
||||
end
|
||||
return instance
|
||||
end
|
||||
-- This is an update
|
||||
local oldInstance = new()
|
||||
|
||||
addToPositions(newInstance, major)
|
||||
local isAceLibrary = (AceLibrary == newInstance)
|
||||
local old_error, old_assert, old_argCheck, old_pcall
|
||||
if isAceLibrary then
|
||||
self = instance
|
||||
AceLibrary = instance
|
||||
|
||||
old_error = instance.error
|
||||
old_assert = instance.assert
|
||||
old_argCheck = instance.argCheck
|
||||
old_pcall = instance.pcall
|
||||
|
||||
self.error = error
|
||||
self.assert = assert
|
||||
self.argCheck = argCheck
|
||||
self.pcall = pcall
|
||||
end
|
||||
deepTransfer(instance, newInstance, oldInstance, major)
|
||||
crawlReplace(instance, instance, newInstance)
|
||||
local oldDeactivateFunc = data.deactivateFunc
|
||||
data.minor = minor
|
||||
data.deactivateFunc = deactivateFunc
|
||||
data.externalFunc = externalFunc
|
||||
rawset(instance, 'GetLibraryVersion', function(self)
|
||||
return major, minor
|
||||
end)
|
||||
if not rawget(instance, 'error') then
|
||||
rawset(instance, 'error', error)
|
||||
end
|
||||
if not rawget(instance, 'assert') then
|
||||
rawset(instance, 'assert', assert)
|
||||
end
|
||||
if not rawget(instance, 'argCheck') then
|
||||
rawset(instance, 'argCheck', argCheck)
|
||||
end
|
||||
if not rawget(instance, 'pcall') then
|
||||
rawset(instance, 'pcall', pcall)
|
||||
end
|
||||
if isAceLibrary then
|
||||
for _,v in pairs(self.libs) do
|
||||
local i = type(v) == "table" and v.instance
|
||||
if type(i) == "table" then
|
||||
if not rawget(i, 'error') or i.error == old_error then
|
||||
rawset(i, 'error', error)
|
||||
end
|
||||
if not rawget(i, 'assert') or i.assert == old_assert then
|
||||
rawset(i, 'assert', assert)
|
||||
end
|
||||
if not rawget(i, 'argCheck') or i.argCheck == old_argCheck then
|
||||
rawset(i, 'argCheck', argCheck)
|
||||
end
|
||||
if not rawget(i, 'pcall') or i.pcall == old_pcall then
|
||||
rawset(i, 'pcall', pcall)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if activateFunc then
|
||||
activateFunc(instance, oldInstance, oldDeactivateFunc)
|
||||
else
|
||||
oldDeactivateFunc(oldInstance)
|
||||
end
|
||||
del(oldInstance)
|
||||
|
||||
if externalFunc then
|
||||
for k,data in pairs(self.libs) do
|
||||
if k ~= major then
|
||||
externalFunc(instance, k, data.instance)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return instance
|
||||
end
|
||||
|
||||
local iter
|
||||
function AceLibrary:IterateLibraries()
|
||||
if not iter then
|
||||
local function iter(t, k)
|
||||
k = next(t, k)
|
||||
if not k then
|
||||
return nil
|
||||
else
|
||||
return k, t[k].instance
|
||||
end
|
||||
end
|
||||
end
|
||||
return iter, self.libs, nil
|
||||
end
|
||||
|
||||
-- @function Activate
|
||||
-- @brief The activateFunc for AceLibrary itself. Called when
|
||||
-- AceLibrary properly registers.
|
||||
-- @param self Reference to AceLibrary
|
||||
-- @param oldLib (optional) Reference to an old version of AceLibrary
|
||||
-- @param oldDeactivate (optional) Function to deactivate the old lib
|
||||
local function activate(self, oldLib, oldDeactivate)
|
||||
if not self.libs then
|
||||
if oldLib then
|
||||
self.libs = oldLib.libs
|
||||
end
|
||||
if not self.libs then
|
||||
self.libs = {}
|
||||
end
|
||||
end
|
||||
if not self.positions then
|
||||
if oldLib then
|
||||
self.positions = oldLib.positions
|
||||
end
|
||||
if not self.positions then
|
||||
self.positions = setmetatable({}, { __mode = "k" })
|
||||
end
|
||||
end
|
||||
|
||||
-- Expose the library in the global environment
|
||||
_G[ACELIBRARY_MAJOR] = self
|
||||
|
||||
if oldDeactivate then
|
||||
oldDeactivate(oldLib)
|
||||
end
|
||||
end
|
||||
|
||||
if not previous then
|
||||
previous = AceLibrary
|
||||
end
|
||||
if not previous.libs then
|
||||
previous.libs = {}
|
||||
end
|
||||
AceLibrary.libs = previous.libs
|
||||
if not previous.positions then
|
||||
previous.positions = setmetatable({}, { __mode = "k" })
|
||||
end
|
||||
AceLibrary.positions = previous.positions
|
||||
AceLibrary:Register(AceLibrary, ACELIBRARY_MAJOR, ACELIBRARY_MINOR, activate)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,26 @@
|
||||
-- zhCN localization by hk2717
|
||||
|
||||
if GetLocale() == "zhCN" then
|
||||
POSTAL_HELP = "将物品拖入下面的空格中。每个物品都将以单独的邮件发送给收件人。邮件标题为你输入的标题后加物品名称数量(例如: <标题> [金锭 x10])。合计邮资显示于顶部右侧。你可以按住Alt键单击你背包中的物品,直接将其添加到邮件列表中。";
|
||||
|
||||
POSTAL_SEND = "发送邮件";
|
||||
POSTAL_SENDBUTTON = "发送";
|
||||
POSTAL_CANCELBUTTON = "取消";
|
||||
|
||||
POSTAL_SENDINFO = "你确定要发送这些邮件吗?合计邮资:";
|
||||
POSTAL_SENDINFO2 = "正在发送:";
|
||||
POSTAL_ITEMS = "物品";
|
||||
POSTAL_ABORT = "中止";
|
||||
|
||||
POSTAL_ITEMNUM = "已发送%d个物品,总计%d个物品。";
|
||||
POSTAL_SENDING = "发送邮件 |c00FFFFFF%d|r/|c00FFFFFF%d|r…";
|
||||
POSTAL_DONESENDING = "邮寄完毕,总计|c00FFFFFF%d|r封邮件";
|
||||
POSTAL_ABORTED = "中止邮寄,已寄出|c00FFFFFF%d|r/|c00FFFFFF%d|r封邮件。";
|
||||
POSTAL_ERROR = "POSTAL出现了一个错误。可能是由网络延迟导致的,请尝试用普通邮件窗口邮寄一个物品。也可能是试图邮寄不能邮寄的物品而导致。";
|
||||
|
||||
POSTAL_INBOX_OPENSELECTED = "打开选择";
|
||||
POSTAL_INBOX_OPENALL = "打开全部";
|
||||
POSTAL_INBOX_OPENALLTITLE = "打开全部?";
|
||||
POSTAL_INBOX_OPENALLCONFIRMATION = "确定要打开全部邮件吗?";
|
||||
POSTAL_INBOX_DISPLAYPROCESSMESSAGES = "显示进程信息";
|
||||
end
|
||||
@@ -0,0 +1,27 @@
|
||||
-- Version : French ( by Sasmira )
|
||||
-- Last Update : 03/29/2005
|
||||
|
||||
if GetLocale() == "frFR" then
|
||||
POSTAL_HELP = "compl\195\169tez autant de cases que vous souhaitez. Chaque article sera envoy\195\169 s\195\169par\195\169ment dans un courrier au destinataire, avec le sujet que vous sp\195\169cifiez et qui sera attach\195\169 au nom de l\'objet plus un num\195\169ro, ( Pour exemple : <Sujet> [Barre d\'Or x10]). L\'affranchissement combin\195\169 est montr\195\169 dans le coin en haut \195\60 droite. Vous pouvez ALT-Clic Gauche sur les objets dans votre inventaire afin de les ajouter \195\60 la liste automatiquement.";
|
||||
|
||||
POSTAL_SEND = "Envoyer un Message";
|
||||
POSTAL_SENDBUTTON = "Envoi";
|
||||
POSTAL_CANCELBUTTON = "Annuler";
|
||||
|
||||
POSTAL_SENDINFO = "Etes vous sur de vouloir envoyer ce message ? La Somme Totale pour les messages post\195\169s sera de :";
|
||||
POSTAL_SENDINFO2 = "Vous avez envoy\195\169 :";
|
||||
POSTAL_ITEMS = "Objet(s)";
|
||||
POSTAL_ABORT = "Abandonner";
|
||||
|
||||
POSTAL_ITEMNUM = "Objet %d hors de %d.";
|
||||
POSTAL_SENDING = "Envoi de Messages |c00FFFFFF%d|r/|c00FFFFFF%d|r...";
|
||||
POSTAL_DONESENDING = "Envoi de |c00FFFFFF%d|r message(s) termin\195\169(s) !";
|
||||
POSTAL_ABORTED = "Abandonn\195\169. |c00FFFFFF%d|r/|c00FFFFFF%d|r de message(s) a \195\169t\195\169 envoy\195\169.";
|
||||
POSTAL_ERROR = "Une Erreur c\'est produite dans Postal. Envoyez un rapport de bug \195\160 l\'url suivante : http://www.ctmod.net";
|
||||
|
||||
POSTAL_INBOX_OPENSELECTED = "Ouvrir la s\195\169lection";
|
||||
POSTAL_INBOX_OPENALL = "Tous les Ouvrir";
|
||||
POSTAL_INBOX_OPENALLTITLE = "Ouvrir les messages ?";
|
||||
POSTAL_INBOX_OPENALLCONFIRMATION = "Etes vous sur de vouloir ouvrir tous les messages ?";
|
||||
POSTAL_INBOX_DISPLAYPROCESSMESSAGES = "Afficher les processus";
|
||||
end
|
||||
@@ -0,0 +1,20 @@
|
||||
if GetLocale() == "deDE" then
|
||||
-- Credits to Hjörvarör for these
|
||||
|
||||
POSTAL_HELP = "Belege soviele Pl\195\164tze wie du m\195\182chtest. Jeder Gegenstand wird seperat an den Empf\195\164nger gesendet, und zwar mit dem Betreff den du bestimmst gefolgt vom Namen des Gegenstands und dessen Anzahl (z.B. <Betreff> [Goldbarren x10]). Die zusammengefassten Versandkosten werden oben rechts angezeigt. Du kannst Gegenst\195\164nde in deinen Taschen durch Alt-Klick automatisch zur Liste hinzuf\195\188gen.";
|
||||
|
||||
POSTAL_SEND = "Post verschicken";
|
||||
POSTAL_SENDBUTTON = "Verschicken";
|
||||
POSTAL_CANCELBUTTON = "Abbrechen";
|
||||
|
||||
POSTAL_SENDINFO = "Bist du sicher das du die Post verschicken willst? Die gesamten Versandkosten belaufen sich auf:";
|
||||
POSTAL_SENDINFO2 = "Du verschickst:";
|
||||
POSTAL_ITEMS = "Item(s)";
|
||||
POSTAL_ABORT = "Abbrechen";
|
||||
|
||||
POSTAL_ITEMNUM = "Gegenstand %d von %d.";
|
||||
POSTAL_SENDING = "Verschicke P\195\164ckchen |c00FFFFFF%d|r/|c00FFFFFF%d|r...";
|
||||
POSTAL_DONESENDING = "Verschicken von |c00FFFFFF%d|r P\195\164ckchen erledigt!";
|
||||
POSTAL_ABORTED = "Abgebrochen. |c00FFFFFF%d|r/|c00FFFFFF%d|r P\195\164ckchen wurde(n) verschickt.";
|
||||
POSTAL_ERROR = "Ein Fehler in Postal ist aufgetreten. Bitte \195\188bermittle einen Fehlerbericht auf http://www.ctmod.net";
|
||||
end
|
||||
@@ -0,0 +1,22 @@
|
||||
POSTAL_HELP = "Fill in as many slots as you want. Each item will be sent in a separate mail to the recipient, with the subject you specify, followed by the item's name and count (for example: <Subject> [Gold Bar x10]). The combined postage is shown in the top right. You can alt-click on items in your bags to add them to the list automatically.";
|
||||
|
||||
POSTAL_SEND = "Send Mail";
|
||||
POSTAL_SENDBUTTON = "Send";
|
||||
POSTAL_CANCELBUTTON = "Cancel";
|
||||
|
||||
POSTAL_SENDINFO = "Are you sure you want to send the mail? Total postage will be:";
|
||||
POSTAL_SENDINFO2 = "You are sending:";
|
||||
POSTAL_ITEMS = "Item(s)";
|
||||
POSTAL_ABORT = "Abort";
|
||||
|
||||
POSTAL_ITEMNUM = "Item %d out of %d.";
|
||||
POSTAL_SENDING = "Sending mail |c00FFFFFF%d|r/|c00FFFFFF%d|r...";
|
||||
POSTAL_DONESENDING = "Done sending |c00FFFFFF%d|r mail(s)!";
|
||||
POSTAL_ABORTED = "Aborted. |c00FFFFFF%d|r/|c00FFFFFF%d|r mail were sent.";
|
||||
POSTAL_ERROR = "An error occured in POSTAL. This might be related to lag, trying to send items with an item placed in the normal send mail window, or trying to send items that cannot be sent.";
|
||||
|
||||
POSTAL_INBOX_OPENSELECTED = "Open Selected";
|
||||
POSTAL_INBOX_OPENALL = "Open All";
|
||||
POSTAL_INBOX_OPENALLTITLE = "Open All?";
|
||||
POSTAL_INBOX_OPENALLCONFIRMATION = "Are you sure you want to open all mail?";
|
||||
POSTAL_INBOX_DISPLAYPROCESSMESSAGES = "Display process messages";
|
||||
@@ -0,0 +1,33 @@
|
||||
if GetLocale() == "zhTW" then
|
||||
POSTAL_HELP = "將物品拖入下面空格中。每件物品都將以單獨的信件寄給收件者。郵件標題為你輸入的標題+物品名稱+數量(例: <標題> [夢葉草 x10])。郵資計算顯示於右上方。你可以使用Alt點選背包中的物品直接加入寄件清單中。";
|
||||
|
||||
POSTAL_SEND = "發送郵件";
|
||||
POSTAL_SENDBUTTON = "發送";
|
||||
POSTAL_CANCELBUTTON = "取消";
|
||||
|
||||
POSTAL_SENDINFO = "你確定要發送這些郵件嗎?合計郵資:";
|
||||
POSTAL_SENDINFO2 = "正在發送:";
|
||||
POSTAL_ITEMS = "物品";
|
||||
POSTAL_ABORT = "中止";
|
||||
|
||||
POSTAL_ITEMNUM = "已發送%d件物品,總計%d件物品。";
|
||||
POSTAL_SENDING = "發送郵件 |c00FFFFFF%d|r/|c00FFFFFF%d|r...";
|
||||
POSTAL_DONESENDING = "寄件完畢,總計|c00FFFFFF%d|r封郵件";
|
||||
POSTAL_ABORTED = "中止發送,已寄出|c00FFFFFF%d|r/|c00FFFFFF%d|r封郵件";
|
||||
POSTAL_ERROR = "Gmail出現了一個錯誤,可能是網路延遲所導致,請嘗試用普通郵件寄出一件物品,也有可能是點選了不能郵寄的物品所導致。";
|
||||
|
||||
POSTAL_INBOX_OPENSELECTED = "打開選擇郵件";
|
||||
POSTAL_INBOX_OPENALL = "打開全部郵件";
|
||||
POSTAL_INBOX_OPENALLTITLE = "打開全部?";
|
||||
POSTAL_INBOX_OPENALLCONFIRMATION = "確定要打開全部郵件嗎?";
|
||||
POSTAL_INBOX_DISPLAYPROCESSMESSAGES = "顯示處理過程";
|
||||
|
||||
POSTAL_MASS_MAIL="群發郵件";
|
||||
POSTAL_FORWARD="轉寄";
|
||||
|
||||
POSTAL_NOSUBJECT="<無標題>"
|
||||
POSTAL_UNKNOWNSENDER="<未知寄件者>"
|
||||
POSTAL_OPEN_FORMAT1="Postal: 郵件 |c00FFFFFF%d|r/|c00FFFFFF%d|r 是C.O.D郵件,忽略。"
|
||||
POSTAL_OPEN_FORMAT2="Postal: 郵件 |c00FFFFFF%d|r/|c00FFFFFF%d|r 沒有附帶金錢或物品,忽略。"
|
||||
POSTAL_OPEN_FORMAT3="Postal: 正在打開郵件 |c00FFFFFF%d|r/|c00FFFFFF%d|r: \"|c00FFFFFF%s|r\" 來自 |c00FFFFFF%s|r。"
|
||||
end
|
||||
@@ -0,0 +1,34 @@
|
||||
--[[ $Id: localization.zhcn.lua 13144 2006-10-06 01:35:52Z hshh $ ]]--
|
||||
if GetLocale() == "zhCN" then
|
||||
POSTAL_HELP = "将你要发送的物品放入下面的格子,每样物品将自动通过分开的邮件发送出去.邮件标题将使用填写的主题加上物品描述.总的邮资显示在右上角.你也可以通过按住ALT键点击你的背包中的物品添加到邮件里.";
|
||||
|
||||
POSTAL_SEND = "发送批量邮件";
|
||||
POSTAL_SENDBUTTON = "发送";
|
||||
POSTAL_CANCELBUTTON = "取消";
|
||||
|
||||
POSTAL_SENDINFO = "你真的确定要发送这个批量邮件么? 总的邮资是:";
|
||||
POSTAL_SENDINFO2 = "你将要发送:";
|
||||
POSTAL_ITEMS = "个物品";
|
||||
POSTAL_ABORT = "终止发送";
|
||||
|
||||
POSTAL_ITEMNUM = "这是批量发送邮件的第%d个物品, 共%d个.";
|
||||
POSTAL_SENDING = "正在发送邮件 |c00FFFFFF%d|r/|c00FFFFFF%d|r...";
|
||||
POSTAL_DONESENDING = "已发送 |c00FFFFFF%d|r 封邮件!";
|
||||
POSTAL_ABORTED = "已终止. |c00FFFFFF%d|r/|c00FFFFFF%d|r 封邮件已发送.";
|
||||
POSTAL_ERROR = "POSTAL 出错. 造成这个原因有可能是网络或服务器延迟, 或者你发送的物品是不能被邮件传递的, 请尝试使用正常途径发送邮件.";
|
||||
|
||||
POSTAL_INBOX_OPENSELECTED = "打开已选";
|
||||
POSTAL_INBOX_OPENALL = "打开所有";
|
||||
POSTAL_INBOX_OPENALLTITLE = "确定打开所有?";
|
||||
POSTAL_INBOX_OPENALLCONFIRMATION = "你确定要打开所有邮件么?";
|
||||
POSTAL_INBOX_DISPLAYPROCESSMESSAGES = "显示处理信息";
|
||||
|
||||
POSTAL_MASS_MAIL="批量邮件";
|
||||
POSTAL_FORWARD="转发";
|
||||
|
||||
POSTAL_NOSUBJECT="<无标题>"
|
||||
POSTAL_UNKNOWNSENDER="<未知发信者>"
|
||||
POSTAL_OPEN_FORMAT1="Postal: 邮件 |c00FFFFFF%d|r/|c00FFFFFF%d|r 是付费邮件, 忽略."
|
||||
POSTAL_OPEN_FORMAT2="Postal: 邮件 |c00FFFFFF%d|r/|c00FFFFFF%d|r 没有附带金钱或物品, 忽略."
|
||||
POSTAL_OPEN_FORMAT3="Postal: 正在打开邮件 |c00FFFFFF%d|r/|c00FFFFFF%d|r: \"|c00FFFFFF%s|r\" 来自 |c00FFFFFF%s|r."
|
||||
end
|
||||
Reference in New Issue
Block a user