8 changed files with 185 additions and 11 deletions
@ -0,0 +1,129 @@ |
|||
using System; |
|||
using System.Linq; |
|||
using System.Reactive.Linq; |
|||
using System.Reactive.Subjects; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
using Avalonia.Controls.DragDrop.Raw; |
|||
using Avalonia.Controls.Platform; |
|||
using Avalonia.Input; |
|||
using Avalonia.Input.Raw; |
|||
using Avalonia.Interactivity; |
|||
using Avalonia.Threading; |
|||
using Avalonia.VisualTree; |
|||
|
|||
namespace Avalonia.Controls.DragDrop |
|||
{ |
|||
class DragSource : IPlatformDragSource |
|||
{ |
|||
private const InputModifiers MOUSE_INPUTMODIFIERS = InputModifiers.LeftMouseButton|InputModifiers.MiddleMouseButton|InputModifiers.RightMouseButton; |
|||
private readonly IDragDropDevice _dragDrop; |
|||
private readonly IInputManager _inputManager; |
|||
|
|||
|
|||
private readonly Subject<DragDropEffects> _result = new Subject<DragDropEffects>(); |
|||
private IDataObject _draggedData; |
|||
private IInputRoot _lastRoot; |
|||
private InputModifiers? _initialInputModifiers; |
|||
|
|||
public DragSource() |
|||
{ |
|||
_inputManager = AvaloniaLocator.Current.GetService<IInputManager>(); |
|||
_dragDrop = AvaloniaLocator.Current.GetService<IDragDropDevice>(); |
|||
} |
|||
|
|||
public async Task<DragDropEffects> DoDragDrop(IDataObject data, DragDropEffects allowedEffects) |
|||
{ |
|||
Dispatcher.UIThread.VerifyAccess(); |
|||
if (_draggedData == null) |
|||
{ |
|||
_draggedData = data; |
|||
_lastRoot = null; |
|||
|
|||
using (_inputManager.PreProcess.OfType<RawMouseEventArgs>().Subscribe(e => ProcessMouseEvents(e, allowedEffects))) |
|||
{ |
|||
var effect = await _result.FirstAsync(); |
|||
return effect; |
|||
} |
|||
} |
|||
return DragDropEffects.None; |
|||
} |
|||
|
|||
private DragDropEffects RaiseDragEvent(RawDragEventType type, IInputElement root, Point pt, DragDropEffects allowedEffects) |
|||
{ |
|||
RawDragEvent rawEvent = new RawDragEvent(_dragDrop, type, root, pt, _draggedData, allowedEffects); |
|||
var tl = root.GetSelfAndVisualAncestors().OfType<TopLevel>().FirstOrDefault(); |
|||
tl.PlatformImpl.Input(rawEvent); |
|||
return rawEvent.Effects; |
|||
} |
|||
|
|||
private void ProcessMouseEvents(RawMouseEventArgs e, DragDropEffects allowedEffects) |
|||
{ |
|||
if (!_initialInputModifiers.HasValue) |
|||
_initialInputModifiers = e.InputModifiers & MOUSE_INPUTMODIFIERS; |
|||
|
|||
void CancelDragging() |
|||
{ |
|||
if (_lastRoot != null) |
|||
RaiseDragEvent(RawDragEventType.DragLeave, _lastRoot, _lastRoot.PointToClient(e.Root.PointToScreen(e.Position)), allowedEffects); |
|||
_result.OnNext(DragDropEffects.None); |
|||
e.Handled = true; |
|||
} |
|||
void AcceptDragging() |
|||
{ |
|||
var result = RaiseDragEvent(RawDragEventType.Drop, e.Root, e.Position, allowedEffects) & allowedEffects; |
|||
_result.OnNext(result); |
|||
e.Handled = true; |
|||
} |
|||
|
|||
switch (e.Type) |
|||
{ |
|||
case RawMouseEventType.LeftButtonDown: |
|||
case RawMouseEventType.RightButtonDown: |
|||
case RawMouseEventType.MiddleButtonDown: |
|||
case RawMouseEventType.NonClientLeftButtonDown: |
|||
CancelDragging(); |
|||
return; |
|||
case RawMouseEventType.LeaveWindow: |
|||
RaiseDragEvent(RawDragEventType.DragLeave, e.Root, e.Position, allowedEffects); |
|||
break; |
|||
case RawMouseEventType.LeftButtonUp: |
|||
if (_initialInputModifiers.Value.HasFlag(InputModifiers.LeftMouseButton)) |
|||
AcceptDragging(); |
|||
else |
|||
CancelDragging(); |
|||
return; |
|||
case RawMouseEventType.MiddleButtonUp: |
|||
if (_initialInputModifiers.Value.HasFlag(InputModifiers.MiddleMouseButton)) |
|||
AcceptDragging(); |
|||
else |
|||
CancelDragging(); |
|||
return; |
|||
case RawMouseEventType.RightButtonUp: |
|||
if (_initialInputModifiers.Value.HasFlag(InputModifiers.RightMouseButton)) |
|||
AcceptDragging(); |
|||
else |
|||
CancelDragging(); |
|||
return; |
|||
case RawMouseEventType.Move: |
|||
var mods = e.InputModifiers & MOUSE_INPUTMODIFIERS; |
|||
if (_initialInputModifiers.Value != mods) |
|||
{ |
|||
CancelDragging(); |
|||
return; |
|||
} |
|||
|
|||
if (e.Root != _lastRoot) |
|||
{ |
|||
if (_lastRoot != null) |
|||
RaiseDragEvent(RawDragEventType.DragLeave, _lastRoot, _lastRoot.PointToClient(e.Root.PointToScreen(e.Position)), allowedEffects); |
|||
RaiseDragEvent(RawDragEventType.DragEnter, e.Root, e.Position, allowedEffects); |
|||
_lastRoot = e.Root; |
|||
} |
|||
else |
|||
RaiseDragEvent(RawDragEventType.DragOver, e.Root, e.Position, allowedEffects); |
|||
return; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,14 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
using Avalonia.Controls.DragDrop; |
|||
using Avalonia.Interactivity; |
|||
|
|||
namespace Avalonia.Controls.Platform |
|||
{ |
|||
public interface IPlatformDragSource |
|||
{ |
|||
Task<DragDropEffects> DoDragDrop(IDataObject data, DragDropEffects allowedEffects); |
|||
} |
|||
} |
|||
@ -0,0 +1,28 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
using Avalonia.Controls.DragDrop; |
|||
using Avalonia.Controls.Platform; |
|||
using Avalonia.Interactivity; |
|||
using Avalonia.Threading; |
|||
using Avalonia.Win32.Interop; |
|||
|
|||
namespace Avalonia.Win32 |
|||
{ |
|||
class DragSource : IPlatformDragSource |
|||
{ |
|||
public Task<DragDropEffects> DoDragDrop(IDataObject data, DragDropEffects allowedEffects) |
|||
{ |
|||
Dispatcher.UIThread.VerifyAccess(); |
|||
|
|||
OleDragSource src = new OleDragSource(); |
|||
DataObject dataObject = new DataObject(data); |
|||
int allowed = (int)OleDropTarget.ConvertDropEffect(allowedEffects); |
|||
|
|||
int[] finalEffect = new int[1]; |
|||
UnmanagedMethods.DoDragDrop(dataObject, src, allowed, finalEffect); |
|||
|
|||
return Task.FromResult(OleDropTarget.ConvertDropEffect((DropEffect)finalEffect[0]));} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue