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:
parent
3e84027885
commit
ace5880fed
14 changed files with 307 additions and 44 deletions
|
|
@ -0,0 +1,90 @@
|
|||
# Retail item drag visuals — pseudocode
|
||||
|
||||
Date: 2026-07-13
|
||||
|
||||
Scope: the cursor graphic and source-cell visual while dragging an item from an
|
||||
item list. This is a focused continuation of
|
||||
`2026-06-16-ui-item-slot-icon-dragdrop-spine-deep-dive.md`.
|
||||
|
||||
## Retail anchors
|
||||
|
||||
- `IconData::RenderIcons` @ `0x0058d180`
|
||||
(`named-retail/acclient_2013_pseudo_c.txt:407524`)
|
||||
- `UIElement_ItemList::PrepareDragIcon` @ `0x004e2a50`
|
||||
(`named-retail/acclient_2013_pseudo_c.txt:230765`)
|
||||
- `UIElement_ItemList::ItemList_BeginDrag` @ `0x004e32d0`
|
||||
(`named-retail/acclient_2013_pseudo_c.txt:231350`)
|
||||
- `UIElement_UIItem::SetWaitingState` @ `0x004e11b0`
|
||||
(`named-retail/acclient_2013_pseudo_c.txt:229190`)
|
||||
- `ACCWeenieObject::SetWaitingState` @ `0x0058c0d0`
|
||||
(`named-retail/acclient_2013_pseudo_c.txt:406260`)
|
||||
- `UIElement_UIItem` layout child `m_elem_Icon_Ghosted = 0x10000349`;
|
||||
the shared UIItem catalog `0x21000037` gives it DirectState surface
|
||||
`0x0600109A`.
|
||||
|
||||
The live DAT catalog and the named retail code agree. The in-tree WorldBuilder
|
||||
reference has no retained UI/item-list implementation to compare for this path.
|
||||
|
||||
## Literal pseudocode
|
||||
|
||||
```text
|
||||
IconData.RenderIcons(item):
|
||||
destroy old m_pIcon and m_pDragIcon
|
||||
|
||||
dragSurface = transparent 32 x 32
|
||||
blit item.baseIcon onto dragSurface using normal blit
|
||||
blit item.customOverlay onto dragSurface using alpha blit
|
||||
replace pure-white dragSurface pixels from the effect-color surface
|
||||
m_pDragIcon = Graphic(dragSurface)
|
||||
|
||||
cellSurface = transparent 32 x 32
|
||||
blit typeDefaultUnderlay onto cellSurface using normal blit
|
||||
blit item.customUnderlay onto cellSurface using alpha blit
|
||||
blit dragSurface onto cellSurface using alpha blit
|
||||
m_pIcon = Graphic(cellSurface)
|
||||
|
||||
ItemList.PrepareDragIcon(cell):
|
||||
clear cell.m_dragIcon image
|
||||
object = GetWeenieObject(cell.itemID)
|
||||
set cell.m_dragIcon image to object.GetDragIcon() # m_pDragIcon, not m_pIcon
|
||||
|
||||
ItemList.ItemList_BeginDrag(cell):
|
||||
if PrepareDragIcon(cell) failed:
|
||||
return
|
||||
if list is not vendor, salvage, or shortcut list:
|
||||
cell.SetWaitingState(true)
|
||||
StartDragAndDrop(cell.m_dragIcon, hotspot = 16,16)
|
||||
|
||||
UIItem.SetWaitingState(waiting):
|
||||
object.SetWaitingState(waiting)
|
||||
if cell is not unghostable:
|
||||
set m_elem_Icon_Ghosted visible = waiting
|
||||
|
||||
on drag release/cancel:
|
||||
clear source waiting state
|
||||
hide m_elem_Icon_Ghosted
|
||||
```
|
||||
|
||||
## Port mapping
|
||||
|
||||
- `IconComposer` caches the underlay-free composite separately and exposes
|
||||
`GetDragIcon`; the ordinary `GetIcon` still layers the two underlays beneath
|
||||
the same cached drag pixels.
|
||||
- `UiItemSlot` stores `IconTexture` and `DragIconTexture` separately.
|
||||
`GetDragGhost` returns the latter, while `OnDraw` keeps the former in the
|
||||
source cell.
|
||||
- `UiRoot` owns the generic source-active lifecycle, including release outside
|
||||
UI and source-subtree removal. `UiItemSlot` maps that lifecycle to the retail
|
||||
waiting visual for physical lists; shortcut aliases remain unghosted.
|
||||
- `UiItemSlot.WaitingSprite` is the authored `0x0600109A` mesh, not a procedural
|
||||
tint.
|
||||
|
||||
## Conformance coverage
|
||||
|
||||
- `DragDropSpineTests.GetDragGhost_prefersDedicatedUnderlayFreeTexture`
|
||||
- `DragDropSpineTests.InventoryDrag_ghostsSourceUntilRelease`
|
||||
- `DragDropSpineTests.ShortcutDrag_doesNotGhostSource`
|
||||
- `UiItemSlotTests.DefaultWaitingSprite_isRetailGhostMesh`
|
||||
- Existing `IconComposerTests.TwoStageWithEffect_copiesTilePixelBeforeUnderlay`
|
||||
locks the two-stage composition order.
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue