|
|
|
@ -19,13 +19,14 @@ namespace Avalonia.Controls.DragDrop |
|
|
|
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 DragDropEffects _allowedEffects; |
|
|
|
private IDataObject _draggedData; |
|
|
|
private IInputElement _lastRoot; |
|
|
|
private InputModifiers? _initialInputModifiers; |
|
|
|
private Point _lastPosition; |
|
|
|
private object _lastCursor; |
|
|
|
private InputModifiers? _initialInputModifiers; |
|
|
|
|
|
|
|
public DragSource() |
|
|
|
{ |
|
|
|
@ -40,35 +41,58 @@ namespace Avalonia.Controls.DragDrop |
|
|
|
{ |
|
|
|
_draggedData = data; |
|
|
|
_lastRoot = null; |
|
|
|
_lastPosition = default(Point); |
|
|
|
_allowedEffects = allowedEffects; |
|
|
|
|
|
|
|
using (_inputManager.PreProcess.OfType<RawMouseEventArgs>().Subscribe(e => ProcessMouseEvents(e, allowedEffects))) |
|
|
|
using (_inputManager.PreProcess.OfType<RawMouseEventArgs>().Subscribe(ProcessMouseEvents)) |
|
|
|
{ |
|
|
|
var effect = await _result.FirstAsync(); |
|
|
|
return effect; |
|
|
|
using (_inputManager.PreProcess.OfType<RawKeyEventArgs>().Subscribe(ProcessKeyEvents)) |
|
|
|
{ |
|
|
|
var effect = await _result.FirstAsync(); |
|
|
|
return effect; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
return DragDropEffects.None; |
|
|
|
} |
|
|
|
|
|
|
|
private DragDropEffects RaiseDragEvent(RawDragEventType type, IInputElement root, Point pt, DragDropEffects allowedEffects) |
|
|
|
|
|
|
|
private DragDropEffects RaiseEventAndUpdateCursor(RawDragEventType type, IInputElement root, Point pt, InputModifiers modifiers) |
|
|
|
{ |
|
|
|
RawDragEvent rawEvent = new RawDragEvent(_dragDrop, type, root, pt, _draggedData, allowedEffects); |
|
|
|
_lastPosition = pt; |
|
|
|
|
|
|
|
RawDragEvent rawEvent = new RawDragEvent(_dragDrop, type, root, pt, _draggedData, _allowedEffects); |
|
|
|
var tl = root.GetSelfAndVisualAncestors().OfType<TopLevel>().FirstOrDefault(); |
|
|
|
tl.PlatformImpl.Input(rawEvent); |
|
|
|
|
|
|
|
SetCursor(root, rawEvent.Effects); |
|
|
|
return rawEvent.Effects; |
|
|
|
|
|
|
|
var effect = GetPreferredEffect(rawEvent.Effects & _allowedEffects, modifiers); |
|
|
|
UpdateCursor(root, effect); |
|
|
|
return effect; |
|
|
|
} |
|
|
|
|
|
|
|
private DragDropEffects GetPreferredEffect(DragDropEffects effect, InputModifiers modifiers) |
|
|
|
{ |
|
|
|
if (effect == DragDropEffects.Copy || effect == DragDropEffects.Move || effect == DragDropEffects.Link || effect == DragDropEffects.None) |
|
|
|
return effect; // No need to check for the modifiers.
|
|
|
|
if (effect.HasFlag(DragDropEffects.Link) && modifiers.HasFlag(InputModifiers.Alt)) |
|
|
|
return DragDropEffects.Link; |
|
|
|
if (effect.HasFlag(DragDropEffects.Copy) && modifiers.HasFlag(InputModifiers.Control)) |
|
|
|
return DragDropEffects.Copy; |
|
|
|
return DragDropEffects.Move; |
|
|
|
} |
|
|
|
|
|
|
|
private Cursor GetCursorForDropEffect(DragDropEffects effects) |
|
|
|
{ |
|
|
|
// Todo. Needs to choose cursor by effect.
|
|
|
|
if (effects == DragDropEffects.None) |
|
|
|
return new Cursor(StandardCursorType.No); |
|
|
|
return new Cursor(StandardCursorType.Hand); |
|
|
|
if (effects.HasFlag(DragDropEffects.Copy)) |
|
|
|
return new Cursor(StandardCursorType.DragCopy); |
|
|
|
if (effects.HasFlag(DragDropEffects.Move)) |
|
|
|
return new Cursor(StandardCursorType.DragMove); |
|
|
|
if (effects.HasFlag(DragDropEffects.Link)) |
|
|
|
return new Cursor(StandardCursorType.DragLink); |
|
|
|
return new Cursor(StandardCursorType.No); |
|
|
|
} |
|
|
|
|
|
|
|
private void SetCursor(IInputElement root, DragDropEffects effect) |
|
|
|
private void UpdateCursor(IInputElement root, DragDropEffects effect) |
|
|
|
{ |
|
|
|
if (_lastRoot != root) |
|
|
|
{ |
|
|
|
@ -96,25 +120,45 @@ namespace Avalonia.Controls.DragDrop |
|
|
|
if (root is InputElement ie) |
|
|
|
ie.Cursor = GetCursorForDropEffect(effect); |
|
|
|
} |
|
|
|
|
|
|
|
private void ProcessMouseEvents(RawMouseEventArgs e, DragDropEffects allowedEffects) |
|
|
|
|
|
|
|
private void CancelDragging() |
|
|
|
{ |
|
|
|
if (!_initialInputModifiers.HasValue) |
|
|
|
_initialInputModifiers = e.InputModifiers & MOUSE_INPUTMODIFIERS; |
|
|
|
if (_lastRoot != null) |
|
|
|
RaiseEventAndUpdateCursor(RawDragEventType.DragLeave, _lastRoot, _lastPosition, InputModifiers.None); |
|
|
|
UpdateCursor(null, DragDropEffects.None); |
|
|
|
_result.OnNext(DragDropEffects.None); |
|
|
|
} |
|
|
|
|
|
|
|
void CancelDragging() |
|
|
|
private void ProcessKeyEvents(RawKeyEventArgs e) |
|
|
|
{ |
|
|
|
if (e.Type == RawKeyEventType.KeyDown && e.Key == Key.Escape) |
|
|
|
{ |
|
|
|
if (_lastRoot != null) |
|
|
|
RaiseDragEvent(RawDragEventType.DragLeave, _lastRoot, _lastRoot.PointToClient(e.Root.PointToScreen(e.Position)), allowedEffects); |
|
|
|
SetCursor(null, DragDropEffects.None); |
|
|
|
RaiseEventAndUpdateCursor(RawDragEventType.DragLeave, _lastRoot, _lastPosition, e.Modifiers); |
|
|
|
UpdateCursor(null, DragDropEffects.None); |
|
|
|
_result.OnNext(DragDropEffects.None); |
|
|
|
e.Handled = true; |
|
|
|
} |
|
|
|
void AcceptDragging() |
|
|
|
else if (e.Key == Key.LeftCtrl || e.Key == Key.RightCtrl || e.Key == Key.LeftAlt || e.Key == Key.RightAlt) |
|
|
|
RaiseEventAndUpdateCursor(RawDragEventType.DragOver, _lastRoot, _lastPosition, e.Modifiers); |
|
|
|
} |
|
|
|
|
|
|
|
private void ProcessMouseEvents(RawMouseEventArgs e) |
|
|
|
{ |
|
|
|
if (!_initialInputModifiers.HasValue) |
|
|
|
_initialInputModifiers = e.InputModifiers & MOUSE_INPUTMODIFIERS; |
|
|
|
|
|
|
|
|
|
|
|
void CheckDraggingAccepted(InputModifiers changedMouseButton) |
|
|
|
{ |
|
|
|
var result = RaiseDragEvent(RawDragEventType.Drop, e.Root, e.Position, allowedEffects) & allowedEffects; |
|
|
|
SetCursor(null, DragDropEffects.None); |
|
|
|
_result.OnNext(result); |
|
|
|
if (_initialInputModifiers.Value.HasFlag(changedMouseButton)) |
|
|
|
{ |
|
|
|
var result = RaiseEventAndUpdateCursor(RawDragEventType.Drop, e.Root, e.Position, e.InputModifiers); |
|
|
|
UpdateCursor(null, DragDropEffects.None); |
|
|
|
_result.OnNext(result); |
|
|
|
} |
|
|
|
else |
|
|
|
CancelDragging(); |
|
|
|
e.Handled = true; |
|
|
|
} |
|
|
|
|
|
|
|
@ -125,45 +169,34 @@ namespace Avalonia.Controls.DragDrop |
|
|
|
case RawMouseEventType.MiddleButtonDown: |
|
|
|
case RawMouseEventType.NonClientLeftButtonDown: |
|
|
|
CancelDragging(); |
|
|
|
e.Handled = true; |
|
|
|
return; |
|
|
|
case RawMouseEventType.LeaveWindow: |
|
|
|
RaiseDragEvent(RawDragEventType.DragLeave, e.Root, e.Position, allowedEffects); |
|
|
|
break; |
|
|
|
RaiseEventAndUpdateCursor(RawDragEventType.DragLeave, e.Root, e.Position, e.InputModifiers); break; |
|
|
|
case RawMouseEventType.LeftButtonUp: |
|
|
|
if (_initialInputModifiers.Value.HasFlag(InputModifiers.LeftMouseButton)) |
|
|
|
AcceptDragging(); |
|
|
|
else |
|
|
|
CancelDragging(); |
|
|
|
return; |
|
|
|
CheckDraggingAccepted(InputModifiers.LeftMouseButton); break; |
|
|
|
case RawMouseEventType.MiddleButtonUp: |
|
|
|
if (_initialInputModifiers.Value.HasFlag(InputModifiers.MiddleMouseButton)) |
|
|
|
AcceptDragging(); |
|
|
|
else |
|
|
|
CancelDragging(); |
|
|
|
return; |
|
|
|
CheckDraggingAccepted(InputModifiers.MiddleMouseButton); break; |
|
|
|
case RawMouseEventType.RightButtonUp: |
|
|
|
if (_initialInputModifiers.Value.HasFlag(InputModifiers.RightMouseButton)) |
|
|
|
AcceptDragging(); |
|
|
|
else |
|
|
|
CancelDragging(); |
|
|
|
return; |
|
|
|
CheckDraggingAccepted(InputModifiers.RightMouseButton); break; |
|
|
|
case RawMouseEventType.Move: |
|
|
|
var mods = e.InputModifiers & MOUSE_INPUTMODIFIERS; |
|
|
|
if (_initialInputModifiers.Value != mods) |
|
|
|
{ |
|
|
|
CancelDragging(); |
|
|
|
e.Handled = true; |
|
|
|
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); |
|
|
|
RaiseEventAndUpdateCursor(RawDragEventType.DragLeave, _lastRoot, _lastRoot.PointToClient(e.Root.PointToScreen(e.Position)), e.InputModifiers); |
|
|
|
RaiseEventAndUpdateCursor(RawDragEventType.DragEnter, e.Root, e.Position, e.InputModifiers); |
|
|
|
} |
|
|
|
else |
|
|
|
RaiseDragEvent(RawDragEventType.DragOver, e.Root, e.Position, allowedEffects); |
|
|
|
return; |
|
|
|
RaiseEventAndUpdateCursor(RawDragEventType.DragOver, e.Root, e.Position, e.InputModifiers); |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|