X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=dali-toolkit%2Finternal%2Ffocus-manager%2Fkeyboard-focus-manager-impl.cpp;h=a950b35c9cf7eafa42a9397ac6d5aaa45d804976;hb=aefac7b91818861d25e2312ea4b63d2deb1a9a86;hp=7b1d9290898ecf3b41a19e8f4f3b66d0305b9ff6;hpb=e2eda444afbe82e9591fe198eef339227f90a616;p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git diff --git a/dali-toolkit/internal/focus-manager/keyboard-focus-manager-impl.cpp b/dali-toolkit/internal/focus-manager/keyboard-focus-manager-impl.cpp index 7b1d929..c03b7dd 100644 --- a/dali-toolkit/internal/focus-manager/keyboard-focus-manager-impl.cpp +++ b/dali-toolkit/internal/focus-manager/keyboard-focus-manager-impl.cpp @@ -1,64 +1,94 @@ -// -// Copyright (c) 2014 Samsung Electronics Co., Ltd. -// -// Licensed under the Flora License, Version 1.0 (the License); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://floralicense.org/license/ -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an AS IS BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ // CLASS HEADER #include "keyboard-focus-manager-impl.h" +// EXTERNAL INCLUDES +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // for strcmp + // INTERNAL INCLUDES -#include +#include +#include +#include +#include #include -#include -#include -#include +#include +#include +#include +#include namespace Dali { - namespace Toolkit { - namespace Internal { - -namespace // unnamed namespace +namespace // Unnamed namespace { - #if defined(DEBUG_ENABLED) Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_KEYBOARD_FOCUS_MANAGER"); #endif -const std::string IS_FOCUS_GROUP_PROPERTY_NAME("is-keyboard-focus-group"); // This property will be replaced by a flag in ControlImpl. +const char* const IS_FOCUS_GROUP_PROPERTY_NAME = "isKeyboardFocusGroup"; // This property will be replaced by a flag in Control. -const char* FOCUS_BORDER_IMAGE_PATH = DALI_IMAGE_DIR "keyboard_focus.png"; -const Vector4 FOCUS_BORDER_IMAGE_BORDER = Vector4(7.0f, 7.0f, 7.0f, 7.0f); +const char* const FOCUS_BORDER_IMAGE_FILE_NAME = "keyboard_focus.9.png"; BaseHandle Create() { BaseHandle handle = KeyboardFocusManager::Get(); - if ( !handle && Adaptor::IsAvailable() ) + if(!handle) { - Toolkit::KeyboardFocusManager manager = Toolkit::KeyboardFocusManager( new Internal::KeyboardFocusManager() ); - Adaptor::Get().RegisterSingleton( typeid( manager ), manager ); - handle = manager; + SingletonService singletonService(SingletonService::Get()); + if(singletonService) + { + Toolkit::KeyboardFocusManager manager = Toolkit::KeyboardFocusManager(new Internal::KeyboardFocusManager()); + singletonService.Register(typeid(manager), manager); + handle = manager; + } } return handle; } -TypeRegistration KEYBOARD_FOCUS_MANAGER_TYPE( typeid(Dali::Toolkit::KeyboardFocusManager), typeid(Dali::BaseHandle), Create, true /* Create instance at startup */ ); + +DALI_TYPE_REGISTRATION_BEGIN_CREATE(Toolkit::KeyboardFocusManager, Dali::BaseHandle, Create, true) + +DALI_SIGNAL_REGISTRATION(Toolkit, KeyboardFocusManager, "keyboardPreFocusChange", SIGNAL_PRE_FOCUS_CHANGE) +DALI_SIGNAL_REGISTRATION(Toolkit, KeyboardFocusManager, "keyboardFocusChanged", SIGNAL_FOCUS_CHANGED) +DALI_SIGNAL_REGISTRATION(Toolkit, KeyboardFocusManager, "keyboardFocusGroupChanged", SIGNAL_FOCUS_GROUP_CHANGED) +DALI_SIGNAL_REGISTRATION(Toolkit, KeyboardFocusManager, "keyboardFocusedActorEnterKey", SIGNAL_FOCUSED_ACTOR_ENTER_KEY) + +DALI_TYPE_REGISTRATION_END() + +const unsigned int MAX_HISTORY_AMOUNT = 30; ///< Max length of focus history stack } // unnamed namespace @@ -66,14 +96,15 @@ Toolkit::KeyboardFocusManager KeyboardFocusManager::Get() { Toolkit::KeyboardFocusManager manager; - if ( Adaptor::IsAvailable() ) + SingletonService singletonService(SingletonService::Get()); + if(singletonService) { // Check whether the keyboard focus manager is already created - Dali::BaseHandle handle = Dali::Adaptor::Get().GetSingleton( typeid( Toolkit::KeyboardFocusManager ) ); + Dali::BaseHandle handle = singletonService.GetSingleton(typeid(Toolkit::KeyboardFocusManager)); if(handle) { // If so, downcast the handle of singleton to keyboard focus manager - manager = Toolkit::KeyboardFocusManager( dynamic_cast< KeyboardFocusManager* >( handle.GetObjectPtr() ) ); + manager = Toolkit::KeyboardFocusManager(dynamic_cast(handle.GetObjectPtr())); } } @@ -81,84 +112,220 @@ Toolkit::KeyboardFocusManager KeyboardFocusManager::Get() } KeyboardFocusManager::KeyboardFocusManager() -: mCurrentFocusActor(0), - mFocusIndicatorActor(Actor()), +: mPreFocusChangeSignal(), + mFocusChangedSignal(), + mFocusGroupChangedSignal(), + mFocusedActorEnterKeySignal(), + mCurrentFocusActor(), + mFocusIndicatorActor(), + mFocusHistory(), + mSlotDelegate(this), + mCustomAlgorithmInterface(NULL), + mCurrentFocusedWindow(), + mIsFocusIndicatorShown(UNKNOWN), + mEnableFocusIndicator(ENABLE), + mAlwaysShowIndicator(ALWAYS_SHOW), mFocusGroupLoopEnabled(false), - mIsKeyboardFocusEnabled(false), - mIsFocusIndicatorEnabled(false), mIsWaitingKeyboardFocusChangeCommit(false), - mSlotDelegate(this) + mClearFocusOnTouch(true) +{ + // TODO: Get FocusIndicatorEnable constant from stylesheet to set mIsFocusIndicatorShown. + + LifecycleController::Get().InitSignal().Connect(mSlotDelegate, &KeyboardFocusManager::OnAdaptorInit); +} + +void KeyboardFocusManager::OnAdaptorInit() { - CreateDefaultFocusIndicatorActor(); + if(Adaptor::IsAvailable()) + { + // Retrieve all the existing scene holders + Dali::SceneHolderList sceneHolders = Adaptor::Get().GetSceneHolders(); + for(auto iter = sceneHolders.begin(); iter != sceneHolders.end(); ++iter) + { + (*iter).KeyEventSignal().Connect(mSlotDelegate, &KeyboardFocusManager::OnKeyEvent); + (*iter).TouchedSignal().Connect(mSlotDelegate, &KeyboardFocusManager::OnTouch); + Dali::Window window = DevelWindow::DownCast(*iter); + if(window) + { + window.FocusChangeSignal().Connect(mSlotDelegate, &KeyboardFocusManager::OnWindowFocusChanged); + } + } - OnPhysicalKeyboardStatusChanged(PhysicalKeyboard::Get()); + // Get notified when any new scene holder is created afterwards + Adaptor::Get().WindowCreatedSignal().Connect(mSlotDelegate, &KeyboardFocusManager::OnSceneHolderCreated); + } +} - Toolkit::KeyInputFocusManager::Get().UnhandledKeyEventSignal().Connect(mSlotDelegate, &KeyboardFocusManager::OnKeyEvent); - Stage::GetCurrent().TouchedSignal().Connect(mSlotDelegate, &KeyboardFocusManager::OnTouched); - PhysicalKeyboard::Get().StatusChangedSignal().Connect(mSlotDelegate, &KeyboardFocusManager::OnPhysicalKeyboardStatusChanged); +void KeyboardFocusManager::OnSceneHolderCreated(Dali::Integration::SceneHolder& sceneHolder) +{ + sceneHolder.KeyEventSignal().Connect(mSlotDelegate, &KeyboardFocusManager::OnKeyEvent); + sceneHolder.TouchedSignal().Connect(mSlotDelegate, &KeyboardFocusManager::OnTouch); + Dali::Window window = DevelWindow::DownCast(sceneHolder); + if(window) + { + window.FocusChangeSignal().Connect(mSlotDelegate, &KeyboardFocusManager::OnWindowFocusChanged); + } } KeyboardFocusManager::~KeyboardFocusManager() { } +void KeyboardFocusManager::GetConfigurationFromStyleManger() +{ + Toolkit::StyleManager styleManager = Toolkit::StyleManager::Get(); + if(styleManager) + { + Property::Map config = Toolkit::DevelStyleManager::GetConfigurations(styleManager); + mAlwaysShowIndicator = config["alwaysShowFocus"].Get() ? ALWAYS_SHOW : NONE; + mIsFocusIndicatorShown = (mAlwaysShowIndicator == ALWAYS_SHOW) ? SHOW : HIDE; + mClearFocusOnTouch = (mIsFocusIndicatorShown == SHOW) ? false : true; + } +} + bool KeyboardFocusManager::SetCurrentFocusActor(Actor actor) { - DALI_ASSERT_DEBUG( !mIsWaitingKeyboardFocusChangeCommit && "Calling this function in the PreFocusChangeSignal callback?" ); + DALI_ASSERT_DEBUG(!mIsWaitingKeyboardFocusChangeCommit && "Calling this function in the PreFocusChangeSignal callback?"); - if(actor) + if(mIsFocusIndicatorShown == UNKNOWN) { - return DoSetCurrentFocusActor(actor.GetId()); + GetConfigurationFromStyleManger(); } - return false; + return DoSetCurrentFocusActor(actor); } -bool KeyboardFocusManager::DoSetCurrentFocusActor(const unsigned int actorID) +bool KeyboardFocusManager::DoSetCurrentFocusActor(Actor actor) { - Actor rootActor = Stage::GetCurrent().GetRootLayer(); - Actor actor = rootActor.FindChildById(actorID); + bool success = false; + if(actor && actor.GetProperty(Actor::Property::KEYBOARD_FOCUSABLE) && actor.GetProperty(Actor::Property::CONNECTED_TO_SCENE)) + { + Integration::SceneHolder currentWindow = Integration::SceneHolder::Get(actor); - // Check whether the actor is in the stage - if(actor) + if(currentWindow.GetRootLayer() != mCurrentFocusedWindow.GetHandle()) + { + Layer rootLayer = currentWindow.GetRootLayer(); + mCurrentFocusedWindow = rootLayer; + } + } + + Actor currentFocusedActor = GetCurrentFocusActor(); + + // If developer set focus on same actor, doing nothing + if(actor == currentFocusedActor) { - // Set the focus only when the actor is keyboard focusable - if(actor.IsKeyboardFocusable()) + if(!actor) { - // Draw the focus indicator upon the focused actor - if(mIsFocusIndicatorEnabled && mFocusIndicatorActor) - { - actor.Add(mFocusIndicatorActor); - } + return false; + } + return true; + } + + // Check whether the actor is in the stage and is keyboard focusable. + if(actor && actor.GetProperty(Actor::Property::KEYBOARD_FOCUSABLE) && actor.GetProperty(Actor::Property::CONNECTED_TO_SCENE)) + { + if((mIsFocusIndicatorShown == SHOW) && (mEnableFocusIndicator == ENABLE)) + { + actor.Add(GetFocusIndicatorActor()); + } + + // Send notification for the change of focus actor + if(!mFocusChangedSignal.Empty()) + { + mFocusChangedSignal.Emit(currentFocusedActor, actor); + } - // Send notification for the change of focus actor - if( !mFocusChangedSignalV2.Empty() ) + Toolkit::Control currentlyFocusedControl = Toolkit::Control::DownCast(currentFocusedActor); + if(currentlyFocusedControl) + { + // Do we need it to remember if it was previously DISABLED? + currentlyFocusedControl.SetProperty(DevelControl::Property::STATE, DevelControl::NORMAL); + currentlyFocusedControl.ClearKeyInputFocus(); + } + + DALI_LOG_INFO(gLogFilter, Debug::General, "[%s:%d] Focus Changed\n", __FUNCTION__, __LINE__); + + // Save the current focused actor + mCurrentFocusActor = actor; + + bool focusedWindowFound = false; + for(unsigned int i = 0; i < mCurrentFocusActors.size(); i++) + { + if(mCurrentFocusActors[i].first == mCurrentFocusedWindow) { - mFocusChangedSignalV2.Emit(GetCurrentFocusActor(), actor); + mCurrentFocusActors[i].second = actor; + focusedWindowFound = true; + break; } + } + if(!focusedWindowFound) + { + // A new window gains the focus, so store the focused actor in that window. + mCurrentFocusActors.push_back(std::pair, WeakHandle >(mCurrentFocusedWindow, actor)); + } - DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] Focus Changed\n", __FUNCTION__, __LINE__); - - // Save the current focused actor - mCurrentFocusActor = actorID; + Toolkit::Control newlyFocusedControl = Toolkit::Control::DownCast(actor); + if(newlyFocusedControl) + { + newlyFocusedControl.SetProperty(DevelControl::Property::STATE, DevelControl::FOCUSED); + newlyFocusedControl.SetKeyInputFocus(); + } - // Move the accessibility focus to the same actor -// Toolkit::FocusManager focusManager = Toolkit::FocusManager::Get(); -// focusManager.SetCurrentFocusActor(actor); + // Push Current Focused Actor to FocusHistory + mFocusHistory.push_back(actor); - DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] SUCCEED\n", __FUNCTION__, __LINE__); - return true; + // Delete first element before add new element when Stack is full. + if(mFocusHistory.size() > MAX_HISTORY_AMOUNT) + { + FocusStackIterator beginPos = mFocusHistory.begin(); + mFocusHistory.erase(beginPos); } + + DALI_LOG_INFO(gLogFilter, Debug::General, "[%s:%d] SUCCEED\n", __FUNCTION__, __LINE__); + success = true; + } + else + { + DALI_LOG_WARNING("[%s:%d] FAILED\n", __FUNCTION__, __LINE__); } - DALI_LOG_WARNING("[%s:%d] FAILED\n", __FUNCTION__, __LINE__); - return false; + return success; } Actor KeyboardFocusManager::GetCurrentFocusActor() { - Actor rootActor = Stage::GetCurrent().GetRootLayer(); - return rootActor.FindChildById(mCurrentFocusActor); + Actor actor = mCurrentFocusActor.GetHandle(); + + if(actor && !actor.GetProperty(Actor::Property::CONNECTED_TO_SCENE)) + { + // If the actor has been removed from the stage, then it should not be focused + actor.Reset(); + mCurrentFocusActor.Reset(); + } + return actor; +} + +Actor KeyboardFocusManager::GetFocusActorFromCurrentWindow() +{ + Actor actor; + unsigned int index; + for(index = 0; index < mCurrentFocusActors.size(); index++) + { + if(mCurrentFocusActors[index].first == mCurrentFocusedWindow) + { + actor = mCurrentFocusActors[index].second.GetHandle(); + break; + } + } + + if(actor && !actor.GetProperty(Actor::Property::CONNECTED_TO_SCENE)) + { + // If the actor has been removed from the window, then the window doesn't have any focused actor + actor.Reset(); + mCurrentFocusActors.erase(mCurrentFocusActors.begin() + index); + } + + return actor; } Actor KeyboardFocusManager::GetCurrentFocusGroup() @@ -166,23 +333,67 @@ Actor KeyboardFocusManager::GetCurrentFocusGroup() return GetFocusGroup(GetCurrentFocusActor()); } +void KeyboardFocusManager::MoveFocusBackward() +{ + // Find Pre Focused Actor when the list size is more than 1 + if(mFocusHistory.size() > 1) + { + // Delete current focused actor in history + mFocusHistory.pop_back(); + + // If pre-focused actors are not on stage or deleted, remove them in stack + while(mFocusHistory.size() > 0) + { + // Get pre focused actor + Actor target = mFocusHistory[mFocusHistory.size() - 1].GetHandle(); + + // Impl of Actor is not null + if(target && target.GetProperty(Actor::Property::CONNECTED_TO_SCENE)) + { + // Delete pre focused actor in history because it will pushed again by SetCurrentFocusActor() + mFocusHistory.pop_back(); + SetCurrentFocusActor(target); + break; + } + else + { + // Target is empty handle or off stage. Erase from queue + mFocusHistory.pop_back(); + } + } + + // if there is no actor which can get focus, then push current focus actor in stack again + if(mFocusHistory.size() == 0) + { + Actor currentFocusedActor = GetCurrentFocusActor(); + mFocusHistory.push_back(currentFocusedActor); + } + } +} + bool KeyboardFocusManager::IsLayoutControl(Actor actor) const { Toolkit::Control control = Toolkit::Control::DownCast(actor); - return control && control.GetImplementation().IsKeyboardNavigationSupported(); + return control && GetImplementation(control).IsKeyboardNavigationSupported(); } Toolkit::Control KeyboardFocusManager::GetParentLayoutControl(Actor actor) const { // Get the actor's parent layout control that supports two dimensional keyboard navigation - Actor rootActor = Stage::GetCurrent().GetRootLayer(); + Actor rootActor; Actor parent; if(actor) { + Integration::SceneHolder window = Integration::SceneHolder::Get(actor); + if(window) + { + rootActor = window.GetRootLayer(); + } + parent = actor.GetParent(); } - while( parent && !IsLayoutControl(parent) && parent != rootActor ) + while(parent && !IsLayoutControl(parent) && parent != rootActor) { parent = parent.GetParent(); } @@ -190,7 +401,7 @@ Toolkit::Control KeyboardFocusManager::GetParentLayoutControl(Actor actor) const return Toolkit::Control::DownCast(parent); } -bool KeyboardFocusManager::MoveFocus(Toolkit::Control::KeyboardFocusNavigationDirection direction) +bool KeyboardFocusManager::MoveFocus(Toolkit::Control::KeyboardFocus::Direction direction) { Actor currentFocusActor = GetCurrentFocusActor(); @@ -200,25 +411,107 @@ bool KeyboardFocusManager::MoveFocus(Toolkit::Control::KeyboardFocusNavigationDi Toolkit::Control parentLayoutControl = GetParentLayoutControl(currentFocusActor); while(parentLayoutControl && !succeed) { - succeed = DoMoveFocusWithinLayoutControl(parentLayoutControl, currentFocusActor, direction); + succeed = DoMoveFocusWithinLayoutControl(parentLayoutControl, currentFocusActor, direction); parentLayoutControl = GetParentLayoutControl(parentLayoutControl); } - if(!succeed && !mPreFocusChangeSignalV2.Empty()) + if(!succeed) { - // Don't know how to move the focus further. The application needs to tell us which actor to move the focus to - mIsWaitingKeyboardFocusChangeCommit = true; - Actor nextFocusableActor = mPreFocusChangeSignalV2.Emit(currentFocusActor, Actor(), direction); - mIsWaitingKeyboardFocusChangeCommit = false; + Actor nextFocusableActor; + + Toolkit::Control currentFocusControl = Toolkit::Control::DownCast(currentFocusActor); + + // If the current focused actor is a control, then find the next focusable actor via the focusable properties. + if(currentFocusControl) + { + int actorId = -1; + Property::Index index = Property::INVALID_INDEX; + Property::Value value; + + // Find property index based upon focus direction + switch(direction) + { + case Toolkit::Control::KeyboardFocus::LEFT: + { + index = Toolkit::DevelControl::Property::LEFT_FOCUSABLE_ACTOR_ID; + break; + } + case Toolkit::Control::KeyboardFocus::RIGHT: + { + index = Toolkit::DevelControl::Property::RIGHT_FOCUSABLE_ACTOR_ID; + break; + } + case Toolkit::Control::KeyboardFocus::UP: + { + index = Toolkit::DevelControl::Property::UP_FOCUSABLE_ACTOR_ID; + break; + } + case Toolkit::Control::KeyboardFocus::DOWN: + { + index = Toolkit::DevelControl::Property::DOWN_FOCUSABLE_ACTOR_ID; + break; + } + default: + break; + } + + // If the focusable property is set then determine next focusable actor + if(index != Property::INVALID_INDEX) + { + value = currentFocusActor.GetProperty(index); + actorId = value.Get(); + + // If actor's id is valid then find actor form actor's id. The actor should be on the stage. + if(actorId != -1) + { + if(currentFocusActor.GetParent()) + { + nextFocusableActor = currentFocusActor.GetParent().FindChildById(actorId); + } + + if(!nextFocusableActor) + { + Integration::SceneHolder window = Integration::SceneHolder::Get(currentFocusActor); + if(window) + { + nextFocusableActor = window.GetRootLayer().FindChildById(actorId); + } + } + } + } + } + + if(!nextFocusableActor) + { + // If the implementation of CustomAlgorithmInterface is provided then the PreFocusChangeSignal is no longer emitted. + if(mCustomAlgorithmInterface) + { + mIsWaitingKeyboardFocusChangeCommit = true; + nextFocusableActor = mCustomAlgorithmInterface->GetNextFocusableActor(currentFocusActor, Actor(), direction); + mIsWaitingKeyboardFocusChangeCommit = false; + } + else if(!mPreFocusChangeSignal.Empty()) + { + // Don't know how to move the focus further. The application needs to tell us which actor to move the focus to + mIsWaitingKeyboardFocusChangeCommit = true; + nextFocusableActor = mPreFocusChangeSignal.Emit(currentFocusActor, Actor(), direction); + mIsWaitingKeyboardFocusChangeCommit = false; + } + else + { + // We should find it among the actors nearby. + nextFocusableActor = Toolkit::FocusFinder::GetNearestFocusableActor(currentFocusActor, direction); + } + } - if ( nextFocusableActor && nextFocusableActor.IsKeyboardFocusable() ) + if(nextFocusableActor && nextFocusableActor.GetProperty(Actor::Property::KEYBOARD_FOCUSABLE)) { // Whether the next focusable actor is a layout control if(IsLayoutControl(nextFocusableActor)) { // If so, move the focus inside it. Toolkit::Control layoutControl = Toolkit::Control::DownCast(nextFocusableActor); - succeed = DoMoveFocusWithinLayoutControl(layoutControl, currentFocusActor, direction); + succeed = DoMoveFocusWithinLayoutControl(layoutControl, currentFocusActor, direction); } else { @@ -231,32 +524,32 @@ bool KeyboardFocusManager::MoveFocus(Toolkit::Control::KeyboardFocusNavigationDi return succeed; } -bool KeyboardFocusManager::DoMoveFocusWithinLayoutControl(Toolkit::Control control, Actor actor, Toolkit::Control::KeyboardFocusNavigationDirection direction) +bool KeyboardFocusManager::DoMoveFocusWithinLayoutControl(Toolkit::Control control, Actor actor, Toolkit::Control::KeyboardFocus::Direction direction) { // Ask the control for the next actor to focus - Actor nextFocusableActor = control.GetImplementation().GetNextKeyboardFocusableActor(actor, direction, mFocusGroupLoopEnabled); + Actor nextFocusableActor = GetImplementation(control).GetNextKeyboardFocusableActor(actor, direction, mFocusGroupLoopEnabled); if(nextFocusableActor) { - if(!nextFocusableActor.IsKeyboardFocusable()) + if(!nextFocusableActor.GetProperty(Actor::Property::KEYBOARD_FOCUSABLE)) { // If the actor is not focusable, ask the same layout control for the next actor to focus return DoMoveFocusWithinLayoutControl(control, nextFocusableActor, direction); } else { - Actor currentFocusActor = GetCurrentFocusActor(); + Actor currentFocusActor = GetCurrentFocusActor(); Actor committedFocusActor = nextFocusableActor; // We will try to move the focus to the actor. Emit a signal to notify the proposed actor to focus // Signal handler can check the proposed actor and return a different actor if it wishes. - if( !mPreFocusChangeSignalV2.Empty() ) + if(!mPreFocusChangeSignal.Empty()) { mIsWaitingKeyboardFocusChangeCommit = true; - committedFocusActor = mPreFocusChangeSignalV2.Emit(currentFocusActor, nextFocusableActor, direction); + committedFocusActor = mPreFocusChangeSignal.Emit(currentFocusActor, nextFocusableActor, direction); mIsWaitingKeyboardFocusChangeCommit = false; } - if (committedFocusActor && committedFocusActor.IsKeyboardFocusable()) + if(committedFocusActor && committedFocusActor.GetProperty(Actor::Property::KEYBOARD_FOCUSABLE)) { // Whether the commited focusable actor is a layout control if(IsLayoutControl(committedFocusActor)) @@ -273,7 +566,7 @@ bool KeyboardFocusManager::DoMoveFocusWithinLayoutControl(Toolkit::Control contr // If the application hasn't changed our proposed actor, we informs the layout control we will // move the focus to what the control returns. The control might wish to perform some actions // before the focus is actually moved. - control.GetImplementation().OnKeyboardFocusChangeCommitted(committedFocusActor); + GetImplementation(control).OnKeyboardFocusChangeCommitted(committedFocusActor); } return SetCurrentFocusActor(committedFocusActor); @@ -303,35 +596,35 @@ bool KeyboardFocusManager::DoMoveFocusToNextFocusGroup(bool forward) { // If the current focus group has a parent layout control, we can probably automatically // move the focus to the next focus group in the forward or backward direction. - Toolkit::Control::KeyboardFocusNavigationDirection direction = forward ? Toolkit::Control::Right : Toolkit::Control::Left; - succeed = DoMoveFocusWithinLayoutControl(parentLayoutControl, GetCurrentFocusActor(), direction); - parentLayoutControl = GetParentLayoutControl(parentLayoutControl); + Toolkit::Control::KeyboardFocus::Direction direction = forward ? Toolkit::Control::KeyboardFocus::RIGHT : Toolkit::Control::KeyboardFocus::LEFT; + succeed = DoMoveFocusWithinLayoutControl(parentLayoutControl, GetCurrentFocusActor(), direction); + parentLayoutControl = GetParentLayoutControl(parentLayoutControl); } - if(!mFocusGroupChangedSignalV2.Empty()) + if(!mFocusGroupChangedSignal.Empty()) { // Emit a focus group changed signal. The applicaton can move the focus to a new focus group - mFocusGroupChangedSignalV2.Emit(GetCurrentFocusActor(), forward); + mFocusGroupChangedSignal.Emit(GetCurrentFocusActor(), forward); } return succeed; } -void KeyboardFocusManager::DoActivate(Actor actor) +void KeyboardFocusManager::DoKeyboardEnter(Actor actor) { if(actor) { Toolkit::Control control = Toolkit::Control::DownCast(actor); if(control) { - // Notify the control that it is activated - control.GetImplementation().OnActivated(); + // Notify the control that enter has been pressed on it. + GetImplementation(control).KeyboardEnter(); } - // Send notification for the activation of focused actor - if( !mFocusedActorActivatedSignalV2.Empty() ) + // Send a notification for the actor. + if(!mFocusedActorEnterKeySignal.Empty()) { - mFocusedActorActivatedSignalV2.Emit(actor); + mFocusedActorEnterKeySignal.Emit(actor); } } } @@ -341,17 +634,27 @@ void KeyboardFocusManager::ClearFocus() Actor actor = GetCurrentFocusActor(); if(actor) { - actor.Remove(mFocusIndicatorActor); + if(mFocusIndicatorActor) + { + actor.Remove(mFocusIndicatorActor); + } // Send notification for the change of focus actor - if( !mFocusChangedSignalV2.Empty() ) + if(!mFocusChangedSignal.Empty()) + { + mFocusChangedSignal.Emit(actor, Actor()); + } + + Toolkit::Control currentlyFocusedControl = Toolkit::Control::DownCast(actor); + if(currentlyFocusedControl) { - mFocusChangedSignalV2.Emit(actor, Actor()); + currentlyFocusedControl.SetProperty(DevelControl::Property::STATE, DevelControl::NORMAL); + currentlyFocusedControl.ClearKeyInputFocus(); } } - mCurrentFocusActor = 0; - mIsFocusIndicatorEnabled = false; + mCurrentFocusActor.Reset(); + mIsFocusIndicatorShown = (mAlwaysShowIndicator == ALWAYS_SHOW) ? SHOW : HIDE; } void KeyboardFocusManager::SetFocusGroupLoop(bool enabled) @@ -368,16 +671,8 @@ void KeyboardFocusManager::SetAsFocusGroup(Actor actor, bool isFocusGroup) { if(actor) { - // Create focus group property if not already created. - Property::Index propertyIsFocusGroup = actor.GetPropertyIndex(IS_FOCUS_GROUP_PROPERTY_NAME); - if(propertyIsFocusGroup == Property::INVALID_INDEX) - { - propertyIsFocusGroup = actor.RegisterProperty(IS_FOCUS_GROUP_PROPERTY_NAME, isFocusGroup); - } - else - { - actor.SetProperty(propertyIsFocusGroup, isFocusGroup); - } + // Create/Set focus group property. + actor.RegisterProperty(IS_FOCUS_GROUP_PROPERTY_NAME, isFocusGroup, Property::READ_WRITE); } } @@ -401,7 +696,7 @@ bool KeyboardFocusManager::IsFocusGroup(Actor actor) const Actor KeyboardFocusManager::GetFocusGroup(Actor actor) { // Go through the actor's hierarchy to check which focus group the actor belongs to - while (actor && !IsFocusGroup(actor)) + while(actor && !IsFocusGroup(actor)) { actor = actor.GetParent(); } @@ -411,226 +706,236 @@ Actor KeyboardFocusManager::GetFocusGroup(Actor actor) void KeyboardFocusManager::SetFocusIndicatorActor(Actor indicator) { - mFocusIndicatorActor = indicator; -} - -Actor KeyboardFocusManager::GetFocusIndicatorActor() -{ - return mFocusIndicatorActor; -} - -void KeyboardFocusManager::CreateDefaultFocusIndicatorActor() -{ - // Create a focus indicator actor shared by all the keyboard focusable actors - Image borderImage = Image::New(FOCUS_BORDER_IMAGE_PATH); - - ImageActor focusIndicator = ImageActor::New(borderImage); - focusIndicator.SetPositionInheritanceMode( Dali::USE_PARENT_POSITION_PLUS_LOCAL_POSITION ); - focusIndicator.SetStyle( ImageActor::STYLE_NINE_PATCH ); - focusIndicator.SetNinePatchBorder(FOCUS_BORDER_IMAGE_BORDER); - focusIndicator.SetPosition(Vector3(0.0f, 0.0f, 1.0f)); - - // Apply size constraint to the focus indicator - Constraint constraint = Constraint::New(Actor::SIZE, - ParentSource(Actor::SIZE), - EqualToConstraint()); - focusIndicator.ApplyConstraint(constraint); - - SetFocusIndicatorActor(focusIndicator); -} - -void KeyboardFocusManager::OnPhysicalKeyboardStatusChanged(PhysicalKeyboard keyboard) -{ - mIsKeyboardFocusEnabled = keyboard.IsAttached(); - - if(mIsKeyboardFocusEnabled) + if(mFocusIndicatorActor != indicator) { - // Show indicator when keyboard focus turned on if there is focused actor. - Actor actor = GetCurrentFocusActor(); - if(actor) + Actor currentFocusActor = GetCurrentFocusActor(); + if(currentFocusActor) { + // The new focus indicator should be added to the current focused actor immediately if(mFocusIndicatorActor) { - actor.Add(mFocusIndicatorActor); + currentFocusActor.Remove(mFocusIndicatorActor); + } + + if(indicator) + { + currentFocusActor.Add(indicator); } } - mIsFocusIndicatorEnabled = true; - } - else - { - // Hide indicator when keyboard focus turned off - Actor actor = GetCurrentFocusActor(); - if(actor) - { - actor.Remove(mFocusIndicatorActor); - } - mIsFocusIndicatorEnabled = false; + + mFocusIndicatorActor = indicator; } } -void KeyboardFocusManager::OnKeyEvent(const KeyEvent& event) +Actor KeyboardFocusManager::GetFocusIndicatorActor() { - if(!mIsKeyboardFocusEnabled) + if(!mFocusIndicatorActor) { - return; + // Create the default if it hasn't been set and one that's shared by all the keyboard focusable actors + const std::string imageDirPath = AssetManager::GetDaliImagePath(); + mFocusIndicatorActor = Toolkit::ImageView::New(imageDirPath + FOCUS_BORDER_IMAGE_FILE_NAME); + + // Apply size constraint to the focus indicator + mFocusIndicatorActor.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS); } - AccessibilityManager accessibilityManager = AccessibilityManager::Get(); - bool isAccessibilityEnabled = accessibilityManager.IsEnabled(); + mFocusIndicatorActor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER); + mFocusIndicatorActor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER); + mFocusIndicatorActor.SetProperty(Actor::Property::POSITION, Vector2(0.0f, 0.0f)); - Toolkit::FocusManager accessibilityFocusManager = Toolkit::FocusManager::Get(); + return mFocusIndicatorActor; +} - std::string keyName = event.keyPressedName; +void KeyboardFocusManager::OnKeyEvent(const KeyEvent& event) +{ + std::string keyName = event.GetKeyName(); + + if(mIsFocusIndicatorShown == UNKNOWN) + { + GetConfigurationFromStyleManger(); + } bool isFocusStartableKey = false; - if(event.state == KeyEvent::Down) + if(event.GetState() == KeyEvent::DOWN) { - if (keyName == "Left") + if(keyName == "Left") { - if(!isAccessibilityEnabled) + if(!mIsFocusIndicatorShown) { - if(!mIsFocusIndicatorEnabled) + if(mIsFocusIndicatorShown == HIDE) { // Show focus indicator - mIsFocusIndicatorEnabled = true; + mIsFocusIndicatorShown = SHOW; } else { // Move the focus towards left - MoveFocus(Toolkit::Control::Left); + MoveFocus(Toolkit::Control::KeyboardFocus::LEFT); } isFocusStartableKey = true; } else { - // Move the accessibility focus backward - accessibilityFocusManager.MoveFocusBackward(); + // Move the focus towards left + MoveFocus(Toolkit::Control::KeyboardFocus::LEFT); } + + isFocusStartableKey = true; } - else if (keyName == "Right") + else if(keyName == "Right") { - if(!isAccessibilityEnabled) + if(!mIsFocusIndicatorShown) { - if(!mIsFocusIndicatorEnabled) + if(mIsFocusIndicatorShown == HIDE) { // Show focus indicator - mIsFocusIndicatorEnabled = true; + mIsFocusIndicatorShown = SHOW; } else { // Move the focus towards right - MoveFocus(Toolkit::Control::Right); + MoveFocus(Toolkit::Control::KeyboardFocus::RIGHT); } - - isFocusStartableKey = true; } else { - // Move the accessibility focus forward - accessibilityFocusManager.MoveFocusForward(); + // Move the focus towards right + MoveFocus(Toolkit::Control::KeyboardFocus::RIGHT); } isFocusStartableKey = true; } - else if (keyName == "Up" && !isAccessibilityEnabled) + else if(keyName == "Up") { - if(!mIsFocusIndicatorEnabled) + if(mIsFocusIndicatorShown == HIDE) { // Show focus indicator - mIsFocusIndicatorEnabled = true; + mIsFocusIndicatorShown = SHOW; } else { // Move the focus towards up - MoveFocus(Toolkit::Control::Up); + MoveFocus(Toolkit::Control::KeyboardFocus::UP); } isFocusStartableKey = true; } - else if (keyName == "Down" && !isAccessibilityEnabled) + else if(keyName == "Down") { - if(!mIsFocusIndicatorEnabled) + if(mIsFocusIndicatorShown == HIDE) { // Show focus indicator - mIsFocusIndicatorEnabled = true; + mIsFocusIndicatorShown = SHOW; } else { // Move the focus towards down - MoveFocus(Toolkit::Control::Down); + MoveFocus(Toolkit::Control::KeyboardFocus::DOWN); + } + + isFocusStartableKey = true; + } + else if(keyName == "Prior") + { + if(mIsFocusIndicatorShown == HIDE) + { + // Show focus indicator + mIsFocusIndicatorShown = SHOW; + } + else + { + // Move the focus towards the previous page + MoveFocus(Toolkit::Control::KeyboardFocus::PAGE_UP); + } + + isFocusStartableKey = true; + } + else if(keyName == "Next") + { + if(mIsFocusIndicatorShown == HIDE) + { + // Show focus indicator + mIsFocusIndicatorShown = SHOW; + } + else + { + // Move the focus towards the next page + MoveFocus(Toolkit::Control::KeyboardFocus::PAGE_DOWN); } isFocusStartableKey = true; } - else if (keyName == "Tab" && !isAccessibilityEnabled) + else if(keyName == "Tab") { - if(!mIsFocusIndicatorEnabled) + if(mIsFocusIndicatorShown == HIDE) { // Show focus indicator - mIsFocusIndicatorEnabled = true; + mIsFocusIndicatorShown = SHOW; } else { // "Tab" key changes the focus group in the forward direction and // "Shift-Tab" key changes it in the backward direction. - DoMoveFocusToNextFocusGroup(!event.IsShiftModifier()); + if(!DoMoveFocusToNextFocusGroup(!event.IsShiftModifier())) + { + // If the focus group is not changed, Move the focus towards right, "Shift-Tap" key moves the focus towards left. + if(!MoveFocus(event.IsShiftModifier() ? Toolkit::Control::KeyboardFocus::LEFT : Toolkit::Control::KeyboardFocus::RIGHT)) + { + // If the focus is not moved, Move the focus towards down, "Shift-Tap" key moves the focus towards up. + MoveFocus(event.IsShiftModifier() ? Toolkit::Control::KeyboardFocus::UP : Toolkit::Control::KeyboardFocus::DOWN); + } + } } isFocusStartableKey = true; } - else if (keyName == "space" && !isAccessibilityEnabled) + else if(keyName == "space") { - if(!mIsFocusIndicatorEnabled) + if(mIsFocusIndicatorShown == HIDE) { // Show focus indicator - mIsFocusIndicatorEnabled = true; + mIsFocusIndicatorShown = SHOW; } isFocusStartableKey = true; } - else if (keyName == "" && !isAccessibilityEnabled) + else if(keyName == "") { // Check the fake key event for evas-plugin case - if(!mIsFocusIndicatorEnabled) + if(mIsFocusIndicatorShown == HIDE) { // Show focus indicator - mIsFocusIndicatorEnabled = true; + mIsFocusIndicatorShown = SHOW; } isFocusStartableKey = true; } - else if (keyName == "Backspace" && !isAccessibilityEnabled) + else if(keyName == "Backspace") { // Emit signal to go back to the previous view??? } + else if(keyName == "Escape") + { + } } - else if(event.state == KeyEvent::Up) + else if(event.GetState() == KeyEvent::UP) { - if (keyName == "Return") + if(keyName == "Return") { - if(!mIsFocusIndicatorEnabled && !isAccessibilityEnabled) + if(mIsFocusIndicatorShown == HIDE) { // Show focus indicator - mIsFocusIndicatorEnabled = true; + mIsFocusIndicatorShown = SHOW; } else { - // Activate the focused actor - Actor actor; - if(!isAccessibilityEnabled) - { - actor = GetCurrentFocusActor(); - } - else - { - actor = accessibilityFocusManager.GetCurrentFocusActor(); - } - + // The focused actor has enter pressed on it + Actor actor = GetCurrentFocusActor(); if(actor) { - DoActivate(actor); + DoKeyboardEnter(actor); } } @@ -638,71 +943,117 @@ void KeyboardFocusManager::OnKeyEvent(const KeyEvent& event) } } - if(isFocusStartableKey && mIsFocusIndicatorEnabled && !isAccessibilityEnabled) + if(isFocusStartableKey && mIsFocusIndicatorShown == SHOW) { Actor actor = GetCurrentFocusActor(); - if( !actor ) + if(actor) + { + if(mEnableFocusIndicator == ENABLE) + { + // Make sure the focused actor is highlighted + actor.Add(GetFocusIndicatorActor()); + } + } + else { // No actor is focused but keyboard focus is activated by the key press // Let's try to move the initial focus - MoveFocus(Toolkit::Control::Right); + MoveFocus(Toolkit::Control::KeyboardFocus::RIGHT); } - else if(mFocusIndicatorActor) + } +} + +void KeyboardFocusManager::OnTouch(const TouchEvent& touch) +{ + // if mIsFocusIndicatorShown is UNKNOWN, it means Configuration is not loaded. + // Try to load configuration. + if(mIsFocusIndicatorShown == UNKNOWN) + { + GetConfigurationFromStyleManger(); + } + + // Clear the focus when user touch the screen. + // We only do this on a Down event, otherwise the clear action may override a manually focused actor. + if(((touch.GetPointCount() < 1) || (touch.GetState(0) == PointState::DOWN))) + { + // If mClearFocusOnTouch is false, do not clear the focus even if user touch the screen. + if(mClearFocusOnTouch) { - // Make sure the focused actor is highlighted - actor.Add(mFocusIndicatorActor); + ClearFocus(); + } + + // If KEYBOARD_FOCUSABLE and TOUCH_FOCUSABLE is true, set focus actor + Actor hitActor = touch.GetHitActor(0); + if(hitActor && hitActor.GetProperty(Actor::Property::KEYBOARD_FOCUSABLE) && hitActor.GetProperty(DevelActor::Property::TOUCH_FOCUSABLE)) + { + SetCurrentFocusActor(hitActor); } } } -void KeyboardFocusManager::OnTouched(const TouchEvent& touchEvent) +void KeyboardFocusManager::OnWindowFocusChanged(Window window, bool focusIn) { - // Clear the focus when user touch the screen - ClearFocus(); + if(focusIn && mCurrentFocusedWindow.GetHandle() != window.GetRootLayer()) + { + // Change Current Focused Window + Layer rootLayer = window.GetRootLayer(); + mCurrentFocusedWindow = rootLayer; + + // Get Current Focused Actor from window + Actor currentFocusedActor = GetFocusActorFromCurrentWindow(); + SetCurrentFocusActor(currentFocusedActor); + + if(currentFocusedActor && (mEnableFocusIndicator == ENABLE)) + { + // Make sure the focused actor is highlighted + currentFocusedActor.Add(GetFocusIndicatorActor()); + mIsFocusIndicatorShown = SHOW; + } + } } -Toolkit::KeyboardFocusManager::PreFocusChangeSignalV2& KeyboardFocusManager::PreFocusChangeSignal() +Toolkit::KeyboardFocusManager::PreFocusChangeSignalType& KeyboardFocusManager::PreFocusChangeSignal() { - return mPreFocusChangeSignalV2; + return mPreFocusChangeSignal; } -Toolkit::KeyboardFocusManager::FocusChangedSignalV2& KeyboardFocusManager::FocusChangedSignal() +Toolkit::KeyboardFocusManager::FocusChangedSignalType& KeyboardFocusManager::FocusChangedSignal() { - return mFocusChangedSignalV2; + return mFocusChangedSignal; } -Toolkit::KeyboardFocusManager::FocusGroupChangedSignalV2& KeyboardFocusManager::FocusGroupChangedSignal() +Toolkit::KeyboardFocusManager::FocusGroupChangedSignalType& KeyboardFocusManager::FocusGroupChangedSignal() { - return mFocusGroupChangedSignalV2; + return mFocusGroupChangedSignal; } -Toolkit::KeyboardFocusManager::FocusedActorActivatedSignalV2& KeyboardFocusManager::FocusedActorActivatedSignal() +Toolkit::KeyboardFocusManager::FocusedActorEnterKeySignalType& KeyboardFocusManager::FocusedActorEnterKeySignal() { - return mFocusedActorActivatedSignalV2; + return mFocusedActorEnterKeySignal; } -bool KeyboardFocusManager::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor ) +bool KeyboardFocusManager::DoConnectSignal(BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor) { - Dali::BaseHandle handle( object ); + Dali::BaseHandle handle(object); - bool connected( true ); - KeyboardFocusManager* manager = dynamic_cast(object); + bool connected(true); + KeyboardFocusManager* manager = static_cast(object); // TypeRegistry guarantees that this is the correct type. - if( Dali::Toolkit::KeyboardFocusManager::SIGNAL_PRE_FOCUS_CHANGE == signalName ) + if(0 == strcmp(signalName.c_str(), SIGNAL_PRE_FOCUS_CHANGE)) { - manager->PreFocusChangeSignal().Connect( tracker, functor ); + manager->PreFocusChangeSignal().Connect(tracker, functor); } - if( Dali::Toolkit::KeyboardFocusManager::SIGNAL_FOCUS_CHANGED == signalName ) + else if(0 == strcmp(signalName.c_str(), SIGNAL_FOCUS_CHANGED)) { - manager->FocusChangedSignal().Connect( tracker, functor ); + manager->FocusChangedSignal().Connect(tracker, functor); } - if( Dali::Toolkit::KeyboardFocusManager::SIGNAL_FOCUS_GROUP_CHANGED == signalName ) + else if(0 == strcmp(signalName.c_str(), SIGNAL_FOCUS_GROUP_CHANGED)) { - manager->FocusGroupChangedSignal().Connect( tracker, functor ); + manager->FocusGroupChangedSignal().Connect(tracker, functor); } - else if( Dali::Toolkit::KeyboardFocusManager::SIGNAL_FOCUSED_ACTOR_ACTIVATED== signalName ) + else if(0 == strcmp(signalName.c_str(), SIGNAL_FOCUSED_ACTOR_ENTER_KEY)) { - manager->FocusedActorActivatedSignal().Connect( tracker, functor ); + manager->FocusedActorEnterKeySignal().Connect(tracker, functor); } else { @@ -713,6 +1064,26 @@ bool KeyboardFocusManager::DoConnectSignal( BaseObject* object, ConnectionTracke return connected; } +void KeyboardFocusManager::SetCustomAlgorithm(CustomAlgorithmInterface& interface) +{ + mCustomAlgorithmInterface = &interface; +} + +void KeyboardFocusManager::EnableFocusIndicator(bool enable) +{ + if(!enable && mFocusIndicatorActor) + { + mFocusIndicatorActor.Unparent(); + } + + mEnableFocusIndicator = enable ? ENABLE : DISABLE; +} + +bool KeyboardFocusManager::IsFocusIndicatorEnabled() const +{ + return (mEnableFocusIndicator == ENABLE); +} + } // namespace Internal } // namespace Toolkit