committed by
GitHub
19 changed files with 712 additions and 81 deletions
@ -0,0 +1,89 @@ |
|||
#include "common.h" |
|||
|
|||
extern AvnDragDropEffects ConvertDragDropEffects(NSDragOperation nsop) |
|||
{ |
|||
int effects = 0; |
|||
if((nsop & NSDragOperationCopy) != 0) |
|||
effects |= (int)AvnDragDropEffects::Copy; |
|||
if((nsop & NSDragOperationMove) != 0) |
|||
effects |= (int)AvnDragDropEffects::Move; |
|||
if((nsop & NSDragOperationLink) != 0) |
|||
effects |= (int)AvnDragDropEffects::Link; |
|||
return (AvnDragDropEffects)effects; |
|||
}; |
|||
|
|||
extern NSString* GetAvnCustomDataType() |
|||
{ |
|||
char buffer[256]; |
|||
sprintf(buffer, "net.avaloniaui.inproc.uti.n%in", getpid()); |
|||
return [NSString stringWithUTF8String:buffer]; |
|||
} |
|||
|
|||
@interface AvnDndSource : NSObject<NSDraggingSource> |
|||
|
|||
@end |
|||
|
|||
@implementation AvnDndSource |
|||
{ |
|||
NSDragOperation _operation; |
|||
ComPtr<IAvnDndResultCallback> _cb; |
|||
void* _sourceHandle; |
|||
}; |
|||
|
|||
- (NSDragOperation)draggingSession:(nonnull NSDraggingSession *)session sourceOperationMaskForDraggingContext:(NSDraggingContext)context |
|||
{ |
|||
return NSDragOperationCopy; |
|||
} |
|||
|
|||
- (AvnDndSource*) initWithOperation: (NSDragOperation)operation |
|||
andCallback: (IAvnDndResultCallback*) cb |
|||
andSourceHandle: (void*) handle |
|||
{ |
|||
self = [super init]; |
|||
_operation = operation; |
|||
_cb = cb; |
|||
_sourceHandle = handle; |
|||
return self; |
|||
} |
|||
|
|||
- (void)draggingSession:(NSDraggingSession *)session |
|||
endedAtPoint:(NSPoint)screenPoint |
|||
operation:(NSDragOperation)operation |
|||
{ |
|||
if(_cb != nil) |
|||
{ |
|||
auto cb = _cb; |
|||
_cb = nil; |
|||
cb->OnDragAndDropComplete(ConvertDragDropEffects(operation)); |
|||
} |
|||
if(_sourceHandle != nil) |
|||
{ |
|||
FreeAvnGCHandle(_sourceHandle); |
|||
_sourceHandle = nil; |
|||
} |
|||
} |
|||
|
|||
- (void*) gcHandle |
|||
{ |
|||
return _sourceHandle; |
|||
} |
|||
|
|||
@end |
|||
|
|||
extern NSObject<NSDraggingSource>* CreateDraggingSource(NSDragOperation op, IAvnDndResultCallback* cb, void* handle) |
|||
{ |
|||
return [[AvnDndSource alloc] initWithOperation:op andCallback:cb andSourceHandle:handle]; |
|||
}; |
|||
|
|||
extern void* GetAvnDataObjectHandleFromDraggingInfo(NSObject<NSDraggingInfo>* info) |
|||
{ |
|||
id obj = [info draggingSource]; |
|||
if(obj == nil) |
|||
return nil; |
|||
if([obj isKindOfClass: [AvnDndSource class]]) |
|||
{ |
|||
auto src = (AvnDndSource*)obj; |
|||
return [src gcHandle]; |
|||
} |
|||
return nil; |
|||
} |
|||
@ -0,0 +1,76 @@ |
|||
using System; |
|||
using System.Runtime.InteropServices; |
|||
using System.Threading.Tasks; |
|||
using Avalonia.Controls; |
|||
using Avalonia.Input; |
|||
using Avalonia.Input.Platform; |
|||
using Avalonia.Interactivity; |
|||
using Avalonia.Native.Interop; |
|||
using Avalonia.Platform; |
|||
using Avalonia.VisualTree; |
|||
|
|||
namespace Avalonia.Native |
|||
{ |
|||
class AvaloniaNativeDragSource : IPlatformDragSource |
|||
{ |
|||
private readonly IAvaloniaNativeFactory _factory; |
|||
|
|||
public AvaloniaNativeDragSource(IAvaloniaNativeFactory factory) |
|||
{ |
|||
_factory = factory; |
|||
} |
|||
|
|||
TopLevel FindRoot(IInteractive interactive) |
|||
{ |
|||
while (interactive != null && !(interactive is IVisual)) |
|||
interactive = interactive.InteractiveParent; |
|||
if (interactive == null) |
|||
return null; |
|||
var visual = (IVisual)interactive; |
|||
return visual.VisualRoot as TopLevel; |
|||
} |
|||
|
|||
class DndCallback : CallbackBase, IAvnDndResultCallback |
|||
{ |
|||
private TaskCompletionSource<DragDropEffects> _tcs; |
|||
|
|||
public DndCallback(TaskCompletionSource<DragDropEffects> tcs) |
|||
{ |
|||
_tcs = tcs; |
|||
} |
|||
public void OnDragAndDropComplete(AvnDragDropEffects effect) |
|||
{ |
|||
_tcs?.TrySetResult((DragDropEffects)effect); |
|||
_tcs = null; |
|||
} |
|||
} |
|||
|
|||
public Task<DragDropEffects> DoDragDrop(PointerEventArgs triggerEvent, IDataObject data, DragDropEffects allowedEffects) |
|||
{ |
|||
// Sanity check
|
|||
var tl = FindRoot(triggerEvent.Source); |
|||
var view = tl?.PlatformImpl as WindowBaseImpl; |
|||
if (view == null) |
|||
throw new ArgumentException(); |
|||
|
|||
triggerEvent.Pointer.Capture(null); |
|||
|
|||
var tcs = new TaskCompletionSource<DragDropEffects>(); |
|||
|
|||
var clipboardImpl = _factory.CreateDndClipboard(); |
|||
using (var clipboard = new ClipboardImpl(clipboardImpl)) |
|||
using (var cb = new DndCallback(tcs)) |
|||
{ |
|||
if (data.Contains(DataFormats.Text)) |
|||
// API is synchronous, so it's OK
|
|||
clipboard.SetTextAsync(data.GetText()).Wait(); |
|||
|
|||
view.BeginDraggingSession((AvnDragDropEffects)allowedEffects, |
|||
triggerEvent.GetPosition(tl).ToAvnPoint(), clipboardImpl, cb, |
|||
GCHandle.ToIntPtr(GCHandle.Alloc(data))); |
|||
} |
|||
|
|||
return tcs.Task; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,39 @@ |
|||
using System.Runtime.InteropServices; |
|||
|
|||
namespace Avalonia.Native.Interop |
|||
{ |
|||
unsafe partial class IAvnString |
|||
{ |
|||
private string _managed; |
|||
|
|||
public string String |
|||
{ |
|||
get |
|||
{ |
|||
if (_managed == null) |
|||
{ |
|||
var ptr = Pointer(); |
|||
if (ptr == null) |
|||
return null; |
|||
_managed = System.Text.Encoding.UTF8.GetString((byte*)ptr.ToPointer(), Length()); |
|||
} |
|||
|
|||
return _managed; |
|||
} |
|||
} |
|||
|
|||
public override string ToString() => String; |
|||
} |
|||
|
|||
partial class IAvnStringArray |
|||
{ |
|||
public string[] ToStringArray() |
|||
{ |
|||
var arr = new string[Count]; |
|||
for(uint c = 0; c<arr.Length;c++) |
|||
using (var s = Get(c)) |
|||
arr[c] = s.String; |
|||
return arr; |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue