DALi Version 2.1.5
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / focus-manager / keyinput-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 "keyinput-focus-manager-impl.h"
20
21 // EXTERNAL INCLUDES
22 #include <dali-toolkit/public-api/controls/control-impl.h>
23 #include <dali/integration-api/adaptor-framework/adaptor.h>
24 #include <dali/integration-api/adaptor-framework/scene-holder.h>
25 #include <dali/integration-api/debug.h>
26 #include <dali/public-api/actors/layer.h>
27 #include <cstring> // for strcmp
28
29 // INTERNAL INCLUDES
30 #include <dali-toolkit/devel-api/controls/control-devel.h>
31
32 namespace Dali
33 {
34 namespace Toolkit
35 {
36 namespace Internal
37 {
38 namespace
39 {
40 // Signals
41
42 const char* const SIGNAL_KEY_INPUT_FOCUS_CHANGED = "keyInputFocusChanged";
43
44 } // namespace
45
46 KeyInputFocusManager::KeyInputFocusManager()
47 : mSlotDelegate(this),
48   mCurrentFocusControl()
49 {
50   // Retrieve all the existing widnows
51   Dali::SceneHolderList sceneHolders = Adaptor::Get().GetSceneHolders();
52   for(auto iter = sceneHolders.begin(); iter != sceneHolders.end(); ++iter)
53   {
54     (*iter).KeyEventGeneratedSignal().Connect(mSlotDelegate, &KeyInputFocusManager::OnKeyEvent);
55   }
56
57   // Get notified when any new scene holder is created afterwards
58   Adaptor::Get().WindowCreatedSignal().Connect(mSlotDelegate, &KeyInputFocusManager::OnSceneHolderCreated);
59 }
60
61 KeyInputFocusManager::~KeyInputFocusManager()
62 {
63 }
64
65 void KeyInputFocusManager::OnSceneHolderCreated(Dali::Integration::SceneHolder& sceneHolder)
66 {
67   sceneHolder.KeyEventGeneratedSignal().Connect(mSlotDelegate, &KeyInputFocusManager::OnKeyEvent);
68 }
69
70 void KeyInputFocusManager::SetFocus(Toolkit::Control control)
71 {
72   if(!control)
73   {
74     // No-op
75     return;
76   }
77
78   if(control == mCurrentFocusControl)
79   {
80     // Control already has focus
81     return;
82   }
83
84   control.OffSceneSignal().Connect(mSlotDelegate, &KeyInputFocusManager::OnFocusControlSceneDisconnection);
85
86   Dali::Toolkit::Control previousFocusControl = GetCurrentFocusControl();
87   if(previousFocusControl)
88   {
89     // Notify the control that it has lost key input focus
90     GetImplementation(previousFocusControl).OnKeyInputFocusLost();
91   }
92
93   // Set control to currentFocusControl
94   mCurrentFocusControl = control;
95
96   // Tell the new actor that it has gained focus.
97   GetImplementation(control).OnKeyInputFocusGained();
98
99   // Emit the signal to inform focus change to the application.
100   if(!mKeyInputFocusChangedSignal.Empty())
101   {
102     mKeyInputFocusChangedSignal.Emit(control, previousFocusControl);
103   }
104 }
105
106 void KeyInputFocusManager::RemoveFocus(Toolkit::Control control)
107 {
108   if(control == mCurrentFocusControl)
109   {
110     control.OffSceneSignal().Disconnect(mSlotDelegate, &KeyInputFocusManager::OnFocusControlSceneDisconnection);
111
112     // Notify the control that it has lost key input focus
113     GetImplementation(control).OnKeyInputFocusLost();
114
115     mCurrentFocusControl.Reset();
116   }
117 }
118
119 Toolkit::Control KeyInputFocusManager::GetCurrentFocusControl() const
120 {
121   return mCurrentFocusControl;
122 }
123
124 Toolkit::KeyInputFocusManager::KeyInputFocusChangedSignalType& KeyInputFocusManager::KeyInputFocusChangedSignal()
125 {
126   return mKeyInputFocusChangedSignal;
127 }
128
129 bool KeyInputFocusManager::OnKeyEvent(const KeyEvent& event)
130 {
131   bool consumed = false;
132
133   Toolkit::Control control = GetCurrentFocusControl();
134   if(control)
135   {
136     Dali::Actor dispatch = control;
137     while(dispatch)
138     {
139       // If the DISPATCH_KEY_EVENTS is false, it cannot emit key event.
140       Toolkit::Control dispatchControl = Toolkit::Control::DownCast(dispatch);
141       if(dispatchControl && !dispatchControl.GetProperty<bool>(Toolkit::DevelControl::Property::DISPATCH_KEY_EVENTS))
142       {
143         return true;
144       }
145       dispatch = dispatch.GetParent();
146     }
147
148     // Notify the control about the key event
149     consumed = EmitKeyEventSignal(control, event);
150   }
151
152   return consumed;
153 }
154
155 bool KeyInputFocusManager::EmitKeyEventSignal(Toolkit::Control control, const KeyEvent& event)
156 {
157   bool consumed = false;
158
159   if(control)
160   {
161     consumed = GetImplementation(control).EmitKeyEventSignal(event);
162
163     // if control doesn't consume KeyEvent, give KeyEvent to its parent.
164     if(!consumed)
165     {
166       Toolkit::Control parent = Toolkit::Control::DownCast(control.GetParent());
167
168       if(parent)
169       {
170         consumed = EmitKeyEventSignal(parent, event);
171       }
172     }
173   }
174
175   return consumed;
176 }
177
178 void KeyInputFocusManager::OnFocusControlSceneDisconnection(Dali::Actor actor)
179 {
180   RemoveFocus(Dali::Toolkit::Control::DownCast(actor));
181 }
182
183 bool KeyInputFocusManager::DoConnectSignal(BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor)
184 {
185   bool                  connected(true);
186   KeyInputFocusManager* manager = dynamic_cast<KeyInputFocusManager*>(object);
187
188   if(manager)
189   {
190     if(0 == strcmp(signalName.c_str(), SIGNAL_KEY_INPUT_FOCUS_CHANGED))
191     {
192       manager->KeyInputFocusChangedSignal().Connect(tracker, functor);
193     }
194     else
195     {
196       // signalName does not match any signal
197       connected = false;
198     }
199   }
200
201   return connected;
202 }
203
204 } // namespace Internal
205
206 } // namespace Toolkit
207
208 } // namespace Dali