From ffbe015becd713c711d67a1c2b7b92539c3041f9 Mon Sep 17 00:00:00 2001 From: "joogab.yun" Date: Tue, 15 Sep 2026 09:17:51 +0900 Subject: [PATCH] [NUI] Add per-device gesture options and recognition thresholds Add GestureDeviceSelector (matches an exact device name, a device class and subclass, or a device class), nested Options types for Pan/Tap/LongPress gesture detectors with GetDefaultOptions, SetDeviceOptions, TryGetDeviceOptions and ClearDeviceOptions, Gesture.DeviceName, and per-device recognition thresholds (PanThresholds, TapThresholds, LongPressThresholds, PinchThresholds, RotationThresholds) exposed through GestureOptions.Instance. Also expose TapGestureDetector.ReceiveAllTapEvents / IsReceiveAllTapEventsEnabled. All new members are [EditorBrowsable(EditorBrowsableState.Never)] until ACR. Adds a DeviceGestureOptionsSample demonstrating the feature: a PanGestureDetector and a TapGestureDetector recognize gestures differently for mouse vs. touch, using detector-local Options (mouse pans restricted to roughly horizontal drags, both allow a double tap) and GestureOptions.Instance per-device thresholds (mouse needs a longer drag before a pan starts and a faster second tap for a double tap than the touch defaults). A touchscreen is not required to see the effect. Co-Authored-By: Claude Opus 5 (1M context) --- .../src/internal/Interop/Interop.Gesture.cs | 3 + .../Interop/Interop.GestureDeviceSelector.cs | 56 +++ .../Interop/Interop.GestureThresholds.cs | 186 ++++++++++ .../Interop.LongPressGestureDetector.cs | 31 ++ .../Interop/Interop.PanGestureDetector.cs | 64 ++++ .../Interop/Interop.TapGestureDetector.cs | 45 +++ src/Tizen.NUI/src/public/Events/Gesture.cs | 16 + .../public/Events/GestureDeviceSelector.cs | 221 ++++++++++++ .../src/public/Events/GestureOptions.cs | 335 ++++++++++++++++++ .../public/Events/LongPressGestureDetector.cs | 145 ++++++++ .../src/public/Events/LongPressThresholds.cs | 72 ++++ .../src/public/Events/PanGestureDetector.cs | 249 +++++++++++++ .../src/public/Events/PanThresholds.cs | 91 +++++ .../src/public/Events/PinchThresholds.cs | 110 ++++++ .../src/public/Events/RotationThresholds.cs | 91 +++++ .../src/public/Events/TapGestureDetector.cs | 177 +++++++++ .../src/public/Events/TapThresholds.cs | 110 ++++++ .../Samples/DeviceGestureOptionsSample.cs | 267 ++++++++++++++ 18 files changed, 2269 insertions(+) create mode 100644 src/Tizen.NUI/src/internal/Interop/Interop.GestureDeviceSelector.cs create mode 100644 src/Tizen.NUI/src/internal/Interop/Interop.GestureThresholds.cs create mode 100644 src/Tizen.NUI/src/public/Events/GestureDeviceSelector.cs create mode 100644 src/Tizen.NUI/src/public/Events/LongPressThresholds.cs create mode 100644 src/Tizen.NUI/src/public/Events/PanThresholds.cs create mode 100644 src/Tizen.NUI/src/public/Events/PinchThresholds.cs create mode 100644 src/Tizen.NUI/src/public/Events/RotationThresholds.cs create mode 100644 src/Tizen.NUI/src/public/Events/TapThresholds.cs create mode 100644 test/Tizen.NUI.Samples/Tizen.NUI.Samples/Samples/DeviceGestureOptionsSample.cs diff --git a/src/Tizen.NUI/src/internal/Interop/Interop.Gesture.cs b/src/Tizen.NUI/src/internal/Interop/Interop.Gesture.cs index be6e22191b6..10477e8647f 100755 --- a/src/Tizen.NUI/src/internal/Interop/Interop.Gesture.cs +++ b/src/Tizen.NUI/src/internal/Interop/Interop.Gesture.cs @@ -44,6 +44,9 @@ internal static partial class Gesture [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_Gesture_sourceSubType_get")] public static extern int SourceSubTypeGet(global::System.Runtime.InteropServices.HandleRef jarg1); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_Gesture_GetDeviceName")] + public static extern string GetDeviceName(global::System.Runtime.InteropServices.HandleRef jarg1); } } } diff --git a/src/Tizen.NUI/src/internal/Interop/Interop.GestureDeviceSelector.cs b/src/Tizen.NUI/src/internal/Interop/Interop.GestureDeviceSelector.cs new file mode 100644 index 00000000000..0bec9afb20a --- /dev/null +++ b/src/Tizen.NUI/src/internal/Interop/Interop.GestureDeviceSelector.cs @@ -0,0 +1,56 @@ +/* + * Copyright(c) 2026 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 static partial class Interop + { + internal static partial class GestureDeviceSelector + { + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_new_GestureDeviceSelector")] + public static extern global::System.IntPtr New(); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_GestureDeviceSelector_ByDeviceClass")] + public static extern global::System.IntPtr ByDeviceClass(int deviceClass); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_GestureDeviceSelector_ByDeviceClassAndSubclass")] + public static extern global::System.IntPtr ByDeviceClassAndSubclass(int deviceClass, int deviceSubclass); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_GestureDeviceSelector_ByDeviceName")] + public static extern global::System.IntPtr ByDeviceName(string deviceName); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_delete_GestureDeviceSelector")] + public static extern void Delete(global::System.Runtime.InteropServices.HandleRef nuiSelector); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_GestureDeviceSelector_GetMatchType")] + public static extern int GetMatchType(global::System.Runtime.InteropServices.HandleRef nuiSelector); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_GestureDeviceSelector_GetDeviceClass")] + public static extern int GetDeviceClass(global::System.Runtime.InteropServices.HandleRef nuiSelector); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_GestureDeviceSelector_GetDeviceSubclass")] + public static extern int GetDeviceSubclass(global::System.Runtime.InteropServices.HandleRef nuiSelector); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_GestureDeviceSelector_GetDeviceName")] + public static extern string GetDeviceName(global::System.Runtime.InteropServices.HandleRef nuiSelector); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_GestureDeviceSelector_Equals")] + [return: global::System.Runtime.InteropServices.MarshalAs(global::System.Runtime.InteropServices.UnmanagedType.U1)] + public static extern bool IsEqual(global::System.Runtime.InteropServices.HandleRef nuiSelector, global::System.Runtime.InteropServices.HandleRef nuiOther); + } + } +} diff --git a/src/Tizen.NUI/src/internal/Interop/Interop.GestureThresholds.cs b/src/Tizen.NUI/src/internal/Interop/Interop.GestureThresholds.cs new file mode 100644 index 00000000000..1aff48ad2c7 --- /dev/null +++ b/src/Tizen.NUI/src/internal/Interop/Interop.GestureThresholds.cs @@ -0,0 +1,186 @@ +/* + * Copyright(c) 2026 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 static partial class Interop + { + internal static partial class GestureThresholds + { + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_new_GestureThresholds_PanThresholds")] + public static extern global::System.IntPtr NewPanThresholds(); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_delete_GestureThresholds_PanThresholds")] + public static extern void DeletePanThresholds(global::System.Runtime.InteropServices.HandleRef nuiThresholds); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_GestureThresholds_PanThresholds_SetMinimumDistance")] + public static extern void PanThresholdsSetMinimumDistance(global::System.Runtime.InteropServices.HandleRef nuiThresholds, int value); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_GestureThresholds_PanThresholds_GetMinimumDistance")] + public static extern int PanThresholdsGetMinimumDistance(global::System.Runtime.InteropServices.HandleRef nuiThresholds); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_GestureThresholds_PanThresholds_SetMinimumPanEvents")] + public static extern void PanThresholdsSetMinimumPanEvents(global::System.Runtime.InteropServices.HandleRef nuiThresholds, int value); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_GestureThresholds_PanThresholds_GetMinimumPanEvents")] + public static extern int PanThresholdsGetMinimumPanEvents(global::System.Runtime.InteropServices.HandleRef nuiThresholds); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_GestureThresholds_GetDefaultPanThresholds")] + public static extern global::System.IntPtr GetDefaultPanThresholds(); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_GestureThresholds_SetPanThresholds")] + public static extern void SetPanThresholds(global::System.Runtime.InteropServices.HandleRef nuiSelector, global::System.Runtime.InteropServices.HandleRef nuiThresholds); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_GestureThresholds_GetPanThresholds")] + [return: global::System.Runtime.InteropServices.MarshalAs(global::System.Runtime.InteropServices.UnmanagedType.U1)] + public static extern bool GetPanThresholds(global::System.Runtime.InteropServices.HandleRef nuiSelector, global::System.Runtime.InteropServices.HandleRef nuiThresholds); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_GestureThresholds_ClearPanThresholds")] + public static extern void ClearPanThresholds(global::System.Runtime.InteropServices.HandleRef nuiSelector); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_new_GestureThresholds_TapThresholds")] + public static extern global::System.IntPtr NewTapThresholds(); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_delete_GestureThresholds_TapThresholds")] + public static extern void DeleteTapThresholds(global::System.Runtime.InteropServices.HandleRef nuiThresholds); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_GestureThresholds_TapThresholds_SetMaximumMultiTapInterval")] + public static extern void TapThresholdsSetMaximumMultiTapInterval(global::System.Runtime.InteropServices.HandleRef nuiThresholds, uint value); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_GestureThresholds_TapThresholds_GetMaximumMultiTapInterval")] + public static extern uint TapThresholdsGetMaximumMultiTapInterval(global::System.Runtime.InteropServices.HandleRef nuiThresholds); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_GestureThresholds_TapThresholds_SetMaximumHoldingTime")] + public static extern void TapThresholdsSetMaximumHoldingTime(global::System.Runtime.InteropServices.HandleRef nuiThresholds, uint value); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_GestureThresholds_TapThresholds_GetMaximumHoldingTime")] + public static extern uint TapThresholdsGetMaximumHoldingTime(global::System.Runtime.InteropServices.HandleRef nuiThresholds); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_GestureThresholds_TapThresholds_SetMaximumMotionDistance")] + public static extern void TapThresholdsSetMaximumMotionDistance(global::System.Runtime.InteropServices.HandleRef nuiThresholds, float value); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_GestureThresholds_TapThresholds_GetMaximumMotionDistance")] + public static extern float TapThresholdsGetMaximumMotionDistance(global::System.Runtime.InteropServices.HandleRef nuiThresholds); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_GestureThresholds_GetDefaultTapThresholds")] + public static extern global::System.IntPtr GetDefaultTapThresholds(); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_GestureThresholds_SetTapThresholds")] + public static extern void SetTapThresholds(global::System.Runtime.InteropServices.HandleRef nuiSelector, global::System.Runtime.InteropServices.HandleRef nuiThresholds); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_GestureThresholds_GetTapThresholds")] + [return: global::System.Runtime.InteropServices.MarshalAs(global::System.Runtime.InteropServices.UnmanagedType.U1)] + public static extern bool GetTapThresholds(global::System.Runtime.InteropServices.HandleRef nuiSelector, global::System.Runtime.InteropServices.HandleRef nuiThresholds); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_GestureThresholds_ClearTapThresholds")] + public static extern void ClearTapThresholds(global::System.Runtime.InteropServices.HandleRef nuiSelector); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_new_GestureThresholds_LongPressThresholds")] + public static extern global::System.IntPtr NewLongPressThresholds(); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_delete_GestureThresholds_LongPressThresholds")] + public static extern void DeleteLongPressThresholds(global::System.Runtime.InteropServices.HandleRef nuiThresholds); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_GestureThresholds_LongPressThresholds_SetMinimumHoldingTime")] + public static extern void LongPressThresholdsSetMinimumHoldingTime(global::System.Runtime.InteropServices.HandleRef nuiThresholds, uint value); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_GestureThresholds_LongPressThresholds_GetMinimumHoldingTime")] + public static extern uint LongPressThresholdsGetMinimumHoldingTime(global::System.Runtime.InteropServices.HandleRef nuiThresholds); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_GestureThresholds_GetDefaultLongPressThresholds")] + public static extern global::System.IntPtr GetDefaultLongPressThresholds(); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_GestureThresholds_SetLongPressThresholds")] + public static extern void SetLongPressThresholds(global::System.Runtime.InteropServices.HandleRef nuiSelector, global::System.Runtime.InteropServices.HandleRef nuiThresholds); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_GestureThresholds_GetLongPressThresholds")] + [return: global::System.Runtime.InteropServices.MarshalAs(global::System.Runtime.InteropServices.UnmanagedType.U1)] + public static extern bool GetLongPressThresholds(global::System.Runtime.InteropServices.HandleRef nuiSelector, global::System.Runtime.InteropServices.HandleRef nuiThresholds); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_GestureThresholds_ClearLongPressThresholds")] + public static extern void ClearLongPressThresholds(global::System.Runtime.InteropServices.HandleRef nuiSelector); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_new_GestureThresholds_PinchThresholds")] + public static extern global::System.IntPtr NewPinchThresholds(); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_delete_GestureThresholds_PinchThresholds")] + public static extern void DeletePinchThresholds(global::System.Runtime.InteropServices.HandleRef nuiThresholds); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_GestureThresholds_PinchThresholds_SetMinimumDistance")] + public static extern void PinchThresholdsSetMinimumDistance(global::System.Runtime.InteropServices.HandleRef nuiThresholds, float value); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_GestureThresholds_PinchThresholds_GetMinimumDistance")] + public static extern float PinchThresholdsGetMinimumDistance(global::System.Runtime.InteropServices.HandleRef nuiThresholds); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_GestureThresholds_PinchThresholds_SetMinimumTouchEvents")] + public static extern void PinchThresholdsSetMinimumTouchEvents(global::System.Runtime.InteropServices.HandleRef nuiThresholds, uint value); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_GestureThresholds_PinchThresholds_GetMinimumTouchEvents")] + public static extern uint PinchThresholdsGetMinimumTouchEvents(global::System.Runtime.InteropServices.HandleRef nuiThresholds); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_GestureThresholds_PinchThresholds_SetMinimumTouchEventsAfterStart")] + public static extern void PinchThresholdsSetMinimumTouchEventsAfterStart(global::System.Runtime.InteropServices.HandleRef nuiThresholds, uint value); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_GestureThresholds_PinchThresholds_GetMinimumTouchEventsAfterStart")] + public static extern uint PinchThresholdsGetMinimumTouchEventsAfterStart(global::System.Runtime.InteropServices.HandleRef nuiThresholds); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_GestureThresholds_GetDefaultPinchThresholds")] + public static extern global::System.IntPtr GetDefaultPinchThresholds(); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_GestureThresholds_SetPinchThresholds")] + public static extern void SetPinchThresholds(global::System.Runtime.InteropServices.HandleRef nuiSelector, global::System.Runtime.InteropServices.HandleRef nuiThresholds); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_GestureThresholds_GetPinchThresholds")] + [return: global::System.Runtime.InteropServices.MarshalAs(global::System.Runtime.InteropServices.UnmanagedType.U1)] + public static extern bool GetPinchThresholds(global::System.Runtime.InteropServices.HandleRef nuiSelector, global::System.Runtime.InteropServices.HandleRef nuiThresholds); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_GestureThresholds_ClearPinchThresholds")] + public static extern void ClearPinchThresholds(global::System.Runtime.InteropServices.HandleRef nuiSelector); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_new_GestureThresholds_RotationThresholds")] + public static extern global::System.IntPtr NewRotationThresholds(); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_delete_GestureThresholds_RotationThresholds")] + public static extern void DeleteRotationThresholds(global::System.Runtime.InteropServices.HandleRef nuiThresholds); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_GestureThresholds_RotationThresholds_SetMinimumTouchEvents")] + public static extern void RotationThresholdsSetMinimumTouchEvents(global::System.Runtime.InteropServices.HandleRef nuiThresholds, uint value); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_GestureThresholds_RotationThresholds_GetMinimumTouchEvents")] + public static extern uint RotationThresholdsGetMinimumTouchEvents(global::System.Runtime.InteropServices.HandleRef nuiThresholds); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_GestureThresholds_RotationThresholds_SetMinimumTouchEventsAfterStart")] + public static extern void RotationThresholdsSetMinimumTouchEventsAfterStart(global::System.Runtime.InteropServices.HandleRef nuiThresholds, uint value); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_GestureThresholds_RotationThresholds_GetMinimumTouchEventsAfterStart")] + public static extern uint RotationThresholdsGetMinimumTouchEventsAfterStart(global::System.Runtime.InteropServices.HandleRef nuiThresholds); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_GestureThresholds_GetDefaultRotationThresholds")] + public static extern global::System.IntPtr GetDefaultRotationThresholds(); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_GestureThresholds_SetRotationThresholds")] + public static extern void SetRotationThresholds(global::System.Runtime.InteropServices.HandleRef nuiSelector, global::System.Runtime.InteropServices.HandleRef nuiThresholds); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_GestureThresholds_GetRotationThresholds")] + [return: global::System.Runtime.InteropServices.MarshalAs(global::System.Runtime.InteropServices.UnmanagedType.U1)] + public static extern bool GetRotationThresholds(global::System.Runtime.InteropServices.HandleRef nuiSelector, global::System.Runtime.InteropServices.HandleRef nuiThresholds); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_GestureThresholds_ClearRotationThresholds")] + public static extern void ClearRotationThresholds(global::System.Runtime.InteropServices.HandleRef nuiSelector); + } + } +} diff --git a/src/Tizen.NUI/src/internal/Interop/Interop.LongPressGestureDetector.cs b/src/Tizen.NUI/src/internal/Interop/Interop.LongPressGestureDetector.cs index f630c7dd2bc..18946edfcc3 100755 --- a/src/Tizen.NUI/src/internal/Interop/Interop.LongPressGestureDetector.cs +++ b/src/Tizen.NUI/src/internal/Interop/Interop.LongPressGestureDetector.cs @@ -54,6 +54,37 @@ internal static partial class LongPressGestureDetector [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_LongPressGestureDetector_DetectedSignal")] public static extern global::System.IntPtr DetectedSignal(global::System.Runtime.InteropServices.HandleRef jarg1); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_new_LongPressGestureDetector_Options")] + public static extern global::System.IntPtr NewOptions(); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_delete_LongPressGestureDetector_Options")] + public static extern void DeleteOptions(global::System.Runtime.InteropServices.HandleRef nuiOptions); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_LongPressGestureDetector_GetDefaultOptions")] + public static extern global::System.IntPtr GetDefaultOptions(global::System.Runtime.InteropServices.HandleRef nuiDetector); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_LongPressGestureDetector_SetDeviceOptions")] + public static extern void SetDeviceOptions(global::System.Runtime.InteropServices.HandleRef nuiDetector, global::System.Runtime.InteropServices.HandleRef nuiSelector, global::System.Runtime.InteropServices.HandleRef nuiOptions); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_LongPressGestureDetector_GetDeviceOptions")] + [return: global::System.Runtime.InteropServices.MarshalAs(global::System.Runtime.InteropServices.UnmanagedType.U1)] + public static extern bool GetDeviceOptions(global::System.Runtime.InteropServices.HandleRef nuiDetector, global::System.Runtime.InteropServices.HandleRef nuiSelector, global::System.Runtime.InteropServices.HandleRef nuiOptions); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_LongPressGestureDetector_ClearDeviceOptions")] + public static extern void ClearDeviceOptions(global::System.Runtime.InteropServices.HandleRef nuiDetector, global::System.Runtime.InteropServices.HandleRef nuiSelector); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_LongPressGestureDetector_Options_SetTouchesRequired__SWIG_0")] + public static extern void OptionsSetTouchesRequired(global::System.Runtime.InteropServices.HandleRef nuiOptions, uint touches); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_LongPressGestureDetector_Options_SetTouchesRequired__SWIG_1")] + public static extern void OptionsSetTouchesRequired(global::System.Runtime.InteropServices.HandleRef nuiOptions, uint minTouches, uint maxTouches); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_LongPressGestureDetector_Options_GetMinimumTouchesRequired")] + public static extern uint OptionsGetMinimumTouchesRequired(global::System.Runtime.InteropServices.HandleRef nuiOptions); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_LongPressGestureDetector_Options_GetMaximumTouchesRequired")] + public static extern uint OptionsGetMaximumTouchesRequired(global::System.Runtime.InteropServices.HandleRef nuiOptions); } } } diff --git a/src/Tizen.NUI/src/internal/Interop/Interop.PanGestureDetector.cs b/src/Tizen.NUI/src/internal/Interop/Interop.PanGestureDetector.cs index 3b58691e148..9f2de0fd597 100755 --- a/src/Tizen.NUI/src/internal/Interop/Interop.PanGestureDetector.cs +++ b/src/Tizen.NUI/src/internal/Interop/Interop.PanGestureDetector.cs @@ -168,6 +168,70 @@ internal static partial class PanGestureDetector [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_delete_PanGestureDetectedSignal")] public static extern void DeletePanGestureDetectedSignal(global::System.Runtime.InteropServices.HandleRef jarg1); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_new_PanGestureDetector_Options")] + public static extern global::System.IntPtr NewOptions(); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_delete_PanGestureDetector_Options")] + public static extern void DeleteOptions(global::System.Runtime.InteropServices.HandleRef nuiOptions); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_PanGestureDetector_GetDefaultOptions")] + public static extern global::System.IntPtr GetDefaultOptions(global::System.Runtime.InteropServices.HandleRef nuiDetector); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_PanGestureDetector_SetDeviceOptions")] + public static extern void SetDeviceOptions(global::System.Runtime.InteropServices.HandleRef nuiDetector, global::System.Runtime.InteropServices.HandleRef nuiSelector, global::System.Runtime.InteropServices.HandleRef nuiOptions); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_PanGestureDetector_GetDeviceOptions")] + [return: global::System.Runtime.InteropServices.MarshalAs(global::System.Runtime.InteropServices.UnmanagedType.U1)] + public static extern bool GetDeviceOptions(global::System.Runtime.InteropServices.HandleRef nuiDetector, global::System.Runtime.InteropServices.HandleRef nuiSelector, global::System.Runtime.InteropServices.HandleRef nuiOptions); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_PanGestureDetector_ClearDeviceOptions")] + public static extern void ClearDeviceOptions(global::System.Runtime.InteropServices.HandleRef nuiDetector, global::System.Runtime.InteropServices.HandleRef nuiSelector); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_PanGestureDetector_Options_SetMinimumTouchesRequired")] + public static extern void OptionsSetMinimumTouchesRequired(global::System.Runtime.InteropServices.HandleRef nuiOptions, uint value); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_PanGestureDetector_Options_GetMinimumTouchesRequired")] + public static extern uint OptionsGetMinimumTouchesRequired(global::System.Runtime.InteropServices.HandleRef nuiOptions); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_PanGestureDetector_Options_SetMaximumTouchesRequired")] + public static extern void OptionsSetMaximumTouchesRequired(global::System.Runtime.InteropServices.HandleRef nuiOptions, uint value); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_PanGestureDetector_Options_GetMaximumTouchesRequired")] + public static extern uint OptionsGetMaximumTouchesRequired(global::System.Runtime.InteropServices.HandleRef nuiOptions); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_PanGestureDetector_Options_SetMaximumMotionEventAge")] + public static extern void OptionsSetMaximumMotionEventAge(global::System.Runtime.InteropServices.HandleRef nuiOptions, uint value); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_PanGestureDetector_Options_GetMaximumMotionEventAge")] + public static extern uint OptionsGetMaximumMotionEventAge(global::System.Runtime.InteropServices.HandleRef nuiOptions); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_PanGestureDetector_Options_AddAngle__SWIG_0")] + public static extern void OptionsAddAngle(global::System.Runtime.InteropServices.HandleRef nuiOptions, global::System.Runtime.InteropServices.HandleRef nuiAngle, global::System.Runtime.InteropServices.HandleRef nuiThreshold); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_PanGestureDetector_Options_AddAngle__SWIG_1")] + public static extern void OptionsAddAngle(global::System.Runtime.InteropServices.HandleRef nuiOptions, global::System.Runtime.InteropServices.HandleRef nuiAngle); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_PanGestureDetector_Options_AddDirection__SWIG_0")] + public static extern void OptionsAddDirection(global::System.Runtime.InteropServices.HandleRef nuiOptions, global::System.Runtime.InteropServices.HandleRef nuiDirection, global::System.Runtime.InteropServices.HandleRef nuiThreshold); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_PanGestureDetector_Options_AddDirection__SWIG_1")] + public static extern void OptionsAddDirection(global::System.Runtime.InteropServices.HandleRef nuiOptions, global::System.Runtime.InteropServices.HandleRef nuiDirection); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_PanGestureDetector_Options_GetAngleCount")] + public static extern uint OptionsGetAngleCount(global::System.Runtime.InteropServices.HandleRef nuiOptions); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_PanGestureDetector_Options_GetAngle")] + public static extern global::System.IntPtr OptionsGetAngle(global::System.Runtime.InteropServices.HandleRef nuiOptions, uint index); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_PanGestureDetector_Options_ClearAngles")] + public static extern void OptionsClearAngles(global::System.Runtime.InteropServices.HandleRef nuiOptions); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_PanGestureDetector_Options_RemoveAngle")] + public static extern void OptionsRemoveAngle(global::System.Runtime.InteropServices.HandleRef nuiOptions, global::System.Runtime.InteropServices.HandleRef nuiAngle); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_PanGestureDetector_Options_RemoveDirection")] + public static extern void OptionsRemoveDirection(global::System.Runtime.InteropServices.HandleRef nuiOptions, global::System.Runtime.InteropServices.HandleRef nuiDirection); } } } diff --git a/src/Tizen.NUI/src/internal/Interop/Interop.TapGestureDetector.cs b/src/Tizen.NUI/src/internal/Interop/Interop.TapGestureDetector.cs index 34b8139b984..5679c6a7e45 100755 --- a/src/Tizen.NUI/src/internal/Interop/Interop.TapGestureDetector.cs +++ b/src/Tizen.NUI/src/internal/Interop/Interop.TapGestureDetector.cs @@ -51,6 +51,51 @@ internal static partial class TapGestureDetector [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_TapGestureDetector_DetectedSignal")] public static extern global::System.IntPtr DetectedSignal(global::System.Runtime.InteropServices.HandleRef jarg1); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_new_TapGestureDetector_Options")] + public static extern global::System.IntPtr NewOptions(); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_delete_TapGestureDetector_Options")] + public static extern void DeleteOptions(global::System.Runtime.InteropServices.HandleRef nuiOptions); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_TapGestureDetector_GetDefaultOptions")] + public static extern global::System.IntPtr GetDefaultOptions(global::System.Runtime.InteropServices.HandleRef nuiDetector); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_TapGestureDetector_SetDeviceOptions")] + public static extern void SetDeviceOptions(global::System.Runtime.InteropServices.HandleRef nuiDetector, global::System.Runtime.InteropServices.HandleRef nuiSelector, global::System.Runtime.InteropServices.HandleRef nuiOptions); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_TapGestureDetector_GetDeviceOptions")] + [return: global::System.Runtime.InteropServices.MarshalAs(global::System.Runtime.InteropServices.UnmanagedType.U1)] + public static extern bool GetDeviceOptions(global::System.Runtime.InteropServices.HandleRef nuiDetector, global::System.Runtime.InteropServices.HandleRef nuiSelector, global::System.Runtime.InteropServices.HandleRef nuiOptions); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_TapGestureDetector_ClearDeviceOptions")] + public static extern void ClearDeviceOptions(global::System.Runtime.InteropServices.HandleRef nuiDetector, global::System.Runtime.InteropServices.HandleRef nuiSelector); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_TapGestureDetector_Options_SetMinimumTapsRequired")] + public static extern void OptionsSetMinimumTapsRequired(global::System.Runtime.InteropServices.HandleRef nuiOptions, uint value); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_TapGestureDetector_Options_GetMinimumTapsRequired")] + public static extern uint OptionsGetMinimumTapsRequired(global::System.Runtime.InteropServices.HandleRef nuiOptions); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_TapGestureDetector_Options_SetMaximumTapsRequired")] + public static extern void OptionsSetMaximumTapsRequired(global::System.Runtime.InteropServices.HandleRef nuiOptions, uint value); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_TapGestureDetector_Options_GetMaximumTapsRequired")] + public static extern uint OptionsGetMaximumTapsRequired(global::System.Runtime.InteropServices.HandleRef nuiOptions); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_TapGestureDetector_Options_SetReceiveAllTapEventsEnabled")] + public static extern void OptionsSetReceiveAllTapEventsEnabled(global::System.Runtime.InteropServices.HandleRef nuiOptions, bool value); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_TapGestureDetector_Options_IsReceiveAllTapEventsEnabled")] + [return: global::System.Runtime.InteropServices.MarshalAs(global::System.Runtime.InteropServices.UnmanagedType.U1)] + public static extern bool OptionsIsReceiveAllTapEventsEnabled(global::System.Runtime.InteropServices.HandleRef nuiOptions); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_TapGestureDetector_ReceiveAllTapEvents")] + public static extern void ReceiveAllTapEvents(global::System.Runtime.InteropServices.HandleRef nuiDetector, bool receive); + + [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_TapGestureDetector_IsReceiveAllTapEventsEnabled")] + [return: global::System.Runtime.InteropServices.MarshalAs(global::System.Runtime.InteropServices.UnmanagedType.U1)] + public static extern bool IsReceiveAllTapEventsEnabled(global::System.Runtime.InteropServices.HandleRef nuiDetector); } } } diff --git a/src/Tizen.NUI/src/public/Events/Gesture.cs b/src/Tizen.NUI/src/public/Events/Gesture.cs index 0ea1a0e2c91..b210a568569 100755 --- a/src/Tizen.NUI/src/public/Events/Gesture.cs +++ b/src/Tizen.NUI/src/public/Events/Gesture.cs @@ -294,6 +294,22 @@ public Gesture.SourceSubType SourceSub } } + /// + /// The name of the input device that started this gesture (read-only).
+ /// Empty when the device did not report a name. Pass it to + /// to register options or thresholds for exactly that device. + ///
+ [EditorBrowsable(EditorBrowsableState.Never)] + public string DeviceName + { + get + { + string ret = Interop.Gesture.GetDeviceName(SwigCPtr); + if (NDalicPINVOKE.SWIGPendingException.Pending) throw new global::System.InvalidOperationException("FATAL: get Exception", NDalicPINVOKE.SWIGPendingException.Retrieve()); + return ret; + } + } + private Gesture.GestureType type { get diff --git a/src/Tizen.NUI/src/public/Events/GestureDeviceSelector.cs b/src/Tizen.NUI/src/public/Events/GestureDeviceSelector.cs new file mode 100644 index 00000000000..a6b28926572 --- /dev/null +++ b/src/Tizen.NUI/src/public/Events/GestureDeviceSelector.cs @@ -0,0 +1,221 @@ +/* + * Copyright(c) 2026 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. + * + */ + +using System; +using System.ComponentModel; +using System.Runtime.InteropServices; + +namespace Tizen.NUI +{ + /// + /// Selects the input devices that a set of gesture options or recognition thresholds applies to.
+ /// A selector matches a gesture by the exact name of the device that started it, by the device class and subclass, + /// or by the device class alone. When several selectors registered on the same object match one gesture, + /// the most specific one wins: device name first, then class and subclass, then class.
+ /// Device names are compared exactly (case-sensitive, no normalization). Read the name to use from + /// or . + ///
+ /// This will be public opened after ACR done. Before ACR, need to be hidden as inhouse API. + [EditorBrowsable(EditorBrowsableState.Never)] + public sealed class GestureDeviceSelector : Disposable + { + /// + /// How a selector matches an input device. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public enum MatchType + { + /// + /// Matches the exact device name. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + DeviceName = 0, + + /// + /// Matches the device class only. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + DeviceClass = 1, + + /// + /// Matches the device class and subclass. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + DeviceClassAndSubclass = 2, + } + + /// + /// Creates a selector that matches by device class. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public GestureDeviceSelector() : this(Interop.GestureDeviceSelector.New(), true) + { + if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); + } + + internal GestureDeviceSelector(global::System.IntPtr cPtr, bool cMemoryOwn) : base(cPtr, cMemoryOwn, false) + { + } + + /// + /// Creates a selector that matches every device of the given class. + /// + /// The device class to match. + /// The selector. + [EditorBrowsable(EditorBrowsableState.Never)] + public static GestureDeviceSelector ByDeviceClass(DeviceClassType deviceClass) + { + GestureDeviceSelector ret = new GestureDeviceSelector(Interop.GestureDeviceSelector.ByDeviceClass((int)deviceClass), true); + if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); + return ret; + } + + /// + /// Creates a selector that matches every device of the given class and subclass. + /// + /// The device class to match. + /// The device subclass to match. + /// The selector. + [EditorBrowsable(EditorBrowsableState.Never)] + public static GestureDeviceSelector ByDeviceClassAndSubclass(DeviceClassType deviceClass, DeviceSubClassType deviceSubClass) + { + GestureDeviceSelector ret = new GestureDeviceSelector(Interop.GestureDeviceSelector.ByDeviceClassAndSubclass((int)deviceClass, (int)deviceSubClass), true); + if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); + return ret; + } + + /// + /// Creates a selector that matches one device by its exact name. + /// + /// The device name as reported by the input system. Must not be null or empty. + /// The selector. + /// Thrown when is null or empty. + [EditorBrowsable(EditorBrowsableState.Never)] + public static GestureDeviceSelector ByDeviceName(string deviceName) + { + if (string.IsNullOrEmpty(deviceName)) + { + throw new ArgumentException("Device name must not be null or empty.", nameof(deviceName)); + } + + GestureDeviceSelector ret = new GestureDeviceSelector(Interop.GestureDeviceSelector.ByDeviceName(deviceName), true); + if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); + return ret; + } + + /// + /// Gets how this selector matches a device (read-only). + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public GestureDeviceSelector.MatchType Match + { + get + { + GestureDeviceSelector.MatchType ret = (GestureDeviceSelector.MatchType)Interop.GestureDeviceSelector.GetMatchType(SwigCPtr); + if (NDalicPINVOKE.SWIGPendingException.Pending) throw new InvalidOperationException("FATAL: get Exception", NDalicPINVOKE.SWIGPendingException.Retrieve()); + return ret; + } + } + + /// + /// Gets the device class this selector matches (read-only).
+ /// when is . + ///
+ [EditorBrowsable(EditorBrowsableState.Never)] + public DeviceClassType DeviceClass + { + get + { + DeviceClassType ret = (DeviceClassType)Interop.GestureDeviceSelector.GetDeviceClass(SwigCPtr); + if (NDalicPINVOKE.SWIGPendingException.Pending) throw new InvalidOperationException("FATAL: get Exception", NDalicPINVOKE.SWIGPendingException.Retrieve()); + return ret; + } + } + + /// + /// Gets the device subclass this selector matches (read-only).
+ /// unless is . + ///
+ [EditorBrowsable(EditorBrowsableState.Never)] + public DeviceSubClassType DeviceSubClass + { + get + { + DeviceSubClassType ret = (DeviceSubClassType)Interop.GestureDeviceSelector.GetDeviceSubclass(SwigCPtr); + if (NDalicPINVOKE.SWIGPendingException.Pending) throw new InvalidOperationException("FATAL: get Exception", NDalicPINVOKE.SWIGPendingException.Retrieve()); + return ret; + } + } + + /// + /// Gets the device name this selector matches (read-only).
+ /// Empty unless is . + ///
+ [EditorBrowsable(EditorBrowsableState.Never)] + public string DeviceName + { + get + { + string ret = Interop.GestureDeviceSelector.GetDeviceName(SwigCPtr); + if (NDalicPINVOKE.SWIGPendingException.Pending) throw new InvalidOperationException("FATAL: get Exception", NDalicPINVOKE.SWIGPendingException.Retrieve()); + return ret; + } + } + + /// + /// Determines whether the specified object is a selector with the same match type and keys. + /// + /// The object to compare with. + /// True if both selectors match the same devices. False when either selector has been disposed. + [EditorBrowsable(EditorBrowsableState.Never)] + public override bool Equals(object obj) + { + GestureDeviceSelector other = obj as GestureDeviceSelector; + if (other == null) + { + return false; + } + + bool ret = Interop.GestureDeviceSelector.IsEqual(SwigCPtr, GestureDeviceSelector.getCPtr(other)); + if (NDalicPINVOKE.SWIGPendingException.Pending) + { + // Only a disposed selector reaches here; Equals must not throw, so treat it as not equal. + NDalicPINVOKE.SWIGPendingException.Retrieve(); + return false; + } + + return ret; + } + + /// + /// Returns a hash code consistent with . + /// + /// The hash code. + [EditorBrowsable(EditorBrowsableState.Never)] + public override int GetHashCode() + { + return HashCode.Combine(Match, DeviceClass, DeviceSubClass, DeviceName); + } + + /// This will not be public opened. + [EditorBrowsable(EditorBrowsableState.Never)] + protected override void ReleaseSwigCPtr(HandleRef swigCPtr) + { + Interop.GestureDeviceSelector.Delete(swigCPtr); + } + } +} diff --git a/src/Tizen.NUI/src/public/Events/GestureOptions.cs b/src/Tizen.NUI/src/public/Events/GestureOptions.cs index 1e5116ea7eb..0d0fcb95b2b 100644 --- a/src/Tizen.NUI/src/public/Events/GestureOptions.cs +++ b/src/Tizen.NUI/src/public/Events/GestureOptions.cs @@ -407,5 +407,340 @@ public void SetTapMaximumMotionAllowedDistance(float distance) Interop.GestureOptions.SetTapMaximumMotionAllowedDistance(distance); if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); } + + /// + /// Returns a copy of the pan recognition thresholds used when no device-specific thresholds match. + /// + /// This is a global configuration option. Affects all pan gesture detectors. + /// A new PanThresholds object. Dispose it when no longer needed. + [EditorBrowsable(EditorBrowsableState.Never)] + public PanThresholds GetDefaultPanThresholds() + { + PanThresholds ret = new PanThresholds(Interop.GestureThresholds.GetDefaultPanThresholds(), true); + if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); + return ret; + } + + /// + /// Registers the pan recognition thresholds to use for gestures that start on a device matching the selector.
+ /// Registering with an equal selector replaces the earlier thresholds. The values are copied, so later changes to + /// have no effect until they are set again. + ///
+ /// This is a global configuration option. Affects all pan gesture detectors, including those created by components. + /// The devices the thresholds apply to. + /// The complete thresholds for those devices. + [EditorBrowsable(EditorBrowsableState.Never)] + public void SetPanThresholds(GestureDeviceSelector selector, PanThresholds thresholds) + { + Interop.GestureThresholds.SetPanThresholds(GestureDeviceSelector.getCPtr(selector), PanThresholds.getCPtr(thresholds)); + if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); + } + + /// + /// Retrieves the pan recognition thresholds registered for exactly this selector. Fallback to a less specific selector is not applied. + /// + /// The selector the thresholds were registered with. + /// The registered thresholds, or null when none are registered for the selector. + /// True when thresholds are registered for the selector. + [EditorBrowsable(EditorBrowsableState.Never)] + public bool TryGetPanThresholds(GestureDeviceSelector selector, out PanThresholds thresholds) + { + PanThresholds result = new PanThresholds(); + bool found = Interop.GestureThresholds.GetPanThresholds(GestureDeviceSelector.getCPtr(selector), PanThresholds.getCPtr(result)); + if (NDalicPINVOKE.SWIGPendingException.Pending) + { + result.Dispose(); + throw NDalicPINVOKE.SWIGPendingException.Retrieve(); + } + + if (!found) + { + result.Dispose(); + thresholds = null; + return false; + } + + thresholds = result; + return true; + } + + /// + /// Removes the pan recognition thresholds registered for exactly this selector. Does nothing when none are registered. + /// + /// The selector the thresholds were registered with. + [EditorBrowsable(EditorBrowsableState.Never)] + public void ClearPanThresholds(GestureDeviceSelector selector) + { + Interop.GestureThresholds.ClearPanThresholds(GestureDeviceSelector.getCPtr(selector)); + if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); + } + + /// + /// Returns a copy of the tap recognition thresholds used when no device-specific thresholds match. + /// + /// This is a global configuration option. Affects all tap gesture detectors. + /// A new TapThresholds object. Dispose it when no longer needed. + [EditorBrowsable(EditorBrowsableState.Never)] + public TapThresholds GetDefaultTapThresholds() + { + TapThresholds ret = new TapThresholds(Interop.GestureThresholds.GetDefaultTapThresholds(), true); + if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); + return ret; + } + + /// + /// Registers the tap recognition thresholds to use for gestures that start on a device matching the selector.
+ /// Registering with an equal selector replaces the earlier thresholds. The values are copied, so later changes to + /// have no effect until they are set again. + ///
+ /// This is a global configuration option. Affects all tap gesture detectors, including those created by components. + /// The devices the thresholds apply to. + /// The complete thresholds for those devices. + [EditorBrowsable(EditorBrowsableState.Never)] + public void SetTapThresholds(GestureDeviceSelector selector, TapThresholds thresholds) + { + Interop.GestureThresholds.SetTapThresholds(GestureDeviceSelector.getCPtr(selector), TapThresholds.getCPtr(thresholds)); + if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); + } + + /// + /// Retrieves the tap recognition thresholds registered for exactly this selector. Fallback to a less specific selector is not applied. + /// + /// The selector the thresholds were registered with. + /// The registered thresholds, or null when none are registered for the selector. + /// True when thresholds are registered for the selector. + [EditorBrowsable(EditorBrowsableState.Never)] + public bool TryGetTapThresholds(GestureDeviceSelector selector, out TapThresholds thresholds) + { + TapThresholds result = new TapThresholds(); + bool found = Interop.GestureThresholds.GetTapThresholds(GestureDeviceSelector.getCPtr(selector), TapThresholds.getCPtr(result)); + if (NDalicPINVOKE.SWIGPendingException.Pending) + { + result.Dispose(); + throw NDalicPINVOKE.SWIGPendingException.Retrieve(); + } + + if (!found) + { + result.Dispose(); + thresholds = null; + return false; + } + + thresholds = result; + return true; + } + + /// + /// Removes the tap recognition thresholds registered for exactly this selector. Does nothing when none are registered. + /// + /// The selector the thresholds were registered with. + [EditorBrowsable(EditorBrowsableState.Never)] + public void ClearTapThresholds(GestureDeviceSelector selector) + { + Interop.GestureThresholds.ClearTapThresholds(GestureDeviceSelector.getCPtr(selector)); + if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); + } + + /// + /// Returns a copy of the long press recognition thresholds used when no device-specific thresholds match. + /// + /// This is a global configuration option. Affects all long press gesture detectors. + /// A new LongPressThresholds object. Dispose it when no longer needed. + [EditorBrowsable(EditorBrowsableState.Never)] + public LongPressThresholds GetDefaultLongPressThresholds() + { + LongPressThresholds ret = new LongPressThresholds(Interop.GestureThresholds.GetDefaultLongPressThresholds(), true); + if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); + return ret; + } + + /// + /// Registers the long press recognition thresholds to use for gestures that start on a device matching the selector.
+ /// Registering with an equal selector replaces the earlier thresholds. The values are copied, so later changes to + /// have no effect until they are set again. + ///
+ /// This is a global configuration option. Affects all long press gesture detectors, including those created by components. + /// The devices the thresholds apply to. + /// The complete thresholds for those devices. + [EditorBrowsable(EditorBrowsableState.Never)] + public void SetLongPressThresholds(GestureDeviceSelector selector, LongPressThresholds thresholds) + { + Interop.GestureThresholds.SetLongPressThresholds(GestureDeviceSelector.getCPtr(selector), LongPressThresholds.getCPtr(thresholds)); + if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); + } + + /// + /// Retrieves the long press recognition thresholds registered for exactly this selector. Fallback to a less specific selector is not applied. + /// + /// The selector the thresholds were registered with. + /// The registered thresholds, or null when none are registered for the selector. + /// True when thresholds are registered for the selector. + [EditorBrowsable(EditorBrowsableState.Never)] + public bool TryGetLongPressThresholds(GestureDeviceSelector selector, out LongPressThresholds thresholds) + { + LongPressThresholds result = new LongPressThresholds(); + bool found = Interop.GestureThresholds.GetLongPressThresholds(GestureDeviceSelector.getCPtr(selector), LongPressThresholds.getCPtr(result)); + if (NDalicPINVOKE.SWIGPendingException.Pending) + { + result.Dispose(); + throw NDalicPINVOKE.SWIGPendingException.Retrieve(); + } + + if (!found) + { + result.Dispose(); + thresholds = null; + return false; + } + + thresholds = result; + return true; + } + + /// + /// Removes the long press recognition thresholds registered for exactly this selector. Does nothing when none are registered. + /// + /// The selector the thresholds were registered with. + [EditorBrowsable(EditorBrowsableState.Never)] + public void ClearLongPressThresholds(GestureDeviceSelector selector) + { + Interop.GestureThresholds.ClearLongPressThresholds(GestureDeviceSelector.getCPtr(selector)); + if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); + } + + /// + /// Returns a copy of the pinch recognition thresholds used when no device-specific thresholds match. + /// + /// This is a global configuration option. Affects all pinch gesture detectors. + /// A new PinchThresholds object. Dispose it when no longer needed. + [EditorBrowsable(EditorBrowsableState.Never)] + public PinchThresholds GetDefaultPinchThresholds() + { + PinchThresholds ret = new PinchThresholds(Interop.GestureThresholds.GetDefaultPinchThresholds(), true); + if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); + return ret; + } + + /// + /// Registers the pinch recognition thresholds to use for gestures that start on a device matching the selector.
+ /// Registering with an equal selector replaces the earlier thresholds. The values are copied, so later changes to + /// have no effect until they are set again. + ///
+ /// This is a global configuration option. Affects all pinch gesture detectors, including those created by components. + /// The devices the thresholds apply to. + /// The complete thresholds for those devices. + [EditorBrowsable(EditorBrowsableState.Never)] + public void SetPinchThresholds(GestureDeviceSelector selector, PinchThresholds thresholds) + { + Interop.GestureThresholds.SetPinchThresholds(GestureDeviceSelector.getCPtr(selector), PinchThresholds.getCPtr(thresholds)); + if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); + } + + /// + /// Retrieves the pinch recognition thresholds registered for exactly this selector. Fallback to a less specific selector is not applied. + /// + /// The selector the thresholds were registered with. + /// The registered thresholds, or null when none are registered for the selector. + /// True when thresholds are registered for the selector. + [EditorBrowsable(EditorBrowsableState.Never)] + public bool TryGetPinchThresholds(GestureDeviceSelector selector, out PinchThresholds thresholds) + { + PinchThresholds result = new PinchThresholds(); + bool found = Interop.GestureThresholds.GetPinchThresholds(GestureDeviceSelector.getCPtr(selector), PinchThresholds.getCPtr(result)); + if (NDalicPINVOKE.SWIGPendingException.Pending) + { + result.Dispose(); + throw NDalicPINVOKE.SWIGPendingException.Retrieve(); + } + + if (!found) + { + result.Dispose(); + thresholds = null; + return false; + } + + thresholds = result; + return true; + } + + /// + /// Removes the pinch recognition thresholds registered for exactly this selector. Does nothing when none are registered. + /// + /// The selector the thresholds were registered with. + [EditorBrowsable(EditorBrowsableState.Never)] + public void ClearPinchThresholds(GestureDeviceSelector selector) + { + Interop.GestureThresholds.ClearPinchThresholds(GestureDeviceSelector.getCPtr(selector)); + if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); + } + + /// + /// Returns a copy of the rotation recognition thresholds used when no device-specific thresholds match. + /// + /// This is a global configuration option. Affects all rotation gesture detectors. + /// A new RotationThresholds object. Dispose it when no longer needed. + [EditorBrowsable(EditorBrowsableState.Never)] + public RotationThresholds GetDefaultRotationThresholds() + { + RotationThresholds ret = new RotationThresholds(Interop.GestureThresholds.GetDefaultRotationThresholds(), true); + if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); + return ret; + } + + /// + /// Registers the rotation recognition thresholds to use for gestures that start on a device matching the selector.
+ /// Registering with an equal selector replaces the earlier thresholds. The values are copied, so later changes to + /// have no effect until they are set again. + ///
+ /// This is a global configuration option. Affects all rotation gesture detectors, including those created by components. + /// The devices the thresholds apply to. + /// The complete thresholds for those devices. + [EditorBrowsable(EditorBrowsableState.Never)] + public void SetRotationThresholds(GestureDeviceSelector selector, RotationThresholds thresholds) + { + Interop.GestureThresholds.SetRotationThresholds(GestureDeviceSelector.getCPtr(selector), RotationThresholds.getCPtr(thresholds)); + if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); + } + + /// + /// Retrieves the rotation recognition thresholds registered for exactly this selector. Fallback to a less specific selector is not applied. + /// + /// The selector the thresholds were registered with. + /// The registered thresholds, or null when none are registered for the selector. + /// True when thresholds are registered for the selector. + [EditorBrowsable(EditorBrowsableState.Never)] + public bool TryGetRotationThresholds(GestureDeviceSelector selector, out RotationThresholds thresholds) + { + RotationThresholds result = new RotationThresholds(); + bool found = Interop.GestureThresholds.GetRotationThresholds(GestureDeviceSelector.getCPtr(selector), RotationThresholds.getCPtr(result)); + if (NDalicPINVOKE.SWIGPendingException.Pending) + { + result.Dispose(); + throw NDalicPINVOKE.SWIGPendingException.Retrieve(); + } + + if (!found) + { + result.Dispose(); + thresholds = null; + return false; + } + + thresholds = result; + return true; + } + + /// + /// Removes the rotation recognition thresholds registered for exactly this selector. Does nothing when none are registered. + /// + /// The selector the thresholds were registered with. + [EditorBrowsable(EditorBrowsableState.Never)] + public void ClearRotationThresholds(GestureDeviceSelector selector) + { + Interop.GestureThresholds.ClearRotationThresholds(GestureDeviceSelector.getCPtr(selector)); + if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); + } } } diff --git a/src/Tizen.NUI/src/public/Events/LongPressGestureDetector.cs b/src/Tizen.NUI/src/public/Events/LongPressGestureDetector.cs index 0b57a531ee0..7cd1d9520e8 100755 --- a/src/Tizen.NUI/src/public/Events/LongPressGestureDetector.cs +++ b/src/Tizen.NUI/src/public/Events/LongPressGestureDetector.cs @@ -332,5 +332,150 @@ public bool Handled } } } + + /// + /// Recognition options of a long press gesture detector that can differ per input device: the touches required.
+ /// An Options object is a complete snapshot of the settings; the detector applies the snapshot registered for the + /// most specific matching and otherwise its own settings.
+ /// Start from to keep the values you do not want to change. + ///
+ [EditorBrowsable(EditorBrowsableState.Never)] + public sealed class Options : Disposable + { + /// + /// Creates an Options object holding the built-in default settings. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Options() : this(Interop.LongPressGestureDetector.NewOptions(), true) + { + if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); + } + + internal Options(global::System.IntPtr cPtr, bool cMemoryOwn) : base(cPtr, cMemoryOwn, false) + { + } + + /// + /// Sets the exact number of touches required for the long press gesture to be detected. + /// + /// The number of touches required. + [EditorBrowsable(EditorBrowsableState.Never)] + public void SetTouchesRequired(uint touches) + { + Interop.LongPressGestureDetector.OptionsSetTouchesRequired(SwigCPtr, touches); + if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); + } + + /// + /// Sets the minimum and maximum number of touches required for the long press gesture to be detected. + /// + /// The minimum number of touches required. + /// The maximum number of touches required. + [EditorBrowsable(EditorBrowsableState.Never)] + public void SetTouchesRequired(uint minTouches, uint maxTouches) + { + Interop.LongPressGestureDetector.OptionsSetTouchesRequired(SwigCPtr, minTouches, maxTouches); + if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); + } + + /// + /// Gets the minimum number of touches required (read-only). The default is 1. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public uint MinimumTouchesRequired + { + get + { + uint ret = Interop.LongPressGestureDetector.OptionsGetMinimumTouchesRequired(SwigCPtr); + if (NDalicPINVOKE.SWIGPendingException.Pending) throw new InvalidOperationException("FATAL: get Exception", NDalicPINVOKE.SWIGPendingException.Retrieve()); + return ret; + } + } + + /// + /// Gets the maximum number of touches required (read-only). The default is 1. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public uint MaximumTouchesRequired + { + get + { + uint ret = Interop.LongPressGestureDetector.OptionsGetMaximumTouchesRequired(SwigCPtr); + if (NDalicPINVOKE.SWIGPendingException.Pending) throw new InvalidOperationException("FATAL: get Exception", NDalicPINVOKE.SWIGPendingException.Retrieve()); + return ret; + } + } + /// This will not be public opened. + [EditorBrowsable(EditorBrowsableState.Never)] + protected override void ReleaseSwigCPtr(HandleRef swigCPtr) + { + Interop.LongPressGestureDetector.DeleteOptions(swigCPtr); + } + } + + /// + /// Returns a copy of the settings this detector uses when no device-specific options match. + /// + /// A new Options object. Dispose it when no longer needed. + [EditorBrowsable(EditorBrowsableState.Never)] + public Options GetDefaultOptions() + { + Options ret = new Options(Interop.LongPressGestureDetector.GetDefaultOptions(SwigCPtr), true); + if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); + return ret; + } + + /// + /// Registers the settings to use for gestures that start on a device matching the selector.
+ /// Registering with an equal selector replaces the earlier settings. The detector copies the options, + /// so later changes to have no effect until it is set again. + ///
+ /// The devices the options apply to. + /// The complete settings for those devices. + [EditorBrowsable(EditorBrowsableState.Never)] + public void SetDeviceOptions(GestureDeviceSelector selector, Options options) + { + Interop.LongPressGestureDetector.SetDeviceOptions(SwigCPtr, GestureDeviceSelector.getCPtr(selector), Options.getCPtr(options)); + if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); + } + + /// + /// Retrieves the settings registered for exactly this selector. Fallback to a less specific selector is not applied. + /// + /// The selector the options were registered with. + /// The registered settings, or null when none are registered for the selector. + /// True when settings are registered for the selector. + [EditorBrowsable(EditorBrowsableState.Never)] + public bool TryGetDeviceOptions(GestureDeviceSelector selector, out Options options) + { + Options result = new Options(); + bool found = Interop.LongPressGestureDetector.GetDeviceOptions(SwigCPtr, GestureDeviceSelector.getCPtr(selector), Options.getCPtr(result)); + if (NDalicPINVOKE.SWIGPendingException.Pending) + { + result.Dispose(); + throw NDalicPINVOKE.SWIGPendingException.Retrieve(); + } + + if (!found) + { + result.Dispose(); + options = null; + return false; + } + + options = result; + return true; + } + + /// + /// Removes the settings registered for exactly this selector. Does nothing when none are registered. + /// + /// The selector the options were registered with. + [EditorBrowsable(EditorBrowsableState.Never)] + public void ClearDeviceOptions(GestureDeviceSelector selector) + { + Interop.LongPressGestureDetector.ClearDeviceOptions(SwigCPtr, GestureDeviceSelector.getCPtr(selector)); + if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); + } } } diff --git a/src/Tizen.NUI/src/public/Events/LongPressThresholds.cs b/src/Tizen.NUI/src/public/Events/LongPressThresholds.cs new file mode 100644 index 00000000000..537c82618df --- /dev/null +++ b/src/Tizen.NUI/src/public/Events/LongPressThresholds.cs @@ -0,0 +1,72 @@ +/* + * Copyright(c) 2026 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. + * + */ + +using System; +using System.ComponentModel; +using System.Runtime.InteropServices; + +namespace Tizen.NUI +{ + /// + /// Recognition thresholds of the long press gesture.
+ /// Register a per-device set with ; it applies to every + /// long press gesture detector in the application, including those created by components, for gestures that start on a matching device. + /// Start from to keep the values you do not want to change. + ///
+ /// This will be public opened after ACR done. Before ACR, need to be hidden as inhouse API. + [EditorBrowsable(EditorBrowsableState.Never)] + public sealed class LongPressThresholds : Disposable + { + /// + /// Creates a thresholds object holding the built-in default values. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public LongPressThresholds() : this(Interop.GestureThresholds.NewLongPressThresholds(), true) + { + if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); + } + + internal LongPressThresholds(global::System.IntPtr cPtr, bool cMemoryOwn) : base(cPtr, cMemoryOwn, false) + { + } + + /// + /// Gets or sets the minimum time, in milliseconds, a touch must be held before a long press is recognized. The default is 500. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public uint MinimumHoldingTime + { + get + { + uint ret = Interop.GestureThresholds.LongPressThresholdsGetMinimumHoldingTime(SwigCPtr); + if (NDalicPINVOKE.SWIGPendingException.Pending) throw new InvalidOperationException("FATAL: get Exception", NDalicPINVOKE.SWIGPendingException.Retrieve()); + return ret; + } + set + { + Interop.GestureThresholds.LongPressThresholdsSetMinimumHoldingTime(SwigCPtr, value); + if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); + } + } + /// This will not be public opened. + [EditorBrowsable(EditorBrowsableState.Never)] + protected override void ReleaseSwigCPtr(HandleRef swigCPtr) + { + Interop.GestureThresholds.DeleteLongPressThresholds(swigCPtr); + } + } +} diff --git a/src/Tizen.NUI/src/public/Events/PanGestureDetector.cs b/src/Tizen.NUI/src/public/Events/PanGestureDetector.cs index ca3086f7f17..b9a1a7b0581 100755 --- a/src/Tizen.NUI/src/public/Events/PanGestureDetector.cs +++ b/src/Tizen.NUI/src/public/Events/PanGestureDetector.cs @@ -750,6 +750,255 @@ public bool Handled } } + /// + /// Recognition options of a pan gesture detector that can differ per input device: the touches required, + /// the maximum motion event age and the allowed angles.
+ /// An Options object is a complete snapshot of the settings; the detector applies the snapshot registered for the + /// most specific matching and otherwise its own settings.
+ /// Start from to keep the values you do not want to change. + ///
+ [EditorBrowsable(EditorBrowsableState.Never)] + public sealed class Options : Disposable + { + /// + /// Creates an Options object holding the built-in default settings. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Options() : this(Interop.PanGestureDetector.NewOptions(), true) + { + if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); + } + + internal Options(global::System.IntPtr cPtr, bool cMemoryOwn) : base(cPtr, cMemoryOwn, false) + { + } + + /// + /// Gets or sets the minimum number of touches required for the pan gesture to be detected. The default is 1. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public uint MinimumTouchesRequired + { + get + { + uint ret = Interop.PanGestureDetector.OptionsGetMinimumTouchesRequired(SwigCPtr); + if (NDalicPINVOKE.SWIGPendingException.Pending) throw new InvalidOperationException("FATAL: get Exception", NDalicPINVOKE.SWIGPendingException.Retrieve()); + return ret; + } + set + { + Interop.PanGestureDetector.OptionsSetMinimumTouchesRequired(SwigCPtr, value); + if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); + } + } + + /// + /// Gets or sets the maximum number of touches required for the pan gesture to be detected. The default is 1. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public uint MaximumTouchesRequired + { + get + { + uint ret = Interop.PanGestureDetector.OptionsGetMaximumTouchesRequired(SwigCPtr); + if (NDalicPINVOKE.SWIGPendingException.Pending) throw new InvalidOperationException("FATAL: get Exception", NDalicPINVOKE.SWIGPendingException.Retrieve()); + return ret; + } + set + { + Interop.PanGestureDetector.OptionsSetMaximumTouchesRequired(SwigCPtr, value); + if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); + } + } + + /// + /// Gets or sets the maximum age, in milliseconds, of a motion event for the pan gesture to be emitted. The default is unlimited (uint.MaxValue). + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public uint MaximumMotionEventAge + { + get + { + uint ret = Interop.PanGestureDetector.OptionsGetMaximumMotionEventAge(SwigCPtr); + if (NDalicPINVOKE.SWIGPendingException.Pending) throw new InvalidOperationException("FATAL: get Exception", NDalicPINVOKE.SWIGPendingException.Retrieve()); + return ret; + } + set + { + Interop.PanGestureDetector.OptionsSetMaximumMotionEventAge(SwigCPtr, value); + if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); + } + } + + /// + /// Adds an angle, with a +/- threshold allowance, in which the pan gesture is emitted. + /// + /// The angle that pan should be allowed. + /// The threshold around that angle. + [EditorBrowsable(EditorBrowsableState.Never)] + public void AddAngle(Radian angle, Radian threshold) + { + Interop.PanGestureDetector.OptionsAddAngle(SwigCPtr, Radian.getCPtr(angle), Radian.getCPtr(threshold)); + if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); + } + + /// + /// Adds an angle in which the pan gesture is emitted, using the default threshold (PI * 0.25). + /// + /// The angle that pan should be allowed. + [EditorBrowsable(EditorBrowsableState.Never)] + public void AddAngle(Radian angle) + { + Interop.PanGestureDetector.OptionsAddAngle(SwigCPtr, Radian.getCPtr(angle)); + if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); + } + + /// + /// Adds a direction, with a +/- threshold allowance, in which the pan gesture is emitted. Both the direction and its opposite are allowed. + /// + /// The direction of panning that should be allowed. + /// The threshold around that direction. + [EditorBrowsable(EditorBrowsableState.Never)] + public void AddDirection(Radian direction, Radian threshold) + { + Interop.PanGestureDetector.OptionsAddDirection(SwigCPtr, Radian.getCPtr(direction), Radian.getCPtr(threshold)); + if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); + } + + /// + /// Adds a direction in which the pan gesture is emitted, using the default threshold (PI * 0.25). + /// + /// The direction of panning that should be allowed. + [EditorBrowsable(EditorBrowsableState.Never)] + public void AddDirection(Radian direction) + { + Interop.PanGestureDetector.OptionsAddDirection(SwigCPtr, Radian.getCPtr(direction)); + if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); + } + + /// + /// Returns the number of angles registered in these options. + /// + /// The number of angles. + [EditorBrowsable(EditorBrowsableState.Never)] + public uint GetAngleCount() + { + uint ret = Interop.PanGestureDetector.OptionsGetAngleCount(SwigCPtr); + if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); + return ret; + } + + internal AngleThresholdPair GetAngle(uint index) + { + AngleThresholdPair ret = new AngleThresholdPair(Interop.PanGestureDetector.OptionsGetAngle(SwigCPtr, index), true); + if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); + return ret; + } + + /// + /// Removes all angles, so the pan gesture is emitted regardless of direction. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public void ClearAngles() + { + Interop.PanGestureDetector.OptionsClearAngles(SwigCPtr); + if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); + } + + /// + /// Removes the angle specified from these options. + /// + /// The angle to remove. + [EditorBrowsable(EditorBrowsableState.Never)] + public void RemoveAngle(Radian angle) + { + Interop.PanGestureDetector.OptionsRemoveAngle(SwigCPtr, Radian.getCPtr(angle)); + if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); + } + + /// + /// Removes the direction specified from these options. + /// + /// The direction to remove. + [EditorBrowsable(EditorBrowsableState.Never)] + public void RemoveDirection(Radian direction) + { + Interop.PanGestureDetector.OptionsRemoveDirection(SwigCPtr, Radian.getCPtr(direction)); + if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); + } + /// This will not be public opened. + [EditorBrowsable(EditorBrowsableState.Never)] + protected override void ReleaseSwigCPtr(HandleRef swigCPtr) + { + Interop.PanGestureDetector.DeleteOptions(swigCPtr); + } + } + + /// + /// Returns a copy of the settings this detector uses when no device-specific options match. + /// + /// A new Options object. Dispose it when no longer needed. + [EditorBrowsable(EditorBrowsableState.Never)] + public Options GetDefaultOptions() + { + Options ret = new Options(Interop.PanGestureDetector.GetDefaultOptions(SwigCPtr), true); + if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); + return ret; + } + + /// + /// Registers the settings to use for gestures that start on a device matching the selector.
+ /// Registering with an equal selector replaces the earlier settings. The detector copies the options, + /// so later changes to have no effect until it is set again. + ///
+ /// The devices the options apply to. + /// The complete settings for those devices. + [EditorBrowsable(EditorBrowsableState.Never)] + public void SetDeviceOptions(GestureDeviceSelector selector, Options options) + { + Interop.PanGestureDetector.SetDeviceOptions(SwigCPtr, GestureDeviceSelector.getCPtr(selector), Options.getCPtr(options)); + if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); + } + + /// + /// Retrieves the settings registered for exactly this selector. Fallback to a less specific selector is not applied. + /// + /// The selector the options were registered with. + /// The registered settings, or null when none are registered for the selector. + /// True when settings are registered for the selector. + [EditorBrowsable(EditorBrowsableState.Never)] + public bool TryGetDeviceOptions(GestureDeviceSelector selector, out Options options) + { + Options result = new Options(); + bool found = Interop.PanGestureDetector.GetDeviceOptions(SwigCPtr, GestureDeviceSelector.getCPtr(selector), Options.getCPtr(result)); + if (NDalicPINVOKE.SWIGPendingException.Pending) + { + result.Dispose(); + throw NDalicPINVOKE.SWIGPendingException.Retrieve(); + } + + if (!found) + { + result.Dispose(); + options = null; + return false; + } + + options = result; + return true; + } + + /// + /// Removes the settings registered for exactly this selector. Does nothing when none are registered. + /// + /// The selector the options were registered with. + [EditorBrowsable(EditorBrowsableState.Never)] + public void ClearDeviceOptions(GestureDeviceSelector selector) + { + Interop.PanGestureDetector.ClearDeviceOptions(SwigCPtr, GestureDeviceSelector.getCPtr(selector)); + if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); + } + internal class Property { internal static readonly int ScreenPosition = Interop.PanGestureDetector.ScreenPositionGet(); diff --git a/src/Tizen.NUI/src/public/Events/PanThresholds.cs b/src/Tizen.NUI/src/public/Events/PanThresholds.cs new file mode 100644 index 00000000000..7a0d5123ae3 --- /dev/null +++ b/src/Tizen.NUI/src/public/Events/PanThresholds.cs @@ -0,0 +1,91 @@ +/* + * Copyright(c) 2026 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. + * + */ + +using System; +using System.ComponentModel; +using System.Runtime.InteropServices; + +namespace Tizen.NUI +{ + /// + /// Recognition thresholds of the pan gesture.
+ /// Register a per-device set with ; it applies to every + /// pan gesture detector in the application, including those created by components, for gestures that start on a matching device. + /// Start from to keep the values you do not want to change. + ///
+ /// This will be public opened after ACR done. Before ACR, need to be hidden as inhouse API. + [EditorBrowsable(EditorBrowsableState.Never)] + public sealed class PanThresholds : Disposable + { + /// + /// Creates a thresholds object holding the built-in default values. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public PanThresholds() : this(Interop.GestureThresholds.NewPanThresholds(), true) + { + if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); + } + + internal PanThresholds(global::System.IntPtr cPtr, bool cMemoryOwn) : base(cPtr, cMemoryOwn, false) + { + } + + /// + /// Gets or sets the minimum distance, in pixels, a touch must move before a pan is recognized. The default is 15. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public int MinimumDistance + { + get + { + int ret = Interop.GestureThresholds.PanThresholdsGetMinimumDistance(SwigCPtr); + if (NDalicPINVOKE.SWIGPendingException.Pending) throw new InvalidOperationException("FATAL: get Exception", NDalicPINVOKE.SWIGPendingException.Retrieve()); + return ret; + } + set + { + Interop.GestureThresholds.PanThresholdsSetMinimumDistance(SwigCPtr, value); + if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); + } + } + + /// + /// Gets or sets the minimum number of motion events required before a pan is recognized. The default is 3. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public int MinimumPanEvents + { + get + { + int ret = Interop.GestureThresholds.PanThresholdsGetMinimumPanEvents(SwigCPtr); + if (NDalicPINVOKE.SWIGPendingException.Pending) throw new InvalidOperationException("FATAL: get Exception", NDalicPINVOKE.SWIGPendingException.Retrieve()); + return ret; + } + set + { + Interop.GestureThresholds.PanThresholdsSetMinimumPanEvents(SwigCPtr, value); + if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); + } + } + /// This will not be public opened. + [EditorBrowsable(EditorBrowsableState.Never)] + protected override void ReleaseSwigCPtr(HandleRef swigCPtr) + { + Interop.GestureThresholds.DeletePanThresholds(swigCPtr); + } + } +} diff --git a/src/Tizen.NUI/src/public/Events/PinchThresholds.cs b/src/Tizen.NUI/src/public/Events/PinchThresholds.cs new file mode 100644 index 00000000000..af48f68d9f2 --- /dev/null +++ b/src/Tizen.NUI/src/public/Events/PinchThresholds.cs @@ -0,0 +1,110 @@ +/* + * Copyright(c) 2026 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. + * + */ + +using System; +using System.ComponentModel; +using System.Runtime.InteropServices; + +namespace Tizen.NUI +{ + /// + /// Recognition thresholds of the pinch gesture.
+ /// Register a per-device set with ; it applies to every + /// pinch gesture detector in the application, including those created by components, for gestures that start on a matching device. + /// Start from to keep the values you do not want to change. + ///
+ /// This will be public opened after ACR done. Before ACR, need to be hidden as inhouse API. + [EditorBrowsable(EditorBrowsableState.Never)] + public sealed class PinchThresholds : Disposable + { + /// + /// Creates a thresholds object holding the built-in default values. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public PinchThresholds() : this(Interop.GestureThresholds.NewPinchThresholds(), true) + { + if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); + } + + internal PinchThresholds(global::System.IntPtr cPtr, bool cMemoryOwn) : base(cPtr, cMemoryOwn, false) + { + } + + /// + /// Gets or sets the minimum change of distance, in pixels, between two touches before a pinch is recognized. A negative value selects the DPI-based default. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public float MinimumDistance + { + get + { + float ret = Interop.GestureThresholds.PinchThresholdsGetMinimumDistance(SwigCPtr); + if (NDalicPINVOKE.SWIGPendingException.Pending) throw new InvalidOperationException("FATAL: get Exception", NDalicPINVOKE.SWIGPendingException.Retrieve()); + return ret; + } + set + { + Interop.GestureThresholds.PinchThresholdsSetMinimumDistance(SwigCPtr, value); + if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); + } + } + + /// + /// Gets or sets the minimum number of touch events required before a pinch is recognized. The default is 4. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public uint MinimumTouchEvents + { + get + { + uint ret = Interop.GestureThresholds.PinchThresholdsGetMinimumTouchEvents(SwigCPtr); + if (NDalicPINVOKE.SWIGPendingException.Pending) throw new InvalidOperationException("FATAL: get Exception", NDalicPINVOKE.SWIGPendingException.Retrieve()); + return ret; + } + set + { + Interop.GestureThresholds.PinchThresholdsSetMinimumTouchEvents(SwigCPtr, value); + if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); + } + } + + /// + /// Gets or sets the minimum number of touch events between pinch updates once started. The default is 4. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public uint MinimumTouchEventsAfterStart + { + get + { + uint ret = Interop.GestureThresholds.PinchThresholdsGetMinimumTouchEventsAfterStart(SwigCPtr); + if (NDalicPINVOKE.SWIGPendingException.Pending) throw new InvalidOperationException("FATAL: get Exception", NDalicPINVOKE.SWIGPendingException.Retrieve()); + return ret; + } + set + { + Interop.GestureThresholds.PinchThresholdsSetMinimumTouchEventsAfterStart(SwigCPtr, value); + if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); + } + } + /// This will not be public opened. + [EditorBrowsable(EditorBrowsableState.Never)] + protected override void ReleaseSwigCPtr(HandleRef swigCPtr) + { + Interop.GestureThresholds.DeletePinchThresholds(swigCPtr); + } + } +} diff --git a/src/Tizen.NUI/src/public/Events/RotationThresholds.cs b/src/Tizen.NUI/src/public/Events/RotationThresholds.cs new file mode 100644 index 00000000000..dec46d02a0d --- /dev/null +++ b/src/Tizen.NUI/src/public/Events/RotationThresholds.cs @@ -0,0 +1,91 @@ +/* + * Copyright(c) 2026 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. + * + */ + +using System; +using System.ComponentModel; +using System.Runtime.InteropServices; + +namespace Tizen.NUI +{ + /// + /// Recognition thresholds of the rotation gesture.
+ /// Register a per-device set with ; it applies to every + /// rotation gesture detector in the application, including those created by components, for gestures that start on a matching device. + /// Start from to keep the values you do not want to change. + ///
+ /// This will be public opened after ACR done. Before ACR, need to be hidden as inhouse API. + [EditorBrowsable(EditorBrowsableState.Never)] + public sealed class RotationThresholds : Disposable + { + /// + /// Creates a thresholds object holding the built-in default values. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public RotationThresholds() : this(Interop.GestureThresholds.NewRotationThresholds(), true) + { + if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); + } + + internal RotationThresholds(global::System.IntPtr cPtr, bool cMemoryOwn) : base(cPtr, cMemoryOwn, false) + { + } + + /// + /// Gets or sets the minimum number of touch events required before a rotation is recognized. The default is 4. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public uint MinimumTouchEvents + { + get + { + uint ret = Interop.GestureThresholds.RotationThresholdsGetMinimumTouchEvents(SwigCPtr); + if (NDalicPINVOKE.SWIGPendingException.Pending) throw new InvalidOperationException("FATAL: get Exception", NDalicPINVOKE.SWIGPendingException.Retrieve()); + return ret; + } + set + { + Interop.GestureThresholds.RotationThresholdsSetMinimumTouchEvents(SwigCPtr, value); + if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); + } + } + + /// + /// Gets or sets the minimum number of touch events between rotation updates once started. The default is 4. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public uint MinimumTouchEventsAfterStart + { + get + { + uint ret = Interop.GestureThresholds.RotationThresholdsGetMinimumTouchEventsAfterStart(SwigCPtr); + if (NDalicPINVOKE.SWIGPendingException.Pending) throw new InvalidOperationException("FATAL: get Exception", NDalicPINVOKE.SWIGPendingException.Retrieve()); + return ret; + } + set + { + Interop.GestureThresholds.RotationThresholdsSetMinimumTouchEventsAfterStart(SwigCPtr, value); + if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); + } + } + /// This will not be public opened. + [EditorBrowsable(EditorBrowsableState.Never)] + protected override void ReleaseSwigCPtr(HandleRef swigCPtr) + { + Interop.GestureThresholds.DeleteRotationThresholds(swigCPtr); + } + } +} diff --git a/src/Tizen.NUI/src/public/Events/TapGestureDetector.cs b/src/Tizen.NUI/src/public/Events/TapGestureDetector.cs index 610aef64ae8..4c27866cbcd 100755 --- a/src/Tizen.NUI/src/public/Events/TapGestureDetector.cs +++ b/src/Tizen.NUI/src/public/Events/TapGestureDetector.cs @@ -319,5 +319,182 @@ public bool Handled } } } + + /// + /// Recognition options of a tap gesture detector that can differ per input device: the taps required and + /// whether every tap event is delivered.
+ /// An Options object is a complete snapshot of the settings; the detector applies the snapshot registered for the + /// most specific matching and otherwise its own settings.
+ /// Start from to keep the values you do not want to change. + ///
+ [EditorBrowsable(EditorBrowsableState.Never)] + public sealed class Options : Disposable + { + /// + /// Creates an Options object holding the built-in default settings. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Options() : this(Interop.TapGestureDetector.NewOptions(), true) + { + if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); + } + + internal Options(global::System.IntPtr cPtr, bool cMemoryOwn) : base(cPtr, cMemoryOwn, false) + { + } + + /// + /// Gets or sets the minimum number of taps required. The default is 1. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public uint MinimumTapsRequired + { + get + { + uint ret = Interop.TapGestureDetector.OptionsGetMinimumTapsRequired(SwigCPtr); + if (NDalicPINVOKE.SWIGPendingException.Pending) throw new InvalidOperationException("FATAL: get Exception", NDalicPINVOKE.SWIGPendingException.Retrieve()); + return ret; + } + set + { + Interop.TapGestureDetector.OptionsSetMinimumTapsRequired(SwigCPtr, value); + if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); + } + } + + /// + /// Gets or sets the maximum number of taps required. The default is 1. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public uint MaximumTapsRequired + { + get + { + uint ret = Interop.TapGestureDetector.OptionsGetMaximumTapsRequired(SwigCPtr); + if (NDalicPINVOKE.SWIGPendingException.Pending) throw new InvalidOperationException("FATAL: get Exception", NDalicPINVOKE.SWIGPendingException.Retrieve()); + return ret; + } + set + { + Interop.TapGestureDetector.OptionsSetMaximumTapsRequired(SwigCPtr, value); + if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); + } + } + + /// + /// Gets or sets whether every tap is delivered immediately (true) or only the final tap of a multi-tap sequence (false). The default is false. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public bool ReceiveAllTapEvents + { + get + { + bool ret = Interop.TapGestureDetector.OptionsIsReceiveAllTapEventsEnabled(SwigCPtr); + if (NDalicPINVOKE.SWIGPendingException.Pending) throw new InvalidOperationException("FATAL: get Exception", NDalicPINVOKE.SWIGPendingException.Retrieve()); + return ret; + } + set + { + Interop.TapGestureDetector.OptionsSetReceiveAllTapEventsEnabled(SwigCPtr, value); + if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); + } + } + /// This will not be public opened. + [EditorBrowsable(EditorBrowsableState.Never)] + protected override void ReleaseSwigCPtr(HandleRef swigCPtr) + { + Interop.TapGestureDetector.DeleteOptions(swigCPtr); + } + } + + /// + /// Returns a copy of the settings this detector uses when no device-specific options match. + /// + /// A new Options object. Dispose it when no longer needed. + [EditorBrowsable(EditorBrowsableState.Never)] + public Options GetDefaultOptions() + { + Options ret = new Options(Interop.TapGestureDetector.GetDefaultOptions(SwigCPtr), true); + if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); + return ret; + } + + /// + /// Registers the settings to use for gestures that start on a device matching the selector.
+ /// Registering with an equal selector replaces the earlier settings. The detector copies the options, + /// so later changes to have no effect until it is set again. + ///
+ /// The devices the options apply to. + /// The complete settings for those devices. + [EditorBrowsable(EditorBrowsableState.Never)] + public void SetDeviceOptions(GestureDeviceSelector selector, Options options) + { + Interop.TapGestureDetector.SetDeviceOptions(SwigCPtr, GestureDeviceSelector.getCPtr(selector), Options.getCPtr(options)); + if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); + } + + /// + /// Retrieves the settings registered for exactly this selector. Fallback to a less specific selector is not applied. + /// + /// The selector the options were registered with. + /// The registered settings, or null when none are registered for the selector. + /// True when settings are registered for the selector. + [EditorBrowsable(EditorBrowsableState.Never)] + public bool TryGetDeviceOptions(GestureDeviceSelector selector, out Options options) + { + Options result = new Options(); + bool found = Interop.TapGestureDetector.GetDeviceOptions(SwigCPtr, GestureDeviceSelector.getCPtr(selector), Options.getCPtr(result)); + if (NDalicPINVOKE.SWIGPendingException.Pending) + { + result.Dispose(); + throw NDalicPINVOKE.SWIGPendingException.Retrieve(); + } + + if (!found) + { + result.Dispose(); + options = null; + return false; + } + + options = result; + return true; + } + + /// + /// Removes the settings registered for exactly this selector. Does nothing when none are registered. + /// + /// The selector the options were registered with. + [EditorBrowsable(EditorBrowsableState.Never)] + public void ClearDeviceOptions(GestureDeviceSelector selector) + { + Interop.TapGestureDetector.ClearDeviceOptions(SwigCPtr, GestureDeviceSelector.getCPtr(selector)); + if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); + } + + /// + /// Sets whether every tap is delivered immediately or only the final tap of a multi-tap sequence.
+ /// When true, each tap arrives as it happens; when false (the default), taps are held back until the multi-tap + /// interval expires and only the final count is delivered. + ///
+ /// True to receive every tap event. + [EditorBrowsable(EditorBrowsableState.Never)] + public void ReceiveAllTapEvents(bool receive) + { + Interop.TapGestureDetector.ReceiveAllTapEvents(SwigCPtr, receive); + if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); + } + + /// + /// Returns whether every tap event is delivered immediately. + /// + /// True if every tap event is delivered. + [EditorBrowsable(EditorBrowsableState.Never)] + public bool IsReceiveAllTapEventsEnabled() + { + bool ret = Interop.TapGestureDetector.IsReceiveAllTapEventsEnabled(SwigCPtr); + if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); + return ret; + } } } diff --git a/src/Tizen.NUI/src/public/Events/TapThresholds.cs b/src/Tizen.NUI/src/public/Events/TapThresholds.cs new file mode 100644 index 00000000000..9444b6b787d --- /dev/null +++ b/src/Tizen.NUI/src/public/Events/TapThresholds.cs @@ -0,0 +1,110 @@ +/* + * Copyright(c) 2026 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. + * + */ + +using System; +using System.ComponentModel; +using System.Runtime.InteropServices; + +namespace Tizen.NUI +{ + /// + /// Recognition thresholds of the tap gesture.
+ /// Register a per-device set with ; it applies to every + /// tap gesture detector in the application, including those created by components, for gestures that start on a matching device. + /// Start from to keep the values you do not want to change. + ///
+ /// This will be public opened after ACR done. Before ACR, need to be hidden as inhouse API. + [EditorBrowsable(EditorBrowsableState.Never)] + public sealed class TapThresholds : Disposable + { + /// + /// Creates a thresholds object holding the built-in default values. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public TapThresholds() : this(Interop.GestureThresholds.NewTapThresholds(), true) + { + if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); + } + + internal TapThresholds(global::System.IntPtr cPtr, bool cMemoryOwn) : base(cPtr, cMemoryOwn, false) + { + } + + /// + /// Gets or sets the maximum interval, in milliseconds, between taps of a multi-tap sequence. The default is 330. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public uint MaximumMultiTapInterval + { + get + { + uint ret = Interop.GestureThresholds.TapThresholdsGetMaximumMultiTapInterval(SwigCPtr); + if (NDalicPINVOKE.SWIGPendingException.Pending) throw new InvalidOperationException("FATAL: get Exception", NDalicPINVOKE.SWIGPendingException.Retrieve()); + return ret; + } + set + { + Interop.GestureThresholds.TapThresholdsSetMaximumMultiTapInterval(SwigCPtr, value); + if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); + } + } + + /// + /// Gets or sets the maximum time, in milliseconds, a touch may be held down and still count as a tap. The default is 330. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public uint MaximumHoldingTime + { + get + { + uint ret = Interop.GestureThresholds.TapThresholdsGetMaximumHoldingTime(SwigCPtr); + if (NDalicPINVOKE.SWIGPendingException.Pending) throw new InvalidOperationException("FATAL: get Exception", NDalicPINVOKE.SWIGPendingException.Retrieve()); + return ret; + } + set + { + Interop.GestureThresholds.TapThresholdsSetMaximumHoldingTime(SwigCPtr, value); + if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); + } + } + + /// + /// Gets or sets the maximum distance, in pixels, a touch may move between down and up and still count as a tap. The default is 20. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public float MaximumMotionDistance + { + get + { + float ret = Interop.GestureThresholds.TapThresholdsGetMaximumMotionDistance(SwigCPtr); + if (NDalicPINVOKE.SWIGPendingException.Pending) throw new InvalidOperationException("FATAL: get Exception", NDalicPINVOKE.SWIGPendingException.Retrieve()); + return ret; + } + set + { + Interop.GestureThresholds.TapThresholdsSetMaximumMotionDistance(SwigCPtr, value); + if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); + } + } + /// This will not be public opened. + [EditorBrowsable(EditorBrowsableState.Never)] + protected override void ReleaseSwigCPtr(HandleRef swigCPtr) + { + Interop.GestureThresholds.DeleteTapThresholds(swigCPtr); + } + } +} diff --git a/test/Tizen.NUI.Samples/Tizen.NUI.Samples/Samples/DeviceGestureOptionsSample.cs b/test/Tizen.NUI.Samples/Tizen.NUI.Samples/Samples/DeviceGestureOptionsSample.cs new file mode 100644 index 00000000000..e85ebd30763 --- /dev/null +++ b/test/Tizen.NUI.Samples/Tizen.NUI.Samples/Samples/DeviceGestureOptionsSample.cs @@ -0,0 +1,267 @@ +using System; +using System.Collections.Generic; +using Tizen.NUI; +using Tizen.NUI.BaseComponents; + +namespace Tizen.NUI.Samples +{ + // Demonstrates GestureDeviceSelector: the same PanGestureDetector and TapGestureDetector give a + // mouse different recognition behaviour than a touchscreen, without the application inspecting + // the device on every event. Two layers are configured once, in Activate(): + // + // - Detector-local Options (PanGestureDetector.Options / TapGestureDetector.Options, via + // SetDeviceOptions()): the mouse profile restricts panning to roughly horizontal drags and + // allows a double-click. + // - Application-wide recognition thresholds (GestureOptions.Instance.Set*Thresholds()): the + // mouse profile needs a longer drag before a pan starts, and a faster second click before + // it counts as a double-click, than the touch defaults. + // + // Drag the block with the mouse: a mostly-horizontal drag moves it; a mostly-vertical drag does + // nothing, because the pan never starts (the angle added via AddDirection() is only checked when + // the gesture starts - once started, it can move freely). On a touchscreen the block follows a + // drag started in any direction. Click (or tap) the button once or twice to see the per-device + // tap count and timing in the log. + // + // Gesture.Source only distinguishes Mouse/Touch (it is a legacy, lossy view of the full device + // class); that is exactly what this sample needs to label its log, so it is used here instead of + // decoding the full Device::Class::Type. + public class DeviceGestureOptionsSample : IExample + { + private const float TrackX = 30.0f, TrackY = 220.0f, TrackWidth = 840.0f, TrackHeight = 170.0f; + private const float HandleSize = 90.0f; + + private const float TapButtonX = 30.0f, TapButtonY = 510.0f, TapButtonWidth = 220.0f, TapButtonHeight = 90.0f; + + // The mouse needs to drag further before a pan starts, and a click needs to repeat sooner to + // count as a double-click, than the touch defaults (GestureOptions.Instance.GetDefault*Thresholds()). + private const int MouseMinimumPanDistance = 40; + private const uint MouseMaximumMultiTapIntervalMs = 250u; + private const uint TouchMaximumMultiTapIntervalMs = 450u; + + private const int MaxTapLogLines = 6; + + private View root; + private View track; + private View handle; + private TextLabel panStatusLabel; + + private View tapButton; + private TextLabel tapStatusLabel; + private readonly Queue tapLog = new Queue(); + + private PanGestureDetector panDetector; + private TapGestureDetector tapDetector; + + private uint mousePanCount; + private uint touchPanCount; + private uint mouseTapCount; + private uint touchTapCount; + + public void Activate() + { + Window window = NUIApplication.GetDefaultWindow(); + window.BackgroundColor = new Color(0x11 / 255.0f, 0x18 / 255.0f, 0x20 / 255.0f, 1.0f); + + root = new View + { + WidthResizePolicy = ResizePolicyType.FillToParent, + HeightResizePolicy = ResizePolicyType.FillToParent, + }; + window.Add(root); + + root.Add(MakeLabel("Device Gesture Options: Mouse vs Touch", 24, new Position(30, 16), new Size(840, 40), + new Color(1, 1, 1, 1))); + root.Add(MakeLabel( + "One PanGestureDetector and one TapGestureDetector; only their per-device Options and " + + "recognition thresholds differ. Mouse and touch see different recognition behaviour below.", + 14, new Position(30, 64), new Size(840, 60), new Color(0xB9 / 255.0f, 0xC9 / 255.0f, 0xDA / 255.0f, 1.0f))); + + SetupPanZone(); + SetupTapZone(); + + var legend = MakeLabel( + "Configured per device (registered once in Activate(), resolved from the device that pressed down):\n" + + $" MOUSE pan: horizontal-only, min distance {MouseMinimumPanDistance}px | tap: up to 2 taps, multi-tap interval {MouseMaximumMultiTapIntervalMs}ms\n" + + $" TOUCH pan: any direction, min distance {GestureOptions.Instance.GetDefaultPanThresholds().MinimumDistance}px (default) | " + + $"tap: up to 2 taps, multi-tap interval {TouchMaximumMultiTapIntervalMs}ms", + 13, new Position(30, 660), new Size(840, 100), new Color(0x8F / 255.0f, 0xA3 / 255.0f, 0xB8 / 255.0f, 1.0f)); + legend.BackgroundColor = new Color(0x1A / 255.0f, 0x25 / 255.0f, 0x31 / 255.0f, 1.0f); + root.Add(legend); + } + + private void SetupPanZone() + { + root.Add(MakeLabel("PAN ZONE — drag the block", 16, new Position(30, 190), new Size(400, 26), + new Color(0xE7 / 255.0f, 0xEE / 255.0f, 0xF5 / 255.0f, 1.0f))); + + track = new View + { + Position = new Position(TrackX, TrackY), + Size = new Size(TrackWidth, TrackHeight), + BackgroundColor = new Color(0x1A / 255.0f, 0x25 / 255.0f, 0x31 / 255.0f, 1.0f), + Sensitive = false, + }; + root.Add(track); + + handle = new View + { + Position = new Position(TrackX + (TrackWidth - HandleSize) / 2.0f, TrackY + (TrackHeight - HandleSize) / 2.0f), + Size = new Size(HandleSize, HandleSize), + BackgroundColor = new Color(0x4D / 255.0f, 0x8F / 255.0f, 0xE8 / 255.0f, 1.0f), + }; + root.Add(handle); + + panDetector = new PanGestureDetector(); + + // Touch keeps the built-in defaults (any direction, GestureOptions.Instance.GetDefaultPanThresholds()); + // registering them explicitly here just makes that intent visible in the code. + panDetector.SetDeviceOptions(GestureDeviceSelector.ByDeviceClass(DeviceClassType.Touch), panDetector.GetDefaultOptions()); + GestureOptions.Instance.SetPanThresholds(GestureDeviceSelector.ByDeviceClass(DeviceClassType.Touch), + GestureOptions.Instance.GetDefaultPanThresholds()); + + // Mouse: only start the pan for a roughly horizontal drag, and require a longer drag first. + PanGestureDetector.Options mouseOptions = panDetector.GetDefaultOptions(); + mouseOptions.AddDirection(PanGestureDetector.DirectionHorizontal); + panDetector.SetDeviceOptions(GestureDeviceSelector.ByDeviceClass(DeviceClassType.Mouse), mouseOptions); + + PanThresholds mouseThresholds = GestureOptions.Instance.GetDefaultPanThresholds(); + mouseThresholds.MinimumDistance = MouseMinimumPanDistance; + GestureOptions.Instance.SetPanThresholds(GestureDeviceSelector.ByDeviceClass(DeviceClassType.Mouse), mouseThresholds); + + panDetector.Attach(handle); + panDetector.Detected += OnPan; + + panStatusLabel = MakeLabel("Pan: waiting for the first drag.", 14, new Position(30, 400), new Size(840, 70), + new Color(0xE7 / 255.0f, 0xEE / 255.0f, 0xF5 / 255.0f, 1.0f)); + panStatusLabel.BackgroundColor = new Color(0x1A / 255.0f, 0x25 / 255.0f, 0x31 / 255.0f, 1.0f); + root.Add(panStatusLabel); + } + + private void SetupTapZone() + { + root.Add(MakeLabel("TAP ZONE — click or tap once or twice", 16, new Position(30, 480), new Size(400, 26), + new Color(0xE7 / 255.0f, 0xEE / 255.0f, 0xF5 / 255.0f, 1.0f))); + + tapButton = new View + { + Position = new Position(TapButtonX, TapButtonY), + Size = new Size(TapButtonWidth, TapButtonHeight), + BackgroundColor = new Color(0x39 / 255.0f, 0x72 / 255.0f, 0x5B / 255.0f, 1.0f), + }; + tapButton.Add(MakeLabel("tap me", 16, new Position(0, 0), new Size(TapButtonWidth, TapButtonHeight), new Color(1, 1, 1, 1))); + root.Add(tapButton); + + tapDetector = new TapGestureDetector(); + + // Both devices allow up to a double tap; only the multi-tap interval differs. + TapGestureDetector.Options doubleTapOptions = tapDetector.GetDefaultOptions(); + doubleTapOptions.MaximumTapsRequired = 2; + tapDetector.SetDeviceOptions(GestureDeviceSelector.ByDeviceClass(DeviceClassType.Mouse), doubleTapOptions); + tapDetector.SetDeviceOptions(GestureDeviceSelector.ByDeviceClass(DeviceClassType.Touch), doubleTapOptions); + + TapThresholds mouseTapThresholds = GestureOptions.Instance.GetDefaultTapThresholds(); + mouseTapThresholds.MaximumMultiTapInterval = MouseMaximumMultiTapIntervalMs; + GestureOptions.Instance.SetTapThresholds(GestureDeviceSelector.ByDeviceClass(DeviceClassType.Mouse), mouseTapThresholds); + + TapThresholds touchTapThresholds = GestureOptions.Instance.GetDefaultTapThresholds(); + touchTapThresholds.MaximumMultiTapInterval = TouchMaximumMultiTapIntervalMs; + GestureOptions.Instance.SetTapThresholds(GestureDeviceSelector.ByDeviceClass(DeviceClassType.Touch), touchTapThresholds); + + tapDetector.Attach(tapButton); + tapDetector.Detected += OnTap; + + tapStatusLabel = MakeLabel("Tap log:\n(nothing yet)", 13, new Position(270, 510), new Size(600, 140), + new Color(0xE7 / 255.0f, 0xEE / 255.0f, 0xF5 / 255.0f, 1.0f)); + tapStatusLabel.BackgroundColor = new Color(0x1A / 255.0f, 0x25 / 255.0f, 0x31 / 255.0f, 1.0f); + root.Add(tapStatusLabel); + } + + private void OnPan(object source, PanGestureDetector.DetectedEventArgs e) + { + bool isMouse = e.PanGesture.Source == Gesture.SourceType.Mouse; + bool isTouch = e.PanGesture.Source == Gesture.SourceType.Touch; + if (isMouse) + { + mousePanCount++; + } + else if (isTouch) + { + touchPanCount++; + } + + if (e.PanGesture.State == Gesture.StateType.Started || e.PanGesture.State == Gesture.StateType.Continuing) + { + Position current = handle.Position; + Vector2 displacement = e.PanGesture.Displacement; + float newX = Math.Min(Math.Max(current.X + displacement.X, TrackX), TrackX + TrackWidth - HandleSize); + float newY = Math.Min(Math.Max(current.Y + displacement.Y, TrackY), TrackY + TrackHeight - HandleSize); + handle.Position = new Position(newX, newY); + } + + string deviceName = isMouse ? "MOUSE" : (isTouch ? "TOUCH" : "OTHER"); + panStatusLabel.Text = + $"Pan {deviceName}: started {mousePanCount} (mouse) / {touchPanCount} (touch) times so far.\n" + + "A mouse drag only starts within 45 degrees of horizontal; a touch drag starts in any direction."; + } + + private void OnTap(object source, TapGestureDetector.DetectedEventArgs e) + { + bool isMouse = e.TapGesture.Source == Gesture.SourceType.Mouse; + bool isTouch = e.TapGesture.Source == Gesture.SourceType.Touch; + if (isMouse) + { + mouseTapCount++; + } + else if (isTouch) + { + touchTapCount++; + } + + string deviceName = isMouse ? "MOUSE" : (isTouch ? "TOUCH" : "OTHER"); + tapLog.Enqueue($"{deviceName}: {e.TapGesture.NumberOfTaps} tap(s)"); + while (tapLog.Count > MaxTapLogLines) + { + tapLog.Dequeue(); + } + + tapStatusLabel.Text = $"Tap log (mouse {mouseTapCount} / touch {touchTapCount}):\n" + string.Join("\n", tapLog); + } + + private static TextLabel MakeLabel(string text, float pointSize, Position position, Size size, Color color) + { + return new TextLabel + { + Text = text, + PointSize = pointSize, + Position = position, + Size = size, + TextColor = color, + MultiLine = true, + }; + } + + public void Deactivate() + { + if (panDetector != null) + { + panDetector.Detected -= OnPan; + panDetector.Dispose(); + panDetector = null; + } + + if (tapDetector != null) + { + tapDetector.Detected -= OnTap; + tapDetector.Dispose(); + tapDetector = null; + } + + if (root != null) + { + NUIApplication.GetDefaultWindow().Remove(root); + root.Dispose(); + root = null; + } + } + } +}