fix(ui): select retained items on mouse down

Port UIElement_ListBox's press-time selection ordering through the shared retained item-list contract. Inventory, loot, paperdoll, and physical shortcuts now update canonical selection before release or drag promotion, while target-mode consumption suppresses drag and release-time activation.

Co-authored-by: Codex <codex@openai.com>
This commit is contained in:
Erik 2026-07-24 06:17:31 +02:00
parent 2dd5cb80d2
commit 043ab10b3c
18 changed files with 292 additions and 62 deletions

View file

@ -99,6 +99,7 @@ public class UiItemSlot : UiElement
private bool _waiting;
internal bool WaitingVisual => _waiting;
private bool _primaryPressConsumed;
/// <summary>RenderSurface id -> (GL texture, w, h). Set by the factory/controller.</summary>
public Func<uint, (uint tex, int w, int h)>? SpriteResolve { get; set; }
@ -134,11 +135,14 @@ public class UiItemSlot : UiElement
DragIconTexture = 0;
Shortcut = null;
_waiting = false;
_primaryPressConsumed = false;
}
/// <inheritdoc/>
public override object? GetDragPayload()
=> ItemId != 0 ? new ItemDragPayload(ItemId, SourceKind, SlotIndex, this, Shortcut) : null;
=> ItemId != 0 && !_primaryPressConsumed
? new ItemDragPayload(ItemId, SourceKind, SlotIndex, this, Shortcut)
: null;
/// <inheritdoc/>
public override (uint tex, int w, int h)? GetDragGhost()
@ -251,8 +255,10 @@ public class UiItemSlot : UiElement
// ── Events / draw ─────────────────────────────────────────────────────────
/// <summary>Invoked by <see cref="OnEvent"/> when a left-button-down lands on
/// a bound slot. Wired by <c>ToolbarController</c> to the use-item callback.</summary>
/// <summary>Invoked by <see cref="OnEvent"/> when a completed left click lands
/// on a bound slot. Selection already occurred on MouseDown through the owning
/// <see cref="UiItemList"/>; this callback performs release-time activation
/// such as opening a bag or using a shortcut.</summary>
public Action? Clicked { get; set; }
/// <summary>Invoked by <see cref="OnEvent"/> when a double-click lands on a bound slot.</summary>
@ -267,12 +273,21 @@ public class UiItemSlot : UiElement
// drag (press + >3px move) does NOT also use the item. UiRoot suppresses the
// post-drag Click (UiRoot.cs FinishDrag returns before the Click emit).
case UiEventType.MouseDown:
return true; // consume the press; no use here
// UIElement_ListBox::MouseDown @ 0x0046E3A0 selects immediately,
// before StartDragSelect. UIElement_ItemList's notice handler
// intercepts target mode first. Activation remains release-time,
// so a press promoted to drag never also uses the item.
_primaryPressConsumed = ItemId != 0
&& FindList() is { PrimaryItemPressed: { } pressed }
&& pressed(ItemId);
return true;
case UiEventType.Click:
Clicked?.Invoke();
if (!_primaryPressConsumed)
Clicked?.Invoke();
return true;
case UiEventType.DoubleClick:
DoubleClicked?.Invoke();
if (!_primaryPressConsumed)
DoubleClicked?.Invoke();
return true;
case UiEventType.RightClick:
if (ItemId != 0