[NUI] Add a new Tizen.NUI.ICustomAwareDeviceFocusAlgorithm.
authorjoogab.yun <joogab.yun@samsung.com>
Fri, 4 Mar 2022 09:28:29 +0000 (18:28 +0900)
committerdongsug-song <35130733+dongsug-song@users.noreply.github.com>
Tue, 29 Mar 2022 03:10:12 +0000 (12:10 +0900)
This interface takes an additional deviceName argument to GetNextFocusableView().
The deviceName is the name of the device where the key event occurred.

A new deviceName added to GetNextFocusableView() should not affect the current app.

Current apps are using the FocusManager.ICustomFocusAlgorithm interface.
So I created a new Tizen.NUI.ICustomAwareDeviceFocusAlgorithm interface.

for example)
Currently

``` c#
class CustomInterface : FocusManager.ICustomFocusAlgorithm
{
 public View GetNextFocusableView(View current, View proposed, View.FocusDirection direction)
 {
   return proposed;
 }
}
```

If you wnat to do GetNextFocusableView() with deviceName, you can inherit ICustomAwareDeviceFocusAlgorithm.

``` c#
class CustomInterface : Tizen.NUI.ICustomAwareDeviceFocusAlgorithm
{
 // This method is called when a direction key is pressed.
 public View GetNextFocusableView(View current, View proposed, View.FocusDirection direction, string deviceName)
 {
  return proposed;
 }

 // This method is never called.
 public View GetNextFocusableView(View current, View proposed, View.FocusDirection direction)
 {
  return proposed;
 }
}
```

dependency
https://review.tizen.org/gerrit/#/c/platform/core/uifw/dali-toolkit/+/271983/
https://review.tizen.org/gerrit/#/c/platform/core/uifw/dali-csharp-binder/+/271984/

src/Tizen.NUI/src/internal/Common/CustomAlgorithmInterface.cs
src/Tizen.NUI/src/internal/Interop/Interop.CustomAlgorithmInterface.cs
src/Tizen.NUI/src/public/Input/FocusManager.cs
src/Tizen.NUI/src/public/Input/ICustomAwareDeviceFocusAlgorithm.cs [new file with mode: 0755]
test/Tizen.NUI.Samples/Tizen.NUI.Samples/Samples/GetNextFocusSample.cs [new file with mode: 0644]

index 23ff57a..3f6dc24 100755 (executable)
@@ -31,9 +31,9 @@ namespace Tizen.NUI
             Interop.CustomAlgorithmInterface.DeleteCustomAlgorithmInterface(swigCPtr);
         }
 
-        public virtual View GetNextFocusableView(View current, View proposed, View.FocusDirection direction)
+        public virtual View GetNextFocusableView(View current, View proposed, View.FocusDirection direction, string deviceName = "")
         {
-            View ret = new View(Interop.CustomAlgorithmInterface.GetNextFocusableActor(SwigCPtr, View.getCPtr(current), View.getCPtr(proposed), (int)direction), true);
+            View ret = new View(Interop.CustomAlgorithmInterface.GetNextFocusableActor(SwigCPtr, View.getCPtr(current), View.getCPtr(proposed), (int)direction, deviceName), true);
             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
             return ret;
         }
@@ -58,7 +58,7 @@ namespace Tizen.NUI
             return hasDerivedMethod && (methodInfo != null);
         }
 
-        private global::System.IntPtr SwigDirectorGetNextFocusableView(global::System.IntPtr current, global::System.IntPtr proposed, int direction)
+        private global::System.IntPtr SwigDirectorGetNextFocusableView(global::System.IntPtr current, global::System.IntPtr proposed, int direction, string deviceName)
         {
             if (current == global::System.IntPtr.Zero && proposed == global::System.IntPtr.Zero)
             {
@@ -70,19 +70,19 @@ namespace Tizen.NUI
                 View currentView = Registry.GetManagedBaseHandleFromNativePtr(current) as View;
                 View proposedView = Registry.GetManagedBaseHandleFromNativePtr(proposed) as View;
 
-                return View.getCPtr(GetNextFocusableView(currentView, proposedView, (View.FocusDirection)direction)).Handle;
+                return View.getCPtr(GetNextFocusableView(currentView, proposedView, (View.FocusDirection)direction, deviceName)).Handle;
             }
             catch (global::System.Exception ex)
             {
                 Tizen.Log.Error("NUI", "Registry Error: " + ex);
+                throw;
             }
-            return global::System.IntPtr.Zero;
         }
 
-        internal delegate global::System.IntPtr SwigDelegateCustomAlgorithmInterface_0(global::System.IntPtr current, global::System.IntPtr proposed, int direction);
+        internal delegate global::System.IntPtr SwigDelegateCustomAlgorithmInterface_0(global::System.IntPtr current, global::System.IntPtr proposed, int direction, string deviceName);
 
         private SwigDelegateCustomAlgorithmInterface_0 swigDelegate0;
 
-        private static global::System.Type[] swigMethodTypes0 = new global::System.Type[] { typeof(View), typeof(View), typeof(View.FocusDirection) };
+        private static global::System.Type[] swigMethodTypes0 = new global::System.Type[] { typeof(View), typeof(View), typeof(View.FocusDirection), typeof(string) };
     }
 }
index 9319dd2..88bb27c 100755 (executable)
@@ -25,7 +25,7 @@ namespace Tizen.NUI
             public static extern void DeleteCustomAlgorithmInterface(global::System.Runtime.InteropServices.HandleRef jarg1);
 
             [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_CustomAlgorithmInterface_GetNextFocusableActor")]
-            public static extern global::System.IntPtr GetNextFocusableActor(global::System.Runtime.InteropServices.HandleRef jarg1, global::System.Runtime.InteropServices.HandleRef jarg2, global::System.Runtime.InteropServices.HandleRef jarg3, int jarg4);
+            public static extern global::System.IntPtr GetNextFocusableActor(global::System.Runtime.InteropServices.HandleRef jarg1, global::System.Runtime.InteropServices.HandleRef jarg2, global::System.Runtime.InteropServices.HandleRef jarg3, int jarg4, string deviceName);
 
             [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_new_CustomAlgorithmInterface")]
             public static extern global::System.IntPtr NewCustomAlgorithmInterface();
index cc27082..7706b56 100755 (executable)
@@ -237,6 +237,7 @@ namespace Tizen.NUI
             View GetNextFocusableView(View current, View proposed, View.FocusDirection direction);
         }
 
+
         /// <summary>
         /// Gets or sets the status of whether the focus movement should be looped within the same focus group.<br />
         /// The focus movement is not looped by default.<br />
@@ -811,14 +812,21 @@ namespace Tizen.NUI
                 this.customFocusAlgorithm = customFocusAlgorithm;
             }
 
-            public override View GetNextFocusableView(View current, View proposed, View.FocusDirection direction)
+            public override View GetNextFocusableView(View current, View proposed, View.FocusDirection direction, string deviceName)
             {
                 if (customFocusAlgorithm == null)
                 {
                     Tizen.Log.Error("NUI", $"[ERROR] User defined ICustomFocusAlgorithm interface class becomes unreachable. Null will be proposed for next focusing!");
                     return null;
                 }
-                return customFocusAlgorithm.GetNextFocusableView(current, proposed, direction);
+                if (customFocusAlgorithm is ICustomAwareDeviceFocusAlgorithm deviceAwared)
+                {
+                    return deviceAwared.GetNextFocusableView(current, proposed, direction, deviceName);
+                }
+                else
+                {
+                    return customFocusAlgorithm.GetNextFocusableView(current, proposed, direction);
+                }
             }
         }
     }
diff --git a/src/Tizen.NUI/src/public/Input/ICustomAwareDeviceFocusAlgorithm.cs b/src/Tizen.NUI/src/public/Input/ICustomAwareDeviceFocusAlgorithm.cs
new file mode 100755 (executable)
index 0000000..6503a4d
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2022 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 Tizen.NUI.BaseComponents;
+using System.ComponentModel;
+
+namespace Tizen.NUI
+{
+    /// <summary>
+    /// ICustomAwareDeviceFocusAlgorithm inherits from <see cref="Tizen.NUI.FocusManager.ICustomFocusAlgorithm"/>
+    /// ICustomAwareDeviceFocusAlgorithm is used to provide the custom keyboard focus algorithm for retrieving the next focusable view.<br />
+    /// The application can implement the interface and override the keyboard focus behavior.<br />
+    /// If the focus is changing within a layout container, then the layout container is queried first to provide the next focusable view.<br />
+    /// If this does not provide a valid view, then the Keyboard FocusManager will check focusable properties to determine the next focusable actor.<br />
+    /// If focusable properties are not set, then the keyboard FocusManager calls the GetNextFocusableView() method of this interface.<br />
+    /// This interface calls GetNextFocusableView() with deviceName. <br />
+    /// </summary>
+    [EditorBrowsable(EditorBrowsableState.Never)]
+    public interface ICustomAwareDeviceFocusAlgorithm : FocusManager.ICustomFocusAlgorithm
+    {
+        /// <summary>
+        /// Get the next focus actor.
+        /// </summary>
+        /// <param name="current">The current focus view.</param>
+        /// <param name="proposed">The proposed focus view</param>
+        /// <param name="direction">The focus move direction</param>
+        /// <param name="deviceName">The name of device the key event originated from</param>
+        /// <returns>The next focus actor.</returns>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        View GetNextFocusableView(View current, View proposed, View.FocusDirection direction, string deviceName);
+    }
+}
diff --git a/test/Tizen.NUI.Samples/Tizen.NUI.Samples/Samples/GetNextFocusSample.cs b/test/Tizen.NUI.Samples/Tizen.NUI.Samples/Samples/GetNextFocusSample.cs
new file mode 100644 (file)
index 0000000..e59873b
--- /dev/null
@@ -0,0 +1,84 @@
+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 GetNextFocusSample : IExample
+    {
+
+        int ItemWidth = 100;
+        int ItemHeight = 100;
+        int ItemSpacing = 10;
+
+        public View TargetView = new View();
+
+        class CustomInterface : ICustomAwareDeviceFocusAlgorithm
+        {
+            // This method is called when a direction key is pressed.
+            public View GetNextFocusableView(View current, View proposed, View.FocusDirection direction, string deviceName)
+            {
+                Tizen.Log.Error("NUI", $" GetNextFocusableView deviceName {deviceName}\n");
+                return proposed;
+            }
+
+            // This method is never called.
+            public View GetNextFocusableView(View current, View proposed, View.FocusDirection direction)
+            {
+                Tizen.Log.Error("NUI", $" GetNextFocusableView \n");
+                return proposed;
+            }
+        }
+
+        public void Activate()
+        {
+            Window window = NUIApplication.GetDefaultWindow();
+
+            CustomInterface custom = new CustomInterface();
+            FocusManager.Instance.SetCustomAlgorithm(custom);
+
+            var absLayout = new View
+            {
+                Layout = new AbsoluteLayout(),
+                WidthResizePolicy = ResizePolicyType.FillToParent,
+                HeightResizePolicy = ResizePolicyType.FillToParent,
+                Focusable = true,
+                FocusableInTouch = true,
+            };
+            window.Add(absLayout);
+
+            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));
+                    absLayout.Add(btn);
+                }
+            }
+        }
+
+        View MakeFocusableButton(string title)
+        {
+            var btn = new Button
+            {
+                Focusable = true,
+                FocusableInTouch = true,
+                Text = title,
+                SizeWidth = ItemWidth,
+                SizeHeight = ItemHeight,
+                BackgroundColor = Color.Blue,
+            };
+
+            btn.FocusGained += (s, e) => btn.Text = $"[{title}]";
+            btn.FocusLost += (s, e) => btn.Text = $"{title}";
+            return btn;
+        }
+
+        public void Deactivate()
+        {
+        }
+    }
+}