Browse Source

Basic generic + Windows Drag support.

pull/1417/head
boombuler 8 years ago
parent
commit
7b3942685e
  1. 4
      src/Avalonia.Controls/Application.cs
  2. 10
      src/Avalonia.Controls/DragDrop/DragDrop.cs
  3. 129
      src/Avalonia.Controls/DragDrop/DragSource.cs
  4. 14
      src/Avalonia.Controls/Platform/IPlatformDragSource.cs
  5. 28
      src/Windows/Avalonia.Win32/DragSource.cs
  6. 4
      src/Windows/Avalonia.Win32/OleDragSource.cs
  7. 4
      src/Windows/Avalonia.Win32/OleDropTarget.cs
  8. 3
      src/Windows/Avalonia.Win32/Win32Platform.cs

4
src/Avalonia.Controls/Application.cs

@ -14,6 +14,7 @@ using Avalonia.Threading;
using System.Reactive.Concurrency;
using Avalonia.Controls.DragDrop;
using Avalonia.Controls.DragDrop.Raw;
using Avalonia.Controls.Platform;
namespace Avalonia
{
@ -237,7 +238,8 @@ namespace Avalonia
.Bind<ILayoutManager>().ToSingleton<LayoutManager>()
.Bind<IApplicationLifecycle>().ToConstant(this)
.Bind<IScheduler>().ToConstant(AvaloniaScheduler.Instance)
.Bind<IDragDropDevice>().ToConstant(DragDropDevice.Instance);
.Bind<IDragDropDevice>().ToConstant(DragDropDevice.Instance)
.Bind<IPlatformDragSource>().ToTransient<DragSource>();
}
}
}

10
src/Avalonia.Controls/DragDrop/DragDrop.cs

@ -1,4 +1,6 @@
using Avalonia.Interactivity;
using System.Threading.Tasks;
using Avalonia.Controls.Platform;
using Avalonia.Interactivity;
namespace Avalonia.Controls.DragDrop
{
@ -25,10 +27,10 @@ namespace Avalonia.Controls.DragDrop
/// Starts a dragging operation with the given <see cref="IDataObject"/> and returns the applied drop effect from the target.
/// <seealso cref="DataObject"/>
/// </summary>
public static DragDropEffects DoDragDrop(this Interactive source, IDataObject data, DragDropEffects allowedEffects)
public static Task<DragDropEffects> DoDragDrop(IDataObject data, DragDropEffects allowedEffects)
{
return DragDropEffects.None;
var src = AvaloniaLocator.Current.GetService<IPlatformDragSource>();
return src?.DoDragDrop(data, allowedEffects) ?? Task.FromResult(DragDropEffects.None);
}
}
}

129
src/Avalonia.Controls/DragDrop/DragSource.cs

@ -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;
}
}
}
}

14
src/Avalonia.Controls/Platform/IPlatformDragSource.cs

@ -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);
}
}

28
src/Windows/Avalonia.Win32/DragSource.cs

@ -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]));}
}
}

4
src/Windows/Avalonia.Win32/OleDragSource.cs

@ -33,9 +33,7 @@ namespace Avalonia.Win32
public int GiveFeedback(int dwEffect)
{
if (dwEffect != 0)
return DRAGDROP_S_USEDEFAULTCURSORS;
return unchecked((int)UnmanagedMethods.HRESULT.S_OK);
return DRAGDROP_S_USEDEFAULTCURSORS;
}
}
}

4
src/Windows/Avalonia.Win32/OleDropTarget.cs

@ -23,7 +23,7 @@ namespace Avalonia.Win32
_target = target;
}
static DropEffect ConvertDropEffect(DragDropEffects operation)
public static DropEffect ConvertDropEffect(DragDropEffects operation)
{
DropEffect result = DropEffect.None;
if (operation.HasFlag(DragDropEffects.Copy))
@ -35,7 +35,7 @@ namespace Avalonia.Win32
return result;
}
static DragDropEffects ConvertDropEffect(DropEffect effect)
public static DragDropEffects ConvertDropEffect(DropEffect effect)
{
DragDropEffects result = DragDropEffects.None;
if (effect.HasFlag(DropEffect.Copy))

3
src/Windows/Avalonia.Win32/Win32Platform.cs

@ -84,7 +84,8 @@ namespace Avalonia.Win32
.Bind<IRenderLoop>().ToConstant(new RenderLoop(60))
.Bind<ISystemDialogImpl>().ToSingleton<SystemDialogImpl>()
.Bind<IWindowingPlatform>().ToConstant(s_instance)
.Bind<IPlatformIconLoader>().ToConstant(s_instance);
.Bind<IPlatformIconLoader>().ToConstant(s_instance)
.Bind<IPlatformDragSource>().ToSingleton<DragSource>();
UseDeferredRendering = deferredRendering;
_uiThread = UnmanagedMethods.GetCurrentThreadId();

Loading…
Cancel
Save