2 * Copyright (c) 2014 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include "keyinput-focus-manager-impl.h"
22 #include <dali/public-api/actors/layer.h>
23 #include <dali/public-api/common/stage.h>
26 #include <dali-toolkit/public-api/controls/control-impl.h>
27 #include <dali/integration-api/debug.h>
43 const char* const SIGNAL_KEY_INPUT_FOCUS_CHANGED = "key-input-focus-changed";
44 const char* const SIGNAL_UNHANDLED_KEY_EVENT = "unhandled-key-event";
48 KeyInputFocusManager::KeyInputFocusManager()
49 : mSlotDelegate( this )
51 Stage::GetCurrent().KeyEventSignal().Connect(mSlotDelegate, &KeyInputFocusManager::OnKeyEvent);
52 mObjectRegistry = Dali::Stage::GetCurrent().GetObjectRegistry();
53 mObjectRegistry.ObjectDestroyedSignal().Connect( this, &KeyInputFocusManager::OnObjectDestroyed );
56 KeyInputFocusManager::~KeyInputFocusManager()
60 void KeyInputFocusManager::SetFocus( Toolkit::Control control )
68 FocusStackIterator pos = FindFocusControlInStack( control );
70 if( ( mFocusStack.Count() != 0 ) && ( pos == mFocusStack.End()-1 ) )
72 // Control already in front, so No-op
76 if( pos != mFocusStack.End() )
78 // A previously focused control wants to regain focus
79 mFocusStack.Erase( pos );
83 control.OffStageSignal().Connect( mSlotDelegate, &KeyInputFocusManager::OnFocusControlStageDisconnection );
86 Dali::Toolkit::Control previousFocusControl = GetCurrentFocusControl();
87 if( previousFocusControl )
89 // Notify the control that it has lost key input focus
90 previousFocusControl.GetImplementation().OnKeyInputFocusLost();
93 mFocusStack.PushBack( &control.GetBaseObject() );
95 // Tell the new actor that it has gained focus.
96 control.GetImplementation().OnKeyInputFocusGained();
98 // Emit the signal to inform focus change to the application.
99 if ( !mKeyInputFocusChangedSignal.Empty() )
101 mKeyInputFocusChangedSignal.Emit( control, previousFocusControl );
105 void KeyInputFocusManager::RemoveFocus( Toolkit::Control control )
109 FocusStackIterator pos = FindFocusControlInStack( control );
110 if( pos != mFocusStack.End() )
112 control.OffStageSignal().Disconnect( mSlotDelegate, &KeyInputFocusManager::OnFocusControlStageDisconnection );
114 // Notify the control that it has lost key input focus
115 control.GetImplementation().OnKeyInputFocusLost();
117 // If this is the top-most actor, pop it and change focus to the previous control
118 if( pos == mFocusStack.End() - 1 )
120 mFocusStack.Erase( pos );
122 Toolkit::Control previouslyFocusedControl = GetCurrentFocusControl();
123 if( previouslyFocusedControl )
125 // Tell the control that it has gained focus.
126 previouslyFocusedControl.GetImplementation().OnKeyInputFocusGained();
131 // If the removed control is not currently focused, then no need to emit signal.
132 mFocusStack.Erase( pos );
138 Toolkit::Control KeyInputFocusManager::GetCurrentFocusControl() const
140 Toolkit::Control currentControl;
142 FocusStack::SizeType count = mFocusStack.Count();
145 BaseObject* object = mFocusStack[ count - 1 ];
146 BaseHandle handle( object );
147 currentControl = Dali::Toolkit::Control::DownCast( handle );
149 return currentControl;
152 bool KeyInputFocusManager::IsKeyboardListener( Toolkit::Control control ) const
156 if( FindFocusControlInStack( control ) != mFocusStack.End() )
164 Toolkit::KeyInputFocusManager::KeyInputFocusChangedSignalType& KeyInputFocusManager::KeyInputFocusChangedSignal()
166 return mKeyInputFocusChangedSignal;
169 Toolkit::KeyInputFocusManager::UnhandledKeyEventSignalType& KeyInputFocusManager::UnhandledKeyEventSignal()
171 return mUnhandledKeyEventSignal;
174 KeyInputFocusManager::FocusStackIterator KeyInputFocusManager::FindFocusControlInStack( Toolkit::Control control ) const
176 BaseObject* controlObject = &control.GetBaseObject();
177 return std::find( mFocusStack.Begin(), mFocusStack.End(), controlObject );
180 void KeyInputFocusManager::OnKeyEvent( const KeyEvent& event )
182 bool consumed = false;
184 if( mFocusStack.Count() > 0 )
186 FocusStack::SizeType index = mFocusStack.Count();
187 while( mFocusStack.Count() != 0 && !consumed && index > 0 )
190 BaseObject* object = mFocusStack[ index ];
191 BaseHandle handle( object );
192 Toolkit::Control control = Toolkit::Control::DownCast( object );
195 // Notify the control about the key event
196 consumed = control.GetImplementation().EmitKeyEventSignal( event );
203 // Emit signal to inform that a key event is not consumed.
204 if( !mUnhandledKeyEventSignal.Empty() )
206 mUnhandledKeyEventSignal.Emit(event);
211 void KeyInputFocusManager::OnFocusControlStageDisconnection( Dali::Actor actor )
213 RemoveFocus( Dali::Toolkit::Control::DownCast( actor ) );
216 void KeyInputFocusManager::OnObjectDestroyed( const Dali::RefObject* object )
218 // The object is already destroyed. Don't create handles to it, or try sending
219 // signals to it. Remove it's pointer from the stack.
220 const BaseObject* baseObject = static_cast<const BaseObject*>( object );
221 FocusStackIterator pos = std::find( mFocusStack.Begin(), mFocusStack.End(), baseObject );
222 if( pos != mFocusStack.End() )
224 mFocusStack.Erase( pos );
228 bool KeyInputFocusManager::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
230 Dali::BaseHandle handle( object );
232 bool connected( true );
233 KeyInputFocusManager* manager = dynamic_cast<KeyInputFocusManager*>( object );
235 if( 0 == strcmp( signalName.c_str(), SIGNAL_KEY_INPUT_FOCUS_CHANGED ) )
237 manager->KeyInputFocusChangedSignal().Connect( tracker, functor );
239 else if( 0 == strcmp( signalName.c_str(), SIGNAL_UNHANDLED_KEY_EVENT ) )
241 manager->UnhandledKeyEventSignal().Connect( tracker, functor );
245 // signalName does not match any signal
252 } // namespace Internal
254 } // namespace Toolkit