Browse Source

first bits of drag+drop support for osx

Florian Sundermann 7 years ago
parent
commit
edf6b12c4d

+ 15 - 0
src/Avalonia.Controls/DragDrop/DataFormats.cs

@@ -0,0 +1,15 @@
+namespace Avalonia.Controls.DragDrop
+{
+    public static class DataFormats
+    {
+        /// <summary>
+        /// Dataformat for plaintext
+        /// </summary>
+        public static string Text = nameof(Text);
+
+        /// <summary>
+        /// Dataformat for one or more filenames
+        /// </summary>
+        public static string FileNames = nameof(FileNames);
+    }
+}

+ 13 - 0
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,
+    }
+}

+ 15 - 0
src/Avalonia.Controls/DragDrop/IDragData.cs

@@ -0,0 +1,15 @@
+using System.Collections.Generic;
+
+namespace Avalonia.Controls.DragDrop
+{
+    public interface IDragData
+    {
+        IEnumerable<string> GetDataFormats();
+
+        bool Contains(string dataFormat);
+
+        string GetText();
+
+        IEnumerable<string> GetFileNames();
+    }
+}

+ 12 - 0
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);
+    }
+}

+ 2 - 2
src/OSX/Avalonia.MonoMac/Avalonia.MonoMac.csproj

@@ -1,4 +1,4 @@
-<Project Sdk="Microsoft.NET.Sdk">
+<Project Sdk="Microsoft.NET.Sdk">
   <PropertyGroup>
     <TargetFrameworks>netstandard2.0</TargetFrameworks>
     <AllowUnsafeBlocks>True</AllowUnsafeBlocks>
@@ -19,4 +19,4 @@
     <ProjectReference Include="..\..\Avalonia.Visuals\Avalonia.Visuals.csproj" />
   </ItemGroup>
   <Import Project="..\..\..\build\MonoMac.props" />
-</Project>
+</Project>

+ 63 - 0
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<string> GetDataFormats()
+        {
+            yield break;
+        }
+
+        public string GetText()
+        {
+            return null;
+        }
+
+        public IEnumerable<string> GetFileNames()
+        {
+            yield break;
+        }
+
+        public bool Contains(string dataFormat)
+        {
+            return false;
+        }
+    }
+}

+ 76 - 0
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<IMouseDevice>();
                 _keyboard = AvaloniaLocator.Current.GetService<IKeyboardDevice>();
+                _dragDispatcher = AvaloniaLocator.Current.GetService<IDragDispatcher>();
+                
+                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)