fix(ui): port retail window control feedback
Map synthetic move and resize affordances to the exact DAT cursors, make chat top chrome movable, and replace stale primary-panel height caps with a dynamic screen-edge constraint. This keeps the retained wrapper adaptation aligned with retail Dragbar/Resizebar behavior.
This commit is contained in:
parent
3f3cfdac30
commit
06016014bc
16 changed files with 578 additions and 27 deletions
|
|
@ -32,17 +32,25 @@ public sealed class CursorFeedbackControllerTests
|
|||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(ResizeEdges.Right, CursorFeedbackKind.ResizeHorizontal)]
|
||||
[InlineData(ResizeEdges.Bottom, CursorFeedbackKind.ResizeVertical)]
|
||||
[InlineData(ResizeEdges.Right | ResizeEdges.Bottom, CursorFeedbackKind.ResizeDiagonalNwse)]
|
||||
[InlineData(ResizeEdges.Left | ResizeEdges.Bottom, CursorFeedbackKind.ResizeDiagonalNesw)]
|
||||
public void ResizeEdges_chooseExpectedCursor(ResizeEdges edges, CursorFeedbackKind expected)
|
||||
[InlineData(ResizeEdges.Left, CursorFeedbackKind.ResizeHorizontal, 0x06006128u)]
|
||||
[InlineData(ResizeEdges.Right, CursorFeedbackKind.ResizeHorizontal, 0x06006128u)]
|
||||
[InlineData(ResizeEdges.Top, CursorFeedbackKind.ResizeVertical, 0x06005E66u)]
|
||||
[InlineData(ResizeEdges.Bottom, CursorFeedbackKind.ResizeVertical, 0x06005E66u)]
|
||||
[InlineData(ResizeEdges.Left | ResizeEdges.Top, CursorFeedbackKind.ResizeDiagonalNwse, 0x06006126u)]
|
||||
[InlineData(ResizeEdges.Right | ResizeEdges.Bottom, CursorFeedbackKind.ResizeDiagonalNwse, 0x06006126u)]
|
||||
[InlineData(ResizeEdges.Left | ResizeEdges.Bottom, CursorFeedbackKind.ResizeDiagonalNesw, 0x06006127u)]
|
||||
[InlineData(ResizeEdges.Right | ResizeEdges.Top, CursorFeedbackKind.ResizeDiagonalNesw, 0x06006127u)]
|
||||
public void ResizeEdges_chooseExpectedRetailCursor(
|
||||
ResizeEdges edges,
|
||||
CursorFeedbackKind expected,
|
||||
uint expectedDid)
|
||||
{
|
||||
var c = new CursorFeedbackController();
|
||||
|
||||
var feedback = c.Resolve(new CursorFeedbackSnapshot(HoverResizeEdges: edges));
|
||||
|
||||
Assert.Equal(expected, feedback.Kind);
|
||||
Assert.Equal(new UiCursorMedia(expectedDid, 16, 16), feedback.Cursor);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -52,10 +60,93 @@ public sealed class CursorFeedbackControllerTests
|
|||
|
||||
Assert.Equal(CursorFeedbackKind.WindowMove,
|
||||
c.Resolve(new CursorFeedbackSnapshot(HoverWindowMove: true)).Kind);
|
||||
Assert.Equal(new UiCursorMedia(0x06006119u, 16, 16),
|
||||
c.Resolve(new CursorFeedbackSnapshot(HoverWindowMove: true)).Cursor);
|
||||
Assert.Equal(CursorFeedbackKind.Text,
|
||||
c.Resolve(new CursorFeedbackSnapshot(HoverTextEdit: true)).Kind);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ActiveSyntheticResize_keepsControlCursorOverAuthoredCapturedElement()
|
||||
{
|
||||
var root = new UiRoot { Width = 400, Height = 300 };
|
||||
var window = new UiPanel
|
||||
{
|
||||
Left = 50,
|
||||
Top = 40,
|
||||
Width = 150,
|
||||
Height = 100,
|
||||
Draggable = true,
|
||||
Resizable = true,
|
||||
};
|
||||
var content = new UiPanel { Width = 150, Height = 100 };
|
||||
var authored = new UiCursorMedia(0x06009999u, 3, 4);
|
||||
content.SetStateCursors(new Dictionary<string, UiCursorMedia> { [""] = authored });
|
||||
window.AddChild(content);
|
||||
root.AddChild(window);
|
||||
var controller = new CursorFeedbackController();
|
||||
|
||||
root.OnMouseMove(199, 90); // inside the five-pixel right-edge resizebar region
|
||||
Assert.Equal(new UiCursorMedia(0x06006128u, 16, 16), controller.Update(root).Cursor);
|
||||
|
||||
root.OnMouseDown(UiMouseButton.Left, 199, 90);
|
||||
root.OnMouseMove(100, 90); // leave the edge while resize capture remains active
|
||||
|
||||
CursorFeedback active = controller.Update(root);
|
||||
Assert.Equal(CursorFeedbackKind.ResizeHorizontal, active.Kind);
|
||||
Assert.Equal(new UiCursorMedia(0x06006128u, 16, 16), active.Cursor);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AuthoredWidgetCursor_winsUntilSyntheticWindowMoveStarts()
|
||||
{
|
||||
var root = new UiRoot { Width = 400, Height = 300 };
|
||||
var window = new UiPanel
|
||||
{
|
||||
Left = 50,
|
||||
Top = 40,
|
||||
Width = 150,
|
||||
Height = 100,
|
||||
Draggable = true,
|
||||
};
|
||||
var dragRegion = new UiPanel { Width = 150, Height = 100 };
|
||||
var authored = new UiCursorMedia(0x06008888u, 7, 8);
|
||||
dragRegion.SetStateCursors(new Dictionary<string, UiCursorMedia> { [""] = authored });
|
||||
window.AddChild(dragRegion);
|
||||
root.AddChild(window);
|
||||
var controller = new CursorFeedbackController();
|
||||
|
||||
root.OnMouseMove(100, 90);
|
||||
Assert.Equal(authored, controller.Update(root).Cursor);
|
||||
|
||||
root.OnMouseDown(UiMouseButton.Left, 100, 90);
|
||||
Assert.Equal(new UiCursorMedia(0x06006119u, 16, 16), controller.Update(root).Cursor);
|
||||
|
||||
root.OnMouseMove(300, 200);
|
||||
Assert.Equal(new UiCursorMedia(0x06006119u, 16, 16), controller.Update(root).Cursor);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void UiLock_suppressesSyntheticWindowControlCursors()
|
||||
{
|
||||
var root = new UiRoot { Width = 400, Height = 300, UiLocked = true };
|
||||
root.AddChild(new UiPanel
|
||||
{
|
||||
Left = 50,
|
||||
Top = 40,
|
||||
Width = 150,
|
||||
Height = 100,
|
||||
Draggable = true,
|
||||
Resizable = true,
|
||||
});
|
||||
root.OnMouseMove(199, 90);
|
||||
|
||||
CursorFeedback feedback = new CursorFeedbackController().Update(root);
|
||||
|
||||
Assert.Equal(CursorFeedbackKind.Default, feedback.Kind);
|
||||
Assert.False(feedback.Cursor.IsValid);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TargetMode_reportsValidInvalidAndPendingTargets()
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue