feat(ui): D.5.3/B.2 — spine: drag-lift hook + ghost snapshot (full opacity) + drop-on-hit-only
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
a497cc631e
commit
41bb70c11a
5 changed files with 84 additions and 26 deletions
|
|
@ -11,6 +11,9 @@ public class DragDropSpineTests
|
|||
public bool AcceptResult = true;
|
||||
public (UiItemList list, UiItemSlot cell, ItemDragPayload payload)? LastOver;
|
||||
public (UiItemList list, UiItemSlot cell, ItemDragPayload payload)? LastDrop;
|
||||
public (UiItemList list, UiItemSlot cell, ItemDragPayload payload)? LastLift;
|
||||
public void OnDragLift(UiItemList list, UiItemSlot cell, ItemDragPayload p)
|
||||
{ LastLift = (list, cell, p); }
|
||||
|
||||
public bool OnDragOver(UiItemList list, UiItemSlot cell, ItemDragPayload p)
|
||||
{ LastOver = (list, cell, p); return AcceptResult; }
|
||||
|
|
@ -125,11 +128,54 @@ public class DragDropSpineTests
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public void DropReleased_notAccepted_skipsDispatch()
|
||||
public void DropReleased_dispatchesToHandler_regardlessOfData0()
|
||||
{
|
||||
var (_, cell, h) = ListWithHandler();
|
||||
// Retail model: reaching the cell means a real slot was hit (FinishDrag only delivers on a
|
||||
// hit), so the handler is authoritative — it dispatches whether or not Data0 is set.
|
||||
var (list, cell, h) = ListWithHandler();
|
||||
cell.OnEvent(new UiEvent(0u, cell, UiEventType.DropReleased, Data0: 0, Payload: SomePayload()));
|
||||
Assert.Null(h.LastDrop);
|
||||
Assert.NotNull(h.LastDrop);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DragBegin_callsHandlerOnDragLift()
|
||||
{
|
||||
var (list, cell, h) = ListWithHandler();
|
||||
var p = SomePayload();
|
||||
cell.OnEvent(new UiEvent(0u, cell, UiEventType.DragBegin, Payload: p));
|
||||
Assert.NotNull(h.LastLift);
|
||||
Assert.Same(list, h.LastLift!.Value.list);
|
||||
Assert.Same(cell, h.LastLift.Value.cell);
|
||||
Assert.Same(p, h.LastLift.Value.payload);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Ghost_isSnapshottedAtBeginDrag_survivesSourceCellClearing()
|
||||
{
|
||||
var (root, _, cell) = RootWithBoundSlot(0x5001u); // icon tex 0x99
|
||||
root.OnMouseDown(UiMouseButton.Left, 10, 10);
|
||||
root.OnMouseMove(20, 10); // BeginDrag → snapshot ghost
|
||||
cell.Clear(); // simulate the lift emptying the source
|
||||
Assert.Equal((0x99u, 32, 32), root.DragGhostForTest);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FinishDrag_overNothing_deliversNoDrop_butLiftStands()
|
||||
{
|
||||
var root = new UiRoot { Width = 800, Height = 600 };
|
||||
var list = new UiItemList(_ => (1u, 1, 1)) { Left = 0, Top = 0, Width = 32, Height = 32 };
|
||||
list.Cell.Width = 32; list.Cell.Height = 32;
|
||||
list.Cell.SetItem(0x5001u, 0x99u);
|
||||
var h = new SpyHandler();
|
||||
list.RegisterDragHandler(h);
|
||||
root.AddChild(list);
|
||||
|
||||
root.OnMouseDown(UiMouseButton.Left, 10, 10);
|
||||
root.OnMouseMove(20, 10); // BeginDrag → OnDragLift
|
||||
root.OnMouseUp(UiMouseButton.Left, 600, 500); // release over empty space
|
||||
Assert.NotNull(h.LastLift); // lift happened
|
||||
Assert.Null(h.LastDrop); // no drop dispatched (off-bar)
|
||||
Assert.Null(root.DragSource); // cleaned up
|
||||
}
|
||||
|
||||
// ── Full UiRoot chain: arming + use-vs-drag ─────────────────────────────
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue