fix: move item to empty category

This commit is contained in:
Vati
2026-04-16 02:05:51 +04:00
parent 150c9d3574
commit 1af002fa08
4 changed files with 331 additions and 56 deletions
+182 -11
View File
@@ -263,30 +263,97 @@ local function IsInCategoryView(isBank)
return (addon.Modules.DB:GetSetting(key) or "single") == "category"
end
-- Auto-clear cursor tracking when cursor is truly empty
-- Uses a short delay to avoid clearing during the pickup transition
-- (CURSOR_UPDATE fires before the item is fully on the cursor)
-- Auto-clear cursor tracking when cursor is truly empty, and notify BagFrame
-- of drag-state transitions. In 1.12 CURSOR_UPDATE is unreliable for item
-- pickups, so we also poll CursorHasItem() on a throttled OnUpdate —
-- matching the Anniversary version's approach.
local cursorWatcher = CreateFrame("Frame")
cursorWatcher:RegisterEvent("CURSOR_UPDATE")
cursorWatcher:RegisterEvent("ITEM_LOCK_CHANGED")
cursorWatcher._lastCarrying = false
cursorWatcher._pollAccum = 0
local function NotifyDragState()
if addon.Modules.BagFrame and addon.Modules.BagFrame.SetDragging then
-- Suppress drop-target state updates while the user is dragging the
-- bag frame itself — nothing on the cursor there, and Update() is
-- deliberately short-circuited anyway.
if addon.Modules.BagFrame.IsFrameMoving
and addon.Modules.BagFrame:IsFrameMoving() then
return
end
local carrying = CursorHasItem and CursorHasItem() and true or false
if carrying ~= cursorWatcher._lastCarrying then
cursorWatcher._lastCarrying = carrying
addon.Modules.BagFrame:SetDragging(carrying)
end
end
end
cursorWatcher:SetScript("OnEvent", function()
-- Don't clear immediately — wait a frame to let the pickup finish
NotifyDragState()
if not cursorItemInfo then
HideCategoryDropIndicator()
return
end
-- Schedule a check next frame
this.pendingCheck = true
end)
cursorWatcher:SetScript("OnUpdate", function()
if not this.pendingCheck then return end
this.pendingCheck = nil
-- Now check if cursor actually has an item
if cursorItemInfo and (not CursorHasItem or not CursorHasItem()) then
cursorItemInfo = nil
HideCategoryDropIndicator()
-- Throttled cursor poll (~10Hz) as a safety net for 1.12's event gaps.
this._pollAccum = (this._pollAccum or 0) + arg1
if this._pollAccum >= 0.1 then
this._pollAccum = 0
NotifyDragState()
end
if this.pendingCheck then
this.pendingCheck = nil
if cursorItemInfo and (not CursorHasItem or not CursorHasItem()) then
cursorItemInfo = nil
HideCategoryDropIndicator()
end
end
end)
-- Pulsing green glow applied to empty-category drop-target placeholder buttons.
-- Uses an OnUpdate-driven sine wave since vanilla 1.12 has no animation groups.
-- Uses a solid-color texture filling the full button, with additive blend +
-- alpha pulse — looks the same regardless of the user's iconSize setting.
local function EnsureDropTargetGlow(button)
if not button.dropGlow then
local g = button:CreateTexture(nil, "OVERLAY")
g:SetTexture(0.2, 1.0, 0.2, 1) -- solid green; alpha is modulated each frame
g:SetBlendMode("ADD")
g:SetAllPoints(button) -- cover the whole button, scales with iconSize
button.dropGlow = g
local driver = CreateFrame("Frame", nil, button)
driver._t = 0
driver:SetScript("OnUpdate", function()
this._t = this._t + arg1
-- period ~1.2s => 2π/1.2 ≈ 5.24
local phase = (math.sin(this._t * 5.24) + 1) * 0.5
if this:GetParent().dropGlow then
-- Subtle pulse: 0.15 → 0.45 alpha with additive blend.
this:GetParent().dropGlow:SetAlpha(0.15 + phase * 0.30)
end
end)
button.dropGlowDriver = driver
end
-- If the button was resized since last show, re-anchor defensively.
button.dropGlow:ClearAllPoints()
button.dropGlow:SetAllPoints(button)
button.dropGlow:Show()
button.dropGlowDriver:Show()
end
local function StopDropTargetGlow(button)
if button.dropGlow then button.dropGlow:Hide() end
if button.dropGlowDriver then button.dropGlowDriver:Hide() end
button.isDropTarget = false
button.dropTargetCategoryId = nil
end
-- Use shared tooltip from Utils module (retrieved on-demand to ensure Utils is loaded)
-- Helper function to check if an item is a quest item
@@ -1080,6 +1147,17 @@ function Guda_ItemButton_OnLoad(self)
end)
self:SetScript("OnClick", function()
-- Click on a drop-target placeholder while carrying an item on the
-- cursor: route to the same handler as OnReceiveDrag (assign to
-- category). Without an item on the cursor a click is a no-op.
if this.isDropTarget then
if CursorHasItem and CursorHasItem() then
local handler = this:GetScript("OnReceiveDrag")
if handler then handler() end
end
return
end
-- Lock/unlock item with Ctrl+Right-Click
if IsControlKeyDown() and arg1 == "RightButton" and this.hasItem and not this.otherChar and not this.isReadOnly then
local link = GetContainerItemLink(this.bagID, this.slotID)
@@ -1240,6 +1318,24 @@ function Guda_ItemButton_OnLoad(self)
local info = Guda_GetCursorItemInfo()
if not info then return end
-- Empty-category drop target: assign cursor item to this.dropTargetCategoryId
if this.isDropTarget and this.dropTargetCategoryId then
if info.itemID and addon.Modules.CategoryManager then
addon.Modules.CategoryManager:AssignItemToCategory(info.itemID, this.dropTargetCategoryId)
addon:Debug("Assigned item %d to empty category: %s", info.itemID, this.dropTargetCategoryId)
end
if CursorHasItem() then
PickupContainerItem(info.bagID, info.slotID)
end
dropCooldownTime = GetTime() + 0.3
HideCategoryDropIndicator()
Guda_ClearCursorItem()
if addon.Modules.BagFrame and addon.Modules.BagFrame.Update then
addon.Modules.BagFrame:Update()
end
return
end
local inCatView = IsInCategoryView(this.isBank)
if not inCatView then
-- Single view: let default swap happen
@@ -1337,6 +1433,14 @@ local function ResetButtonVisualState(self)
local chargesText = getglobal(self:GetName().."_Charges")
if chargesText then chargesText:Hide() end
-- Reset effects the drop-target render may have applied on this pooled button
self:SetAlpha(1)
local iconTex = getglobal(self:GetName().."IconTexture") or getglobal(self:GetName().."Icon") or self.icon or self.Icon
if iconTex then
if iconTex.SetDesaturated then iconTex:SetDesaturated(false) end
iconTex:SetVertexColor(1, 1, 1)
end
-- Clear cooldown overlay
local cd = getglobal(self:GetName().."Cooldown") or self.cooldown
if cd then
@@ -1658,6 +1762,60 @@ function Guda_ItemButton_SetItem(self, bagID, slotID, itemData, isBank, otherCha
-- Reset all visual state before reassigning pooled button
ResetButtonVisualState(self)
-- Pooled buttons may have carried a drop-target glow from the previous
-- render — clear it before deciding what this button is now.
StopDropTargetGlow(self)
-- Drop-target pseudo-items (empty category placeholders during drag).
-- Shown with the category's icon, dim+desaturated, with a pulsing green
-- glow. OnReceiveDrag/OnClick will route to AssignItemToCategory.
if itemData and itemData.isDropTarget then
self.bagID = 0
self.slotID = 0
self.bagIndex = -100
self.itemData = itemData
self.isBank = isBank or false
self.otherChar = nil
self.isReadOnly = false
self.isMail = false
self.hasItem = false
self.isDropTarget = true
self.dropTargetCategoryId = itemData.categoryId
SetupDragDrop(self)
local iconSize = 37
if addon and addon.Modules and addon.Modules.Utils and addon.Modules.Utils.SafeCall then
iconSize = addon.Modules.Utils:SafeCall("DB", "GetSetting", "iconSize") or iconSize
end
self:SetWidth(iconSize)
self:SetHeight(iconSize)
if SetItemButtonTexture then
SetItemButtonTexture(self, itemData.texture)
end
local iconTexture = getglobal(self:GetName().."IconTexture") or getglobal(self:GetName().."Icon") or self.icon or self.Icon
if iconTexture then
iconTexture:SetTexture(itemData.texture)
-- Mirror PositionIconAndBorders() so the category icon fills the
-- full button at the user's configured iconSize. PositionIconAndBorders
-- itself is guarded by `self.hasItem`, which drop-targets don't set.
iconTexture:ClearAllPoints()
iconTexture:SetPoint("CENTER", self, "CENTER", 0, 0)
iconTexture:SetWidth(iconSize)
iconTexture:SetHeight(iconSize)
iconTexture:SetTexCoord(0, 1, 0, 1)
iconTexture:Show()
if iconTexture.SetDesaturated then iconTexture:SetDesaturated(true) end
iconTexture:SetVertexColor(0.6, 1.0, 0.6)
end
if SetItemButtonCount then SetItemButtonCount(self, 0) end
self:SetAlpha(0.85)
EnsureDropTargetGlow(self)
self:Show()
return
end
-- Set button properties
self.bagID = bagID
@@ -2198,6 +2356,19 @@ end
-- OnEnter handler (show tooltip)
function Guda_ItemButton_OnEnter(self)
addon:Debug("OnEnter FIRED: button=%s CursorHasItem=%s", tostring(self:GetName()), tostring(CursorHasItem and CursorHasItem()))
-- Drop-target placeholder: simple tooltip, skip the normal item tooltip path.
if self.isDropTarget then
GameTooltip:SetOwner(UIParent, "ANCHOR_NONE")
GameTooltip:ClearAllPoints()
GameTooltip:SetPoint("BOTTOMRIGHT", self, "TOPLEFT", 10, 0)
local catName = self.dropTargetCategoryId or ""
local label = (Guda_L and Guda_L["Drop to assign to %s"]) or "Drop to assign to %s"
GameTooltip:SetText(format(label, catName), 1, 1, 1)
GameTooltip:Show()
return
end
-- Category drag-drop: show "+" indicator when hovering with cursor item in category view
local hasCursor = CursorHasItem and CursorHasItem()
if hasCursor then