Add ElmSharp.GestureLayer class
authorPiotr Szydelko <p.szydelko@samsung.com>
Mon, 3 Oct 2016 11:33:35 +0000 (13:33 +0200)
committerPiotr Szydelko <p.szydelko@samsung.com>
Thu, 6 Oct 2016 10:16:09 +0000 (12:16 +0200)
Change-Id: I86d2736395a10a1da10e6fb860d06e3d77b73612

packaging/elm-sharp.spec
src/ElmSharp/ElmSharp.Net45.csproj
src/ElmSharp/ElmSharp.csproj
src/ElmSharp/ElmSharp/GestureLayer.cs [new file with mode: 0644]
src/ElmSharp/Interop/Interop.Elementary.GestureLayer.cs [new file with mode: 0644]
test/ElmSharp.Test/TC/GestureLayerTest1.cs [new file with mode: 0644]

index f4081d5..142470c 100644 (file)
@@ -8,7 +8,7 @@
 
 Name:       elm-sharp
 Summary:    C# Binding for Elementary
-Version:    1.0.5
+Version:    1.0.6
 Release:    1
 Group:      Development/Libraries
 License:    Apache-2.0
index f6d676e..ebea12d 100644 (file)
@@ -79,6 +79,7 @@
     <Compile Include="ElmSharp\GenItemClass.cs" />\r
     <Compile Include="ElmSharp\GenList.cs" />\r
     <Compile Include="ElmSharp\GenListItem.cs" />\r
+    <Compile Include="ElmSharp\GestureLayer.cs" />\r
     <Compile Include="ElmSharp\Icon.cs" />\r
     <Compile Include="ElmSharp\Image.cs" />\r
     <Compile Include="ElmSharp\Index.cs" />\r
     <Compile Include="Interop\Interop.Elementary.Entry.cs" />\r
     <Compile Include="Interop\Interop.Elementary.GenGridView.cs" />\r
     <Compile Include="Interop\Interop.Elementary.GenListView.cs" />\r
+    <Compile Include="Interop\Interop.Elementary.GestureLayer.cs" />\r
     <Compile Include="Interop\Interop.Elementary.Image.cs" />\r
     <Compile Include="Interop\Interop.Elementary.Index.cs" />\r
     <Compile Include="Interop\Interop.Elementary.Label.cs" />\r
index f5aabe1..bf21751 100644 (file)
@@ -76,6 +76,7 @@
     <Compile Include="ElmSharp\GenItemClass.cs" />\r
     <Compile Include="ElmSharp\GenList.cs" />\r
     <Compile Include="ElmSharp\GenListItem.cs" />\r
+    <Compile Include="ElmSharp\GestureLayer.cs" />\r
     <Compile Include="ElmSharp\Icon.cs" />\r
     <Compile Include="ElmSharp\Image.cs" />\r
     <Compile Include="ElmSharp\Index.cs" />\r
     <Compile Include="Interop\Interop.Elementary.Entry.cs" />\r
     <Compile Include="Interop\Interop.Elementary.GenGridView.cs" />\r
     <Compile Include="Interop\Interop.Elementary.GenListView.cs" />\r
+    <Compile Include="Interop\Interop.Elementary.GestureLayer.cs" />\r
     <Compile Include="Interop\Interop.Elementary.Image.cs" />\r
     <Compile Include="Interop\Interop.Elementary.Index.cs" />\r
     <Compile Include="Interop\Interop.Elementary.Label.cs" />\r
diff --git a/src/ElmSharp/ElmSharp/GestureLayer.cs b/src/ElmSharp/ElmSharp/GestureLayer.cs
new file mode 100644 (file)
index 0000000..24d3944
--- /dev/null
@@ -0,0 +1,610 @@
+using System;
+using System.Runtime.InteropServices;
+using System.Collections.Generic;
+
+namespace ElmSharp
+{
+    public class GestureLayer : EvasObject
+    {
+        private readonly Interop.Elementary.GestureEventCallback _gestureCallback;
+
+        // Important: don't remove items from _handlers list
+        // The list can grow up to (number of GestureType) * (number of GestureState)
+        // but all gestures share the callback and you don't want to desynchronize mapping
+        private readonly List<NativeCallback> _handlers = new List<NativeCallback>();
+
+        public GestureLayer(EvasObject parent) : base(parent)
+        {
+            _gestureCallback = new Interop.Elementary.GestureEventCallback(GestureCallbackHandler);
+        }
+
+        public enum GestureType
+        {
+            Tap = 1,
+            LongTap,
+            DoubleTap,
+            TripleTap,
+            Momentum,
+            Line,
+            Flick,
+            Zoom,
+            Rotate,
+        }
+
+        public enum GestureState
+        {
+            Undefined = -1,
+            Start,
+            Move,
+            End,
+            Abort,
+        }
+
+        #region Properties
+        public bool HoldEvents
+        {
+            get
+            {
+                return Interop.Elementary.elm_gesture_layer_hold_events_get(Handle);
+            }
+            set
+            {
+                Interop.Elementary.elm_gesture_layer_hold_events_set(Handle, value);
+            }
+        }
+
+        public bool Continues
+        {
+            get
+            {
+                return Interop.Elementary.elm_gesture_layer_continues_enable_get(Handle);
+            }
+            set
+            {
+                Interop.Elementary.elm_gesture_layer_continues_enable_set(Handle, value);
+            }
+        }
+
+        public int TapFingerSize
+        {
+            get
+            {
+                return Interop.Elementary.elm_gesture_layer_tap_finger_size_get(Handle);
+            }
+            set
+            {
+                Interop.Elementary.elm_gesture_layer_tap_finger_size_set(Handle, value);
+            }
+        }
+
+        public double LongTapTimeout
+        {
+            get
+            {
+                return Interop.Elementary.elm_gesture_layer_long_tap_start_timeout_get(Handle);
+            }
+            set
+            {
+                Interop.Elementary.elm_gesture_layer_long_tap_start_timeout_set(Handle, value);
+            }
+        }
+
+        public double DoubleTapTimeout
+        {
+            get
+            {
+                return Interop.Elementary.elm_gesture_layer_double_tap_timeout_get(Handle);
+            }
+            set
+            {
+                Interop.Elementary.elm_gesture_layer_double_tap_timeout_set(Handle, value);
+            }
+        }
+
+        public int FlickTimeLimit
+        {
+            get
+            {
+                return (int)Interop.Elementary.elm_gesture_layer_flick_time_limit_ms_get(Handle);
+            }
+            set
+            {
+                Interop.Elementary.elm_gesture_layer_flick_time_limit_ms_set(Handle, (UInt32)value);
+            }
+        }
+
+        public int MinimumLineLength
+        {
+            get
+            {
+                return Interop.Elementary.elm_gesture_layer_line_min_length_get(Handle);
+            }
+            set
+            {
+                Interop.Elementary.elm_gesture_layer_line_min_length_set(Handle, value);
+            }
+        }
+
+        public double LineAngularTolerance
+        {
+            get
+            {
+                return Interop.Elementary.elm_gesture_layer_line_angular_tolerance_get(Handle);
+            }
+            set
+            {
+                Interop.Elementary.elm_gesture_layer_line_angular_tolerance_set(Handle, value);
+            }
+        }
+
+        public int LineDistanceTolerance
+        {
+            get
+            {
+                return Interop.Elementary.elm_gesture_layer_line_distance_tolerance_get(Handle);
+            }
+            set
+            {
+                Interop.Elementary.elm_gesture_layer_line_distance_tolerance_set(Handle, value);
+            }
+        }
+
+        public double RotateStep
+        {
+            get
+            {
+                return Interop.Elementary.elm_gesture_layer_rotate_step_get(Handle);
+            }
+            set
+            {
+                Interop.Elementary.elm_gesture_layer_rotate_step_set(Handle, value);
+            }
+        }
+
+        public double RotateAngularTolerance
+        {
+            get
+            {
+                return Interop.Elementary.elm_gesture_layer_rotate_angular_tolerance_get(Handle);
+            }
+            set
+            {
+                Interop.Elementary.elm_gesture_layer_rotate_angular_tolerance_set(Handle, value);
+            }
+        }
+
+        public double ZoomStep
+        {
+            get
+            {
+                return Interop.Elementary.elm_gesture_layer_zoom_step_get(Handle);
+            }
+            set
+            {
+                Interop.Elementary.elm_gesture_layer_zoom_step_set(Handle, value);
+            }
+        }
+
+        public int ZoomDistanceTolerance
+        {
+            get
+            {
+                return Interop.Elementary.elm_gesture_layer_zoom_distance_tolerance_get(Handle);
+            }
+            set
+            {
+                Interop.Elementary.elm_gesture_layer_zoom_distance_tolerance_set(Handle, value);
+            }
+        }
+
+        public double ZoomFingerFactor
+        {
+            get
+            {
+                return Interop.Elementary.elm_gesture_layer_zoom_finger_factor_get(Handle);
+            }
+            set
+            {
+                Interop.Elementary.elm_gesture_layer_zoom_finger_factor_set(Handle, value);
+            }
+        }
+
+        public double ZoomWheelFactor
+        {
+            get
+            {
+                return Interop.Elementary.elm_gesture_layer_zoom_wheel_factor_get(Handle);
+            }
+            set
+            {
+                Interop.Elementary.elm_gesture_layer_zoom_wheel_factor_set(Handle, value);
+            }
+        }
+        #endregion Properties
+
+        public void Attach(EvasObject target)
+        {
+            Interop.Elementary.elm_gesture_layer_attach(Handle, target.Handle);
+        }
+
+        public void SetGestureCallback(GestureType type, GestureState state, Action<object> action)
+        {
+            lock (_handlers)
+            {
+                bool found = false;
+                int i = 0;
+                // if this (type, state) already exists in _handlers, we will reuse it
+                foreach (var handler in _handlers)
+                {
+                    if (handler.Type == type && handler.State == state)
+                    {
+                        found = true;
+                        break;
+                    }
+                    i++;
+                }
+                if (found)
+                {
+                    // if we are changing null -> not-null, or not-null -> null, then inform the EFL
+                    if (_handlers[i].Action == null ^ action == null)
+                        Interop.Elementary.elm_gesture_layer_cb_set(Handle, type, state, action == null ? null : _gestureCallback, new IntPtr(i));
+                    // overwrite previous action
+                    _handlers[i].Action = action;
+                }
+                else
+                {
+                    if (action == null)
+                    {
+                        // ignore unsetting a handler for event which was not registered yet?
+                        return;
+                    }
+                    // (type, state) was not found, so we are adding a new entry and registering the callback
+                    _handlers.Add(new NativeCallback(type, state, action));
+                    // callback is always the same, the event is recognised by the index in _handler list (the index is passed as data)
+                    Interop.Elementary.elm_gesture_layer_cb_set(Handle, type, state, _gestureCallback, new IntPtr(i));
+                }
+            }
+        }
+
+        public void ClearCallbacks()
+        {
+            lock (_handlers)
+            {
+                int i = 0;
+                foreach (var handler in _handlers)
+                {
+                    if (handler.Action != null)
+                    {
+                        Interop.Elementary.elm_gesture_layer_cb_set(Handle, handler.Type, handler.State, null, new IntPtr(i));
+                        handler.Action = null;
+                    }
+                    i++;
+                }
+            }
+        }
+
+        #region Typed callback setting methods
+        // Following methods have been added for convenience, so the user will not have to convert Info structures himself
+        public void SetTapCallback(GestureType type, GestureState state, Action<TapData> action)
+        {
+            SetCallback(type, state, action);
+        }
+
+        public void SetMomentumCallback(GestureState state, Action<MomentumData> action)
+        {
+            SetCallback(GestureType.Momentum, state, action);
+        }
+
+        public void SetLineCallback(GestureState state, Action<LineData> action)
+        {
+            SetCallback(GestureType.Line, state, action);
+        }
+
+        public void SetFlickCallback(GestureState state, Action<LineData> action)
+        {
+            SetCallback(GestureType.Flick, state, action);
+        }
+
+        public void SetZoomCallback(GestureState state, Action<ZoomData> action)
+        {
+            SetCallback(GestureType.Zoom, state, action);
+        }
+
+        public void SetRotateCallback(GestureState state, Action<RotateData> action)
+        {
+            SetCallback(GestureType.Rotate, state, action);
+        }
+        #endregion Typed callback setting methods
+
+        protected override IntPtr CreateHandle(EvasObject parent)
+        {
+            return Interop.Elementary.elm_gesture_layer_add(parent);
+        }
+
+        protected override void OnUnrealize()
+        {
+            ClearCallbacks();
+            base.OnUnrealize();
+        }
+
+        private void SetCallback<T>(GestureType type, GestureState state, Action<T> action)
+        {
+            if (action == null)
+                SetGestureCallback(type, state, null);
+            else
+                SetGestureCallback(type, state, new Action<object>((info) => action((T)info)));
+        }
+
+        private void GestureCallbackHandler(IntPtr data, IntPtr event_info)
+        {
+            // so EFL called our callback, lets use data to find the right Action to call
+            var handlerIndex = (int)data;
+            // thanks to the fact that we never remove item from _handlers, we don't need a lock here
+            if (handlerIndex < 0 || handlerIndex >= _handlers.Count)
+                return;
+            Action<object> action = _handlers[handlerIndex].Action;
+            if (action == null)
+                return;
+            // the interpretation of the event_info struct pointer depends on the GestureType
+            switch (_handlers[handlerIndex].Type)
+            {
+                case GestureType.Tap:
+                case GestureType.LongTap:
+                case GestureType.DoubleTap:
+                case GestureType.TripleTap:
+                    action(Marshal.PtrToStructure<TapData>(event_info));
+                    break;
+                case GestureType.Momentum:
+                    action(Marshal.PtrToStructure<MomentumData>(event_info));
+                    break;
+                case GestureType.Line:
+                case GestureType.Flick:
+                    action(Marshal.PtrToStructure<LineData>(event_info));
+                    break;
+                case GestureType.Zoom:
+                    action(Marshal.PtrToStructure<ZoomData>(event_info));
+                    break;
+                case GestureType.Rotate:
+                    action(Marshal.PtrToStructure<RotateData>(event_info));
+                    break;
+            }
+        }
+
+        #region Info structures
+
+        [StructLayout(LayoutKind.Sequential)]
+        public struct TapData
+        {
+            /// <summary>
+            /// The x coordinate of the center point.
+            /// </summary>
+            public Int32 X;
+
+            /// <summary>
+            /// The y coordinate of the center point.
+            /// </summary>
+            public Int32 Y;
+
+            #pragma warning disable 3003
+            /// <summary>
+            /// The number of fingers tapped.
+            /// </summary>
+            public UInt32 FingersCount;
+
+            /// <summary>
+            /// The timestamp.
+            /// </summary>
+            public UInt32 Timestamp;
+            #pragma warning restore 3003
+        }
+
+        [StructLayout(LayoutKind.Sequential)]
+        public struct MomentumData
+        {
+            /// <summary>
+            /// Final-swipe direction starting point on X.
+            /// </summary>
+            public Int32 X1;
+
+            /// <summary>
+            /// Final-swipe direction starting point on Y.
+            /// </summary>
+            public Int32 Y1;
+
+            /// <summary>
+            /// Final-swipe direction ending point on X.
+            /// </summary>
+            public Int32 X2;
+
+            /// <summary>
+            /// Final-swipe direction ending point on Y
+            /// </summary>
+            public Int32 Y2;
+
+            #pragma warning disable 3003
+            /// <summary>
+            /// Timestamp of start of final x-swipe.
+            /// </summary>
+            public UInt32 HorizontalSwipeTimestamp;
+
+            /// <summary>
+            /// Timestamp of start of final y-swipe.
+            /// </summary>
+            public UInt32 VerticalSwipeTimestamp;
+
+            /// <summary>
+            /// Momentum on X.
+            /// </summary>
+            public Int32 HorizontalMomentum;
+
+            /// <summary>
+            /// Momentum on Y.
+            /// </summary>
+            public Int32 VerticalMomentum;
+
+            /// <summary>
+            /// Number of fingers.
+            /// </summary>
+            public UInt32 FingersCount;
+            #pragma warning restore 3003
+        }
+
+        [StructLayout(LayoutKind.Sequential)]
+        public struct LineData
+        {
+            /// <summary>
+            /// Final-swipe direction starting point on X.
+            /// </summary>
+            public Int32 X1;
+
+            /// <summary>
+            /// Final-swipe direction starting point on Y.
+            /// </summary>
+            public Int32 Y1;
+
+            /// <summary>
+            /// Final-swipe direction ending point on X.
+            /// </summary>
+            public Int32 X2;
+
+            /// <summary>
+            /// Final-swipe direction ending point on Y
+            /// </summary>
+            public Int32 Y2;
+
+            #pragma warning disable 3003
+            /// <summary>
+            /// Timestamp of start of final x-swipe.
+            /// </summary>
+            public UInt32 HorizontalSwipeTimestamp;
+
+            /// <summary>
+            /// Timestamp of start of final y-swipe.
+            /// </summary>
+            public UInt32 VerticalSwipeTimestamp;
+
+            /// <summary>
+            /// Momentum on X.
+            /// </summary>
+            public Int32 HorizontalMomentum;
+
+            /// <summary>
+            /// Momentum on Y.
+            /// </summary>
+            public Int32 VerticalMomentum;
+
+            /// <summary>
+            /// Number of fingers.
+            /// </summary>
+            public UInt32 FingersCount;
+            #pragma warning restore 3003
+
+            /// <summary>
+            /// Angle (direction) of lines.
+            /// </summary>
+            public double Angle;
+        }
+
+        [StructLayout(LayoutKind.Sequential)]
+        public struct ZoomData
+        {
+            /// <summary>
+            /// The x coordinate of zoom center point reported to user.
+            /// </summary>
+            public Int32 X;
+
+            /// <summary>
+            /// The y coordinate of zoom center point reported to user.
+            /// </summary>
+            public Int32 Y;
+
+            /// <summary>
+            /// The radius (distance) between fingers reported to user.
+            /// </summary>
+            public Int32 Radius;
+
+            /// <summary>
+            /// The zoom value. 1.0 means no zoom.
+            /// </summary>
+            public double Zoom;
+
+            /// <summary>
+            /// Zoom momentum: zoom growth per second (NOT YET SUPPORTED).
+            /// </summary>
+            private double Momentum;
+        }
+
+        [StructLayout(LayoutKind.Sequential)]
+        public struct RotateData
+        {
+            /// <summary>
+            /// The x coordinate of rotation center point reported to user.
+            /// </summary>
+            public Int32 X;
+
+            /// <summary>
+            /// The y coordinate of rotation center point reported to user.
+            /// </summary>
+            public Int32 Y;
+
+            /// <summary>
+            /// The radius (distance) between fingers reported to user.
+            /// </summary>
+            public Int32 Radius;
+
+            /// <summary>
+            /// The start-angle.
+            /// </summary>
+            public double BaseAngle;
+
+            /// <summary>
+            /// The rotation value. 0.0 means no rotation.
+            /// </summary>
+            public double Angle;
+
+            /// <summary>
+            /// Rotation momentum: rotation done per second (NOT YET SUPPORTED).
+            /// </summary>
+            private double Momentum;
+        }
+
+        #endregion Info structures
+
+        public static class Config
+        {
+            public static double DefaultLongTapTimeout
+            {
+                get {
+                    return Interop.Elementary.elm_config_glayer_long_tap_start_timeout_get();
+                }
+                set {
+                    Interop.Elementary.elm_config_glayer_long_tap_start_timeout_set(value);
+                }
+            }
+
+            public static double DefaultDoubleTapTimeout
+            {
+                get {
+                    return Interop.Elementary.elm_config_glayer_double_tap_timeout_get();
+                }
+                set {
+                    Interop.Elementary.elm_config_glayer_double_tap_timeout_set(value);
+                }
+            }
+        }
+
+        private class NativeCallback
+        {
+            public readonly GestureType Type;
+            public readonly GestureState State;
+            public Action<object> Action;
+
+            public NativeCallback(GestureType type, GestureState state, Action<object> action)
+            {
+                Type = type;
+                State = state;
+                Action = action;
+            }
+        }
+    }
+}
diff --git a/src/ElmSharp/Interop/Interop.Elementary.GestureLayer.cs b/src/ElmSharp/Interop/Interop.Elementary.GestureLayer.cs
new file mode 100644 (file)
index 0000000..726c0bc
--- /dev/null
@@ -0,0 +1,130 @@
+// Copyright 2016 by Samsung Electronics, Inc.,
+//
+// This software is the confidential and proprietary information
+// of Samsung Electronics, Inc. ("Confidential Information"). You
+// shall not disclose such Confidential Information and shall use
+// it only in accordance with the terms of the license agreement
+// you entered into with Samsung.
+
+using System;
+using System.Runtime.InteropServices;
+
+internal static partial class Interop
+{
+    internal static partial class Elementary
+    {
+        public delegate void GestureEventCallback(IntPtr data, IntPtr event_info);
+
+        [DllImport(Libraries.Elementary)]
+        internal static extern IntPtr elm_gesture_layer_add(IntPtr parent);
+
+        [DllImport(Libraries.Elementary)]
+        internal static extern bool elm_gesture_layer_attach(IntPtr obj, IntPtr target);
+
+        [DllImport(Libraries.Elementary)]
+        internal static extern void elm_gesture_layer_zoom_step_set(IntPtr obj, double step);
+
+        [DllImport(Libraries.Elementary)]
+        internal static extern double elm_gesture_layer_zoom_step_get(IntPtr obj);
+
+        [DllImport(Libraries.Elementary)]
+        internal static extern void elm_gesture_layer_tap_finger_size_set(IntPtr obj, int sz);
+
+        [DllImport(Libraries.Elementary)]
+        internal static extern int elm_gesture_layer_tap_finger_size_get(IntPtr obj);
+
+        [DllImport(Libraries.Elementary)]
+        internal static extern void elm_gesture_layer_hold_events_set(IntPtr obj, bool hold_events);
+
+        [DllImport(Libraries.Elementary)]
+        internal static extern bool elm_gesture_layer_hold_events_get(IntPtr obj);
+
+        [DllImport(Libraries.Elementary)]
+        internal static extern void elm_gesture_layer_rotate_step_set(IntPtr obj, double step);
+
+        [DllImport(Libraries.Elementary)]
+        internal static extern double elm_gesture_layer_rotate_step_get(IntPtr obj);
+
+        [DllImport(Libraries.Elementary)]
+        internal static extern void elm_gesture_layer_cb_set(IntPtr obj, ElmSharp.GestureLayer.GestureType idx, ElmSharp.GestureLayer.GestureState cb_type, GestureEventCallback cb, IntPtr data);
+
+        [DllImport(Libraries.Elementary)]
+        internal static extern void elm_gesture_layer_line_min_length_set(IntPtr obj, int line_min_length);
+
+        [DllImport(Libraries.Elementary)]
+        internal static extern int elm_gesture_layer_line_min_length_get(IntPtr obj);
+
+        [DllImport(Libraries.Elementary)]
+        internal static extern void elm_gesture_layer_zoom_distance_tolerance_set(IntPtr obj, int zoom_distance_tolerance);
+
+        [DllImport(Libraries.Elementary)]
+        internal static extern int elm_gesture_layer_zoom_distance_tolerance_get(IntPtr obj);
+
+        [DllImport(Libraries.Elementary)]
+        internal static extern void elm_gesture_layer_line_distance_tolerance_set(IntPtr obj, int line_distance_tolerance);
+
+        [DllImport(Libraries.Elementary)]
+        internal static extern int elm_gesture_layer_line_distance_tolerance_get (IntPtr obj);
+
+        [DllImport(Libraries.Elementary)]
+        internal static extern void elm_gesture_layer_line_angular_tolerance_set(IntPtr obj, double line_angular_tolerance);
+
+        [DllImport(Libraries.Elementary)]
+        internal static extern double elm_gesture_layer_line_angular_tolerance_get(IntPtr obj);
+
+        [DllImport(Libraries.Elementary)]
+        internal static extern void elm_gesture_layer_zoom_wheel_factor_set(IntPtr obj, double zoom_wheel_factor);
+
+        [DllImport(Libraries.Elementary)]
+        internal static extern double elm_gesture_layer_zoom_wheel_factor_get (IntPtr obj);
+
+        [DllImport(Libraries.Elementary)]
+        internal static extern void elm_gesture_layer_zoom_finger_factor_set (IntPtr obj, double zoom_finger_factor);
+
+        [DllImport(Libraries.Elementary)]
+        internal static extern double elm_gesture_layer_zoom_finger_factor_get (IntPtr obj);
+
+        [DllImport(Libraries.Elementary)]
+        internal static extern void elm_gesture_layer_rotate_angular_tolerance_set (IntPtr obj, double rotate_angular_tolerance);
+
+        [DllImport(Libraries.Elementary)]
+        internal static extern double elm_gesture_layer_rotate_angular_tolerance_get (IntPtr obj);
+
+        [DllImport(Libraries.Elementary)]
+        internal static extern void elm_gesture_layer_flick_time_limit_ms_set (IntPtr obj, UInt32 flick_time_limit_ms);
+
+        [DllImport(Libraries.Elementary)]
+        internal static extern UInt32 elm_gesture_layer_flick_time_limit_ms_get (IntPtr obj);
+
+        [DllImport(Libraries.Elementary)]
+        internal static extern void elm_gesture_layer_long_tap_start_timeout_set(IntPtr obj, double long_tap_start_timeout);
+
+        [DllImport(Libraries.Elementary)]
+        internal static extern double elm_gesture_layer_long_tap_start_timeout_get (IntPtr obj);
+
+        [DllImport(Libraries.Elementary)]
+        internal static extern void elm_gesture_layer_continues_enable_set(IntPtr obj, bool continues_enable);
+
+        [DllImport(Libraries.Elementary)]
+        internal static extern bool elm_gesture_layer_continues_enable_get (IntPtr obj);
+
+        [DllImport(Libraries.Elementary)]
+        internal static extern void elm_gesture_layer_double_tap_timeout_set (IntPtr obj, double double_tap_timeout);
+
+        [DllImport(Libraries.Elementary)]
+        internal static extern double elm_gesture_layer_double_tap_timeout_get (IntPtr obj);
+
+        [DllImport(Libraries.Elementary)]
+        internal static extern double elm_config_glayer_long_tap_start_timeout_get ();
+
+        [DllImport(Libraries.Elementary)]
+        internal static extern void elm_config_glayer_long_tap_start_timeout_set(double long_tap_timeout);
+
+        [DllImport(Libraries.Elementary)]
+        internal static extern double elm_config_glayer_double_tap_timeout_get();
+
+        [DllImport(Libraries.Elementary)]
+        internal static extern void elm_config_glayer_double_tap_timeout_set(double double_tap_timeout);
+    }
+}
+
diff --git a/test/ElmSharp.Test/TC/GestureLayerTest1.cs b/test/ElmSharp.Test/TC/GestureLayerTest1.cs
new file mode 100644 (file)
index 0000000..b59cbcc
--- /dev/null
@@ -0,0 +1,86 @@
+using System;
+using ElmSharp;
+using System.Collections.Generic;
+
+namespace ElmSharp.Test
+{
+    class GestureLayerTest1 : TestCaseBase
+    {
+        public override string TestName => "GestureLayerTest1";
+        public override string TestDescription => "Demonstrate GestureLayer features: Tap, DoubleTap, Rotate, Zoom detection.";
+
+        private GestureLayer _glayer;
+        private Label _log;
+        private List<string> _logEntries;
+        private Background _background;
+        private Rectangle _box1;
+
+        public override void Run(Window window)
+        {
+            _background = new Background(window);
+            var windowSize = window.ScreenSize;
+            _background.Color = Color.White;
+            _background.Resize(windowSize.Width, windowSize.Height);
+            _background.Show();
+
+            _box1 = new Rectangle(window)
+                {
+                    Color = Color.Yellow
+                };
+            _box1.Resize(400, 600);
+            _box1.Move(160, 160);
+            _box1.Show();
+
+            _log = new Label(window);
+            _log.Resize(700, 1280 - 780);
+            _log.Move(10, 770);
+            _log.Show();
+            _logEntries = new List<string>();
+            Log("Double tap to register additional gestures. Tripple tap to unregister them.");
+
+            _glayer = new GestureLayer(_box1);
+            _glayer.Attach(_box1);
+
+            _glayer.SetTapCallback(GestureLayer.GestureType.Tap, GestureLayer.GestureState.End, (info) => {
+                Log("Tap {0},{1}", info.X, info.Y);
+            });
+
+            _glayer.SetTapCallback(GestureLayer.GestureType.DoubleTap, GestureLayer.GestureState.End, (info) => {
+                Log("DoubleTap {0},{1} {2}", info.X, info.Y, info.FingersCount);
+                _glayer.SetLineCallback(GestureLayer.GestureState.End, (line) => {
+                    Log("Line {0},{1}-{2},{3}, M:{4},{5}", line.X1, line.Y1, line.X2, line.Y2, line.HorizontalMomentum, line.VerticalMomentum);
+                });
+                _glayer.SetFlickCallback(GestureLayer.GestureState.End, (flick) => {
+                    Log("Flick {0},{1}-{2},{3}, M:{4},{5}", flick.X1, flick.Y1, flick.X2, flick.Y2, flick.HorizontalMomentum, flick.VerticalMomentum);
+                });
+                _glayer.RotateStep = 3;
+                _glayer.SetRotateCallback(GestureLayer.GestureState.Move, (rotate) => {
+                    Log("Rotation {0},{1} a:{2:F3} ba:{3:F3}", rotate.X, rotate.Y, rotate.Angle, rotate.BaseAngle);
+                });
+                _glayer.SetZoomCallback(GestureLayer.GestureState.End, (zoom) => {
+                    Log("Zoom {0},{1} r:{2} z:{3:F3}", zoom.X, zoom.Y, zoom.Radius, zoom.Zoom);
+                });
+                Log("Line, Flick, Rotate, and Zoom callbacks enabled.");
+            });
+
+            _glayer.SetTapCallback(GestureLayer.GestureType.TripleTap, GestureLayer.GestureState.End, (info) => {
+                Log("TrippleTap {0},{1} {2}", info.X, info.Y, info.FingersCount);
+                _glayer.SetLineCallback(GestureLayer.GestureState.End, null);
+                _glayer.SetFlickCallback(GestureLayer.GestureState.End, null);
+                _glayer.SetRotateCallback(GestureLayer.GestureState.Move, null);
+                _glayer.SetZoomCallback(GestureLayer.GestureState.End, null);
+                Log("Cleared Line, Flick, Rotate, and Zoom callbacks.");
+            });
+            // Momentum is not used, it seems that it conflicts with Rotate and Zoom
+        }
+
+        private void Log(string format, params object[] args)
+        {
+            var entry = string.Format(format, args);
+            if (_logEntries.Count > 15)
+                _logEntries.RemoveRange(0, _logEntries.Count - 15);
+            _logEntries.Add(entry);
+            _log.Text = string.Join("<br>", _logEntries);
+        }
+    }
+}