[NUI] Add InterceptTouchEvent (#2098)
authorJoogabYun <40262755+JoogabYun@users.noreply.github.com>
Tue, 20 Oct 2020 01:27:36 +0000 (10:27 +0900)
committerGitHub <noreply@github.com>
Tue, 20 Oct 2020 01:27:36 +0000 (10:27 +0900)
The Touch event calls the TouchEvent callback by going back from the last child actor to the parent via hitTest.
InterceptTouchEvent checks the touch event in the parent first.
Returning false from interceptTouchEvent allows child actors to receive TouchEvents.
If it returns true, the actor will receive a TouchEvent.

for example

   View parent = new View();
   View child = new View();
   parent.Add(child);
   child.TouchEvent += childFunctor;
   parent.TouchEvent += parentFunctor;

The callbacks are called in the order childFunctor -> parentFunctor.

If you connect interceptTouchSignal to parentActor.

   parent.InterceptTouchEvent += interceptFunctor;

When interceptFunctor returns false, it is called in the same order childFunctor -> parentFunctor.
If intereptFunctor returns true, it means that the TouchEvent was intercepted.
So the child actor will not be able to receive touch events.
Only the parentFunctor is called.

src/Tizen.NUI/src/internal/InterceptTouchSignal.cs [new file with mode: 0755]
src/Tizen.NUI/src/internal/Interop/Interop.ActorSignal.cs
src/Tizen.NUI/src/internal/Interop/Interop.TouchSignal.cs
src/Tizen.NUI/src/public/BaseComponents/ViewEvent.cs
src/Tizen.NUI/src/public/BaseComponents/ViewInternal.cs

diff --git a/src/Tizen.NUI/src/internal/InterceptTouchSignal.cs b/src/Tizen.NUI/src/internal/InterceptTouchSignal.cs
new file mode 100755 (executable)
index 0000000..d676da6
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * Copyright(c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+namespace Tizen.NUI
+{
+    internal class InterceptTouchSignal : Disposable
+    {
+
+        internal InterceptTouchSignal(global::System.IntPtr cPtr, bool cMemoryOwn) : base(cPtr, cMemoryOwn)
+        {
+        }
+
+
+        protected override void ReleaseSwigCPtr(System.Runtime.InteropServices.HandleRef swigCPtr)
+        {
+            Interop.TouchSignal.delete_TouchSignal(swigCPtr);
+        }
+
+
+        public bool Empty()
+        {
+            bool ret = Interop.TouchSignal.TouchSignal_Empty(swigCPtr);
+            if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+            return ret;
+        }
+
+        public uint GetConnectionCount()
+        {
+            uint ret = Interop.TouchSignal.TouchSignal_GetConnectionCount(swigCPtr);
+            if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+            return ret;
+        }
+
+        public void Connect(System.Delegate func)
+        {
+            System.IntPtr ip = System.Runtime.InteropServices.Marshal.GetFunctionPointerForDelegate<System.Delegate>(func);
+            {
+                Interop.TouchSignal.TouchSignal_Connect(swigCPtr, new System.Runtime.InteropServices.HandleRef(this, ip));
+                if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+            }
+        }
+
+        public void Disconnect(System.Delegate func)
+        {
+            System.IntPtr ip = System.Runtime.InteropServices.Marshal.GetFunctionPointerForDelegate<System.Delegate>(func);
+            {
+                Interop.TouchSignal.TouchSignal_Disconnect(swigCPtr, new System.Runtime.InteropServices.HandleRef(this, ip));
+                if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+            }
+        }
+
+        public void Emit(Touch arg)
+        {
+            Interop.TouchSignal.TouchSignal_Emit(swigCPtr, Touch.getCPtr(arg));
+            if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+        }
+
+        public InterceptTouchSignal() : this(Interop.TouchSignal.new_InterceptTouchSignal(), true)
+        {
+            if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+        }
+    }
+}
index 5070afd..ba79ba1 100755 (executable)
@@ -29,6 +29,9 @@ namespace Tizen.NUI
             [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_delete_ActorSignal")]
             public static extern void delete_ActorSignal(global::System.Runtime.InteropServices.HandleRef jarg1);
 
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_Actor_InterceptTouchSignal")]
+            public static extern global::System.IntPtr Actor_InterceptTouchSignal(global::System.Runtime.InteropServices.HandleRef jarg1);
+
             [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_Actor_TouchSignal")]
             public static extern global::System.IntPtr Actor_TouchSignal(global::System.Runtime.InteropServices.HandleRef jarg1);
 
index 5606d8e..09bd628 100755 (executable)
@@ -26,6 +26,9 @@ namespace Tizen.NUI
             [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_new_TouchSignal")]
             public static extern global::System.IntPtr new_TouchSignal();
 
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_new_InterceptTouchSignal")]
+            public static extern global::System.IntPtr new_InterceptTouchSignal();
+
             [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_delete_TouchSignal")]
             public static extern void delete_TouchSignal(global::System.Runtime.InteropServices.HandleRef jarg1);
         }
index 321650d..2e89367 100755 (executable)
@@ -34,6 +34,8 @@ namespace Tizen.NUI.BaseComponents
         private WheelEventCallbackType _wheelEventCallback;
         private EventHandlerWithReturnType<object, KeyEventArgs, bool> _keyEventHandler;
         private KeyCallbackType _keyCallback;
+        private EventHandlerWithReturnType<object, TouchEventArgs, bool> _interceptTouchDataEventHandler;
+        private TouchDataCallbackType _interceptTouchDataCallback;
         private EventHandlerWithReturnType<object, TouchEventArgs, bool> _touchDataEventHandler;
         private TouchDataCallbackType _touchDataCallback;
         private EventHandlerWithReturnType<object, HoverEventArgs, bool> _hoverEventHandler;
@@ -221,6 +223,37 @@ namespace Tizen.NUI.BaseComponents
         /// <summary>
         /// An event for the touched signal which can be used to subscribe or unsubscribe the event handler provided by the user.<br />
         /// The touched signal is emitted when the touch input is received.<br />
+        /// This can receive touch events before child. <br />
+        /// If it returns false, the child can receive the touch event. If it returns true, the touch event is intercepted. So child cannot receive touch event.<br />
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public event EventHandlerWithReturnType<object, TouchEventArgs, bool> InterceptTouchEvent
+        {
+            add
+            {
+                if (_interceptTouchDataEventHandler == null)
+                {
+                    _interceptTouchDataCallback = OnInterceptTouch;
+                    this.InterceptTouchSignal().Connect(_interceptTouchDataCallback);
+                }
+
+                _interceptTouchDataEventHandler += value;
+            }
+
+            remove
+            {
+                _interceptTouchDataEventHandler -= value;
+
+                if (_interceptTouchDataEventHandler == null && InterceptTouchSignal().Empty() == false)
+                {
+                    this.InterceptTouchSignal().Disconnect(_interceptTouchDataCallback);
+                }
+            }
+        }
+
+        /// <summary>
+        /// An event for the touched signal which can be used to subscribe or unsubscribe the event handler provided by the user.<br />
+        /// The touched signal is emitted when the touch input is received.<br />
         /// </summary>
         /// <since_tizen> 3 </since_tizen>
         public event EventHandlerWithReturnType<object, TouchEventArgs, bool> TouchEvent
@@ -516,6 +549,14 @@ namespace Tizen.NUI.BaseComponents
             }
         }
 
+        internal TouchDataSignal InterceptTouchSignal()
+        {
+            TouchDataSignal ret = new TouchDataSignal(Interop.ActorSignal.Actor_InterceptTouchSignal(swigCPtr), false);
+            if (NDalicPINVOKE.SWIGPendingException.Pending)
+                throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+            return ret;
+        }
+
         internal TouchDataSignal TouchSignal()
         {
             TouchDataSignal ret = new TouchDataSignal(Interop.ActorSignal.Actor_TouchSignal(swigCPtr), false);
@@ -763,6 +804,34 @@ namespace Tizen.NUI.BaseComponents
         }
 
         // Callback for View TouchSignal
+        private bool OnInterceptTouch(IntPtr view, IntPtr touchData)
+        {
+            if (touchData == global::System.IntPtr.Zero)
+            {
+                NUILog.Error("touchData should not be null!");
+                return true;
+            }
+
+            TouchEventArgs e = new TouchEventArgs();
+
+            e.Touch = Tizen.NUI.Touch.GetTouchFromPtr(touchData);
+
+            bool consumed = false;
+
+            if (_interceptTouchDataEventHandler != null)
+            {
+                consumed = _interceptTouchDataEventHandler(this, e);
+            }
+
+            if (enableControlState && !consumed)
+            {
+                consumed = HandleControlStateOnTouch(e.Touch);
+            }
+
+            return consumed;
+        }
+
+        // Callback for View TouchSignal
         private bool OnTouch(IntPtr view, IntPtr touchData)
         {
             if (touchData == global::System.IntPtr.Zero)
index cf42ffa..1e9c0f7 100755 (executable)
@@ -1160,6 +1160,11 @@ namespace Tizen.NUI.BaseComponents
                 this.HoveredSignal().Disconnect(_hoverEventCallback);
             }
 
+            if (_interceptTouchDataCallback != null)
+            {
+                this.InterceptTouchSignal().Disconnect(_interceptTouchDataCallback);
+            }
+
             if (_touchDataCallback != null)
             {
                 this.TouchSignal().Disconnect(_touchDataCallback);