feat(ui): ghost-window drag infrastructure for task rows

Add the borderless, transparent, topmost, click-through DragGhostWindow that
hosts a tilted (~-6deg) translucent snapshot of the dragged row, a
TaskDragController that owns its lifecycle (snapshot -> show -> follow -> close),
and a pure DPI-aware DragHitTest helper (unit-tested) for the cross-window
screen hit test. Adds the TaskRowViewModel.IsDragging flag and the
'grabbed' Border.task-row.dragging style (lift + scale + lower opacity +
shadow). Not yet wired into the drag source.
This commit is contained in:
Mika Kuns
2026-06-25 22:39:17 +02:00
parent 946d26cc4b
commit 05aec8ebfa
8 changed files with 200 additions and 0 deletions

View File

@@ -0,0 +1,44 @@
using Avalonia;
using ClaudeDo.Ui.Views.Controls;
using Xunit;
namespace ClaudeDo.Ui.Tests;
public class DragHitTestTests
{
[Fact]
public void Cursor_inside_window_rect_is_contained()
{
var pos = new PixelPoint(100, 100);
var client = new Size(800, 600);
Assert.True(DragHitTest.WindowContains(pos, client, 1.0, new PixelPoint(500, 400)));
}
[Fact]
public void Cursor_outside_window_rect_is_not_contained()
{
var pos = new PixelPoint(100, 100);
var client = new Size(800, 600);
Assert.False(DragHitTest.WindowContains(pos, client, 1.0, new PixelPoint(50, 50))); // above-left
Assert.False(DragHitTest.WindowContains(pos, client, 1.0, new PixelPoint(950, 400))); // past right edge
}
[Fact]
public void Top_left_is_inclusive_bottom_right_is_exclusive()
{
var pos = new PixelPoint(100, 100);
var client = new Size(800, 600);
Assert.True(DragHitTest.WindowContains(pos, client, 1.0, new PixelPoint(100, 100))); // top-left corner
Assert.False(DragHitTest.WindowContains(pos, client, 1.0, new PixelPoint(900, 700))); // bottom-right corner
}
[Fact]
public void Scaling_expands_the_physical_rect()
{
var pos = new PixelPoint(100, 100);
var client = new Size(800, 600); // logical
// At 2x the right edge is 100 + 1600 = 1700, so a point at x=1600 now falls inside.
Assert.False(DragHitTest.WindowContains(pos, client, 1.0, new PixelPoint(1600, 400)));
Assert.True(DragHitTest.WindowContains(pos, client, 2.0, new PixelPoint(1600, 400)));
}
}