feat(ui): centralize retail selection state

This commit is contained in:
Erik 2026-07-11 00:51:20 +02:00
parent c7607f019c
commit 7983309d23
30 changed files with 591 additions and 108 deletions

View file

@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using AcDream.App.UI;
using AcDream.Core.Items;
using AcDream.Core.Selection;
namespace AcDream.App.UI.Layout;
@ -76,6 +77,7 @@ public sealed class PaperdollController : IItemListDragHandler, IRetainedPanelCo
private readonly Func<ItemType, uint, uint, uint, uint, uint> _iconIds;
private readonly Action<uint, uint>? _sendWield; // (itemGuid, equipMask) → GetAndWieldItem 0x001A
private readonly ItemInteractionController? _itemInteraction;
private readonly SelectionState _selection;
private readonly List<(EquipMask Mask, UiItemList List)> _slots = new();
// ── Slots-toggle state ────────────────────────────────────────────────────────────────────────
@ -86,11 +88,13 @@ public sealed class PaperdollController : IItemListDragHandler, IRetainedPanelCo
private PaperdollController(
ImportedLayout layout, ClientObjectTable objects, Func<uint> playerGuid,
Func<ItemType, uint, uint, uint, uint, uint> iconIds, Action<uint, uint>? sendWield,
Func<ItemType, uint, uint, uint, uint, uint> iconIds, SelectionState selection,
Action<uint, uint>? sendWield,
uint emptySlotSprite, UiDatFont? datFont, ItemInteractionController? itemInteraction)
{
_objects = objects; _playerGuid = playerGuid; _iconIds = iconIds; _sendWield = sendWield;
_itemInteraction = itemInteraction;
_selection = selection ?? throw new ArgumentNullException(nameof(selection));
for (int i = 0; i < SlotMap.Length; i++)
{
@ -100,7 +104,16 @@ public sealed class PaperdollController : IItemListDragHandler, IRetainedPanelCo
list.Cell.SourceKind = ItemDragSource.Equipment;
list.Cell.SlotIndex = i; // SlotMap position = this equipped item's drag-payload SourceSlot when dragged out to unwield
list.Cell.EmptySprite = emptySlotSprite; // visible empty-slot frame so every position is seen + usable. The live
list.Cell.Clicked = () => { _itemInteraction?.AcquireSelfTarget(); };
list.Cell.Clicked = () =>
{
if (_itemInteraction?.IsTargetModeActive == true)
{
_itemInteraction.AcquireSelfTarget();
return;
}
if (list.Cell.ItemId != 0)
_selection.Select(list.Cell.ItemId, SelectionChangeSource.Paperdoll);
};
list.Cell.DoubleClicked = () =>
{
if (list.Cell.ItemId != 0)
@ -119,6 +132,7 @@ public sealed class PaperdollController : IItemListDragHandler, IRetainedPanelCo
_objects.ObjectMoved += OnObjectMoved;
_objects.ObjectRemoved += OnObjectChanged;
_objects.ObjectUpdated += OnObjectChanged;
_selection.Changed += OnSelectionChanged;
// ── Slots-toggle wiring ───────────────────────────────────────────────────────────────────
foreach (var id in ArmorSlotElementIds)
@ -154,14 +168,18 @@ public sealed class PaperdollController : IItemListDragHandler, IRetainedPanelCo
public static PaperdollController Bind(
ImportedLayout layout, ClientObjectTable objects, Func<uint> playerGuid,
Func<ItemType, uint, uint, uint, uint, uint> iconIds, Action<uint, uint>? sendWield = null,
Func<ItemType, uint, uint, uint, uint, uint> iconIds, SelectionState selection,
Action<uint, uint>? sendWield = null,
uint emptySlotSprite = 0u, UiDatFont? datFont = null,
ItemInteractionController? itemInteraction = null)
=> new PaperdollController(layout, objects, playerGuid, iconIds, sendWield, emptySlotSprite, datFont, itemInteraction);
=> new PaperdollController(
layout, objects, playerGuid, iconIds, selection, sendWield, emptySlotSprite,
datFont, itemInteraction);
private void OnObjectChanged(ClientObject o) { if (Concerns(o)) Populate(); }
private void OnObjectMoved(ClientObject o, uint from, uint to)
{ if (Concerns(o) || from == _playerGuid() || to == _playerGuid()) Populate(); }
private void OnSelectionChanged(SelectionTransition _) => ApplySelectionIndicators();
/// <summary>The object belongs to the player (wielded gear or pack contents) — so a change to it may
/// add/remove/repaint a doll slot. Player-scoped: an NPC's or vendor's wielded item (which also carries
@ -196,6 +214,16 @@ public sealed class PaperdollController : IItemListDragHandler, IRetainedPanelCo
uint tex = _iconIds(worn.Type, worn.IconId, worn.IconUnderlayId, worn.IconOverlayId, worn.Effects);
list.Cell.SetItem(worn.ObjectId, tex);
}
ApplySelectionIndicators();
}
private void ApplySelectionIndicators()
{
foreach (var (_, list) in _slots)
{
list.Cell.Selected = list.Cell.ItemId != 0
&& list.Cell.ItemId == _selection.SelectedObjectId;
}
}
private EquipMask MaskFor(UiItemList list)
@ -251,5 +279,6 @@ public sealed class PaperdollController : IItemListDragHandler, IRetainedPanelCo
_objects.ObjectMoved -= OnObjectMoved;
_objects.ObjectRemoved -= OnObjectChanged;
_objects.ObjectUpdated -= OnObjectChanged;
_selection.Changed -= OnSelectionChanged;
}
}