Fix build break on Net45
[platform/core/csapi/tizenfx.git] / src / ElmSharp / ElmSharp / GestureLayer.cs
1 using System;
2 using System.Runtime.InteropServices;
3 using System.Collections.Generic;
4
5 namespace ElmSharp
6 {
7     public class GestureLayer : EvasObject
8     {
9         private readonly Interop.Elementary.GestureEventCallback _gestureCallback;
10
11         // Important: don't remove items from _handlers list
12         // The list can grow up to (number of GestureType) * (number of GestureState)
13         // but all gestures share the callback and you don't want to desynchronize mapping
14         private readonly List<NativeCallback> _handlers = new List<NativeCallback>();
15
16         public GestureLayer(EvasObject parent) : base(parent)
17         {
18             _gestureCallback = new Interop.Elementary.GestureEventCallback(GestureCallbackHandler);
19         }
20
21         public enum GestureType
22         {
23             Tap = 1,
24             LongTap,
25             DoubleTap,
26             TripleTap,
27             Momentum,
28             Line,
29             Flick,
30             Zoom,
31             Rotate,
32         }
33
34         public enum GestureState
35         {
36             Undefined = -1,
37             Start,
38             Move,
39             End,
40             Abort,
41         }
42
43         #region Properties
44         public bool HoldEvents
45         {
46             get
47             {
48                 return Interop.Elementary.elm_gesture_layer_hold_events_get(Handle);
49             }
50             set
51             {
52                 Interop.Elementary.elm_gesture_layer_hold_events_set(Handle, value);
53             }
54         }
55
56         public bool Continues
57         {
58             get
59             {
60                 return Interop.Elementary.elm_gesture_layer_continues_enable_get(Handle);
61             }
62             set
63             {
64                 Interop.Elementary.elm_gesture_layer_continues_enable_set(Handle, value);
65             }
66         }
67
68         public int TapFingerSize
69         {
70             get
71             {
72                 return Interop.Elementary.elm_gesture_layer_tap_finger_size_get(Handle);
73             }
74             set
75             {
76                 Interop.Elementary.elm_gesture_layer_tap_finger_size_set(Handle, value);
77             }
78         }
79
80         public double LongTapTimeout
81         {
82             get
83             {
84                 return Interop.Elementary.elm_gesture_layer_long_tap_start_timeout_get(Handle);
85             }
86             set
87             {
88                 Interop.Elementary.elm_gesture_layer_long_tap_start_timeout_set(Handle, value);
89             }
90         }
91
92         public double DoubleTapTimeout
93         {
94             get
95             {
96                 return Interop.Elementary.elm_gesture_layer_double_tap_timeout_get(Handle);
97             }
98             set
99             {
100                 Interop.Elementary.elm_gesture_layer_double_tap_timeout_set(Handle, value);
101             }
102         }
103
104         public int FlickTimeLimit
105         {
106             get
107             {
108                 return (int)Interop.Elementary.elm_gesture_layer_flick_time_limit_ms_get(Handle);
109             }
110             set
111             {
112                 Interop.Elementary.elm_gesture_layer_flick_time_limit_ms_set(Handle, (UInt32)value);
113             }
114         }
115
116         public int MinimumLineLength
117         {
118             get
119             {
120                 return Interop.Elementary.elm_gesture_layer_line_min_length_get(Handle);
121             }
122             set
123             {
124                 Interop.Elementary.elm_gesture_layer_line_min_length_set(Handle, value);
125             }
126         }
127
128         public double LineAngularTolerance
129         {
130             get
131             {
132                 return Interop.Elementary.elm_gesture_layer_line_angular_tolerance_get(Handle);
133             }
134             set
135             {
136                 Interop.Elementary.elm_gesture_layer_line_angular_tolerance_set(Handle, value);
137             }
138         }
139
140         public int LineDistanceTolerance
141         {
142             get
143             {
144                 return Interop.Elementary.elm_gesture_layer_line_distance_tolerance_get(Handle);
145             }
146             set
147             {
148                 Interop.Elementary.elm_gesture_layer_line_distance_tolerance_set(Handle, value);
149             }
150         }
151
152         public double RotateStep
153         {
154             get
155             {
156                 return Interop.Elementary.elm_gesture_layer_rotate_step_get(Handle);
157             }
158             set
159             {
160                 Interop.Elementary.elm_gesture_layer_rotate_step_set(Handle, value);
161             }
162         }
163
164         public double RotateAngularTolerance
165         {
166             get
167             {
168                 return Interop.Elementary.elm_gesture_layer_rotate_angular_tolerance_get(Handle);
169             }
170             set
171             {
172                 Interop.Elementary.elm_gesture_layer_rotate_angular_tolerance_set(Handle, value);
173             }
174         }
175
176         public double ZoomStep
177         {
178             get
179             {
180                 return Interop.Elementary.elm_gesture_layer_zoom_step_get(Handle);
181             }
182             set
183             {
184                 Interop.Elementary.elm_gesture_layer_zoom_step_set(Handle, value);
185             }
186         }
187
188         public int ZoomDistanceTolerance
189         {
190             get
191             {
192                 return Interop.Elementary.elm_gesture_layer_zoom_distance_tolerance_get(Handle);
193             }
194             set
195             {
196                 Interop.Elementary.elm_gesture_layer_zoom_distance_tolerance_set(Handle, value);
197             }
198         }
199
200         public double ZoomFingerFactor
201         {
202             get
203             {
204                 return Interop.Elementary.elm_gesture_layer_zoom_finger_factor_get(Handle);
205             }
206             set
207             {
208                 Interop.Elementary.elm_gesture_layer_zoom_finger_factor_set(Handle, value);
209             }
210         }
211
212         public double ZoomWheelFactor
213         {
214             get
215             {
216                 return Interop.Elementary.elm_gesture_layer_zoom_wheel_factor_get(Handle);
217             }
218             set
219             {
220                 Interop.Elementary.elm_gesture_layer_zoom_wheel_factor_set(Handle, value);
221             }
222         }
223         #endregion Properties
224
225         public void Attach(EvasObject target)
226         {
227             Interop.Elementary.elm_gesture_layer_attach(Handle, target.Handle);
228         }
229
230         public void SetGestureCallback(GestureType type, GestureState state, Action<object> action)
231         {
232             lock (_handlers)
233             {
234                 bool found = false;
235                 int i = 0;
236                 // if this (type, state) already exists in _handlers, we will reuse it
237                 foreach (var handler in _handlers)
238                 {
239                     if (handler.Type == type && handler.State == state)
240                     {
241                         found = true;
242                         break;
243                     }
244                     i++;
245                 }
246                 if (found)
247                 {
248                     // if we are changing null -> not-null, or not-null -> null, then inform the EFL
249                     if (_handlers[i].Action == null ^ action == null)
250                         Interop.Elementary.elm_gesture_layer_cb_set(Handle, type, state, action == null ? null : _gestureCallback, new IntPtr(i));
251                     // overwrite previous action
252                     _handlers[i].Action = action;
253                 }
254                 else
255                 {
256                     if (action == null)
257                     {
258                         // ignore unsetting a handler for event which was not registered yet?
259                         return;
260                     }
261                     // (type, state) was not found, so we are adding a new entry and registering the callback
262                     _handlers.Add(new NativeCallback(type, state, action));
263                     // callback is always the same, the event is recognised by the index in _handler list (the index is passed as data)
264                     Interop.Elementary.elm_gesture_layer_cb_set(Handle, type, state, _gestureCallback, new IntPtr(i));
265                 }
266             }
267         }
268
269         public void ClearCallbacks()
270         {
271             lock (_handlers)
272             {
273                 int i = 0;
274                 foreach (var handler in _handlers)
275                 {
276                     if (handler.Action != null)
277                     {
278                         Interop.Elementary.elm_gesture_layer_cb_set(Handle, handler.Type, handler.State, null, new IntPtr(i));
279                         handler.Action = null;
280                     }
281                     i++;
282                 }
283             }
284         }
285
286         #region Typed callback setting methods
287         // Following methods have been added for convenience, so the user will not have to convert Info structures himself
288         public void SetTapCallback(GestureType type, GestureState state, Action<TapData> action)
289         {
290             SetCallback(type, state, action);
291         }
292
293         public void SetMomentumCallback(GestureState state, Action<MomentumData> action)
294         {
295             SetCallback(GestureType.Momentum, state, action);
296         }
297
298         public void SetLineCallback(GestureState state, Action<LineData> action)
299         {
300             SetCallback(GestureType.Line, state, action);
301         }
302
303         public void SetFlickCallback(GestureState state, Action<LineData> action)
304         {
305             SetCallback(GestureType.Flick, state, action);
306         }
307
308         public void SetZoomCallback(GestureState state, Action<ZoomData> action)
309         {
310             SetCallback(GestureType.Zoom, state, action);
311         }
312
313         public void SetRotateCallback(GestureState state, Action<RotateData> action)
314         {
315             SetCallback(GestureType.Rotate, state, action);
316         }
317         #endregion Typed callback setting methods
318
319         protected override IntPtr CreateHandle(EvasObject parent)
320         {
321             return Interop.Elementary.elm_gesture_layer_add(parent);
322         }
323
324         protected override void OnUnrealize()
325         {
326             ClearCallbacks();
327             base.OnUnrealize();
328         }
329
330         private void SetCallback<T>(GestureType type, GestureState state, Action<T> action)
331         {
332             if (action == null)
333                 SetGestureCallback(type, state, null);
334             else
335                 SetGestureCallback(type, state, new Action<object>((info) => action((T)info)));
336         }
337
338         private void GestureCallbackHandler(IntPtr data, IntPtr event_info)
339         {
340             // so EFL called our callback, lets use data to find the right Action to call
341             var handlerIndex = (int)data;
342             // thanks to the fact that we never remove item from _handlers, we don't need a lock here
343             if (handlerIndex < 0 || handlerIndex >= _handlers.Count)
344                 return;
345             Action<object> action = _handlers[handlerIndex].Action;
346             if (action == null)
347                 return;
348             // the interpretation of the event_info struct pointer depends on the GestureType
349             switch (_handlers[handlerIndex].Type)
350             {
351                 case GestureType.Tap:
352                 case GestureType.LongTap:
353                 case GestureType.DoubleTap:
354                 case GestureType.TripleTap:
355                     action(Marshal.PtrToStructure(event_info, typeof(TapData)));
356                     break;
357                 case GestureType.Momentum:
358                     action(Marshal.PtrToStructure(event_info, typeof(MomentumData)));
359                     break;
360                 case GestureType.Line:
361                 case GestureType.Flick:
362                     action(Marshal.PtrToStructure(event_info, typeof(LineData)));
363                     break;
364                 case GestureType.Zoom:
365                     action(Marshal.PtrToStructure(event_info, typeof(ZoomData)));
366                     break;
367                 case GestureType.Rotate:
368                     action(Marshal.PtrToStructure(event_info, typeof(RotateData)));
369                     break;
370             }
371         }
372
373         #region Info structures
374
375         [StructLayout(LayoutKind.Sequential)]
376         public struct TapData
377         {
378             /// <summary>
379             /// The x coordinate of the center point.
380             /// </summary>
381             public Int32 X;
382
383             /// <summary>
384             /// The y coordinate of the center point.
385             /// </summary>
386             public Int32 Y;
387
388             #pragma warning disable 3003
389             /// <summary>
390             /// The number of fingers tapped.
391             /// </summary>
392             public UInt32 FingersCount;
393
394             /// <summary>
395             /// The timestamp.
396             /// </summary>
397             public UInt32 Timestamp;
398             #pragma warning restore 3003
399         }
400
401         [StructLayout(LayoutKind.Sequential)]
402         public struct MomentumData
403         {
404             /// <summary>
405             /// Final-swipe direction starting point on X.
406             /// </summary>
407             public Int32 X1;
408
409             /// <summary>
410             /// Final-swipe direction starting point on Y.
411             /// </summary>
412             public Int32 Y1;
413
414             /// <summary>
415             /// Final-swipe direction ending point on X.
416             /// </summary>
417             public Int32 X2;
418
419             /// <summary>
420             /// Final-swipe direction ending point on Y
421             /// </summary>
422             public Int32 Y2;
423
424             #pragma warning disable 3003
425             /// <summary>
426             /// Timestamp of start of final x-swipe.
427             /// </summary>
428             public UInt32 HorizontalSwipeTimestamp;
429
430             /// <summary>
431             /// Timestamp of start of final y-swipe.
432             /// </summary>
433             public UInt32 VerticalSwipeTimestamp;
434
435             /// <summary>
436             /// Momentum on X.
437             /// </summary>
438             public Int32 HorizontalMomentum;
439
440             /// <summary>
441             /// Momentum on Y.
442             /// </summary>
443             public Int32 VerticalMomentum;
444
445             /// <summary>
446             /// Number of fingers.
447             /// </summary>
448             public UInt32 FingersCount;
449             #pragma warning restore 3003
450         }
451
452         [StructLayout(LayoutKind.Sequential)]
453         public struct LineData
454         {
455             /// <summary>
456             /// Final-swipe direction starting point on X.
457             /// </summary>
458             public Int32 X1;
459
460             /// <summary>
461             /// Final-swipe direction starting point on Y.
462             /// </summary>
463             public Int32 Y1;
464
465             /// <summary>
466             /// Final-swipe direction ending point on X.
467             /// </summary>
468             public Int32 X2;
469
470             /// <summary>
471             /// Final-swipe direction ending point on Y
472             /// </summary>
473             public Int32 Y2;
474
475             #pragma warning disable 3003
476             /// <summary>
477             /// Timestamp of start of final x-swipe.
478             /// </summary>
479             public UInt32 HorizontalSwipeTimestamp;
480
481             /// <summary>
482             /// Timestamp of start of final y-swipe.
483             /// </summary>
484             public UInt32 VerticalSwipeTimestamp;
485
486             /// <summary>
487             /// Momentum on X.
488             /// </summary>
489             public Int32 HorizontalMomentum;
490
491             /// <summary>
492             /// Momentum on Y.
493             /// </summary>
494             public Int32 VerticalMomentum;
495
496             /// <summary>
497             /// Number of fingers.
498             /// </summary>
499             public UInt32 FingersCount;
500             #pragma warning restore 3003
501
502             /// <summary>
503             /// Angle (direction) of lines.
504             /// </summary>
505             public double Angle;
506         }
507
508         [StructLayout(LayoutKind.Sequential)]
509         public struct ZoomData
510         {
511             /// <summary>
512             /// The x coordinate of zoom center point reported to user.
513             /// </summary>
514             public Int32 X;
515
516             /// <summary>
517             /// The y coordinate of zoom center point reported to user.
518             /// </summary>
519             public Int32 Y;
520
521             /// <summary>
522             /// The radius (distance) between fingers reported to user.
523             /// </summary>
524             public Int32 Radius;
525
526             /// <summary>
527             /// The zoom value. 1.0 means no zoom.
528             /// </summary>
529             public double Zoom;
530
531             /// <summary>
532             /// Zoom momentum: zoom growth per second (NOT YET SUPPORTED).
533             /// </summary>
534             private double Momentum;
535         }
536
537         [StructLayout(LayoutKind.Sequential)]
538         public struct RotateData
539         {
540             /// <summary>
541             /// The x coordinate of rotation center point reported to user.
542             /// </summary>
543             public Int32 X;
544
545             /// <summary>
546             /// The y coordinate of rotation center point reported to user.
547             /// </summary>
548             public Int32 Y;
549
550             /// <summary>
551             /// The radius (distance) between fingers reported to user.
552             /// </summary>
553             public Int32 Radius;
554
555             /// <summary>
556             /// The start-angle.
557             /// </summary>
558             public double BaseAngle;
559
560             /// <summary>
561             /// The rotation value. 0.0 means no rotation.
562             /// </summary>
563             public double Angle;
564
565             /// <summary>
566             /// Rotation momentum: rotation done per second (NOT YET SUPPORTED).
567             /// </summary>
568             private double Momentum;
569         }
570
571         #endregion Info structures
572
573         public static class Config
574         {
575             public static double DefaultLongTapTimeout
576             {
577                 get {
578                     return Interop.Elementary.elm_config_glayer_long_tap_start_timeout_get();
579                 }
580                 set {
581                     Interop.Elementary.elm_config_glayer_long_tap_start_timeout_set(value);
582                 }
583             }
584
585             public static double DefaultDoubleTapTimeout
586             {
587                 get {
588                     return Interop.Elementary.elm_config_glayer_double_tap_timeout_get();
589                 }
590                 set {
591                     Interop.Elementary.elm_config_glayer_double_tap_timeout_set(value);
592                 }
593             }
594         }
595
596         private class NativeCallback
597         {
598             public readonly GestureType Type;
599             public readonly GestureState State;
600             public Action<object> Action;
601
602             public NativeCallback(GestureType type, GestureState state, Action<object> action)
603             {
604                 Type = type;
605                 State = state;
606                 Action = action;
607             }
608         }
609     }
610 }