Skip to content

Commit

Permalink
Add GestureManager (#96)
Browse files Browse the repository at this point in the history
* Add GestureManager

* Fix DragGestureHandler

* Fix GestureManager

* Check nullable enable
  • Loading branch information
sung-su authored and rookiejava committed Apr 13, 2022
1 parent 469bdca commit 8297e5b
Show file tree
Hide file tree
Showing 11 changed files with 1,485 additions and 1 deletion.
121 changes: 120 additions & 1 deletion src/Controls/src/Core/Platform/GestureManager/GestureManager.Tizen.cs
Original file line number Diff line number Diff line change
@@ -1,18 +1,137 @@
#nullable enable

using System;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Linq;

namespace Microsoft.Maui.Controls.Platform
{
class GestureManager : IDisposable
{
IViewHandler? _handler;
GestureDetector? _gestureDetector;
bool _disposed = false;

protected virtual VisualElement? Element => _handler?.VirtualView as VisualElement;

public GestureManager(IViewHandler handler)
{
//TODO: Need to impl
_handler = handler;
_gestureDetector = null;
SetupElement(null, Element);
}

void SetupElement(VisualElement? oldElement, VisualElement? newElement)
{
if (oldElement != null)
{
if (oldElement is View ov &&
ov.GestureRecognizers is INotifyCollectionChanged incc)
{
incc.CollectionChanged -= OnGestureRecognizerCollectionChanged;
_gestureDetector?.Clear();
}
oldElement.PropertyChanged -= OnElementPropertyChanged;
}

if (newElement != null)
{
if (newElement is View ov &&
ov.GestureRecognizers is INotifyCollectionChanged incc)
{
incc.CollectionChanged += OnGestureRecognizerCollectionChanged;
if (ov.GestureRecognizers.Count > 0)
{
_gestureDetector = new GestureDetector(_handler);
_gestureDetector.AddGestures(ov.GestureRecognizers);
}
}
newElement.PropertyChanged += OnElementPropertyChanged;
}

UpdateInputTransparent();
UpdateIsEnabled();
}

void OnElementPropertyChanged(object? sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == VisualElement.InputTransparentProperty.PropertyName)
UpdateInputTransparent();
else if (e.PropertyName == VisualElement.IsEnabledProperty.PropertyName)
UpdateIsEnabled();
}

public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}

public void Dispose(bool disposing)
{
if (_disposed)
{
return;
}

_disposed = true;

if (disposing)
{
SetupElement(Element, null);
if (_gestureDetector != null)
{
_gestureDetector.Dispose();
_gestureDetector = null;
}
_handler = null;
}
}

void UpdateInputTransparent()
{
if (Element != null && _gestureDetector != null)
{
_gestureDetector.InputTransparent = Element.InputTransparent;
}
}

void UpdateIsEnabled()
{
if (Element != null && _gestureDetector != null)
{
_gestureDetector.IsEnabled = Element.IsEnabled;
}
}

void OnGestureRecognizerCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
{
if (_gestureDetector == null)
{
_gestureDetector = new GestureDetector(_handler);
}

// Gestures will be registered/unregistered according to changes in the GestureRecognizers list
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
_gestureDetector.AddGestures(e.NewItems?.OfType<IGestureRecognizer>());
break;

case NotifyCollectionChangedAction.Replace:
_gestureDetector.RemoveGestures(e.OldItems?.OfType<IGestureRecognizer>());
_gestureDetector.AddGestures(e.NewItems?.OfType<IGestureRecognizer>());
break;

case NotifyCollectionChangedAction.Remove:
_gestureDetector.RemoveGestures(e.OldItems?.OfType<IGestureRecognizer>());
break;

case NotifyCollectionChangedAction.Reset:
_gestureDetector.Clear();
break;
}
}
}
}
243 changes: 243 additions & 0 deletions src/Controls/src/Core/Platform/Tizen/DragGestureHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,243 @@
using System;
using System.Threading.Tasks;
using ElmSharp;
using Microsoft.Maui.Controls.Internals;
using Tizen.UIExtensions.ElmSharp;
using EGestureType = ElmSharp.GestureLayer.GestureType;
using TImage = Tizen.UIExtensions.ElmSharp.Image;
using TLabel = Tizen.UIExtensions.ElmSharp.Label;

namespace Microsoft.Maui.Controls.Platform
{
public class DragGestureHandler : GestureHandler
{
DragDropExtensions.Interop.DragIconCreateCallback _iconCallback;
DragDropExtensions.Interop.DragStateCallback _dragDoneCallback;

static bool s_isDragging;
static CustomDragStateData s_currentDragStateData;

protected virtual IView Element => Handler?.VirtualView as IView;

public DragGestureHandler(IGestureRecognizer recognizer, IViewHandler handler) : base(recognizer)
{
_iconCallback = OnIconCallback;
_dragDoneCallback = OnDragDoneCallback;
Handler = handler;
}

public override EGestureType Type => EGestureType.LongTap;

public IViewHandler Handler { get; }

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

EvasObject NativeView
{
get
{
return Handler.NativeView as EvasObject;
}
}

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 (Handler == null)
return;

var arg = dragGestureRecognizer.SendDragStarting(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 = GetImageIconAsync(parent).Result;
}
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 TLabel)
{
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 TLabel(parent);
label.Text = s_currentDragStateData.DataPackage.Text;

if (Element is IFontElement fe)
label.FontSize = fe.FontSize;

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

async Task<EvasObject> GetImageIconAsync(EvasObject parent)
{
var image = new TImage(parent);
var mImage = s_currentDragStateData.DataPackage.Image;
var services = Handler.MauiContext?.Services;
var provider = services.GetService(typeof(IImageSourceServiceProvider)) as IImageSourceServiceProvider;
var service = provider?.GetImageSourceService(mImage);
var result = await service.LoadImageAsync(mImage, image);
if (result == null)
return null;
return image;
}

EvasObject GetShapeView(EvasObject parent)
{
var copiedImg = new EvasImage(parent)
{
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;
}
}
}
Loading

0 comments on commit 8297e5b

Please sign in to comment.