pfUI:RegisterModule("bags", function () local rawborder, default_border = GetBorderSize("bags") local extractSpells = { [13262] = {frame="disenchant"}, [1804] = {frame="picklock"}, } local function BagSortOpts() return { reverse = C.appearance.bags.sortreverse == "1", reversePrio = C.appearance.bags.sortprioreverse == "1", } end -- function to detect openable items in inventory local openable = { bag = nil, slot = nil, icon = nil } local function GetNextOpenable() if openable.icon and openable.icon == GetContainerItemInfo(openable.bag, openable.slot) then return openable.bag, openable.slot end for bag=-2, 11 do local bagsize = GetContainerNumSlots(bag) if bag == -2 and pfUI.bag.showKeyring == true then bagsize = GetKeyRingSize() end for slot=1, bagsize do local _, canOpen = C_Container.IsContainerItemOpenable(bag, slot) if canOpen then openable.bag = bag openable.slot = slot openable.icon = GetContainerItemInfo(bag, slot) return openable.bag, openable.slot end end end end -- prevent from being placed offscreen _G.StackSplitFrame:SetClampedToScreen(true) -- overwrite some bag functions function _G.OpenAllBags() if pfUI.bag.right:IsShown() then pfUI.bag.right:Hide() else pfUI.bag.right:Show() end end function _G.CloseAllBags() pfUI.bag.right:Hide() end function _G.ToggleBackpack() if pfUI.bag.right:IsShown() then pfUI.bag.right:Hide() else pfUI.bag.right:Show() end end function _G.OpenBackpack() if ( pfUI.bag.right:IsShown() ) then ContainerFrame1.backpackWasOpen = 1 return else ContainerFrame1.backpackWasOpen = nil end if ( not ContainerFrame1.backpackWasOpen ) then ToggleBackpack() end end function _G.ToggleBag() return end -- hide blizzard's bankframe BankFrame:SetScale(0.001) BankFrame:SetPoint("TOPLEFT", 0,0) BankFrame:SetAlpha(0) pfUI.bag = CreateFrame("Frame", "pfUIBag") pfUI.bag:RegisterEvent("PLAYER_ENTERING_WORLD") pfUI.bag:RegisterEvent("BAG_UPDATE") pfUI.bag:RegisterEvent("PLAYERBANKSLOTS_CHANGED") pfUI.bag:RegisterEvent("PLAYERBANKBAGSLOTS_CHANGED") pfUI.bag:RegisterEvent("BAG_UPDATE_COOLDOWN") pfUI.bag:RegisterEvent("BAG_CLOSED") pfUI.bag:RegisterEvent("BANKFRAME_CLOSED") pfUI.bag:RegisterEvent("BANKFRAME_OPENED") pfUI.bag:RegisterEvent("ITEM_LOCK_CHANGED") pfUI.bag:RegisterEvent("SPELLS_CHANGED") pfUI.bag:RegisterEvent("MERCHANT_CLOSED") pfUI.bag:RegisterEvent("INVENTORY_SEARCH_UPDATE") pfUI.bag.delay = { UpdateBag = {} } pfUI.bag:SetScript("OnUpdate", function() -- update delayed ones every 0.1s if ( this.tick or 1) > GetTime() then return else this.tick = GetTime() + .1 end if this.delay.RefreshSpells then this.delay.RefreshSpells = nil pfUI.bag:RefreshSpells() end if this.delay.CheckFullUpdate then this.delay.CheckFullUpdate = nil pfUI.bag:CheckFullUpdate() end if this.delay.UpdateCooldowns then this.delay.UpdateCooldowns = nil pfUI.bag:UpdateCooldowns() end if this.delay.UpdateItemLock then this.delay.UpdateItemLock = nil pfUI.bag:UpdateItemLock() end if this.delay.UpdateSearch then this.delay.UpdateSearch = nil pfUI.bag:UpdateSearch() end for bag in pairs(this.delay.UpdateBag) do this.delay.UpdateBag[bag] = nil pfUI.bag:UpdateBag(bag) end end) pfUI.bag:SetScript("OnEvent", function() if event == "PLAYER_ENTERING_WORLD" then pfUI.bag:CreateBags() pfUI.bag.right:Hide() pfUI.bag:CreateBags("bank") pfUI.bag.left:Hide() pfUI.bag:CreateBagSlots(pfUI.bag.right) pfUI.bag:CreateBagSlots(pfUI.bag.left) pfUI.bag:RefreshSpells() end if event == "SPELLS_CHANGED" then this.delay.RefreshSpells = true end if event == "BAG_CLOSED" or event == "PLAYERBANKSLOTS_CHANGED" or event == "PLAYERBANKBAGSLOTS_CHANGED" or event == "BAG_UPDATE" or event == "BANKFRAME_OPENED" or event == "BANKFRAME_CLOSED" then this.delay.CheckFullUpdate = true end if event == "BAG_UPDATE_COOLDOWN" then this.delay.UpdateCooldowns = true end if event == "ITEM_LOCK_CHANGED" then this.delay.UpdateItemLock = true end if event == "INVENTORY_SEARCH_UPDATE" then this.delay.UpdateSearch = true end if event == "PLAYERBANKSLOTS_CHANGED" then this.delay.UpdateBag[-1] = true end if event == "BAG_UPDATE" then this.delay.UpdateBag[arg1] = true end if event == "PLAYERBANKBAGSLOTS_CHANGED" then pfUI.bag:CreateBagSlots(pfUI.bag.left) end if event == "BANKFRAME_OPENED" then pfUI.bag.left:Show() OpenBackpack() end if event == "BANKFRAME_CLOSED" then pfUI.bag.left:Hide() end if event == "MERCHANT_CLOSED" then if not ContainerFrame1.backpackWasOpen then pfUI.bag.right:Hide() end end end) tinsert(UISpecialFrames,"pfBag") pfUI.BACKPACK = { -2, 0, 1, 2, 3, 4 } pfUI.BANK = { -1, 5, 6, 7, 8, 9, 10, 11 } pfUI.bags = {} pfUI.slots = {} function pfUI.bag:CheckFullUpdate() local maxslots = 0 for bag = -2,11 do local bagsize = GetContainerNumSlots(bag) if bag == -2 and pfUI.bag.showKeyring == true then bagsize = GetKeyRingSize() end maxslots = maxslots + bagsize end if maxslots ~= pfUI.bag.maxslots then for bag = -2,11 do for slot, f in ipairs(pfUI.bags[bag].slots) do local bagsize = GetContainerNumSlots(bag) if bag == -2 and pfUI.bag.showKeyring == true then bagsize = GetKeyRingSize() end if slot > bagsize then pfUI.bags[bag].slots[slot].frame:Hide() end end end pfUI.bag:CreateBags() pfUI.bag:CreateBags("bank") pfUI.bag.maxslots = maxslots end end function pfUI.bag:CreateBags(object) local x = 0 local y = 0 local frame = {} local iterate = {} local anchor, rowlength, cwidth if object == "bank" then if not pfUI.bag.left then pfUI.bag.left = CreateFrame("Frame", "pfBank", UIParent) end anchor = { "BOTTOMLEFT", (pfUI.chat and pfUI.chat.left or nil), "BOTTOMRIGHT", "TOPLEFT", "TOPRIGHT" } rowlength = tonumber(C.appearance.bags.bankrowlength) cwidth = C.chat.left.width iterate = pfUI.BANK frame = pfUI.bag.left else if not pfUI.bag.right then pfUI.bag.right = CreateFrame("Frame", "pfBag", UIParent) end rowlength = tonumber(C.appearance.bags.bagrowlength) anchor = { "BOTTOMRIGHT", (pfUI.chat and pfUI.chat.right or nil), "BOTTOMLEFT", "TOPRIGHT", "TOPLEFT" } cwidth = C.chat.right.width iterate = pfUI.BACKPACK frame = pfUI.bag.right end if not frame.init then pfUI.bag:CreateAdditions(frame) frame:SetFrameStrata("HIGH") CreateBackdrop(frame, default_border) CreateBackdropShadow(frame) frame.init = true end if pfUI.chat and C.appearance.bags.icon_size == "-1" then -- align bags to chat if no custom size is set frame:SetWidth(cwidth * anchor[2]:GetScale()) elseif C.appearance.bags.icon_size ~= "-1" then -- use custom size if set frame:SetWidth((C.appearance.bags.icon_size + default_border*3) * rowlength - default_border) else -- fallback to 22px without any anchor or custom setting frame:SetWidth((22 + default_border*3) * rowlength - default_border) end if pfUI.chat and C.appearance.bags.icon_size ~= "-1" then -- ignore custom icon size frame:SetPoint(anchor[1], anchor[2], anchor[1], 0, 0) elseif pfUI.chat then -- use chat frame as anchor if existing if C.appearance.bags.abovechat == "0" then frame:SetPoint(anchor[1], anchor[2], anchor[1], 0, 0) frame:SetPoint(anchor[3], anchor[2], anchor[3], 0, 0) else frame:SetPoint(anchor[3], anchor[2], anchor[5], 0, 3*default_border) frame:SetPoint(anchor[1], anchor[2], anchor[4], 0, 3*default_border) end else -- align frame to UIParent if no anchor is available frame:SetPoint(anchor[1], UIParent, anchor[1], 5, 5) end if C.appearance.bags.movable == "1" then -- enable movable bag frames LoadMovable(frame) frame:EnableMouse(1) frame:SetMovable(1) frame:RegisterForDrag("LeftButton") frame:SetScript("OnDragStart", function() this:StartMoving() end) frame:SetScript("OnDragStop", function() this:StopMovingOrSizing() SaveMovable(this) end) end frame:EnableMouse(1) if C.appearance.bags.movable == "1" and C.appearance.bags.icon_size ~= "-1" then frame.button_size = C.appearance.bags.icon_size else frame.button_size = (frame:GetWidth() - 2*default_border - (rowlength-1)*default_border*3)/ rowlength end local topspace = pfUI.bag.right.close:GetHeight() + default_border * 2 local bottomspace = pfUI.panel and pfUI.panel.right:IsShown() and pfUI.panel.right:GetHeight() + default_border or 16 + default_border for id, bag in pairs(iterate) do if not pfUI.bags[bag] then pfUI.bags[bag] = CreateFrame("Frame", "pfBag" .. bag, frame) pfUI.bags[bag]:SetAllPoints(frame) pfUI.bags[bag].slots = {} end pfUI.bags[bag]:SetID(bag) local bagsize = GetContainerNumSlots(bag) if bag == -2 and pfUI.bag.showKeyring == true then bagsize = GetKeyRingSize() end for slot=1, bagsize do pfUI.bag:UpdateSlot(bag, slot) pfUI.bags[bag].slots[slot].frame:ClearAllPoints() pfUI.bags[bag].slots[slot].frame:SetPoint("TOPLEFT", default_border + x*(frame.button_size+default_border*3), -default_border*2 - y*(frame.button_size+default_border*3) - topspace) pfUI.bags[bag].slots[slot].frame:SetSize(frame.button_size, frame.button_size) if x >= rowlength - 1 then y = y + 1 x = 0 else x = x + 1 end end end if x > 0 then y = y + 1 end frame:SetHeight( default_border*2 + y*(frame.button_size+default_border*3) + topspace + bottomspace) local chat = pfUI.chat and ( object == "bank" and pfUI.chat.left or pfUI.chat.right) or nil frame:SetScript("OnShow", function() frame.opened = true if C.appearance.bags.hidechat == "1" and chat and chat:IsVisible() then frame.chatWasOpen = true chat:Hide() end if C.appearance.bags.autoSortOnOpen == "1" then libbagsort:Sort({0, 1, 2, 3, 4}, BagSortOpts()) end pfUI.bag:CreateBags(object) PlaySound("INTERFACESOUND_BACKPACKOPEN") end) frame:SetScript("OnHide", function() if C.appearance.bags.hidechat == "1" and chat and frame.chatWasOpen then chat:Show() frame.chatWasOpen = false end pfUI.bag:CreateBags(object) PlaySound("INTERFACESOUND_BACKPACKCLOSE") if frame.opened then frame.opened = nil pfUI.events:TriggerEvent("bag:closed", object) end end) end function pfUI.bag:UpdateBag(bag) local bagsize = GetContainerNumSlots(bag) if bag == -2 and pfUI.bag.showKeyring == true then bagsize = GetKeyRingSize() end for slot=1, bagsize do pfUI.bag:UpdateSlot(bag, slot) end end -- dim the slots that the bag search (C_Container.SetItemSearch) filters out local searchInfo = {} function pfUI.bag:UpdateSlotSearch(bag, slot) local info = C_Container.GetContainerItemInfo(bag, slot, searchInfo) pfUI.bags[bag].slots[slot].frame:SetAlpha(info and info.isFiltered and .25 or 1) end function pfUI.bag:UpdateSearch() for bag = -2, 11 do for slot in ipairs(pfUI.bags[bag].slots) do pfUI.bag:UpdateSlotSearch(bag, slot) end end end function pfUI.bag:UpdateSlot(bag, slot) if not pfUI.bags[bag] then return end if not pfUI.bags[bag].slots[slot] then local tpl = "ContainerFrameItemButtonTemplate" if bag == -1 then tpl = "BankItemButtonGenericTemplate" end pfUI.bags[bag].slots[slot] = {} pfUI.bags[bag].slots[slot].frame = CreateFrame("Button", "pfBag" .. bag .. "item" .. slot, pfUI.bags[bag], tpl) pfUI.bags[bag].slots[slot].frame.qtext = pfUI.bags[bag].slots[slot].frame:CreateFontString(nil, "OVERLAY", "GameFontNormal") pfUI.bags[bag].slots[slot].frame:SetNormalTexture("") pfUI.bags[bag].slots[slot].bag = bag pfUI.bags[bag].slots[slot].slot = slot pfUI.bags[bag].slots[slot].frame:SetID(slot) -- native cooldown frame: the bank template has none and the bag -- template's is 1.12's indicator Model, which can't reverse. -- ContainerFrame_UpdateCooldown reads the "