feat(ui): D.5.3/B.1 — UiRoot payload injection + cursor drag ghost (AP-47)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Erik 2026-06-20 12:51:01 +02:00
parent 1672eaa620
commit 595c4bdac4
3 changed files with 97 additions and 3 deletions

View file

@ -141,9 +141,25 @@ public sealed class UiRoot : UiElement
// beats even rect backgrounds. Faithful to retail's root-level MakePopup.
ctx.BeginOverlayLayer();
DrawOverlays(ctx);
DrawDragGhost(ctx);
ctx.EndOverlayLayer();
}
/// <summary>Translucency of the cursor-following drag ghost. AP-47: we reuse the
/// item's full composited icon at this alpha rather than retail's dedicated
/// underlay-less m_pDragIcon.</summary>
private const float GhostAlpha = 0.6f;
/// <summary>Paint the drag ghost at the cursor. The texture comes from the source
/// element's <see cref="UiElement.GetDragGhost"/> so UiRoot stays item-agnostic; the
/// ghost is NOT a tree element, so it never intercepts hit-tests.</summary>
private void DrawDragGhost(UiRenderContext ctx)
{
if (DragSource?.GetDragGhost() is not { } g || g.tex == 0) return;
ctx.DrawSprite(g.tex, MouseX - g.w / 2f, MouseY - g.h / 2f, g.w, g.h,
0f, 0f, 1f, 1f, new Vector4(1f, 1f, 1f, GhostAlpha));
}
// ── Input entry points (called from GameWindow's Silk.NET handlers) ──
public void OnMouseMove(int x, int y)
@ -185,7 +201,7 @@ public sealed class UiRoot : UiElement
if (Math.Abs(x - _pressX) > DragDistanceThreshold
|| Math.Abs(y - _pressY) > DragDistanceThreshold)
{
BeginDrag(Captured, payload: null);
BeginDrag(Captured);
}
}
if (DragSource is not null)
@ -447,8 +463,13 @@ public sealed class UiRoot : UiElement
// ── Drag-drop (retail event chain 0x15 → 0x21 → 0x1C → 0x3E) ────────
private void BeginDrag(UiElement source, object? payload)
private void BeginDrag(UiElement source)
{
// Pull the payload from the source; a null payload (e.g. an empty item cell)
// CANCELS the drag — retail's ItemList_BeginDrag only arms an occupied cell.
var payload = source.GetDragPayload();
if (payload is null) { _dragCandidate = false; return; }
DragSource = source;
DragPayload = payload;
var e = new UiEvent(source.EventId, source, UiEventType.DragBegin, Payload: payload);