feat(ui): port retail spellbook interactions
Resolve the authored spell shortcut row prototype so the spellbook presents the retail icon, name, separator, selected overlay, and scrollbar geometry. Port exact school and level filters, stable display ordering, selection exposure, and learned-spell drags into the open favorite bar. Route deletion through the shared retail confirmation dialog and send CM_Magic::Event_RemoveSpell only after an affirmative answer, leaving the inbound server notice authoritative for list state. Co-Authored-By: Codex <noreply@openai.com>
This commit is contained in:
parent
ad30c37a48
commit
ac2ca8f965
17 changed files with 727 additions and 47 deletions
|
|
@ -274,6 +274,12 @@ public sealed class SpellcastingUiController : IRetainedPanelController
|
|||
UiItemList? list = _lists[tab];
|
||||
if (list is null) continue;
|
||||
IReadOnlyList<uint> favorites = _spellbook.GetFavorites(tab);
|
||||
int targetTab = tab;
|
||||
list.CatalogDropped = (payload, x, _) =>
|
||||
{
|
||||
if (payload is SpellbookShortcutDragPayload shortcut)
|
||||
DropSpellbookShortcut(shortcut, targetTab, DropPosition(list, x));
|
||||
};
|
||||
using (list.DeferLayout())
|
||||
{
|
||||
list.Flush();
|
||||
|
|
@ -297,7 +303,9 @@ public sealed class SpellcastingUiController : IRetainedPanelController
|
|||
Dropped = payload =>
|
||||
{
|
||||
if (payload is SpellFavoriteDragPayload favorite)
|
||||
DropFavorite(favorite, tab, position);
|
||||
DropFavorite(favorite, targetTab, position);
|
||||
else if (payload is SpellbookShortcutDragPayload shortcut)
|
||||
DropSpellbookShortcut(shortcut, targetTab, position);
|
||||
},
|
||||
};
|
||||
slot.Clicked = () => SelectSpell(id);
|
||||
|
|
@ -322,6 +330,27 @@ public sealed class SpellcastingUiController : IRetainedPanelController
|
|||
_selected[targetTab] = payload.SpellId;
|
||||
}
|
||||
|
||||
private void DropSpellbookShortcut(
|
||||
SpellbookShortcutDragPayload payload,
|
||||
int targetTab,
|
||||
int targetPosition)
|
||||
{
|
||||
// gmSpellbookUI::ListenToElementMessage @ 0x0048BFD0 publishes
|
||||
// CM_Magic::SendNotice_AddSpellShortcut; the open spellcasting menu
|
||||
// chooses the favorite tab/position and persists it.
|
||||
_addFavorite?.Invoke(targetTab, targetPosition, payload.SpellId);
|
||||
_spellbook.SetFavorite(targetTab, targetPosition, payload.SpellId);
|
||||
_selected[targetTab] = payload.SpellId;
|
||||
}
|
||||
|
||||
private static int DropPosition(UiItemList list, int localX)
|
||||
{
|
||||
int position = list.CellWidth <= 0f
|
||||
? list.GetNumUIItems()
|
||||
: (int)MathF.Floor(MathF.Max(0f, localX) / list.CellWidth);
|
||||
return Math.Clamp(position, 0, list.GetNumUIItems());
|
||||
}
|
||||
|
||||
private void OnSpellbookChanged() => _favoritesDirty = true;
|
||||
|
||||
private void OnObjectChanged(ClientObject _) => _endowmentDirty = true;
|
||||
|
|
@ -465,6 +494,12 @@ public sealed class SpellcastingUiController : IRetainedPanelController
|
|||
|
||||
public sealed record SpellFavoriteDragPayload(int SourceTab, int SourcePosition, uint SpellId);
|
||||
|
||||
/// <summary>
|
||||
/// A learned-spell shortcut carried from the spellbook. Unlike a favorite drag,
|
||||
/// lifting this payload never removes anything from its source collection.
|
||||
/// </summary>
|
||||
public sealed record SpellbookShortcutDragPayload(uint SpellId);
|
||||
|
||||
internal static class FavoriteListExtensions
|
||||
{
|
||||
public static int IndexOf(this IReadOnlyList<uint> values, uint value)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue