1627 lines
62 KiB
Lua
1627 lines
62 KiB
Lua
--------------------------------------------------------------------------------
|
|
-- S-Frames: Bag Container UI (Bags/Container.lua)
|
|
--------------------------------------------------------------------------------
|
|
|
|
SFrames.Bags.Container = {}
|
|
|
|
local SLOT_SIZE = 36
|
|
local SPACING = 6
|
|
local MARGIN = 10
|
|
local TOP_OFFSET = 52 -- Space for title + search bar + gold
|
|
local TEXT_EMPTY = "\231\169\186"
|
|
local TEXT_ITEM = "\231\137\169\229\147\129"
|
|
local TEXT_BACKPACK = "\232\131\140\229\140\133"
|
|
local TEXT_BAGS_TITLE = "\232\131\140\229\140\133"
|
|
local TEXT_BANK_TITLE = "\233\147\182\232\161\140"
|
|
local TEXT_SORT = "\230\149\180\231\144\134"
|
|
local TEXT_SETTINGS = "\232\174\190\231\189\174"
|
|
local TEXT_BAG_SLOT = "\232\131\140\229\140\133\230\167\189"
|
|
local TEXT_BAG_EMPTY = "\231\169\186"
|
|
local TEXT_BAG_SLOTS = "\230\160\188"
|
|
local TEXT_EQUIPPED_BAG = "\229\183\178\232\163\133\229\164\135\232\131\140\229\140\133"
|
|
local TEXT_HS_USE = "\231\130\185\229\135\187\228\189\191\231\148\168\231\130\137\231\159\179"
|
|
local TEXT_HS_NOT_FOUND = "\232\131\140\229\140\133\228\184\173\230\156\170\230\137\190\229\136\176\231\130\137\231\159\179\227\128\130"
|
|
local TEXT_CHARACTER = "\232\167\146\232\137\178"
|
|
local TEXT_ONLINE = "\229\156\168\231\186\191"
|
|
local TEXT_OFFLINE = "\231\166\187\231\186\191"
|
|
local PANEL_BG_ALPHA = 0.55
|
|
local SLOT_BG_ALPHA = 0.22
|
|
local CHARACTER_SELECTOR_ICON = "Interface\\CHARACTERFRAME\\TemporaryPortrait-Female-Human"
|
|
|
|
local _A = SFrames.ActiveTheme
|
|
|
|
local BagFrame = nil
|
|
local ItemSlots = {}
|
|
local playerBagInvSlots = { [1] = 20, [2] = 21, [3] = 22, [4] = 23 }
|
|
|
|
local function IsLiveBankOpen()
|
|
local bankFrame = _G["SFramesBankFrame"]
|
|
if not bankFrame or not bankFrame:IsVisible() then return false end
|
|
if not SFrames.Bags.Bank then return false end
|
|
return not SFrames.Bags.Bank.isOffline
|
|
end
|
|
|
|
local function SetTooltipFromContainerItem(bagID, slotID)
|
|
if not GameTooltip then return false end
|
|
GameTooltip:ClearLines()
|
|
|
|
if GameTooltip.SetBagItem then
|
|
local ok = pcall(function() GameTooltip:SetBagItem(bagID, slotID) end)
|
|
if ok then
|
|
local left1 = _G["GameTooltipTextLeft1"]
|
|
if left1 and left1:GetText() and left1:GetText() ~= "" then
|
|
return true
|
|
end
|
|
end
|
|
end
|
|
|
|
local link = GetContainerItemLink(bagID, slotID)
|
|
if link then
|
|
local ok = pcall(function() GameTooltip:SetHyperlink(link) end)
|
|
if ok then
|
|
local left1 = _G["GameTooltipTextLeft1"]
|
|
if left1 and left1:GetText() and left1:GetText() ~= "" then
|
|
return true
|
|
end
|
|
end
|
|
|
|
local name = GetItemInfo(link)
|
|
if name and name ~= "" then
|
|
GameTooltip:SetText(name, 1, 1, 1)
|
|
return true
|
|
end
|
|
end
|
|
|
|
return false
|
|
end
|
|
|
|
local function HasTooltipText()
|
|
local left1 = _G["GameTooltipTextLeft1"]
|
|
return left1 and left1:GetText() and left1:GetText() ~= ""
|
|
end
|
|
|
|
local function GetItemNameFromLink(link)
|
|
if type(link) ~= "string" or link == "" then
|
|
return nil
|
|
end
|
|
|
|
local name = GetItemInfo(link)
|
|
if name and name ~= "" then
|
|
return name
|
|
end
|
|
|
|
local _, _, parsed = string.find(link, "%[(.+)%]")
|
|
if parsed and parsed ~= "" then
|
|
return parsed
|
|
end
|
|
|
|
return nil
|
|
end
|
|
|
|
local function ShowMerchantCursorForSlot(button)
|
|
if not button then return end
|
|
if button.bagID == nil or button.slotID == nil then return end
|
|
if SFrames.Bags.Container and SFrames.Bags.Container.isOffline then return end
|
|
if not ((MerchantFrame and MerchantFrame:IsVisible()) or (SFramesMerchantFrame and SFramesMerchantFrame:IsVisible())) then return end
|
|
|
|
local texture, _, locked = GetContainerItemInfo(button.bagID, button.slotID)
|
|
if not texture or locked then return end
|
|
|
|
-- Prefer container-aware API when available.
|
|
if ShowContainerSellCursor then
|
|
local ok = pcall(function()
|
|
ShowContainerSellCursor(button.bagID, button.slotID)
|
|
end)
|
|
if ok then return end
|
|
end
|
|
|
|
-- Fallback to generic merchant sell cursor.
|
|
if ShowMerchantSellCursor then
|
|
local ok = pcall(function()
|
|
ShowMerchantSellCursor()
|
|
end)
|
|
if ok then return end
|
|
end
|
|
|
|
-- Final fallback for clients lacking both APIs.
|
|
if SetCursor then
|
|
pcall(function()
|
|
SetCursor("BUY_CURSOR")
|
|
end)
|
|
end
|
|
end
|
|
|
|
local function ResolvePlayerBagInvSlots()
|
|
local fallback = { [1] = 20, [2] = 21, [3] = 22, [4] = 23 }
|
|
for bagIndex = 1, 4 do
|
|
local invSlot = nil
|
|
local liveBtn = _G["CharacterBag" .. (bagIndex - 1) .. "Slot"]
|
|
|
|
-- Most reliable when Blizzard character UI is loaded.
|
|
if liveBtn and liveBtn.GetID then
|
|
local id = liveBtn:GetID()
|
|
if type(id) == "number" and id > 0 then
|
|
invSlot = id
|
|
end
|
|
end
|
|
|
|
if (not invSlot) and ContainerIDToInventoryID then
|
|
local ok, slotID = pcall(function() return ContainerIDToInventoryID(bagIndex) end)
|
|
if ok and type(slotID) == "number" and slotID > 0 then
|
|
invSlot = slotID
|
|
end
|
|
end
|
|
|
|
if (not invSlot) and GetInventorySlotInfo then
|
|
local slotNames = {
|
|
"Bag" .. (bagIndex - 1) .. "Slot",
|
|
"Bag" .. bagIndex .. "Slot",
|
|
"CharacterBag" .. (bagIndex - 1) .. "Slot",
|
|
}
|
|
for _, slotName in ipairs(slotNames) do
|
|
local ok, slotID = pcall(function() return GetInventorySlotInfo(slotName) end)
|
|
if ok and type(slotID) == "number" and slotID > 0 then
|
|
invSlot = slotID
|
|
break
|
|
end
|
|
end
|
|
end
|
|
|
|
playerBagInvSlots[bagIndex] = invSlot or fallback[bagIndex]
|
|
end
|
|
end
|
|
|
|
local function GetLivePlayerBagIconTexture(bagIndex)
|
|
local btn = _G["CharacterBag" .. (bagIndex - 1) .. "Slot"]
|
|
if not btn then return nil end
|
|
|
|
local icon = _G[btn:GetName() .. "IconTexture"] or _G[btn:GetName() .. "Icon"]
|
|
if icon and icon.GetTexture then
|
|
local tex = icon:GetTexture()
|
|
if tex and tex ~= "" then
|
|
return tex
|
|
end
|
|
end
|
|
|
|
return nil
|
|
end
|
|
|
|
local function IsDisabledIconTexture(tex)
|
|
if type(tex) ~= "string" then return false end
|
|
local lower = string.lower(tex)
|
|
lower = string.gsub(lower, "\\", "/")
|
|
return string.find(lower, "disabled", 1, true) ~= nil
|
|
end
|
|
|
|
local function IsPaperdollBagPlaceholder(tex)
|
|
if type(tex) ~= "string" then return false end
|
|
local lower = string.lower(tex)
|
|
lower = string.gsub(lower, "\\", "/")
|
|
|
|
if string.find(lower, "ui-paperdoll-slot-bag", 1, true) then
|
|
return true
|
|
end
|
|
|
|
-- Some clients may return slightly different placeholder paths.
|
|
if string.find(lower, "paperdoll", 1, true) and
|
|
string.find(lower, "slot", 1, true) and
|
|
string.find(lower, "bag", 1, true) then
|
|
return true
|
|
end
|
|
|
|
return false
|
|
end
|
|
|
|
local function IsUsableBagIconTexture(tex)
|
|
if type(tex) ~= "string" or tex == "" then
|
|
return false
|
|
end
|
|
if IsPaperdollBagPlaceholder(tex) then
|
|
return false
|
|
end
|
|
if IsDisabledIconTexture(tex) then
|
|
return false
|
|
end
|
|
return true
|
|
end
|
|
|
|
local function GetIconFromItemLink(link)
|
|
if not link then return nil end
|
|
|
|
local _, _, _, _, _, _, _, _, tex = GetItemInfo(link)
|
|
if tex then return tex end
|
|
|
|
local _, _, itemID = string.find(link, "item:(%d+)")
|
|
if itemID then
|
|
local _, _, _, _, _, _, _, _, tex2 = GetItemInfo("item:" .. itemID)
|
|
if tex2 then return tex2 end
|
|
end
|
|
|
|
return nil
|
|
end
|
|
|
|
local function BuildPlayerTradeLinkSet()
|
|
local links = {}
|
|
if not (TradeFrame and TradeFrame:IsVisible()) then return links end
|
|
if not GetTradePlayerItemLink then return links end
|
|
for i = 1, 6 do
|
|
local link = GetTradePlayerItemLink(i)
|
|
if link and link ~= "" then
|
|
links[link] = true
|
|
end
|
|
end
|
|
return links
|
|
end
|
|
|
|
local function CreateCoinDisplay(parent, frameName)
|
|
local frame = CreateFrame("Frame", frameName, parent, "SmallMoneyFrameTemplate")
|
|
frame:SetFrameStrata(parent:GetFrameStrata())
|
|
frame:SetFrameLevel(parent:GetFrameLevel() + 30)
|
|
frame:SetWidth(140)
|
|
frame:SetHeight(16)
|
|
return frame
|
|
end
|
|
|
|
local function SetCoinDisplayMoney(display, copper)
|
|
if not display then return end
|
|
local value = tonumber(copper) or 0
|
|
if value < 0 then value = 0 end
|
|
|
|
if SmallMoneyFrame_SetAmount then
|
|
local ok = pcall(function() SmallMoneyFrame_SetAmount(display, value) end)
|
|
if ok then return end
|
|
end
|
|
|
|
if MoneyFrame_Update and display.GetName then
|
|
local frameName = display:GetName()
|
|
if frameName and frameName ~= "" then
|
|
pcall(function() MoneyFrame_Update(frameName, value) end)
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Create a single item slot button
|
|
local function CreateSlot(parent, id)
|
|
local button = CreateFrame("Button", "SFramesBagSlot" .. id, parent, "ItemButtonTemplate")
|
|
button:RegisterForClicks("LeftButtonUp", "RightButtonUp")
|
|
button:RegisterForDrag("LeftButton")
|
|
|
|
-- Rounded backdrop style (matching CharacterPanel equipment slots)
|
|
local DEFAULT_BORDER = (_A and _A.slotBorder) or { 0.25, 0.25, 0.3, 0.8 }
|
|
button:SetBackdrop({
|
|
bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
|
|
edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
|
|
tile = true, tileSize = 16, edgeSize = 18,
|
|
insets = { left = 2, right = 2, top = 2, bottom = 2 }
|
|
})
|
|
button:SetBackdropColor(_A.slotBg[1], _A.slotBg[2], _A.slotBg[3], _A.slotBg[4] or 0.9)
|
|
button:SetBackdropBorderColor(DEFAULT_BORDER[1], DEFAULT_BORDER[2], DEFAULT_BORDER[3], DEFAULT_BORDER[4])
|
|
|
|
-- Inset icon within the rounded border
|
|
local icon = _G[button:GetName() .. "IconTexture"]
|
|
if icon then
|
|
icon:SetTexCoord(0.08, 0.92, 0.08, 0.92)
|
|
icon:ClearAllPoints()
|
|
icon:SetPoint("TOPLEFT", button, "TOPLEFT", 4, -4)
|
|
icon:SetPoint("BOTTOMRIGHT", button, "BOTTOMRIGHT", -4, 4)
|
|
end
|
|
|
|
local qualGlow = button:CreateTexture(nil, "OVERLAY")
|
|
qualGlow:SetTexture("Interface\\Buttons\\UI-ActionButton-Border")
|
|
qualGlow:SetBlendMode("ADD")
|
|
qualGlow:SetAlpha(0.8)
|
|
qualGlow:SetWidth(SLOT_SIZE * 1.9)
|
|
qualGlow:SetHeight(SLOT_SIZE * 1.9)
|
|
qualGlow:SetPoint("CENTER", button, "CENTER", 0, 0)
|
|
qualGlow:Hide()
|
|
button.qualGlow = qualGlow
|
|
|
|
function button:SetBorderColor(r, g, b, a)
|
|
self.qualGlow:SetVertexColor(r, g, b)
|
|
self.qualGlow:Show()
|
|
self._qualityBorder = true
|
|
end
|
|
function button:ShowBorder()
|
|
self._qualityBorder = true
|
|
end
|
|
function button:HideBorder()
|
|
self.qualGlow:Hide()
|
|
self._qualityBorder = false
|
|
end
|
|
|
|
-- Hide the ugly default rounded Blizzard border
|
|
local nt = _G[button:GetName() .. "NormalTexture"]
|
|
if nt then nt:SetTexture(nil) nt:Hide() end
|
|
|
|
-- Grey item marker (a small coin/junk icon in the corner)
|
|
local junkIcon = button:CreateTexture(nil, "OVERLAY")
|
|
junkIcon:SetTexture("Interface\\Buttons\\UI-GroupLoot-Coin-Up")
|
|
junkIcon:SetWidth(14)
|
|
junkIcon:SetHeight(14)
|
|
-- Place it on top of everything
|
|
junkIcon:SetPoint("TOPLEFT", button, "TOPLEFT", 1, -1)
|
|
junkIcon:Hide()
|
|
button.junkIcon = junkIcon
|
|
|
|
local previewGlow = button:CreateTexture(nil, "OVERLAY")
|
|
previewGlow:SetTexture("Interface\\Buttons\\ButtonHilight-Square")
|
|
previewGlow:SetBlendMode("ADD")
|
|
previewGlow:SetAllPoints(button)
|
|
previewGlow:Hide()
|
|
button.previewGlow = previewGlow
|
|
|
|
local tradeText = button:CreateFontString(nil, "OVERLAY")
|
|
tradeText:SetFont("Fonts\\Zekton.ttf", 10, "OUTLINE")
|
|
if setglobal then -- check Vanilla or use default font
|
|
tradeText:SetFontObject(GameFontNormal)
|
|
end
|
|
tradeText:SetPoint("CENTER", button, "CENTER", 0, 0)
|
|
tradeText:SetText("交易")
|
|
tradeText:SetTextColor(0, 1, 0, 1)
|
|
tradeText:Hide()
|
|
button.tradeText = tradeText
|
|
|
|
button:SetScript("OnEnter", function()
|
|
if this.bagID == nil or this.slotID == nil then return end
|
|
SFrames.Bags._hoveredSlot = this
|
|
GameTooltip:SetOwner(this, "ANCHOR_RIGHT")
|
|
GameTooltip:ClearLines()
|
|
|
|
if SFrames.Bags.Container.isOffline and SFrames.Bags.Container.offlineChar then
|
|
local data = SFrames.Bags.Offline:GetCharacterData(SFrames.Bags.Container.offlineChar)
|
|
if data and data.bags[this.bagID] and data.bags[this.bagID].items[this.slotID] then
|
|
local link = data.bags[this.bagID].items[this.slotID].link
|
|
local shown = false
|
|
if link then
|
|
local _, _, itemStr = string.find(link, "(item:[%-?%d:]+)")
|
|
local ok = false
|
|
if itemStr then
|
|
ok = pcall(function() GameTooltip:SetHyperlink(itemStr) end)
|
|
else
|
|
ok = pcall(function() GameTooltip:SetHyperlink(link) end)
|
|
end
|
|
shown = ok and HasTooltipText()
|
|
|
|
if not shown then
|
|
local name = GetItemNameFromLink(link)
|
|
if name and name ~= "" then
|
|
GameTooltip:SetText(name, 1, 1, 1)
|
|
shown = true
|
|
end
|
|
end
|
|
|
|
if not shown then
|
|
GameTooltip:SetText(TEXT_ITEM, 1, 1, 1)
|
|
end
|
|
else
|
|
GameTooltip:SetText(TEXT_EMPTY, 0.65, 0.65, 0.65)
|
|
end
|
|
else
|
|
GameTooltip:SetText(TEXT_EMPTY, 0.65, 0.65, 0.65)
|
|
end
|
|
else
|
|
local shown = SetTooltipFromContainerItem(this.bagID, this.slotID)
|
|
if not shown then
|
|
GameTooltip:SetText(TEXT_EMPTY, 0.65, 0.65, 0.65)
|
|
end
|
|
end
|
|
if IsControlKeyDown() then
|
|
ShowInspectCursor()
|
|
else
|
|
ShowMerchantCursorForSlot(this)
|
|
end
|
|
GameTooltip:Show()
|
|
end)
|
|
|
|
button:SetScript("OnLeave", function()
|
|
SFrames.Bags._hoveredSlot = nil
|
|
this.controlDownLast = nil
|
|
GameTooltip:Hide()
|
|
if HideContainerSellCursor and this.bagID and this.slotID then
|
|
pcall(function()
|
|
HideContainerSellCursor(this.bagID, this.slotID)
|
|
end)
|
|
end
|
|
ResetCursor()
|
|
end)
|
|
|
|
local cooldown = CreateFrame("Model", button:GetName().."Cooldown", button, "CooldownFrameTemplate")
|
|
cooldown:SetAllPoints(button)
|
|
|
|
function button:SplitStack(split)
|
|
if not split or split < 1 then return end
|
|
if self.bagID == nil or self.slotID == nil then return end
|
|
SplitContainerItem(self.bagID, self.slotID, split)
|
|
end
|
|
|
|
button:SetScript("OnClick", function()
|
|
local bagID = this.bagID
|
|
local slotID = this.slotID
|
|
local isOffline = SFrames.Bags.Container.isOffline
|
|
|
|
-- Helper: get item link for this slot (works both online and offline)
|
|
local function GetSlotLink()
|
|
if isOffline and SFrames.Bags.Container.offlineChar then
|
|
local data = SFrames.Bags.Offline:GetCharacterData(SFrames.Bags.Container.offlineChar)
|
|
if data and data.bags[bagID] and data.bags[bagID].items[slotID] then
|
|
return data.bags[bagID].items[slotID].link
|
|
end
|
|
return nil
|
|
end
|
|
return GetContainerItemLink(bagID, slotID)
|
|
end
|
|
|
|
if IsControlKeyDown() and arg1 == "LeftButton" then
|
|
local link = GetSlotLink()
|
|
if link and DressUpItemLink then
|
|
DressUpItemLink(link)
|
|
return
|
|
end
|
|
end
|
|
if IsShiftKeyDown() then
|
|
local eb = ChatFrameEditBox
|
|
if eb and eb.IsVisible and eb:IsVisible() then
|
|
local link = GetSlotLink()
|
|
if link then eb:Insert(link) end
|
|
return
|
|
end
|
|
if not isOffline and arg1 == "LeftButton" and (not CursorHasItem()) and OpenStackSplitFrame then
|
|
local _, itemCount = GetContainerItemInfo(bagID, slotID)
|
|
if itemCount and itemCount > 1 then
|
|
OpenStackSplitFrame(itemCount, this, "BOTTOMLEFT", "TOPLEFT")
|
|
return
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Block all other actions in offline mode
|
|
if isOffline then return end
|
|
|
|
if arg1 == "RightButton" then
|
|
if SFrames.Mail and SFrames.Mail.TryAddItemFromBag then
|
|
if SFrames.Mail.TryAddItemFromBag(bagID, slotID) then return end
|
|
end
|
|
if this.bagID >= 0 and IsLiveBankOpen() and AutoStoreBagItem then
|
|
local ok = pcall(function() AutoStoreBagItem(this.bagID, this.slotID) end)
|
|
if ok then return end
|
|
end
|
|
|
|
if TradeFrame and TradeFrame:IsVisible() and not IsShiftKeyDown() then
|
|
local _, _, locked = GetContainerItemInfo(this.bagID, this.slotID)
|
|
if locked then
|
|
local link = GetSlotLink()
|
|
if link and GetTradePlayerItemLink then
|
|
local inTradeSlot = nil
|
|
for i = 1, 6 do
|
|
if GetTradePlayerItemLink(i) == link then
|
|
inTradeSlot = i
|
|
break
|
|
end
|
|
end
|
|
if inTradeSlot then
|
|
ClearCursor()
|
|
ClickTradeButton(inTradeSlot)
|
|
ClearCursor()
|
|
return
|
|
end
|
|
if BagFrame and BagFrame:IsVisible() then
|
|
SFrames.Bags.Container:UpdateLayout()
|
|
end
|
|
end
|
|
else
|
|
PickupContainerItem(this.bagID, this.slotID)
|
|
local tradeSlot = TradeFrame_GetAvailableSlot and TradeFrame_GetAvailableSlot()
|
|
if tradeSlot then ClickTradeButton(tradeSlot) end
|
|
if CursorHasItem() then ClearCursor() end
|
|
return
|
|
end
|
|
end
|
|
|
|
if AuctionFrame and AuctionFrame:IsShown() and not IsShiftKeyDown() then
|
|
if AuctionFrameBrowse and AuctionFrameBrowse:IsShown() then
|
|
local link = GetContainerItemLink(this.bagID, this.slotID)
|
|
if link then
|
|
local _, _, itemName = string.find(link, "%[(.+)%]")
|
|
if itemName and BrowseName then
|
|
BrowseName:SetText(itemName)
|
|
if AuctionFrameBrowse_Search then AuctionFrameBrowse_Search() end
|
|
end
|
|
end
|
|
return
|
|
elseif AuctionFrameAuctions and AuctionFrameAuctions:IsShown() then
|
|
PickupContainerItem(this.bagID, this.slotID)
|
|
if AuctionsItemButton then AuctionsItemButton:Click() end
|
|
if CursorHasItem() then ClearCursor() end
|
|
return
|
|
end
|
|
end
|
|
|
|
UseContainerItem(this.bagID, this.slotID)
|
|
else
|
|
PickupContainerItem(this.bagID, this.slotID)
|
|
end
|
|
end)
|
|
|
|
button:SetScript("OnDragStart", function()
|
|
if SFrames.Bags.Container.isOffline then return end
|
|
if CursorHasItem() then return end
|
|
PickupContainerItem(this.bagID, this.slotID)
|
|
end)
|
|
|
|
button:SetScript("OnReceiveDrag", function()
|
|
if SFrames.Bags.Container.isOffline then return end
|
|
if CursorHasItem() then
|
|
PickupContainerItem(this.bagID, this.slotID)
|
|
end
|
|
end)
|
|
|
|
return button
|
|
end
|
|
|
|
local function SaveBagFramePosition()
|
|
if not (BagFrame and SFramesDB and SFramesDB.Bags) then return end
|
|
local point, _, relPoint, x, y = BagFrame:GetPoint()
|
|
if not point or not relPoint then return end
|
|
SFramesDB.Bags.bagPosition = {
|
|
point = point,
|
|
relPoint = relPoint,
|
|
x = x or 0,
|
|
y = y or 0,
|
|
}
|
|
end
|
|
|
|
local function ApplyBagFramePosition()
|
|
if not BagFrame then return end
|
|
BagFrame:ClearAllPoints()
|
|
|
|
local pos = SFramesDB and SFramesDB.Bags and SFramesDB.Bags.bagPosition
|
|
if pos and pos.point and pos.relPoint and type(pos.x) == "number" and type(pos.y) == "number" then
|
|
BagFrame:SetPoint(pos.point, UIParent, pos.relPoint, pos.x, pos.y)
|
|
else
|
|
BagFrame:SetPoint("RIGHT", UIParent, "RIGHT", -20, 0)
|
|
end
|
|
end
|
|
|
|
function SFrames.Bags.Container:PreviewBagSlots(targetBagID)
|
|
for _, btn in ipairs(ItemSlots) do
|
|
if btn and btn:IsShown() then
|
|
local icon = _G[btn:GetName() .. "IconTexture"]
|
|
local isMatch = (btn.bagID == targetBagID)
|
|
|
|
if icon then
|
|
icon:SetVertexColor(1, 1, 1)
|
|
end
|
|
|
|
if btn.previewGlow then
|
|
if isMatch then
|
|
btn.previewGlow:Show()
|
|
else
|
|
btn.previewGlow:Hide()
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function SFrames.Bags.Container:ClearBagPreview()
|
|
for _, btn in ipairs(ItemSlots) do
|
|
if btn and btn:IsShown() then
|
|
local icon = _G[btn:GetName() .. "IconTexture"]
|
|
if icon then icon:SetVertexColor(1, 1, 1) end
|
|
if btn.previewGlow then btn.previewGlow:Hide() end
|
|
end
|
|
end
|
|
|
|
-- Restore search dimming state after preview.
|
|
local query = ""
|
|
if SFramesBagSearchBox and SFramesBagSearchBox.GetText then
|
|
query = SFramesBagSearchBox:GetText() or ""
|
|
end
|
|
if SFrames.Bags.Features and SFrames.Bags.Features.ApplySearch then
|
|
SFrames.Bags.Features:ApplySearch(query)
|
|
end
|
|
end
|
|
|
|
-- Build/Update the item slot grid
|
|
function SFrames.Bags.Container:UpdateLayout()
|
|
if not BagFrame then return end
|
|
|
|
local cols = (SFramesDB and SFramesDB.Bags and SFramesDB.Bags.columns) or 10
|
|
local spacing = (SFramesDB and SFramesDB.Bags and SFramesDB.Bags.bagSpacing) or SPACING
|
|
spacing = tonumber(spacing) or SPACING
|
|
if spacing < 0 then spacing = 0 end
|
|
local slots = {}
|
|
|
|
local isOffline = self.isOffline
|
|
local charName = self.offlineChar
|
|
local offlineDB = nil
|
|
if isOffline and charName then
|
|
offlineDB = SFrames.Bags.Offline:GetCharacterData(charName)
|
|
if not offlineDB then
|
|
isOffline = false
|
|
self.isOffline = false
|
|
self.offlineChar = nil
|
|
if BagFrame and BagFrame.RefreshCharacterSelectorText then
|
|
BagFrame.RefreshCharacterSelectorText()
|
|
end
|
|
end
|
|
end
|
|
|
|
local tradeLinks = nil
|
|
if not isOffline and TradeFrame and TradeFrame:IsVisible() then
|
|
tradeLinks = BuildPlayerTradeLinkSet()
|
|
end
|
|
|
|
-- Collect all slots (bags 0-4)
|
|
for bag = 0, 4 do
|
|
local size = 0
|
|
if isOffline and offlineDB then
|
|
if offlineDB.bags[bag] then size = offlineDB.bags[bag].size end
|
|
else
|
|
size = GetContainerNumSlots(bag)
|
|
end
|
|
for slot = 1, size do
|
|
table.insert(slots, { bag = bag, slot = slot })
|
|
end
|
|
end
|
|
|
|
local numSlots = table.getn(slots)
|
|
if numSlots == 0 then numSlots = 1 end
|
|
local rows = math.ceil(numSlots / cols)
|
|
|
|
-- Resize frame
|
|
local width = MARGIN * 2 + (cols * SLOT_SIZE) + math.max(0, (cols - 1)) * spacing
|
|
local height = MARGIN * 2 + TOP_OFFSET + (rows * SLOT_SIZE) + math.max(0, (rows - 1)) * spacing + 24
|
|
BagFrame:SetWidth(math.max(width, 160))
|
|
BagFrame:SetHeight(height)
|
|
|
|
-- Position & update slots
|
|
for i, meta in ipairs(slots) do
|
|
local btn = ItemSlots[i]
|
|
if not btn then
|
|
btn = CreateSlot(BagFrame, i)
|
|
ItemSlots[i] = btn
|
|
end
|
|
|
|
btn.bagID = meta.bag
|
|
btn.slotID = meta.slot
|
|
|
|
local row = math.floor((i - 1) / cols)
|
|
local col = math.mod((i - 1), cols)
|
|
btn:ClearAllPoints()
|
|
btn:SetPoint("TOPLEFT", BagFrame, "TOPLEFT",
|
|
MARGIN + col * (SLOT_SIZE + spacing),
|
|
-(MARGIN + TOP_OFFSET + row * (SLOT_SIZE + spacing)))
|
|
|
|
-- Fetch item info
|
|
local texture, count, quality, link, locked
|
|
if isOffline and offlineDB then
|
|
if offlineDB.bags[meta.bag] and offlineDB.bags[meta.bag].items[meta.slot] then
|
|
local item = offlineDB.bags[meta.bag].items[meta.slot]
|
|
texture = item.texture
|
|
count = item.count
|
|
quality = item.quality
|
|
link = item.link
|
|
locked = false
|
|
end
|
|
else
|
|
local t, c, l, q = GetContainerItemInfo(meta.bag, meta.slot)
|
|
texture = t; count = c; locked = l; quality = q
|
|
link = GetContainerItemLink(meta.bag, meta.slot)
|
|
end
|
|
|
|
SetItemButtonTexture(btn, texture)
|
|
SetItemButtonCount(btn, count)
|
|
local iconTex = _G[btn:GetName() .. "IconTexture"]
|
|
|
|
local isDesaturated = locked and (not tradeLinks)
|
|
if btn.tradeText then btn.tradeText:Hide() end
|
|
if tradeLinks and link then
|
|
local isLockedByTrade = locked and (tradeLinks[link] and true or false)
|
|
if isLockedByTrade then
|
|
if btn.tradeText then btn.tradeText:Show() end
|
|
isDesaturated = true
|
|
else
|
|
-- Ignore stale locked flags for items no longer in trade.
|
|
isDesaturated = false
|
|
SFramesBagsTooltipScanner = SFramesBagsTooltipScanner or CreateFrame("GameTooltip", "SFramesBagsTooltipScanner", nil, "GameTooltipTemplate")
|
|
SFramesBagsTooltipScanner:SetOwner(UIParent, "ANCHOR_NONE")
|
|
SFramesBagsTooltipScanner:ClearLines()
|
|
local hasItem = SFramesBagsTooltipScanner:SetBagItem(meta.bag, meta.slot)
|
|
if hasItem then
|
|
for i = 1, 10 do
|
|
local line = _G["SFramesBagsTooltipScannerTextLeft" .. i]
|
|
if line then
|
|
local text = line:GetText()
|
|
if text and (text == ITEM_SOULBOUND or text == ITEM_BIND_QUEST or text == "Quest Item") then
|
|
isDesaturated = true
|
|
break
|
|
end
|
|
else
|
|
break
|
|
end
|
|
end
|
|
end
|
|
end
|
|
elseif not isOffline and TradeFrame and TradeFrame:IsVisible() and link then
|
|
SFramesBagsTooltipScanner = SFramesBagsTooltipScanner or CreateFrame("GameTooltip", "SFramesBagsTooltipScanner", nil, "GameTooltipTemplate")
|
|
SFramesBagsTooltipScanner:SetOwner(UIParent, "ANCHOR_NONE")
|
|
SFramesBagsTooltipScanner:ClearLines()
|
|
local hasItem = SFramesBagsTooltipScanner:SetBagItem(meta.bag, meta.slot)
|
|
if hasItem then
|
|
for i = 1, 10 do
|
|
local line = _G["SFramesBagsTooltipScannerTextLeft" .. i]
|
|
if line then
|
|
local text = line:GetText()
|
|
if text and (text == ITEM_SOULBOUND or text == ITEM_BIND_QUEST or text == "Quest Item") then
|
|
isDesaturated = true
|
|
break
|
|
end
|
|
else
|
|
break
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
if iconTex then
|
|
if isDesaturated then
|
|
iconTex:SetVertexColor(0.5, 0.5, 0.5)
|
|
else
|
|
iconTex:SetVertexColor(1, 1, 1)
|
|
end
|
|
end
|
|
if btn.previewGlow then btn.previewGlow:Hide() end
|
|
|
|
-- Quality border & Grey marker
|
|
btn:HideBorder()
|
|
btn.junkIcon:Hide()
|
|
|
|
if link then
|
|
-- 1st attempt: Safest 1.12 generic approach: Read the color straight out of the hyperlink!
|
|
-- Standard link format: |cffAABBCC|Hitem:...
|
|
local _, _, hex = string.find(link, "|c(%x+)|H")
|
|
local parsedColor = false
|
|
|
|
if hex and string.len(hex) == 8 then
|
|
local hexLower = string.lower(hex)
|
|
if hexLower == "ff9d9d9d" then
|
|
-- Poor / Grey Item
|
|
btn:SetBorderColor(0.5, 0.5, 0.5, 1)
|
|
btn:ShowBorder()
|
|
btn.junkIcon:Show()
|
|
parsedColor = true
|
|
elseif hexLower == "ffffffff" then
|
|
-- Common / White Item (No special border)
|
|
parsedColor = true
|
|
else
|
|
-- Green, Blue, Purple, Orange
|
|
local r = tonumber(string.sub(hex, 3, 4), 16) / 255
|
|
local g = tonumber(string.sub(hex, 5, 6), 16) / 255
|
|
local b = tonumber(string.sub(hex, 7, 8), 16) / 255
|
|
btn:SetBorderColor(r, g, b, 1)
|
|
btn:ShowBorder()
|
|
parsedColor = true
|
|
end
|
|
end
|
|
|
|
-- 2nd attempt fallback: Use the API quality return values if regex fails
|
|
if not parsedColor then
|
|
local q = quality
|
|
if not q then
|
|
local _, _, itemString = string.find(link, "item:(%d+)")
|
|
if itemString then
|
|
local _, _, scanRarity = GetItemInfo("item:" .. itemString)
|
|
q = scanRarity
|
|
end
|
|
end
|
|
|
|
if q then
|
|
if q == 0 then
|
|
btn:SetBorderColor(0.5, 0.5, 0.5, 1)
|
|
btn:ShowBorder()
|
|
btn.junkIcon:Show()
|
|
elseif q > 1 then
|
|
local r, g, b = GetItemQualityColor(q)
|
|
btn:SetBorderColor(r, g, b, 1)
|
|
btn:ShowBorder()
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Cooldowns
|
|
local cooldown = _G[btn:GetName() .. "Cooldown"]
|
|
if cooldown then
|
|
if isOffline then
|
|
cooldown:Hide()
|
|
else
|
|
local start, duration, enable = GetContainerItemCooldown(meta.bag, meta.slot)
|
|
if start and duration and start > 0 and duration > 0 then
|
|
CooldownFrame_SetTimer(cooldown, start, duration, enable)
|
|
cooldown:Show()
|
|
else
|
|
cooldown:Hide()
|
|
end
|
|
end
|
|
end
|
|
|
|
btn:Show()
|
|
end
|
|
|
|
-- Hide excess buttons
|
|
for i = numSlots + 1, table.getn(ItemSlots) do
|
|
if ItemSlots[i] then ItemSlots[i]:Hide() end
|
|
end
|
|
|
|
if BagFrame.UpdateBagSlotIcons then
|
|
BagFrame.UpdateBagSlotIcons()
|
|
end
|
|
|
|
-- Update money display
|
|
if BagFrame.moneyFrame then
|
|
local copper = 0
|
|
if isOffline and offlineDB then
|
|
copper = offlineDB.money or 0
|
|
else
|
|
copper = GetMoney()
|
|
end
|
|
SetCoinDisplayMoney(BagFrame.moneyFrame, copper)
|
|
end
|
|
end
|
|
|
|
-- Main frame initialization (called once after PLAYER_LOGIN)
|
|
function SFrames.Bags.Container:Initialize()
|
|
if BagFrame then return end
|
|
|
|
BagFrame = CreateFrame("Frame", "SFramesBagFrame", UIParent)
|
|
BagFrame:SetWidth(420)
|
|
BagFrame:SetHeight(200)
|
|
BagFrame:SetFrameStrata("HIGH")
|
|
BagFrame:SetToplevel(true)
|
|
BagFrame:EnableMouse(true)
|
|
BagFrame:SetMovable(true)
|
|
BagFrame:SetClampedToScreen(true)
|
|
BagFrame:RegisterForDrag("LeftButton")
|
|
BagFrame:SetScript("OnDragStart", function() this:StartMoving() end)
|
|
BagFrame:SetScript("OnDragStop", function()
|
|
this:StopMovingOrSizing()
|
|
SaveBagFramePosition()
|
|
end)
|
|
ApplyBagFramePosition()
|
|
tinsert(UISpecialFrames, "SFramesBagFrame")
|
|
|
|
BagFrame:SetScript("OnUpdate", function()
|
|
local btn = SFrames.Bags._hoveredSlot
|
|
if not btn then return end
|
|
if not GameTooltip:IsOwned(btn) then
|
|
SFrames.Bags._hoveredSlot = nil
|
|
return
|
|
end
|
|
if IsControlKeyDown() then
|
|
if not btn.controlDownLast then
|
|
btn.controlDownLast = true
|
|
ShowInspectCursor()
|
|
end
|
|
else
|
|
if btn.controlDownLast then
|
|
btn.controlDownLast = false
|
|
ResetCursor()
|
|
ShowMerchantCursorForSlot(btn)
|
|
end
|
|
end
|
|
end)
|
|
|
|
-- ESC menu style rounded backdrop
|
|
BagFrame:SetBackdrop({
|
|
bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
|
|
edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
|
|
tile = true, tileSize = 16, edgeSize = 14,
|
|
insets = { left = 3, right = 3, top = 3, bottom = 3 },
|
|
})
|
|
local _A = SFrames.ActiveTheme
|
|
local _bagBgA = (SFramesDB and SFramesDB.Bags and type(SFramesDB.Bags.bgAlpha) == "number") and SFramesDB.Bags.bgAlpha or 0.95
|
|
if _A and _A.panelBg then
|
|
BagFrame:SetBackdropColor(_A.panelBg[1], _A.panelBg[2], _A.panelBg[3], _bagBgA)
|
|
BagFrame:SetBackdropBorderColor(_A.panelBorder[1], _A.panelBorder[2], _A.panelBorder[3], _A.panelBorder[4] or 0.9)
|
|
else
|
|
BagFrame:SetBackdropColor(0.12, 0.06, 0.10, _bagBgA)
|
|
BagFrame:SetBackdropBorderColor(0.55, 0.30, 0.42, 0.9)
|
|
end
|
|
local bagShadow = CreateFrame("Frame", nil, BagFrame)
|
|
bagShadow:SetPoint("TOPLEFT", BagFrame, "TOPLEFT", -5, 5)
|
|
bagShadow:SetPoint("BOTTOMRIGHT", BagFrame, "BOTTOMRIGHT", 5, -5)
|
|
bagShadow:SetFrameLevel(math.max(BagFrame:GetFrameLevel() - 1, 0))
|
|
bagShadow:SetBackdrop({
|
|
bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
|
|
edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
|
|
tile = true, tileSize = 16, edgeSize = 16,
|
|
insets = { left = 4, right = 4, top = 4, bottom = 4 },
|
|
})
|
|
bagShadow:SetBackdropColor(0, 0, 0, 0.55)
|
|
bagShadow:SetBackdropBorderColor(0, 0, 0, 0.4)
|
|
local scale = (SFramesDB and SFramesDB.Bags and type(SFramesDB.Bags.scale) == "number" and SFramesDB.Bags.scale) or 0.85
|
|
BagFrame:SetScale(scale)
|
|
local bagAlpha = (SFramesDB and SFramesDB.Bags and type(SFramesDB.Bags.alpha) == "number" and SFramesDB.Bags.alpha) or 1
|
|
BagFrame:SetAlpha(bagAlpha)
|
|
|
|
local titleIco = SFrames:CreateIcon(BagFrame, "backpack", 14)
|
|
titleIco:SetDrawLayer("OVERLAY")
|
|
titleIco:SetPoint("TOPLEFT", BagFrame, "TOPLEFT", 10, -7)
|
|
titleIco:SetVertexColor(_A.title[1], _A.title[2], _A.title[3])
|
|
|
|
local titleFS = SFrames:CreateFontString(BagFrame, 12, "LEFT")
|
|
titleFS:SetPoint("LEFT", titleIco, "RIGHT", 4, 0)
|
|
titleFS:SetText(TEXT_BAGS_TITLE)
|
|
titleFS:SetTextColor(_A.title[1], _A.title[2], _A.title[3])
|
|
BagFrame.title = titleFS
|
|
|
|
-- Close button
|
|
local closeBtn = CreateFrame("Button", "SFramesBagClose", BagFrame, "UIPanelCloseButton")
|
|
closeBtn:SetPoint("TOPRIGHT", BagFrame, "TOPRIGHT", 0, 0)
|
|
closeBtn:SetScript("OnClick", function() SFrames.Bags.Container:Close() end)
|
|
|
|
-- Money display
|
|
BagFrame.moneyFrame = CreateCoinDisplay(BagFrame, "SFramesBagMoneyFrame")
|
|
BagFrame.moneyFrame:SetPoint("RIGHT", BagFrame, "BOTTOMRIGHT", -8, 17)
|
|
SetCoinDisplayMoney(BagFrame.moneyFrame, 0)
|
|
|
|
-- Bag slot management buttons (5 slots: 0=backpack, 1-4 = equipped bags)
|
|
BagFrame.bagSlotBtns = {}
|
|
local BAG_BTN_SIZE = 22
|
|
ResolvePlayerBagInvSlots()
|
|
local bagInvSlots = playerBagInvSlots
|
|
local bagBar = CreateFrame("Frame", "SFramesBagBar", BagFrame)
|
|
bagBar:SetWidth((BAG_BTN_SIZE * 5) + (3 * 4))
|
|
bagBar:SetHeight(BAG_BTN_SIZE)
|
|
bagBar:SetPoint("BOTTOMLEFT", BagFrame, "BOTTOMLEFT", 8, 6)
|
|
bagBar:SetFrameStrata(BagFrame:GetFrameStrata())
|
|
bagBar:SetFrameLevel(BagFrame:GetFrameLevel() + 40)
|
|
bagBar:EnableMouse(false)
|
|
BagFrame.bagBar = bagBar
|
|
|
|
local function PlaceCursorItemInBagSlot(invSlot)
|
|
if not invSlot or not CursorHasItem() then return false end
|
|
|
|
local ok = false
|
|
if EquipCursorItem then
|
|
ok = pcall(function() EquipCursorItem(invSlot) end)
|
|
if ok and (not CursorHasItem()) then
|
|
return true
|
|
end
|
|
end
|
|
|
|
-- In vanilla this can both place and swap bag items in bag slots.
|
|
ok = pcall(function() PickupBagFromSlot(invSlot) end)
|
|
if ok and (not CursorHasItem()) then
|
|
return true
|
|
end
|
|
|
|
if PutItemInBag then
|
|
ok = pcall(function() PutItemInBag(invSlot) end)
|
|
if ok and (not CursorHasItem()) then
|
|
return true
|
|
end
|
|
end
|
|
|
|
-- Fallback path if PutItemInBag is unavailable.
|
|
if CursorHasItem() then
|
|
local fallbackOk = pcall(function() PickupInventoryItem(invSlot) end)
|
|
ok = fallbackOk or ok
|
|
end
|
|
|
|
return ok and (not CursorHasItem())
|
|
end
|
|
|
|
for bagIndex = 0, 4 do
|
|
local bsBtn = CreateFrame("Button", "SFramesBagMgrBtn"..bagIndex, bagBar)
|
|
bsBtn:SetWidth(BAG_BTN_SIZE)
|
|
bsBtn:SetHeight(BAG_BTN_SIZE)
|
|
bsBtn:EnableMouse(true)
|
|
bsBtn:SetFrameStrata(bagBar:GetFrameStrata())
|
|
bsBtn:SetFrameLevel(bagBar:GetFrameLevel() + 1)
|
|
|
|
-- Anchor: first one at BOTTOMLEFT, rest chained RIGHT
|
|
if bagIndex == 0 then
|
|
bsBtn:SetPoint("TOPLEFT", bagBar, "TOPLEFT", 0, 0)
|
|
else
|
|
bsBtn:SetPoint("LEFT", _G["SFramesBagMgrBtn" .. (bagIndex-1)], "RIGHT", 3, 0)
|
|
end
|
|
bsBtn.bagID = bagIndex
|
|
|
|
-- Rounded backdrop (matching item slot style)
|
|
bsBtn:SetBackdrop({
|
|
bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
|
|
edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
|
|
tile = true, tileSize = 16, edgeSize = 12,
|
|
insets = { left = 2, right = 2, top = 2, bottom = 2 }
|
|
})
|
|
bsBtn:SetBackdropColor(_A.slotBg[1], _A.slotBg[2], _A.slotBg[3], _A.slotBg[4] or 0.9)
|
|
bsBtn:SetBackdropBorderColor(_A.slotBorder[1], _A.slotBorder[2], _A.slotBorder[3], _A.slotBorder[4] or 0.8)
|
|
|
|
-- Icon texture inset within border
|
|
local bsIcon = bsBtn:CreateTexture(nil, "OVERLAY")
|
|
bsIcon:SetPoint("TOPLEFT", bsBtn, "TOPLEFT", 2, -2)
|
|
bsIcon:SetPoint("BOTTOMRIGHT", bsBtn, "BOTTOMRIGHT", -2, 2)
|
|
bsIcon:SetTexCoord(0.08, 0.92, 0.08, 0.92)
|
|
bsIcon:SetBlendMode("BLEND")
|
|
bsIcon:SetVertexColor(1, 1, 1, 1)
|
|
bsBtn.icon = bsIcon
|
|
|
|
local bsHighlight = bsBtn:CreateTexture(nil, "HIGHLIGHT")
|
|
bsHighlight:SetTexture("Interface\\Buttons\\ButtonHilight-Square")
|
|
bsHighlight:SetBlendMode("ADD")
|
|
bsHighlight:SetAllPoints(bsBtn)
|
|
|
|
bsBtn:SetScript("OnEnter", function()
|
|
GameTooltip:SetOwner(this, "ANCHOR_RIGHT")
|
|
GameTooltip:ClearLines()
|
|
if SFrames.Bags.Container.isOffline and SFrames.Bags.Container.offlineChar then
|
|
local data = SFrames.Bags.Offline:GetCharacterData(SFrames.Bags.Container.offlineChar)
|
|
if this.bagID == 0 then
|
|
local slots = data and data.bags and data.bags[0] and data.bags[0].size or 0
|
|
if slots and slots > 0 then
|
|
GameTooltip:SetText(string.format("%s (%d%s)", TEXT_BACKPACK, slots, TEXT_BAG_SLOTS), 1, 1, 1)
|
|
else
|
|
GameTooltip:SetText(TEXT_BACKPACK, 1, 1, 1)
|
|
end
|
|
else
|
|
local shown = false
|
|
local slots = data and data.bags and data.bags[this.bagID] and data.bags[this.bagID].size or 0
|
|
local bagMeta = data and data.equippedBags and data.equippedBags[this.bagID]
|
|
|
|
if bagMeta and bagMeta.link then
|
|
local ok = pcall(function() GameTooltip:SetHyperlink(bagMeta.link) end)
|
|
shown = ok and HasTooltipText()
|
|
|
|
if not shown then
|
|
local name = GetItemNameFromLink(bagMeta.link)
|
|
if name and name ~= "" then
|
|
GameTooltip:SetText(name, 1, 1, 1)
|
|
shown = true
|
|
end
|
|
end
|
|
end
|
|
|
|
if not shown then
|
|
if slots and slots > 0 then
|
|
GameTooltip:SetText(string.format("%s %d (%d%s)", TEXT_BAG_SLOT, this.bagID, slots, TEXT_BAG_SLOTS), 1, 1, 1)
|
|
else
|
|
GameTooltip:SetText(string.format("%s %d (%s)", TEXT_BAG_SLOT, this.bagID, TEXT_BAG_EMPTY), 0.6, 0.6, 0.6)
|
|
end
|
|
end
|
|
end
|
|
GameTooltip:AddLine(TEXT_OFFLINE, 0.75, 0.75, 0.75)
|
|
else
|
|
if this.bagID == 0 then
|
|
GameTooltip:SetText(TEXT_BACKPACK, 1, 1, 1)
|
|
else
|
|
local invSlot = playerBagInvSlots[this.bagID]
|
|
local shown = false
|
|
if invSlot then
|
|
if GameTooltip.SetInventoryItem then
|
|
local ok = pcall(function() GameTooltip:SetInventoryItem("player", invSlot) end)
|
|
if ok then
|
|
local left1 = _G["GameTooltipTextLeft1"]
|
|
if left1 and left1:GetText() and left1:GetText() ~= "" then
|
|
shown = true
|
|
end
|
|
end
|
|
end
|
|
|
|
if not shown then
|
|
local bagLink = GetInventoryItemLink("player", invSlot)
|
|
if bagLink then
|
|
local ok = pcall(function() GameTooltip:SetHyperlink(bagLink) end)
|
|
if ok then
|
|
shown = true
|
|
else
|
|
local name = GetItemInfo(bagLink) or (TEXT_EQUIPPED_BAG.." "..this.bagID)
|
|
GameTooltip:SetText(name, 1, 1, 1)
|
|
shown = true
|
|
end
|
|
end
|
|
end
|
|
|
|
if not shown then
|
|
local slots = GetContainerNumSlots(this.bagID) or 0
|
|
if slots > 0 then
|
|
GameTooltip:SetText(string.format("%s %d (%d%s)", TEXT_BAG_SLOT, this.bagID, slots, TEXT_BAG_SLOTS), 1, 1, 1)
|
|
else
|
|
GameTooltip:SetText(string.format("%s %d (%s)", TEXT_BAG_SLOT, this.bagID, TEXT_BAG_EMPTY), 0.6, 0.6, 0.6)
|
|
end
|
|
end
|
|
else
|
|
GameTooltip:SetText(string.format("%s %d", TEXT_BAG_SLOT, this.bagID), 0.8, 0.8, 0.8)
|
|
end
|
|
end
|
|
end
|
|
if BagFrame:IsVisible() then
|
|
SFrames.Bags.Container:PreviewBagSlots(this.bagID)
|
|
end
|
|
GameTooltip:Show()
|
|
end)
|
|
bsBtn:SetScript("OnLeave", function()
|
|
GameTooltip:Hide()
|
|
if BagFrame:IsVisible() then
|
|
SFrames.Bags.Container:ClearBagPreview()
|
|
end
|
|
end)
|
|
|
|
bsBtn:RegisterForClicks("LeftButtonUp", "RightButtonUp")
|
|
bsBtn:RegisterForDrag("LeftButton")
|
|
|
|
bsBtn:SetScript("OnDragStart", function()
|
|
if this.bagID <= 0 then return end
|
|
local invSlot = playerBagInvSlots[this.bagID]
|
|
if invSlot then
|
|
pcall(function() PickupBagFromSlot(invSlot) end)
|
|
end
|
|
end)
|
|
|
|
bsBtn:SetScript("OnReceiveDrag", function()
|
|
if not CursorHasItem() then return end
|
|
|
|
if this.bagID == 0 then
|
|
if PutItemInBackpack then
|
|
pcall(function() PutItemInBackpack() end)
|
|
end
|
|
else
|
|
local invSlot = playerBagInvSlots[this.bagID]
|
|
PlaceCursorItemInBagSlot(invSlot)
|
|
end
|
|
|
|
if BagFrame.UpdateBagSlotIcons then BagFrame.UpdateBagSlotIcons() end
|
|
if BagFrame:IsVisible() then SFrames.Bags.Container:UpdateLayout() end
|
|
end)
|
|
|
|
bsBtn:SetScript("OnClick", function()
|
|
if CursorHasItem() then
|
|
if this.bagID == 0 then
|
|
if PutItemInBackpack then
|
|
pcall(function() PutItemInBackpack() end)
|
|
end
|
|
else
|
|
local invSlot = playerBagInvSlots[this.bagID]
|
|
PlaceCursorItemInBagSlot(invSlot)
|
|
end
|
|
if BagFrame.UpdateBagSlotIcons then BagFrame.UpdateBagSlotIcons() end
|
|
if BagFrame:IsVisible() then SFrames.Bags.Container:UpdateLayout() end
|
|
return
|
|
end
|
|
|
|
if this.bagID > 0 then
|
|
local invSlot = playerBagInvSlots[this.bagID]
|
|
if invSlot then
|
|
pcall(function() PickupBagFromSlot(invSlot) end)
|
|
end
|
|
elseif arg1 == "RightButton" then
|
|
-- Backpack slot has no equip slot to pick up from.
|
|
else
|
|
SFrames.Bags.Container:Toggle()
|
|
end
|
|
end)
|
|
|
|
BagFrame.bagSlotBtns[bagIndex] = bsBtn
|
|
end
|
|
-- Update bag slot textures whenever bag contents change
|
|
BagFrame.UpdateBagSlotIcons = function()
|
|
local isOffline = SFrames.Bags.Container.isOffline and SFrames.Bags.Container.offlineChar
|
|
local offlineDB = nil
|
|
if isOffline then
|
|
offlineDB = SFrames.Bags.Offline:GetCharacterData(SFrames.Bags.Container.offlineChar)
|
|
end
|
|
|
|
ResolvePlayerBagInvSlots()
|
|
for bagIndex = 0, 4 do
|
|
local btn = BagFrame.bagSlotBtns[bagIndex]
|
|
if btn then
|
|
if bagIndex == 0 then
|
|
btn.icon:SetTexture("Interface\\Buttons\\Button-Backpack-Up")
|
|
elseif isOffline and offlineDB then
|
|
local slots = offlineDB.bags and offlineDB.bags[bagIndex] and offlineDB.bags[bagIndex].size or 0
|
|
local bagMeta = offlineDB.equippedBags and offlineDB.equippedBags[bagIndex]
|
|
local tex = nil
|
|
|
|
if bagMeta and bagMeta.link then
|
|
tex = GetIconFromItemLink(bagMeta.link)
|
|
end
|
|
if (not tex) and bagMeta and IsUsableBagIconTexture(bagMeta.texture) then
|
|
tex = bagMeta.texture
|
|
end
|
|
|
|
if (not tex) and slots and slots > 0 then
|
|
tex = "Interface\\Icons\\INV_Misc_Bag_08"
|
|
end
|
|
if not tex then
|
|
tex = "Interface\\Icons\\INV_Misc_Bag_08"
|
|
end
|
|
btn.icon:SetTexture(tex)
|
|
else
|
|
local invSlot = playerBagInvSlots[bagIndex]
|
|
local tex = nil
|
|
local slots = GetContainerNumSlots(bagIndex) or 0
|
|
|
|
if invSlot then
|
|
local link = GetInventoryItemLink("player", invSlot)
|
|
tex = GetIconFromItemLink(link)
|
|
|
|
if (not tex) and slots > 0 then
|
|
local rawTex = GetInventoryItemTexture("player", invSlot)
|
|
if type(rawTex) ~= "string" then
|
|
tex = rawTex
|
|
elseif IsUsableBagIconTexture(rawTex) then
|
|
tex = rawTex
|
|
end
|
|
end
|
|
end
|
|
|
|
if (not tex) and slots > 0 then
|
|
local liveTex = GetLivePlayerBagIconTexture(bagIndex)
|
|
if IsUsableBagIconTexture(liveTex) then
|
|
tex = liveTex
|
|
end
|
|
end
|
|
|
|
if tex then
|
|
btn.icon:SetTexture(tex)
|
|
else
|
|
btn.icon:SetTexture("Interface\\Icons\\INV_Misc_Bag_08")
|
|
end
|
|
end
|
|
btn:Enable()
|
|
if btn.icon.SetDesaturated then
|
|
pcall(function() btn.icon:SetDesaturated(false) end)
|
|
end
|
|
btn.icon:SetVertexColor(1, 1, 1, 1)
|
|
btn.icon:SetAlpha(1)
|
|
end
|
|
end
|
|
end
|
|
local function QueueBagSlotIconRefreshes()
|
|
if not BagFrame or not BagFrame.UpdateBagSlotIcons then return end
|
|
local elapsed = 0
|
|
local nextRefresh = 1
|
|
local refreshPoints = { 0.08, 0.25, 0.55 }
|
|
local refreshTimer = CreateFrame("Frame")
|
|
refreshTimer:SetScript("OnUpdate", function()
|
|
elapsed = elapsed + arg1
|
|
if nextRefresh <= table.getn(refreshPoints) and elapsed >= refreshPoints[nextRefresh] then
|
|
if BagFrame.UpdateBagSlotIcons then
|
|
BagFrame.UpdateBagSlotIcons()
|
|
end
|
|
if BagFrame:IsVisible() then
|
|
SFrames.Bags.Container:UpdateLayout()
|
|
end
|
|
nextRefresh = nextRefresh + 1
|
|
end
|
|
if nextRefresh > table.getn(refreshPoints) then
|
|
this:SetScript("OnUpdate", nil)
|
|
end
|
|
end)
|
|
end
|
|
BagFrame.UpdateBagSlotIcons()
|
|
QueueBagSlotIconRefreshes()
|
|
|
|
-- Search bar
|
|
local eb = CreateFrame("EditBox", "SFramesBagSearchBox", BagFrame, "InputBoxTemplate")
|
|
eb:SetWidth(120)
|
|
eb:SetHeight(18)
|
|
eb:SetPoint("TOPLEFT", BagFrame, "TOPLEFT", 10, -26)
|
|
eb:SetAutoFocus(false)
|
|
eb:SetScript("OnEnterPressed", function() this:ClearFocus() end)
|
|
eb:SetScript("OnEscapePressed", function() this:ClearFocus(); this:SetText("") end)
|
|
eb:SetScript("OnTextChanged", function()
|
|
SFrames.Bags.Features:ApplySearch(this:GetText())
|
|
end)
|
|
|
|
local function CreateHeaderIconButton(name, parent, iconPath)
|
|
local btn = CreateFrame("Button", name, parent)
|
|
btn:SetWidth(18)
|
|
btn:SetHeight(18)
|
|
btn:SetFrameStrata(parent:GetFrameStrata())
|
|
btn:SetFrameLevel(parent:GetFrameLevel() + 45)
|
|
|
|
btn:SetBackdrop({
|
|
bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
|
|
edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
|
|
tile = true, tileSize = 16, edgeSize = 12,
|
|
insets = { left = 2, right = 2, top = 2, bottom = 2 }
|
|
})
|
|
btn:SetBackdropColor(_A.slotBg[1], _A.slotBg[2], _A.slotBg[3], _A.slotBg[4] or 0.86)
|
|
btn:SetBackdropBorderColor(_A.slotBorder[1], _A.slotBorder[2], _A.slotBorder[3], _A.slotBorder[4] or 0.8)
|
|
|
|
local icon = btn:CreateTexture(nil, "ARTWORK")
|
|
icon:SetTexture(iconPath or "Interface\\Icons\\INV_Misc_QuestionMark")
|
|
icon:SetPoint("TOPLEFT", btn, "TOPLEFT", 2, -2)
|
|
icon:SetPoint("BOTTOMRIGHT", btn, "BOTTOMRIGHT", -2, 2)
|
|
icon:SetTexCoord(0.08, 0.92, 0.08, 0.92)
|
|
btn.icon = icon
|
|
|
|
local hl = btn:CreateTexture(nil, "HIGHLIGHT")
|
|
hl:SetTexture("Interface\\Buttons\\ButtonHilight-Square")
|
|
hl:SetBlendMode("ADD")
|
|
hl:SetAllPoints(btn)
|
|
|
|
return btn
|
|
end
|
|
|
|
-- Character selector: icon button-triggered dropdown.
|
|
local function GetCurrentCharacterName()
|
|
local live = UnitName("player")
|
|
if type(live) == "string" and live ~= "" then
|
|
return live
|
|
end
|
|
local cached = SFrames.Bags.Offline:GetCurrentPlayerName()
|
|
if type(cached) == "string" and cached ~= "" then
|
|
return cached
|
|
end
|
|
return TEXT_CHARACTER
|
|
end
|
|
|
|
local function GetOfflineBankTargetCharacter()
|
|
if SFrames.Bags.Container.isOffline and SFrames.Bags.Container.offlineChar then
|
|
return SFrames.Bags.Container.offlineChar
|
|
end
|
|
return GetCurrentCharacterName()
|
|
end
|
|
|
|
local charBtn = CreateHeaderIconButton("SFramesBagCharBtn", BagFrame, CHARACTER_SELECTOR_ICON)
|
|
charBtn:SetPoint("TOPRIGHT", BagFrame, "TOPRIGHT", -8, -26)
|
|
BagFrame.charSelectBtn = charBtn
|
|
|
|
local cfgBtn = CreateHeaderIconButton("SFramesBagConfigBtn", BagFrame, "Interface\\Icons\\INV_Misc_Gear_01")
|
|
cfgBtn:SetPoint("RIGHT", charBtn, "LEFT", -4, 0)
|
|
SFrames:SetIcon(cfgBtn.icon, "settings")
|
|
cfgBtn:SetScript("OnClick", function()
|
|
if SFrames.ConfigUI and SFrames.ConfigUI.Build then
|
|
SFrames.ConfigUI:Build("bags")
|
|
end
|
|
end)
|
|
cfgBtn:SetScript("OnEnter", function()
|
|
GameTooltip:SetOwner(this, "ANCHOR_RIGHT")
|
|
GameTooltip:SetText(TEXT_SETTINGS, 1, 1, 1)
|
|
GameTooltip:Show()
|
|
end)
|
|
cfgBtn:SetScript("OnLeave", function()
|
|
GameTooltip:Hide()
|
|
end)
|
|
|
|
local bankBtn = CreateHeaderIconButton("SFramesBagOfflineBankBtn", BagFrame, "Interface\\Icons\\INV_Misc_Key_05")
|
|
bankBtn:SetPoint("RIGHT", cfgBtn, "LEFT", -4, 0)
|
|
SFrames:SetIcon(bankBtn.icon, "gold")
|
|
bankBtn:SetScript("OnEnter", function()
|
|
GameTooltip:SetOwner(this, "ANCHOR_RIGHT")
|
|
GameTooltip:SetText(TEXT_OFFLINE .. TEXT_BANK_TITLE, 1, 1, 1)
|
|
local target = GetOfflineBankTargetCharacter()
|
|
if target and target ~= "" and target ~= TEXT_CHARACTER then
|
|
GameTooltip:AddLine(target, 0.8, 0.8, 0.8)
|
|
end
|
|
GameTooltip:Show()
|
|
end)
|
|
bankBtn:SetScript("OnLeave", function()
|
|
GameTooltip:Hide()
|
|
end)
|
|
bankBtn:SetScript("OnClick", function()
|
|
if not (SFrames.Bags and SFrames.Bags.Bank) then return end
|
|
local target = GetOfflineBankTargetCharacter()
|
|
if target == TEXT_CHARACTER then
|
|
target = nil
|
|
end
|
|
if SFrames.Bags.Bank.OpenOffline then
|
|
SFrames.Bags.Bank:OpenOffline(target)
|
|
else
|
|
SFrames.Bags.Bank:Open()
|
|
end
|
|
end)
|
|
|
|
-- Sort button (icon)
|
|
local sortBtn = CreateHeaderIconButton("SFramesBagSortBtn", BagFrame, "Interface\\Icons\\INV_Misc_Note_05")
|
|
sortBtn:SetPoint("LEFT", eb, "RIGHT", 6, 0)
|
|
SFrames:SetIcon(sortBtn.icon, "backpack")
|
|
sortBtn:RegisterForClicks("LeftButtonUp", "RightButtonUp")
|
|
sortBtn:SetScript("OnEnter", function()
|
|
GameTooltip:SetOwner(this, "ANCHOR_RIGHT")
|
|
GameTooltip:SetText(TEXT_SORT, 1, 1, 1)
|
|
GameTooltip:AddLine("\229\183\166\233\148\174\230\149\180\231\144\134 | \229\143\179\233\148\174\229\143\141\229\186\143\230\149\180\231\144\134", 0.7, 0.7, 0.7)
|
|
GameTooltip:Show()
|
|
end)
|
|
sortBtn:SetScript("OnLeave", function()
|
|
GameTooltip:Hide()
|
|
end)
|
|
sortBtn:SetScript("OnClick", function()
|
|
if SFrames.Bags.Sort then
|
|
local reverse = (arg1 == "RightButton")
|
|
SFrames.Bags.Sort:Start(reverse)
|
|
end
|
|
end)
|
|
|
|
local hsBtn = CreateHeaderIconButton("SFramesBagHSBtn", BagFrame, "Interface\\Icons\\INV_Misc_Rune_01")
|
|
hsBtn:SetPoint("LEFT", sortBtn, "RIGHT", 4, 0)
|
|
SFrames:SetIcon(hsBtn.icon, "hearthstone")
|
|
hsBtn:SetScript("OnEnter", function()
|
|
GameTooltip:SetOwner(this, "ANCHOR_RIGHT")
|
|
GameTooltip:SetText(TEXT_HS_USE, 1, 1, 1)
|
|
GameTooltip:Show()
|
|
end)
|
|
hsBtn:SetScript("OnLeave", function() GameTooltip:Hide() end)
|
|
|
|
hsBtn:SetScript("OnClick", function()
|
|
for bag = 0, 4 do
|
|
for slot = 1, GetContainerNumSlots(bag) do
|
|
local link = GetContainerItemLink(bag, slot)
|
|
if link and (string.find(link, "6948") or string.find(link, "Hearthstone")) then
|
|
UseContainerItem(bag, slot)
|
|
return
|
|
end
|
|
end
|
|
end
|
|
SFrames:Print(TEXT_HS_NOT_FOUND)
|
|
end)
|
|
|
|
local keyBtn = CreateHeaderIconButton("SFramesBagKeyBtn", BagFrame, "Interface\\Icons\\INV_Misc_Key_04")
|
|
keyBtn:SetPoint("LEFT", hsBtn, "RIGHT", 4, 0)
|
|
SFrames:SetIcon(keyBtn.icon, "key")
|
|
keyBtn:RegisterForClicks("LeftButtonUp")
|
|
keyBtn:SetScript("OnEnter", function()
|
|
GameTooltip:SetOwner(this, "ANCHOR_RIGHT")
|
|
GameTooltip:SetText("\233\146\165\229\140\153\233\147\190", 1, 0.82, 0)
|
|
GameTooltip:Show()
|
|
end)
|
|
keyBtn:SetScript("OnLeave", function() GameTooltip:Hide() end)
|
|
keyBtn:SetScript("OnClick", function()
|
|
if SFrames.Bags._origToggleKeyRing then
|
|
SFrames.Bags._origToggleKeyRing()
|
|
elseif ToggleKeyRing then
|
|
ToggleKeyRing()
|
|
end
|
|
end)
|
|
|
|
local dbMenu = CreateFrame("Frame", "SFramesBagDropdown", BagFrame, "UIDropDownMenuTemplate")
|
|
dbMenu:Hide()
|
|
dbMenu:SetPoint("TOPRIGHT", charBtn, "BOTTOMRIGHT", 0, 0)
|
|
|
|
local function RefreshCharacterSelectorText()
|
|
if not BagFrame or not BagFrame.charSelectBtn then return end
|
|
if SFrames.Bags.Container.isOffline and SFrames.Bags.Container.offlineChar then
|
|
BagFrame.charSelectorLabel = SFrames.Bags.Container.offlineChar .. " (" .. TEXT_OFFLINE .. ")"
|
|
else
|
|
BagFrame.charSelectorLabel = GetCurrentCharacterName() .. " (" .. TEXT_ONLINE .. ")"
|
|
end
|
|
end
|
|
BagFrame.RefreshCharacterSelectorText = RefreshCharacterSelectorText
|
|
|
|
local function OnDropdownClick()
|
|
local char = this.value
|
|
if char == "ONLINE" then
|
|
SFrames.Bags.Container.isOffline = false
|
|
SFrames.Bags.Container.offlineChar = nil
|
|
else
|
|
SFrames.Bags.Container.isOffline = true
|
|
SFrames.Bags.Container.offlineChar = char
|
|
end
|
|
RefreshCharacterSelectorText()
|
|
SFrames.Bags.Container:UpdateLayout()
|
|
end
|
|
|
|
UIDropDownMenu_Initialize(dbMenu, function()
|
|
local info = UIDropDownMenu_CreateInfo and UIDropDownMenu_CreateInfo() or {}
|
|
local currentName = GetCurrentCharacterName()
|
|
|
|
info.text = currentName .. " (" .. TEXT_ONLINE .. ")"
|
|
info.value = "ONLINE"
|
|
info.func = OnDropdownClick
|
|
info.checked = (not SFrames.Bags.Container.isOffline)
|
|
UIDropDownMenu_AddButton(info)
|
|
|
|
local chars = SFrames.Bags.Offline:GetCharacterList()
|
|
table.sort(chars)
|
|
for _, char in ipairs(chars) do
|
|
if char ~= currentName then
|
|
info = UIDropDownMenu_CreateInfo and UIDropDownMenu_CreateInfo() or {}
|
|
info.text = char .. " (" .. TEXT_OFFLINE .. ")"
|
|
info.value = char
|
|
info.func = OnDropdownClick
|
|
info.checked = SFrames.Bags.Container.isOffline and SFrames.Bags.Container.offlineChar == char
|
|
UIDropDownMenu_AddButton(info)
|
|
end
|
|
end
|
|
end)
|
|
|
|
charBtn:SetScript("OnClick", function()
|
|
ToggleDropDownMenu(1, nil, dbMenu, this, 0, 0)
|
|
end)
|
|
charBtn:SetScript("OnEnter", function()
|
|
GameTooltip:SetOwner(this, "ANCHOR_RIGHT")
|
|
GameTooltip:SetText(BagFrame.charSelectorLabel or TEXT_CHARACTER, 1, 1, 1)
|
|
GameTooltip:Show()
|
|
end)
|
|
charBtn:SetScript("OnLeave", function()
|
|
GameTooltip:Hide()
|
|
end)
|
|
RefreshCharacterSelectorText()
|
|
|
|
-- React to bag updates while open
|
|
BagFrame:RegisterEvent("BAG_UPDATE")
|
|
BagFrame:RegisterEvent("PLAYER_MONEY")
|
|
BagFrame:RegisterEvent("BAG_UPDATE_COOLDOWN")
|
|
BagFrame:RegisterEvent("UNIT_INVENTORY_CHANGED")
|
|
BagFrame:RegisterEvent("PLAYER_ENTERING_WORLD")
|
|
BagFrame:RegisterEvent("TRADE_SHOW")
|
|
BagFrame:RegisterEvent("TRADE_CLOSED")
|
|
BagFrame:RegisterEvent("TRADE_UPDATE")
|
|
BagFrame:RegisterEvent("TRADE_PLAYER_ITEM_CHANGED")
|
|
BagFrame:RegisterEvent("TRADE_TARGET_ITEM_CHANGED")
|
|
BagFrame:RegisterEvent("TRADE_ACCEPT_UPDATE")
|
|
BagFrame:SetScript("OnEvent", function()
|
|
if BagFrame:IsVisible() then
|
|
SFrames.Bags.Container:UpdateLayout()
|
|
end
|
|
if event == "PLAYER_ENTERING_WORLD" then
|
|
if BagFrame.UpdateBagSlotIcons then BagFrame.UpdateBagSlotIcons() end
|
|
QueueBagSlotIconRefreshes()
|
|
elseif event == "BAG_UPDATE" or event == "UNIT_INVENTORY_CHANGED" then
|
|
if BagFrame.UpdateBagSlotIcons then BagFrame.UpdateBagSlotIcons() end
|
|
elseif event == "TRADE_SHOW" or event == "TRADE_CLOSED" or event == "TRADE_UPDATE"
|
|
or event == "TRADE_PLAYER_ITEM_CHANGED" or event == "TRADE_TARGET_ITEM_CHANGED"
|
|
or event == "TRADE_ACCEPT_UPDATE" then
|
|
if event == "TRADE_CLOSED" then
|
|
for _, btn in ipairs(ItemSlots) do
|
|
if btn.tradeText then btn.tradeText:Hide() end
|
|
local iconTex = _G[btn:GetName() .. "IconTexture"]
|
|
if iconTex and iconTex.SetDesaturated then
|
|
pcall(function() iconTex:SetDesaturated(false) end)
|
|
end
|
|
if iconTex then iconTex:SetVertexColor(1, 1, 1, 1) end
|
|
end
|
|
end
|
|
if BagFrame.UpdateBagSlotIcons then BagFrame.UpdateBagSlotIcons() end
|
|
QueueBagSlotIconRefreshes()
|
|
end
|
|
end)
|
|
|
|
BagFrame:Hide()
|
|
end
|
|
|
|
function SFrames.Bags.Container:Toggle()
|
|
if not BagFrame then return end
|
|
if BagFrame:IsVisible() then self:Close() else self:Open() end
|
|
end
|
|
|
|
function SFrames.Bags.Container:Open()
|
|
if not BagFrame then return end
|
|
self.isOffline = false
|
|
self.offlineChar = nil
|
|
if BagFrame.RefreshCharacterSelectorText then BagFrame.RefreshCharacterSelectorText() end
|
|
-- Clear search
|
|
if SFramesBagSearchBox then SFramesBagSearchBox:SetText("") end
|
|
self:UpdateLayout()
|
|
BagFrame:Show()
|
|
local elapsed = 0
|
|
local nextRefresh = 1
|
|
local refreshPoints = { 0.05, 0.18, 0.40 }
|
|
local refreshTimer = CreateFrame("Frame")
|
|
refreshTimer:SetScript("OnUpdate", function()
|
|
elapsed = elapsed + arg1
|
|
if nextRefresh <= table.getn(refreshPoints) and elapsed >= refreshPoints[nextRefresh] then
|
|
if BagFrame:IsVisible() then
|
|
if BagFrame.UpdateBagSlotIcons then
|
|
BagFrame.UpdateBagSlotIcons()
|
|
end
|
|
SFrames.Bags.Container:UpdateLayout()
|
|
end
|
|
nextRefresh = nextRefresh + 1
|
|
end
|
|
if nextRefresh > table.getn(refreshPoints) then
|
|
this:SetScript("OnUpdate", nil)
|
|
end
|
|
end)
|
|
PlaySound("igBackPackOpen")
|
|
end
|
|
|
|
function SFrames.Bags.Container:Close()
|
|
if not BagFrame then return end
|
|
BagFrame:Hide()
|
|
PlaySound("igBackPackClose")
|
|
end
|