1088 lines
35 KiB
Lua
1088 lines
35 KiB
Lua
-- Guda Bag Frame
|
|
-- Main bag viewing UI
|
|
|
|
local addon = Guda
|
|
|
|
local BagFrame = {}
|
|
addon.Modules.BagFrame = BagFrame
|
|
|
|
local currentViewChar = nil -- nil = current character
|
|
local searchText = ""
|
|
local itemButtons = {}
|
|
local showKeyring = false -- Toggle for keyring display
|
|
|
|
-- Global click catcher for clearing search focus
|
|
local clickCatcher = nil
|
|
|
|
-- Get player race icon path (using racial ability icons)
|
|
function Guda_GetPlayerRaceIcon()
|
|
local _, race = UnitRace("player")
|
|
|
|
-- Use racial ability icons that exist in vanilla
|
|
local raceIcons = {
|
|
Human = "Interface\\Icons\\Spell_Magic_PolymorphPig",
|
|
Dwarf = "Interface\\Icons\\Spell_Shadow_UnholyFrenzy",
|
|
NightElf = "Interface\\Icons\\Spell_Nature_Invisibility",
|
|
Gnome = "Interface\\Icons\\Ability_Repair",
|
|
Orc = "Interface\\Icons\\Ability_Racial_BloodRage",
|
|
Undead = "Interface\\Icons\\Spell_Shadow_RaiseDead",
|
|
Tauren = "Interface\\Icons\\Ability_Thunderclap",
|
|
Troll = "Interface\\Icons\\Ability_Racial_Avatar",
|
|
}
|
|
|
|
return raceIcons[race] or "Interface\\Icons\\INV_Misc_GroupNeedMore"
|
|
end
|
|
|
|
-- OnLoad
|
|
function Guda_BagFrame_OnLoad(self)
|
|
-- Set up search box placeholder
|
|
local searchBox = getglobal(self:GetName().."_SearchBar_SearchBox")
|
|
if searchBox then
|
|
searchBox:SetText("Search, try ~equipment")
|
|
searchBox:SetTextColor(0.5, 0.5, 0.5, 1)
|
|
end
|
|
|
|
-- Create invisible full-screen frame to catch clicks outside bag
|
|
if not clickCatcher then
|
|
clickCatcher = CreateFrame("Frame", "Guda_ClickCatcher", UIParent)
|
|
clickCatcher:SetFrameStrata("BACKGROUND")
|
|
clickCatcher:SetAllPoints(UIParent)
|
|
clickCatcher:EnableMouse(true)
|
|
clickCatcher:Hide()
|
|
|
|
clickCatcher:SetScript("OnMouseDown", function()
|
|
local searchBox = getglobal("Guda_BagFrame_SearchBar_SearchBox")
|
|
if searchBox then
|
|
searchBox:ClearFocus()
|
|
end
|
|
end)
|
|
end
|
|
|
|
addon:Debug("Bag frame loaded")
|
|
end
|
|
|
|
|
|
-- OnShow
|
|
function Guda_BagFrame_OnShow(self)
|
|
-- Save bag data when opening bags
|
|
addon.Modules.BagScanner:SaveToDatabase()
|
|
addon.Modules.MoneyTracker:Update()
|
|
|
|
-- Restore saved position if it exists (only if saved as BOTTOMRIGHT)
|
|
if addon and addon.Modules and addon.Modules.DB then
|
|
local pos = addon.Modules.DB:GetSetting("bagFramePosition")
|
|
if pos and pos.point == "BOTTOMRIGHT" and pos.x and pos.y then
|
|
self:ClearAllPoints()
|
|
self:SetPoint("BOTTOMRIGHT", "UIParent", "BOTTOMRIGHT", pos.x, pos.y)
|
|
end
|
|
end
|
|
|
|
-- Set lock state when frame is shown (ensures all child frames are loaded)
|
|
if BagFrame.UpdateLockState then
|
|
BagFrame:UpdateLockState()
|
|
end
|
|
BagFrame:Update()
|
|
end
|
|
|
|
-- OnHide
|
|
function Guda_BagFrame_OnHide(self)
|
|
-- Release buttons
|
|
Guda_ReleaseAllButtons()
|
|
end
|
|
|
|
-- Toggle visibility
|
|
function BagFrame:Toggle()
|
|
if Guda_BagFrame:IsShown() then
|
|
Guda_BagFrame:Hide()
|
|
else
|
|
Guda_BagFrame:Show()
|
|
end
|
|
end
|
|
|
|
-- Show specific character's bags
|
|
function BagFrame:ShowCharacter(fullName)
|
|
currentViewChar = fullName
|
|
self:Update()
|
|
end
|
|
|
|
-- Show current character
|
|
function BagFrame:ShowCurrentCharacter()
|
|
currentViewChar = nil
|
|
self:Update()
|
|
end
|
|
|
|
-- Update display
|
|
function BagFrame:Update()
|
|
if not Guda_BagFrame:IsShown() then
|
|
return
|
|
end
|
|
|
|
-- Clear existing buttons
|
|
Guda_ReleaseAllButtons()
|
|
|
|
local bagData
|
|
local isOtherChar = false
|
|
local charName = ""
|
|
|
|
local titleFont = getglobal("Guda_BagFrame_Title")
|
|
local displayName
|
|
|
|
if currentViewChar then
|
|
-- Viewing another character
|
|
bagData = addon.Modules.DB:GetCharacterBags(currentViewChar)
|
|
isOtherChar = true
|
|
charName = currentViewChar
|
|
|
|
local dash = string.find(currentViewChar, "-")
|
|
if dash then
|
|
displayName = string.sub(currentViewChar, 1, dash - 1)
|
|
else
|
|
displayName = currentViewChar
|
|
end
|
|
else
|
|
-- Viewing current character
|
|
bagData = addon.Modules.BagScanner:ScanBags()
|
|
displayName = UnitName("player") or "Character"
|
|
end
|
|
|
|
if titleFont and displayName then
|
|
titleFont:SetText(string.format("%s's Bags", displayName))
|
|
end
|
|
|
|
-- Display items
|
|
self:DisplayItems(bagData, isOtherChar, charName)
|
|
|
|
-- Update money
|
|
self:UpdateMoney()
|
|
|
|
-- Update bag slots info
|
|
self:UpdateBagSlotsInfo(bagData, isOtherChar)
|
|
end
|
|
|
|
-- Display items
|
|
function BagFrame:DisplayItems(bagData, isOtherChar, charName)
|
|
local x, y = 10, -10
|
|
local row = 0
|
|
local col = 0
|
|
local buttonSize = addon.Modules.DB:GetSetting("iconSize") or addon.Constants.BUTTON_SIZE
|
|
local spacing = addon.Modules.DB:GetSetting("iconSpacing") or addon.Constants.BUTTON_SPACING
|
|
local perRow = addon.Modules.DB:GetSetting("bagColumns") or 10
|
|
local itemContainer = getglobal("Guda_BagFrame_ItemContainer")
|
|
|
|
-- Build bag list - include keyring if toggled on
|
|
local bagsToShow = {}
|
|
for _, bagID in ipairs(addon.Constants.BAGS) do
|
|
table.insert(bagsToShow, bagID)
|
|
end
|
|
|
|
-- Add keyring (-2) at the end if toggled on
|
|
if showKeyring then
|
|
table.insert(bagsToShow, -2) -- Insert at end
|
|
end
|
|
|
|
for _, bagID in ipairs(bagsToShow) do
|
|
local bag = bagData[bagID]
|
|
|
|
-- Add spacing before keyring section
|
|
if bagID == -2 then
|
|
-- Add spacing before keyring
|
|
if col > 0 then
|
|
-- Move to next row if not at start of row
|
|
col = 0
|
|
row = row + 1
|
|
end
|
|
-- Add extra spacing (1 row)
|
|
row = row + 1
|
|
end
|
|
|
|
-- Get slot count for this bag
|
|
local numSlots
|
|
if isOtherChar and bag and bag.numSlots then
|
|
-- Use stored slot count for other characters
|
|
numSlots = bag.numSlots
|
|
else
|
|
-- Use current character's bag slot count
|
|
numSlots = addon.Modules.Utils:GetBagSlotCount(bagID)
|
|
end
|
|
|
|
-- Only show bags that have slots
|
|
if numSlots and numSlots > 0 then
|
|
-- Iterate through ALL slots (1 to numSlots) to show empty slots too
|
|
for slot = 1, numSlots do
|
|
local itemData = bag and bag.slots and bag.slots[slot] or nil
|
|
|
|
-- Check if item matches search filter
|
|
local matchesFilter = self:PassesSearchFilter(itemData)
|
|
|
|
local button = Guda_GetItemButton(itemContainer)
|
|
|
|
-- Position button
|
|
local xPos = x + (col * (buttonSize + spacing))
|
|
local yPos = y - (row * (buttonSize + spacing))
|
|
|
|
button:ClearAllPoints()
|
|
button:SetPoint("TOPLEFT", itemContainer, "TOPLEFT", xPos, yPos)
|
|
|
|
-- Set item data with filter match info
|
|
Guda_ItemButton_SetItem(button, bagID, slot, itemData, false, isOtherChar and charName or nil, matchesFilter)
|
|
|
|
table.insert(itemButtons, button)
|
|
|
|
-- Advance position
|
|
col = col + 1
|
|
if col >= perRow then
|
|
col = 0
|
|
row = row + 1
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Resize frame dynamically based on content
|
|
self:ResizeFrame(row, col, perRow)
|
|
end
|
|
|
|
-- Resize frame based on number of rows and columns
|
|
function BagFrame:ResizeFrame(currentRow, currentCol, columns)
|
|
local buttonSize = addon.Modules.DB:GetSetting("iconSize") or addon.Constants.BUTTON_SIZE
|
|
local spacing = addon.Modules.DB:GetSetting("iconSpacing") or addon.Constants.BUTTON_SPACING
|
|
|
|
-- Calculate actual number of rows used
|
|
local totalRows = currentRow + 1
|
|
|
|
-- Ensure at least 1 row
|
|
if totalRows < 1 then
|
|
totalRows = 1
|
|
end
|
|
|
|
-- Calculate required dimensions based on columns
|
|
local containerWidth = (columns * (buttonSize + spacing)) + 20
|
|
local containerHeight = (totalRows * (buttonSize + spacing)) + 20
|
|
local frameWidth = containerWidth + 20
|
|
local frameHeight = containerHeight + 115 -- Title (40) + search (30) + footer (45)
|
|
|
|
-- Minimum sizes
|
|
if containerWidth < 200 then
|
|
containerWidth = 200
|
|
frameWidth = 220
|
|
end
|
|
if containerHeight < 150 then
|
|
containerHeight = 150
|
|
end
|
|
if frameHeight < 250 then
|
|
frameHeight = 250
|
|
end
|
|
|
|
-- Maximum sizes
|
|
if containerWidth > 800 then
|
|
containerWidth = 800
|
|
frameWidth = 820
|
|
end
|
|
if containerHeight > 600 then
|
|
containerHeight = 600
|
|
end
|
|
if frameHeight > 800 then
|
|
frameHeight = 800
|
|
end
|
|
|
|
-- Resize frames
|
|
local bagFrame = getglobal("Guda_BagFrame")
|
|
local itemContainer = getglobal("Guda_BagFrame_ItemContainer")
|
|
|
|
if bagFrame then
|
|
bagFrame:SetWidth(frameWidth)
|
|
bagFrame:SetHeight(frameHeight)
|
|
|
|
-- Always use BOTTOMRIGHT anchor to make frame grow left
|
|
bagFrame:ClearAllPoints()
|
|
|
|
if addon and addon.Modules and addon.Modules.DB then
|
|
local pos = addon.Modules.DB:GetSetting("bagFramePosition")
|
|
-- Only use saved position if it was saved as BOTTOMRIGHT
|
|
if pos and pos.point == "BOTTOMRIGHT" and pos.x and pos.y then
|
|
bagFrame:SetPoint("BOTTOMRIGHT", "UIParent", "BOTTOMRIGHT", pos.x, pos.y)
|
|
else
|
|
-- Default position: bottom right corner
|
|
bagFrame:SetPoint("BOTTOMRIGHT", UIParent, "BOTTOMRIGHT", -50, 100)
|
|
end
|
|
else
|
|
-- Fallback to default if DB not available
|
|
bagFrame:SetPoint("BOTTOMRIGHT", UIParent, "BOTTOMRIGHT", -50, 100)
|
|
end
|
|
end
|
|
|
|
if itemContainer then
|
|
itemContainer:SetWidth(containerWidth)
|
|
itemContainer:SetHeight(containerHeight)
|
|
end
|
|
|
|
-- Resize search bar and toolbar to match container width
|
|
local searchBar = getglobal("Guda_BagFrame_SearchBar")
|
|
if searchBar then
|
|
searchBar:SetWidth(containerWidth)
|
|
end
|
|
|
|
local toolbar = getglobal("Guda_BagFrame_Toolbar")
|
|
if toolbar then
|
|
toolbar:SetWidth(containerWidth)
|
|
end
|
|
end
|
|
|
|
-- Check if search is currently active
|
|
function BagFrame:IsSearchActive()
|
|
return searchText and searchText ~= "" and searchText ~= "Search, try ~equipment"
|
|
end
|
|
|
|
-- Check if item passes search filter (pfUI style)
|
|
function BagFrame:PassesSearchFilter(itemData)
|
|
-- If no search text, everything matches
|
|
if not self:IsSearchActive() then
|
|
return true
|
|
end
|
|
|
|
-- Empty slots don't match when searching (pfUI style - they get dimmed)
|
|
if not itemData then
|
|
return false
|
|
end
|
|
|
|
-- Get item name from itemData.name or parse from link
|
|
local itemName = itemData.name
|
|
if not itemName and itemData.link then
|
|
-- Parse name from item link: |cffffffff|Hitem:...|h[Item Name]|h|r
|
|
local _, _, name = string.find(itemData.link, "%[(.+)%]")
|
|
itemName = name
|
|
if not self.warnedAboutParsing then
|
|
addon:Print("DEBUG: Had to parse item name from link: " .. (itemName or "FAILED"))
|
|
self.warnedAboutParsing = true
|
|
end
|
|
end
|
|
|
|
if not itemName then
|
|
if not self.warnedAboutNoName then
|
|
addon:Print("DEBUG: Item has no name and no link! texture = " .. tostring(itemData.texture))
|
|
self.warnedAboutNoName = true
|
|
end
|
|
return false
|
|
end
|
|
|
|
-- Case-insensitive search in item name
|
|
itemName = string.lower(itemName)
|
|
local search = string.lower(searchText)
|
|
|
|
-- Check if item name contains search text
|
|
local matches = string.find(itemName, search, 1, true) ~= nil
|
|
|
|
-- Debug: print first match found
|
|
if matches and not self.foundFirstMatch then
|
|
addon:Print("DEBUG: Found match! Item: '" .. itemName .. "' matches search: '" .. searchText .. "'")
|
|
self.foundFirstMatch = true
|
|
end
|
|
|
|
return matches
|
|
end
|
|
|
|
function BagFrame:UpdateMoney()
|
|
local moneyFrame = getglobal("Guda_BagFrame_MoneyFrame")
|
|
|
|
if not moneyFrame then
|
|
addon:Debug("MoneyFrame not found! Checking parent...")
|
|
addon:Debug("Guda_BagFrame exists: " .. tostring(getglobal("Guda_BagFrame") ~= nil))
|
|
|
|
-- Try to create it manually
|
|
self:CreateMoneyFrame()
|
|
moneyFrame = getglobal("Guda_BagFrame_MoneyFrame")
|
|
end
|
|
|
|
if moneyFrame then
|
|
MoneyFrame_Update("Guda_BagFrame_MoneyFrame", GetMoney())
|
|
moneyFrame:Show()
|
|
|
|
-- Ensure tooltip overlay exists
|
|
self:EnsureMoneyTooltipOverlay()
|
|
|
|
-- Also add tooltip to toolbar empty space
|
|
self:SetupToolbarTooltip()
|
|
else
|
|
addon:Debug("Still couldn't find or create MoneyFrame!")
|
|
end
|
|
end
|
|
|
|
-- Update bag slots info text (excluding keyring)
|
|
function BagFrame:UpdateBagSlotsInfo(bagData, isOtherChar)
|
|
local infoText = getglobal("Guda_BagFrame_Toolbar_BagSlotsInfo_Text")
|
|
if not infoText then return end
|
|
|
|
local totalSlots = 0
|
|
local usedSlots = 0
|
|
|
|
-- Count slots in regular bags only (0-4), exclude keyring (-2)
|
|
for _, bagID in ipairs(addon.Constants.BAGS) do
|
|
local bag = bagData[bagID]
|
|
|
|
-- Get slot count for this bag
|
|
local numSlots
|
|
if isOtherChar and bag and bag.numSlots then
|
|
numSlots = bag.numSlots
|
|
else
|
|
numSlots = addon.Modules.Utils:GetBagSlotCount(bagID)
|
|
end
|
|
|
|
if numSlots and numSlots > 0 then
|
|
totalSlots = totalSlots + numSlots
|
|
|
|
-- Count used slots
|
|
if bag and bag.slots then
|
|
for slot = 1, numSlots do
|
|
if bag.slots[slot] then
|
|
usedSlots = usedSlots + 1
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
local freeSlots = totalSlots - usedSlots
|
|
|
|
-- Format: "56 / 80" (free / total)
|
|
infoText:SetText(string.format("%d / %d", freeSlots, totalSlots))
|
|
infoText:SetTextColor(0.7, 0.7, 0.7)
|
|
end
|
|
|
|
function BagFrame:CreateMoneyFrame()
|
|
local moneyFrame = CreateFrame("Frame", "Guda_BagFrame_MoneyFrame", Guda_BagFrame, "SmallMoneyFrameTemplate")
|
|
moneyFrame:SetPoint("BOTTOMRIGHT", Guda_BagFrame, "BOTTOMRIGHT", -15, 10)
|
|
moneyFrame:SetWidth(180)
|
|
moneyFrame:SetHeight(35)
|
|
addon:Debug("MoneyFrame created via CreateMoneyFrame")
|
|
end
|
|
|
|
-- Setup tooltip on toolbar empty space
|
|
function BagFrame:SetupToolbarTooltip()
|
|
local toolbar = getglobal("Guda_BagFrame_Toolbar")
|
|
if not toolbar then return end
|
|
|
|
-- Only set up once
|
|
if toolbar.tooltipSetup then return end
|
|
|
|
-- Get the existing OnEnter script (if any)
|
|
local originalOnEnter = toolbar:GetScript("OnEnter")
|
|
|
|
-- Set new OnEnter that shows money tooltip
|
|
toolbar:SetScript("OnEnter", function()
|
|
-- Call original if it exists
|
|
if originalOnEnter then
|
|
originalOnEnter()
|
|
end
|
|
|
|
-- Show money tooltip
|
|
addon:Debug("Toolbar OnEnter - showing money tooltip")
|
|
Guda_BagFrame_MoneyOnEnter(getglobal("Guda_BagFrame_MoneyFrame"))
|
|
end)
|
|
|
|
-- Set OnLeave to hide tooltip
|
|
toolbar:SetScript("OnLeave", function()
|
|
addon:Debug("Toolbar OnLeave - hiding tooltip")
|
|
GameTooltip:Hide()
|
|
end)
|
|
|
|
toolbar.tooltipSetup = true
|
|
addon:Debug("Toolbar tooltip handlers set up")
|
|
end
|
|
|
|
-- Create transparent overlay for money tooltip
|
|
function BagFrame:EnsureMoneyTooltipOverlay()
|
|
local overlayName = "Guda_BagFrame_MoneyTooltipOverlay"
|
|
local overlay = getglobal(overlayName)
|
|
|
|
if not overlay then
|
|
local moneyFrame = getglobal("Guda_BagFrame_MoneyFrame")
|
|
if not moneyFrame then return end
|
|
|
|
-- Create transparent overlay frame
|
|
overlay = CreateFrame("Frame", overlayName, moneyFrame)
|
|
overlay:SetAllPoints(moneyFrame)
|
|
overlay:SetFrameLevel(moneyFrame:GetFrameLevel() + 1)
|
|
overlay:EnableMouse(true)
|
|
|
|
-- Set tooltip handlers on overlay
|
|
overlay:SetScript("OnEnter", function()
|
|
addon:Debug("Money overlay OnEnter triggered")
|
|
Guda_BagFrame_MoneyOnEnter(moneyFrame)
|
|
end)
|
|
|
|
overlay:SetScript("OnLeave", function()
|
|
addon:Debug("Money overlay OnLeave triggered")
|
|
GameTooltip:Hide()
|
|
end)
|
|
|
|
-- Forward drag events to bag frame (if not locked)
|
|
overlay:SetScript("OnMouseDown", function()
|
|
local searchBox = getglobal("Guda_BagFrame_SearchBar_SearchBox")
|
|
if searchBox then
|
|
searchBox:ClearFocus()
|
|
end
|
|
|
|
local bagFrame = getglobal("Guda_BagFrame")
|
|
local isLocked = addon.Modules.DB and addon.Modules.DB:GetSetting("lockBags")
|
|
|
|
if bagFrame and not isLocked and arg1 == "LeftButton" then
|
|
bagFrame:StartMoving()
|
|
end
|
|
end)
|
|
|
|
overlay:SetScript("OnMouseUp", function()
|
|
local bagFrame = getglobal("Guda_BagFrame")
|
|
local isLocked = addon.Modules.DB and addon.Modules.DB:GetSetting("lockBags")
|
|
|
|
if bagFrame and not isLocked then
|
|
bagFrame:StopMovingOrSizing()
|
|
SaveBagFramePosition()
|
|
end
|
|
end)
|
|
|
|
addon:Debug("Money tooltip overlay created")
|
|
end
|
|
|
|
overlay:Show()
|
|
end
|
|
|
|
-- Money frame OnLoad handler
|
|
function Guda_BagFrame_MoneyFrame_OnLoad(self)
|
|
addon:Debug("MoneyFrame OnLoad called for: " .. self:GetName())
|
|
|
|
-- Set tooltip handlers on all money denomination buttons
|
|
local buttons = {"GoldButton", "SilverButton", "CopperButton"}
|
|
|
|
for _, buttonName in ipairs(buttons) do
|
|
local fullName = self:GetName() .. buttonName
|
|
local button = getglobal(fullName)
|
|
addon:Debug("Looking for button: " .. fullName .. " - Found: " .. tostring(button ~= nil))
|
|
if button then
|
|
button:SetScript("OnEnter", function()
|
|
addon:Debug("Money button OnEnter triggered")
|
|
Guda_BagFrame_MoneyOnEnter(this:GetParent())
|
|
end)
|
|
button:SetScript("OnLeave", function()
|
|
GameTooltip:Hide()
|
|
end)
|
|
end
|
|
end
|
|
|
|
-- Also try setting handlers directly on the parent frame
|
|
addon:Debug("Setting handlers on parent frame as fallback")
|
|
self:EnableMouse(true)
|
|
self:SetScript("OnEnter", function()
|
|
addon:Debug("Parent frame OnEnter triggered")
|
|
Guda_BagFrame_MoneyOnEnter(this)
|
|
end)
|
|
self:SetScript("OnLeave", function()
|
|
GameTooltip:Hide()
|
|
end)
|
|
end
|
|
|
|
-- Money tooltip handler
|
|
function Guda_BagFrame_MoneyOnEnter(self)
|
|
if not self then return end
|
|
|
|
-- Anchor tooltip to TOPRIGHT - aligns tooltip's right edge with money container's right edge
|
|
GameTooltip:SetOwner(self, "ANCHOR_TOPRIGHT", 0, 0)
|
|
GameTooltip:ClearLines()
|
|
|
|
-- Get all characters and total
|
|
local chars = addon.Modules.DB:GetAllCharacters(true)
|
|
local totalMoney = addon.Modules.DB:GetTotalMoney(true)
|
|
|
|
-- Header with faction/realm total - use colored money
|
|
GameTooltip:AddLine(
|
|
"Faction/realm-wide gold: " .. addon.Modules.Utils:FormatMoney(totalMoney, false, true),
|
|
1, 0.82, 0
|
|
)
|
|
GameTooltip:AddLine(" ")
|
|
|
|
-- List each character with class-colored names
|
|
for _, char in ipairs(chars) do
|
|
-- Get class color from WoW's built-in table using English class token
|
|
local classToken = char.classToken
|
|
local classColor = classToken and (CUSTOM_CLASS_COLORS or RAID_CLASS_COLORS)[classToken]
|
|
local colorR, colorG, colorB = 0.7, 0.7, 0.7
|
|
|
|
if classColor then
|
|
colorR, colorG, colorB = classColor.r, classColor.g, classColor.b
|
|
end
|
|
|
|
-- Create colored name
|
|
local coloredName = addon.Modules.Utils:ColorText(char.name, colorR, colorG, colorB)
|
|
|
|
GameTooltip:AddLine(
|
|
coloredName .. ": " .. addon.Modules.Utils:FormatMoney(char.money or 0, false, true)
|
|
)
|
|
end
|
|
|
|
GameTooltip:Show()
|
|
end
|
|
|
|
-- Character dropdown management
|
|
local characterDropdown = nil
|
|
|
|
-- Toggle character dropdown
|
|
function Guda_BagFrame_ToggleCharacterDropdown(button)
|
|
if characterDropdown and characterDropdown:IsShown() then
|
|
characterDropdown:Hide()
|
|
return
|
|
end
|
|
|
|
if not characterDropdown then
|
|
-- Create dropdown frame
|
|
characterDropdown = CreateFrame("Frame", "Guda_CharacterDropdown", UIParent)
|
|
characterDropdown:SetFrameStrata("DIALOG")
|
|
characterDropdown:SetWidth(200)
|
|
characterDropdown:SetBackdrop({
|
|
bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
|
|
edgeFile = "Interface\\DialogFrame\\UI-DialogBox-Border",
|
|
tile = true,
|
|
tileSize = 16,
|
|
edgeSize = 16,
|
|
insets = { left = 4, right = 4, top = 4, bottom = 4 }
|
|
})
|
|
characterDropdown:SetBackdropColor(0, 0, 0, 0.95)
|
|
characterDropdown:EnableMouse(true)
|
|
characterDropdown:Hide()
|
|
|
|
characterDropdown.buttons = {}
|
|
end
|
|
|
|
-- Position dropdown below the button
|
|
characterDropdown:ClearAllPoints()
|
|
characterDropdown:SetPoint("TOPLEFT", button, "BOTTOMLEFT", 0, -2)
|
|
|
|
-- Clear existing buttons
|
|
for _, btn in ipairs(characterDropdown.buttons) do
|
|
btn:Hide()
|
|
end
|
|
characterDropdown.buttons = {}
|
|
|
|
-- Get all characters
|
|
local chars = addon.Modules.DB:GetAllCharacters(true)
|
|
|
|
-- Add "Current Character" option at the top
|
|
local yOffset = -8
|
|
local currentCharButton = CreateFrame("Button", nil, characterDropdown)
|
|
currentCharButton:SetWidth(188)
|
|
currentCharButton:SetHeight(20)
|
|
currentCharButton:SetPoint("TOP", characterDropdown, "TOP", 0, yOffset)
|
|
|
|
-- Button background on hover
|
|
local currentCharBg = currentCharButton:CreateTexture(nil, "BACKGROUND")
|
|
currentCharBg:SetAllPoints()
|
|
currentCharBg:SetTexture("Interface\\QuestFrame\\UI-QuestTitleHighlight")
|
|
currentCharBg:SetBlendMode("ADD")
|
|
currentCharBg:SetAlpha(0)
|
|
|
|
-- Button text
|
|
local currentCharText = currentCharButton:CreateFontString(nil, "ARTWORK", "GameFontHighlight")
|
|
currentCharText:SetPoint("LEFT", currentCharButton, "LEFT", 8, 0)
|
|
currentCharText:SetText("Current Character")
|
|
|
|
-- Button scripts
|
|
currentCharButton:SetScript("OnEnter", function()
|
|
currentCharBg:SetAlpha(0.3)
|
|
end)
|
|
currentCharButton:SetScript("OnLeave", function()
|
|
currentCharBg:SetAlpha(0)
|
|
end)
|
|
currentCharButton:SetScript("OnClick", function()
|
|
addon.Modules.BagFrame:ShowCurrentCharacter()
|
|
characterDropdown:Hide()
|
|
end)
|
|
|
|
table.insert(characterDropdown.buttons, currentCharButton)
|
|
yOffset = yOffset - 20
|
|
|
|
-- Add separator
|
|
local separator = characterDropdown:CreateTexture(nil, "ARTWORK")
|
|
separator:SetHeight(1)
|
|
separator:SetWidth(180)
|
|
separator:SetPoint("TOP", characterDropdown, "TOP", 0, yOffset)
|
|
separator:SetTexture(1, 1, 1, 0.2)
|
|
yOffset = yOffset - 4
|
|
|
|
-- Get current player's full name for comparison
|
|
local currentPlayerFullName = addon.Modules.DB:GetPlayerFullName()
|
|
|
|
-- Add character buttons
|
|
for _, char in ipairs(chars) do
|
|
-- Capture variables in local scope for closure
|
|
local charFullName = char.fullName
|
|
local charName = char.name
|
|
local charMoney = char.money or 0
|
|
local charClassToken = char.classToken
|
|
local isCurrentChar = (charFullName == currentPlayerFullName)
|
|
|
|
local charButton = CreateFrame("Button", nil, characterDropdown)
|
|
charButton:SetWidth(188)
|
|
charButton:SetHeight(20)
|
|
charButton:SetPoint("TOP", characterDropdown, "TOP", 0, yOffset)
|
|
|
|
-- Button background on hover
|
|
local charBg = charButton:CreateTexture(nil, "BACKGROUND")
|
|
charBg:SetAllPoints()
|
|
charBg:SetTexture("Interface\\QuestFrame\\UI-QuestTitleHighlight")
|
|
charBg:SetBlendMode("ADD")
|
|
charBg:SetAlpha(0)
|
|
|
|
-- Get class color
|
|
local classColor = charClassToken and RAID_CLASS_COLORS[charClassToken]
|
|
local r, g, b = 1, 1, 1
|
|
if classColor then
|
|
r, g, b = classColor.r, classColor.g, classColor.b
|
|
end
|
|
|
|
-- Button text
|
|
local charText = charButton:CreateFontString(nil, "ARTWORK", "GameFontHighlight")
|
|
charText:SetPoint("LEFT", charButton, "LEFT", 8, 0)
|
|
charText:SetText(charName)
|
|
charText:SetTextColor(r, g, b)
|
|
|
|
-- Money text
|
|
local moneyText = charButton:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
|
|
moneyText:SetPoint("RIGHT", charButton, "RIGHT", -8, 0)
|
|
moneyText:SetText(addon.Modules.Utils:FormatMoney(charMoney))
|
|
moneyText:SetTextColor(0.7, 0.7, 0.7)
|
|
|
|
-- Button scripts
|
|
charButton:SetScript("OnEnter", function()
|
|
charBg:SetAlpha(0.3)
|
|
end)
|
|
charButton:SetScript("OnLeave", function()
|
|
charBg:SetAlpha(0)
|
|
end)
|
|
charButton:SetScript("OnClick", function()
|
|
if charFullName then
|
|
if isCurrentChar then
|
|
-- Clicking current character - show current live view
|
|
addon.Modules.BagFrame:ShowCurrentCharacter()
|
|
else
|
|
-- Clicking different character - show their stored bags
|
|
addon.Modules.BagFrame:ShowCharacter(charFullName)
|
|
end
|
|
characterDropdown:Hide()
|
|
else
|
|
addon:Print("Error: Character fullName is nil")
|
|
end
|
|
end)
|
|
|
|
table.insert(characterDropdown.buttons, charButton)
|
|
yOffset = yOffset - 20
|
|
end
|
|
|
|
-- Set dropdown height based on content
|
|
characterDropdown:SetHeight(math.abs(yOffset) + 8)
|
|
|
|
-- Show dropdown
|
|
characterDropdown:Show()
|
|
end
|
|
|
|
-- Hide dropdown when clicking elsewhere
|
|
local function HideCharacterDropdown()
|
|
if characterDropdown then
|
|
characterDropdown:Hide()
|
|
end
|
|
end
|
|
|
|
-- Search changed handler
|
|
function Guda_BagFrame_OnSearchChanged(self)
|
|
local text = self:GetText()
|
|
-- Ignore placeholder text
|
|
if text == "Search, try ~equipment" then
|
|
text = ""
|
|
end
|
|
if text ~= searchText then
|
|
searchText = text
|
|
BagFrame.foundFirstMatch = false -- Reset debug flags
|
|
BagFrame.warnedAboutParsing = false
|
|
BagFrame.warnedAboutNoName = false
|
|
addon:Print("Search text changed to: '" .. (searchText or "empty") .. "'")
|
|
BagFrame:Update()
|
|
end
|
|
end
|
|
|
|
-- Keyring toggle handler
|
|
function Guda_BagFrame_ToggleKeyring()
|
|
showKeyring = not showKeyring
|
|
|
|
-- Update button appearance to show toggle state
|
|
local button = getglobal("Guda_BagFrame_Toolbar_KeyringButton")
|
|
if button then
|
|
local icon = getglobal(button:GetName().."_Icon")
|
|
if icon then
|
|
if showKeyring then
|
|
-- Highlighted when active
|
|
icon:SetVertexColor(1.0, 1.0, 0.5)
|
|
else
|
|
-- Normal color when inactive
|
|
icon:SetVertexColor(0.8, 0.8, 0.8)
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Refresh display
|
|
BagFrame:Update()
|
|
end
|
|
|
|
-- Sort button handler
|
|
function Guda_BagFrame_Sort()
|
|
if currentViewChar then
|
|
addon:Print("Cannot sort another character's bags!")
|
|
return
|
|
end
|
|
|
|
addon.Modules.SortEngine:SortBags()
|
|
|
|
-- Update after a delay to allow items to move
|
|
local frame = CreateFrame("Frame")
|
|
local elapsed = 0
|
|
frame:SetScript("OnUpdate", function()
|
|
elapsed = elapsed + arg1
|
|
if elapsed >= 0.5 then
|
|
frame:SetScript("OnUpdate", nil)
|
|
BagFrame:Update()
|
|
end
|
|
end)
|
|
end
|
|
|
|
-- Hook to default bag opening
|
|
local function HookDefaultBags()
|
|
-- Override ToggleBackpack
|
|
local originalToggleBackpack = ToggleBackpack
|
|
function ToggleBackpack()
|
|
BagFrame:Toggle()
|
|
end
|
|
|
|
-- Override OpenAllBags
|
|
local originalOpenAllBags = OpenAllBags
|
|
function OpenAllBags()
|
|
Guda_BagFrame:Show()
|
|
end
|
|
|
|
-- Override CloseAllBags
|
|
local originalCloseAllBags = CloseAllBags
|
|
function CloseAllBags()
|
|
Guda_BagFrame:Hide()
|
|
end
|
|
end
|
|
|
|
-- Save bag frame position (always as BOTTOMRIGHT)
|
|
local function SaveBagFramePosition()
|
|
local frame = getglobal("Guda_BagFrame")
|
|
if not frame or not addon or not addon.Modules or not addon.Modules.DB then return end
|
|
|
|
-- Always save as BOTTOMRIGHT coordinates
|
|
local right = frame:GetRight()
|
|
local bottom = frame:GetBottom()
|
|
local screenWidth = GetScreenWidth()
|
|
|
|
if right and bottom and screenWidth then
|
|
local xOffset = right - screenWidth
|
|
local yOffset = bottom
|
|
|
|
addon.Modules.DB:SetSetting("bagFramePosition", {
|
|
point = "BOTTOMRIGHT",
|
|
x = xOffset,
|
|
y = yOffset
|
|
})
|
|
end
|
|
end
|
|
|
|
-- Update lock state (controls whether frame is draggable)
|
|
function BagFrame:UpdateLockState()
|
|
-- Safety check: ensure addon and modules exist
|
|
if not addon or not addon.Modules then return end
|
|
|
|
local frame = getglobal("Guda_BagFrame")
|
|
if not frame then return end
|
|
|
|
-- Check if DB module is available
|
|
if not addon.Modules.DB or not addon.Modules.DB.GetSetting then return end
|
|
|
|
local success, isLocked = pcall(function()
|
|
return addon.Modules.DB:GetSetting("lockBags")
|
|
end)
|
|
|
|
if not success then return end
|
|
|
|
if isLocked == nil then
|
|
isLocked = false
|
|
end
|
|
|
|
-- Get draggable areas
|
|
local toolbar = getglobal("Guda_BagFrame_Toolbar")
|
|
local moneyFrame = getglobal("Guda_BagFrame_MoneyFrame")
|
|
local itemContainer = getglobal("Guda_BagFrame_ItemContainer")
|
|
|
|
if isLocked then
|
|
-- Disable dragging on main frame
|
|
if frame.SetScript then
|
|
frame:SetScript("OnMouseDown", function()
|
|
local searchBox = getglobal("Guda_BagFrame_SearchBar_SearchBox")
|
|
if searchBox then
|
|
searchBox:ClearFocus()
|
|
end
|
|
end)
|
|
frame:SetScript("OnMouseUp", nil)
|
|
end
|
|
|
|
-- Disable dragging on toolbar
|
|
if toolbar and toolbar.SetScript then
|
|
toolbar:SetScript("OnMouseDown", function()
|
|
local searchBox = getglobal("Guda_BagFrame_SearchBar_SearchBox")
|
|
if searchBox then
|
|
searchBox:ClearFocus()
|
|
end
|
|
end)
|
|
toolbar:SetScript("OnMouseUp", nil)
|
|
end
|
|
|
|
-- Disable dragging on money frame (preserve tooltip handlers on child buttons)
|
|
if moneyFrame and moneyFrame.SetScript then
|
|
moneyFrame:SetScript("OnMouseDown", function()
|
|
local searchBox = getglobal("Guda_BagFrame_SearchBar_SearchBox")
|
|
if searchBox then
|
|
searchBox:ClearFocus()
|
|
end
|
|
end)
|
|
moneyFrame:SetScript("OnMouseUp", nil)
|
|
end
|
|
|
|
-- Disable dragging on item container
|
|
if itemContainer and itemContainer.SetScript then
|
|
itemContainer:SetScript("OnMouseDown", function()
|
|
local searchBox = getglobal("Guda_BagFrame_SearchBar_SearchBox")
|
|
if searchBox then
|
|
searchBox:ClearFocus()
|
|
end
|
|
end)
|
|
itemContainer:SetScript("OnMouseUp", nil)
|
|
end
|
|
else
|
|
-- Enable dragging on main frame
|
|
if frame and frame.SetScript then
|
|
frame:SetScript("OnMouseDown", function()
|
|
local searchBox = getglobal("Guda_BagFrame_SearchBar_SearchBox")
|
|
if searchBox then
|
|
searchBox:ClearFocus()
|
|
end
|
|
|
|
local bagFrame = getglobal("Guda_BagFrame")
|
|
if bagFrame and arg1 == "LeftButton" then
|
|
bagFrame:StartMoving()
|
|
end
|
|
end)
|
|
frame:SetScript("OnMouseUp", function()
|
|
local bagFrame = getglobal("Guda_BagFrame")
|
|
if bagFrame then
|
|
bagFrame:StopMovingOrSizing()
|
|
SaveBagFramePosition()
|
|
end
|
|
end)
|
|
end
|
|
|
|
-- Enable dragging on toolbar (title area)
|
|
if toolbar and toolbar.SetScript then
|
|
toolbar:SetScript("OnMouseDown", function()
|
|
local searchBox = getglobal("Guda_BagFrame_SearchBar_SearchBox")
|
|
if searchBox then
|
|
searchBox:ClearFocus()
|
|
end
|
|
|
|
local bagFrame = getglobal("Guda_BagFrame")
|
|
if bagFrame and arg1 == "LeftButton" then
|
|
bagFrame:StartMoving()
|
|
end
|
|
end)
|
|
toolbar:SetScript("OnMouseUp", function()
|
|
local bagFrame = getglobal("Guda_BagFrame")
|
|
if bagFrame then
|
|
bagFrame:StopMovingOrSizing()
|
|
SaveBagFramePosition()
|
|
end
|
|
end)
|
|
end
|
|
|
|
-- Enable dragging on money frame (preserve tooltip handlers on child buttons)
|
|
if moneyFrame and moneyFrame.SetScript then
|
|
moneyFrame:SetScript("OnMouseDown", function()
|
|
local searchBox = getglobal("Guda_BagFrame_SearchBar_SearchBox")
|
|
if searchBox then
|
|
searchBox:ClearFocus()
|
|
end
|
|
|
|
local bagFrame = getglobal("Guda_BagFrame")
|
|
if bagFrame and arg1 == "LeftButton" then
|
|
bagFrame:StartMoving()
|
|
end
|
|
end)
|
|
moneyFrame:SetScript("OnMouseUp", function()
|
|
local bagFrame = getglobal("Guda_BagFrame")
|
|
if bagFrame then
|
|
bagFrame:StopMovingOrSizing()
|
|
SaveBagFramePosition()
|
|
end
|
|
end)
|
|
end
|
|
|
|
-- Enable dragging on item container
|
|
if itemContainer and itemContainer.SetScript then
|
|
itemContainer:SetScript("OnMouseDown", function()
|
|
local searchBox = getglobal("Guda_BagFrame_SearchBar_SearchBox")
|
|
if searchBox then
|
|
searchBox:ClearFocus()
|
|
end
|
|
|
|
local bagFrame = getglobal("Guda_BagFrame")
|
|
if bagFrame and arg1 == "LeftButton" then
|
|
bagFrame:StartMoving()
|
|
end
|
|
end)
|
|
itemContainer:SetScript("OnMouseUp", function()
|
|
local bagFrame = getglobal("Guda_BagFrame")
|
|
if bagFrame then
|
|
bagFrame:StopMovingOrSizing()
|
|
SaveBagFramePosition()
|
|
end
|
|
end)
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Initialize
|
|
function BagFrame:Initialize()
|
|
-- Hook default bag functions
|
|
HookDefaultBags()
|
|
|
|
-- Update on bag changes
|
|
addon.Modules.Events:OnBagUpdate(function()
|
|
if not currentViewChar then
|
|
BagFrame:Update()
|
|
end
|
|
end, "BagFrame")
|
|
|
|
-- Update on money changes
|
|
addon.Modules.Events:OnMoneyChanged(function()
|
|
BagFrame:UpdateMoney()
|
|
end, "BagFrame")
|
|
|
|
-- Hide character dropdown when clicking on bag frame
|
|
local bagFrame = getglobal("Guda_BagFrame")
|
|
if bagFrame then
|
|
local originalOnMouseDown = bagFrame:GetScript("OnMouseDown")
|
|
bagFrame:SetScript("OnMouseDown", function()
|
|
HideCharacterDropdown()
|
|
if originalOnMouseDown then
|
|
originalOnMouseDown()
|
|
end
|
|
end)
|
|
end
|
|
|
|
addon:Debug("Bag frame initialized")
|
|
end
|