csharpc-sharpdotnetxamlavaloniauicross-platformcross-platform-xamlavaloniaguimulti-platformuser-interfacedotnetcore
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
124 lines
4.4 KiB
124 lines
4.4 KiB
using System;
|
|
using System.Collections.Generic;
|
|
using System.Data;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Linq.Expressions;
|
|
using System.Reactive.Linq;
|
|
using System.Reactive.Subjects;
|
|
using System.Runtime.InteropServices;
|
|
using System.Runtime.Serialization.Formatters.Binary;
|
|
using System.Threading.Tasks;
|
|
using Avalonia.Controls;
|
|
using Avalonia.Input;
|
|
using Avalonia.Input.Platform;
|
|
using Avalonia.Input.Raw;
|
|
using MonoMac;
|
|
using MonoMac.AppKit;
|
|
using MonoMac.CoreGraphics;
|
|
using MonoMac.Foundation;
|
|
using MonoMac.OpenGL;
|
|
|
|
namespace Avalonia.MonoMac
|
|
{
|
|
public class DragSource : NSDraggingSource, IPlatformDragSource
|
|
{
|
|
private const string NSPasteboardTypeString = "public.utf8-plain-text";
|
|
private const string NSPasteboardTypeFileUrl = "public.file-url";
|
|
|
|
private readonly Subject<DragDropEffects> _result = new Subject<DragDropEffects>();
|
|
private readonly IInputManager _inputManager;
|
|
private DragDropEffects _allowedEffects;
|
|
|
|
public override bool IgnoreModifierKeysWhileDragging => false;
|
|
|
|
public DragSource()
|
|
{
|
|
_inputManager = AvaloniaLocator.Current.GetService<IInputManager>();
|
|
}
|
|
|
|
private string DataFormatToUTI(string s)
|
|
{
|
|
if (s == DataFormats.FileNames)
|
|
return NSPasteboardTypeFileUrl;
|
|
if (s == DataFormats.Text)
|
|
return NSPasteboardTypeString;
|
|
return s;
|
|
}
|
|
|
|
private NSDraggingItem CreateDraggingItem(string format, object data)
|
|
{
|
|
var pasteboardItem = new NSPasteboardItem();
|
|
NSData nsData;
|
|
if (data is string s)
|
|
{
|
|
if (format == DataFormats.FileNames)
|
|
s = new Uri(s).AbsoluteUri; // Ensure file uris...
|
|
nsData = NSData.FromString(s);
|
|
}
|
|
else if (data is Stream strm)
|
|
nsData = NSData.FromStream(strm);
|
|
else if (data is byte[] bytes)
|
|
nsData = NSData.FromArray(bytes);
|
|
else
|
|
{
|
|
BinaryFormatter bf = new BinaryFormatter();
|
|
using (var ms = new MemoryStream())
|
|
{
|
|
bf.Serialize(ms, data);
|
|
ms.Position = 0;
|
|
nsData = NSData.FromStream(ms);
|
|
}
|
|
}
|
|
pasteboardItem.SetDataForType(nsData, DataFormatToUTI(format));
|
|
|
|
NSPasteboardWriting writing = new NSPasteboardWriting(pasteboardItem.Handle);
|
|
|
|
return new NSDraggingItem(writing);
|
|
}
|
|
|
|
public IEnumerable<NSDraggingItem> CreateDraggingItems(string format, object data)
|
|
{
|
|
if (format == DataFormats.FileNames && data is IEnumerable<string> files)
|
|
{
|
|
foreach (var file in files)
|
|
yield return CreateDraggingItem(format, file);
|
|
|
|
yield break;
|
|
}
|
|
|
|
yield return CreateDraggingItem(format, data);
|
|
}
|
|
|
|
|
|
public async Task<DragDropEffects> DoDragDrop(IDataObject data, DragDropEffects allowedEffects)
|
|
{
|
|
// We need the TopLevelImpl + a mouse location so we just wait for the next event.
|
|
var mouseEv = await _inputManager.PreProcess.OfType<RawMouseEventArgs>().FirstAsync();
|
|
var view = ((mouseEv.Root as TopLevel)?.PlatformImpl as TopLevelImpl)?.View;
|
|
if (view == null)
|
|
return DragDropEffects.None;
|
|
|
|
// Prepare the source event:
|
|
var pt = view.TranslateLocalPoint(mouseEv.Position).ToMonoMacPoint();
|
|
var ev = NSEvent.MouseEvent(NSEventType.LeftMouseDown, pt, 0, 0, 0, null, 0, 0, 0);
|
|
|
|
_allowedEffects = allowedEffects;
|
|
var items = data.GetDataFormats().SelectMany(fmt => CreateDraggingItems(fmt, data.Get(fmt))).ToArray();
|
|
view.BeginDraggingSession(items ,ev, this);
|
|
|
|
return await _result;
|
|
}
|
|
|
|
public override NSDragOperation DraggingSourceOperationMaskForLocal(bool flag)
|
|
{
|
|
return DraggingInfo.ConvertDragOperation(_allowedEffects);
|
|
}
|
|
|
|
public override void DraggedImageEndedAtOperation(NSImage image, CGPoint screenPoint, NSDragOperation operation)
|
|
{
|
|
_result.OnNext(DraggingInfo.ConvertDragOperation(operation));
|
|
_result.OnCompleted();
|
|
}
|
|
}
|
|
}
|