Implement FocusFinder
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / focus-manager / keyboard-focus-manager-impl.cpp
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 // CLASS HEADER
19 #include "keyboard-focus-manager-impl.h"
20
21 // EXTERNAL INCLUDES
22 #include <dali/devel-api/adaptor-framework/lifecycle-controller.h>
23 #include <dali/devel-api/common/singleton-service.h>
24 #include <dali/integration-api/adaptor-framework/adaptor.h>
25 #include <dali/integration-api/adaptor-framework/scene-holder.h>
26 #include <dali/integration-api/debug.h>
27 #include <dali/public-api/actors/layer.h>
28 #include <dali/public-api/animation/constraints.h>
29 #include <dali/public-api/events/key-event.h>
30 #include <dali/public-api/events/touch-event.h>
31 #include <dali/public-api/object/property-map.h>
32 #include <dali/public-api/object/type-registry-helper.h>
33 #include <dali/public-api/object/type-registry.h>
34 #include <cstring> // for strcmp
35
36 // INTERNAL INCLUDES
37 #include <dali-toolkit/devel-api/asset-manager/asset-manager.h>
38 #include <dali-toolkit/devel-api/controls/control-devel.h>
39 #include <dali-toolkit/devel-api/focus-manager/focus-finder.h>
40 #include <dali-toolkit/devel-api/styling/style-manager-devel.h>
41 #include <dali-toolkit/public-api/controls/control-impl.h>
42 #include <dali-toolkit/public-api/controls/control.h>
43 #include <dali-toolkit/public-api/controls/image-view/image-view.h>
44 #include <dali-toolkit/public-api/styling/style-manager.h>
45 #include <dali/devel-api/adaptor-framework/accessibility.h>
46
47 namespace Dali
48 {
49 namespace Toolkit
50 {
51 namespace Internal
52 {
53 namespace // Unnamed namespace
54 {
55 #if defined(DEBUG_ENABLED)
56 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_KEYBOARD_FOCUS_MANAGER");
57 #endif
58
59 const char* const IS_FOCUS_GROUP_PROPERTY_NAME = "isKeyboardFocusGroup"; // This property will be replaced by a flag in Control.
60
61 const char* const FOCUS_BORDER_IMAGE_FILE_NAME = "keyboard_focus.9.png";
62
63 BaseHandle Create()
64 {
65   BaseHandle handle = KeyboardFocusManager::Get();
66
67   if(!handle)
68   {
69     SingletonService singletonService(SingletonService::Get());
70     if(singletonService)
71     {
72       Toolkit::KeyboardFocusManager manager = Toolkit::KeyboardFocusManager(new Internal::KeyboardFocusManager());
73       singletonService.Register(typeid(manager), manager);
74       handle = manager;
75     }
76   }
77
78   return handle;
79 }
80
81 DALI_TYPE_REGISTRATION_BEGIN_CREATE(Toolkit::KeyboardFocusManager, Dali::BaseHandle, Create, true)
82
83 DALI_SIGNAL_REGISTRATION(Toolkit, KeyboardFocusManager, "keyboardPreFocusChange", SIGNAL_PRE_FOCUS_CHANGE)
84 DALI_SIGNAL_REGISTRATION(Toolkit, KeyboardFocusManager, "keyboardFocusChanged", SIGNAL_FOCUS_CHANGED)
85 DALI_SIGNAL_REGISTRATION(Toolkit, KeyboardFocusManager, "keyboardFocusGroupChanged", SIGNAL_FOCUS_GROUP_CHANGED)
86 DALI_SIGNAL_REGISTRATION(Toolkit, KeyboardFocusManager, "keyboardFocusedActorEnterKey", SIGNAL_FOCUSED_ACTOR_ENTER_KEY)
87
88 DALI_TYPE_REGISTRATION_END()
89
90 const unsigned int MAX_HISTORY_AMOUNT = 30; ///< Max length of focus history stack
91
92 } // unnamed namespace
93
94 Toolkit::KeyboardFocusManager KeyboardFocusManager::Get()
95 {
96   Toolkit::KeyboardFocusManager manager;
97
98   SingletonService singletonService(SingletonService::Get());
99   if(singletonService)
100   {
101     // Check whether the keyboard focus manager is already created
102     Dali::BaseHandle handle = singletonService.GetSingleton(typeid(Toolkit::KeyboardFocusManager));
103     if(handle)
104     {
105       // If so, downcast the handle of singleton to keyboard focus manager
106       manager = Toolkit::KeyboardFocusManager(dynamic_cast<KeyboardFocusManager*>(handle.GetObjectPtr()));
107     }
108   }
109
110   return manager;
111 }
112
113 KeyboardFocusManager::KeyboardFocusManager()
114 : mPreFocusChangeSignal(),
115   mFocusChangedSignal(),
116   mFocusGroupChangedSignal(),
117   mFocusedActorEnterKeySignal(),
118   mCurrentFocusActor(),
119   mFocusIndicatorActor(),
120   mFocusHistory(),
121   mSlotDelegate(this),
122   mCustomAlgorithmInterface(NULL),
123   mCurrentFocusedWindow(),
124   mIsFocusIndicatorShown(UNKNOWN),
125   mEnableFocusIndicator(ENABLE),
126   mAlwaysShowIndicator(ALWAYS_SHOW),
127   mFocusGroupLoopEnabled(false),
128   mIsWaitingKeyboardFocusChangeCommit(false),
129   mClearFocusOnTouch(true)
130 {
131   // TODO: Get FocusIndicatorEnable constant from stylesheet to set mIsFocusIndicatorShown.
132
133   LifecycleController::Get().InitSignal().Connect(mSlotDelegate, &KeyboardFocusManager::OnAdaptorInit);
134 }
135
136 void KeyboardFocusManager::OnAdaptorInit()
137 {
138   if(Adaptor::IsAvailable())
139   {
140     // Retrieve all the existing scene holders
141     Dali::SceneHolderList sceneHolders = Adaptor::Get().GetSceneHolders();
142     for(auto iter = sceneHolders.begin(); iter != sceneHolders.end(); ++iter)
143     {
144       (*iter).KeyEventSignal().Connect(mSlotDelegate, &KeyboardFocusManager::OnKeyEvent);
145       (*iter).TouchedSignal().Connect(mSlotDelegate, &KeyboardFocusManager::OnTouch);
146       Dali::Window window = DevelWindow::DownCast(*iter);
147       if(window)
148       {
149         window.FocusChangeSignal().Connect(mSlotDelegate, &KeyboardFocusManager::OnWindowFocusChanged);
150       }
151     }
152
153     // Get notified when any new scene holder is created afterwards
154     Adaptor::Get().WindowCreatedSignal().Connect(mSlotDelegate, &KeyboardFocusManager::OnSceneHolderCreated);
155   }
156 }
157
158 void KeyboardFocusManager::OnSceneHolderCreated(Dali::Integration::SceneHolder& sceneHolder)
159 {
160   sceneHolder.KeyEventSignal().Connect(mSlotDelegate, &KeyboardFocusManager::OnKeyEvent);
161   sceneHolder.TouchedSignal().Connect(mSlotDelegate, &KeyboardFocusManager::OnTouch);
162   Dali::Window window = DevelWindow::DownCast(sceneHolder);
163   if(window)
164   {
165     window.FocusChangeSignal().Connect(mSlotDelegate, &KeyboardFocusManager::OnWindowFocusChanged);
166   }
167 }
168
169 KeyboardFocusManager::~KeyboardFocusManager()
170 {
171 }
172
173 void KeyboardFocusManager::GetConfigurationFromStyleManger()
174 {
175   Toolkit::StyleManager styleManager = Toolkit::StyleManager::Get();
176   if(styleManager)
177   {
178     Property::Map config   = Toolkit::DevelStyleManager::GetConfigurations(styleManager);
179     mAlwaysShowIndicator   = config["alwaysShowFocus"].Get<bool>() ? ALWAYS_SHOW : NONE;
180     mIsFocusIndicatorShown = (mAlwaysShowIndicator == ALWAYS_SHOW) ? SHOW : HIDE;
181     mClearFocusOnTouch     = (mIsFocusIndicatorShown == SHOW) ? false : true;
182   }
183 }
184
185 bool KeyboardFocusManager::SetCurrentFocusActor(Actor actor)
186 {
187   DALI_ASSERT_DEBUG(!mIsWaitingKeyboardFocusChangeCommit && "Calling this function in the PreFocusChangeSignal callback?");
188
189   if(mIsFocusIndicatorShown == UNKNOWN)
190   {
191     GetConfigurationFromStyleManger();
192   }
193
194   return DoSetCurrentFocusActor(actor);
195 }
196
197 bool KeyboardFocusManager::DoSetCurrentFocusActor(Actor actor)
198 {
199   bool success = false;
200   if(actor && actor.GetProperty<bool>(Actor::Property::KEYBOARD_FOCUSABLE) && actor.GetProperty<bool>(Actor::Property::CONNECTED_TO_SCENE))
201   {
202     Integration::SceneHolder currentWindow = Integration::SceneHolder::Get(actor);
203
204     if(currentWindow.GetRootLayer() != mCurrentFocusedWindow.GetHandle())
205     {
206       Layer rootLayer       = currentWindow.GetRootLayer();
207       mCurrentFocusedWindow = rootLayer;
208     }
209   }
210
211   Actor currentFocusedActor = GetCurrentFocusActor();
212
213   // If developer set focus on same actor, doing nothing
214   if(actor == currentFocusedActor)
215   {
216     if(!actor)
217     {
218       return false;
219     }
220     return true;
221   }
222
223   // Check whether the actor is in the stage and is keyboard focusable.
224   if(actor && actor.GetProperty<bool>(Actor::Property::KEYBOARD_FOCUSABLE) && actor.GetProperty<bool>(Actor::Property::CONNECTED_TO_SCENE))
225   {
226     if((mIsFocusIndicatorShown == SHOW) && (mEnableFocusIndicator == ENABLE))
227     {
228       actor.Add(GetFocusIndicatorActor());
229     }
230
231     // Send notification for the change of focus actor
232     if(!mFocusChangedSignal.Empty())
233     {
234       mFocusChangedSignal.Emit(currentFocusedActor, actor);
235     }
236
237     Toolkit::Control currentlyFocusedControl = Toolkit::Control::DownCast(currentFocusedActor);
238     if(currentlyFocusedControl)
239     {
240       // Do we need it to remember if it was previously DISABLED?
241       currentlyFocusedControl.SetProperty(DevelControl::Property::STATE, DevelControl::NORMAL);
242       currentlyFocusedControl.ClearKeyInputFocus();
243     }
244
245     DALI_LOG_INFO(gLogFilter, Debug::General, "[%s:%d] Focus Changed\n", __FUNCTION__, __LINE__);
246
247     // Save the current focused actor
248     mCurrentFocusActor = actor;
249
250     bool focusedWindowFound = false;
251     for(unsigned int i = 0; i < mCurrentFocusActors.size(); i++)
252     {
253       if(mCurrentFocusActors[i].first == mCurrentFocusedWindow)
254       {
255         mCurrentFocusActors[i].second = actor;
256         focusedWindowFound            = true;
257         break;
258       }
259     }
260     if(!focusedWindowFound)
261     {
262       // A new window gains the focus, so store the focused actor in that window.
263       mCurrentFocusActors.push_back(std::pair<WeakHandle<Layer>, WeakHandle<Actor> >(mCurrentFocusedWindow, actor));
264     }
265
266     Toolkit::Control newlyFocusedControl = Toolkit::Control::DownCast(actor);
267     if(newlyFocusedControl)
268     {
269       newlyFocusedControl.SetProperty(DevelControl::Property::STATE, DevelControl::FOCUSED);
270       newlyFocusedControl.SetKeyInputFocus();
271     }
272
273     // Push Current Focused Actor to FocusHistory
274     mFocusHistory.push_back(actor);
275
276     // Delete first element before add new element when Stack is full.
277     if(mFocusHistory.size() > MAX_HISTORY_AMOUNT)
278     {
279       FocusStackIterator beginPos = mFocusHistory.begin();
280       mFocusHistory.erase(beginPos);
281     }
282
283     DALI_LOG_INFO(gLogFilter, Debug::General, "[%s:%d] SUCCEED\n", __FUNCTION__, __LINE__);
284     success = true;
285   }
286   else
287   {
288     DALI_LOG_WARNING("[%s:%d] FAILED\n", __FUNCTION__, __LINE__);
289   }
290
291   return success;
292 }
293
294 Actor KeyboardFocusManager::GetCurrentFocusActor()
295 {
296   Actor actor = mCurrentFocusActor.GetHandle();
297
298   if(actor && !actor.GetProperty<bool>(Actor::Property::CONNECTED_TO_SCENE))
299   {
300     // If the actor has been removed from the stage, then it should not be focused
301     actor.Reset();
302     mCurrentFocusActor.Reset();
303   }
304   return actor;
305 }
306
307 Actor KeyboardFocusManager::GetFocusActorFromCurrentWindow()
308 {
309   Actor        actor;
310   unsigned int index;
311   for(index = 0; index < mCurrentFocusActors.size(); index++)
312   {
313     if(mCurrentFocusActors[index].first == mCurrentFocusedWindow)
314     {
315       actor = mCurrentFocusActors[index].second.GetHandle();
316       break;
317     }
318   }
319
320   if(actor && !actor.GetProperty<bool>(Actor::Property::CONNECTED_TO_SCENE))
321   {
322     // If the actor has been removed from the window, then the window doesn't have any focused actor
323     actor.Reset();
324     mCurrentFocusActors.erase(mCurrentFocusActors.begin() + index);
325   }
326
327   return actor;
328 }
329
330 Actor KeyboardFocusManager::GetCurrentFocusGroup()
331 {
332   return GetFocusGroup(GetCurrentFocusActor());
333 }
334
335 void KeyboardFocusManager::MoveFocusBackward()
336 {
337   // Find Pre Focused Actor when the list size is more than 1
338   if(mFocusHistory.size() > 1)
339   {
340     // Delete current focused actor in history
341     mFocusHistory.pop_back();
342
343     // If pre-focused actors are not on stage or deleted, remove them in stack
344     while(mFocusHistory.size() > 0)
345     {
346       // Get pre focused actor
347       Actor target = mFocusHistory[mFocusHistory.size() - 1].GetHandle();
348
349       // Impl of Actor is not null
350       if(target && target.GetProperty<bool>(Actor::Property::CONNECTED_TO_SCENE))
351       {
352         // Delete pre focused actor in history because it will pushed again by SetCurrentFocusActor()
353         mFocusHistory.pop_back();
354         SetCurrentFocusActor(target);
355         break;
356       }
357       else
358       {
359         // Target is empty handle or off stage. Erase from queue
360         mFocusHistory.pop_back();
361       }
362     }
363
364     // if there is no actor which can get focus, then push current focus actor in stack again
365     if(mFocusHistory.size() == 0)
366     {
367       Actor currentFocusedActor = GetCurrentFocusActor();
368       mFocusHistory.push_back(currentFocusedActor);
369     }
370   }
371 }
372
373 bool KeyboardFocusManager::IsLayoutControl(Actor actor) const
374 {
375   Toolkit::Control control = Toolkit::Control::DownCast(actor);
376   return control && GetImplementation(control).IsKeyboardNavigationSupported();
377 }
378
379 Toolkit::Control KeyboardFocusManager::GetParentLayoutControl(Actor actor) const
380 {
381   // Get the actor's parent layout control that supports two dimensional keyboard navigation
382   Actor rootActor;
383   Actor parent;
384   if(actor)
385   {
386     Integration::SceneHolder window = Integration::SceneHolder::Get(actor);
387     if(window)
388     {
389       rootActor = window.GetRootLayer();
390     }
391
392     parent = actor.GetParent();
393   }
394
395   while(parent && !IsLayoutControl(parent) && parent != rootActor)
396   {
397     parent = parent.GetParent();
398   }
399
400   return Toolkit::Control::DownCast(parent);
401 }
402
403 bool KeyboardFocusManager::MoveFocus(Toolkit::Control::KeyboardFocus::Direction direction)
404 {
405   Actor currentFocusActor = GetCurrentFocusActor();
406
407   bool succeed = false;
408
409   // Go through the actor's hierarchy until we find a layout control that knows how to move the focus
410   Toolkit::Control parentLayoutControl = GetParentLayoutControl(currentFocusActor);
411   while(parentLayoutControl && !succeed)
412   {
413     succeed             = DoMoveFocusWithinLayoutControl(parentLayoutControl, currentFocusActor, direction);
414     parentLayoutControl = GetParentLayoutControl(parentLayoutControl);
415   }
416
417   if(!succeed)
418   {
419     Actor nextFocusableActor;
420
421     Toolkit::Control currentFocusControl = Toolkit::Control::DownCast(currentFocusActor);
422
423     // If the current focused actor is a control, then find the next focusable actor via the focusable properties.
424     if(currentFocusControl)
425     {
426       int             actorId = -1;
427       Property::Index index   = Property::INVALID_INDEX;
428       Property::Value value;
429
430       // Find property index based upon focus direction
431       switch(direction)
432       {
433         case Toolkit::Control::KeyboardFocus::LEFT:
434         {
435           index = Toolkit::DevelControl::Property::LEFT_FOCUSABLE_ACTOR_ID;
436           break;
437         }
438         case Toolkit::Control::KeyboardFocus::RIGHT:
439         {
440           index = Toolkit::DevelControl::Property::RIGHT_FOCUSABLE_ACTOR_ID;
441           break;
442         }
443         case Toolkit::Control::KeyboardFocus::UP:
444         {
445           index = Toolkit::DevelControl::Property::UP_FOCUSABLE_ACTOR_ID;
446           break;
447         }
448         case Toolkit::Control::KeyboardFocus::DOWN:
449         {
450           index = Toolkit::DevelControl::Property::DOWN_FOCUSABLE_ACTOR_ID;
451           break;
452         }
453         default:
454           break;
455       }
456
457       // If the focusable property is set then determine next focusable actor
458       if(index != Property::INVALID_INDEX)
459       {
460         value   = currentFocusActor.GetProperty(index);
461         actorId = value.Get<int>();
462
463         // If actor's id is valid then find actor form actor's id. The actor should be on the stage.
464         if(actorId != -1)
465         {
466           if(currentFocusActor.GetParent())
467           {
468             nextFocusableActor = currentFocusActor.GetParent().FindChildById(actorId);
469           }
470
471           if(!nextFocusableActor)
472           {
473             Integration::SceneHolder window = Integration::SceneHolder::Get(currentFocusActor);
474             if(window)
475             {
476               nextFocusableActor = window.GetRootLayer().FindChildById(actorId);
477             }
478           }
479         }
480       }
481     }
482
483     if(!nextFocusableActor)
484     {
485       // If the implementation of CustomAlgorithmInterface is provided then the PreFocusChangeSignal is no longer emitted.
486       if(mCustomAlgorithmInterface)
487       {
488         mIsWaitingKeyboardFocusChangeCommit = true;
489         nextFocusableActor                  = mCustomAlgorithmInterface->GetNextFocusableActor(currentFocusActor, Actor(), direction);
490         mIsWaitingKeyboardFocusChangeCommit = false;
491       }
492       else if(!mPreFocusChangeSignal.Empty())
493       {
494         // Don't know how to move the focus further. The application needs to tell us which actor to move the focus to
495         mIsWaitingKeyboardFocusChangeCommit = true;
496         nextFocusableActor                  = mPreFocusChangeSignal.Emit(currentFocusActor, Actor(), direction);
497         mIsWaitingKeyboardFocusChangeCommit = false;
498       }
499       else
500       {
501         // We should find it among the actors nearby.
502         nextFocusableActor = Toolkit::FocusFinder::Get().GetNearestFocusableActor(currentFocusActor, direction);
503       }
504     }
505
506     if(nextFocusableActor && nextFocusableActor.GetProperty<bool>(Actor::Property::KEYBOARD_FOCUSABLE))
507     {
508       // Whether the next focusable actor is a layout control
509       if(IsLayoutControl(nextFocusableActor))
510       {
511         // If so, move the focus inside it.
512         Toolkit::Control layoutControl = Toolkit::Control::DownCast(nextFocusableActor);
513         succeed                        = DoMoveFocusWithinLayoutControl(layoutControl, currentFocusActor, direction);
514       }
515       else
516       {
517         // Otherwise, just set focus to the next focusable actor
518         succeed = SetCurrentFocusActor(nextFocusableActor);
519       }
520     }
521   }
522
523   return succeed;
524 }
525
526 bool KeyboardFocusManager::DoMoveFocusWithinLayoutControl(Toolkit::Control control, Actor actor, Toolkit::Control::KeyboardFocus::Direction direction)
527 {
528   // Ask the control for the next actor to focus
529   Actor nextFocusableActor = GetImplementation(control).GetNextKeyboardFocusableActor(actor, direction, mFocusGroupLoopEnabled);
530   if(nextFocusableActor)
531   {
532     if(!nextFocusableActor.GetProperty<bool>(Actor::Property::KEYBOARD_FOCUSABLE))
533     {
534       // If the actor is not focusable, ask the same layout control for the next actor to focus
535       return DoMoveFocusWithinLayoutControl(control, nextFocusableActor, direction);
536     }
537     else
538     {
539       Actor currentFocusActor   = GetCurrentFocusActor();
540       Actor committedFocusActor = nextFocusableActor;
541
542       // We will try to move the focus to the actor. Emit a signal to notify the proposed actor to focus
543       // Signal handler can check the proposed actor and return a different actor if it wishes.
544       if(!mPreFocusChangeSignal.Empty())
545       {
546         mIsWaitingKeyboardFocusChangeCommit = true;
547         committedFocusActor                 = mPreFocusChangeSignal.Emit(currentFocusActor, nextFocusableActor, direction);
548         mIsWaitingKeyboardFocusChangeCommit = false;
549       }
550
551       if(committedFocusActor && committedFocusActor.GetProperty<bool>(Actor::Property::KEYBOARD_FOCUSABLE))
552       {
553         // Whether the commited focusable actor is a layout control
554         if(IsLayoutControl(committedFocusActor))
555         {
556           // If so, move the focus inside it.
557           Toolkit::Control layoutControl = Toolkit::Control::DownCast(committedFocusActor);
558           return DoMoveFocusWithinLayoutControl(layoutControl, currentFocusActor, direction);
559         }
560         else
561         {
562           // Otherwise, just set focus to the next focusable actor
563           if(committedFocusActor == nextFocusableActor)
564           {
565             // If the application hasn't changed our proposed actor, we informs the layout control we will
566             // move the focus to what the control returns. The control might wish to perform some actions
567             // before the focus is actually moved.
568             GetImplementation(control).OnKeyboardFocusChangeCommitted(committedFocusActor);
569           }
570
571           return SetCurrentFocusActor(committedFocusActor);
572         }
573       }
574       else
575       {
576         return false;
577       }
578     }
579   }
580   else
581   {
582     // No more actor can be focused in the given direction within the same layout control.
583     return false;
584   }
585 }
586
587 bool KeyboardFocusManager::DoMoveFocusToNextFocusGroup(bool forward)
588 {
589   bool succeed = false;
590
591   // Get the parent layout control of the current focus group
592   Toolkit::Control parentLayoutControl = GetParentLayoutControl(GetCurrentFocusGroup());
593
594   while(parentLayoutControl && !succeed)
595   {
596     // If the current focus group has a parent layout control, we can probably automatically
597     // move the focus to the next focus group in the forward or backward direction.
598     Toolkit::Control::KeyboardFocus::Direction direction = forward ? Toolkit::Control::KeyboardFocus::RIGHT : Toolkit::Control::KeyboardFocus::LEFT;
599     succeed                                              = DoMoveFocusWithinLayoutControl(parentLayoutControl, GetCurrentFocusActor(), direction);
600     parentLayoutControl                                  = GetParentLayoutControl(parentLayoutControl);
601   }
602
603   if(!mFocusGroupChangedSignal.Empty())
604   {
605     // Emit a focus group changed signal. The applicaton can move the focus to a new focus group
606     mFocusGroupChangedSignal.Emit(GetCurrentFocusActor(), forward);
607   }
608
609   return succeed;
610 }
611
612 void KeyboardFocusManager::DoKeyboardEnter(Actor actor)
613 {
614   if(actor)
615   {
616     Toolkit::Control control = Toolkit::Control::DownCast(actor);
617     if(control)
618     {
619       // Notify the control that enter has been pressed on it.
620       GetImplementation(control).KeyboardEnter();
621     }
622
623     // Send a notification for the actor.
624     if(!mFocusedActorEnterKeySignal.Empty())
625     {
626       mFocusedActorEnterKeySignal.Emit(actor);
627     }
628   }
629 }
630
631 void KeyboardFocusManager::ClearFocus()
632 {
633   Actor actor = GetCurrentFocusActor();
634   if(actor)
635   {
636     if(mFocusIndicatorActor)
637     {
638       actor.Remove(mFocusIndicatorActor);
639     }
640
641     // Send notification for the change of focus actor
642     if(!mFocusChangedSignal.Empty())
643     {
644       mFocusChangedSignal.Emit(actor, Actor());
645     }
646
647     Toolkit::Control currentlyFocusedControl = Toolkit::Control::DownCast(actor);
648     if(currentlyFocusedControl)
649     {
650       currentlyFocusedControl.SetProperty(DevelControl::Property::STATE, DevelControl::NORMAL);
651       currentlyFocusedControl.ClearKeyInputFocus();
652     }
653   }
654
655   mCurrentFocusActor.Reset();
656   mIsFocusIndicatorShown = (mAlwaysShowIndicator == ALWAYS_SHOW) ? SHOW : HIDE;
657 }
658
659 void KeyboardFocusManager::SetFocusGroupLoop(bool enabled)
660 {
661   mFocusGroupLoopEnabled = enabled;
662 }
663
664 bool KeyboardFocusManager::GetFocusGroupLoop() const
665 {
666   return mFocusGroupLoopEnabled;
667 }
668
669 void KeyboardFocusManager::SetAsFocusGroup(Actor actor, bool isFocusGroup)
670 {
671   if(actor)
672   {
673     // Create/Set focus group property.
674     actor.RegisterProperty(IS_FOCUS_GROUP_PROPERTY_NAME, isFocusGroup, Property::READ_WRITE);
675   }
676 }
677
678 bool KeyboardFocusManager::IsFocusGroup(Actor actor) const
679 {
680   // Check whether the actor is a focus group
681   bool isFocusGroup = false;
682
683   if(actor)
684   {
685     Property::Index propertyIsFocusGroup = actor.GetPropertyIndex(IS_FOCUS_GROUP_PROPERTY_NAME);
686     if(propertyIsFocusGroup != Property::INVALID_INDEX)
687     {
688       isFocusGroup = actor.GetProperty<bool>(propertyIsFocusGroup);
689     }
690   }
691
692   return isFocusGroup;
693 }
694
695 Actor KeyboardFocusManager::GetFocusGroup(Actor actor)
696 {
697   // Go through the actor's hierarchy to check which focus group the actor belongs to
698   while(actor && !IsFocusGroup(actor))
699   {
700     actor = actor.GetParent();
701   }
702
703   return actor;
704 }
705
706 void KeyboardFocusManager::SetFocusIndicatorActor(Actor indicator)
707 {
708   if(mFocusIndicatorActor != indicator)
709   {
710     Actor currentFocusActor = GetCurrentFocusActor();
711     if(currentFocusActor)
712     {
713       // The new focus indicator should be added to the current focused actor immediately
714       if(mFocusIndicatorActor)
715       {
716         currentFocusActor.Remove(mFocusIndicatorActor);
717       }
718
719       if(indicator)
720       {
721         currentFocusActor.Add(indicator);
722       }
723     }
724
725     mFocusIndicatorActor = indicator;
726   }
727 }
728
729 Actor KeyboardFocusManager::GetFocusIndicatorActor()
730 {
731   if(!mFocusIndicatorActor)
732   {
733     // Create the default if it hasn't been set and one that's shared by all the keyboard focusable actors
734     const std::string imageDirPath = AssetManager::GetDaliImagePath();
735     mFocusIndicatorActor           = Toolkit::ImageView::New(imageDirPath + FOCUS_BORDER_IMAGE_FILE_NAME);
736
737     // Apply size constraint to the focus indicator
738     mFocusIndicatorActor.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS);
739   }
740
741   mFocusIndicatorActor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
742   mFocusIndicatorActor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
743   mFocusIndicatorActor.SetProperty(Actor::Property::POSITION, Vector2(0.0f, 0.0f));
744
745   return mFocusIndicatorActor;
746 }
747
748 void KeyboardFocusManager::OnKeyEvent(const KeyEvent& event)
749 {
750   std::string keyName = event.GetKeyName();
751
752   if(mIsFocusIndicatorShown == UNKNOWN)
753   {
754     GetConfigurationFromStyleManger();
755   }
756
757   bool isFocusStartableKey = false;
758
759   if(event.GetState() == KeyEvent::DOWN)
760   {
761     if(keyName == "Left")
762     {
763       if(!mIsFocusIndicatorShown)
764       {
765         if(mIsFocusIndicatorShown == HIDE)
766         {
767           // Show focus indicator
768           mIsFocusIndicatorShown = SHOW;
769         }
770         else
771         {
772           // Move the focus towards left
773           MoveFocus(Toolkit::Control::KeyboardFocus::LEFT);
774         }
775
776         isFocusStartableKey = true;
777       }
778       else
779       {
780         // Move the focus towards left
781         MoveFocus(Toolkit::Control::KeyboardFocus::LEFT);
782       }
783
784       isFocusStartableKey = true;
785     }
786     else if(keyName == "Right")
787     {
788       if(!mIsFocusIndicatorShown)
789       {
790         if(mIsFocusIndicatorShown == HIDE)
791         {
792           // Show focus indicator
793           mIsFocusIndicatorShown = SHOW;
794         }
795         else
796         {
797           // Move the focus towards right
798           MoveFocus(Toolkit::Control::KeyboardFocus::RIGHT);
799         }
800       }
801       else
802       {
803         // Move the focus towards right
804         MoveFocus(Toolkit::Control::KeyboardFocus::RIGHT);
805       }
806
807       isFocusStartableKey = true;
808     }
809     else if(keyName == "Up")
810     {
811       if(mIsFocusIndicatorShown == HIDE)
812       {
813         // Show focus indicator
814         mIsFocusIndicatorShown = SHOW;
815       }
816       else
817       {
818         // Move the focus towards up
819         MoveFocus(Toolkit::Control::KeyboardFocus::UP);
820       }
821
822       isFocusStartableKey = true;
823     }
824     else if(keyName == "Down")
825     {
826       if(mIsFocusIndicatorShown == HIDE)
827       {
828         // Show focus indicator
829         mIsFocusIndicatorShown = SHOW;
830       }
831       else
832       {
833         // Move the focus towards down
834         MoveFocus(Toolkit::Control::KeyboardFocus::DOWN);
835       }
836
837       isFocusStartableKey = true;
838     }
839     else if(keyName == "Prior")
840     {
841       if(mIsFocusIndicatorShown == HIDE)
842       {
843         // Show focus indicator
844         mIsFocusIndicatorShown = SHOW;
845       }
846       else
847       {
848         // Move the focus towards the previous page
849         MoveFocus(Toolkit::Control::KeyboardFocus::PAGE_UP);
850       }
851
852       isFocusStartableKey = true;
853     }
854     else if(keyName == "Next")
855     {
856       if(mIsFocusIndicatorShown == HIDE)
857       {
858         // Show focus indicator
859         mIsFocusIndicatorShown = SHOW;
860       }
861       else
862       {
863         // Move the focus towards the next page
864         MoveFocus(Toolkit::Control::KeyboardFocus::PAGE_DOWN);
865       }
866
867       isFocusStartableKey = true;
868     }
869     else if(keyName == "Tab")
870     {
871       if(mIsFocusIndicatorShown == HIDE)
872       {
873         // Show focus indicator
874         mIsFocusIndicatorShown = SHOW;
875       }
876       else
877       {
878         // "Tab" key changes the focus group in the forward direction and
879         // "Shift-Tab" key changes it in the backward direction.
880         DoMoveFocusToNextFocusGroup(!event.IsShiftModifier());
881       }
882
883       isFocusStartableKey = true;
884     }
885     else if(keyName == "space")
886     {
887       if(mIsFocusIndicatorShown == HIDE)
888       {
889         // Show focus indicator
890         mIsFocusIndicatorShown = SHOW;
891       }
892
893       isFocusStartableKey = true;
894     }
895     else if(keyName == "")
896     {
897       // Check the fake key event for evas-plugin case
898       if(mIsFocusIndicatorShown == HIDE)
899       {
900         // Show focus indicator
901         mIsFocusIndicatorShown = SHOW;
902       }
903
904       isFocusStartableKey = true;
905     }
906     else if(keyName == "Backspace")
907     {
908       // Emit signal to go back to the previous view???
909     }
910     else if(keyName == "Escape")
911     {
912     }
913   }
914   else if(event.GetState() == KeyEvent::UP)
915   {
916     if(keyName == "Return")
917     {
918       if(mIsFocusIndicatorShown == HIDE)
919       {
920         // Show focus indicator
921         mIsFocusIndicatorShown = SHOW;
922       }
923       else
924       {
925         // The focused actor has enter pressed on it
926         Actor actor = GetCurrentFocusActor();
927         if(actor)
928         {
929           DoKeyboardEnter(actor);
930         }
931       }
932
933       isFocusStartableKey = true;
934     }
935   }
936
937   if(isFocusStartableKey && mIsFocusIndicatorShown == SHOW)
938   {
939     Actor actor = GetCurrentFocusActor();
940     if(actor)
941     {
942       if(mEnableFocusIndicator == ENABLE)
943       {
944         // Make sure the focused actor is highlighted
945         actor.Add(GetFocusIndicatorActor());
946       }
947     }
948     else
949     {
950       // No actor is focused but keyboard focus is activated by the key press
951       // Let's try to move the initial focus
952       MoveFocus(Toolkit::Control::KeyboardFocus::RIGHT);
953     }
954   }
955 }
956
957 void KeyboardFocusManager::OnTouch(const TouchEvent& touch)
958 {
959   // if mIsFocusIndicatorShown is UNKNOWN, it means Configuration is not loaded.
960   // Try to load configuration.
961   if(mIsFocusIndicatorShown == UNKNOWN)
962   {
963     GetConfigurationFromStyleManger();
964   }
965
966   // Clear the focus when user touch the screen.
967   // We only do this on a Down event, otherwise the clear action may override a manually focused actor.
968   // If mClearFocusOnTouch is false, do not clear the focus even if user touch the screen.
969   if(((touch.GetPointCount() < 1) || (touch.GetState(0) == PointState::DOWN)) && mClearFocusOnTouch)
970   {
971     ClearFocus();
972   }
973 }
974
975 void KeyboardFocusManager::OnWindowFocusChanged(Window window, bool focusIn)
976 {
977   if(focusIn && mCurrentFocusedWindow.GetHandle() != window.GetRootLayer())
978   {
979     // Change Current Focused Window
980     Layer rootLayer       = window.GetRootLayer();
981     mCurrentFocusedWindow = rootLayer;
982
983     // Get Current Focused Actor from window
984     Actor currentFocusedActor = GetFocusActorFromCurrentWindow();
985     SetCurrentFocusActor(currentFocusedActor);
986
987     if(currentFocusedActor && (mEnableFocusIndicator == ENABLE))
988     {
989       // Make sure the focused actor is highlighted
990       currentFocusedActor.Add(GetFocusIndicatorActor());
991       mIsFocusIndicatorShown = SHOW;
992     }
993   }
994 }
995
996 Toolkit::KeyboardFocusManager::PreFocusChangeSignalType& KeyboardFocusManager::PreFocusChangeSignal()
997 {
998   return mPreFocusChangeSignal;
999 }
1000
1001 Toolkit::KeyboardFocusManager::FocusChangedSignalType& KeyboardFocusManager::FocusChangedSignal()
1002 {
1003   return mFocusChangedSignal;
1004 }
1005
1006 Toolkit::KeyboardFocusManager::FocusGroupChangedSignalType& KeyboardFocusManager::FocusGroupChangedSignal()
1007 {
1008   return mFocusGroupChangedSignal;
1009 }
1010
1011 Toolkit::KeyboardFocusManager::FocusedActorEnterKeySignalType& KeyboardFocusManager::FocusedActorEnterKeySignal()
1012 {
1013   return mFocusedActorEnterKeySignal;
1014 }
1015
1016 bool KeyboardFocusManager::DoConnectSignal(BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor)
1017 {
1018   Dali::BaseHandle handle(object);
1019
1020   bool                  connected(true);
1021   KeyboardFocusManager* manager = static_cast<KeyboardFocusManager*>(object); // TypeRegistry guarantees that this is the correct type.
1022
1023   if(0 == strcmp(signalName.c_str(), SIGNAL_PRE_FOCUS_CHANGE))
1024   {
1025     manager->PreFocusChangeSignal().Connect(tracker, functor);
1026   }
1027   else if(0 == strcmp(signalName.c_str(), SIGNAL_FOCUS_CHANGED))
1028   {
1029     manager->FocusChangedSignal().Connect(tracker, functor);
1030   }
1031   else if(0 == strcmp(signalName.c_str(), SIGNAL_FOCUS_GROUP_CHANGED))
1032   {
1033     manager->FocusGroupChangedSignal().Connect(tracker, functor);
1034   }
1035   else if(0 == strcmp(signalName.c_str(), SIGNAL_FOCUSED_ACTOR_ENTER_KEY))
1036   {
1037     manager->FocusedActorEnterKeySignal().Connect(tracker, functor);
1038   }
1039   else
1040   {
1041     // signalName does not match any signal
1042     connected = false;
1043   }
1044
1045   return connected;
1046 }
1047
1048 void KeyboardFocusManager::SetCustomAlgorithm(CustomAlgorithmInterface& interface)
1049 {
1050   mCustomAlgorithmInterface = &interface;
1051 }
1052
1053 void KeyboardFocusManager::EnableFocusIndicator(bool enable)
1054 {
1055   if(!enable && mFocusIndicatorActor)
1056   {
1057     mFocusIndicatorActor.Unparent();
1058   }
1059
1060   mEnableFocusIndicator = enable ? ENABLE : DISABLE;
1061 }
1062
1063 bool KeyboardFocusManager::IsFocusIndicatorEnabled() const
1064 {
1065   return (mEnableFocusIndicator == ENABLE);
1066 }
1067
1068 } // namespace Internal
1069
1070 } // namespace Toolkit
1071
1072 } // namespace Dali