[NUI] Binding EnableFocusIndicator and IsFocusIndicatorEnabled
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI / src / public / Input / FocusManager.cs
index 7706b56..d43f75b 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;
 
@@ -73,6 +76,7 @@ namespace Tizen.NUI
         private delegate void FocusedViewEnterKeyEventCallback2(IntPtr view);
 
         private View internalFocusIndicator = null;
+        private View nullFocusIndicator = null;
 
         /// <summary>
         /// PreFocusChange will be triggered before the focus is going to be changed.<br />
@@ -82,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 FocusChanging 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
@@ -89,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)
+                {
+                    signal?.Disconnect(preFocusChangeCallback);
+                }
+            }
+        }
+
+        /// <summary>
+        /// 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)
                 {
-                    PreFocusChangeSignal().Disconnect(preFocusChangeCallback);
+                    signal?.Disconnect(focusChangingCallback);
                 }
             }
         }
 
         /// <summary>
-        /// The FocusGroupChanged will be triggered after the current focused view has been changed.
+        /// The FocusChanged will be triggered after the current focused view has been changed.
         /// </summary>
         /// <since_tizen> 3 </since_tizen>
         public event EventHandler<FocusChangedEventArgs> FocusChanged
@@ -114,7 +159,8 @@ namespace Tizen.NUI
                 if (focusChangedEventCallback == null)
                 {
                     focusChangedEventCallback = OnFocusChanged;
-                    FocusChangedSignal().Connect(focusChangedEventCallback);
+                    using FocusChangedSignal signal = FocusChangedSignal();
+                    signal?.Connect(focusChangedEventCallback);
                 }
                 focusChangedEventHandler += value;
             }
@@ -122,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);
                 }
             }
         }
@@ -142,7 +189,8 @@ namespace Tizen.NUI
                 if (focusGroupChangedEventCallback == null)
                 {
                     focusGroupChangedEventCallback = OnFocusGroupChanged;
-                    FocusGroupChangedSignal().Connect(focusGroupChangedEventCallback);
+                    using FocusGroupChangedSignal signal = FocusGroupChangedSignal();
+                    signal?.Connect(focusGroupChangedEventCallback);
                 }
                 focusGroupChangedEventHandler += value;
             }
@@ -150,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);
                 }
             }
         }
@@ -168,28 +217,30 @@ namespace Tizen.NUI
                 if (focusedViewEnterKeyEventCallback == null)
                 {
                     focusedViewEnterKeyEventCallback = OnFocusedViewEnterKey;
-                    FocusedViewEnterKeySignal().Connect(focusedViewEnterKeyEventCallback);
+                    Interop.FocusManager.FocusedActorEnterKeySignalConnect(SwigCPtr, focusedViewEnterKeyEventCallback.ToHandleRef(this));
+                    NDalicPINVOKE.ThrowExceptionIfExists();
                 }
                 focusedViewEnterKeyEventHandler += value;
             }
             remove
             {
                 focusedViewEnterKeyEventHandler -= value;
-
-                if (focusedViewEnterKeyEventCallback != null && FocusedViewEnterKeySignal().Empty() == false)
+                if (focusedViewEnterKeyEventHandler == null && focusedViewEnterKeyEventCallback != null)
                 {
-                    FocusedViewEnterKeySignal().Disconnect(focusedViewEnterKeyEventCallback);
+                    Interop.FocusManager.FocusedActorEnterKeySignalDisconnect(SwigCPtr, focusedViewEnterKeyEventCallback.ToHandleRef(this));
+                    NDalicPINVOKE.ThrowExceptionIfExists();
+                    focusedViewEnterKeyEventCallback = null;
                 }
             }
         }
 
         /// <summary>
-        /// [Obsolete("Please do not use! this will be deprecated")]
+        /// [Obsolete("Do not use this, that will be deprecated.")]
         /// </summary>
         /// <since_tizen> 3 </since_tizen>
-        /// Please do not use! this will be deprecated!
-        /// Instead please use FocusedViewActivated.
-        [Obsolete("Please do not use! This will be deprecated! Please use FocusManager.FocusedViewActivated instead! " +
+        /// Do not use this, that will be deprecated.
+        /// Instead Use FocusedViewActivated.
+        [Obsolete("Do not use this, that will be deprecated. Use FocusManager.FocusedViewActivated instead. " +
             "Like: " +
             "FocusManager.Instance.FocusedViewActivated = OnFocusedViewActivated; " +
             "private void OnFocusedViewActivated(object source, FocusManager.FocusedViewActivatedEventArgs args) {...}")]
@@ -201,7 +252,8 @@ namespace Tizen.NUI
                 if (focusedViewEnterKeyEventCallback2 == null)
                 {
                     focusedViewEnterKeyEventCallback2 = OnFocusedViewEnterKey2;
-                    FocusedViewEnterKeySignal().Connect(focusedViewEnterKeyEventCallback2);
+                    Interop.FocusManager.FocusedActorEnterKeySignalConnect(SwigCPtr, focusedViewEnterKeyEventCallback2.ToHandleRef(this));
+                    NDalicPINVOKE.ThrowExceptionIfExists();
                 }
                 focusedViewEnterKeyEventHandler2 += value;
             }
@@ -209,9 +261,11 @@ namespace Tizen.NUI
             {
                 focusedViewEnterKeyEventHandler2 -= value;
 
-                if (focusedViewEnterKeyEventCallback2 != null && FocusedViewEnterKeySignal().Empty() == false)
+                if (focusedViewEnterKeyEventHandler2 == null && focusedViewEnterKeyEventCallback2 != null)
                 {
-                    FocusedViewEnterKeySignal().Disconnect(focusedViewEnterKeyEventCallback2);
+                    Interop.FocusManager.FocusedActorEnterKeySignalDisconnect(SwigCPtr, focusedViewEnterKeyEventCallback2.ToHandleRef(this));
+                    NDalicPINVOKE.ThrowExceptionIfExists();
+                    focusedViewEnterKeyEventCallback2 = null;
                 }
             }
         }
@@ -264,11 +318,23 @@ namespace Tizen.NUI
         {
             set
             {
-                SetFocusIndicatorView(value);
+                internalFocusIndicator = value;
+                if (internalFocusIndicator == null)
+                {
+                    if (nullFocusIndicator == null)
+                    {
+                        nullFocusIndicator = new View();
+                    }
+                    SetFocusIndicatorView(nullFocusIndicator);
+                }
+                else
+                {
+                    SetFocusIndicatorView(internalFocusIndicator);
+                }
             }
             get
             {
-                return GetFocusIndicatorView();
+                return internalFocusIndicator;
             }
         }
 
@@ -453,10 +519,98 @@ namespace Tizen.NUI
             return ret;
         }
 
+        /// <summary>
+        /// Sets the root view to start moving focus when DefaultAlgorithm is enabled.
+        /// This will only look for focusable Views within that View tree when looking for the next focus.
+        /// </summary>
+        /// <param name="rootView">The root view in which to find the next focusable view.</param>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void SetFocusFinderRootView(View rootView)
+        {
+            Interop.FocusManager.SetFocusFinderRootView(SwigCPtr, View.getCPtr(rootView));
+            if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+        }
+
+        /// <summary>
+        /// Reset the root view that starts moving focus when DefaultAlgorithm is enabled.
+        /// When reset, the window becomes root.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void ResetFocusFinderRootView()
+        {
+            Interop.FocusManager.ResetFocusFinderRootView(SwigCPtr);
+            if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+        }
+
+        /// <summary>
+        /// Decide using focus indicator or not
+        /// </summary>
+        /// <param name="enable">Whether using focus indicator or not</param>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void EnableFocusIndicator(bool enable)
+        {
+            Interop.FocusManager.EnableFocusIndicator(SwigCPtr, enable);
+            if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+        }
+
+        /// <summary>
+        /// Check focus indicator is enabled or not
+        /// </summary>
+        /// <returns>Whether focus indicator is enabled</returns>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public bool IsFocusIndicatorEnabled()
+        {
+            bool ret = Interop.FocusManager.IsFocusIndicatorEnabled(SwigCPtr);
+            if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+            return ret;
+        }
+
+        /// <summary>
+        /// Get a default focus indicator
+        /// </summary>
+        /// <remarks>
+        /// The type actually <see cref="Tizen.NUI.BaseComponents.ImageView"/> of blue border squred png image, so it would be difficult to modify itself.
+        /// To change focus indicator, creating new indicator and assigning it to FocusIndicator are recommended.
+        /// For example,
+        /// <code>
+        /// FocusManager.Instance.FocusIndicator = new View()
+        /// {
+        ///     PositionUsesPivotPoint = true,
+        ///     PivotPoint = new Position(0, 0, 0),
+        ///     WidthResizePolicy = ResizePolicyType.FillToParent,
+        ///     HeightResizePolicy = ResizePolicyType.FillToParent,
+        ///     BorderlineColor = Color.Orange,
+        ///     BorderlineWidth = 4.0f,
+        ///     BorderlineOffset = -1f,
+        ///     BackgroundColor = new Color(0.2f, 0.2f, 0.2f, 0.2f),
+        /// };
+        /// </code>
+        /// </remarks>
+        /// <returns>instance of default focus indicator</returns>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public View GetDefaultFocusIndicator()
+        {
+            ImageView ret = new ImageView(FrameworkInformation.ResourcePath + "keyboard_focus.9.png")
+            {
+                Name = "DefaultFocusIndicatorCreatedByNUI",
+                PositionUsesAnchorPoint = true,
+                ParentOrigin = ParentOrigin.Center,
+                PivotPoint = ParentOrigin.Center,
+                Position2D = new Position2D(0, 0),
+            };
+            ret.SetResizePolicy(ResizePolicyType.FillToParent, DimensionType.AllDimensions);
+            return ret;
+        }
+
         internal static FocusManager Get()
         {
             FocusManager ret = new FocusManager(Interop.FocusManager.Get(), true);
             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+
+#if !PROFILE_TV
+            //tv profile never use default focus indicator, so this is not needed!
+            ret.FocusIndicator = ret.GetDefaultFocusIndicator();
+#endif
             return ret;
         }
 
@@ -477,15 +631,13 @@ namespace Tizen.NUI
         {
             Interop.FocusManager.SetFocusIndicatorActor(SwigCPtr, View.getCPtr(indicator));
             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
-            internalFocusIndicator = indicator;
         }
 
         internal View GetFocusIndicatorView()
         {
             //to fix memory leak issue, match the handle count with native side.
             IntPtr cPtr = Interop.FocusManager.GetFocusIndicatorActor(SwigCPtr);
-            internalFocusIndicator = this.GetInstanceSafely<View>(cPtr);
-            return internalFocusIndicator;
+            return this.GetInstanceSafely<View>(cPtr);
         }
 
         internal PreFocusChangeSignal PreFocusChangeSignal()
@@ -509,13 +661,6 @@ namespace Tizen.NUI
             return ret;
         }
 
-        internal ViewSignal FocusedViewEnterKeySignal()
-        {
-            ViewSignal ret = new ViewSignal(Interop.FocusManager.FocusedActorEnterKeySignal(SwigCPtr), false);
-            if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
-            return ret;
-        }
-
         private IntPtr OnPreFocusChange(IntPtr current, IntPtr proposed, View.FocusDirection direction)
         {
             View view = null;
@@ -547,14 +692,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);
             }
         }
@@ -582,11 +762,11 @@ namespace Tizen.NUI
         }
 
         /// <summary>
-        /// Please do not use! this will be deprecated!
+        /// Do not use this, that will be deprecated.
         /// </summary>
-        /// Please do not use! this will be deprecated!
-        /// Instead please use OnFocusedViewEnterKey.
-        [Obsolete("Please do not use! This will be deprecated! Please use FocusManager.OnFocusedViewEnterKey instead!")]
+        /// Do not use this, that will be deprecated.
+        /// Instead Use OnFocusedViewEnterKey.
+        [Obsolete("Do not use this, that will be deprecated. Use FocusManager.OnFocusedViewEnterKey instead.")]
         [EditorBrowsable(EditorBrowsableState.Never)]
         private void OnFocusedViewEnterKey2(IntPtr view)
         {
@@ -602,6 +782,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;
@@ -663,37 +846,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;
                 }
             }
         }
@@ -766,12 +983,12 @@ namespace Tizen.NUI
         }
 
         /// <summary>
-        /// Please do not use! this will be deprecated
+        /// Do not use this, that will be deprecated.
         /// </summary>
         /// <since_tizen> 3 </since_tizen>
-        /// Please do not use! this will be deprecated.
-        /// Instead please use FocusedViewActivatedEventArgs.
-        [Obsolete("Please do not use! This will be deprecated! Please use FocusedViewActivatedEventArgs instead! " +
+        /// Do not use this, that will be deprecated.
+        /// Instead Use FocusedViewActivatedEventArgs.
+        [Obsolete("Do not use this, that will be deprecated. Use FocusedViewActivatedEventArgs instead. " +
             "Like: " +
             "FocusManager.Instance.FocusedViewActivated = OnFocusedViewActivated; " +
             "private void OnFocusedViewActivated(object source, FocusManager.FocusedViewActivatedEventArgs arg)" +