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.Numerics;
using AcDream.App.UI;
using AcDream.Core.Items;
using AcDream.Core.Selection;
namespace AcDream.App.UI.Layout;
@ -53,7 +54,7 @@ public sealed class InventoryController : IItemListDragHandler, IRetainedPanelCo
private static readonly Vector4 CaptionColor = new(1f, 1f, 1f, 1f);
private uint _openContainer; // 0 = the main pack (the player); else the open side bag's guid
private uint _selectedItem; // 0 = none; the panel-wide selected item (green square)
private readonly SelectionState _selection;
private readonly Action<uint>? _sendUse;
private readonly Action<uint>? _sendNoLongerViewing;
private readonly Action<uint, uint, int>? _sendPutItemInContainer; // (item, container, placement)
@ -70,6 +71,7 @@ public sealed class InventoryController : IItemListDragHandler, IRetainedPanelCo
Func<uint> playerGuid,
Func<ItemType, uint, uint, uint, uint, uint> iconIds,
Func<int?> strength,
SelectionState selection,
Func<string>? ownerName,
UiDatFont? datFont,
uint contentsEmptySprite,
@ -90,6 +92,7 @@ public sealed class InventoryController : IItemListDragHandler, IRetainedPanelCo
_sendNoLongerViewing = sendNoLongerViewing;
_sendPutItemInContainer = sendPutItemInContainer;
_itemInteraction = itemInteraction;
_selection = selection ?? throw new ArgumentNullException(nameof(selection));
WindowChromeController.BindCloseButton(layout, onClose);
@ -152,8 +155,9 @@ public sealed class InventoryController : IItemListDragHandler, IRetainedPanelCo
// Rebuild on any change to the player's possessions.
_objects.ObjectAdded += OnObjectChanged;
_objects.ObjectMoved += OnObjectMoved;
_objects.ObjectRemoved += OnObjectChanged;
_objects.ObjectRemoved += OnObjectRemoved;
_objects.ObjectUpdated += OnObjectChanged;
_selection.Changed += OnSelectionChanged;
if (_itemInteraction is not null)
_itemInteraction.StateChanged += OnInteractionStateChanged;
@ -184,6 +188,7 @@ public sealed class InventoryController : IItemListDragHandler, IRetainedPanelCo
Func<uint> playerGuid,
Func<ItemType, uint, uint, uint, uint, uint> iconIds,
Func<int?> strength,
SelectionState selection,
UiDatFont? datFont,
Func<string>? ownerName = null,
uint contentsEmptySprite = 0u,
@ -194,14 +199,27 @@ public sealed class InventoryController : IItemListDragHandler, IRetainedPanelCo
Action<uint, uint, int>? sendPutItemInContainer = null,
ItemInteractionController? itemInteraction = null,
Action? onClose = null)
=> new InventoryController(layout, objects, playerGuid, iconIds, strength, ownerName, datFont,
=> new InventoryController(layout, objects, playerGuid, iconIds, strength, selection,
ownerName, datFont,
contentsEmptySprite, sideBagEmptySprite, mainPackEmptySprite,
sendUse, sendNoLongerViewing, sendPutItemInContainer, itemInteraction, onClose);
sendUse, sendNoLongerViewing, sendPutItemInContainer, itemInteraction,
onClose);
private void OnObjectChanged(ClientObject o) { if (Concerns(o)) Populate(); }
private void OnObjectRemoved(ClientObject o)
{
if (_selection.SelectedObjectId == o.ObjectId)
{
_selection.Clear(
SelectionChangeSource.System,
SelectionChangeReason.SelectedObjectRemoved);
}
if (Concerns(o)) Populate();
}
private void OnObjectMoved(ClientObject o, uint from, uint to)
{ if (Concerns(o) || from == _playerGuid() || to == _playerGuid()) Populate(); }
private void OnInteractionStateChanged() => ApplyIndicators();
private void OnSelectionChanged(SelectionTransition _) => ApplyIndicators();
/// <summary>True if the object is in (or wielded by) the player — i.e. a rebuild is warranted.</summary>
private bool Concerns(ClientObject o)
@ -402,8 +420,7 @@ public sealed class InventoryController : IItemListDragHandler, IRetainedPanelCo
private void SelectItem(uint guid)
{
if (guid == 0) return;
_selectedItem = guid;
ApplyIndicators();
_selection.Select(guid, SelectionChangeSource.Inventory);
}
/// <summary>Open a container (side bag or main pack): it becomes both the selected item and the
@ -413,7 +430,7 @@ public sealed class InventoryController : IItemListDragHandler, IRetainedPanelCo
private void OpenContainer(uint guid)
{
if (guid == 0) return;
_selectedItem = guid; // the container cell is also the selected item
_selection.Select(guid, SelectionChangeSource.Inventory);
uint open = EffectiveOpen();
if (guid == open) { ApplyIndicators(); return; } // already open — just move the square
@ -444,7 +461,9 @@ public sealed class InventoryController : IItemListDragHandler, IRetainedPanelCo
var cell = list.GetItem(i);
if (cell is null) continue;
bool pendingTargetSource = _itemInteraction?.IsPendingSource(cell.ItemId) == true;
cell.Selected = cell.ItemId != 0 && cell.ItemId == _selectedItem && !pendingTargetSource;
cell.Selected = cell.ItemId != 0
&& cell.ItemId == _selection.SelectedObjectId
&& !pendingTargetSource;
cell.IsOpenContainer = cell.ItemId != 0 && cell.ItemId == open;
}
}
@ -533,8 +552,9 @@ public sealed class InventoryController : IItemListDragHandler, IRetainedPanelCo
_disposed = true;
_objects.ObjectAdded -= OnObjectChanged;
_objects.ObjectMoved -= OnObjectMoved;
_objects.ObjectRemoved -= OnObjectChanged;
_objects.ObjectRemoved -= OnObjectRemoved;
_objects.ObjectUpdated -= OnObjectChanged;
_selection.Changed -= OnSelectionChanged;
if (_itemInteraction is not null)
_itemInteraction.StateChanged -= OnInteractionStateChanged;
}