refactor: consolidate small compatibility layers

This commit is contained in:
Dusk-92
2026-09-06 08:54:46 +02:00
parent e096ba2d90
commit cadf154d0f
18 changed files with 757 additions and 727 deletions
+247
View File
@@ -254,3 +254,250 @@ initFrame:SetScript("OnEvent", function()
this:UnregisterEvent("PLAYER_ENTERING_WORLD")
end
end)
--=====================================================
-- Consolidated from UI/UsabilityTintClassicAPI.lua
--=====================================================
-- Guda ClassicAPI usability tint safety
-- Re-applies unusable-item tint after sorting/moves without synchronous mass scans.
-- Lua 5.0 compatible.
local addon = Guda
if not addon or not Guda_ItemButton_SetItem then return end
local OriginalSetItem = Guda_ItemButton_SetItem
local function EnsureUnusableOverlay(button)
if button.unusableOverlay then return button.unusableOverlay end
local overlay = button:CreateTexture(nil, "OVERLAY")
overlay:SetAllPoints(button)
overlay:SetTexture("Interface\\ChatFrame\\ChatFrameBackground")
overlay:Hide()
button.unusableOverlay = overlay
return overlay
end
-- Mirror ItemButton.lua's unusable color selection exactly. The original helper
-- is local to ItemButton.lua, so this safety layer cannot call it directly.
local function GetUnusableColor()
if pfUI and C and C.appearance and C.appearance.bags and C.appearance.bags.unusable_color then
local cr, cg, cb, ca = strsplit(",", C.appearance.bags.unusable_color)
local r = tonumber(cr) or 0.9
local g = tonumber(cg) or 0.2
local b = tonumber(cb) or 0.2
local a = tonumber(ca) or 1.0
return r, g, b, a
end
if RED_FONT_COLOR then
return RED_FONT_COLOR.r, RED_FONT_COLOR.g, RED_FONT_COLOR.b, 1.0
end
return 0.9, 0.2, 0.2, 1.0
end
local function ApplyUnusableTint(button, unusable)
if not button then return end
local markUnusable = true
if addon.Modules and addon.Modules.DB then
local setting = addon.Modules.DB:GetSetting("markUnusableItems")
if setting ~= nil then markUnusable = setting and true or false end
end
local overlay = button.unusableOverlay
if not markUnusable or not unusable then
if overlay then overlay:Hide() end
return
end
overlay = EnsureUnusableOverlay(button)
local r, g, b, a = GetUnusableColor()
-- Match ItemButton.lua exactly: configured alpha is reduced once by 45%.
local alpha = (a or 1.0) * 0.45
overlay:SetVertexColor(r or 0.9, g or 0.2, b or 0.2, alpha)
overlay:Show()
end
local function RefreshUsabilityAsync(button, itemData, bagID, slotID, isReadOnly, otherCharName)
if not button or not itemData or not itemData.link then return end
if isReadOnly or otherCharName then return end
local detection = addon.Modules and addon.Modules.ItemDetection
if not detection then return end
-- Never scan tooltip state while the sort engine is actively moving/locking items.
-- The final post-sort redraw will call SetItem again and schedule a safe refresh.
if addon.Modules.SortEngine and addon.Modules.SortEngine.sortingInProgress then
return
end
local link = itemData.link
local cached = detection.IsUnusableCached and detection:IsUnusableCached(itemData) or nil
if cached ~= nil then
ApplyUnusableTint(button, cached)
return
end
-- Avoid duplicate jobs when BAG_UPDATE causes several redraws for the same item.
if button._gudaUsabilityPendingLink == link then return end
button._gudaUsabilityPendingLink = link
local function DoRefresh()
if button._gudaUsabilityPendingLink ~= link then return end
button._gudaUsabilityPendingLink = nil
if not button.IsShown or not button:IsShown() or not button.hasItem then return end
if button.otherChar or button.isReadOnly then return end
if button.bagID ~= bagID or button.slotID ~= slotID then return end
if not button.itemData or button.itemData.link ~= link then return end
local props = detection:GetItemProperties(button.itemData, button.bagID, button.slotID)
ApplyUnusableTint(button, props and props.isUnusable)
end
local Utils = addon.Modules and addon.Modules.Utils
if Utils and Utils.QueueWork then
Utils:QueueWork(DoRefresh)
else
DoRefresh()
end
end
function Guda_ItemButton_SetItem(self, bagID, slotID, itemData, isBank, otherCharName, matchesFilter, isReadOnly)
OriginalSetItem(self, bagID, slotID, itemData, isBank, otherCharName, matchesFilter, isReadOnly)
if not self then return end
local currentData = self.itemData or itemData
local currentLink = currentData and currentData.link or nil
-- Cancel a stale pending job if this pooled button now represents another item.
if self._gudaUsabilityPendingLink and self._gudaUsabilityPendingLink ~= currentLink then
self._gudaUsabilityPendingLink = nil
end
if self.hasItem and currentData then
RefreshUsabilityAsync(self, currentData, tonumber(bagID), tonumber(slotID), isReadOnly, otherCharName)
elseif self.unusableOverlay then
self.unusableOverlay:Hide()
end
end
addon:Debug("ClassicAPI usability tint safety enabled")
--=====================================================
-- Consolidated from UI/TooltipPositionFix.lua
--=====================================================
-- Guda item/comparison tooltip positioning fix.
-- Keeps Guda item tooltips toward the inside of the screen so comparison
-- tooltips have room to render with pfUI/DFUI and the ClassicAPI tooltip code.
local addon = Guda
if not addon or not Guda_ItemButton_OnEnter then return end
local originalOnEnter = Guda_ItemButton_OnEnter
local function IsCursorAnchored()
if GameTooltip and GameTooltip.GetAnchorType then
return GameTooltip:GetAnchorType() == "ANCHOR_CURSOR"
end
-- Compatibility with pfUI versions that expose cursor positioning only
-- through their configuration table.
if pfUI and pfUI.env and pfUI.env.C and pfUI.env.C.tooltip then
return pfUI.env.C.tooltip.position == "cursor"
end
return false
end
local function PositionMainTooltip(button)
if not button or not GameTooltip or not GameTooltip:IsShown() then return end
if IsCursorAnchored() then return end
local centerX = button.GetCenter and button:GetCenter()
local screenWidth = UIParent and UIParent.GetWidth and UIParent:GetWidth()
if not centerX or not screenWidth or screenWidth <= 0 then return end
GameTooltip:ClearAllPoints()
if centerX < (screenWidth / 2) then
-- Item is on the left: grow the tooltip group toward the right.
GameTooltip:SetPoint("BOTTOMLEFT", button, "TOPRIGHT", -10, 0)
else
-- Preserve Guda's historical position for items on the right.
GameTooltip:SetPoint("BOTTOMRIGHT", button, "TOPLEFT", 10, 0)
end
end
local function GetComparisonGap(tooltip)
local separation = 6
local edgeSize = 0
if tooltip and tooltip.GetBackdrop then
local backdrop = tooltip:GetBackdrop()
if type(backdrop) == "table" and backdrop.edgeSize then
edgeSize = backdrop.edgeSize
end
end
return separation + edgeSize
end
local function PositionComparisonTooltips()
if not GameTooltip or not GameTooltip:IsShown() then return end
local first = ShoppingTooltip1
local second = ShoppingTooltip2
if not first or not first:IsShown() then return end
local screenWidth = UIParent and UIParent.GetWidth and UIParent:GetWidth()
local left = GameTooltip.GetLeft and GameTooltip:GetLeft()
local right = GameTooltip.GetRight and GameTooltip:GetRight()
if not screenWidth or not left or not right then return end
local leftSpace = left
local rightSpace = screenWidth - right
local useLeft = leftSpace > rightSpace
local gap = GetComparisonGap(first)
first:SetOwner(GameTooltip, "ANCHOR_NONE")
first:ClearAllPoints()
if useLeft then
first:SetPoint("TOPRIGHT", GameTooltip, "TOPLEFT", -gap, -10)
else
first:SetPoint("TOPLEFT", GameTooltip, "TOPRIGHT", gap, -10)
end
if second and second:IsShown() then
second:SetOwner(first, "ANCHOR_NONE")
second:ClearAllPoints()
if useLeft then
second:SetPoint("TOPRIGHT", first, "TOPLEFT", -gap, 0)
else
second:SetPoint("TOPLEFT", first, "TOPRIGHT", gap, 0)
end
end
end
function Guda_ItemButton_OnEnter(self)
originalOnEnter(self)
-- Empty/drop-target buttons either have no item tooltip or use a small
-- custom tooltip that does not participate in equipment comparison.
if not self or self.isDropTarget or not self.hasItem then return end
if not GameTooltip or not GameTooltip:IsShown() then return end
if IsCursorAnchored() then return end
PositionMainTooltip(self)
-- Comparison tooltips may already have been shown synchronously by a
-- tooltip hook. Re-anchor them now; if they are shown later, ClassicAPI's
-- own side selection will use the corrected GameTooltip position.
PositionComparisonTooltips()
end
addon:Debug("Guda comparison tooltip positioning fix enabled")
+109
View File
@@ -833,3 +833,112 @@ function QuestItemBar:Debug()
end
QuestItemBar.isLoaded = true
--=====================================================
-- Consolidated from UI/QuestItemBarClassicAPI.lua
--=====================================================
-- Guda ClassicAPI Quest Item Bar fast path
-- Keeps the upstream UI/flyout logic but reuses BagScanner item data so the
-- quest detector does not perform a second container scan for each item.
local addon = Guda
local QuestItemBar = addon.Modules.QuestItemBar
if not QuestItemBar then return end
function QuestItemBar:CheckQuestItemUsable(bagID, slotID)
if not bagID or not slotID then return false, false, false end
local itemData = nil
if addon.Modules.BagScanner and addon.Modules.BagScanner.GetBagData then
local bagData = addon.Modules.BagScanner:GetBagData()
local bag = bagData and bagData[bagID]
itemData = bag and bag.slots and bag.slots[slotID]
end
if addon.Modules.ItemDetection and itemData then
local props = addon.Modules.ItemDetection:GetItemProperties(itemData, bagID, slotID)
if props then
return props.isQuestItem, props.isQuestStarter, props.isQuestUsable
end
end
-- Preserve the upstream fallback if the slot is not represented in the
-- shared snapshot for any reason.
if addon.Modules.Utils and addon.Modules.Utils.IsQuestItem then
local isQuestItem, isQuestStarter =
addon.Modules.Utils:IsQuestItem(bagID, slotID, itemData and itemData.link, false, false)
return isQuestItem, isQuestStarter, isQuestItem
end
return false, false, false
end
addon:Debug("QuestItemBar ClassicAPI snapshot detector loaded")
--=====================================================
-- Consolidated from UI/QuestItemBarMoveSafety.lua
--=====================================================
-- Guda Quest Item Bar movement safety
-- Prevents structural Quest Bar refreshes while the frame is being dragged.
-- Lua 5.0 compatible.
local addon = Guda
if not addon or not addon.Modules or not addon.Modules.QuestItemBar then return end
local QuestItemBar = addon.Modules.QuestItemBar
if not QuestItemBar.Update then return end
local OriginalUpdate = QuestItemBar.Update
local function FlushDeferredUpdate(barFrame)
if not barFrame or barFrame.isMoving then return end
if not barFrame._gudaQuestBarDeferredUpdate then return end
barFrame._gudaQuestBarDeferredUpdate = nil
QuestItemBar:Update()
end
local function WrapMouseUp(frame, barFrame)
if not frame or frame._gudaQuestBarMoveSafetyWrapped then return end
local originalMouseUp = frame:GetScript("OnMouseUp")
frame._gudaQuestBarMoveSafetyWrapped = true
frame:SetScript("OnMouseUp", function()
if originalMouseUp then
originalMouseUp()
end
FlushDeferredUpdate(barFrame or Guda_QuestItemBar)
end)
end
local function EnsureMoveSafetyHooks()
local barFrame = Guda_QuestItemBar
if not barFrame then return end
-- The bar itself can be dragged from its empty area.
WrapMouseUp(barFrame, barFrame)
-- The two visible quest item buttons also start/stop movement on behalf
-- of their parent frame. Wrap them after they are created by Update().
WrapMouseUp(getglobal("Guda_QuestItemBarButton1"), barFrame)
WrapMouseUp(getglobal("Guda_QuestItemBarButton2"), barFrame)
end
function QuestItemBar:Update()
local barFrame = Guda_QuestItemBar
-- BAG_UPDATE and other events can arrive while StartMoving() is active.
-- Rebuilding/hiding/resizing the frame in that state is unsafe on 1.12.
-- Coalesce any number of refresh requests into one update after mouse-up.
if barFrame and barFrame.isMoving then
barFrame._gudaQuestBarDeferredUpdate = true
return
end
OriginalUpdate(self)
EnsureMoveSafetyHooks()
end
addon:Debug("QuestItemBar movement safety enabled")
-37
View File
@@ -1,37 +0,0 @@
-- Guda ClassicAPI Quest Item Bar fast path
-- Keeps the upstream UI/flyout logic but reuses BagScanner item data so the
-- quest detector does not perform a second container scan for each item.
local addon = Guda
local QuestItemBar = addon.Modules.QuestItemBar
if not QuestItemBar then return end
function QuestItemBar:CheckQuestItemUsable(bagID, slotID)
if not bagID or not slotID then return false, false, false end
local itemData = nil
if addon.Modules.BagScanner and addon.Modules.BagScanner.GetBagData then
local bagData = addon.Modules.BagScanner:GetBagData()
local bag = bagData and bagData[bagID]
itemData = bag and bag.slots and bag.slots[slotID]
end
if addon.Modules.ItemDetection and itemData then
local props = addon.Modules.ItemDetection:GetItemProperties(itemData, bagID, slotID)
if props then
return props.isQuestItem, props.isQuestStarter, props.isQuestUsable
end
end
-- Preserve the upstream fallback if the slot is not represented in the
-- shared snapshot for any reason.
if addon.Modules.Utils and addon.Modules.Utils.IsQuestItem then
local isQuestItem, isQuestStarter =
addon.Modules.Utils:IsQuestItem(bagID, slotID, itemData and itemData.link, false, false)
return isQuestItem, isQuestStarter, isQuestItem
end
return false, false, false
end
addon:Debug("QuestItemBar ClassicAPI snapshot detector loaded")
-64
View File
@@ -1,64 +0,0 @@
-- Guda Quest Item Bar movement safety
-- Prevents structural Quest Bar refreshes while the frame is being dragged.
-- Lua 5.0 compatible.
local addon = Guda
if not addon or not addon.Modules or not addon.Modules.QuestItemBar then return end
local QuestItemBar = addon.Modules.QuestItemBar
if not QuestItemBar.Update then return end
local OriginalUpdate = QuestItemBar.Update
local function FlushDeferredUpdate(barFrame)
if not barFrame or barFrame.isMoving then return end
if not barFrame._gudaQuestBarDeferredUpdate then return end
barFrame._gudaQuestBarDeferredUpdate = nil
QuestItemBar:Update()
end
local function WrapMouseUp(frame, barFrame)
if not frame or frame._gudaQuestBarMoveSafetyWrapped then return end
local originalMouseUp = frame:GetScript("OnMouseUp")
frame._gudaQuestBarMoveSafetyWrapped = true
frame:SetScript("OnMouseUp", function()
if originalMouseUp then
originalMouseUp()
end
FlushDeferredUpdate(barFrame or Guda_QuestItemBar)
end)
end
local function EnsureMoveSafetyHooks()
local barFrame = Guda_QuestItemBar
if not barFrame then return end
-- The bar itself can be dragged from its empty area.
WrapMouseUp(barFrame, barFrame)
-- The two visible quest item buttons also start/stop movement on behalf
-- of their parent frame. Wrap them after they are created by Update().
WrapMouseUp(getglobal("Guda_QuestItemBarButton1"), barFrame)
WrapMouseUp(getglobal("Guda_QuestItemBarButton2"), barFrame)
end
function QuestItemBar:Update()
local barFrame = Guda_QuestItemBar
-- BAG_UPDATE and other events can arrive while StartMoving() is active.
-- Rebuilding/hiding/resizing the frame in that state is unsafe on 1.12.
-- Coalesce any number of refresh requests into one update after mouse-up.
if barFrame and barFrame.isMoving then
barFrame._gudaQuestBarDeferredUpdate = true
return
end
OriginalUpdate(self)
EnsureMoveSafetyHooks()
end
addon:Debug("QuestItemBar movement safety enabled")
-110
View File
@@ -1,110 +0,0 @@
-- Guda item/comparison tooltip positioning fix.
-- Keeps Guda item tooltips toward the inside of the screen so comparison
-- tooltips have room to render with pfUI/DFUI and the ClassicAPI tooltip code.
local addon = Guda
if not addon or not Guda_ItemButton_OnEnter then return end
local originalOnEnter = Guda_ItemButton_OnEnter
local function IsCursorAnchored()
if GameTooltip and GameTooltip.GetAnchorType then
return GameTooltip:GetAnchorType() == "ANCHOR_CURSOR"
end
-- Compatibility with pfUI versions that expose cursor positioning only
-- through their configuration table.
if pfUI and pfUI.env and pfUI.env.C and pfUI.env.C.tooltip then
return pfUI.env.C.tooltip.position == "cursor"
end
return false
end
local function PositionMainTooltip(button)
if not button or not GameTooltip or not GameTooltip:IsShown() then return end
if IsCursorAnchored() then return end
local centerX = button.GetCenter and button:GetCenter()
local screenWidth = UIParent and UIParent.GetWidth and UIParent:GetWidth()
if not centerX or not screenWidth or screenWidth <= 0 then return end
GameTooltip:ClearAllPoints()
if centerX < (screenWidth / 2) then
-- Item is on the left: grow the tooltip group toward the right.
GameTooltip:SetPoint("BOTTOMLEFT", button, "TOPRIGHT", -10, 0)
else
-- Preserve Guda's historical position for items on the right.
GameTooltip:SetPoint("BOTTOMRIGHT", button, "TOPLEFT", 10, 0)
end
end
local function GetComparisonGap(tooltip)
local separation = 6
local edgeSize = 0
if tooltip and tooltip.GetBackdrop then
local backdrop = tooltip:GetBackdrop()
if type(backdrop) == "table" and backdrop.edgeSize then
edgeSize = backdrop.edgeSize
end
end
return separation + edgeSize
end
local function PositionComparisonTooltips()
if not GameTooltip or not GameTooltip:IsShown() then return end
local first = ShoppingTooltip1
local second = ShoppingTooltip2
if not first or not first:IsShown() then return end
local screenWidth = UIParent and UIParent.GetWidth and UIParent:GetWidth()
local left = GameTooltip.GetLeft and GameTooltip:GetLeft()
local right = GameTooltip.GetRight and GameTooltip:GetRight()
if not screenWidth or not left or not right then return end
local leftSpace = left
local rightSpace = screenWidth - right
local useLeft = leftSpace > rightSpace
local gap = GetComparisonGap(first)
first:SetOwner(GameTooltip, "ANCHOR_NONE")
first:ClearAllPoints()
if useLeft then
first:SetPoint("TOPRIGHT", GameTooltip, "TOPLEFT", -gap, -10)
else
first:SetPoint("TOPLEFT", GameTooltip, "TOPRIGHT", gap, -10)
end
if second and second:IsShown() then
second:SetOwner(first, "ANCHOR_NONE")
second:ClearAllPoints()
if useLeft then
second:SetPoint("TOPRIGHT", first, "TOPLEFT", -gap, 0)
else
second:SetPoint("TOPLEFT", first, "TOPRIGHT", gap, 0)
end
end
end
function Guda_ItemButton_OnEnter(self)
originalOnEnter(self)
-- Empty/drop-target buttons either have no item tooltip or use a small
-- custom tooltip that does not participate in equipment comparison.
if not self or self.isDropTarget or not self.hasItem then return end
if not GameTooltip or not GameTooltip:IsShown() then return end
if IsCursorAnchored() then return end
PositionMainTooltip(self)
-- Comparison tooltips may already have been shown synchronously by a
-- tooltip hook. Re-anchor them now; if they are shown later, ClassicAPI's
-- own side selection will use the corrected GameTooltip position.
PositionComparisonTooltips()
end
addon:Debug("Guda comparison tooltip positioning fix enabled")
+73
View File
@@ -305,3 +305,76 @@ function TrackedItemBar:Update()
end
addon:Debug("TrackedItemBar ClassicAPI snapshot consumer loaded")
--=====================================================
-- Consolidated from UI/TrackedItemBarMoveSafety.lua
--=====================================================
-- Guda Tracked Item Bar movement safety
-- Prevents structural Tracked Item Bar refreshes while the frame is being dragged.
-- Lua 5.0 compatible.
local addon = Guda
if not addon or not addon.Modules or not addon.Modules.TrackedItemBar then return end
local TrackedItemBar = addon.Modules.TrackedItemBar
if not TrackedItemBar.Update then return end
local OriginalUpdate = TrackedItemBar.Update
local function FlushDeferredUpdate(barFrame)
if not barFrame or barFrame.isMoving then return end
if not barFrame._gudaTrackedBarDeferredUpdate then return end
barFrame._gudaTrackedBarDeferredUpdate = nil
TrackedItemBar:Update()
end
local function WrapMouseUp(frame, barFrame)
if not frame or frame._gudaTrackedBarMoveSafetyWrapped then return end
local originalMouseUp = frame:GetScript("OnMouseUp")
frame._gudaTrackedBarMoveSafetyWrapped = true
frame:SetScript("OnMouseUp", function()
if originalMouseUp then
originalMouseUp()
end
FlushDeferredUpdate(barFrame or Guda_TrackedItemBar)
end)
end
local function EnsureMoveSafetyHooks()
local barFrame = Guda_TrackedItemBar
if not barFrame then return end
-- The bar itself can be dragged from its empty area.
WrapMouseUp(barFrame, barFrame)
-- Tracked-item buttons can also start/stop movement on behalf of the bar.
-- Buttons are created dynamically, so wrap every currently existing one.
local i = 1
while true do
local button = getglobal("Guda_TrackedItemBarButton" .. i)
if not button then break end
WrapMouseUp(button, barFrame)
i = i + 1
end
end
function TrackedItemBar:Update()
local barFrame = Guda_TrackedItemBar
-- BAG_UPDATE, PLAYER_LEVEL_UP and other refreshes can arrive while
-- StartMoving() is active. Rebuilding/hiding/resizing the frame in that
-- state is unsafe on 1.12, so coalesce them into one post-drag refresh.
if barFrame and barFrame.isMoving then
barFrame._gudaTrackedBarDeferredUpdate = true
return
end
OriginalUpdate(self)
EnsureMoveSafetyHooks()
end
addon:Debug("TrackedItemBar movement safety enabled")
-69
View File
@@ -1,69 +0,0 @@
-- Guda Tracked Item Bar movement safety
-- Prevents structural Tracked Item Bar refreshes while the frame is being dragged.
-- Lua 5.0 compatible.
local addon = Guda
if not addon or not addon.Modules or not addon.Modules.TrackedItemBar then return end
local TrackedItemBar = addon.Modules.TrackedItemBar
if not TrackedItemBar.Update then return end
local OriginalUpdate = TrackedItemBar.Update
local function FlushDeferredUpdate(barFrame)
if not barFrame or barFrame.isMoving then return end
if not barFrame._gudaTrackedBarDeferredUpdate then return end
barFrame._gudaTrackedBarDeferredUpdate = nil
TrackedItemBar:Update()
end
local function WrapMouseUp(frame, barFrame)
if not frame or frame._gudaTrackedBarMoveSafetyWrapped then return end
local originalMouseUp = frame:GetScript("OnMouseUp")
frame._gudaTrackedBarMoveSafetyWrapped = true
frame:SetScript("OnMouseUp", function()
if originalMouseUp then
originalMouseUp()
end
FlushDeferredUpdate(barFrame or Guda_TrackedItemBar)
end)
end
local function EnsureMoveSafetyHooks()
local barFrame = Guda_TrackedItemBar
if not barFrame then return end
-- The bar itself can be dragged from its empty area.
WrapMouseUp(barFrame, barFrame)
-- Tracked-item buttons can also start/stop movement on behalf of the bar.
-- Buttons are created dynamically, so wrap every currently existing one.
local i = 1
while true do
local button = getglobal("Guda_TrackedItemBarButton" .. i)
if not button then break end
WrapMouseUp(button, barFrame)
i = i + 1
end
end
function TrackedItemBar:Update()
local barFrame = Guda_TrackedItemBar
-- BAG_UPDATE, PLAYER_LEVEL_UP and other refreshes can arrive while
-- StartMoving() is active. Rebuilding/hiding/resizing the frame in that
-- state is unsafe on 1.12, so coalesce them into one post-drag refresh.
if barFrame and barFrame.isMoving then
barFrame._gudaTrackedBarDeferredUpdate = true
return
end
OriginalUpdate(self)
EnsureMoveSafetyHooks()
end
addon:Debug("TrackedItemBar movement safety enabled")
-129
View File
@@ -1,129 +0,0 @@
-- Guda ClassicAPI usability tint safety
-- Re-applies unusable-item tint after sorting/moves without synchronous mass scans.
-- Lua 5.0 compatible.
local addon = Guda
if not addon or not Guda_ItemButton_SetItem then return end
local OriginalSetItem = Guda_ItemButton_SetItem
local function EnsureUnusableOverlay(button)
if button.unusableOverlay then return button.unusableOverlay end
local overlay = button:CreateTexture(nil, "OVERLAY")
overlay:SetAllPoints(button)
overlay:SetTexture("Interface\\ChatFrame\\ChatFrameBackground")
overlay:Hide()
button.unusableOverlay = overlay
return overlay
end
-- Mirror ItemButton.lua's unusable color selection exactly. The original helper
-- is local to ItemButton.lua, so this safety layer cannot call it directly.
local function GetUnusableColor()
if pfUI and C and C.appearance and C.appearance.bags and C.appearance.bags.unusable_color then
local cr, cg, cb, ca = strsplit(",", C.appearance.bags.unusable_color)
local r = tonumber(cr) or 0.9
local g = tonumber(cg) or 0.2
local b = tonumber(cb) or 0.2
local a = tonumber(ca) or 1.0
return r, g, b, a
end
if RED_FONT_COLOR then
return RED_FONT_COLOR.r, RED_FONT_COLOR.g, RED_FONT_COLOR.b, 1.0
end
return 0.9, 0.2, 0.2, 1.0
end
local function ApplyUnusableTint(button, unusable)
if not button then return end
local markUnusable = true
if addon.Modules and addon.Modules.DB then
local setting = addon.Modules.DB:GetSetting("markUnusableItems")
if setting ~= nil then markUnusable = setting and true or false end
end
local overlay = button.unusableOverlay
if not markUnusable or not unusable then
if overlay then overlay:Hide() end
return
end
overlay = EnsureUnusableOverlay(button)
local r, g, b, a = GetUnusableColor()
-- Match ItemButton.lua exactly: configured alpha is reduced once by 45%.
local alpha = (a or 1.0) * 0.45
overlay:SetVertexColor(r or 0.9, g or 0.2, b or 0.2, alpha)
overlay:Show()
end
local function RefreshUsabilityAsync(button, itemData, bagID, slotID, isReadOnly, otherCharName)
if not button or not itemData or not itemData.link then return end
if isReadOnly or otherCharName then return end
local detection = addon.Modules and addon.Modules.ItemDetection
if not detection then return end
-- Never scan tooltip state while the sort engine is actively moving/locking items.
-- The final post-sort redraw will call SetItem again and schedule a safe refresh.
if addon.Modules.SortEngine and addon.Modules.SortEngine.sortingInProgress then
return
end
local link = itemData.link
local cached = detection.IsUnusableCached and detection:IsUnusableCached(itemData) or nil
if cached ~= nil then
ApplyUnusableTint(button, cached)
return
end
-- Avoid duplicate jobs when BAG_UPDATE causes several redraws for the same item.
if button._gudaUsabilityPendingLink == link then return end
button._gudaUsabilityPendingLink = link
local function DoRefresh()
if button._gudaUsabilityPendingLink ~= link then return end
button._gudaUsabilityPendingLink = nil
if not button.IsShown or not button:IsShown() or not button.hasItem then return end
if button.otherChar or button.isReadOnly then return end
if button.bagID ~= bagID or button.slotID ~= slotID then return end
if not button.itemData or button.itemData.link ~= link then return end
local props = detection:GetItemProperties(button.itemData, button.bagID, button.slotID)
ApplyUnusableTint(button, props and props.isUnusable)
end
local Utils = addon.Modules and addon.Modules.Utils
if Utils and Utils.QueueWork then
Utils:QueueWork(DoRefresh)
else
DoRefresh()
end
end
function Guda_ItemButton_SetItem(self, bagID, slotID, itemData, isBank, otherCharName, matchesFilter, isReadOnly)
OriginalSetItem(self, bagID, slotID, itemData, isBank, otherCharName, matchesFilter, isReadOnly)
if not self then return end
local currentData = self.itemData or itemData
local currentLink = currentData and currentData.link or nil
-- Cancel a stale pending job if this pooled button now represents another item.
if self._gudaUsabilityPendingLink and self._gudaUsabilityPendingLink ~= currentLink then
self._gudaUsabilityPendingLink = nil
end
if self.hasItem and currentData then
RefreshUsabilityAsync(self, currentData, tonumber(bagID), tonumber(slotID), isReadOnly, otherCharName)
elseif self.unusableOverlay then
self.unusableOverlay:Hide()
end
end
addon:Debug("ClassicAPI usability tint safety enabled")