fix(ui): port retail item drag visuals

Keep retail's underlay-free m_pDragIcon separate from the full cell icon and reveal the authored ghost mesh on physical source cells for the complete drag lifecycle. This removes the backpack backing from the cursor and retires AP-47.

Co-Authored-By: Codex <codex@openai.com>
This commit is contained in:
Erik 2026-07-13 09:14:24 +02:00
parent 3e84027885
commit ace5880fed
14 changed files with 307 additions and 44 deletions

View file

@ -233,6 +233,7 @@ public sealed class UiRoot : UiElement
Modal = null;
if (IsWithinSubtree(DragSource, subtree))
{
DragSource?.SetDragSourceActive(false, DragPayload);
DragSource = null;
DragPayload = null;
_dragGhost = null;
@ -756,6 +757,7 @@ public sealed class UiRoot : UiElement
DragSource = source;
DragPayload = payload;
_dragGhost = source.GetDragGhost(); // snapshot NOW — the DragBegin handler may empty the source cell
source.SetDragSourceActive(true, payload);
var e = new UiEvent(source.EventId, source, UiEventType.DragBegin, Payload: payload);
source.OnEvent(in e);
}
@ -787,16 +789,24 @@ public sealed class UiRoot : UiElement
private void FinishDrag(int x, int y)
{
UiElement? source = DragSource;
object? payload = DragPayload;
// Retail's source UIItem receives the release and hides m_elem_Icon_Ghosted
// before the target handles the move. Keep this at the root lifecycle boundary so
// releases over world space and non-item widgets clear the same state deterministically.
source?.SetDragSourceActive(false, payload);
var (t, lx, ly) = HitTestTopDown(x, y);
if (t is not null)
{
// Dropped on a real element — deliver DropReleased; the hit cell's handler places.
// A non-item target's OnEvent ignores it, so an off-bar drop leaves the lift's removal.
var e = new UiEvent(DragSource!.EventId, t, UiEventType.DropReleased,
Data1: (int)lx, Data2: (int)ly, Payload: DragPayload);
var e = new UiEvent(source!.EventId, t, UiEventType.DropReleased,
Data1: (int)lx, Data2: (int)ly, Payload: payload);
t.OnEvent(in e);
}
else if (DragPayload is { } payload)
else if (payload is not null)
{
DragReleasedOutsideUi?.Invoke(payload, x, y);
}