From edf6b12c4d7c9ba6844201f6c29f83b9ac9d4b1d Mon Sep 17 00:00:00 2001 From: Florian Sundermann Date: Sat, 3 Mar 2018 11:28:21 +0100 Subject: [PATCH] first bits of drag+drop support for osx --- src/Avalonia.Controls/DragDrop/DataFormats.cs | 15 ++++ .../DragDrop/DragOperation.cs | 13 ++++ src/Avalonia.Controls/DragDrop/IDragData.cs | 15 ++++ .../DragDrop/IDragDispatcher.cs | 12 +++ .../Avalonia.MonoMac/Avalonia.MonoMac.csproj | 4 +- src/OSX/Avalonia.MonoMac/DraggingInfo.cs | 63 +++++++++++++++ src/OSX/Avalonia.MonoMac/TopLevelImpl.cs | 76 +++++++++++++++++++ 7 files changed, 196 insertions(+), 2 deletions(-) create mode 100644 src/Avalonia.Controls/DragDrop/DataFormats.cs create mode 100644 src/Avalonia.Controls/DragDrop/DragOperation.cs create mode 100644 src/Avalonia.Controls/DragDrop/IDragData.cs create mode 100644 src/Avalonia.Controls/DragDrop/IDragDispatcher.cs create mode 100644 src/OSX/Avalonia.MonoMac/DraggingInfo.cs diff --git a/src/Avalonia.Controls/DragDrop/DataFormats.cs b/src/Avalonia.Controls/DragDrop/DataFormats.cs new file mode 100644 index 0000000000..f46651ed3b --- /dev/null +++ b/src/Avalonia.Controls/DragDrop/DataFormats.cs @@ -0,0 +1,15 @@ +namespace Avalonia.Controls.DragDrop +{ + public static class DataFormats + { + /// + /// Dataformat for plaintext + /// + public static string Text = nameof(Text); + + /// + /// Dataformat for one or more filenames + /// + public static string FileNames = nameof(FileNames); + } +} \ No newline at end of file diff --git a/src/Avalonia.Controls/DragDrop/DragOperation.cs b/src/Avalonia.Controls/DragDrop/DragOperation.cs new file mode 100644 index 0000000000..ffc6f666f7 --- /dev/null +++ b/src/Avalonia.Controls/DragDrop/DragOperation.cs @@ -0,0 +1,13 @@ +using System; + +namespace Avalonia.Controls.DragDrop +{ + [Flags] + public enum DragOperation + { + None = 0, + Copy = 1, + Move = 2, + Link = 4, + } +} \ No newline at end of file diff --git a/src/Avalonia.Controls/DragDrop/IDragData.cs b/src/Avalonia.Controls/DragDrop/IDragData.cs new file mode 100644 index 0000000000..b6dc53d32d --- /dev/null +++ b/src/Avalonia.Controls/DragDrop/IDragData.cs @@ -0,0 +1,15 @@ +using System.Collections.Generic; + +namespace Avalonia.Controls.DragDrop +{ + public interface IDragData + { + IEnumerable GetDataFormats(); + + bool Contains(string dataFormat); + + string GetText(); + + IEnumerable GetFileNames(); + } +} \ No newline at end of file diff --git a/src/Avalonia.Controls/DragDrop/IDragDispatcher.cs b/src/Avalonia.Controls/DragDrop/IDragDispatcher.cs new file mode 100644 index 0000000000..5c39635dd0 --- /dev/null +++ b/src/Avalonia.Controls/DragDrop/IDragDispatcher.cs @@ -0,0 +1,12 @@ +using Avalonia.Input; + +namespace Avalonia.Controls.DragDrop +{ + public interface IDragDispatcher + { + DragOperation DragEnter(IInputRoot inputRoot, Point point, IDragData data, DragOperation operation); + DragOperation DragOver(IInputRoot inputRoot, Point point, IDragData data, DragOperation operation); + void DragLeave(IInputRoot inputRoot); + DragOperation Drop(IInputRoot inputRoot, Point point, IDragData data, DragOperation operation); + } +} \ No newline at end of file diff --git a/src/OSX/Avalonia.MonoMac/Avalonia.MonoMac.csproj b/src/OSX/Avalonia.MonoMac/Avalonia.MonoMac.csproj index 5f6be91571..c31c131ea9 100644 --- a/src/OSX/Avalonia.MonoMac/Avalonia.MonoMac.csproj +++ b/src/OSX/Avalonia.MonoMac/Avalonia.MonoMac.csproj @@ -1,4 +1,4 @@ - + netstandard2.0 True @@ -19,4 +19,4 @@ - + \ No newline at end of file diff --git a/src/OSX/Avalonia.MonoMac/DraggingInfo.cs b/src/OSX/Avalonia.MonoMac/DraggingInfo.cs new file mode 100644 index 0000000000..3abcb8c68c --- /dev/null +++ b/src/OSX/Avalonia.MonoMac/DraggingInfo.cs @@ -0,0 +1,63 @@ +using System.Collections.Generic; +using Avalonia.Controls.DragDrop; +using MonoMac.AppKit; + +namespace Avalonia.MonoMac +{ + class DraggingInfo : IDragData + { + private readonly NSDraggingInfo _info; + + public DraggingInfo(NSDraggingInfo info) + { + _info = info; + } + + + internal static NSDragOperation ConvertDragOperation(DragOperation d) + { + NSDragOperation result = NSDragOperation.None; + if (d.HasFlag(DragOperation.Copy)) + result |= NSDragOperation.Copy; + if (d.HasFlag(DragOperation.Link)) + result |= NSDragOperation.Link; + if (d.HasFlag(DragOperation.Move)) + result |= NSDragOperation.Move; + return result; + } + + internal static DragOperation ConvertDragOperation(NSDragOperation d) + { + DragOperation result = DragOperation.None; + if (d.HasFlag(NSDragOperation.Copy)) + result |= DragOperation.Copy; + if (d.HasFlag(NSDragOperation.Link)) + result |= DragOperation.Link; + if (d.HasFlag(NSDragOperation.Move)) + result |= DragOperation.Move; + return result; + } + + public Point Location => new Point(_info.DraggingLocation.X, _info.DraggingLocation.Y); + + public IEnumerable GetDataFormats() + { + yield break; + } + + public string GetText() + { + return null; + } + + public IEnumerable GetFileNames() + { + yield break; + } + + public bool Contains(string dataFormat) + { + return false; + } + } +} \ No newline at end of file diff --git a/src/OSX/Avalonia.MonoMac/TopLevelImpl.cs b/src/OSX/Avalonia.MonoMac/TopLevelImpl.cs index 667ee12fa0..91e822f802 100644 --- a/src/OSX/Avalonia.MonoMac/TopLevelImpl.cs +++ b/src/OSX/Avalonia.MonoMac/TopLevelImpl.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using Avalonia.Controls.DragDrop; using Avalonia.Input; using Avalonia.Input.Raw; using Avalonia.Platform; @@ -36,6 +37,7 @@ namespace Avalonia.MonoMac bool _isLeftPressed, _isRightPressed, _isMiddlePressed; private readonly IMouseDevice _mouse; private readonly IKeyboardDevice _keyboard; + private readonly IDragDispatcher _dragDispatcher; private NSTrackingArea _area; private NSCursor _cursor; private bool _nonUiRedrawQueued; @@ -52,6 +54,11 @@ namespace Avalonia.MonoMac _tl = tl; _mouse = AvaloniaLocator.Current.GetService(); _keyboard = AvaloniaLocator.Current.GetService(); + _dragDispatcher = AvaloniaLocator.Current.GetService(); + + RegisterForDraggedTypes(new string[] { + "public.data" // register for any kind of data. + }); } protected override void Dispose(bool disposing) @@ -144,6 +151,75 @@ namespace Avalonia.MonoMac UpdateCursor(); } + public override NSDragOperation DraggingEntered(NSDraggingInfo sender) + { + IInputRoot root = _tl?.InputRoot; + if (root == null || _dragDispatcher == null) + return NSDragOperation.None; + + var dragOp = DraggingInfo.ConvertDragOperation(sender.DraggingSourceOperationMask); + DraggingInfo info = new DraggingInfo(sender); + var pt = TranslateLocalPoint(info.Location); + + dragOp = _dragDispatcher.DragEnter(root, pt, info, dragOp); + + return DraggingInfo.ConvertDragOperation(dragOp); + } + + public override NSDragOperation DraggingUpdated(NSDraggingInfo sender) + { + IInputRoot root = _tl?.InputRoot; + if (root == null || _dragDispatcher == null) + return NSDragOperation.None; + + var dragOp = DraggingInfo.ConvertDragOperation(sender.DraggingSourceOperationMask); + DraggingInfo info = new DraggingInfo(sender); + var pt = TranslateLocalPoint(info.Location); + + dragOp = _dragDispatcher.DragOver(root, pt, info, dragOp); + + return DraggingInfo.ConvertDragOperation(dragOp); + } + + public override void DraggingExited(NSDraggingInfo sender) + { + IInputRoot root = _tl?.InputRoot; + if (root == null || _dragDispatcher == null) + return; + _dragDispatcher.DragLeave(root); + } + + public override bool PrepareForDragOperation(NSDraggingInfo sender) + { + IInputRoot root = _tl?.InputRoot; + if (root == null || _dragDispatcher == null) + return false; + + var dragOp = DraggingInfo.ConvertDragOperation(sender.DraggingSourceOperationMask); + DraggingInfo info = new DraggingInfo(sender); + var pt = TranslateLocalPoint(info.Location); + + dragOp = _dragDispatcher.DragOver(root, pt, info, dragOp); + + return DraggingInfo.ConvertDragOperation(dragOp) != DragOperation.None; + } + + public override bool PerformDragOperation(NSDraggingInfo sender) + { + IInputRoot root = _tl?.InputRoot; + if (root == null || _dragDispatcher == null) + return false; + + var dragOp = DraggingInfo.ConvertDragOperation(sender.DraggingSourceOperationMask); + DraggingInfo info = new DraggingInfo(sender); + var pt = TranslateLocalPoint(info.Location); + + dragOp = _dragDispatcher.Drop(root, pt, info, dragOp); + + return DraggingInfo.ConvertDragOperation(dragOp) != DragOperation.None; + } + + public override void SetFrameSize(CGSize newSize) { lock (SyncRoot)