Improved key-input focus manager performance
[platform/core/uifw/dali-toolkit.git] / base / dali-toolkit / internal / focus-manager / keyinput-focus-manager-impl.cpp
1 /*
2  * Copyright (c) 2014 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 "keyinput-focus-manager-impl.h"
20
21 // EXTERNAL INCLUDES
22 #include <dali/public-api/actors/layer.h>
23 #include <dali/public-api/common/stage.h>
24
25 // INTERNAL INCLUDES
26 #include <dali-toolkit/public-api/controls/control-impl.h>
27 #include <dali/integration-api/debug.h>
28
29 namespace Dali
30 {
31
32 namespace Toolkit
33 {
34
35 namespace Internal
36 {
37
38 KeyInputFocusManager::KeyInputFocusManager()
39 : mSlotDelegate( this )
40 {
41   Stage::GetCurrent().KeyEventSignal().Connect(mSlotDelegate, &KeyInputFocusManager::OnKeyEvent);
42   mObjectRegistry = Dali::Stage::GetCurrent().GetObjectRegistry();
43   mObjectRegistry.ObjectDestroyedSignal().Connect( this, &KeyInputFocusManager::OnObjectDestroyed );
44 }
45
46 KeyInputFocusManager::~KeyInputFocusManager()
47 {
48 }
49
50 void KeyInputFocusManager::SetFocus( Toolkit::Control control )
51 {
52   if( !control )
53   {
54     // No-op
55     return;
56   }
57
58   FocusStackIterator pos = FindFocusControlInStack( control );
59
60   if( ( mFocusStack.Count() != 0 ) && ( pos == mFocusStack.End()-1 ) )
61   {
62     // Control already in front, so No-op
63     return;
64   }
65
66   if( pos != mFocusStack.End() )
67   {
68     // A previously focused control wants to regain focus
69     mFocusStack.Erase( pos );
70   }
71   else
72   {
73     control.OffStageSignal().Connect( mSlotDelegate, &KeyInputFocusManager::OnFocusControlStageDisconnection );
74   }
75
76   Dali::Toolkit::Control previousFocusControl = GetCurrentFocusControl();
77   if( previousFocusControl )
78   {
79     // Notify the control that it has lost key input focus
80     previousFocusControl.GetImplementation().OnKeyInputFocusLost();
81   }
82
83   mFocusStack.PushBack( &control.GetBaseObject() );
84
85   // Tell the new actor that it has gained focus.
86   control.GetImplementation().OnKeyInputFocusGained();
87
88   // Emit the signal to inform focus change to the application.
89   if ( !mKeyInputFocusChangedSignalV2.Empty() )
90   {
91     mKeyInputFocusChangedSignalV2.Emit( control, previousFocusControl );
92   }
93 }
94
95 void KeyInputFocusManager::RemoveFocus( Toolkit::Control control )
96 {
97   if( control )
98   {
99     FocusStackIterator pos = FindFocusControlInStack( control );
100     if( pos != mFocusStack.End() )
101     {
102       control.OffStageSignal().Disconnect( mSlotDelegate, &KeyInputFocusManager::OnFocusControlStageDisconnection );
103
104       // Notify the control that it has lost key input focus
105       control.GetImplementation().OnKeyInputFocusLost();
106
107       // If this is the top-most actor, pop it and change focus to the previous control
108       if( pos == mFocusStack.End() - 1 )
109       {
110         mFocusStack.Erase( pos );
111
112         Toolkit::Control previouslyFocusedControl = GetCurrentFocusControl();
113         if( previouslyFocusedControl )
114         {
115           // Tell the control that it has gained focus.
116           previouslyFocusedControl.GetImplementation().OnKeyInputFocusGained();
117         }
118       }
119       else
120       {
121         // If the removed control is not currently focused, then no need to emit signal.
122         mFocusStack.Erase( pos );
123       }
124     }
125   }
126 }
127
128 Toolkit::Control KeyInputFocusManager::GetCurrentFocusControl() const
129 {
130   Toolkit::Control currentControl;
131
132   FocusStack::SizeType count = mFocusStack.Count();
133   if( count != 0 )
134   {
135     BaseObject* object = mFocusStack[ count - 1 ];
136     BaseHandle handle( object );
137     currentControl = Dali::Toolkit::Control::DownCast( handle );
138   }
139   return currentControl;
140 }
141
142 bool KeyInputFocusManager::IsKeyboardListener( Toolkit::Control control ) const
143 {
144   bool result = false;
145
146   if( FindFocusControlInStack( control ) != mFocusStack.End() )
147   {
148     result = true;
149   }
150
151   return result;
152 }
153
154 Toolkit::KeyInputFocusManager::KeyInputFocusChangedSignalV2& KeyInputFocusManager::KeyInputFocusChangedSignal()
155 {
156   return mKeyInputFocusChangedSignalV2;
157 }
158
159 Toolkit::KeyInputFocusManager::UnhandledKeyEventSignalV2& KeyInputFocusManager::UnhandledKeyEventSignal()
160 {
161   return mUnhandledKeyEventSignalV2;
162 }
163
164 KeyInputFocusManager::FocusStackIterator KeyInputFocusManager::FindFocusControlInStack( Toolkit::Control control ) const
165 {
166   BaseObject* controlObject = &control.GetBaseObject();
167   return std::find( mFocusStack.Begin(), mFocusStack.End(), controlObject );
168 }
169
170 void KeyInputFocusManager::OnKeyEvent( const KeyEvent& event )
171 {
172   bool consumed = false;
173
174   if( mFocusStack.Count() > 0 )
175   {
176     FocusStack::SizeType index = mFocusStack.Count();
177     while( mFocusStack.Count() != 0 && !consumed && index > 0 )
178     {
179       --index;
180       BaseObject* object = mFocusStack[ index ];
181       BaseHandle handle( object );
182       Toolkit::Control control = Toolkit::Control::DownCast( object );
183       if( control )
184       {
185         // Notify the control about the key event
186         consumed = control.GetImplementation().EmitKeyEventSignal( event );
187       }
188     }
189   }
190
191   if( !consumed )
192   {
193     // Emit signal to inform that a key event is not consumed.
194     if( !mUnhandledKeyEventSignalV2.Empty() )
195     {
196       mUnhandledKeyEventSignalV2.Emit(event);
197     }
198   }
199 }
200
201 void KeyInputFocusManager::OnFocusControlStageDisconnection( Dali::Actor actor )
202 {
203   RemoveFocus( Dali::Toolkit::Control::DownCast( actor ) );
204 }
205
206 void KeyInputFocusManager::OnObjectDestroyed( const Dali::RefObject* object )
207 {
208   // The object is already destroyed. Don't create handles to it, or try sending
209   // signals to it. Remove it's pointer from the stack.
210   const BaseObject* baseObject = static_cast<const BaseObject*>( object );
211   FocusStackIterator pos = std::find( mFocusStack.Begin(), mFocusStack.End(), baseObject );
212   if( pos != mFocusStack.End() )
213   {
214     mFocusStack.Erase( pos );
215   }
216 }
217
218 bool KeyInputFocusManager::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
219 {
220   Dali::BaseHandle handle( object );
221
222   bool connected( true );
223   KeyInputFocusManager* manager = dynamic_cast<KeyInputFocusManager*>(object);
224
225   if( Dali::Toolkit::KeyInputFocusManager::SIGNAL_KEY_INPUT_FOCUS_CHANGED == signalName )
226   {
227     manager->KeyInputFocusChangedSignal().Connect( tracker, functor );
228   }
229   else
230   {
231     // signalName does not match any signal
232     connected = false;
233   }
234
235   return connected;
236 }
237
238 } // namespace Internal
239
240 } // namespace Toolkit
241
242 } // namespace Dali