[NUI] Fix scrollableBase focus issue. (#4340)
authorSangHyeon Jade Lee <sh10233.lee@samsung.com>
Fri, 17 Jun 2022 10:21:25 +0000 (19:21 +0900)
committerdongsug-song <35130733+dongsug-song@users.noreply.github.com>
Tue, 21 Jun 2022 10:27:08 +0000 (19:27 +0900)
* [NUI] Fix scrollableBase focus issue.

fix several issue on focus of scrollableBase.

1. fix wrong focus fallback when next focused children is invisble.
- if current focused object is children of scrollableBase,
  keep focus to current focused object.
- if current focused object is out of scrollableBase,
  to keep focus within the scrollableBase, set focus on scrollableBase.

2. fix wrong next focus returns on next find failed case.
   if next focus find is failed, we can move scroll when key can move
   foward and backward only not other directions.
   In other direction inputs, escape the scrollableBase.

3. fix wrong escape condition of EOS(end of scroll).
   we escape scrollableBase in EOS, but we need to reached EOS firstly,
   and escape scrollableBase on next key input to move out.

4. add conditional debugging log.

5. fix focus samples.
   add text label for notify prev/current focused object.
   fix title of items.
   make padding longer on items.

* [NUI] fix samples.

* [NUI] return null as nextFocusedView will always null.

* [NUI] Update scrollableBase focus logic for missing cases.

* [NUI] Update scrollableBase focus to find next focus properly.

* [NUI] remove unreachable code.

src/Tizen.NUI.Components/Controls/ScrollableBase.cs
test/Tizen.NUI.Samples/Tizen.NUI.Samples/Samples/ScrollableFocus/ScrollableFocusAllChildrenSample.cs
test/Tizen.NUI.Samples/Tizen.NUI.Samples/Samples/ScrollableFocus/ScrollableFocusNoneChildrenSample.cs
test/Tizen.NUI.Samples/Tizen.NUI.Samples/Samples/ScrollableFocus/ScrollableFocusSparseChildrenSample.cs

index 4855dc1..ff79153 100755 (executable)
@@ -148,6 +148,7 @@ namespace Tizen.NUI.Components
     public partial class ScrollableBase : Control
     {
         static bool LayoutDebugScrollableBase = false; // Debug flag
+        static bool focusDebugScrollableBase = false; // Debug flag
         private Direction mScrollingDirection = Direction.Vertical;
         private bool mScrollEnabled = true;
         private int mScrollDuration = 125;
@@ -1971,7 +1972,6 @@ namespace Tizen.NUI.Components
             }
         }
 
-
         /// <inheritdoc/>
         [EditorBrowsable(EditorBrowsableState.Never)]
         public override View GetNextFocusableView(View currentFocusedView, View.FocusDirection direction, bool loopEnabled)
@@ -1980,8 +1980,32 @@ namespace Tizen.NUI.Components
             float targetPosition = -(ScrollingDirection == Direction.Horizontal ? ContentContainer.CurrentPosition.X : ContentContainer.CurrentPosition.Y);
             float stepDistance = (stepScrollDistance != 0? stepScrollDistance : (isHorizontal ? Size.Width * 0.25f :  Size.Height * 0.25f));
 
+            bool forward = ((isHorizontal && direction == View.FocusDirection.Right) ||
+                            (!isHorizontal && direction == View.FocusDirection.Down));
+            bool backward = ((isHorizontal && direction == View.FocusDirection.Left) ||
+                                (!isHorizontal && direction == View.FocusDirection.Up));
+
+             // Reached end of scroll. move out focus from ScrollableBase.
+            if ((forward && maxScrollDistance - targetPosition < 0.1f) || (backward && targetPosition < 0.1f))
+            {
+                var next = FocusManager.Instance.GetNearestFocusableActor(this.Parent, this, direction);
+                Debug.WriteLineIf(focusDebugScrollableBase, $"Reached End of Scroll. Next focus target {next}:{next?.ID}");
+                return next;
+            }
+
             View nextFocusedView = FocusManager.Instance.GetNearestFocusableActor(this, currentFocusedView, direction);
 
+            if (focusDebugScrollableBase)
+            {
+                global::System.Text.StringBuilder debugMessage = new global::System.Text.StringBuilder("=========================================================\n");
+                debugMessage.Append($"GetNextFocusableView On: {this}:{this.ID}\n");
+                debugMessage.Append($"----------------Current: {currentFocusedView}:{currentFocusedView?.ID}\n");
+                debugMessage.Append($"-------------------Next: {nextFocusedView}:{nextFocusedView?.ID}\n");
+                debugMessage.Append($"--------------Direction: {direction}\n");
+                debugMessage.Append("=========================================================");
+                Debug.WriteLineIf(focusDebugScrollableBase, debugMessage);
+            }
+
             if (nextFocusedView != null)
             {
                 if (null != FindDescendantByID(nextFocusedView.ID))
@@ -1989,38 +2013,30 @@ namespace Tizen.NUI.Components
                     if (IsChildNearlyVisble(nextFocusedView, stepDistance) == true)
                     {
                         ScrollToChild(nextFocusedView, true);
-                    }
-                    else
-                    {
-                        if ((isHorizontal && direction == View.FocusDirection.Right) ||
-                            (!isHorizontal && direction == View.FocusDirection.Down))
-                        {
-                            targetPosition += stepDistance;
-                            targetPosition = targetPosition > maxScrollDistance ? maxScrollDistance : targetPosition;
-
-                        }
-                        else if ((isHorizontal && direction == View.FocusDirection.Left) ||
-                                 (!isHorizontal && direction == View.FocusDirection.Up))
-                        {
-                            targetPosition -= stepDistance;
-                            targetPosition = targetPosition < 0 ? 0 : targetPosition;
-                        }
-
-                        ScrollTo(targetPosition, true);
+                        return nextFocusedView;
                     }
                 }
             }
-            else
+
+            if (forward || backward)
             {
-                if((isHorizontal && direction == View.FocusDirection.Right) ||
-                    (!isHorizontal && direction == View.FocusDirection.Down))
+                // Fallback to current focus or scrollableBase till next focus visible in scrollable.
+                if (null != currentFocusedView && null != FindDescendantByID(currentFocusedView.ID))
+                {
+                    nextFocusedView = currentFocusedView;
+                }
+                else
+                {
+                    return this;
+                }
+
+                if (forward)
                 {
                     targetPosition += stepDistance;
                     targetPosition = targetPosition > maxScrollDistance ? maxScrollDistance : targetPosition;
 
                 }
-                else if((isHorizontal && direction == View.FocusDirection.Left) ||
-                        (!isHorizontal && direction == View.FocusDirection.Up))
+                else if (backward)
                 {
                     targetPosition -= stepDistance;
                     targetPosition = targetPosition < 0 ? 0 : targetPosition;
@@ -2028,13 +2044,10 @@ namespace Tizen.NUI.Components
 
                 ScrollTo(targetPosition, true);
 
-                // End of scroll. escape.
-                if ((targetPosition == 0 || targetPosition == maxScrollDistance) == false)
-                {
-                    return this;
-                }
-
+                Debug.WriteLineIf(focusDebugScrollableBase, $"ScrollTo :({targetPosition})");
             }
+
+            Debug.WriteLineIf(focusDebugScrollableBase, $"return end : {nextFocusedView}:{nextFocusedView?.ID}");
             return nextFocusedView;
         }
 
index 50318ad..67bb8af 100755 (executable)
@@ -11,6 +11,37 @@ namespace Tizen.NUI.Samples
         int SCROLLMAX = 50;
         public View root;
 
+        private string GetChildText(View parent)
+        {
+            if (parent != null)
+            {
+                foreach(View child in parent.Children)
+                {
+                    if (child is TextLabel label)
+                    {
+                        return $"{label.Text}";
+                    }
+                }
+            }
+
+            return "";
+        }
+
+        private string GetLabelText(int i)
+        {
+            switch (i)
+            {
+                case 0:
+                    return "[1st]";
+                case 1:
+                    return "[2nd]";
+                case 2:
+                    return "[3rd]";
+                default:
+                    return $"[{i+1}th]";
+            }
+        }
+
         public void Activate()
         {
 
@@ -31,7 +62,34 @@ namespace Tizen.NUI.Samples
             };
             window.Add(root);
 
+            var focusInfo = new TextLabel()
+            {
+                BackgroundColor = Color.Yellow,
+                TextColor = Color.Red,
+                Text = "Prev:[N/A] Current:[N/A]"
+            };
+            root.Add(focusInfo);
+
             FocusManager.Instance.EnableDefaultAlgorithm(true);
+            FocusManager.Instance.FocusChanged += (object s, FocusManager.FocusChangedEventArgs e) =>
+            {
+                string prev = "[N/A]";
+                string cur = "[N/A]";
+                if (e.Previous != null)
+                {
+                    var prevView = e.Previous;
+                    prev = $"{prevView.Name}[{prevView.ID}]{GetChildText(prevView)}";
+                }
+
+                if (e.Current != null)
+                {
+                    var curView = e.Current;
+                    cur = $"{curView.Name}[{curView.ID}]{GetChildText(curView)}";
+                }
+
+                focusInfo.Text = $"Prev:{prev} Current:{cur}";
+                Console.WriteLine($"Focus Changed Prev:{prev} => Current:{cur}");
+            };
 
             var top = new Button()
             {
@@ -51,7 +109,7 @@ namespace Tizen.NUI.Samples
                 {
                     LinearOrientation = LinearLayout.Orientation.Vertical,
                     HorizontalAlignment = HorizontalAlignment.Center,
-                    CellPadding = new Size2D(10, 10),
+                    CellPadding = new Size2D(10, 30),
                 }
             };
             root.Add(verticalScrollView);
@@ -74,7 +132,7 @@ namespace Tizen.NUI.Samples
                 };
                 var label = new TextLabel()
                 {
-                    Text = $"[{i}]",
+                    Text = GetLabelText(i),
                     PointSize = 20,
                 };
                 colorItem.Add(label);
@@ -122,7 +180,7 @@ namespace Tizen.NUI.Samples
                 {
                     LinearOrientation = LinearLayout.Orientation.Horizontal,
                     VerticalAlignment = VerticalAlignment.Center,
-                    CellPadding = new Size2D(10, 10),
+                    CellPadding = new Size2D(30, 10),
                 }
             };
             horizontalLayout.Add(horizontalScrollView);
@@ -145,7 +203,7 @@ namespace Tizen.NUI.Samples
                 };
                 var label = new TextLabel()
                 {
-                    Text = $"[{i}]",
+                    Text = GetLabelText(i),
                     PointSize = 20,
                 };
                 colorItem.Add(label);
index 280e740..c654071 100755 (executable)
@@ -11,6 +11,37 @@ namespace Tizen.NUI.Samples
         int SCROLLMAX = 50;
         public View root;
 
+        private string GetChildText(View parent)
+        {
+            if (parent != null)
+            {
+                foreach(View child in parent.Children)
+                {
+                    if (child is TextLabel label)
+                    {
+                        return $"{label.Text}";
+                    }
+                }
+            }
+
+            return "";
+        }
+
+        private string GetLabelText(int i)
+        {
+            switch (i)
+            {
+                case 0:
+                    return "[1st]";
+                case 1:
+                    return "[2nd]";
+                case 2:
+                    return "[3rd]";
+                default:
+                    return $"[{i+1}th]";
+            }
+        }
+
         public void Activate()
         {
 
@@ -31,7 +62,35 @@ namespace Tizen.NUI.Samples
             };
             window.Add(root);
 
+            var focusInfo = new TextLabel()
+            {
+                BackgroundColor = Color.Yellow,
+                TextColor = Color.Red,
+                //Focusable = true,
+                Text = "Prev:[N/A] Current:[N/A]"
+            };
+            root.Add(focusInfo);
+
             FocusManager.Instance.EnableDefaultAlgorithm(true);
+            FocusManager.Instance.FocusChanged += (object s, FocusManager.FocusChangedEventArgs e) =>
+            {
+                string prev = "[N/A]";
+                string cur = "[N/A]";
+                if (e.Previous != null)
+                {
+                    var prevView = e.Previous;
+                    prev = $"{prevView.Name}[{prevView.ID}]{GetChildText(prevView)}";
+                }
+
+                if (e.Current != null)
+                {
+                    var curView = e.Current;
+                    cur = $"{curView.Name}[{curView.ID}]{GetChildText(curView)}";
+                }
+
+                focusInfo.Text = $"Prev:{prev} Current:{cur}";
+                Console.WriteLine($"Focus Changed Prev:{prev} => Current:{cur}");
+            };
 
             var top = new Button()
             {
@@ -56,7 +115,7 @@ namespace Tizen.NUI.Samples
                 {
                     LinearOrientation = LinearLayout.Orientation.Vertical,
                     HorizontalAlignment = HorizontalAlignment.Center,
-                    CellPadding = new Size2D(10, 10),
+                    CellPadding = new Size2D(10, 30),
                 }
             };
             root.Add(verticalScrollView);
@@ -74,12 +133,14 @@ namespace Tizen.NUI.Samples
                         VerticalAlignment = VerticalAlignment.Center,
                         CellPadding = new Size2D(10, 10),
                     }
+
                 };
                 var label = new TextLabel()
                 {
-                    Text = $"[{i}]",
+                    Text = GetLabelText(i),
                     PointSize = 20,
                 };
+
                 colorItem.Add(label);
                 verticalScrollView.Add(colorItem);
             }
@@ -130,7 +191,7 @@ namespace Tizen.NUI.Samples
                 {
                     LinearOrientation = LinearLayout.Orientation.Horizontal,
                     VerticalAlignment = VerticalAlignment.Center,
-                    CellPadding = new Size2D(10, 10),
+                    CellPadding = new Size2D(30, 10),
                 }
             };
             horizontalLayout.Add(horizontalScrollView);
@@ -151,7 +212,7 @@ namespace Tizen.NUI.Samples
                 };
                 var label = new TextLabel()
                 {
-                    Text = $"[{i}]",
+                    Text = GetLabelText(i),
                     PointSize = 20,
                 };
                 colorItem.Add(label);
index 3ef9526..a5e5edd 100755 (executable)
@@ -11,6 +11,37 @@ namespace Tizen.NUI.Samples
         int SCROLLMAX = 50;
         public View root;
 
+        private string GetChildText(View parent)
+        {
+            if (parent != null)
+            {
+                foreach(View child in parent.Children)
+                {
+                    if (child is TextLabel label)
+                    {
+                        return $"{label.Text}";
+                    }
+                }
+            }
+
+            return "";
+        }
+
+        private string GetLabelText(int i)
+        {
+            switch (i)
+            {
+                case 0:
+                    return "[1st]";
+                case 1:
+                    return "[2nd]";
+                case 2:
+                    return "[3rd]";
+                default:
+                    return $"[{i+1}th]";
+            }
+        }
+
         public void Activate()
         {
 
@@ -31,7 +62,34 @@ namespace Tizen.NUI.Samples
             };
             window.Add(root);
 
+            var focusInfo = new TextLabel()
+            {
+                BackgroundColor = Color.Yellow,
+                TextColor = Color.Red,
+                Text = "Prev:[N/A] Current:[N/A]"
+            };
+            root.Add(focusInfo);
+
             FocusManager.Instance.EnableDefaultAlgorithm(true);
+            FocusManager.Instance.FocusChanged += (object s, FocusManager.FocusChangedEventArgs e) =>
+            {
+                string prev = "[N/A]";
+                string cur = "[N/A]";
+                if (e.Previous != null)
+                {
+                    var prevView = e.Previous;
+                    prev = $"{prevView.Name}[{prevView.ID}]{GetChildText(prevView)}";
+                }
+
+                if (e.Current != null)
+                {
+                    var curView = e.Current;
+                    cur = $"{curView.Name}[{curView.ID}]{GetChildText(curView)}";
+                }
+
+                focusInfo.Text = $"Prev:{prev} Current:{cur}";
+                Console.WriteLine($"Focus Changed Prev:{prev} => Current:{cur}");
+            };
 
             var top = new Button()
             {
@@ -56,7 +114,7 @@ namespace Tizen.NUI.Samples
                 {
                     LinearOrientation = LinearLayout.Orientation.Vertical,
                     HorizontalAlignment = HorizontalAlignment.Center,
-                    CellPadding = new Size2D(10, 10),
+                    CellPadding = new Size2D(10, 30),
                 }
             };
             root.Add(verticalScrollView);
@@ -77,7 +135,7 @@ namespace Tizen.NUI.Samples
                 };
                 var label = new TextLabel()
                 {
-                    Text = $"[{i}]",
+                    Text = GetLabelText(i),
                     PointSize = 20,
                 };
 
@@ -137,7 +195,7 @@ namespace Tizen.NUI.Samples
                 {
                     LinearOrientation = LinearLayout.Orientation.Horizontal,
                     VerticalAlignment = VerticalAlignment.Center,
-                    CellPadding = new Size2D(10, 10),
+                    CellPadding = new Size2D(30, 10),
                 }
             };
             horizontalLayout.Add(horizontalScrollView);
@@ -158,7 +216,7 @@ namespace Tizen.NUI.Samples
                 };
                 var label = new TextLabel()
                 {
-                    Text = $"[{i}]",
+                    Text = GetLabelText(i),
                     PointSize = 20,
                 };