refactor(ui): own retained controller lifetimes

This commit is contained in:
Erik 2026-07-10 23:35:26 +02:00
parent 921c388e2c
commit 5d9e98c118
21 changed files with 373 additions and 35 deletions

View file

@ -23,7 +23,7 @@ namespace AcDream.App.UI.Layout;
/// <c>CreateObject</c> resolves a formerly-unknown guid.
/// </para>
/// </summary>
public sealed class ToolbarController : IItemListDragHandler
public sealed class ToolbarController : IItemListDragHandler, IRetainedPanelController
{
// Slot element ids in slot-index order (toolbar LayoutDesc 0x21000016, pre-dump).
// Row 1 = slots 0-8 (0x100001A7..0x100001AF), Row 2 = slots 9-17 (0x100006B7..0x100006BF).
@ -62,6 +62,7 @@ public sealed class ToolbarController : IItemListDragHandler
private readonly UiButton? _characterButton;
private readonly UiButton? _inventoryButton;
private readonly ClientObjectTable _repo;
private readonly CombatState? _combatState;
private readonly Func<IReadOnlyList<PlayerDescriptionParser.ShortcutEntry>> _shortcuts;
private readonly Func<ItemType, uint, uint, uint, uint, uint> _iconIds; // (itemType, icon, underlay, overlay, effects) → GL tex
private readonly Action<uint> _useItem; // guid → fire UseObject
@ -70,6 +71,7 @@ public sealed class ToolbarController : IItemListDragHandler
private readonly Action<uint, uint>? _sendAddShortcut; // (index, objectGuid)
private readonly Action<uint>? _sendRemoveShortcut; // (index)
private readonly ItemInteractionController? _itemInteraction;
private bool _disposed;
// Digit sprite DID arrays for slot labels (top row, numbers 1-9).
// Read from LayoutDesc 0x21000037, element 0x1000034A under composite 0x10000346.
@ -98,6 +100,7 @@ public sealed class ToolbarController : IItemListDragHandler
Action<uint>? sendRemoveShortcut = null)
{
_repo = repo;
_combatState = combatState;
_shortcuts = shortcuts;
_iconIds = iconIds;
_useItem = useItem;
@ -141,15 +144,21 @@ public sealed class ToolbarController : IItemListDragHandler
SetCombatMode(CombatMode.NonCombat);
// Wire live combat-mode changes if a CombatState was provided.
if (combatState is not null)
combatState.CombatModeChanged += SetCombatMode;
if (_combatState is not null)
_combatState.CombatModeChanged += SetCombatMode;
// D.5.4: the table now holds ALL objects (creatures, NPCs, etc.), so filter
// to our 18 shortcut guids — else every creature spawn in a busy zone
// needlessly re-populates the bar (gmToolbarUI::SetDelayedShortcutNum pattern).
repo.ObjectAdded += o => { if (IsShortcutGuid(o.ObjectId)) Populate(); };
repo.ObjectUpdated += o => { if (IsShortcutGuid(o.ObjectId)) Populate(); };
repo.ObjectRemoved += o => { if (IsShortcutGuid(o.ObjectId)) Populate(); };
repo.ObjectAdded += OnRepositoryObjectChanged;
repo.ObjectUpdated += OnRepositoryObjectChanged;
repo.ObjectRemoved += OnRepositoryObjectChanged;
}
private void OnRepositoryObjectChanged(ClientObject obj)
{
if (IsShortcutGuid(obj.ObjectId))
Populate();
}
/// <summary>
@ -409,4 +418,16 @@ public sealed class ToolbarController : IItemListDragHandler
}
Populate();
}
public void Dispose()
{
if (_disposed) return;
_disposed = true;
if (_combatState is not null)
_combatState.CombatModeChanged -= SetCombatMode;
_repo.ObjectAdded -= OnRepositoryObjectChanged;
_repo.ObjectUpdated -= OnRepositoryObjectChanged;
_repo.ObjectRemoved -= OnRepositoryObjectChanged;
}
}