ed2a92f9566142d66e3708a8b822738743edc615
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI / src / public / Input / FocusManager.cs
1 /*
2  * Copyright(c) 2021 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 using System;
19 using System.Runtime.InteropServices;
20 using Tizen.NUI.BaseComponents;
21 using System.ComponentModel;
22
23 namespace Tizen.NUI
24 {
25     /// <summary>
26     /// Provides the functionality of handling keyboard navigation and maintaining the two-dimensional keyboard focus chain.<br />
27     /// It provides functionality of setting the focus and moving the focus in four directions( i.e., left, right, up, and down).<br />
28     /// It also draws a highlight for the focused view and sends an event when the focus is changed.<br />
29     /// </summary>
30     /// <since_tizen> 3 </since_tizen>
31     public class FocusManager : BaseHandle
32     {
33         private static readonly FocusManager instance = FocusManager.Get();
34         private CustomAlgorithmInterfaceWrapper customAlgorithmInterfaceWrapper;
35
36         private EventHandlerWithReturnType<object, PreFocusChangeEventArgs, View> preFocusChangeEventHandler;
37         private PreFocusChangeEventCallback preFocusChangeCallback;
38
39         private EventHandler<FocusChangingEventArgs> focusChangingEventHandler;
40         private PreFocusChangeEventCallback focusChangingCallback;
41
42         private EventHandler<FocusChangedEventArgs> focusChangedEventHandler;
43         private FocusChangedEventCallback focusChangedEventCallback;
44
45         private EventHandler<FocusGroupChangedEventArgs> focusGroupChangedEventHandler;
46         private FocusGroupChangedEventCallback focusGroupChangedEventCallback;
47
48         private EventHandler<FocusedViewActivatedEventArgs> focusedViewEnterKeyEventHandler;
49         private FocusedViewEnterKeyEventCallback focusedViewEnterKeyEventCallback;
50
51         private EventHandler<FocusedViewActivatedEventArgs> focusedViewEnterKeyEventHandler2;
52         private FocusedViewEnterKeyEventCallback2 focusedViewEnterKeyEventCallback2;
53
54         internal FocusManager(global::System.IntPtr cPtr, bool cMemoryOwn) : base(cPtr, cMemoryOwn)
55         {
56         }
57
58         internal FocusManager() : this(Interop.FocusManager.NewFocusManager(), true)
59         {
60             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
61         }
62
63         [UnmanagedFunctionPointer(CallingConvention.StdCall)]
64         internal delegate IntPtr PreFocusChangeEventCallback(IntPtr current, IntPtr proposed, View.FocusDirection direction);
65
66         [UnmanagedFunctionPointer(CallingConvention.StdCall)]
67         internal delegate void FocusChangedEventCallback(IntPtr current, IntPtr next);
68
69         [UnmanagedFunctionPointer(CallingConvention.StdCall)]
70         private delegate void FocusGroupChangedEventCallback(IntPtr current, bool forwardDirection);
71
72         [UnmanagedFunctionPointer(CallingConvention.StdCall)]
73         private delegate void FocusedViewEnterKeyEventCallback(IntPtr view);
74
75         [UnmanagedFunctionPointer(CallingConvention.StdCall)]
76         private delegate void FocusedViewEnterKeyEventCallback2(IntPtr view);
77
78         private View internalFocusIndicator = null;
79         private View nullFocusIndicator = null;
80
81         /// <summary>
82         /// PreFocusChange will be triggered before the focus is going to be changed.<br />
83         /// The FocusManager makes the best guess for which view to focus towards the given direction, but applications might want to change that.<br />
84         /// By connecting with this event, they can check the proposed view to focus and return a different view if they wish.<br />
85         /// This event is only triggered when the navigation key is pressed and KeyboardFocusManager tries to move the focus automatically.<br />
86         /// It won't be emitted for focus movement by calling the SetCurrentFocusView directly.<br />
87         /// </summary>
88         /// <since_tizen> 3 </since_tizen>
89         [Obsolete("Please do not use! This will be deprecated in API10. Please use FocusChanging instead!")]
90         // this will be deprecated, so suppress warning would be OK.
91         [System.Diagnostics.CodeAnalysis.SuppressMessage("Naming", "CA1710:Identifiers should have correct suffix", Justification = "<Pending>")]
92         public event EventHandlerWithReturnType<object, PreFocusChangeEventArgs, View> PreFocusChange
93         {
94             add
95             {
96                 if (preFocusChangeEventHandler == null)
97                 {
98                     preFocusChangeCallback = OnPreFocusChange;
99                     using PreFocusChangeSignal signal = PreFocusChangeSignal();
100                     signal?.Connect(preFocusChangeCallback);
101                 }
102                 preFocusChangeEventHandler += value;
103             }
104             remove
105             {
106                 preFocusChangeEventHandler -= value;
107                 using PreFocusChangeSignal signal = PreFocusChangeSignal();
108                 if (preFocusChangeEventHandler == null && signal?.Empty() == false)
109                 {
110                     signal?.Disconnect(preFocusChangeCallback);
111                 }
112             }
113         }
114
115         /// <summary>
116         /// FocusChanging will be triggered before the focus is going to be changed.<br />
117         /// The FocusManager makes the best guess for which view to focus towards the given direction, but applications might want to change that.<br />
118         /// By connecting with this event, they can check the proposed view to focus and assign a different view if they wish.<br />
119         /// This event is only triggered when the navigation key is pressed and FocusManager tries to move the focus automatically.<br />
120         /// It won't be emitted for focus movement by calling the SetCurrentFocusView directly.<br />
121         /// </summary>
122         /// <remarks>
123         /// By setting FocusChangingEventArgs.Proposed with the view to be focused, the focus will be moved to the assigned view.
124         /// </remarks>
125         /// <since_tizen> 10 </since_tizen>
126         public event EventHandler<FocusChangingEventArgs> FocusChanging
127         {
128             add
129             {
130                 if (focusChangingEventHandler == null)
131                 {
132                     focusChangingCallback = OnFocusChanging;
133                     //this is same as old PreFocusChangeSignal, so the body will be same. (only name is changed, behavior is same)
134                     using PreFocusChangeSignal signal = PreFocusChangeSignal();
135                     signal?.Connect(focusChangingCallback);
136                 }
137                 focusChangingEventHandler += value;
138             }
139             remove
140             {
141                 focusChangingEventHandler -= value;
142                 //this is same as old PreFocusChangeSignal, so the body will be same. (only name is changed, behavior is same)
143                 using PreFocusChangeSignal signal = PreFocusChangeSignal();
144                 if (focusChangingEventHandler == null && signal?.Empty() == false)
145                 {
146                     signal?.Disconnect(focusChangingCallback);
147                 }
148             }
149         }
150
151         /// <summary>
152         /// The FocusChanged will be triggered after the current focused view has been changed.
153         /// </summary>
154         /// <since_tizen> 3 </since_tizen>
155         public event EventHandler<FocusChangedEventArgs> FocusChanged
156         {
157             add
158             {
159                 if (focusChangedEventCallback == null)
160                 {
161                     focusChangedEventCallback = OnFocusChanged;
162                     using FocusChangedSignal signal = FocusChangedSignal();
163                     signal?.Connect(focusChangedEventCallback);
164                 }
165                 focusChangedEventHandler += value;
166             }
167             remove
168             {
169                 focusChangedEventHandler -= value;
170
171                 using FocusChangedSignal signal = FocusChangedSignal();
172                 if (focusChangedEventCallback == null && signal?.Empty() == false)
173                 {
174                     signal?.Disconnect(focusChangedEventCallback);
175                 }
176             }
177         }
178
179         /// <summary>
180         /// The FocusGroupChanged will be triggered when the focus group has been changed.<br />
181         /// If the current focus group has a parent layout control, the FocusManager will make the best guess for the next focus group to move the focus to in the given direction (forward or backward).<br />
182         /// If not, the application has to set the new focus.<br />
183         /// </summary>
184         /// <since_tizen> 3 </since_tizen>
185         public event EventHandler<FocusGroupChangedEventArgs> FocusGroupChanged
186         {
187             add
188             {
189                 if (focusGroupChangedEventCallback == null)
190                 {
191                     focusGroupChangedEventCallback = OnFocusGroupChanged;
192                     using FocusGroupChangedSignal signal = FocusGroupChangedSignal();
193                     signal?.Connect(focusGroupChangedEventCallback);
194                 }
195                 focusGroupChangedEventHandler += value;
196             }
197             remove
198             {
199                 focusGroupChangedEventHandler -= value;
200
201                 using FocusGroupChangedSignal signal = FocusGroupChangedSignal();
202                 if (focusGroupChangedEventCallback == null && signal?.Empty() == false)
203                 {
204                     signal?.Disconnect(focusGroupChangedEventCallback);
205                 }
206             }
207         }
208
209         /// <summary>
210         /// The FocusedViewActivated will be triggered when the current focused view has the enter key pressed on it.
211         /// </summary>
212         /// <since_tizen> 3 </since_tizen>
213         public event EventHandler<FocusedViewActivatedEventArgs> FocusedViewActivated
214         {
215             add
216             {
217                 if (focusedViewEnterKeyEventCallback == null)
218                 {
219                     focusedViewEnterKeyEventCallback = OnFocusedViewEnterKey;
220                     Interop.FocusManager.FocusedActorEnterKeySignalConnect(SwigCPtr, focusedViewEnterKeyEventCallback.ToHandleRef(this));
221                     NDalicPINVOKE.ThrowExceptionIfExists();
222                 }
223                 focusedViewEnterKeyEventHandler += value;
224             }
225             remove
226             {
227                 focusedViewEnterKeyEventHandler -= value;
228                 if (focusedViewEnterKeyEventHandler == null && focusedViewEnterKeyEventCallback != null)
229                 {
230                     Interop.FocusManager.FocusedActorEnterKeySignalDisconnect(SwigCPtr, focusedViewEnterKeyEventCallback.ToHandleRef(this));
231                     NDalicPINVOKE.ThrowExceptionIfExists();
232                     focusedViewEnterKeyEventCallback = null;
233                 }
234             }
235         }
236
237         /// <summary>
238         /// [Obsolete("Do not use this, that will be deprecated.")]
239         /// </summary>
240         /// <since_tizen> 3 </since_tizen>
241         /// Do not use this, that will be deprecated.
242         /// Instead Use FocusedViewActivated.
243         [Obsolete("Do not use this, that will be deprecated. Use FocusManager.FocusedViewActivated instead. " +
244             "Like: " +
245             "FocusManager.Instance.FocusedViewActivated = OnFocusedViewActivated; " +
246             "private void OnFocusedViewActivated(object source, FocusManager.FocusedViewActivatedEventArgs args) {...}")]
247         [EditorBrowsable(EditorBrowsableState.Never)]
248         public event EventHandler<FocusedViewActivatedEventArgs> FocusedViewEnterKeyPressed
249         {
250             add
251             {
252                 if (focusedViewEnterKeyEventCallback2 == null)
253                 {
254                     focusedViewEnterKeyEventCallback2 = OnFocusedViewEnterKey2;
255                     Interop.FocusManager.FocusedActorEnterKeySignalConnect(SwigCPtr, focusedViewEnterKeyEventCallback2.ToHandleRef(this));
256                     NDalicPINVOKE.ThrowExceptionIfExists();
257                 }
258                 focusedViewEnterKeyEventHandler2 += value;
259             }
260             remove
261             {
262                 focusedViewEnterKeyEventHandler2 -= value;
263
264                 if (focusedViewEnterKeyEventHandler2 == null && focusedViewEnterKeyEventCallback2 != null)
265                 {
266                     Interop.FocusManager.FocusedActorEnterKeySignalDisconnect(SwigCPtr, focusedViewEnterKeyEventCallback2.ToHandleRef(this));
267                     NDalicPINVOKE.ThrowExceptionIfExists();
268                     focusedViewEnterKeyEventCallback2 = null;
269                 }
270             }
271         }
272
273         /// <summary>
274         /// ICustomFocusAlgorithm is used to provide the custom keyboard focus algorithm for retrieving the next focusable view.<br />
275         /// The application can implement the interface and override the keyboard focus behavior.<br />
276         /// If the focus is changing within a layout container, then the layout container is queried first to provide the next focusable view.<br />
277         /// If this does not provide a valid view, then the Keyboard FocusManager will check focusable properties to determine the next focusable actor.<br />
278         /// If focusable properties are not set, then the keyboard FocusManager calls the GetNextFocusableView() method of this interface.<br />
279         /// </summary>
280         /// <since_tizen> 3 </since_tizen>
281         public interface ICustomFocusAlgorithm
282         {
283             /// <summary>
284             /// Get the next focus actor.
285             /// </summary>
286             /// <param name="current">The current focus view.</param>
287             /// <param name="proposed">The proposed focus view</param>
288             /// <param name="direction">The focus move direction</param>
289             /// <returns>The next focus actor.</returns>
290             /// <since_tizen> 3 </since_tizen>
291             View GetNextFocusableView(View current, View proposed, View.FocusDirection direction);
292         }
293
294
295         /// <summary>
296         /// Gets or sets the status of whether the focus movement should be looped within the same focus group.<br />
297         /// The focus movement is not looped by default.<br />
298         /// </summary>
299         /// <since_tizen> 3 </since_tizen>
300         public bool FocusGroupLoop
301         {
302             set
303             {
304                 SetFocusGroupLoop(value);
305             }
306             get
307             {
308                 return GetFocusGroupLoop();
309             }
310         }
311
312         /// <summary>
313         /// Gets or sets the focus indicator view.<br />
314         /// This will replace the default focus indicator view in the FocusManager and will be added to the focused view as a highlight.<br />
315         /// </summary>
316         /// <since_tizen> 3 </since_tizen>
317         public View FocusIndicator
318         {
319             set
320             {
321                 internalFocusIndicator = value;
322                 if (internalFocusIndicator == null)
323                 {
324                     if (nullFocusIndicator == null)
325                     {
326                         nullFocusIndicator = new View();
327                     }
328                     SetFocusIndicatorView(nullFocusIndicator);
329                 }
330                 else
331                 {
332                     SetFocusIndicatorView(internalFocusIndicator);
333                 }
334             }
335             get
336             {
337                 return internalFocusIndicator;
338             }
339         }
340
341         /// <summary>
342         /// Gets the singleton of the FocusManager object.
343         /// </summary>
344         /// <since_tizen> 3 </since_tizen>
345         public static FocusManager Instance
346         {
347             get
348             {
349                 return instance;
350             }
351         }
352
353         /// <summary>
354         /// Moves the keyboard focus to the given view.<br />
355         /// Only one view can be focused at the same time.<br />
356         /// The view must be in the stage already and keyboard focusable.<br />
357         /// </summary>
358         /// <param name="view">The view to be focused.</param>
359         /// <returns>Whether the focus is successful or not.</returns>
360         /// <since_tizen> 3 </since_tizen>
361         public bool SetCurrentFocusView(View view)
362         {
363             if (view == null)
364             {
365                 throw new ArgumentNullException(nameof(view), "the target view should not be null");
366             }
367
368             bool ret = Interop.FocusManager.SetCurrentFocusActor(SwigCPtr, View.getCPtr(view));
369             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
370             return ret;
371         }
372
373         /// <summary>
374         /// Gets the current focused view.
375         /// </summary>
376         /// <returns>A handle to the current focused view or an empty handle if no view is focused.</returns>
377         /// <since_tizen> 3 </since_tizen>
378         public View GetCurrentFocusView()
379         {
380             //to fix memory leak issue, match the handle count with native side.
381             IntPtr cPtr = Interop.FocusManager.GetCurrentFocusActor(SwigCPtr);
382             View ret = this.GetInstanceSafely<View>(cPtr);
383             return ret;
384         }
385
386         /// <summary>
387         /// Moves the focus to the next focusable view in the focus chain in the given direction (according to the focus traversal order).
388         /// </summary>
389         /// <param name="direction">The direction of the focus movement.</param>
390         /// <returns>True if the movement was successful.</returns>
391         /// <since_tizen> 3 </since_tizen>
392         public bool MoveFocus(View.FocusDirection direction)
393         {
394             bool ret = Interop.FocusManager.MoveFocus(SwigCPtr, (int)direction);
395             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
396             return ret;
397         }
398
399         /// <summary>
400         /// Clears the focus from the current focused view if any, so that no view is focused in the focus chain.<br />
401         /// It will emit the FocusChanged event without the current focused view.<br />
402         /// </summary>
403         /// <since_tizen> 3 </since_tizen>
404         public void ClearFocus()
405         {
406             Interop.FocusManager.ClearFocus(SwigCPtr);
407             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
408         }
409
410         /// <summary>
411         /// Move the focus to previous focused view.
412         /// </summary>
413         /// <since_tizen> 3 </since_tizen>
414         public void MoveFocusBackward()
415         {
416             Interop.FocusManager.MoveFocusBackward(SwigCPtr);
417             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
418         }
419
420         /// <summary>
421         /// Sets whether the view is a focus group that can limit the scope of the focus movement to its child views in the focus chain.<br />
422         /// Layout controls set themselves as focus groups by default.<br />
423         /// </summary>
424         /// <param name="view">The view to be set as a focus group.</param>
425         /// <param name="isFocusGroup">Whether to set the view as a focus group or not.</param>
426         /// <since_tizen> 3 </since_tizen>
427         public void SetAsFocusGroup(View view, bool isFocusGroup)
428         {
429             Interop.FocusManager.SetAsFocusGroup(SwigCPtr, View.getCPtr(view), isFocusGroup);
430             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
431         }
432
433         /// <summary>
434         /// Checks whether the view is set as a focus group or not.
435         /// </summary>
436         /// <param name="view">The view to be checked.</param>
437         /// <returns>Whether the view is set as a focus group.</returns>
438         /// <since_tizen> 3 </since_tizen>
439         public bool IsFocusGroup(View view)
440         {
441             bool ret = Interop.FocusManager.IsFocusGroup(SwigCPtr, View.getCPtr(view));
442             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
443             return ret;
444         }
445
446         /// <summary>
447         /// Returns the closest ancestor of the given view that is a focus group.
448         /// </summary>
449         /// <param name="view">The view to be checked for its focus group.</param>
450         /// <returns>The focus group the given view belongs to or an empty handle if the given view.</returns>
451         /// <since_tizen> 3 </since_tizen>
452         public View GetFocusGroup(View view)
453         {
454             //to fix memory leak issue, match the handle count with native side.
455             IntPtr cPtr = Interop.FocusManager.GetFocusGroup(SwigCPtr, View.getCPtr(view));
456             View ret = this.GetInstanceSafely<View>(cPtr);
457             return ret;
458         }
459
460         /// <summary>
461         /// Provides the implementation of a custom focus algorithm interface to allow the application to define the focus logic.<br />
462         /// </summary>
463         /// <param name="arg0">The user's implementation of ICustomFocusAlgorithm.</param>
464         /// <since_tizen> 3 </since_tizen>
465         public void SetCustomAlgorithm(ICustomFocusAlgorithm arg0)
466         {
467             if (arg0 != null)
468             {
469                 customAlgorithmInterfaceWrapper = new CustomAlgorithmInterfaceWrapper();
470                 customAlgorithmInterfaceWrapper.SetFocusAlgorithm(arg0);
471
472                 Interop.NDalic.SetCustomAlgorithm(SwigCPtr, CustomAlgorithmInterface.getCPtr(customAlgorithmInterfaceWrapper));
473                 if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
474             }
475             else
476             {
477                 Interop.NDalic.SetCustomAlgorithm(SwigCPtr, new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero));
478                 if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
479             }
480         }
481
482         /// <summary>
483         /// Sets to use the automatic focus moveing algorithm. <br />
484         /// It moves the focus to the view closest to the keyboard movement direction.
485         /// </summary>
486         /// <param name="enable">Whether using default focus algorithm or not</param>
487         [EditorBrowsable(EditorBrowsableState.Never)]
488         public void EnableDefaultAlgorithm(bool enable)
489         {
490             Interop.FocusManager.EnableDefaultAlgorithm(SwigCPtr, enable);
491             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
492         }
493
494         /// <summary>
495         ///  Checks default focus moveing algorithm is enabled or not
496         /// </summary>
497         /// <returns>Whether default focus algorithm is enabled</returns>
498         [EditorBrowsable(EditorBrowsableState.Never)]
499         public bool IsDefaultAlgorithmEnabled()
500         {
501             bool ret = Interop.FocusManager.IsDefaultAlgorithmEnabled(SwigCPtr);
502             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
503             return ret;
504         }
505
506         /// <summary>
507         /// Get the nearest focusable view.
508         /// </summary>
509         /// <param name="rootView">The view group in which to find the next focusable view.</param>
510         /// <param name="focusedView">The current focused view.</param>
511         /// <param name="direction">The direction.</param>
512         /// <returns>The nearest focusable view, or an empty handle if none exists.</returns>
513         [EditorBrowsable(EditorBrowsableState.Never)]
514         public View GetNearestFocusableActor(View rootView, View focusedView, View.FocusDirection direction)
515         {
516             //to fix memory leak issue, match the handle count with native side.
517             IntPtr cPtr = Interop.FocusManager.GetNearestFocusableActor(View.getCPtr(rootView), View.getCPtr(focusedView), (int)direction);
518             View ret = this.GetInstanceSafely<View>(cPtr);
519             return ret;
520         }
521
522         /// <summary>
523         /// Sets the root view to start moving focus when DefaultAlgorithm is enabled.
524         /// This will only look for focusable Views within that View tree when looking for the next focus.
525         /// </summary>
526         /// <param name="rootView">The root view in which to find the next focusable view.</param>
527         [EditorBrowsable(EditorBrowsableState.Never)]
528         public void SetFocusFinderRootView(View rootView)
529         {
530             Interop.FocusManager.SetFocusFinderRootView(SwigCPtr, View.getCPtr(rootView));
531             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
532         }
533
534         /// <summary>
535         /// Reset the root view that starts moving focus when DefaultAlgorithm is enabled.
536         /// When reset, the window becomes root.
537         /// </summary>
538         [EditorBrowsable(EditorBrowsableState.Never)]
539         public void ResetFocusFinderRootView()
540         {
541             Interop.FocusManager.ResetFocusFinderRootView(SwigCPtr);
542             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
543         }
544
545         /// <summary>
546         /// Get a default focus indicator
547         /// </summary>
548         /// <remarks>
549         /// The type actually <see cref="Tizen.NUI.BaseComponents.ImageView"/> of blue border squred png image, so it would be difficult to modify itself.
550         /// To change focus indicator, creating new indicator and assigning it to FocusIndicator are recommended.
551         /// For example,
552         /// <code>
553         /// FocusManager.Instance.FocusIndicator = new View()
554         /// {
555         ///     PositionUsesPivotPoint = true,
556         ///     PivotPoint = new Position(0, 0, 0),
557         ///     WidthResizePolicy = ResizePolicyType.FillToParent,
558         ///     HeightResizePolicy = ResizePolicyType.FillToParent,
559         ///     BorderlineColor = Color.Orange,
560         ///     BorderlineWidth = 4.0f,
561         ///     BorderlineOffset = -1f,
562         ///     BackgroundColor = new Color(0.2f, 0.2f, 0.2f, 0.2f),
563         /// };
564         /// </code>
565         /// </remarks>
566         /// <returns>instance of default focus indicator</returns>
567         [EditorBrowsable(EditorBrowsableState.Never)]
568         public View GetDefaultFocusIndicator()
569         {
570             ImageView ret = new ImageView(FrameworkInformation.ResourcePath + "keyboard_focus.9.png")
571             {
572                 Name = "DefaultFocusIndicatorCreatedByNUI",
573                 PositionUsesAnchorPoint = true,
574                 ParentOrigin = ParentOrigin.Center,
575                 PivotPoint = ParentOrigin.Center,
576                 Position2D = new Position2D(0, 0),
577             };
578             ret.SetResizePolicy(ResizePolicyType.FillToParent, DimensionType.AllDimensions);
579             return ret;
580         }
581
582         internal static FocusManager Get()
583         {
584             FocusManager ret = new FocusManager(Interop.FocusManager.Get(), true);
585             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
586
587 #if !PROFILE_TV
588             //tv profile never use default focus indicator, so this is not needed!
589             ret.FocusIndicator = ret.GetDefaultFocusIndicator();
590 #endif
591             return ret;
592         }
593
594         internal void SetFocusGroupLoop(bool enabled)
595         {
596             Interop.FocusManager.SetFocusGroupLoop(SwigCPtr, enabled);
597             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
598         }
599
600         internal bool GetFocusGroupLoop()
601         {
602             bool ret = Interop.FocusManager.GetFocusGroupLoop(SwigCPtr);
603             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
604             return ret;
605         }
606
607         internal void SetFocusIndicatorView(View indicator)
608         {
609             Interop.FocusManager.SetFocusIndicatorActor(SwigCPtr, View.getCPtr(indicator));
610             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
611         }
612
613         internal View GetFocusIndicatorView()
614         {
615             //to fix memory leak issue, match the handle count with native side.
616             IntPtr cPtr = Interop.FocusManager.GetFocusIndicatorActor(SwigCPtr);
617             return this.GetInstanceSafely<View>(cPtr);
618         }
619
620         internal PreFocusChangeSignal PreFocusChangeSignal()
621         {
622             PreFocusChangeSignal ret = new PreFocusChangeSignal(Interop.FocusManager.PreFocusChangeSignal(SwigCPtr), false);
623             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
624             return ret;
625         }
626
627         internal FocusChangedSignal FocusChangedSignal()
628         {
629             FocusChangedSignal ret = new FocusChangedSignal(Interop.FocusManager.FocusChangedSignal(SwigCPtr), false);
630             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
631             return ret;
632         }
633
634         internal FocusGroupChangedSignal FocusGroupChangedSignal()
635         {
636             FocusGroupChangedSignal ret = new FocusGroupChangedSignal(Interop.FocusManager.FocusGroupChangedSignal(SwigCPtr), false);
637             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
638             return ret;
639         }
640
641         private IntPtr OnPreFocusChange(IntPtr current, IntPtr proposed, View.FocusDirection direction)
642         {
643             View view = null;
644             PreFocusChangeEventArgs e = new PreFocusChangeEventArgs();
645
646             if (current != global::System.IntPtr.Zero)
647             {
648                 e.CurrentView = Registry.GetManagedBaseHandleFromNativePtr(current) as View;
649             }
650             if (proposed != global::System.IntPtr.Zero)
651             {
652                 e.ProposedView = Registry.GetManagedBaseHandleFromNativePtr(proposed) as View;
653             }
654             e.Direction = direction;
655
656             if (preFocusChangeEventHandler != null)
657             {
658                 view = preFocusChangeEventHandler(this, e);
659             }
660
661             if (view != null)
662             {
663                 return view.GetPtrfromView();
664             }
665             else
666             {
667                 if (e.ProposedView != null) return proposed;
668                 else return current;
669             }
670         }
671
672         private IntPtr OnFocusChanging(IntPtr current, IntPtr proposed, View.FocusDirection direction)
673         {
674             View originallyProposed = null;
675             FocusChangingEventArgs e = new FocusChangingEventArgs();
676
677             if (current != global::System.IntPtr.Zero)
678             {
679                 e.Current = Registry.GetManagedBaseHandleFromNativePtr(current) as View;
680             }
681             if (proposed != global::System.IntPtr.Zero)
682             {
683                 originallyProposed = e.Proposed = Registry.GetManagedBaseHandleFromNativePtr(proposed) as View;
684             }
685             e.Direction = direction;
686
687             focusChangingEventHandler?.Invoke(this, e);
688
689             if (originallyProposed != e.Proposed)
690             {
691                 //when user has changed Proposed
692                 return e.Proposed.GetPtrfromView();
693             }
694             else
695             {
696                 if (originallyProposed != null)
697                 {
698                     return proposed;
699                 }
700                 else
701                 {
702                     return current;
703                 }
704             }
705         }
706
707         private void OnFocusChanged(IntPtr current, IntPtr next)
708         {
709             if (focusChangedEventHandler != null)
710             {
711                 FocusChangedEventArgs e = new FocusChangedEventArgs();
712
713                 e.Previous = e.CurrentView = Registry.GetManagedBaseHandleFromNativePtr(current) as View;
714                 e.Current = e.NextView = Registry.GetManagedBaseHandleFromNativePtr(next) as View;
715                 focusChangedEventHandler(this, e);
716             }
717         }
718
719         private void OnFocusGroupChanged(IntPtr current, bool forwardDirection)
720         {
721             if (focusGroupChangedEventHandler != null)
722             {
723                 FocusGroupChangedEventArgs e = new FocusGroupChangedEventArgs();
724
725                 e.CurrentView = Registry.GetManagedBaseHandleFromNativePtr(current) as View;
726                 e.ForwardDirection = forwardDirection;
727                 focusGroupChangedEventHandler(this, e);
728             }
729         }
730
731         private void OnFocusedViewEnterKey(IntPtr view)
732         {
733             if (focusedViewEnterKeyEventHandler != null)
734             {
735                 FocusedViewActivatedEventArgs e = new FocusedViewActivatedEventArgs();
736                 e.View = Registry.GetManagedBaseHandleFromNativePtr(view) as View;
737                 focusedViewEnterKeyEventHandler(this, e);
738             }
739         }
740
741         /// <summary>
742         /// Do not use this, that will be deprecated.
743         /// </summary>
744         /// Do not use this, that will be deprecated.
745         /// Instead Use OnFocusedViewEnterKey.
746         [Obsolete("Do not use this, that will be deprecated. Use FocusManager.OnFocusedViewEnterKey instead.")]
747         [EditorBrowsable(EditorBrowsableState.Never)]
748         private void OnFocusedViewEnterKey2(IntPtr view)
749         {
750             if (focusedViewEnterKeyEventHandler != null)
751             {
752                 FocusedViewActivatedEventArgs e = new FocusedViewActivatedEventArgs();
753                 e.View = Registry.GetManagedBaseHandleFromNativePtr(view) as View;
754                 focusedViewEnterKeyEventHandler(this, e);
755             }
756         }
757
758         ///<summary>
759         /// Event arguments that passed via the PreFocusChange signal.
760         /// </summary>
761         /// <since_tizen> 3 </since_tizen>
762         [Obsolete("Please do not use! This will be deprecated in API10. Please use FocusChangingEventArgs instead!")]
763         [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1034:Nested types should not be visible", Justification = "<Pending>")]
764         // this will be deprecated, so suppress warning would be OK.
765         public class PreFocusChangeEventArgs : EventArgs
766         {
767             private View current;
768             private View proposed;
769             private View.FocusDirection direction;
770
771             /// <summary>
772             /// The current focus view.
773             /// </summary>
774             /// <since_tizen> 3 </since_tizen>
775             public View CurrentView
776             {
777                 get
778                 {
779                     return current;
780                 }
781                 set
782                 {
783                     current = value;
784                 }
785             }
786
787             /// <summary>
788             /// The  proposed view.
789             /// </summary>
790             /// <since_tizen> 3 </since_tizen>
791             public View ProposedView
792             {
793                 get
794                 {
795                     return proposed;
796                 }
797                 set
798                 {
799                     proposed = value;
800                 }
801             }
802
803             /// <summary>
804             /// The focus move direction.
805             /// </summary>
806             /// <since_tizen> 3 </since_tizen>
807             public View.FocusDirection Direction
808             {
809                 get
810                 {
811                     return direction;
812                 }
813                 set
814                 {
815                     direction = value;
816                 }
817             }
818         }
819
820         ///<summary>
821         /// Event arguments that passed via the FocusChanged signal.
822         /// </summary>
823         /// <since_tizen> 3 </since_tizen>
824         public class FocusChangedEventArgs : EventArgs
825         {
826             private View currentView;
827             private View nextView;
828             private View previous;
829             private View current;
830
831             /// <summary>
832             /// The current focus view.
833             /// </summary>
834             /// <since_tizen> 3 </since_tizen>
835             [Obsolete("Please do not use! This will be deprecated! Please use Previous instead!")]
836             public View CurrentView
837             {
838                 get
839                 {
840                     return currentView;
841                 }
842                 set
843                 {
844                     currentView = value;
845                 }
846             }
847             /// <summary>
848             /// The next focus view.
849             /// </summary>
850             /// <since_tizen> 3 </since_tizen>
851             [Obsolete("Please do not use! This will be deprecated! Please use Current instead!")]
852             public View NextView
853             {
854                 get
855                 {
856                     return nextView;
857                 }
858                 set
859                 {
860                     nextView = value;
861                 }
862             }
863             /// <summary>
864             /// The previously focused view.
865             /// </summary>
866             /// <since_tizen> 10 </since_tizen>
867             public View Previous
868             {
869                 get
870                 {
871                     return previous;
872                 }
873                 set
874                 {
875                     previous = value;
876                 }
877             }
878             /// <summary>
879             /// The current focused view after focus changed.
880             /// </summary>
881             /// <since_tizen> 10 </since_tizen>
882             public View Current
883             {
884                 get
885                 {
886                     return current;
887                 }
888                 set
889                 {
890                     current = value;
891                 }
892             }
893         }
894
895         ///<summary>
896         /// Event arguments that passed via the FocusGroupChanged signal.
897         /// </summary>
898         /// <since_tizen> 3 </since_tizen>
899         public class FocusGroupChangedEventArgs : EventArgs
900         {
901             private View current;
902             private bool forwardDirection;
903
904             /// <summary>
905             /// The current focus view.
906             /// </summary>
907             /// <since_tizen> 3 </since_tizen>
908             public View CurrentView
909             {
910                 get
911                 {
912                     return current;
913                 }
914                 set
915                 {
916                     current = value;
917                 }
918             }
919
920             /// <summary>
921             /// The forward direction.
922             /// </summary>
923             /// <since_tizen> 3 </since_tizen>
924             public bool ForwardDirection
925             {
926                 get
927                 {
928                     return forwardDirection;
929                 }
930                 set
931                 {
932                     forwardDirection = value;
933                 }
934             }
935         }
936
937         ///<summary>
938         /// Event arguments that passed via the FocusedViewEnterKey signal.
939         /// </summary>
940         /// <since_tizen> 3 </since_tizen>
941         public class FocusedViewActivatedEventArgs : EventArgs
942         {
943             private View view;
944
945             /// <summary>
946             /// View.
947             /// </summary>
948             /// <since_tizen> 3 </since_tizen>
949             public View View
950             {
951                 get
952                 {
953                     return view;
954                 }
955                 set
956                 {
957                     view = value;
958                 }
959             }
960         }
961
962         /// <summary>
963         /// Do not use this, that will be deprecated.
964         /// </summary>
965         /// <since_tizen> 3 </since_tizen>
966         /// Do not use this, that will be deprecated.
967         /// Instead Use FocusedViewActivatedEventArgs.
968         [Obsolete("Do not use this, that will be deprecated. Use FocusedViewActivatedEventArgs instead. " +
969             "Like: " +
970             "FocusManager.Instance.FocusedViewActivated = OnFocusedViewActivated; " +
971             "private void OnFocusedViewActivated(object source, FocusManager.FocusedViewActivatedEventArgs arg)" +
972             "{...}")]
973         [EditorBrowsable(EditorBrowsableState.Never)]
974         [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1034:NestedTypesShouldNotBeVisible")]
975         public class FocusedViewEnterKeyEventArgs : EventArgs
976         {
977             private View view;
978
979             /// <summary>
980             /// View.
981             /// </summary>
982             /// <since_tizen> 3 </since_tizen>
983             public View View
984             {
985                 get
986                 {
987                     return view;
988                 }
989                 set
990                 {
991                     view = value;
992                 }
993             }
994         }
995
996         private class CustomAlgorithmInterfaceWrapper : CustomAlgorithmInterface
997         {
998             private FocusManager.ICustomFocusAlgorithm customFocusAlgorithm;
999
1000             public CustomAlgorithmInterfaceWrapper()
1001             {
1002             }
1003
1004             public void SetFocusAlgorithm(FocusManager.ICustomFocusAlgorithm customFocusAlgorithm)
1005             {
1006                 this.customFocusAlgorithm = customFocusAlgorithm;
1007             }
1008
1009             public override View GetNextFocusableView(View current, View proposed, View.FocusDirection direction, string deviceName)
1010             {
1011                 if (customFocusAlgorithm == null)
1012                 {
1013                     Tizen.Log.Error("NUI", $"[ERROR] User defined ICustomFocusAlgorithm interface class becomes unreachable. Null will be proposed for next focusing!");
1014                     return null;
1015                 }
1016                 if (customFocusAlgorithm is ICustomAwareDeviceFocusAlgorithm deviceAwared)
1017                 {
1018                     return deviceAwared.GetNextFocusableView(current, proposed, direction, deviceName);
1019                 }
1020                 else
1021                 {
1022                     return customFocusAlgorithm.GetNextFocusableView(current, proposed, direction);
1023                 }
1024             }
1025         }
1026     }
1027 }