Merge pull request #2 from

bug fixing
This commit is contained in:
Vati
2025-11-22 04:36:57 +04:00
committed by GitHub
11 changed files with 2069 additions and 1679 deletions
+1 -1
View File
@@ -117,7 +117,7 @@ end
-- Get current player's full name
function DB:GetPlayerFullName()
return playerName
return playerName .. "-" .. playerRealm
end
-- Get current character data
+69 -12
View File
@@ -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
+3 -3
View File
@@ -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
+1 -2
View File
@@ -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
+1529 -1436
View File
File diff suppressed because it is too large Load Diff
+5 -11
View File
@@ -193,7 +193,7 @@
</OnClick>
<OnEnter>
GameTooltip:SetOwner(this, "ANCHOR_TOP")
GameTooltip:SetText("View Other Characters")
GameTooltip:SetText("My Characters")
GameTooltip:Show()
</OnEnter>
<OnLeave>
@@ -638,7 +638,8 @@
<!-- Container for item buttons -->
<Frame name="$parent_ItemContainer" enableMouse="true">
<!-- Set enableMouse to false so it does not intercept drag/drop meant for child item buttons -->
<Frame name="$parent_ItemContainer" enableMouse="false">
<Size>
<AbsDimension x="400" y="480"/>
</Size>
@@ -654,15 +655,8 @@
</TileSize>
<Color r="0" g="0" b="0" a="0.5"/>
</Backdrop>
<Scripts>
<OnMouseDown>
-- Clear search focus when clicking in item area
local searchBox = getglobal("Guda_BagFrame_SearchBar_SearchBox")
if searchBox then
searchBox:ClearFocus()
end
</OnMouseDown>
</Scripts>
<!-- Note: with enableMouse=false, OnMouseDown/OnReceiveDrag here would not fire;
child item buttons will handle mouse events directly. -->
</Frame>
</Frames>
+141 -58
View File
@@ -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
+14 -2
View File
@@ -240,7 +240,7 @@
</OnClick>
<OnEnter>
GameTooltip:SetOwner(this, "ANCHOR_TOP")
GameTooltip:SetText("View Other Characters' Bank")
GameTooltip:SetText("View Bank")
GameTooltip:Show()
</OnEnter>
<OnLeave>
@@ -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
</OnEditFocusGained>
<OnEditFocusLost>
-- 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
</OnEscapePressed>
</Scripts>
</EditBox>
@@ -595,7 +603,11 @@
Guda_BankFrame_OnShow(this)
</OnShow>
<OnHide>
Guda_BankFrame_OnHide(this)
Guda_BankFrame:Hide()
-- Close the actual Blizzard bank too
if BankFrame and BankFrame:IsShown() then
CloseBankFrame()
end
</OnHide>
<OnMouseDown>
-- Clear search box focus when clicking on bank frame
+297 -81
View File
@@ -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
+9 -16
View File
@@ -1,7 +1,7 @@
<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/">
<!-- Item Button Template -->
<Button name="Guda_ItemButtonTemplate" virtual="true" inherits="ItemButtonTemplate">
<!-- Item Button Template (inherit Blizzard container item button for classic behavior/skins) -->
<Button name="Guda_ItemButtonTemplate" virtual="true" inherits="ContainerFrameItemButtonTemplate">
<Size>
<AbsDimension x="37" y="37"/>
</Size>
@@ -16,9 +16,8 @@
</Anchors>
</Texture>
</Layer>
<!-- Item count -->
<!-- Custom item count (this intentionally co-exists with Blizzard's $parentCount in rollback state) -->
<Layer level="OVERLAY">
<FontString name="$parent_Count" inherits="NumberFontNormal" justifyH="RIGHT">
<Anchors>
@@ -34,9 +33,12 @@
<Scripts>
<OnLoad>
-- Our visual setup
Guda_ItemButton_OnLoad(this)
this:RegisterForDrag("LeftButton")
this:RegisterForClicks("LeftButtonUp", "RightButtonUp")
-- Ensure Blizzard default container item button behavior is active
if ContainerFrameItemButton_OnLoad then
ContainerFrameItemButton_OnLoad()
end
</OnLoad>
<OnEnter>
Guda_ItemButton_OnEnter(this)
@@ -44,15 +46,6 @@
<OnLeave>
Guda_ItemButton_OnLeave(this)
</OnLeave>
<OnClick>
Guda_ItemButton_OnClick(this, arg1)
</OnClick>
<OnDragStart>
Guda_ItemButton_OnDragStart(this, arg1)
</OnDragStart>
<OnReceiveDrag>
Guda_ItemButton_OnReceiveDrag(this)
</OnReceiveDrag>
</Scripts>
</Button>
-57
View File
@@ -1,57 +0,0 @@
-- Guda Money Display
-- Handles money display in UI
local addon = Guda
local MoneyDisplay = {}
addon.Modules.MoneyDisplay = MoneyDisplay
-- Create a money display frame
function MoneyDisplay:CreateDisplay(parent, x, y)
local frame = CreateFrame("Frame", nil, parent)
frame:SetPoint("TOPLEFT", parent, "TOPLEFT", x, y)
frame:SetWidth(200)
frame:SetHeight(20)
-- Gold text
frame.gold = frame:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
frame.gold:SetPoint("LEFT", frame, "LEFT", 0, 0)
-- Silver text
frame.silver = frame:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
frame.silver:SetPoint("LEFT", frame.gold, "RIGHT", 2, 0)
-- Copper text
frame.copper = frame:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
frame.copper:SetPoint("LEFT", frame.silver, "RIGHT", 2, 0)
return frame
end
-- Update money display
function MoneyDisplay:Update(frame, copper)
if not frame or not copper then
return
end
local gold = math.floor(copper / 10000)
local silver = math.floor(mod(copper, 10000) / 100)
local bronze = mod(copper, 100)
if gold > 0 then
frame.gold:SetText(gold .. "|cFFFFD700g|r")
frame.gold:Show()
else
frame.gold:Hide()
end
if silver > 0 or gold > 0 then
frame.silver:SetText(silver .. "|cFFC0C0C0s|r")
frame.silver:Show()
else
frame.silver:Hide()
end
frame.copper:SetText(bronze .. "|cFFFF6600c|r")
frame.copper:Show()
end