fix(ui): assess retained items on right click
Port UIElement_ItemList's physical-item right-click branch through the shared retained list. Select and appraise backpack, loot, paperdoll, and shortcut items through their canonical owners, while preventing RMB movement from lifting items or issuing appraisal requests. Co-authored-by: Codex <codex@openai.com>
This commit is contained in:
parent
5ad32d5753
commit
2dd5cb80d2
17 changed files with 264 additions and 5 deletions
|
|
@ -275,6 +275,35 @@ public class DragDropSpineTests
|
|||
Assert.True(used);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RightClick_withoutDrag_requestsItemListAppraisal()
|
||||
{
|
||||
var (root, list, _) = RootWithBoundSlot(0x5001u);
|
||||
var examined = new List<uint>();
|
||||
list.ExamineItemRequested = examined.Add;
|
||||
|
||||
root.OnMouseDown(UiMouseButton.Right, 10, 10);
|
||||
root.OnMouseUp(UiMouseButton.Right, 10, 10);
|
||||
|
||||
Assert.Equal(new uint[] { 0x5001u }, examined);
|
||||
Assert.Null(root.DragSource);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RightButtonMovement_cancelsAppraisal_andNeverStartsItemDrag()
|
||||
{
|
||||
var (root, list, _) = RootWithBoundSlot(0x5001u);
|
||||
var examined = new List<uint>();
|
||||
list.ExamineItemRequested = examined.Add;
|
||||
|
||||
root.OnMouseDown(UiMouseButton.Right, 10, 10);
|
||||
root.OnMouseMove(14, 10);
|
||||
root.OnMouseUp(UiMouseButton.Right, 14, 10);
|
||||
|
||||
Assert.Empty(examined);
|
||||
Assert.Null(root.DragSource);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CompletedDrag_doesNotFireUse()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ public sealed class ExternalContainerControllerTests
|
|||
public readonly List<uint> Uses = new();
|
||||
public readonly List<uint> NoLonger = new();
|
||||
public readonly List<uint> Pickups = new();
|
||||
public readonly List<uint> Examines = new();
|
||||
public readonly List<(uint Item, uint Container, int Placement)> Puts = new();
|
||||
public readonly List<(uint Item, uint Container, uint Placement, uint Amount)> Splits = new();
|
||||
public readonly UiRoot Screen = new() { Width = 800f, Height = 600f };
|
||||
|
|
@ -110,6 +111,7 @@ public sealed class ExternalContainerControllerTests
|
|||
sendUseWithTarget: null,
|
||||
sendWield: null,
|
||||
sendDrop: null,
|
||||
sendExamine: Examines.Add,
|
||||
groundObjectId: () => State.CurrentContainerId,
|
||||
placeInBackpack: (item, _, _) => Pickups.Add(item),
|
||||
sendPutItemInContainer: (item, container, placement) =>
|
||||
|
|
@ -183,6 +185,20 @@ public sealed class ExternalContainerControllerTests
|
|||
Assert.Equal(new uint[] { Item }, h.Pickups);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RightClickLoot_selectsAndExaminesWithoutPickingUp()
|
||||
{
|
||||
using var h = new Harness();
|
||||
h.Open(Chest, new ContainerContentEntry(Item, 0u));
|
||||
|
||||
UiItemSlot cell = h.Contents.GetItem(0)!;
|
||||
cell.OnEvent(new UiEvent(0u, cell, UiEventType.RightClick));
|
||||
|
||||
Assert.Equal(Item, h.Selection.SelectedObjectId);
|
||||
Assert.Equal(new uint[] { Item }, h.Examines);
|
||||
Assert.Empty(h.Pickups);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CloseAndRangeExit_SendUseOnceWithoutNoLongerViewing()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -62,7 +62,8 @@ public class InventoryControllerTests
|
|||
string? ownerName = null,
|
||||
Action? onClose = null,
|
||||
SelectionState? selection = null,
|
||||
StackSplitQuantityState? stackSplitQuantity = null)
|
||||
StackSplitQuantityState? stackSplitQuantity = null,
|
||||
ItemInteractionController? itemInteraction = null)
|
||||
=> InventoryController.Bind(layout, objects, () => Player,
|
||||
iconIds: (_, _, _, _, _) => 0u,
|
||||
strength: () => strength, datFont: null,
|
||||
|
|
@ -76,7 +77,8 @@ public class InventoryControllerTests
|
|||
notifyMergeAttempt: mergeNotices is null ? null : (s, t) => mergeNotices.Add((s, t)),
|
||||
onClose: onClose,
|
||||
selection: selection ?? new SelectionState(),
|
||||
stackSplitQuantity: stackSplitQuantity);
|
||||
stackSplitQuantity: stackSplitQuantity,
|
||||
itemInteraction: itemInteraction);
|
||||
|
||||
private static UiButton MakeButton(uint id)
|
||||
{
|
||||
|
|
@ -494,6 +496,37 @@ public class InventoryControllerTests
|
|||
Assert.True(grid.GetItem(1)!.Selected);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RightClickGridItem_selectsAndUsesSharedAppraisalOwner()
|
||||
{
|
||||
var (layout, grid, _, _, _, _, _, _) = BuildLayout();
|
||||
var objects = new ClientObjectTable();
|
||||
SeedContained(objects, 0xAu, Player, slot: 0);
|
||||
var selection = new SelectionState();
|
||||
var appraisals = new List<uint>();
|
||||
using var interaction = new ItemInteractionController(
|
||||
objects,
|
||||
playerGuid: () => Player,
|
||||
sendUse: null,
|
||||
sendUseWithTarget: null,
|
||||
sendWield: null,
|
||||
sendDrop: null,
|
||||
sendExamine: appraisals.Add);
|
||||
Bind(
|
||||
layout,
|
||||
objects,
|
||||
selection: selection,
|
||||
itemInteraction: interaction);
|
||||
|
||||
grid.GetItem(0)!.OnEvent(
|
||||
new UiEvent(0u, grid.GetItem(0), UiEventType.RightClick));
|
||||
|
||||
Assert.Equal(0xAu, selection.SelectedObjectId);
|
||||
Assert.True(grid.GetItem(0)!.Selected);
|
||||
Assert.Equal(new uint[] { 0xAu }, appraisals);
|
||||
Assert.Equal(1, interaction.BusyCount);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TargetMode_suppressesSelectedSquare_onPendingSource()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ public class PaperdollControllerTests
|
|||
IReadOnlyDictionary<uint, uint>? emptySlotSprites = null,
|
||||
List<(uint item, uint container, int placement)>? puts = null,
|
||||
List<string>? systemMessages = null,
|
||||
List<uint>? examines = null,
|
||||
Action<ItemInteractionController>? configureInteraction = null)
|
||||
{
|
||||
var itemInteraction = new ItemInteractionController(
|
||||
|
|
@ -56,6 +57,7 @@ public class PaperdollControllerTests
|
|||
sendUseWithTarget: null,
|
||||
sendWield: wields is null ? null : (i, m) => wields.Add((i, m)),
|
||||
sendDrop: null,
|
||||
sendExamine: examines is null ? null : examines.Add,
|
||||
sendPutItemInContainer: puts is null
|
||||
? null
|
||||
: (item, container, placement) => puts.Add((item, container, placement)),
|
||||
|
|
@ -116,6 +118,28 @@ public class PaperdollControllerTests
|
|||
Assert.Equal(0u, lists[ShieldSlot].Cell.ItemId); // shield slot empty
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RightClickEquippedSlot_selectsAndExaminesItem()
|
||||
{
|
||||
var (layout, lists) = BuildLayout();
|
||||
var objects = new ClientObjectTable();
|
||||
SeedEquipped(objects, 0xA01u, EquipMask.HeadWear);
|
||||
var selection = new SelectionState();
|
||||
var appraisals = new List<uint>();
|
||||
Bind(
|
||||
layout,
|
||||
objects,
|
||||
selection: selection,
|
||||
examines: appraisals);
|
||||
|
||||
UiItemSlot cell = lists[HeadSlot].Cell;
|
||||
cell.OnEvent(new UiEvent(0u, cell, UiEventType.RightClick));
|
||||
|
||||
Assert.Equal(0xA01u, selection.SelectedObjectId);
|
||||
Assert.True(cell.Selected);
|
||||
Assert.Equal(new uint[] { 0xA01u }, appraisals);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SessionTableClearRemovesOldEquipmentAndLocksAetheriaSlots()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -763,6 +763,42 @@ public class ToolbarControllerTests
|
|||
Assert.Equal(itemId, selected);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RightClickPhysicalShortcut_selectsAndExaminesItem()
|
||||
{
|
||||
const uint player = 0x50000001u;
|
||||
const uint itemId = 0x50001001u;
|
||||
var (layout, slots, _) = FakeToolbar();
|
||||
var repo = new ClientObjectTable();
|
||||
repo.AddOrUpdate(new ClientObject { ObjectId = itemId, Type = ItemType.Misc });
|
||||
var shortcuts = new[] { new ShortcutEntry(0, itemId, 0) };
|
||||
var selection = new SelectionState();
|
||||
var appraisals = new List<uint>();
|
||||
using var interaction = new ItemInteractionController(
|
||||
repo,
|
||||
playerGuid: () => player,
|
||||
sendUse: null,
|
||||
sendUseWithTarget: null,
|
||||
sendWield: null,
|
||||
sendDrop: null,
|
||||
sendExamine: appraisals.Add);
|
||||
using var controller = ToolbarController.Bind(
|
||||
layout,
|
||||
repo,
|
||||
() => shortcuts,
|
||||
iconIds: (_, _, _, _, _) => 1u,
|
||||
useItem: _ => { },
|
||||
itemInteraction: interaction,
|
||||
selectItem: id => selection.Select(id, SelectionChangeSource.Toolbar),
|
||||
selection: selection);
|
||||
|
||||
UiItemSlot cell = slots[Row1[0]].Cell;
|
||||
cell.OnEvent(new UiEvent(0u, cell, UiEventType.RightClick));
|
||||
|
||||
Assert.Equal(itemId, selection.SelectedObjectId);
|
||||
Assert.Equal(new uint[] { itemId }, appraisals);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void UseShortcut_targetModePrecedesUseAndClearsOneShotMode()
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue