diff --git a/Core/Database.lua b/Core/Database.lua
index 7e3c835..7bdeeb0 100644
--- a/Core/Database.lua
+++ b/Core/Database.lua
@@ -117,7 +117,7 @@ end
-- Get current player's full name
function DB:GetPlayerFullName()
- return playerName
+ return playerName .. "-" .. playerRealm
end
-- Get current character data
diff --git a/Core/Tooltip.lua b/Core/Tooltip.lua
index 533ce93..442f0d6 100644
--- a/Core/Tooltip.lua
+++ b/Core/Tooltip.lua
@@ -218,6 +218,8 @@ function Tooltip:AddInventoryInfo(tooltip, link)
local totalCount = totalBags + totalBank + totalEquipped
if hasAnyItems then
+
+ -- Top padding above the Inventory block (~10-12px visually)
tooltip:AddLine(" ")
-- Inventory label in exact bag frame title color
@@ -263,8 +265,8 @@ function Tooltip:AddInventoryInfo(tooltip, link)
tooltip:AddDoubleLine(displayName, countText, r, g, b, 1.0, 1.0, 1.0)
end
- -- Add small gap between inventory data and vendor sell price
- tooltip:AddLine(" ")
+ -- Bottom padding below the Inventory block (~10-12px visually)
+ --tooltip:AddLine(" ")
tooltip:Show()
end
@@ -275,6 +277,32 @@ function Tooltip:Initialize()
-- Helper function to defer vendor money so we can insert our Inventory block above it
local Orig_SetTooltipMoney = SetTooltipMoney
+ -- Move the tooltip money frame(s) vertically to fine-tune their position under our custom block
+ local function AdjustMoneyFrames(tooltip, yOffset)
+ if not tooltip or not tooltip.GetName then return end
+ local baseName = tooltip:GetName()
+ if not baseName then return end
+
+ -- Collect potential money frame names used by WoW tooltips
+ local candidates = {}
+ -- Primary money frame
+ tinsert(candidates, baseName .. "MoneyFrame")
+ -- Sometimes multiple money frames are created with numeric suffixes
+ for i = 1, 8 do
+ tinsert(candidates, baseName .. "MoneyFrame" .. i)
+ tinsert(candidates, baseName .. "SmallMoneyFrame" .. i)
+ end
+
+ for i = 1, getn(candidates) do
+ local f = getglobal(candidates[i])
+ if f and f:IsShown() and f.GetPoint then
+ local point, relTo, relPoint, xOfs, yOfs = f:GetPoint(1)
+ if point then
+ f:SetPoint(point, relTo, relPoint, xOfs or 0, (yOfs or 0) + (yOffset or 0))
+ end
+ end
+ end
+ end
local function WithDeferredMoney(tooltip, buildFunc)
local queue = {}
-- Temporarily override global SetTooltipMoney
@@ -295,30 +323,59 @@ function Tooltip:Initialize()
local q = queue[i]
Orig_SetTooltipMoney(q[1], q[2], q[3], q[4], q[5], q[6], q[7])
end
+
+ -- Add ~5px more space below the Inventory block by reducing the upward nudge from 15px to 10px
+ --AdjustMoneyFrames(tooltip, 12)
return ret
end
-- Hook SetBagItem
local oldSetBagItem = GameTooltip.SetBagItem
+ local oldSetInventoryItem = GameTooltip.SetInventoryItem
function GameTooltip:SetBagItem(bag, slot)
return WithDeferredMoney(self, function()
- local ret = oldSetBagItem(self, bag, slot)
- local link = GetContainerItemLink(bag, slot)
- if link then
- Tooltip:AddInventoryInfo(self, link)
+ local bankFrame = getglobal("BankFrame")
+ if bag == -1 and bankFrame and bankFrame:IsVisible() then
+ local invSlot = BankButtonIDToInvSlotID(slot)
+ if invSlot then
+ -- Use the inventory item method for bank main bag
+ local ret = oldSetInventoryItem(self, "player", invSlot)
+ local link = GetInventoryItemLink("player", invSlot)
+ if link then
+ Tooltip:AddInventoryInfo(self, link)
+ end
+ return ret
+ end
+ return nil
+ else
+ local ret = oldSetBagItem(self, bag, slot)
+ local link = GetContainerItemLink(bag, slot)
+ if link then
+ Tooltip:AddInventoryInfo(self, link)
+ end
+ return ret
end
- return ret
end)
end
- -- Hook SetHyperlink for chat links
- local oldSetHyperlink = GameTooltip.SetHyperlink
+ -- Hook SetHyperlink for hyperlinks from chat and cached links
+ local oldSetHyperlink = GameTooltip.SetHyperlink
function GameTooltip:SetHyperlink(link)
return WithDeferredMoney(self, function()
- local ret = oldSetHyperlink(self, link)
- if link and strfind(link, "item:") then
- Tooltip:AddInventoryInfo(self, link)
+ local _, _, inner = string.find(link or "", "|H(.+)|h")
+ local forwarded = link
+ local itemLinkForCounts = link
+ if inner then
+ forwarded = inner
+ if strfind(inner, "^item:") then
+ itemLinkForCounts = inner
+ end
end
+ local ret = oldSetHyperlink(self, forwarded)
+ if itemLinkForCounts and strfind(itemLinkForCounts, "item:") then
+ Tooltip:AddInventoryInfo(self, itemLinkForCounts)
+ end
+
return ret
end)
end
diff --git a/Data/BagScanner.lua b/Data/BagScanner.lua
index 13b308a..05cc15c 100644
--- a/Data/BagScanner.lua
+++ b/Data/BagScanner.lua
@@ -104,17 +104,17 @@ function BagScanner:Initialize()
-- Create event frame for bag updates
local eventFrame = CreateFrame("Frame")
self.eventFrame = eventFrame
-
+
-- Register bag update events
eventFrame:RegisterEvent("BAG_UPDATE")
eventFrame:RegisterEvent("BAG_UPDATE_DELAYED")
-
+
eventFrame:SetScript("OnEvent", function()
if event == "BAG_UPDATE" or event == "BAG_UPDATE_DELAYED" then
addon:Debug("Bag update detected, saving data...")
self:SaveToDatabase()
end
end)
-
+
addon:Debug("Bag scanner initialized with auto-save")
end
\ No newline at end of file
diff --git a/Guda.toc b/Guda.toc
index 550365c..037f9e7 100644
--- a/Guda.toc
+++ b/Guda.toc
@@ -2,7 +2,7 @@
## Title: Guda
## Notes: All-in-one bag and bank addon for Turtle WoW
## Author: Vati
-## Version: 1.1.2
+## Version: 1.1.3
## SavedVariables: Guda_DB
## SavedVariablesPerCharacter: Guda_CharDB
@@ -25,7 +25,6 @@ Sorting\SortEngine.lua
UI\ItemButton.lua
UI\BagFrame.lua
UI\BankFrame.lua
-UI\MoneyDisplay.lua
UI\SettingsPopup.lua
UI\ItemButton.xml
diff --git a/UI/BagFrame.lua b/UI/BagFrame.lua
index 6b94cf7..30c6d42 100644
--- a/UI/BagFrame.lua
+++ b/UI/BagFrame.lua
@@ -11,725 +11,785 @@ local searchText = ""
local itemButtons = {}
local showKeyring = false -- Toggle for keyring display
local hiddenBags = {} -- Track which bags are hidden (bagID -> true/false)
+local bagParents = {} -- Per-bag parent frames to carry bagID for Blizzard item button templates
-- 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")
+ 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",
- }
+ -- 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"
+ 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
+-- 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()
+ -- 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()
- Guda_BagFrame_ClearSearch()
- end)
- end
+ clickCatcher:SetScript("OnMouseDown", function()
+ Guda_BagFrame_ClearSearch()
+ end)
+ end
end
-- OnShow
function Guda_BagFrame_OnShow(self)
- -- Save bag data when opening bags
- addon.Modules.BagScanner:SaveToDatabase()
- addon.Modules.MoneyTracker:Update()
+-- 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
+ -- 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
+ -- Set lock state when frame is shown (ensures all child frames are loaded)
+ if BagFrame.UpdateLockState then
+ BagFrame:UpdateLockState()
+ end
- -- Apply border visibility setting
- if BagFrame.UpdateBorderVisibility then
- BagFrame:UpdateBorderVisibility()
- end
+ -- Apply border visibility setting
+ if BagFrame.UpdateBorderVisibility then
+ BagFrame:UpdateBorderVisibility()
+ end
- -- Apply search bar visibility setting
- if BagFrame.UpdateSearchBarVisibility then
- BagFrame:UpdateSearchBarVisibility()
- end
+ -- Apply search bar visibility setting
+ if BagFrame.UpdateSearchBarVisibility then
+ BagFrame:UpdateSearchBarVisibility()
+ end
- BagFrame:Update()
+ BagFrame:Update()
end
-- OnHide
function Guda_BagFrame_OnHide(self)
- -- Only release buttons that belong to this frame
- local itemContainer = getglobal("Guda_BagFrame_ItemContainer")
- if itemContainer then
- local children = { itemContainer:GetChildren() }
- for _, child in ipairs(children) do
- if child.hasItem ~= nil then -- It's an item button
- child:Hide()
- child:ClearAllPoints()
- end
- end
- end
+ -- Clean up all buttons when frame is hidden (safe since we're not displaying)
+ for _, bagParent in pairs(bagParents) do
+ if bagParent then
+ local buttons = { bagParent:GetChildren() }
+ for _, button in ipairs(buttons) do
+ if button.hasItem ~= nil then
+ button:Hide()
+ button:ClearAllPoints()
+ end
+ end
+ end
+ end
end
-- Toggle visibility
function BagFrame:Toggle()
- if Guda_BagFrame:IsShown() then
- Guda_BagFrame:Hide()
- else
- Guda_BagFrame:Show()
- end
+ 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()
+ currentViewChar = fullName
+ self:Update()
end
-- Show current character
function BagFrame:ShowCurrentCharacter()
- currentViewChar = nil
- self:Update()
+ currentViewChar = nil
+ self:Update()
+end
+
+-- Update lock states of existing buttons (lightweight, used during drag)
+function BagFrame:UpdateLockStates()
+ for _, bagParent in pairs(bagParents) do
+ if bagParent then
+ local buttons = { bagParent:GetChildren() }
+ for _, button in ipairs(buttons) do
+ if button.hasItem ~= nil and button:IsShown() and button.bagID and button.slotID then
+ -- Get live lock state
+ local _, _, locked = GetContainerItemInfo(button.bagID, button.slotID)
+ -- Update desaturation (gray out locked items)
+ if not button.otherChar and not button.isReadOnly and SetItemButtonDesaturated then
+ SetItemButtonDesaturated(button, locked, 0.5, 0.5, 0.5)
+ end
+ end
+ end
+ end
+ end
end
-- Update display
function BagFrame:Update()
- if not Guda_BagFrame:IsShown() then
- return
- end
+ if not Guda_BagFrame:IsShown() then
+ return
+ end
- -- Only release buttons that belong to this frame
- local itemContainer = getglobal("Guda_BagFrame_ItemContainer")
- if itemContainer then
- local children = { itemContainer:GetChildren() }
- for _, child in ipairs(children) do
- if child.hasItem ~= nil then -- It's an item button
- child:Hide()
- child:ClearAllPoints()
- end
- end
- end
+ -- If cursor is holding an item (mid-drag), only update lock states, don't rebuild UI
+ if CursorHasItem and CursorHasItem() then
+ self:UpdateLockStates()
+ return
+ end
- local bagData
- local isOtherChar = false
- local charName = ""
+ -- Mark all existing buttons as not in use (we'll mark active ones during display)
+ for _, bagParent in pairs(bagParents) do
+ if bagParent then
+ local buttons = { bagParent:GetChildren() }
+ for _, button in ipairs(buttons) do
+ if button.hasItem ~= nil then
+ button.inUse = false
+ end
+ end
+ end
+ end
- local titleFont = getglobal("Guda_BagFrame_Title")
- local displayName
+ local bagData
+ local isOtherChar = false
+ local charName = ""
- if currentViewChar then
- -- Viewing another character
- bagData = addon.Modules.DB:GetCharacterBags(currentViewChar)
- isOtherChar = true
- charName = currentViewChar
+ local titleFont = getglobal("Guda_BagFrame_Title")
+ local displayName
- 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 currentViewChar then
+ -- Viewing another character
+ bagData = addon.Modules.DB:GetCharacterBags(currentViewChar)
+ isOtherChar = true
+ charName = currentViewChar
- if titleFont and displayName then
- titleFont:SetText(string.format("%s's Bags", displayName))
- end
+ 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
- -- Display items
- self:DisplayItems(bagData, isOtherChar, charName)
+ if titleFont and displayName then
+ titleFont:SetText(string.format("%s's Bags", displayName))
+ end
- -- Update money
- self:UpdateMoney()
+ -- Display items
+ self:DisplayItems(bagData, isOtherChar, charName)
- -- Update bag slots info
- self:UpdateBagSlotsInfo(bagData, isOtherChar)
+ -- Update money
+ self:UpdateMoney()
+
+ -- Update bag slots info
+ self:UpdateBagSlotsInfo(bagData, isOtherChar)
+
+ -- Clean up unused buttons AFTER display is complete (prevents drag/drop issues)
+ for _, bagParent in pairs(bagParents) do
+ if bagParent then
+ local buttons = { bagParent:GetChildren() }
+ for _, button in ipairs(buttons) do
+ if button.hasItem ~= nil and not button.inUse then
+ button:Hide()
+ button:ClearAllPoints()
+ end
+ end
+ end
+ end
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")
+ 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")
- -- Separate bags into regular, soul, and ammo/quiver types
- local regularBags = {}
- local soulBags = {}
- local ammoQuiverBags = {}
+ -- Separate bags into regular, soul, and ammo/quiver types
+ local regularBags = {}
+ local soulBags = {}
+ local ammoQuiverBags = {}
- for _, bagID in ipairs(addon.Constants.BAGS) do
- -- Skip hidden bags
- if not hiddenBags[bagID] then
- local bagType
- if isOtherChar then
- -- For other characters, use saved bag type
- local bag = bagData[bagID]
- bagType = bag and bag.bagType or "regular"
- else
- -- For current character, detect bag type in real-time
- if addon.Modules.Utils:IsSoulBag(bagID) then
- bagType = "soul"
- elseif addon.Modules.Utils:IsAmmoQuiverBag(bagID) then
- bagType = "ammo"
- else
- bagType = "regular"
- end
- end
+ for _, bagID in ipairs(addon.Constants.BAGS) do
+ -- Skip hidden bags
+ if not hiddenBags[bagID] then
+ local bagType
+ if isOtherChar then
+ -- For other characters, use saved bag type
+ local bag = bagData[bagID]
+ bagType = bag and bag.bagType or "regular"
+ else
+ -- For current character, detect bag type in real-time
+ if addon.Modules.Utils:IsSoulBag(bagID) then
+ bagType = "soul"
+ elseif addon.Modules.Utils:IsAmmoQuiverBag(bagID) then
+ bagType = "ammo"
+ else
+ bagType = "regular"
+ end
+ end
- if bagType == "soul" then
- table.insert(soulBags, bagID)
- elseif bagType == "ammo" then
- table.insert(ammoQuiverBags, bagID)
- else
- table.insert(regularBags, bagID)
- end
- end
- end
+ if bagType == "soul" then
+ table.insert(soulBags, bagID)
+ elseif bagType == "ammo" then
+ table.insert(ammoQuiverBags, bagID)
+ else
+ table.insert(regularBags, bagID)
+ end
+ end
+ end
- -- Build display order: regular bags -> soul bags -> ammo/quiver bags -> keyring
- local bagsToShow = {}
- for _, bagID in ipairs(regularBags) do
- table.insert(bagsToShow, {bagID = bagID, needsSpacing = false})
- end
+ -- Build display order: regular bags -> soul bags -> ammo/quiver bags -> keyring
+ local bagsToShow = {}
+ for _, bagID in ipairs(regularBags) do
+ table.insert(bagsToShow, {bagID = bagID, needsSpacing = false})
+ end
- -- Add soul bags with spacing marker
- if table.getn(soulBags) > 0 then
- for i, bagID in ipairs(soulBags) do
- table.insert(bagsToShow, {bagID = bagID, needsSpacing = (i == 1)})
- end
- end
+ -- Add soul bags with spacing marker
+ if table.getn(soulBags) > 0 then
+ for i, bagID in ipairs(soulBags) do
+ table.insert(bagsToShow, {bagID = bagID, needsSpacing = (i == 1)})
+ end
+ end
- -- Add ammo/quiver bags with spacing marker
- if table.getn(ammoQuiverBags) > 0 then
- for i, bagID in ipairs(ammoQuiverBags) do
- table.insert(bagsToShow, {bagID = bagID, needsSpacing = (i == 1)})
- end
- end
+ -- Add ammo/quiver bags with spacing marker
+ if table.getn(ammoQuiverBags) > 0 then
+ for i, bagID in ipairs(ammoQuiverBags) do
+ table.insert(bagsToShow, {bagID = bagID, needsSpacing = (i == 1)})
+ end
+ end
- -- Add keyring at the end if toggled on and not hidden
- if showKeyring and not hiddenBags[-2] then
- table.insert(bagsToShow, {bagID = -2, needsSpacing = true})
- end
+ -- Add keyring at the end if toggled on and not hidden
+ if showKeyring and not hiddenBags[-2] then
+ table.insert(bagsToShow, {bagID = -2, needsSpacing = true})
+ end
- for _, bagInfo in ipairs(bagsToShow) do
- local bagID = bagInfo.bagID
- local bag = bagData[bagID]
+ for _, bagInfo in ipairs(bagsToShow) do
+ local bagID = bagInfo.bagID
+ local bag = bagData[bagID]
- -- Add spacing before soul, ammo/quiver, or keyring sections
- if bagInfo.needsSpacing then
- if col > 0 then
- -- Move to next row if not at start of row
- col = 0
- row = row + 1
- end
- -- Add extra spacing (0.5 row for tighter spacing)
- row = row + 0.5
- end
+ -- Add spacing before soul, ammo/quiver, or keyring sections
+ if bagInfo.needsSpacing then
+ if col > 0 then
+ -- Move to next row if not at start of row
+ col = 0
+ row = row + 1
+ end
+ -- Add extra spacing (0.5 row for tighter spacing)
+ row = row + 0.5
+ 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
+ -- 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
+ -- Only show bags that have slots
+ if numSlots and numSlots > 0 then
+ -- Iterate through ALL slots (1 to numSlots) to show empty slots too
+ -- Ensure a per-bag parent frame exists and carries the bag ID (Blizzard expects parent:GetID() == bagID)
+ local bagParent
+ do
+ if not bagParents[bagID] then
+ bagParents[bagID] = CreateFrame("Frame", "Guda_BagFrame_BagParent"..bagID, itemContainer)
+ bagParents[bagID]:SetAllPoints(itemContainer)
+ if bagParents[bagID].SetID then
+ bagParents[bagID]:SetID(bagID)
+ end
+ end
+ bagParent = bagParents[bagID]
+ end
- -- Check if item matches search filter
- local matchesFilter = self:PassesSearchFilter(itemData)
+ for slot = 1, numSlots do
+ local itemData = bag and bag.slots and bag.slots[slot] or nil
- local button = Guda_GetItemButton(itemContainer)
+ -- Check if item matches search filter
+ local matchesFilter = self:PassesSearchFilter(itemData)
- -- Position button
- local xPos = x + (col * (buttonSize + spacing))
- local yPos = y - (row * (buttonSize + spacing))
+ local button = Guda_GetItemButton(bagParent)
+ button.inUse = true -- Mark this button as actively in use
- button:ClearAllPoints()
- button:SetPoint("TOPLEFT", itemContainer, "TOPLEFT", xPos, yPos)
+ -- Position button
+ local xPos = x + (col * (buttonSize + spacing))
+ local yPos = y - (row * (buttonSize + spacing))
- -- Set item data with filter match info
- Guda_ItemButton_SetItem(button, bagID, slot, itemData, false, isOtherChar and charName or nil, matchesFilter)
+ button:ClearAllPoints()
+ button:SetPoint("TOPLEFT", itemContainer, "TOPLEFT", xPos, yPos)
- table.insert(itemButtons, button)
+ -- Set item data with filter match info
+ -- isReadOnly = true when viewing other characters (can't interact with their items)
+ Guda_ItemButton_SetItem(button, bagID, slot, itemData, false, isOtherChar and charName or nil, matchesFilter, isOtherChar)
- -- Advance position
- col = col + 1
- if col >= perRow then
- col = 0
- row = row + 1
- end
- end
- end
- end
+ 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)
+
+ -- Ensure cooldown visuals are current after (re)building buttons
+ if self.RefreshCooldowns then
+ self:RefreshCooldowns()
+ end
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
+ 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
+ -- Calculate actual number of rows used
+ local totalRows = currentRow + 1
- -- Ensure at least 1 row
- if totalRows < 1 then
- totalRows = 1
- end
+ -- 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
+ -- Calculate required dimensions based on columns
+ local containerWidth = (columns * (buttonSize + spacing)) + 20
+ local containerHeight = (totalRows * (buttonSize + spacing)) + 20
+ local frameWidth = containerWidth + 20
- -- Check if search bar is visible
- local showSearchBar = addon.Modules.DB:GetSetting("showSearchBar")
- if showSearchBar == nil then
- showSearchBar = true
- end
+ -- Check if search bar is visible
+ local showSearchBar = addon.Modules.DB:GetSetting("showSearchBar")
+ if showSearchBar == nil then
+ showSearchBar = true
+ end
- -- Adjust frame height based on search bar visibility
- -- Footer height varies: more space needed when search bar is visible
- local titleHeight = 40
- local searchBarHeight = 30
- local footerHeight
- local frameHeight
- if showSearchBar then
- footerHeight = 55 -- Increased footer height when search bar is visible (toolbar 40px + spacing 15px)
- frameHeight = containerHeight + titleHeight + searchBarHeight + footerHeight -- 125 total
- else
- footerHeight = 45 -- Normal footer height (toolbar 40px + spacing 5px)
- frameHeight = containerHeight + titleHeight + footerHeight -- 85 total
- end
+ -- Adjust frame height based on search bar visibility
+ -- Footer height varies: more space needed when search bar is visible
+ local titleHeight = 40
+ local searchBarHeight = 30
+ local footerHeight
+ local frameHeight
+ if showSearchBar then
+ footerHeight = 55 -- Increased footer height when search bar is visible (toolbar 40px + spacing 15px)
+ frameHeight = containerHeight + titleHeight + searchBarHeight + footerHeight -- 125 total
+ else
+ footerHeight = 45 -- Normal footer height (toolbar 40px + spacing 5px)
+ frameHeight = containerHeight + titleHeight + footerHeight -- 85 total
+ end
- -- 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
+ -- 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
+ -- 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")
+ -- Resize frames
+ local bagFrame = getglobal("Guda_BagFrame")
+ local itemContainer = getglobal("Guda_BagFrame_ItemContainer")
- if bagFrame then
- bagFrame:SetWidth(frameWidth)
- bagFrame:SetHeight(frameHeight)
+ if bagFrame then
+ bagFrame:SetWidth(frameWidth)
+ bagFrame:SetHeight(frameHeight)
- -- Always use BOTTOMRIGHT anchor to make frame grow left
- bagFrame:ClearAllPoints()
+ -- 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 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
+ 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
+ -- 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
+ 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"
+ 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
+-- 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
+ -- 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
+ -- 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
+ 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)
+ -- 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
+ -- 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
- self.foundFirstMatch = true
- end
+ -- Debug: print first match found
+ if matches and not self.foundFirstMatch then
+ self.foundFirstMatch = true
+ end
- return matches
+ return matches
end
function BagFrame:UpdateMoney()
- local moneyFrame = getglobal("Guda_BagFrame_MoneyFrame")
+ local moneyFrame = getglobal("Guda_BagFrame_MoneyFrame")
- if not moneyFrame then
- addon:Debug("Guda_BagFrame exists: " .. tostring(getglobal("Guda_BagFrame") ~= nil))
+ if not moneyFrame then
+ addon:Debug("Guda_BagFrame exists: " .. tostring(getglobal("Guda_BagFrame") ~= nil))
- -- Try to create it manually
- self:CreateMoneyFrame()
- moneyFrame = getglobal("Guda_BagFrame_MoneyFrame")
- end
+ -- Try to create it manually
+ self:CreateMoneyFrame()
+ moneyFrame = getglobal("Guda_BagFrame_MoneyFrame")
+ end
- if moneyFrame then
- MoneyFrame_Update("Guda_BagFrame_MoneyFrame", GetMoney())
- moneyFrame:Show()
+ if moneyFrame then
+ MoneyFrame_Update("Guda_BagFrame_MoneyFrame", GetMoney())
+ moneyFrame:Show()
- -- Ensure tooltip overlay exists
- self:EnsureMoneyTooltipOverlay()
+ -- 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
+ -- 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 infoText = getglobal("Guda_BagFrame_Toolbar_BagSlotsInfo_Text")
+ if not infoText then return end
- local totalSlots = 0
- local usedSlots = 0
+ 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]
+ -- 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
+ -- 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
+ 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
+ -- 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
- -- Format: "24 / 80" (used / total)
- infoText:SetText(string.format("%d / %d", usedSlots, totalSlots))
- infoText:SetTextColor(0.7, 0.7, 0.7)
+ -- Format: "24 / 80" (used / total)
+ infoText:SetText(string.format("%d / %d", usedSlots, 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")
+ 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
+ local toolbar = getglobal("Guda_BagFrame_Toolbar")
+ if not toolbar then return end
- -- Only set up once
- if toolbar.tooltipSetup 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")
+ -- 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
+ -- 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)
+ -- 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)
+ -- 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")
+ toolbar.tooltipSetup = true
+ addon:Debug("Toolbar tooltip handlers set up")
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
+ 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()
+ -- 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
+ 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
+ addon.Modules.DB:SetSetting("bagFramePosition", {
+ point = "BOTTOMRIGHT",
+ x = xOffset,
+ y = yOffset
+ })
+ end
end
-- Create transparent overlay for money tooltip
function BagFrame:EnsureMoneyTooltipOverlay()
- local overlayName = "Guda_BagFrame_MoneyTooltipOverlay"
- local overlay = getglobal(overlayName)
+ 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
+ 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)
+ -- 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)
+ -- 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)
+ 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
+ -- 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")
+ 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)
+ 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")
+ 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)
+ if bagFrame and not isLocked then
+ bagFrame:StopMovingOrSizing()
+ SaveBagFramePosition()
+ end
+ end)
- addon:Debug("Money tooltip overlay created")
- end
+ addon:Debug("Money tooltip overlay created")
+ end
- overlay:Show()
+ overlay:Show()
end
-- Money frame OnLoad handler
function Guda_BagFrame_MoneyFrame_OnLoad(self)
- addon:Debug("MoneyFrame OnLoad called for: " .. self:GetName())
+ addon:Debug("MoneyFrame OnLoad called for: " .. self:GetName())
- -- Set tooltip handlers on all money denomination buttons
- local buttons = {"GoldButton", "SilverButton", "CopperButton"}
+ -- 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
+ 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)
+ -- 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
+ 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()
+ -- 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 (realm filtered, all factions)
- local chars = addon.Modules.DB:GetAllCharacters(false, true)
- local totalMoney = addon.Modules.DB:GetTotalMoney(false, true)
+ -- Get all characters and total (realm filtered, all factions)
+ local chars = addon.Modules.DB:GetAllCharacters(false, true)
+ local totalMoney = addon.Modules.DB:GetTotalMoney(false, true)
- -- Header with current realm total - use colored money
- GameTooltip:AddLine(
- "Current realm gold: " .. addon.Modules.Utils:FormatMoney(totalMoney, false, true),
- 1, 0.82, 0
- )
- GameTooltip:AddLine(" ")
+ -- Header with current realm total - use colored money
+ GameTooltip:AddLine(
+ "Current realm 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
+ -- 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
+ 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)
+ -- 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:AddLine(
+ coloredName .. ": " .. addon.Modules.Utils:FormatMoney(char.money or 0, false, true)
+ )
+ end
- GameTooltip:Show()
+ GameTooltip:Show()
end
-- Dropdown management
@@ -738,1135 +798,1168 @@ local bankDropdown = nil
-- Toggle character dropdown
function Guda_BagFrame_ToggleCharacterDropdown(button)
- -- Hide bank dropdown if it's shown
- if bankDropdown and bankDropdown:IsShown() then
- bankDropdown:Hide()
- end
+-- Hide bank dropdown if it's shown
+ if bankDropdown and bankDropdown:IsShown() then
+ bankDropdown:Hide()
+ end
- if characterDropdown and characterDropdown:IsShown() then
- characterDropdown:Hide()
- return
- end
+ 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()
+ 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
+ characterDropdown.buttons = {}
+ end
- -- Position dropdown below the button
- characterDropdown:ClearAllPoints()
- characterDropdown:SetPoint("TOPLEFT", button, "BOTTOMLEFT", 0, -2)
+ -- 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 = {}
+ -- Clear existing buttons
+ for _, btn in ipairs(characterDropdown.buttons) do
+ btn:Hide()
+ end
+ characterDropdown.buttons = {}
- -- Get all characters on current realm
- local chars = addon.Modules.DB:GetAllCharacters(false, true)
+ -- Get all characters on current realm
+ local chars = addon.Modules.DB:GetAllCharacters(false, 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)
+ -- 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 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 text
+ local currentCharText = currentCharButton:CreateFontString(nil, "ARTWORK", "GameFontHighlight")
+ currentCharText:SetPoint("LEFT", currentCharButton, "LEFT", 8, 0)
+ currentCharText:SetText("Characters")
- -- 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)
+ -- 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
+ 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
+ -- 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()
+ -- 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)
+ -- 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)
+ 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)
+ -- 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
+ -- 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)
+ -- 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)
+ -- 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)
+ -- 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
+ table.insert(characterDropdown.buttons, charButton)
+ yOffset = yOffset - 20
+ end
- -- Set dropdown height based on content
- characterDropdown:SetHeight(math.abs(yOffset) + 8)
+ -- Set dropdown height based on content
+ characterDropdown:SetHeight(math.abs(yOffset) + 8)
- -- Show dropdown
- characterDropdown:Show()
+ -- Show dropdown
+ characterDropdown:Show()
end
-- Hide dropdown when clicking elsewhere
local function HideCharacterDropdown()
- if characterDropdown then
- characterDropdown:Hide()
- end
+ if characterDropdown then
+ characterDropdown:Hide()
+ end
end
-- Toggle bank dropdown
function Guda_BagFrame_ToggleBankDropdown(button)
- -- Hide character dropdown if it's shown
- if characterDropdown and characterDropdown:IsShown() then
- characterDropdown:Hide()
- end
+-- Hide character dropdown if it's shown
+ if characterDropdown and characterDropdown:IsShown() then
+ characterDropdown:Hide()
+ end
- if bankDropdown and bankDropdown:IsShown() then
- bankDropdown:Hide()
- return
- end
+ if bankDropdown and bankDropdown:IsShown() then
+ bankDropdown:Hide()
+ return
+ end
- if not bankDropdown then
- -- Create dropdown frame
- bankDropdown = CreateFrame("Frame", "Guda_BankDropdown", UIParent)
- bankDropdown:SetFrameStrata("DIALOG")
- bankDropdown:SetWidth(200)
- bankDropdown: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 }
- })
- bankDropdown:SetBackdropColor(0, 0, 0, 0.95)
- bankDropdown:EnableMouse(true)
- bankDropdown:Hide()
+ if not bankDropdown then
+ -- Create dropdown frame
+ bankDropdown = CreateFrame("Frame", "Guda_BankDropdown", UIParent)
+ bankDropdown:SetFrameStrata("DIALOG")
+ bankDropdown:SetWidth(200)
+ bankDropdown: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 }
+ })
+ bankDropdown:SetBackdropColor(0, 0, 0, 0.95)
+ bankDropdown:EnableMouse(true)
+ bankDropdown:Hide()
- bankDropdown.buttons = {}
- end
+ bankDropdown.buttons = {}
+ end
- -- Position dropdown below the button
- bankDropdown:ClearAllPoints()
- bankDropdown:SetPoint("TOPLEFT", button, "BOTTOMLEFT", 0, -2)
+ -- Position dropdown below the button
+ bankDropdown:ClearAllPoints()
+ bankDropdown:SetPoint("TOPLEFT", button, "BOTTOMLEFT", 0, -2)
+ -- Clear existing buttons
+ for _, btn in ipairs(bankDropdown.buttons) do
+ btn:Hide()
+ end
+ bankDropdown.buttons = {}
- -- Clear existing buttons
- for _, btn in ipairs(bankDropdown.buttons) do
- btn:Hide()
- end
- bankDropdown.buttons = {}
+ -- Get all characters on current realm
+ local chars = addon.Modules.DB:GetAllCharacters(false, true)
- -- Get all characters on current realm
- local chars = addon.Modules.DB:GetAllCharacters(false, true)
+ local yOffset = -8
- local yOffset = -8
+ -- 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
- -- 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 charButton = CreateFrame("Button", nil, bankDropdown)
+ charButton:SetWidth(188)
+ charButton:SetHeight(20)
+ charButton:SetPoint("TOP", bankDropdown, "TOP", 0, yOffset)
- local charButton = CreateFrame("Button", nil, bankDropdown)
- charButton:SetWidth(188)
- charButton:SetHeight(20)
- charButton:SetPoint("TOP", bankDropdown, "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)
- -- 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
- -- 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)
- -- 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)
- -- 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
+ -- Show bank for this character
+ Guda_BagFrame_ShowCharacterBank(charFullName, charName)
+ bankDropdown:Hide()
+ else
+ addon:Print("Error: Character fullName is nil")
+ end
+ end)
- -- 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
- -- Show bank for this character
- Guda_BagFrame_ShowCharacterBank(charFullName, charName)
- bankDropdown:Hide()
- else
- addon:Print("Error: Character fullName is nil")
- end
- end)
+ table.insert(bankDropdown.buttons, charButton)
+ yOffset = yOffset - 20
+ end
- table.insert(bankDropdown.buttons, charButton)
- yOffset = yOffset - 20
- end
+ -- Set dropdown height based on content
+ bankDropdown:SetHeight(math.abs(yOffset) + 8)
- -- Set dropdown height based on content
- bankDropdown:SetHeight(math.abs(yOffset) + 8)
-
- -- Show dropdown
- bankDropdown:Show()
+ -- Show dropdown
+ bankDropdown:Show()
end
-- Show character's bank
function Guda_BagFrame_ShowCharacterBank(fullName, displayName)
- -- Use the existing BankFrame module
- if not addon.Modules.BankFrame then
- addon:Print("Bank frame module not available")
- return
- end
+-- Use the existing BankFrame module
+ if not addon.Modules.BankFrame then
+ addon:Print("Bank frame module not available")
+ return
+ end
- -- Position bank frame at center of screen
- if Guda_BankFrame then
- Guda_BankFrame:ClearAllPoints()
- Guda_BankFrame:SetPoint("CENTER", UIParent, "CENTER", 0, 0)
- end
+ -- Position bank frame at center of screen
+ if Guda_BankFrame then
+ Guda_BankFrame:ClearAllPoints()
+ Guda_BankFrame:SetPoint("CENTER", UIParent, "CENTER", 0, 0)
+ end
- -- Show the character's bank
- addon.Modules.BankFrame:ShowCharacter(fullName)
+ -- Show the character's bank
+ addon.Modules.BankFrame:ShowCharacter(fullName)
- -- Make sure frame is shown
- if Guda_BankFrame then
- Guda_BankFrame:Show()
- end
+ -- Make sure frame is shown
+ if Guda_BankFrame then
+ Guda_BankFrame:Show()
+ end
end
-- Clear search and restore placeholder
function Guda_BagFrame_ClearSearch()
- local searchBox = getglobal("Guda_BagFrame_SearchBar_SearchBox")
- if searchBox then
- searchBox:SetText("Search, try ~equipment")
- searchBox:SetTextColor(0.5, 0.5, 0.5, 1)
- searchBox:ClearFocus()
- end
+ local searchBox = getglobal("Guda_BagFrame_SearchBar_SearchBox")
+ if searchBox then
+ searchBox:SetText("Search, try ~equipment")
+ searchBox:SetTextColor(0.5, 0.5, 0.5, 1)
+ searchBox:ClearFocus()
+ end
- -- Reset search state
- searchText = ""
- BagFrame.foundFirstMatch = false
- BagFrame.warnedAboutParsing = false
- BagFrame.warnedAboutNoName = false
+ -- Reset search state
+ searchText = ""
+ BagFrame.foundFirstMatch = false
+ BagFrame.warnedAboutParsing = false
+ BagFrame.warnedAboutNoName = false
- -- Update display
- BagFrame:Update()
+ -- Update display
+ BagFrame:Update()
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
- BagFrame:Update()
- end
+ 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
+ BagFrame:Update()
+ end
end
-- Keyring toggle handler
function Guda_BagFrame_ToggleKeyring()
- showKeyring = not showKeyring
+ 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
+ -- 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()
+ -- Refresh display
+ BagFrame:Update()
end
-- Sort button handler with auto-repeat and smart pass calculation
function Guda_BagFrame_Sort()
- if currentViewChar then
- addon:Print("Cannot sort another character's bags!")
- return
- end
+ if currentViewChar then
+ addon:Print("Cannot sort another character's bags!")
+ return
+ end
- -- Analyze bags to determine how many passes are needed
- local analysis = addon.Modules.SortEngine:AnalyzeBags()
+ -- Analyze bags to determine how many passes are needed
+ local analysis = addon.Modules.SortEngine:AnalyzeBags()
- -- Check if already sorted
- if analysis.alreadySorted then
- addon:Print("Bags are already sorted!")
- return
- end
+ -- Check if already sorted
+ if analysis.alreadySorted then
+ addon:Print("Bags are already sorted!")
+ return
+ end
- -- Print analysis results
- addon:Print("Sorting bags... (%d/%d items need sorting, estimated %d passes)",
- analysis.itemsOutOfPlace, analysis.totalItems, analysis.passes)
+ -- Print analysis results
+ addon:Print("Sorting bags... (%d/%d items need sorting, estimated %d passes)",
+ analysis.itemsOutOfPlace, analysis.totalItems, analysis.passes)
- local passCount = 0
- local maxPasses = math.max(analysis.passes, 1) -- Use estimated passes, minimum 1
- local safetyLimit = maxPasses + 3 -- Add 3 extra passes as safety margin
+ local passCount = 0
+ local maxPasses = math.max(analysis.passes, 1) -- Use estimated passes, minimum 1
+ local safetyLimit = maxPasses + 3 -- Add 3 extra passes as safety margin
- local function DoSortPass()
- passCount = passCount + 1
+ local function DoSortPass()
+ passCount = passCount + 1
- -- Perform one sort pass
- local moveCount = addon.Modules.SortEngine:SortBags()
+ -- Perform one sort pass
+ local moveCount = addon.Modules.SortEngine:SortBags()
- -- If items were moved and we haven't hit the limit, do another pass
- if moveCount > 0 and passCount < safetyLimit then
- -- Wait for items to settle, then sort again
- local frame = CreateFrame("Frame")
- local elapsed = 0
- frame:SetScript("OnUpdate", function()
- elapsed = elapsed + arg1
- if elapsed >= 0.7 then
- frame:SetScript("OnUpdate", nil)
- DoSortPass() -- Recursive call for next pass
- end
- end)
- else
- -- Sorting complete
- if passCount >= safetyLimit then
- addon:Print("Sort complete! (reached safety limit after %d passes)", passCount)
- elseif passCount <= maxPasses then
- addon:Print("Sort complete! (%d passes, as predicted)", passCount)
- else
- addon:Print("Sort complete! (%d passes, %d more than estimated)", passCount, passCount - maxPasses)
- end
+ -- If items were moved and we haven't hit the limit, do another pass
+ if moveCount > 0 and passCount < safetyLimit then
+ -- Wait for items to settle, then sort again
+ local frame = CreateFrame("Frame")
+ local elapsed = 0
+ frame:SetScript("OnUpdate", function()
+ elapsed = elapsed + arg1
+ if elapsed >= 0.7 then
+ frame:SetScript("OnUpdate", nil)
+ DoSortPass() -- Recursive call for next pass
+ end
+ end)
+ else
+ -- Sorting complete
+ if passCount >= safetyLimit then
+ addon:Print("Sort complete! (reached safety limit after %d passes)", passCount)
+ elseif passCount <= maxPasses then
+ addon:Print("Sort complete! (%d passes, as predicted)", passCount)
+ else
+ addon:Print("Sort complete! (%d passes, %d more than estimated)", passCount, passCount - maxPasses)
+ end
- -- Final update
- local frame = CreateFrame("Frame")
- local elapsed = 0
- frame:SetScript("OnUpdate", function()
- elapsed = elapsed + arg1
- if elapsed >= 0.7 then
- frame:SetScript("OnUpdate", nil)
- BagFrame:Update()
- end
- end)
- end
- end
+ -- Final update
+ local frame = CreateFrame("Frame")
+ local elapsed = 0
+ frame:SetScript("OnUpdate", function()
+ elapsed = elapsed + arg1
+ if elapsed >= 0.7 then
+ frame:SetScript("OnUpdate", nil)
+ BagFrame:Update()
+ end
+ end)
+ end
+ end
- -- Start the first pass
- DoSortPass()
+ -- Start the first pass
+ DoSortPass()
end
-- Hook bag container buttons to open Guda Bag View
local function HookBagContainers()
- -- Hook the main bag container buttons (bags 1-4)
- for i = 1, 4 do
- local buttonName = "CharacterBag"..i.."Slot"
- local button = getglobal(buttonName)
+-- Hook the main bag container buttons (bags 1-4)
+ for i = 1, 4 do
+ local buttonName = "CharacterBag"..i.."Slot"
+ local button = getglobal(buttonName)
- if button then
- local originalOnClick = button:GetScript("OnClick")
- button:SetScript("OnClick", function()
- local mouseButton = arg1 or "LeftButton" -- Vanilla uses global arg1
- if mouseButton == "LeftButton" then
- -- Open Guda Bag View instead of default bag
- BagFrame:Toggle()
- else
- -- Allow right-click and other buttons to work normally
- if originalOnClick then
- originalOnClick()
- end
- end
- end)
- end
- end
+ if button then
+ local originalOnClick = button:GetScript("OnClick")
+ button:SetScript("OnClick", function()
+ local mouseButton = arg1 or "LeftButton" -- Vanilla uses global arg1
+ if mouseButton == "LeftButton" then
+ -- Open Guda Bag View instead of default bag
+ BagFrame:Toggle()
+ else
+ -- Allow right-click and other buttons to work normally
+ if originalOnClick then
+ originalOnClick()
+ end
+ end
+ end)
+ end
+ end
- -- Also hook the backpack button
- local backpackButton = getglobal("MainMenuBarBackpackButton")
- if backpackButton then
- local originalOnClick = backpackButton:GetScript("OnClick")
- backpackButton:SetScript("OnClick", function()
- local mouseButton = arg1 or "LeftButton" -- Vanilla uses global arg1
- if mouseButton == "LeftButton" then
- -- Open Guda Bag View instead of default bag
- BagFrame:Toggle()
- else
- -- Allow right-click and other buttons to work normally
- if originalOnClick then
- originalOnClick()
- end
- end
- end)
- end
+ -- Also hook the backpack button
+ local backpackButton = getglobal("MainMenuBarBackpackButton")
+ if backpackButton then
+ local originalOnClick = backpackButton:GetScript("OnClick")
+ backpackButton:SetScript("OnClick", function()
+ local mouseButton = arg1 or "LeftButton" -- Vanilla uses global arg1
+ if mouseButton == "LeftButton" then
+ -- Open Guda Bag View instead of default bag
+ BagFrame:Toggle()
+ else
+ -- Allow right-click and other buttons to work normally
+ if originalOnClick then
+ originalOnClick()
+ end
+ end
+ end)
+ end
- -- Hook keyring button if it exists
- local keyringButton = getglobal("KeyRingButton")
- if keyringButton then
- local originalOnClick = keyringButton:GetScript("OnClick")
- keyringButton:SetScript("OnClick", function()
- local mouseButton = arg1 or "LeftButton" -- Vanilla uses global arg1
- if mouseButton == "LeftButton" then
- -- Toggle keyring in Guda Bag View
- Guda_BagFrame_ToggleKeyring()
- BagFrame:Toggle() -- Also open the bag frame
- else
- -- Allow right-click and other buttons to work normally
- if originalOnClick then
- originalOnClick()
- end
- end
- end)
- end
+ -- Hook keyring button if it exists
+ local keyringButton = getglobal("KeyRingButton")
+ if keyringButton then
+ local originalOnClick = keyringButton:GetScript("OnClick")
+ keyringButton:SetScript("OnClick", function()
+ local mouseButton = arg1 or "LeftButton" -- Vanilla uses global arg1
+ if mouseButton == "LeftButton" then
+ -- Toggle keyring in Guda Bag View
+ Guda_BagFrame_ToggleKeyring()
+ BagFrame:Toggle() -- Also open the bag frame
+ else
+ -- Allow right-click and other buttons to work normally
+ if originalOnClick then
+ originalOnClick()
+ end
+ end
+ end)
+ end
end
-- Alternative approach: Completely replace the bag open functions
local function ReplaceBagOpenFunctions()
- -- Override OpenBag (if it exists)
- if OpenBag then
- local originalOpenBag = OpenBag
- function OpenBag(bagId)
- if bagId and bagId >= 0 and bagId <= 4 then
- -- For regular bags, open Guda Bag View
- BagFrame:Toggle()
- else
- -- For other containers, use original function
- if originalOpenBag then
- originalOpenBag(bagId)
- end
- end
- end
- end
+-- Override OpenBag (if it exists)
+ if OpenBag then
+ local originalOpenBag = OpenBag
+ function OpenBag(bagId)
+ if bagId and bagId >= 0 and bagId <= 4 then
+ -- For regular bags, open Guda Bag View
+ BagFrame:Toggle()
+ else
+ -- For other containers, use original function
+ if originalOpenBag then
+ originalOpenBag(bagId)
+ end
+ end
+ end
+ end
- -- Override ToggleBag (if it exists)
- if ToggleBag then
- local originalToggleBag = ToggleBag
- function ToggleBag(bagId)
- if bagId and bagId >= 0 and bagId <= 4 then
- -- For regular bags, toggle Guda Bag View
- BagFrame:Toggle()
- else
- -- For other containers, use original function
- if originalToggleBag then
- originalToggleBag(bagId)
- end
- end
- end
- end
+ -- Override ToggleBag (if it exists)
+ if ToggleBag then
+ local originalToggleBag = ToggleBag
+ function ToggleBag(bagId)
+ if bagId and bagId >= 0 and bagId <= 4 then
+ -- For regular bags, toggle Guda Bag View
+ BagFrame:Toggle()
+ else
+ -- For other containers, use original function
+ if originalToggleBag then
+ originalToggleBag(bagId)
+ end
+ end
+ end
+ end
end
-- Hook to default bag opening
local function HookDefaultBags()
- -- Override ToggleBackpack (if it exists)
- if ToggleBackpack then
- local originalToggleBackpack = ToggleBackpack
- function ToggleBackpack()
- BagFrame:Toggle()
- end
- end
+-- Override ToggleBackpack (if it exists)
+ if ToggleBackpack then
+ local originalToggleBackpack = ToggleBackpack
+ function ToggleBackpack()
+ BagFrame:Toggle()
+ end
+ end
- -- Override OpenAllBags (if it exists)
- if OpenAllBags then
- local originalOpenAllBags = OpenAllBags
- function OpenAllBags()
- Guda_BagFrame:Show()
- end
- end
+ -- Override OpenAllBags (if it exists)
+ if OpenAllBags then
+ local originalOpenAllBags = OpenAllBags
+ function OpenAllBags()
+ Guda_BagFrame:Show()
+ end
+ end
- -- Override CloseAllBags (if it exists)
- if CloseAllBags then
- local originalCloseAllBags = CloseAllBags
- function CloseAllBags()
- Guda_BagFrame:Hide()
- end
- end
+ -- Override CloseAllBags (if it exists)
+ if CloseAllBags then
+ local originalCloseAllBags = CloseAllBags
+ function CloseAllBags()
+ Guda_BagFrame:Hide()
+ end
+ end
- -- Hook individual bag opening functions (for bag slot buttons)
- ReplaceBagOpenFunctions()
+ -- Hook individual bag opening functions (for bag slot buttons)
+ ReplaceBagOpenFunctions()
- -- Hook the bag slot button clicks directly
- HookBagContainers()
+ -- Hook the bag slot button clicks directly
+ HookBagContainers()
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
+-- 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
+ 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
+ -- 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)
+ local success, isLocked = pcall(function()
+ return addon.Modules.DB:GetSetting("lockBags")
+ end)
- if not success then return end
+ if not success then return end
- if isLocked == nil then
- isLocked = false
- 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")
+ -- 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
+ 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 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 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
+ -- 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
+ 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
+ -- 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
+ 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
+ -- 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
+ 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
+ -- 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
+ 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
-- Update border visibility based on setting
function BagFrame:UpdateBorderVisibility()
- if not addon or not addon.Modules or not addon.Modules.DB then return end
+ if not addon or not addon.Modules or not addon.Modules.DB then return end
- local frame = getglobal("Guda_BagFrame")
- if not frame then return end
+ local frame = getglobal("Guda_BagFrame")
+ if not frame then return end
- local hideBorders = addon.Modules.DB:GetSetting("hideBorders")
- if hideBorders == nil then
- hideBorders = false
- end
+ local hideBorders = addon.Modules.DB:GetSetting("hideBorders")
+ if hideBorders == nil then
+ hideBorders = false
+ end
- -- Use helper function with constants
- if hideBorders then
- addon:ApplyBackdrop(frame, "MINIMALIST_BORDER", "DEFAULT")
- else
- addon:ApplyBackdrop(frame, "DEFAULT_FRAME", "DEFAULT")
- end
+ -- Use helper function with constants
+ if hideBorders then
+ addon:ApplyBackdrop(frame, "MINIMALIST_BORDER", "DEFAULT")
+ else
+ addon:ApplyBackdrop(frame, "DEFAULT_FRAME", "DEFAULT")
+ end
end
-- Update search bar visibility based on setting
function BagFrame:UpdateSearchBarVisibility()
- if not addon or not addon.Modules or not addon.Modules.DB then return end
+ if not addon or not addon.Modules or not addon.Modules.DB then return end
- local searchBar = getglobal("Guda_BagFrame_SearchBar")
- local itemContainer = getglobal("Guda_BagFrame_ItemContainer")
- if not searchBar or not itemContainer then return end
+ local searchBar = getglobal("Guda_BagFrame_SearchBar")
+ local itemContainer = getglobal("Guda_BagFrame_ItemContainer")
+ if not searchBar or not itemContainer then return end
- local showSearchBar = addon.Modules.DB:GetSetting("showSearchBar")
- if showSearchBar == nil then
- showSearchBar = true
- end
+ local showSearchBar = addon.Modules.DB:GetSetting("showSearchBar")
+ if showSearchBar == nil then
+ showSearchBar = true
+ end
- if showSearchBar then
- searchBar:Show()
- -- Anchor ItemContainer to SearchBar's bottom
- itemContainer:ClearAllPoints()
- itemContainer:SetPoint("TOP", searchBar, "BOTTOM", 0, -5)
- else
- searchBar:Hide()
- -- Anchor ItemContainer directly to frame top (skip search bar space)
- itemContainer:ClearAllPoints()
- itemContainer:SetPoint("TOP", "Guda_BagFrame", "TOP", 0, -40)
- end
+ if showSearchBar then
+ searchBar:Show()
+ -- Anchor ItemContainer to SearchBar's bottom
+ itemContainer:ClearAllPoints()
+ itemContainer:SetPoint("TOP", searchBar, "BOTTOM", 0, -5)
+ else
+ searchBar:Hide()
+ -- Anchor ItemContainer directly to frame top (skip search bar space)
+ itemContainer:ClearAllPoints()
+ itemContainer:SetPoint("TOP", "Guda_BagFrame", "TOP", 0, -40)
+ end
end
-- Bag Slot Button Handlers
-- OnLoad handler for bag slot buttons
function Guda_BagSlot_OnLoad(button, bagID)
- -- Hide borders from ItemButtonTemplate
- local buttonName = button:GetName()
+-- Hide borders from ItemButtonTemplate
+ local buttonName = button:GetName()
- -- Hide the normal texture border
- local normalTexture = getglobal(buttonName .. "NormalTexture")
- if normalTexture then
- normalTexture:SetTexture(nil)
- normalTexture:Hide()
- end
+ -- Hide the normal texture border
+ local normalTexture = getglobal(buttonName .. "NormalTexture")
+ if normalTexture then
+ normalTexture:SetTexture(nil)
+ normalTexture:Hide()
+ end
- -- Hide icon border
- local iconBorder = getglobal(buttonName .. "IconBorder")
- if iconBorder then
- iconBorder:Hide()
- end
+ -- Hide icon border
+ local iconBorder = getglobal(buttonName .. "IconBorder")
+ if iconBorder then
+ iconBorder:Hide()
+ end
- -- Set up the button with proper ID
- if bagID == 0 then
- -- Backpack (bag 0)
- button.bagID = 0
- button.hasItem = 1
- SetItemButtonTexture(button, "Interface\\Buttons\\Button-Backpack-Up")
- else
- -- Bags 1-4
- local invSlot = ContainerIDToInventoryID(bagID)
- button:SetID(invSlot)
- button.bagID = bagID
+ -- Set up the button with proper ID
+ if bagID == 0 then
+ -- Backpack (bag 0)
+ button.bagID = 0
+ button.hasItem = 1
+ SetItemButtonTexture(button, "Interface\\Buttons\\Button-Backpack-Up")
+ else
+ -- Bags 1-4
+ local invSlot = ContainerIDToInventoryID(bagID)
+ button:SetID(invSlot)
+ button.bagID = bagID
- -- REGISTER FOR DRAG - This is crucial for Classic
- button:RegisterForDrag("LeftButton")
-
- -- Register for updates
- button:RegisterEvent("BAG_UPDATE")
- button:RegisterEvent("ITEM_LOCK_CHANGED")
- button:RegisterEvent("CURSOR_UPDATE")
- button:RegisterEvent("UNIT_INVENTORY_CHANGED")
+ -- REGISTER FOR DRAG - This is crucial for Classic
+ button:RegisterForDrag("LeftButton")
- -- Accept drops (equip when a bag is dropped on this slot)
- button:SetScript("OnReceiveDrag", function()
- if this and this.bagID and this.bagID ~= 0 and CursorHasItem and CursorHasItem() then
- local inv = ContainerIDToInventoryID(this.bagID)
- if EquipCursorItem then
- EquipCursorItem(inv)
- elseif PutItemInBag then
- PutItemInBag(inv)
- end
- Guda_BagSlot_Update(this, this.bagID)
- if BagFrame and BagFrame.Update then BagFrame:Update() end
- end
- end)
- end
+ -- Register for updates
+ button:RegisterEvent("BAG_UPDATE")
+ button:RegisterEvent("ITEM_LOCK_CHANGED")
+ button:RegisterEvent("CURSOR_UPDATE")
+ button:RegisterEvent("UNIT_INVENTORY_CHANGED")
- -- Ensure we handle right-click toggling like BankFrame
- if button.RegisterForClicks then
- button:RegisterForClicks("LeftButtonUp", "RightButtonUp")
- end
+ -- Accept drops (equip when a bag is dropped on this slot)
+ button:SetScript("OnReceiveDrag", function()
+ if this and this.bagID and this.bagID ~= 0 and CursorHasItem and CursorHasItem() then
+ local inv = ContainerIDToInventoryID(this.bagID)
+ if EquipCursorItem then
+ EquipCursorItem(inv)
+ elseif PutItemInBag then
+ PutItemInBag(inv)
+ end
+ Guda_BagSlot_Update(this, this.bagID)
+ if BagFrame and BagFrame.Update then BagFrame:Update() end
+ end
+ end)
+ end
- -- Initial update
- Guda_BagSlot_Update(button, bagID)
+ -- Ensure we handle right-click toggling like BankFrame
+ if button.RegisterForClicks then
+ button:RegisterForClicks("LeftButtonUp", "RightButtonUp")
+ end
+
+ -- Initial update
+ Guda_BagSlot_Update(button, bagID)
end
function Guda_BagSlot_OnDragStart(frame, bagID)
- if bagID == 0 then return end
-
- -- Check if we should start dragging (only if there's an item)
- local invSlot = ContainerIDToInventoryID(bagID)
- local texture = GetInventoryItemTexture("player", invSlot)
-
- if texture then
- frame:SetAlpha(0.6)
- -- Immediate pickup for Classic
- PickupInventoryItem(invSlot)
- -- Instantly reflect the change in UI (slot is now empty on cursor pickup)
- Guda_BagSlot_Update(frame, bagID)
- if BagFrame and BagFrame.Update then BagFrame:Update() end
- end
- -- If no texture (empty slot), do nothing - drag won't start
+ if bagID == 0 then return end
+
+ -- Check if we should start dragging (only if there's an item)
+ local invSlot = ContainerIDToInventoryID(bagID)
+ local texture = GetInventoryItemTexture("player", invSlot)
+
+ if texture then
+ frame:SetAlpha(0.6)
+ -- Immediate pickup for Classic
+ PickupInventoryItem(invSlot)
+ -- Instantly reflect the change in UI (slot is now empty on cursor pickup)
+ Guda_BagSlot_Update(frame, bagID)
+ if BagFrame and BagFrame.Update then BagFrame:Update() end
+ end
+-- If no texture (empty slot), do nothing - drag won't start
end
function Guda_BagSlot_OnDragStop(frame, bagID)
- frame:SetAlpha(1.0)
+ frame:SetAlpha(1.0)
end
-- Update bag slot button texture
function Guda_BagSlot_Update(button, bagID)
- local isHidden = hiddenBags[bagID]
+ local isHidden = hiddenBags[bagID]
- if bagID == 0 then
- -- Backpack always has the same texture
- SetItemButtonTexture(button, "Interface\\Buttons\\Button-Backpack-Up")
- -- Dim if hidden
- if isHidden then
- SetItemButtonTextureVertexColor(button, 0.4, 0.4, 0.4)
- else
- SetItemButtonTextureVertexColor(button, 1.0, 1.0, 1.0)
- end
- return
- end
+ if bagID == 0 then
+ -- Backpack always has the same texture
+ SetItemButtonTexture(button, "Interface\\Buttons\\Button-Backpack-Up")
+ -- Dim if hidden
+ if isHidden then
+ SetItemButtonTextureVertexColor(button, 0.4, 0.4, 0.4)
+ else
+ SetItemButtonTextureVertexColor(button, 1.0, 1.0, 1.0)
+ end
+ return
+ end
- -- Get the inventory slot ID for this bag
- local invSlot = ContainerIDToInventoryID(bagID)
- local texture = GetInventoryItemTexture("player", invSlot)
+ -- Get the inventory slot ID for this bag
+ local invSlot = ContainerIDToInventoryID(bagID)
+ local texture = GetInventoryItemTexture("player", invSlot)
- if texture then
- -- Bag is equipped
- SetItemButtonTexture(button, texture)
- -- Dim if hidden
- if isHidden then
- SetItemButtonTextureVertexColor(button, 0.4, 0.4, 0.4)
- else
- SetItemButtonTextureVertexColor(button, 1.0, 1.0, 1.0)
- end
- else
- -- No bag in this slot
- SetItemButtonTexture(button, "Interface\\PaperDoll\\UI-PaperDoll-Slot-Bag")
- SetItemButtonTextureVertexColor(button, 0.5, 0.5, 0.5)
- end
+ if texture then
+ -- Bag is equipped
+ SetItemButtonTexture(button, texture)
+ -- Dim if hidden
+ if isHidden then
+ SetItemButtonTextureVertexColor(button, 0.4, 0.4, 0.4)
+ else
+ SetItemButtonTextureVertexColor(button, 1.0, 1.0, 1.0)
+ end
+ else
+ -- No bag in this slot
+ SetItemButtonTexture(button, "Interface\\PaperDoll\\UI-PaperDoll-Slot-Bag")
+ SetItemButtonTextureVertexColor(button, 0.5, 0.5, 0.5)
+ end
end
-- OnEvent handler
function Guda_BagSlot_OnEvent(button, event, arg1)
- local bagID = button.bagID
- if not bagID then
- return
- end
+ local bagID = button.bagID
+ if not bagID then
+ return
+ end
- if event == "BAG_UPDATE" then
- if arg1 == bagID then
- Guda_BagSlot_Update(button, bagID)
- end
- elseif event == "UNIT_INVENTORY_CHANGED" then
- if arg1 == "player" then
- Guda_BagSlot_Update(button, bagID)
- end
- elseif event == "ITEM_LOCK_CHANGED" or event == "CURSOR_UPDATE" then
- Guda_BagSlot_Update(button, bagID)
- end
+ if event == "BAG_UPDATE" then
+ if arg1 == bagID then
+ Guda_BagSlot_Update(button, bagID)
+ end
+ elseif event == "UNIT_INVENTORY_CHANGED" then
+ if arg1 == "player" then
+ Guda_BagSlot_Update(button, bagID)
+ end
+ elseif event == "ITEM_LOCK_CHANGED" or event == "CURSOR_UPDATE" then
+ Guda_BagSlot_Update(button, bagID)
+ end
end
-- OnClick handler
function Guda_BagSlot_OnClick(button, bagID)
- local which = arg1 -- Vanilla uses global arg1 for mouse button name
+ local which = arg1 -- Vanilla uses global arg1 for mouse button name
- -- Right-Click: toggle visibility
- if which == "RightButton" then
- hiddenBags[bagID] = not hiddenBags[bagID]
+ -- Right-Click: toggle visibility
+ if which == "RightButton" then
+ hiddenBags[bagID] = not hiddenBags[bagID]
- -- Update bag slot visual (dim/undim)
- Guda_BagSlot_Update(button, bagID)
+ -- Update bag slot visual (dim/undim)
+ Guda_BagSlot_Update(button, bagID)
- -- Refresh the bag display
- BagFrame:Update()
+ -- Refresh the bag display
+ BagFrame:Update()
- return
- end
+ return
+ end
- -- Left-Click: equip bag from cursor into this slot (bags 1-4 only)
- if which == "LeftButton" then
- if bagID ~= 0 and CursorHasItem and CursorHasItem() then
- local invSlot = ContainerIDToInventoryID(bagID)
- if EquipCursorItem then
- EquipCursorItem(invSlot)
- else
- if PutItemInBag then PutItemInBag(invSlot) end
- end
- -- Update visuals after attempted equip
- Guda_BagSlot_Update(button, bagID)
- BagFrame:Update()
- end
- return
- end
+ -- Left-Click: equip bag from cursor into this slot (bags 1-4 only)
+ if which == "LeftButton" then
+ if bagID ~= 0 and CursorHasItem and CursorHasItem() then
+ local invSlot = ContainerIDToInventoryID(bagID)
+ if EquipCursorItem then
+ EquipCursorItem(invSlot)
+ else
+ if PutItemInBag then PutItemInBag(invSlot) end
+ end
+ -- Update visuals after attempted equip
+ Guda_BagSlot_Update(button, bagID)
+ BagFrame:Update()
+ end
+ return
+ end
end
-- OnEnter handler for tooltip
function Guda_BagSlot_OnEnter(button, bagID)
- GameTooltip:SetOwner(button, "ANCHOR_TOP")
+ GameTooltip:SetOwner(button, "ANCHOR_TOP")
- if bagID == 0 then
- -- Backpack tooltip
- GameTooltip:SetText("Backpack", 1.0, 1.0, 1.0)
- local numSlots = GetContainerNumSlots(0)
- GameTooltip:AddLine(string.format("%d Slots", numSlots), 0.8, 0.8, 0.8)
- if hiddenBags[bagID] then
- GameTooltip:AddLine("(Hidden - Right-Click to show)", 0.8, 0.5, 0.5)
- else
- GameTooltip:AddLine("(Right-Click to hide)", 0.5, 0.8, 0.5)
- end
- else
- -- Bag slot tooltip
- local invSlot = ContainerIDToInventoryID(bagID)
- local hasItem = GetInventoryItemTexture("player", invSlot)
+ if bagID == 0 then
+ -- Backpack tooltip
+ GameTooltip:SetText("Backpack", 1.0, 1.0, 1.0)
+ local numSlots = GetContainerNumSlots(0)
+ GameTooltip:AddLine(string.format("%d Slots", numSlots), 0.8, 0.8, 0.8)
+ if hiddenBags[bagID] then
+ GameTooltip:AddLine("(Hidden - Right-Click to show)", 0.8, 0.5, 0.5)
+ else
+ GameTooltip:AddLine("(Right-Click to hide)", 0.5, 0.8, 0.5)
+ end
+ else
+ -- Bag slot tooltip
+ local invSlot = ContainerIDToInventoryID(bagID)
+ local hasItem = GetInventoryItemTexture("player", invSlot)
- if hasItem then
- -- Show bag item tooltip
- GameTooltip:SetInventoryItem("player", invSlot)
- if hiddenBags[bagID] then
- GameTooltip:AddLine("(Hidden - Right-Click to show)", 0.8, 0.5, 0.5)
- else
- GameTooltip:AddLine("(Right-Click to hide)", 0.5, 0.8, 0.5)
- end
- else
- -- Empty slot
- GameTooltip:SetText(string.format("Bag %d", bagID), 1.0, 1.0, 1.0)
- GameTooltip:AddLine("Empty", 0.5, 0.5, 0.5)
- if hiddenBags[bagID] then
- GameTooltip:AddLine("(Hidden - Right-Click to show)", 0.8, 0.5, 0.5)
- else
- GameTooltip:AddLine("(Right-Click to hide)", 0.5, 0.8, 0.5)
- end
- end
- end
+ if hasItem then
+ -- Show bag item tooltip
+ GameTooltip:SetInventoryItem("player", invSlot)
+ if hiddenBags[bagID] then
+ GameTooltip:AddLine("(Hidden - Right-Click to show)", 0.8, 0.5, 0.5)
+ else
+ GameTooltip:AddLine("(Right-Click to hide)", 0.5, 0.8, 0.5)
+ end
+ else
+ -- Empty slot
+ GameTooltip:SetText(string.format("Bag %d", bagID), 1.0, 1.0, 1.0)
+ GameTooltip:AddLine("Empty", 0.5, 0.5, 0.5)
+ if hiddenBags[bagID] then
+ GameTooltip:AddLine("(Hidden - Right-Click to show)", 0.8, 0.5, 0.5)
+ else
+ GameTooltip:AddLine("(Right-Click to hide)", 0.5, 0.8, 0.5)
+ end
+ end
+ end
- GameTooltip:Show()
+ GameTooltip:Show()
end
-- Highlight all item slots belonging to a specific bag by dimming others
function Guda_BagFrame_HighlightBagSlots(bagID)
- local itemContainer = getglobal("Guda_BagFrame_ItemContainer")
- if not itemContainer then
- return
- end
+ -- Use the tracked itemButtons list because actual buttons are parented under per-bag parents
+ if not itemButtons or type(itemButtons) ~= "table" then return end
- local highlightCount = 0
- local dimCount = 0
+ local highlightCount, dimCount = 0, 0
- -- Iterate through all children (item buttons)
- local children = { itemContainer:GetChildren() }
- for _, button in ipairs(children) do
- -- Check if this is an item button
- if button.hasItem ~= nil and button:IsShown() then
+ for _, button in ipairs(itemButtons) do
+ if button and button:IsShown() and button.hasItem ~= nil and not button.isBagSlot then
if button.bagID == bagID then
- -- This button belongs to the hovered bag - keep it bright
button:SetAlpha(1.0)
highlightCount = highlightCount + 1
else
- -- This button belongs to a different bag - dim it
button:SetAlpha(0.25)
dimCount = dimCount + 1
end
end
end
-
end
-- Clear all highlighting by restoring full opacity to all slots
function Guda_BagFrame_ClearHighlightedSlots()
- local itemContainer = getglobal("Guda_BagFrame_ItemContainer")
- if not itemContainer then return end
+ -- Restore alpha to whatever the search filter dictates (pfUI style). If no search, full opacity.
+ if not itemButtons or type(itemButtons) ~= "table" then return end
- -- Iterate through all children (item buttons)
- local children = { itemContainer:GetChildren() }
- for _, button in ipairs(children) do
- -- Check if this is an item button
- if button.hasItem ~= nil and button:IsShown() then
- -- Restore full opacity
- button:SetAlpha(1.0)
+ local searchActive = BagFrame and BagFrame.IsSearchActive and BagFrame:IsSearchActive()
+ for _, button in ipairs(itemButtons) do
+ if button and button:IsShown() and button.hasItem ~= nil and not button.isBagSlot then
+ if searchActive and BagFrame and BagFrame.PassesSearchFilter then
+ local matches = BagFrame:PassesSearchFilter(button.itemData)
+ button:SetAlpha(matches and 1.0 or 0.25)
+ else
+ button:SetAlpha(1.0)
+ end
end
end
end
-- Highlight a specific bag button in the toolbar
function Guda_BagFrame_HighlightBagButton(bagID)
- if not bagID then return end
+ if not bagID then return end
- local buttonName
- if bagID == -2 then
- -- Keyring button
- buttonName = "Guda_BagFrame_Toolbar_KeyringButton"
- elseif bagID >= 0 and bagID <= 4 then
- -- Bag buttons 0-4 (0 is backpack)
- buttonName = "Guda_BagFrame_Toolbar_BagSlot" .. bagID
- else
- return
- end
+ local buttonName
+ if bagID == -2 then
+ -- Keyring button
+ buttonName = "Guda_BagFrame_Toolbar_KeyringButton"
+ elseif bagID >= 0 and bagID <= 4 then
+ -- Bag buttons 0-4 (0 is backpack)
+ buttonName = "Guda_BagFrame_Toolbar_BagSlot" .. bagID
+ else
+ return
+ end
- local button = getglobal(buttonName)
- if button then
- -- Set the button's pushed texture to highlight it
- button:LockHighlight()
- end
+ local button = getglobal(buttonName)
+ if button then
+ -- Set the button's pushed texture to highlight it
+ button:LockHighlight()
+ end
end
-- Clear bag button highlighting
function Guda_BagFrame_ClearBagButtonHighlight()
- -- Clear highlight from all bag buttons (0-4)
- for bagID = 0, 4 do
- local buttonName = "Guda_BagFrame_Toolbar_BagSlot" .. bagID
- local button = getglobal(buttonName)
- if button then
- button:UnlockHighlight()
- end
- end
+-- Clear highlight from all bag buttons (0-4)
+ for bagID = 0, 4 do
+ local buttonName = "Guda_BagFrame_Toolbar_BagSlot" .. bagID
+ local button = getglobal(buttonName)
+ if button then
+ button:UnlockHighlight()
+ end
+ end
- -- Clear keyring button highlight
- local keyringButton = getglobal("Guda_BagFrame_Toolbar_KeyringButton")
- if keyringButton then
- keyringButton:UnlockHighlight()
- end
+ -- Clear keyring button highlight
+ local keyringButton = getglobal("Guda_BagFrame_Toolbar_KeyringButton")
+ if keyringButton then
+ keyringButton:UnlockHighlight()
+ end
end
-- Initialize
function BagFrame:Initialize()
- -- Hook default bag functions (with slight delay to ensure UI is loaded)
- local frame = CreateFrame("Frame")
- frame:RegisterEvent("PLAYER_LOGIN")
- frame:SetScript("OnEvent", function()
- HookDefaultBags()
+-- Hook default bag functions (with slight delay to ensure UI is loaded)
+ local frame = CreateFrame("Frame")
+ frame:RegisterEvent("PLAYER_LOGIN")
+ frame:SetScript("OnEvent", function()
+ HookDefaultBags()
- -- Re-hook when character frame is opened (for safety)
- local charFrame = getglobal("CharacterFrame")
- if charFrame then
- local originalShow = charFrame:GetScript("OnShow")
- charFrame:SetScript("OnShow", function()
- HookBagContainers()
- if originalShow then
- originalShow()
- end
- end)
- end
- end)
+ -- Re-hook when character frame is opened (for safety)
+ local charFrame = getglobal("CharacterFrame")
+ if charFrame then
+ local originalShow = charFrame:GetScript("OnShow")
+ charFrame:SetScript("OnShow", function()
+ HookBagContainers()
+ if originalShow then
+ originalShow()
+ end
+ end)
+ end
+ end)
- -- Update on bag changes
- addon.Modules.Events:OnBagUpdate(function()
- if not currentViewChar then
- BagFrame:Update()
- end
- end, "BagFrame")
+ -- 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")
+ -- Update item cooldown overlays when item cooldowns change
+ addon.Modules.Events:Register("BAG_UPDATE_COOLDOWN", function()
+ if not currentViewChar then
+ if BagFrame.RefreshCooldowns then
+ BagFrame:RefreshCooldowns()
+ end
+ end
+ end, "BagFrame")
- -- Update when items get locked/unlocked (for trading, mailing, etc.)
- addon.Modules.Events:Register("ITEM_LOCK_CHANGED", function()
- if not currentViewChar then
- BagFrame:Update()
- end
- end, "BagFrame")
+ -- Update on money changes
+ addon.Modules.Events:OnMoneyChanged(function()
+ BagFrame:UpdateMoney()
+ end, "BagFrame")
- -- Auto-open bag frame when mail is opened
- addon.Modules.Events:Register("MAIL_SHOW", function()
- Guda_BagFrame:Show()
- end, "BagFrame")
+ -- Update when items get locked/unlocked (for trading, mailing, etc.)
+ addon.Modules.Events:Register("ITEM_LOCK_CHANGED", function()
+ if not currentViewChar then
+ BagFrame:Update()
+ end
+ 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
+ -- Auto-open bag frame when mail is opened
+ addon.Modules.Events:Register("MAIL_SHOW", function()
+ Guda_BagFrame:Show()
+ 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
+
+-- Refresh cooldown overlays for all visible item buttons
+function BagFrame:RefreshCooldowns()
+ local itemContainer = getglobal("Guda_BagFrame_ItemContainer")
+ if not itemContainer then return end
+
+ -- Iterate through all children; our item buttons are direct children of per-bag parents inside the container,
+ -- so iterate all descendants by scanning children of children as well.
+ local function refreshChildren(parent)
+ local children = { parent:GetChildren() }
+ for _, child in ipairs(children) do
+ if child and child.hasItem ~= nil then
+ if child:IsShown() and Guda_ItemButton_UpdateCooldown then
+ Guda_ItemButton_UpdateCooldown(child)
+ end
+ end
+ -- Recurse one level to reach actual buttons under bag parents
+ local grandChildren = { child:GetChildren() }
+ if table.getn(grandChildren) > 0 then
+ for _, gc in ipairs(grandChildren) do
+ if gc and gc.hasItem ~= nil then
+ if gc:IsShown() and Guda_ItemButton_UpdateCooldown then
+ Guda_ItemButton_UpdateCooldown(gc)
+ end
+ end
+ end
+ end
+ end
+ end
+
+ refreshChildren(itemContainer)
end
\ No newline at end of file
diff --git a/UI/BagFrame.xml b/UI/BagFrame.xml
index faa1716..1059ac6 100644
--- a/UI/BagFrame.xml
+++ b/UI/BagFrame.xml
@@ -193,7 +193,7 @@
GameTooltip:SetOwner(this, "ANCHOR_TOP")
- GameTooltip:SetText("View Other Characters")
+ GameTooltip:SetText("My Characters")
GameTooltip:Show()
@@ -638,7 +638,8 @@
-
+
+
@@ -654,15 +655,8 @@
-
-
- -- Clear search focus when clicking in item area
- local searchBox = getglobal("Guda_BagFrame_SearchBar_SearchBox")
- if searchBox then
- searchBox:ClearFocus()
- end
-
-
+
diff --git a/UI/BankFrame.lua b/UI/BankFrame.lua
index 212610c..9b527ae 100644
--- a/UI/BankFrame.lua
+++ b/UI/BankFrame.lua
@@ -10,6 +10,9 @@ local currentViewChar = nil
local searchText = ""
local isReadOnlyMode = false -- Track if viewing saved bank (read-only) or live bank (interactive)
local hiddenBankBags = {} -- Track which bank bags are hidden (bagID -> true/false)
+local bankBagParents = {} -- Parent frames per bank bag (same approach as BagFrame)
+-- Global click catcher for clearing bank search focus
+local bankClickCatcher = nil
-- OnLoad
function Guda_BankFrame_OnLoad(self)
@@ -20,6 +23,21 @@ function Guda_BankFrame_OnLoad(self)
searchBox:SetTextColor(0.5, 0.5, 0.5, 1)
end
+ -- Create invisible full-screen frame to catch clicks outside the bank frame while typing in search
+ if not bankClickCatcher then
+ bankClickCatcher = CreateFrame("Frame", "Guda_BankClickCatcher", UIParent)
+ bankClickCatcher:SetFrameStrata("BACKGROUND")
+ bankClickCatcher:SetAllPoints(UIParent)
+ bankClickCatcher:EnableMouse(true)
+ bankClickCatcher:Hide()
+
+ bankClickCatcher:SetScript("OnMouseDown", function()
+ if Guda_BankFrame_ClearSearch then
+ Guda_BankFrame_ClearSearch()
+ end
+ end)
+ end
+
end
-- OnShow
@@ -47,22 +65,6 @@ function Guda_BankFrame_OnShow(self)
BankFrame:Update()
end
--- OnHide
-function Guda_BankFrame_OnHide(self)
- -- Only release buttons that belong to this frame
- local itemContainer = getglobal("Guda_BankFrame_ItemContainer")
- if itemContainer then
- -- Hide only the buttons that are children of this container
- local children = { itemContainer:GetChildren() }
- for _, child in ipairs(children) do
- if child.hasItem ~= nil then -- It's an item button
- child:Hide()
- child:ClearAllPoints()
- end
- end
- end
-end
-
-- Toggle visibility
function BankFrame:Toggle()
if Guda_BankFrame:IsShown() then
@@ -86,20 +88,45 @@ function BankFrame:ShowCurrentCharacter()
self:Update()
end
+-- Update lock states of existing buttons (lightweight, used during drag)
+function BankFrame:UpdateLockStates()
+ for _, bankBagParent in pairs(bankBagParents) do
+ if bankBagParent then
+ local buttons = { bankBagParent:GetChildren() }
+ for _, button in ipairs(buttons) do
+ if button.hasItem ~= nil and button:IsShown() and button.bagID and button.slotID then
+ -- Get live lock state
+ local _, _, locked = GetContainerItemInfo(button.bagID, button.slotID)
+ -- Update desaturation (gray out locked items)
+ if not button.otherChar and not button.isReadOnly and SetItemButtonDesaturated then
+ SetItemButtonDesaturated(button, locked, 0.5, 0.5, 0.5)
+ end
+ end
+ end
+ end
+ end
+end
+
-- Update display
function BankFrame:Update()
if not Guda_BankFrame:IsShown() then
return
end
- -- Only release buttons that belong to this frame
- local itemContainer = getglobal("Guda_BankFrame_ItemContainer")
- if itemContainer then
- local children = { itemContainer:GetChildren() }
- for _, child in ipairs(children) do
- if child.hasItem ~= nil then -- It's an item button
- child:Hide()
- child:ClearAllPoints()
+ -- If cursor is holding an item (mid-drag), only update lock states, don't rebuild UI
+ if CursorHasItem and CursorHasItem() then
+ self:UpdateLockStates()
+ return
+ end
+
+ -- Mark all existing buttons as not in use (we'll mark active ones during display)
+ for _, bankBagParent in pairs(bankBagParents) do
+ if bankBagParent then
+ local buttons = { bankBagParent:GetChildren() }
+ for _, button in ipairs(buttons) do
+ if button.hasItem ~= nil then
+ button.inUse = false
+ end
end
end
end
@@ -120,7 +147,7 @@ function BankFrame:Update()
bankData = addon.Modules.DB:GetCharacterBank(currentViewChar)
isOtherChar = true
charName = currentViewChar
- getglobal("Guda_BankFrame_Title"):SetText("Bank - " .. currentViewChar)
+ getglobal("Guda_BankFrame_Title"):SetText(currentViewChar .. "'s Bank")
else
-- Viewing current character's bank
if bankIsOpen then
@@ -128,12 +155,12 @@ function BankFrame:Update()
bankData = addon.Modules.BankScanner:ScanBank()
-- Use current character's name for the title
local playerName = addon.Modules.DB:GetPlayerFullName()
- getglobal("Guda_BankFrame_Title"):SetText("Bank - " .. playerName)
+ getglobal("Guda_BankFrame_Title"):SetText(playerName .. "'s Bank")
else
-- Bank is closed - use saved data (read-only mode)
local playerName = addon.Modules.DB:GetPlayerFullName()
bankData = addon.Modules.DB:GetCharacterBank(playerName)
- getglobal("Guda_BankFrame_Title"):SetText("Bank - " .. playerName)
+ getglobal("Guda_BankFrame_Title"):SetText(playerName .. "'s Bank")
end
end
@@ -144,6 +171,19 @@ function BankFrame:Update()
-- Update bank slots info
self:UpdateBankSlotsInfo(bankData, isOtherChar)
+
+ -- Clean up unused buttons AFTER display is complete (prevents drag/drop issues)
+ for _, bankBagParent in pairs(bankBagParents) do
+ if bankBagParent then
+ local buttons = { bankBagParent:GetChildren() }
+ for _, button in ipairs(buttons) do
+ if button.hasItem ~= nil and not button.inUse then
+ button:Hide()
+ button:ClearAllPoints()
+ end
+ end
+ end
+ end
end
-- Display items
@@ -180,13 +220,26 @@ function BankFrame:DisplayItems(bankData, isOtherChar, charName)
-- Check if item matches search filter
local matchesFilter = self:PassesSearchFilter(itemData)
- local button = Guda_GetItemButton(itemContainer)
+ -- Ensure a per-bag parent frame exists and carries the bag ID
+ local bankBagParent
+ if not bankBagParents[bagID] then
+ bankBagParents[bagID] = CreateFrame("Frame", "Guda_BankFrame_BankBagParent"..bagID, itemContainer)
+ bankBagParents[bagID]:SetAllPoints(itemContainer)
+ if bankBagParents[bagID].SetID then
+ bankBagParents[bagID]:SetID(bagID)
+ end
+ end
+ bankBagParent = bankBagParents[bagID]
+
+ local button = Guda_GetItemButton(bankBagParent)
-- Ensure this is NOT a bag slot button
if button.isBagSlot then
break
end
+ button.inUse = true -- Mark this button as actively in use
+
-- Position button
local xPos = x + (col * (buttonSize + spacing))
local yPos = y - (row * (buttonSize + spacing))
@@ -522,6 +575,27 @@ function Guda_BankFrame_OnSearchChanged(self)
end
end
+-- Clear bank search and restore placeholder
+function Guda_BankFrame_ClearSearch()
+ local searchBox = getglobal("Guda_BankFrame_SearchBar_SearchBox")
+ if searchBox then
+ searchBox:SetText("Search bank...")
+ searchBox:SetTextColor(0.5, 0.5, 0.5, 1)
+ if searchBox.ClearFocus then searchBox:ClearFocus() end
+ end
+
+ -- Reset search state
+ searchText = ""
+
+ -- Update display
+ BankFrame:Update()
+
+ -- Hide click catcher if present
+ if bankClickCatcher and bankClickCatcher.Hide then
+ bankClickCatcher:Hide()
+ end
+end
+
-- Sort button handler with auto-repeat and smart pass calculation
function Guda_BankFrame_Sort()
if isReadOnlyMode or currentViewChar then
@@ -861,6 +935,12 @@ function BankFrame:Initialize()
-- Show current character's bank in interactive mode
currentViewChar = nil
+ -- Hide BagFrame to prevent button overlap
+ local bagFrame = getglobal("Guda_BagFrame")
+ if bagFrame and bagFrame:IsShown() then
+ bagFrame:Hide()
+ end
+
-- Show and update custom bank frame
local customBankFrame = getglobal("Guda_BankFrame")
if customBankFrame then
@@ -1170,46 +1250,49 @@ end
-- Highlight all item slots belonging to a specific bank bag by dimming others
function Guda_BankFrame_HighlightBagSlots(bagID)
- local itemContainer = getglobal("Guda_BankFrame_ItemContainer")
- if not itemContainer then
- return
- end
+ -- Buttons are parented under per-bag parents, not directly under the item container
+ local highlightCount, dimCount = 0, 0
- local highlightCount = 0
- local dimCount = 0
-
- -- Iterate through all children (item buttons)
- local children = { itemContainer:GetChildren() }
- for _, button in ipairs(children) do
- -- Check if this is an item button
- if button.hasItem ~= nil and button:IsShown() and not button.isBagSlot then
- if button.bagID == bagID then
- -- This button belongs to the hovered bag - keep it bright
- button:SetAlpha(1.0)
- highlightCount = highlightCount + 1
- else
- -- This button belongs to a different bag - dim it
- button:SetAlpha(0.25)
- dimCount = dimCount + 1
+ for _, bankBagParent in pairs(bankBagParents) do
+ if bankBagParent then
+ local children = { bankBagParent:GetChildren() }
+ for _, button in ipairs(children) do
+ if button and button:IsShown() and button.hasItem ~= nil and not button.isBagSlot then
+ if button.bagID == bagID then
+ button:SetAlpha(1.0)
+ highlightCount = highlightCount + 1
+ else
+ button:SetAlpha(0.25)
+ dimCount = dimCount + 1
+ end
+ end
end
end
end
- addon:Debug(string.format("BankFrame HighlightBagSlots: Highlighted %d slots, dimmed %d slots for bagID %d", highlightCount, dimCount, bagID))
+ if addon and addon.Debug then
+ addon:Debug(string.format("BankFrame HighlightBagSlots: Highlighted %d slots, dimmed %d slots for bagID %d", highlightCount, dimCount, bagID))
+ end
end
-- Clear all highlighting by restoring full opacity to all slots
function Guda_BankFrame_ClearHighlightedSlots()
- local itemContainer = getglobal("Guda_BankFrame_ItemContainer")
- if not itemContainer then return end
+ -- Restore alpha to search-filter state (pfUI style). If no search, full opacity.
+ local searchActive = BankFrame and BankFrame.IsSearchActive and BankFrame:IsSearchActive()
- -- Iterate through all children (item buttons)
- local children = { itemContainer:GetChildren() }
- for _, button in ipairs(children) do
- -- Check if this is an item button
- if button.hasItem ~= nil and button:IsShown() and not button.isBagSlot then
- -- Restore full opacity
- button:SetAlpha(1.0)
+ for _, bankBagParent in pairs(bankBagParents) do
+ if bankBagParent then
+ local children = { bankBagParent:GetChildren() }
+ for _, button in ipairs(children) do
+ if button and button:IsShown() and button.hasItem ~= nil and not button.isBagSlot then
+ if searchActive and BankFrame and BankFrame.PassesSearchFilter then
+ local matches = BankFrame:PassesSearchFilter(button.itemData)
+ button:SetAlpha(matches and 1.0 or 0.25)
+ else
+ button:SetAlpha(1.0)
+ end
+ end
+ end
end
end
end
diff --git a/UI/BankFrame.xml b/UI/BankFrame.xml
index 994e150..2bf3685 100644
--- a/UI/BankFrame.xml
+++ b/UI/BankFrame.xml
@@ -240,7 +240,7 @@
GameTooltip:SetOwner(this, "ANCHOR_TOP")
- GameTooltip:SetText("View Other Characters' Bank")
+ GameTooltip:SetText("View Bank")
GameTooltip:Show()
@@ -286,8 +286,14 @@
this:SetText("")
this:SetTextColor(1, 1, 1, 1)
end
+ -- Show bank click catcher to detect clicks outside bank while typing
+ local cc = getglobal("Guda_BankClickCatcher")
+ if cc then cc:Show() end
+ -- Hide bank click catcher when focus is lost
+ local cc = getglobal("Guda_BankClickCatcher")
+ if cc then cc:Hide() end
if this:GetText() == "" then
this:SetText("Search bank...")
this:SetTextColor(0.5, 0.5, 0.5, 1)
@@ -302,6 +308,8 @@
this:SetTextColor(0.5, 0.5, 0.5, 1)
this:ClearFocus()
Guda_BankFrame_OnSearchChanged(this)
+ local cc = getglobal("Guda_BankClickCatcher")
+ if cc then cc:Hide() end
@@ -595,7 +603,11 @@
Guda_BankFrame_OnShow(this)
- Guda_BankFrame_OnHide(this)
+ Guda_BankFrame:Hide()
+ -- Close the actual Blizzard bank too
+ if BankFrame and BankFrame:IsShown() then
+ CloseBankFrame()
+ end
-- Clear search box focus when clicking on bank frame
diff --git a/UI/ItemButton.lua b/UI/ItemButton.lua
index 50b84d6..51da5e5 100644
--- a/UI/ItemButton.lua
+++ b/UI/ItemButton.lua
@@ -1,8 +1,6 @@
--- Guda Item Button
--- Handles item button display and interaction
-
+-- Local alias to the addon root table (must be defined before any usages below)
local addon = Guda
-
+
-- Item button pool
local buttonPool = {}
local nextButtonID = 1
@@ -11,6 +9,8 @@ local nextButtonID = 1
local scanTooltip = CreateFrame("GameTooltip", "Guda_QuestScanTooltip", nil, "GameTooltipTemplate")
scanTooltip:SetOwner(WorldFrame, "ANCHOR_NONE")
+-- (rollback) no custom drag-source tracking or target resolution; rely on Blizzard handlers
+
-- Check if an item is a quest item by scanning its tooltip
local function IsQuestItem(bagID, slotID)
if not bagID or not slotID then return false end
@@ -108,30 +108,172 @@ function Guda_ItemButton_OnLoad(self)
iconFrame:Hide()
self.questIcon = iconFrame
end
+
+ -- Ensure the item button sits above its container backdrop and is mouse-enabled
+ local parent = self:GetParent()
+ if parent and parent.GetFrameLevel then
+ -- Place button above parent backdrop/mouse layer to reliably receive drops
+ local parentLevel = parent:GetFrameLevel()
+ if parentLevel and self:GetFrameLevel() <= parentLevel + 1 then
+ self:SetFrameLevel(parentLevel + 2)
+ end
+ end
+
+ -- Enable mouse and register for drag/drop (crucial for Classic/Vanilla WoW)
+ if self.EnableMouse then
+ self:EnableMouse(true)
+ end
+ if self.RegisterForDrag then
+ self:RegisterForDrag("LeftButton")
+ end
+ if self.RegisterForClicks then
+ self:RegisterForClicks("LeftButtonUp", "RightButtonUp")
+ end
+end
+
+-- Update the Blizzard cooldown overlay on this item button
+function Guda_ItemButton_UpdateCooldown(self)
+ -- Only show cooldowns for live items of the current character
+ if not self or self.isReadOnly or self.otherChar then return end
+
+ local cooldown = getglobal(self:GetName().."Cooldown") or self.cooldown
+ if not cooldown then return end
+
+ if not self.hasItem or not self.bagID or not self.slotID then
+ cooldown:Hide()
+ return
+ end
+
+ local start, duration, enable = GetContainerItemCooldown(self.bagID, self.slotID)
+ if start and duration and duration > 0 and enable == 1 then
+ if CooldownFrame_SetTimer then
+ CooldownFrame_SetTimer(cooldown, start, duration, enable)
+ elseif CooldownFrame_Set then
+ -- Some clients expose CooldownFrame_Set instead
+ CooldownFrame_Set(cooldown, start, duration, enable)
+ else
+ -- Fallback: show the frame if API missing
+ cooldown:Show()
+ end
+ else
+ cooldown:Hide()
+ end
end
-- Set item data
function Guda_ItemButton_SetItem(self, bagID, slotID, itemData, isBank, otherCharName, matchesFilter, isReadOnly)
self.bagID = bagID
self.slotID = slotID
+ -- Also set the Blizzard slot ID for compatibility with ContainerFrameItemButtonTemplate behavior
+ if self.SetID and slotID then
+ self:SetID(slotID)
+ end
self.itemData = itemData
self.isBank = isBank or false
self.otherChar = otherCharName
self.isReadOnly = isReadOnly or false -- Track if this is read-only mode
+ -- Re-register for drag/drop every time (crucial for button reuse in Classic/Vanilla)
+ if not self.isReadOnly and not self.otherChar then
+ if self.RegisterForDrag then
+ self:RegisterForDrag("LeftButton")
+ end
+ if self.RegisterForClicks then
+ self:RegisterForClicks("LeftButtonUp", "RightButtonUp")
+ end
+ if self.EnableMouse then
+ self:EnableMouse(true)
+ end
+ else
+ -- Disable drag for read-only or other character items
+ if self.RegisterForDrag then
+ self:RegisterForDrag() -- Clear drag registration
+ end
+ if self.EnableMouse then
+ self:EnableMouse(true) -- Still enable mouse for tooltips
+ end
+ end
+
-- Default to true if not specified (for non-filtered displays)
if matchesFilter == nil then
matchesFilter = true
end
- local countText = getglobal(self:GetName().."_Count")
+ -- Use Blizzard's default count fontstring (ContainerFrameItemButtonTemplate creates $parentCount)
+ local countText = getglobal(self:GetName().."Count")
local emptySlotBg = getglobal(self:GetName().."_EmptySlotBg")
- -- Apply icon size setting
- local iconSize = Guda.Modules.DB:GetSetting("iconSize") or addon.Constants.BUTTON_SIZE
+ -- Apply icon size setting (nil-safe)
+ local iconSize = 37
+ if addon and addon.Modules and addon.Modules.DB and addon.Modules.DB.GetSetting then
+ iconSize = addon.Modules.DB:GetSetting("iconSize") or iconSize
+ elseif Guda and Guda.Modules and Guda.Modules.DB and Guda.Modules.DB.GetSetting then
+ iconSize = Guda.Modules.DB:GetSetting("iconSize") or iconSize
+ end
+ if addon and addon.Constants and addon.Constants.BUTTON_SIZE then
+ iconSize = iconSize or addon.Constants.BUTTON_SIZE
+ end
self:SetWidth(iconSize)
self:SetHeight(iconSize)
+ -- In live mode (readOnly=false), query real-time game state instead of cached DB
+ -- In read-only mode (readOnly=true), use cached itemData from DB
+ local displayTexture, displayCount
+
+ if not self.isReadOnly then
+ -- LIVE MODE: Always query game state directly, never use cached itemData
+ local liveTexture, liveCount = GetContainerItemInfo(bagID, slotID)
+ if liveTexture then
+ displayTexture = liveTexture
+ displayCount = liveCount
+ self.hasItem = true
+ else
+ -- No item in this slot (even if itemData has cached data)
+ self.hasItem = false
+ end
+ else
+ -- READ-ONLY MODE: Use cached itemData from DB (can't query other characters)
+ if itemData and itemData.texture then
+ displayTexture = itemData.texture
+ displayCount = itemData.count
+ self.hasItem = true
+ else
+ self.hasItem = false
+ end
+ end
+
+ -- Apply the determined texture and count
+ if self.hasItem then
+ if SetItemButtonTexture then SetItemButtonTexture(self, displayTexture) end
+ if SetItemButtonCount then SetItemButtonCount(self, displayCount or 1) end
+ if emptySlotBg then emptySlotBg:Hide() end
+ -- Update cooldown overlay for live items
+ if not self.isReadOnly and Guda_ItemButton_UpdateCooldown then
+ Guda_ItemButton_UpdateCooldown(self)
+ end
+ else
+ -- Fully clear all item button state for empty slots
+ if SetItemButtonTexture then SetItemButtonTexture(self, nil) end
+ if SetItemButtonCount then SetItemButtonCount(self, 0) end
+ if SetItemButtonDesaturated then SetItemButtonDesaturated(self, false) end
+
+ -- Ensure cooldown overlay is hidden for empty slots
+ local cooldown = getglobal(self:GetName().."Cooldown") or self.cooldown
+ if cooldown and cooldown.Hide then cooldown:Hide() end
+
+ -- Also clear the icon texture directly
+ local iconTexture = getglobal(self:GetName().."IconTexture")
+ if not iconTexture then
+ iconTexture = getglobal(self:GetName().."Icon") or self.icon or self.Icon
+ end
+ if iconTexture then
+ iconTexture:SetTexture(nil)
+ iconTexture:Hide()
+ end
+
+ if emptySlotBg then emptySlotBg:Show() end
+ end
+
-- Resize empty slot background to match icon size (slightly larger to ensure coverage)
if emptySlotBg then
emptySlotBg:ClearAllPoints()
@@ -190,7 +332,12 @@ function Guda_ItemButton_SetItem(self, bagID, slotID, itemData, isBank, otherCha
-- Apply icon font size setting to stack count text
if countText and countText.GetFont then
local font, _, flags = countText:GetFont()
- local fontSize = Guda.Modules.DB:GetSetting("iconFontSize") or 12
+ local fontSize = 12
+ if addon and addon.Modules and addon.Modules.DB and addon.Modules.DB.GetSetting then
+ fontSize = addon.Modules.DB:GetSetting("iconFontSize") or fontSize
+ elseif Guda and Guda.Modules and Guda.Modules.DB and Guda.Modules.DB.GetSetting then
+ fontSize = Guda.Modules.DB:GetSetting("iconFontSize") or fontSize
+ end
countText:SetFont(font, fontSize, flags)
-- Adjust count text position based on icon size for better alignment
@@ -204,16 +351,28 @@ function Guda_ItemButton_SetItem(self, bagID, slotID, itemData, isBank, otherCha
end
end
- if itemData then
- self.hasItem = true
+ -- Get live metadata if in live mode (quality, link, lock status)
+ local itemQuality, itemLink, isLocked
+ if not self.isReadOnly and bagID and slotID and self.hasItem then
+ -- Query live game state for metadata
+ local _, _, locked, quality = GetContainerItemInfo(bagID, slotID)
+ itemLink = GetContainerItemLink(bagID, slotID)
+ itemQuality = quality
+ isLocked = locked
+ elseif itemData then
+ -- Use cached metadata from database
+ itemQuality = itemData.quality
+ itemLink = itemData.link
+ isLocked = itemData.locked
+ end
- -- Set icon
- SetItemButtonTexture(self, itemData.texture)
+ if self.hasItem then
+ -- Icon already set above based on mode (live vs cached)
-- Gray out locked items (being traded, mailed, or auctioned) - BagShui style
-- Don't desaturate items from other characters since they're read-only anyway
if not self.otherChar and not self.isReadOnly then
- SetItemButtonDesaturated(self, itemData.locked, 0.5, 0.5, 0.5)
+ SetItemButtonDesaturated(self, isLocked, 0.5, 0.5, 0.5)
end
-- Hide NormalTexture for filled slots (pfUI style)
@@ -238,9 +397,9 @@ function Guda_ItemButton_SetItem(self, bagID, slotID, itemData, isBank, otherCha
self:SetAlpha(0.25)
end
- -- Set count
- if itemData.count and itemData.count > 1 then
- countText:SetText(itemData.count)
+ -- Set count (use displayCount which was determined above based on mode)
+ if displayCount and displayCount > 1 then
+ countText:SetText(displayCount)
countText:Show()
else
countText:Hide()
@@ -252,10 +411,16 @@ function Guda_ItemButton_SetItem(self, bagID, slotID, itemData, isBank, otherCha
-- Special border for keyring items (cyan/blue)
self.qualityBorder:SetBackdropBorderColor(0.2, 0.8, 1.0, 1)
self.qualityBorder:Show()
- elseif itemData.quality and itemData.link then
- -- Check settings to determine if we should show borders
- local showEquipmentBorder = addon.Modules.DB:GetSetting("showQualityBorderEquipment")
- local showOtherBorder = addon.Modules.DB:GetSetting("showQualityBorderOther")
+ elseif itemQuality and itemLink then
+ -- Check settings to determine if we should show borders (nil-safe)
+ local showEquipmentBorder, showOtherBorder
+ if addon and addon.Modules and addon.Modules.DB and addon.Modules.DB.GetSetting then
+ showEquipmentBorder = addon.Modules.DB:GetSetting("showQualityBorderEquipment")
+ showOtherBorder = addon.Modules.DB:GetSetting("showQualityBorderOther")
+ elseif Guda and Guda.Modules and Guda.Modules.DB and Guda.Modules.DB.GetSetting then
+ showEquipmentBorder = Guda.Modules.DB:GetSetting("showQualityBorderEquipment")
+ showOtherBorder = Guda.Modules.DB:GetSetting("showQualityBorderOther")
+ end
-- Default to true if settings not found
if showEquipmentBorder == nil then
@@ -265,15 +430,25 @@ function Guda_ItemButton_SetItem(self, bagID, slotID, itemData, isBank, otherCha
showOtherBorder = true
end
- -- Check if item is equipment
- local isEquipment = addon.Modules.Utils:IsEquipment(itemData.link)
+ -- Check if item is equipment (nil-safe)
+ local isEquipment = false
+ if addon and addon.Modules and addon.Modules.Utils and addon.Modules.Utils.IsEquipment then
+ isEquipment = addon.Modules.Utils:IsEquipment(itemLink)
+ elseif Guda and Guda.Modules and Guda.Modules.Utils and Guda.Modules.Utils.IsEquipment then
+ isEquipment = Guda.Modules.Utils:IsEquipment(itemLink)
+ end
-- Determine if we should show the border based on item type and settings
local shouldShowBorder = (isEquipment and showEquipmentBorder) or (not isEquipment and showOtherBorder)
if shouldShowBorder then
-- Show colored border for all items (Poor, Common, Uncommon, Rare, Epic, etc.)
- local r, g, b = addon.Modules.Utils:GetQualityColor(itemData.quality)
+ local r, g, b = 1, 1, 1
+ if addon and addon.Modules and addon.Modules.Utils and addon.Modules.Utils.GetQualityColor then
+ r, g, b = addon.Modules.Utils:GetQualityColor(itemQuality)
+ elseif Guda and Guda.Modules and Guda.Modules.Utils and Guda.Modules.Utils.GetQualityColor then
+ r, g, b = Guda.Modules.Utils:GetQualityColor(itemQuality)
+ end
self.qualityBorder:SetBackdropBorderColor(r, g, b, 1)
self.qualityBorder:Show()
else
@@ -417,51 +592,64 @@ end
-- OnEnter handler (show tooltip)
function Guda_ItemButton_OnEnter(self)
- -- Highlight the corresponding bag button in the footer (works for empty and filled slots)
- if not self.otherChar and self.bagID then
- if self.isBank then
- -- Bank item - highlight bank bag button
- Guda_BankFrame_HighlightBagButton(self.bagID)
- else
- -- Regular bag item - highlight bag button
- Guda_BagFrame_HighlightBagButton(self.bagID)
- end
- end
+-- Highlight the corresponding bag button in the footer (works for empty and filled slots)
+ if not self.otherChar and self.bagID then
+ if self.isBank then
+ -- Bank item - highlight bank bag button
+ Guda_BankFrame_HighlightBagButton(self.bagID)
+ else
+ -- Regular bag item - highlight bag button
+ Guda_BagFrame_HighlightBagButton(self.bagID)
+ end
+ end
- -- Early return for empty slots (no tooltip needed)
- if not self.hasItem or not self.itemData then
- return
- end
+ -- Early return for empty slots (no tooltip needed)
+ if not self.hasItem or not self.itemData then
+ return
+ end
- GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
+ GameTooltip:SetOwner(UIParent, "ANCHOR_NONE")
+ -- important position of tooltip
+ GameTooltip:SetPoint("BOTTOMRIGHT", self, "TOPLEFT", 10, 0)
- -- For bank items, use the item link directly since SetBagItem might not work for bank bags
- if self.isBank and self.itemData.link then
- -- Extract hyperlink from item link: |cFFFFFFFF|Hitem:1234:0:0:0|h[Name]|h|r -> item:1234:0:0:0
- local _, _, hyperlink = strfind(self.itemData.link, "|H(.+)|h")
- if hyperlink then
- GameTooltip:SetHyperlink(hyperlink)
- else
- -- Fallback to SetBagItem
- GameTooltip:SetBagItem(self.bagID, self.slotID)
- end
- else
- -- For regular bags, use SetBagItem as normal
- GameTooltip:SetBagItem(self.bagID, self.slotID)
- end
-
- GameTooltip:Show()
-
- -- Handle merchant sell cursor (same approach as BagShui)
- if MerchantFrame:IsShown() and not self.isBank and not self.otherChar and self.hasItem then
- ShowContainerSellCursor(self.bagID, self.slotID)
- else
- ResetCursor()
- end
+ if self.otherChar or self.isReadOnly then
+ GameTooltip.GudaViewedCharacter = self.otherChar
+ if self.itemData and self.itemData.link then
+ GameTooltip:SetHyperlink(self.itemData.link)
+ else
+ GameTooltip:Hide()
+ return
+ end
+ -- Special handling for bank main bag when bank might be closed
+ elseif self.isBank and self.bagID == -1 then
+ local bankFrame = getglobal("BankFrame")
+ if bankFrame and bankFrame:IsVisible() then
+ -- Bank is open - use SetBagItem which will trigger inventory slot handling
+ GameTooltip:SetBagItem(self.bagID, self.slotID)
+ elseif self.itemData and self.itemData.link then
+ -- Bank is closed - use cached link
+ GameTooltip:SetHyperlink(self.itemData.link)
+ end
+ else
+ -- For live mode: use SetBagItem for all bags
+ GameTooltip:SetBagItem(self.bagID, self.slotID)
+ end
+ GameTooltip:Show()
+ -- Handle merchant sell cursor (same approach as BagShui)
+ if MerchantFrame:IsShown() and not self.isBank and not self.otherChar and self.hasItem then
+ ShowContainerSellCursor(self.bagID, self.slotID)
+ else
+ ResetCursor()
+ end
end
+
-- OnLeave handler
function Guda_ItemButton_OnLeave(self)
+ -- Clear any viewed character hint on the tooltip when leaving
+ if GameTooltip and GameTooltip.GudaViewedCharacter then
+ GameTooltip.GudaViewedCharacter = nil
+ end
GameTooltip:Hide()
ResetCursor()
@@ -484,6 +672,11 @@ function Guda_ItemButton_OnDragStart(self, button)
-- Only allow left button drag
if button == "LeftButton" and self.hasItem then
+ -- Ensure the global click catcher doesn't intercept the drag/drop
+ local cc = getglobal and getglobal("Guda_ClickCatcher")
+ if cc and cc.Hide and cc:IsShown() then
+ cc:Hide()
+ end
PickupContainerItem(self.bagID, self.slotID)
end
end
@@ -497,6 +690,30 @@ function Guda_ItemButton_OnReceiveDrag(self)
-- Place the item being dragged
PickupContainerItem(self.bagID, self.slotID)
+
+ -- Trigger UI update after drop completes (was skipped during drag)
+ if addon and addon.Modules and addon.Modules.BagFrame then
+ addon.Modules.BagFrame:Update()
+ end
+end
+
+-- Handle mouse-up to emulate Blizzard drop behavior on 1.12 where OnReceiveDrag may not always fire
+-- (rollback) no custom OnMouseUp; rely on Blizzard default
+
+-- OnMouseDown handler - pick up item when pressing mouse button (classic pattern)
+-- (rollback) no custom OnMouseDown; rely on Blizzard default
+
+-- OnDragStop handler (optional cleanup)
+function Guda_ItemButton_OnDragStop(self)
+ -- Reset cursor to default to avoid lingering special cursors
+ if ResetCursor then
+ ResetCursor()
+ end
+
+ -- Trigger UI update after drag completes (was skipped during drag)
+ if addon and addon.Modules and addon.Modules.BagFrame then
+ addon.Modules.BagFrame:Update()
+ end
end
-- Stack split callback (called by StackSplitFrame)
@@ -509,44 +726,43 @@ end
-- OnClick handler
function Guda_ItemButton_OnClick(self, button)
-- Don't allow interaction with other characters' items or in read-only mode
- if self.otherChar or self.isReadOnly then
- return
- end
+ if self.otherChar or self.isReadOnly then return end
-- Set the split callback
self.SplitStack = ItemButton_SplitStack
- -- Handle modified clicks first
+ -- Modified clicks
if IsShiftKeyDown() then
if button == "LeftButton" and self.hasItem then
+ -- Get live count and link
+ local _, count = GetContainerItemInfo(self.bagID, self.slotID)
+ local itemLink = GetContainerItemLink(self.bagID, self.slotID)
+
-- Shift+Left Click on stackable item: Show split stack dialog
- if self.itemData and self.itemData.count and self.itemData.count > 1 then
- -- Get the actual stack count from the container
- local _, count = GetContainerItemInfo(self.bagID, self.slotID)
- if count and count > 1 then
- -- Open the stack split frame (positioned to the left)
- OpenStackSplitFrame(count, self, "BOTTOMRIGHT", "TOPRIGHT")
- return
- end
+ if count and count > 1 then
+ OpenStackSplitFrame(count, self, "BOTTOMRIGHT", "TOPRIGHT")
+ return
end
-- If not stackable or only 1 item, link to chat
- if self.itemData and self.itemData.link and ChatFrameEditBox:IsVisible() then
- ChatFrameEditBox:Insert(self.itemData.link)
+ if itemLink and ChatFrameEditBox:IsVisible() then
+ ChatFrameEditBox:Insert(itemLink)
end
end
return
elseif IsControlKeyDown() then
-- Ctrl+Click: Dress up (if applicable)
- if self.hasItem and self.itemData and self.itemData.link then
- DressUpItemLink(self.itemData.link)
+ if self.hasItem then
+ local itemLink = GetContainerItemLink(self.bagID, self.slotID)
+ if itemLink then
+ DressUpItemLink(itemLink)
+ end
end
return
end
- -- Normal clicks - handle item pickup/placement
if button == "LeftButton" then
- -- Pick up or place item
- PickupContainerItem(self.bagID, self.slotID)
+ -- Left clicks are handled by MouseDown/MouseUp to prevent instant self-drop.
+ return
elseif button == "RightButton" then
-- Right click: Use item (only if slot has an item)
if self.hasItem then
@@ -561,4 +777,4 @@ function Guda_ReleaseAllButtons()
button:Hide()
button:ClearAllPoints()
end
-end
+end
\ No newline at end of file
diff --git a/UI/ItemButton.xml b/UI/ItemButton.xml
index dccdb67..cc0affb 100644
--- a/UI/ItemButton.xml
+++ b/UI/ItemButton.xml
@@ -1,7 +1,7 @@
-
-