Skip to content

Commit

Permalink
Add Control.DragEnd event
Browse files Browse the repository at this point in the history
This is useful when you want to know when the drag operation finishes after DoDragDrop() is called, since it is only blocking on Windows.
  • Loading branch information
cwensley committed Aug 24, 2022
1 parent d51f5e4 commit 9712ee5
Show file tree
Hide file tree
Showing 13 changed files with 152 additions and 14 deletions.
4 changes: 2 additions & 2 deletions src/Eto.Gtk/Forms/Controls/GridViewHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@ protected class GridViewConnector : GridConnector

public new GridViewHandler Handler { get { return (GridViewHandler)base.Handler; } }

protected override DragEventArgs GetDragEventArgs(Gdk.DragContext context, PointF? location, uint time = 0, object controlObject = null)
protected override DragEventArgs GetDragEventArgs(Gdk.DragContext context, PointF? location, uint time = 0, object controlObject = null, DataObject data = null)
{
var t = Handler?.Control;
GridViewDragInfo dragInfo = _dragInfo;
Expand All @@ -264,7 +264,7 @@ protected override DragEventArgs GetDragEventArgs(Gdk.DragContext context, Point
}
}

return base.GetDragEventArgs(context, location, time, dragInfo);
return base.GetDragEventArgs(context, location, time, dragInfo, data);
}

public override void HandleDragMotion(object o, Gtk.DragMotionArgs args)
Expand Down
4 changes: 2 additions & 2 deletions src/Eto.Gtk/Forms/Controls/TreeGridViewHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ public void HandleRowActivated(object o, Gtk.RowActivatedArgs args)
Handler?.Callback.OnActivated(Handler.Widget, new TreeGridViewItemEventArgs(Handler.model.GetItemAtPath(args.Path)));
}

protected override DragEventArgs GetDragEventArgs(Gdk.DragContext context, PointF? location, uint time = 0, object controlObject = null)
protected override DragEventArgs GetDragEventArgs(Gdk.DragContext context, PointF? location, uint time = 0, object controlObject = null, DataObject data = null)
{
var h = Handler;
var t = h?.Control;
Expand All @@ -298,7 +298,7 @@ protected override DragEventArgs GetDragEventArgs(Gdk.DragContext context, Point
}
}

return base.GetDragEventArgs(context, location, time, dragInfo);
return base.GetDragEventArgs(context, location, time, dragInfo, data);
}

public override void HandleDragMotion(object o, Gtk.DragMotionArgs args)
Expand Down
29 changes: 27 additions & 2 deletions src/Eto.Gtk/Forms/GtkControl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ static class GtkControl
public static readonly object ScrollAmount_Key = new object();
public static readonly object DragInfo_Key = new object();
public static readonly object DropSource_Key = new object();
public static readonly object DropSourceData_Key = new object();
public static readonly object Font_Key = new object();
public static readonly object TabIndex_Key = new object();
public static readonly object Cursor_Key = new object();
Expand Down Expand Up @@ -455,6 +456,9 @@ public override void AttachEvent(string id)
HandleEvent(Eto.Forms.Control.DragOverEvent);
DragControl.DragLeave += Connector.HandleDragLeave;
break;
case Eto.Forms.Control.DragEndEvent:
DragControl.DragEnd += Connector.HandleDragEnd;
break;
case Eto.Forms.Control.EnabledChangedEvent:
#if GTK3
ContainerControl.StateFlagsChanged += Connector.HandleStateFlagsChangedForEnabled;
Expand Down Expand Up @@ -720,7 +724,7 @@ public virtual void MappedEvent(object sender, EventArgs e)
Handler?.Callback.OnShown(Handler.Widget, EventArgs.Empty);
}

protected virtual DragEventArgs GetDragEventArgs(Gdk.DragContext context, PointF? location, uint time = 0, object controlObject = null)
protected virtual DragEventArgs GetDragEventArgs(Gdk.DragContext context, PointF? location = null, uint time = 0, object controlObject = null, DataObject data = null)
{
var widget = Gtk.Drag.GetSourceWidget(context);
var source = widget?.Data[GtkControl.DropSource_Key] as Eto.Forms.Control;
Expand All @@ -731,7 +735,7 @@ protected virtual DragEventArgs GetDragEventArgs(Gdk.DragContext context, PointF
var action = context.SelectedAction;
#endif

var data = new DataObject(new DataObjectHandler(Handler.DragControl, context, time));
data = data ?? new DataObject(new DataObjectHandler(Handler.DragControl, context, time));
if (location == null)
location = Handler.PointFromScreen(Mouse.Position);

Expand Down Expand Up @@ -809,6 +813,23 @@ public virtual void HandleDragLeave(object o, Gtk.DragLeaveArgs args)
Eto.Forms.Application.Instance.AsyncInvoke(() => DragArgs = null);
}

public virtual void HandleDragEnd(object o, Gtk.DragEndArgs args)
{
var handler = Handler;
if (handler == null)
return;
var data = handler.DragControl.Data[GtkControl.DropSourceData_Key] as DataObject;

var e = GetDragEventArgs(args.Context, data: data);
#if GTK2
e.Effects = args.Context.Action.ToEto();
#else
e.Effects = args.Context.SelectedAction.ToEto();
#endif
handler.Callback.OnDragEnd(handler.Widget, e);
handler.DragControl.Data[GtkControl.DropSourceData_Key] = null;
}

#if GTK3
public virtual void HandleStateFlagsChangedForEnabled(object o, Gtk.StateFlagsChangedArgs args)
{
Expand Down Expand Up @@ -971,6 +992,10 @@ public void DoDragDrop(DataObject data, DragEffects allowedEffects, Image image,
DragInfo = new DragInfoObject { Data = data, AllowedEffects = allowedEffects };

DragControl.Data[GtkControl.DropSource_Key] = Widget;

// set data and ensure it gets cleared out.
DragControl.Data[GtkControl.DropSourceData_Key] = data;
HandleEvent(Eto.Forms.Control.DragEndEvent);

#if GTKCORE
var context = Gtk.Drag.BeginWithCoordinates(DragControl, targets, allowedEffects.ToGdk(), 1, Gtk.Application.CurrentEvent, -1, -1);
Expand Down
5 changes: 4 additions & 1 deletion src/Eto.Mac/Forms/Controls/GridHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,8 @@ class GridDragInfo
public NSDragOperation AllowedOperation { get; set; }
public NSImage DragImage { get; set; }
public PointF ImageOffset { get; set; }

public DataObject Data { get; set; }

public CGPoint GetDragImageOffset()
{
Expand Down Expand Up @@ -722,7 +724,8 @@ public override void DoDragDrop(DataObject data, DragEffects allowedAction, Imag
{
AllowedOperation = allowedAction.ToNS(),
DragImage = image.ToNS(),
ImageOffset = origin
ImageOffset = origin,
Data = data
};
}
else
Expand Down
6 changes: 6 additions & 0 deletions src/Eto.Mac/Forms/Controls/GridViewHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,12 @@ public override void DraggingSessionEnded(NSTableView tableView, NSDraggingSessi
h.CustomSelectedRows = null;
h.Callback.OnSelectionChanged(h.Widget, EventArgs.Empty);
}

var allowedOperation = h.DragInfo?.AllowedOperation ?? NSDragOperation.None;
var data = h.DragInfo?.Data;
var args = new DragEventArgs(h.Widget, data, allowedOperation.ToEto(), endedAtScreenPoint.ToEto(h.ContainerControl), Keyboard.Modifiers, Mouse.Buttons);
args.Effects = operation.ToEto();
h.Callback.OnDragEnd(h.Widget, args);
}

public override bool WriteRows(NSTableView tableView, NSIndexSet rowIndexes, NSPasteboard pboard)
Expand Down
6 changes: 6 additions & 0 deletions src/Eto.Mac/Forms/Controls/TreeGridViewHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -465,6 +465,12 @@ public override void DraggingSessionEnded(NSOutlineView outlineView, NSDraggingS
h.CustomSelectedItems = null;
h.Callback.OnSelectionChanged(h.Widget, EventArgs.Empty);
}

var allowedOperation = h.DragInfo?.AllowedOperation ?? NSDragOperation.None;
var data = h.DragInfo?.Data;
var args = new DragEventArgs(h.Widget, data, allowedOperation.ToEto(), screenPoint.ToEto(h.ContainerControl), Keyboard.Modifiers, Mouse.Buttons);
args.Effects = operation.ToEto();
h.Callback.OnDragEnd(h.Widget, args);
}

public override bool OutlineViewwriteItemstoPasteboard(NSOutlineView outlineView, NSArray items, NSPasteboard pboard)
Expand Down
16 changes: 15 additions & 1 deletion src/Eto.Mac/Forms/EtoDragSource.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
using System;

using Eto.Forms;

namespace Eto.Mac.Forms
{
class EtoDragSource : NSDraggingSource
{
public DataObject Data { get; set; }
public IMacViewHandler Handler { get; set; }

[Export("sourceView")]
public NSView SourceView { get; set; }

Expand All @@ -16,5 +19,16 @@ public NSDragOperation DraggingSessionSourceOperationMask(NSDraggingSession sess
{
return AllowedOperation;
}

[Export("draggingSession:endedAtPoint:operation:")]
public void DraggingSessionEnded(NSDraggingSession session, CGPoint point, NSDragOperation operation)
{
var h = Handler;
if (h == null)
return;
var args = new DragEventArgs(h.Widget, Data, AllowedOperation.ToEto(), point.ToEto(), Keyboard.Modifiers, Mouse.Buttons, this);
args.Effects = operation.ToEto();
h.Callback.OnDragEnd(h.Widget, args);
}
}
}
5 changes: 4 additions & 1 deletion src/Eto.Mac/Forms/MacView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -817,6 +817,9 @@ public override void AttachEvent(string id)
case Eto.Forms.Control.DragLeaveEvent:
AddMethod(MacView.selDraggingExited, MacView.TriggerDraggingExited_Delegate, "v@:@", DragControl);
break;
case Eto.Forms.Control.DragEndEvent:
// handled in EtoDragSource, TreeGridViewHandler.EtoDragSource, and GridViewHandler.EtoDragSource
break;
default:
base.AttachEvent(id);
break;
Expand Down Expand Up @@ -1268,7 +1271,7 @@ public virtual void DoDragDrop(DataObject data, DragEffects allowedAction, Image
{
var handler = data.Handler as IDataObjectHandler;

var source = new EtoDragSource { AllowedOperation = allowedAction.ToNS(), SourceView = ContainerControl };
var source = new EtoDragSource { AllowedOperation = allowedAction.ToNS(), SourceView = ContainerControl, Handler = this, Data = data };

NSDraggingItem[] draggingItems = null;
if (image != null)
Expand Down
7 changes: 6 additions & 1 deletion src/Eto.Mac/MacConversions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -531,7 +531,12 @@ public static NSBorderType ToNS(this BorderType border)
}
}

public static DataObject ToEto(this NSPasteboard pasteboard) => new DataObject(new DataObjectHandler(pasteboard));
public static DataObject ToEto(this NSPasteboard pasteboard)
{
if (pasteboard == null)
return null;
return new DataObject(new DataObjectHandler(pasteboard));
}

public static NSPasteboard ToNS(this DataObject data) => DataObjectHandler.GetControl(data);

Expand Down
16 changes: 13 additions & 3 deletions src/Eto.WinForms/Forms/WindowsControl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -474,6 +474,9 @@ public override void AttachEvent(string id)
Callback.OnDragLeave(Widget, new DragEventArgs(null, new DataObject(), DragEffects.None, PointF.Empty, Keys.None, MouseButtons.None));
};
break;
case Eto.Forms.Control.DragEndEvent:
// Handled in DoDragDrop as it is blocking on Windows.
break;
case Eto.Forms.Control.EnabledChangedEvent:
Control.EnabledChanged += Control_EnabledChanged;
break;
Expand All @@ -496,7 +499,9 @@ DragEventArgs GetDragEventArgs(swf.DragEventArgs data)
var modifiers = data.GetEtoModifiers();
var buttons = data.GetEtoButtons();
var location = PointFromScreen(new PointF(data.X, data.Y));
return new SwfDragEventArgs(source, dragData, data.AllowedEffect.ToEto(), location, modifiers, buttons);
var args = new SwfDragEventArgs(source, dragData, data.AllowedEffect.ToEto(), location, modifiers, buttons);
args.Effects = data.Effect.ToEto();
return args;
}

void HandleMouseWheel(object sender, swf.MouseEventArgs e)
Expand Down Expand Up @@ -1000,6 +1005,7 @@ public void DoDragDrop(DataObject data, DragEffects allowedEffects, Image image,
{
var dataObject = data.ToSwf();
WindowsControl.DragSourceControl = Widget;
swf.DragDropEffects effects;
if (UseShellDropManager)
{
swf.DragSourceHelper.AllowDropDescription(true);
Expand All @@ -1010,17 +1016,21 @@ public void DoDragDrop(DataObject data, DragEffects allowedEffects, Image image,

swf.SwfDataObjectExtensions.SetDragImage(dataObject, image.ToSD(), cursorOffset.ToSDPoint());
swf.DragSourceHelper.RegisterDefaultDragSource(Control, dataObject);
Control.DoDragDrop(dataObject, allowedEffects.ToSwf());
effects = Control.DoDragDrop(dataObject, allowedEffects.ToSwf());
swf.DragSourceHelper.UnregisterDefaultDragSource(Control);
}
else
{
if (image != null)
Debug.WriteLine("DoDragDrop cannot show drag image when UseShellDropManager is false");

Control.DoDragDrop(dataObject, allowedEffects.ToSwf());
effects = Control.DoDragDrop(dataObject, allowedEffects.ToSwf());
}
WindowsControl.DragSourceControl = null;

var args = new DragEventArgs(Widget, data, allowedEffects, PointFromScreen(Mouse.Position), Keyboard.Modifiers, Mouse.Buttons);
args.Effects = effects.ToEto();
Callback.OnDragEnd(Widget, args);
}

public Window GetNativeParentWindow() => ContainerControl.FindForm().ToEtoWindow();
Expand Down
9 changes: 8 additions & 1 deletion src/Eto.Wpf/Forms/WpfFrameworkElement.cs
Original file line number Diff line number Diff line change
Expand Up @@ -516,6 +516,9 @@ public override void AttachEvent(string id)
Control.DragLeave += Control_DragLeave;
HandleEvent(Eto.Forms.Control.DragEnterEvent); // need DragEnter so it doesn't get called when going over children
break;
case Eto.Forms.Control.DragEndEvent:
// handled in DoDragDrop, as it is blocking on Windows
break;
case Eto.Forms.Control.EnabledChangedEvent:
Control.IsEnabledChanged += Control_IsEnabledChanged;
break;
Expand Down Expand Up @@ -1028,10 +1031,14 @@ public void DoDragDrop(DataObject data, DragEffects allowedAction, Image image,
sw.WpfDataObjectExtensions.SetDragImage(dataObject, image.ToWpf(), PointF.Empty.ToWpf());
}

sw.DragDrop.DoDragDrop(Control, dataObject, allowedAction.ToWpf());
var effects = sw.DragDrop.DoDragDrop(Control, dataObject, allowedAction.ToWpf());

WpfFrameworkElement.DragSourceControl = null;
sw.DragSourceHelper.UnregisterDefaultDragSource(Control);

var args = new DragEventArgs(Widget, data, allowedAction, PointFromScreen(Mouse.Position), Keyboard.Modifiers, Mouse.Buttons);
args.Effects = effects.ToEto();
Callback.OnDragEnd(Widget, args);
}


Expand Down
47 changes: 47 additions & 0 deletions src/Eto/Forms/Controls/Control.cs
Original file line number Diff line number Diff line change
Expand Up @@ -682,6 +682,31 @@ public event EventHandler<DragEventArgs> DragLeave
/// <param name="e">Event arguments</param>
protected virtual void OnDragLeave(DragEventArgs e) => Properties.TriggerEvent(DragLeaveEvent, this, e);


/// <summary>
/// Event identifier for handlers when attaching the <see cref="DragEnd"/> event
/// </summary>
public const string DragEndEvent = "Control.DragEnd";

/// <summary>
/// Occurs for a source control after a call to <see cref="DoDragDrop(DataObject, DragEffects, Image, PointF)"/> when the drag operation has ended.
/// The <see cref="DragEventArgs.Effects"/> is the final <see cref="DragEffects"/> used at the drop destination.
/// </summary>
/// <remarks>
/// For controls that you are dragging from this event is useful to know what to do with the dragged content after it is dropped in a different control or application.
/// </remarks>
public event EventHandler<DragEventArgs> DragEnd
{
add { Properties.AddHandlerEvent(DragEndEvent, value); }
remove { Properties.RemoveEvent(DragEndEvent, value); }
}

/// <summary>
/// Raises the <see cref="DragEnd"/> event.
/// </summary>
/// <param name="e">Event arguments</param>
protected virtual void OnDragEnd(DragEventArgs e) => Properties.TriggerEvent(DragEndEvent, this, e);

/// <summary>
/// Event identifier for handlers when attaching the <see cref="EnabledChanged"/> event
/// </summary>
Expand Down Expand Up @@ -724,6 +749,7 @@ static Control()
EventLookup.Register<Control>(c => c.OnDragOver(null), Control.DragOverEvent);
EventLookup.Register<Control>(c => c.OnDragEnter(null), Control.DragEnterEvent);
EventLookup.Register<Control>(c => c.OnDragLeave(null), Control.DragLeaveEvent);
EventLookup.Register<Control>(c => c.OnDragEnd(null), Control.DragEndEvent);
EventLookup.Register<Control>(c => c.OnEnabledChanged(null), Control.EnabledChangedEvent);
}

Expand Down Expand Up @@ -1313,6 +1339,10 @@ public virtual bool AllowDrop
/// <summary>
/// Starts drag operation using this control as drag source.
/// </summary>
/// <remarks>
/// This method can be blocking on some platforms (Wpf, WinForms), and non-blocking on others (Mac, Gtk).
/// Use the <see cref="DragEnd"/> event to determine when the drag operation is completed and get its resulting DragEffects.
/// </remarks>
/// <param name="data">Drag data.</param>
/// <param name="allowedEffects">Allowed action.</param>
public virtual void DoDragDrop(DataObject data, DragEffects allowedEffects)
Expand All @@ -1323,6 +1353,10 @@ public virtual void DoDragDrop(DataObject data, DragEffects allowedEffects)
/// <summary>
/// Starts drag operation using this control as drag source.
/// </summary>
/// <remarks>
/// This method can be blocking on some platforms (Wpf, WinForms), and non-blocking on others (Mac, Gtk).
/// Use the <see cref="DragEnd"/> event to determine when the drag operation is completed and get its resulting DragEffects.
/// </remarks>
/// <param name="data">Drag data.</param>
/// <param name="allowedEffects">Allowed effects.</param>
/// <param name="image">Custom drag image</param>
Expand Down Expand Up @@ -1510,6 +1544,10 @@ public static implicit operator Control(Image image)
/// </summary>
void OnDragLeave(Control widget, DragEventArgs e);
/// <summary>
/// Raises the DragEnd event.
/// </summary>
void OnDragEnd(Control widget, DragEventArgs e);
/// <summary>
/// Raises the EnabledChanged event.
/// </summary>
void OnEnabledChanged(Control widget, EventArgs e);
Expand Down Expand Up @@ -1669,6 +1707,15 @@ public void OnDragLeave(Control widget, DragEventArgs e)
widget.OnDragLeave(e);
}

/// <summary>
/// Raises the DragEnd event.
/// </summary>
public void OnDragEnd(Control widget, DragEventArgs e)
{
using (widget.Platform.Context)
widget.OnDragEnd(e);
}

/// <summary>
/// Raises the EnabledChanged event.
/// </summary>
Expand Down
Loading

0 comments on commit 9712ee5

Please sign in to comment.