# 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.