[NUI] Binding EnableFocusIndicator and IsFocusIndicatorEnabled
[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         /// Decide using focus indicator or not
547         /// </summary>
548         /// <param name="enable">Whether using focus indicator or not</param>
549         [EditorBrowsable(EditorBrowsableState.Never)]
550         public void EnableFocusIndicator(bool enable)
551         {
552             Interop.FocusManager.EnableFocusIndicator(SwigCPtr, enable);
553             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
554         }
555
556         /// <summary>
557         /// Check focus indicator is enabled or not
558         /// </summary>
559         /// <returns>Whether focus indicator is enabled</returns>
560         [EditorBrowsable(EditorBrowsableState.Never)]
561         public bool IsFocusIndicatorEnabled()
562         {
563             bool ret = Interop.FocusManager.IsFocusIndicatorEnabled(SwigCPtr);
564             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
565             return ret;
566         }
567
568         /// <summary>
569         /// Get a default focus indicator
570         /// </summary>
571         /// <remarks>
572         /// The type actually <see cref="Tizen.NUI.BaseComponents.ImageView"/> of blue border squred png image, so it would be difficult to modify itself.
573         /// To change focus indicator, creating new indicator and assigning it to FocusIndicator are recommended.
574         /// For example,
575         /// <code>
576         /// FocusManager.Instance.FocusIndicator = new View()
577         /// {
578         ///     PositionUsesPivotPoint = true,
579         ///     PivotPoint = new Position(0, 0, 0),
580         ///     WidthResizePolicy = ResizePolicyType.FillToParent,
581         ///     HeightResizePolicy = ResizePolicyType.FillToParent,
582         ///     BorderlineColor = Color.Orange,
583         ///     BorderlineWidth = 4.0f,
584         ///     BorderlineOffset = -1f,
585         ///     BackgroundColor = new Color(0.2f, 0.2f, 0.2f, 0.2f),
586         /// };
587         /// </code>
588         /// </remarks>
589         /// <returns>instance of default focus indicator</returns>
590         [EditorBrowsable(EditorBrowsableState.Never)]
591         public View GetDefaultFocusIndicator()
592         {
593             ImageView ret = new ImageView(FrameworkInformation.ResourcePath + "keyboard_focus.9.png")
594             {
595                 Name = "DefaultFocusIndicatorCreatedByNUI",
596                 PositionUsesAnchorPoint = true,
597                 ParentOrigin = ParentOrigin.Center,
598                 PivotPoint = ParentOrigin.Center,
599                 Position2D = new Position2D(0, 0),
600             };
601             ret.SetResizePolicy(ResizePolicyType.FillToParent, DimensionType.AllDimensions);
602             return ret;
603         }
604
605         internal static FocusManager Get()
606         {
607             FocusManager ret = new FocusManager(Interop.FocusManager.Get(), true);
608             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
609
610 #if !PROFILE_TV
611             //tv profile never use default focus indicator, so this is not needed!
612             ret.FocusIndicator = ret.GetDefaultFocusIndicator();
613 #endif
614             return ret;
615         }
616
617         internal void SetFocusGroupLoop(bool enabled)
618         {
619             Interop.FocusManager.SetFocusGroupLoop(SwigCPtr, enabled);
620             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
621         }
622
623         internal bool GetFocusGroupLoop()
624         {
625             bool ret = Interop.FocusManager.GetFocusGroupLoop(SwigCPtr);
626             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
627             return ret;
628         }
629
630         internal void SetFocusIndicatorView(View indicator)
631         {
632             Interop.FocusManager.SetFocusIndicatorActor(SwigCPtr, View.getCPtr(indicator));
633             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
634         }
635
636         internal View GetFocusIndicatorView()
637         {
638             //to fix memory leak issue, match the handle count with native side.
639             IntPtr cPtr = Interop.FocusManager.GetFocusIndicatorActor(SwigCPtr);
640             return this.GetInstanceSafely<View>(cPtr);
641         }
642
643         internal PreFocusChangeSignal PreFocusChangeSignal()
644         {
645             PreFocusChangeSignal ret = new PreFocusChangeSignal(Interop.FocusManager.PreFocusChangeSignal(SwigCPtr), false);
646             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
647             return ret;
648         }
649
650         internal FocusChangedSignal FocusChangedSignal()
651         {
652             FocusChangedSignal ret = new FocusChangedSignal(Interop.FocusManager.FocusChangedSignal(SwigCPtr), false);
653             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
654             return ret;
655         }
656
657         internal FocusGroupChangedSignal FocusGroupChangedSignal()
658         {
659             FocusGroupChangedSignal ret = new FocusGroupChangedSignal(Interop.FocusManager.FocusGroupChangedSignal(SwigCPtr), false);
660             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
661             return ret;
662         }
663
664         private IntPtr OnPreFocusChange(IntPtr current, IntPtr proposed, View.FocusDirection direction)
665         {
666             View view = null;
667             PreFocusChangeEventArgs e = new PreFocusChangeEventArgs();
668
669             if (current != global::System.IntPtr.Zero)
670             {
671                 e.CurrentView = Registry.GetManagedBaseHandleFromNativePtr(current) as View;
672             }
673             if (proposed != global::System.IntPtr.Zero)
674             {
675                 e.ProposedView = Registry.GetManagedBaseHandleFromNativePtr(proposed) as View;
676             }
677             e.Direction = direction;
678
679             if (preFocusChangeEventHandler != null)
680             {
681                 view = preFocusChangeEventHandler(this, e);
682             }
683
684             if (view != null)
685             {
686                 return view.GetPtrfromView();
687             }
688             else
689             {
690                 if (e.ProposedView != null) return proposed;
691                 else return current;
692             }
693         }
694
695         private IntPtr OnFocusChanging(IntPtr current, IntPtr proposed, View.FocusDirection direction)
696         {
697             View originallyProposed = null;
698             FocusChangingEventArgs e = new FocusChangingEventArgs();
699
700             if (current != global::System.IntPtr.Zero)
701             {
702                 e.Current = Registry.GetManagedBaseHandleFromNativePtr(current) as View;
703             }
704             if (proposed != global::System.IntPtr.Zero)
705             {
706                 originallyProposed = e.Proposed = Registry.GetManagedBaseHandleFromNativePtr(proposed) as View;
707             }
708             e.Direction = direction;
709
710             focusChangingEventHandler?.Invoke(this, e);
711
712             if (originallyProposed != e.Proposed)
713             {
714                 //when user has changed Proposed
715                 return e.Proposed.GetPtrfromView();
716             }
717             else
718             {
719                 if (originallyProposed != null)
720                 {
721                     return proposed;
722                 }
723                 else
724                 {
725                     return current;
726                 }
727             }
728         }
729
730         private void OnFocusChanged(IntPtr current, IntPtr next)
731         {
732             if (focusChangedEventHandler != null)
733             {
734                 FocusChangedEventArgs e = new FocusChangedEventArgs();
735
736                 e.Previous = e.CurrentView = Registry.GetManagedBaseHandleFromNativePtr(current) as View;
737                 e.Current = e.NextView = Registry.GetManagedBaseHandleFromNativePtr(next) as View;
738                 focusChangedEventHandler(this, e);
739             }
740         }
741
742         private void OnFocusGroupChanged(IntPtr current, bool forwardDirection)
743         {
744             if (focusGroupChangedEventHandler != null)
745             {
746                 FocusGroupChangedEventArgs e = new FocusGroupChangedEventArgs();
747
748                 e.CurrentView = Registry.GetManagedBaseHandleFromNativePtr(current) as View;
749                 e.ForwardDirection = forwardDirection;
750                 focusGroupChangedEventHandler(this, e);
751             }
752         }
753
754         private void OnFocusedViewEnterKey(IntPtr view)
755         {
756             if (focusedViewEnterKeyEventHandler != null)
757             {
758                 FocusedViewActivatedEventArgs e = new FocusedViewActivatedEventArgs();
759                 e.View = Registry.GetManagedBaseHandleFromNativePtr(view) as View;
760                 focusedViewEnterKeyEventHandler(this, e);
761             }
762         }
763
764         /// <summary>
765         /// Do not use this, that will be deprecated.
766         /// </summary>
767         /// Do not use this, that will be deprecated.
768         /// Instead Use OnFocusedViewEnterKey.
769         [Obsolete("Do not use this, that will be deprecated. Use FocusManager.OnFocusedViewEnterKey instead.")]
770         [EditorBrowsable(EditorBrowsableState.Never)]
771         private void OnFocusedViewEnterKey2(IntPtr view)
772         {
773             if (focusedViewEnterKeyEventHandler != null)
774             {
775                 FocusedViewActivatedEventArgs e = new FocusedViewActivatedEventArgs();
776                 e.View = Registry.GetManagedBaseHandleFromNativePtr(view) as View;
777                 focusedViewEnterKeyEventHandler(this, e);
778             }
779         }
780
781         ///<summary>
782         /// Event arguments that passed via the PreFocusChange signal.
783         /// </summary>
784         /// <since_tizen> 3 </since_tizen>
785         [Obsolete("Please do not use! This will be deprecated in API10. Please use FocusChangingEventArgs instead!")]
786         [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1034:Nested types should not be visible", Justification = "<Pending>")]
787         // this will be deprecated, so suppress warning would be OK.
788         public class PreFocusChangeEventArgs : EventArgs
789         {
790             private View current;
791             private View proposed;
792             private View.FocusDirection direction;
793
794             /// <summary>
795             /// The current focus view.
796             /// </summary>
797             /// <since_tizen> 3 </since_tizen>
798             public View CurrentView
799             {
800                 get
801                 {
802                     return current;
803                 }
804                 set
805                 {
806                     current = value;
807                 }
808             }
809
810             /// <summary>
811             /// The  proposed view.
812             /// </summary>
813             /// <since_tizen> 3 </since_tizen>
814             public View ProposedView
815             {
816                 get
817                 {
818                     return proposed;
819                 }
820                 set
821                 {
822                     proposed = value;
823                 }
824             }
825
826             /// <summary>
827             /// The focus move direction.
828             /// </summary>
829             /// <since_tizen> 3 </since_tizen>
830             public View.FocusDirection Direction
831             {
832                 get
833                 {
834                     return direction;
835                 }
836                 set
837                 {
838                     direction = value;
839                 }
840             }
841         }
842
843         ///<summary>
844         /// Event arguments that passed via the FocusChanged signal.
845         /// </summary>
846         /// <since_tizen> 3 </since_tizen>
847         public class FocusChangedEventArgs : EventArgs
848         {
849             private View currentView;
850             private View nextView;
851             private View previous;
852             private View current;
853
854             /// <summary>
855             /// The current focus view.
856             /// </summary>
857             /// <since_tizen> 3 </since_tizen>
858             [Obsolete("Please do not use! This will be deprecated! Please use Previous instead!")]
859             public View CurrentView
860             {
861                 get
862                 {
863                     return currentView;
864                 }
865                 set
866                 {
867                     currentView = value;
868                 }
869             }
870             /// <summary>
871             /// The next focus view.
872             /// </summary>
873             /// <since_tizen> 3 </since_tizen>
874             [Obsolete("Please do not use! This will be deprecated! Please use Current instead!")]
875             public View NextView
876             {
877                 get
878                 {
879                     return nextView;
880                 }
881                 set
882                 {
883                     nextView = value;
884                 }
885             }
886             /// <summary>
887             /// The previously focused view.
888             /// </summary>
889             /// <since_tizen> 10 </since_tizen>
890             public View Previous
891             {
892                 get
893                 {
894                     return previous;
895                 }
896                 set
897                 {
898                     previous = value;
899                 }
900             }
901             /// <summary>
902             /// The current focused view after focus changed.
903             /// </summary>
904             /// <since_tizen> 10 </since_tizen>
905             public View Current
906             {
907                 get
908                 {
909                     return current;
910                 }
911                 set
912                 {
913                     current = value;
914                 }
915             }
916         }
917
918         ///<summary>
919         /// Event arguments that passed via the FocusGroupChanged signal.
920         /// </summary>
921         /// <since_tizen> 3 </since_tizen>
922         public class FocusGroupChangedEventArgs : EventArgs
923         {
924             private View current;
925             private bool forwardDirection;
926
927             /// <summary>
928             /// The current focus view.
929             /// </summary>
930             /// <since_tizen> 3 </since_tizen>
931             public View CurrentView
932             {
933                 get
934                 {
935                     return current;
936                 }
937                 set
938                 {
939                     current = value;
940                 }
941             }
942
943             /// <summary>
944             /// The forward direction.
945             /// </summary>
946             /// <since_tizen> 3 </since_tizen>
947             public bool ForwardDirection
948             {
949                 get
950                 {
951                     return forwardDirection;
952                 }
953                 set
954                 {
955                     forwardDirection = value;
956                 }
957             }
958         }
959
960         ///<summary>
961         /// Event arguments that passed via the FocusedViewEnterKey signal.
962         /// </summary>
963         /// <since_tizen> 3 </since_tizen>
964         public class FocusedViewActivatedEventArgs : EventArgs
965         {
966             private View view;
967
968             /// <summary>
969             /// View.
970             /// </summary>
971             /// <since_tizen> 3 </since_tizen>
972             public View View
973             {
974                 get
975                 {
976                     return view;
977                 }
978                 set
979                 {
980                     view = value;
981                 }
982             }
983         }
984
985         /// <summary>
986         /// Do not use this, that will be deprecated.
987         /// </summary>
988         /// <since_tizen> 3 </since_tizen>
989         /// Do not use this, that will be deprecated.
990         /// Instead Use FocusedViewActivatedEventArgs.
991         [Obsolete("Do not use this, that will be deprecated. Use FocusedViewActivatedEventArgs instead. " +
992             "Like: " +
993             "FocusManager.Instance.FocusedViewActivated = OnFocusedViewActivated; " +
994             "private void OnFocusedViewActivated(object source, FocusManager.FocusedViewActivatedEventArgs arg)" +
995             "{...}")]
996         [EditorBrowsable(EditorBrowsableState.Never)]
997         [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1034:NestedTypesShouldNotBeVisible")]
998         public class FocusedViewEnterKeyEventArgs : EventArgs
999         {
1000             private View view;
1001
1002             /// <summary>
1003             /// View.
1004             /// </summary>
1005             /// <since_tizen> 3 </since_tizen>
1006             public View View
1007             {
1008                 get
1009                 {
1010                     return view;
1011                 }
1012                 set
1013                 {
1014                     view = value;
1015                 }
1016             }
1017         }
1018
1019         private class CustomAlgorithmInterfaceWrapper : CustomAlgorithmInterface
1020         {
1021             private FocusManager.ICustomFocusAlgorithm customFocusAlgorithm;
1022
1023             public CustomAlgorithmInterfaceWrapper()
1024             {
1025             }
1026
1027             public void SetFocusAlgorithm(FocusManager.ICustomFocusAlgorithm customFocusAlgorithm)
1028             {
1029                 this.customFocusAlgorithm = customFocusAlgorithm;
1030             }
1031
1032             public override View GetNextFocusableView(View current, View proposed, View.FocusDirection direction, string deviceName)
1033             {
1034                 if (customFocusAlgorithm == null)
1035                 {
1036                     Tizen.Log.Error("NUI", $"[ERROR] User defined ICustomFocusAlgorithm interface class becomes unreachable. Null will be proposed for next focusing!");
1037                     return null;
1038                 }
1039                 if (customFocusAlgorithm is ICustomAwareDeviceFocusAlgorithm deviceAwared)
1040                 {
1041                     return deviceAwared.GetNextFocusableView(current, proposed, direction, deviceName);
1042                 }
1043                 else
1044                 {
1045                     return customFocusAlgorithm.GetNextFocusableView(current, proposed, direction);
1046                 }
1047             }
1048         }
1049     }
1050 }