Files
Bagshui/Components/Bags.lua
T
OEVG 896f46f0d1
enUS Localization Update Announcement / localization-update-announcement (push) Canceled after 0s
Bagshui 1.6.4
2026-10-30 15:55:43 +00:00

162 lines
6.5 KiB
Lua

-- Bagshui Bags Inventory Class Instance
-- Exposes: Bagshui.components.Bags [via Inventory:New()]
Bagshui:AddComponent(function()
-- Create class instance.
local Bags = Bagshui.prototypes.Inventory:New(BS_INVENTORY_TYPE.BAGS)
-- Hook handling.
-- The original WoW API function needs to be called for Close* and Toggle* if the
-- original container frame is open. If this isn't done, clicking the close button
-- on the original frame will only affect Bagshui and leave the original frame
-- stuck on the screen forever.
--- Open bag hooks (OpenAllBags, OpenBackpack, OpenBag(bagNum)).
---@param hookFunctionName string Name of the original WoW API function.
---@param bagNumParam number Container ID.
function Bags:OpenBag(hookFunctionName, bagNumParam)
self:OpenCloseToggle(BS_INVENTORY_UI_VISIBILITY_ACTION.OPEN, hookFunctionName, bagNumParam)
end
--- Close bag hooks (CloseBackpack, CloseBag(bagNum)).
---@param hookFunctionName string Name of the original WoW API function.
---@param bagNumParam number Container ID.
function Bags:CloseBag(hookFunctionName, bagNumParam)
self:OpenCloseToggle(
BS_INVENTORY_UI_VISIBILITY_ACTION.CLOSE,
hookFunctionName,
bagNumParam,
self:OriginalContainerFrameVisible(bagNumParam)
)
end
--- Toggle bag hooks (ToggleBackpack, ToggleBag(bagNum)).
---@param hookFunctionName string Name of the original WoW API function.
---@param bagNumParam number Container ID.
function Bags:ToggleBag(hookFunctionName, bagNumParam)
self:OpenCloseToggle(
BS_INVENTORY_UI_VISIBILITY_ACTION.TOGGLE,
hookFunctionName,
bagNumParam,
self:OriginalContainerFrameVisible(bagNumParam)
)
end
--- Register additional events and properties to make bag slot buttons "just work" with Blizzard code.
---@param bagSlotButton table Bag slot button instance.
function Bags:BagSlotButton_Init(bagSlotButton)
bagSlotButton:RegisterEvent("BAG_UPDATE")
bagSlotButton.isBag = 1 -- We're not relying too much on PaperDollItemSlotButton, but let's set this just to be safe.
local oldOnClick = bagSlotButton:GetScript("OnClick")
--- If there was an item in the cursor when the slot was clicked, catch it and prevent the original
--- from being called, since since PaperDollItemSlotButton will interpret that as trying to *equip*
--- the item in that slot, instead of trying to put it in the bag. Note that due to the behavior of
--- `PutItemInBag()`, this will *not* intercept bags, but that's handled in the bag slot button's OnClick.
bagSlotButton:SetScript("OnClick", function()
if
-- Pass through to the default Bagshui OnClick for bags
-- so native bag swapping can be invoked.
(_G.CursorHasItem() and BsItemInfo:IsContainer(Bagshui.cursorItem))
-- Otherwise, allow PutItemInBag() to catch cursor items and move them.
or not _G.PutItemInBag(_G.this.bagshuiData.inventorySlotId)
then
oldOnClick()
end
end)
end
--- Override Inventory:UpdateBagBar() and Inventory:UiFrame_OnHide() so we can correctly set the
--- highlight state of the Blizzard action bar bag slot buttons when our window opens/closes/updates.
function Bags:UpdateBagBar()
self._super.UpdateBagBar(self)
-- Don't update action bar bag slot buttons until the next update tick.
-- This avoids having the Blizzard UI code immediately turn off the checked state.
Bagshui:QueueClassCallback(self, self.UpdateActionBarBagSlotButtonState)
end
--- Ensure the Blizzard action bar bag buttons are un-highlighted when the Bags window is closed.
function Bags:UiFrame_OnHide()
self._super.UiFrame_OnHide(self)
-- It's safe to instantly un-highlight the action bar bag buttons when the window is closed.
self:UpdateActionBarBagSlotButtonState()
end
Bags._actionBarButtonWasChecked = {}
--- Set Blizzard action bar bag slot buttons to "checked" (highlighted) when our
--- window is open and unchecked when it's closed.
function Bags:UpdateActionBarBagSlotButtonState()
local shouldBeChecked = self:Visible()
local actionBarButtonName, actionBarButton
for _, bagNum in pairs(self.containerIds) do
local hookEnabled = self:GetHookEnabled("Bag", bagNum)
-- Only highlight bags in the action bar that we're hooking.
if
(hookEnabled or self._actionBarButtonWasChecked[bagNum])
and type(self.currentCharacterInventory[bagNum]) == "table"
then
if bagNum == 0 then
actionBarButtonName = "MainMenuBarBackpackButton"
else
actionBarButtonName = string.format("CharacterBag%dSlot", bagNum + self.bagSlotNameNumberOffset)
end
actionBarButton = _G[actionBarButtonName]
-- Avoid messing with the highlight state when the original container frame is open.
if actionBarButton and not self:OriginalContainerFrameVisible(bagNum) then
actionBarButton:SetChecked(
shouldBeChecked
and hookEnabled
-- Only highlight buttons where there are bags.
and (table.getn(self.currentCharacterInventory[bagNum]) > 0)
)
self._actionBarButtonWasChecked[bagNum] = hookEnabled
end
end
end
end
--- Helper to determine when when one of the Blizzard bag frames is open.
---@param bagNum any
---@return boolean frameVisible
function Bags:OriginalContainerFrameVisible(bagNum)
if not bagNum then
return false
end
return self.ui:IsFrameVisible("ContainerFrame" .. tostring(bagNum))
end
--- Execute `self:Open()/Close()` and the superclass version only if there isn't a reason to block it.
---@param action "Open"|"Close"
---@return boolean? # false if event was blocked.
function Bags:SmartOpenClose(action)
-- Block based on settings.
if
type(_G.event) == "string"
and (
(string.find(_G.event, "^AUCTION_HOUSE_") and self.settings.toggleBagsWithAuctionHouse == false)
or (string.find(_G.event, "^BANKFRAME_") and self.settings.toggleBagsWithBankFrame == false)
or (string.find(_G.event, "^MAIL_") and self.settings.toggleBagsWithMailFrame == false)
or (string.find(_G.event, "^TRADE_") and self.settings.toggleBagsWithTradeFrame == false)
)
then
return
end
-- Proceed with action.
self._super[action](self)
end
--- Add intelligence to Open().
function Bags:Open()
self:SmartOpenClose("Open")
end
--- Add intelligence to Close().
function Bags:Close()
self:SmartOpenClose("Close")
self.lastOpenEventTrigger = nil
end
end)