Skip to content
This repository has been archived by the owner on May 1, 2024. It is now read-only.

Commit

Permalink
[Tizen] Add drag and drop gesture handlers (#13692)
Browse files Browse the repository at this point in the history
  • Loading branch information
shyunMin committed Feb 10, 2021
1 parent c16c8c4 commit 020fc33
Show file tree
Hide file tree
Showing 8 changed files with 525 additions and 2 deletions.
243 changes: 243 additions & 0 deletions Xamarin.Forms.Platform.Tizen/DragGestureHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,243 @@
using System;
using System.Threading;
using ElmSharp;
using Tizen.Common;
using Xamarin.Forms.Platform.Tizen.SkiaSharp;
using EGestureType = ElmSharp.GestureLayer.GestureType;

namespace Xamarin.Forms.Platform.Tizen
{
public class DragGestureHandler : GestureHandler
{
bool _isApi4;

DragDropExtensions.Interop.DragIconCreateCallback _iconCallback;
DragDropExtensions.Interop.DragStateCallback _dragDoneCallback;

static bool s_isDragging;
static CustomDragStateData s_currentDragStateData;

public DragGestureHandler(IGestureRecognizer recognizer, IVisualElementRenderer renderer) : base(recognizer)
{
_iconCallback = OnIconCallback;
_dragDoneCallback = OnDragDoneCallback;
_isApi4 = DotnetUtil.TizenAPIVersion <= 4;
Renderer = renderer;
}

public override EGestureType Type => EGestureType.LongTap;

public IVisualElementRenderer Renderer { get; }

public static CustomDragStateData CurrentStateData
{
get
{
return s_currentDragStateData;
}
}

EvasObject NativeView
{
get
{
var native = Renderer.NativeView;
if (Renderer is SkiaSharp.ICanvasRenderer canvasRenderer)
{
native = canvasRenderer.RealNativeView;
}
return native;
}
}

public void ResetCurrentStateData()
{
s_currentDragStateData = null;
}

protected override void OnStarted(View sender, object data)
{
}

protected override void OnMoved(View sender, object data)
{
//Workaround to prevent an error occuring by multiple StartDrag calling in Tizen 6.5
if (!s_isDragging)
{
ResetCurrentStateData();
StartDrag();
}
}

protected override void OnCompleted(View sender, object data)
{
}

protected override void OnCanceled(View sender, object data)
{
}

void StartDrag()
{
if (Recognizer is DragGestureRecognizer dragGestureRecognizer && dragGestureRecognizer.CanDrag)
{
if (Renderer == null)
return;

var arg = dragGestureRecognizer.SendDragStarting(Renderer.Element);

if (arg.Cancel)
return;

s_currentDragStateData = new CustomDragStateData();
s_currentDragStateData.DataPackage = arg.Data;

var target = DragDropExtensions.DragDropContentType.Text;
var strData = string.IsNullOrEmpty(arg.Data.Text) ? " " : arg.Data.Text;

s_isDragging = true;

DragDropExtensions.StartDrag(NativeView,
target,
strData,
DragDropExtensions.DragDropActionType.Move,
_iconCallback,
null,
null,
_dragDoneCallback);
}
}

IntPtr OnIconCallback(IntPtr data, IntPtr window, ref int xoff, ref int yoff)
{
EvasObject icon = null;
EvasObject parent = new CustomWindow(NativeView, window);

if (s_currentDragStateData.DataPackage.Image != null)
{
icon = GetImageIcon(parent);
}
else if (NativeView is ShapeView)
{
icon = GetShapeView(parent);
}
else
{
icon = GetDefaultIcon(parent);
}
var bound = NativeView.Geometry;
bound.X = 0;
bound.Y = 0;
icon.Geometry = bound;

if (icon is Native.Label)
{
icon.Resized += (s, e) =>
{
var map = new EvasMap(4);
map.PopulatePoints(icon.Geometry, 0);
map.Zoom(0.5, 0.5, 0, 0);
icon.IsMapEnabled = true;
icon.EvasMap = map;
};
}
else
{
var map = new EvasMap(4);
map.PopulatePoints(icon.Geometry, 0);
map.Zoom(0.5, 0.5, 0, 0);
icon.IsMapEnabled = true;
icon.EvasMap = map;
}


return icon;
}

EvasObject GetDefaultIcon(EvasObject parent)
{
if (!string.IsNullOrEmpty(s_currentDragStateData.DataPackage.Text))
{
var label = new Native.Label(parent);
label.Text = s_currentDragStateData.DataPackage.Text;

if (Renderer.Element is Label lb)
label.FontSize = lb.FontSize;
else if (Renderer.Element is Entry et)
label.FontSize = et.FontSize;
else if (Renderer.Element is Editor ed)
label.FontSize = ed.FontSize;

return label;
}
else
{
var box = new ElmSharp.Rectangle(parent);
box.Color = new ElmSharp.Color(128, 128, 128, 128);
return box;
}
}

EvasObject GetImageIcon(EvasObject parent)
{
var image = new Native.Image(parent);
_ = image.LoadFromImageSourceAsync(s_currentDragStateData.DataPackage.Image);
return image;
}

EvasObject GetShapeView(EvasObject parent)
{
var copiedImg = new EvasImage(parent);
copiedImg.IsFilled = true;

if (NativeView is ShapeView shapeView)
{
var canvas = shapeView.SKCanvasView;
var realHandle = DragDropExtensions.Interop.elm_object_part_content_get(canvas, "elm.swallow.content");

DragDropExtensions.Interop.evas_object_image_size_get(realHandle, out int w, out int h);
DragDropExtensions.Interop.evas_object_image_size_set(copiedImg, w, h);

var imgData = DragDropExtensions.Interop.evas_object_image_data_get(realHandle, false);
DragDropExtensions.Interop.evas_object_image_data_set(copiedImg, imgData);
}

return copiedImg;
}

void OnDragDoneCallback(IntPtr data, IntPtr obj)
{
s_isDragging = false;
if (Recognizer is DragGestureRecognizer dragGestureRecognizer && dragGestureRecognizer.CanDrag)
{
dragGestureRecognizer.SendDropCompleted(new DropCompletedEventArgs());
}
}

public class CustomWindow : EvasObject
{
IntPtr _handle;

public CustomWindow(EvasObject parent, IntPtr handle) : base()
{
_handle = handle;
Realize(parent);
}

public CustomWindow(EvasObject handle) : base(handle)
{
}

protected override IntPtr CreateHandle(EvasObject parent)
{
return _handle;
}
}

public class CustomDragStateData
{
public DataPackage DataPackage { get; set; }
public DataPackageOperation AcceptedOperation { get; set; } = DataPackageOperation.Copy;
}
}
}
133 changes: 133 additions & 0 deletions Xamarin.Forms.Platform.Tizen/DropGestureHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
using System;
using System.Linq;
using ElmSharp;
using Tizen.Common;
using EGestureType = ElmSharp.GestureLayer.GestureType;

namespace Xamarin.Forms.Platform.Tizen
{
public class DropGestureHandler : GestureHandler
{
bool _isApi4;

DragDropExtensions.Interop.DragStateCallback _dragEnterCallback;
DragDropExtensions.Interop.DragStateCallback _dragLeaveCallback;
DragDropExtensions.Interop.DropCallback _dropCallback;

public override EGestureType Type => default(EGestureType);

public DropGestureHandler(IGestureRecognizer recognizer, IVisualElementRenderer renderer) : base(recognizer)
{
_dragEnterCallback = OnEnterCallback;
_dragLeaveCallback = OnLeaveCallback;
_dropCallback = OnDropCallback;
_isApi4 = DotnetUtil.TizenAPIVersion <= 4;
Renderer = renderer;
}

public IVisualElementRenderer Renderer { get; }

EvasObject NativeView
{
get
{
var native = Renderer.NativeView;
if (Renderer is SkiaSharp.ICanvasRenderer canvasRenderer)
{
native = canvasRenderer.RealNativeView;
}

if (native is Native.Canvas canvas)
{
var child = canvas.Children.LastOrDefault<EvasObject>();

if (child != null)
{
if (child.PassEvents)
child.PassEvents = false;

return child;
}
}
return native;
}
}


public void AddDropGesture()
{
if (Renderer == null)
return;

var target = DragDropExtensions.DragDropContentType.Targets;

DragDropExtensions.AddDropTarget(NativeView,
target,
_dragEnterCallback,
_dragLeaveCallback, null,
_dropCallback);
}

void OnEnterCallback(IntPtr data, IntPtr obj)
{
var currentStateData = DragGestureHandler.CurrentStateData;
if (currentStateData == null)
return;

var arg = new DragEventArgs(currentStateData.DataPackage);

if (Recognizer is DropGestureRecognizer dropRecognizer && dropRecognizer.AllowDrop)
dropRecognizer.SendDragOver(arg);

DragGestureHandler.CurrentStateData.AcceptedOperation = arg.AcceptedOperation;
}

void OnLeaveCallback(IntPtr data, IntPtr obj)
{
var currentStateData = DragGestureHandler.CurrentStateData;
if (currentStateData == null)
return;

var arg = new DragEventArgs(currentStateData.DataPackage);

if (Recognizer is DropGestureRecognizer dropRecognizer && dropRecognizer.AllowDrop)
dropRecognizer.SendDragLeave(arg);

DragGestureHandler.CurrentStateData.AcceptedOperation = arg.AcceptedOperation;
}

bool OnDropCallback(IntPtr data, IntPtr obj, IntPtr selectionData)
{
var currentStateData = DragGestureHandler.CurrentStateData;

if (currentStateData.DataPackage == null || currentStateData.AcceptedOperation == DataPackageOperation.None)
return false;

Device.BeginInvokeOnMainThread(async ()=>
{
if (Recognizer is DropGestureRecognizer dropRecognizer && dropRecognizer.AllowDrop)
await dropRecognizer.SendDrop(new DropEventArgs(currentStateData.DataPackage.View));
});

return true;
}

#region GestureHandler
protected override void OnStarted(View sender, object data)
{
}

protected override void OnMoved(View sender, object data)
{
}

protected override void OnCompleted(View sender, object data)
{
}

protected override void OnCanceled(View sender, object data)
{
}
#endregion
}
}
Loading

0 comments on commit 020fc33

Please sign in to comment.