66392d7892d47bdb3ca7e5acbdd0d54d4fdb3847
[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                     using ViewSignal signal = FocusedViewEnterKeySignal();
221                     signal?.Connect(focusedViewEnterKeyEventCallback);
222                 }
223                 focusedViewEnterKeyEventHandler += value;
224             }
225             remove
226             {
227                 focusedViewEnterKeyEventHandler -= value;
228
229                 using ViewSignal signal = FocusedViewEnterKeySignal();
230                 if (focusedViewEnterKeyEventCallback != null && signal?.Empty() == false)
231                 {
232                     signal?.Disconnect(focusedViewEnterKeyEventCallback);
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                     using ViewSignal signal = FocusedViewEnterKeySignal();
256                     signal?.Connect(focusedViewEnterKeyEventCallback2);
257                 }
258                 focusedViewEnterKeyEventHandler2 += value;
259             }
260             remove
261             {
262                 focusedViewEnterKeyEventHandler2 -= value;
263
264                 using ViewSignal signal = FocusedViewEnterKeySignal();
265                 if (focusedViewEnterKeyEventCallback2 != null && signal?.Empty() == false)
266                 {
267                     signal?.Disconnect(focusedViewEnterKeyEventCallback2);
268                 }
269             }
270         }
271
272         /// <summary>
273         /// ICustomFocusAlgorithm is used to provide the custom keyboard focus algorithm for retrieving the next focusable view.<br />
274         /// The application can implement the interface and override the keyboard focus behavior.<br />
275         /// If the focus is changing within a layout container, then the layout container is queried first to provide the next focusable view.<br />
276         /// If this does not provide a valid view, then the Keyboard FocusManager will check focusable properties to determine the next focusable actor.<br />
277         /// If focusable properties are not set, then the keyboard FocusManager calls the GetNextFocusableView() method of this interface.<br />
278         /// </summary>
279         /// <since_tizen> 3 </since_tizen>
280         public interface ICustomFocusAlgorithm
281         {
282             /// <summary>
283             /// Get the next focus actor.
284             /// </summary>
285             /// <param name="current">The current focus view.</param>
286             /// <param name="proposed">The proposed focus view</param>
287             /// <param name="direction">The focus move direction</param>
288             /// <returns>The next focus actor.</returns>
289             /// <since_tizen> 3 </since_tizen>
290             View GetNextFocusableView(View current, View proposed, View.FocusDirection direction);
291         }
292
293
294         /// <summary>
295         /// Gets or sets the status of whether the focus movement should be looped within the same focus group.<br />
296         /// The focus movement is not looped by default.<br />
297         /// </summary>
298         /// <since_tizen> 3 </since_tizen>
299         public bool FocusGroupLoop
300         {
301             set
302             {
303                 SetFocusGroupLoop(value);
304             }
305             get
306             {
307                 return GetFocusGroupLoop();
308             }
309         }
310
311         /// <summary>
312         /// Gets or sets the focus indicator view.<br />
313         /// This will replace the default focus indicator view in the FocusManager and will be added to the focused view as a highlight.<br />
314         /// </summary>
315         /// <since_tizen> 3 </since_tizen>
316         public View FocusIndicator
317         {
318             set
319             {
320                 internalFocusIndicator = value;
321                 if (internalFocusIndicator == null)
322                 {
323                     if (nullFocusIndicator == null)
324                     {
325                         nullFocusIndicator = new View();
326                     }
327                     SetFocusIndicatorView(nullFocusIndicator);
328                 }
329                 else
330                 {
331                     SetFocusIndicatorView(internalFocusIndicator);
332                 }
333             }
334             get
335             {
336                 return internalFocusIndicator;
337             }
338         }
339
340         /// <summary>
341         /// Gets the singleton of the FocusManager object.
342         /// </summary>
343         /// <since_tizen> 3 </since_tizen>
344         public static FocusManager Instance
345         {
346             get
347             {
348                 return instance;
349             }
350         }
351
352         /// <summary>
353         /// Moves the keyboard focus to the given view.<br />
354         /// Only one view can be focused at the same time.<br />
355         /// The view must be in the stage already and keyboard focusable.<br />
356         /// </summary>
357         /// <param name="view">The view to be focused.</param>
358         /// <returns>Whether the focus is successful or not.</returns>
359         /// <since_tizen> 3 </since_tizen>
360         public bool SetCurrentFocusView(View view)
361         {
362             if (view == null)
363             {
364                 throw new ArgumentNullException(nameof(view), "the target view should not be null");
365             }
366
367             bool ret = Interop.FocusManager.SetCurrentFocusActor(SwigCPtr, View.getCPtr(view));
368             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
369             return ret;
370         }
371
372         /// <summary>
373         /// Gets the current focused view.
374         /// </summary>
375         /// <returns>A handle to the current focused view or an empty handle if no view is focused.</returns>
376         /// <since_tizen> 3 </since_tizen>
377         public View GetCurrentFocusView()
378         {
379             //to fix memory leak issue, match the handle count with native side.
380             IntPtr cPtr = Interop.FocusManager.GetCurrentFocusActor(SwigCPtr);
381             View ret = this.GetInstanceSafely<View>(cPtr);
382             return ret;
383         }
384
385         /// <summary>
386         /// Moves the focus to the next focusable view in the focus chain in the given direction (according to the focus traversal order).
387         /// </summary>
388         /// <param name="direction">The direction of the focus movement.</param>
389         /// <returns>True if the movement was successful.</returns>
390         /// <since_tizen> 3 </since_tizen>
391         public bool MoveFocus(View.FocusDirection direction)
392         {
393             bool ret = Interop.FocusManager.MoveFocus(SwigCPtr, (int)direction);
394             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
395             return ret;
396         }
397
398         /// <summary>
399         /// Clears the focus from the current focused view if any, so that no view is focused in the focus chain.<br />
400         /// It will emit the FocusChanged event without the current focused view.<br />
401         /// </summary>
402         /// <since_tizen> 3 </since_tizen>
403         public void ClearFocus()
404         {
405             Interop.FocusManager.ClearFocus(SwigCPtr);
406             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
407         }
408
409         /// <summary>
410         /// Move the focus to previous focused view.
411         /// </summary>
412         /// <since_tizen> 3 </since_tizen>
413         public void MoveFocusBackward()
414         {
415             Interop.FocusManager.MoveFocusBackward(SwigCPtr);
416             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
417         }
418
419         /// <summary>
420         /// 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 />
421         /// Layout controls set themselves as focus groups by default.<br />
422         /// </summary>
423         /// <param name="view">The view to be set as a focus group.</param>
424         /// <param name="isFocusGroup">Whether to set the view as a focus group or not.</param>
425         /// <since_tizen> 3 </since_tizen>
426         public void SetAsFocusGroup(View view, bool isFocusGroup)
427         {
428             Interop.FocusManager.SetAsFocusGroup(SwigCPtr, View.getCPtr(view), isFocusGroup);
429             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
430         }
431
432         /// <summary>
433         /// Checks whether the view is set as a focus group or not.
434         /// </summary>
435         /// <param name="view">The view to be checked.</param>
436         /// <returns>Whether the view is set as a focus group.</returns>
437         /// <since_tizen> 3 </since_tizen>
438         public bool IsFocusGroup(View view)
439         {
440             bool ret = Interop.FocusManager.IsFocusGroup(SwigCPtr, View.getCPtr(view));
441             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
442             return ret;
443         }
444
445         /// <summary>
446         /// Returns the closest ancestor of the given view that is a focus group.
447         /// </summary>
448         /// <param name="view">The view to be checked for its focus group.</param>
449         /// <returns>The focus group the given view belongs to or an empty handle if the given view.</returns>
450         /// <since_tizen> 3 </since_tizen>
451         public View GetFocusGroup(View view)
452         {
453             //to fix memory leak issue, match the handle count with native side.
454             IntPtr cPtr = Interop.FocusManager.GetFocusGroup(SwigCPtr, View.getCPtr(view));
455             View ret = this.GetInstanceSafely<View>(cPtr);
456             return ret;
457         }
458
459         /// <summary>
460         /// Provides the implementation of a custom focus algorithm interface to allow the application to define the focus logic.<br />
461         /// </summary>
462         /// <param name="arg0">The user's implementation of ICustomFocusAlgorithm.</param>
463         /// <since_tizen> 3 </since_tizen>
464         public void SetCustomAlgorithm(ICustomFocusAlgorithm arg0)
465         {
466             if (arg0 != null)
467             {
468                 customAlgorithmInterfaceWrapper = new CustomAlgorithmInterfaceWrapper();
469                 customAlgorithmInterfaceWrapper.SetFocusAlgorithm(arg0);
470
471                 Interop.NDalic.SetCustomAlgorithm(SwigCPtr, CustomAlgorithmInterface.getCPtr(customAlgorithmInterfaceWrapper));
472                 if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
473             }
474             else
475             {
476                 Interop.NDalic.SetCustomAlgorithm(SwigCPtr, new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero));
477                 if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
478             }
479         }
480
481         /// <summary>
482         /// Sets to use the automatic focus moveing algorithm. <br />
483         /// It moves the focus to the view closest to the keyboard movement direction.
484         /// </summary>
485         /// <param name="enable">Whether using default focus algorithm or not</param>
486         [EditorBrowsable(EditorBrowsableState.Never)]
487         public void EnableDefaultAlgorithm(bool enable)
488         {
489             Interop.FocusManager.EnableDefaultAlgorithm(SwigCPtr, enable);
490             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
491         }
492
493         /// <summary>
494         ///  Checks default focus moveing algorithm is enabled or not
495         /// </summary>
496         /// <returns>Whether default focus algorithm is enabled</returns>
497         [EditorBrowsable(EditorBrowsableState.Never)]
498         public bool IsDefaultAlgorithmEnabled()
499         {
500             bool ret = Interop.FocusManager.IsDefaultAlgorithmEnabled(SwigCPtr);
501             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
502             return ret;
503         }
504
505         /// <summary>
506         /// Get the nearest focusable view.
507         /// </summary>
508         /// <param name="rootView">The view group in which to find the next focusable view.</param>
509         /// <param name="focusedView">The current focused view.</param>
510         /// <param name="direction">The direction.</param>
511         /// <returns>The nearest focusable view, or an empty handle if none exists.</returns>
512         [EditorBrowsable(EditorBrowsableState.Never)]
513         public View GetNearestFocusableActor(View rootView, View focusedView, View.FocusDirection direction)
514         {
515             //to fix memory leak issue, match the handle count with native side.
516             IntPtr cPtr = Interop.FocusManager.GetNearestFocusableActor(View.getCPtr(rootView), View.getCPtr(focusedView), (int)direction);
517             View ret = this.GetInstanceSafely<View>(cPtr);
518             return ret;
519         }
520
521         /// <summary>
522         /// Sets the root view to start moving focus when DefaultAlgorithm is enabled.
523         /// This will only look for focusable Views within that View tree when looking for the next focus.
524         /// </summary>
525         /// <param name="rootView">The root view in which to find the next focusable view.</param>
526         [EditorBrowsable(EditorBrowsableState.Never)]
527         public void SetFocusFinderRootView(View rootView)
528         {
529             Interop.FocusManager.SetFocusFinderRootView(SwigCPtr, View.getCPtr(rootView));
530             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
531         }
532
533         /// <summary>
534         /// Reset the root view that starts moving focus when DefaultAlgorithm is enabled.
535         /// When reset, the window becomes root.
536         /// </summary>
537         [EditorBrowsable(EditorBrowsableState.Never)]
538         public void ResetFocusFinderRootView()
539         {
540             Interop.FocusManager.ResetFocusFinderRootView(SwigCPtr);
541             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
542         }
543
544         /// <summary>
545         /// Get a default focus indicator
546         /// </summary>
547         /// <remarks>
548         /// The type actually <see cref="Tizen.NUI.BaseComponents.ImageView"/> of blue border squred png image, so it would be difficult to modify itself.
549         /// To change focus indicator, creating new indicator and assigning it to FocusIndicator are recommended.
550         /// For example,
551         /// <code>
552         /// FocusManager.Instance.FocusIndicator = new View()
553         /// {
554         ///     PositionUsesPivotPoint = true,
555         ///     PivotPoint = new Position(0, 0, 0),
556         ///     WidthResizePolicy = ResizePolicyType.FillToParent,
557         ///     HeightResizePolicy = ResizePolicyType.FillToParent,
558         ///     BorderlineColor = Color.Orange,
559         ///     BorderlineWidth = 4.0f,
560         ///     BorderlineOffset = -1f,
561         ///     BackgroundColor = new Color(0.2f, 0.2f, 0.2f, 0.2f),
562         /// };
563         /// </code>
564         /// </remarks>
565         /// <returns>instance of default focus indicator</returns>
566         [EditorBrowsable(EditorBrowsableState.Never)]
567         public View GetDefaultFocusIndicator()
568         {
569             ImageView ret = new ImageView(FrameworkInformation.ResourcePath + "keyboard_focus.9.png")
570             {
571                 Name = "DefaultFocusIndicatorCreatedByNUI",
572                 PositionUsesAnchorPoint = true,
573                 ParentOrigin = ParentOrigin.Center,
574                 PivotPoint = ParentOrigin.Center,
575                 Position2D = new Position2D(0, 0),
576             };
577             ret.SetResizePolicy(ResizePolicyType.FillToParent, DimensionType.AllDimensions);
578             return ret;
579         }
580
581         internal static FocusManager Get()
582         {
583             FocusManager ret = new FocusManager(Interop.FocusManager.Get(), true);
584             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
585
586 #if !PROFILE_TV
587             ret.FocusIndicator = ret.GetDefaultFocusIndicator();
588 #endif
589             return ret;
590         }
591
592         internal void SetFocusGroupLoop(bool enabled)
593         {
594             Interop.FocusManager.SetFocusGroupLoop(SwigCPtr, enabled);
595             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
596         }
597
598         internal bool GetFocusGroupLoop()
599         {
600             bool ret = Interop.FocusManager.GetFocusGroupLoop(SwigCPtr);
601             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
602             return ret;
603         }
604
605         internal void SetFocusIndicatorView(View indicator)
606         {
607             Interop.FocusManager.SetFocusIndicatorActor(SwigCPtr, View.getCPtr(indicator));
608             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
609         }
610
611         internal View GetFocusIndicatorView()
612         {
613             //to fix memory leak issue, match the handle count with native side.
614             IntPtr cPtr = Interop.FocusManager.GetFocusIndicatorActor(SwigCPtr);
615             return this.GetInstanceSafely<View>(cPtr);
616         }
617
618         internal PreFocusChangeSignal PreFocusChangeSignal()
619         {
620             PreFocusChangeSignal ret = new PreFocusChangeSignal(Interop.FocusManager.PreFocusChangeSignal(SwigCPtr), false);
621             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
622             return ret;
623         }
624
625         internal FocusChangedSignal FocusChangedSignal()
626         {
627             FocusChangedSignal ret = new FocusChangedSignal(Interop.FocusManager.FocusChangedSignal(SwigCPtr), false);
628             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
629             return ret;
630         }
631
632         internal FocusGroupChangedSignal FocusGroupChangedSignal()
633         {
634             FocusGroupChangedSignal ret = new FocusGroupChangedSignal(Interop.FocusManager.FocusGroupChangedSignal(SwigCPtr), false);
635             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
636             return ret;
637         }
638
639         internal ViewSignal FocusedViewEnterKeySignal()
640         {
641             ViewSignal ret = new ViewSignal(Interop.FocusManager.FocusedActorEnterKeySignal(SwigCPtr), false);
642             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
643             return ret;
644         }
645
646         private IntPtr OnPreFocusChange(IntPtr current, IntPtr proposed, View.FocusDirection direction)
647         {
648             View view = null;
649             PreFocusChangeEventArgs e = new PreFocusChangeEventArgs();
650
651             if (current != global::System.IntPtr.Zero)
652             {
653                 e.CurrentView = Registry.GetManagedBaseHandleFromNativePtr(current) as View;
654             }
655             if (proposed != global::System.IntPtr.Zero)
656             {
657                 e.ProposedView = Registry.GetManagedBaseHandleFromNativePtr(proposed) as View;
658             }
659             e.Direction = direction;
660
661             if (preFocusChangeEventHandler != null)
662             {
663                 view = preFocusChangeEventHandler(this, e);
664             }
665
666             if (view != null)
667             {
668                 return view.GetPtrfromView();
669             }
670             else
671             {
672                 if (e.ProposedView != null) return proposed;
673                 else return current;
674             }
675         }
676
677         private IntPtr OnFocusChanging(IntPtr current, IntPtr proposed, View.FocusDirection direction)
678         {
679             View originallyProposed = null;
680             FocusChangingEventArgs e = new FocusChangingEventArgs();
681
682             if (current != global::System.IntPtr.Zero)
683             {
684                 e.Current = Registry.GetManagedBaseHandleFromNativePtr(current) as View;
685             }
686             if (proposed != global::System.IntPtr.Zero)
687             {
688                 originallyProposed = e.Proposed = Registry.GetManagedBaseHandleFromNativePtr(proposed) as View;
689             }
690             e.Direction = direction;
691
692             focusChangingEventHandler?.Invoke(this, e);
693
694             if (originallyProposed != e.Proposed)
695             {
696                 //when user has changed Proposed
697                 return e.Proposed.GetPtrfromView();
698             }
699             else
700             {
701                 if (originallyProposed != null)
702                 {
703                     return proposed;
704                 }
705                 else
706                 {
707                     return current;
708                 }
709             }
710         }
711
712         private void OnFocusChanged(IntPtr current, IntPtr next)
713         {
714             if (focusChangedEventHandler != null)
715             {
716                 FocusChangedEventArgs e = new FocusChangedEventArgs();
717
718                 e.Previous = e.CurrentView = Registry.GetManagedBaseHandleFromNativePtr(current) as View;
719                 e.Current = e.NextView = Registry.GetManagedBaseHandleFromNativePtr(next) as View;
720                 focusChangedEventHandler(this, e);
721             }
722         }
723
724         private void OnFocusGroupChanged(IntPtr current, bool forwardDirection)
725         {
726             if (focusGroupChangedEventHandler != null)
727             {
728                 FocusGroupChangedEventArgs e = new FocusGroupChangedEventArgs();
729
730                 e.CurrentView = Registry.GetManagedBaseHandleFromNativePtr(current) as View;
731                 e.ForwardDirection = forwardDirection;
732                 focusGroupChangedEventHandler(this, e);
733             }
734         }
735
736         private void OnFocusedViewEnterKey(IntPtr view)
737         {
738             if (focusedViewEnterKeyEventHandler != null)
739             {
740                 FocusedViewActivatedEventArgs e = new FocusedViewActivatedEventArgs();
741                 e.View = Registry.GetManagedBaseHandleFromNativePtr(view) as View;
742                 focusedViewEnterKeyEventHandler(this, e);
743             }
744         }
745
746         /// <summary>
747         /// Do not use this, that will be deprecated.
748         /// </summary>
749         /// Do not use this, that will be deprecated.
750         /// Instead Use OnFocusedViewEnterKey.
751         [Obsolete("Do not use this, that will be deprecated. Use FocusManager.OnFocusedViewEnterKey instead.")]
752         [EditorBrowsable(EditorBrowsableState.Never)]
753         private void OnFocusedViewEnterKey2(IntPtr view)
754         {
755             if (focusedViewEnterKeyEventHandler != null)
756             {
757                 FocusedViewActivatedEventArgs e = new FocusedViewActivatedEventArgs();
758                 e.View = Registry.GetManagedBaseHandleFromNativePtr(view) as View;
759                 focusedViewEnterKeyEventHandler(this, e);
760             }
761         }
762
763         ///<summary>
764         /// Event arguments that passed via the PreFocusChange signal.
765         /// </summary>
766         /// <since_tizen> 3 </since_tizen>
767         [Obsolete("Please do not use! This will be deprecated in API10. Please use FocusChangingEventArgs instead!")]
768         [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1034:Nested types should not be visible", Justification = "<Pending>")]
769         // this will be deprecated, so suppress warning would be OK.
770         public class PreFocusChangeEventArgs : EventArgs
771         {
772             private View current;
773             private View proposed;
774             private View.FocusDirection direction;
775
776             /// <summary>
777             /// The current focus view.
778             /// </summary>
779             /// <since_tizen> 3 </since_tizen>
780             public View CurrentView
781             {
782                 get
783                 {
784                     return current;
785                 }
786                 set
787                 {
788                     current = value;
789                 }
790             }
791
792             /// <summary>
793             /// The  proposed view.
794             /// </summary>
795             /// <since_tizen> 3 </since_tizen>
796             public View ProposedView
797             {
798                 get
799                 {
800                     return proposed;
801                 }
802                 set
803                 {
804                     proposed = value;
805                 }
806             }
807
808             /// <summary>
809             /// The focus move direction.
810             /// </summary>
811             /// <since_tizen> 3 </since_tizen>
812             public View.FocusDirection Direction
813             {
814                 get
815                 {
816                     return direction;
817                 }
818                 set
819                 {
820                     direction = value;
821                 }
822             }
823         }
824
825         ///<summary>
826         /// Event arguments that passed via the FocusChanged signal.
827         /// </summary>
828         /// <since_tizen> 3 </since_tizen>
829         public class FocusChangedEventArgs : EventArgs
830         {
831             private View currentView;
832             private View nextView;
833             private View previous;
834             private View current;
835
836             /// <summary>
837             /// The current focus view.
838             /// </summary>
839             /// <since_tizen> 3 </since_tizen>
840             [Obsolete("Please do not use! This will be deprecated! Please use Previous instead!")]
841             public View CurrentView
842             {
843                 get
844                 {
845                     return currentView;
846                 }
847                 set
848                 {
849                     currentView = value;
850                 }
851             }
852             /// <summary>
853             /// The next focus view.
854             /// </summary>
855             /// <since_tizen> 3 </since_tizen>
856             [Obsolete("Please do not use! This will be deprecated! Please use Current instead!")]
857             public View NextView
858             {
859                 get
860                 {
861                     return nextView;
862                 }
863                 set
864                 {
865                     nextView = value;
866                 }
867             }
868             /// <summary>
869             /// The previously focused view.
870             /// </summary>
871             /// <since_tizen> 10 </since_tizen>
872             public View Previous
873             {
874                 get
875                 {
876                     return previous;
877                 }
878                 set
879                 {
880                     previous = value;
881                 }
882             }
883             /// <summary>
884             /// The current focused view after focus changed.
885             /// </summary>
886             /// <since_tizen> 10 </since_tizen>
887             public View Current
888             {
889                 get
890                 {
891                     return current;
892                 }
893                 set
894                 {
895                     current = value;
896                 }
897             }
898         }
899
900         ///<summary>
901         /// Event arguments that passed via the FocusGroupChanged signal.
902         /// </summary>
903         /// <since_tizen> 3 </since_tizen>
904         public class FocusGroupChangedEventArgs : EventArgs
905         {
906             private View current;
907             private bool forwardDirection;
908
909             /// <summary>
910             /// The current focus view.
911             /// </summary>
912             /// <since_tizen> 3 </since_tizen>
913             public View CurrentView
914             {
915                 get
916                 {
917                     return current;
918                 }
919                 set
920                 {
921                     current = value;
922                 }
923             }
924
925             /// <summary>
926             /// The forward direction.
927             /// </summary>
928             /// <since_tizen> 3 </since_tizen>
929             public bool ForwardDirection
930             {
931                 get
932                 {
933                     return forwardDirection;
934                 }
935                 set
936                 {
937                     forwardDirection = value;
938                 }
939             }
940         }
941
942         ///<summary>
943         /// Event arguments that passed via the FocusedViewEnterKey signal.
944         /// </summary>
945         /// <since_tizen> 3 </since_tizen>
946         public class FocusedViewActivatedEventArgs : EventArgs
947         {
948             private View view;
949
950             /// <summary>
951             /// View.
952             /// </summary>
953             /// <since_tizen> 3 </since_tizen>
954             public View View
955             {
956                 get
957                 {
958                     return view;
959                 }
960                 set
961                 {
962                     view = value;
963                 }
964             }
965         }
966
967         /// <summary>
968         /// Do not use this, that will be deprecated.
969         /// </summary>
970         /// <since_tizen> 3 </since_tizen>
971         /// Do not use this, that will be deprecated.
972         /// Instead Use FocusedViewActivatedEventArgs.
973         [Obsolete("Do not use this, that will be deprecated. Use FocusedViewActivatedEventArgs instead. " +
974             "Like: " +
975             "FocusManager.Instance.FocusedViewActivated = OnFocusedViewActivated; " +
976             "private void OnFocusedViewActivated(object source, FocusManager.FocusedViewActivatedEventArgs arg)" +
977             "{...}")]
978         [EditorBrowsable(EditorBrowsableState.Never)]
979         [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1034:NestedTypesShouldNotBeVisible")]
980         public class FocusedViewEnterKeyEventArgs : EventArgs
981         {
982             private View view;
983
984             /// <summary>
985             /// View.
986             /// </summary>
987             /// <since_tizen> 3 </since_tizen>
988             public View View
989             {
990                 get
991                 {
992                     return view;
993                 }
994                 set
995                 {
996                     view = value;
997                 }
998             }
999         }
1000
1001         private class CustomAlgorithmInterfaceWrapper : CustomAlgorithmInterface
1002         {
1003             private FocusManager.ICustomFocusAlgorithm customFocusAlgorithm;
1004
1005             public CustomAlgorithmInterfaceWrapper()
1006             {
1007             }
1008
1009             public void SetFocusAlgorithm(FocusManager.ICustomFocusAlgorithm customFocusAlgorithm)
1010             {
1011                 this.customFocusAlgorithm = customFocusAlgorithm;
1012             }
1013
1014             public override View GetNextFocusableView(View current, View proposed, View.FocusDirection direction, string deviceName)
1015             {
1016                 if (customFocusAlgorithm == null)
1017                 {
1018                     Tizen.Log.Error("NUI", $"[ERROR] User defined ICustomFocusAlgorithm interface class becomes unreachable. Null will be proposed for next focusing!");
1019                     return null;
1020                 }
1021                 if (customFocusAlgorithm is ICustomAwareDeviceFocusAlgorithm deviceAwared)
1022                 {
1023                     return deviceAwared.GetNextFocusableView(current, proposed, direction, deviceName);
1024                 }
1025                 else
1026                 {
1027                     return customFocusAlgorithm.GetNextFocusableView(current, proposed, direction);
1028                 }
1029             }
1030         }
1031     }
1032 }