1. [NUI] Add TouchArea property.
authorJoogab Yun <joogab.yun@samsung.com>
Fri, 12 Mar 2021 01:50:58 +0000 (10:50 +0900)
committerdongsug-song <35130733+dongsug-song@users.noreply.github.com>
Thu, 16 Dec 2021 01:46:02 +0000 (10:46 +0900)
Default touchable area is view's size.
TouchArea can reset the view's touchable area.

This is usefull when the view is small, but it should have a larger touch area.

for example

      View view = new View();
      view.Size = new Size(10, 10);
      view.TouchEvent += OnTouchEvent;
      view.TouchArea = new Size2D(200, 200);

The view is small, If you want to set the touch area to a larger area,
you can use the TouchArea property.

2. [NUI] change type from Size2D to Size at TouchArea api

3. [NUI] Change  TouchArea to TouchAreaOffset (#2948)

    You can expand the touch area.

    for example)
      View view = new View();
      view.Size = new Size(10, 10);
      view.TouchEvent += OnTouch;
      view.TouchAreaOffset = new Offset(-100, 100, 100, -100); // left, right, bottom, top

    then touch area is 210x210.
    this is view.width  -touchAreaOffset.left + touchAreaOffset.right
    and view.height + touchAreaOffset.bottom  -touchAreaOffset.top

4. [NUI] Change ulong to uint at Interop.Touch.GetMouseButton (#3057)

5. [NUI] Change interruptView to InterceptTouchEvent

6. [NUI] Add NeedGesturePropagation (#3130)

This is used when the parent view wants to listen to gesture events.

7. [NUI] Add FocusableInTouch property

This is a property that allows you to have focus even when touched.

If Focusable is false, FocusableInTouchMode is disabled.
If you want to have focus on touch in touch mode, you need to set both settings to true.

focusable = true,
focusableInTouch = true,

8. [NUI] Add source type to TapGesture.

This is similar to MouseButton in TouchEvent.

Now, you can see from which input the tap was made.

9. [NUI] Supports moving focus of items in ScrollableBase

10. [NUI] Add EnableDefaultAlgorithm and IsDefaultAlgorithmEnabled

11. [NUI] Add FocusableChildren

12. [NUI] Check if pan gesture need to propagation

If it's a nested scroll, calculate whether the gesture should be sent to the parent.

23 files changed:
src/Tizen.NUI.Components/Controls/ScrollableBase.cs
src/Tizen.NUI/src/internal/Interop/Interop.Actor.cs
src/Tizen.NUI/src/internal/Interop/Interop.ActorInternal.cs
src/Tizen.NUI/src/internal/Interop/Interop.FocusManager.cs
src/Tizen.NUI/src/internal/Interop/Interop.TapGesture.cs
src/Tizen.NUI/src/internal/Interop/Interop.Touch.cs
src/Tizen.NUI/src/internal/ViewWrapperImpl.cs
src/Tizen.NUI/src/public/BaseComponents/Style/ViewStyle.cs
src/Tizen.NUI/src/public/BaseComponents/Style/ViewStyleBindableProperty.cs
src/Tizen.NUI/src/public/BaseComponents/View.cs
src/Tizen.NUI/src/public/BaseComponents/ViewBindableProperty.cs
src/Tizen.NUI/src/public/BaseComponents/ViewEvent.cs
src/Tizen.NUI/src/public/BaseComponents/ViewInternal.cs
src/Tizen.NUI/src/public/FocusManager.cs
src/Tizen.NUI/src/public/LongPressGestureDetector.cs
src/Tizen.NUI/src/public/NUIConstants.cs
src/Tizen.NUI/src/public/PanGestureDetector.cs
src/Tizen.NUI/src/public/PinchGestureDetector.cs
src/Tizen.NUI/src/public/RotationGestureDetector.cs
src/Tizen.NUI/src/public/TapGesture.cs
src/Tizen.NUI/src/public/TapGestureDetector.cs
test/Tizen.NUI.Samples/Tizen.NUI.Samples/Samples/FocusFinderSample.cs [new file with mode: 0644]
test/Tizen.NUI.Samples/Tizen.NUI.Samples/Samples/TouchGestureSample.cs

index 4b26f15..cc3e317 100755 (executable)
@@ -610,7 +610,6 @@ namespace Tizen.NUI.Components
         private float maxScrollDistance;
         private float childTargetPosition = 0.0f;
         private PanGestureDetector mPanGestureDetector;
-        private View mInterruptTouchingChild;
         private ScrollbarBase scrollBar;
         private bool scrolling = false;
         private float ratioOfScreenWidthToCompleteScroll = 0.5f;
@@ -686,13 +685,6 @@ namespace Tizen.NUI.Components
             propertyNotification.Notified += OnPropertyChanged;
             base.Add(ContentContainer);
 
-            //Interrupt touching when panning is started
-            mInterruptTouchingChild = new View()
-            {
-                Size = new Size(Window.Instance.WindowSize),
-                BackgroundColor = Color.Transparent,
-            };
-            mInterruptTouchingChild.TouchEvent += OnIterruptTouchingChildTouched;
             Scrollbar = new Scrollbar();
 
             //Show vertical shadow on the top (or bottom) of the scrollable when panning down (or up).
@@ -718,9 +710,11 @@ namespace Tizen.NUI.Components
             {
                 AccessibilityManager.Instance.SetAccessibilityAttribute(this, AccessibilityManager.AccessibilityAttribute.Trait, "ScrollableBase");
             }
+
+            SetKeyboardNavigationSupport(true);
         }
 
-        private bool OnIterruptTouchingChildTouched(object source, View.TouchEventArgs args)
+        private bool OnInterruptTouchingChildTouched(object source, View.TouchEventArgs args)
         {
             if (args.Touch.GetState(0) == PointStateType.Down)
             {
@@ -874,7 +868,7 @@ namespace Tizen.NUI.Components
         private void OnScrollAnimationEnded()
         {
             scrolling = false;
-            base.Remove(mInterruptTouchingChild);
+            this.InterceptTouchEvent -= OnInterruptTouchingChildTouched;
 
             ScrollEventArgs eventArgs = new ScrollEventArgs(ContentContainer.CurrentPosition);
             ScrollAnimationEnded?.Invoke(this, eventArgs);
@@ -1285,20 +1279,19 @@ namespace Tizen.NUI.Components
 
         private void OnPanGestureDetected(object source, PanGestureDetector.DetectedEventArgs e)
         {
-            OnPanGesture(e.PanGesture);
+            e.Handled = OnPanGesture(e.PanGesture);
         }
 
-        private void OnPanGesture(PanGesture panGesture)
+        private bool OnPanGesture(PanGesture panGesture)
         {
+            bool handled = true;
             if (SnapToPage && scrollAnimation != null && scrollAnimation.State == Animation.States.Playing)
             {
-                return;
+                return handled;
             }
-
             if (panGesture.State == Gesture.StateType.Started)
             {
                 readyToNotice = false;
-                base.Add(mInterruptTouchingChild);
                 AttachShadowView();
                 Debug.WriteLineIf(LayoutDebugScrollableBase, "Gesture Start");
                 if (scrolling && !SnapToPage)
@@ -1306,6 +1299,21 @@ namespace Tizen.NUI.Components
                     StopScroll();
                 }
                 totalDisplacementForPan = 0.0f;
+
+                // check if gesture need to propagation
+                var checkDisplacement = (ScrollingDirection == Direction.Horizontal) ? panGesture.Displacement.X : panGesture.Displacement.Y;
+                var checkChildCurrentPosition = (ScrollingDirection == Direction.Horizontal) ? ContentContainer.PositionX : ContentContainer.PositionY;
+                var checkChildTargetPosition = checkChildCurrentPosition + checkDisplacement;
+                var checkFinalTargetPosition = BoundScrollPosition(checkChildTargetPosition);
+                handled = !((int)checkFinalTargetPosition == 0 || -(int)checkFinalTargetPosition == (int)maxScrollDistance);
+                // If you propagate a gesture event, return;
+                if(!handled)
+                {
+                    return handled;
+                }
+
+                //Interrupt touching when panning is started
+                this.InterceptTouchEvent += OnInterruptTouchingChildTouched;
                 OnScrollDragStarted();
             }
             else if (panGesture.State == Gesture.StateType.Continuing)
@@ -1326,6 +1334,7 @@ namespace Tizen.NUI.Components
                     DragVerticalShadow(totalDisplacementForPan, panGesture.Displacement.Y);
                 }
                 Debug.WriteLineIf(LayoutDebugScrollableBase, "OnPanGestureDetected Continue totalDisplacementForPan:" + totalDisplacementForPan);
+
             }
             else if (panGesture.State == Gesture.StateType.Finished || panGesture.State == Gesture.StateType.Cancelled)
             {
@@ -1366,6 +1375,7 @@ namespace Tizen.NUI.Components
                 readyToNotice = true;
                 OnScrollAnimationStarted();
             }
+            return handled;
         }
 
         internal override bool OnAccessibilityPan(PanGesture gestures)
@@ -1568,6 +1578,81 @@ namespace Tizen.NUI.Components
             }
         }
 
+
+        /// <inheritdoc/>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public override View GetNextFocusableView(View currentFocusedView, View.FocusDirection direction, bool loopEnabled)
+        {
+            View nextFocusedView = null;
+
+            int currentIndex = ContentContainer.Children.IndexOf(currentFocusedView);
+
+            switch (direction)
+            {
+                case View.FocusDirection.Left:
+                case View.FocusDirection.Up:
+                {
+                    if (currentIndex > 0)
+                    {
+                        nextFocusedView = ContentContainer.Children[--currentIndex];
+                    }
+                    break;
+                }
+                case View.FocusDirection.Right:
+                case View.FocusDirection.Down:
+                {
+                    if (currentIndex < ContentContainer.Children.Count - 1)
+                    {
+                        nextFocusedView =  ContentContainer.Children[++currentIndex];
+                    }
+                    break;
+                }
+            }
+
+            if (nextFocusedView != null)
+            {
+                // Check next focused view is inside of visible area.
+                // If it is not, move scroll position to make it visible.
+                Position scrollPosition = ContentContainer.CurrentPosition;
+                float targetPosition = -(ScrollingDirection == Direction.Horizontal ? scrollPosition.X : scrollPosition.Y);
+
+                float left = nextFocusedView.Position.X;
+                float right = nextFocusedView.Position.X + nextFocusedView.Size.Width;
+                float top = nextFocusedView.Position.Y;
+                float bottom = nextFocusedView.Position.Y + nextFocusedView.Size.Height;
+
+                float visibleRectangleLeft = -scrollPosition.X;
+                float visibleRectangleRight = -scrollPosition.X + Size.Width;
+                float visibleRectangleTop = -scrollPosition.Y;
+                float visibleRectangleBottom = -scrollPosition.Y + Size.Height;
+
+                if (ScrollingDirection == Direction.Horizontal)
+                {
+                    if (left < visibleRectangleLeft)
+                    {
+                        targetPosition = left;
+                    }
+                    else if (right > visibleRectangleRight)
+                    {
+                        targetPosition = right - Size.Width;
+                    }
+                }
+                else
+                {
+                    if (top < visibleRectangleTop)
+                    {
+                        targetPosition = top;
+                    }
+                    else if (bottom > visibleRectangleBottom)
+                    {
+                        targetPosition = bottom - Size.Height;
+                    }
+                }
+                ScrollTo(targetPosition, true);
+            }
+
+            return nextFocusedView;
+        }
     }
 
 } // namespace
index 90dfbfc..12caa13 100755 (executable)
@@ -121,6 +121,9 @@ namespace Tizen.NUI
 
             [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_Actor_RemoveRenderer__SWIG_1")]
             public static extern void Actor_RemoveRenderer__SWIG_1(global::System.Runtime.InteropServices.HandleRef jarg1, uint jarg2);
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_Actor_SetNeedGesturePropagation")]
+            public static extern float SetNeedGesturePropagation(global::System.Runtime.InteropServices.HandleRef jarg1, bool jarg2);
         }
     }
 }
index c1962bb..816b018 100755 (executable)
@@ -182,6 +182,19 @@ namespace Tizen.NUI
             [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_Actor_IsKeyboardFocusable")]
             public static extern bool Actor_IsKeyboardFocusable(global::System.Runtime.InteropServices.HandleRef jarg1);
 
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_Actor_SetKeyboardFocusableChildren")]
+            public static extern void SetKeyboardFocusableChildren(global::System.Runtime.InteropServices.HandleRef manager, bool focusable);
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_Actor_AreChildrenKeyBoardFocusable")]
+            [return: global::System.Runtime.InteropServices.MarshalAs(global::System.Runtime.InteropServices.UnmanagedType.U1)]
+            public static extern bool AreChildrenKeyBoardFocusable(global::System.Runtime.InteropServices.HandleRef manager);
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_Actor_SetTouchFocusable")]
+            public static extern void SetFocusableInTouch(global::System.Runtime.InteropServices.HandleRef jarg1, bool jarg2);
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_Actor_IsTouchFocusable")]
+            public static extern bool IsFocusableInTouch(global::System.Runtime.InteropServices.HandleRef jarg1);
+
             [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_Actor_SetSizeScalePolicy")]
             public static extern void Actor_SetSizeScalePolicy(global::System.Runtime.InteropServices.HandleRef jarg1, int jarg2);
 
@@ -199,6 +212,12 @@ namespace Tizen.NUI
 
             [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_Actor_GetMaximumSize")]
             public static extern global::System.IntPtr Actor_GetMaximumSize(global::System.Runtime.InteropServices.HandleRef jarg1);
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_DevelActor_Property_SetTouchAreaOffset")]
+            public static extern void SetTouchAreaOffset(global::System.Runtime.InteropServices.HandleRef jarg1, int jarg2, int jarg3, int jarg4, int jarg5);
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_DevelActor_Property_GetTouchAreaOffset")]
+            public static extern void GetTouchAreaOffset(global::System.Runtime.InteropServices.HandleRef jarg1, out int jarg2, out int jarg3, out int jarg4, out int jarg5);
         }
     }
 }
index 3ab94b0..c35d820 100755 (executable)
@@ -65,6 +65,13 @@ namespace Tizen.NUI
             [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_KeyboardFocusManager_FocusedActorEnterKeySignal")]
             public static extern global::System.IntPtr FocusManager_FocusedActorEnterKeySignal(global::System.Runtime.InteropServices.HandleRef jarg1);
 
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_KeyboardFocusManager_EnableDefaultAlgorithm")]
+            public static extern void EnableDefaultAlgorithm(global::System.Runtime.InteropServices.HandleRef jarg1, bool jarg2);
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_KeyboardFocusManager_IsDefaultAlgorithmEnabled")]
+            [return: global::System.Runtime.InteropServices.MarshalAs(global::System.Runtime.InteropServices.UnmanagedType.U1)]
+            public static extern bool IsDefaultAlgorithmEnabled(global::System.Runtime.InteropServices.HandleRef jarg1);
+
             [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_KeyboardFocusManager_SWIGUpcast")]
             public static extern global::System.IntPtr FocusManager_SWIGUpcast(global::System.IntPtr jarg1);
         }
index 62e76d7..6cf439e 100755 (executable)
@@ -49,6 +49,9 @@ namespace Tizen.NUI
 
             [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_TapGesture_localPoint_get")]
             public static extern global::System.IntPtr TapGesture_localPoint_get(global::System.Runtime.InteropServices.HandleRef jarg1);
+
+            [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_TapGesture_sourceType_get")]
+            public static extern int SourceTypeGet(global::System.Runtime.InteropServices.HandleRef jarg1);
         }
     }
 }
\ No newline at end of file
index c8f9f45..daeb119 100755 (executable)
@@ -15,7 +15,7 @@ namespace Tizen.NUI
             public static extern global::System.IntPtr new_Touch__SWIG_1(global::System.Runtime.InteropServices.HandleRef jarg1);
 
             [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_Touch_GetMouseButton")]
-            public static extern int Touch_GetMouseButton(global::System.Runtime.InteropServices.HandleRef jarg1, ulong jarg2);
+            public static extern int Touch_GetMouseButton(global::System.Runtime.InteropServices.HandleRef jarg1, uint jarg2);
 
             [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_Touch_Assign")]
             public static extern global::System.IntPtr Touch_Assign(global::System.Runtime.InteropServices.HandleRef jarg1, global::System.Runtime.InteropServices.HandleRef jarg2);
index 3b0f6ff..47cbf8d 100755 (executable)
@@ -520,7 +520,7 @@ namespace Tizen.NUI
             }
             else
             {
-                return currentFocusedActor;
+                return global::System.IntPtr.Zero;
             }
         }
 
index a1c3f6e..3f7b28a 100755 (executable)
@@ -44,6 +44,8 @@ namespace Tizen.NUI.BaseComponents
         private View upFocusableView;
         private View downFocusableView;
         private bool? focusable;
+        private bool? focusableChildren;
+        private bool? focusableInTouch;
         private bool? positionUsesPivotPoint;
         private int? siblingOrder;
         private Position parentOrigin;
@@ -248,6 +250,29 @@ namespace Tizen.NUI.BaseComponents
             set => SetValue(FocusableProperty, value);
         }
 
+        /// <summary>
+        /// Whether the children of this view can be focusable by keyboard navigation. If user sets this to false, the children of this view will not be focused.
+        /// Note : Default value is true.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public bool? FocusableChildren
+        {
+            get => (bool?)GetValue(FocusableChildrenProperty);
+            set => SetValue(FocusableChildrenProperty, value);
+        }
+
+        /// <summary>
+        /// Whether this view can focus by touch.
+        /// If Focusable is false, FocusableInTouch is disabled.
+        /// If you want to have focus on touch, you need to set both Focusable and FocusableInTouch settings to true.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public bool? FocusableInTouch
+        {
+            get => (bool?)GetValue(FocusableInTouchProperty);
+            set => SetValue(FocusableInTouchProperty, value);
+        }
+
         /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
         [EditorBrowsable(EditorBrowsableState.Never)]
         public Size2D Size2D
index c0e91a3..76db179 100755 (executable)
@@ -222,6 +222,22 @@ namespace Tizen.NUI.BaseComponents
             var viewStyle = (ViewStyle)bindable;
             return viewStyle.downFocusableView;
         });
+
+        /// <summary> Bindable property of FocusableChildren. Please do not open it. </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public static readonly BindableProperty FocusableChildrenProperty = BindableProperty.Create(nameof(FocusableChildren), typeof(bool?), typeof(ViewStyle), true,
+            propertyChanged: (bindable, oldValue, newValue) => ((ViewStyle)bindable).focusableChildren = (bool?)newValue,
+            defaultValueCreator: (bindable) => ((ViewStyle)bindable).focusableChildren
+        );
+
+
+        /// <summary> Bindable property of FocusableInTouch. Please do not open it. </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public static readonly BindableProperty FocusableInTouchProperty = BindableProperty.Create(nameof(FocusableInTouch), typeof(bool?), typeof(ViewStyle), null,
+            propertyChanged: (bindable, oldValue, newValue) => ((ViewStyle)bindable).focusableInTouch = (bool?)newValue,
+            defaultValueCreator: (bindable) => ((ViewStyle)bindable).focusableInTouch
+        );
+        
         /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
         [EditorBrowsable(EditorBrowsableState.Never)]
         public static readonly BindableProperty FocusableProperty = BindableProperty.Create(nameof(Focusable), typeof(bool?), typeof(ViewStyle), null, propertyChanged: (bindable, oldValue, newValue) =>
index e6243cc..8d19a98 100755 (executable)
@@ -738,6 +738,43 @@ namespace Tizen.NUI.BaseComponents
         }
 
         /// <summary>
+        /// Whether the children of this view can be focusable by keyboard navigation. If user sets this to false, the children of this actor view will not be focused.
+        /// Note : Default value is true.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public bool FocusableChildren
+        {
+            set
+            {
+                SetValue(FocusableChildrenProperty, value);
+                NotifyPropertyChanged();
+            }
+            get
+            {
+                return (bool)GetValue(FocusableChildrenProperty);
+            }
+        }
+
+        /// <summary>
+        /// Whether this view can focus by touch.
+        /// If Focusable is false, FocusableInTouch is disabled.
+        /// If you want to have focus on touch, you need to set both Focusable and FocusableInTouch settings to true.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public bool FocusableInTouch
+        {
+            set
+            {
+                SetValue(FocusableInTouchProperty, value);
+                NotifyPropertyChanged();
+            }
+            get
+            {
+                return (bool)GetValue(FocusableInTouchProperty);
+            }
+        }
+
+        /// <summary>
         ///  Retrieves the position of the view.<br />
         ///  The coordinates are relative to the view's parent.<br />
         /// </summary>
index b2cb0fa..908115e 100755 (executable)
@@ -605,6 +605,36 @@ namespace Tizen.NUI.BaseComponents
         });
 
         /// <summary>
+        /// FocusableChildrenProperty
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public static readonly BindableProperty FocusableChildrenProperty = BindableProperty.Create(nameof(FocusableChildren), typeof(bool), typeof(View), true, propertyChanged: (bindable, oldValue, newValue) =>
+        {
+            var view = (View)bindable;
+            if (newValue != null) { view.SetKeyboardFocusableChildren((bool)newValue); }
+        },
+        defaultValueCreator: (bindable) =>
+        {
+            var view = (View)bindable;
+            return view.AreChildrenKeyBoardFocusable();
+        });
+
+        /// <summary>
+        /// FocusableInTouchProperty
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public static readonly BindableProperty FocusableInTouchProperty = BindableProperty.Create(nameof(FocusableInTouch), typeof(bool), typeof(View), false, propertyChanged: (bindable, oldValue, newValue) =>
+        {
+            var view = (View)bindable;
+            if (newValue != null) { view.SetFocusableInTouch((bool)newValue); }
+        },
+        defaultValueCreator: (bindable) =>
+        {
+            var view = (View)bindable;
+            return view.IsFocusableInTouch();
+        });
+
+        /// <summary>
         /// Size2DProperty
         /// </summary>
         [EditorBrowsable(EditorBrowsableState.Never)]
index 1bcf86e..3f491fd 100755 (executable)
@@ -1278,5 +1278,51 @@ namespace Tizen.NUI.BaseComponents
             }
         }
 
+        /// <summary>
+        /// TouchArea can expand the view's touchable area.<br/>
+        /// If you set the TouchAreaOffset on an view, when you touch the view, the touch area is used rather than the size of the view.<br/>
+        /// This is based on the top left x, y coordinates.<br/>
+        /// example) <br/>
+        ///  view.Size = new Size(100, 100);<br/>
+        ///  view.TouchAreaOffset = new Offset(-10, 20, 30, -40); // left, right, bottom, top <br/>
+        /// then touch area is 130x170.<br/>
+        /// this is view.width + TouchAreaOffset.right - TouchAreaOffset.left and view.height + TouchAreaOffset.bottom - TouchAreaOffset.top <br/>
+        /// +---------------------+ <br/>
+        /// |         ^           | <br/>
+        /// |         |           | <br/>
+        /// |         | -40       | <br/>
+        /// |         |           | <br/>
+        /// |         |           | <br/>
+        /// |    +----+----+      | <br/>
+        /// |    |         |      | <br/>
+        /// | -10|         | 20   | <br/>
+        /// |<---+         +----->| <br/>
+        /// |    |         |      | <br/>
+        /// |    |         |      | <br/>
+        /// |    +----+----+      | <br/>
+        /// |         |           | <br/>
+        /// |         | 30        | <br/>
+        /// |         |           | <br/>
+        /// |         v           | <br/>
+        /// +---------------------+ <br/>
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public Offset TouchAreaOffset
+        {
+            get
+            {
+                Interop.ActorInternal.GetTouchAreaOffset(SwigCPtr, out int left, out int right, out int bottom, out int top);
+                if (NDalicPINVOKE.SWIGPendingException.Pending)
+                    throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+                return new Offset(left, right, bottom, top);
+            }
+            set
+            {
+                Interop.ActorInternal.SetTouchAreaOffset(SwigCPtr, value.Left, value.Right, value.Bottom, value.Top);
+                if (NDalicPINVOKE.SWIGPendingException.Pending)
+                    throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+            }
+        }
+
     }
 }
index 11b06d2..ad173f1 100755 (executable)
@@ -873,6 +873,36 @@ namespace Tizen.NUI.BaseComponents
             return ret;
         }
 
+        internal void SetKeyboardFocusableChildren(bool focusable)
+        {
+            Interop.ActorInternal.SetKeyboardFocusableChildren(SwigCPtr, focusable);
+            if (NDalicPINVOKE.SWIGPendingException.Pending)
+                throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+        }
+
+        internal bool AreChildrenKeyBoardFocusable()
+        {
+            bool ret = Interop.ActorInternal.AreChildrenKeyBoardFocusable(SwigCPtr);
+            if (NDalicPINVOKE.SWIGPendingException.Pending)
+                throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+            return ret;
+        }
+
+        internal void SetFocusableInTouch(bool enabled)
+        {
+            Interop.ActorInternal.SetFocusableInTouch(SwigCPtr, enabled);
+            if (NDalicPINVOKE.SWIGPendingException.Pending)
+                throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+        }
+
+        internal bool IsFocusableInTouch()
+        {
+            bool ret = Interop.ActorInternal.IsFocusableInTouch(SwigCPtr);
+            if (NDalicPINVOKE.SWIGPendingException.Pending)
+                throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+            return ret;
+        }
+
         internal void SetResizePolicy(ResizePolicyType policy, DimensionType dimension)
         {
             Interop.Actor.Actor_SetResizePolicy(swigCPtr, (int)policy, (int)dimension);
index 33e146f..f9827c1 100755 (executable)
@@ -410,6 +410,30 @@ namespace Tizen.NUI
             }
         }
 
+        /// <summary>
+        /// Sets to use the automatic focus moveing algorithm. <br />
+        /// It moves the focus to the view closest to the keyboard movement direction.
+        /// </summary>
+        /// <param name="enable">Whether using default focus algorithm or not</param>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void EnableDefaultAlgorithm(bool enable)
+        {
+            Interop.FocusManager.EnableDefaultAlgorithm(SwigCPtr, enable);
+            if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+        }
+
+        /// <summary>
+        ///  Checks default focus moveing algorithm is enabled or not
+        /// </summary>
+        /// <returns>Whether default focus algorithm is enabled</returns>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public bool IsDefaultAlgorithmEnabled()
+        {
+            bool ret = Interop.FocusManager.IsDefaultAlgorithmEnabled(SwigCPtr);
+            if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+            return ret;
+        }
+
         internal static FocusManager Get()
         {
             FocusManager ret = new FocusManager(Interop.FocusManager.FocusManager_Get(), true);
index df9645f..f76fa07 100755 (executable)
@@ -241,6 +241,7 @@ namespace Tizen.NUI
         {
             private View _view;
             private LongPressGesture _longPressGesture;
+            private bool handled = true;
 
             /// <summary>
             /// View the attached view.
@@ -277,6 +278,22 @@ namespace Tizen.NUI
                     _longPressGesture = value;
                 }
             }
+
+            /// <summary>
+            /// Gets or sets a value that indicates whether the event handler has completely handled the event or whether the system should continue its own processing.
+            /// </summary>
+            [EditorBrowsable(EditorBrowsableState.Never)]
+            public bool Handled
+            {
+                get => handled;
+                set
+                {
+                    handled = value;
+                    Interop.Actor.SetNeedGesturePropagation(View.getCPtr(_view), !value);
+                    if (NDalicPINVOKE.SWIGPendingException.Pending)
+                        throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+                }
+            }
         }
     }
 }
index 178d165..3a02c2c 100755 (executable)
@@ -1806,6 +1806,55 @@ namespace Tizen.NUI
         NoThirdParty
     }
 
+
+    /// <summary>
+    /// Offset has left, right, bottom, top value.
+    /// </summary>
+    [EditorBrowsable(EditorBrowsableState.Never)]
+    public struct Offset
+    {
+        /// <summary>
+        /// Constructor
+        /// </summary>
+        /// <param name="left">left offset</param>
+        /// <param name="right">right offset</param>
+        /// <param name="bottom">bottom offset</param>
+        /// <param name="top">top offset</param>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public Offset(int left, int right, int bottom, int top)
+        {
+            Left = left;
+            Right = right;
+            Bottom = bottom;
+            Top = top;
+        }
+
+        /// <summary>
+        /// Left
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public int Left {get; set;}
+
+        /// <summary>
+        /// Right
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public int Right {get; set;}
+
+        /// <summary>
+        /// Bottom
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public int Bottom {get; set;}
+
+        /// <summary>
+        /// Top
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public int Top {get; set;}
+
+    }
+
     /// <summary>
     /// TODO This is to get TizenFX resource path. It needs to be fixed to use application framework API in the future.
     /// Internal use only. Do not open this API.
index 9d144f6..d7980bd 100755 (executable)
@@ -554,6 +554,7 @@ namespace Tizen.NUI
         {
             private View _view;
             private PanGesture _panGesture;
+            private bool handled = true;
 
             /// <summary>
             /// The attached view.
@@ -590,6 +591,22 @@ namespace Tizen.NUI
                     _panGesture = value;
                 }
             }
+
+            /// <summary>
+            /// Gets or sets a value that indicates whether the event handler has completely handled the event or whether the system should continue its own processing.
+            /// </summary>
+            [EditorBrowsable(EditorBrowsableState.Never)]
+            public bool Handled
+            {
+                get => handled;
+                set
+                {
+                    handled = value;
+                    Interop.Actor.SetNeedGesturePropagation(View.getCPtr(_view), !value);
+                    if (NDalicPINVOKE.SWIGPendingException.Pending)
+                        throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+                }
+            }
         }
 
         internal class Property
index b34ee58..e7a8d38 100755 (executable)
@@ -164,6 +164,7 @@ namespace Tizen.NUI
         {
             private View _view;
             private PinchGesture _pinchGesture;
+            private bool handled = true;
 
             /// <summary>
             /// The attached view.
@@ -200,6 +201,22 @@ namespace Tizen.NUI
                     _pinchGesture = value;
                 }
             }
+
+            /// <summary>
+            /// Gets or sets a value that indicates whether the event handler has completely handled the event or whether the system should continue its own processing.
+            /// </summary>
+            [EditorBrowsable(EditorBrowsableState.Never)]
+            public bool Handled
+            {
+                get => handled;
+                set
+                {
+                    handled = value;
+                    Interop.Actor.SetNeedGesturePropagation(View.getCPtr(_view), !value);
+                    if (NDalicPINVOKE.SWIGPendingException.Pending)
+                        throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+                }
+            }
         }
     }
 }
index 8ca4a4b..86b995d 100755 (executable)
@@ -164,6 +164,7 @@ namespace Tizen.NUI
         {
             private View _view;
             private RotationGesture _rotationGesture;
+            private bool handled = true;
 
             /// <summary>
             /// The attached view.
@@ -200,6 +201,22 @@ namespace Tizen.NUI
                     _rotationGesture = value;
                 }
             }
+
+            /// <summary>
+            /// Gets or sets a value that indicates whether the event handler has completely handled the event or whether the system should continue its own processing.
+            /// </summary>
+            [EditorBrowsable(EditorBrowsableState.Never)]
+            public bool Handled
+            {
+                get => handled;
+                set
+                {
+                    handled = value;
+                    Interop.Actor.SetNeedGesturePropagation(View.getCPtr(_view), !value);
+                    if (NDalicPINVOKE.SWIGPendingException.Pending)
+                        throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+                }
+            }
         }
 
     }
index 1f23710..ec454c9 100755 (executable)
@@ -87,6 +87,20 @@ namespace Tizen.NUI
             }
         }
 
+        /// <summary>
+        /// The gesture source type of touches property (read-only).
+        /// If you tap with a mouse button, this will tell you which mouse input you tapped.
+        /// Primary(Left), Secondary(Right). Tertiary(Wheel).
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public GestureSourceType SourceType
+        {
+            get
+            {
+                return sourceType;
+            }
+        }
+
         private uint numberOfTaps
         {
             set
@@ -149,6 +163,16 @@ namespace Tizen.NUI
             }
         }
 
+        private GestureSourceType sourceType
+        {
+            get
+            {
+                GestureSourceType ret = (GestureSourceType)Interop.TapGesture.SourceTypeGet(SwigCPtr);
+                if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+                return ret;
+            }
+        }
+
         internal static global::System.Runtime.InteropServices.HandleRef getCPtr(TapGesture obj)
         {
             return (obj == null) ? new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero) : obj.swigCPtr;
@@ -173,4 +197,32 @@ namespace Tizen.NUI
             Interop.TapGesture.delete_TapGesture(swigCPtr);
         }
     }
+
+    /// <summary>
+    /// Gesture source type.
+    /// </summary>
+    [EditorBrowsable(EditorBrowsableState.Never)]
+    public enum GestureSourceType
+    {
+        /// <summary>
+        /// invalid data.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        Invalid = -1,
+        /// <summary>
+        /// Primary.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        Primary = 1,
+        /// <summary>
+        /// Secondary.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        Secondary = 3,
+        /// <summary>
+        /// Third (tertiary)
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        Tertiary = 2,
+    }
 }
index ae2e45b..f6a1142 100755 (executable)
@@ -214,6 +214,7 @@ namespace Tizen.NUI
 
             if (_detectedEventHandler != null)
             {
+                e.Handled = true;
                 //here we send all data to user event handlers
                 _detectedEventHandler(this, e);
             }
@@ -229,6 +230,7 @@ namespace Tizen.NUI
         {
             private View _view;
             private TapGesture _tapGesture;
+            private bool handled = true;
 
             /// <summary>
             /// The attached view.
@@ -265,6 +267,22 @@ namespace Tizen.NUI
                     _tapGesture = value;
                 }
             }
+
+            /// <summary>
+            /// Gets or sets a value that indicates whether the event handler has completely handled the event or whether the system should continue its own processing.
+            /// </summary>
+            [EditorBrowsable(EditorBrowsableState.Never)]
+            public bool Handled
+            {
+                get => handled;
+                set
+                {
+                    handled = value;
+                    Interop.Actor.SetNeedGesturePropagation(View.getCPtr(_view), !value);
+                    if (NDalicPINVOKE.SWIGPendingException.Pending)
+                        throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+                }
+            }
         }
     }
 }
diff --git a/test/Tizen.NUI.Samples/Tizen.NUI.Samples/Samples/FocusFinderSample.cs b/test/Tizen.NUI.Samples/Tizen.NUI.Samples/Samples/FocusFinderSample.cs
new file mode 100644 (file)
index 0000000..813cbf1
--- /dev/null
@@ -0,0 +1,233 @@
+using Tizen.NUI;
+using Tizen.NUI.BaseComponents;
+using Tizen.NUI.Components;
+using Tizen.NUI.Events;
+using System.Collections.Generic;
+
+namespace Tizen.NUI.Samples
+{
+    public class FocusFinderSample : IExample
+    {
+
+        int ItemWidth = 100;
+        int ItemHeight = 100;
+        int ItemSpacing = 10;
+
+        public View TargetView = new View();
+        TextLabel _textLabel;
+
+
+        public void Activate()
+        {
+            Window window = NUIApplication.GetDefaultWindow();
+
+            FocusManager.Instance.EnableDefaultAlgorithm(true);
+
+            var absLayout = new View
+            {
+                Layout = new AbsoluteLayout(),
+                WidthResizePolicy = ResizePolicyType.FillToParent,
+                HeightResizePolicy = ResizePolicyType.FillToParent,
+                // FocusableChildren = false,
+            };
+            window.Add(absLayout);
+
+            List<View> buttons = new List<View>();
+
+            for (int row = 0; row < 5; row++)
+            {
+                for (int cols = 0; cols < 5; cols++)
+                {
+                    var btn = MakeFocusableButton($"{row * 5 + cols}");
+                    btn.Position = new Position(ItemWidth + cols * (ItemWidth + ItemSpacing), ItemHeight + 300 + row * (ItemHeight + ItemSpacing));
+                    buttons.Add(btn);
+                    absLayout.Add(btn);
+                }
+            }
+
+            var changeLayout = new Button
+            {
+                Focusable = true,
+                FocusableInTouch = true,
+                Text = "Change Position",
+                SizeWidth = 300,
+                SizeHeight = 100,
+            };
+
+            changeLayout.Position = new Position(10, 10);
+
+            absLayout.Add(changeLayout);
+            changeLayout.Clicked += (s, e) =>
+            {
+                buttons.Reverse();
+
+                for (int row = 0; row < 5; row++)
+                {
+                    for (int cols = 0; cols < 5; cols++)
+                    {
+
+                        var btn = buttons[row * 5 + cols];
+                        btn.Position = new Position(ItemWidth + cols * (ItemWidth + ItemSpacing), ItemHeight + 300 + row * (ItemHeight + ItemSpacing));
+                    }
+                }
+            };
+
+            var hideButton = new Button
+            {
+                Focusable = true,
+                FocusableInTouch = true,
+                Text = "Hide button",
+                SizeWidth = 400,
+                SizeHeight = 100,
+            };
+
+            hideButton.Position = new Position(340, 10);
+            hideButton.Clicked += (s, e) =>
+            {
+
+                for (int i = 0; i < buttons.Count; i++)
+                {
+                    if (i % 2 == 0)
+                    {
+                        if (buttons[i].Visibility)
+                        {
+                            buttons[i].Hide();
+                        }
+                        else
+                        {
+                            buttons[i].Show();
+                        }
+                    }
+                }
+            };
+            absLayout.Add(hideButton);
+
+
+            var overlap = new Button
+            {
+                Focusable = true,
+                FocusableInTouch = true,
+                Text = "Overlap view",
+                SizeWidth = 300,
+                SizeHeight = 100,
+            };
+            overlap.Position = new Position(10, 120);
+            absLayout.Add(overlap);
+
+            View overlappedView = null;
+            overlap.Clicked += (s, e) =>
+            {
+                if (overlappedView != null)
+                {
+                    overlappedView.Unparent();
+                    overlappedView.Dispose();
+                    overlappedView = null;
+                    return;
+                }
+
+                overlappedView = new View
+                {
+                    Focusable = true,
+                    FocusableInTouch = true,
+                    Layout = new AbsoluteLayout(),
+                    SizeWidth = 400,
+                    SizeHeight = 400,
+                    BackgroundColor = new Color(1f, 0.5f, 0.5f, 0.5f)
+                };
+                overlappedView.Position = new Position(ItemWidth, ItemHeight + 300);
+                absLayout.Add(overlappedView);
+
+                var innerButton = MakeFocusableButton("InnerButton");
+                innerButton.SizeWidth = 350;
+                innerButton.SizeHeight = 350;
+                overlappedView.Add(innerButton);
+                innerButton.Position = new Position(10, 10);
+            };
+
+            _textLabel = new TextLabel
+            {
+                Text = "Focused : ",
+                SizeWidth = 500,
+                SizeHeight = 200,
+            };
+            _textLabel.Position = new Position(340, 220);
+            absLayout.Add(_textLabel);
+
+
+
+
+
+
+            var absLayout2 = new View
+            {
+                Layout = new AbsoluteLayout(),
+                WidthResizePolicy = ResizePolicyType.FillToParent,
+                HeightResizePolicy = ResizePolicyType.FillToParent,
+            };
+            window.Add(absLayout2);
+
+            var btn1 = MakeFocusableButton("#");
+            btn1.Position = new Position(ItemWidth, ItemHeight + 170);
+            ((Button)btn1).TextColor = Color.Red;
+            absLayout2.Add(btn1);
+
+            var btn2 = MakeFocusableButton("%");
+            btn2.Position = new Position(ItemWidth + 1 * (ItemWidth + ItemSpacing), ItemHeight + 170);
+            ((Button)btn2).TextColor = Color.Red;
+            absLayout2.Add(btn2);
+
+            var btn3 = MakeFocusableButton("*");
+            btn3.Position = new Position(ItemWidth + 2 * (ItemWidth + ItemSpacing), ItemHeight + 170);
+            ((Button)btn3).TextColor = Color.Red;
+            absLayout2.Add(btn3);
+
+            var btn4 = MakeFocusableButton("+");
+            btn4.Position = new Position(ItemWidth + 3 * (ItemWidth + ItemSpacing), ItemHeight + 170);
+            ((Button)btn4).TextColor = Color.Red;
+            absLayout2.Add(btn4);
+
+            var btn5 = MakeFocusableButton("-");
+            btn5.Position = new Position(ItemWidth + 4 * (ItemWidth + ItemSpacing), ItemHeight + 170);
+            ((Button)btn5).TextColor = Color.Red;
+            absLayout2.Add(btn5);
+
+
+            var focusableChildrenView = new Button
+            {
+                Focusable = true,
+                FocusableInTouch = true,
+                Text = "FocusableChildren",
+                SizeWidth = 400,
+                SizeHeight = 100,
+            };
+            focusableChildrenView.Position = new Position(340, 120);
+            absLayout.Add(focusableChildrenView);
+
+            focusableChildrenView.Clicked += (s, e) =>
+            {
+                absLayout2.FocusableChildren = false;
+            };
+        }
+
+        View MakeFocusableButton(string title)
+        {
+            var btn = new Button
+            {
+                Focusable = true,
+                FocusableInTouch = true,
+                Text = title,
+                SizeWidth = ItemWidth,
+                SizeHeight = ItemHeight,
+            };
+
+            btn.FocusGained += (s, e) => btn.Text = $"[{title}]";
+            btn.FocusLost += (s, e) => btn.Text = $"{title}";
+            btn.FocusGained += (s, e) => _textLabel.Text = $"Focused : {title}";
+            return btn;
+        }
+
+        public void Deactivate()
+        {
+        }
+    }
+}
index e956f00..05e2578 100755 (executable)
@@ -9,7 +9,6 @@ namespace Tizen.NUI.Samples
     public class TouchGestureSample : IExample
     {
         private View root;
-        GestureDetectorManager mGestureDetector;
         private TextLabel frontView;
         private TextLabel backView;
 
@@ -33,6 +32,7 @@ namespace Tizen.NUI.Samples
                 BackgroundColor = new Color(1.0f, 0.0f, 0.0f, 1.0f),
             };
             frontView.TouchEvent += OnFrontTouchEvent;
+            frontView.TouchAreaOffset = new Offset(-10, 20, 30, -40); // left, right, bottom, top
 
 
             backView = new TextLabel
@@ -44,7 +44,6 @@ namespace Tizen.NUI.Samples
                 BackgroundColor = new Color(1.0f, 1.0f, 0.0f, 1.0f),
             };
 
-            mGestureDetector = new GestureDetectorManager(backView, new MyGestureListener());
             backView.TouchEvent += OnBackTouchEvent;
 
             backView.Add(frontView);
@@ -63,37 +62,9 @@ namespace Tizen.NUI.Samples
         private bool OnBackTouchEvent(object source, View.TouchEventArgs e)
         {
             Tizen.Log.Error("NUI", $"OnBackTouchEvent {e.Touch.GetState(0)}\n");
-            mGestureDetector.FeedTouchEvent(source, e, this);
             return false;
         }
 
-        class MyGestureListener : GestureDetectorManager.GestureListener
-        {
-          public override void OnTap(object sender, TapGestureDetector.DetectedEventArgs e, object userData)
-          {
-            Tizen.Log.Error("NUI", $"OnTap \n");
-            if(userData != null)
-            {
-              TouchGestureSample sample = (TouchGestureSample) userData;
-              sample.ChangeText();
-            }
-          }
-
-          public override void OnPan(object sender, PanGestureDetector.DetectedEventArgs e, object userData)
-          {
-            Tizen.Log.Error("NUI", $"OnPan \n");
-          }
-
-          public override void OnPinch(object sender, PinchGestureDetector.DetectedEventArgs e, object userData)
-          {
-            Tizen.Log.Error("NUI", $"OnPinch \n");
-          }
-
-          public override void OnLongPress(object sender, LongPressGestureDetector.DetectedEventArgs e, object userData)
-          {
-            Tizen.Log.Error("NUI", $"OnLongPress \n");
-          }
-        }
 
         public void Deactivate()
         {