fix(inventory): correct drag overlay priority

Keep the persistent selection indicator above retail's waiting mesh, use the normal green accept circle for backpack-grid placement, and reserve the green drop-in arrow for bag-column containers as ItemList_DragOver does.

Co-Authored-By: Codex <codex@openai.com>
This commit is contained in:
Erik 2026-07-13 09:21:22 +02:00
parent ace5880fed
commit 64a056e656
6 changed files with 63 additions and 19 deletions

View file

@ -365,8 +365,7 @@ public sealed class InventoryController : IItemListDragHandler, IRetainedPanelCo
var cell = new UiItemSlot { SpriteResolve = list.SpriteResolve };
cell.SetItem(guid, tex, dragIconTexture: dragTex);
cell.SlotIndex = list.GetNumUIItems(); // index it will occupy (== its slot in a packed list)
cell.DragAcceptSprite = 0x060011F7u; // green insert arrow (export-confirmed)
cell.DragRejectSprite = 0x060011F8u; // red circle
ConfigureDropFeedback(list, cell);
cell.DoubleClicked = () => _itemInteraction?.ActivateItem(guid);
if (isContainer)
{
@ -388,14 +387,27 @@ public sealed class InventoryController : IItemListDragHandler, IRetainedPanelCo
fallback();
}
private static void AddEmptyCell(UiItemList list)
private void AddEmptyCell(UiItemList list)
{
var cell = new UiItemSlot { SpriteResolve = list.SpriteResolve, SlotIndex = list.GetNumUIItems() };
cell.DragAcceptSprite = 0x060011F7u;
cell.DragRejectSprite = 0x060011F8u;
ConfigureDropFeedback(list, cell);
list.AddItem(cell);
}
/// <summary>
/// Bind the exact ItemList_DragOver state for this destination. A normal contents-grid
/// insertion uses ItemSlot_DragOver_Accept (0x10000041 → green circle 0x060011F9).
/// An occupied container selector uses ItemSlot_DragOver_DropIn
/// (0x10000046 → green arrow 0x060011F7). Retail: 0x004e3400.
/// </summary>
private void ConfigureDropFeedback(UiItemList list, UiItemSlot cell)
{
cell.DragAcceptSprite = ReferenceEquals(list, _contentsGrid)
? 0x060011F9u
: 0x060011F7u;
cell.DragRejectSprite = 0x060011F8u;
}
/// <summary>Set the per-cell container capacity bar — retail UIElement_UIItem::UpdateCapacityDisplay
/// (0x004e16e0): visible only for a container with itemsCapacity &gt; 0; fill =
/// GetNumContainedItems / itemsCapacity, clamped [0,1]. -1 hides the bar (non-container / unknown

View file

@ -338,10 +338,22 @@ public sealed class UiItemSlot : UiElement
}
}
// Pending/drag-source mesh — retail UIElement_UIItem::SetWaitingState (0x004e11b0)
// reveals m_elem_Icon_Ghosted (0x10000349). ItemList_BeginDrag (0x004e32d0)
// sets it for physical inventory/equipment cells while leaving their icon in place.
// Draw it before the persistent selected/open indicators: retail keeps selection visible
// while the source is waiting, so the grey mesh must not erase the selected square.
if (_waiting && SpriteResolve is not null && WaitingSprite != 0)
{
var (tex, _, _) = SpriteResolve(WaitingSprite);
if (tex != 0)
ctx.DrawSprite(tex, 0f, 0f, Width, Height, 0f, 0f, 1f, 1f, Vector4.One);
}
// Open-container triangle (retail SetOpenContainerState 0x004e1200) + selected-item square
// (retail SetSelectedState 0x004e1240). Drawn procedurally like the digit/drag overlays;
// guard id != 0 BEFORE resolving (feedback_ui_resolve_zero_magenta). Triangle under the
// square; both under the transient drag overlay below.
// square; both remain above the transient waiting mesh and below drag-accept feedback.
if (IsOpenContainer && SpriteResolve is not null && OpenContainerSprite != 0)
{
var (tex, _, _) = SpriteResolve(OpenContainerSprite);
@ -355,16 +367,6 @@ public sealed class UiItemSlot : UiElement
ctx.DrawSprite(tex, 0f, 0f, Width, Height, 0f, 0f, 1f, 1f, Vector4.One);
}
// Pending/drag-source mesh — retail UIElement_UIItem::SetWaitingState (0x004e11b0)
// reveals m_elem_Icon_Ghosted (0x10000349). ItemList_BeginDrag (0x004e32d0)
// sets it for physical inventory/equipment cells while leaving their icon in place.
if (_waiting && SpriteResolve is not null && WaitingSprite != 0)
{
var (tex, _, _) = SpriteResolve(WaitingSprite);
if (tex != 0)
ctx.DrawSprite(tex, 0f, 0f, Width, Height, 0f, 0f, 1f, 1f, Vector4.One);
}
// Drag-rollover accept/reject frame (retail SetDragAcceptState 0x10000041/40).
// Guard id != 0 BEFORE resolving — resolve(0) returns the 1×1 magenta placeholder
// with a non-zero GL handle (feedback_ui_resolve_zero_magenta).