[NUI] Apply constant value for default drag window size
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI / src / public / DragAndDrop / DragAndDrop.cs
1 /*
2  * Copyright(c) 2022 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17 using System;
18 using System.ComponentModel;
19 using System.Runtime.InteropServices;
20 using System.Collections.Generic;
21 using System.Diagnostics.CodeAnalysis;
22 using Tizen.NUI.BaseComponents;
23
24 namespace Tizen.NUI
25 {
26     /// <summary>
27     /// DragAndDrop controls the drag object and data.
28     /// </summary>
29     /// <since_tizen> 10 </since_tizen>
30     [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000: Dispose objects before losing scope", Justification = "It does not have ownership.")]
31     public class DragAndDrop : BaseHandle
32     {
33         public delegate void SourceEventHandler(DragSourceEventType sourceEventType);
34         private delegate void InternalSourceEventHandler(int sourceEventType);
35         public delegate void DragAndDropEventHandler(View targetView, DragEvent dragEvent);
36         private delegate void InternalDragAndDropEventHandler(global::System.IntPtr dragEvent);
37         private InternalSourceEventHandler sourceEventCb;
38         private Dictionary<View, InternalDragAndDropEventHandler> targetEventDictionary = new Dictionary<View, InternalDragAndDropEventHandler>();
39         private View mShadowView;
40         private Window mDragWindow;
41         private int shadowWidth;
42         private int shadowHeight;
43
44         private bool initDrag = false;
45
46         private const int MinDragWindowWidth = 100;
47         private const int MinDragWindowHeight = 100;
48
49         private DragAndDrop() : this(Interop.DragAndDrop.New(), true)
50         {
51             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
52         }
53
54         private DragAndDrop(global::System.IntPtr cPtr, bool cMemoryOwn) : base(cPtr, cMemoryOwn)
55         {
56
57         }
58
59         private void ReleaseDragWindow()
60         {
61             if (mDragWindow)
62             {                        
63                 if (mShadowView)
64                 {
65                     //Application has Shadow View ownership, so DnD doesn't dispose Shadow View
66                     mDragWindow.Remove(mShadowView);
67                     mShadowView = null;
68                 }
69             
70                 mDragWindow.Dispose();
71                 mDragWindow = null;                      
72             }         
73         }
74
75         /// <summary>
76         /// Gets the singleton instance of DragAndDrop.
77         /// </summary>
78         /// <since_tizen> 10 </since_tizen>
79         public static DragAndDrop Instance { get; } = new DragAndDrop();
80
81         /// <summary>
82         /// Starts drag and drop.
83         /// </summary>
84         /// <param name="sourceView">The soruce view</param>
85         /// <param name="shadowView">The shadow view for drag object</param>
86         /// <param name="dragData">The data to send</param>
87         /// <param name="callback">The source event callback</param>
88         /// <since_tizen> 10 </since_tizen>
89         public void StartDragAndDrop(View sourceView, View shadowView, DragData dragData, SourceEventHandler callback)
90         {            
91             if (initDrag)
92             {
93                  Tizen.Log.Fatal("NUI", "Start Drag And Drop Initializing...");
94                  return;
95             }
96             initDrag = true;
97
98             if (Window.IsSupportedMultiWindow() == false)
99             {
100                 throw new NotSupportedException("This device does not support surfaceless_context. So Window cannot be created.");
101             }
102
103             if (null == shadowView)
104             {
105                 throw new ArgumentNullException(nameof(shadowView));
106             }
107
108             ReleaseDragWindow();
109
110             shadowWidth = (int)shadowView.Size.Width;
111             shadowHeight = (int)shadowView.Size.Height;
112
113             if (shadowView.Size.Width < MinDragWindowWidth)
114             {
115                 shadowWidth = MinDragWindowWidth;
116             }
117
118             if (shadowView.Size.Height < MinDragWindowHeight)
119             {
120                 shadowHeight = MinDragWindowHeight;
121             }
122
123             mDragWindow = new Window("DragWindow", new Rectangle(-shadowWidth, -shadowHeight, shadowWidth, shadowHeight), true)
124             {
125                 BackgroundColor = Color.Transparent,
126             };
127
128             if (mDragWindow)
129             {
130                 //Set Window Orientation Available
131                 List<Window.WindowOrientation> list = new List<Window.WindowOrientation>();
132                 list.Add(Window.WindowOrientation.Landscape);
133                 list.Add(Window.WindowOrientation.LandscapeInverse);
134                 list.Add(Window.WindowOrientation.NoOrientationPreference);
135                 list.Add(Window.WindowOrientation.Portrait);
136                 list.Add(Window.WindowOrientation.PortraitInverse);
137                 mDragWindow.SetAvailableOrientations(list);
138
139                 //Initialize Drag Window Size based on Shadow View Size,
140                 //Don't set Drag Window Posiiton, Window Server sets Position Internally
141                 mDragWindow.SetWindowSize(new Size(shadowWidth, shadowHeight));
142
143                 //Make Position 0, 0 for Moving into Drag Window
144                 shadowView.Position = new Position(0, 0);
145             
146                 mShadowView = shadowView;
147                 mDragWindow.Add(mShadowView);
148            
149                 sourceEventCb = (sourceEventType) =>
150                 {   
151                     if ((DragSourceEventType)sourceEventType != DragSourceEventType.Start)
152                     {     
153                         Tizen.Log.Fatal("NUI", "DnD Source Event is Called");  
154                         ReleaseDragWindow();                
155                     }
156
157                     callback((DragSourceEventType)sourceEventType);
158                 };
159
160                 //Show Drag Window before StartDragAndDrop
161                 mDragWindow.Show();
162
163                 if (!Interop.DragAndDrop.StartDragAndDrop(SwigCPtr, View.getCPtr(sourceView), Window.getCPtr(mDragWindow), dragData.MimeType, dragData.Data,
164                                                         new global::System.Runtime.InteropServices.HandleRef(this, Marshal.GetFunctionPointerForDelegate<Delegate>(sourceEventCb))))
165                 {
166                     throw new InvalidOperationException("Fail to StartDragAndDrop");
167                 }
168
169             }         
170             
171             initDrag = false;
172         }
173
174         /// <summary>
175         /// Adds listener for drop targets
176         /// </summary>
177         /// <param name="targetView">The target view</param>
178         /// <param name="callback">The callback function to get drag event when the drag source enters, moves, leaves and drops on the drop target</param>
179         /// <since_tizen> 10 </since_tizen>
180         public void AddListener(View targetView, DragAndDropEventHandler callback)
181         {
182             InternalDragAndDropEventHandler cb = (dragEvent) =>
183             {
184                 DragType type = (DragType)Interop.DragAndDrop.GetAction(dragEvent);
185                 DragEvent ev = new DragEvent();
186                 global::System.IntPtr cPtr = Interop.DragAndDrop.GetPosition(dragEvent);
187                 ev.Position = (cPtr == global::System.IntPtr.Zero) ? null : new Position(cPtr, false);
188
189                 if (type == DragType.Enter)
190                 {
191                     ev.DragType = type;
192                     callback(targetView, ev);
193                 }
194                 else if (type == DragType.Leave)
195                 {
196                     ev.DragType = type;
197                     callback(targetView, ev);
198                 }
199                 else if (type == DragType.Move)
200                 {
201                     ev.DragType = type;
202                     callback(targetView, ev);
203                 }
204                 else if (type == DragType.Drop)
205                 {
206                     ev.DragType = type;
207                     ev.MimeType = Interop.DragAndDrop.GetMimeType(dragEvent);
208                     ev.Data = Interop.DragAndDrop.GetData(dragEvent);
209                     callback(targetView, ev);
210                 }
211             };
212
213             targetEventDictionary.Add(targetView, cb);
214
215             if (!Interop.DragAndDrop.AddListener(SwigCPtr, View.getCPtr(targetView),
216                                                  new global::System.Runtime.InteropServices.HandleRef(this, Marshal.GetFunctionPointerForDelegate<Delegate>(cb))))
217             {
218                  throw new InvalidOperationException("Fail to AddListener");
219             }
220         }
221
222         /// <summary>
223         /// Removes listener for drop targets
224         /// </summary>
225         /// <param name="targetView">The target view</param>
226         /// <param name="callback">The callback function to remove</param>
227         /// <since_tizen> 10 </since_tizen>
228         public void RemoveListener(View targetView, DragAndDropEventHandler callback)
229         {
230             if (!targetEventDictionary.ContainsKey(targetView))
231             {
232                  throw new InvalidOperationException("Fail to RemoveListener");
233             }
234
235             InternalDragAndDropEventHandler cb = targetEventDictionary[targetView];
236             targetEventDictionary.Remove(targetView);
237             if (!Interop.DragAndDrop.RemoveListener(SwigCPtr, View.getCPtr(targetView),
238                                                     new global::System.Runtime.InteropServices.HandleRef(this, Marshal.GetFunctionPointerForDelegate<Delegate>(cb))))
239             {
240                  throw new InvalidOperationException("Fail to RemoveListener");
241             }
242         }
243     }
244 }