[NUI] Change key focus related event's name
authordongsug.song <dongsug.song@samsung.com>
Tue, 29 Mar 2022 13:23:34 +0000 (22:23 +0900)
committerSeoyeon2Kim <34738918+Seoyeon2Kim@users.noreply.github.com>
Fri, 27 May 2022 06:15:42 +0000 (15:15 +0900)
src/Tizen.NUI/src/public/Input/FocusManager.cs
src/Tizen.NUI/src/public/Input/FocusManagerArgs.cs [new file with mode: 0755]
test/Tizen.NUI.Samples/Tizen.NUI.Samples/Samples/FocusManagerEventTest.cs [new file with mode: 0644]

index cdfa12c..2b23bf6 100755 (executable)
@@ -36,6 +36,9 @@ namespace Tizen.NUI
         private EventHandlerWithReturnType<object, PreFocusChangeEventArgs, View> preFocusChangeEventHandler;
         private PreFocusChangeEventCallback preFocusChangeCallback;
 
+        private EventHandler<FocusChangingEventArgs> focusChangingEventHandler;
+        private PreFocusChangeEventCallback focusChangingCallback;
+
         private EventHandler<FocusChangedEventArgs> focusChangedEventHandler;
         private FocusChangedEventCallback focusChangedEventCallback;
 
@@ -83,6 +86,9 @@ namespace Tizen.NUI
         /// It won't be emitted for focus movement by calling the SetCurrentFocusView directly.<br />
         /// </summary>
         /// <since_tizen> 3 </since_tizen>
+        [Obsolete("Please do not use! This will be deprecated in API10. Please use KeyFocusChanging instead!")]
+        // this will be deprecated, so suppress warning would be OK.
+        [System.Diagnostics.CodeAnalysis.SuppressMessage("Naming", "CA1710:Identifiers should have correct suffix", Justification = "<Pending>")]
         public event EventHandlerWithReturnType<object, PreFocusChangeEventArgs, View> PreFocusChange
         {
             add
@@ -90,22 +96,60 @@ namespace Tizen.NUI
                 if (preFocusChangeEventHandler == null)
                 {
                     preFocusChangeCallback = OnPreFocusChange;
-                    PreFocusChangeSignal().Connect(preFocusChangeCallback);
+                    using PreFocusChangeSignal signal = PreFocusChangeSignal();
+                    signal?.Connect(preFocusChangeCallback);
                 }
                 preFocusChangeEventHandler += value;
             }
             remove
             {
                 preFocusChangeEventHandler -= value;
-                if (preFocusChangeEventHandler == null && PreFocusChangeSignal().Empty() == false)
+                using PreFocusChangeSignal signal = PreFocusChangeSignal();
+                if (preFocusChangeEventHandler == null && signal?.Empty() == false)
                 {
-                    PreFocusChangeSignal().Disconnect(preFocusChangeCallback);
+                    signal?.Disconnect(preFocusChangeCallback);
                 }
             }
         }
 
         /// <summary>
-        /// The FocusGroupChanged will be triggered after the current focused view has been changed.
+        /// FocusChanging will be triggered before the focus is going to be changed.<br />
+        /// The FocusManager makes the best guess for which view to focus towards the given direction, but applications might want to change that.<br />
+        /// By connecting with this event, they can check the proposed view to focus and assign a different view if they wish.<br />
+        /// This event is only triggered when the navigation key is pressed and FocusManager tries to move the focus automatically.<br />
+        /// It won't be emitted for focus movement by calling the SetCurrentFocusView directly.<br />
+        /// </summary>
+        /// <remarks>
+        /// by setting FocusChangingEventArgs.Proposed with the view to be focused, the focus will be moved to the assigned view.
+        /// </remarks>
+        /// <since_tizen> 10 </since_tizen>
+        public event EventHandler<FocusChangingEventArgs> FocusChanging
+        {
+            add
+            {
+                if (focusChangingEventHandler == null)
+                {
+                    focusChangingCallback = OnFocusChanging;
+                    //this is same as old PreFocusChangeSignal, so the body will be same. (only name is changed, behavior is same)
+                    using PreFocusChangeSignal signal = PreFocusChangeSignal();
+                    signal?.Connect(focusChangingCallback);
+                }
+                focusChangingEventHandler += value;
+            }
+            remove
+            {
+                focusChangingEventHandler -= value;
+                //this is same as old PreFocusChangeSignal, so the body will be same. (only name is changed, behavior is same)
+                using PreFocusChangeSignal signal = PreFocusChangeSignal();
+                if (focusChangingEventHandler == null && signal?.Empty() == false)
+                {
+                    signal?.Disconnect(focusChangingCallback);
+                }
+            }
+        }
+
+        /// <summary>
+        /// The FocusChanged will be triggered after the current focused view has been changed.
         /// </summary>
         /// <since_tizen> 3 </since_tizen>
         public event EventHandler<FocusChangedEventArgs> FocusChanged
@@ -115,7 +159,8 @@ namespace Tizen.NUI
                 if (focusChangedEventCallback == null)
                 {
                     focusChangedEventCallback = OnFocusChanged;
-                    FocusChangedSignal().Connect(focusChangedEventCallback);
+                    using FocusChangedSignal signal = FocusChangedSignal();
+                    signal?.Connect(focusChangedEventCallback);
                 }
                 focusChangedEventHandler += value;
             }
@@ -123,9 +168,10 @@ namespace Tizen.NUI
             {
                 focusChangedEventHandler -= value;
 
-                if (focusChangedEventCallback == null && FocusChangedSignal().Empty() == false)
+                using FocusChangedSignal signal = FocusChangedSignal();
+                if (focusChangedEventCallback == null && signal?.Empty() == false)
                 {
-                    FocusChangedSignal().Disconnect(focusChangedEventCallback);
+                    signal?.Disconnect(focusChangedEventCallback);
                 }
             }
         }
@@ -143,7 +189,8 @@ namespace Tizen.NUI
                 if (focusGroupChangedEventCallback == null)
                 {
                     focusGroupChangedEventCallback = OnFocusGroupChanged;
-                    FocusGroupChangedSignal().Connect(focusGroupChangedEventCallback);
+                    using FocusGroupChangedSignal signal = FocusGroupChangedSignal();
+                    signal?.Connect(focusGroupChangedEventCallback);
                 }
                 focusGroupChangedEventHandler += value;
             }
@@ -151,9 +198,10 @@ namespace Tizen.NUI
             {
                 focusGroupChangedEventHandler -= value;
 
-                if (focusGroupChangedEventCallback == null && FocusGroupChangedSignal().Empty() == false)
+                using FocusGroupChangedSignal signal = FocusGroupChangedSignal();
+                if (focusGroupChangedEventCallback == null && signal?.Empty() == false)
                 {
-                    FocusGroupChangedSignal().Disconnect(focusGroupChangedEventCallback);
+                    signal?.Disconnect(focusGroupChangedEventCallback);
                 }
             }
         }
@@ -169,7 +217,8 @@ namespace Tizen.NUI
                 if (focusedViewEnterKeyEventCallback == null)
                 {
                     focusedViewEnterKeyEventCallback = OnFocusedViewEnterKey;
-                    FocusedViewEnterKeySignal().Connect(focusedViewEnterKeyEventCallback);
+                    using ViewSignal signal = FocusedViewEnterKeySignal();
+                    signal?.Connect(focusedViewEnterKeyEventCallback);
                 }
                 focusedViewEnterKeyEventHandler += value;
             }
@@ -177,9 +226,10 @@ namespace Tizen.NUI
             {
                 focusedViewEnterKeyEventHandler -= value;
 
-                if (focusedViewEnterKeyEventCallback != null && FocusedViewEnterKeySignal().Empty() == false)
+                using ViewSignal signal = FocusedViewEnterKeySignal();
+                if (focusedViewEnterKeyEventCallback != null && signal?.Empty() == false)
                 {
-                    FocusedViewEnterKeySignal().Disconnect(focusedViewEnterKeyEventCallback);
+                    signal?.Disconnect(focusedViewEnterKeyEventCallback);
                 }
             }
         }
@@ -202,7 +252,8 @@ namespace Tizen.NUI
                 if (focusedViewEnterKeyEventCallback2 == null)
                 {
                     focusedViewEnterKeyEventCallback2 = OnFocusedViewEnterKey2;
-                    FocusedViewEnterKeySignal().Connect(focusedViewEnterKeyEventCallback2);
+                    using ViewSignal signal = FocusedViewEnterKeySignal();
+                    signal?.Connect(focusedViewEnterKeyEventCallback2);
                 }
                 focusedViewEnterKeyEventHandler2 += value;
             }
@@ -210,9 +261,10 @@ namespace Tizen.NUI
             {
                 focusedViewEnterKeyEventHandler2 -= value;
 
-                if (focusedViewEnterKeyEventCallback2 != null && FocusedViewEnterKeySignal().Empty() == false)
+                using ViewSignal signal = FocusedViewEnterKeySignal();
+                if (focusedViewEnterKeyEventCallback2 != null && signal?.Empty() == false)
                 {
-                    FocusedViewEnterKeySignal().Disconnect(focusedViewEnterKeyEventCallback2);
+                    signal?.Disconnect(focusedViewEnterKeyEventCallback2);
                 }
             }
         }
@@ -620,14 +672,49 @@ namespace Tizen.NUI
             }
         }
 
+        private IntPtr OnFocusChanging(IntPtr current, IntPtr proposed, View.FocusDirection direction)
+        {
+            View originallyProposed = null;
+            FocusChangingEventArgs e = new FocusChangingEventArgs();
+
+            if (current != global::System.IntPtr.Zero)
+            {
+                e.Current = Registry.GetManagedBaseHandleFromNativePtr(current) as View;
+            }
+            if (proposed != global::System.IntPtr.Zero)
+            {
+                originallyProposed = e.Proposed = Registry.GetManagedBaseHandleFromNativePtr(proposed) as View;
+            }
+            e.Direction = direction;
+
+            focusChangingEventHandler?.Invoke(this, e);
+
+            if (originallyProposed != e.Proposed)
+            {
+                //when user has changed Proposed
+                return e.Proposed.GetPtrfromView();
+            }
+            else
+            {
+                if (originallyProposed != null)
+                {
+                    return proposed;
+                }
+                else
+                {
+                    return current;
+                }
+            }
+        }
+
         private void OnFocusChanged(IntPtr current, IntPtr next)
         {
             if (focusChangedEventHandler != null)
             {
                 FocusChangedEventArgs e = new FocusChangedEventArgs();
 
-                e.CurrentView = Registry.GetManagedBaseHandleFromNativePtr(current) as View;
-                e.NextView = Registry.GetManagedBaseHandleFromNativePtr(next) as View;
+                e.Previous = e.CurrentView = Registry.GetManagedBaseHandleFromNativePtr(current) as View;
+                e.Current = e.NextView = Registry.GetManagedBaseHandleFromNativePtr(next) as View;
                 focusChangedEventHandler(this, e);
             }
         }
@@ -675,6 +762,9 @@ namespace Tizen.NUI
         /// Event arguments that passed via the PreFocusChange signal.
         /// </summary>
         /// <since_tizen> 3 </since_tizen>
+        [Obsolete("Please do not use! This will be deprecated in API10. Please use FocusChangingEventArgs instead!")]
+        [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1034:Nested types should not be visible", Justification = "<Pending>")]
+        // this will be deprecated, so suppress warning would be OK.
         public class PreFocusChangeEventArgs : EventArgs
         {
             private View current;
@@ -736,37 +826,71 @@ namespace Tizen.NUI
         /// <since_tizen> 3 </since_tizen>
         public class FocusChangedEventArgs : EventArgs
         {
+            private View currentView;
+            private View nextView;
+            private View previous;
             private View current;
-            private View next;
 
             /// <summary>
             /// The current focus view.
             /// </summary>
             /// <since_tizen> 3 </since_tizen>
+            [Obsolete("Please do not use! This will be deprecated! Please use Previous instead!")]
             public View CurrentView
             {
                 get
                 {
-                    return current;
+                    return currentView;
                 }
                 set
                 {
-                    current = value;
+                    currentView = value;
                 }
             }
             /// <summary>
             /// The next focus view.
             /// </summary>
             /// <since_tizen> 3 </since_tizen>
+            [Obsolete("Please do not use! This will be deprecated! Please use Current instead!")]
             public View NextView
             {
                 get
                 {
-                    return next;
+                    return nextView;
                 }
                 set
                 {
-                    next = value;
+                    nextView = value;
+                }
+            }
+            /// <summary>
+            /// The previously focused view.
+            /// </summary>
+            /// <since_tizen> 10 </since_tizen>
+            public View Previous
+            {
+                get
+                {
+                    return previous;
+                }
+                set
+                {
+                    previous = value;
+                }
+            }
+            /// <summary>
+            /// The current focused view after focus changed.
+            /// </summary>
+            /// <since_tizen> 10 </since_tizen>
+            public View Current
+            {
+                get
+                {
+                    return current;
+                }
+                set
+                {
+                    current = value;
                 }
             }
         }
diff --git a/src/Tizen.NUI/src/public/Input/FocusManagerArgs.cs b/src/Tizen.NUI/src/public/Input/FocusManagerArgs.cs
new file mode 100755 (executable)
index 0000000..62b66b2
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * 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;
+
+namespace Tizen.NUI
+{
+    ///<summary>
+    /// Event arguments that passed via the FocusChanging signal.
+    /// </summary>
+    /// <since_tizen> 10 </since_tizen>
+    public class FocusChangingEventArgs : EventArgs
+    {
+        private View current;
+        private View proposed;
+        private View.FocusDirection direction;
+
+        /// <summary>
+        /// The current focus view.
+        /// </summary>
+        /// <since_tizen> 10 </since_tizen>
+        public View Current
+        {
+            get
+            {
+                return current;
+            }
+            set
+            {
+                current = value;
+            }
+        }
+
+        /// <summary>
+        /// The  proposed view.
+        /// </summary>
+        /// <since_tizen> 10 </since_tizen>
+        public View Proposed
+        {
+            get
+            {
+                return proposed;
+            }
+            set
+            {
+                proposed = value;
+            }
+        }
+
+        /// <summary>
+        /// The focus move direction.
+        /// </summary>
+        /// <since_tizen> 10 </since_tizen>
+        public View.FocusDirection Direction
+        {
+            get
+            {
+                return direction;
+            }
+            set
+            {
+                direction = value;
+            }
+        }
+    }
+}
diff --git a/test/Tizen.NUI.Samples/Tizen.NUI.Samples/Samples/FocusManagerEventTest.cs b/test/Tizen.NUI.Samples/Tizen.NUI.Samples/Samples/FocusManagerEventTest.cs
new file mode 100644 (file)
index 0000000..8d06c9a
--- /dev/null
@@ -0,0 +1,239 @@
+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 FocusManagerEventTest : IExample
+    {
+        private const int TestWidth = 100, TestHeight = 100;
+        private Window window;
+        private View rootView, left, center, right;
+        private View childUpper, childLower;
+        private Animation focusOut, focusIn;
+
+        public void Activate()
+        {
+            window = NUIApplication.GetDefaultWindow();
+
+            rootView = new View()
+            {
+                WidthSpecification = LayoutParamPolicies.MatchParent,
+                HeightSpecification = LayoutParamPolicies.MatchParent,
+
+                Layout = new LinearLayout()
+                {
+                    LinearOrientation = LinearLayout.Orientation.Horizontal,
+                    HorizontalAlignment = HorizontalAlignment.Center,
+                    VerticalAlignment = VerticalAlignment.Center,
+                    CellPadding = new Size2D(20, 20),
+                },
+                Name = "rootView",
+                BackgroundColor = Color.Gray,
+                Focusable = true,
+            };
+            window.Add(rootView);
+
+            left = new View()
+            {
+                Name = "left",
+                WidthSpecification = TestWidth,
+                HeightSpecification = TestHeight,
+                BackgroundColor = Color.Red,
+                Focusable = true,
+            };
+            rootView.Add(left);
+
+            center = new View()
+            {
+                Name = "center",
+                WidthSpecification = TestWidth,
+                HeightSpecification = TestHeight,
+                BackgroundColor = Color.Blue,
+                Focusable = true,
+            };
+            rootView.Add(center);
+
+            right = new View()
+            {
+                Name = "right",
+                WidthSpecification = TestWidth * 2,
+                HeightSpecification = TestHeight * 3,
+                BackgroundColor = Color.Green,
+                Focusable = true,
+                Layout = new LinearLayout()
+                {
+                    LinearOrientation = LinearLayout.Orientation.Vertical,
+                    HorizontalAlignment = HorizontalAlignment.Center,
+                    VerticalAlignment = VerticalAlignment.Center,
+                    CellPadding = new Size2D(10, 10),
+                },
+            };
+            rootView.Add(right);
+
+            childUpper = new View()
+            {
+                Name = "childUpper",
+                WidthSpecification = TestWidth,
+                HeightSpecification = TestHeight,
+                BackgroundColor = Color.Yellow,
+                Focusable = true,
+            };
+            right.Add(childUpper);
+
+            childLower = new View()
+            {
+                Name = "childLower",
+                WidthSpecification = TestWidth,
+                HeightSpecification = TestHeight,
+                BackgroundColor = Color.Pink,
+                Focusable = true,
+            };
+            right.Add(childLower);
+
+            FocusManager.Instance.FocusChanging += onFocusChanging;
+            FocusManager.Instance.FocusChanged += onFocusChanged;
+            FocusManager.Instance.SetCurrentFocusView(center);
+        }
+
+        public void Deactivate()
+        {
+            rootView.Unparent();
+            left.Unparent();
+            center.Unparent();
+            right.Unparent();
+            childUpper.Unparent();
+            childLower.Unparent();
+            rootView.Dispose();
+            left.Dispose();
+            center.Dispose();
+            right.Dispose();
+            childUpper.Dispose();
+            childLower.Dispose();
+        }
+
+        private void onFocusChanging(object sender, FocusChangingEventArgs e)
+        {
+            if (e.Current)
+            {
+                Tizen.Log.Debug("NUITEST", $"e.Current.Name={e.Current.Name}");
+            }
+
+            if (e.Proposed)
+            {
+                Tizen.Log.Debug("NUITEST", $"e.Proposed.Name={e.Proposed.Name}");
+            }
+
+            Tizen.Log.Debug("NUITEST", $"e.Direction.Name={e.Direction}");
+
+            if (e.Current == left)
+            {
+                if (e.Direction == View.FocusDirection.Right)
+                {
+                    e.Proposed = center;
+                }
+                else
+                {
+                    e.Proposed = rootView;
+                }
+            }
+            else if (e.Current == center)
+            {
+                if (e.Direction == View.FocusDirection.Right)
+                {
+                    e.Proposed = right;
+                }
+                else if (e.Direction == View.FocusDirection.Left)
+                {
+                    e.Proposed = left;
+                }
+                else
+                {
+                    e.Proposed = rootView;
+                }
+            }
+            else if (e.Current == right)
+            {
+                if (e.Direction == View.FocusDirection.Left)
+                {
+                    e.Proposed = center;
+                }
+                else if (e.Direction == View.FocusDirection.Forward || e.Direction == View.FocusDirection.Backward)
+                {
+                    //for FocusGroup
+                    e.Proposed = rootView;
+                }
+                else if (e.Direction == View.FocusDirection.Down)
+                {
+                    e.Proposed = childUpper;
+                }
+            }
+            else if (e.Current == rootView)
+            {
+                if (e.Direction == View.FocusDirection.Down || e.Direction == View.FocusDirection.Right)
+                {
+                    e.Proposed = left;
+                }
+                else if (e.Direction == View.FocusDirection.Forward || e.Direction == View.FocusDirection.Backward)
+                {
+                    //for FocusGroup
+                    e.Proposed = right;
+                }
+            }
+            else if (e.Current == childUpper)
+            {
+                if (e.Direction == View.FocusDirection.Down)
+                {
+                    e.Proposed = childLower;
+                }
+                else if (e.Direction == View.FocusDirection.Up)
+                {
+                    e.Proposed = right;
+                }
+            }
+            else if (e.Current == childLower)
+            {
+                if (e.Direction == View.FocusDirection.Down)
+                {
+                    e.Proposed = right;
+                }
+                else if (e.Direction == View.FocusDirection.Up)
+                {
+                    e.Proposed = childUpper;
+                }
+            }
+            else if (e.Current == null)
+            {
+                e.Proposed = center;
+            }
+        }
+
+        private void onFocusChanged(object sender, NUI.FocusManager.FocusChangedEventArgs e)
+        {
+            if (e.Previous)
+            {
+                Tizen.Log.Debug("NUITEST", $"e.Previous.Name={e.Previous.Name}");
+                if (e.Previous != rootView && e.Previous != right)
+                {
+                    focusOut = new Animation(500);
+                    focusOut.AnimateTo(e.Previous, "size", new Size(TestWidth * 0.7f, TestWidth * 0.7f, 0));
+                    focusOut.Play();
+                }
+            }
+
+            if (e.Current)
+            {
+                Tizen.Log.Debug("NUITEST", $"e.Current.Name={e.Current.Name}");
+                if (e.Current != rootView && e.Current != right)
+                {
+                    focusIn = new Animation(500);
+                    focusIn.AnimateTo(e.Current, "size", new Size(TestWidth, TestWidth, 0));
+                    focusIn.Play();
+                }
+            }
+        }
+
+    }
+}