X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git;a=blobdiff_plain;f=dali-toolkit%2Finternal%2Ffocus-manager%2Fkeyboard-focus-manager-impl.cpp;h=57fe0767cac47d71a6bb6bd1faefd47cf2485ccf;hp=1e55ba0f2c12d31edf274d634bcd50898fef1922;hb=9795d65d103bdf0524aa92e96475019eff2705f3;hpb=8d522afed46c436b653f991b7e383fae80eee7df 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 1e55ba0..57fe076 100644 --- a/dali-toolkit/internal/focus-manager/keyboard-focus-manager-impl.cpp +++ b/dali-toolkit/internal/focus-manager/keyboard-focus-manager-impl.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Samsung Electronics Co., Ltd. + * Copyright (c) 2017 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. @@ -26,8 +26,9 @@ #include #include #include +#include #include -#include +#include #include #include @@ -36,7 +37,7 @@ #include #include #include -#include +#include namespace Dali { @@ -78,13 +79,15 @@ BaseHandle Create() 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, "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 Toolkit::KeyboardFocusManager KeyboardFocusManager::Get() @@ -107,74 +110,93 @@ Toolkit::KeyboardFocusManager KeyboardFocusManager::Get() } KeyboardFocusManager::KeyboardFocusManager() -: mCurrentFocusActor(0), - mFocusIndicatorActor(Actor()), - mFocusGroupLoopEnabled(false), - mIsKeyboardFocusEnabled(false), - mIsFocusIndicatorEnabled(false), - mIsWaitingKeyboardFocusChangeCommit(false), - mSlotDelegate(this) -{ - CreateDefaultFocusIndicatorActor(); - - OnPhysicalKeyboardStatusChanged(PhysicalKeyboard::Get()); - - Toolkit::KeyInputFocusManager::Get().UnhandledKeyEventSignal().Connect(mSlotDelegate, &KeyboardFocusManager::OnKeyEvent); - Stage::GetCurrent().TouchedSignal().Connect(mSlotDelegate, &KeyboardFocusManager::OnTouched); - PhysicalKeyboard::Get().StatusChangedSignal().Connect(mSlotDelegate, &KeyboardFocusManager::OnPhysicalKeyboardStatusChanged); +: mPreFocusChangeSignal(), + mFocusChangedSignal(), + mFocusGroupChangedSignal(), + mFocusedActorEnterKeySignal(), + mCurrentFocusActor( 0 ), + mFocusIndicatorActor(), + mFocusGroupLoopEnabled( false ), + mIsFocusIndicatorEnabled( false ), + mIsWaitingKeyboardFocusChangeCommit( false ), + mFocusHistory(), + mSlotDelegate( this ), + mCustomAlgorithmInterface(NULL) +{ + // TODO: Get FocusIndicatorEnable constant from stylesheet to set mIsFocusIndicatorEnabled. + Stage::GetCurrent().KeyEventSignal().Connect( mSlotDelegate, &KeyboardFocusManager::OnKeyEvent); + Stage::GetCurrent().TouchSignal().Connect( mSlotDelegate, &KeyboardFocusManager::OnTouch ); } KeyboardFocusManager::~KeyboardFocusManager() { } -bool KeyboardFocusManager::SetCurrentFocusActor(Actor actor) +bool KeyboardFocusManager::SetCurrentFocusActor( Actor actor ) { DALI_ASSERT_DEBUG( !mIsWaitingKeyboardFocusChangeCommit && "Calling this function in the PreFocusChangeSignal callback?" ); - if( actor ) - { - return DoSetCurrentFocusActor( actor.GetId() ); - } - - 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; - // Check whether the actor is in the stage - if(actor) + // Check whether the actor is in the stage and is keyboard focusable. + if( actor && actor.IsKeyboardFocusable() ) { - // Set the focus only when the actor is keyboard focusable - if(actor.IsKeyboardFocusable()) + if( mIsFocusIndicatorEnabled ) { - // Draw the focus indicator upon the focused actor - if(mIsFocusIndicatorEnabled && mFocusIndicatorActor) - { - actor.Add(mFocusIndicatorActor); - } + actor.Add( GetFocusIndicatorActor() ); + } + // Send notification for the change of focus actor + Actor currentFocusedActor = GetCurrentFocusActor(); - // Send notification for the change of focus actor - if( !mFocusChangedSignal.Empty() ) - { - mFocusChangedSignal.Emit(GetCurrentFocusActor(), actor); - } + if( !mFocusChangedSignal.Empty() ) + { + mFocusChangedSignal.Emit(currentFocusedActor, actor); + } - DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] Focus Changed\n", __FUNCTION__, __LINE__); + 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 = actorID; + // Save the current focused actor + mCurrentFocusActor = actor.GetId(); - DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] SUCCEED\n", __FUNCTION__, __LINE__); - return true; + Toolkit::Control newlyFocusedControl = Toolkit::Control::DownCast(actor); + if( newlyFocusedControl ) + { + newlyFocusedControl.SetProperty(DevelControl::Property::STATE, DevelControl::FOCUSED ); + newlyFocusedControl.SetKeyInputFocus(); } + + // Push Current Focused Actor to FocusHistory + mFocusHistory.PushBack( &actor.GetBaseObject() ); + + // Delete first element before add new element when Stack is full. + if( mFocusHistory.Count() > 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() @@ -188,6 +210,33 @@ Actor KeyboardFocusManager::GetCurrentFocusGroup() return GetFocusGroup(GetCurrentFocusActor()); } +void KeyboardFocusManager::MoveFocusBackward() +{ + // Find Pre Focused Actor when the list size is more than 1 + if( mFocusHistory.Count() > 1 ) + { + // Delete current focused actor in history + FocusStackIterator endPos = mFocusHistory.End(); + endPos = mFocusHistory.Erase( --endPos ); + + // If pre-focused actors are not on stage, remove them in stack + while( !Dali::Actor::DownCast(BaseHandle(mFocusHistory[ mFocusHistory.Count() - 1 ])).OnStage() ) + { + endPos = mFocusHistory.Erase( --endPos ); + } + + // Get pre focused actor + BaseObject* object = mFocusHistory[ mFocusHistory.Count() - 1 ]; + BaseHandle handle( object ); + Actor preFocusedActor = Dali::Actor::DownCast( handle ); + + // Delete pre focused actor in history because it will pushed again by SetCurrentFocusActor() + mFocusHistory.Erase( --endPos ); + + SetCurrentFocusActor( preFocusedActor ); + } +} + bool KeyboardFocusManager::IsLayoutControl(Actor actor) const { Toolkit::Control control = Toolkit::Control::DownCast(actor); @@ -219,33 +268,106 @@ bool KeyboardFocusManager::MoveFocus(Toolkit::Control::KeyboardFocus::Direction bool succeed = false; // Go through the actor's hierarchy until we find a layout control that knows how to move the focus - Toolkit::Control parentLayoutControl = GetParentLayoutControl(currentFocusActor); - while(parentLayoutControl && !succeed) + Toolkit::Control parentLayoutControl = GetParentLayoutControl( currentFocusActor ); + while( parentLayoutControl && !succeed ) { - succeed = DoMoveFocusWithinLayoutControl(parentLayoutControl, currentFocusActor, direction); - parentLayoutControl = GetParentLayoutControl(parentLayoutControl); + succeed = DoMoveFocusWithinLayoutControl( parentLayoutControl, currentFocusActor, direction ); + parentLayoutControl = GetParentLayoutControl( parentLayoutControl ); } - if(!succeed && !mPreFocusChangeSignal.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 = mPreFocusChangeSignal.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 ) + { + nextFocusableActor = Stage::GetCurrent().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; + } + } - if ( nextFocusableActor && nextFocusableActor.IsKeyboardFocusable() ) + if( nextFocusableActor && nextFocusableActor.IsKeyboardFocusable() ) { // Whether the next focusable actor is a layout control - if(IsLayoutControl(nextFocusableActor)) + if( IsLayoutControl( nextFocusableActor ) ) { // If so, move the focus inside it. - Toolkit::Control layoutControl = Toolkit::Control::DownCast(nextFocusableActor); - succeed = DoMoveFocusWithinLayoutControl(layoutControl, currentFocusActor, direction); + Toolkit::Control layoutControl = Toolkit::Control::DownCast( nextFocusableActor) ; + succeed = DoMoveFocusWithinLayoutControl( layoutControl, currentFocusActor, direction ); } else { // Otherwise, just set focus to the next focusable actor - succeed = SetCurrentFocusActor(nextFocusableActor); + succeed = SetCurrentFocusActor( nextFocusableActor ); } } } @@ -361,17 +483,24 @@ void KeyboardFocusManager::DoKeyboardEnter(Actor actor) void KeyboardFocusManager::ClearFocus() { Actor actor = GetCurrentFocusActor(); - if(actor) + if( actor ) { - if(mFocusIndicatorActor) + if( mFocusIndicatorActor ) { - actor.Remove(mFocusIndicatorActor); + actor.Remove( mFocusIndicatorActor ); } // Send notification for the change of focus actor if( !mFocusChangedSignal.Empty() ) { - mFocusChangedSignal.Emit(actor, Actor()); + mFocusChangedSignal.Emit( actor, Actor() ); + } + + Toolkit::Control currentlyFocusedControl = Toolkit::Control::DownCast( actor ); + if( currentlyFocusedControl ) + { + currentlyFocusedControl.SetProperty( DevelControl::Property::STATE, DevelControl::NORMAL ); + currentlyFocusedControl.ClearKeyInputFocus(); } } @@ -451,58 +580,24 @@ void KeyboardFocusManager::SetFocusIndicatorActor(Actor indicator) Actor KeyboardFocusManager::GetFocusIndicatorActor() { - return mFocusIndicatorActor; -} - -void KeyboardFocusManager::CreateDefaultFocusIndicatorActor() -{ - // Create a focus indicator actor shared by all the keyboard focusable actors - Toolkit::ImageView focusIndicator = Toolkit::ImageView::New(FOCUS_BORDER_IMAGE_PATH); - focusIndicator.SetPositionInheritanceMode( Dali::USE_PARENT_POSITION_PLUS_LOCAL_POSITION ); - focusIndicator.SetPosition(Vector3(0.0f, 0.0f, 1.0f)); + if( ! mFocusIndicatorActor ) + { + // Create the default if it hasn't been set and one that's shared by all the keyboard focusable actors + mFocusIndicatorActor = Toolkit::ImageView::New( FOCUS_BORDER_IMAGE_PATH ); - // Apply size constraint to the focus indicator - focusIndicator.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS ); + // Apply size constraint to the focus indicator + mFocusIndicatorActor.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS ); + } - SetFocusIndicatorActor(focusIndicator); -} + mFocusIndicatorActor.SetParentOrigin( ParentOrigin::CENTER ); + mFocusIndicatorActor.SetAnchorPoint( AnchorPoint::CENTER ); + mFocusIndicatorActor.SetPosition(0.0f, 0.0f); -void KeyboardFocusManager::OnPhysicalKeyboardStatusChanged(PhysicalKeyboard keyboard) -{ - mIsKeyboardFocusEnabled = keyboard.IsAttached(); - - if(mIsKeyboardFocusEnabled) - { - // Show indicator when keyboard focus turned on if there is focused actor. - Actor actor = GetCurrentFocusActor(); - if(actor) - { - if(mFocusIndicatorActor) - { - actor.Add(mFocusIndicatorActor); - } - } - mIsFocusIndicatorEnabled = true; - } - else - { - // Hide indicator when keyboard focus turned off - Actor actor = GetCurrentFocusActor(); - if(actor) - { - actor.Remove(mFocusIndicatorActor); - } - mIsFocusIndicatorEnabled = false; - } + return mFocusIndicatorActor; } void KeyboardFocusManager::OnKeyEvent(const KeyEvent& event) { - if(!mIsKeyboardFocusEnabled) - { - return; - } - AccessibilityAdaptor accessibilityAdaptor = AccessibilityAdaptor::Get(); bool isAccessibilityEnabled = accessibilityAdaptor.IsEnabled(); @@ -590,6 +685,36 @@ void KeyboardFocusManager::OnKeyEvent(const KeyEvent& event) isFocusStartableKey = true; } + else if (keyName == "Prior" && !isAccessibilityEnabled) + { + if(!mIsFocusIndicatorEnabled) + { + // Show focus indicator + mIsFocusIndicatorEnabled = true; + } + else + { + // Move the focus towards the previous page + MoveFocus(Toolkit::Control::KeyboardFocus::PAGE_UP); + } + + isFocusStartableKey = true; + } + else if (keyName == "Next" && !isAccessibilityEnabled) + { + if(!mIsFocusIndicatorEnabled) + { + // Show focus indicator + mIsFocusIndicatorEnabled = true; + } + else + { + // Move the focus towards the next page + MoveFocus(Toolkit::Control::KeyboardFocus::PAGE_DOWN); + } + + isFocusStartableKey = true; + } else if (keyName == "Tab" && !isAccessibilityEnabled) { if(!mIsFocusIndicatorEnabled) @@ -631,6 +756,9 @@ void KeyboardFocusManager::OnKeyEvent(const KeyEvent& event) { // Emit signal to go back to the previous view??? } + else if (keyName == "Escape" && !isAccessibilityEnabled) + { + } } else if(event.state == KeyEvent::Up) { @@ -667,25 +795,25 @@ void KeyboardFocusManager::OnKeyEvent(const KeyEvent& event) if(isFocusStartableKey && mIsFocusIndicatorEnabled && !isAccessibilityEnabled) { Actor actor = GetCurrentFocusActor(); - if( !actor ) + if( actor ) + { + // 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::KeyboardFocus::RIGHT); } - else if(mFocusIndicatorActor) - { - // Make sure the focused actor is highlighted - actor.Add(mFocusIndicatorActor); - } } } -void KeyboardFocusManager::OnTouched(const TouchEvent& touchEvent) +void KeyboardFocusManager::OnTouch(const TouchData& touch) { // 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( ( touchEvent.GetPointCount() < 1 ) || ( touchEvent.GetPoint( 0 ).state == TouchPoint::Down ) ) + if( ( touch.GetPointCount() < 1 ) || ( touch.GetState( 0 ) == PointState::DOWN ) ) { ClearFocus(); } @@ -716,17 +844,17 @@ bool KeyboardFocusManager::DoConnectSignal( BaseObject* object, ConnectionTracke Dali::BaseHandle handle( object ); bool connected( true ); - KeyboardFocusManager* manager = dynamic_cast( object ); + KeyboardFocusManager* manager = static_cast< KeyboardFocusManager* >( object ); // TypeRegistry guarantees that this is the correct type. if( 0 == strcmp( signalName.c_str(), SIGNAL_PRE_FOCUS_CHANGE ) ) { manager->PreFocusChangeSignal().Connect( tracker, functor ); } - if( 0 == strcmp( signalName.c_str(), SIGNAL_FOCUS_CHANGED ) ) + else if( 0 == strcmp( signalName.c_str(), SIGNAL_FOCUS_CHANGED ) ) { manager->FocusChangedSignal().Connect( tracker, functor ); } - if( 0 == strcmp( signalName.c_str(), SIGNAL_FOCUS_GROUP_CHANGED ) ) + else if( 0 == strcmp( signalName.c_str(), SIGNAL_FOCUS_GROUP_CHANGED ) ) { manager->FocusGroupChangedSignal().Connect( tracker, functor ); } @@ -743,6 +871,11 @@ bool KeyboardFocusManager::DoConnectSignal( BaseObject* object, ConnectionTracke return connected; } +void KeyboardFocusManager::SetCustomAlgorithm(CustomAlgorithmInterface& interface) +{ + mCustomAlgorithmInterface = &interface; +} + } // namespace Internal } // namespace Toolkit