-
-
Notifications
You must be signed in to change notification settings - Fork 2.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Drag and drop doesn't work using Headless #17331
Labels
Comments
Drag&drop itself is working in headless with one important problem: it doesn't understand teleporting cursor. Between example of testsusing System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Controls.Shapes;
using Avalonia.Headless;
using Avalonia.Headless.XUnit;
using Avalonia.Input;
using Avalonia.Media;
using Avalonia.Reactive;
using Xunit;
namespace HeadlessTest;
public class UnitTest1 : IAsyncLifetime
{
[AvaloniaFact]
public async Task InWindowDragDrop()
{
var win = new Window()
{
Width = 640,
Height = 480,
};
var left = new Ellipse
{
Fill = Brushes.Red,
};
var dropComplete = new TaskCompletionSource<object?>();
bool isPressed = false;
left.PointerPressed += (sender, e) => { isPressed = true; };
left.PointerReleased += (sender, e) => { isPressed = false; };
left.PointerMoved += async (sender, e) =>
{
if (isPressed)
{
await DragDrop.DoDragDrop(e, new DataObject { }, DragDropEffects.Link);
isPressed = false;
}
};
var right = new Rectangle
{
Fill = Brushes.Green,
[DragDrop.AllowDropProperty] = true,
};
right.AddHandler(DragDrop.DropEvent, (sender, e) =>
{
right.Fill = Brushes.Blue;
dropComplete.SetResult(null);
});
right.AddHandler(DragDrop.DragEnterEvent, (sender, e) =>
{
right.Fill = Brushes.Yellow;
});
right.AddHandler(DragDrop.DragLeaveEvent, (sender, e) =>
{
right.Fill = Brushes.Green;
});
win.Content = new UniformGrid
{
Columns = 2,
Children = { left, right }
};
win.Show();
DragMouse(win, new Point(160, 240), new Point(480, 240));
await dropComplete.Task.WaitAsync2(TimeSpan.FromSeconds(1));
}
[AvaloniaFact]
public async Task BetweenWindowsDragDrop()
{
var left = new Ellipse
{
Fill = Brushes.Red,
};
var leftWin = new Window()
{
Width = 640,
Height = 480,
Content = left,
Position = new PixelPoint(0, 0),
};
var dropComplete = new TaskCompletionSource<object?>();
bool isPressed = false;
left.PointerPressed += (sender, e) => { isPressed = true; };
left.PointerReleased += (sender, e) => { isPressed = false; };
left.PointerMoved += async (sender, e) =>
{
if (isPressed)
{
await DragDrop.DoDragDrop(e, new DataObject { }, DragDropEffects.Link);
isPressed = false;
}
};
var right = new Rectangle
{
Fill = Brushes.Green,
[DragDrop.AllowDropProperty] = true,
};
var rightWin = new Window
{
Width = 640,
Height = 480,
Content = right,
Position = new PixelPoint(640, 0),
};
right.AddHandler(DragDrop.DropEvent, (sender, e) =>
{
right.Fill = Brushes.Blue;
dropComplete.SetResult(null);
});
right.AddHandler(DragDrop.DragEnterEvent, (sender, e) =>
{
right.Fill = Brushes.Yellow;
});
right.AddHandler(DragDrop.DragLeaveEvent, (sender, e) =>
{
right.Fill = Brushes.Green;
});
leftWin.Show();
rightWin.Show();
DragMouseAbsolute(new Point(320, 240), new Point(960, 240));
await dropComplete.Task.WaitAsync2(TimeSpan.FromSeconds(1));
}
private static void DragMouse(Window win, Point start, Point end)
{
win.MouseDown(start, MouseButton.Left, RawInputModifiers.LeftMouseButton);
win.MouseMove(start + GetDirection(start, end), RawInputModifiers.LeftMouseButton);
win.MouseMove(end, RawInputModifiers.LeftMouseButton);
win.MouseUp(end, MouseButton.Left, RawInputModifiers.LeftMouseButton);
}
private static void DragMouseAbsolute(Point start, Point end)
{
var startWin = WindowLocator.FindWindow(start) ?? throw new Exception("Cannot find window under 'start'");
var endWin = WindowLocator.FindWindow(end) ?? throw new Exception("Cannot find window under 'end'");
var direction = GetDirection(start, end);
var localStart = start - startWin.Position.ToPoint(1);
var localEnd = end - endWin.Position.ToPoint(1);
startWin.MouseDown(localStart, MouseButton.Left, RawInputModifiers.LeftMouseButton);
startWin.MouseMove(localStart + direction, RawInputModifiers.LeftMouseButton);
endWin.MouseMove(localEnd - direction, RawInputModifiers.LeftMouseButton);
endWin.MouseUp(localEnd, MouseButton.Left, RawInputModifiers.LeftMouseButton);
}
private static Point GetDirection(Point start, Point end)
{
var x = Math.Sign(end.X - start.X);
var y = Math.Sign(end.Y - start.Y);
return new Point(x, y);
}
public Task InitializeAsync()
{
// force WindowLocator to subscribe to events and start monitoring windows
RuntimeHelpers.RunClassConstructor(typeof(WindowLocator).TypeHandle);
return Task.CompletedTask;
}
public Task DisposeAsync()
{
return Task.CompletedTask;
}
}
internal static class TaskExtensions
{
// Task.WaitAsync is not available on netstandard2.0
public static async Task<T> WaitAsync2<T>(this Task<T> task, TimeSpan timeout)
{
var completedTask = await Task.WhenAny(task, Task.Delay(timeout));
if (completedTask is Task<T> t)
{
return await t;
}
else
{
throw new TimeoutException();
}
}
}
internal static class WindowLocator
{
private static readonly HashSet<Window> s_windows = [];
static WindowLocator()
{
Window.WindowOpenedEvent.Raised.Subscribe(e =>
{
s_windows.Add((Window)e.Item1);
});
Window.WindowClosedEvent.Raised.Subscribe(e =>
{
s_windows.Remove((Window)e.Item1);
});
}
public static IEnumerable<Window> GetWindows()
{
return s_windows;
}
public static Window? FindWindow(Point point)
{
foreach (var win in s_windows)
{
var bounds = new Rect(win.Position.ToPoint(1), win.Bounds.Size);
if (bounds.Contains(point))
{
return win;
}
}
return null;
}
} Attached code contains 2 most important methods:
|
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Describe the bug
You can't emulate drag and drop using Headless
To Reproduce
public static void DragAndDrop(this Window window, Point dragStartPosition, Point dropPosition)
{
window.MouseDown(dragStartPosition, MouseButton.Left);
window.MouseMove(dropPosition);
window.MouseUp(dropPosition, MouseButton.Left);
}
Expected behavior
No response
Avalonia version
11.1.3
OS
Windows
Additional context
No response
The text was updated successfully, but these errors were encountered: