diff --git a/Bagnon/Bagnon.toc b/Bagnon/Bagnon.toc
new file mode 100644
index 0000000..744f118
--- /dev/null
+++ b/Bagnon/Bagnon.toc
@@ -0,0 +1,13 @@
+## Interface: 30300
+## 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
\ No newline at end of file
diff --git a/Bagnon/Bindings.xml b/Bagnon/Bindings.xml
new file mode 100644
index 0000000..d6685eb
--- /dev/null
+++ b/Bagnon/Bindings.xml
@@ -0,0 +1,11 @@
+
+
+ Bagnon:ToggleFrame('inventory')
+
+
+ Bagnon:ToggleFrame('bank')
+
+
+ Bagnon:ToggleFrame('keys')
+
+
\ No newline at end of file
diff --git a/Bagnon/components.xml b/Bagnon/components.xml
new file mode 100644
index 0000000..54a6028
--- /dev/null
+++ b/Bagnon/components.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Bagnon/components/bag.lua b/Bagnon/components/bag.lua
new file mode 100644
index 0000000..5c86c1b
--- /dev/null
+++ b/Bagnon/components/bag.lua
@@ -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(self: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
\ No newline at end of file
diff --git a/Bagnon/components/bagFrame.lua b/Bagnon/components/bagFrame.lua
new file mode 100644
index 0000000..a0efe30
--- /dev/null
+++ b/Bagnon/components/bagFrame.lua
@@ -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
\ No newline at end of file
diff --git a/Bagnon/components/bagToggle.lua b/Bagnon/components/bagToggle.lua
new file mode 100644
index 0000000..9ab3614
--- /dev/null
+++ b/Bagnon/components/bagToggle.lua
@@ -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
\ No newline at end of file
diff --git a/Bagnon/components/brokerDisplay.lua b/Bagnon/components/brokerDisplay.lua
new file mode 100644
index 0000000..92d3945
--- /dev/null
+++ b/Bagnon/components/brokerDisplay.lua
@@ -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('NumberFontNormalRight')
+ text:SetJustifyH('LEFT')
+
+ return text
+end
+
+
+--[[
+ Broker Selection Buttons
+--]]
+
+function BrokerDisplay:CreateLeftButton()
+ local b = CreateFrame('Button', nil, self)
+
+ b:SetNormalFontObject('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:SetNormalFontObject('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
\ No newline at end of file
diff --git a/Bagnon/components/frame.lua b/Bagnon/components/frame.lua
new file mode 100644
index 0000000..790ff47
--- /dev/null
+++ b/Bagnon/components/frame.lua
@@ -0,0 +1,884 @@
+--[[
+ 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('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: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: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
+
+
+--[[ 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
\ No newline at end of file
diff --git a/Bagnon/components/frameSettings.lua b/Bagnon/components/frameSettings.lua
new file mode 100644
index 0000000..25c71c8
--- /dev/null
+++ b/Bagnon/components/frameSettings.lua
@@ -0,0 +1,512 @@
+--[[
+ 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
+
+--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
\ No newline at end of file
diff --git a/Bagnon/components/item.lua b/Bagnon/components/item.lua
new file mode 100644
index 0000000..76f062f
--- /dev/null
+++ b/Bagnon/components/item.lua
@@ -0,0 +1,748 @@
+--[[
+ 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
+function ItemSlot:ConstructNewItemSlot(id)
+ return CreateFrame('Button', 'BagnonItemSlot' .. id, nil, 'ContainerFrameItemButtonTemplate')
+end
+
+--returns an available blizzard item slot for
+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
+
+
+local reTooltip = CreateFrame("GameTooltip", "BagNonItemListREInspectTooltip", UIParent, "GameTooltipTemplate")
+-- TODO: Nihilianth: This change does not affect guild bank search. Also tooltips in guild bank are not colored properly
+function ItemSlot:UpdateREName()
+ local itemLink = self:GetItem()
+ if itemLink and reTooltip then
+
+ local tooltip = reTooltip
+ tooltip:ClearLines()
+ tooltip:SetOwner(self:GetParent(), "ANCHOR_NONE")
+ if self:GetBag() == -1 then
+ tooltip:SetInventoryItem("player", BankButtonIDToInvSlotID(self:GetID()))
+ else
+ tooltip:SetBagItem(self:GetBag(), self:GetID())
+ end
+
+ for line = 1, tooltip:NumLines() do
+ local ttLine = _G[tooltip:GetName() .. "TextLeft" .. line]
+ local text = ttLine:GetText()
+ if text and string.find(text, "Equip:") then
+ local descStart = text:find("( )(\-)( )")
+ if descStart then
+ self.reName = string.lower(text:sub(7, descStart - 1))
+ return
+ end
+ end
+ end
+ -- reTooltip:Hide()
+ end --else print("no item link") end
+end
+
+function ItemSlot:UpdateLocked()
+ if self:IsLocked() then
+ self.reName = ""
+ else
+ self:UpdateREName()
+ end
+ 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)))
+ if self.reName and string.find(self.reName, string.lower(search)) then
+ shouldFade = false
+ end
+
+ 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(12, 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
\ No newline at end of file
diff --git a/Bagnon/components/itemFrame.lua b/Bagnon/components/itemFrame.lua
new file mode 100644
index 0000000..c3e69c9
--- /dev/null
+++ b/Bagnon/components/itemFrame.lua
@@ -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
\ No newline at end of file
diff --git a/Bagnon/components/moneyFrame.lua b/Bagnon/components/moneyFrame.lua
new file mode 100644
index 0000000..5c6efb6
--- /dev/null
+++ b/Bagnon/components/moneyFrame.lua
@@ -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
\ No newline at end of file
diff --git a/Bagnon/components/optionsToggle.lua b/Bagnon/components/optionsToggle.lua
new file mode 100644
index 0000000..06add05
--- /dev/null
+++ b/Bagnon/components/optionsToggle.lua
@@ -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
\ No newline at end of file
diff --git a/Bagnon/components/playerSelector.lua b/Bagnon/components/playerSelector.lua
new file mode 100644
index 0000000..f2916b1
--- /dev/null
+++ b/Bagnon/components/playerSelector.lua
@@ -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\Icons\Achievement_Character_%s_%s]], enRace, 'Female')
+ end
+ return string.format([[Interface\Icons\Achievement_Character_%s_%s]], enRace, 'Male')
+end
\ No newline at end of file
diff --git a/Bagnon/components/savedFrameSettings.lua b/Bagnon/components/savedFrameSettings.lua
new file mode 100644
index 0000000..494e608
--- /dev/null
+++ b/Bagnon/components/savedFrameSettings.lua
@@ -0,0 +1,543 @@
+--[[
+ 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: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,
+
+ --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,
+
+ --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,
+
+ --dbo display object
+ dataBrokerObject = 'BagnonLauncher',
+
+ --slot ordering
+ reverseSlotOrder = false,
+ }
+ SavedFrameSettings.keyDefaults = defaults
+ return defaults
+end
+
+function SavedFrameSettings:GetDefaultGuildBankSettings()
+ return self:GetDefaultInventorySettings()
+end
\ No newline at end of file
diff --git a/Bagnon/components/savedSettings.lua b/Bagnon/components/savedSettings.lua
new file mode 100644
index 0000000..9973161
--- /dev/null
+++ b/Bagnon/components/savedSettings.lua
@@ -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
diff --git a/Bagnon/components/searchFrame.lua b/Bagnon/components/searchFrame.lua
new file mode 100644
index 0000000..5f70902
--- /dev/null
+++ b/Bagnon/components/searchFrame.lua
@@ -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
\ No newline at end of file
diff --git a/Bagnon/components/searchToggle.lua b/Bagnon/components/searchToggle.lua
new file mode 100644
index 0000000..59dc7f7
--- /dev/null
+++ b/Bagnon/components/searchToggle.lua
@@ -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
\ No newline at end of file
diff --git a/Bagnon/components/settings.lua b/Bagnon/components/settings.lua
new file mode 100644
index 0000000..eb3f154
--- /dev/null
+++ b/Bagnon/components/settings.lua
@@ -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
\ No newline at end of file
diff --git a/Bagnon/components/titleFrame.lua b/Bagnon/components/titleFrame.lua
new file mode 100644
index 0000000..83cc822
--- /dev/null
+++ b/Bagnon/components/titleFrame.lua
@@ -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:SetNormalFontObject('GameFontNormalLeft')
+ b:SetHighlightFontObject('GameFontHighlightLeft')
+ 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
\ No newline at end of file
diff --git a/Bagnon/embeds.xml b/Bagnon/embeds.xml
new file mode 100644
index 0000000..d3f4e7c
--- /dev/null
+++ b/Bagnon/embeds.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Bagnon/libs/AceAddon-3.0/AceAddon-3.0.lua b/Bagnon/libs/AceAddon-3.0/AceAddon-3.0.lua
new file mode 100644
index 0000000..6c89654
--- /dev/null
+++ b/Bagnon/libs/AceAddon-3.0/AceAddon-3.0.lua
@@ -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
diff --git a/Bagnon/libs/AceAddon-3.0/AceAddon-3.0.xml b/Bagnon/libs/AceAddon-3.0/AceAddon-3.0.xml
new file mode 100644
index 0000000..e6ad639
--- /dev/null
+++ b/Bagnon/libs/AceAddon-3.0/AceAddon-3.0.xml
@@ -0,0 +1,4 @@
+
+
+
\ No newline at end of file
diff --git a/Bagnon/libs/AceConsole-3.0/AceConsole-3.0.lua b/Bagnon/libs/AceConsole-3.0/AceConsole-3.0.lua
new file mode 100644
index 0000000..c001123
--- /dev/null
+++ b/Bagnon/libs/AceConsole-3.0/AceConsole-3.0.lua
@@ -0,0 +1,250 @@
+--- **AceConsole-3.0** provides registration facilities for slash commands.
+-- You can register slash commands to your custom functions and use the `GetArgs` function to parse them
+-- to your addons individual needs.
+--
+-- **AceConsole-3.0** can be embeded into your addon, either explicitly by calling AceConsole:Embed(MyAddon) or by
+-- specifying it as an embeded library in your AceAddon. All functions will be available on your addon object
+-- and can be accessed directly, without having to explicitly call AceConsole itself.\\
+-- It is recommended to embed AceConsole, otherwise you'll have to specify a custom `self` on all calls you
+-- make into AceConsole.
+-- @class file
+-- @name AceConsole-3.0
+-- @release $Id: AceConsole-3.0.lua 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
diff --git a/Bagnon/libs/AceConsole-3.0/AceConsole-3.0.xml b/Bagnon/libs/AceConsole-3.0/AceConsole-3.0.xml
new file mode 100644
index 0000000..be9f47c
--- /dev/null
+++ b/Bagnon/libs/AceConsole-3.0/AceConsole-3.0.xml
@@ -0,0 +1,4 @@
+
+
+
\ No newline at end of file
diff --git a/Bagnon/libs/AceEvent-3.0/AceEvent-3.0.lua b/Bagnon/libs/AceEvent-3.0/AceEvent-3.0.lua
new file mode 100644
index 0000000..e9b18b1
--- /dev/null
+++ b/Bagnon/libs/AceEvent-3.0/AceEvent-3.0.lua
@@ -0,0 +1,126 @@
+--- AceEvent-3.0 provides event registration and secure dispatching.
+-- All dispatching is done using **CallbackHandler-1.0**. AceEvent is a simple wrapper around
+-- CallbackHandler, and dispatches all game events or addon message to the registrees.
+--
+-- **AceEvent-3.0** can be embeded into your addon, either explicitly by calling AceEvent:Embed(MyAddon) or by
+-- specifying it as an embeded library in your AceAddon. All functions will be available on your addon object
+-- and can be accessed directly, without having to explicitly call AceEvent itself.\\
+-- It is recommended to embed AceEvent, otherwise you'll have to specify a custom `self` on all calls you
+-- make into AceEvent.
+-- @class file
+-- @name AceEvent-3.0
+-- @release $Id: AceEvent-3.0.lua 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
diff --git a/Bagnon/libs/AceEvent-3.0/AceEvent-3.0.xml b/Bagnon/libs/AceEvent-3.0/AceEvent-3.0.xml
new file mode 100644
index 0000000..313ef4d
--- /dev/null
+++ b/Bagnon/libs/AceEvent-3.0/AceEvent-3.0.xml
@@ -0,0 +1,4 @@
+
+
+
\ No newline at end of file
diff --git a/Bagnon/libs/AceLocale-3.0/AceLocale-3.0.lua b/Bagnon/libs/AceLocale-3.0/AceLocale-3.0.lua
new file mode 100644
index 0000000..0f7c8fd
--- /dev/null
+++ b/Bagnon/libs/AceLocale-3.0/AceLocale-3.0.lua
@@ -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
diff --git a/Bagnon/libs/AceLocale-3.0/AceLocale-3.0.xml b/Bagnon/libs/AceLocale-3.0/AceLocale-3.0.xml
new file mode 100644
index 0000000..e017af0
--- /dev/null
+++ b/Bagnon/libs/AceLocale-3.0/AceLocale-3.0.xml
@@ -0,0 +1,4 @@
+
+
+
\ No newline at end of file
diff --git a/Bagnon/libs/CallbackHandler-1.0/CallbackHandler-1.0.lua b/Bagnon/libs/CallbackHandler-1.0/CallbackHandler-1.0.lua
new file mode 100644
index 0000000..712bf7e
--- /dev/null
+++ b/Bagnon/libs/CallbackHandler-1.0/CallbackHandler-1.0.lua
@@ -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.
+
diff --git a/Bagnon/libs/CallbackHandler-1.0/CallbackHandler-1.0.xml b/Bagnon/libs/CallbackHandler-1.0/CallbackHandler-1.0.xml
new file mode 100644
index 0000000..876df83
--- /dev/null
+++ b/Bagnon/libs/CallbackHandler-1.0/CallbackHandler-1.0.xml
@@ -0,0 +1,4 @@
+
+
+
\ No newline at end of file
diff --git a/Bagnon/libs/LibDataBroker-1.1.lua b/Bagnon/libs/LibDataBroker-1.1.lua
new file mode 100644
index 0000000..f47c0cd
--- /dev/null
+++ b/Bagnon/libs/LibDataBroker-1.1.lua
@@ -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
diff --git a/Bagnon/libs/LibItemSearch-1.0/LibItemSearch-1.0.lua b/Bagnon/libs/LibItemSearch-1.0/LibItemSearch-1.0.lua
new file mode 100644
index 0000000..e7f52a6
--- /dev/null
+++ b/Bagnon/libs/LibItemSearch-1.0/LibItemSearch-1.0.lua
@@ -0,0 +1,417 @@
+--[[
+ ItemSearch
+ An item text search engine of some sort
+
+ Grammar:
+ :=
+ := & ;
+ := | ;
+ := ! ;
+ := ; ; ;
+ := bop ; boa ; bou ; boe ; quest
+ := q ; q
+ := ilvl
+ := t:
+ :=
+ := : | = | == | != | ~= | < | > | <= | >=
+
+ 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: & ]]--
+
+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: | ]]--
+
+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: ! ]]--
+
+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 is in the search defined by
+ }
+--]]
+
+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,
+}
\ No newline at end of file
diff --git a/Bagnon/libs/LibStub/.pkgmeta b/Bagnon/libs/LibStub/.pkgmeta
new file mode 100644
index 0000000..3508f81
--- /dev/null
+++ b/Bagnon/libs/LibStub/.pkgmeta
@@ -0,0 +1 @@
+package-as: LibStub
diff --git a/Bagnon/libs/LibStub/LibStub.lua b/Bagnon/libs/LibStub/LibStub.lua
new file mode 100644
index 0000000..0a41ac0
--- /dev/null
+++ b/Bagnon/libs/LibStub/LibStub.lua
@@ -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
diff --git a/Bagnon/libs/LibStub/LibStub.toc b/Bagnon/libs/LibStub/LibStub.toc
new file mode 100644
index 0000000..4d9130c
--- /dev/null
+++ b/Bagnon/libs/LibStub/LibStub.toc
@@ -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
diff --git a/Bagnon/localization.xml b/Bagnon/localization.xml
new file mode 100644
index 0000000..f5aff1d
--- /dev/null
+++ b/Bagnon/localization.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Bagnon/localization/localization.cn.lua b/Bagnon/localization/localization.cn.lua
new file mode 100644
index 0000000..17f5d86
--- /dev/null
+++ b/Bagnon/localization/localization.cn.lua
@@ -0,0 +1,61 @@
+--[[
+ 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.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 = '右击 打开设置菜单'
\ No newline at end of file
diff --git a/Bagnon/localization/localization.de.lua b/Bagnon/localization/localization.de.lua
new file mode 100644
index 0000000..0f60f0d
--- /dev/null
+++ b/Bagnon/localization/localization.de.lua
@@ -0,0 +1,55 @@
+--[[
+ 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 = ' um die Gegenst\195\164nde anderer Charaktere anzuzeigen.'
+L.TipGoldOnRealm = 'Auf %s gesamt'
+L.TipHideBag = ' um diese Tasche zu verstecken.'
+L.TipHideBags = ' um die Taschenanzeige zu verstecken.'
+L.TipHideSearch = ' um das Suchfenster zu verstecken.'
+L.TipPurchaseBag = ' um das Bankfach zu kaufen.'
+L.TipShowBag = ' um diese Tasche anzuzeigen.'
+L.TipShowBags = ' um das Taschenfenster anzuzeigen.'
+L.TipShowMenu = ' um das Fenster zu konfigurieren.'
+L.TipShowSearch = ' um das Suchfenster anzuzeigen.'
+L.TipShowSearch = ' zum Suchen.'
+L.TipShowFrameConfig = ' um dieses Fenster zu konfigurieren.'
+L.TipDoubleClickSearch = ' zum Verschieben.\n zum Konfigurieren.\n zum Suchen.'
+L.Total = 'Gesamt'
+
+--databroker plugin tooltips
+L.TipShowBank = ' um die Bank umzuschalten'
+L.TipShowInventory = ' um das Inventar umzuschalten'
+L.TipShowKeyring = ' um den Schl\195\188sselring umzuschalten'
+L.TipShowOptions = ' um das Konfigurationsmen\195\188 anzuzeigen'
\ No newline at end of file
diff --git a/Bagnon/localization/localization.es.lua b/Bagnon/localization/localization.es.lua
new file mode 100644
index 0000000..6fb6f56
--- /dev/null
+++ b/Bagnon/localization/localization.es.lua
@@ -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
\ No newline at end of file
diff --git a/Bagnon/localization/localization.fr.lua b/Bagnon/localization/localization.fr.lua
new file mode 100644
index 0000000..1ed6797
--- /dev/null
+++ b/Bagnon/localization/localization.fr.lua
@@ -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
\ No newline at end of file
diff --git a/Bagnon/localization/localization.lua b/Bagnon/localization/localization.lua
new file mode 100644
index 0000000..c94662f
--- /dev/null
+++ b/Bagnon/localization/localization.lua
@@ -0,0 +1,55 @@
+--[[
+ 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.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 = ' to toggle your bank.'
+L.TipShowInventory = ' to toggle your inventory.'
+L.TipShowKeyring = ' to toggle your keyring.'
+L.TipShowOptions = ' to open the options menu.'
\ No newline at end of file
diff --git a/Bagnon/localization/localization.ru.lua b/Bagnon/localization/localization.ru.lua
new file mode 100644
index 0000000..be658cb
--- /dev/null
+++ b/Bagnon/localization/localization.ru.lua
@@ -0,0 +1,57 @@
+--[[
+ 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.TipGoldOnRealm = 'Всего денег на %s'
+L.TipHideBag = '<Клик> - скрыть сумку.'
+L.TipHideBags = '<Клик> - скрыть область сумок.'
+L.TipHideSearch = '<Клик> скрыть область поиска.'
+L.TipPurchaseBag = '<Клик> - купить ячейку в банке.'
+L.TipShowBag = '<Клик> - показать сумку.'
+L.TipShowBags = '<Клик> - показать область сумки.'
+L.TipShowMenu = '<Правый-клик> - настройки.'
+L.TipShowSearch = '<Клик> - показать область поиска.'
+L.TipShowSearch = '<Клик> - поиск.'
+L.TipShowFrameConfig = '<Правый-клик> - настройки.'
+L.TipDoubleClickSearch = ' - переместить.\n<Правый-клик> - настройка.\n<Двойной-клик> - поиск.'
+L.Total = 'Всего'
+
+--databroker plugin tooltips
+L.TipShowBank = ' - открыть/закрыть банк.'
+L.TipShowInventory = '<Левый клик> - открыть/закрыть инвентарь.'
+L.TipShowKeyring = ' - открыть/закрыть связку ключей.'
+L.TipShowOptions = '<Правый-клик> - настройки.'
\ No newline at end of file
diff --git a/Bagnon/localization/localization.tw.lua b/Bagnon/localization/localization.tw.lua
new file mode 100644
index 0000000..230dfba
--- /dev/null
+++ b/Bagnon/localization/localization.tw.lua
@@ -0,0 +1,64 @@
+--[[
+ THIS FILE IS ENCODED IN UTF-8
+
+ Bagnon Localization Information: Chinese Traditional
+ 2007/11/17 by matini< yiting.jheng gmail 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.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 = '右擊 打開設置菜單'
\ No newline at end of file
diff --git a/Bagnon/main.lua b/Bagnon/main.lua
new file mode 100644
index 0000000..d5d9249
--- /dev/null
+++ b/Bagnon/main.lua
@@ -0,0 +1,408 @@
+--[[
+ 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
+ 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
+
+ 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_OpenToCategory(self.GeneralOptions)
+ return true
+ end
+ return false
+end
\ No newline at end of file
diff --git a/Bagnon/todo.txt b/Bagnon/todo.txt
new file mode 100644
index 0000000..094d32f
--- /dev/null
+++ b/Bagnon/todo.txt
@@ -0,0 +1,2 @@
+* Saved searches
+* Guild bank
\ No newline at end of file
diff --git a/Bagnon/utility.xml b/Bagnon/utility.xml
new file mode 100644
index 0000000..1578841
--- /dev/null
+++ b/Bagnon/utility.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Bagnon/utility/bagSlotInfo.lua b/Bagnon/utility/bagSlotInfo.lua
new file mode 100644
index 0000000..aab7e5c
--- /dev/null
+++ b/Bagnon/utility/bagSlotInfo.lua
@@ -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
\ No newline at end of file
diff --git a/Bagnon/utility/callbacks.lua b/Bagnon/utility/callbacks.lua
new file mode 100644
index 0000000..3420420
--- /dev/null
+++ b/Bagnon/utility/callbacks.lua
@@ -0,0 +1,7 @@
+--[[
+ callBacks.lua
+ Initializes the Bagnon callback handler
+--]]
+
+local Bagnon = LibStub('AceAddon-3.0'):GetAddon('Bagnon')
+Bagnon.Callbacks = Bagnon.Ears:New()
\ No newline at end of file
diff --git a/Bagnon/utility/classy.lua b/Bagnon/utility/classy.lua
new file mode 100644
index 0000000..ccf9789
--- /dev/null
+++ b/Bagnon/utility/classy.lua
@@ -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
\ No newline at end of file
diff --git a/Bagnon/utility/ears.lua b/Bagnon/utility/ears.lua
new file mode 100644
index 0000000..90b9295
--- /dev/null
+++ b/Bagnon/utility/ears.lua
@@ -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 , 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 , 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 , 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 , 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
\ No newline at end of file
diff --git a/Bagnon/utility/itemEvents.lua b/Bagnon/utility/itemEvents.lua
new file mode 100644
index 0000000..5f71fcd
--- /dev/null
+++ b/Bagnon/utility/itemEvents.lua
@@ -0,0 +1,279 @@
+--[[
+ 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)
+ 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()
\ No newline at end of file
diff --git a/Bagnon/utility/itemSlotInfo.lua b/Bagnon/utility/itemSlotInfo.lua
new file mode 100644
index 0000000..a30bbb9
--- /dev/null
+++ b/Bagnon/utility/itemSlotInfo.lua
@@ -0,0 +1,39 @@
+--[[
+ 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)
+
+ --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
+
+ -- link = GetContainerItemLinkWithRE(bag, slot)
+ 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
+ return (select(3, GetContainerItemInfo(bag, slot)))
+end
+
+function ItemSlotInfo:IsCached(player, bag, slot)
+ return Bagnon.BagSlotInfo:IsCached(player, bag)
+end
\ No newline at end of file
diff --git a/Bagnon/utility/playerInfo.lua b/Bagnon/utility/playerInfo.lua
new file mode 100644
index 0000000..3cab8c2
--- /dev/null
+++ b/Bagnon/utility/playerInfo.lua
@@ -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
\ No newline at end of file
diff --git a/Bagnon_Config/Bagnon_Config.toc b/Bagnon_Config/Bagnon_Config.toc
new file mode 100644
index 0000000..082a76c
--- /dev/null
+++ b/Bagnon_Config/Bagnon_Config.toc
@@ -0,0 +1,9 @@
+## Interface: 30300
+## Title: Bagnon Config
+## Notes: GUI based configuration for Bagnon
+## Author: Tuller
+## Dependencies: Bagnon
+## LoadOnDemand: 1
+localization.xml
+widgets.xml
+panels.xml
\ No newline at end of file
diff --git a/Bagnon_Config/localization.xml b/Bagnon_Config/localization.xml
new file mode 100644
index 0000000..ae15d95
--- /dev/null
+++ b/Bagnon_Config/localization.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Bagnon_Config/localization/localization.cn.lua b/Bagnon_Config/localization/localization.cn.lua
new file mode 100644
index 0000000..f36c999
--- /dev/null
+++ b/Bagnon_Config/localization/localization.cn.lua
@@ -0,0 +1,53 @@
+--[[
+ 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.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 = '禁用的背包使用暴雪默认框体'
\ No newline at end of file
diff --git a/Bagnon_Config/localization/localization.de.lua b/Bagnon_Config/localization/localization.de.lua
new file mode 100644
index 0000000..3f8858b
--- /dev/null
+++ b/Bagnon_Config/localization/localization.de.lua
@@ -0,0 +1,57 @@
+--[[
+ 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.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'
\ No newline at end of file
diff --git a/Bagnon_Config/localization/localization.lua b/Bagnon_Config/localization/localization.lua
new file mode 100644
index 0000000..8266be9
--- /dev/null
+++ b/Bagnon_Config/localization/localization.lua
@@ -0,0 +1,57 @@
+--[[
+ 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.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'
\ No newline at end of file
diff --git a/Bagnon_Config/localization/localization.ru.lua b/Bagnon_Config/localization/localization.ru.lua
new file mode 100644
index 0000000..4276ac3
--- /dev/null
+++ b/Bagnon_Config/localization/localization.ru.lua
@@ -0,0 +1,58 @@
+--[[
+ 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.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 = 'Окраска ячейки ключей'
\ No newline at end of file
diff --git a/Bagnon_Config/localization/localization.tw.lua b/Bagnon_Config/localization/localization.tw.lua
new file mode 100644
index 0000000..3c8d01f
--- /dev/null
+++ b/Bagnon_Config/localization/localization.tw.lua
@@ -0,0 +1,53 @@
+--[[
+ 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.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 = '禁用的背包使用暴雪默認框體'
\ No newline at end of file
diff --git a/Bagnon_Config/panels.xml b/Bagnon_Config/panels.xml
new file mode 100644
index 0000000..0f4673d
--- /dev/null
+++ b/Bagnon_Config/panels.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Bagnon_Config/panels/colorOptions.lua b/Bagnon_Config/panels/colorOptions.lua
new file mode 100644
index 0000000..63b8d3b
--- /dev/null
+++ b/Bagnon_Config/panels/colorOptions.lua
@@ -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()
\ No newline at end of file
diff --git a/Bagnon_Config/panels/displayOptions.lua b/Bagnon_Config/panels/displayOptions.lua
new file mode 100644
index 0000000..cb67232
--- /dev/null
+++ b/Bagnon_Config/panels/displayOptions.lua
@@ -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()
\ No newline at end of file
diff --git a/Bagnon_Config/panels/frameOptions.lua b/Bagnon_Config/panels/frameOptions.lua
new file mode 100644
index 0000000..ffb2816
--- /dev/null
+++ b/Bagnon_Config/panels/frameOptions.lua
@@ -0,0 +1,633 @@
+--[[
+ 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_OpenToCategory(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('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: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 toggleSearchFrame = self:CreateToggleSearchFrameCheckbox()
+ toggleSearchFrame:SetPoint('TOPLEFT', toggleDBOFrame, '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: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)
+ self:AddItem(L.Inventory, 'inventory')
+ self:AddItem(L.Bank, 'bank')
+ self:AddItem(L.KeyRing, 'keys')
+
+ if IsAddOnLoaded('Bagnon_GuildBank') then
+ self: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
+
+
+--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()
\ No newline at end of file
diff --git a/Bagnon_Config/panels/general.lua b/Bagnon_Config/panels/general.lua
new file mode 100644
index 0000000..4891b67
--- /dev/null
+++ b/Bagnon_Config/panels/general.lua
@@ -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_OpenToCategory(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()
\ No newline at end of file
diff --git a/Bagnon_Config/widgets.xml b/Bagnon_Config/widgets.xml
new file mode 100644
index 0000000..128df34
--- /dev/null
+++ b/Bagnon_Config/widgets.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Bagnon_Config/widgets/checkButton.lua b/Bagnon_Config/widgets/checkButton.lua
new file mode 100644
index 0000000..281bf3d
--- /dev/null
+++ b/Bagnon_Config/widgets/checkButton.lua
@@ -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
\ No newline at end of file
diff --git a/Bagnon_Config/widgets/colorSelector.lua b/Bagnon_Config/widgets/colorSelector.lua
new file mode 100644
index 0000000..362460e
--- /dev/null
+++ b/Bagnon_Config/widgets/colorSelector.lua
@@ -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
\ No newline at end of file
diff --git a/Bagnon_Config/widgets/dropdown.lua b/Bagnon_Config/widgets/dropdown.lua
new file mode 100644
index 0000000..e70ce02
--- /dev/null
+++ b/Bagnon_Config/widgets/dropdown.lua
@@ -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, self.width)
+ 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, dropdown)
+ dropdown:SetSavedValue(self.value)
+ UIDropDownMenu_SetSelectedValue(dropdown, self.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
\ No newline at end of file
diff --git a/Bagnon_Config/widgets/optionsPanel.lua b/Bagnon_Config/widgets/optionsPanel.lua
new file mode 100644
index 0000000..fd4ab1e
--- /dev/null
+++ b/Bagnon_Config/widgets/optionsPanel.lua
@@ -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
\ No newline at end of file
diff --git a/Bagnon_Config/widgets/slider.lua b/Bagnon_Config/widgets/slider.lua
new file mode 100644
index 0000000..c68bc75
--- /dev/null
+++ b/Bagnon_Config/widgets/slider.lua
@@ -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('GameFontNormalLeft')
+ _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
\ No newline at end of file
diff --git a/Bagnon_Forever/Bagnon_Forever.toc b/Bagnon_Forever/Bagnon_Forever.toc
new file mode 100644
index 0000000..74fd28f
--- /dev/null
+++ b/Bagnon_Forever/Bagnon_Forever.toc
@@ -0,0 +1,11 @@
+## Interface: 30300
+## 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
\ No newline at end of file
diff --git a/Bagnon_Forever/db.lua b/Bagnon_Forever/db.lua
new file mode 100644
index 0000000..cbd2a01
--- /dev/null
+++ b/Bagnon_Forever/db.lua
@@ -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
\ No newline at end of file
diff --git a/Bagnon_Forever/ui.lua b/Bagnon_Forever/ui.lua
new file mode 100644
index 0000000..9b56f33
--- /dev/null
+++ b/Bagnon_Forever/ui.lua
@@ -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(self, 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(self, 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
\ No newline at end of file
diff --git a/Bagnon_Forever/ui.xml b/Bagnon_Forever/ui.xml
new file mode 100644
index 0000000..3c899f6
--- /dev/null
+++ b/Bagnon_Forever/ui.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Bagnon_GuildBank/Bagnon_GuildBank.toc b/Bagnon_GuildBank/Bagnon_GuildBank.toc
new file mode 100644
index 0000000..bb9aee9
--- /dev/null
+++ b/Bagnon_GuildBank/Bagnon_GuildBank.toc
@@ -0,0 +1,10 @@
+## Interface: 30300
+## Title: Bagnon Guild Bank
+## Author: Tuller
+## Notes: Single window display for your guild bank
+## Version: 1.0.0
+## RequiredDeps: Bagnon
+## LoadOnDemand: 1
+## DefaultState: disabled
+main.lua
+components.xml
\ No newline at end of file
diff --git a/Bagnon_GuildBank/components.xml b/Bagnon_GuildBank/components.xml
new file mode 100644
index 0000000..bfae83c
--- /dev/null
+++ b/Bagnon_GuildBank/components.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Bagnon_GuildBank/components/frame.lua b/Bagnon_GuildBank/components/frame.lua
new file mode 100644
index 0000000..7c0bbce
--- /dev/null
+++ b/Bagnon_GuildBank/components/frame.lua
@@ -0,0 +1,76 @@
+--[[
+ frame.lua
+ A specialized version of the bagnon frame for guild banks
+--]]
+
+local Bagnon = LibStub('AceAddon-3.0'):GetAddon('Bagnon')
+local Frame = Bagnon.Classy:New('Frame', Bagnon.Frame)
+Frame:Hide()
+Bagnon.GuildFrame = Frame
+
+
+--[[
+ Events
+--]]
+
+function Frame:OnShow()
+ PlaySound('GuildVaultOpen')
+
+ self:UpdateEvents()
+ self:UpdateLook()
+end
+
+function Frame:OnHide()
+-- GuildBankPopupFrame:Hide()
+ StaticPopup_Hide('GUILDBANK_WITHDRAW')
+ StaticPopup_Hide('GUILDBANK_DEPOSIT')
+ StaticPopup_Hide('CONFIRM_BUY_GUILDBANK_TAB')
+ CloseGuildBankFrame()
+ PlaySound('GuildVaultClose')
+
+ 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
+
+
+--[[
+ Actions
+--]]
+
+function Frame:CreateItemFrame()
+ local f = Bagnon.GuildItemFrame:New(self:GetFrameID(), self)
+ self.itemFrame = f
+ return f
+end
+
+function Frame:CreateBagFrame()
+ local f = Bagnon.GuildTabFrame:New(self:GetFrameID(), self)
+ self.bagFrame = f
+ return f
+end
+
+function Frame:CreateMoneyFrame()
+ local f = Bagnon.GuildMoneyFrame:New(self:GetFrameID(), self)
+ self.moneyFrame = f
+ return f
+end
+
+function Frame:HasBagFrame()
+ return true
+end
+
+function Frame:IsBagFrameShown()
+ return true
+end
+
+function Frame:HasBagToggle()
+ return false
+end
+
+function Frame:HasPlayerSelector()
+ return false
+end
\ No newline at end of file
diff --git a/Bagnon_GuildBank/components/item.lua b/Bagnon_GuildBank/components/item.lua
new file mode 100644
index 0000000..a00de94
--- /dev/null
+++ b/Bagnon_GuildBank/components/item.lua
@@ -0,0 +1,444 @@
+--[[
+ item.lua
+ A guild item slot button
+--]]
+
+local Bagnon = LibStub('AceAddon-3.0'):GetAddon('Bagnon')
+local ItemSlot = Bagnon.Classy:New('Button')
+ItemSlot:Hide()
+Bagnon.GuildItemSlot = ItemSlot
+
+local ItemSearch = LibStub('LibItemSearch-1.0')
+
+
+--[[
+ The item widget
+--]]
+
+
+--[[ ItemSlot Constructor ]]--
+
+function ItemSlot:New(tab, slot, frameID, parent)
+ local item = self:Restore() or self:Create()
+ item:SetParent(parent)
+ item:SetSlot(tab, 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:ConstructNewItemSlot(id))
+
+ item:RegisterForClicks('anyUp')
+ item:RegisterForDrag('LeftButton')
+
+ item:SetScript('OnEvent', item.HandleEvent)
+ item:SetScript('OnClick', item.OnClick)
+ item:SetScript('OnDragStart', item.OnDragStart)
+ item:SetScript('OnReceiveDrag', item.OnReceiveDrag)
+ item:SetScript('OnEnter', item.OnEnter)
+ item:SetScript('OnLeave', item.OnLeave)
+ item:SetScript('OnShow', item.OnShow)
+ item:SetScript('OnHide', item.OnHide)
+
+ return item
+end
+
+--creates a new item slot for
+function ItemSlot:ConstructNewItemSlot(id)
+ local item = CreateFrame('Button', 'BagnonGuildItemSlot' .. id, nil, 'ItemButtonTemplate')
+ item:Hide()
+
+ --add a quality border texture
+ 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
+
+ return item
+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:GUILDBANK_ITEM_LOCK_CHANGED(event, tab, slot)
+ self:UpdateLocked()
+end
+
+function ItemSlot:TEXT_SEARCH_UPDATE(msg, frameID, search)
+ self:UpdateSearch()
+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:SHOW_EMPTY_ITEM_SLOT_TEXTURE_UPDATE(msg, enable)
+ self:Update()
+end
+
+function ItemSlot:ITEM_SLOT_COLOR_UPDATE(msg, enable)
+ self:Update()
+end
+
+function ItemSlot:HandleEvent(msg, ...)
+ local action = self[msg]
+ if action then
+ action(self, msg, ...)
+ end
+end
+
+
+--[[ Frame Events ]]--
+
+function ItemSlot:OnClick(button)
+ if HandleModifiedItemClick(self:GetItem()) then
+ return
+ end
+
+ if self:IsCached() then
+ return
+ end
+
+ if IsModifiedClick('SPLITSTACK') then
+ if not self:IsLocked() then
+ OpenStackSplitFrame(self:GetCount(), self, 'BOTTOMLEFT', 'TOPLEFT')
+ end
+ return
+ end
+
+ local type, money = GetCursorInfo()
+ if type == 'money' then
+ DepositGuildBankMoney(money)
+ ClearCursor()
+ elseif type == 'guildbankmoney' then
+ DropCursorMoney()
+ ClearCursor()
+ else
+ if button == 'RightButton' then
+ AutoStoreGuildBankItem(self:GetSlot())
+ else
+ PickupGuildBankItem(self:GetSlot())
+ end
+ end
+end
+
+function ItemSlot:OnDragStart(button)
+ PickupGuildBankItem(self:GetSlot())
+end
+
+function ItemSlot:OnReceiveDrag(button)
+ PickupGuildBankItem(self:GetSlot())
+end
+
+function ItemSlot:OnShow()
+ self:Update()
+ self:RegisterEvent('GUILDBANK_ITEM_LOCK_CHANGED')
+end
+
+function ItemSlot:OnHide()
+ self:HideStackSplitFrame()
+ self:UnregisterAllEvents()
+end
+
+function ItemSlot:OnEnter()
+ self:AnchorTooltip()
+ self:UpdateTooltip()
+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, itemCount, locked, itemLink = self:GetItemSlotInfo()
+
+ self:SetItem(itemLink)
+ self:SetTexture(texture)
+ self:SetCount(itemCount)
+ self:SetLocked(locked)
+
+ self:UpdateBorder()
+ 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
+
+local EMPTY_SLOT_TEXTURE = [[Interface\PaperDoll\UI-Backpack-EmptySlot]]
+function ItemSlot:GetEmptyItemTexture()
+ if self:ShowingEmptyItemSlotTexture() then
+ return EMPTY_SLOT_TEXTURE
+ end
+ return nil
+end
+
+--item count
+function ItemSlot:SetCount(count)
+ SetItemButtonCount(self, count)
+end
+
+function ItemSlot:GetCount()
+ local texture, itemCount = self:GetItemSlotInfo()
+ return itemCount or 0
+end
+
+--locked status
+function ItemSlot:SetLocked(locked)
+ SetItemButtonDesaturated(self, locked, 0.5, 0.5, 0.5)
+end
+
+function ItemSlot:UpdateLocked()
+ self:SetLocked(self:IsLocked())
+end
+
+--returns true if the slot is locked, and false otherwise
+function ItemSlot:IsLocked()
+ local texture, itemCount, locked = self:GetItemSlotInfo()
+ return locked
+end
+
+--colors the item border based on the quality of the item. hides it for common/poor items
+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
+
+function ItemSlot:UpdateBorder()
+ local itemLink = self:GetItem()
+
+ if itemLink then
+ local name, link, quality = GetItemInfo(itemLink)
+ self:SetBorderQuality(quality)
+ else
+ self:SetBorderQuality(nil)
+ end
+end
+
+--stack split frame
+function ItemSlot:SplitStack(split)
+ local tab, slot = self:GetSlot()
+ SplitGuildBankItem(tab, slot, split)
+end
+
+function ItemSlot:HideStackSplitFrame()
+ if self.hasStackSplit and self.hasStackSplit == 1 then
+ StackSplitFrame:Hide()
+ end
+end
+
+--tooltip methods
+function ItemSlot:UpdateTooltip()
+ if self:IsCached() then
+ GameTooltip:SetHyperlink(self:GetItem())
+ else
+ GameTooltip:SetGuildBankItem(self:GetSlot())
+ end
+
+ GameTooltip:Show()
+end
+
+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
+
+
+
+--[[ 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:SetSlot(tab, slot)
+ self.tab = tab
+ self:SetID(slot)
+ self:Update()
+end
+
+function ItemSlot:GetSlot()
+ return self.tab, self:GetID()
+end
+
+function ItemSlot:IsSlot(tab, slot)
+ return self.tab == tab and self:GetID() == slot
+end
+
+function ItemSlot:IsCached()
+ return false
+end
+
+function ItemSlot:GetItemSlotInfo()
+ local texture, itemCount, locked = GetGuildBankItemInfo(self:GetSlot())
+ local itemLink = GetGuildBankItemLink(self:GetSlot())
+
+ return texture, itemCount, locked, itemLink
+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
+
+local QUEST_ITEM_SEARCH = string.format('t:%s|%s', select(12, GetAuctionItemClasses()), 'quest')
+function ItemSlot:IsQuestItem()
+ local itemLink = self:GetItem()
+ if not itemLink then
+ return false
+ end
+
+ return ItemSearch:Find(itemLink, QUEST_ITEM_SEARCH)
+end
+
+
+--[[ Empty Slot Visibility ]]--
+
+function ItemSlot:ShowingEmptyItemSlotTexture()
+ return Bagnon.Settings:ShowingEmptyItemSlotTextures()
+end
\ No newline at end of file
diff --git a/Bagnon_GuildBank/components/itemFrame.lua b/Bagnon_GuildBank/components/itemFrame.lua
new file mode 100644
index 0000000..c72e913
--- /dev/null
+++ b/Bagnon_GuildBank/components/itemFrame.lua
@@ -0,0 +1,255 @@
+--[[
+ itemFrame.lua
+ An guild bank item slot container
+--]]
+
+local Bagnon = LibStub('AceAddon-3.0'):GetAddon('Bagnon')
+local ItemFrame = Bagnon.Classy:New('Frame')
+ItemFrame:Hide()
+Bagnon.GuildItemFrame = ItemFrame
+
+
+--[[ 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:GUILDBANKBAGSLOTS_CHANGED(event, ...)
+ self:ReloadAllItemSlots()
+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:HandleGlobalItemEvent(msg, ...)
+ for i, item in self:GetAllItemSlots() do
+ item:HandleEvent(msg, ...)
+ end
+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:UnregisterAllMessages()
+
+ if self:IsVisible() then
+ self:RegisterEvent('GUILDBANKBAGSLOTS_CHANGED')
+
+ self:RegisterMessage('ITEM_FRAME_SPACING_UPDATE')
+ self:RegisterMessage('ITEM_FRAME_COLUMNS_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(slot)
+ if not self:GetItemSlot(slot) then
+ local itemSlot = self:NewItemSlot(slot)
+ self.itemSlots[slot] = itemSlot
+ self:RequestLayout()
+ end
+end
+
+function ItemFrame:NewItemSlot(slot)
+ return Bagnon.GuildItemSlot:New(self:GetCurrentTab(), slot, self:GetFrameID(), self)
+end
+
+--returns the item slot assigned to the given slotIndex
+function ItemFrame:GetItemSlot(slot)
+ return self.itemSlots[slot]
+end
+
+function ItemFrame:GetAllItemSlots()
+ return ipairs(self.itemSlots)
+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 currentTab = self:GetCurrentTab()
+ for slot = 1, self:GetCurrentTabSize() do
+ local itemSlot = self:GetItemSlot(slot)
+ if not itemSlot then
+ self:AddItemSlot(slot)
+ changed = true
+ else
+ itemSlot:SetSlot(currentTab, slot)
+ end
+ end
+
+ if changed then
+ self:RequestLayout()
+ end
+end
+
+
+--[[ Layout Methods ]]--
+
+--arranges itemSlots on the ItemFrame, and adjusts size to fit
+--it should be noted that the guild bank is wacky in that items go down a column
+function ItemFrame:Layout()
+ self.needsLayout = nil
+
+ local numItems = self:GetCurrentTabSize()
+ local numColumns = math.min(self:NumColumns(), numItems)
+ local numRows = math.floor(numItems / numColumns + 0.5)
+ local spacing = self:GetSpacing()
+ local effItemSize = self.ITEM_SIZE + spacing
+
+ local row, col = 0, 1
+ for i, itemSlot in self:GetAllItemSlots() do
+ row = row + 1
+ if row > numRows then
+ row = 1
+ col = col + 1
+ end
+
+ itemSlot:ClearAllPoints()
+ itemSlot:SetPoint('TOPLEFT', self, 'TOPLEFT', effItemSize * (col - 1), -effItemSize * (row - 1))
+ end
+
+ local width = effItemSize * col - spacing
+ local height = effItemSize * numRows - spacing
+ 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
+
+--layout info
+function ItemFrame:NumColumns()
+ return self:GetSettings():GetItemFrameColumns()
+end
+
+function ItemFrame:GetSpacing()
+ return self:GetSettings():GetItemFrameSpacing()
+end
+
+--guild bank info
+function ItemFrame:GetCurrentTab()
+ return GetCurrentGuildBankTab() or 0
+end
+
+function ItemFrame:GetCurrentTabSize()
+ return 98
+end
\ No newline at end of file
diff --git a/Bagnon_GuildBank/components/moneyFrame.lua b/Bagnon_GuildBank/components/moneyFrame.lua
new file mode 100644
index 0000000..29c490a
--- /dev/null
+++ b/Bagnon_GuildBank/components/moneyFrame.lua
@@ -0,0 +1,247 @@
+--[[
+ moneyFrame.lua
+ A money frame object
+--]]
+
+local Bagnon = LibStub('AceAddon-3.0'):GetAddon('Bagnon')
+local MoneyFrame = Bagnon.Classy:New('Frame')
+MoneyFrame:Hide()
+Bagnon.GuildMoneyFrame = 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', 'BagnonGuildMoneyFrame' .. self:GetNextID(), parent, 'SmallMoneyFrameTemplate'))
+ f:SetFrameID(frameID)
+ f:AddClickFrame()
+
+ f:SetScript('OnShow', f.OnShow)
+ f:SetScript('OnHide', f.OnHide)
+ f:SetScript('OnEvent', f.OnEvent)
+
+ 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:RegisterForClicks('anyUp')
+
+ 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:GUILDBANK_UPDATE_MONEY()
+ self:UpdateValue()
+end
+
+--[[ Frame Events ]]--
+
+function MoneyFrame:OnShow()
+ self:UpdateEverything()
+end
+
+function MoneyFrame:OnHide()
+ self:UpdateEvents()
+end
+
+function MoneyFrame:OnClick(button)
+ local cMoney = GetCursorMoney() or 0
+ if cMoney > 0 then
+ self:DepositMoney(cMoney)
+ return
+ end
+
+ if button == 'LeftButton' and (not IsShiftKeyDown()) then
+ self:ShowDepositDialog()
+ return
+ end
+
+ if button == 'RightButton' or (button == 'LeftButton' and IsShiftKeyDown()) then
+ self:ShowWithdrawDialog()
+ return
+ end
+end
+
+function MoneyFrame:OnEnter()
+ GameTooltip:SetOwner(self, 'ANCHOR_TOPRIGHT')
+ self:UpdateTooltip()
+end
+
+function MoneyFrame:OnLeave()
+ if GameTooltip:IsOwned(self) then
+ GameTooltip:Hide()
+ end
+end
+
+function MoneyFrame:OnEvent(event, ...)
+ local action = self[event]
+ if action then
+ action(self, event, ...)
+ end
+end
+
+
+--[[ Actions ]]--
+
+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:UnregisterAllEvents()
+ if self:IsVisible() then
+ self:RegisterEvent('GUILDBANK_UPDATE_MONEY')
+ end
+end
+
+function MoneyFrame:UpdateTooltip()
+ GameTooltip:SetText('Guild Funds')
+ GameTooltip:AddLine(' to deposit.', 1, 1, 1)
+
+ if CanWithdrawGuildBankMoney() then
+ local withdrawMoney = GetGuildBankWithdrawMoney()
+ if withdrawMoney > 0 then
+ GameTooltip:AddLine(string.format(' to withdraw (%s remaining).', self:GetCurrencyText(withdrawMoney)), 1, 1, 1)
+ else
+ GameTooltip:AddLine(' to withdraw.')
+ end
+ end
+
+ GameTooltip:Show()
+end
+
+function MoneyFrame:DepositMoney(amount)
+ DepositGuildBankMoney(cMoney)
+ DropCursorMoney()
+end
+
+function MoneyFrame:ShowDepositDialog()
+ PlaySound('igMainMenuOption')
+
+ StaticPopup_Hide('GUILDBANK_WITHDRAW')
+ if StaticPopup_Visible('GUILDBANK_DEPOSIT') then
+ StaticPopup_Hide('GUILDBANK_DEPOSIT')
+ else
+ StaticPopup_Show('GUILDBANK_DEPOSIT')
+ end
+end
+
+function MoneyFrame:ShowWithdrawDialog()
+ if not CanWithdrawGuildBankMoney() then return end
+
+ PlaySound('igMainMenuOption')
+
+ StaticPopup_Hide('GUILDBANK_DEPOSIT')
+ if StaticPopup_Visible('GUILDBANK_WITHDRAW') then
+ StaticPopup_Hide('GUILDBANK_WITHDRAW')
+ else
+ StaticPopup_Show('GUILDBANK_WITHDRAW')
+ 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 GetGuildBankMoney()
+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:GetCurrencyText(money)
+ 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 or (gold == 0 and silver == 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
+
+ return text
+end
\ No newline at end of file
diff --git a/Bagnon_GuildBank/components/savedFrameSettings.lua b/Bagnon_GuildBank/components/savedFrameSettings.lua
new file mode 100644
index 0000000..695b92b
--- /dev/null
+++ b/Bagnon_GuildBank/components/savedFrameSettings.lua
@@ -0,0 +1,38 @@
+--[[
+ SavedFrameSettings.lua
+ behold the monkeypatching
+--]]
+
+local Bagnon = LibStub('AceAddon-3.0'):GetAddon('Bagnon')
+local SavedFrameSettings = Bagnon.SavedFrameSettings
+
+function SavedFrameSettings:GetDefaultGuildBankSettings()
+ local defaults = SavedFrameSettings.guildBankDefaults or {
+ --frame
+ frameColor = {0, 0, 0, 0.5},
+ frameBorderColor = {0, 1, 0, 1},
+ scale = 1,
+ opacity = 1,
+ point = 'CENTER',
+ x = 0,
+ y = 0,
+ frameLayer = 'HIGH',
+
+ --itemFrame
+ itemFrameColumns = 14,
+ itemFrameSpacing = 2,
+
+ --optional components
+ hasMoneyFrame = false,
+ hasBagFrame = true,
+ hasDBOFrame = true,
+ hasSearchToggle = true,
+ hasOptionsToggle = true,
+
+ --dbo display object
+ dataBrokerObject = 'BagnonLauncher',
+ }
+
+ SavedFrameSettings.guildBankDefaults = defaults
+ return defaults
+end
\ No newline at end of file
diff --git a/Bagnon_GuildBank/components/tab.lua b/Bagnon_GuildBank/components/tab.lua
new file mode 100644
index 0000000..0a7ee51
--- /dev/null
+++ b/Bagnon_GuildBank/components/tab.lua
@@ -0,0 +1,265 @@
+--[[
+ bag.lua
+ A bag button object for Bagnon
+--]]
+
+local Bagnon = LibStub('AceAddon-3.0'):GetAddon('Bagnon')
+local GuildTab = Bagnon.Classy:New('CheckButton')
+Bagnon.GuildTab = GuildTab
+
+--constants
+local SIZE = 32
+local NORMAL_TEXTURE_SIZE = 64 * (SIZE/36)
+
+
+--[[ Constructor ]]--
+
+function GuildTab:New(tabID, frameID, parent)
+ local tab = self:Create(tabID, parent)
+ tab:SetFrameID(frameID)
+
+ tab:SetScript('OnEnter', tab.OnEnter)
+ tab:SetScript('OnLeave', tab.OnLeave)
+ tab:SetScript('OnClick', tab.OnClick)
+ tab:SetScript('OnDragStart', tab.OnDrag)
+ tab:SetScript('OnReceiveDrag', tab.OnClick)
+ tab:SetScript('OnEvent', tab.OnEvent)
+ tab:SetScript('OnShow', tab.OnShow)
+ tab:SetScript('OnHide', tab.OnHide)
+
+ return tab
+end
+
+function GuildTab:Create(tabID, parent)
+ local tab = self:Bind(CreateFrame('CheckButton', 'BagnonGuildTab' .. self:GetNextID(), parent))
+ tab:SetWidth(SIZE)
+ tab:SetHeight(SIZE)
+ tab:SetID(tabID)
+
+ local name = tab:GetName()
+ local icon = tab:CreateTexture(name .. 'IconTexture', 'BORDER')
+ icon:SetAllPoints(tab)
+
+ local count = tab:CreateFontString(name .. 'Count', 'OVERLAY')
+ count:SetFontObject('NumberFontNormalSmall')
+ count:SetJustifyH('RIGHT')
+ count:SetPoint('BOTTOMRIGHT', -2, 2)
+
+ local nt = tab:CreateTexture(name .. 'NormalTexture')
+ nt:SetTexture([[Interface\Buttons\UI-Quickslot2]])
+ nt:SetWidth(NORMAL_TEXTURE_SIZE)
+ nt:SetHeight(NORMAL_TEXTURE_SIZE)
+ nt:SetPoint('CENTER', 0, -1)
+ tab:SetNormalTexture(nt)
+
+ local pt = tab:CreateTexture()
+ pt:SetTexture([[Interface\Buttons\UI-Quickslot-Depress]])
+ pt:SetAllPoints(tab)
+ tab:SetPushedTexture(pt)
+
+ local ht = tab:CreateTexture()
+ ht:SetTexture([[Interface\Buttons\ButtonHilight-Square]])
+ ht:SetAllPoints(tab)
+ tab:SetHighlightTexture(ht)
+
+ local ct = tab:CreateTexture()
+ ct:SetTexture([[Interface\Buttons\CheckButtonHilight]])
+ ct:SetAllPoints(tab)
+ ct:SetBlendMode('ADD')
+ tab:SetCheckedTexture(ct)
+
+ tab:RegisterForClicks('anyUp')
+ tab:RegisterForDrag('LeftButton')
+
+ return tab
+end
+
+do
+ local id = 0
+ function GuildTab:GetNextID()
+ id = id + 1
+ return id
+ end
+end
+
+
+--[[ Events ]]--
+
+function GuildTab:OnEvent(event, ...)
+ local action = self[event]
+ if action then
+ action(self, event, ...)
+ end
+end
+
+function GuildTab:UpdateEvents()
+ self:UnregisterAllEvents()
+ self:UnregisterAllMessages()
+
+ if self:IsVisible() then
+ self:RegisterMessage('GUILD_BANK_TAB_CHANGE')
+ self:RegisterEvent('GUILDBANK_UPDATE_TABS')
+ self:RegisterEvent('GUILDBANKBAGSLOTS_CHANGED')
+ end
+end
+
+
+--[[ Messages ]]--
+
+function GuildTab:GUILDBANK_UPDATE_TABS()
+ self:Update()
+end
+
+function GuildTab:GUILD_BANK_TAB_CHANGE(msg, tabID)
+ self:UpdateChecked()
+end
+
+function GuildTab:GUILDBANKBAGSLOTS_CHANGED()
+ self:UpdateCount()
+end
+
+--[[ Frame Events ]]--
+
+function GuildTab:OnShow()
+ self:UpdateEverything()
+end
+
+function GuildTab:OnHide()
+ self:UpdateEvents()
+end
+
+function GuildTab:OnClick()
+ SetCurrentGuildBankTab(self:GetID())
+ QueryGuildBankTab(self:GetID())
+ self:SendMessage('GUILD_BANK_TAB_CHANGE', self:GetID())
+end
+
+function GuildTab:OnDrag()
+ --on drag
+end
+
+function GuildTab:OnEnter()
+ if self:GetRight() > (GetScreenWidth() / 2) then
+ GameTooltip:SetOwner(self, 'ANCHOR_LEFT')
+ else
+ GameTooltip:SetOwner(self, 'ANCHOR_RIGHT')
+ end
+
+ self:UpdateTooltip()
+end
+
+function GuildTab:OnLeave()
+ if GameTooltip:IsOwned(self) then
+ GameTooltip:Hide()
+ end
+end
+
+
+--[[ Actions ]]--
+
+function GuildTab:UpdateEverything()
+ self:UpdateEvents()
+ self:Update()
+ self:UpdateChecked()
+end
+
+function GuildTab:Update()
+ local name, icon, isViewable, canDeposit, numWithdrawals, remainingWithdrawals = GetGuildBankTabInfo(self:GetID())
+ SetItemButtonTexture(self, icon or [[Interface\PaperDoll\UI-PaperDoll-Slot-Bag]])
+
+ self:UpdateCount(remainingWithdrawals)
+
+ --color red if the bag can be purchased
+ if not isViewable then
+ SetItemButtonTextureVertexColor(self, 1, 0.1, 0.1)
+ else
+ SetItemButtonTextureVertexColor(self, 1, 1, 1)
+ end
+end
+
+function GuildTab: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
+
+function GuildTab:UpdateChecked()
+ self:SetChecked(self:IsCurrentTab())
+end
+
+function GuildTab:UpdateCount(count)
+ --hack, since the amount of withdrawls seems to only be correct when we're looking at the current tab
+ if not self:IsCurrentTab() then
+ return
+ end
+
+ if not count then
+ local name, icon, isViewable, canDeposit, numWithdrawals, remainingWithdrawals = GetGuildBankTabInfo(self:GetID())
+ count = remainingWithdrawals
+ end
+
+ self:SetCount(count)
+end
+
+function GuildTab:IsCurrentTab()
+ return self:GetID() == GetCurrentGuildBankTab()
+end
+
+
+--[[ Tooltip Methods ]]--
+
+function GuildTab:UpdateTooltip()
+ local name, icon, isViewable, canDeposit, numWithdrawals, remainingWithdrawals = GetGuildBankTabInfo(self:GetID())
+
+ if name then
+ GameTooltip:SetText(name)
+
+ local access
+ if not canDeposit and numWithdrawals == 0 then
+ access = RED_FONT_COLOR_CODE .. "(" .. GUILDBANK_TAB_LOCKED .. ")" .. FONT_COLOR_CODE_CLOSE;
+ elseif not canDeposit then
+ access = RED_FONT_COLOR_CODE .."(" .. GUILDBANK_TAB_WITHDRAW_ONLY .. ")" .. FONT_COLOR_CODE_CLOSE;
+ elseif numWithdrawals == 0 then
+ access = RED_FONT_COLOR_CODE .."(" .. GUILDBANK_TAB_DEPOSIT_ONLY .. ")" .. FONT_COLOR_CODE_CLOSE;
+ else
+ access = GREEN_FONT_COLOR_CODE .. "(" .. GUILDBANK_TAB_FULL_ACCESS .. ")" .. FONT_COLOR_CODE_CLOSE;
+ end
+
+ GameTooltip:AddLine(access)
+ else
+ GameTooltip:SetText('Unavailable')
+ end
+
+ GameTooltip:Show()
+end
+
+
+--[[ Accessor Functions ]]--
+
+
+--returns the bagnon frame we're attached to
+function GuildTab:SetFrameID(frameID)
+ if self:GetFrameID() ~= frameID then
+ self.frameID = frameID
+ self:UpdateEverything()
+ end
+end
+
+function GuildTab:GetFrameID()
+ return self.frameID
+end
+
+--return the settings object associated with this frame
+function GuildTab:GetSettings()
+ return Bagnon.FrameSettings:Get(self:GetFrameID())
+end
\ No newline at end of file
diff --git a/Bagnon_GuildBank/components/tabFrame.lua b/Bagnon_GuildBank/components/tabFrame.lua
new file mode 100644
index 0000000..0aa64ad
--- /dev/null
+++ b/Bagnon_GuildBank/components/tabFrame.lua
@@ -0,0 +1,145 @@
+--[[
+ bagFrame.lua
+ A container object for bags
+--]]
+
+local Bagnon = LibStub('AceAddon-3.0'):GetAddon('Bagnon')
+local TabFrame = Bagnon.Classy:New('Frame')
+Bagnon.GuildTabFrame = TabFrame
+
+
+--[[ Constructor ]]--
+
+function TabFrame: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 TabFrame:CreateBagSlots()
+ local bags = {}
+
+ for id = 1, MAX_GUILDBANK_TABS do
+ table.insert(bags, Bagnon.GuildTab:New(id, self:GetFrameID(), self))
+ end
+
+ self.bags = bags
+end
+
+
+--[[ Messages ]]--
+
+function TabFrame:BAG_FRAME_SHOW(msg, frameID)
+ if frameID == self:GetFrameID() then
+ self:UpdateShown()
+ end
+end
+
+function TabFrame:BAG_FRAME_HIDE(msg, frameID)
+ if frameID == self:GetFrameID() then
+ self:UpdateShown()
+ end
+end
+
+
+--[[ Frame Events ]]--
+
+function TabFrame:OnShow()
+ self:Layout()
+ self:SendMessage('BAG_FRAME_UPDATE_SHOWN', self:GetFrameID())
+end
+
+function TabFrame:OnHide()
+ self:SendMessage('BAG_FRAME_UPDATE_SHOWN', self:GetFrameID())
+end
+
+
+--[[ Update Methods ]]--
+
+function TabFrame:UpdateShown()
+ if self:IsBagFrameShown() then
+ if not self:IsShown() then
+ UIFrameFadeIn(self, 0.1)
+ end
+ else
+ self:Hide()
+ end
+end
+
+function TabFrame:UpdateEvents()
+ self:UnregisterAllMessages()
+
+ self:RegisterMessage('BAG_FRAME_SHOW')
+ self:RegisterMessage('BAG_FRAME_HIDE')
+end
+
+function TabFrame: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 TabFrame:SetFrameID(frameID)
+ if self:GetFrameID() ~= frameID then
+ self.frameID = frameID
+-- self:UpdateShown()
+ end
+end
+
+function TabFrame:GetFrameID()
+ return self.frameID
+end
+
+function TabFrame:GetBags()
+ return ipairs(self.bags)
+end
+
+
+--[[ Frame Settings ]]--
+
+function TabFrame:GetSettings()
+ return Bagnon.FrameSettings:Get(self:GetFrameID())
+end
+
+function TabFrame:IsBagFrameShown()
+ return self:GetSettings():IsBagFrameShown()
+end
+
+function TabFrame:GetSpacing()
+ return 4
+end
+
+function TabFrame:GetPadding()
+ return 0
+end
\ No newline at end of file
diff --git a/Bagnon_GuildBank/localization.xml b/Bagnon_GuildBank/localization.xml
new file mode 100644
index 0000000..f5aff1d
--- /dev/null
+++ b/Bagnon_GuildBank/localization.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Bagnon_GuildBank/main.lua b/Bagnon_GuildBank/main.lua
new file mode 100644
index 0000000..8b0cbd7
--- /dev/null
+++ b/Bagnon_GuildBank/main.lua
@@ -0,0 +1,23 @@
+--[[
+ main.lua
+ The bagnon driver thingy
+--]]
+
+local Bagnon = LibStub('AceAddon-3.0'):GetAddon('Bagnon')
+local GuildBank = Bagnon:NewModule('GuildBank', 'AceEvent-3.0')
+
+function GuildBank:OnEnable()
+ Bagnon.GuildFrame:New('guildbank')
+
+ self:RegisterEvent('GUILDBANKFRAME_OPENED')
+ self:RegisterEvent('GUILDBANKFRAME_CLOSED')
+end
+
+function GuildBank:GUILDBANKFRAME_OPENED()
+ Bagnon.FrameSettings:Get('guildbank'):Show()
+ QueryGuildBankTab(GetCurrentGuildBankTab())
+end
+
+function GuildBank:GUILDBANKFRAME_CLOSED()
+ Bagnon.FrameSettings:Get('guildbank'):Hide()
+end
diff --git a/Bagnon_GuildBank/todo.txt b/Bagnon_GuildBank/todo.txt
new file mode 100644
index 0000000..4da427f
--- /dev/null
+++ b/Bagnon_GuildBank/todo.txt
@@ -0,0 +1,4 @@
+* Clean up tab display, if I can
+* Add guildmaster functionality (purchase/edit tabs)
+* Add money and item log viewing
+* Add basic cached item view
\ No newline at end of file
diff --git a/Bagnon_Tooltips/Bagnon_Tooltips.toc b/Bagnon_Tooltips/Bagnon_Tooltips.toc
new file mode 100644
index 0000000..becf798
--- /dev/null
+++ b/Bagnon_Tooltips/Bagnon_Tooltips.toc
@@ -0,0 +1,13 @@
+## Interface: 30300
+## Title: Bagnon Tooltips
+## Author: Tuller
+## Notes: Tooltips for telling who has what
+## Notes-zhCN: 物品提示上显示同帐号下其他角色银行/背包黑该物品情况
+## Notes-zhTW: 物品提示上顯示同帳號下其他角色銀行/背包黑該物品情況
+## RequiredDeps: Bagnon_Forever
+localization\localization.lua
+localization\localization.tw.lua
+localization\localization.cn.lua
+localization\localization.ru.lua
+localization\localization.de.lua
+tooltips.lua
diff --git a/Bagnon_Tooltips/localization/localization.cn.lua b/Bagnon_Tooltips/localization/localization.cn.lua
new file mode 100644
index 0000000..4483573
--- /dev/null
+++ b/Bagnon_Tooltips/localization/localization.cn.lua
@@ -0,0 +1,10 @@
+--[[
+ Bagnon_Tooltips Localization
+ 2008-12-01 by yleaf@cwdg(yaroot@gmail.com)
+--]]
+
+if GetLocale() ~= "zhCN" then return end
+
+BAGNON_NUM_BAGS = '背包: %d'
+BAGNON_NUM_BANK = '银行: %d'
+BAGNON_EQUIPPED = '已装备'
\ No newline at end of file
diff --git a/Bagnon_Tooltips/localization/localization.de.lua b/Bagnon_Tooltips/localization/localization.de.lua
new file mode 100644
index 0000000..837260a
--- /dev/null
+++ b/Bagnon_Tooltips/localization/localization.de.lua
@@ -0,0 +1,12 @@
+--[[
+ Bagnon_Tooltips Localization
+ German
+--]]
+
+if ( GetLocale() == "deDE" ) then
+
+BAGNON_NUM_BAGS = 'Taschen: %d'
+BAGNON_NUM_BANK = 'Bank: %d'
+BAGNON_EQUIPPED = 'Angelegt'
+
+end
\ No newline at end of file
diff --git a/Bagnon_Tooltips/localization/localization.lua b/Bagnon_Tooltips/localization/localization.lua
new file mode 100644
index 0000000..f0a31eb
--- /dev/null
+++ b/Bagnon_Tooltips/localization/localization.lua
@@ -0,0 +1,8 @@
+--[[
+ Bagnon_Tooltips Localization
+ English: default language
+--]]
+
+BAGNON_NUM_BAGS = 'Bags: %d'
+BAGNON_NUM_BANK = 'Bank: %d'
+BAGNON_EQUIPPED = 'Equipped'
\ No newline at end of file
diff --git a/Bagnon_Tooltips/localization/localization.ru.lua b/Bagnon_Tooltips/localization/localization.ru.lua
new file mode 100644
index 0000000..fe7dc9f
--- /dev/null
+++ b/Bagnon_Tooltips/localization/localization.ru.lua
@@ -0,0 +1,10 @@
+--[[
+ Bagnon_Tooltips Localization
+ Russian: Russian Localization by kutensky
+--]]
+
+if ( GetLocale() == "ruRU" ) then
+ BAGNON_NUM_BAGS = 'В сумке: %d'
+ BAGNON_NUM_BANK = 'В банке: %d'
+ BAGNON_EQUIPPED = 'На персонаже'
+end
\ No newline at end of file
diff --git a/Bagnon_Tooltips/localization/localization.tw.lua b/Bagnon_Tooltips/localization/localization.tw.lua
new file mode 100644
index 0000000..c37fec5
--- /dev/null
+++ b/Bagnon_Tooltips/localization/localization.tw.lua
@@ -0,0 +1,9 @@
+--[[
+ Bagnon_Tooltips Localization
+ Traditional Chinse - 20071117 by matini< yiting.jheng gmail com
+--]]
+if GetLocale() ~= "zhTW" then return end
+
+BAGNON_NUM_BAGS = '背包: %d'
+BAGNON_NUM_BANK = '銀行: %d'
+BAGNON_EQUIPPED = '已裝備'
\ No newline at end of file
diff --git a/Bagnon_Tooltips/tooltips.lua b/Bagnon_Tooltips/tooltips.lua
new file mode 100644
index 0000000..30f238a
--- /dev/null
+++ b/Bagnon_Tooltips/tooltips.lua
@@ -0,0 +1,108 @@
+--[[
+ Bagnon Tooltips
+ Does ownership tooltips based on Bagnon_Forever data
+--]]
+
+local currentPlayer = UnitName('player')
+local itemInfo = {}
+local SILVER = '|cffc7c7cf%s|r'
+local TEAL = '|cff00ff9a%s|r'
+
+local function CountsToInfoString(invCount, bankCount, equipCount)
+ local info
+ local total = invCount + bankCount + equipCount
+
+ if invCount > 0 then
+ info = BAGNON_NUM_BAGS:format(invCount)
+ end
+
+ if bankCount > 0 then
+ local count = BAGNON_NUM_BANK:format(bankCount)
+ if info then
+ info = strjoin(', ', info, count)
+ else
+ info = count
+ end
+ end
+
+ if equipCount > 0 then
+ if info then
+ info = strjoin(', ', info, BAGNON_EQUIPPED)
+ else
+ info = BAGNON_EQUIPPED
+ end
+ end
+
+ if info then
+ if total and not(total == invCount or total == bankCount or total == equipCount) then
+ --split into two steps for debugging purposes
+ local totalStr = format(TEAL, total)
+ return totalStr .. format(SILVER, format(' (%s)', info))
+ end
+ return format(TEAL, info)
+ end
+end
+
+--make up the self populating table
+do
+ for player in BagnonDB:GetPlayers() do
+ if player ~= currentPlayer then
+ itemInfo[player] = setmetatable({}, {__index = function(self, link)
+ local invCount = BagnonDB:GetItemCount(link, KEYRING_CONTAINER, player)
+ for bag = 0, NUM_BAG_SLOTS do
+ invCount = invCount + BagnonDB:GetItemCount(link, bag, player)
+ end
+
+ local bankCount = BagnonDB:GetItemCount(link, BANK_CONTAINER, player)
+ for i = 1, NUM_BANKBAGSLOTS do
+ bankCount = bankCount + BagnonDB:GetItemCount(link, NUM_BAG_SLOTS + i, player)
+ end
+
+ local equipCount = BagnonDB:GetItemCount(link, 'e', player)
+
+ self[link] = CountsToInfoString(invCount or 0, bankCount or 0, equipCount or 0) or ''
+ return self[link]
+ end})
+ end
+ end
+end
+
+local function AddOwners(frame, link)
+ for player in BagnonDB:GetPlayers() do
+ local infoString
+ if player == currentPlayer then
+ local invCount = BagnonDB:GetItemCount(link, KEYRING_CONTAINER, player)
+ for bag = 0, NUM_BAG_SLOTS do
+ invCount = invCount + BagnonDB:GetItemCount(link, bag, player)
+ end
+
+ local bankCount = BagnonDB:GetItemCount(link, BANK_CONTAINER, player)
+ for i = 1, NUM_BANKBAGSLOTS do
+ bankCount = bankCount + BagnonDB:GetItemCount(link, NUM_BAG_SLOTS + i, player)
+ end
+
+ local equipCount = BagnonDB:GetItemCount(link, 'e', player)
+
+ infoString = CountsToInfoString(invCount or 0, bankCount or 0, equipCount or 0)
+ else
+ infoString = itemInfo[player][link]
+ end
+
+ if infoString and infoString ~= '' then
+ frame:AddDoubleLine(format(TEAL, player), infoString)
+ end
+ end
+ frame:Show()
+end
+
+local function HookTip(tooltip)
+ tooltip:HookScript('OnTooltipSetItem', function(self, ...)
+ local itemLink = select(2, self:GetItem())
+ if itemLink and GetItemInfo(itemLink) then --fix for blizzard doing craziness when doing getiteminfo
+ AddOwners(self, itemLink)
+ end
+ end)
+end
+
+HookTip(GameTooltip)
+HookTip(ItemRefTooltip)
\ No newline at end of file
diff --git a/README.md b/README.md
index 226db33..afaf488 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,3 @@
-# Addon Name
+# Bagnon
-This is the repository for . Modified for Ascension.gg.
\ No newline at end of file
+This is the repository for Bagnon. Modified for Ascension.gg.
\ No newline at end of file