[NUI] Add multi-mimetype feature for Drag and Drop (#6294)
authorTaehyub Kim <taehyub.kim@samsung.com>
Wed, 11 Sep 2024 04:22:01 +0000 (13:22 +0900)
committerTaehyub Kim <taehyub.kim@samsung.com>
Wed, 11 Sep 2024 11:20:30 +0000 (20:20 +0900)
* [NUI] Add multi-mimetype feature for Drag and Drop
Contents
- Allow to set multi-mimetypes for source client (use DragInfo)
- Target client receive source's mimetypes from source client when Enter, Move, Leave
- Target client can set mimetype to receive - Refactoring code for readability
- Refactoring codes for readability

* Refactoring data structure and duplicated codes

* Apply clean code for Drag and Drop

src/Tizen.NUI/src/internal/Interop/Interop.DragAndDrop.cs
src/Tizen.NUI/src/public/DragAndDrop/DragAndDrop.cs
src/Tizen.NUI/src/public/DragAndDrop/DragEvent.cs
test/NUIDnDMultiWindow/NUIDnDMultiWindow.cs
test/NUIDnDSource/NUIDnDSource.cs

index 1acf55699bede35b23fbbfd4fd77782096907851..278ea1b2fed164907cd5426ad25d55255995b64c 100755 (executable)
@@ -33,11 +33,11 @@ namespace Tizen.NUI
             public static extern global::System.IntPtr New();
 
             [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_DragAndDrop_StartDragAndDrop")]
-            public static extern bool StartDragAndDrop(global::System.Runtime.InteropServices.HandleRef dragAndDrop, global::System.Runtime.InteropServices.HandleRef sourceView, global::System.Runtime.InteropServices.HandleRef shadow, string mimeType, string data, global::System.Runtime.InteropServices.HandleRef callback);
+            public static extern bool StartDragAndDrop(global::System.Runtime.InteropServices.HandleRef dragAndDrop, global::System.Runtime.InteropServices.HandleRef sourceView, global::System.Runtime.InteropServices.HandleRef shadow, string [] mimeTypes, int mimeTypsSize, string [] dataSet, int dataSetSize, global::System.Runtime.InteropServices.HandleRef callback);
 
             [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_DragAndDrop_AddListener")]
             [return: global::System.Runtime.InteropServices.MarshalAs(global::System.Runtime.InteropServices.UnmanagedType.U1)]
-            public static extern bool AddListener(global::System.Runtime.InteropServices.HandleRef dragAndDrop, global::System.Runtime.InteropServices.HandleRef targetView, global::System.Runtime.InteropServices.HandleRef callback);
+            public static extern bool AddListener(global::System.Runtime.InteropServices.HandleRef dragAndDrop, global::System.Runtime.InteropServices.HandleRef targetView, string mimeType, global::System.Runtime.InteropServices.HandleRef callback);
 
             [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_DragAndDrop_RemoveListener")]
             [return: global::System.Runtime.InteropServices.MarshalAs(global::System.Runtime.InteropServices.UnmanagedType.U1)]
@@ -45,7 +45,7 @@ namespace Tizen.NUI
 
             [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_DragAndDrop_Window_AddListener")]
             [return: global::System.Runtime.InteropServices.MarshalAs(global::System.Runtime.InteropServices.UnmanagedType.U1)]
-            public static extern bool WindowAddListener(global::System.Runtime.InteropServices.HandleRef dragAndDrop, global::System.Runtime.InteropServices.HandleRef targetWindow, global::System.Runtime.InteropServices.HandleRef callback);
+            public static extern bool WindowAddListener(global::System.Runtime.InteropServices.HandleRef dragAndDrop, global::System.Runtime.InteropServices.HandleRef targetWindow, string mimeType, global::System.Runtime.InteropServices.HandleRef callback);
 
             [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_DragAndDrop_Window_RemoveListener")]
             [return: global::System.Runtime.InteropServices.MarshalAs(global::System.Runtime.InteropServices.UnmanagedType.U1)]
@@ -57,8 +57,8 @@ namespace Tizen.NUI
             [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_DragEvent_GetPosition")]
             public static extern global::System.IntPtr GetPosition(global::System.IntPtr dragAndDrop);
 
-            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_DragEvent_GetMimeType")]
-            public static extern string GetMimeType(global::System.IntPtr dragAndDrop);
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_DragEvent_GetMimeTypes")]
+            public static extern bool GetMimeTypes(global::System.IntPtr dragAndDrop, out global::System.IntPtr mimeTypes, out int count);
 
             [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_DragEvent_GetData")]
             public static extern string GetData(global::System.IntPtr dragAndDrop);
index b37a11c2afc8d0fb313f7074bc59ec1e0cc99a70..c0d9120baaf41a917cbeec4a207db88afa073379 100755 (executable)
@@ -18,6 +18,7 @@ using System;
 using System.ComponentModel;
 using System.Runtime.InteropServices;
 using System.Collections.Generic;
+using System.Linq;
 using System.Diagnostics.CodeAnalysis;
 using Tizen.NUI.BaseComponents;
 
@@ -32,10 +33,10 @@ namespace Tizen.NUI
     {
         public delegate void SourceEventHandler(DragSourceEventType sourceEventType);
         private delegate void InternalSourceEventHandler(int sourceEventType);
-        public delegate void DragAndDropEventHandler(View targetView, DragEvent dragEvent);
+        public delegate void DragAndDropEventHandler(View targetView, DragEvent navtiveDragEvent);
         [EditorBrowsable(EditorBrowsableState.Never)]
-        public delegate void DragAndDropWindowEventHandler(Window targetWindow, DragEvent dragEvent);
-        private delegate void InternalDragAndDropEventHandler(global::System.IntPtr dragEvent);
+        public delegate void DragAndDropWindowEventHandler(Window targetWindow, DragEvent navtiveDragEvent);
+        private delegate void InternalDragAndDropEventHandler(global::System.IntPtr navtiveDragEvent);
         private InternalSourceEventHandler sourceEventCb;
         private Dictionary<View, InternalDragAndDropEventHandler> targetEventDictionary = new Dictionary<View, InternalDragAndDropEventHandler>();
         private Dictionary<Window, InternalDragAndDropEventHandler> targetWindowEventDictionary = new Dictionary<Window, InternalDragAndDropEventHandler>();
@@ -46,11 +47,107 @@ namespace Tizen.NUI
         private int dragWindowOffsetX = 0;
         private int dragWindowOffsetY = 0;
 
-        private bool initDrag = false;
-
         private const int MinDragWindowWidth = 100;
         private const int MinDragWindowHeight = 100;
 
+        private void ProcessDragEventTargetCallback(IntPtr navtiveDragEvent, View targetView, DragAndDropEventHandler callback)
+        {
+            DragType type = (DragType)Interop.DragAndDrop.GetAction(navtiveDragEvent);
+            DragEvent dragEvent = new DragEvent();
+            global::System.IntPtr cPtr = Interop.DragAndDrop.GetPosition(navtiveDragEvent);
+            dragEvent.Position = (cPtr == global::System.IntPtr.Zero) ? null : new Position(cPtr, true);
+
+            IntPtr nativeMimeTypes;
+            int count;
+            Interop.DragAndDrop.GetMimeTypes(navtiveDragEvent, out nativeMimeTypes, out count);
+            if (count > 0)
+            {
+                IntPtr [] nativeMimeTypesArrary = new IntPtr[count];
+                Marshal.Copy(nativeMimeTypes, nativeMimeTypesArrary, 0, count);
+
+                string [] managedMimeTypes = new string[count];
+
+                for (int iterator = 0; iterator < count; iterator++)
+                {
+                managedMimeTypes[iterator] = Marshal.PtrToStringAnsi(nativeMimeTypesArrary[iterator]);
+                }
+
+                dragEvent.MimeType = managedMimeTypes[0];
+                dragEvent.MimeTypes = managedMimeTypes;
+            }
+
+            if (type == DragType.Enter)
+            {
+                dragEvent.DragType = type;
+                callback(targetView, dragEvent);
+            }
+            else if (type == DragType.Leave)
+            {
+                dragEvent.DragType = type;
+                callback(targetView, dragEvent);
+            }
+            else if (type == DragType.Move)
+            {
+                dragEvent.DragType = type;
+                callback(targetView, dragEvent);
+            }
+            else if (type == DragType.Drop)
+            {
+                dragEvent.DragType = type;
+                dragEvent.Data = Interop.DragAndDrop.GetData(navtiveDragEvent);
+                callback(targetView, dragEvent);
+            }
+        }
+
+        private void ProcessDragEventWindowCallback(IntPtr navtiveDragEvent, Window targetWindow, DragAndDropWindowEventHandler callback)
+        {
+            DragType type = (DragType)Interop.DragAndDrop.GetAction(navtiveDragEvent);
+            DragEvent dragEvent = new DragEvent();
+            global::System.IntPtr cPtr = Interop.DragAndDrop.GetPosition(navtiveDragEvent);
+            dragEvent.Position = (cPtr == global::System.IntPtr.Zero) ? null : new Position(cPtr, false);
+
+            IntPtr nativeMimeTypes;
+            int count;
+            Interop.DragAndDrop.GetMimeTypes(navtiveDragEvent, out nativeMimeTypes, out count);
+            if (count > 0)
+            {
+                IntPtr [] nativeMimeTypesArrary = new IntPtr[count];
+                Marshal.Copy(nativeMimeTypes, nativeMimeTypesArrary, 0, count);
+
+                string [] managedMimeTypes = new string[count];
+
+                for (int iterator = 0; iterator < count; iterator++)
+                {
+                managedMimeTypes[iterator] = Marshal.PtrToStringAnsi(nativeMimeTypesArrary[iterator]);
+                }
+
+                dragEvent.MimeType = managedMimeTypes[0];
+                dragEvent.MimeTypes = managedMimeTypes;
+            }
+
+            if (type == DragType.Enter)
+            {
+                dragEvent.DragType = type;
+                callback(targetWindow, dragEvent);
+            }
+            else if (type == DragType.Leave)
+            {
+                dragEvent.DragType = type;
+                callback(targetWindow, dragEvent);
+            }
+            else if (type == DragType.Move)
+            {
+                dragEvent.DragType = type;
+                callback(targetWindow, dragEvent);
+            }
+            else if (type == DragType.Drop)
+            {
+                dragEvent.DragType = type;
+                dragEvent.Data = Interop.DragAndDrop.GetData(navtiveDragEvent);
+                callback(targetWindow, dragEvent);
+            }
+        }
+
         private DragAndDrop() : this(Interop.DragAndDrop.New(), true)
         {
             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
@@ -92,14 +189,7 @@ namespace Tizen.NUI
         /// <param name="callback">The source event callback</param>
         /// <since_tizen> 10 </since_tizen>
         public void StartDragAndDrop(View sourceView, View shadowView, DragData dragData, SourceEventHandler callback)
-        {            
-            if (initDrag)
-            {
-                 Tizen.Log.Fatal("NUI", "Start Drag And Drop Initializing...");
-                 return;
-            }
-            initDrag = true;
-
+        {
             if (Window.IsSupportedMultiWindow() == false)
             {
                 throw new NotSupportedException("This device does not support surfaceless_context. So Window cannot be created.");
@@ -155,7 +245,7 @@ namespace Tizen.NUI
                 {   
                     if ((DragSourceEventType)sourceEventType != DragSourceEventType.Start)
                     {     
-                        Tizen.Log.Fatal("NUI", "DnD Source Event is Called");  
+                        Tizen.Log.Fatal("NUI", "DnD Source Event is Called");
                         ReleaseDragWindow();                
                     }
 
@@ -165,15 +255,29 @@ namespace Tizen.NUI
                 //Show Drag Window before StartDragAndDrop
                 mDragWindow.Show();
 
-                if (!Interop.DragAndDrop.StartDragAndDrop(SwigCPtr, View.getCPtr(sourceView), Window.getCPtr(mDragWindow), dragData.MimeType, dragData.Data,
+                string [] mimeTypes;
+                string [] dataSet;
+
+                if (string.IsNullOrEmpty(dragData.MimeType) && dragData.DataMap != null)
+                {
+                    mimeTypes = dragData.DataMap.Keys.ToArray();
+                    dataSet = dragData.DataMap.Values.ToArray();
+                }
+                else
+                {
+                    mimeTypes = new string[1];
+                    mimeTypes[0] = dragData.MimeType;
+
+                    dataSet = new string[1];
+                    dataSet[0] = dragData.Data;
+                }
+
+                if (!Interop.DragAndDrop.StartDragAndDrop(SwigCPtr, View.getCPtr(sourceView), Window.getCPtr(mDragWindow), mimeTypes, mimeTypes.Length, dataSet, dataSet.Length,
                                                         new global::System.Runtime.InteropServices.HandleRef(this, Marshal.GetFunctionPointerForDelegate<Delegate>(sourceEventCb))))
                 {
                     throw new InvalidOperationException("Fail to StartDragAndDrop");
                 }
-
-            }         
-            
-            initDrag = false;
+            }
         }
 
         /// <summary>
@@ -184,42 +288,23 @@ namespace Tizen.NUI
         /// <since_tizen> 10 </since_tizen>
         public void AddListener(View targetView, DragAndDropEventHandler callback)
         {
-            InternalDragAndDropEventHandler cb = (dragEvent) =>
-            {
-                DragType type = (DragType)Interop.DragAndDrop.GetAction(dragEvent);
-                DragEvent ev = new DragEvent();
-                global::System.IntPtr cPtr = Interop.DragAndDrop.GetPosition(dragEvent);
-                ev.Position = (cPtr == global::System.IntPtr.Zero) ? null : new Position(cPtr, true);
+            AddListener(targetView, "*/*", callback);
+        }
 
-                if (type == DragType.Enter)
-                {
-                    ev.DragType = type;
-                    ev.MimeType = Interop.DragAndDrop.GetMimeType(dragEvent);
-                    callback(targetView, ev);
-                }
-                else if (type == DragType.Leave)
-                {
-                    ev.DragType = type;
-                    callback(targetView, ev);
-                }
-                else if (type == DragType.Move)
-                {
-                    ev.DragType = type;
-                    ev.MimeType = Interop.DragAndDrop.GetMimeType(dragEvent);
-                    callback(targetView, ev);
-                }
-                else if (type == DragType.Drop)
-                {
-                    ev.DragType = type;
-                    ev.MimeType = Interop.DragAndDrop.GetMimeType(dragEvent);
-                    ev.Data = Interop.DragAndDrop.GetData(dragEvent);
-                    callback(targetView, ev);
-                }
-            };
+        /// <summary>
+        /// Adds listener for drop targets
+        /// </summary>
+        /// <param name="targetView">The target view</param>
+        /// <param name="mimeType">The mime type for target view</param>
+        /// <param name="callback">The callback function to get drag event when the drag source enters, moves, leaves and drops on the drop target</param> 
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void AddListener(View targetView, string mimeType, DragAndDropEventHandler callback)
+        {
+            InternalDragAndDropEventHandler cb = (navtiveDragEvent) => ProcessDragEventTargetCallback(navtiveDragEvent, targetView, callback);
 
             targetEventDictionary.Add(targetView, cb);
 
-            if (!Interop.DragAndDrop.AddListener(SwigCPtr, View.getCPtr(targetView),
+            if (!Interop.DragAndDrop.AddListener(SwigCPtr, View.getCPtr(targetView), mimeType,
                                                  new global::System.Runtime.InteropServices.HandleRef(this, Marshal.GetFunctionPointerForDelegate<Delegate>(cb))))
             {
                  throw new InvalidOperationException("Fail to AddListener for View");
@@ -256,40 +341,23 @@ namespace Tizen.NUI
         [EditorBrowsable(EditorBrowsableState.Never)]
         public void AddListener(Window targetWindow, DragAndDropWindowEventHandler callback)
         {
-            InternalDragAndDropEventHandler cb = (dragEvent) =>
-            {
-                DragType type = (DragType)Interop.DragAndDrop.GetAction(dragEvent);
-                DragEvent ev = new DragEvent();
-                global::System.IntPtr cPtr = Interop.DragAndDrop.GetPosition(dragEvent);
-                ev.Position = (cPtr == global::System.IntPtr.Zero) ? null : new Position(cPtr, false);
+            AddListener(targetWindow, "*/*", callback);
+        }
 
-                if (type == DragType.Enter)
-                {
-                    ev.DragType = type;
-                    callback(targetWindow, ev);
-                }
-                else if (type == DragType.Leave)
-                {
-                    ev.DragType = type;
-                    callback(targetWindow, ev);
-                }
-                else if (type == DragType.Move)
-                {
-                    ev.DragType = type;
-                    callback(targetWindow, ev);
-                }
-                else if (type == DragType.Drop)
-                {
-                    ev.DragType = type;
-                    ev.MimeType = Interop.DragAndDrop.GetMimeType(dragEvent);
-                    ev.Data = Interop.DragAndDrop.GetData(dragEvent);
-                    callback(targetWindow, ev);
-                }
-            };
+        /// <summary>
+        /// Adds listener for drop targets
+        /// </summary>
+        /// <param name="targetWindow">The target Window</param>
+        /// <param name="mimeType">The mime type for target view</param>
+        /// <param name="callback">The callback function to get drag event when the drag source enters, moves, leaves and drops on the drop target</param>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void AddListener(Window targetWindow, string mimeType, DragAndDropWindowEventHandler callback)
+        {
+            InternalDragAndDropEventHandler cb = (navtiveDragEvent) => ProcessDragEventWindowCallback(navtiveDragEvent, targetWindow, callback);
 
             targetWindowEventDictionary.Add(targetWindow, cb);
 
-            if (!Interop.DragAndDrop.WindowAddListener(SwigCPtr, Window.getCPtr(targetWindow),
+            if (!Interop.DragAndDrop.WindowAddListener(SwigCPtr, Window.getCPtr(targetWindow), mimeType,
                                                        new global::System.Runtime.InteropServices.HandleRef(this, Marshal.GetFunctionPointerForDelegate<Delegate>(cb))))
             {
                  throw new InvalidOperationException("Fail to AddListener for Window");
index 6c705b90d3d45bc59aa516d6fcb9b7777881acd5..da4cc9ae183f54c8c5eca67f970b41f44f2292fc 100755 (executable)
@@ -16,6 +16,7 @@
  */
 using System;
 using System.ComponentModel;
+using System.Collections.Generic;
 using Tizen.NUI.Binding;
 
 namespace Tizen.NUI
@@ -60,6 +61,12 @@ namespace Tizen.NUI
         /// The drag data to send
         /// </summary>
         public string Data { get; set; }
+
+        /// <summary>
+        /// The mime types and drag data set
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public Dictionary<string, string> DataMap;
     }
 
     /// <summary>
@@ -106,6 +113,13 @@ namespace Tizen.NUI
         /// The mime type of drag object
         /// </summary>
         public string MimeType { get; set; }
+
+        /// <summary>
+        /// The mime types of drag object
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public string [] MimeTypes { get; set; }
+
         /// <summary>
         /// The drag data to receive
         /// </summary>
index 3d95b347b28c42e0e07e0b319f2697c38af12e48..dec31805f7853941f3c8271db8520f85d045da7b 100644 (file)
@@ -89,7 +89,7 @@ namespace NUIDnDMultiWindow
                 Tizen.Log.Debug("NUIDnDMultiWindow", "StartDragAndDrop");
                 shadowView = new ImageView(Tizen.Applications.Application.Current.DirectoryInfo.SharedResource + "dragsource.png");
                 shadowView.Size = new Size(150, 150);
-                DragData dragData;
+                DragData dragData = new DragData();
                 dragData.MimeType = "text/uri-list";
                 dragData.Data = Tizen.Applications.Application.Current.DirectoryInfo.SharedResource + "dragsource.png";
                 dnd.StartDragAndDrop(sourceView, shadowView, dragData, OnSourceApp_SourceFunc);
index 7bceebef55cb90bfe615235d0b8b986d0227da25..ae242037a8aef81eb393fce10dadf55ef1e9f237 100644 (file)
@@ -91,7 +91,7 @@ namespace NUIDnDSource
                 Tizen.Log.Debug("NUIDnDSource", "StartDragAndDrop");
                 shadowView = new ImageView(Tizen.Applications.Application.Current.DirectoryInfo.SharedResource + "dragsource.png");
                 shadowView.Size = new Size(150, 150);
-                DragData dragData;
+                DragData dragData = new DragData();
                 dragData.MimeType = "text/uri-list";
                 dragData.Data = Tizen.Applications.Application.Current.DirectoryInfo.SharedResource + "dragsource.png";
                 dnd.StartDragAndDrop(sourceView, shadowView, dragData, OnSourceEventFunc);