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