From c80db884b7624ab924c9bb88e1baab276797a1c9 Mon Sep 17 00:00:00 2001 From: David Date: Wed, 7 Oct 2020 19:40:58 -0400 Subject: [PATCH] feat(dragdrop): Abstract the drag event source so they can be built from another source than pointer --- src/Uno.UI/UI/Xaml/DragDropManager.cs | 111 +++++++++++------- src/Uno.UI/UI/Xaml/DragEventArgs.cs | 9 +- src/Uno.UI/UI/Xaml/DropUITarget.cs | 33 ++---- src/Uno.UI/UI/Xaml/Input/Pointer.cs | 16 ++- .../UI/Xaml/Input/PointerRoutedEventArgs.cs | 55 ++++++++- src/Uno.UI/UI/Xaml/UIElement.Pointers.cs | 43 +++---- .../DragDrop/Core/CoreDragInfo.cs | 52 +++++--- 7 files changed, 204 insertions(+), 115 deletions(-) diff --git a/src/Uno.UI/UI/Xaml/DragDropManager.cs b/src/Uno.UI/UI/Xaml/DragDropManager.cs index 50ffb0bf2ca5..92a95faca16e 100644 --- a/src/Uno.UI/UI/Xaml/DragDropManager.cs +++ b/src/Uno.UI/UI/Xaml/DragDropManager.cs @@ -3,20 +3,30 @@ using System; using System.Collections.Generic; using System.Linq; +using Windows.ApplicationModel.DataTransfer; +using Windows.ApplicationModel.DataTransfer.DragDrop; using Windows.ApplicationModel.DataTransfer.DragDrop.Core; using Windows.UI.Core; using Windows.UI.Xaml.Input; +using Uno.Foundation.Extensibility; namespace Windows.UI.Xaml { - internal class DragDropManager : CoreDragDropManager.IDragDropManager + internal sealed class DragDropManager : CoreDragDropManager.IDragDropManager { private readonly Window _window; private readonly List _dragOperations = new List(); + private readonly IDragDropExtension? _hostExtension; + + private bool _areWindowEventsRegistered; public DragDropManager(Window window) { _window = window; + if (ApiExtensibility.CreateInstance(this, out var extension)) + { + _hostExtension = extension; + } } /// @@ -43,69 +53,84 @@ public void BeginDragAndDrop(CoreDragInfo info, ICoreDropOperationTarget? target } } - RegisterHandlers(); + RegisterWindowHandlers(); - var op = new DragOperation(_window, info, target); + var op = new DragOperation(_window, _hostExtension, info, target); - info.RegisterCompletedCallback(_ => _dragOperations.Remove(op)); _dragOperations.Add(op); + info.RegisterCompletedCallback(_ => _dragOperations.Remove(op)); } - private DragOperation? FindOperation(PointerRoutedEventArgs args) - { - var pointer = args.Pointer!; - var op = _dragOperations.FirstOrDefault(drag => pointer.Equals(drag.Pointer)) - ?? _dragOperations.FirstOrDefault(drag => drag.Pointer == null); - - return op; - } - - private bool _registered = false; - private void RegisterHandlers() + /// + /// This method is expected to be invoked each time a pointer involved in a drag operation is moved, + /// no matter if the drag operation has been initiated from this app or from an external app. + /// + /// + /// The last accepted operation. + /// Be aware that due to the async processing of dragging in UWP, this might not be the up to date. + /// + public DataPackageOperation ProcessMoved(IDragEventSource src) + => FindOperation(src)?.Moved(src) ?? DataPackageOperation.None; + + /// + /// This method is expected to be invoked when pointer involved in a drag operation is released, + /// no matter if the drag operation has been initiated from this app or from an external app. + /// + /// + /// The last accepted operation. + /// Be aware that due to the async processing of dragging in UWP, this might not be the up to date. + /// + public DataPackageOperation ProcessDropped(IDragEventSource src) + => FindOperation(src)?.Dropped(src) ?? DataPackageOperation.None; + + /// + /// This method is expected to be invoked when pointer involved in a drag operation + /// is lost for operation initiated by the current app, + /// or left the window (a.k.a. the "virtual pointer" is lost) for operation initiated by an other app. + /// + /// + /// The last accepted operation. + /// Be aware that due to the async processing of dragging in UWP, this might not be the up to date. + /// + public DataPackageOperation ProcessAborted(IDragEventSource src) + => FindOperation(src)?.Aborted(src) ?? DataPackageOperation.None; + + private DragOperation? FindOperation(IDragEventSource src) + => _dragOperations.FirstOrDefault(drag => drag.Info.SourceId == src.Id); + + private void RegisterWindowHandlers() { - if (_registered) + if (_areWindowEventsRegistered) { return; } + // Those events are subscribed for safety, but they are usually useless as: + // + // # for internally initiated drag operation: + // the pointer is (implicitly) captured by the GestureRecognizer when a Drag manipulation is detected; + // + // # for externally initiated drag operation: + // the current app does not receive any pointer event, but instead receive platform specific drag events, + // that are expected to be interpreted by the IDragDropExtension and forwarded to this manager using the Process* methods. + var root = _window.RootElement; - root.AddHandler(UIElement.PointerEnteredEvent, new PointerEventHandler(OnPointerEntered), handledEventsToo: true); - root.AddHandler(UIElement.PointerExitedEvent, new PointerEventHandler(OnPointerExited), handledEventsToo: true); + root.AddHandler(UIElement.PointerEnteredEvent, new PointerEventHandler(OnPointerMoved), handledEventsToo: true); + root.AddHandler(UIElement.PointerExitedEvent, new PointerEventHandler(OnPointerMoved), handledEventsToo: true); root.AddHandler(UIElement.PointerMovedEvent, new PointerEventHandler(OnPointerMoved), handledEventsToo: true); root.AddHandler(UIElement.PointerReleasedEvent, new PointerEventHandler(OnPointerReleased), handledEventsToo: true); root.AddHandler(UIElement.PointerCanceledEvent, new PointerEventHandler(OnPointerCanceled), handledEventsToo: true); - _registered = true; + _areWindowEventsRegistered = true; } - private static void OnPointerEntered(object snd, PointerRoutedEventArgs e) - => Window.Current.DragDrop.ProcessPointerEnteredWindow(e); - - private static void OnPointerExited(object snd, PointerRoutedEventArgs e) - => Window.Current.DragDrop.ProcessPointerExitedWindow(e); - private static void OnPointerMoved(object snd, PointerRoutedEventArgs e) - => Window.Current.DragDrop.ProcessPointerMovedOverWindow(e); + => Window.Current.DragDrop.ProcessMoved(e); private static void OnPointerReleased(object snd, PointerRoutedEventArgs e) - => Window.Current.DragDrop.ProcessPointerReleased(e); + => Window.Current.DragDrop.ProcessDropped(e); private static void OnPointerCanceled(object snd, PointerRoutedEventArgs e) - => Window.Current.DragDrop.ProcessPointerCanceled(e); - - public void ProcessPointerEnteredWindow(PointerRoutedEventArgs args) - => FindOperation(args)?.Entered(args); - - public void ProcessPointerExitedWindow(PointerRoutedEventArgs args) - => FindOperation(args)?.Exited(args); - - public void ProcessPointerMovedOverWindow(PointerRoutedEventArgs args) - => FindOperation(args)?.Moved(args); - - public void ProcessPointerReleased(PointerRoutedEventArgs args) - => FindOperation(args)?.Dropped(args); - - public void ProcessPointerCanceled(PointerRoutedEventArgs args) - => FindOperation(args)?.Aborted(args); + => Window.Current.DragDrop.ProcessAborted(e); } } diff --git a/src/Uno.UI/UI/Xaml/DragEventArgs.cs b/src/Uno.UI/UI/Xaml/DragEventArgs.cs index 74229e009a83..3c8b7f06de3a 100644 --- a/src/Uno.UI/UI/Xaml/DragEventArgs.cs +++ b/src/Uno.UI/UI/Xaml/DragEventArgs.cs @@ -15,19 +15,16 @@ namespace Windows.UI.Xaml public partial class DragEventArgs : RoutedEventArgs, ICancellableRoutedEventArgs { private readonly CoreDragInfo _info; - private readonly PointerRoutedEventArgs _pointer; internal DragEventArgs( UIElement originalSource, CoreDragInfo info, - DragUIOverride uiOverride, - PointerRoutedEventArgs pointer) + DragUIOverride uiOverride) : base(originalSource) { CanBubbleNatively = false; _info = info; - _pointer = pointer; DragUIOverride = uiOverride; } @@ -43,7 +40,7 @@ internal DragEventArgs( public DragDropModifiers Modifiers => _info.Modifiers; - internal Pointer Pointer => _pointer.Pointer; + internal long SourceId => _info.SourceId; #endregion #region Properties that are expected to be updated by the handler @@ -55,7 +52,7 @@ internal DragEventArgs( #endregion public Point GetPosition(UIElement relativeTo) - => _pointer.GetCurrentPoint(relativeTo).Position; + => _info.GetPosition(relativeTo); public DragOperationDeferral GetDeferral() => Deferral ??= new DragOperationDeferral(); diff --git a/src/Uno.UI/UI/Xaml/DropUITarget.cs b/src/Uno.UI/UI/Xaml/DropUITarget.cs index 391a87373006..ae7b17354d86 100644 --- a/src/Uno.UI/UI/Xaml/DropUITarget.cs +++ b/src/Uno.UI/UI/Xaml/DropUITarget.cs @@ -56,13 +56,7 @@ public IAsyncOperation OverAsync(CoreDragInfo dragInfo, Co private IAsyncOperation EnterOrOverAsync(CoreDragInfo dragInfo, CoreDragUIOverride dragUIOverride) => AsyncOperation.FromTask(async ct => { - if (!(dragInfo.PointerRoutedEventArgs is PointerRoutedEventArgs ptArgs)) - { - this.Log().Error("The pointer event args was not set. Impossible to raise the drag args on the view."); - return DataPackageOperation.None; - } - - var target = await UpdateTarget(dragInfo, dragUIOverride, ptArgs, ct); + var target = await UpdateTarget(dragInfo, dragUIOverride, ct); if (!target.HasValue) { return DataPackageOperation.None; @@ -85,19 +79,13 @@ private IAsyncOperation EnterOrOverAsync(CoreDragInfo drag public IAsyncAction LeaveAsync(CoreDragInfo dragInfo) => AsyncAction.FromTask(async ct => { - if (!(dragInfo.PointerRoutedEventArgs is PointerRoutedEventArgs ptArgs)) - { - this.Log().Error("The pointer event args was not set. Impossible to raise the drag args on the view."); - return; - } - var leaveTasks = _pendingDropTargets.ToArray().Select(RaiseLeave); _pendingDropTargets.Clear(); Task.WhenAll(leaveTasks); async Task RaiseLeave(KeyValuePair target) { - var args = new DragEventArgs(target.Key, dragInfo, target.Value.uiOverride, ptArgs); + var args = new DragEventArgs(target.Key, dragInfo, target.Value.uiOverride); target.Key.RaiseDragLeave(args); @@ -112,13 +100,7 @@ async Task RaiseLeave(KeyValuePair DropAsync(CoreDragInfo dragInfo) => AsyncOperation.FromTask(async ct => { - if (!(dragInfo.PointerRoutedEventArgs is PointerRoutedEventArgs ptArgs)) - { - this.Log().Error("The pointer event args was not set. Impossible to raise the drag args on the view."); - return DataPackageOperation.None; - } - - var target = await UpdateTarget(dragInfo, null, ptArgs, ct); + var target = await UpdateTarget(dragInfo, null, ct); if (!target.HasValue) { return DataPackageOperation.None; @@ -138,13 +120,12 @@ public IAsyncOperation DropAsync(CoreDragInfo dragInfo) private async Task<(UIElement element, global::Windows.UI.Xaml.DragEventArgs args)?> UpdateTarget( CoreDragInfo dragInfo, CoreDragUIOverride? dragUIOverride, - PointerRoutedEventArgs ptArgs, CancellationToken ct) { var target = VisualTreeHelper.HitTest( dragInfo.Position, getTestability: _getDropHitTestability, - isStale: elt => elt.IsDragOver(ptArgs.Pointer)); + isStale: elt => elt.IsDragOver(dragInfo.SourceId)); // First raise the drag leave event on stale branch if any. if (target.stale is { } staleBranch) @@ -163,7 +144,7 @@ public IAsyncOperation DropAsync(CoreDragInfo dragInfo) // This is acceptable as a MVP as we usually have only one Drop target par app. // Anyway if we Leave a bit too much, we will Enter again below var leaf = leftElements.First(); - var leaveArgs = new DragEventArgs(leaf.elt, dragInfo, leaf.dragState.uiOverride, ptArgs); + var leaveArgs = new DragEventArgs(leaf.elt, dragInfo, leaf.dragState.uiOverride); staleBranch.Leaf.RaiseDragLeave(leaveArgs); @@ -182,14 +163,14 @@ public IAsyncOperation DropAsync(CoreDragInfo dragInfo) DragEventArgs args; if (target.element is {} && _pendingDropTargets.TryGetValue(target.element, out var state)) { - args = new DragEventArgs(target.element!, dragInfo, state.uiOverride, ptArgs) + args = new DragEventArgs(target.element!, dragInfo, state.uiOverride) { AcceptedOperation = state.acceptedOperation }; } else { - args = new DragEventArgs(target.element!, dragInfo, new DragUIOverride(dragUIOverride ?? new CoreDragUIOverride()), ptArgs); + args = new DragEventArgs(target.element!, dragInfo, new DragUIOverride(dragUIOverride ?? new CoreDragUIOverride())); } return (target.element!, args); diff --git a/src/Uno.UI/UI/Xaml/Input/Pointer.cs b/src/Uno.UI/UI/Xaml/Input/Pointer.cs index a77f80376fd5..87b7ae003fba 100644 --- a/src/Uno.UI/UI/Xaml/Input/Pointer.cs +++ b/src/Uno.UI/UI/Xaml/Input/Pointer.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Text; +using System.Threading; using Uno; using Windows.Devices.Input; @@ -8,12 +9,18 @@ namespace Windows.UI.Xaml.Input { public sealed partial class Pointer : IEquatable { + private static int _unknownId; + internal static long CreateUniqueIdForUnknownPointer() + => (long)1 << 63 | (long)Interlocked.Increment(ref _unknownId); + public Pointer(uint id, PointerDeviceType type, bool isInContact, bool isInRange) { PointerId = id; PointerDeviceType = type; IsInContact = isInContact; IsInRange = isInRange; + + UniqueId = (long)PointerDeviceType << 32 | PointerId; } @@ -25,6 +32,11 @@ internal Pointer(uint id, PointerDeviceType type) } #endif + /// + /// A unique identifier which contains and . + /// + internal long UniqueId { get; } + public uint PointerId { get; } public PointerDeviceType PointerDeviceType { get;} @@ -43,7 +55,7 @@ public bool Equals(Pointer other) if (ReferenceEquals(null, other)) return false; if (ReferenceEquals(this, other)) return true; - return PointerDeviceType == other.PointerDeviceType && PointerId == other.PointerId; + return UniqueId == other.UniqueId; } public override bool Equals(object obj) @@ -52,7 +64,7 @@ public override bool Equals(object obj) if (ReferenceEquals(this, obj)) return true; if (!(obj is Pointer other)) return false; - return PointerDeviceType == other.PointerDeviceType && PointerId == other.PointerId; + return UniqueId == other.UniqueId; } public override int GetHashCode() diff --git a/src/Uno.UI/UI/Xaml/Input/PointerRoutedEventArgs.cs b/src/Uno.UI/UI/Xaml/Input/PointerRoutedEventArgs.cs index f5bf14f1485d..42230e22ff8b 100644 --- a/src/Uno.UI/UI/Xaml/Input/PointerRoutedEventArgs.cs +++ b/src/Uno.UI/UI/Xaml/Input/PointerRoutedEventArgs.cs @@ -3,6 +3,8 @@ using System.Collections.Generic; using System.Text; using System.Threading; +using Windows.ApplicationModel.DataTransfer.DragDrop; +using Windows.ApplicationModel.DataTransfer.DragDrop.Core; using Uno; using Uno.UI.Xaml.Input; using Windows.System; @@ -11,7 +13,7 @@ namespace Windows.UI.Xaml.Input { - public sealed partial class PointerRoutedEventArgs : RoutedEventArgs, ICancellableRoutedEventArgs, CoreWindow.IPointerEventArgs + public sealed partial class PointerRoutedEventArgs : RoutedEventArgs, ICancellableRoutedEventArgs, CoreWindow.IPointerEventArgs, IDragEventSource { #if __IOS__ || __MACOS__ || __ANDROID__ || __WASM__ internal const bool PlatformSupportsNativeBubbling = true; @@ -49,5 +51,56 @@ public IList GetIntermediatePoints(UIElement relativeTo) /// public override string ToString() => $"PointerRoutedEventArgs({Pointer}@{GetCurrentPoint(null).Position})"; + + long IDragEventSource.Id => Pointer.UniqueId; + uint IDragEventSource.FrameId => FrameId; + + Point IDragEventSource.GetPosition(object relativeTo) + { + if (relativeTo is null || relativeTo is UIElement) + { + return GetCurrentPoint(relativeTo as UIElement).Position; + } + else + { + throw new ArgumentOutOfRangeException(nameof(relativeTo), "The relative element must be a UIElement."); + } + } + + (Point location, DragDropModifiers modifier) IDragEventSource.GetState() + { + var point = GetCurrentPoint(null); + var mods = DragDropModifiers.None; + + var props = point.Properties; + if (props.IsLeftButtonPressed) + { + mods |= DragDropModifiers.LeftButton; + } + if (props.IsMiddleButtonPressed) + { + mods |= DragDropModifiers.MiddleButton; + } + if (props.IsRightButtonPressed) + { + mods |= DragDropModifiers.RightButton; + } + + var window = Window.Current.CoreWindow; + if (window.GetAsyncKeyState(VirtualKey.Shift) == CoreVirtualKeyStates.Down) + { + mods |= DragDropModifiers.Shift; + } + if (window.GetAsyncKeyState(VirtualKey.Control) == CoreVirtualKeyStates.Down) + { + mods |= DragDropModifiers.Control; + } + if (window.GetAsyncKeyState(VirtualKey.Menu) == CoreVirtualKeyStates.Down) + { + mods |= DragDropModifiers.Alt; + } + + return (point.Position, mods); + } } } diff --git a/src/Uno.UI/UI/Xaml/UIElement.Pointers.cs b/src/Uno.UI/UI/Xaml/UIElement.Pointers.cs index 8742fd12b49b..b4041eb2063e 100644 --- a/src/Uno.UI/UI/Xaml/UIElement.Pointers.cs +++ b/src/Uno.UI/UI/Xaml/UIElement.Pointers.cs @@ -490,7 +490,7 @@ partial void PrepareManagedDragAndDropEventBubbling(RoutedEvent routedEvent, ref case RoutedEventFlag.DragEnter: { - var pt = ((global::Windows.UI.Xaml.DragEventArgs)args).Pointer; + var pt = ((global::Windows.UI.Xaml.DragEventArgs)args).SourceId; var wasDragOver = IsDragOver(pt); // As the IsDragOver is expected to reflect teh state of the current element **and the state of its children**, @@ -508,7 +508,7 @@ partial void PrepareManagedDragAndDropEventBubbling(RoutedEvent routedEvent, ref case RoutedEventFlag.DragOver: // As the IsDragOver is expected to reflect teh state of the current element **and the state of its children**, // even if the AllowDrop flag has not been set, we have to update the IsDragOver state. - SetIsDragOver(((global::Windows.UI.Xaml.DragEventArgs)args).Pointer, true); + SetIsDragOver(((global::Windows.UI.Xaml.DragEventArgs)args).SourceId, true); if (!AllowDrop) // The Drag and Drop "routed" events are raised only on controls that opted-in { @@ -519,7 +519,7 @@ partial void PrepareManagedDragAndDropEventBubbling(RoutedEvent routedEvent, ref case RoutedEventFlag.DragLeave: case RoutedEventFlag.Drop: { - var pt = ((global::Windows.UI.Xaml.DragEventArgs)args).Pointer; + var pt = ((global::Windows.UI.Xaml.DragEventArgs)args).SourceId; var wasDragOver = IsDragOver(pt); // As the IsDragOver is expected to reflect teh state of the current element **and the state of its children**, @@ -588,10 +588,10 @@ private Task StartDragAsyncCore(PointerPoint pointer, Poin result.Task.ContinueWith(OnDragCompleted, this, TaskContinuationOptions.NotOnCanceled | TaskContinuationOptions.RunContinuationsAsynchronously); var dragInfo = new CoreDragInfo( - routedArgs.Data.GetView(), + source: ptArgs, + data: routedArgs.Data.GetView(), routedArgs.AllowedOperations, - dragUI: routedArgs.DragUI, - pointer: pointer.PointerDevice); + dragUI: routedArgs.DragUI); dragInfo.RegisterCompletedCallback(result.SetResult); CoreDragDropManager.GetForCurrentView()!.DragStarted(dragInfo); @@ -622,18 +622,18 @@ private protected virtual void PrepareShare(DataPackage data) internal void RaiseDragEnterOrOver(global::Windows.UI.Xaml.DragEventArgs args) { - var evt = IsDragOver(args.Pointer) + var evt = IsDragOver(args.SourceId) ? DragOverEvent : DragEnterEvent; - (_draggingOver ??= new HashSet()).Add(args.Pointer); + (_draggingOver ??= new HashSet()).Add(args.SourceId); SafeRaiseEvent(evt, args); } internal void RaiseDragLeave(global::Windows.UI.Xaml.DragEventArgs args) { - if (_draggingOver?.Remove(args.Pointer) ?? false) + if (_draggingOver?.Remove(args.SourceId) ?? false) { SafeRaiseEvent(DragLeaveEvent, args); } @@ -641,7 +641,7 @@ internal void RaiseDragLeave(global::Windows.UI.Xaml.DragEventArgs args) internal void RaiseDrop(global::Windows.UI.Xaml.DragEventArgs args) { - if (_draggingOver?.Remove(args.Pointer) ?? false) + if (_draggingOver?.Remove(args.SourceId) ?? false) { SafeRaiseEvent(DropEvent, args); } @@ -760,7 +760,7 @@ private bool OnNativePointerMoveWithOverCheck(PointerRoutedEventArgs args, bool _gestures.Value.ProcessMoveEvents(args.GetIntermediatePoints(this), isOverOrCaptured); if (_gestures.Value.IsDragging) { - Window.Current.DragDrop.ProcessPointerMovedOverWindow(args); + Window.Current.DragDrop.ProcessMoved(args); } } @@ -791,7 +791,7 @@ private bool OnPointerMove(PointerRoutedEventArgs args, bool isManagedBubblingEv _gestures.Value.ProcessMoveEvents(args.GetIntermediatePoints(this), !isManagedBubblingEvent || isOverOrCaptured); if (_gestures.Value.IsDragging) { - Window.Current.DragDrop.ProcessPointerMovedOverWindow(args); + Window.Current.DragDrop.ProcessMoved(args); } } @@ -820,7 +820,7 @@ private bool OnPointerUp(PointerRoutedEventArgs args, bool isManagedBubblingEven _gestures.Value.ProcessUpEvent(args.GetCurrentPoint(this), !isManagedBubblingEvent || isOverOrCaptured); if (isDragging) { - Window.Current.DragDrop.ProcessPointerReleased(args); + Window.Current.DragDrop.ProcessDropped(args); } } @@ -847,7 +847,7 @@ private bool OnPointerExited(PointerRoutedEventArgs args, bool isManagedBubbling if (_gestures.IsValueCreated && _gestures.Value.IsDragging) { - Window.Current.DragDrop.ProcessPointerMovedOverWindow(args); + Window.Current.DragDrop.ProcessMoved(args); } // We release the captures on exit when pointer if not pressed @@ -892,7 +892,7 @@ private bool OnPointerCancel(PointerRoutedEventArgs args, bool isManagedBubbling _gestures.Value.CompleteGesture(); if (_gestures.Value.IsDragging) { - Window.Current.DragDrop.ProcessPointerCanceled(args); + Window.Current.DragDrop.ProcessAborted(args); } } @@ -1247,7 +1247,7 @@ private bool Release(PointerCapture capture, PointerCaptureKind kinds, PointerRo #endregion #region Drag state (Updated by the RaiseDrag***, should not be updated externaly) - private HashSet _draggingOver; + private HashSet _draggingOver; /// /// Gets a boolean which indicates if there is currently a Drag and Drop operation pending over this element. @@ -1257,17 +1257,20 @@ private bool Release(PointerCapture capture, PointerCaptureKind kinds, PointerRo /// /// The pointer associated to the drag and drop operation internal bool IsDragOver(Pointer pointer) - => _draggingOver?.Contains(pointer) ?? false; + => _draggingOver?.Contains(pointer.UniqueId) ?? false; - private void SetIsDragOver(Pointer pointer, bool isOver) + internal bool IsDragOver(long sourceId) + => _draggingOver?.Contains(sourceId) ?? false; + + private void SetIsDragOver(long sourceId, bool isOver) { if (isOver) { - (_draggingOver ??= new HashSet()).Add(pointer); + (_draggingOver ??= new HashSet()).Add(sourceId); } else { - _draggingOver?.Remove(pointer); + _draggingOver?.Remove(sourceId); } } diff --git a/src/Uno.UWP/ApplicationModel/DataTransfer/DragDrop/Core/CoreDragInfo.cs b/src/Uno.UWP/ApplicationModel/DataTransfer/DragDrop/Core/CoreDragInfo.cs index 65f90690162a..20f544cd920e 100644 --- a/src/Uno.UWP/ApplicationModel/DataTransfer/DragDrop/Core/CoreDragInfo.cs +++ b/src/Uno.UWP/ApplicationModel/DataTransfer/DragDrop/Core/CoreDragInfo.cs @@ -13,30 +13,48 @@ namespace Windows.ApplicationModel.DataTransfer.DragDrop.Core { + internal interface IDragEventSource + { + long Id { get; } + + uint FrameId { get; } + + //bool IsExternal { get; } + + (Point location, DragDropModifiers modifier) GetState(); + + Point GetPosition(object? relativeTo); + } + public partial class CoreDragInfo { private ImmutableList>? _completions = ImmutableList>.Empty; private int _result = -1; + private IDragEventSource _source; internal CoreDragInfo( + IDragEventSource source, DataPackageView data, DataPackageOperation allowedOperations, - object? dragUI = null, - object? pointer = null) + object? dragUI = null) { + _source = source; + (Position, Modifiers) = source.GetState(); + Data = data; AllowedOperations = allowedOperations; DragUI = dragUI; - Pointer = pointer; } public DataPackageView Data { get; } public DataPackageOperation AllowedOperations { get; } - public DragDropModifiers Modifiers { get; internal set; } + public DragDropModifiers Modifiers { get; private set; } + + public Point Position { get; private set; } - public Point Position { get; internal set; } + internal Point GetPosition(object? relativeTo) => _source.GetPosition(relativeTo); /// /// If this drag operation has been initiated by the current application, @@ -45,20 +63,20 @@ internal CoreDragInfo( internal object? DragUI { get; } /// - /// If this drag operation has been initiated by the current application, - /// this is expected to be the Windows.UI.Xaml.Input.Pointer used to initiate this operation. + /// A unique identifier of the source that trigger those drag operation (Pointer.UniqueId for internal drag and drop) /// - internal object? Pointer { get; } + internal long SourceId => _source.Id; - /// - /// This will contains the current Windows.UI.Xaml.Input.PointerRoutedEventArgs which is triggering an update - /// on . - /// This is going to be updated before the invocation of any method of the ICoreDropOperationTarget. - /// - /// - /// This is a hack for the UIDropTarget which needs to known the location of the pointer for the Windows.UI.Xaml.DragEventArgs. - /// - internal object? PointerRoutedEventArgs { get; set; } + internal void UpdateSource(IDragEventSource src) + { + if (src.Id != SourceId) + { + throw new InvalidOperationException("Cannot change the source id of pending drag operation"); + } + + _source = src; + (Position, Modifiers) = src.GetState(); + } internal void RegisterCompletedCallback(Action onCompleted) {