Initial commit

This commit is contained in:
Richard Steininger 2023-10-18 20:34:32 +02:00
commit 37d072dcc4
140 changed files with 14763 additions and 0 deletions

13
Bagnon/Bagnon.toc Normal file
View file

@ -0,0 +1,13 @@
## Interface: 20400
## Title: Bagnon
## Author: Tuller
## Notes: Single window displays for your inventory, bank, and keys
## SavedVariables: BagnonGlobalSettings
## SavedVariablesPerCharacter: BagnonFrameSettings
## Version: 2.13.3
## OptionalDeps: Ace3, Bagnon_Forever, Bagnon_Armory, LibItemSearch
embeds.xml
localization.xml
main.lua
utility.xml
components.xml

11
Bagnon/Bindings.xml Normal file
View file

@ -0,0 +1,11 @@
<Bindings>
<Binding name="BAGNON_TOGGLE" description="BINDING_NAME_BAGNON_TOGGLE" header="BAGNON">
Bagnon:ToggleFrame('inventory')
</Binding>
<Binding name="BANKNON_TOGGLE" description="BINDING_NAME_BANKNON_TOGGLE">
Bagnon:ToggleFrame('bank')
</Binding>
<Binding name="BAGNON_KEYS_TOGGLE" description="BINDING_NAME_BAGNON_KEYS_TOGGLE">
Bagnon:ToggleFrame('keys')
</Binding>
</Bindings>

20
Bagnon/components.xml Normal file
View file

@ -0,0 +1,20 @@
<Ui xmlns="http://www.blizzard.com/wow/ui/">
<Script file="components\bag.lua"/>
<Script file="components\bagFrame.lua"/>
<Script file="components\bagToggle.lua"/>
<Script file="components\brokerDisplay.lua"/>
<Script file="components\frame.lua"/>
<Script file="components\frameSettings.lua"/>
<Script file="components\item.lua"/>
<Script file="components\itemFrame.lua"/>
<Script file="components\moneyFrame.lua"/>
<Script file="components\optionsToggle.lua"/>
<Script file="components\playerSelector.lua"/>
<Script file="components\savedSettings.lua"/>
<Script file="components\searchFrame.lua"/>
<Script file="components\sortButton.lua"/>
<Script file="components\searchToggle.lua"/>
<Script file="components\settings.lua"/>
<Script file="components\titleFrame.lua"/>
<Script file="components\savedFrameSettings.lua"/>
</Ui>

516
Bagnon/components/bag.lua Normal file
View file

@ -0,0 +1,516 @@
--[[
bag.lua
A bag button object for Bagnon
--]]
local Bagnon = LibStub('AceAddon-3.0'):GetAddon('Bagnon')
local L = LibStub('AceLocale-3.0'):GetLocale('Bagnon')
local Bag = Bagnon.Classy:New('CheckButton')
Bagnon.Bag = Bag
--constants
local SIZE = 32
local NORMAL_TEXTURE_SIZE = 64 * (SIZE/36)
--[[ Constructor ]]--
function Bag:New(slotID, frameID, parent)
local bag = Bag:CreateBag(slotID, parent)
bag:SetFrameID(frameID)
bag:SetScript('OnEnter', bag.OnEnter)
bag:SetScript('OnLeave', bag.OnLeave)
bag:SetScript('OnClick', bag.OnClick)
bag:SetScript('OnDragStart', bag.OnDrag)
bag:SetScript('OnReceiveDrag', bag.OnClick)
bag:SetScript('OnEvent', bag.OnEvent)
bag:SetScript('OnShow', bag.OnShow)
bag:SetScript('OnHide', bag.OnHide)
return bag
end
function Bag:CreateBag(slotID, parent)
local bag = self:Bind(CreateFrame('CheckButton', 'BagnonBag' .. self:GetNextBagSlotID(), parent))
bag:SetWidth(SIZE)
bag:SetHeight(SIZE)
bag:SetID(slotID)
local name = bag:GetName()
local icon = bag:CreateTexture(name .. 'IconTexture', 'BORDER')
icon:SetAllPoints(bag)
local count = bag:CreateFontString(name .. 'Count', 'OVERLAY')
count:SetFontObject('NumberFontNormalSmall')
count:SetJustifyH('RIGHT')
count:SetPoint('BOTTOMRIGHT', -2, 2)
local nt = bag:CreateTexture(name .. 'NormalTexture')
nt:SetTexture([[Interface\Buttons\UI-Quickslot2]])
nt:SetWidth(NORMAL_TEXTURE_SIZE)
nt:SetHeight(NORMAL_TEXTURE_SIZE)
nt:SetPoint('CENTER', 0, -1)
bag:SetNormalTexture(nt)
local pt = bag:CreateTexture()
pt:SetTexture([[Interface\Buttons\UI-Quickslot-Depress]])
pt:SetAllPoints(bag)
bag:SetPushedTexture(pt)
local ht = bag:CreateTexture()
ht:SetTexture([[Interface\Buttons\ButtonHilight-Square]])
ht:SetAllPoints(bag)
bag:SetHighlightTexture(ht)
local ct = bag:CreateTexture()
ct:SetTexture([[Interface\Buttons\CheckButtonHilight]])
ct:SetAllPoints(bag)
ct:SetBlendMode('ADD')
bag:SetCheckedTexture(ct)
if bag:IsBackpack() or bag:IsBank() then
SetItemButtonTexture(bag, [[Interface\Buttons\Button-Backpack-Up]])
SetItemButtonTextureVertexColor(bag, 1, 1, 1)
elseif bag:IsKeyRing() then
SetItemButtonTexture(bag, [[Interface\ContainerFrame\KeyRing-Bag-Icon]])
SetItemButtonTextureVertexColor(bag, 1, 1, 1)
_G[bag:GetName() .. 'IconTexture']:SetTexCoord(0, 0.9, 0.1, 1)
end
bag:RegisterForClicks('anyUp')
bag:RegisterForDrag('LeftButton')
return bag
end
do
local id = 0
function Bag:GetNextBagSlotID()
local nextID = id + 1
id = nextID
return nextID
end
end
--[[ Events ]]--
function Bag:OnEvent(event, ...)
local action = self[event]
if action then
action(self, event, ...)
end
end
function Bag:UpdateEvents()
self:UnregisterAllMessages()
self:UnregisterAllEvents()
self:UnregisterAllItemSlotEvents()
if self:IsVisible() then
self:RegisterMessage('BAG_SLOT_SHOW')
self:RegisterMessage('BAG_SLOT_HIDE')
if self:IsBagSlot() then
self:RegisterMessage('PLAYER_UPDATE')
if not self:IsCached() then
self:RegisterEvent('ITEM_LOCK_CHANGED')
self:RegisterEvent('CURSOR_UPDATE')
self:RegisterEvent('BAG_UPDATE')
self:RegisterEvent('PLAYERBANKSLOTS_UPDATED')
self:RegisterEvent('PLAYERBANKBAGSLOTS_UPDATED')
end
end
if self:IsBankBagSlot() then
self:RegisterItemSlotEvent('BANK_OPENED')
self:RegisterItemSlotEvent('BANK_CLOSED')
end
end
end
--event registration
function Bag:RegisterItemSlotEvent(...)
Bagnon.BagEvents:Listen(self, ...)
end
function Bag:UnregisterAllItemSlotEvents(...)
Bagnon.BagEvents:IgnoreAll(self, ...)
end
--[[ Messages ]]--
function Bag:ITEM_LOCK_CHANGED(event, inventorySlot)
if self:GetInventorySlot() == inventorySlot then
self:UpdateLock()
end
end
function Bag:CURSOR_UPDATE()
self:UpdateCursor()
end
function Bag:BAG_UPDATE(event, bag)
self:UpdateLock()
self:UpdateSlotInfo()
end
function Bag:PLAYERBANKSLOTS_UPDATED(event)
self:UpdateLock()
self:UpdateSlotInfo()
end
function Bag:PLAYERBANKBAGSLOTS_UPDATED(event)
self:UpdateLock()
self:UpdateSlotInfo()
end
function Bag:BANK_OPENED(msg)
self:UpdateLock()
self:UpdateSlotInfo()
end
function Bag:BANK_CLOSED(msg)
self:UpdateLock()
self:UpdateSlotInfo()
end
function Bag:BAG_SLOT_SHOW(msg, frameID, slotID)
if frameID == self:GetFrameID() and slotID == self:GetID() then
self:UpdateShown()
end
end
function Bag:BAG_SLOT_HIDE(msg, frameID, slotID)
if frameID == self:GetFrameID() and slotID == self:GetID() then
self:UpdateShown()
end
end
function Bag:PLAYER_UPDATE(msg, frameID, player)
if frameID == self:GetFrameID() then
self:Update()
end
end
--[[ Frame Events ]]--
function Bag:OnShow()
self:UpdateEverything()
end
function Bag:OnHide()
self:UpdateEvents()
end
function Bag:OnClick()
if self:IsPurchasable() and not self:IsCached() then
self:PurchaseSlot()
elseif CursorHasItem() and not self:IsCached() then
if self:IsBackpack() then
PutItemInBackpack()
elseif self:IsKeyRing() then
PutKeyInKeyRing()
else
PutItemInBag(self:GetInventorySlot())
end
elseif self:CanToggleSlot() then
self:ToggleSlot()
end
self:UpdateShown()
end
function Bag:OnDrag()
if self:IsBagSlot() and not self:IsCached() then
PlaySound('BAGMENUBUTTONPRESS')
PickupBagFromSlot(self:GetInventorySlot())
end
end
function Bag:OnEnter()
if self:GetRight() > (GetScreenWidth() / 2) then
GameTooltip:SetOwner(self, 'ANCHOR_LEFT')
else
GameTooltip:SetOwner(self, 'ANCHOR_RIGHT')
end
self:UpdateTooltip()
self:SetSearch()
end
function Bag:OnLeave()
if GameTooltip:IsOwned(self) then
GameTooltip:Hide()
end
self:ClearSearch()
end
--[[ Tooltip Methods ]]--
function Bag:UpdateTooltip()
GameTooltip:ClearLines()
if self:IsBackpack() then
GameTooltip:SetText(BACKPACK_TOOLTIP, 1, 1, 1)
elseif self:IsBank() then
GameTooltip:SetText(L.TipBank, 1, 1, 1)
elseif self:IsKeyRing() then
GameTooltip:SetText(KEYRING, 1, 1, 1)
elseif self:IsCached() then
self:UpdateCachedBagTooltip()
else
self:UpdateBagTooltip()
end
if self:CanToggleSlot() then
GameTooltip:AddLine(self:IsSlotShown() and L.TipHideBag or L.TipShowBag)
end
GameTooltip:Show()
end
function Bag:UpdateCachedBagTooltip()
local link = (self:GetItemInfo())
if link then
GameTooltip:SetHyperlink(link)
elseif self:IsPurchasable() then
GameTooltip:SetText(BANK_BAG_PURCHASE, 1, 1, 1)
elseif self:IsBankBagSlot() then
GameTooltip:SetText(BANK_BAG, 1, 1, 1)
else
GameTooltip:SetText(EQUIP_CONTAINER, 1, 1, 1)
end
end
function Bag:UpdateBagTooltip()
if not GameTooltip:SetInventoryItem('player', self:GetInventorySlot()) then
if self:IsPurchasable() then
GameTooltip:SetText(BANK_BAG_PURCHASE, 1, 1, 1)
GameTooltip:AddLine(L.TipPurchaseBag)
SetTooltipMoney(GameTooltip, GetBankSlotCost(GetNumBankSlots()))
else
GameTooltip:SetText(EQUIP_CONTAINER, 1, 1, 1)
end
end
end
--[[ Display Updating ]]--
function Bag:UpdateEverything()
self:UpdateEvents()
self:Update()
end
function Bag:Update()
if not self:IsVisible() then return end
self:UpdateLock()
self:UpdateSlotInfo()
self:UpdateCursor()
self:UpdateShown()
end
function Bag:UpdateLock()
if not self:IsBagSlot() then return end
SetItemButtonDesaturated(self, self:IsLocked())
end
function Bag:UpdateCursor()
if not self:IsBagSlot() then return end
if CursorCanGoInSlot(self:GetInventorySlot()) then
self:LockHighlight()
else
self:UnlockHighlight()
end
end
function Bag:UpdateSlotInfo()
if not self:IsBagSlot() then return end
local link, count, texture = self:GetItemInfo()
if link then
self.hasItem = link
SetItemButtonTexture(self, texture or GetItemIcon(link))
SetItemButtonTextureVertexColor(self, 1, 1, 1)
else
self.hasItem = nil
SetItemButtonTexture(self, [[Interface\PaperDoll\UI-PaperDoll-Slot-Bag]])
--color red if the bag can be purchased
if self:IsPurchasable() then
SetItemButtonTextureVertexColor(self, 1, 0.1, 0.1)
else
SetItemButtonTextureVertexColor(self, 1, 1, 1)
end
end
self:SetCount(count)
end
function Bag:SetCount(count)
local text = _G[self:GetName() .. 'Count']
local count = count or 0
if count > 1 then
if count > 999 then
text:SetFormattedText('%.1fk', count/1000)
else
text:SetText(count)
end
text:Show()
else
text:Hide()
end
end
--[[ Bag Slot Actions ]]--
--show the purchase slot dialog
function Bag:PurchaseSlot()
if not StaticPopupDialogs['CONFIRM_BUY_BANK_SLOT_BAGNON'] then
StaticPopupDialogs['CONFIRM_BUY_BANK_SLOT_BAGNON'] = {
text = CONFIRM_BUY_BANK_SLOT,
button1 = YES,
button2 = NO,
OnAccept = function()
PurchaseSlot()
end,
OnShow = function(self)
MoneyFrame_Update(this:GetName() .. 'MoneyFrame', GetBankSlotCost(GetNumBankSlots()))
end,
hasMoneyFrame = 1,
timeout = 0,
hideOnEscape = 1,
}
end
-- PlaySound('igMainMenuOption')
StaticPopup_Show('CONFIRM_BUY_BANK_SLOT_BAGNON')
end
--item viewing
function Bag:ToggleSlot()
self:GetSettings():ToggleBagSlot(self:GetID())
end
function Bag:UpdateShown()
self:SetChecked(self:IsSlotShown())
end
function Bag:IsSlotShown()
return self:CanToggleSlot() and self:GetSettings():IsBagSlotShown(self:GetID())
end
function Bag:CanToggleSlot()
return self:IsBank() or self:IsBackpack() or self:IsKeyRing() or (self:IsBagSlot() and self.hasItem)
end
--searching
function Bag:SetSearch()
self:GetSettings():SetBagSearch(self:GetID())
end
function Bag:ClearSearch()
if self:GetSearch() == self:GetID() then
self:GetSettings():SetBagSearch(false)
end
end
function Bag:GetSearch()
return self:GetSettings():GetBagSearch()
end
--[[ Accessor Functions ]]--
--returns true if the bag is loaded from offline data, and false otehrwise
function Bag:IsCached()
return Bagnon.BagSlotInfo:IsCached(self:GetPlayer(), self:GetID())
end
--returns true if the given bag represents the backpack container
function Bag:IsBackpack()
return Bagnon.BagSlotInfo:IsBackpack(self:GetID())
end
--returns true if the given bag represetns the main bank container
function Bag:IsBank()
return Bagnon.BagSlotInfo:IsBank(self:GetID())
end
function Bag:IsKeyRing()
return Bagnon.BagSlotInfo:IsKeyRing(self:GetID())
end
--returns true if the given bag slot is an inventory bag slot
function Bag:IsInventoryBagSlot()
return Bagnon.BagSlotInfo:IsBackpackBag(self:GetID())
end
--returns true if the given bag slot is a purchasable bank bag slot
function Bag:IsBankBagSlot()
return Bagnon.BagSlotInfo:IsBankBag(self:GetID())
end
--returns true if the given bagSlot is one the player can place a bag in, and false otherwise
function Bag:IsBagSlot()
return self:IsInventoryBagSlot() or self:IsBankBagSlot()
end
--returns true if the bag is a purchasable bank slot, and false otherwise
function Bag:IsPurchasable()
return Bagnon.BagSlotInfo:IsPurchasable(self:GetPlayer(), self:GetID())
end
--returns the inventory slot id representation of the given bag
function Bag:GetInventorySlot()
return Bagnon.BagSlotInfo:ToInventorySlot(self:GetID())
end
function Bag:GetItemInfo()
local link, count, texture = Bagnon.BagSlotInfo:GetItemInfo(self:GetPlayer(), self:GetID())
return link, count, texture
end
function Bag:IsLocked()
return Bagnon.BagSlotInfo:IsLocked(self:GetPlayer(), self:GetID())
end
--returns the currently selected player for this frame
function Bag:GetPlayer()
return self:GetSettings():GetPlayerFilter()
end
--returns the bagnon frame we're attached to
function Bag:SetFrameID(frameID)
if self:GetFrameID() ~= frameID then
self.frameID = frameID
self:UpdateEverything()
end
end
function Bag:GetFrameID()
return self.frameID
end
--return the settings object associated with this frame
function Bag:GetSettings()
return Bagnon.FrameSettings:Get(self:GetFrameID())
end

View file

@ -0,0 +1,150 @@
--[[
bagFrame.lua
A container object for bags
--]]
local Bagnon = LibStub('AceAddon-3.0'):GetAddon('Bagnon')
local L = LibStub('AceLocale-3.0'):GetLocale('Bagnon')
local BagFrame = Bagnon.Classy:New('Frame')
Bagnon.BagFrame = BagFrame
--[[ Constructor ]]--
function BagFrame:New(frameID, parent)
local f = self:Bind(CreateFrame('Frame', nil, parent))
f:Hide()
f:SetScript('OnShow', f.OnShow)
f:SetScript('OnHide', f.OnHide)
f:SetFrameID(frameID)
f:CreateBagSlots()
f:UpdateEvents()
return f
end
function BagFrame:CreateBagSlots()
local bags = {}
for i, slotID in self:GetBagSlots() do
bags[i] = Bagnon.Bag:New(slotID, self:GetFrameID(), self)
end
self.bags = bags
end
--[[ Messages ]]--
function BagFrame:BAG_FRAME_SHOW(msg, frameID)
if frameID == self:GetFrameID() then
self:UpdateShown()
end
end
function BagFrame:BAG_FRAME_HIDE(msg, frameID)
if frameID == self:GetFrameID() then
self:UpdateShown()
end
end
--[[ Frame Events ]]--
function BagFrame:OnShow()
self:Layout()
self:SendMessage('BAG_FRAME_UPDATE_SHOWN', self:GetFrameID())
end
function BagFrame:OnHide()
self:SendMessage('BAG_FRAME_UPDATE_SHOWN', self:GetFrameID())
end
--[[ Update Methods ]]--
function BagFrame:UpdateShown()
if self:IsBagFrameShown() then
if not self:IsShown() then
UIFrameFadeIn(self, 0.1)
end
else
self:Hide()
end
end
function BagFrame:UpdateEvents()
self:UnregisterAllMessages()
self:RegisterMessage('BAG_FRAME_SHOW')
self:RegisterMessage('BAG_FRAME_HIDE')
end
function BagFrame:Layout()
if not self:IsVisible() then return end
local width = 0
local height = 0
local spacing = self:GetSpacing()
local padding = self:GetPadding()
width = self.bags[1]:GetWidth() * #self.bags + spacing * (#self.bags - 1) + padding * 2
height = self.bags[1]:GetHeight() + padding * 2
local prev
for i, bag in self:GetBags() do
if prev then
bag:SetPoint('LEFT', prev, 'RIGHT', spacing, 0)
else
bag:SetPoint('LEFT', padding, 0)
end
bag:Show()
prev = bag
end
self:SetWidth(width)
self:SetHeight(height)
end
--[[ Properties ]]--
function BagFrame:SetFrameID(frameID)
if self:GetFrameID() ~= frameID then
self.frameID = frameID
self:UpdateShown()
end
end
function BagFrame:GetFrameID()
return self.frameID
end
function BagFrame:GetBags()
return ipairs(self.bags)
end
--[[ Frame Settings ]]--
function BagFrame:GetSettings()
return Bagnon.FrameSettings:Get(self:GetFrameID())
end
function BagFrame:IsBagFrameShown()
return self:GetSettings():IsBagFrameShown()
end
function BagFrame:GetSpacing()
return 4
end
function BagFrame:GetPadding()
return 0
end
function BagFrame:GetBagSlots()
return self:GetSettings():GetBagSlots()
end

View file

@ -0,0 +1,153 @@
--[[
bagToggle.lua
A bag toggle widget
--]]
local Bagnon = LibStub('AceAddon-3.0'):GetAddon('Bagnon')
local L = LibStub('AceLocale-3.0'):GetLocale('Bagnon')
local BagToggle = Bagnon.Classy:New('CheckButton')
Bagnon.BagToggle = BagToggle
local SIZE = 20
local NORMAL_TEXTURE_SIZE = 64 * (SIZE/36)
--[[ Constructor ]]--
function BagToggle:New(frameID, parent)
local b = self:Bind(CreateFrame('CheckButton', nil, parent))
b:SetWidth(SIZE)
b:SetHeight(SIZE)
b:RegisterForClicks('anyUp')
local nt = b:CreateTexture()
nt:SetTexture([[Interface\Buttons\UI-Quickslot2]])
nt:SetWidth(NORMAL_TEXTURE_SIZE)
nt:SetHeight(NORMAL_TEXTURE_SIZE)
nt:SetPoint('CENTER', 0, -1)
b:SetNormalTexture(nt)
local pt = b:CreateTexture()
pt:SetTexture([[Interface\Buttons\UI-Quickslot-Depress]])
pt:SetAllPoints(b)
b:SetPushedTexture(pt)
local ht = b:CreateTexture()
ht:SetTexture([[Interface\Buttons\ButtonHilight-Square]])
ht:SetAllPoints(b)
b:SetHighlightTexture(ht)
local ct = b:CreateTexture()
ct:SetTexture([[Interface\Buttons\CheckButtonHilight]])
ct:SetAllPoints(b)
ct:SetBlendMode('ADD')
b:SetCheckedTexture(ct)
local icon = b:CreateTexture()
icon:SetAllPoints(b)
icon:SetTexture([[Interface\Buttons\Button-Backpack-Up]])
b:SetScript('OnClick', b.OnClick)
b:SetScript('OnEnter', b.OnEnter)
b:SetScript('OnLeave', b.OnLeave)
b:SetScript('OnShow', b.OnShow)
b:SetScript('OnHide', b.OnHide)
b:SetFrameID(frameID)
return b
end
--[[ Messages ]]--
function BagToggle:FRAME_BAGS_SHOW(msg, frameID)
if frameID == self:GetFrameID() then
self:Update()
end
end
function BagToggle:FRAME_BAGS_HIDE(msg, frameID)
if frameID == self:GetFrameID() then
self:Update()
end
end
--[[ Frame Events ]]--
function BagToggle:OnClick()
self:GetSettings():ToggleBagFrame()
end
function BagToggle:OnEnter()
if self:GetRight() > (GetScreenWidth() / 2) then
GameTooltip:SetOwner(self, 'ANCHOR_LEFT')
else
GameTooltip:SetOwner(self, 'ANCHOR_RIGHT')
end
self:UpdateTooltip()
end
function BagToggle:OnLeave()
GameTooltip:Hide()
end
function BagToggle:OnShow()
self:UpdateEvents()
self:Update()
end
function BagToggle:OnHide()
self:UpdateEvents()
self:Update()
end
--[[ Update Methods ]]--
function BagToggle:Update()
self:SetChecked(self:IsBagFrameShown())
end
function BagToggle:UpdateEvents()
if self:IsVisible() then
self:RegisterMessage('FRAME_BAGS_SHOW')
self:RegisterMessage('FRAME_BAGS_HIDE')
end
end
function BagToggle:UpdateTooltip()
if not GameTooltip:IsOwned(self) then return end
if self:IsBagFrameShown() then
GameTooltip:SetText(L.TipHideBags)
else
GameTooltip:SetText(L.TipShowBags)
end
end
--[[ Properties ]]--
function BagToggle:SetFrameID(frameID)
if self:GetFrameID() ~= frameID then
self.frameID = frameID
self:Update()
end
end
function BagToggle:GetFrameID()
return self.frameID
end
--[[ Frame Settings ]]--
function BagToggle:GetSettings()
return Bagnon.FrameSettings:Get(self:GetFrameID())
end
function BagToggle:IsBagFrameShown()
return self:GetSettings():IsBagFrameShown()
end

View file

@ -0,0 +1,380 @@
--[[
brokerDisplay.lua
A databroker display object
--]]
local Bagnon = LibStub('AceAddon-3.0'):GetAddon('Bagnon')
local BrokerDisplay = Bagnon.Classy:New('Button')
BrokerDisplay:Hide()
Bagnon.BrokerDisplay = BrokerDisplay
local ICON_SIZE = 18
--[[ Constructor ]]--
function BrokerDisplay:New(id, frameID, parent)
local obj = self:Bind(CreateFrame('Button', nil, parent))
obj:RegisterForClicks('anyUp')
obj:SetID(id)
obj.left = obj:CreateLeftButton()
obj.left:SetPoint('LEFT')
obj.right = obj:CreateRightButton()
obj.right:SetPoint('RIGHT')
obj.icon = obj:AddIcon()
obj.icon:SetPoint('LEFT', obj.left, 'RIGHT')
obj.text = obj:AddText()
obj:SetScript('OnShow', obj.OnShow)
obj:SetScript('OnHide', obj.OnHide)
obj:SetScript('OnEnter', obj.OnEnter)
obj:SetScript('OnLeave', obj.OnLeave)
obj:SetScript('OnClick', obj.OnClick)
obj:SetScript('OnMouseWheel', obj.OnMouseWheel)
obj:SetFrameID(frameID)
obj:SetHeight(13)
obj:EnableMouseWheel(true)
obj:UpdateInsets()
return obj
end
function BrokerDisplay:AddIcon()
local texture = self:CreateTexture(nil, 'OVERLAY')
texture:SetWidth(ICON_SIZE)
texture:SetHeight(ICON_SIZE)
return texture
end
function BrokerDisplay:AddText()
local text = self:CreateFontString()
text:SetFontObject('GameFontNormal')
text:SetJustifyH('LEFT')
return text
end
--[[
Broker Selection Buttons
--]]
function BrokerDisplay:CreateLeftButton()
local b = CreateFrame('Button', nil, self)
b:SetTextFontObject('GameFontNormal')
b:SetHighlightFontObject('GameFontHighlight')
b:SetText('<')
b:SetWidth(b:GetTextWidth() + 4)
b:SetHeight(b:GetTextHeight())
b:SetScript('OnClick', function(self) self:GetParent():SetPreviousObject() end)
b:SetToplevel(true)
return b
end
function BrokerDisplay:CreateRightButton()
local b = CreateFrame('Button', nil, self)
b:SetWidth(ICON_SIZE)
b:SetHeight(ICON_SIZE)
b:SetTextFontObject('GameFontNormal')
b:SetHighlightFontObject('GameFontHighlight')
b:SetText('>')
b:SetWidth(b:GetTextWidth() + 2)
b:SetHeight(b:GetTextHeight())
b:SetScript('OnClick', function(self) self:GetParent():SetNextObject() end)
b:SetToplevel(true)
return b
end
--[[ Messages ]]--
function BrokerDisplay:LibDataBroker_DataObjectCreated(msg, name, dataobj)
if self:GetObjectName() == name then
self:UpdateDisplay()
end
end
function BrokerDisplay:LibDataBroker_AttributeChanged(msg, name, attr, value, dataobj)
if self:GetObjectName() == name then
if attr == 'icon' then
self:UpdateIcon()
elseif attr == 'text' then
self:UpdateText()
end
end
end
function BrokerDisplay:DATABROKER_OBJECT_UPDATE(msg, frameID, objectName)
if self:GetFrameID() == frameID then
self:UpdateDisplay()
if GameTooltip:IsOwned(self) then
self:OnEnter()
end
end
end
--[[ Frame Events ]]--
function BrokerDisplay:OnEnter()
local dbo = self:GetObject()
if not dbo then return end
if dbo.OnEnter then
dbo.OnEnter(self)
elseif dbo.OnTooltipShow then
GameTooltip:SetOwner(self, 'ANCHOR_TOPRIGHT')
GameTooltip:ClearLines()
dbo.OnTooltipShow(GameTooltip)
GameTooltip:Show()
else
GameTooltip:SetOwner(self, 'ANCHOR_TOPRIGHT')
GameTooltip:ClearLines()
GameTooltip:SetText(self:GetObjectName())
GameTooltip:Show()
end
end
function BrokerDisplay:OnLeave()
local dbo = self:GetObject()
if not dbo then return end
if dbo.OnLeave then
dbo.OnLeave(self)
else
if GameTooltip:IsOwned(self) then
GameTooltip:Hide()
end
end
end
function BrokerDisplay:OnClick(...)
local dbo = self:GetObject()
if dbo and dbo.OnClick then
dbo.OnClick(self, ...)
end
end
function BrokerDisplay:OnShow()
self:UpdateEverything()
end
function BrokerDisplay:OnHide()
self:UpdateEvents()
end
function BrokerDisplay:OnMouseWheel(direction)
if direction > 0 then
self:SetNextObject()
else
self:SetPreviousObject()
end
end
--[[ Update Methods ]]--
function BrokerDisplay:UpdateEverything()
self:UpdateEvents()
self:UpdateDisplay()
end
function BrokerDisplay:UpdateEvents()
local LDB = LibStub:GetLibrary('LibDataBroker-1.1', true)
if LDB then
LDB.UnregisterAllCallbacks(self)
if self:IsVisible() then
LDB.RegisterCallback(self, 'LibDataBroker_DataObjectCreated')
LDB.RegisterCallback(self, 'LibDataBroker_AttributeChanged')
end
end
self:UnregisterAllMessages()
if self:IsVisible() then
self:RegisterMessage('DATABROKER_OBJECT_UPDATE')
end
end
function BrokerDisplay:UpdateDisplay()
self:UpdateIcon()
self:UpdateText()
end
function BrokerDisplay:UpdateText()
local obj = self:GetObject()
local text
if obj then
text = obj.text or ''
else
text = 'Select Databroker Plugin'
end
self.text:SetText(text)
self:Layout()
end
function BrokerDisplay:UpdateIcon()
local obj = self:GetObject()
local icon = obj and obj.icon
if icon then
self.icon:SetTexture(icon)
self.icon:Show()
else
self.icon:Hide()
end
self:Layout()
end
function BrokerDisplay:Layout()
if self.icon:IsShown() then
self.text:SetPoint('LEFT', self.icon, 'RIGHT', 2, 0)
self.text:SetPoint('RIGHT', self.right, 'LEFT', -2, 0)
else
self.text:SetPoint('LEFT', self.left, 'RIGHT', 2, 0)
self.text:SetPoint('RIGHT', self.right, 'LEFT', -2, 0)
end
self:UpdateInsets()
end
--calculate the clickable portion of the frame
function BrokerDisplay:UpdateInsets()
local realWidth = self.left:GetWidth()
if self.text:IsShown() then
realWidth = realWidth + (self.text:GetStringWidth() or 0)
end
if self.icon:IsShown() then
realWidth = realWidth + (self.icon:GetWidth() or 0)
end
self:SetHitRectInsets(0, self:GetWidth() - realWidth, 0, 0)
end
--[[ Display Object Updating ]]--
function BrokerDisplay:SetObject(objectName)
self:GetSettings():SetBrokerDisplayObject(objectName)
end
function BrokerDisplay:GetObject()
local LDB = LibStub:GetLibrary('LibDataBroker-1.1', true)
if LDB then
return LDB:GetDataObjectByName(self:GetObjectName())
end
return nil
end
function BrokerDisplay:GetObjectName()
return self:GetSettings():GetBrokerDisplayObject()
end
function BrokerDisplay:SetNextObject()
local LDB = LibStub:GetLibrary('LibDataBroker-1.1', true)
if not LDB then return end
local currObjName = self:GetObjectName()
local prevObjName = nil
for i, nextObjName in self:GetAvailableObjects() do
if currObjName == prevObjName then
self:SetObject(nextObjName)
return
end
prevObjName = nextObjName
end
for i, nextObjName in self:GetAvailableObjects() do
if currObjName == prevObjName then
self:SetObject(nextObjName)
return
end
prevObjName = nextObjName
end
self:SetObject(prevObjName)
end
function BrokerDisplay:SetPreviousObject()
local LDB = LibStub:GetLibrary('LibDataBroker-1.1', true)
if not LDB then return end
local currObjName = self:GetObjectName()
local prevObjName = nil
for i, nextObjName in self:GetAvailableObjects() do
if prevObjName and (currObjName == nextObjName) then
self:SetObject(prevObjName)
return
end
prevObjName = nextObjName
end
for i, nextObjName in self:GetAvailableObjects() do
if prevObjName and (currObjName == nextObjName) then
self:SetObject(prevObjName)
return
end
prevObjName = nextObjName
end
self:SetObject(prevObjName)
end
do
local objects = {}
function BrokerDisplay:GetAvailableObjects()
if next(objects) ~= nil then
for k, v in pairs(objects) do
objects[k] = nil
end
end
local LDB = LibStub:GetLibrary('LibDataBroker-1.1', true)
if LDB then
for name, obj in LDB:DataObjectIterator() do
table.insert(objects, name)
end
end
table.sort(objects)
return ipairs(objects)
end
end
--[[ Properties ]]--
function BrokerDisplay:SetFrameID(frameID)
if self:GetFrameID() ~= frameID then
self.frameID = frameID
self:UpdateEverything()
end
end
function BrokerDisplay:GetFrameID()
return self.frameID
end
function BrokerDisplay:GetSettings()
return Bagnon.FrameSettings:Get(self:GetFrameID())
end

916
Bagnon/components/frame.lua Normal file
View file

@ -0,0 +1,916 @@
--[[
frame.lua
A Bagnon frame widget
--]]
local Bagnon = LibStub('AceAddon-3.0'):GetAddon('Bagnon')
local L = LibStub('AceLocale-3.0'):GetLocale('Bagnon')
local Frame = Bagnon.Classy:New('Frame')
Frame:Hide()
Bagnon.Frame = Frame
--[[
Constructor
--]]
function Frame:New(frameID)
local f = self:Bind(CreateFrame('Frame', 'BagnonFrame' .. frameID, UIParent))
f:Hide()
f:SetClampedToScreen(true)
f:SetMovable(true)
f:EnableMouse(true)
f:SetBackdrop{
bgFile = [[Interface\ChatFrame\ChatFrameBackground]],
edgeFile = [[Interface\Tooltips\UI-Tooltip-Border]],
edgeSize = 16,
tile = true, tileSize = 16,
insets = {left = 4, right = 4, top = 4, bottom = 4}
}
f:SetScript('OnShow', f.OnShow)
f:SetScript('OnHide', f.OnHide)
f.frameID = frameID
f:Rescale()
f:UpdateEverything()
table.insert(UISpecialFrames, f:GetName())
return f
end
--[[
Frame Messages
--]]
function Frame:UpdateEvents()
self:UnregisterAllMessages()
self:RegisterMessage('FRAME_SHOW')
if self:IsVisible() then
self:RegisterMessage('FRAME_HIDE')
self:RegisterMessage('FRAME_LAYER_UPDATE')
self:RegisterMessage('FRAME_MOVE_START')
self:RegisterMessage('FRAME_MOVE_STOP')
self:RegisterMessage('FRAME_POSITION_UPDATE')
self:RegisterMessage('FRAME_OPACITY_UPDATE')
self:RegisterMessage('FRAME_COLOR_UPDATE')
self:RegisterMessage('FRAME_BORDER_COLOR_UPDATE')
self:RegisterMessage('FRAME_SCALE_UPDATE')
self:RegisterMessage('BAG_FRAME_UPDATE_SHOWN')
self:RegisterMessage('BAG_FRAME_UPDATE_LAYOUT')
self:RegisterMessage('ITEM_FRAME_SIZE_CHANGE')
self:RegisterMessage('BAG_FRAME_ENABLE_UPDATE')
self:RegisterMessage('MONEY_FRAME_ENABLE_UPDATE')
self:RegisterMessage('DATABROKER_FRAME_ENABLE_UPDATE')
self:RegisterMessage('SEARCH_TOGGLE_ENABLE_UPDATE')
self:RegisterMessage('SORT_BUTTON_ENABLE_UPDATE')
self:RegisterMessage('OPTIONS_TOGGLE_ENABLE_UPDATE')
end
end
function Frame:FRAME_SHOW(msg, frameID)
if self:GetFrameID() == frameID then
self:Show()
end
end
function Frame:FRAME_HIDE(msg, frameID)
if self:GetFrameID() == frameID then
self:Hide()
end
end
function Frame:FRAME_MOVE_START(msg, frameID)
if self:GetFrameID() == frameID then
self:StartMoving()
end
end
function Frame:FRAME_MOVE_STOP(msg, frameID)
if self:GetFrameID() == frameID then
self:StopMovingOrSizing()
self:SavePosition()
end
end
function Frame:FRAME_POSITION_UPDATE(msg, frameID)
if self:GetFrameID() == frameID then
self:UpdatePosition()
end
end
function Frame:FRAME_SCALE_UPDATE(msg, frameID, scale)
if self:GetFrameID() == frameID then
self:UpdateScale()
end
end
function Frame:FRAME_OPACITY_UPDATE(msg, frameID, opacity)
if self:GetFrameID() == frameID then
self:UpdateOpacity()
end
end
function Frame:FRAME_COLOR_UPDATE(msg, frameID, r, g, b, a)
if self:GetFrameID() == frameID then
self:UpdateBackdrop()
end
end
function Frame:FRAME_BORDER_COLOR_UPDATE(msg, frameID, r, g, b, a)
if self:GetFrameID() == frameID then
self:UpdateBackdropBorder()
end
end
function Frame:BAG_FRAME_UPDATE_SHOWN(msg, frameID)
if self:GetFrameID() == frameID then
self:Layout()
end
end
function Frame:BAG_FRAME_UPDATE_LAYOUT(msg, frameID)
if self:GetFrameID() == frameID then
self:Layout()
end
end
function Frame:ITEM_FRAME_SIZE_CHANGE(msg, frameID)
if self:GetFrameID() == frameID then
self:Layout()
end
end
function Frame:FRAME_LAYER_UPDATE(msg, frameID, layer)
if self:GetFrameID() == frameID then
self:SetFrameLayer(layer)
end
end
function Frame:BAG_FRAME_ENABLE_UPDATE(msg, frameID, enable)
if self:GetFrameID() == frameID then
self:Layout()
end
end
function Frame:MONEY_FRAME_ENABLE_UPDATE(msg, frameID, enable)
if self:GetFrameID() == frameID then
self:Layout()
end
end
function Frame:DATABROKER_FRAME_ENABLE_UPDATE(msg, frameID, enable)
if self:GetFrameID() == frameID then
self:Layout()
end
end
function Frame:SEARCH_TOGGLE_ENABLE_UPDATE(msg, frameID, enable)
if self:GetFrameID() == frameID then
self:Layout()
end
end
function Frame:SORT_BUTTON_ENABLE_UPDATE(msg, frameID, enable)
if self:GetFrameID() == frameID then
self:Layout()
end
end
function Frame:OPTIONS_TOGGLE_ENABLE_UPDATE(msg, frameID, enable)
if self:GetFrameID() == frameID then
self:Layout()
end
end
--[[
Frame Events
--]]
function Frame:OnShow()
PlaySound('igBackPackOpen')
self:UpdateEvents()
self:UpdateLook()
end
function Frame:OnHide()
PlaySound('igBackPackClose')
if self:IsBankFrame() then
self:CloseBankFrame()
end
self:UpdateEvents()
--fix issue where a frame is hidden, but not via bagnon controlled methods (ie, close on escape)
if self:IsFrameShown() then
self:HideFrame()
end
end
function Frame:CloseBankFrame()
if Bagnon.PlayerInfo:AtBank() then
CloseBankFrame()
end
end
function Frame:IsBankFrame()
return self:GetFrameID() == 'bank'
end
--[[
Update Methods
--]]
function Frame:UpdateEverything()
self:UpdateEvents()
self:UpdateLook()
end
function Frame:UpdateLook()
if not self:IsVisible() then
return
end
self:UpdatePosition()
self:UpdateScale()
self:UpdateOpacity()
self:UpdateBackdrop()
self:UpdateBackdropBorder()
self:UpdateShown()
self:UpdateFrameLayer()
self:Layout()
end
--[[
Frame Scale
--]]
--alter the frame's cale, but maintain the same relative position of the frame
function Frame:UpdateScale()
local oldScale = self:GetScale()
local newScale = self:GetFrameScale()
if oldScale ~= newScale then
local point, x, y = self:GetFramePosition()
local ratio = newScale / oldScale
self:SetScale(newScale)
self:GetSettings():SetPosition(point, x/ratio, y/ratio)
end
end
function Frame:GetFrameScale()
return self:GetSettings():GetScale()
end
--rescale frame without altering position, needed when loading settins
function Frame:Rescale()
self:SetScale(self:GetFrameScale())
end
--[[
Frame Opacity
--]]
function Frame:UpdateOpacity()
self:SetAlpha(self:GetFrameOpacity())
end
function Frame:GetFrameOpacity()
return self:GetSettings():GetOpacity()
end
--[[
Frame Position
--]]
--position
function Frame:SavePosition()
local point, x, y = self:GetRelativePosition()
if point then
self:GetSettings():SetPosition(point, x, y)
end
end
--get a frame's position relative to its parent
function Frame:GetRelativePosition()
local parent = self:GetParent()
local w, h = parent:GetWidth(), parent:GetHeight()
local x, y = self:GetCenter()
local s = self:GetScale()
if not (x and y) then return end
w = w/s h = h/s
local dx, dy
local hHalf = (x > w/2) and 'RIGHT' or 'LEFT'
if hHalf == 'RIGHT' then
dx = self:GetRight() - w
else
dx = self:GetLeft()
end
local vHalf = (y > h/2) and 'TOP' or 'BOTTOM'
if vHalf == 'TOP' then
dy = self:GetTop() - h
else
dy = self:GetBottom()
end
return vHalf..hHalf, dx, dy
end
function Frame:UpdatePosition()
self:ClearAllPoints()
self:SetPoint(self:GetFramePosition())
end
function Frame:GetFramePosition()
return self:GetSettings():GetPosition()
end
--[[
Frame Color
--]]
--background
function Frame:UpdateBackdrop()
self:SetBackdropColor(self:GetFrameBackdropColor())
end
function Frame:GetFrameBackdropColor()
return self:GetSettings():GetColor()
end
--border
function Frame:UpdateBackdropBorder()
self:SetBackdropBorderColor(self:GetFrameBackdropBorderColor())
end
function Frame:GetFrameBackdropBorderColor()
return self:GetSettings():GetBorderColor()
end
--[[
Frame Visibility
--]]
function Frame:UpdateShown()
if self:IsFrameShown() then
self:Show()
else
self:Hide()
end
end
function Frame:IsFrameShown()
return self:GetSettings():IsShown()
end
function Frame:HideFrame()
self:GetSettings():Hide()
end
--[[
Frame Layer/Strata
--]]
function Frame:UpdateFrameLayer()
self:SetFrameLayer(self:GetFrameLayer())
end
function Frame:SetFrameLayer(layer)
local strata, topLevel = nil, false
if layer == 'TOPLEVEL' then
strata = 'HIGH'
topLevel = true
elseif layer == 'MEDIUMLOW' then
strata = 'LOW'
topLevel = true
elseif layer == 'MEDIUMHIGH' then
strata = 'MEDIUM'
topLevel = true
else
strata = layer
topLevel = false
end
self:SetFrameStrata(strata)
self:SetToplevel(topLevel)
end
function Frame:GetFrameLayer()
return self:GetSettings():GetLayer()
end
--[[
Layout Methods
--]]
--place components & update size
function Frame:Layout()
if not self:IsVisible() then
return
end
local padW = 16
local padH = 16
local width, height = 0, 0
--place menu butons, this determines our base width
local w, h = self:PlaceMenuButtons()
width = width + w
local w, h = self:PlaceCloseButton()
width = width + w
local w, h = self:PlaceOptionsToggle()
width = width + w + 24 --append spacing between close button and this
height = height + 20
local w, h = self:PlaceTitleFrame()
width = width + w
local w, h = self:PlaceSearchFrame()
--place the middle frames
local w, h = self:PlaceBagFrame()
width = math.max(w, width)
height = height + h
local w, h = self:PlaceItemFrame()
width = math.max(w, width)
height = height + h
--place the bottom menu frames
local w, h = self:PlaceMoneyFrame()
width = math.max(w, width)
height = height + h
local w, h = self:PlaceBrokerDisplayFrame()
if not self:HasMoneyFrame() then
height = height + h
end
--adjust size
self:SetWidth(math.max(width, 156) + padW)
self:SetHeight(height + padH)
self:SavePosition()
end
--[[ Menu Button Placement ]]--
function Frame:PlaceMenuButtons()
local menuButtons = self.menuButtons or {}
self.menuButtons = menuButtons
--hide the old buttons
for i, button in pairs(menuButtons) do
button:Hide()
menuButtons[i] = nil
end
if self:HasPlayerSelector() then
local selector = self:GetPlayerSelector() or self:CreatePlayerSelector()
table.insert(menuButtons, selector)
end
if self:HasBagFrame() and self:HasBagToggle() then
local toggle = self:GetBagToggle() or self:CreateBagToggle()
table.insert(menuButtons, toggle)
end
if self:HasSortButton() then
table.insert(menuButtons, self.sortButton or self:CreateSortButton())
end
if self:HasSearchToggle() then
local toggle = self:GetSearchToggle() or self:CreateSearchToggle()
table.insert(menuButtons, toggle)
end
for i, button in ipairs(menuButtons) do
button:ClearAllPoints()
if i == 1 then
button:SetPoint('TOPLEFT', self, 'TOPLEFT', 8, -8)
else
button:SetPoint('TOPLEFT', menuButtons[i-1], 'TOPRIGHT', 4, 0)
end
button:Show()
end
local numButtons = #menuButtons
if numButtons > 0 then
return (menuButtons[1]:GetWidth() + 4 * numButtons - 4), menuButtons[1]:GetHeight()
end
return 0, 0
end
function Frame:GetMenuButtons()
if not self.menuButtons then
self:PlaceMenuButtons()
end
return self.menuButtons
end
--[[
Frame Components
--]]
--[[ close button ]]--
local function CloseButton_OnClick(self)
self:GetParent():GetSettings():Hide(true) --force hide the frame
end
function Frame:CreateCloseButton()
local b = CreateFrame('Button', self:GetName() .. 'CloseButton', self, 'UIPanelCloseButton')
b:SetScript('OnClick', CloseButton_OnClick)
self.closeButton = b
return b
end
function Frame:GetCloseButton()
return self.closeButton
end
function Frame:PlaceCloseButton()
local b = self:GetCloseButton() or self:CreateCloseButton()
b:ClearAllPoints()
b:SetPoint('TOPRIGHT', -2, -2)
b:Show()
return 20, 20 --make the same size as the other menu buttons
end
--[[ search frame ]]--
function Frame:CreateSearchFrame()
local f = Bagnon.SearchFrame:New(self:GetFrameID(), self)
self.searchFrame = f
return f
end
function Frame:GetSearchFrame()
return self.searchFrame
end
function Frame:PlaceSearchFrame()
local menuButtons = self:GetMenuButtons()
local frame = self:GetSearchFrame() or self:CreateSearchFrame()
frame:ClearAllPoints()
if #menuButtons > 0 then
frame:SetPoint('LEFT', menuButtons[#menuButtons], 'RIGHT', 2, 0)
else
frame:SetPoint('TOPLEFT', self, 'TOPLEFT', 8, -8)
end
if self:HasOptionsToggle() then
frame:SetPoint('RIGHT', self:GetOptionsToggle(), 'LEFT', -2, 0)
else
frame:SetPoint('RIGHT', self:GetCloseButton(), 'LEFT', -2, 0)
end
frame:SetHeight(28)
return frame:GetWidth(), frame:GetHeight()
end
--[[ search toggle ]]--
function Frame:CreateSearchToggle()
local toggle = Bagnon.SearchToggle:New(self:GetFrameID(), self)
self.searchToggle = toggle
return toggle
end
function Frame:GetSearchToggle()
return self.searchToggle
end
function Frame:HasSearchToggle()
return self:GetSettings():HasSearchToggle()
end
--[[ bag frame ]]--
function Frame:CreateBagFrame()
local f = Bagnon.BagFrame:New(self:GetFrameID(), self)
self.bagFrame = f
return f
end
function Frame:GetBagFrame()
return self.bagFrame
end
function Frame:HasBagFrame()
return self:GetSettings():HasBagFrame()
end
function Frame:IsBagFrameShown()
return self:GetSettings():IsBagFrameShown()
end
function Frame:PlaceBagFrame()
if self:HasBagFrame() then
--the bag frame has to be created here to respond to events
local frame = self:GetBagFrame() or self:CreateBagFrame()
if self:IsBagFrameShown() then
frame:ClearAllPoints()
local menuButtons = self:GetMenuButtons()
if #menuButtons > 0 then
frame:SetPoint('TOPLEFT', menuButtons[1], 'BOTTOMLEFT', 0, -4)
else
frame:SetPoint('TOPLEFT', self:GetTitleFrame(), 'BOTTOMLEFT', 0, -4)
end
frame:Show()
return frame:GetWidth(), frame:GetHeight() + 4
else
frame:Hide()
return 0, 0
end
end
local frame = self:GetBagFrame()
if frame then
frame:Hide()
end
return 0, 0
end
--[[ sort button ]]--
function Frame:CreateSortButton()
self.sortButton = Bagnon.SortButton:New(self:GetFrameID(), self)
return self.sortButton
end
function Frame:GetSortButton()
return self.sortButton
end
function Frame:HasSortButton()
return self:GetSettings():HasSortButton()
end
--[[ bag toggle ]]--
function Frame:CreateBagToggle()
local toggle = Bagnon.BagToggle:New(self:GetFrameID(), self)
self.bagToggle = toggle
return toggle
end
function Frame:GetBagToggle()
return self.bagToggle
end
--this exists purely so that it can be overridden by guildBank
function Frame:HasBagToggle()
return true
end
--[[ title frame ]]--
function Frame:CreateTitleFrame()
local f = Bagnon.TitleFrame:New(self:GetFrameID(), self)
self.titleFrame = f
return f
end
function Frame:GetTitleFrame()
return self.titleFrame
end
function Frame:PlaceTitleFrame()
local menuButtons = self:GetMenuButtons()
local frame = self:GetTitleFrame() or self:CreateTitleFrame()
local w, h = 0, 0
frame:ClearAllPoints()
if #menuButtons > 0 then
frame:SetPoint('LEFT', menuButtons[#menuButtons], 'RIGHT', 4, 0)
w = frame:GetTextWidth() / 2 + 4
h = 20
else
frame:SetPoint('TOPLEFT', self, 'TOPLEFT', 8, -8)
w = frame:GetTextWidth() + 8
h = 20
end
if self:HasOptionsToggle() then
frame:SetPoint('RIGHT', self:GetOptionsToggle(), 'LEFT', -4, 0)
else
frame:SetPoint('RIGHT', self:GetCloseButton(), 'LEFT', -4, 0)
end
frame:SetHeight(20)
return w, h
end
--[[ item frame ]]--
function Frame:CreateItemFrame()
local f = Bagnon.ItemFrame:New(self:GetFrameID(), self)
self.itemFrame = f
return f
end
function Frame:GetItemFrame()
return self.itemFrame
end
function Frame:PlaceItemFrame()
local frame = self:GetItemFrame() or self:CreateItemFrame()
frame:ClearAllPoints()
if self:HasBagFrame() and self:IsBagFrameShown() then
frame:SetPoint('TOPLEFT', self:GetBagFrame(), 'BOTTOMLEFT', 0, -4)
else
local menuButtons = self:GetMenuButtons()
if #menuButtons > 0 then
frame:SetPoint('TOPLEFT', menuButtons[1], 'BOTTOMLEFT', 0, -4)
else
frame:SetPoint('TOPLEFT', self:GetTitleFrame(), 'BOTTOMLEFT', 0, -4)
end
end
frame:Show()
return frame:GetWidth() - 2, frame:GetHeight()
end
--[[ player selector ]]--
function Frame:GetPlayerSelector()
return self.playerSelector
end
function Frame:CreatePlayerSelector()
local f = Bagnon.PlayerSelector:New(self:GetFrameID(), self)
self.playerSelector = f
return f
end
function Frame:HasPlayerSelector()
return BagnonDB and true or false
end
--[[ money frame ]]--
function Frame:GetMoneyFrame()
return self.moneyFrame
end
function Frame:CreateMoneyFrame()
local f = Bagnon.MoneyFrame:New(self:GetFrameID(), self)
self.moneyFrame = f
return f
end
function Frame:HasMoneyFrame()
return self:GetSettings():HasMoneyFrame()
end
function Frame:PlaceMoneyFrame()
if self:HasMoneyFrame() then
local frame = self:GetMoneyFrame() or self:CreateMoneyFrame()
frame:ClearAllPoints()
frame:SetPoint('BOTTOMRIGHT', self, 'BOTTOMRIGHT', 0, 10)
frame:Show()
return frame:GetWidth(), 24
end
local frame = self:GetMoneyFrame()
if frame then
frame:Hide()
end
return 0, 0
end
--[[ libdatabroker display ]]--
function Frame:GetBrokerDisplay()
return self.brokerDisplay
end
function Frame:CreateBrokerDisplay()
local f = Bagnon.BrokerDisplay:New(1, self:GetFrameID(), self)
self.brokerDisplay = f
return f
end
function Frame:HasBrokerDisplay()
return self:GetSettings():HasDBOFrame()
end
function Frame:PlaceBrokerDisplayFrame()
if self:HasBrokerDisplay() then
local frame = self:GetBrokerDisplay() or self:CreateBrokerDisplay()
frame:ClearAllPoints()
frame:SetPoint('BOTTOMLEFT', self, 'BOTTOMLEFT', 8, 10)
if self:HasMoneyFrame() then
frame:SetPoint('BOTTOMRIGHT', self, 'BOTTOMRIGHT', -(self:GetMoneyFrame():GetWidth() + 4), 10)
else
frame:SetPoint('BOTTOMRIGHT', self, 'BOTTOMRIGHT', -8, 10)
end
frame:Show()
return frame:GetWidth(), 24
end
local frame = self:GetBrokerDisplay()
if frame then
frame:Hide()
end
return 0, 0
end
--[[ options toggle ]]--
function Frame:GetOptionsToggle()
return self.optionsToggle
end
function Frame:CreateOptionsToggle()
local f = Bagnon.OptionsToggle:New(self:GetFrameID(), self)
self.optionsToggle = f
return f
end
function Frame:PlaceOptionsToggle()
if self:HasOptionsToggle() then
local toggle = self:GetOptionsToggle() or self:CreateOptionsToggle()
toggle:ClearAllPoints()
toggle:SetPoint('TOPRIGHT', self, 'TOPRIGHT', -32, -8)
toggle:Show()
return toggle:GetWidth(), toggle:GetHeight()
end
local toggle = self:GetOptionsToggle()
if toggle then
toggle:Hide()
end
return 0, 0
end
function Frame:HasOptionsToggle()
local name, title, notes, enabled = GetAddOnInfo('Bagnon_Config')
return enabled and self:GetSettings():HasOptionsToggle()
end
--[[
Frame Settings Access
--]]
function Frame:GetFrameID()
return self.frameID
end
function Frame:GetSettings()
return Bagnon.FrameSettings:Get(self:GetFrameID())
end
--[[ Shared ]]--
function Frame:SortItems()
Bagnon.Sorting:Start(self:GetItemFrame())
end

View file

@ -0,0 +1,525 @@
--[[
frameSettings.lua
A bagnon frame settings object
--]]
local FrameSettings = {}
local Bagnon = LibStub('AceAddon-3.0'):GetAddon('Bagnon')
Bagnon.FrameSettings = FrameSettings
--[[---------------------------------------------------------------------------
Constructorish
--]]---------------------------------------------------------------------------
FrameSettings.mt = {
__index = FrameSettings
}
FrameSettings.objects = setmetatable({}, {__index = function(tbl, id)
local obj = setmetatable({frameID = id, shown = 0}, FrameSettings.mt)
tbl[id] = obj
return obj
end})
function FrameSettings:Get(id)
return self.objects[id]
end
--[[---------------------------------------------------------------------------
Accessor Methods
--]]---------------------------------------------------------------------------
function FrameSettings:GetID()
return self.frameID
end
function FrameSettings:GetDB()
local db = self.db or Bagnon.SavedFrameSettings:Get(self:GetID())
self.db = db
return db
end
--[[---------------------------------------------------------------------------
Message Passing
--]]---------------------------------------------------------------------------
function FrameSettings:SendMessage(msg, ...)
Bagnon.Callbacks:SendMessage(msg, self:GetID(), ...)
end
--[[---------------------------------------------------------------------------
Update Methods
--]]---------------------------------------------------------------------------
--[[ Frame Visibility ]]--
--the logic here is a little wacky, since we deal with auto open/close events
--if a frame was manually opened, then it should only be closable manually
function FrameSettings:Show()
local wasShown = self:IsShown()
self.shown = (self.shown or 0) + 1
if not wasShown then
self:SendMessage('FRAME_SHOW')
end
end
function FrameSettings:Hide(forceHide)
self.shown = (self.shown or 1) - 1
if forceHide or self.shown <= 0 then
self.shown = 0
--reset player filter on hide
self:SetPlayerFilter(UnitName('player'))
self:SendMessage('FRAME_HIDE')
end
end
function FrameSettings:Toggle()
if self:IsShown() then
self:Hide(true)
else
self:Show()
end
end
function FrameSettings:IsShown()
return (self.shown or 0) > 0
end
--[[ Frame Position ]]--
--position
function FrameSettings:SetPosition(point, x, y)
local oPoint, oX, oY = self:GetPosition()
if not(point == oPoint and x == oX and y == oY) then
self:GetDB():SetPosition(point, x, y)
self:SendMessage('FRAME_POSITION_UPDATE', self:GetPosition())
end
end
function FrameSettings:GetPosition()
local point, x, y = self:GetDB():GetPosition()
return point, x, y
end
function FrameSettings:IsMovable()
return not Bagnon.Settings:AreFramePositionsLocked()
end
--[[ Frame Layout ]]--
--scale
function FrameSettings:SetScale(scale)
if self:GetScale() ~= scale then
self:GetDB():SetScale(scale)
self:SendMessage('FRAME_SCALE_UPDATE', self:GetScale())
end
end
function FrameSettings:GetScale()
return self:GetDB():GetScale()
end
--opacity
function FrameSettings:SetOpacity(opacity)
if self:GetOpacity() ~= opacity then
self:GetDB():SetOpacity(opacity)
self:SendMessage('FRAME_OPACITY_UPDATE', self:GetOpacity())
end
end
function FrameSettings:GetOpacity()
return self:GetDB():GetOpacity()
end
--frame color
function FrameSettings:SetColor(r, g, b, a)
local pR, pG, pB, pA = self:GetColor()
if not(pR == r and pG == g and pB == b and pA == a) then
self:GetDB():SetColor(r, g, b, a)
self:SendMessage('FRAME_COLOR_UPDATE', self:GetColor())
end
end
function FrameSettings:GetColor()
return self:GetDB():GetColor()
end
--border color
function FrameSettings:SetBorderColor(r, g, b, a)
local pR, pG, pB, pA = self:GetBorderColor()
if not(pR == r and pG == g and pB == b and pA == a) then
self:GetDB():SetBorderColor(r, g, b, a)
self:SendMessage('FRAME_BORDER_COLOR_UPDATE', self:GetBorderColor())
end
end
function FrameSettings:GetBorderColor()
return self:GetDB():GetBorderColor()
end
--frame layer
function FrameSettings:SetLayer(layer)
if self:GetLayer() ~= layer then
self:GetDB():SetLayer(layer)
self:SendMessage('FRAME_LAYER_UPDATE', self:GetLayer())
end
end
function FrameSettings:GetLayer()
return self:GetDB():GetLayer()
end
--returns a list of all possible frame layers
function FrameSettings:GetAvailableLayers()
if not FrameSettings.availableFrameLayers then
FrameSettings.availableFrameLayers = {'LOW', 'MEDIUMLOW', 'MEDIUM', 'MEDIUMHIGH', 'HIGH', 'TOPLEVEL'}
end
return FrameSettings.availableFrameLayers
end
--[[ Frame Components ]]--
--returns true if the frame has a bag frame, and false otherwise
function FrameSettings:SetHasBagFrame(enable)
local enable = enable and true or false --done to handle 1/nil cases
if self:HasBagFrame() ~= enable then
self:GetDB():SetHasBagFrame(enable)
self:SendMessage('BAG_FRAME_ENABLE_UPDATE', self:HasBagFrame())
end
end
function FrameSettings:HasBagFrame()
return self:GetDB():HasBagFrame()
end
--returns true if the frame has a money frame, and false otherwise
function FrameSettings:SetHasMoneyFrame(enable)
local enable = enable and true or false
if self:HasMoneyFrame() ~= enable then
self:GetDB():SetHasMoneyFrame(enable)
self:SendMessage('MONEY_FRAME_ENABLE_UPDATE', self:HasMoneyFrame())
end
end
function FrameSettings:HasMoneyFrame()
return self:GetDB():HasMoneyFrame()
end
--returns true if the frame has a databroker object frame, and false otherwise
function FrameSettings:SetHasDBOFrame(enable)
local enable = enable and true or false
if self:HasDBOFrame() ~= enable then
self:GetDB():SetHasDBOFrame(enable)
self:SendMessage('DATABROKER_FRAME_ENABLE_UPDATE', self:HasDBOFrame())
end
end
function FrameSettings:HasDBOFrame()
return self:GetDB():HasDBOFrame()
end
--returns true if the search frame TOGGLE is shown, and false otherwise
function FrameSettings:SetHasSearchToggle(enable)
local enable = enable and true or false
if self:HasSearchToggle() ~= enable then
self:GetDB():SetHasSearchToggle(enable)
self:SendMessage('SEARCH_TOGGLE_ENABLE_UPDATE', self:HasSearchToggle())
end
end
function FrameSettings:HasSearchToggle()
return self:GetDB():HasSearchToggle()
end
function FrameSettings:SetHasSortButton(enable)
local enable = enable and true or false
if self:HasSortButton() ~= enable then
self:GetDB():SetHasSortButton(enable)
self:SendMessage('SORT_BUTTON_ENABLE_UPDATE', self:HasSortButton())
end
end
function FrameSettings:HasSortButton()
return self:GetDB():HasSortButton()
end
--options toggle
function FrameSettings:SetHasOptionsToggle(enable)
local enable = enable and true or false
if self:HasOptionsToggle() ~= enable then
self:GetDB():SetHasOptionsToggle(enable)
self:SendMessage('OPTIONS_TOGGLE_ENABLE_UPDATE', self:HasOptionsToggle())
end
end
function FrameSettings:HasOptionsToggle()
return self:GetDB():HasOptionsToggle()
end
--[[ Broker Display Object ]]--
function FrameSettings:SetBrokerDisplayObject(objectName)
if self:GetBrokerDisplayObject() ~= objectName then
self:GetDB():SetBrokerDisplayObject(objectName)
self:SendMessage('DATABROKER_OBJECT_UPDATE', self:GetBrokerDisplayObject())
end
end
function FrameSettings:GetBrokerDisplayObject()
return self:GetDB():GetBrokerDisplayObject()
end
--[[ Bag Frame Visibility ]]--
function FrameSettings:ShowBagFrame()
if not self:IsBagFrameShown() then
self.showBagFrame = true
self:SendMessage('BAG_FRAME_SHOW')
end
end
function FrameSettings:HideBagFrame()
if self:IsBagFrameShown() then
self.showBagFrame = false
self:SendMessage('BAG_FRAME_HIDE')
end
end
function FrameSettings:ToggleBagFrame()
if self:IsBagFrameShown() then
self:HideBagFrame()
else
self:ShowBagFrame()
end
end
function FrameSettings:IsBagFrameShown()
return self.showBagFrame
end
--[[ Item Frame Layout ]]--
--spacing
function FrameSettings:SetItemFrameSpacing(spacing)
if self:GetItemFrameSpacing() ~= spacing then
self:GetDB():SetItemFrameSpacing(spacing)
self:SendMessage('ITEM_FRAME_SPACING_UPDATE', self:GetItemFrameSpacing())
end
end
function FrameSettings:GetItemFrameSpacing()
return self:GetDB():GetItemFrameSpacing()
end
--columns
function FrameSettings:SetItemFrameColumns(columns)
if self:GetItemFrameColumns() ~= columns then
self:GetDB():SetItemFrameColumns(columns)
self:SendMessage('ITEM_FRAME_COLUMNS_UPDATE', self:GetItemFrameColumns())
end
end
function FrameSettings:GetItemFrameColumns()
return self:GetDB():GetItemFrameColumns()
end
--bag break layout
function FrameSettings:SetBagBreak(enable)
local enable = enable and true or false
if self:IsBagBreakEnabled() ~= enable then
self:GetDB():SetBagBreak(enable)
self:SendMessage('ITEM_FRAME_BAG_BREAK_UPDATE', self:IsBagBreakEnabled())
end
end
function FrameSettings:IsBagBreakEnabled()
return self:GetDB():IsBagBreakEnabled()
end
--[[ Bag Slot Availability ]]--
--returns true if the slot is available to this frame, and false otherwise
function FrameSettings:HasBagSlot(slot)
for i, bagSlot in self:GetBagSlots() do
if bagSlot == slot then
return true
end
end
return false
end
--returns an iterator for all bag slots available to this frame
function FrameSettings:GetBagSlots()
return ipairs(self:GetDB():GetBags())
end
--[[ Bag Slot Visibility ]]--
function FrameSettings:ShowBagSlot(slotToShow)
if not self:IsBagSlotShown(slotToShow) then
self:GetDB():ShowBag(slotToShow)
self:SendMessage('BAG_SLOT_SHOW', slotToShow)
end
end
function FrameSettings:HideBagSlot(slotToHide)
if self:IsBagSlotShown(slotToHide) then
self:GetDB():HideBag(slotToHide)
self:SendMessage('BAG_SLOT_HIDE', slotToHide)
end
end
function FrameSettings:ToggleBagSlot(slot)
if self:IsBagSlotShown(slot) then
self:HideBagSlot(slot)
else
self:ShowBagSlot(slot)
end
end
function FrameSettings:IsBagSlotShown(slot)
for i, bagSlot in self:GetVisibleBagSlots() do
if bagSlot == slot then
return true
end
end
return false
end
function FrameSettings:IsBagSlotHidden(slot)
return not self:GetDB():IsBagShown(slot)
end
--[[ Bag Slot Iterators ]]--
--returns an iterator for all bag slots that are available to this frame and marked as visible
local function reverseVisibleSlotIterator(obj, i)
local bagSlots = obj:GetDB():GetBags()
local nextSlot = i - 1
for j = nextSlot, 1, -1 do
local slot = bagSlots[j]
if not obj:IsBagSlotHidden(slot) then
return j, slot
end
end
end
local function visibleSlotIterator(obj, i)
local bagSlots = obj:GetDB():GetBags()
local nextSlot = i + 1
for j = nextSlot, #bagSlots do
local slot = bagSlots[j]
if not obj:IsBagSlotHidden(slot) then
return j, slot
end
end
end
function FrameSettings:GetVisibleBagSlots()
if self:IsSlotOrderReversed() then
local bagSlots = self:GetDB():GetBags()
return reverseVisibleSlotIterator, self, #bagSlots + 1
end
return visibleSlotIterator, self, 0
end
function FrameSettings:SetReverseSlotOrder(enable)
local enable = enable and true or false
if self:IsSlotOrderReversed() ~= enable then
self:GetDB():SetReverseSlotOrder(enable)
self:SendMessage('SLOT_ORDER_UPDATE', self:IsSlotOrderReversed())
end
end
function FrameSettings:IsSlotOrderReversed()
return self:GetDB():IsSlotOrderReversed()
end
--[[ Text Filtering ]]--
function FrameSettings:EnableTextSearch()
if not self:IsTextSearchEnabled() then
self.enableTextSearch = true
self:SendMessage('TEXT_SEARCH_ENABLE')
end
end
function FrameSettings:DisableTextSearch()
if self:IsTextSearchEnabled() then
self.enableTextSearch = false
self:SendMessage('TEXT_SEARCH_DISABLE')
end
end
function FrameSettings:ToggleTextSearch()
if self:IsTextSearchEnabled() then
self:DisableTextSearch()
else
self:EnableTextSearch()
end
end
function FrameSettings:IsTextSearchEnabled()
return self.enableTextSearch
end
--[[ Bag Filtering ]]--
function FrameSettings:SetBagSearch(bagSlotID)
if self:GetBagSearch() ~= bagSlotID then
self.bagSearch = bagSlotID
self:SendMessage('BAG_SEARCH_UPDATE', self:GetBagSearch())
end
end
function FrameSettings:GetBagSearch()
return self.bagSearch or false
end
--[[ Player Filtering ]]--
function FrameSettings:SetPlayerFilter(player)
local currentFilter = self:GetPlayerFilter()
if currentFilter ~= player then
self.playerFilter = player
self:SendMessage('PLAYER_UPDATE', self:GetPlayerFilter())
end
end
function FrameSettings:GetPlayerFilter()
return self.playerFilter or UnitName('player')
end

706
Bagnon/components/item.lua Normal file
View file

@ -0,0 +1,706 @@
--[[
item.lua
An item slot button
--]]
local Bagnon = LibStub('AceAddon-3.0'):GetAddon('Bagnon')
local ItemSlot = Bagnon.Classy:New('Button')
ItemSlot:Hide()
Bagnon.ItemSlot = ItemSlot
local ItemSearch = LibStub('LibItemSearch-1.0')
local function hasBlizzQuestHighlight()
return GetContainerItemQuestInfo and true or false
end
--[[
The item widget
--]]
--[[ ItemSlot Constructor ]]--
function ItemSlot:New(bag, slot, frameID, parent)
local item = self:Restore() or self:Create()
item:SetParent(item:GetDummyBag(parent, bag))
item:SetID(slot)
item:SetFrameID(frameID)
if item:IsVisible() then
item:Update()
else
item:Show()
end
return item
end
--constructs a brand new item slot
function ItemSlot:Create()
local id = self:GetNextItemSlotID()
local item = self:Bind(self:GetBlizzardItemSlot(id) or self:ConstructNewItemSlot(id))
item:Hide()
--add a quality border texture
item.questBorder = _G[item:GetName() .. 'IconQuestTexture']
local border = item:CreateTexture(nil, 'OVERLAY')
border:SetWidth(67)
border:SetHeight(67)
border:SetPoint('CENTER', item)
border:SetTexture([[Interface\Buttons\UI-ActionButton-Border]])
border:SetBlendMode('ADD')
border:Hide()
item.border = border
--hack, make sure the cooldown model stays visible
item.cooldown = _G[item:GetName() .. 'Cooldown']
--get rid of any registered frame events, and use my own
item:SetScript('OnEvent', nil)
item:SetScript('OnEnter', item.OnEnter)
item:SetScript('OnLeave', item.OnLeave)
item:SetScript('OnShow', item.OnShow)
item:SetScript('OnHide', item.OnHide)
item:SetScript('PostClick', item.PostClick)
item.UpdateTooltip = nil
return item
end
--creates a new item slot for <id>
function ItemSlot:ConstructNewItemSlot(id)
return CreateFrame('Button', 'BagnonItemSlot' .. id, nil, 'ContainerFrameItemButtonTemplate')
end
--returns an available blizzard item slot for <id>
function ItemSlot:GetBlizzardItemSlot(id)
--only allow reuse of blizzard frames if all frames are enabled
if not self:CanReuseBlizzardBagSlots() then
return nil
end
local bag = math.ceil(id / MAX_CONTAINER_ITEMS)
local slot = (id-1) % MAX_CONTAINER_ITEMS + 1
local item = _G[format('ContainerFrame%dItem%d', bag, slot)]
if item then
item:SetID(0)
item:ClearAllPoints()
return item
end
end
function ItemSlot:CanReuseBlizzardBagSlots()
return Bagnon.Settings:AreAllFramesEnabled() and (not Bagnon.Settings:IsBlizzardBagPassThroughEnabled())
end
--returns the next available item slot
function ItemSlot:Restore()
local item = ItemSlot.unused and next(ItemSlot.unused)
if item then
ItemSlot.unused[item] = nil
return item
end
end
--gets the next unique item slot id
do
local id = 1
function ItemSlot:GetNextItemSlotID()
local nextID = id
id = id + 1
return nextID
end
end
--[[ ItemSlot Destructor ]]--
function ItemSlot:Free()
self:Hide()
self:SetParent(nil)
self:UnregisterAllEvents()
self:UnregisterAllMessages()
ItemSlot.unused = ItemSlot.unused or {}
ItemSlot.unused[self] = true
end
--[[ Events ]]--
function ItemSlot:ITEM_SLOT_UPDATE(msg, bag, slot)
self:Update()
end
function ItemSlot:ITEM_LOCK_CHANGED(event, bag, slot)
self:UpdateLocked()
end
function ItemSlot:ITEM_SLOT_UPDATE_COOLDOWN(msg, bag, slot)
self:UpdateCooldown()
end
function ItemSlot:TEXT_SEARCH_UPDATE(msg, frameID, search)
self:UpdateSearch()
end
function ItemSlot:BAG_SEARCH_UPDATE(msg, frameID, search)
if self:GetFrameID() == frameID then
self:UpdateBagSearch()
end
end
function ItemSlot:ITEM_HIGHLIGHT_QUALITY_UPDATE(msg, enable)
self:UpdateBorder()
end
function ItemSlot:ITEM_HIGHLIGHT_QUEST_UPDATE(msg, enable)
self:UpdateBorder()
end
function ItemSlot:ITEM_HIGHLIGHT_OPACITY_UPDATE(msg, opacity)
self:UpdateBorder()
end
function ItemSlot:SHOW_EMPTY_ITEM_SLOT_TEXTURE_UPDATE(msg, enable)
self:Update()
end
function ItemSlot:ITEM_SLOT_COLOR_ENABLED_UPDATE(msg, type, r, g, b)
self:Update()
end
function ItemSlot:ITEM_SLOT_COLOR_UPDATE(msg, type, r, g, b)
self:Update()
end
function ItemSlot:QUEST_ACCEPTED()
self:UpdateBorder()
end
function ItemSlot:UNIT_QUEST_LOG_CHANGED()
self:UpdateBorder()
end
function ItemSlot:HandleEvent(msg, ...)
local action = self[msg]
if action then
action(self, msg, ...)
end
end
--[[ Frame Events ]]--
function ItemSlot:OnShow()
self:Update()
end
function ItemSlot:OnHide()
self:HideStackSplitFrame()
end
function ItemSlot:OnDragStart()
if self:IsCached() and CursorHasItemSlot() then
ClearCursor()
end
end
function ItemSlot:OnModifiedClick(button)
local link = self:IsCached() and self:GetItem()
if link then
HandleModifiedItemClick(link)
end
end
function ItemSlot:OnEnter()
local dummySlot = self:GetDummyItemSlot()
if self:IsCached() then
dummySlot:SetParent(self)
dummySlot:SetAllPoints(self)
dummySlot:Show()
else
dummySlot:Hide()
if self:IsBank() then
if self:GetItem() then
self:AnchorTooltip()
GameTooltip:SetInventoryItem('player', BankButtonIDToInvSlotID(self:GetID()))
GameTooltip:Show()
CursorUpdate(self)
end
else
ContainerFrameItemButton_OnEnter(self)
end
end
end
function ItemSlot:OnLeave()
GameTooltip:Hide()
ResetCursor()
end
--[[ Update Methods ]]--
-- Update the texture, lock status, and other information about an item
function ItemSlot:Update()
if not self:IsVisible() then return end
local texture, count, locked, quality, readable, lootable, link = self:GetItemSlotInfo()
self:SetItem(link)
self:SetTexture(texture)
self:SetCount(count)
self:SetLocked(locked)
self:SetReadable(readable)
self:SetBorderQuality(quality)
self:UpdateCooldown()
self:UpdateSlotColor()
self:UpdateSearch()
self:UpdateBagSearch()
if GameTooltip:IsOwned(self) then
self:UpdateTooltip()
end
end
--item link
function ItemSlot:SetItem(itemLink)
self.hasItem = itemLink or nil
end
function ItemSlot:GetItem()
return self.hasItem
end
--item texture
function ItemSlot:SetTexture(texture)
SetItemButtonTexture(self, texture or self:GetEmptyItemTexture())
end
function ItemSlot:GetEmptyItemTexture()
if self:ShowingEmptyItemSlotTexture() then
return [[Interface\PaperDoll\UI-Backpack-EmptySlot]]
end
return nil
end
--item slot color
function ItemSlot:UpdateSlotColor()
if (not self:GetItem()) and self:ColoringBagSlots() then
if self:IsKeyRingSlot() then
local r, g, b = self:GetKeyringSlotColor()
SetItemButtonTextureVertexColor(self, r, g, b)
self:GetNormalTexture():SetVertexColor(r, g, b)
return
end
if self:IsAmmoBagSlot() then
local r, g, b = self:GetAmmoSlotColor()
SetItemButtonTextureVertexColor(self, r, g, b)
self:GetNormalTexture():SetVertexColor(r, g, b)
return
end
if self:IsTradeBagSlot() then
local r, g, b = self:GetTradeSlotColor()
SetItemButtonTextureVertexColor(self, r, g, b)
self:GetNormalTexture():SetVertexColor(r, g, b)
return
end
if self:IsShardBagSlot() then
local r, g, b = self:GetShardSlotColor()
SetItemButtonTextureVertexColor(self, r, g, b)
self:GetNormalTexture():SetVertexColor(r, g, b)
return
end
end
SetItemButtonTextureVertexColor(self, 1, 1, 1)
self:GetNormalTexture():SetVertexColor(1, 1, 1)
end
--item count
function ItemSlot:SetCount(count)
SetItemButtonCount(self, count)
end
--readable status
function ItemSlot:SetReadable(readable)
self.readable = readable
end
--locked status
function ItemSlot:SetLocked(locked)
SetItemButtonDesaturated(self, locked)
end
function ItemSlot:UpdateLocked()
self:SetLocked(self:IsLocked())
end
--returns true if the slot is locked, and false otherwise
function ItemSlot:IsLocked()
return Bagnon.ItemSlotInfo:IsLocked(self:GetPlayer(), self:GetBag(), self:GetID())
end
--colors the item border based on the quality of the item. hides it for common/poor items
if hasBlizzQuestHighlight() then
function ItemSlot:SetBorderQuality(quality)
local border = self.border
local qBorder = self.questBorder
if self:HighlightingQuestItems() then
local isQuestItem, isQuestStarter = self:IsQuestItem()
if isQuestItem then
qBorder:SetTexture(TEXTURE_ITEM_QUEST_BORDER)
qBorder:SetAlpha(self:GetHighlightAlpha())
qBorder:Show()
border:Hide()
return
end
if isQuestStarter then
qBorder:SetTexture(TEXTURE_ITEM_QUEST_BANG)
qBorder:SetAlpha(self:GetHighlightAlpha())
qBorder:Show()
border:Hide()
return
end
end
if self:HighlightingItemsByQuality() then
if self:GetItem() and quality and quality > 1 then
local r, g, b = GetItemQualityColor(quality)
border:SetVertexColor(r, g, b, self:GetHighlightAlpha())
border:Show()
qBorder:Hide()
return
end
end
qBorder:Hide()
border:Hide()
end
else
function ItemSlot:SetBorderQuality(quality)
local border = self.border
if self:HighlightingItemsByQuality() then
if self:GetItem() and quality and quality > 1 then
local r, g, b = GetItemQualityColor(quality)
border:SetVertexColor(r, g, b, self:GetHighlightAlpha())
border:Show()
return
end
end
if self:HighlightingQuestItems() then
if self:IsQuestItem() then
border:SetVertexColor(1, 1, 0, self:GetHighlightAlpha())
border:Show()
return
end
end
border:Hide()
end
end
function ItemSlot:UpdateBorder()
local texture, count, locked, quality = self:GetItemSlotInfo()
self:SetBorderQuality(quality)
end
--cooldown
function ItemSlot:UpdateCooldown()
if self:GetItem() and (not self:IsCached()) then
ContainerFrame_UpdateCooldown(self:GetBag(), self)
else
CooldownFrame_SetTimer(self.cooldown, 0, 0, 0)
SetItemButtonTextureVertexColor(self, 1, 1, 1)
end
end
--stack split frame
function ItemSlot:HideStackSplitFrame()
if self.hasStackSplit and self.hasStackSplit == 1 then
StackSplitFrame:Hide()
end
end
--tooltip methods
ItemSlot.UpdateTooltip = ItemSlot.OnEnter
function ItemSlot:AnchorTooltip()
if self:GetRight() >= (GetScreenWidth() / 2) then
GameTooltip:SetOwner(self, 'ANCHOR_LEFT')
else
GameTooltip:SetOwner(self, 'ANCHOR_RIGHT')
end
end
--search
function ItemSlot:UpdateSearch()
local shouldFade = false
local search = self:GetItemSearch()
if search and search ~= '' then
local itemLink = self:GetItem()
shouldFade = not(itemLink and ItemSearch:Find(itemLink, search))
end
if shouldFade then
self:SetAlpha(0.4)
SetItemButtonDesaturated(self, true)
self.border:Hide()
else
self:SetAlpha(1)
self:UpdateLocked()
self:UpdateBorder()
self:UpdateSlotColor()
end
end
function ItemSlot:GetItemSearch()
return Bagnon.Settings:GetTextSearch()
end
--bag search
function ItemSlot:UpdateBagSearch()
local search = self:GetBagSearch()
if self:GetBag() == search then
self:LockHighlight()
else
self:UnlockHighlight()
end
end
function ItemSlot:GetBagSearch()
return self:GetSettings():GetBagSearch()
end
--[[ Accessor Methods ]]--
function ItemSlot:SetFrameID(frameID)
if self:GetFrameID() ~= frameID then
self.frameID = frameID
self:Update()
end
end
function ItemSlot:GetFrameID()
return self.frameID
end
function ItemSlot:GetSettings()
return Bagnon.FrameSettings:Get(self:GetFrameID())
end
function ItemSlot:GetPlayer()
return self:GetSettings():GetPlayerFilter()
end
function ItemSlot:GetBag()
return self:GetParent() and self:GetParent():GetID() or 1
end
function ItemSlot:IsSlot(bag, slot)
return self:GetBag() == bag and self:GetID() == slot
end
function ItemSlot:IsCached()
return Bagnon.BagSlotInfo:IsCached(self:GetPlayer(), self:GetBag())
end
function ItemSlot:IsBank()
return Bagnon.BagSlotInfo:IsBank(self:GetBag())
end
function ItemSlot:IsBankSlot()
local bag = self:GetBag()
return Bagnon.BagSlotInfo:IsBank(bag) or Bagnon.BagSlotInfo:IsBankBag(bag)
end
function ItemSlot:AtBank()
return Bagnon.PlayerInfo:AtBank()
end
function ItemSlot:GetItemSlotInfo()
local texture, count, locked, quality, readable, lootable, link = Bagnon.ItemSlotInfo:GetItemInfo(self:GetPlayer(), self:GetBag(), self:GetID())
return texture, count, locked, quality, readable, lootable, link
end
--[[ Item Type Highlighting ]]--
function ItemSlot:HighlightingItemsByQuality()
return Bagnon.Settings:HighlightingItemsByQuality()
end
function ItemSlot:HighlightingQuestItems()
return Bagnon.Settings:HighlightingQuestItems()
end
function ItemSlot:GetHighlightAlpha()
return Bagnon.Settings:GetHighlightOpacity()
end
--returns true if the item is a quest item or not
--in 3.3, includes a second return to determine if the item is a quest starter for a quest the player lacks
local QUEST_ITEM_SEARCH = string.format('t:%s|%s', select(11, GetAuctionItemClasses()), 'quest')
if hasBlizzQuestHighlight() then
function ItemSlot:IsQuestItem()
local itemLink = self:GetItem()
if not itemLink then
return false, false
end
if self:IsCached() then
return ItemSearch:Find(itemLink, QUEST_ITEM_SEARCH), false
else
local isQuestItem, questID, isActive = GetContainerItemQuestInfo(self:GetBag(), self:GetID())
return isQuestItem, (questID and not isActive)
end
end
else
function ItemSlot:IsQuestItem()
local itemLink = self:GetItem()
if not itemLink then
return false
end
return ItemSearch:Find(itemLink, QUEST_ITEM_SEARCH)
end
end
--[[ Item Slot Coloring ]]--
function ItemSlot:IsAmmoBagSlot()
return Bagnon.BagSlotInfo:IsAmmoBag(self:GetPlayer(), self:GetBag())
end
function ItemSlot:GetAmmoSlotColor()
return Bagnon.Settings:GetItemSlotColor('ammo')
end
function ItemSlot:IsTradeBagSlot()
return Bagnon.BagSlotInfo:IsTradeBag(self:GetPlayer(), self:GetBag())
end
function ItemSlot:GetTradeSlotColor()
return Bagnon.Settings:GetItemSlotColor('trade')
end
function ItemSlot:IsShardBagSlot()
return Bagnon.BagSlotInfo:IsShardBag(self:GetPlayer(), self:GetBag())
end
function ItemSlot:GetShardSlotColor()
return Bagnon.Settings:GetItemSlotColor('shard')
end
function ItemSlot:IsKeyRingSlot()
return Bagnon.BagSlotInfo:IsKeyRing(self:GetBag())
end
function ItemSlot:GetKeyringSlotColor()
return Bagnon.Settings:GetItemSlotColor('keyring')
end
function ItemSlot:ColoringBagSlots()
return Bagnon.Settings:ColoringBagSlots()
end
--[[ Empty Slot Visibility ]]--
function ItemSlot:ShowingEmptyItemSlotTexture()
return Bagnon.Settings:ShowingEmptyItemSlotTextures()
end
--[[ Delicious Hacks ]]--
-- dummy slot - A hack, used to provide a tooltip for cached items without tainting other item code
function ItemSlot:GetDummyItemSlot()
ItemSlot.dummySlot = ItemSlot.dummySlot or ItemSlot:CreateDummyItemSlot()
return ItemSlot.dummySlot
end
function ItemSlot:CreateDummyItemSlot()
local slot = CreateFrame('Button')
slot:RegisterForClicks('anyUp')
slot:SetToplevel(true)
slot:Hide()
local function Slot_OnEnter(self)
local parent = self:GetParent()
parent:LockHighlight()
if parent:IsCached() and parent:GetItem() then
ItemSlot.AnchorTooltip(self)
GameTooltip:SetHyperlink(parent:GetItem())
GameTooltip:Show()
end
end
local function Slot_OnLeave(self)
GameTooltip:Hide()
self:Hide()
end
local function Slot_OnHide(self)
local parent = self:GetParent()
if parent then
parent:UnlockHighlight()
end
end
local function Slot_OnClick(self, button)
self:GetParent():OnModifiedClick(button)
end
slot.UpdateTooltip = Slot_OnEnter
slot:SetScript('OnClick', Slot_OnClick)
slot:SetScript('OnEnter', Slot_OnEnter)
slot:SetScript('OnLeave', Slot_OnLeave)
slot:SetScript('OnShow', Slot_OnEnter)
slot:SetScript('OnHide', Slot_OnHide)
return slot
end
--dummy bag, a hack to enforce the internal blizzard rule that item:GetParent():GetID() == bagID
function ItemSlot:GetDummyBag(parent, bag)
local dummyBags = parent.dummyBags
--metatable magic to create a new frame on demand
if not dummyBags then
dummyBags = setmetatable({}, {
__index = function(t, k)
local f = CreateFrame('Frame', nil, parent)
f:SetID(k)
t[k] = f
return f
end
})
parent.dummyBags = dummyBags
end
return dummyBags[bag]
end

View file

@ -0,0 +1,504 @@
--[[
itemFrame.lua
An item slot container
--]]
local Bagnon = LibStub('AceAddon-3.0'):GetAddon('Bagnon')
local ItemFrame = Bagnon.Classy:New('Frame')
ItemFrame:Hide()
Bagnon.ItemFrame = ItemFrame
local function hasBlizzQuestHighlight()
return GetContainerItemQuestInfo and true or false
end
--[[ Extreme Constants! ]]--
ItemFrame.ITEM_SIZE = 39
--[[ Constructor ]]--
local function throttledUpdater_OnUpdate(self, elapsed)
local p = self:GetParent()
if p:NeedsLayout() then
p:Layout()
end
self:Hide()
end
function ItemFrame:New(frameID, parent)
local f = self:Bind(CreateFrame('Frame', nil, parent))
f.itemSlots = {}
f.throttledUpdater = CreateFrame('Frame', nil, f)
f.throttledUpdater:SetScript('OnUpdate', throttledUpdater_OnUpdate)
f:SetFrameID(frameID)
f:SetScript('OnSizeChanged', f.OnSizeChanged)
f:SetScript('OnEvent', f.OnEvent)
f:SetScript('OnShow', f.OnShow)
f:SetScript('OnHide', f.OnHide)
return f
end
--[[ Messages ]]--
function ItemFrame:OnEvent(event, ...)
local action = self[event]
if action then
action(self, event, ...)
end
end
function ItemFrame:ITEM_SLOT_ADD(msg, bag, slot)
if self:IsBagShown(bag) and (not self:IsBagSlotCached(bag)) then
self:AddItemSlot(bag, slot)
end
end
function ItemFrame:ITEM_SLOT_REMOVE(msg, bag, slot)
if self:IsBagShown(bag) and (not self:IsBagSlotCached(bag)) then
self:RemoveItemSlot(bag, slot)
end
end
function ItemFrame:ITEM_LOCK_CHANGED(msg, bag, slot, ...)
if slot and self:IsBagShown(bag) and (not self:IsBagSlotCached(bag)) then
self:HandleSpecificItemEvent(msg, bag, slot, ...)
end
end
function ItemFrame:BANK_OPENED(msg)
self:UpdateEverything()
end
function ItemFrame:BANK_CLOSED(msg)
self:UpdateEverything()
end
function ItemFrame:PLAYER_UPDATE(msg, frameID, player)
if self:GetFrameID() == frameID then
self:UpdateEverything()
end
end
function ItemFrame:BAG_UPDATE_TYPE(msg, bag, type)
if self:IsBagShown(bag) and not self:IsBagSlotCached(bag) then
self:UpdateAllItemSlotsForBag(bag)
end
end
function ItemFrame:BAG_SLOT_SHOW(msg, frameID, bagSlot)
if self:GetFrameID() == frameID then
self:AddAllItemSlotsForBag(bagSlot)
end
end
function ItemFrame:BAG_SLOT_HIDE(msg, frameID, bagSlot)
if self:GetFrameID() == frameID then
self:RemoveAllItemSlotsForBag(bagSlot)
end
end
function ItemFrame:ITEM_FRAME_SPACING_UPDATE(msg, frameID, spacing)
if self:GetFrameID() == frameID then
self:RequestLayout()
end
end
function ItemFrame:ITEM_FRAME_COLUMNS_UPDATE(msg, frameID, columns)
if self:GetFrameID() == frameID then
self:RequestLayout()
end
end
function ItemFrame:SLOT_ORDER_UPDATE(msg, frameID, enable)
if self:GetFrameID() == frameID then
self:RequestLayout()
end
end
function ItemFrame:ITEM_FRAME_BAG_BREAK_UPDATE(msg, frameID, enable)
if self:GetFrameID() == frameID then
self:RequestLayout()
end
end
function ItemFrame:UNIT_QUEST_LOG_CHANGED(event, unit)
if unit == 'player' then
self:HandleGlobalItemEvent(event)
end
end
function ItemFrame:QUEST_ACCEPTED(event)
self:HandleGlobalItemEvent(event)
end
function ItemFrame:HandleGlobalItemEvent(msg, ...)
for i, item in self:GetAllItemSlots() do
item:HandleEvent(msg, ...)
end
end
function ItemFrame:HandleSpecificItemEvent(msg, bag, slot, ...)
if self:IsBagShown(bag) and (not self:IsBagSlotCached(bag)) then
local item = self:GetItemSlot(bag, slot)
if item then
item:HandleEvent(msg, bag, slot, ...)
end
end
end
function ItemFrame:RegisterItemEvent(...)
Bagnon.BagEvents:Listen(self, ...)
end
function ItemFrame:UnregisterItemEvent(...)
Bagnon.BagEvents:Ignore(self, ...)
end
function ItemFrame:UnregisterAllItemEvents(...)
Bagnon.BagEvents:IgnoreAll(self, ...)
end
--[[ Frame Events ]]--
function ItemFrame:OnShow()
self:UpdateEverything()
end
function ItemFrame:OnHide()
self:UpdateEvents()
end
function ItemFrame:OnSizeChanged()
self:SendMessage('ITEM_FRAME_SIZE_CHANGE', self:GetFrameID())
end
--[[ Update Methods ]]--
function ItemFrame:UpdateEverything()
self:UpdateEvents()
if self:IsVisible() then
self:ReloadAllItemSlots()
self:RequestLayout()
end
end
function ItemFrame:UpdateEvents()
self:UnregisterAllEvents()
self:UnregisterAllItemEvents()
self:UnregisterAllMessages()
if self:IsVisible() then
--live item events
if not self:IsCached() then
self:RegisterEvent('ITEM_LOCK_CHANGED')
if hasBlizzQuestHighlight() then
self:RegisterEvent('QUEST_ACCEPTED')
self:RegisterEvent('UNIT_QUEST_LOG_CHANGED')
end
self:RegisterItemEvent('ITEM_SLOT_ADD')
self:RegisterItemEvent('ITEM_SLOT_REMOVE')
self:RegisterItemEvent('ITEM_SLOT_UPDATE', 'HandleSpecificItemEvent')
self:RegisterItemEvent('ITEM_SLOT_UPDATE_COOLDOWN', 'HandleSpecificItemEvent')
self:RegisterItemEvent('BAG_UPDATE_TYPE')
if self:HasBankBags() then
self:RegisterItemEvent('BANK_OPENED')
self:RegisterItemEvent('BANK_CLOSED')
end
end
self:RegisterMessage('BAG_SLOT_SHOW')
self:RegisterMessage('BAG_SLOT_HIDE')
self:RegisterMessage('PLAYER_UPDATE')
self:RegisterMessage('ITEM_FRAME_SPACING_UPDATE')
self:RegisterMessage('ITEM_FRAME_COLUMNS_UPDATE')
self:RegisterMessage('SLOT_ORDER_UPDATE')
self:RegisterMessage('ITEM_FRAME_BAG_BREAK_UPDATE')
self:RegisterMessage('TEXT_SEARCH_UPDATE', 'HandleGlobalItemEvent')
self:RegisterMessage('BAG_SEARCH_UPDATE', 'HandleGlobalItemEvent')
self:RegisterMessage('ITEM_HIGHLIGHT_QUEST_UPDATE', 'HandleGlobalItemEvent')
self:RegisterMessage('ITEM_HIGHLIGHT_QUALITY_UPDATE', 'HandleGlobalItemEvent')
self:RegisterMessage('ITEM_HIGHLIGHT_OPACITY_UPDATE', 'HandleGlobalItemEvent')
self:RegisterMessage('SHOW_EMPTY_ITEM_SLOT_TEXTURE_UPDATE', 'HandleGlobalItemEvent')
self:RegisterMessage('ITEM_SLOT_COLOR_UPDATE', 'HandleGlobalItemEvent')
self:RegisterMessage('ITEM_SLOT_COLOR_ENABLED_UPDATE', 'HandleGlobalItemEvent')
end
end
--[[ Item Slot Management ]]--
--if an item is not assigned to the given slotIndex, then add an item
function ItemFrame:AddItemSlot(bag, slot)
if self:IsBagShown(bag) and not self:GetItemSlot(bag, slot) then
local itemSlot = self:NewItemSlot(bag, slot)
self.itemSlots[self:GetSlotIndex(bag, slot)] = itemSlot
self:RequestLayout()
end
end
function ItemFrame:NewItemSlot(bag, slot)
return Bagnon.ItemSlot:New(bag, slot, self:GetFrameID(), self)
end
--removes any item slot associated with the given slotIndex
function ItemFrame:RemoveItemSlot(bag, slot)
local itemSlot = self:GetItemSlot(bag, slot)
if itemSlot then
itemSlot:Free()
self.itemSlots[self:GetSlotIndex(bag, slot)] = nil
self:RequestLayout()
end
end
function ItemFrame:UpdateItemSlot(bag, slot)
local itemSlot = self:GetItemSlot(bag, slot)
if itemSlot then
itemSlot:Update()
end
end
--returns the item slot assigned to the given slotIndex
function ItemFrame:GetItemSlot(bag, slot)
return self.itemSlots[self:GetSlotIndex(bag, slot)]
end
function ItemFrame:GetAllItemSlots()
return pairs(self.itemSlots)
end
--takes a bag and a slot, and returns an array index
function ItemFrame:GetSlotIndex(bag, slot)
if bag < 0 then
return bag*100 - slot
end
return bag * 100 + slot
end
--remove all item slots from the frame
function ItemFrame:AddAllItemSlotsForBag(bag)
for slot = 1, self:GetBagSize(bag) do
self:AddItemSlot(bag, slot)
end
end
function ItemFrame:RemoveAllItemSlotsForBag(bag)
for slot = 1, self:GetBagSize(bag) do
self:RemoveItemSlot(bag, slot)
end
end
function ItemFrame:UpdateAllItemSlotsForBag(bag)
for slot = 1, self:GetBagSize(bag) do
self:UpdateItemSlot(bag, slot)
end
end
--remove all unused item slots from the frame
--add all missing slots to the frame
--update all existing slots on the frame
--if slots have been added or removed, then request a layout update
function ItemFrame:ReloadAllItemSlots()
local changed = false
local itemSlots = self.itemSlots
for i, itemSlot in pairs(itemSlots) do
local used = self:IsBagShown(itemSlot:GetBag()) and (itemSlot:GetID() <= self:GetBagSize(itemSlot:GetBag()))
if not used then
itemSlot:Free()
itemSlots[i] = nil
changed = true
end
end
for _, bag in self:GetVisibleBags() do
for slot = 1, self:GetBagSize(bag) do
local itemSlot = self:GetItemSlot(bag, slot)
if not itemSlot then
self:AddItemSlot(bag, slot)
changed = true
else
itemSlot:Update()
end
end
end
if changed then
self:RequestLayout()
end
end
--[[ Layout Methods ]]--
function ItemFrame:Layout()
if self:IsBagBreakEnabled() then
self:Layout_BagBreak()
else
self:Layout_Default()
end
end
--arranges itemSlots on the itemFrame, and adjusts size to fit
function ItemFrame:Layout_Default()
self.needsLayout = nil
local columns = self:NumColumns()
local spacing = self:GetSpacing()
local effItemSize = self.ITEM_SIZE + spacing
local i = 0
for _, bag in self:GetVisibleBags() do
for slot = 1, self:GetBagSize(bag) do
local itemSlot = self:GetItemSlot(bag, slot)
if itemSlot then
i = i + 1
local row = (i - 1) % columns
local col = math.ceil(i / columns) - 1
itemSlot:ClearAllPoints()
itemSlot:SetPoint('TOPLEFT', self, 'TOPLEFT', effItemSize * row, -effItemSize * col)
end
end
end
local width = effItemSize * math.min(columns, i) - spacing
local height = effItemSize * ceil(i / columns) - spacing
self:SetWidth(width)
self:SetHeight(height)
end
function ItemFrame:Layout_BagBreak()
self.needsLayout = nil
local columns = self:NumColumns()
local spacing = self:GetSpacing()
local effItemSize = self.ITEM_SIZE + spacing
local rows = 1
local col = 1
local maxCols = 0
for _, bag in self:GetVisibleBags() do
local bagSize = self:GetBagSize(bag)
for slot = 1, bagSize do
local itemSlot = self:GetItemSlot(bag, slot)
itemSlot:ClearAllPoints()
itemSlot:SetPoint('TOPLEFT', self, 'TOPLEFT', effItemSize * (col - 1), -effItemSize * (rows - 1))
if col == columns then
col = 1
if slot < bagSize then
rows = rows + 1
end
else
col = col + 1
maxCols = math.max(maxCols, col)
end
end
rows = rows + 1
col = 1
end
local width = effItemSize * maxCols - spacing*2
local height = effItemSize * (rows - 1) - spacing*2
self:SetWidth(width)
self:SetHeight(height)
end
--request a layout update on this frame
function ItemFrame:RequestLayout()
self.needsLayout = true
self.throttledUpdater:Show()
end
--returns true if the frame should have its layout updated, and false otherwise
function ItemFrame:NeedsLayout()
return self.needsLayout
end
--[[ Frame Properties ]]--
--frameID
function ItemFrame:SetFrameID(frameID)
if self:GetFrameID() ~= frameID then
self.frameID = frameID
self:UpdateEverything()
end
end
function ItemFrame:GetFrameID()
return self.frameID
end
--frame settings
function ItemFrame:GetSettings()
return Bagnon.FrameSettings:Get(self:GetFrameID())
end
--player info
function ItemFrame:GetPlayer()
return self:GetSettings():GetPlayerFilter()
end
function ItemFrame:IsCached()
return Bagnon.PlayerInfo:IsCached(self:GetPlayer())
end
--bag info
function ItemFrame:HasBag(bag)
return self:GetSettings():HasBagSlot(slot)
end
function ItemFrame:GetBagSize(bag)
return Bagnon.BagSlotInfo:GetSize(self:GetPlayer(), bag)
end
function ItemFrame:IsBagShown(bag)
return self:GetSettings():IsBagSlotShown(bag)
end
function ItemFrame:IsBagSlotCached(bag)
return Bagnon.BagSlotInfo:IsCached(self:GetPlayer(), bag)
end
function ItemFrame:GetVisibleBags()
return self:GetSettings():GetVisibleBagSlots()
end
function ItemFrame:HasBankBags()
for _, bag in self:GetVisibleBags() do
if Bagnon.BagSlotInfo:IsBank(bag) or Bagnon.BagSlotInfo:IsBankBag(bag) then
return true
end
end
return false
end
--layout info
function ItemFrame:NumColumns()
return self:GetSettings():GetItemFrameColumns()
end
function ItemFrame:GetSpacing()
return self:GetSettings():GetItemFrameSpacing()
end
function ItemFrame:IsBagBreakEnabled()
return self:GetSettings():IsBagBreakEnabled()
end

View file

@ -0,0 +1,212 @@
--[[
moneyFrame.lua
A money frame object
--]]
local Bagnon = LibStub('AceAddon-3.0'):GetAddon('Bagnon')
local MoneyFrame = Bagnon.Classy:New('Frame')
MoneyFrame:Hide()
Bagnon.MoneyFrame = MoneyFrame
--[[ Things! ]]--
local L = LibStub('AceLocale-3.0'):GetLocale('Bagnon')
local GOLD_TEXT = string.format('|cffffd700%s|r', 'g')
local SILVER_TEXT = string.format('|cffc7c7cf%s|r', 's')
local COPPER_TEXT = string.format('|cffeda55f%s|r', 'c')
--[[ Constructor ]]--
function MoneyFrame:New(frameID, parent)
local f = self:Bind(CreateFrame('Frame', 'BagnonMoneyFrame' .. self:GetNextID(), parent, 'SmallMoneyFrameTemplate'))
f:SetFrameID(frameID)
f:AddClickFrame()
f:SetScript('OnShow', f.OnShow)
f:SetScript('OnHide', f.OnHide)
f:RegisterMessage('PLAYER_UPDATE')
return f
end
--creates a clickable frame for tooltips/etc
local function ClickFrame_OnClick(self, button)
self:GetParent():OnClick(button)
end
local function ClickFrame_OnEnter(self)
self:GetParent():OnEnter()
end
local function ClickFrame_OnLeave(self)
self:GetParent():OnLeave()
end
function MoneyFrame:AddClickFrame()
local f = CreateFrame('Button', self:GetName() .. 'Click', self)
f:SetFrameLevel(self:GetFrameLevel() + 3)
f:SetAllPoints(self)
f:SetScript('OnClick', ClickFrame_OnClick)
f:SetScript('OnEnter', ClickFrame_OnEnter)
f:SetScript('OnLeave', ClickFrame_OnLeave)
return f
end
do
local id = 0
function MoneyFrame:GetNextID()
local nextID = id + 1
id = nextID
return nextID
end
end
--[[ Events ]]--
function MoneyFrame:PLAYER_UPDATE(msg, frameID, player)
if self:GetFrameID() == frameID then
self:UpdateValue()
end
end
--[[ Frame Events ]]--
function MoneyFrame:OnShow()
self:UpdateEverything()
end
function MoneyFrame:OnHide()
self:UpdateEvents()
end
function MoneyFrame:OnClick()
local name = self:GetName()
if MouseIsOver(_G[name .. 'GoldButton']) then
OpenCoinPickupFrame(COPPER_PER_GOLD, MoneyTypeInfo[self.moneyType].UpdateFunc(), self)
self.hasPickup = 1
elseif MouseIsOver(_G[name .. 'SilverButton']) then
OpenCoinPickupFrame(COPPER_PER_SILVER, MoneyTypeInfo[self.moneyType].UpdateFunc(), self)
self.hasPickup = 1
elseif MouseIsOver(_G[name .. 'CopperButton']) then
OpenCoinPickupFrame(1, MoneyTypeInfo[self.moneyType].UpdateFunc(), self)
self.hasPickup = 1
end
self:OnLeave()
end
function MoneyFrame:OnEnter()
if not BagnonDB then return end
GameTooltip:SetOwner(self, 'ANCHOR_TOPRIGHT')
GameTooltip:SetText(string.format(L.TipGoldOnRealm, GetRealmName()))
local totalMoney = 0
for i, player in pairs(BagnonDB:GetPlayerList()) do
local money = Bagnon.PlayerInfo:GetMoney(player)
if money > 0 then
totalMoney = totalMoney + money
self:AddPlayerTotalToTooltip(player, money, GameTooltip)
end
end
GameTooltip:AddLine('----------------------------------------')
self:AddPlayerTotalToTooltip(L.Total, totalMoney, GameTooltip)
GameTooltip:Show()
end
function MoneyFrame:OnLeave()
if GameTooltip:IsOwned(self) then
GameTooltip:Hide()
end
end
--[[ Update Methods ]]--
function MoneyFrame:UpdateEverything()
self:UpdateEvents()
self:UpdateValue()
end
function MoneyFrame:UpdateValue()
if self:IsVisible() then
MoneyFrame_Update(self:GetName(), self:GetMoney())
end
end
function MoneyFrame:UpdateEvents()
self:UnregisterAllMessages()
if self:IsVisible() then
self:RegisterMessage('PLAYER_UPDATE')
end
end
--[[ Frame Properties ]]--
function MoneyFrame:GetSettings()
return Bagnon.FrameSettings:Get(self:GetFrameID())
end
function MoneyFrame:GetPlayer()
return self:GetSettings():GetPlayerFilter()
end
function MoneyFrame:SetFrameID(frameID)
if self:GetFrameID() ~= frameID then
self.frameID = frameID
self:UpdateEverything()
end
end
function MoneyFrame:GetFrameID()
return self.frameID
end
function MoneyFrame:GetMoney()
return Bagnon.PlayerInfo:GetMoney(self:GetPlayer())
end
function MoneyFrame:GetGoldSilverCopper(money)
local gold = math.floor(money / (COPPER_PER_SILVER * SILVER_PER_GOLD))
local silver = math.floor((money - (gold * COPPER_PER_SILVER * SILVER_PER_GOLD)) / COPPER_PER_SILVER)
local copper = money % COPPER_PER_SILVER
return gold, silver, copper
end
function MoneyFrame:AddPlayerTotalToTooltip(player, money, tooltip)
local gold, silver, copper = self:GetGoldSilverCopper(money)
local text
if gold > 0 then
text = string.format('|cffffffff%d|r%s', gold, GOLD_TEXT)
end
if silver > 0 then
if text then
text = text .. string.format(' |cffffffff%d|r%s', silver, SILVER_TEXT)
else
text = string.format('|cffffffff%d|r%s', silver, SILVER_TEXT)
end
end
if copper > 0 then
if text then
text = text .. string.format(' |cffffffff%d|r%s', copper, COPPER_TEXT)
else
text = string.format('|cffffffff%d|r%s', copper, COPPER_TEXT)
end
end
tooltip:AddDoubleLine(player, text, 1, 1, 1, 1, 1, 1, 0)
end

View file

@ -0,0 +1,97 @@
--[[
optionsToggle.lua
A options frame toggle widget
--]]
local Bagnon = LibStub('AceAddon-3.0'):GetAddon('Bagnon')
local L = LibStub('AceLocale-3.0'):GetLocale('Bagnon')
local OptionsToggle = Bagnon.Classy:New('Button')
Bagnon.OptionsToggle = OptionsToggle
local SIZE = 20
local NORMAL_TEXTURE_SIZE = 64 * (SIZE/36)
--[[ Constructor ]]--
function OptionsToggle:New(frameID, parent)
local b = self:Bind(CreateFrame('Button', nil, parent))
b:SetWidth(SIZE)
b:SetHeight(SIZE)
b:RegisterForClicks('anyUp')
local nt = b:CreateTexture()
nt:SetTexture([[Interface\Buttons\UI-Quickslot2]])
nt:SetWidth(NORMAL_TEXTURE_SIZE)
nt:SetHeight(NORMAL_TEXTURE_SIZE)
nt:SetPoint('CENTER', 0, -1)
b:SetNormalTexture(nt)
local pt = b:CreateTexture()
pt:SetTexture([[Interface\Buttons\UI-Quickslot-Depress]])
pt:SetAllPoints(b)
b:SetPushedTexture(pt)
local ht = b:CreateTexture()
ht:SetTexture([[Interface\Buttons\ButtonHilight-Square]])
ht:SetAllPoints(b)
b:SetHighlightTexture(ht)
local icon = b:CreateTexture()
icon:SetAllPoints(b)
icon:SetTexture([[Interface\Icons\Trade_Engineering]])
b:SetScript('OnClick', b.OnClick)
b:SetScript('OnEnter', b.OnEnter)
b:SetScript('OnLeave', b.OnLeave)
b:SetFrameID(frameID)
return b
end
--[[ Frame Events ]]--
function OptionsToggle:OnClick()
if LoadAddOn('Bagnon_Config') then
Bagnon.FrameOptions:ShowFrame(self:GetFrameID())
end
end
function OptionsToggle:OnEnter()
if self:GetRight() > (GetScreenWidth() / 2) then
GameTooltip:SetOwner(self, 'ANCHOR_LEFT')
else
GameTooltip:SetOwner(self, 'ANCHOR_RIGHT')
end
self:UpdateTooltip()
end
function OptionsToggle:OnLeave()
if GameTooltip:IsOwned(self) then
GameTooltip:Hide()
end
end
--[[ Update Methods ]]--
function OptionsToggle:UpdateTooltip()
if GameTooltip:IsOwned(self) then
GameTooltip:SetText(L.TipShowFrameConfig)
end
end
--[[ Properties ]]--
function OptionsToggle:SetFrameID(frameID)
if self:GetFrameID() ~= frameID then
self.frameID = frameID
end
end
function OptionsToggle:GetFrameID()
return self.frameID
end

View file

@ -0,0 +1,133 @@
--[[
playerSelector.lua
A player selector widget
--]]
local Bagnon = LibStub('AceAddon-3.0'):GetAddon('Bagnon')
local L = LibStub('AceLocale-3.0'):GetLocale('Bagnon')
local PlayerSelector = Bagnon.Classy:New('Button')
Bagnon.PlayerSelector = PlayerSelector
local SIZE = 20
local NORMAL_TEXTURE_SIZE = 64 * (SIZE/36)
--[[ Constructor ]]--
function PlayerSelector:New(frameID, parent)
local b = self:Bind(CreateFrame('Button', nil, parent))
b:SetWidth(SIZE)
b:SetHeight(SIZE)
b:RegisterForClicks('anyUp')
local nt = b:CreateTexture()
nt:SetTexture([[Interface\Buttons\UI-Quickslot2]])
nt:SetWidth(NORMAL_TEXTURE_SIZE)
nt:SetHeight(NORMAL_TEXTURE_SIZE)
nt:SetPoint('CENTER', 0, -1)
b:SetNormalTexture(nt)
local pt = b:CreateTexture()
pt:SetTexture([[Interface\Buttons\UI-Quickslot-Depress]])
pt:SetAllPoints(b)
b:SetPushedTexture(pt)
local ht = b:CreateTexture()
ht:SetTexture([[Interface\Buttons\ButtonHilight-Square]])
ht:SetAllPoints(b)
b:SetHighlightTexture(ht)
local icon = b:CreateTexture()
icon:SetAllPoints(b)
icon:SetTexture(self:GetPlayerIcon())
b.icon = icon
b:SetScript('OnClick', b.OnClick)
b:SetScript('OnEnter', b.OnEnter)
b:SetScript('OnLeave', b.OnLeave)
b:SetScript('OnShow', b.OnShow)
b:SetFrameID(frameID)
return b
end
--[[ Frame Events ]]--
function PlayerSelector:OnShow()
self.icon:SetTexture(self:GetPlayerIcon())
end
function PlayerSelector:OnClick()
self:ShowPlayerSelector()
end
function PlayerSelector:OnEnter()
if self:GetRight() > (GetScreenWidth() / 2) then
GameTooltip:SetOwner(self, 'ANCHOR_LEFT')
else
GameTooltip:SetOwner(self, 'ANCHOR_RIGHT')
end
self:UpdateTooltip()
end
function PlayerSelector:OnLeave()
if GameTooltip:IsOwned(self) then
GameTooltip:Hide()
end
end
--[[ Update Methods ]]--
function PlayerSelector:ShowPlayerSelector()
if BagnonDB then
BagnonDB:SetDropdownFrame(self)
BagnonDB:ToggleDropdown(self, -4, -2)
end
end
function PlayerSelector:UpdateTooltip()
GameTooltip:SetText(L.TipChangePlayer)
end
--[[ Properties ]]--
function PlayerSelector:SetFrameID(frameID)
if self:GetFrameID() ~= frameID then
self.frameID = frameID
end
end
function PlayerSelector:GetFrameID()
return self.frameID
end
function PlayerSelector:GetSettings()
return Bagnon.FrameSettings:Get(self:GetFrameID())
end
function PlayerSelector:SetPlayer(player)
self:GetSettings():SetPlayerFilter(player)
end
function PlayerSelector:GetPlayer()
return self:GetSettings():GetPlayerFilter()
end
function PlayerSelector:GetPlayerIcon()
local race, enRace = UnitRace('player')
--forsaken hack
if enRace == 'Scourge' then
enRace = 'Undead'
end
local sex = UnitSex('player')
if sex == 3 then
return string.format([[Interface\AddOns\Bagnon\textures\Achievement_Character_%s_%s]], enRace, 'Female')
end
return string.format([[Interface\AddOns\Bagnon\textures\Achievement_Character_%s_%s]], enRace, 'Male')
end

View file

@ -0,0 +1,554 @@
--[[
savedFrameSettings.lua
Persistent frame settings
--]]
local SavedFrameSettings = {}
local Bagnon = LibStub('AceAddon-3.0'):GetAddon('Bagnon')
Bagnon.SavedFrameSettings = SavedFrameSettings
--[[---------------------------------------------------------------------------
Local Functions of Justice
--]]---------------------------------------------------------------------------
local function removeDefaults(tbl, defaults)
for k, v in pairs(defaults) do
if type(tbl[k]) == 'table' and type(v) == 'table' then
removeDefaults(tbl[k], v)
if next(tbl[k]) == nil then
tbl[k] = nil
end
elseif tbl[k] == v then
tbl[k] = nil
end
end
end
local function copyDefaults(tbl, defaults)
for k, v in pairs(defaults) do
if type(v) == 'table' then
tbl[k] = copyDefaults(tbl[k] or {}, v)
elseif tbl[k] == nil then
tbl[k] = v
end
end
return tbl
end
--[[---------------------------------------------------------------------------
Constructorish
--]]---------------------------------------------------------------------------
SavedFrameSettings.mt = {
__index = SavedFrameSettings
}
SavedFrameSettings.objects = setmetatable({}, {__index = function(tbl, id)
local obj = setmetatable({frameID = id}, SavedFrameSettings.mt)
tbl[id] = obj
return obj
end})
function SavedFrameSettings:Get(id)
return self.objects[id]
end
--[[---------------------------------------------------------------------------
Events
--]]---------------------------------------------------------------------------
--create an event handler
do
local f = CreateFrame('Frame')
f:SetScript('OnEvent', function(self, event, ...)
local action = SavedFrameSettings[event]
if action then
action(SavedFrameSettings, event, ...)
end
end)
f:RegisterEvent('PLAYER_LOGOUT')
end
--remove any settings that are set to defaults upon logout
function SavedFrameSettings:PLAYER_LOGOUT()
self:ClearDefaults()
end
--[[---------------------------------------------------------------------------
Accessor Methods
--]]---------------------------------------------------------------------------
--get settings for all frames
--only one instance of this for everything (hence the lack of self use)
function SavedFrameSettings:GetGlobalDB()
if not SavedFrameSettings.db then
SavedFrameSettings.db = _G['BagnonFrameSettings']
if SavedFrameSettings.db then
if self:IsDBOutOfDate() then
self:UpgradeDB()
end
else
SavedFrameSettings.db = {
frames = {},
version = self:GetAddOnVersion()
}
_G['BagnonFrameSettings'] = SavedFrameSettings.db
end
end
return SavedFrameSettings.db
end
--get frame specific settings
function SavedFrameSettings:GetDB()
if not self.frameDB then
self.frameDB = self:GetGlobalDB().frames[self:GetFrameID()]
if not self.frameDB then
self.frameDB = {}
self:GetGlobalDB().frames[self:GetFrameID()] = self.frameDB
end
copyDefaults(self.frameDB, self:GetDefaultSettings())
end
return self.frameDB
end
function SavedFrameSettings:GetFrameID()
return self.frameID
end
--[[---------------------------------------------------------------------------
Upgrade Methods
--]]---------------------------------------------------------------------------
function SavedFrameSettings:UpgradeDB()
local major, minor, bugfix = self:GetDBVersion():match('(%w+)%.(%w+)%.(%w+)')
local db = self:GetGlobalDB()
--hidden bags upgrade
for frameID, settings in pairs(db.frames) do
local hiddenBags = settings.hiddenBags
if hiddenBags then
for k, v in pairs(hiddenBags) do
if tonumber(k) and tonumber(v) then
hiddenBags[v] = true
hiddenBags[k] = nil
end
end
end
end
db.version = self:GetAddOnVersion()
end
function SavedFrameSettings:IsDBOutOfDate()
return self:GetDBVersion() ~= self:GetAddOnVersion()
end
function SavedFrameSettings:GetDBVersion()
return self:GetGlobalDB().version
end
function SavedFrameSettings:GetAddOnVersion()
return GetAddOnMetadata('Bagnon', 'Version')
end
function SavedFrameSettings:ClearDefaults()
local db = self:GetGlobalDB()
for frameID, settings in pairs(db.frames) do
removeDefaults(settings, self:GetDefaultSettings(frameID))
if next(settings) == nil then
db[frameID] = nil
end
end
end
--[[---------------------------------------------------------------------------
Update Methods
--]]---------------------------------------------------------------------------
--[[ Frame Color ]]--
--background
function SavedFrameSettings:SetColor(r, g, b, a)
local color = self:GetDB().frameColor
color[1] = r
color[2] = g
color[3] = b
color[4] = a
end
function SavedFrameSettings:GetColor()
local r, g, b, a = unpack(self:GetDB().frameColor)
return r, g, b, a
end
--border
function SavedFrameSettings:SetBorderColor(r, g, b, a)
local color = self:GetDB().frameBorderColor
color[1] = r
color[2] = g
color[3] = b
color[4] = a
end
function SavedFrameSettings:GetBorderColor()
local r, g, b, a = unpack(self:GetDB().frameBorderColor)
return r, g, b, a
end
--[[ Frame Position ]]--
function SavedFrameSettings:SetPosition(point, x, y)
local db = self:GetDB()
db.point = point
db.x = x
db.y = y
end
function SavedFrameSettings:GetPosition()
local db = self:GetDB()
return db.point, db.x, db.y
end
--[[ Frame Scale ]]--
function SavedFrameSettings:SetScale(scale)
self:GetDB().scale = scale
end
function SavedFrameSettings:GetScale()
return self:GetDB().scale
end
--[[ Frame Opacity ]]--
function SavedFrameSettings:SetOpacity(opacity)
self:GetDB().opacity = opacity
end
function SavedFrameSettings:GetOpacity()
return self:GetDB().opacity
end
--[[ Frame Layer]]--
function SavedFrameSettings:SetLayer(layer)
self:GetDB().frameLayer = layer
end
function SavedFrameSettings:GetLayer()
return self:GetDB().frameLayer
end
--[[ Frame Components ]]--
function SavedFrameSettings:SetHasBagFrame(enable)
self:GetDB().hasBagFrame = enable or false
end
function SavedFrameSettings:HasBagFrame()
return self:GetDB().hasBagFrame
end
function SavedFrameSettings:SetHasMoneyFrame(enable)
self:GetDB().hasMoneyFrame = enable or false
end
function SavedFrameSettings:HasMoneyFrame()
return self:GetDB().hasMoneyFrame
end
function SavedFrameSettings:SetHasDBOFrame(enable)
self:GetDB().hasDBOFrame = enable or false
end
function SavedFrameSettings:HasDBOFrame()
return self:GetDB().hasDBOFrame
end
function SavedFrameSettings:SetHasSearchToggle(enable)
self:GetDB().hasSearchToggle = enable or false
end
function SavedFrameSettings:HasSearchToggle()
return self:GetDB().hasSearchToggle
end
function SavedFrameSettings:SetHasSortButton(enable)
self:GetDB().hasSortButton = enable or false
end
function SavedFrameSettings:HasSortButton()
return self:GetDB().hasSortButton
end
function SavedFrameSettings:SetHasOptionsToggle(enable)
self:GetDB().hasOptionsToggle = enable or false
end
function SavedFrameSettings:HasOptionsToggle()
return self:GetDB().hasOptionsToggle
end
--[[ Frame Bags ]]--
--show a bag
function SavedFrameSettings:ShowBag(bag)
self:GetDB().hiddenBags[bag] = false
end
--hide a bag
function SavedFrameSettings:HideBag(bag)
self:GetDB().hiddenBags[bag] = true
end
function SavedFrameSettings:IsBagShown(bag)
return not self:GetDB().hiddenBags[bag]
end
--get all available bags
function SavedFrameSettings:GetBags()
return self:GetDB().availableBags
end
--get all hidden bags
function SavedFrameSettings:GetHiddenBags()
return self:GetDB().hiddenBags
end
--[[ Item Frame Layout ]]--
--columns
function SavedFrameSettings:SetItemFrameColumns(columns)
self:GetDB().itemFrameColumns = columns
end
function SavedFrameSettings:GetItemFrameColumns()
return self:GetDB().itemFrameColumns
end
--spacing
function SavedFrameSettings:SetItemFrameSpacing(spacing)
self:GetDB().itemFrameSpacing = spacing
end
function SavedFrameSettings:GetItemFrameSpacing()
return self:GetDB().itemFrameSpacing
end
--bag break layout
function SavedFrameSettings:SetBagBreak(enable)
self:GetDB().bagBreak = enable
end
function SavedFrameSettings:IsBagBreakEnabled()
return self:GetDB().bagBreak
end
--[[ Item Frame Slot ORdering ]]--
function SavedFrameSettings:SetReverseSlotOrder(enable)
self:GetDB().reverseSlotOrder = enable
end
function SavedFrameSettings:IsSlotOrderReversed()
return self:GetDB().reverseSlotOrder
end
--[[ Databroker Display Object ]]--
function SavedFrameSettings:SetBrokerDisplayObject(objectName)
self:GetDB().dataBrokerObject = objectName
end
function SavedFrameSettings:GetBrokerDisplayObject()
return self:GetDB().dataBrokerObject
end
--[[---------------------------------------------------------------------------
Frame Defaults
--]]---------------------------------------------------------------------------
--generic
function SavedFrameSettings:GetDefaultSettings(frameID)
local frameID = frameID or self:GetFrameID()
if frameID == 'keys' then
return self:GetDefaultKeyRingSettings()
elseif frameID == 'bank' then
return self:GetDefaultBankSettings()
elseif frameID == 'guildbank' then
return self:GetDefaultGuildBankSettings()
end
return self:GetDefaultInventorySettings()
end
--inventory
function SavedFrameSettings:GetDefaultInventorySettings()
local defaults = SavedFrameSettings.invDefaults or {
--bag settings
availableBags = {BACKPACK_CONTAINER, 1, 2, 3, 4, KEYRING_CONTAINER},
hiddenBags = {
[BACKPACK_CONTAINER] = false,
[1] = false,
[2] = false,
[3] = false,
[4] = false,
[KEYRING_CONTAINER] = true,
},
--frame
frameColor = {0, 0, 0, 0.5},
frameBorderColor = {1, 1, 1, 1},
scale = 1,
opacity = 1,
point = 'BOTTOMRIGHT',
x = 0,
y = 150,
frameLayer = 'HIGH',
--itemFrame
itemFrameColumns = 8,
itemFrameSpacing = 2,
bagBreak = false,
--optional components
hasMoneyFrame = true,
hasBagFrame = true,
hasDBOFrame = true,
hasSearchToggle = true,
hasOptionsToggle = true,
hasKeyringToggle = true,
hasSortButton = true,
--dbo display object
dataBrokerObject = 'BagnonLauncher',
--slot ordering
reverseSlotOrder = false,
}
SavedFrameSettings.invDefaults = defaults
return defaults
end
--bank
function SavedFrameSettings:GetDefaultBankSettings()
local defaults = SavedFrameSettings.bankDefaults or {
--bag settings
availableBags = {BANK_CONTAINER, 5, 6, 7, 8, 9, 10, 11},
hiddenBags = {
[BANK_CONTAINER] = false,
[5] = false,
[6] = false,
[7] = false,
[8] = false,
[9] = false,
[10] = false,
[11] = false
},
--frame
frameColor = {0, 0, 0, 0.5},
frameBorderColor = {1, 1, 0, 1},
scale = 1,
opacity = 1,
point = 'BOTTOMLEFT',
x = 0,
y = 150,
frameLayer = 'HIGH',
--itemFrame
itemFrameColumns = 10,
itemFrameSpacing = 2,
bagBreak = false,
--optional components
hasMoneyFrame = true,
hasBagFrame = true,
hasDBOFrame = true,
hasSearchToggle = true,
hasOptionsToggle = true,
hasKeyringToggle = false,
hasSortButton = true,
--dbo display object
dataBrokerObject = 'BagnonLauncher',
--slot ordering
reverseSlotOrder = false,
}
SavedFrameSettings.bankDefaults = defaults
return defaults
end
--keys
function SavedFrameSettings:GetDefaultKeyRingSettings()
local defaults = SavedFrameSettings.keyDefaults or {
--bag settings
availableBags = {KEYRING_CONTAINER},
hiddenBags = {
[KEYRING_CONTAINER] = false
},
--frame,
frameColor = {0, 0, 0, 0.5},
frameBorderColor = {0, 1, 1, 1},
scale = 1,
opacity = 1,
point = 'BOTTOMRIGHT',
x = -350,
y = 150,
frameLayer = 'HIGH',
--itemFrame
itemFrameColumns = 4,
itemFrameSpacing = 2,
bagBreak = false,
--optional components
hasMoneyFrame = false,
hasBagFrame = false,
hasDBOFrame = false,
hasSearchToggle = false,
hasOptionsToggle = true,
hasKeyringToggle = false,
hasSortButton = false,
--dbo display object
dataBrokerObject = 'BagnonLauncher',
--slot ordering
reverseSlotOrder = false,
}
SavedFrameSettings.keyDefaults = defaults
return defaults
end
function SavedFrameSettings:GetDefaultGuildBankSettings()
return self:GetDefaultInventorySettings()
end

View file

@ -0,0 +1,210 @@
--[[
dbSettings.lua
Database access for Bagnon
--]]
local Bagnon = LibStub('AceAddon-3.0'):GetAddon('Bagnon')
local L = LibStub('AceLocale-3.0'):GetLocale('Bagnon')
local SavedSettings = {}
Bagnon.SavedSettings = SavedSettings
--[[---------------------------------------------------------------------------
Local Functions of Justice
--]]---------------------------------------------------------------------------
local function removeDefaults(tbl, defaults)
for k, v in pairs(defaults) do
if type(tbl[k]) == 'table' and type(v) == 'table' then
removeDefaults(tbl[k], v)
if next(tbl[k]) == nil then
tbl[k] = nil
end
elseif tbl[k] == v then
tbl[k] = nil
end
end
end
local function copyDefaults(tbl, defaults)
for k, v in pairs(defaults) do
if type(v) == 'table' then
tbl[k] = copyDefaults(tbl[k] or {}, v)
elseif tbl[k] == nil then
tbl[k] = v
end
end
return tbl
end
--[[---------------------------------------------------------------------------
Constructorish
--]]---------------------------------------------------------------------------
function SavedSettings:GetDB()
if not self.db then
self.db = _G['BagnonGlobalSettings']
if self.db then
if self:IsDBOutOfDate() then
self:UpgradeDB()
end
else
self.db = self:CreateNewDB()
Bagnon:Print(L.NewUser)
end
copyDefaults(self.db, self:GetDefaultSettings())
end
return self.db
end
function SavedSettings:GetDefaultSettings()
self.defaults = self.defaults or {
highlightItemsByQuality = true,
highlightQuestItems = true,
showEmptyItemSlotTexture = true,
lockFramePositions = false,
colorBagSlots = true,
enableBlizzardBagPassThrough = false,
enabledFrames = {
inventory = true,
bank = true,
keys = true,
},
autoDisplayEvents = {
inventory = {
ah = false,
bank = true,
vendor = true,
mail = true,
guildbank = true,
trade = false,
craft = false,
player = false
},
},
slotColors = {
ammo = {0.7, 0.7, 1},
trade = {0.5, 1, 0.5},
shard = {0.9, 0.7, 1},
keyring = {1, 0.8, 0},
},
highlightOpacity = 0.5,
}
return self.defaults
end
--[[---------------------------------------------------------------------------
Upgrade Methods
--]]---------------------------------------------------------------------------
function SavedSettings:CreateNewDB()
local db = {
version = self:GetAddOnVersion()
}
_G['BagnonGlobalSettings'] = db
return db
end
function SavedSettings:UpgradeDB()
local major, minor, bugfix = self:GetDBVersion():match('(%w+)%.(%w+)%.(%w+)')
--do upgrade stuff
if tonumber(minor) <= 6 and tonumber(bugfix) <= 2 then
local db = self.db
local autoDisplayEvents = self.db.autoDisplayEvents
if autoDisplayEvents then
for i = 1, #autoDisplayEvents do
autoDisplayEvents[i] = nil
end
end
end
self:GetDB().version = self:GetAddOnVersion()
Bagnon:Print(string.format(L.Updated, self:GetDBVersion()))
end
function SavedSettings:IsDBOutOfDate()
return self:GetDBVersion() ~= self:GetAddOnVersion()
end
function SavedSettings:GetDBVersion()
return self:GetDB().version
end
function SavedSettings:GetAddOnVersion()
return GetAddOnMetadata('Bagnon', 'Version')
end
--[[---------------------------------------------------------------------------
Events
--]]---------------------------------------------------------------------------
--create an event handler
do
local f = CreateFrame('Frame')
f:SetScript('OnEvent', function(self, event, ...)
local action = SavedSettings[event]
if action then
action(SavedSettings, event, ...)
end
end)
f:RegisterEvent('PLAYER_LOGOUT')
end
--remove any settings that are set to defaults upon logout
function SavedSettings:PLAYER_LOGOUT()
self:UpdateEnableFrames()
self:UpdateEnableBlizzardBagPassThrough()
self:ClearDefaults()
end
--handle enabling/disabling of frames
function SavedSettings:UpdateEnableFrames()
local framesToEnable = Bagnon.Settings.framesToEnable
if framesToEnable then
for frameID, enableStatus in pairs(framesToEnable) do
self:GetDB().enabledFrames[frameID] = enableStatus
end
end
end
function SavedSettings:UpdateEnableBlizzardBagPassThrough()
self:GetDB().enableBlizzardBagPassThrough = Bagnon.Settings:WillBlizzardBagPassThroughBeEnabled()
end
function SavedSettings:ClearDefaults()
if self.db then
removeDefaults(self.db, self:GetDefaultSettings())
end
end
--[[---------------------------------------------------------------------------
Complex Settings
--]]---------------------------------------------------------------------------
--frame auto display events
function SavedSettings:SetShowFrameAtEvent(frameID, event, enable)
self:GetDB().autoDisplayEvents[frameID][event] = enable and true or false
end
function SavedSettings:IsFrameShownAtEvent(frameID, event)
return self:GetDB().autoDisplayEvents[frameID][event]
end

View file

@ -0,0 +1,175 @@
--[[
searchFrame.lua
A searcn frame widget
--]]
local Bagnon = LibStub('AceAddon-3.0'):GetAddon('Bagnon')
local L = LibStub('AceLocale-3.0'):GetLocale('Bagnon')
local SearchFrame = Bagnon.Classy:New('EditBox')
SearchFrame:Hide()
Bagnon.SearchFrame = SearchFrame
SearchFrame.backdrop = {
edgeFile = [[Interface\Tooltips\UI-Tooltip-Border]],
bgFile = [[Interface\ChatFrame\ChatFrameBackground]],
insets = {
left = 2,
right = 2,
top = 2,
bottom = 2
},
tile = true,
tileSize = 16,
edgeSize = 16,
}
function SearchFrame:New(frameID, parent)
local f = self:Bind(CreateFrame('EditBox', nil, parent))
f:SetToplevel(true)
f:Hide()
f:SetFrameStrata('DIALOG')
f:SetTextInsets(8, 8, 0, 0)
f:SetFontObject('ChatFontNormal')
f:SetBackdrop(f.backdrop)
f:SetBackdropColor(0, 0, 0, 0.8)
f:SetBackdropBorderColor(1, 1, 1, 0.8)
f:SetScript('OnShow', f.OnShow)
f:SetScript('OnHide', f.OnHide)
f:SetScript('OnTextChanged', f.OnTextChanged)
f:SetScript('OnEscapePressed', f.OnEscapePressed)
f:SetScript('OnEnterPressed', f.OnEnterPressed)
f:SetFrameID(frameID)
f:UpdateEvents()
f:SetAutoFocus(false)
-- f:UpdateShown()
-- f:UpdateText()
return f
end
--[[ Messages ]]--
function SearchFrame:TEXT_SEARCH_ENABLE(msg, frameID)
if self:GetFrameID() == frameID then
self:UpdateShown()
end
end
function SearchFrame:TEXT_SEARCH_DISABLE(msg, frameID)
if self:GetFrameID() == frameID then
self:UpdateShown()
end
end
function SearchFrame:TEXT_SEARCH_UPDATE(msg, search)
self:UpdateText()
end
--[[ Frame Events ]]--
function SearchFrame:OnShow()
self:UpdateEvents()
self:SetSearch(self:GetLastSearch())
self:HighlightText()
self:SetFocus()
end
function SearchFrame:OnHide()
self:UpdateEvents()
self:ClearFocus()
self:SetSearch('')
end
function SearchFrame:OnTextChanged()
self:SetSearch(self:GetText())
end
function SearchFrame:OnEscapePressed()
self:DisableSearch()
end
function SearchFrame:OnEnterPressed()
self:DisableSearch()
end
--[[ Update Methods ]]--
function SearchFrame:UpdateEvents()
self:UnregisterAllMessages()
self:RegisterMessage('TEXT_SEARCH_ENABLE')
self:RegisterMessage('TEXT_SEARCH_DISABLE')
--[[
if self:IsVisible() then
self:RegisterMessage('TEXT_SEARCH_UPDATE')
end
--]]
end
function SearchFrame:UpdateShown()
if self:IsSearchEnabled() then
if not self:IsShown() then
UIFrameFadeIn(self, 0.1)
end
else
self:Hide()
end
end
function SearchFrame:UpdateText()
self:SetText(self:GetSearch())
end
--[[ Propertiesish ]]--
function SearchFrame:SetFrameID(frameID)
if self:GetFrameID() ~= frameID then
self.frameID = frameID
self:UpdateShown()
self:UpdateText()
end
end
function SearchFrame:GetFrameID()
return self.frameID
end
--[[ Frame Settings ]]--
function SearchFrame:GetSettings()
return Bagnon.FrameSettings:Get(self:GetFrameID())
end
function SearchFrame:SetSearch(search)
Bagnon.Settings:SetTextSearch(search)
end
function SearchFrame:GetSearch()
return Bagnon.Settings:GetTextSearch()
end
function SearchFrame:GetLastSearch()
return Bagnon.Settings:GetLastTextSearch()
end
function SearchFrame:EnableSearch()
self:GetSettings():EnableTextSearch()
end
function SearchFrame:DisableSearch()
self:GetSettings():DisableTextSearch()
end
function SearchFrame:IsSearchEnabled()
return self:GetSettings():IsTextSearchEnabled()
end

View file

@ -0,0 +1,160 @@
--[[
searchToggle.lua
A searcn toggle widget
--]]
local Bagnon = LibStub('AceAddon-3.0'):GetAddon('Bagnon')
local L = LibStub('AceLocale-3.0'):GetLocale('Bagnon')
local SearchToggle = Bagnon.Classy:New('CheckButton')
Bagnon.SearchToggle = SearchToggle
local SIZE = 20
local NORMAL_TEXTURE_SIZE = 64 * (SIZE/36)
--[[ Constructor ]]--
function SearchToggle:New(frameID, parent)
local b = self:Bind(CreateFrame('CheckButton', nil, parent))
b:SetWidth(SIZE)
b:SetHeight(SIZE)
b:RegisterForClicks('anyUp')
local nt = b:CreateTexture()
nt:SetTexture([[Interface\Buttons\UI-Quickslot2]])
nt:SetWidth(NORMAL_TEXTURE_SIZE)
nt:SetHeight(NORMAL_TEXTURE_SIZE)
nt:SetPoint('CENTER', 0, -1)
b:SetNormalTexture(nt)
local pt = b:CreateTexture()
pt:SetTexture([[Interface\Buttons\UI-Quickslot-Depress]])
pt:SetAllPoints(b)
b:SetPushedTexture(pt)
local ht = b:CreateTexture()
ht:SetTexture([[Interface\Buttons\ButtonHilight-Square]])
ht:SetAllPoints(b)
b:SetHighlightTexture(ht)
local ct = b:CreateTexture()
ct:SetTexture([[Interface\Buttons\CheckButtonHilight]])
ct:SetAllPoints(b)
ct:SetBlendMode('ADD')
b:SetCheckedTexture(ct)
local icon = b:CreateTexture()
icon:SetAllPoints(b)
icon:SetTexture([[Interface\Icons\INV_Misc_Spyglass_03]])
b:SetScript('OnClick', b.OnClick)
b:SetScript('OnEnter', b.OnEnter)
b:SetScript('OnLeave', b.OnLeave)
b:SetScript('OnShow', b.OnShow)
b:SetScript('OnHide', b.OnHide)
b:SetFrameID(frameID)
return b
end
--[[ Messages ]]--
function SearchToggle:TEXT_SEARCH_ENABLE(msg, frameID)
if frameID == self:GetFrameID() then
self:Update()
end
end
function SearchToggle:TEXT_SEARCH_DISABLE(msg, frameID)
if frameID == self:GetFrameID() then
self:Update()
end
end
--[[ Frame Events ]]--
function SearchToggle:OnShow()
self:UpdateEvents()
self:Update()
end
function SearchToggle:OnHide()
self:UpdateEvents()
end
function SearchToggle:OnClick()
self:ToggleSearch()
end
function SearchToggle:OnEnter()
if self:GetRight() > (GetScreenWidth() / 2) then
GameTooltip:SetOwner(self, 'ANCHOR_LEFT')
else
GameTooltip:SetOwner(self, 'ANCHOR_RIGHT')
end
self:UpdateTooltip()
end
function SearchToggle:OnLeave()
if GameTooltip:IsOwned(self) then
GameTooltip:Hide()
end
end
--[[ Update Methods ]]--
function SearchToggle:Update()
if self:IsVisible() then
self:SetChecked(self:IsSearchEnabled())
end
end
function SearchToggle:UpdateEvents()
self:UnregisterAllMessages()
if self:IsVisible() then
self:RegisterMessage('TEXT_SEARCH_ENABLE')
self:RegisterMessage('TEXT_SEARCH_DISABLE')
end
end
function SearchToggle:UpdateTooltip()
if not GameTooltip:IsOwned(self) then return end
if self:IsSearchEnabled() then
GameTooltip:SetText(L.TipHideSearch)
else
GameTooltip:SetText(L.TipShowSearch)
end
end
--[[ Properties ]]--
function SearchToggle:SetFrameID(frameID)
if self:GetFrameID() ~= frameID then
self.frameID = frameID
self:UpdateEvents()
self:Update()
end
end
function SearchToggle:GetFrameID()
return self.frameID
end
function SearchToggle:GetSettings()
return Bagnon.FrameSettings:Get(self:GetFrameID())
end
function SearchToggle:ToggleSearch()
self:GetSettings():ToggleTextSearch()
end
function SearchToggle:IsSearchEnabled()
return self:GetSettings():IsTextSearchEnabled()
end

View file

@ -0,0 +1,214 @@
--[[
profileSettings.lua
Handles non specific frame settings
--]]
local Settings = {}
local Bagnon = LibStub('AceAddon-3.0'):GetAddon('Bagnon')
Bagnon.Settings = Settings
--[[---------------------------------------------------------------------------
Accessor Methods
--]]---------------------------------------------------------------------------
function Settings:GetDB()
return Bagnon.SavedSettings:GetDB()
end
--[[---------------------------------------------------------------------------
Message Passing
--]]---------------------------------------------------------------------------
function Settings:SendMessage(msg, ...)
Bagnon.Callbacks:SendMessage(msg, ...)
end
--[[---------------------------------------------------------------------------
Settings...Setting
--]]---------------------------------------------------------------------------
--highlight items by quality
function Settings:SetHighlightItemsByQuality(enable)
if self:HighlightingItemsByQuality() ~= enable then
self:GetDB().highlightItemsByQuality = enable
self:SendMessage('ITEM_HIGHLIGHT_QUALITY_UPDATE', enable)
end
end
function Settings:HighlightingItemsByQuality()
return self:GetDB().highlightItemsByQuality
end
--highlight quest items
function Settings:SetHighlightQuestItems(enable)
if self:HighlightingQuestItems() ~= enable then
self:GetDB().highlightQuestItems = enable
self:SendMessage('ITEM_HIGHLIGHT_QUEST_UPDATE', enable)
end
end
function Settings:HighlightingQuestItems()
return self:GetDB().highlightQuestItems
end
--highlight opacity
function Settings:SetHighlightOpacity(value)
local value = math.max(math.min(value, 1), 0)
if self:GetHighlightOpacity() ~= value then
self:GetDB().highlightOpacity = value
self:SendMessage('ITEM_HIGHLIGHT_OPACITY_UPDATE', value)
end
end
function Settings:GetHighlightOpacity()
return self:GetDB().highlightOpacity
end
--show empty item slots
function Settings:SetShowEmptyItemSlotTexture(enable)
if self:ShowingEmptyItemSlotTextures() ~= enable then
self:GetDB().showEmptyItemSlotTexture = enable
self:SendMessage('SHOW_EMPTY_ITEM_SLOT_TEXTURE_UPDATE', enable)
end
end
function Settings:ShowingEmptyItemSlotTextures()
return self:GetDB().showEmptyItemSlotTexture
end
--lock frame positions
function Settings:SetLockFramePositions(enable)
if self:AreFramePositionsLocked() ~= enable then
self:GetDB().lockFramePositions = enable
self:SendMessage('LOCK_FRAME_POSITIONS_UPDATE', enable)
end
end
function Settings:AreFramePositionsLocked()
return self:GetDB().lockFramePositions
end
--item slot coloring
function Settings:SetColorBagSlots(enable)
if self:ColoringBagSlots() ~= enable then
self:GetDB().colorBagSlots = enable
self:SendMessage('ITEM_SLOT_COLOR_ENABLED_UPDATE', enable)
end
end
function Settings:ColoringBagSlots()
return self:GetDB().colorBagSlots
end
function Settings:SetItemSlotColor(type, r, g, b)
local oR, oG, oB = self:GetItemSlotColor(type)
if not(oR == r and oG == g and oB == b) then
local slotColor = self:GetDB().slotColors[type]
slotColor[1] = r
slotColor[2] = g
slotColor[3] = b
self:SendMessage('ITEM_SLOT_COLOR_UPDATE', type, self:GetItemSlotColor(type))
end
end
function Settings:GetItemSlotColor(type)
local slotColor = self:GetDB().slotColors[type]
return unpack(slotColor)
end
--enable frames
function Settings:SetEnableFrame(frameID, enable)
local enable = enable and true or false
if self:WillFrameBeEnabled(frameID) ~= enable then
self.framesToEnable = self.framesToEnable or setmetatable({}, {__index = self:GetDB().enabledFrames})
self.framesToEnable[frameID] = enable and true or false
self:SendMessage('ENABLE_FRAME_UPDATE', frameID, self:WillFrameBeEnabled(frameID))
end
end
function Settings:IsFrameEnabled(frameID)
return self:GetDB().enabledFrames[frameID] and true or false
end
function Settings:WillFrameBeEnabled(frameID)
self.framesToEnable = self.framesToEnable or setmetatable({}, {__index = self:GetDB().enabledFrames})
return self.framesToEnable[frameID]
end
function Settings:AreAllFramesEnabled()
for frameID, isEnabled in pairs(self:GetDB().enabledFrames) do
if not isEnabled then
return false
end
end
return true
end
--automatic frame display
function Settings:SetShowFrameAtEvent(frameID, event, enable)
local enable = enable and true or false
if self:IsFrameShownAtEvent(frameID, event) ~= enable then
Bagnon.SavedSettings:SetShowFrameAtEvent(frameID, event, enable)
self:SendMessage('FRAME_DISPLAY_EVENT_UPDATE', frameID, event, self:IsFrameShownAtEvent(frameID, event))
end
end
function Settings:IsFrameShownAtEvent(frameID, event)
return Bagnon.SavedSettings:IsFrameShownAtEvent(frameID, event)
end
--blizzard bag passthrough
function Settings:SetEnableBlizzardBagPassThrough(enable)
local enable = enable and true or false
if self:WillBlizzardBagPassThroughBeEnabled() ~= enable then
self.enableBlizzardBagPassThrough = enable
self:SendMessage('BLIZZARD_BAG_PASSTHROUGH_UPDATE', self:WillBlizzardBagPassThroughBeEnabled())
end
end
function Settings:IsBlizzardBagPassThroughEnabled()
return self:GetDB().enableBlizzardBagPassThrough
end
function Settings:WillBlizzardBagPassThroughBeEnabled()
if self.enableBlizzardBagPassThrough == nil then
self.enableBlizzardBagPassThrough = self:IsBlizzardBagPassThroughEnabled()
end
return self.enableBlizzardBagPassThrough
end
--item searching
function Settings:SetTextSearch(search)
local lastSearch = self:GetTextSearch()
if lastSearch ~= search then
self.textSearch = search
self:SetLastTextSearch(lastSearch)
self:SendMessage('TEXT_SEARCH_UPDATE', self:GetTextSearch())
end
end
function Settings:GetTextSearch()
return self.textSearch or ''
end
function Settings:SetLastTextSearch(search)
if search and search ~= '' then
self.lastTextSearch = search
end
end
function Settings:GetLastTextSearch()
return self.lastTextSearch or ''
end

View file

@ -0,0 +1,99 @@
--[[
sortButton.lua
A style agnostic item sorting button
--]]
local Bagnon = LibStub('AceAddon-3.0'):GetAddon('Bagnon')
local L = LibStub('AceLocale-3.0'):GetLocale("Bagnon")
local SortButton = Bagnon.Classy:New('CheckButton')
Bagnon.SortButton = SortButton
local SIZE = 20
local NORMAL_TEXTURE_SIZE = 64 * (SIZE/36)
--[[ Construct ]]--
function SortButton:New(frameID, parent)
local b = self:Bind(CreateFrame('CheckButton', nil, parent))
b:SetWidth(SIZE)
b:SetHeight(SIZE)
b:RegisterForClicks('anyUp')
local nt = b:CreateTexture()
nt:SetTexture([[Interface\Buttons\UI-Quickslot2]])
nt:SetWidth(NORMAL_TEXTURE_SIZE)
nt:SetHeight(NORMAL_TEXTURE_SIZE)
nt:SetPoint('CENTER', 0, -1)
b:SetNormalTexture(nt)
local pt = b:CreateTexture()
pt:SetTexture([[Interface\Buttons\UI-Quickslot-Depress]])
pt:SetAllPoints(b)
b:SetPushedTexture(pt)
local ht = b:CreateTexture()
ht:SetTexture([[Interface\Buttons\ButtonHilight-Square]])
ht:SetAllPoints(b)
b:SetHighlightTexture(ht)
local ct = b:CreateTexture()
ct:SetTexture([[Interface\Buttons\CheckButtonHilight]])
ct:SetAllPoints(b)
ct:SetBlendMode('ADD')
b:SetCheckedTexture(ct)
local icon = b:CreateTexture()
icon:SetAllPoints(b)
icon:SetTexture([[Interface\AddOns\Bagnon\textures\Broom]])
b:SetScript('OnClick', b.OnClick)
b:SetScript('OnEnter', b.OnEnter)
b:SetScript('OnLeave', b.OnLeave)
b:SetFrameID(frameID)
return b
end
function SortButton:OnClick(button)
self:SetChecked(true)
self:RegisterMessage('SORTING_STATUS')
local frame = self:GetParent()
-- frame:IsCached ?
frame:SortItems()
end
function SortButton:OnEnter()
if self:GetRight() > (GetScreenWidth() / 2) then
GameTooltip:SetOwner(self, 'ANCHOR_LEFT')
else
GameTooltip:SetOwner(self, 'ANCHOR_RIGHT')
end
GameTooltip:SetText(L.TipCleanItems)
GameTooltip:Show()
end
function SortButton:OnLeave()
if GameTooltip:IsOwned(self) then
GameTooltip:Hide()
end
end
function SortButton:SORTING_STATUS()
self:SetChecked(nil)
self:UnregisterAllMessages()
end
--[[ Properties ]]--
function SortButton:SetFrameID(frameID)
if self:GetFrameID() ~= frameID then
self.frameID = frameID
end
end
function SortButton:GetFrameID()
return self.frameID
end

View file

@ -0,0 +1,175 @@
--[[
titleFrame.lua
A title frame widget
--]]
local Bagnon = LibStub('AceAddon-3.0'):GetAddon('Bagnon')
local L = LibStub('AceLocale-3.0'):GetLocale('Bagnon')
local TitleFrame = Bagnon.Classy:New('Button')
TitleFrame:Hide()
Bagnon.TitleFrame = TitleFrame
--[[ Constructor ]]--
function TitleFrame:New(frameID, parent)
local b = self:Bind(CreateFrame('Button', nil, parent))
b:SetToplevel(true)
b:SetTextFontObject('GameFontNormal')
b:SetHighlightFontObject('GameFontHighlight')
b:RegisterForClicks('anyUp')
b:SetScript('OnShow', b.OnShow)
b:SetScript('OnHide', b.OnHide)
b:SetScript('OnMouseDown', b.OnMouseDown)
b:SetScript('OnMouseUp', b.OnMouseUp)
b:SetScript('OnDoubleClick', b.OnDoubleClick)
b:SetScript('OnEnter', b.OnEnter)
b:SetScript('OnLeave', b.OnLeave)
b:SetScript('OnClick', b.OnClick)
b:SetFrameID(frameID)
b:UpdateEvents()
return b
end
--[[ Messages ]]--
function TitleFrame:PLAYER_UPDATE(msg, frameID, player)
if frameID == self:GetFrameID() then
self:UpdateText()
end
end
--[[ Frame Events ]]--
function TitleFrame:OnShow()
self:UpdateText()
self:UpdateEvents()
end
function TitleFrame:OnHide()
self:StopMovingFrame()
end
function TitleFrame:OnMouseDown()
if self:IsFrameMovable() or IsAltKeyDown() then
self:StartMovingFrame()
end
end
function TitleFrame:OnMouseUp()
self:StopMovingFrame()
end
function TitleFrame:OnDoubleClick()
self:ToggleSearchFrame()
end
function TitleFrame:OnClick(button)
if button == 'RightButton' then
if LoadAddOn('Bagnon_Config') then
Bagnon.FrameOptions:ShowFrame(self:GetFrameID())
end
end
end
function TitleFrame:OnEnter()
if self:GetRight() > (GetScreenWidth() / 2) then
GameTooltip:SetOwner(self, 'ANCHOR_LEFT')
else
GameTooltip:SetOwner(self, 'ANCHOR_RIGHT')
end
self:UpdateTooltip()
end
function TitleFrame:OnLeave()
if GameTooltip:IsOwned(self) then
GameTooltip:Hide()
end
end
--[[ Update Methods ]]--
function TitleFrame:UpdateText()
self:SetFormattedText(self:GetTitleText(), self:GetPlayer())
self:GetFontString():SetAllPoints(self)
end
function TitleFrame:UpdateTooltip()
GameTooltip:SetText(L.TipDoubleClickSearch)
GameTooltip:Show()
end
function TitleFrame:UpdateEvents()
self:UnregisterAllMessages()
if self:IsVisible() then
self:RegisterMessage('PLAYER_UPDATE')
end
end
function TitleFrame:StartMovingFrame()
self:SendMessage('FRAME_MOVE_START', self:GetFrameID())
end
function TitleFrame:StopMovingFrame()
self:SendMessage('FRAME_MOVE_STOP', self:GetFrameID())
end
--[[ Properties ]]--
function TitleFrame:SetFrameID(frameID)
if self:GetFrameID() ~= frameID then
self.frameID = frameID
self:UpdateText()
end
end
function TitleFrame:GetFrameID()
return self.frameID
end
--yeah, still hardcoded
function TitleFrame:GetTitleText()
if self:GetFrameID() == 'bank' then
return L.TitleBank
end
if self:GetFrameID() == 'keys' then
return L.TitleKeys
end
if self:GetFrameID() == 'guildbank' then
return [[%s's Guild Bank]]
end
return L.TitleBags
end
--[[ Frame Settings ]]--
function TitleFrame:GetSettings()
return Bagnon.FrameSettings:Get(self:GetFrameID())
end
function TitleFrame:GetPlayer()
return self:GetSettings():GetPlayerFilter()
end
function TitleFrame:IsFrameMovable()
return self:GetSettings():IsMovable()
end
function TitleFrame:ToggleSearchFrame()
self:GetSettings():ToggleTextSearch()
end

12
Bagnon/embeds.xml Normal file
View file

@ -0,0 +1,12 @@
<Ui xmlns="http://www.blizzard.com/wow/ui/">
<Script file="libs\LibStub\LibStub.lua"/>
<Include file="libs\AceAddon-3.0\AceAddon-3.0.xml"/>
<Include file="libs\CallbackHandler-1.0\CallbackHandler-1.0.xml"/>
<Include file="libs\AceEvent-3.0\AceEvent-3.0.xml"/>
<Include file="libs\AceConsole-3.0\AceConsole-3.0.xml"/>
<Include file="libs\AceLocale-3.0\AceLocale-3.0.xml"/>
<Include file="libs\AceTimer-3.0\AceTimer-3.0.xml"/>
<Script file="libs\LibDataBroker-1.1.lua"/>
<Script file="libs\LibItemSearch-1.0\LibItemSearch-1.0.lua"/>
</Ui>

View file

@ -0,0 +1,642 @@
--- **AceAddon-3.0** provides a template for creating addon objects.
-- It'll provide you with a set of callback functions that allow you to simplify the loading
-- process of your addon.\\
-- Callbacks provided are:\\
-- * **OnInitialize**, which is called directly after the addon is fully loaded.
-- * **OnEnable** which gets called during the PLAYER_LOGIN event, when most of the data provided by the game is already present.
-- * **OnDisable**, which is only called when your addon is manually being disabled.
-- @usage
-- -- A small (but complete) addon, that doesn't do anything,
-- -- but shows usage of the callbacks.
-- local MyAddon = LibStub("AceAddon-3.0"):NewAddon("MyAddon")
--
-- function MyAddon:OnInitialize()
-- -- do init tasks here, like loading the Saved Variables,
-- -- or setting up slash commands.
-- end
--
-- function MyAddon:OnEnable()
-- -- Do more initialization here, that really enables the use of your addon.
-- -- Register Events, Hook functions, Create Frames, Get information from
-- -- the game that wasn't available in OnInitialize
-- end
--
-- function MyAddon:OnDisable()
-- -- Unhook, Unregister Events, Hide frames that you created.
-- -- You would probably only use an OnDisable if you want to
-- -- build a "standby" mode, or be able to toggle modules on/off.
-- end
-- @class file
-- @name AceAddon-3.0.lua
-- @release $Id: AceAddon-3.0.lua 895 2009-12-06 16:28:55Z nevcairiel $
local MAJOR, MINOR = "AceAddon-3.0", 5
local AceAddon, oldminor = LibStub:NewLibrary(MAJOR, MINOR)
if not AceAddon then return end -- No Upgrade needed.
AceAddon.frame = AceAddon.frame or CreateFrame("Frame", "AceAddon30Frame") -- Our very own frame
AceAddon.addons = AceAddon.addons or {} -- addons in general
AceAddon.statuses = AceAddon.statuses or {} -- statuses of addon.
AceAddon.initializequeue = AceAddon.initializequeue or {} -- addons that are new and not initialized
AceAddon.enablequeue = AceAddon.enablequeue or {} -- addons that are initialized and waiting to be enabled
AceAddon.embeds = AceAddon.embeds or setmetatable({}, {__index = function(tbl, key) tbl[key] = {} return tbl[key] end }) -- contains a list of libraries embedded in an addon
-- Lua APIs
local tinsert, tconcat, tremove = table.insert, table.concat, table.remove
local fmt, tostring = string.format, tostring
local select, pairs, next, type, unpack = select, pairs, next, type, unpack
local loadstring, assert, error = loadstring, assert, error
local setmetatable, getmetatable, rawset, rawget = setmetatable, getmetatable, rawset, rawget
-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
-- List them here for Mikk's FindGlobals script
-- GLOBALS: LibStub, IsLoggedIn, geterrorhandler
--[[
xpcall safecall implementation
]]
local xpcall = xpcall
local function errorhandler(err)
return geterrorhandler()(err)
end
local function CreateDispatcher(argCount)
local code = [[
local xpcall, eh = ...
local method, ARGS
local function call() return method(ARGS) end
local function dispatch(func, ...)
method = func
if not method then return end
ARGS = ...
return xpcall(call, eh)
end
return dispatch
]]
local ARGS = {}
for i = 1, argCount do ARGS[i] = "arg"..i end
code = code:gsub("ARGS", tconcat(ARGS, ", "))
return assert(loadstring(code, "safecall Dispatcher["..argCount.."]"))(xpcall, errorhandler)
end
local Dispatchers = setmetatable({}, {__index=function(self, argCount)
local dispatcher = CreateDispatcher(argCount)
rawset(self, argCount, dispatcher)
return dispatcher
end})
Dispatchers[0] = function(func)
return xpcall(func, errorhandler)
end
local function safecall(func, ...)
-- we check to see if the func is passed is actually a function here and don't error when it isn't
-- this safecall is used for optional functions like OnInitialize OnEnable etc. When they are not
-- present execution should continue without hinderance
if type(func) == "function" then
return Dispatchers[select('#', ...)](func, ...)
end
end
-- local functions that will be implemented further down
local Enable, Disable, EnableModule, DisableModule, Embed, NewModule, GetModule, GetName, SetDefaultModuleState, SetDefaultModuleLibraries, SetEnabledState, SetDefaultModulePrototype
-- used in the addon metatable
local function addontostring( self ) return self.name end
--- Create a new AceAddon-3.0 addon.
-- Any libraries you specified will be embeded, and the addon will be scheduled for
-- its OnInitialize and OnEnable callbacks.
-- The final addon object, with all libraries embeded, will be returned.
-- @paramsig [object ,]name[, lib, ...]
-- @param object Table to use as a base for the addon (optional)
-- @param name Name of the addon object to create
-- @param lib List of libraries to embed into the addon
-- @usage
-- -- Create a simple addon object
-- MyAddon = LibStub("AceAddon-3.0"):NewAddon("MyAddon", "AceEvent-3.0")
--
-- -- Create a Addon object based on the table of a frame
-- local MyFrame = CreateFrame("Frame")
-- MyAddon = LibStub("AceAddon-3.0"):NewAddon(MyFrame, "MyAddon", "AceEvent-3.0")
function AceAddon:NewAddon(objectorname, ...)
local object,name
local i=1
if type(objectorname)=="table" then
object=objectorname
name=...
i=2
else
name=objectorname
end
if type(name)~="string" then
error(("Usage: NewAddon([object,] name, [lib, lib, lib, ...]): 'name' - string expected got '%s'."):format(type(name)), 2)
end
if self.addons[name] then
error(("Usage: NewAddon([object,] name, [lib, lib, lib, ...]): 'name' - Addon '%s' already exists."):format(name), 2)
end
object = object or {}
object.name = name
local addonmeta = {}
local oldmeta = getmetatable(object)
if oldmeta then
for k, v in pairs(oldmeta) do addonmeta[k] = v end
end
addonmeta.__tostring = addontostring
setmetatable( object, addonmeta )
self.addons[name] = object
object.modules = {}
object.defaultModuleLibraries = {}
Embed( object ) -- embed NewModule, GetModule methods
self:EmbedLibraries(object, select(i,...))
-- add to queue of addons to be initialized upon ADDON_LOADED
tinsert(self.initializequeue, object)
return object
end
--- Get the addon object by its name from the internal AceAddon registry.
-- Throws an error if the addon object cannot be found (except if silent is set).
-- @param name unique name of the addon object
-- @param silent if true, the addon is optional, silently return nil if its not found
-- @usage
-- -- Get the Addon
-- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon")
function AceAddon:GetAddon(name, silent)
if not silent and not self.addons[name] then
error(("Usage: GetAddon(name): 'name' - Cannot find an AceAddon '%s'."):format(tostring(name)), 2)
end
return self.addons[name]
end
-- - Embed a list of libraries into the specified addon.
-- This function will try to embed all of the listed libraries into the addon
-- and error if a single one fails.
--
-- **Note:** This function is for internal use by :NewAddon/:NewModule
-- @paramsig addon, [lib, ...]
-- @param addon addon object to embed the libs in
-- @param lib List of libraries to embed into the addon
function AceAddon:EmbedLibraries(addon, ...)
for i=1,select("#", ... ) do
local libname = select(i, ...)
self:EmbedLibrary(addon, libname, false, 4)
end
end
-- - Embed a library into the addon object.
-- This function will check if the specified library is registered with LibStub
-- and if it has a :Embed function to call. It'll error if any of those conditions
-- fails.
--
-- **Note:** This function is for internal use by :EmbedLibraries
-- @paramsig addon, libname[, silent[, offset]]
-- @param addon addon object to embed the library in
-- @param libname name of the library to embed
-- @param silent marks an embed to fail silently if the library doesn't exist (optional)
-- @param offset will push the error messages back to said offset, defaults to 2 (optional)
function AceAddon:EmbedLibrary(addon, libname, silent, offset)
local lib = LibStub:GetLibrary(libname, true)
if not lib and not silent then
error(("Usage: EmbedLibrary(addon, libname, silent, offset): 'libname' - Cannot find a library instance of %q."):format(tostring(libname)), offset or 2)
elseif lib and type(lib.Embed) == "function" then
lib:Embed(addon)
tinsert(self.embeds[addon], libname)
return true
elseif lib then
error(("Usage: EmbedLibrary(addon, libname, silent, offset): 'libname' - Library '%s' is not Embed capable"):format(libname), offset or 2)
end
end
--- Return the specified module from an addon object.
-- Throws an error if the addon object cannot be found (except if silent is set)
-- @name //addon//:GetModule
-- @paramsig name[, silent]
-- @param name unique name of the module
-- @param silent if true, the module is optional, silently return nil if its not found (optional)
-- @usage
-- -- Get the Addon
-- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon")
-- -- Get the Module
-- MyModule = MyAddon:GetModule("MyModule")
function GetModule(self, name, silent)
if not self.modules[name] and not silent then
error(("Usage: GetModule(name, silent): 'name' - Cannot find module '%s'."):format(tostring(name)), 2)
end
return self.modules[name]
end
local function IsModuleTrue(self) return true end
--- Create a new module for the addon.
-- The new module can have its own embeded libraries and/or use a module prototype to be mixed into the module.\\
-- A module has the same functionality as a real addon, it can have modules of its own, and has the same API as
-- an addon object.
-- @name //addon//:NewModule
-- @paramsig name[, prototype|lib[, lib, ...]]
-- @param name unique name of the module
-- @param prototype object to derive this module from, methods and values from this table will be mixed into the module (optional)
-- @param lib List of libraries to embed into the addon
-- @usage
-- -- Create a module with some embeded libraries
-- MyModule = MyAddon:NewModule("MyModule", "AceEvent-3.0", "AceHook-3.0")
--
-- -- Create a module with a prototype
-- local prototype = { OnEnable = function(self) print("OnEnable called!") end }
-- MyModule = MyAddon:NewModule("MyModule", prototype, "AceEvent-3.0", "AceHook-3.0")
function NewModule(self, name, prototype, ...)
if type(name) ~= "string" then error(("Usage: NewModule(name, [prototype, [lib, lib, lib, ...]): 'name' - string expected got '%s'."):format(type(name)), 2) end
if type(prototype) ~= "string" and type(prototype) ~= "table" and type(prototype) ~= "nil" then error(("Usage: NewModule(name, [prototype, [lib, lib, lib, ...]): 'prototype' - table (prototype), string (lib) or nil expected got '%s'."):format(type(prototype)), 2) end
if self.modules[name] then error(("Usage: NewModule(name, [prototype, [lib, lib, lib, ...]): 'name' - Module '%s' already exists."):format(name), 2) end
-- modules are basically addons. We treat them as such. They will be added to the initializequeue properly as well.
-- NewModule can only be called after the parent addon is present thus the modules will be initialized after their parent is.
local module = AceAddon:NewAddon(fmt("%s_%s", self.name or tostring(self), name))
module.IsModule = IsModuleTrue
module:SetEnabledState(self.defaultModuleState)
module.moduleName = name
if type(prototype) == "string" then
AceAddon:EmbedLibraries(module, prototype, ...)
else
AceAddon:EmbedLibraries(module, ...)
end
AceAddon:EmbedLibraries(module, unpack(self.defaultModuleLibraries))
if not prototype or type(prototype) == "string" then
prototype = self.defaultModulePrototype or nil
end
if type(prototype) == "table" then
local mt = getmetatable(module)
mt.__index = prototype
setmetatable(module, mt) -- More of a Base class type feel.
end
safecall(self.OnModuleCreated, self, module) -- Was in Ace2 and I think it could be a cool thing to have handy.
self.modules[name] = module
return module
end
--- Returns the real name of the addon or module, without any prefix.
-- @name //addon//:GetName
-- @paramsig
-- @usage
-- print(MyAddon:GetName())
-- -- prints "MyAddon"
function GetName(self)
return self.moduleName or self.name
end
--- Enables the Addon, if possible, return true or false depending on success.
-- This internally calls AceAddon:EnableAddon(), thus dispatching a OnEnable callback
-- and enabling all modules of the addon (unless explicitly disabled).\\
-- :Enable() also sets the internal `enableState` variable to true
-- @name //addon//:Enable
-- @paramsig
-- @usage
-- -- Enable MyModule
-- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon")
-- MyModule = MyAddon:GetModule("MyModule")
-- MyModule:Enable()
function Enable(self)
self:SetEnabledState(true)
return AceAddon:EnableAddon(self)
end
--- Disables the Addon, if possible, return true or false depending on success.
-- This internally calls AceAddon:DisableAddon(), thus dispatching a OnDisable callback
-- and disabling all modules of the addon.\\
-- :Disable() also sets the internal `enableState` variable to false
-- @name //addon//:Disable
-- @paramsig
-- @usage
-- -- Disable MyAddon
-- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon")
-- MyAddon:Disable()
function Disable(self)
self:SetEnabledState(false)
return AceAddon:DisableAddon(self)
end
--- Enables the Module, if possible, return true or false depending on success.
-- Short-hand function that retrieves the module via `:GetModule` and calls `:Enable` on the module object.
-- @name //addon//:EnableModule
-- @paramsig name
-- @usage
-- -- Enable MyModule using :GetModule
-- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon")
-- MyModule = MyAddon:GetModule("MyModule")
-- MyModule:Enable()
--
-- -- Enable MyModule using the short-hand
-- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon")
-- MyAddon:EnableModule("MyModule")
function EnableModule(self, name)
local module = self:GetModule( name )
return module:Enable()
end
--- Disables the Module, if possible, return true or false depending on success.
-- Short-hand function that retrieves the module via `:GetModule` and calls `:Disable` on the module object.
-- @name //addon//:DisableModule
-- @paramsig name
-- @usage
-- -- Disable MyModule using :GetModule
-- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon")
-- MyModule = MyAddon:GetModule("MyModule")
-- MyModule:Disable()
--
-- -- Disable MyModule using the short-hand
-- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon")
-- MyAddon:DisableModule("MyModule")
function DisableModule(self, name)
local module = self:GetModule( name )
return module:Disable()
end
--- Set the default libraries to be mixed into all modules created by this object.
-- Note that you can only change the default module libraries before any module is created.
-- @name //addon//:SetDefaultModuleLibraries
-- @paramsig lib[, lib, ...]
-- @param lib List of libraries to embed into the addon
-- @usage
-- -- Create the addon object
-- MyAddon = LibStub("AceAddon-3.0"):NewAddon("MyAddon")
-- -- Configure default libraries for modules (all modules need AceEvent-3.0)
-- MyAddon:SetDefaultModuleLibraries("AceEvent-3.0")
-- -- Create a module
-- MyModule = MyAddon:NewModule("MyModule")
function SetDefaultModuleLibraries(self, ...)
if next(self.modules) then
error("Usage: SetDefaultModuleLibraries(...): cannot change the module defaults after a module has been registered.", 2)
end
self.defaultModuleLibraries = {...}
end
--- Set the default state in which new modules are being created.
-- Note that you can only change the default state before any module is created.
-- @name //addon//:SetDefaultModuleState
-- @paramsig state
-- @param state Default state for new modules, true for enabled, false for disabled
-- @usage
-- -- Create the addon object
-- MyAddon = LibStub("AceAddon-3.0"):NewAddon("MyAddon")
-- -- Set the default state to "disabled"
-- MyAddon:SetDefaultModuleState(false)
-- -- Create a module and explicilty enable it
-- MyModule = MyAddon:NewModule("MyModule")
-- MyModule:Enable()
function SetDefaultModuleState(self, state)
if next(self.modules) then
error("Usage: SetDefaultModuleState(state): cannot change the module defaults after a module has been registered.", 2)
end
self.defaultModuleState = state
end
--- Set the default prototype to use for new modules on creation.
-- Note that you can only change the default prototype before any module is created.
-- @name //addon//:SetDefaultModulePrototype
-- @paramsig prototype
-- @param prototype Default prototype for the new modules (table)
-- @usage
-- -- Define a prototype
-- local prototype = { OnEnable = function(self) print("OnEnable called!") end }
-- -- Set the default prototype
-- MyAddon:SetDefaultModulePrototype(prototype)
-- -- Create a module and explicitly Enable it
-- MyModule = MyAddon:NewModule("MyModule")
-- MyModule:Enable()
-- -- should print "OnEnable called!" now
-- @see NewModule
function SetDefaultModulePrototype(self, prototype)
if next(self.modules) then
error("Usage: SetDefaultModulePrototype(prototype): cannot change the module defaults after a module has been registered.", 2)
end
if type(prototype) ~= "table" then
error(("Usage: SetDefaultModulePrototype(prototype): 'prototype' - table expected got '%s'."):format(type(prototype)), 2)
end
self.defaultModulePrototype = prototype
end
--- Set the state of an addon or module
-- This should only be called before any enabling actually happend, e.g. in/before OnInitialize.
-- @name //addon//:SetEnabledState
-- @paramsig state
-- @param state the state of an addon or module (enabled=true, disabled=false)
function SetEnabledState(self, state)
self.enabledState = state
end
--- Return an iterator of all modules associated to the addon.
-- @name //addon//:IterateModules
-- @paramsig
-- @usage
-- -- Enable all modules
-- for name, module in MyAddon:IterateModules() do
-- module:Enable()
-- end
local function IterateModules(self) return pairs(self.modules) end
-- Returns an iterator of all embeds in the addon
-- @name //addon//:IterateEmbeds
-- @paramsig
local function IterateEmbeds(self) return pairs(AceAddon.embeds[self]) end
--- Query the enabledState of an addon.
-- @name //addon//:IsEnabled
-- @paramsig
-- @usage
-- if MyAddon:IsEnabled() then
-- MyAddon:Disable()
-- end
local function IsEnabled(self) return self.enabledState end
local mixins = {
NewModule = NewModule,
GetModule = GetModule,
Enable = Enable,
Disable = Disable,
EnableModule = EnableModule,
DisableModule = DisableModule,
IsEnabled = IsEnabled,
SetDefaultModuleLibraries = SetDefaultModuleLibraries,
SetDefaultModuleState = SetDefaultModuleState,
SetDefaultModulePrototype = SetDefaultModulePrototype,
SetEnabledState = SetEnabledState,
IterateModules = IterateModules,
IterateEmbeds = IterateEmbeds,
GetName = GetName,
}
local function IsModule(self) return false end
local pmixins = {
defaultModuleState = true,
enabledState = true,
IsModule = IsModule,
}
-- Embed( target )
-- target (object) - target object to embed aceaddon in
--
-- this is a local function specifically since it's meant to be only called internally
function Embed(target)
for k, v in pairs(mixins) do
target[k] = v
end
for k, v in pairs(pmixins) do
target[k] = target[k] or v
end
end
-- - Initialize the addon after creation.
-- This function is only used internally during the ADDON_LOADED event
-- It will call the **OnInitialize** function on the addon object (if present),
-- and the **OnEmbedInitialize** function on all embeded libraries.
--
-- **Note:** Do not call this function manually, unless you're absolutely sure that you know what you are doing.
-- @param addon addon object to intialize
function AceAddon:InitializeAddon(addon)
safecall(addon.OnInitialize, addon)
local embeds = self.embeds[addon]
for i = 1, #embeds do
local lib = LibStub:GetLibrary(embeds[i], true)
if lib then safecall(lib.OnEmbedInitialize, lib, addon) end
end
-- we don't call InitializeAddon on modules specifically, this is handled
-- from the event handler and only done _once_
end
-- - Enable the addon after creation.
-- Note: This function is only used internally during the PLAYER_LOGIN event, or during ADDON_LOADED,
-- if IsLoggedIn() already returns true at that point, e.g. for LoD Addons.
-- It will call the **OnEnable** function on the addon object (if present),
-- and the **OnEmbedEnable** function on all embeded libraries.\\
-- This function does not toggle the enable state of the addon itself, and will return early if the addon is disabled.
--
-- **Note:** Do not call this function manually, unless you're absolutely sure that you know what you are doing.
-- Use :Enable on the addon itself instead.
-- @param addon addon object to enable
function AceAddon:EnableAddon(addon)
if type(addon) == "string" then addon = AceAddon:GetAddon(addon) end
if self.statuses[addon.name] or not addon.enabledState then return false end
-- set the statuses first, before calling the OnEnable. this allows for Disabling of the addon in OnEnable.
self.statuses[addon.name] = true
safecall(addon.OnEnable, addon)
-- make sure we're still enabled before continueing
if self.statuses[addon.name] then
local embeds = self.embeds[addon]
for i = 1, #embeds do
local lib = LibStub:GetLibrary(embeds[i], true)
if lib then safecall(lib.OnEmbedEnable, lib, addon) end
end
-- enable possible modules.
for name, module in pairs(addon.modules) do
self:EnableAddon(module)
end
end
return self.statuses[addon.name] -- return true if we're disabled
end
-- - Disable the addon
-- Note: This function is only used internally.
-- It will call the **OnDisable** function on the addon object (if present),
-- and the **OnEmbedDisable** function on all embeded libraries.\\
-- This function does not toggle the enable state of the addon itself, and will return early if the addon is still enabled.
--
-- **Note:** Do not call this function manually, unless you're absolutely sure that you know what you are doing.
-- Use :Disable on the addon itself instead.
-- @param addon addon object to enable
function AceAddon:DisableAddon(addon)
if type(addon) == "string" then addon = AceAddon:GetAddon(addon) end
if not self.statuses[addon.name] then return false end
-- set statuses first before calling OnDisable, this allows for aborting the disable in OnDisable.
self.statuses[addon.name] = false
safecall( addon.OnDisable, addon )
-- make sure we're still disabling...
if not self.statuses[addon.name] then
local embeds = self.embeds[addon]
for i = 1, #embeds do
local lib = LibStub:GetLibrary(embeds[i], true)
if lib then safecall(lib.OnEmbedDisable, lib, addon) end
end
-- disable possible modules.
for name, module in pairs(addon.modules) do
self:DisableAddon(module)
end
end
return not self.statuses[addon.name] -- return true if we're disabled
end
--- Get an iterator over all registered addons.
-- @usage
-- -- Print a list of all installed AceAddon's
-- for name, addon in AceAddon:IterateAddons() do
-- print("Addon: " .. name)
-- end
function AceAddon:IterateAddons() return pairs(self.addons) end
--- Get an iterator over the internal status registry.
-- @usage
-- -- Print a list of all enabled addons
-- for name, status in AceAddon:IterateAddonStatus() do
-- if status then
-- print("EnabledAddon: " .. name)
-- end
-- end
function AceAddon:IterateAddonStatus() return pairs(self.statuses) end
-- Following Iterators are deprecated, and their addon specific versions should be used
-- e.g. addon:IterateEmbeds() instead of :IterateEmbedsOnAddon(addon)
function AceAddon:IterateEmbedsOnAddon(addon) return pairs(self.embeds[addon]) end
function AceAddon:IterateModulesOfAddon(addon) return pairs(addon.modules) end
-- Event Handling
local function onEvent(this, event, arg1)
if event == "ADDON_LOADED" or event == "PLAYER_LOGIN" then
-- if a addon loads another addon, recursion could happen here, so we need to validate the table on every iteration
while(#AceAddon.initializequeue > 0) do
local addon = tremove(AceAddon.initializequeue, 1)
-- this might be an issue with recursion - TODO: validate
if event == "ADDON_LOADED" then addon.baseName = arg1 end
AceAddon:InitializeAddon(addon)
tinsert(AceAddon.enablequeue, addon)
end
if IsLoggedIn() then
while(#AceAddon.enablequeue > 0) do
local addon = tremove(AceAddon.enablequeue, 1)
AceAddon:EnableAddon(addon)
end
end
end
end
AceAddon.frame:RegisterEvent("ADDON_LOADED")
AceAddon.frame:RegisterEvent("PLAYER_LOGIN")
AceAddon.frame:SetScript("OnEvent", onEvent)
-- upgrade embeded
for name, addon in pairs(AceAddon.addons) do
Embed(addon)
end

View file

@ -0,0 +1,4 @@
<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/
..\FrameXML\UI.xsd">
<Script file="AceAddon-3.0.lua"/>
</Ui>

View file

@ -0,0 +1,250 @@
--- **AceConsole-3.0** provides registration facilities for slash commands.
-- You can register slash commands to your custom functions and use the `GetArgs` function to parse them
-- to your addons individual needs.
--
-- **AceConsole-3.0** can be embeded into your addon, either explicitly by calling AceConsole:Embed(MyAddon) or by
-- specifying it as an embeded library in your AceAddon. All functions will be available on your addon object
-- and can be accessed directly, without having to explicitly call AceConsole itself.\\
-- It is recommended to embed AceConsole, otherwise you'll have to specify a custom `self` on all calls you
-- make into AceConsole.
-- @class file
-- @name AceConsole-3.0
-- @release $Id: AceConsole-3.0.lua 878 2009-11-02 18:51:58Z nevcairiel $
local MAJOR,MINOR = "AceConsole-3.0", 7
local AceConsole, oldminor = LibStub:NewLibrary(MAJOR, MINOR)
if not AceConsole then return end -- No upgrade needed
AceConsole.embeds = AceConsole.embeds or {} -- table containing objects AceConsole is embedded in.
AceConsole.commands = AceConsole.commands or {} -- table containing commands registered
AceConsole.weakcommands = AceConsole.weakcommands or {} -- table containing self, command => func references for weak commands that don't persist through enable/disable
-- Lua APIs
local tconcat, tostring, select = table.concat, tostring, select
local type, pairs, error = type, pairs, error
local format, strfind, strsub = string.format, string.find, string.sub
local max = math.max
-- WoW APIs
local _G = _G
-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
-- List them here for Mikk's FindGlobals script
-- GLOBALS: DEFAULT_CHAT_FRAME, SlashCmdList, hash_SlashCmdList
local tmp={}
local function Print(self,frame,...)
local n=0
if self ~= AceConsole then
n=n+1
tmp[n] = "|cff33ff99"..tostring( self ).."|r:"
end
for i=1, select("#", ...) do
n=n+1
tmp[n] = tostring(select(i, ...))
end
frame:AddMessage( tconcat(tmp," ",1,n) )
end
--- Print to DEFAULT_CHAT_FRAME or given ChatFrame (anything with an .AddMessage function)
-- @paramsig [chatframe ,] ...
-- @param chatframe Custom ChatFrame to print to (or any frame with an .AddMessage function)
-- @param ... List of any values to be printed
function AceConsole:Print(...)
local frame = ...
if type(frame) == "table" and frame.AddMessage then -- Is first argument something with an .AddMessage member?
return Print(self, frame, select(2,...))
else
return Print(self, DEFAULT_CHAT_FRAME, ...)
end
end
--- Formatted (using format()) print to DEFAULT_CHAT_FRAME or given ChatFrame (anything with an .AddMessage function)
-- @paramsig [chatframe ,] "format"[, ...]
-- @param chatframe Custom ChatFrame to print to (or any frame with an .AddMessage function)
-- @param format Format string - same syntax as standard Lua format()
-- @param ... Arguments to the format string
function AceConsole:Printf(...)
local frame = ...
if type(frame) == "table" and frame.AddMessage then -- Is first argument something with an .AddMessage member?
return Print(self, frame, format(select(2,...)))
else
return Print(self, DEFAULT_CHAT_FRAME, format(...))
end
end
--- Register a simple chat command
-- @param command Chat command to be registered WITHOUT leading "/"
-- @param func Function to call when the slash command is being used (funcref or methodname)
-- @param persist if false, the command will be soft disabled/enabled when aceconsole is used as a mixin (default: true)
function AceConsole:RegisterChatCommand( command, func, persist )
if type(command)~="string" then error([[Usage: AceConsole:RegisterChatCommand( "command", func[, persist ]): 'command' - expected a string]], 2) end
if persist==nil then persist=true end -- I'd rather have my addon's "/addon enable" around if the author screws up. Having some extra slash regged when it shouldnt be isn't as destructive. True is a better default. /Mikk
local name = "ACECONSOLE_"..command:upper()
if type( func ) == "string" then
SlashCmdList[name] = function(input, editBox)
self[func](self, input, editBox)
end
else
SlashCmdList[name] = func
end
_G["SLASH_"..name.."1"] = "/"..command:lower()
AceConsole.commands[command] = name
-- non-persisting commands are registered for enabling disabling
if not persist then
if not AceConsole.weakcommands[self] then AceConsole.weakcommands[self] = {} end
AceConsole.weakcommands[self][command] = func
end
return true
end
--- Unregister a chatcommand
-- @param command Chat command to be unregistered WITHOUT leading "/"
function AceConsole:UnregisterChatCommand( command )
local name = AceConsole.commands[command]
if name then
SlashCmdList[name] = nil
_G["SLASH_" .. name .. "1"] = nil
hash_SlashCmdList["/" .. command:upper()] = nil
AceConsole.commands[command] = nil
end
end
--- Get an iterator over all Chat Commands registered with AceConsole
-- @return Iterator (pairs) over all commands
function AceConsole:IterateChatCommands() return pairs(AceConsole.commands) end
local function nils(n, ...)
if n>1 then
return nil, nils(n-1, ...)
elseif n==1 then
return nil, ...
else
return ...
end
end
--- Retreive one or more space-separated arguments from a string.
-- Treats quoted strings and itemlinks as non-spaced.
-- @param string The raw argument string
-- @param numargs How many arguments to get (default 1)
-- @param startpos Where in the string to start scanning (default 1)
-- @return Returns arg1, arg2, ..., nextposition\\
-- Missing arguments will be returned as nils. 'nextposition' is returned as 1e9 at the end of the string.
function AceConsole:GetArgs(str, numargs, startpos)
numargs = numargs or 1
startpos = max(startpos or 1, 1)
local pos=startpos
-- find start of new arg
pos = strfind(str, "[^ ]", pos)
if not pos then -- whoops, end of string
return nils(numargs, 1e9)
end
if numargs<1 then
return pos
end
-- quoted or space separated? find out which pattern to use
local delim_or_pipe
local ch = strsub(str, pos, pos)
if ch=='"' then
pos = pos + 1
delim_or_pipe='([|"])'
elseif ch=="'" then
pos = pos + 1
delim_or_pipe="([|'])"
else
delim_or_pipe="([| ])"
end
startpos = pos
while true do
-- find delimiter or hyperlink
local ch,_
pos,_,ch = strfind(str, delim_or_pipe, pos)
if not pos then break end
if ch=="|" then
-- some kind of escape
if strsub(str,pos,pos+1)=="|H" then
-- It's a |H....|hhyper link!|h
pos=strfind(str, "|h", pos+2) -- first |h
if not pos then break end
pos=strfind(str, "|h", pos+2) -- second |h
if not pos then break end
elseif strsub(str,pos, pos+1) == "|T" then
-- It's a |T....|t texture
pos=strfind(str, "|t", pos+2)
if not pos then break end
end
pos=pos+2 -- skip past this escape (last |h if it was a hyperlink)
else
-- found delimiter, done with this arg
return strsub(str, startpos, pos-1), AceConsole:GetArgs(str, numargs-1, pos+1)
end
end
-- search aborted, we hit end of string. return it all as one argument. (yes, even if it's an unterminated quote or hyperlink)
return strsub(str, startpos), nils(numargs-1, 1e9)
end
--- embedding and embed handling
local mixins = {
"Print",
"Printf",
"RegisterChatCommand",
"UnregisterChatCommand",
"GetArgs",
}
-- Embeds AceConsole into the target object making the functions from the mixins list available on target:..
-- @param target target object to embed AceBucket in
function AceConsole:Embed( target )
for k, v in pairs( mixins ) do
target[v] = self[v]
end
self.embeds[target] = true
return target
end
function AceConsole:OnEmbedEnable( target )
if AceConsole.weakcommands[target] then
for command, func in pairs( AceConsole.weakcommands[target] ) do
target:RegisterChatCommand( command, func, false, true ) -- nonpersisting and silent registry
end
end
end
function AceConsole:OnEmbedDisable( target )
if AceConsole.weakcommands[target] then
for command, func in pairs( AceConsole.weakcommands[target] ) do
target:UnregisterChatCommand( command ) -- TODO: this could potentially unregister a command from another application in case of command conflicts. Do we care?
end
end
end
for addon in pairs(AceConsole.embeds) do
AceConsole:Embed(addon)
end

View file

@ -0,0 +1,4 @@
<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/
..\FrameXML\UI.xsd">
<Script file="AceConsole-3.0.lua"/>
</Ui>

View file

@ -0,0 +1,126 @@
--- AceEvent-3.0 provides event registration and secure dispatching.
-- All dispatching is done using **CallbackHandler-1.0**. AceEvent is a simple wrapper around
-- CallbackHandler, and dispatches all game events or addon message to the registrees.
--
-- **AceEvent-3.0** can be embeded into your addon, either explicitly by calling AceEvent:Embed(MyAddon) or by
-- specifying it as an embeded library in your AceAddon. All functions will be available on your addon object
-- and can be accessed directly, without having to explicitly call AceEvent itself.\\
-- It is recommended to embed AceEvent, otherwise you'll have to specify a custom `self` on all calls you
-- make into AceEvent.
-- @class file
-- @name AceEvent-3.0
-- @release $Id: AceEvent-3.0.lua 877 2009-11-02 15:56:50Z nevcairiel $
local MAJOR, MINOR = "AceEvent-3.0", 3
local AceEvent = LibStub:NewLibrary(MAJOR, MINOR)
if not AceEvent then return end
-- Lua APIs
local pairs = pairs
local CallbackHandler = LibStub:GetLibrary("CallbackHandler-1.0")
AceEvent.frame = AceEvent.frame or CreateFrame("Frame", "AceEvent30Frame") -- our event frame
AceEvent.embeds = AceEvent.embeds or {} -- what objects embed this lib
-- APIs and registry for blizzard events, using CallbackHandler lib
if not AceEvent.events then
AceEvent.events = CallbackHandler:New(AceEvent,
"RegisterEvent", "UnregisterEvent", "UnregisterAllEvents")
end
function AceEvent.events:OnUsed(target, eventname)
AceEvent.frame:RegisterEvent(eventname)
end
function AceEvent.events:OnUnused(target, eventname)
AceEvent.frame:UnregisterEvent(eventname)
end
-- APIs and registry for IPC messages, using CallbackHandler lib
if not AceEvent.messages then
AceEvent.messages = CallbackHandler:New(AceEvent,
"RegisterMessage", "UnregisterMessage", "UnregisterAllMessages"
)
AceEvent.SendMessage = AceEvent.messages.Fire
end
--- embedding and embed handling
local mixins = {
"RegisterEvent", "UnregisterEvent",
"RegisterMessage", "UnregisterMessage",
"SendMessage",
"UnregisterAllEvents", "UnregisterAllMessages",
}
--- Register for a Blizzard Event.
-- The callback will always be called with the event as the first argument, and if supplied, the `arg` as second argument.
-- Any arguments to the event will be passed on after that.
-- @name AceEvent:RegisterEvent
-- @class function
-- @paramsig event[, callback [, arg]]
-- @param event The event to register for
-- @param callback The callback function to call when the event is triggered (funcref or method, defaults to a method with the event name)
-- @param arg An optional argument to pass to the callback function
--- Unregister an event.
-- @name AceEvent:UnregisterEvent
-- @class function
-- @paramsig event
-- @param event The event to unregister
--- Register for a custom AceEvent-internal message.
-- The callback will always be called with the event as the first argument, and if supplied, the `arg` as second argument.
-- Any arguments to the event will be passed on after that.
-- @name AceEvent:RegisterMessage
-- @class function
-- @paramsig message[, callback [, arg]]
-- @param message The message to register for
-- @param callback The callback function to call when the message is triggered (funcref or method, defaults to a method with the event name)
-- @param arg An optional argument to pass to the callback function
--- Unregister a message
-- @name AceEvent:UnregisterMessage
-- @class function
-- @paramsig message
-- @param message The message to unregister
--- Send a message over the AceEvent-3.0 internal message system to other addons registered for this message.
-- @name AceEvent:SendMessage
-- @class function
-- @paramsig message, ...
-- @param message The message to send
-- @param ... Any arguments to the message
-- Embeds AceEvent into the target object making the functions from the mixins list available on target:..
-- @param target target object to embed AceEvent in
function AceEvent:Embed(target)
for k, v in pairs(mixins) do
target[v] = self[v]
end
self.embeds[target] = true
return target
end
-- AceEvent:OnEmbedDisable( target )
-- target (object) - target object that is being disabled
--
-- Unregister all events messages etc when the target disables.
-- this method should be called by the target manually or by an addon framework
function AceEvent:OnEmbedDisable(target)
target:UnregisterAllEvents()
target:UnregisterAllMessages()
end
-- Script to fire blizzard events into the event listeners
local events = AceEvent.events
AceEvent.frame:SetScript("OnEvent", function(this, event, ...)
events:Fire(event, ...)
end)
--- Finally: upgrade our old embeds
for target, v in pairs(AceEvent.embeds) do
AceEvent:Embed(target)
end

View file

@ -0,0 +1,4 @@
<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/
..\FrameXML\UI.xsd">
<Script file="AceEvent-3.0.lua"/>
</Ui>

View file

@ -0,0 +1,136 @@
--- **AceLocale-3.0** manages localization in addons, allowing for multiple locale to be registered with fallback to the base locale for untranslated strings.
-- @class file
-- @name AceLocale-3.0
-- @release $Id: AceLocale-3.0.lua 895 2009-12-06 16:28:55Z nevcairiel $
local MAJOR,MINOR = "AceLocale-3.0", 2
local AceLocale, oldminor = LibStub:NewLibrary(MAJOR, MINOR)
if not AceLocale then return end -- no upgrade needed
-- Lua APIs
local assert, tostring, error = assert, tostring, error
local setmetatable, rawset, rawget = setmetatable, rawset, rawget
-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
-- List them here for Mikk's FindGlobals script
-- GLOBALS: GAME_LOCALE, geterrorhandler
local gameLocale = GetLocale()
if gameLocale == "enGB" then
gameLocale = "enUS"
end
AceLocale.apps = AceLocale.apps or {} -- array of ["AppName"]=localetableref
AceLocale.appnames = AceLocale.appnames or {} -- array of [localetableref]="AppName"
-- This metatable is used on all tables returned from GetLocale
local readmeta = {
__index = function(self, key) -- requesting totally unknown entries: fire off a nonbreaking error and return key
rawset(self, key, key) -- only need to see the warning once, really
geterrorhandler()(MAJOR..": "..tostring(AceLocale.appnames[self])..": Missing entry for '"..tostring(key).."'")
return key
end
}
-- This metatable is used on all tables returned from GetLocale if the silent flag is true, it does not issue a warning on unknown keys
local readmetasilent = {
__index = function(self, key) -- requesting totally unknown entries: return key
rawset(self, key, key) -- only need to invoke this function once
return key
end
}
-- Remember the locale table being registered right now (it gets set by :NewLocale())
-- NOTE: Do never try to register 2 locale tables at once and mix their definition.
local registering
-- local assert false function
local assertfalse = function() assert(false) end
-- This metatable proxy is used when registering nondefault locales
local writeproxy = setmetatable({}, {
__newindex = function(self, key, value)
rawset(registering, key, value == true and key or value) -- assigning values: replace 'true' with key string
end,
__index = assertfalse
})
-- This metatable proxy is used when registering the default locale.
-- It refuses to overwrite existing values
-- Reason 1: Allows loading locales in any order
-- Reason 2: If 2 modules have the same string, but only the first one to be
-- loaded has a translation for the current locale, the translation
-- doesn't get overwritten.
--
local writedefaultproxy = setmetatable({}, {
__newindex = function(self, key, value)
if not rawget(registering, key) then
rawset(registering, key, value == true and key or value)
end
end,
__index = assertfalse
})
--- Register a new locale (or extend an existing one) for the specified application.
-- :NewLocale will return a table you can fill your locale into, or nil if the locale isn't needed for the players
-- game locale.
-- @paramsig application, locale[, isDefault[, silent]]
-- @param application Unique name of addon / module
-- @param locale Name of the locale to register, e.g. "enUS", "deDE", etc.
-- @param isDefault If this is the default locale being registered (your addon is written in this language, generally enUS)
-- @param silent If true, the locale will not issue warnings for missing keys. Can only be set on the default locale.
-- @usage
-- -- enUS.lua
-- local L = LibStub("AceLocale-3.0"):NewLocale("TestLocale", "enUS", true)
-- L["string1"] = true
--
-- -- deDE.lua
-- local L = LibStub("AceLocale-3.0"):NewLocale("TestLocale", "deDE")
-- if not L then return end
-- L["string1"] = "Zeichenkette1"
-- @return Locale Table to add localizations to, or nil if the current locale is not required.
function AceLocale:NewLocale(application, locale, isDefault, silent)
if silent and not isDefault then
error("Usage: NewLocale(application, locale[, isDefault[, silent]]): 'silent' can only be specified for the default locale", 2)
end
-- GAME_LOCALE allows translators to test translations of addons without having that wow client installed
-- Ammo: I still think this is a bad idea, for instance an addon that checks for some ingame string will fail, just because some other addon
-- gives the user the illusion that they can run in a different locale? Ditch this whole thing or allow a setting per 'application'. I'm of the
-- opinion to remove this.
local gameLocale = GAME_LOCALE or gameLocale
if locale ~= gameLocale and not isDefault then
return -- nop, we don't need these translations
end
local app = AceLocale.apps[application]
if not app then
app = setmetatable({}, silent and readmetasilent or readmeta)
AceLocale.apps[application] = app
AceLocale.appnames[app] = application
end
registering = app -- remember globally for writeproxy and writedefaultproxy
if isDefault then
return writedefaultproxy
end
return writeproxy
end
--- Returns localizations for the current locale (or default locale if translations are missing).
-- Errors if nothing is registered (spank developer, not just a missing translation)
-- @param application Unique name of addon / module
-- @param silent If true, the locale is optional, silently return nil if it's not found (defaults to false, optional)
-- @return The locale table for the current language.
function AceLocale:GetLocale(application, silent)
if not silent and not AceLocale.apps[application] then
error("Usage: GetLocale(application[, silent]): 'application' - No locales registered for '"..tostring(application).."'", 2)
end
return AceLocale.apps[application]
end

View file

@ -0,0 +1,4 @@
<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/
..\FrameXML\UI.xsd">
<Script file="AceLocale-3.0.lua"/>
</Ui>

View file

@ -0,0 +1,327 @@
--- **AceTimer-3.0** provides a central facility for registering timers.
-- AceTimer supports one-shot timers and repeating timers. All timers are stored in an efficient
-- data structure that allows easy dispatching and fast rescheduling. Timers can be registered
-- or canceled at any time, even from within a running timer, without conflict or large overhead.\\
-- AceTimer is currently limited to firing timers at a frequency of 0.01s.
--
-- All `:Schedule` functions will return a handle to the current timer, which you will need to store if you
-- need to cancel the timer you just registered.
--
-- **AceTimer-3.0** can be embeded into your addon, either explicitly by calling AceTimer:Embed(MyAddon) or by
-- specifying it as an embeded library in your AceAddon. All functions will be available on your addon object
-- and can be accessed directly, without having to explicitly call AceTimer itself.\\
-- It is recommended to embed AceTimer, otherwise you'll have to specify a custom `self` on all calls you
-- make into AceTimer.
-- @class file
-- @name AceTimer-3.0
-- @release $Id$
local MAJOR, MINOR = "AceTimer-3.0", 1017 -- Bump minor on changes
local AceTimer, oldminor = LibStub:NewLibrary(MAJOR, MINOR)
if not AceTimer then return end -- No upgrade needed
AceTimer.frame = AceTimer.frame or CreateFrame("Frame", "AceTimer30Frame")
AceTimer.activeTimers = AceTimer.activeTimers or {} -- Active timer list
local activeTimers = AceTimer.activeTimers -- Upvalue our private data
-- Lua APIs
local assert, loadstring, rawset, tconcat = assert, loadstring, rawset, table.concat
local type, unpack, next, error, select = type, unpack, next, error, select
-- WoW APIs
local GetTime = GetTime
--[[
xpcall safecall implementation
]]
local xpcall = xpcall
local function errorhandler(err)
return geterrorhandler()(err)
end
local function CreateDispatcher(argCount)
local code = [[
local xpcall, eh = ...
local method, ARGS
local function call() return method(ARGS) end
local function dispatch(func, ...)
method = func
if not method then return end
ARGS = ...
return xpcall(call, eh)
end
return dispatch
]]
local ARGS = {}
for i = 1, argCount do ARGS[i] = "arg"..i end
code = code:gsub("ARGS", tconcat(ARGS, ", "))
return assert(loadstring(code, "safecall Dispatcher["..argCount.."]"))(xpcall, errorhandler)
end
local Dispatchers = setmetatable({}, {__index=function(self, argCount)
local dispatcher = CreateDispatcher(argCount)
rawset(self, argCount, dispatcher)
return dispatcher
end})
Dispatchers[0] = function(func)
return xpcall(func, errorhandler)
end
local function safecall(func, ...)
return Dispatchers[select("#", ...)](func, ...)
end
local function new(self, loop, func, delay, ...)
if delay < 0.01 then
delay = 0.01 -- Restrict to the lowest time
end
local timer = {
object = self,
func = func,
looping = loop,
argsCount = select("#", ...),
delay = delay,
timeleft = delay,
ends = GetTime() + delay,
...
}
activeTimers[timer] = timer
return timer
end
--- Schedule a new one-shot timer.
-- The timer will fire once in `delay` seconds, unless canceled before.
-- @param callback Callback function for the timer pulse (funcref or method name).
-- @param delay Delay for the timer, in seconds.
-- @param ... An optional, unlimited amount of arguments to pass to the callback function.
-- @usage
-- MyAddOn = LibStub("AceAddon-3.0"):NewAddon("MyAddOn", "AceTimer-3.0")
--
-- function MyAddOn:OnEnable()
-- self:ScheduleTimer("TimerFeedback", 5)
-- end
--
-- function MyAddOn:TimerFeedback()
-- print("5 seconds passed")
-- end
function AceTimer:ScheduleTimer(func, delay, ...)
if not func or not delay then
error(MAJOR..": ScheduleTimer(callback, delay, args...): 'callback' and 'delay' must have set values.", 2)
end
if type(func) == "string" then
if type(self) ~= "table" then
error(MAJOR..": ScheduleTimer(callback, delay, args...): 'self' - must be a table.", 2)
elseif not self[func] then
error(MAJOR..": ScheduleTimer(callback, delay, args...): Tried to register '"..func.."' as the callback, but it doesn't exist in the module.", 2)
end
end
return new(self, nil, func, delay, ...)
end
--- Schedule a repeating timer.
-- The timer will fire every `delay` seconds, until canceled.
-- @param callback Callback function for the timer pulse (funcref or method name).
-- @param delay Delay for the timer, in seconds.
-- @param ... An optional, unlimited amount of arguments to pass to the callback function.
-- @usage
-- MyAddOn = LibStub("AceAddon-3.0"):NewAddon("MyAddOn", "AceTimer-3.0")
--
-- function MyAddOn:OnEnable()
-- self.timerCount = 0
-- self.testTimer = self:ScheduleRepeatingTimer("TimerFeedback", 5)
-- end
--
-- function MyAddOn:TimerFeedback()
-- self.timerCount = self.timerCount + 1
-- print(("%d seconds passed"):format(5 * self.timerCount))
-- -- run 30 seconds in total
-- if self.timerCount == 6 then
-- self:CancelTimer(self.testTimer)
-- end
-- end
function AceTimer:ScheduleRepeatingTimer(func, delay, ...)
if not func or not delay then
error(MAJOR..": ScheduleRepeatingTimer(callback, delay, args...): 'callback' and 'delay' must have set values.", 2)
end
if type(func) == "string" then
if type(self) ~= "table" then
error(MAJOR..": ScheduleRepeatingTimer(callback, delay, args...): 'self' - must be a table.", 2)
elseif not self[func] then
error(MAJOR..": ScheduleRepeatingTimer(callback, delay, args...): Tried to register '"..func.."' as the callback, but it doesn't exist in the module.", 2)
end
end
return new(self, true, func, delay, ...)
end
--- Cancels a timer with the given id, registered by the same addon object as used for `:ScheduleTimer`
-- Both one-shot and repeating timers can be canceled with this function, as long as the `id` is valid
-- and the timer has not fired yet or was canceled before.
-- @param id The id of the timer, as returned by `:ScheduleTimer` or `:ScheduleRepeatingTimer`
function AceTimer:CancelTimer(id)
local timer = activeTimers[id]
if not timer then
return false
else
timer.cancelled = true
activeTimers[id] = nil
return true
end
end
--- Cancels all timers registered to the current addon object ('self')
function AceTimer:CancelAllTimers()
for k,v in next, activeTimers do
if v.object == self then
AceTimer.CancelTimer(self, k)
end
end
end
--- Returns the time left for a timer with the given id, registered by the current addon object ('self').
-- This function will return 0 when the id is invalid.
-- @param id The id of the timer, as returned by `:ScheduleTimer` or `:ScheduleRepeatingTimer`
-- @return The time left on the timer.
function AceTimer:TimeLeft(id)
local timer = activeTimers[id]
if not timer then
return
else
return timer.ends - GetTime()
end
end
-- ---------------------------------------------------------------------
-- Upgrading
-- Upgrade from old hash-bucket based timers to C_Timer.After timers.
if oldminor and oldminor < 10 then
-- disable old timer logic
AceTimer.frame:SetScript("OnUpdate", nil)
AceTimer.frame:SetScript("OnEvent", nil)
AceTimer.frame:UnregisterAllEvents()
-- convert timers
for object,timers in next, AceTimer.selfs do
for handle,timer in next, timers do
if type(timer) == "table" and timer.callback then
local newTimer
if timer.delay then
newTimer = AceTimer.ScheduleRepeatingTimer(timer.object, timer.callback, timer.delay, timer.arg)
else
newTimer = AceTimer.ScheduleTimer(timer.object, timer.callback, timer.when - GetTime(), timer.arg)
end
-- Use the old handle for old timers
activeTimers[newTimer] = nil
activeTimers[handle] = newTimer
newTimer.handle = handle
end
end
end
AceTimer.selfs = nil
AceTimer.hash = nil
AceTimer.debug = nil
elseif oldminor and oldminor < 17 then
-- Upgrade from old animation based timers to C_Timer.After timers.
AceTimer.inactiveTimers = nil
local oldTimers = AceTimer.activeTimers
-- Clear old timer table and update upvalue
AceTimer.activeTimers = {}
activeTimers = AceTimer.activeTimers
for handle, timer in next, oldTimers do
local newTimer
-- Stop the old timer animation
local duration, elapsed = timer:GetDuration(), timer:GetElapsed()
timer:GetParent():Stop()
if timer.looping then
newTimer = AceTimer.ScheduleRepeatingTimer(timer.object, timer.func, duration, unpack(timer.args, 1, timer.argsCount))
else
newTimer = AceTimer.ScheduleTimer(timer.object, timer.func, duration - elapsed, unpack(timer.args, 1, timer.argsCount))
end
-- Use the old handle for old timers
activeTimers[newTimer] = nil
activeTimers[handle] = newTimer
newTimer.handle = handle
end
-- Migrate transitional handles
if oldminor < 13 and AceTimer.hashCompatTable then
for handle, id in next, AceTimer.hashCompatTable do
local t = activeTimers[id]
if t then
activeTimers[id] = nil
activeTimers[handle] = t
t.handle = handle
end
end
AceTimer.hashCompatTable = nil
end
end
-- ---------------------------------------------------------------------
-- Embed handling
AceTimer.embeds = AceTimer.embeds or {}
local mixins = {
"ScheduleTimer", "ScheduleRepeatingTimer",
"CancelTimer", "CancelAllTimers",
"TimeLeft"
}
function AceTimer:Embed(target)
AceTimer.embeds[target] = true
for _,v in next, mixins do
target[v] = AceTimer[v]
end
return target
end
-- AceTimer:OnEmbedDisable(target)
-- target (object) - target object that AceTimer is embedded in.
--
-- cancel all timers registered for the object
function AceTimer:OnEmbedDisable(target)
target:CancelAllTimers()
end
for addon in next, AceTimer.embeds do
AceTimer:Embed(addon)
end
AceTimer.frame:SetScript("OnUpdate", function(self, elapsed)
for _, timer in next, activeTimers do
if not timer.cancelled then
if timer.timeleft > elapsed then
timer.timeleft = timer.timeleft - elapsed
else
if type(timer.func) == "string" then
-- We manually set the unpack count to prevent issues with an arg set that contains nil and ends with nil
-- e.g. local t = {1, 2, nil, 3, nil} print(#t) will result in 2, instead of 5. This fixes said issue.
safecall(timer.object[timer.func], timer.object, unpack(timer, 1, timer.argsCount))
else
safecall(timer.func, unpack(timer, 1, timer.argsCount))
end
if timer.looping and not timer.cancelled then
-- Compensate delay to get a perfect average delay, even if individual times don't match up perfectly
-- due to fps differences
local time = GetTime()
local delay = timer.delay - (time - timer.ends)
-- Ensure the delay doesn't go below the threshold
if delay < 0.01 then delay = 0.01 end
timer.ends = time + delay
timer.timeleft = timer.delay
else
activeTimers[timer.handle or timer] = nil
end
end
end
end
end)

View file

@ -0,0 +1,4 @@
<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/
..\FrameXML\UI.xsd">
<Script file="AceTimer-3.0.lua"/>
</Ui>

View file

@ -0,0 +1,240 @@
--[[ $Id: CallbackHandler-1.0.lua 895 2009-12-06 16:28:55Z nevcairiel $ ]]
local MAJOR, MINOR = "CallbackHandler-1.0", 5
local CallbackHandler = LibStub:NewLibrary(MAJOR, MINOR)
if not CallbackHandler then return end -- No upgrade needed
local meta = {__index = function(tbl, key) tbl[key] = {} return tbl[key] end}
-- Lua APIs
local tconcat = table.concat
local assert, error, loadstring = assert, error, loadstring
local setmetatable, rawset, rawget = setmetatable, rawset, rawget
local next, select, pairs, type, tostring = next, select, pairs, type, tostring
-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
-- List them here for Mikk's FindGlobals script
-- GLOBALS: geterrorhandler
local xpcall = xpcall
local function errorhandler(err)
return geterrorhandler()(err)
end
local function CreateDispatcher(argCount)
local code = [[
local next, xpcall, eh = ...
local method, ARGS
local function call() method(ARGS) end
local function dispatch(handlers, ...)
local index
index, method = next(handlers)
if not method then return end
local OLD_ARGS = ARGS
ARGS = ...
repeat
xpcall(call, eh)
index, method = next(handlers, index)
until not method
ARGS = OLD_ARGS
end
return dispatch
]]
local ARGS, OLD_ARGS = {}, {}
for i = 1, argCount do ARGS[i], OLD_ARGS[i] = "arg"..i, "old_arg"..i end
code = code:gsub("OLD_ARGS", tconcat(OLD_ARGS, ", ")):gsub("ARGS", tconcat(ARGS, ", "))
return assert(loadstring(code, "safecall Dispatcher["..argCount.."]"))(next, xpcall, errorhandler)
end
local Dispatchers = setmetatable({}, {__index=function(self, argCount)
local dispatcher = CreateDispatcher(argCount)
rawset(self, argCount, dispatcher)
return dispatcher
end})
--------------------------------------------------------------------------
-- CallbackHandler:New
--
-- target - target object to embed public APIs in
-- RegisterName - name of the callback registration API, default "RegisterCallback"
-- UnregisterName - name of the callback unregistration API, default "UnregisterCallback"
-- UnregisterAllName - name of the API to unregister all callbacks, default "UnregisterAllCallbacks". false == don't publish this API.
function CallbackHandler:New(target, RegisterName, UnregisterName, UnregisterAllName, OnUsed, OnUnused)
-- TODO: Remove this after beta has gone out
assert(not OnUsed and not OnUnused, "ACE-80: OnUsed/OnUnused are deprecated. Callbacks are now done to registry.OnUsed and registry.OnUnused")
RegisterName = RegisterName or "RegisterCallback"
UnregisterName = UnregisterName or "UnregisterCallback"
if UnregisterAllName==nil then -- false is used to indicate "don't want this method"
UnregisterAllName = "UnregisterAllCallbacks"
end
-- we declare all objects and exported APIs inside this closure to quickly gain access
-- to e.g. function names, the "target" parameter, etc
-- Create the registry object
local events = setmetatable({}, meta)
local registry = { recurse=0, events=events }
-- registry:Fire() - fires the given event/message into the registry
function registry:Fire(eventname, ...)
if not rawget(events, eventname) or not next(events[eventname]) then return end
local oldrecurse = registry.recurse
registry.recurse = oldrecurse + 1
Dispatchers[select('#', ...) + 1](events[eventname], eventname, ...)
registry.recurse = oldrecurse
if registry.insertQueue and oldrecurse==0 then
-- Something in one of our callbacks wanted to register more callbacks; they got queued
for eventname,callbacks in pairs(registry.insertQueue) do
local first = not rawget(events, eventname) or not next(events[eventname]) -- test for empty before. not test for one member after. that one member may have been overwritten.
for self,func in pairs(callbacks) do
events[eventname][self] = func
-- fire OnUsed callback?
if first and registry.OnUsed then
registry.OnUsed(registry, target, eventname)
first = nil
end
end
end
registry.insertQueue = nil
end
end
-- Registration of a callback, handles:
-- self["method"], leads to self["method"](self, ...)
-- self with function ref, leads to functionref(...)
-- "addonId" (instead of self) with function ref, leads to functionref(...)
-- all with an optional arg, which, if present, gets passed as first argument (after self if present)
target[RegisterName] = function(self, eventname, method, ... --[[actually just a single arg]])
if type(eventname) ~= "string" then
error("Usage: "..RegisterName.."(eventname, method[, arg]): 'eventname' - string expected.", 2)
end
method = method or eventname
local first = not rawget(events, eventname) or not next(events[eventname]) -- test for empty before. not test for one member after. that one member may have been overwritten.
if type(method) ~= "string" and type(method) ~= "function" then
error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): 'methodname' - string or function expected.", 2)
end
local regfunc
if type(method) == "string" then
-- self["method"] calling style
if type(self) ~= "table" then
error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): self was not a table?", 2)
elseif self==target then
error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): do not use Library:"..RegisterName.."(), use your own 'self'", 2)
elseif type(self[method]) ~= "function" then
error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): 'methodname' - method '"..tostring(method).."' not found on self.", 2)
end
if select("#",...)>=1 then -- this is not the same as testing for arg==nil!
local arg=select(1,...)
regfunc = function(...) self[method](self,arg,...) end
else
regfunc = function(...) self[method](self,...) end
end
else
-- function ref with self=object or self="addonId"
if type(self)~="table" and type(self)~="string" then
error("Usage: "..RegisterName.."(self or \"addonId\", eventname, method): 'self or addonId': table or string expected.", 2)
end
if select("#",...)>=1 then -- this is not the same as testing for arg==nil!
local arg=select(1,...)
regfunc = function(...) method(arg,...) end
else
regfunc = method
end
end
if events[eventname][self] or registry.recurse<1 then
-- if registry.recurse<1 then
-- we're overwriting an existing entry, or not currently recursing. just set it.
events[eventname][self] = regfunc
-- fire OnUsed callback?
if registry.OnUsed and first then
registry.OnUsed(registry, target, eventname)
end
else
-- we're currently processing a callback in this registry, so delay the registration of this new entry!
-- yes, we're a bit wasteful on garbage, but this is a fringe case, so we're picking low implementation overhead over garbage efficiency
registry.insertQueue = registry.insertQueue or setmetatable({},meta)
registry.insertQueue[eventname][self] = regfunc
end
end
-- Unregister a callback
target[UnregisterName] = function(self, eventname)
if not self or self==target then
error("Usage: "..UnregisterName.."(eventname): bad 'self'", 2)
end
if type(eventname) ~= "string" then
error("Usage: "..UnregisterName.."(eventname): 'eventname' - string expected.", 2)
end
if rawget(events, eventname) and events[eventname][self] then
events[eventname][self] = nil
-- Fire OnUnused callback?
if registry.OnUnused and not next(events[eventname]) then
registry.OnUnused(registry, target, eventname)
end
end
if registry.insertQueue and rawget(registry.insertQueue, eventname) and registry.insertQueue[eventname][self] then
registry.insertQueue[eventname][self] = nil
end
end
-- OPTIONAL: Unregister all callbacks for given selfs/addonIds
if UnregisterAllName then
target[UnregisterAllName] = function(...)
if select("#",...)<1 then
error("Usage: "..UnregisterAllName.."([whatFor]): missing 'self' or \"addonId\" to unregister events for.", 2)
end
if select("#",...)==1 and ...==target then
error("Usage: "..UnregisterAllName.."([whatFor]): supply a meaningful 'self' or \"addonId\"", 2)
end
for i=1,select("#",...) do
local self = select(i,...)
if registry.insertQueue then
for eventname, callbacks in pairs(registry.insertQueue) do
if callbacks[self] then
callbacks[self] = nil
end
end
end
for eventname, callbacks in pairs(events) do
if callbacks[self] then
callbacks[self] = nil
-- Fire OnUnused callback?
if registry.OnUnused and not next(callbacks) then
registry.OnUnused(registry, target, eventname)
end
end
end
end
end
end
return registry
end
-- CallbackHandler purposefully does NOT do explicit embedding. Nor does it
-- try to upgrade old implicit embeds since the system is selfcontained and
-- relies on closures to work.

View file

@ -0,0 +1,4 @@
<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/
..\FrameXML\UI.xsd">
<Script file="CallbackHandler-1.0.lua"/>
</Ui>

View file

@ -0,0 +1,90 @@
assert(LibStub, "LibDataBroker-1.1 requires LibStub")
assert(LibStub:GetLibrary("CallbackHandler-1.0", true), "LibDataBroker-1.1 requires CallbackHandler-1.0")
local lib, oldminor = LibStub:NewLibrary("LibDataBroker-1.1", 4)
if not lib then return end
oldminor = oldminor or 0
lib.callbacks = lib.callbacks or LibStub:GetLibrary("CallbackHandler-1.0"):New(lib)
lib.attributestorage, lib.namestorage, lib.proxystorage = lib.attributestorage or {}, lib.namestorage or {}, lib.proxystorage or {}
local attributestorage, namestorage, callbacks = lib.attributestorage, lib.namestorage, lib.callbacks
if oldminor < 2 then
lib.domt = {
__metatable = "access denied",
__index = function(self, key) return attributestorage[self] and attributestorage[self][key] end,
}
end
if oldminor < 3 then
lib.domt.__newindex = function(self, key, value)
if not attributestorage[self] then attributestorage[self] = {} end
if attributestorage[self][key] == value then return end
attributestorage[self][key] = value
local name = namestorage[self]
if not name then return end
callbacks:Fire("LibDataBroker_AttributeChanged", name, key, value, self)
callbacks:Fire("LibDataBroker_AttributeChanged_"..name, name, key, value, self)
callbacks:Fire("LibDataBroker_AttributeChanged_"..name.."_"..key, name, key, value, self)
callbacks:Fire("LibDataBroker_AttributeChanged__"..key, name, key, value, self)
end
end
if oldminor < 2 then
function lib:NewDataObject(name, dataobj)
if self.proxystorage[name] then return end
if dataobj then
assert(type(dataobj) == "table", "Invalid dataobj, must be nil or a table")
self.attributestorage[dataobj] = {}
for i,v in pairs(dataobj) do
self.attributestorage[dataobj][i] = v
dataobj[i] = nil
end
end
dataobj = setmetatable(dataobj or {}, self.domt)
self.proxystorage[name], self.namestorage[dataobj] = dataobj, name
self.callbacks:Fire("LibDataBroker_DataObjectCreated", name, dataobj)
return dataobj
end
end
if oldminor < 1 then
function lib:DataObjectIterator()
return pairs(self.proxystorage)
end
function lib:GetDataObjectByName(dataobjectname)
return self.proxystorage[dataobjectname]
end
function lib:GetNameByDataObject(dataobject)
return self.namestorage[dataobject]
end
end
if oldminor < 4 then
local next = pairs(attributestorage)
function lib:pairs(dataobject_or_name)
local t = type(dataobject_or_name)
assert(t == "string" or t == "table", "Usage: ldb:pairs('dataobjectname') or ldb:pairs(dataobject)")
local dataobj = self.proxystorage[dataobject_or_name] or dataobject_or_name
assert(attributestorage[dataobj], "Data object not found")
return next, attributestorage[dataobj], nil
end
local ipairs_iter = ipairs(attributestorage)
function lib:ipairs(dataobject_or_name)
local t = type(dataobject_or_name)
assert(t == "string" or t == "table", "Usage: ldb:ipairs('dataobjectname') or ldb:ipairs(dataobject)")
local dataobj = self.proxystorage[dataobject_or_name] or dataobject_or_name
assert(attributestorage[dataobj], "Data object not found")
return ipairs_iter, attributestorage[dataobj], 0
end
end

View file

@ -0,0 +1,417 @@
--[[
ItemSearch
An item text search engine of some sort
Grammar:
<search> := <intersect search>
<intersect search> := <union search> & <union search> ; <union search>
<union search> := <negatable search> | <negatable search> ; <negatable search>
<negatable search> := !<primitive search> ; <primitive search>
<primitive search> := <tooltip search> ; <quality search> ; <type search> ; <text search>
<tooltip search> := bop ; boa ; bou ; boe ; quest
<quality search> := q<op><text> ; q<op><digit>
<ilvl search> := ilvl<op><number>
<type search> := t:<text>
<text search> := <text>
<op> := : | = | == | != | ~= | < | > | <= | >=
I kindof half want to make a full parser for this
--]]
local MAJOR, MINOR = "LibItemSearch-1.0", 2
local ItemSearch = LibStub:NewLibrary(MAJOR, MINOR)
if not ItemSearch then return end
--[[ general search ]]--
function ItemSearch:Find(itemLink, search)
if not search then
return true
end
if not itemLink then
return false
end
local search = search:lower()
if search:match('\124') then
return self:FindUnionSearch(itemLink, strsplit('\124', search))
end
return self:FindUnionSearch(itemLink, search)
end
--[[ union search: <search>&<search> ]]--
function ItemSearch:FindUnionSearch(itemLink, ...)
for i = 1, select('#', ...) do
local search = select(i, ...)
if search and search ~= '' then
if search:match('\038') then
if self:FindIntersectSearch(itemLink, strsplit('\038', search)) then
return true
end
else
if self:FindIntersectSearch(itemLink, search) then
return true
end
end
end
end
return false
end
--[[ intersect search: <search>|<search> ]]--
function ItemSearch:FindIntersectSearch(itemLink, ...)
for i = 1, select('#', ...) do
local search = select(i, ...)
if search and search ~= '' then
if not self:FindNegatableSearch(itemLink, search) then
return false
end
end
end
return true
end
--[[ negated search: !<search> ]]--
function ItemSearch:FindNegatableSearch(itemLink, search)
local negatedSearch = search:match('^\033(.+)$')
if negatedSearch then
return not self:FindTypedSearch(itemLink, negatedSearch)
end
return self:FindTypedSearch(itemLink, search)
end
--[[
typed search:
user defined search types
A typed search object should look like the following:
{
string id
unique identifier for the search type,
string searchCapture = function isSearch(self, search)
returns a capture if the given search matches this typed search
returns nil if the search is not a match for this type
bool isMatch = function findItem(self, itemLink, searchCapture)
returns true if <itemLink> is in the search defined by <searchCapture>
}
--]]
local typedSearches = {}
function ItemSearch:RegisterTypedSearch(typedSearchObj)
typedSearches[typedSearchObj.id] = typedSearchObj
end
function ItemSearch:GetTypedSearches()
return pairs(typedSearches)
end
function ItemSearch:GetTypedSearch(id)
return typedSearches[id]
end
function ItemSearch:FindTypedSearch(itemLink, search)
if not search then
return false
end
for id, searchInfo in self:GetTypedSearches() do
local capture1, capture2, capture3 = searchInfo:isSearch(search)
if capture1 then
return searchInfo:findItem(itemLink, capture1, capture2, capture3)
end
end
return self:GetTypedSearch('itemTypeGeneric'):findItem(itemLink, search) or self:GetTypedSearch('itemName'):findItem(itemLink, search)
end
--[[
Basic typed searches
--]]
function ItemSearch:Compare(op, lhs, rhs)
--ugly, but it works
if op == ':' or op == '=' or op == '==' then
return lhs == rhs
end
if op == '!=' or op == '~=' then
return lhs ~= rhs
end
if op == '<=' then
return lhs <= rhs
end
if op == '<' then
return lhs < rhs
end
if op == '>' then
return lhs > rhs
end
if op == '>=' then
return lhs >= rhs
end
return false
end
--[[ basic text search n:(.+) ]]--
local function search_IsInText(search, ...)
for i = 1, select('#', ...) do
local text = select(i, ...)
text = text and tostring(text):lower()
if text and (text == search or text:match(search)) then
return true
end
end
return false
end
ItemSearch:RegisterTypedSearch{
id = 'itemName',
isSearch = function(self, search)
return search and search:match('^n:(.+)$')
end,
findItem = function(self, itemLink, search)
local itemName = (GetItemInfo(itemLink))
return search_IsInText(search, itemName)
end
}
--[[ item type,subtype,equip loc search t:(.+) ]]--
ItemSearch:RegisterTypedSearch{
id = 'itemTypeGeneric',
isSearch = function(self, search)
return search and search:match('^t:(.+)$')
end,
findItem = function(self, itemLink, search)
local name, link, quality, iLevel, reqLevel, type, subType, maxStack, equipSlot = GetItemInfo(itemLink)
if not name then
return false
end
return search_IsInText(search, type, subType, _G[equipSlot])
end
}
--[[ item quality search: q(sign)(%d+) | q:(qualityName) ]]--
ItemSearch:RegisterTypedSearch{
id = 'itemQuality',
isSearch = function(self, search)
if search then
return search:match('^q([%~%:%<%>%=%!]+)(%w+)$')
end
end,
descToQuality = function(self, desc)
local q = 0
local quality = _G['ITEM_QUALITY' .. q .. '_DESC']
while quality and quality:lower() ~= desc do
q = q + 1
quality = _G['ITEM_QUALITY' .. q .. '_DESC']
end
if quality then
return q
end
end,
findItem = function(self, itemLink, op, search)
local name, link, quality = GetItemInfo(itemLink)
if not name then
return false
end
local num = tonumber(search) or self:descToQuality(search)
return num and ItemSearch:Compare(op, quality, num) or false
end,
}
--[[ item level search: lvl(sign)(%d+) ]]--
ItemSearch:RegisterTypedSearch{
id = 'itemLevel',
isSearch = function(self, search)
if search then
return search:match('^ilvl([:<>=!]+)(%d+)$')
end
end,
findItem = function(self, itemLink, op, search)
local name, link, quality, iLvl = GetItemInfo(itemLink)
if not iLvl then
return false
end
local num = tonumber(search)
return num and ItemSearch:Compare(op, iLvl, num) or false
end,
}
--[[ tooltip keyword search ]]--
local tooltipCache = setmetatable({}, {__index = function(t, k) local v = {} t[k] = v return v end})
local tooltipScanner = _G['LibItemSearchTooltipScanner'] or CreateFrame('GameTooltip', 'LibItemSearchTooltipScanner', UIParent, 'GameTooltipTemplate')
local function link_FindSearchInTooltip(itemLink, search)
--look in the cache for the result
local itemID = itemLink:match('item:(%d+)')
local cachedResult = tooltipCache[search][itemID]
if cachedResult ~= nil then
return cachedResult
end
--no match?, pull in the resut from tooltip parsing
tooltipScanner:SetOwner(UIParent, 'ANCHOR_NONE')
tooltipScanner:SetHyperlink(itemLink)
local result = false
if tooltipScanner:NumLines() > 1 and _G[tooltipScanner:GetName() .. 'TextLeft2']:GetText() == search then
result = true
elseif tooltipScanner:NumLines() > 2 and _G[tooltipScanner:GetName() .. 'TextLeft3']:GetText() == search then
result = true
end
tooltipScanner:Hide()
tooltipCache[search][itemID] = result
return result
end
ItemSearch:RegisterTypedSearch{
id = 'tooltip',
isSearch = function(self, search)
return self.keywords[search]
end,
findItem = function(self, itemLink, search)
return search and link_FindSearchInTooltip(itemLink, search)
end,
keywords = {
['boe'] = ITEM_BIND_ON_EQUIP,
['bop'] = ITEM_BIND_ON_PICKUP,
['bou'] = ITEM_BIND_ON_USE,
['quest'] = ITEM_BIND_QUEST,
['boa'] = ITEM_BIND_TO_ACCOUNT
}
}
--[[ equipment set search ]]--
local function IsWardrobeLoaded()
local name, title, notes, enabled, loadable, reason, security = GetAddOnInfo('Wardrobe')
return enabled
end
local function findEquipmentSetByName(search)
local startsWithSearch = '^' .. search
local partialMatch = nil
for i = 1, GetNumEquipmentSets() do
local setName = (GetEquipmentSetInfo(i))
local lSetName = setName:lower()
if lSetName == search then
return setName
end
if lSetName:match(startsWithSearch) then
partialMatch = setName
end
end
-- Wardrobe Support
if Wardrobe then
for i, outfit in ipairs( Wardrobe.CurrentConfig.Outfit) do
local setName = outfit.OutfitName
local lSetName = setName:lower()
if lSetName == search then
return setName
end
if lSetName:match(startsWithSearch) then
partialMatch = setName
end
end
end
return partialMatch
end
local function isItemInEquipmentSet(itemLink, setName)
if not setName then
return false
end
local itemIDs = GetEquipmentSetItemIDs(setName)
if not itemIDs then
return false
end
local itemID = tonumber(itemLink:match('item:(%d+)'))
for inventoryID, setItemID in pairs(itemIDs) do
if itemID == setItemID then
return true
end
end
return false
end
local function isItemInWardrobeSet(itemLink, setName)
if not Wardrobe then return false end
local itemName = (GetItemInfo(itemLink))
for i, outfit in ipairs(Wardrobe.CurrentConfig.Outfit) do
if outfit.OutfitName == setName then
for j, item in pairs(outfit.Item) do
if item and (item.IsSlotUsed == 1) and (item.Name == itemName) then
return true
end
end
end
end
return false
end
ItemSearch:RegisterTypedSearch{
id = 'equipmentSet',
isSearch = function(self, search)
return search and search:match('^s:(.+)$')
end,
findItem = function(self, itemLink, search)
local setName = findEquipmentSetByName(search)
if not setName then
return false
end
return isItemInEquipmentSet(itemLink, setName)
or isItemInWardrobeSet(itemLink, setName)
end,
}

View file

@ -0,0 +1 @@
package-as: LibStub

View file

@ -0,0 +1,30 @@
-- LibStub is a simple versioning stub meant for use in Libraries. http://www.wowace.com/wiki/LibStub for more info
-- LibStub is hereby placed in the Public Domain Credits: Kaelten, Cladhaire, ckknight, Mikk, Ammo, Nevcairiel, joshborke
local LIBSTUB_MAJOR, LIBSTUB_MINOR = "LibStub", 2 -- NEVER MAKE THIS AN SVN REVISION! IT NEEDS TO BE USABLE IN ALL REPOS!
local LibStub = _G[LIBSTUB_MAJOR]
if not LibStub or LibStub.minor < LIBSTUB_MINOR then
LibStub = LibStub or {libs = {}, minors = {} }
_G[LIBSTUB_MAJOR] = LibStub
LibStub.minor = LIBSTUB_MINOR
function LibStub:NewLibrary(major, minor)
assert(type(major) == "string", "Bad argument #2 to `NewLibrary' (string expected)")
minor = assert(tonumber(strmatch(minor, "%d+")), "Minor version must either be a number or contain a number.")
local oldminor = self.minors[major]
if oldminor and oldminor >= minor then return nil end
self.minors[major], self.libs[major] = minor, self.libs[major] or {}
return self.libs[major], oldminor
end
function LibStub:GetLibrary(major, silent)
if not self.libs[major] and not silent then
error(("Cannot find a library instance of %q."):format(tostring(major)), 2)
end
return self.libs[major], self.minors[major]
end
function LibStub:IterateLibraries() return pairs(self.libs) end
setmetatable(LibStub, { __call = LibStub.GetLibrary })
end

View file

@ -0,0 +1,9 @@
## Interface: 20400
## Title: Lib: LibStub
## Notes: Universal Library Stub
## Credits: Kaelten, Cladhaire, ckknight, Mikk, Ammo, Nevcairiel
## X-Website: http://jira.wowace.com/browse/LS
## X-Category: Library
## X-License: Public Domain
LibStub.lua

9
Bagnon/localization.xml Normal file
View file

@ -0,0 +1,9 @@
<Ui xmlns="http://www.blizzard.com/wow/ui/">
<Script file="localization\localization.lua"/>
<Script file="localization\localization.cn.lua"/>
<Script file="localization\localization.de.lua"/>
<Script file="localization\localization.es.lua"/>
<Script file="localization\localization.fr.lua"/>
<Script file="localization\localization.ru.lua"/>
<Script file="localization\localization.tw.lua"/>
</Ui>

View file

@ -0,0 +1,62 @@
--[[
THIS FILE IS ENCODED IN UTF-8
Bagnon Localization Information: Chinese Simplified
Credits: Diablohu, yleaf@cwdg(yaroot@gmail.com), @cwdg(networm@qq.com)
Last Update: 2009/06/19 by @cwdg(networm@qq.com)
--]]
local L = LibStub('AceLocale-3.0'):NewLocale('Bagnon', 'zhCN')
if not L then return end
--keybinding text
L.ToggleBags = '开关 背包'
L.ToggleBank = '开关 银行'
L.ToggleKeys = '开关 钥匙链'
--system messages
L.NewUser = '这是该角色第一次使用 Bagnon已载入默认设置。'
L.Updated = '已更新到 Bagnon v%s'
L.UpdatedIncompatible = '由一个不相容版本升级,已载入默认设置。'
--slash commands
L.Commands = '命令:'
L.CmdShowInventory = '开关背包界面'
L.CmdShowBank = '开关银行界面'
L.CmdShowKeyring = '开关钥匙链界面'
L.CmdShowVersion = '显示当前版本'
--frame text
L.TitleBags = '%s的背包'
L.TitleBank = '%s的银行'
L.TitleKeys = '%s的钥匙链'
--tooltips
L.TipBank = '银行'
L.TipChangePlayer = '查看其他角色的物品'
L.TipCleanItems = '点击整理物品。'
L.TipGoldOnRealm = '%s上的总资产'
L.TipHideBag = '隐藏包裹'
L.TipHideBags = '隐藏背包'
L.TipHideSearch = '隐藏搜索界面'
L.TipPurchaseBag = '购买银行空位'
L.TipShowBag = '显示包裹'
L.TipShowBags = '显示背包'
L.TipShowMenu = '右击打开设置菜单'
L.TipShowSearch = '显示搜索界面'
L.TipShowSearch = '搜索'
L.TipShowFrameConfig = '打开设置菜单'
L.TipDoubleClickSearch = '双击打开搜索框'
L.Total = '总共'
--databroker plugin tooltips
L.TipShowBank = 'Shift-点击 开关银行'
L.TipShowInventory = '点击 开关背包'
L.TipShowKeyring = 'Alt-点击 开关钥匙链'
L.TipShowOptions = '右击 打开设置菜单'

View file

@ -0,0 +1,56 @@
--[[
Bagnon Localization Information: German
--]]
local L = LibStub('AceLocale-3.0'):NewLocale('Bagnon', 'deDE')
if not L then return end
--keybinding text
L.ToggleBags = 'Inventar umschalten'
L.ToggleBank = 'Bank umschalten'
L.ToggleKeys = 'Schl\195\188sselbund umschalten'
--system messages
L.NewUser = 'Neuen Benutzer erkannt. Standardeinstellungen wurden geladen'
L.Updated = 'Aktualisiert auf v%s'
L.UpdatedIncompatible = 'Aktualisierung von einer inkompatiblen Version. Standardeinstellungen wurden geladen'
--slash commands
L.Commands = 'Befehle:'
L.CmdShowInventory = 'Schaltet die Inventaranzeige um'
L.CmdShowBank = 'Schaltet die Bankanzeige um'
L.CmdShowKeyring = 'Schaltet die Schl\195\188sselringanzeige um'
L.CmdShowVersion = 'Zeigt die aktuelle Version an'
--frame text
L.TitleBags = '%s\'s Inventar'
L.TitleBank = '%s\'s Bank'
L.TitleKeys = '%s\'s Schl\195\188ssel'
--tooltips
L.TipBank = 'Bank'
L.TipChangePlayer = '<Klicken> um die Gegenst\195\164nde anderer Charaktere anzuzeigen.'
L.TipCleanItems = '<Klicken> um die Taschen zu sortieren.'
L.TipGoldOnRealm = 'Auf %s gesamt'
L.TipHideBag = '<Klicken> um diese Tasche zu verstecken.'
L.TipHideBags = '<Klicken> um die Taschenanzeige zu verstecken.'
L.TipHideSearch = '<Klicken> um das Suchfenster zu verstecken.'
L.TipPurchaseBag = '<Klicken> um das Bankfach zu kaufen.'
L.TipShowBag = '<Klicken> um diese Tasche anzuzeigen.'
L.TipShowBags = '<Klicken> um das Taschenfenster anzuzeigen.'
L.TipShowMenu = '<Rechtsklick> um das Fenster zu konfigurieren.'
L.TipShowSearch = '<Klicken> um das Suchfenster anzuzeigen.'
L.TipShowSearch = '<Klicken> zum Suchen.'
L.TipShowFrameConfig = '<Klick> um dieses Fenster zu konfigurieren.'
L.TipDoubleClickSearch = '<Alt-Ziehen> zum Verschieben.\n<Rechtsklick> zum Konfigurieren.\n<Doppelklick> zum Suchen.'
L.Total = 'Gesamt'
--databroker plugin tooltips
L.TipShowBank = '<Umschalt-Linksklick> um die Bank umzuschalten'
L.TipShowInventory = '<Linksklick> um das Inventar umzuschalten'
L.TipShowKeyring = '<Alt-Linksklick> um den Schl\195\188sselring umzuschalten'
L.TipShowOptions = '<Rechtsklick> um das Konfigurationsmen\195\188 anzuzeigen'

View file

@ -0,0 +1,7 @@
--[[
Bagnon Localization file: Spanish
Credit goes to Ferroginus
--]]
local L = LibStub('AceLocale-3.0'):NewLocale('Bagnon', 'esES')
if not L then return end

View file

@ -0,0 +1,7 @@
--[[
Bagnon Localization file: French Language
Credit goes to namAtsar
--]]
local L = LibStub('AceLocale-3.0'):NewLocale('Bagnon', 'frFR')
if not L then return end

View file

@ -0,0 +1,56 @@
--[[
Bagnon Localization Information: English Language
This file must be present to have partial translations
--]]
local L = LibStub('AceLocale-3.0'):NewLocale('Bagnon', 'enUS', true)
--keybinding text
L.ToggleBags = 'Toggle Inventory'
L.ToggleBank = 'Toggle Bank'
L.ToggleKeys = 'Toggle Keyring'
--system messages
L.NewUser = 'New user detected, default settings loaded'
L.Updated = 'Updated to v%s'
L.UpdatedIncompatible = 'Updating from an incompatible version, defaults loaded'
--slash commands
L.Commands = 'Commands:'
L.CmdShowInventory = 'Toggles the inventory frame'
L.CmdShowBank = 'Toggles the bank frame'
L.CmdShowKeyring = 'Toggles the keyring'
L.CmdShowVersion = 'Prints the current verison'
--frame text
L.TitleBags = '%s\'s Inventory'
L.TitleBank = '%s\'s Bank'
L.TitleKeys = '%s\'s Keys'
--tooltips
L.TipBank = 'Bank'
L.TipChangePlayer = 'Click to view another character\'s items.'
L.TipCleanItems = 'Click to clean items.'
L.TipGoldOnRealm = '%s Totals'
L.TipHideBag = 'Click to hide this bag.'
L.TipHideBags = 'Click to hide the bag frame.'
L.TipHideSearch = 'Click to hide the search frame.'
L.TipPurchaseBag = 'Click to purchase this bank slot.'
L.TipShowBag = 'Click to show this bag.'
L.TipShowBags = 'Click to show the bag frame.'
L.TipShowMenu = 'Right-Click to configure this frame.'
L.TipShowSearch = 'Click to show the search frame.'
L.TipShowSearch = 'Click to search.'
L.TipShowFrameConfig = 'Click to configure this frame.'
L.TipDoubleClickSearch = 'Alt-Drag to move.\nRight-Click to configure.\nDouble-Click to search.'
L.Total = 'Total'
--databroker plugin tooltips
L.TipShowBank = '<Shift Left Click> to toggle your bank.'
L.TipShowInventory = '<Left Click> to toggle your inventory.'
L.TipShowKeyring = '<Alt Left Click> to toggle your keyring.'
L.TipShowOptions = '<Right Click> to open the options menu.'

View file

@ -0,0 +1,58 @@
--[[
Bagnon Localization Information: Russian Localization by kutensky
Updated by StingerSoft
This file must be present to have partial translations
--]]
local L = LibStub('AceLocale-3.0'):NewLocale('Bagnon', 'ruRU')
if not L then return end
--keybinding text
L.ToggleBags = 'Открыть/закрыть инвентарь'
L.ToggleBank = 'Открыть/закрыть банк'
L.ToggleKeys = 'Открыть/закрыть связку ключей'
--system messages
L.NewUser = 'Обнаружен новый пользователь, загружены стандартные настройки'
L.Updated = 'Обновлено до v%s'
L.UpdatedIncompatible = 'Обновление от несовместимой версии, загружены стандартные настройки'
--slash commands
L.Commands = 'Команды:'
L.CmdShowInventory = 'Открыть/закрыть инвентарь'
L.CmdShowBank = 'Открыть/закрыть банк'
L.CmdShowKeyring = 'Открыть/закрыть связку ключей'
L.CmdShowVersion = 'Сообщить текущую версию модификации'
--frame text
L.TitleBags = 'Инвентарь |3-1(%s)'
L.TitleBank = 'Банк |3-1(%s)'
L.TitleKeys = 'Связка ключей |3-1(%s)'
--tooltips
L.TipBank = 'Банк'
L.TipChangePlayer = '<Клик> - просмотр предметов другого персонажа.'
L.TipCleanItems = '<Клик> — сортировать предметы.'
L.TipGoldOnRealm = 'Всего денег на %s'
L.TipHideBag = '<Клик> - скрыть сумку.'
L.TipHideBags = '<Клик> - скрыть область сумок.'
L.TipHideSearch = '<Клик> скрыть область поиска.'
L.TipPurchaseBag = '<Клик> - купить ячейку в банке.'
L.TipShowBag = '<Клик> - показать сумку.'
L.TipShowBags = '<Клик> - показать область сумки.'
L.TipShowMenu = '<Правый-клик> - настройки.'
L.TipShowSearch = '<Клик> - показать область поиска.'
L.TipShowSearch = '<Клик> - поиск.'
L.TipShowFrameConfig = '<Правый-клик> - настройки.'
L.TipDoubleClickSearch = '<Alt-тищить> - переместить.\n<Правый-клик> - настройка.\n<Двойной-клик> - поиск.'
L.Total = 'Всего'
--databroker plugin tooltips
L.TipShowBank = '<Shift-Левый клик> - открыть/закрыть банк.'
L.TipShowInventory = '<Левый клик> - открыть/закрыть инвентарь.'
L.TipShowKeyring = '<Alt-левый клик> - открыть/закрыть связку ключей.'
L.TipShowOptions = '<Правый-клик> - настройки.'

View file

@ -0,0 +1,65 @@
--[[
THIS FILE IS ENCODED IN UTF-8
Bagnon Localization Information: Chinese Traditional
2007/11/17 by matini< yiting.jheng <at> gmail <dot> com
2008/12/01 by yleaf@cwdg(yaroot@gmail.com)
2009/04/23 by youngway@
2009/06/19 by @cwdg(networm@qq.com)
Last Update: 2009/06/19 by @cwdg(networm@qq.com)
--]]
local L = LibStub('AceLocale-3.0'):NewLocale('Bagnon', 'zhTW')
if not L then return end
--keybinding text
L.ToggleBags = '開關 背包'
L.ToggleBank = '開關 銀行'
L.ToggleKeys = '開關 鑰匙鏈'
--system messages
L.NewUser = '這是該角色第一次使用 Bagnon已載入默認設置。'
L.Updated = '已更新到 Bagnon v%s'
L.UpdatedIncompatible = '由一個不相容版本升級,已載入默認設置。'
--slash commands
L.Commands = '命令:'
L.CmdShowInventory = '開關背包介面'
L.CmdShowBank = '開關銀行介面'
L.CmdShowKeyring = '開關鑰匙鏈介面'
L.CmdShowVersion = '顯示當前版本'
--frame text
L.TitleBags = '%s的背包'
L.TitleBank = '%s的銀行'
L.TitleKeys = '%s的鑰匙鏈'
--tooltips
L.TipBank = '銀行'
L.TipChangePlayer = '查看其他角色的物品'
L.TipCleanItems = '整理物品'
L.TipGoldOnRealm = '%s上的總資產'
L.TipHideBag = '隱藏包裹'
L.TipHideBags = '隱藏背包'
L.TipHideSearch = '隱藏搜索介面'
L.TipPurchaseBag = '購買銀行空位'
L.TipShowBag = '顯示包裹'
L.TipShowBags = '顯示背包'
L.TipShowMenu = '右擊打開設置菜單'
L.TipShowSearch = '顯示搜索介面'
L.TipShowSearch = '搜索'
L.TipShowFrameConfig = '打開設置菜單'
L.TipDoubleClickSearch = '按兩下打開搜索框'
L.Total = '總共'
--databroker plugin tooltips
L.TipShowBank = 'Shift-點擊 開關銀行'
L.TipShowInventory = '點擊 開關背包'
L.TipShowKeyring = 'Alt-點擊 開關鑰匙鏈'
L.TipShowOptions = '右擊 打開設置菜單'

412
Bagnon/main.lua Normal file
View file

@ -0,0 +1,412 @@
--[[
main.lua
The bagnon driver thingy
--]]
Bagnon = LibStub('AceAddon-3.0'):NewAddon('Bagnon', 'AceEvent-3.0', 'AceConsole-3.0')
local L = LibStub('AceLocale-3.0'):GetLocale('Bagnon')
--[[
Binding Setup
--]]
BINDING_HEADER_BAGNON = 'Bagnon'
BINDING_NAME_BAGNON_TOGGLE = L.ToggleBags
BINDING_NAME_BANKNON_TOGGLE = L.ToggleBank
BINDING_NAME_BAGNON_KEYS_TOGGLE = L.ToggleKeys
--[[
Startup
--]]
function Bagnon:OnInitialize()
self.frames = {}
self:HookBagClickEvents()
self:RegisterAutoDisplayEvents()
self:AddSlashCommands()
self:CreateOptionsLoader()
self:CreateLDBLauncher()
self:CreateGuildBankLoader()
end
--create a loader for the options menu
function Bagnon:CreateOptionsLoader()
local f = CreateFrame('Frame', nil, InterfaceOptionsFrame)
f:SetScript('OnShow', function(self)
self:SetScript('OnShow', nil)
LoadAddOn('Bagnon_Config')
end)
end
function Bagnon:CreateGuildBankLoader()
local name, title, notes, enabled, loadable = GetAddOnInfo('Bagnon_GuildBank')
if enabled and loadable then
GuildBankFrame_LoadUI = function()
LoadAddOn('Bagnon_GuildBank')
end
end
end
function Bagnon:CreateLDBLauncher()
local LDB = LibStub:GetLibrary('LibDataBroker-1.1', true)
if not LDB then return end
LDB:NewDataObject('BagnonLauncher', {
type = 'launcher',
icon = [[Interface\Icons\INV_Misc_Bag_07]],
OnClick = function(_, button)
if button == 'LeftButton' then
if IsShiftKeyDown() then
Bagnon:ToggleFrame('bank')
elseif IsAltKeyDown() then
Bagnon:ToggleFrame('keys')
else
Bagnon:ToggleFrame('inventory')
end
elseif button == 'RightButton' then
Bagnon:ShowOptions()
end
end,
OnTooltipShow = function(tooltip)
if not tooltip or not tooltip.AddLine then return end
tooltip:AddLine('Bagnon')
tooltip:AddLine(L.TipShowInventory, 1, 1, 1)
tooltip:AddLine(L.TipShowBank, 1, 1, 1)
tooltip:AddLine(L.TipShowKeyring, 1, 1, 1)
tooltip:AddLine(L.TipShowOptions, 1, 1, 1)
end,
})
end
--[[
Frame Display
--]]
function Bagnon:GetFrame(frameID)
for i, frame in pairs(self.frames) do
if frame:GetFrameID() == frameID then
return frame
end
end
end
function Bagnon:CreateFrame(frameID)
table.insert(self.frames, self.Frame:New(frameID))
end
function Bagnon:ShowFrame(frameID)
if self:IsFrameEnabled(frameID) then
if not self:GetFrame(frameID) then
self:CreateFrame(frameID)
end
self.FrameSettings:Get(frameID):Show()
return true
end
return false
end
function Bagnon:HideFrame(frameID)
if self:IsFrameEnabled(frameID) then
self.FrameSettings:Get(frameID):Hide()
return true
end
return false
end
function Bagnon:ToggleFrame(frameID)
if self:IsFrameEnabled(frameID) then
if not self:GetFrame(frameID) then
self:CreateFrame(frameID)
end
self.FrameSettings:Get(frameID):Toggle()
return true
end
return false
end
function Bagnon:IsFrameEnabled(frameID)
return self.Settings:IsFrameEnabled(frameID)
end
function Bagnon:FrameControlsBag(frameID, bagSlot)
return self.FrameSettings:Get(frameID):IsBagSlotShown(bagSlot) or (not self:IsBlizzardBagPassThroughEnabled())
end
function Bagnon:IsBlizzardBagPassThroughEnabled()
return self.Settings:IsBlizzardBagPassThroughEnabled()
end
--[[
Bag Click Events
--]]
function Bagnon:HookBagClickEvents()
--backpack
hooksecurefunc('CloseBackpack', function()
self:HideFrame('inventory')
end)
local oOpenBackpack = OpenBackpack
OpenBackpack = function()
local shown = self:FrameControlsBag('inventory', BACKPACK_CONTAINER) and self:ShowFrame('inventory')
if not shown then
oOpenBackpack()
end
end
local oToggleBackpack = ToggleBackpack
ToggleBackpack = function()
local toggled = self:FrameControlsBag('inventory', BACKPACK_CONTAINER) and self:ToggleFrame('inventory')
if not toggled then
oToggleBackpack()
end
end
--single bag
local oToggleBag = ToggleBag
ToggleBag = function(bagSlot)
local frameID = self.BagSlotInfo:IsBankBag(bagSlot) and 'bank' or 'inventory'
local toggled = self:FrameControlsBag(frameID, bagSlot) and self:ToggleFrame(frameID)
if not toggled then
oToggleBag(bagSlot)
end
end
--keyring
local oToggleKeyRing = ToggleKeyRing
ToggleKeyRing = function()
local toggled = self:FrameControlsBag('keys', KEYRING_CONTAINER) and self:ToggleFrame('keys')
if not toggled then
toggled = self:FrameControlsBag('inventory', KEYRING_CONTAINER) and self:ToggleFrame('inventory')
end
if not toggled then
oToggleKeyRing()
end
end
--all bags
--closing the game menu triggers this function, and can be done in combat
hooksecurefunc('CloseAllBags', function()
self:HideFrame('inventory')
end)
local oOpenAllBags = OpenAllBags
OpenAllBags = function(force)
local opened = false
-- force does not exist?
--[[
if force then
opened = self:FrameControlsBag('inventory', BACKPACK_CONTAINER) and self:ShowFrame('inventory')
else
opened = self:FrameControlsBag('inventory', BACKPACK_CONTAINER) and self:ToggleFrame('inventory')
end
]]
opened = self:FrameControlsBag('inventory', BACKPACK_CONTAINER) and self:ShowFrame('inventory')
if not opened then
oOpenAllBags(force)
end
end
end
--[[
Automatic Display
--]]
function Bagnon:RegisterAutoDisplayEvents()
self.BagEvents:Listen(self, 'BANK_OPENED')
self.BagEvents:Listen(self, 'BANK_CLOSED')
self:RegisterEvent('MAIL_CLOSED')
self:RegisterEvent('AUCTION_HOUSE_SHOW')
self:RegisterEvent('AUCTION_HOUSE_CLOSED')
self:RegisterEvent('MERCHANT_SHOW')
self:RegisterEvent('MERCHANT_CLOSED')
self:RegisterEvent('TRADE_SHOW')
self:RegisterEvent('TRADE_CLOSED')
self:RegisterEvent('TRADE_SKILL_SHOW')
self:RegisterEvent('TRADE_SKILL_CLOSE')
self:RegisterEvent('GUILDBANKFRAME_OPENED')
self:RegisterEvent('GUILDBANKFRAME_CLOSED')
--override normal bank display
BankFrame:UnregisterEvent('BANKFRAME_OPENED')
BankFrame:UnregisterEvent('BANKFRAME_CLOSED')
local f = CreateFrame('Frame', nil, CharacterFrame)
f:SetScript('OnShow', function() Bagnon:PLAYER_FRAME_SHOW() end)
f:SetScript('OnHide', function() Bagnon:PLAYER_FRAME_HIDE() end)
end
function Bagnon:ShowFrameAtEvent(frameID, event)
if self:AutoDisplayingFrameOnEvent(frameID, event) then
self:ShowFrame(frameID)
end
end
function Bagnon:HideFrameAtEvent(frameID, event)
if self:AutoDisplayingFrameOnEvent(frameID, event) then
self:HideFrame(frameID)
end
end
function Bagnon:AutoDisplayingFrameOnEvent(frameID, event)
return self.Settings:IsFrameShownAtEvent(frameID, event)
end
function Bagnon:ShowBlizzardBankFrame()
BankFrame_OnEvent(_G['BankFrame'], 'BANKFRAME_OPENED')
end
function Bagnon:HideBlizzardBankFrame()
BankFrame_OnEvent(_G['BankFrame'], 'BANKFRAME_CLOSED')
end
--[[ Display Events ]]--
--visiting the bank
function Bagnon:BANK_OPENED()
if not self:ShowFrame('bank') then
self:ShowBlizzardBankFrame()
end
self:ShowFrameAtEvent('inventory', 'bank')
end
function Bagnon:BANK_CLOSED()
if not self:HideFrame('bank') then
self:HideBlizzardBankFrame()
end
self:HideFrameAtEvent('inventory', 'bank')
end
--visiting the mailbox
--mail frame is a special case, since its automatically handled by the stock interface
function Bagnon:MAIL_CLOSED()
self:HideFrame('inventory')
end
--visiting the auction house
function Bagnon:AUCTION_HOUSE_SHOW()
self:ShowFrameAtEvent('inventory', 'ah')
end
function Bagnon:AUCTION_HOUSE_CLOSED()
self:HideFrameAtEvent('inventory', 'ah')
end
--visitng a vendor
function Bagnon:MERCHANT_SHOW()
self:ShowFrameAtEvent('inventory', 'vendor')
end
function Bagnon:MERCHANT_CLOSED()
self:HideFrameAtEvent('inventory', 'vendor')
end
--trading
function Bagnon:TRADE_SHOW()
self:ShowFrameAtEvent('inventory', 'trade')
end
function Bagnon:TRADE_CLOSED()
self:HideFrameAtEvent('inventory', 'trade')
end
--visiting the guild bank
function Bagnon:GUILDBANKFRAME_OPENED()
self:ShowFrameAtEvent('inventory', 'guildbank')
end
function Bagnon:GUILDBANKFRAME_CLOSED()
self:HideFrameAtEvent('inventory', 'guildbank')
end
--crafting
function Bagnon:TRADE_SKILL_SHOW()
self:ShowFrameAtEvent('inventory', 'craft')
end
function Bagnon:TRADE_SKILL_CLOSE()
self:HideFrameAtEvent('inventory', 'craft')
end
--player frame
function Bagnon:PLAYER_FRAME_SHOW()
self:ShowFrameAtEvent('inventory', 'player')
end
function Bagnon:PLAYER_FRAME_HIDE()
self:HideFrameAtEvent('inventory', 'player')
end
--[[
Slash Commands
--]]
function Bagnon:AddSlashCommands()
self:RegisterChatCommand('bagnon', 'HandleSlashCommand')
self:RegisterChatCommand('bgn', 'HandleSlashCommand')
end
function Bagnon:HandleSlashCommand(cmd)
cmd = cmd and cmd:lower() or ''
if cmd == 'bank' then
self:ToggleFrame('bank')
elseif cmd == 'bags' then
self:ToggleFrame('inventory')
elseif cmd == 'keys' then
self:ToggleFrame('keys')
elseif cmd == 'version' then
self:PrintVersion()
elseif cmd == 'config' then
self:ShowOptions()
elseif cmd == '?' or cmd == 'help' then
self:PrintHelp()
else
if not self:ShowOptions() then
self:PrintHelp()
end
end
end
function Bagnon:PrintVersion()
self:Print(self.SavedSettings:GetDBVersion())
end
function Bagnon:PrintHelp()
local function PrintCmd(cmd, desc)
print(string.format(' - |cFF33FF99%s|r: %s', cmd, desc))
end
self:Print(L.Commands)
PrintCmd('bags', L.CmdShowInventory)
PrintCmd('bank', L.CmdShowBank)
PrintCmd('keys', L.CmdShowKeyring)
PrintCmd('version', L.CmdShowVersion)
end
function Bagnon:ShowOptions()
if LoadAddOn('Bagnon_Config') then
InterfaceOptionsFrame_OpenToFrame(self.GeneralOptions)
return true
end
return false
end

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
Bagnon/textures/Broom.tga Normal file

Binary file not shown.

2
Bagnon/todo.txt Normal file
View file

@ -0,0 +1,2 @@
* Saved searches
* Guild bank

11
Bagnon/utility.xml Normal file
View file

@ -0,0 +1,11 @@
<Ui xmlns="http://www.blizzard.com/wow/ui/">
<Script file="utility\ears.lua"/>
<Script file="utility\classy.lua"/>
<Script file="utility\callbacks.lua"/>
<Script file="utility\itemEvents.lua"/>
<Script file="utility\bagSlotInfo.lua"/>
<Script file="utility\itemSlotInfo.lua"/>
<Script file="utility\playerInfo.lua"/>
<Script file="utility\sorting.lua"/>
</Ui>

View file

@ -0,0 +1,169 @@
--[[
bagSlotInfo.lua
Generic methods for accessing bag slot information
--]]
local Bagnon = LibStub('AceAddon-3.0'):GetAddon('Bagnon')
local BagSlotInfo = {}
Bagnon.BagSlotInfo = BagSlotInfo
--[[ Slot Info ]]--
--returns true if the given bagSlot is a purchasable bank slot
function BagSlotInfo:IsBankBag(bagSlot)
return bagSlot > NUM_BAG_SLOTS and bagSlot < (NUM_BAG_SLOTS + NUM_BANKBAGSLOTS + 1)
end
--returns true if the given bagSlot is the bank container slot
function BagSlotInfo:IsBank(bagSlot)
return bagSlot == BANK_CONTAINER
end
--returns true if the given bagSlot is the backpack
function BagSlotInfo:IsBackpack(bagSlot)
return bagSlot == BACKPACK_CONTAINER
end
--returns true if the given bagSlot is an optional inventory bag slot
function BagSlotInfo:IsBackpackBag(bagSlot)
return bagSlot > 0 and bagSlot < (NUM_BAG_SLOTS + 1)
end
--returns true if the given bagSlot is the keyring
function BagSlotInfo:IsKeyRing(bagSlot)
return bagSlot == KEYRING_CONTAINER
end
--returns true if the given bagSlot for the given player is cached
function BagSlotInfo:IsCached(player, bagSlot)
if Bagnon.PlayerInfo:IsCached(player) then
return true
end
if self:IsBank(bagSlot) or self:IsBankBag(bagSlot) then
return not Bagnon.PlayerInfo:AtBank()
end
return false
end
--returns true if the given bagSlot is purchasable for the given player and false otherwise
function BagSlotInfo:IsPurchasable(player, bagSlot)
local purchasedSlots
if self:IsCached(player, bagSlot) then
if BagnonDB then
purchasedSlots = BagnonDB:GetNumBankSlots(player) or 0
else
purchasedSlots = 0
end
else
purchasedSlots = GetNumBankSlots()
end
return bagSlot > (purchasedSlots + NUM_BAG_SLOTS)
end
function BagSlotInfo:IsLocked(player, bagSlot)
if self:IsBackpack(bagSlot) or self:IsKeyRing(bagSlot) or self:IsBank(bagSlot) or self:IsCached(player, bagSlot) then
return false
end
return IsInventoryItemLocked(self:ToInventorySlot(bagSlot))
end
--[[ Slot Item Info ]]--
--returns how many items can fit in the given bag
function BagSlotInfo:GetSize(player, bagSlot)
local size = 0
if self:IsCached(player, bagSlot) then
if BagnonDB then
size = (BagnonDB:GetBagData(bagSlot, player))
end
elseif self:IsBank(bagSlot) then
size = NUM_BANKGENERIC_SLOTS
elseif self:IsKeyRing(bagSlot) then
size = GetKeyRingSize()
else
size = GetContainerNumSlots(bagSlot)
end
return size or 0
end
--returns the itemLink, number of items in, and item icon texture of the given bagSlot
function BagSlotInfo:GetItemInfo(player, bagSlot)
local link, texture, count, size
if self:IsCached(player, bagSlot) then
if BagnonDB then
size, link, count, texture = BagnonDB:GetBagData(bagSlot, player)
end
else
local invSlot = self:ToInventorySlot(bagSlot)
link = GetInventoryItemLink('player', invSlot)
texture = GetInventoryItemTexture('player', invSlot)
count = GetInventoryItemCount('player', invSlot)
end
return link, count, texture
end
--[[ Slot Type Info ]]--
function BagSlotInfo:GetBagType(player, bagSlot)
if self:IsKeyRing(bagSlot) then
return 256
end
if self:IsBank(bagSlot) or self:IsBackpack(bagSlot) then
return 0
end
local itemLink = (self:GetItemInfo(player, bagSlot))
if itemLink then
return GetItemFamily(itemLink)
end
return 0
end
-- Stolen from OneBag, since my bitflag knowledge could be better
-- BAGTYPE_QUIVER = Quiver + Ammo
local BAGTYPE_QUIVER = 0x0001 + 0x0002
function BagSlotInfo:IsAmmoBag(player, bagSlot)
return bit.band(self:GetBagType(player, bagSlot), BAGTYPE_QUIVER) > 0
end
-- BAGTYPE_SOUL = Soul Bags
local BAGTYPE_SOUL = 0x004
function BagSlotInfo:IsShardBag(player, bagSlot)
return bit.band(self:GetBagType(player, bagSlot), BAGTYPE_SOUL) > 0
end
-- BAGTYPE_PROFESSION = Leather + Inscription + Herb + Enchanting + Engineering + Gem + Mining
local BAGTYPE_PROFESSION = 0x0008 + 0x0010 + 0x0020 + 0x0040 + 0x0080 + 0x0200 + 0x0400
function BagSlotInfo:IsTradeBag(player, bagSlot)
return bit.band(self:GetBagType(player, bagSlot), BAGTYPE_PROFESSION) > 0
end
--[[ Conversion Methods ]]--
--converts the given bag slot into an applicable inventory slot
function BagSlotInfo:ToInventorySlot(bagSlot)
if self:IsKeyRing(bagSlot) then
return KeyRingButtonIDToInvSlotID(bagSlot)
end
if self:IsBackpackBag(bagSlot) then
return ContainerIDToInventoryID(bagSlot)
end
if self:IsBankBag(bagSlot) then
return BankButtonIDToInvSlotID(bagSlot, 1)
end
return nil
end

View file

@ -0,0 +1,7 @@
--[[
callBacks.lua
Initializes the Bagnon callback handler
--]]
local Bagnon = LibStub('AceAddon-3.0'):GetAddon('Bagnon')
Bagnon.Callbacks = Bagnon.Ears:New()

41
Bagnon/utility/classy.lua Normal file
View file

@ -0,0 +1,41 @@
--[[
Classy.lua
Utility methods for constructing a Bagnon object class
--]]
local Bagnon = LibStub('AceAddon-3.0'):GetAddon('Bagnon')
local Classy = {}
Bagnon.Classy = Classy
function Classy:New(frameType, parentClass)
local class = CreateFrame(frameType)
class.mt = {__index = class}
if parentClass then
class = setmetatable(class, {__index = parentClass})
class.super = parentClass
end
class.Bind = function(self, obj)
return setmetatable(obj, self.mt)
end
--callback support
class.RegisterMessage = function(self, ...)
Bagnon.Callbacks:Listen(self, ...)
end
class.SendMessage = function(self, ...)
Bagnon.Callbacks:SendMessage(...)
end
class.UnregisterMessage = function(self, ...)
Bagnon.Callbacks:Ignore(self, ...)
end
class.UnregisterAllMessages = function(self, ...)
Bagnon.Callbacks:IgnoreAll(self, ...)
end
return class
end

83
Bagnon/utility/ears.lua Normal file
View file

@ -0,0 +1,83 @@
--[[
Ears.lua
A simple message passing object.
--]]
local Bagnon = LibStub('AceAddon-3.0'):GetAddon('Bagnon')
local Ears = {}
Bagnon.Ears = Ears
--ye old constructor
local ears_MT = {__index = Ears}
function Ears:New()
local o = setmetatable({}, ears_MT)
o.listeners = {}
return o
end
--trigger a message, with the given args
function Ears:SendMessage(msg, ...)
assert(msg, 'Usage: Ears:SendMessage(msg[, args])')
assert(type(msg) == 'string', 'String expected for <msg>, got: \'' .. type(msg) .. '\'')
local listeners = self.listeners[msg]
if listeners then
for obj, action in pairs(listeners) do
action(obj, msg, ...)
end
end
end
--tells obj to do something when msg happens
function Ears:Listen(obj, msg, method)
assert(obj and msg, 'Usage: Ears:Listen(obj, msg[, method])')
assert(type(msg) == 'string', 'String expected for <msg>, got: \'' .. type(msg) .. '\'')
local method = method or msg
local action
if type(method) == 'string' then
assert(obj[method] and type(obj[method]) == 'function', 'Object does not have an instance of ' .. method)
action = obj[method]
else
assert(type(method) == 'function', 'String or function expected for <method>, got: \'' .. type(method) .. '\'')
action = method
end
local listeners = self.listeners[msg] or {}
listeners[obj] = action
self.listeners[msg] = listeners
-- assert(self.listeners[msg] and self.listeners[msg][obj], 'Ears: Failed to register ' .. msg)
end
--tells obj to do nothing when msg happens
function Ears:Ignore(obj, msg)
assert(obj and msg, 'Usage: Ears:Ignore(obj, msg)')
assert(type(msg) == 'string', 'String expected for <msg>, got: \'' .. type(msg) .. '\'')
local listeners = self.listeners[msg]
if listeners then
listeners[obj] = nil
if not next(listeners) then
self.listeners[msg] = nil
end
end
-- assert(not(self.listeners[msg] and self.listeners[msg][obj]), 'Ears: Failed to ignore ' .. msg)
end
--ignore all messages for obj
function Ears:IgnoreAll(obj)
assert(obj, 'Usage: Ears:IgnoreAll(obj)')
for msg in pairs(self.listeners) do
self:Ignore(obj, msg)
end
end

View file

@ -0,0 +1,280 @@
--[[
BagEvents
A library of functions for accessing and updating bag slot information
Based on SpecialEvents-Bags by Tekkub Stoutwrithe (tekkub@gmail.com)
ITEM_SLOT_ADD
args: bag, slot, link, count, locked, coolingDown
called when a new slot becomes available to the player
ITEM_SLOT_REMOVE
args: bag, slot
called when an item slot is removed from being in use
ITEM_SLOT_UPDATE
args: bag, slot, link, count, locked, coolingDown
called when an item slot's item or item count changes
ITEM_SLOT_UPDATE_COOLDOWN
args: bag, slot, coolingDown
called when an item's cooldown starts/ends
BANK_OPENED
args: none
called when the bank has opened and all of the bagnon events have SendMessaged
BANK_CLOSED
args: none
called when the bank is closed and all of the bagnon events have SendMessaged
BAG_UPDATE_TYPE
args: bag, type
called when the type of a bag changes (aka, what items you can put in it changes)
--]]
local Bagnon = LibStub('AceAddon-3.0'):GetAddon('Bagnon')
local BagEvents = Bagnon.Ears:New()
Bagnon.BagEvents = BagEvents
--[[ privates? ]]--
local slots = {}
local bagTypes = {}
local function ToIndex(bag, slot)
return (bag < 0 and bag*100 - slot) or bag*100 + slot
end
local function GetBagSize(bag)
return (bag == KEYRING_CONTAINER and GetKeyRingSize()) or GetContainerNumSlots(bag)
end
--[[ Startup ]]--
function BagEvents:Load()
self.atBank = false
self.firstVisit = true
self.frame = CreateFrame('Frame')
self.RegisterEvent = function(self, event)
self.frame:RegisterEvent(event)
end
self.OnEvent = function(f, event, ...)
if self[event] then
self[event](self, event, ...)
end
end
self.frame:SetScript('OnEvent', self.OnEvent)
self:RegisterEvent('PLAYER_LOGIN')
end
--[[ Update Functions ]]--
--all info
function BagEvents:AddItem(bag, slot)
local index = ToIndex(bag,slot)
if not slots[index] then slots[index] = {} end
local data = slots[index]
local texture, count, locked, quality, readable, lootable, link = GetContainerItemInfo(bag, slot)
local start, duration, enable = GetContainerItemCooldown(bag, slot)
local onCooldown = (start > 0 and duration > 0 and enable > 0)
data[1] = link
data[2] = count
data[3] = locked
data[4] = onCooldown
self:SendMessage('ITEM_SLOT_ADD', bag, slot, link, count, locked, onCooldown)
end
function BagEvents:RemoveItem(bag, slot)
local data = slots[ToIndex(bag, slot)]
if data and next(data) then
local prevLink = data[1]
for i in pairs(data) do
data[i] = nil
end
self:SendMessage('ITEM_SLOT_REMOVE', bag, slot, prevLink)
end
end
function BagEvents:UpdateItem(bag, slot)
local data = slots[ToIndex(bag, slot)]
if data then
local prevLink = data[1]
local prevCount = data[2]
local texture, count, locked, quality, readable, lootable, link = GetContainerItemInfo(bag, slot)
link = GetContainerItemLink(bag, slot)
local start, duration, enable = GetContainerItemCooldown(bag, slot)
local onCooldown = (start > 0 and duration > 0 and enable > 0)
if not(prevLink == link and prevCount == count) then
data[1] = link
data[2] = count
data[3] = locked
data[4] = onCooldown
self:SendMessage('ITEM_SLOT_UPDATE', bag, slot, link, count, locked, onCooldown)
end
end
end
function BagEvents:UpdateItems(bag)
for slot = 1, GetBagSize(bag) do
self:UpdateItem(bag, slot)
end
end
--cooldowns
function BagEvents:UpdateCooldown(bag, slot)
local data = slots[ToIndex(bag,slot)]
if data and data[1] then
local start, duration, enable = GetContainerItemCooldown(bag, slot)
local onCooldown = (start > 0 and duration > 0 and enable > 0)
if data[4] ~= onCooldown then
data[4] = onCooldown
self:SendMessage('ITEM_SLOT_UPDATE_COOLDOWN', bag, slot, onCooldown)
end
end
end
function BagEvents:UpdateCooldowns(bag)
for slot = 1, GetBagSize(bag) do
self:UpdateCooldown(bag, slot)
end
end
--bag sizes
function BagEvents:UpdateBagSize(bag)
local prevSize = slots[bag*100] or 0
local newSize = GetBagSize(bag) or 0
slots[bag*100] = newSize
if prevSize > newSize then
for slot = newSize+1, prevSize do
self:RemoveItem(bag, slot)
end
elseif prevSize < newSize then
for slot = prevSize+1, newSize do
self:AddItem(bag, slot)
end
end
end
function BagEvents:UpdateBagType(bag)
local _, newType = GetContainerNumFreeSlots(bag)
local prevType = bagTypes[bag]
if newType ~= prevType then
bagTypes[bag] = newType
self:SendMessage('BAG_UPDATE_TYPE', bag, newType)
end
end
function BagEvents:UpdateBagSizes()
if self:AtBank() then
for bag = 1, NUM_BAG_SLOTS + GetNumBankSlots() do
self:UpdateBagSize(bag)
end
else
for bag = 1, NUM_BAG_SLOTS do
self:UpdateBagSize(bag)
end
end
self:UpdateBagSize(KEYRING_CONTAINER)
end
function BagEvents:UpdateBagTypes()
if self:AtBank() then
for bag = 1, NUM_BAG_SLOTS + GetNumBankSlots() do
self:UpdateBagType(bag)
end
else
for bag = 1, NUM_BAG_SLOTS do
self:UpdateBagType(bag)
end
end
end
--[[ Events ]]--
function BagEvents:PLAYER_LOGIN(...)
self:RegisterEvent('BAG_UPDATE')
self:RegisterEvent('BAG_UPDATE_COOLDOWN')
self:RegisterEvent('PLAYERBANKSLOTS_CHANGED')
self:RegisterEvent('BANKFRAME_OPENED')
self:RegisterEvent('BANKFRAME_CLOSED')
self:UpdateBagSize(KEYRING_CONTAINER)
self:UpdateItems(KEYRING_CONTAINER)
self:UpdateBagSize(BACKPACK_CONTAINER)
self:UpdateItems(BACKPACK_CONTAINER)
end
function BagEvents:BAG_UPDATE(event, bag)
self:UpdateBagTypes()
self:UpdateBagSizes()
self:UpdateItems(bag)
end
function BagEvents:PLAYERBANKSLOTS_CHANGED(...)
self:UpdateBagTypes()
self:UpdateBagSizes()
self:UpdateItems(BANK_CONTAINER)
end
function BagEvents:BANKFRAME_OPENED(...)
self.atBank = true
if self.firstVisit then
self.firstVisit = nil
self:UpdateBagSize(BANK_CONTAINER)
self:UpdateBagTypes()
self:UpdateBagSizes()
end
self:SendMessage('BANK_OPENED')
end
function BagEvents:BANKFRAME_CLOSED(...)
self.atBank = false
self:SendMessage('BANK_CLOSED')
end
function BagEvents:BAG_UPDATE_COOLDOWN(...)
self:UpdateCooldowns(BACKPACK_CONTAINER)
for bag = 1, NUM_BAG_SLOTS do
self:UpdateCooldowns(bag)
end
end
--[[ Accessor Methods ]]--
function BagEvents:AtBank()
return self.atBank
end
--load the thing
BagEvents:Load()

View file

@ -0,0 +1,42 @@
--[[
itemSlotInfo.lua
Generic methods for accessing item slot information
--]]
local Bagnon = LibStub('AceAddon-3.0'):GetAddon('Bagnon')
local ItemSlotInfo = {}
Bagnon.ItemSlotInfo = ItemSlotInfo
function ItemSlotInfo:GetItemInfo(player, bag, slot)
local link, count, texture, quality, readable, locked, lootable
if self:IsCached(player, bag, slot) then
if BagnonDB then
link, count, texture, quality = BagnonDB:GetItemData(bag, slot, player)
end
else
texture, count, locked, quality, readable, lootable, link = GetContainerItemInfo(bag, slot)
link = GetContainerItemLink(bag, slot)
--GetContainerItemInfo does not return a quality value for all items. If it does not, it returns -1
if link and quality < 0 then
quality = (select(3, GetItemInfo(link)))
end
end
return texture, count, locked, quality, readable, lootable, link
end
function ItemSlotInfo:IsLocked(player, bag, slot)
if self:IsCached(player, bag, slot) then
return false
end
local texture, count, locked, quality, readable, lootable, link = GetContainerItemInfo(bag, slot)
link = GetContainerItemLink(bag, slot)
--return (select(3, GetContainerItemInfo(bag, slot)))
return locked, quality, readable, lootable, link
end
function ItemSlotInfo:IsCached(player, bag, slot)
return Bagnon.BagSlotInfo:IsCached(player, bag)
end

View file

@ -0,0 +1,33 @@
--[[
player.lua
Generic methods for accessing player information
--]]
--[[ Player Info ]]--
local Bagnon = LibStub('AceAddon-3.0'):GetAddon('Bagnon')
local PlayerInfo = {}
Bagnon.PlayerInfo = PlayerInfo
local CURRENT_PLAYER = UnitName('player')
function PlayerInfo:IsCached(player)
return player ~= CURRENT_PLAYER
end
function PlayerInfo:GetMoney(player)
local money = 0
if self:IsCached(player) then
if BagnonDB then
money = BagnonDB:GetMoney(player)
end
else
money = GetMoney()
end
return money
end
function PlayerInfo:AtBank()
return Bagnon.BagEvents:AtBank()
end

245
Bagnon/utility/sorting.lua Normal file
View file

@ -0,0 +1,245 @@
--[[
sorting.lua
Client side bag sorting algorithm
--]]
--local Search = LibStub('ItemSearch-1.3')
local Sort = Bagnon:NewModule('Sorting', 'AceTimer-3.0')
Bagnon.Sorting = Sort
Sort.Proprieties = {
--'set',
'class', 'subclass', --'equip',
'quality',
'icon',
'level', 'name', 'id',
'count'
}
Sort.init = false
function Sort:Init()
Sort.init = true
Sort.Classes = {}
for i, itemClass in ipairs({GetAuctionItemClasses()}) do
local subClasses = {}
for j, subClass in ipairs({GetAuctionItemSubClasses(i)}) do
subClasses[subClass] = j
end
Sort.Classes[itemClass] = {index = i, subClasses = subClasses}
end
end
--[[ Process ]]--
function Sort:Start(itemFrame)
if not self:CanRun() then
return
end
if not self.init then
self:Init()
end
self.itemFrame = itemFrame
--self:SendMessage('SORTING_STATUS', itemFrame)
self:Run()
end
function Sort:Run()
if self:CanRun() then
ClearCursor()
self:Iterate()
else
self:Stop()
end
end
function Sort:Iterate()
local spaces = self:GetSpaces()
local families = self:GetFamilies(spaces)
local updateRequired = false;
local stackable = function(item)
return (item.count or 1) < (item.stack or 1)
end
for k, target in pairs(spaces) do
local item = target.item
if item.id and stackable(item) then
for j = k+1, #spaces do
local from = spaces[j]
local other = from.item
if item.id == other.id and stackable(other) then
self:Move(from, target)
updateRequired = true
end
end
end
end
local moveDistance = function(item, goal)
return math.abs(item.space.index - goal.index)
end
for _, family in ipairs(families) do
local order, spaces = self:GetOrder(spaces, family)
local n = min(#order, #spaces)
for index = 1, n do
local goal = spaces[index]
local item = order[index]
item.sorted = true
if item.space ~= goal then
local distance = moveDistance(item, goal)
for j = index, n do
local other = order[j]
if other.id == item.id and other.count == item.count then
local d = moveDistance(other, spaces[j])
if d > distance then
item = other
distance = d
end
end
end
self:Move(item.space, goal)
updateRequired = true
end
end
end
if updateRequired then
self:ScheduleTimer("Run", 0.05)
else
self:Stop()
end
end
function Sort:Stop()
self.itemFrame:SendMessage('SORTING_STATUS')
end
--[[ Data Structures ]]--
function Sort:GetSpaces()
local spaces = {}
local itemFrame = self.itemFrame
for _, bag in itemFrame:GetVisibleBags() do
local family = Bagnon.BagSlotInfo:GetBagType(itemFrame:GetPlayer(), bag)
for slot = 1, itemFrame:GetBagSize(bag) do
local itemSlot = itemFrame:GetItemSlot(bag, slot)
local texture, count, locked, quality, readable, lootable, link = itemSlot:GetItemSlotInfo()
local item = {}
tinsert(spaces, {index = #spaces, bag = bag, slot = slot, family = family, item = item})
item.space = spaces[#spaces]
if link then
local itemName, itemLink, itemRarity, itemLevel, itemMinLevel, itemType, itemSubType, itemStackCount = GetItemInfo(link)
item.class = Sort.Classes[itemType] and Sort.Classes[itemType].index or 0
item.subclass = Sort.Classes[itemType] and Sort.Classes[itemType].subClasses[itemSubType] or 0
item.stack = itemStackCount
item.count = count
item.id = tonumber(link:match("item:(%d+)")) or 0
item.locked = locked
item.quality = quality
item.icon = texture
item.level = itemLevel
item.name = itemName
end
end
end
--[[
for _, bag in pairs(self.bags) do
local link, count, texture = bag:GetBagInfo()
for slot = 1, (container.count or 0) do
local item = Bagnon.Bag:GetItemInfo(self.owner, bag, slot)
tinsert(spaces, {index = #spaces, bag = bag, slot = slot, family = container.family, item = item})
item.class = item.id and Search:IsQuestItem(item.id) and Enum.ItemClass.Questitem or item.class
item.space = spaces[#spaces]
--item.set = item.id and Search:BelongsToSet(item.id) and 0 or 1
end
end
]]
return spaces
end
function Sort:GetFamilies(spaces)
local set = {}
for _, space in ipairs(spaces) do
set[space.family] = true
end
local list = {}
for family in pairs(set) do
tinsert(list, family)
end
sort(list, function(a, b) return a > b end)
return list
end
function Sort:GetOrder(spaces, family)
local order, slots = {}, {}
for _, space in ipairs(spaces) do
local item = space.item
if item.id and not item.sorted and self:FitsIn(item.id, family) then
tinsert(order, space.item)
end
if space.family == family then
tinsert(slots, space)
end
end
sort(order, self.Rule)
return order, slots
end
function Sort:CanRun()
return not InCombatLockdown() and not UnitIsDead('player')
end
function Sort:FitsIn(id, family)
if family == 9 then
return GetItemFamily(id) == 256
end
return family == 0 or (bit.band(GetItemFamily(id), family) > 0 and select(9, GetItemInfo(id)) ~= 'INVTYPE_BAG')
end
function Sort.Rule(a, b)
for _,prop in pairs(Sort.Proprieties) do
if a[prop] ~= b[prop] then
return a[prop] > b[prop]
end
end
if a.space.family ~= b.space.family then
return a.space.family > b.space.family
end
return a.space.index < b.space.index
end
function Sort:Move(from, to)
if from.locked or to.locked or (to.item.id and not self:FitsIn(to.item.id, from.family)) then
return
end
ClearCursor()
PickupContainerItem(from.bag, from.slot)
PickupContainerItem(to.bag, to.slot)
ClearCursor()
from.locked = true
to.locked = true
return true
end

View file

@ -0,0 +1,9 @@
## Interface: 20400
## Title: Bagnon Config
## Notes: GUI based configuration for Bagnon
## Author: Tuller
## Dependencies: Bagnon
## LoadOnDemand: 1
localization.xml
widgets.xml
panels.xml

View file

@ -0,0 +1,9 @@
<Ui xmlns="http://www.blizzard.com/wow/ui/">
<Script file="localization\localization.lua"/>
<Script file="localization\localization.cn.lua"/>
<Script file="localization\localization.de.lua"/>
<Script file="localization\localization.fr.lua"/>
<Script file="localization\localization.ko.lua"/>
<Script file="localization\localization.ru.lua"/>
<Script file="localization\localization.tw.lua"/>
</Ui>

View file

@ -0,0 +1,54 @@
--[[
THIS FILE IS ENCODED IN UTF-8
Bagnon Config Localization Information: Chinese Simplified
Credits: Diablohu, yleaf@cwdg(yaroot@gmail.com), @cwdg(networm@qq.com)
Last Update: 2009/07/03 by @cwdg(networm@qq.com)
--]]
local L = LibStub('AceLocale-3.0'):NewLocale('Bagnon-Config', 'zhCN')
if not L then return end
L.Columns = '列数'
L.Scale = '缩放'
L.Spacing = '间距'
L.Opacity = '透明度'
L.FrameColor = '窗口颜色'
L.FrameBorderColor = '窗口边框颜色'
L.Frame = '窗口'
L.Inventory = '背包'
L.Bank = '银行'
L.KeyRing = '钥匙链'
L.LockFramePositions = '锁定位置'
L.ShowEmptyItemSlotBackground = '显示空格背景材质'
L.HighlightItemsByQuality = '按物品品质对物品染色'
L.HighlightQuestItems = '对任务物品染色'
L.ReverseSlotOrdering = '反向排列'
L.ColorItemSlotsByBagType = '按背包类型对空格染色'
L.FrameLayer = '窗口层级'
L.EnableBagFrame = '启用背包按钮'
L.EnableMoneyFrame = '启用货币窗口'
L.EnableDBOFrame = '启用信息窗口'
L.EnableSearchToggle = '启用搜索按钮'
L.EnableOptionsToggle = '启用设置按钮'
L.EnableSortButton = "Enable sort button"
L.EnableFrame_inventory = '启用背包框体'
L.EnableFrame_bank = '启用银行框体'
L.EnableFrame_keys = '启用钥匙链框体'
L.SettingRequiresRestart = '这个设置将在你下次登录时生效'
L.EnableAutoDisplay_bank = '打开银行时'
L.EnableAutoDisplay_ah = '打开拍卖行时'
L.EnableAutoDisplay_vendor = '与商贩对话时'
L.EnableAutoDisplay_trade = '交易时'
L.EnableAutoDisplay_craft = '制作物品时'
L.EnableAutoDisplay_mail = '打开邮箱时'
L.EnableAutoDisplay_guildbank = '打开公会银行时'
L.DisplaySettings = '事件设置'
L.DisplaySettingsTitle = '何时自动打开背包'
L.FrameSettings = '显示设置'
L.FrameSettingsTitle = '窗口显示设置'
L.GeneralSettings = '通用设置'
L.GeneralSettingsTitle = 'Bagnon的通用设置'
L.EnableBlizzardBagPassThrough = '禁用的背包使用暴雪默认框体'

View file

@ -0,0 +1,58 @@
--[[
Bagnon Config Localization Information: German Language
--]]
local L = LibStub('AceLocale-3.0'):NewLocale('Bagnon-Config', 'deDE')
if not L then return end
L.Columns = 'Spalten'
L.Scale = 'Skalierung'
L.Spacing = 'Abstand'
L.Opacity = 'Transparenz'
L.FrameColor = 'Farbe des Fensters'
L.FrameBorderColor = 'Farbe des Fensterrands'
L.Frame = 'Fenster'
L.Inventory = 'Inventar'
L.Bank = 'Bank'
L.KeyRing = 'Schl\195\188sselbund'
L.GuildBank = 'Gildenbank'
L.LockFramePositions = 'Fensterpositionen sperren'
L.ShowEmptyItemSlotBackground = 'Zeige einen Hintergrund f\195\188r leere Gegenstandslots'
L.HighlightItemsByQuality = 'Gegenst\195\164nde nach der Seltenheit hervorheben'
L.HighlightQuestItems = 'Questgegenst\195\164nde hervorheben'
L.ReverseSlotOrdering = 'Anordnung der Slots umdrehen'
L.ColorItemSlotsByBagType = 'Leere Gegenstandslots nach der Taschen-Art einf\195\164rben'
L.FrameLayer = 'Layer'
L.EnableBagFrame = 'Taschen-Anzeige aktivieren'
L.EnableMoneyFrame = 'Gold-Anzeige aktivieren'
L.EnableDBOFrame = 'Databroker-Anzeige aktivieren'
L.EnableSearchToggle = 'Suchfeld aktivieren'
L.EnableOptionsToggle = 'Schalter f\195\188r die Optionen aktivieren'
L.EnableSortButton = "Schalter f\195\188r den Sortierfunktion"
L.EnableFrame_inventory = 'Inventar aktivieren'
L.EnableFrame_bank = 'Bank aktivieren'
L.EnableFrame_keys = 'Schl\195\188sselbund aktivieren'
L.SettingRequiresRestart = 'Diese Einstellung wird nach dem n\195\164chsten Einloggen in Kraft treten'
L.EnableAutoDisplay_bank = 'Inventar anzeigen, wenn die Bank besucht wird'
L.EnableAutoDisplay_ah = 'Inventar anzeigen, wenn das Auktionshaus besucht wird'
L.EnableAutoDisplay_vendor = 'Inventar anzeigen, wenn ein H\195\164ndler besucht wird'
L.EnableAutoDisplay_trade = 'Inventar beim Handeln von Gegenst\195\164nden anzeigen'
L.EnableAutoDisplay_craft = 'Inventar beim Herstellen anzeigen'
L.EnableAutoDisplay_mail = 'Inventar beim Abholen der Post anzeigen'
L.EnableAutoDisplay_guildbank = 'Inventar anzeigen, wenn die Gildenbank besucht wird'
L.EnableAutoDisplay_player = 'Inventar anzeigen, wenn das Spielerfenster ge\195\182ffnet wird'
L.DisplaySettings = 'Automatische Anzeige'
L.DisplaySettingsTitle = 'Einstellungen f\195\188r das automatische \195\150ffnen der Fenster'
L.FrameSettings = 'Fenstereinstellungen'
L.FrameSettingsTitle = 'Einstellungen f\195\188r ein bestimmtes Bagnon Fenster anpassen'
L.GeneralSettings = 'Allgemeine Einstellungen'
L.GeneralSettingsTitle = 'Allgemeine Einstellungen f\195\188r Bagnon anpassen'
L.EnableBlizzardBagPassThrough = 'Blizzard Fenster f\195\188r die deaktivierten Taschen anzeigen'
L.EnableBagBreak = 'Trennen der Taschen aktivieren'
L.ColorSettings = 'Farbeinstellungen'
L.ColorSettingsTitle = 'Einstellungen f\195\188r das Einf\195\164rben der Gegenstandslots'
L.ItemHighlightOpacity = 'Helligkeit der Gegenstandshervorhebung'
L.ItemSlotColor_ammo = 'Farbe f\195\188r die Slots der Munitionstasche'
L.ItemSlotColor_trade = 'Farbe f\195\188r die Slots der Handeltasche'
L.ItemSlotColor_shard = 'Farbe f\195\188r die Slots der Seelentasche'
L.ItemSlotColor_keyring = 'Farbe f\195\188r die Slots des Schl\195\188sselbunds'

View file

@ -0,0 +1,58 @@
--[[
Bagnon Config Localization Information: English Language
This file must be present to have partial translations
--]]
local L = LibStub('AceLocale-3.0'):NewLocale('Bagnon-Config', 'enUS', true)
L.Columns = 'Columns'
L.Scale = 'Scale'
L.Spacing = 'Spacing'
L.Opacity = 'Opacity'
L.FrameColor = 'Frame Color'
L.FrameBorderColor = 'Frame Border Color'
L.Frame = 'Frame'
L.Inventory = 'Inventory'
L.Bank = 'Bank'
L.KeyRing = 'Keyring'
L.GuildBank = 'Guild Bank'
L.LockFramePositions = 'Lock frame positions'
L.ShowEmptyItemSlotBackground = 'Display a background for empty item slots'
L.HighlightItemsByQuality = 'Highlight items by quality'
L.HighlightQuestItems = 'Highlight quest items'
L.ReverseSlotOrdering = 'Reverse bag slot ordering'
L.ColorItemSlotsByBagType = 'Color empty item slots by bag type'
L.FrameLayer = 'Layer'
L.EnableBagFrame = 'Enable bag frame'
L.EnableMoneyFrame = 'Enable money frame'
L.EnableDBOFrame = 'Enable databroker frame'
L.EnableSearchToggle = 'Enable search toggle'
L.EnableOptionsToggle = 'Enable options toggle'
L.EnableSortButton = "Enable sort button"
L.EnableFrame_inventory = 'Enable inventory frame'
L.EnableFrame_bank = 'Enable bank frame'
L.EnableFrame_keys = 'Enable keyring'
L.SettingRequiresRestart = 'This setting will take effect the next time you log in'
L.EnableAutoDisplay_bank = 'Display inventory when visiting the bank'
L.EnableAutoDisplay_ah = 'Display inventory when visiting the auction house'
L.EnableAutoDisplay_vendor = 'Display inventory when visiting a vendor'
L.EnableAutoDisplay_trade = 'Display inventory when trading items'
L.EnableAutoDisplay_craft = 'Display inventory when crafting'
L.EnableAutoDisplay_mail = 'Display inventory when checking a mailbox'
L.EnableAutoDisplay_guildbank = 'Display inventory when visiting the guild bank'
L.EnableAutoDisplay_player = 'Display inventory when opening the player frame'
L.DisplaySettings = 'Automatic Display'
L.DisplaySettingsTitle = 'Automatic frame display settings'
L.FrameSettings = 'Frame Settings'
L.FrameSettingsTitle = 'Configuration settings specific to a Bagnon frame'
L.GeneralSettings = 'General Settings'
L.GeneralSettingsTitle = 'General configuration settings for Bagnon'
L.EnableBlizzardBagPassThrough = 'Display Blizzard frames for disabled bags'
L.EnableBagBreak = 'Enable bag break layout'
L.ColorSettings = 'Color Settings'
L.ColorSettingsTitle = 'Item slot coloring settings'
L.ItemHighlightOpacity = 'Item highlight brightness'
L.ItemSlotColor_ammo = 'Ammo bag slot color'
L.ItemSlotColor_trade = 'Trade bag slot color'
L.ItemSlotColor_shard = 'Soul bag slot color'
L.ItemSlotColor_keyring = 'Keyring slot color'

View file

@ -0,0 +1,59 @@
--[[
Bagnon Config Localization Information: Translated by StingerSoft
This file must be present to have partial translations
--]]
local L = LibStub('AceLocale-3.0'):NewLocale('Bagnon-Config', 'ruRU')
if not L then return end
L.Columns = 'Колонок'
L.Scale = 'Масштаб'
L.Spacing = 'Промежуток'
L.Opacity = 'Прозрачность'
L.FrameColor = 'Цвет окна'
L.FrameBorderColor = 'Цвет граници окна'
L.Frame = 'Окно'
L.Inventory = 'Инвентарь'
L.Bank = 'Банк'
L.KeyRing = 'Связка ключей'
L.GuildBank = 'Банк гильдии'
L.LockFramePositions = 'Закрепить позицию окна'
L.ShowEmptyItemSlotBackground = 'Отображать фон пустых ячеек'
L.HighlightItemsByQuality = 'Подсветка предметов по качеству'
L.HighlightQuestItems = 'Подсветка предметов для задания'
L.ReverseSlotOrdering = 'Обратить порядок ячеек сумкок'
L.ColorItemSlotsByBagType = 'Цвет пустых ячеек по типу сумки'
L.FrameLayer = 'Слой окна'
L.EnableBagFrame = 'Показывать кнопку сумок'
L.EnableMoneyFrame = 'Показывать область денег'
L.EnableDBOFrame = 'Показывать область databroker'
L.EnableSearchToggle = 'Показывать кнопку поиска'
L.EnableOptionsToggle = 'Показывать кнопку настроек'
L.EnableSortButton = "Enable sort button"
L.EnableFrame_inventory = 'Включить область инвентаря'
L.EnableFrame_bank = 'Включить область банка'
L.EnableFrame_keys = 'Включить связку ключей'
L.SettingRequiresRestart = 'Настройки вступят в силу после следующего входа в игру или перезагрузки интерфейса,\nКомандой: /reloadui.'
L.EnableAutoDisplay_bank = 'Показать инвентарь при посещении банка.'
L.EnableAutoDisplay_ah = 'Показать инвентарь при посещении аукциона.'
L.EnableAutoDisplay_vendor = 'Показать инвентарь при посещении торговца.'
L.EnableAutoDisplay_trade = 'Показать инвентарь при обмене предметами.'
L.EnableAutoDisplay_craft = 'Показать инвентарь во время изготовления.'
L.EnableAutoDisplay_mail = 'Показать инвентарь во время просмотра почты.'
L.EnableAutoDisplay_guildbank = 'Показать инвентарь при посещении банка гильдии.'
L.EnableAutoDisplay_player = 'Показать инвентарь при открытии окна игрока.'
L.DisplaySettings = 'Настройки авто показа'
L.DisplaySettingsTitle = 'Настройки автоматического открытия окна.'
L.FrameSettings = 'Настройки окна'
L.FrameSettingsTitle = 'Настройка окна Bagnon.'
L.GeneralSettings = 'Основные настройки'
L.GeneralSettingsTitle = 'Основные настройки Bagnon.'
L.EnableBlizzardBagPassThrough = 'Открывать стандартные окна для отключенных сумок.'
L.EnableBagBreak = 'Включить прерывание размещения сумок'
L.ColorSettings = 'Настройка окраски'
L.ColorSettingsTitle = 'Настройки окраски ячеек предметов'
L.ItemHighlightOpacity = 'Яркость подсветки предметов'
L.ItemSlotColor_ammo = 'Окраска ячейки боеприпасов'
L.ItemSlotColor_trade = 'Окраска ячейки товаров'
L.ItemSlotColor_shard = 'Окраска ячейки камней'
L.ItemSlotColor_keyring = 'Окраска ячейки ключей'

View file

@ -0,0 +1,54 @@
--[[
THIS FILE IS ENCODED IN UTF-8
Bagnon Config Localization Information: Chinese Traditional
Credits: yleaf@cwdg(yaroot@gmail.com), @cwdg(networm@qq.com)
Last Update: 2009/07/03 by @cwdg(networm@qq.com)
--]]
local L = LibStub('AceLocale-3.0'):NewLocale('Bagnon-Config', 'zhTW')
if not L then return end
L.Columns = '列數'
L.Scale = '縮放'
L.Spacing = '間距'
L.Opacity = '透明度'
L.FrameColor = '窗口顏色'
L.FrameBorderColor = '窗口邊框顏色'
L.Frame = '窗口'
L.Inventory = '背包'
L.Bank = '銀行'
L.KeyRing = '鑰匙鏈'
L.LockFramePositions = '鎖定位置'
L.ShowEmptyItemSlotBackground = '顯示空格背景材質'
L.HighlightItemsByQuality = '按物品品質對物品染色'
L.HighlightQuestItems = '對任務物品染色'
L.ReverseSlotOrdering = '反向排列'
L.ColorItemSlotsByBagType = '按背包類型對空格染色'
L.FrameLayer = '窗口層級'
L.EnableBagFrame = '啟用背包按鈕'
L.EnableMoneyFrame = '啟用貨幣窗口'
L.EnableDBOFrame = '啟用資訊視窗'
L.EnableSearchToggle = '啟用搜索按鈕'
L.EnableOptionsToggle = '啟用設置按鈕'
L.EnableSortButton = "Enable sort button"
L.EnableFrame_inventory = '啟用背包框體'
L.EnableFrame_bank = '啟用銀行框體'
L.EnableFrame_keys = '啟用鑰匙鏈框體'
L.SettingRequiresRestart = '這個設置將在你下次登錄時生效'
L.EnableAutoDisplay_bank = '打開銀行時'
L.EnableAutoDisplay_ah = '打開拍賣行時'
L.EnableAutoDisplay_vendor = '與商販對話時'
L.EnableAutoDisplay_trade = '交易時'
L.EnableAutoDisplay_craft = '製作物品時'
L.EnableAutoDisplay_mail = '打開郵箱時'
L.EnableAutoDisplay_guildbank = '打開公會銀行時'
L.DisplaySettings = '事件設置'
L.DisplaySettingsTitle = '何時自動打開背包'
L.FrameSettings = '顯示設定'
L.FrameSettingsTitle = '窗口顯示設定'
L.GeneralSettings = '通用設置'
L.GeneralSettingsTitle = 'Bagnon的通用設置'
L.EnableBlizzardBagPassThrough = '禁用的背包使用暴雪默認框體'

6
Bagnon_Config/panels.xml Normal file
View file

@ -0,0 +1,6 @@
<Ui xmlns="http://www.blizzard.com/wow/ui/">
<Script file="panels\general.lua"/>
<Script file="panels\frameOptions.lua"/>
<Script file="panels\displayOptions.lua"/>
<Script file="panels\colorOptions.lua"/>
</Ui>

View file

@ -0,0 +1,276 @@
--[[
Frame.lua
General Bagnon settings
--]]
local Bagnon = LibStub('AceAddon-3.0'):GetAddon('Bagnon')
local L = LibStub('AceLocale-3.0'):GetLocale('Bagnon-Config')
local ColorOptions = Bagnon.OptionsPanel:New('BagnonOptions_Colors', 'Bagnon', L.ColorSettings, L.ColorSettingsTitle)
ColorOptions:Hide()
Bagnon.ColorOptions = ColorOptions
local SPACING = 4
local ITEM_SLOT_COLOR_TYPES = {'ammo', 'trade', 'shard', 'keyring'}
--[[
Startup
--]]
function ColorOptions:Load()
self:SetScript('OnShow', self.OnShow)
self:SetScript('OnHide', self.OnHide)
self:AddWidgets()
end
function ColorOptions:ShowFrame(frameID)
self:SetFrameID(frameID)
InterfaceOptionsFrame_OpenToCategory(self)
end
--[[
Messages
--]]
function ColorOptions:UpdateMessages()
if not self:IsVisible() then
self:UnregisterAllMessages()
return
end
self:RegisterMessage('ITEM_HIGHLIGHT_QUALITY_UPDATE')
self:RegisterMessage('ITEM_HIGHLIGHT_QUEST_UPDATE')
self:RegisterMessage('ITEM_SLOT_COLOR_ENABLED_UPDATE')
self:RegisterMessage('ITEM_SLOT_COLOR_UPDATE')
self:RegisterMessage('ITEM_HIGHLIGHT_OPACITY_UPDATE')
end
function ColorOptions:ITEM_HIGHLIGHT_QUALITY_UPDATE(msg, enable)
self:GetHighlightItemsByQualityCheckbox():UpdateChecked()
end
function ColorOptions:ITEM_HIGHLIGHT_QUEST_UPDATE(msg, enable)
self:GetHighlightQuestItemsCheckbox():UpdateChecked()
end
function ColorOptions:ITEM_SLOT_COLOR_ENABLED_UPDATE(msg, enable)
self:GetColorItemSlotsCheckbox():UpdateChecked()
end
function ColorOptions:ITEM_SLOT_COLOR_UPDATE(msg, type, r, g, b)
self:GetItemSlotColorSelector(type):SetColor(r, g, b, a)
end
function ColorOptions:ITEM_HIGHLIGHT_OPACITY_UPDATE(msg, value)
self:GetHighlightOpacitySlider():UpdateValue()
end
--[[
Frame Events
--]]
function ColorOptions:OnShow()
self:UpdateMessages()
end
function ColorOptions:OnHide()
self:UpdateMessages()
end
--[[
Components
--]]
function ColorOptions:AddWidgets()
local colorItemSlots = self:CreateColorItemSlotsCheckbox()
colorItemSlots:SetPoint('TOPLEFT', self, 'TOPLEFT', 14, -72)
local highlightItemsByQuality = self:CreateHighlightItemsByQualityCheckbox()
highlightItemsByQuality:SetPoint('TOPLEFT', colorItemSlots, 'BOTTOMLEFT', 0, -SPACING)
local highightQuestItems = self:CreateHighlightQuestItemsCheckbox()
highightQuestItems:SetPoint('TOPLEFT', highlightItemsByQuality, 'BOTTOMLEFT', 0, -SPACING)
local opacity = self:CreateHighlightOpacitySlider()
opacity:SetPoint('BOTTOMLEFT', self, 'BOTTOMLEFT', 16, 10)
opacity:SetPoint('BOTTOMRIGHT', self, 'BOTTOMRIGHT', -16, 10)
local lastCheckbox = highightQuestItems
local lastSelector = nil
for i, type in self:GetColorTypes() do
local selector = self:CreateItemSlotColorSelector(type)
if i == 1 then
selector:SetPoint('TOPLEFT', lastCheckbox, 'BOTTOMLEFT', 4, -(SPACING + 4))
else
selector:SetPoint('TOPLEFT', lastSelector, 'BOTTOMLEFT', 0, -(SPACING + 6))
end
lastSelector = selector
end
end
function ColorOptions:UpdateWidgets()
if not self:IsVisible() then
return
end
self:GetHighlightItemsByQualityCheckbox():UpdateChecked()
self:GetHighlightQuestItemsCheckbox():UpdateChecked()
self:GetColorItemSlotsCheckbox():UpdateChecked()
self:GetHighlightOpacitySlider():UpdateValue()
for i, type in self:GetColorTypes() do
local selector = self:GetItemSlotColorSelector(type)
selector:UpdateColor()
end
end
function ColorOptions:GetColorTypes()
return pairs(ITEM_SLOT_COLOR_TYPES)
end
--[[ Check Boxes ]]--
--highlight items by quality
function ColorOptions:CreateHighlightItemsByQualityCheckbox()
local button = Bagnon.OptionsCheckButton:New(L.HighlightItemsByQuality, self)
button.OnEnableSetting = function(self, enable)
Bagnon.Settings:SetHighlightItemsByQuality(enable)
end
button.IsSettingEnabled = function(self)
return Bagnon.Settings:HighlightingItemsByQuality()
end
self.highlightItemsByQualityCheckbox = button
return button
end
function ColorOptions:GetHighlightItemsByQualityCheckbox()
return self.highlightItemsByQualityCheckbox
end
--highlight quest items
function ColorOptions:CreateHighlightQuestItemsCheckbox()
local button = Bagnon.OptionsCheckButton:New(L.HighlightQuestItems, self)
button.OnEnableSetting = function(self, enable)
Bagnon.Settings:SetHighlightQuestItems(enable)
end
button.IsSettingEnabled = function(self)
return Bagnon.Settings:HighlightingQuestItems()
end
self.highlightQuestItemsCheckbox = button
return button
end
function ColorOptions:GetHighlightQuestItemsCheckbox()
return self.highlightQuestItemsCheckbox
end
--color item slots
function ColorOptions:CreateColorItemSlotsCheckbox()
local button = Bagnon.OptionsCheckButton:New(L.ColorItemSlotsByBagType, self)
button.OnEnableSetting = function(self, enable)
Bagnon.Settings:SetColorBagSlots(enable)
end
button.IsSettingEnabled = function(self)
return Bagnon.Settings:ColoringBagSlots()
end
self.colorItemSlotsCheckbox = button
return button
end
function ColorOptions:GetColorItemSlotsCheckbox()
return self.colorItemSlotsCheckbox
end
--[[ Sliders ]]--
--border opacity
function ColorOptions:CreateHighlightOpacitySlider()
local slider = Bagnon.OptionsSlider:New(L.ItemHighlightOpacity, self, 10, 100, 1)
slider.SetSavedValue = function(self, value)
Bagnon.Settings:SetHighlightOpacity(value / 100)
end
slider.GetSavedValue = function(self)
return Bagnon.Settings:GetHighlightOpacity() * 100
end
slider.GetFormattedText = function(self, value)
return value .. '%'
end
self.highlightOpacitySlider = slider
return slider
end
function ColorOptions:GetHighlightOpacitySlider()
return self.highlightOpacitySlider
end
--[[ Color Pickers ]]--
--frame color
function ColorOptions:CreateItemSlotColorSelector(type)
local selector = Bagnon.OptionsColorSelector:New(L['ItemSlotColor_' .. type], self, false)
selector.itemSlotType = type
selector.OnSetColor = function(self, r, g, b)
Bagnon.Settings:SetItemSlotColor(self.itemSlotType, r, g, b)
end
selector.GetColor = function(self)
return Bagnon.Settings:GetItemSlotColor(self.itemSlotType)
end
local colorSelectors = self.colorSelectors or {}
colorSelectors[type] = selector
self.colorSelectors = colorSelectors
return selector
end
function ColorOptions:GetItemSlotColorSelector(type)
return self.colorSelectors and self.colorSelectors[type]
end
--[[
Update Methods
--]]
function ColorOptions:SetFrameID(frameID)
if self:GetFrameID() ~= frameID then
self.frameID = frameID
self:UpdateWidgets()
end
end
function ColorOptions:GetFrameID()
return self.frameID
end
--[[ Load the thing ]]--
ColorOptions:Load()

View file

@ -0,0 +1,146 @@
--[[
Frame.lua
General Bagnon settings
--]]
local Bagnon = LibStub('AceAddon-3.0'):GetAddon('Bagnon')
local L = LibStub('AceLocale-3.0'):GetLocale('Bagnon-Config')
local DisplayOptions = Bagnon.OptionsPanel:New('BagnonOptions_Display', 'Bagnon', L.DisplaySettings, L.DisplaySettingsTitle)
DisplayOptions:Hide()
Bagnon.DisplayOptions = DisplayOptions
local SPACING = 4
--[[
Startup
--]]
function DisplayOptions:Load()
self:SetScript('OnShow', self.OnShow)
self:SetScript('OnHide', self.OnHide)
self:AddWidgets()
self:SetFrameID('inventory')
end
function DisplayOptions:ShowFrame(frameID)
self:SetFrameID(frameID)
InterfaceOptionsFrame_OpenToCategory(self)
end
--[[
Messages
--]]
function DisplayOptions:UpdateMessages()
if self:IsVisible() then
self:RegisterMessage('FRAME_DISPLAY_EVENT_UPDATE')
else
self:UnregisterMessage('FRAME_DISPLAY_EVENT_UPDATE')
end
end
function DisplayOptions:FRAME_DISPLAY_EVENT_UPDATE(msg, frameID, event, enable)
if self:GetFrameID() == frameID then
self:GetDisplayEventCheckbox(event):UpdateChecked()
end
end
--[[
Frame Events
--]]
function DisplayOptions:OnShow()
self:UpdateMessages()
end
function DisplayOptions:OnHide()
self:UpdateMessages()
end
--[[
Components
--]]
function DisplayOptions:AddWidgets()
local displayEvents = {'bank', 'ah', 'vendor', 'trade', 'guildbank', 'craft', 'player'}
for i, event in ipairs(displayEvents) do
self:AddDisplayEventCheckbox(event)
end
end
function DisplayOptions:UpdateWidgets()
if not self:IsVisible() then
return
end
for i, button in self:GetDisplayEventCheckboxes() do
button:UpdateChecked()
end
end
--[[ Check Boxes ]]--
--bag frame
function DisplayOptions:AddDisplayEventCheckbox(event)
local button = Bagnon.OptionsCheckButton:New(L['EnableAutoDisplay_' .. event], self)
button.event = event
button.OnEnableSetting = function(self, enable)
Bagnon.Settings:SetShowFrameAtEvent(self:GetParent():GetFrameID(), self.event, enable)
end
button.IsSettingEnabled = function(self, enable)
return Bagnon.Settings:IsFrameShownAtEvent(self:GetParent():GetFrameID(), self.event)
end
if self.displayEventCheckboxes then
button:SetPoint('TOPLEFT', self.displayEventCheckboxes[#self.displayEventCheckboxes], 'BOTTOMLEFT', 0, -SPACING)
else
self.displayEventCheckboxes = {}
button:SetPoint('TOPLEFT', self, 'TOPLEFT', 14, -72)
end
table.insert(self.displayEventCheckboxes, button)
return button
end
function DisplayOptions:GetDisplayEventCheckbox(event)
for i, button in self:GetDisplayEventCheckboxes() do
if button.event == event then
return button
end
end
return false
end
function DisplayOptions:GetDisplayEventCheckboxes()
return ipairs(self.displayEventCheckboxes)
end
--[[
Update Methods
--]]
function DisplayOptions:SetFrameID(frameID)
if self:GetFrameID() ~= frameID then
self.frameID = frameID
self:UpdateWidgets()
end
end
function DisplayOptions:GetFrameID()
return self.frameID
end
--[[ Load the thing ]]--
DisplayOptions:Load()

View file

@ -0,0 +1,664 @@
--[[
Frame.lua
General Bagnon settings
--]]
local Bagnon = LibStub('AceAddon-3.0'):GetAddon('Bagnon')
local L = LibStub('AceLocale-3.0'):GetLocale('Bagnon-Config')
local FrameOptions = Bagnon.OptionsPanel:New('BagnonOptions_Frame', 'Bagnon', L.FrameSettings, L.FrameSettingsTitle)
FrameOptions:Hide()
Bagnon.FrameOptions = FrameOptions
local CHECK_BUTTON_SPACING = 4
--[[
Startup
--]]
function FrameOptions:Load()
self:SetFrameID('inventory')
self:SetScript('OnShow', self.OnShow)
self:SetScript('OnHide', self.OnHide)
self:AddWidgets()
end
function FrameOptions:ShowFrame(frameID)
self:SetFrameID(frameID)
InterfaceOptionsFrame_OpenToFrame(self)
end
--[[
Messages
--]]
function FrameOptions:UpdateMessages()
if not self:IsVisible() then
self:UnregisterAllMessages()
return
end
self:RegisterMessage('FRAME_LAYER_UPDATE')
self:RegisterMessage('FRAME_SCALE_UPDATE')
self:RegisterMessage('FRAME_OPACITY_UPDATE')
self:RegisterMessage('FRAME_COLOR_UPDATE')
self:RegisterMessage('FRAME_BORDER_COLOR_UPDATE')
self:RegisterMessage('ITEM_FRAME_SPACING_UPDATE')
self:RegisterMessage('ITEM_FRAME_COLUMNS_UPDATE')
self:RegisterMessage('BAG_FRAME_ENABLE_UPDATE')
self:RegisterMessage('MONEY_FRAME_ENABLE_UPDATE')
self:RegisterMessage('DATABROKER_FRAME_ENABLE_UPDATE')
self:RegisterMessage('SEARCH_TOGGLE_ENABLE_UPDATE')
self:RegisterMessage('SORT_BUTTON_ENABLE_UPDATE')
self:RegisterMessage('SLOT_ORDER_UPDATE')
self:RegisterMessage('OPTIONS_TOGGLE_ENABLE_UPDATE')
end
function FrameOptions:FRAME_LAYER_UPDATE(msg, frameID, layer)
if self:GetFrameID() == frameID then
self:GetLayerSlider():UpdateValue()
end
end
function FrameOptions:FRAME_SCALE_UPDATE(msg, frameID, scale)
if self:GetFrameID() == frameID then
self:GetScaleSlider():UpdateValue()
end
end
function FrameOptions:FRAME_OPACITY_UPDATE(msg, frameID, opacity)
if self:GetFrameID() == frameID then
self:GetOpacitySlider():UpdateValue()
end
end
function FrameOptions:FRAME_COLOR_UPDATE(msg, frameID, r, g, b, a)
if self:GetFrameID() == frameID then
self:GetColorSelector():SetColor(r, g, b, a)
end
end
function FrameOptions:FRAME_BORDER_COLOR_UPDATE(msg, frameID, r, g, b, a)
if self:GetFrameID() == frameID then
self:GetBorderColorSelector():SetColor(r, g, b, a)
end
end
function FrameOptions:ITEM_FRAME_SPACING_UPDATE(msg, frameID, spacing)
if self:GetFrameID() == frameID then
self:GetSpacingSlider():UpdateValue()
end
end
function FrameOptions:ITEM_FRAME_COLUMNS_UPDATE(msg, frameID, columns)
if self:GetFrameID() == frameID then
self:GetColumnsSlider():UpdateValue()
end
end
function FrameOptions:BAG_FRAME_ENABLE_UPDATE(msg, frameID, enable)
if self:GetFrameID() == frameID then
self:GetToggleBagFrameCheckbox():UpdateChecked()
end
end
function FrameOptions:MONEY_FRAME_ENABLE_UPDATE(msg, frameID, enable)
if self:GetFrameID() == frameID then
self:GetToggleMoneyFrameCheckbox():UpdateChecked()
end
end
function FrameOptions:DATABROKER_FRAME_ENABLE_UPDATE(msg, frameID, enable)
if self:GetFrameID() == frameID then
self:GetToggleDBOFrameCheckbox():UpdateChecked()
end
end
function FrameOptions:SEARCH_TOGGLE_ENABLE_UPDATE(msg, frameID, enable)
if self:GetFrameID() == frameID then
self:GetToggleSearchFrameCheckbox():UpdateChecked()
end
end
function FrameOptions:SORT_BUTTON_ENABLE_UPDATE(msg, frameID, enable)
if self:GetFrameID() == frameID then
self:GetSortButtonCheckbox():UpdateChecked()
end
end
function FrameOptions:SLOT_ORDER_UPDATE(msg, frameID, enable)
if self:GetFrameID() == frameID then
self:GetReverseSlotOrderCheckbox():UpdateChecked()
end
end
function FrameOptions:ITEM_FRAME_BAG_BREAK_UPDATE(msg, frameID, enable)
if self:GetFrameID() == frameID then
self:GetBagBreakCheckbox():UpdateChecked()
end
end
function FrameOptions:OPTIONS_TOGGLE_ENABLE_UPDATE(msg, frameID, enable)
if self:GetFrameID() == frameID then
self:GetToggleOptionsCheckbox():UpdateChecked()
end
end
--[[
Frame Events
--]]
function FrameOptions:OnShow()
self:UpdateMessages()
self:UpdateWidgets()
end
function FrameOptions:OnHide()
self:UpdateMessages()
end
--[[
Components
--]]
function FrameOptions:AddWidgets()
--[[ Dropdowns ]]--
--add frame selector
local frameSelector = self:CreateFrameSelector()
frameSelector:SetPoint('TOPLEFT', self, 'TOPLEFT', -4, -64)
--[[ Checkboxes ]]--
local toggleBagFrame = self:CreateToggleBagFrameCheckbox()
toggleBagFrame:SetPoint('TOPLEFT', frameSelector, 'BOTTOMLEFT', 16, -4)
local toggleMoneyFrame = self:CreateToggleMoneyFrameCheckbox()
toggleMoneyFrame:SetPoint('TOPLEFT', toggleBagFrame, 'BOTTOMLEFT', 0, -CHECK_BUTTON_SPACING)
local toggleDBOFrame = self:CreateToggleDBOFrameCheckbox()
toggleDBOFrame:SetPoint('TOPLEFT', toggleMoneyFrame, 'BOTTOMLEFT', 0, -CHECK_BUTTON_SPACING)
local sortButtonFrame = self:CreateSortButtonCheckbox()
sortButtonFrame:SetPoint('TOPLEFT', toggleDBOFrame, 'BOTTOMLEFT', 0, -CHECK_BUTTON_SPACING)
local toggleSearchFrame = self:CreateToggleSearchFrameCheckbox()
toggleSearchFrame:SetPoint('TOPLEFT', sortButtonFrame, 'BOTTOMLEFT', 0, -CHECK_BUTTON_SPACING)
local toggleOptionsFrame = self:CreateToggleOptionsCheckbox()
toggleOptionsFrame:SetPoint('TOPLEFT', toggleSearchFrame, 'BOTTOMLEFT', 0, -CHECK_BUTTON_SPACING)
local reverseSlotOrdering = self:CreateReverseSlotOrderCheckbox()
reverseSlotOrdering:SetPoint('TOPLEFT', toggleOptionsFrame, 'BOTTOMLEFT', 0, -CHECK_BUTTON_SPACING)
local bagBreak = self:CreateBagBreakCheckbox()
bagBreak:SetPoint('TOPLEFT', reverseSlotOrdering, 'BOTTOMLEFT', 0, -CHECK_BUTTON_SPACING)
--[[ Color Selectors ]]--
--add color selector
local frameColor = self:CreateColorSelector()
frameColor:SetPoint('TOPLEFT', frameSelector, 'BOTTOMRIGHT', -28, -6)
--add border colors selector
local frameBorderColor = self:CreateBorderColorSelector()
frameBorderColor:SetPoint('TOPLEFT', frameColor, 'BOTTOMLEFT', 0, -8)
--[[ Sliders ]]--
--add opacity slider
local opacity = self:CreateOpacitySlider()
opacity:SetWidth(180)
opacity:SetPoint('BOTTOMRIGHT', self, 'BOTTOMRIGHT', -16, 10)
local scale = self:CreateScaleSlider()
scale:SetPoint('BOTTOMLEFT', opacity, 'TOPLEFT', 0, 20)
scale:SetPoint('BOTTOMRIGHT', opacity, 'TOPRIGHT', 0, 20)
local spacing = self:CreateSpacingSlider()
spacing:SetPoint('BOTTOMLEFT', scale, 'TOPLEFT', 0, 20)
spacing:SetPoint('BOTTOMRIGHT', scale, 'TOPRIGHT', 0, 20)
local cols = self:CreateColumnsSlider()
cols:SetPoint('BOTTOMLEFT', spacing, 'TOPLEFT', 0, 20)
cols:SetPoint('BOTTOMRIGHT', spacing, 'TOPRIGHT', 0, 20)
local layer = self:CreateLayerSlider()
layer:SetPoint('BOTTOMLEFT', cols, 'TOPLEFT', 0, 20)
layer:SetPoint('BOTTOMRIGHT', cols, 'TOPRIGHT', 0, 20)
end
function FrameOptions:UpdateWidgets()
if not self:IsVisible() then
return
end
local settings = self:GetSettings()
self:GetColorSelector():SetColor(settings:GetColor())
self:GetBorderColorSelector():SetColor(settings:GetBorderColor())
self:GetColumnsSlider():UpdateValue()
self:GetSpacingSlider():UpdateValue()
self:GetScaleSlider():UpdateValue()
self:GetOpacitySlider():UpdateValue()
self:GetLayerSlider():UpdateValue()
self:GetToggleBagFrameCheckbox():UpdateChecked()
self:GetToggleBagFrameCheckbox():SetDisabled(self:GetFrameID() == 'keys' or self:GetFrameID() == 'guildbank')
self:GetToggleMoneyFrameCheckbox():UpdateChecked()
self:GetToggleDBOFrameCheckbox():UpdateChecked()
self:GetToggleSearchFrameCheckbox():UpdateChecked()
self:GetToggleOptionsCheckbox():UpdateChecked()
self:GetSortButtonCheckbox():UpdateChecked()
self:GetReverseSlotOrderCheckbox():UpdateChecked()
self:GetReverseSlotOrderCheckbox():SetDisabled(self:GetFrameID() == 'guildbank')
self:GetBagBreakCheckbox():UpdateChecked()
self:GetBagBreakCheckbox():SetDisabled(self:GetFrameID() == 'keys' or self:GetFrameID() == 'guildbank')
end
--[[ Dropdowns ]]--
--frame selector
function FrameOptions:CreateFrameSelector()
local dropdown = Bagnon.OptionsDropdown:New(L.Frame, self, 200)
dropdown.titleText:Hide()
dropdown.Initialize = function(self)
dropdown:AddItem(L.Inventory, 'inventory')
dropdown:AddItem(L.Bank, 'bank')
dropdown:AddItem(L.KeyRing, 'keys')
if IsAddOnLoaded('Bagnon_GuildBank') then
dropdown:AddItem(L.GuildBank, 'guildbank')
end
end
dropdown.SetSavedValue = function(self, value)
self:GetParent():SetFrameID(value)
end
dropdown.GetSavedValue = function(self)
return self:GetParent():GetFrameID()
end
self.frameSelector = dropdown
return dropdown
end
function FrameOptions:GetFrameSelector()
return self.frameSelector
end
--[[ Color Pickers ]]--
--frame color
function FrameOptions:CreateColorSelector()
local selector = Bagnon.OptionsColorSelector:New(L.FrameColor, self, true)
selector.OnSetColor = function(self, r, g, b, a)
self:GetParent():GetSettings():SetColor(r, g, b, a)
end
selector.GetColor = function(self)
return self:GetParent():GetSettings():GetColor()
end
self.colorSelector = selector
return selector
end
function FrameOptions:GetColorSelector()
return self.colorSelector
end
--background color
function FrameOptions:CreateBorderColorSelector()
local selector = Bagnon.OptionsColorSelector:New(L.FrameBorderColor, self, true)
selector.OnSetColor = function(self, r, g, b, a)
self:GetParent():GetSettings():SetBorderColor(r, g, b, a)
end
selector.GetColor = function(self)
return self:GetParent():GetSettings():GetBorderColor()
end
self.borderColorSelector = selector
return selector
end
function FrameOptions:GetBorderColorSelector()
return self.borderColorSelector
end
--[[ Sliders ]]--
--columns
function FrameOptions:CreateColumnsSlider()
local slider = Bagnon.OptionsSlider:New(L.Columns, self, 4, 36, 1)
slider.SetSavedValue = function(self, value)
self:GetParent():GetSettings():SetItemFrameColumns(value)
end
slider.GetSavedValue = function(self)
return self:GetParent():GetSettings():GetItemFrameColumns()
end
self.columnsSlider = slider
return slider
end
function FrameOptions:GetColumnsSlider()
return self.columnsSlider
end
--spacing
function FrameOptions:CreateSpacingSlider()
local slider = Bagnon.OptionsSlider:New(L.Spacing, self, -16, 36, 2)
slider.SetSavedValue = function(self, value)
self:GetParent():GetSettings():SetItemFrameSpacing(value)
end
slider.GetSavedValue = function(self)
return self:GetParent():GetSettings():GetItemFrameSpacing()
end
self.spacingSlider = slider
return slider
end
function FrameOptions:GetSpacingSlider()
return self.spacingSlider
end
--scale
function FrameOptions:CreateScaleSlider()
local slider = Bagnon.OptionsSlider:New(L.Scale, self, 50, 200, 5)
slider.SetSavedValue = function(self, value)
self:GetParent():GetSettings():SetScale(value / 100)
end
slider.GetSavedValue = function(self)
return self:GetParent():GetSettings():GetScale() * 100
end
slider.GetFormattedText = function(self, value)
return value .. '%'
end
self.scaleSlider = slider
return slider
end
function FrameOptions:GetScaleSlider()
return self.scaleSlider
end
--opacity
function FrameOptions:CreateOpacitySlider()
local slider = Bagnon.OptionsSlider:New(L.Opacity, self, 10, 100, 1)
slider.SetSavedValue = function(self, value)
self:GetParent():GetSettings():SetOpacity(value / 100)
end
slider.GetSavedValue = function(self)
return self:GetParent():GetSettings():GetOpacity() * 100
end
slider.GetFormattedText = function(self, value)
return value .. '%'
end
self.opacitySlider = slider
return slider
end
function FrameOptions:GetOpacitySlider()
return self.opacitySlider
end
--layer
function FrameOptions:CreateLayerSlider()
local availableLayers = self:GetSettings():GetAvailableLayers()
local slider = Bagnon.OptionsSlider:New(L.FrameLayer, self, 1, #availableLayers, 1)
slider.layers = availableLayers
slider.SetSavedValue = function(self, value)
self:GetParent():GetSettings():SetLayer(self.layers[value])
end
slider.GetSavedValue = function(self)
local layer = self:GetParent():GetSettings():GetLayer()
for k, v in pairs(self.layers) do
if v == layer then
return k
end
end
return 1
end
slider.GetFormattedText = function(self, value)
return self.layers[value]
end
self.layerSlider = slider
return slider
end
function FrameOptions:GetLayerSlider()
return self.layerSlider
end
--[[ Check Boxes ]]--
--bag frame
function FrameOptions:CreateToggleBagFrameCheckbox()
local button = Bagnon.OptionsCheckButton:New(L.EnableBagFrame, self)
button.OnEnableSetting = function(self, enable)
self:GetParent():GetSettings():SetHasBagFrame(enable)
end
button.IsSettingEnabled = function(self, enable)
return self:GetParent():GetSettings():HasBagFrame()
end
self.toggleBagFrameCheckbox = button
return button
end
function FrameOptions:GetToggleBagFrameCheckbox()
return self.toggleBagFrameCheckbox
end
--money frame
function FrameOptions:CreateToggleMoneyFrameCheckbox()
local button = Bagnon.OptionsCheckButton:New(L.EnableMoneyFrame, self)
button.OnEnableSetting = function(self, enable)
self:GetParent():GetSettings():SetHasMoneyFrame(enable)
end
button.IsSettingEnabled = function(self, enable)
return self:GetParent():GetSettings():HasMoneyFrame()
end
self.toggleMoneyFrameCheckbox = button
return button
end
function FrameOptions:GetToggleMoneyFrameCheckbox()
return self.toggleMoneyFrameCheckbox
end
--databroker frame
function FrameOptions:CreateToggleDBOFrameCheckbox()
local button = Bagnon.OptionsCheckButton:New(L.EnableDBOFrame, self)
button.OnEnableSetting = function(self, enable)
self:GetParent():GetSettings():SetHasDBOFrame(enable)
end
button.IsSettingEnabled = function(self, enable)
return self:GetParent():GetSettings():HasDBOFrame()
end
self.toggleDBOFrameCheckbox = button
return button
end
function FrameOptions:GetToggleDBOFrameCheckbox()
return self.toggleDBOFrameCheckbox
end
--search frame toggle
function FrameOptions:CreateToggleSearchFrameCheckbox()
local button = Bagnon.OptionsCheckButton:New(L.EnableSearchToggle, self)
button.OnEnableSetting = function(self, enable)
self:GetParent():GetSettings():SetHasSearchToggle(enable)
end
button.IsSettingEnabled = function(self, enable)
return self:GetParent():GetSettings():HasSearchToggle()
end
self.toggleSearchFrameCheckbox = button
return button
end
function FrameOptions:GetToggleSearchFrameCheckbox()
return self.toggleSearchFrameCheckbox
end
--options frame toggle
function FrameOptions:CreateToggleOptionsCheckbox()
local button = Bagnon.OptionsCheckButton:New(L.EnableOptionsToggle, self)
button.OnEnableSetting = function(self, enable)
self:GetParent():GetSettings():SetHasOptionsToggle(enable)
end
button.IsSettingEnabled = function(self, enable)
return self:GetParent():GetSettings():HasOptionsToggle()
end
self.toggleOptionsCheckbox = button
return button
end
function FrameOptions:GetToggleOptionsCheckbox()
return self.toggleOptionsCheckbox
end
--options sort button
function FrameOptions:CreateSortButtonCheckbox()
local button = Bagnon.OptionsCheckButton:New(L.EnableSortButton, self)
button.OnEnableSetting = function(self, enable)
self:GetParent():GetSettings():SetHasSortButton(enable)
end
button.IsSettingEnabled = function(self, enable)
return self:GetParent():GetSettings():HasSortButton()
end
self.sortButtonCheckbox = button
return button
end
function FrameOptions:GetSortButtonCheckbox()
return self.sortButtonCheckbox
end
--reverse slot ordering
function FrameOptions:CreateReverseSlotOrderCheckbox()
local button = Bagnon.OptionsCheckButton:New(L.ReverseSlotOrdering, self)
button.OnEnableSetting = function(self, enable)
self:GetParent():GetSettings():SetReverseSlotOrder(enable)
end
button.IsSettingEnabled = function(self)
return self:GetParent():GetSettings():IsSlotOrderReversed()
end
self.reverseSlotOrderCheckbox = button
return button
end
function FrameOptions:GetReverseSlotOrderCheckbox()
return self.reverseSlotOrderCheckbox
end
--bag break layout
function FrameOptions:CreateBagBreakCheckbox()
local button = Bagnon.OptionsCheckButton:New(L.EnableBagBreak, self)
button.OnEnableSetting = function(self, enable)
self:GetParent():GetSettings():SetBagBreak(enable)
end
button.IsSettingEnabled = function(self)
return self:GetParent():GetSettings():IsBagBreakEnabled()
end
self.bagBreakCheckbox = button
return button
end
function FrameOptions:GetBagBreakCheckbox()
return self.bagBreakCheckbox
end
--[[
Update Methods
--]]
function FrameOptions:SetFrameID(frameID)
if self:GetFrameID() ~= frameID then
self.frameID = frameID
self:UpdateWidgets()
end
end
function FrameOptions:GetFrameID()
return self.frameID
end
function FrameOptions:GetSettings()
return Bagnon.FrameSettings:Get(self:GetFrameID())
end
--[[ Load the thing ]]--
FrameOptions:Load()

View file

@ -0,0 +1,223 @@
--[[
General.lua
General Bagnon settings
--]]
local Bagnon = LibStub('AceAddon-3.0'):GetAddon('Bagnon')
local L = LibStub('AceLocale-3.0'):GetLocale('Bagnon-Config')
--a hack panel, this is designed to force open to the general options panel when clicked
local BagnonOptions = Bagnon.OptionsPanel:New('Bagnon', nil, 'Bagnon')
BagnonOptions:SetScript('OnShow', function(self)
InterfaceOptionsFrame_OpenToFrame(Bagnon.GeneralOptions)
self:Hide()
end)
local GeneralOptions = Bagnon.OptionsPanel:New('BagnonOptions_General', 'Bagnon', L.GeneralSettings, L.GeneralSettingsTitle)
Bagnon.GeneralOptions = GeneralOptions
local SPACING = 6
--[[
Startup
--]]
function GeneralOptions:Load()
self:AddWidgets()
self:UpdateMessages()
end
--[[
Frame Events
--]]
function GeneralOptions:OnShow()
self:UpdateMessages()
end
function GeneralOptions:OnHide()
self:UpdateMessages()
end
--[[
Messages
--]]
function GeneralOptions:UpdateMessages()
if not self:IsVisible() then
self:UnregisterAllMessages()
return
end
self:RegisterMessage('SHOW_EMPTY_ITEM_SLOT_TEXTURE_UPDATE')
self:RegisterMessage('LOCK_FRAME_POSITIONS_UPDATE')
self:RegisterMessage('ENABLE_FRAME_UPDATE')
self:RegisterMessage('BLIZZARD_BAG_PASSTHROUGH_UPDATE')
end
function GeneralOptions:SHOW_EMPTY_ITEM_SLOT_TEXTURE_UPDATE(msg, enable)
self:GetEmptyItemSlotTextureCheckbox():UpdateChecked()
end
function GeneralOptions:LOCK_FRAME_POSITIONS_UPDATE(msg, enable)
self:GetLockFramePositionsCheckbox():UpdateChecked()
end
function GeneralOptions:ENABLE_FRAME_UPDATE(msg, frameID, enable)
self:GetEnableFrameCheckbox(frameID):UpdateChecked()
end
function GeneralOptions:BLIZZARD_BAG_PASSTHROUGH_UPDATE(msg, enable)
self:GetBlizzardBagPassThroughCheckbox():UpdateChecked()
end
--[[
Widgets
--]]
function GeneralOptions:AddWidgets()
local enableInventory = self:CreateEnableFrameCheckbox('inventory')
enableInventory:SetPoint('TOPLEFT', self, 'TOPLEFT', 14, -72)
local enableBank = self:CreateEnableFrameCheckbox('bank')
enableBank:SetPoint('TOPLEFT', enableInventory, 'BOTTOMLEFT', 0, -SPACING)
local enableKeyring = self:CreateEnableFrameCheckbox('keys')
enableKeyring:SetPoint('TOPLEFT', enableBank, 'BOTTOMLEFT', 0, -SPACING)
local lockFramePositions = self:CreateLockFramePositionsCheckbox()
lockFramePositions:SetPoint('TOPLEFT', enableKeyring, 'BOTTOMLEFT', 0, -SPACING)
local showEmptyItemSlotTextures = self:CreateEmptyItemSlotTextureCheckbox()
showEmptyItemSlotTextures:SetPoint('TOPLEFT', lockFramePositions, 'BOTTOMLEFT', 0, -SPACING)
local enableBlizzardBagPassThrough = self:CreateBlizzardBagPassThroughCheckbox()
enableBlizzardBagPassThrough:SetPoint('TOPLEFT', showEmptyItemSlotTextures, 'BOTTOMLEFT', 0, -SPACING)
end
function GeneralOptions:UpdateWidgets()
if not self:IsVisible() then
return
end
self:GetEnableFrameCheckbox('inventory'):UpdateChecked()
self:GetEnableFrameCheckbox('bank'):UpdateChecked()
self:GetEnableFrameCheckbox('keyring'):UpdateChecked()
self:GetEmptyItemSlotTextureCheckbox():UpdateChecked()
self:GetHighlightItemsByQualityCheckbox():UpdateChecked()
self:GetHighlightQuestItemsCheckbox():UpdateChecked()
self:GetColorItemSlotsCheckbox():UpdateChecked()
self:GetBlizzardBagPassThroughCheckbox():UpdateChecked()
end
--[[ Checkboxes ]]--
function GeneralOptions:CreateEnableFrameCheckbox(frameID)
local button = Bagnon.OptionsCheckButton:New(L['EnableFrame_' .. frameID], self)
button.frameID = frameID
button.OnEnableSetting = function(self, enable)
Bagnon.Settings:SetEnableFrame(self.frameID, enable)
GeneralOptions:DisplayRequiresRestartPopup()
end
button.IsSettingEnabled = function(self)
return Bagnon.Settings:WillFrameBeEnabled(self.frameID)
end
self['enableFrame_' .. frameID .. '_Checkbox'] = button
return button
end
function GeneralOptions:GetEnableFrameCheckbox(frameID)
return self['enableFrame_' .. frameID .. '_Checkbox']
end
function GeneralOptions:DisplayRequiresRestartPopup()
self:CreateRequiresRestartDialog()
StaticPopup_Show('BAGNON_CONFIRM_REQUIRES_RESTART')
end
function GeneralOptions:CreateRequiresRestartDialog()
if not StaticPopupDialogs['BAGNON_CONFIRM_REQUIRES_RESTART'] then
StaticPopupDialogs['BAGNON_CONFIRM_REQUIRES_RESTART'] = {
text = L.SettingRequiresRestart,
button1 = OKAY,
timeout = 0, exclusive = 1, hideOnEscape = 1
}
end
end
--show empty item slot textures
function GeneralOptions:CreateEmptyItemSlotTextureCheckbox()
local button = Bagnon.OptionsCheckButton:New(L.ShowEmptyItemSlotBackground, self)
button.OnEnableSetting = function(self, enable)
Bagnon.Settings:SetShowEmptyItemSlotTexture(enable)
end
button.IsSettingEnabled = function(self)
return Bagnon.Settings:ShowingEmptyItemSlotTextures()
end
self.showEmptyItemsTextureCheckbox = button
return button
end
function GeneralOptions:GetEmptyItemSlotTextureCheckbox()
return self.showEmptyItemsTextureCheckbox
end
--lock frame positions
function GeneralOptions:CreateLockFramePositionsCheckbox()
local button = Bagnon.OptionsCheckButton:New(L.LockFramePositions, self)
button.OnEnableSetting = function(self, enable)
Bagnon.Settings:SetLockFramePositions(enable)
end
button.IsSettingEnabled = function(self)
return Bagnon.Settings:AreFramePositionsLocked()
end
self.lockFramePositionsCheckbox = button
return button
end
function GeneralOptions:GetLockFramePositionsCheckbox()
return self.lockFramePositionsCheckbox
end
--blizzard bag passthrough
function GeneralOptions:CreateBlizzardBagPassThroughCheckbox()
local button = Bagnon.OptionsCheckButton:New(L.EnableBlizzardBagPassThrough, self)
button.OnEnableSetting = function(self, enable)
Bagnon.Settings:SetEnableBlizzardBagPassThrough(enable)
GeneralOptions:DisplayRequiresRestartPopup()
end
button.IsSettingEnabled = function(self)
return Bagnon.Settings:WillBlizzardBagPassThroughBeEnabled()
end
self.blizzardBagPassThroughCheckbox = button
return button
end
function GeneralOptions:GetBlizzardBagPassThroughCheckbox()
return self.blizzardBagPassThroughCheckbox
end
--[[ Load the thing ]]--
GeneralOptions:Load()

View file

@ -0,0 +1,8 @@
<Ui xmlns="http://www.blizzard.com/wow/ui/">
<Script file="widgets\button.lua"/>
<Script file="widgets\checkButton.lua"/>
<Script file="widgets\colorSelector.lua"/>
<Script file="widgets\dropdown.lua"/>
<Script file="widgets\optionsPanel.lua"/>
<Script file="widgets\slider.lua"/>
</Ui>

View file

@ -0,0 +1,52 @@
--[[
dropdown.lua
A bagnon dropdown menu
--]]
local OptionsCheckButton = Bagnon.Classy:New('CheckButton')
Bagnon.OptionsCheckButton = OptionsCheckButton
function OptionsCheckButton:New(name, parent)
local b = self:Bind(CreateFrame('CheckButton', parent:GetName() .. name, parent, 'InterfaceOptionsCheckButtonTemplate'))
_G[b:GetName() .. 'Text']:SetText(name)
b:SetScript('OnClick', b.OnClick)
b:SetScript('OnShow', b.OnShow)
return b
end
function OptionsCheckButton:SetDisabled(disable)
if disable then
self:Disable()
_G[self:GetName() .. 'Text']:SetFontObject('GameFontDisable')
else
self:Enable()
_G[self:GetName() .. 'Text']:SetFontObject('GameFontHighlight')
end
end
function OptionsCheckButton:OnClick()
self:EnableSetting(self:GetChecked())
end
function OptionsCheckButton:OnShow()
self:UpdateChecked()
end
function OptionsCheckButton:UpdateChecked()
self:SetChecked(self:IsSettingEnabled())
end
function OptionsCheckButton:EnableSetting(enable)
self:OnEnableSetting(enable and true or false)
self:UpdateChecked()
end
function OptionsCheckButton:OnEnableSetting(enable)
assert(false, 'Hey you forgot to implement OnEnableSetting for ' .. self:GetName())
end
function OptionsCheckButton:IsSettingEnabled()
assert(false, 'Hey you forgot to implement IsSettingEnabled for ' .. self:GetName())
end

View file

@ -0,0 +1,115 @@
--[[
colorSelector.lua
A bagnon color selector
--]]
local Bagnon = LibStub('AceAddon-3.0'):GetAddon('Bagnon')
local ColorSelector = Bagnon.Classy:New('Button')
Bagnon.OptionsColorSelector = ColorSelector
--[[ Constructor ]]--
function ColorSelector:New(name, parent, hasOpacity)
local f = self:Bind(CreateFrame('Button', parent:GetName() .. name, parent))
f.hasOpacity = hasOpacity
f:SetWidth(18)
f:SetHeight(18)
if hasOpacity then
f.swatchFunc = function()
local r, g, b = ColorPickerFrame:GetColorRGB()
local a = 1 - OpacitySliderFrame:GetValue()
f:SetColor(r, g, b, a)
end
f.opacityFunc = f.swatchFunc
f.cancelFunc = function()
local prev = ColorPickerFrame.previousValues
f:SetColor(prev.r, prev.g, prev.b, 1 - prev.opacity)
end
else
f.swatchFunc = function()
f:SetColor(ColorPickerFrame:GetColorRGB())
end
f.cancelFunc = function()
f:SetColor(ColorPicker_GetPreviousValues())
end
end
local nt = f:CreateTexture(nil, 'OVERLAY')
nt:SetTexture([[Interface\ChatFrame\ChatFrameColorSwatch]])
nt:SetAllPoints(f)
f:SetNormalTexture(nt)
local bg = f:CreateTexture(nil, 'BACKGROUND')
bg:SetWidth(16)
bg:SetHeight(16)
bg:SetTexture(1, 1, 1)
bg:SetPoint('CENTER')
f.bg = bg
local text = f:CreateFontString(nil, 'ARTWORK', 'GameFontHighlight')
text:SetPoint('LEFT', f, 'RIGHT', 4, 0)
text:SetText(name)
f.text = text
f:SetScript('OnClick', f.OnClick)
f:SetScript('OnEnter', f.OnEnter)
f:SetScript('OnLeave', f.OnLeave)
f:SetScript('OnShow', f.OnShow)
return f
end
--[[ Frame Events ]]--
function ColorSelector:OnClick()
if ColorPickerFrame:IsShown() then
ColorPickerFrame:Hide()
else
self.r, self.g, self.b, self.opacity = self:GetColor()
self.opacity = 1 - (self.opacity or 1) --correction, since the color menu is crazy
OpenColorPicker(self)
ColorPickerFrame:SetFrameStrata('TOOLTIP')
ColorPickerFrame:Raise()
end
end
function ColorSelector:OnShow()
local r, g, b = self:GetColor()
self:GetNormalTexture():SetVertexColor(r, g, b)
end
function ColorSelector:OnEnter()
local color = _G['NORMAL_FONT_COLOR']
self.bg:SetVertexColor(color.r, color.g, color.b)
end
function ColorSelector:OnLeave()
local color = _G['HIGHLIGHT_FONT_COLOR']
self.bg:SetVertexColor(color.r, color.g, color.b)
end
--[[ Update Methods ]]--
function ColorSelector:SetColor(r, g, b, a)
self:GetNormalTexture():SetVertexColor(r, g, b)
self:OnSetColor(r, g, b, a)
end
function ColorSelector:OnSetColor(r, g, b, a)
assert(false, 'Hey, you forgot to implement OnSetColor for ' .. self:GetName())
end
function ColorSelector:GetColor(r, g, b, a)
assert(false, 'Hey, you forgot to implement GetColor for ' .. self:GetName())
end
function ColorSelector:UpdateColor()
self:SetColor(self:GetColor())
end

View file

@ -0,0 +1,63 @@
--[[
dropdown.lua
A bagnon dropdown menu
--]]
local OptionsDropdown = Bagnon.Classy:New('Frame')
Bagnon.OptionsDropdown = OptionsDropdown
function OptionsDropdown:New(name, parent, width)
local f = self:Bind(CreateFrame('Frame', parent:GetName() .. name, parent, 'UIDropDownMenuTemplate'))
f.width = width
local text = f:CreateFontString(nil, 'BACKGROUND', 'GameFontNormalSmall')
text:SetPoint('BOTTOMLEFT', f, 'TOPLEFT', 21, 0)
text:SetText(name)
f.titleText = text
f:SetScript('OnShow', f.OnShow)
return f
end
--[[ Frame Evnets ]]--
function OptionsDropdown:OnShow()
UIDropDownMenu_SetWidth(self.width, self)
UIDropDownMenu_Initialize(self, self.Initialize)
UIDropDownMenu_SetSelectedValue(self, self:GetSavedValue())
end
--[[ Update Methods ]]--
function OptionsDropdown:Initialize()
assert(false, 'Hey you forgot to implement Initialize for ' .. self:GetName())
end
function OptionsDropdown:SetSavedValue(value)
assert(false, 'Hey you forgot to implement SetSavedValue for ' .. self:GetName())
end
function OptionsDropdown:GetSavedValue()
assert(false, 'Hey you forgot to implement GetSavedValue for ' .. self:GetName())
end
--[[ Item Adding ]]--
local function item_OnClick(self)
self:SetSavedValue(this.value)
UIDropDownMenu_SetSelectedValue(self, this.value)
end
function OptionsDropdown:AddItem(name, value)
local info = UIDropDownMenu_CreateInfo()
info.text = name
info.value = value or name
info.arg1 = self
info.func = item_OnClick
info.checked = (self:GetSavedValue() == info.value)
UIDropDownMenu_AddButton(info)
end

View file

@ -0,0 +1,34 @@
--[[
optionsPanel.lua
A bagnon options panel
--]]
local OptionsPanel = Bagnon.Classy:New('Frame')
Bagnon.OptionsPanel = OptionsPanel
function OptionsPanel:New(name, parent, title, subtitle, icon)
local f = self:Bind(CreateFrame('Frame', name))
f.name = title
f.parent = parent
local text = f:CreateFontString(nil, 'ARTWORK', 'GameFontNormalLarge')
text:SetPoint('TOPLEFT', 16, -16)
if icon then
text:SetFormattedText('|T%s:%d|t %s', icon, 32, title)
else
text:SetText(title)
end
local subtext = f:CreateFontString(nil, 'ARTWORK', 'GameFontHighlightSmall')
subtext:SetHeight(32)
subtext:SetPoint('TOPLEFT', text, 'BOTTOMLEFT', 0, -8)
subtext:SetPoint('RIGHT', f, -32, 0)
subtext:SetNonSpaceWrap(true)
subtext:SetJustifyH('LEFT')
subtext:SetJustifyV('TOP')
subtext:SetText(subtitle)
InterfaceOptions_AddCategory(f, 'Bagnon')
return f
end

View file

@ -0,0 +1,87 @@
--[[
slider.lua
A bagnon options slider
--]]
local Bagnon = LibStub('AceAddon-3.0'):GetAddon('Bagnon')
local OptionsSlider = Bagnon.Classy:New('Slider')
Bagnon.OptionsSlider = OptionsSlider
--[[ Constructor ]]--
function OptionsSlider:New(name, parent, low, high, step)
local f = self:Bind(CreateFrame('Slider', parent:GetName() .. name, parent, 'OptionsSliderTemplate'))
f:SetMinMaxValues(low, high)
f:SetValueStep(step)
f:EnableMouseWheel(true)
_G[f:GetName() .. 'Text']:SetText(name)
_G[f:GetName() .. 'Text']:SetFontObject('GameFontNormal')
_G[f:GetName() .. 'Text']:ClearAllPoints()
_G[f:GetName() .. 'Text']:SetPoint('BOTTOMLEFT', f, 'TOPLEFT')
-- _G[f:GetName() .. 'Text']:SetJustifyH('LEFT')
_G[f:GetName() .. 'Low']:SetText('')
_G[f:GetName() .. 'High']:SetText('')
local text = f:CreateFontString(nil, 'BACKGROUND', 'GameFontHighlightSmall')
text:SetJustifyH('RIGHT')
text:SetPoint('BOTTOMRIGHT', f, 'TOPRIGHT')
-- text:SetPoint('LEFT', f, 'RIGHT', 7, 0)
f.valText = text
f:SetScript('OnShow', f.OnShow)
f:SetScript('OnMouseWheel', f.OnMouseWheel)
f:SetScript('OnValueChanged', f.OnValueChanged)
f:SetScript('OnMouseWheel', f.OnMouseWheel)
return f
end
--[[ Frame Events ]]--
function OptionsSlider:OnShow()
self:UpdateValue()
end
function OptionsSlider:OnValueChanged(value)
self:SetSavedValue(value)
self:UpdateText(self:GetSavedValue())
end
function OptionsSlider:OnMouseWheel(direction)
local step = self:GetValueStep() * direction
local value = self:GetValue()
local minVal, maxVal = self:GetMinMaxValues()
if step > 0 then
self:SetValue(math.min(value+step, maxVal))
else
self:SetValue(math.max(value+step, minVal))
end
end
--[[ Update Methods ]]--
function OptionsSlider:SetSavedValue(value)
assert(false, 'Hey, you forgot to set SetSavedValue for ' .. self:GetName())
end
function OptionsSlider:GetSavedValue()
assert(false, 'Hey, you forgot to set GetSavedValue for ' .. self:GetName())
end
function OptionsSlider:UpdateValue()
self:SetValue(self:GetSavedValue())
self:UpdateText(self:GetSavedValue())
end
function OptionsSlider:UpdateText(value)
if self.GetFormattedText then
self.valText:SetText(self:GetFormattedText(value))
else
self.valText:SetText(value)
end
end

View file

@ -0,0 +1,11 @@
## Interface: 20400
## Title: Bagnon Forever
## Notes: Stores inventory information about your characters
## Notes-zhTW: 儲存角色背包和銀行的物品資訊
## Notes-zhCN: 保存角色背包与银行内物品的信息
## Author: Tuller
## Version: 1.1.2
## SavedVariables: BagnonForeverDB
## LoadOnDemand: 0
db.lua
ui.xml

454
Bagnon_Forever/db.lua Normal file
View file

@ -0,0 +1,454 @@
--[[
Database.lua
BagnonForever's implementation of BagnonDB
--]]
BagnonDB = CreateFrame('GameTooltip', 'BagnonDB', nil, 'GameTooltipTemplate')
BagnonDB:SetScript('OnEvent', function(self, event, arg1)
if arg1 == 'Bagnon_Forever' then
self:UnregisterEvent('ADDON_LOADED')
self:Initialize()
end
end)
BagnonDB:RegisterEvent('ADDON_LOADED')
--constants
local L = BAGNON_FOREVER_LOCALS
local CURRENT_VERSION = GetAddOnMetadata('Bagnon_Forever', 'Version')
local NUM_EQUIPMENT_SLOTS = 19
--locals
local currentPlayer = UnitName('player') --the name of the current player that's logged on
local currentRealm = GetRealmName() --what currentRealm we're on
local playerList --a sorted list of players
--[[ Local Functions ]]--
local function ToIndex(bag, slot)
if tonumber(bag) then
return (bag < 0 and bag*100 - slot) or bag*100 + slot
end
return bag .. slot
end
local function ToBagIndex(bag)
return (tonumber(bag) and bag*100) or bag
end
--returns the full item link only for items that have enchants/suffixes, otherwise returns the item's ID
local function ToShortLink(link)
if link then
local a,b,c,d,e,f,g,h = link:match('(%-?%d+):(%-?%d+):(%-?%d+):(%-?%d+):(%-?%d+):(%-?%d+):(%-?%d+):(%-?%d+)')
if(b == '0' and b == c and c == d and d == e and e == f and f == g) then
return a
end
return format('item:%s:%s:%s:%s:%s:%s:%s:%s', a, b, c, d, e, f, g, h)
end
end
local function GetBagSize(bag)
if bag == KEYRING_CONTAINER then
return GetKeyRingSize()
end
if bag == 'e' then
return NUM_EQUIPMENT_SLOTS
end
return GetContainerNumSlots(bag)
end
--[[ Addon Loading ]]--
function BagnonDB:Initialize()
self:LoadSettings()
self:SetScript('OnEvent', function(self, event, ...)
if self[event] then
self[event](self, event, ...)
end
end)
if IsLoggedIn() then
self:PLAYER_LOGIN()
else
self:RegisterEvent('PLAYER_LOGIN')
end
end
function BagnonDB:LoadSettings()
if not(BagnonForeverDB and BagnonForeverDB.version) then
BagnonForeverDB = {version = CURRENT_VERSION}
else
local cMajor, cMinor = CURRENT_VERSION:match('(%d+)%.(%d+)')
local major, minor = BagnonForeverDB.version:match('(%d+)%.(%d+)')
if major ~= cMajor then
BagnonForeverDB = {version = cVersion}
elseif minor ~= cMinor then
self:UpdateSettings()
end
if BagnonForeverDB.version ~= CURRENT_VERSION then
self:UpdateVersion()
end
end
self.db = BagnonForeverDB
if not self.db[currentRealm] then
self.db[currentRealm] = {}
end
self.rdb = self.db[currentRealm]
if not self.rdb[currentPlayer] then
self.rdb[currentPlayer] = {}
end
self.pdb = self.rdb[currentPlayer]
end
function BagnonDB:UpdateSettings()
end
function BagnonDB:UpdateVersion()
BagnonForeverDB.version = CURRENT_VERSION
print(format('BagnonForever: Updated to v%s', BagnonForeverDB.version))
end
--[[ Events ]]--
function BagnonDB:PLAYER_LOGIN()
self:SaveMoney()
self:UpdateBag(BACKPACK_CONTAINER)
self:UpdateBag(KEYRING_CONTAINER)
self:SaveEquipment()
self:SaveNumBankSlots()
self:RegisterEvent('BANKFRAME_OPENED')
self:RegisterEvent('BANKFRAME_CLOSED')
self:RegisterEvent('PLAYER_MONEY')
self:RegisterEvent('BAG_UPDATE')
self:RegisterEvent('PLAYERBANKSLOTS_CHANGED')
self:RegisterEvent('UNIT_INVENTORY_CHANGED')
self:RegisterEvent('PLAYERBANKBAGSLOTS_CHANGED')
end
function BagnonDB:PLAYER_MONEY()
self:SaveMoney()
end
function BagnonDB:BAG_UPDATE(event, bag)
if not(bag == BANK_CONTAINER or bag > NUM_BAG_SLOTS) or self.atBank then
self:OnBagUpdate(bag)
end
end
function BagnonDB:PLAYERBANKSLOTS_CHANGED()
self:UpdateBag(BANK_CONTAINER)
end
function BagnonDB:PLAYERBANKBAGSLOTS_CHANGED()
self:SaveNumBankSlots()
end
function BagnonDB:BANKFRAME_OPENED()
self.atBank = true
self:UpdateBag(BANK_CONTAINER)
for i = 1, GetNumBankSlots() do
self:UpdateBag(i + 4)
end
end
function BagnonDB:BANKFRAME_CLOSED()
self.atBank = nil
end
function BagnonDB:UNIT_INVENTORY_CHANGED(event, unit)
if unit == 'player' then
self:SaveEquipment()
end
end
--[[
Access Functions
Bagnon requires all of these functions to be present when attempting to view cached data
--]]
--[[
BagnonDB:GetPlayerList()
returns:
iterator of all players on this realm with data
usage:
for playerName, data in BagnonDB:GetPlayers()
--]]
function BagnonDB:GetPlayerList()
if(not playerList) then
playerList = {}
for player in self:GetPlayers() do
table.insert(playerList, player)
end
--sort by currentPlayer first, then alphabetically
table.sort(playerList, function(a, b)
if(a == currentPlayer) then
return true
elseif(b == currentPlayer) then
return false
end
return a < b
end)
end
return playerList
end
function BagnonDB:GetPlayers()
return pairs(self.rdb)
end
--[[
BagnonDB:GetMoney(player)
args:
player (string)
the name of the player we're looking at. This is specific to the current realm we're on
returns:
(number) How much money, in copper, the given player has
--]]
function BagnonDB:GetMoney(player)
local playerData = self.rdb[player]
if playerData then
return playerData.g or 0
end
return 0
end
--[[
BagnonDB:GetNumBankSlots(player)
args:
player (string)
the name of the player we're looking at. This is specific to the current realm we're on
returns:
(number or nil) How many bank slots the current player has purchased
--]]
function BagnonDB:GetNumBankSlots(player)
local playerData = self.rdb[player]
if playerData then
return playerData.numBankSlots
end
end
--[[
BagnonDB:GetBagData(bag, player)
args:
player (string)
the name of the player we're looking at. This is specific to the current realm we're on
bag (number)
the number of the bag we're looking at.
returns:
size (number)
How many items the bag can hold (number)
hyperlink (string)
The hyperlink of the bag
count (number)
How many items are in the bag. This is used by ammo and soul shard bags
--]]
function BagnonDB:GetBagData(bag, player)
local playerDB = self.rdb[player]
if playerDB then
local bagInfo = playerDB[ToBagIndex(bag)]
if bagInfo then
local size, link, count = strsplit(',', bagInfo)
local hyperLink = (link and select(2, GetItemInfo(link))) or nil
return tonumber(size), hyperLink, tonumber(count) or 1, GetItemIcon(link)
end
end
end
--[[
BagnonDB:GetItemData(bag, slot, player)
args:
player (string)
the name of the player we're looking at. This is specific to the current realm we're on
bag (number)
the number of the bag we're looking at.
itemSlot (number)
the specific item slot we're looking at
returns:
hyperLink (string)
The hyperLink of the item
count (number)
How many of there are of the specific item
texture (string)
The filepath of the item's texture
quality (number)
The numeric representaiton of the item's quality: from 0 (poor) to 7 (artifcat)
--]]
function BagnonDB:GetItemData(bag, slot, player)
local playerDB = self.rdb[player]
if playerDB then
local itemInfo = playerDB[ToIndex(bag, slot)]
if itemInfo then
local link, count = strsplit(',', itemInfo)
if link then
local hyperLink, quality = select(2, GetItemInfo(link))
return hyperLink, tonumber(count) or 1, GetItemIcon(link), tonumber(quality)
end
end
end
end
--[[
Returns how many of the specific item id the given player has in the given bag
--]]
function BagnonDB:GetItemCount(itemLink, bag, player)
local total = 0
local itemLink = select(2, GetItemInfo(ToShortLink(itemLink)))
local size = (self:GetBagData(bag, player)) or 0
for slot = 1, size do
local link, count = self:GetItemData(bag, slot, player)
if link == itemLink then
total = total + (count or 1)
end
end
return total
end
--[[
Storage Functions
How we store the data (duh)
--]]
--[[ Storage Functions ]]--
function BagnonDB:SaveMoney()
self.pdb.g = GetMoney()
end
function BagnonDB:SaveNumBankSlots()
self.pdb.numBankSlots = GetNumBankSlots()
end
--saves all the player's equipment data information
function BagnonDB:SaveEquipment()
for slot = 0, NUM_EQUIPMENT_SLOTS do
local link = GetInventoryItemLink('player', slot)
local index = ToIndex('e', slot)
if link then
local link = ToShortLink(link)
local count = GetInventoryItemCount('player', slot)
count = count > 1 and count or nil
if(link and count) then
self.pdb[index] = format('%s,%d', link, count)
else
self.pdb[index] = link
end
else
self.pdb[index] = nil
end
end
end
--saves data about a specific item the current player has
function BagnonDB:SaveItem(bag, slot)
local texture, count = GetContainerItemInfo(bag, slot)
local index = ToIndex(bag, slot)
if texture then
local link = ToShortLink(GetContainerItemLink(bag, slot))
count = count > 1 and count or nil
if(link and count) then
self.pdb[index] = format('%s,%d', link, count)
else
self.pdb[index] = link
end
else
self.pdb[index] = nil
end
end
--saves all information about the given bag, EXCEPT the bag's contents
function BagnonDB:SaveBag(bag)
local data = self.pdb
local size = GetBagSize(bag)
local index = ToBagIndex(bag)
if size > 0 then
local equipSlot = bag > 0 and ContainerIDToInventoryID(bag)
local link = ToShortLink(GetInventoryItemLink('player', equipSlot))
local count = GetInventoryItemCount('player', equipSlot)
if count < 1 then
count = nil
end
if(size and link and count) then
self.pdb[index] = format('%d,%s,%d', size, link, count)
elseif(size and link) then
self.pdb[index] = format('%d,%s', size, link)
else
self.pdb[index] = size
end
else
self.pdb[index] = nil
end
end
--saves both relevant information about the given bag, and all information about items in the given bag
function BagnonDB:UpdateBag(bag)
self:SaveBag(bag)
for slot = 1, GetBagSize(bag) do
self:SaveItem(bag, slot)
end
end
function BagnonDB:OnBagUpdate(bag)
if self.atBank then
for i = 1, (NUM_BAG_SLOTS + GetNumBankSlots()) do
self:SaveBag(i)
end
else
for i = 1, NUM_BAG_SLOTS do
self:SaveBag(i)
end
end
for slot = 1, GetBagSize(bag) do
self:SaveItem(bag, slot)
end
end
--[[ Removal Functions ]]--
--removes all saved data about the given player
function BagnonDB:RemovePlayer(player, realm)
local realm = realm or currentRealm
local rdb = self.db[realm]
if rdb then
rdb[player] = nil
end
if realm == currentRealm and playerList then
for i,character in pairs(playerList) do
if(character == player) then
table.remove(playerList, i)
break
end
end
end
end

97
Bagnon_Forever/ui.lua Normal file
View file

@ -0,0 +1,97 @@
--[[
BagnonDBUI
Functions for the dropdown menu for showing cached data
No alterations if this code should be needed to make it work with other databases
Essentially the dropdown is used to switch between the inventory of other characters
Why not use a normal dropdown? It takes a lot of memory
--]]
local currentFrame
local dropdown
local info = {}
--adds a checkable item to a dropdown menu
local function AddCheckItem(text, value, func, checked, hasArrow, level, arg1, arg2)
info.text = text
info.func = func
info.value = value
info.hasArrow = (hasArrow and true) or nil
info.notCheckable = false
info.checked = checked
info.arg1 = arg1
info.arg2 = arg2
UIDropDownMenu_AddButton(info, level)
end
--adds an uncheckable item to a dropdown menu
local function AddItem(text, value, func, level, arg1, arg2)
info.text = text
info.func = func
info.value = value
info.hasArrow = false
info.notCheckable = true
info.checked = false
info.arg1 = arg1
info.arg2 = arg2
UIDropDownMenu_AddButton(info, level)
end
local function CharSelect_OnClick(player, delete)
local newPlayer
if delete then
--remove the selected player
BagnonDB:RemovePlayer(player)
--select the current player
newPlayer = UnitName('player')
else
--select the clicked player
newPlayer = player
end
--show the given player, and check the selected one
currentFrame:SetPlayer(newPlayer)
--hide the previous dropdown menus (hack)
for i = 1, UIDROPDOWNMENU_MENU_LEVEL-1 do
getglobal("DropDownList"..i):Hide()
end
end
--populate the list, add a delete button to all characters that aren't the current player
local function CharSelect_Initialize(level)
local playerList = BagnonDB:GetPlayerList()
local level = level or 1
if level == 1 then
local selected = currentFrame:GetPlayer()
local current = UnitName('player')
for i,player in ipairs(playerList) do
AddCheckItem(player, i, CharSelect_OnClick, player == selected, player ~= current, level, player)
end
elseif level == 2 then
AddItem(REMOVE, nil, CharSelect_OnClick, level, playerList[UIDROPDOWNMENU_MENU_VALUE], true)
end
end
local function CharSelect_Create()
dropdown = CreateFrame("Frame", "BagnonDBCharSelect", UIParent, "UIDropDownMenuTemplate")
dropdown:SetID(1)
UIDropDownMenu_Initialize(dropdown, CharSelect_Initialize, "MENU")
return dropdown
end
--[[ Usable Functions ]]--
--set which frame to "parent" the dropdown to
function BagnonDB:SetDropdownFrame(frame)
currentFrame = frame
end
--show the character select list at the given location
function BagnonDB:ToggleDropdown(anchor, offX, offY)
ToggleDropDownMenu(1, nil, dropdown or CharSelect_Create(), anchor, offX, offY)
end

Some files were not shown because too many files have changed in this diff Show more