From ff1b30e653d792d77c85a9fe6f20620a90d7a46c Mon Sep 17 00:00:00 2001 From: David Steele Date: Mon, 27 Oct 2014 17:06:12 +0000 Subject: [PATCH] Improved key-input focus manager performance [model] KIRAN [binary_type] Lite [customer] OPEN [issue#] N/A [problem] KeyInput focus manager uses actor ID's and traverses the entire actor tree for all focus methods. [cause] Bad programming [solution] Changed stack to use BaseObject pointers. Track object lifetime using the registry (Controls are automatically registered). [team] Graphics [request] N/A [horizontal_expansion] N/A Change-Id: I4e49f0ca5adb990a71bedb8a4b5e6c08114db43c Signed-off-by: David Steele --- .../utc-Dali-KeyInputFocusManager.cpp | 416 ++++++++++++++++-- .../keyinput-focus-manager-impl.cpp | 161 +++---- .../keyinput-focus-manager-impl.h | 41 +- 3 files changed, 496 insertions(+), 122 deletions(-) diff --git a/automated-tests/src/dali-toolkit-unmanaged/utc-Dali-KeyInputFocusManager.cpp b/automated-tests/src/dali-toolkit-unmanaged/utc-Dali-KeyInputFocusManager.cpp index 2e087c338b..ab377f67c5 100644 --- a/automated-tests/src/dali-toolkit-unmanaged/utc-Dali-KeyInputFocusManager.cpp +++ b/automated-tests/src/dali-toolkit-unmanaged/utc-Dali-KeyInputFocusManager.cpp @@ -21,6 +21,7 @@ #include #include +#include "dummy-control.h" using namespace Dali; using namespace Toolkit; @@ -125,21 +126,78 @@ int UtcDaliKeyInputFocusManagerGet(void) END_TEST; } -int UtcDaliKeyInputFocusManagerSetFocus(void) +int UtcDaliKeyInputFocusManagerSetFocus01(void) { ToolkitTestApplication application; Stage stage = Stage::GetCurrent(); - tet_infoline(" UtcDaliKeyInputFocusManagerSetFocus"); + tet_infoline(" Check that there is no focused control. Add a control to the stack. Check it is now the focused actor and receives KeyInputFocusGained signal"); KeyInputFocusManager manager = KeyInputFocusManager::Get(); DALI_TEST_CHECK(manager); - PushButton pushButton1 = PushButton::New(); - stage.Add( pushButton1 ); + Control focusedControl = manager.GetCurrentFocusControl(); + DALI_TEST_CHECK( ! focusedControl ); + + DummyControl dummy = DummyControl::New(true); + DummyControlImplOverride& dummyImpl = static_cast(dummy.GetImplementation()); + dummy.SetSize(100.0f, 100.0f); + stage.Add( dummy ); + DALI_TEST_CHECK( ! dummyImpl.keyInputFocusGained ); + + manager.SetFocus( dummy ); + DALI_TEST_CHECK( dummy.HasKeyInputFocus()); // Also tests IsKeyboardListener() API + DALI_TEST_CHECK( dummyImpl.keyInputFocusGained ); + + focusedControl = manager.GetCurrentFocusControl(); + DALI_TEST_CHECK( focusedControl ); + DALI_TEST_CHECK( focusedControl == dummy ); + + END_TEST; +} + +int UtcDaliKeyInputFocusManagerSetFocus02(void) +{ + ToolkitTestApplication application; + Stage stage = Stage::GetCurrent(); + + tet_infoline(" Add a control to the stack. Check it is now the focused actor and receives KeyInputFocusGained signal. Add another control - check that the first control receives KeyInputFocusLost"); + + KeyInputFocusManager manager = KeyInputFocusManager::Get(); + DALI_TEST_CHECK(manager); + + DummyControl dummy1 = DummyControl::New(true); + DummyControlImplOverride& dummy1Impl = static_cast(dummy1.GetImplementation()); + dummy1.SetSize(100.0f, 100.0f); + stage.Add( dummy1 ); + DALI_TEST_CHECK( ! dummy1Impl.keyInputFocusGained ); + DALI_TEST_CHECK( ! dummy1Impl.keyInputFocusLost ); + + stage.Add( dummy1 ); + + manager.SetFocus( dummy1 ); + DALI_TEST_CHECK( dummy1.HasKeyInputFocus()); // Also tests IsKeyboardListener() API + DALI_TEST_CHECK( dummy1Impl.keyInputFocusGained ); + dummy1Impl.keyInputFocusGained = false; + + DummyControl dummy2 = DummyControl::New(true); + DummyControlImplOverride& dummy2Impl = static_cast(dummy2.GetImplementation()); + dummy2.SetSize(100.0f, 100.0f); + stage.Add( dummy2 ); + DALI_TEST_CHECK( ! dummy2Impl.keyInputFocusGained ); + DALI_TEST_CHECK( ! dummy1Impl.keyInputFocusLost ); + + stage.Add( dummy2 ); + + manager.SetFocus( dummy2 ); + DALI_TEST_CHECK( dummy2.HasKeyInputFocus()); // Also tests IsKeyboardListener() API + DALI_TEST_CHECK( dummy2Impl.keyInputFocusGained ); + dummy1Impl.keyInputFocusGained = false; + + DALI_TEST_CHECK( ! dummy1Impl.keyInputFocusGained ); + DALI_TEST_CHECK( dummy1Impl.keyInputFocusLost ); + - manager.SetFocus(pushButton1); - DALI_TEST_CHECK(pushButton1.HasKeyInputFocus()); END_TEST; } @@ -148,53 +206,355 @@ int UtcDaliKeyInputFocusManagerGetCurrentFocusControl(void) ToolkitTestApplication application; Stage stage = Stage::GetCurrent(); - tet_infoline(" UtcDaliKeyInputFocusManagerGetCurrentFocusControl"); + tet_infoline(" Add 2 controls, check they each get focused. Re-focus the first control - ensure it's now got focus (check signals)"); KeyInputFocusManager manager = KeyInputFocusManager::Get(); DALI_TEST_CHECK(manager); - PushButton pushButton1 = PushButton::New(); - PushButton pushButton2 = PushButton::New(); - stage.Add( pushButton1 ); - stage.Add( pushButton2 ); + DummyControl dummy1 = DummyControl::New(true); + DummyControlImplOverride& dummy1Impl = static_cast(dummy1.GetImplementation()); + dummy1.SetSize(100.0f, 100.0f); + stage.Add( dummy1 ); + DALI_TEST_CHECK( ! dummy1Impl.keyInputFocusGained ); + DALI_TEST_CHECK( ! dummy1Impl.keyInputFocusLost ); + + DummyControl dummy2 = DummyControl::New(true); + DummyControlImplOverride& dummy2Impl = static_cast(dummy2.GetImplementation()); + dummy2.SetSize(100.0f, 100.0f); + stage.Add( dummy2 ); + DALI_TEST_CHECK( ! dummy2Impl.keyInputFocusGained ); + DALI_TEST_CHECK( ! dummy2Impl.keyInputFocusLost ); + + manager.SetFocus(dummy1); + DALI_TEST_CHECK( dummy1 == manager.GetCurrentFocusControl() ); + DALI_TEST_CHECK( dummy1Impl.keyInputFocusGained ); + DALI_TEST_CHECK( ! dummy1Impl.keyInputFocusLost ); + dummy1Impl.keyInputFocusGained = false; + dummy1Impl.keyInputFocusLost = false; + + manager.SetFocus(dummy2); + DALI_TEST_CHECK( dummy2 == manager.GetCurrentFocusControl() ); + DALI_TEST_CHECK( dummy1Impl.keyInputFocusLost ); + DALI_TEST_CHECK( dummy2Impl.keyInputFocusGained ); + DALI_TEST_CHECK( ! dummy1Impl.keyInputFocusGained ); + DALI_TEST_CHECK( ! dummy2Impl.keyInputFocusLost ); + // Reset signal received + dummy1Impl.keyInputFocusGained = false; + dummy1Impl.keyInputFocusLost = false; + dummy2Impl.keyInputFocusGained = false; + dummy2Impl.keyInputFocusLost = false; + + manager.SetFocus(dummy1); + DALI_TEST_CHECK( dummy1 == manager.GetCurrentFocusControl()); + DALI_TEST_CHECK( dummy1Impl.keyInputFocusGained ); + DALI_TEST_CHECK( dummy2Impl.keyInputFocusLost ); + DALI_TEST_CHECK( ! dummy1Impl.keyInputFocusLost ); + DALI_TEST_CHECK( ! dummy2Impl.keyInputFocusGained ); + END_TEST; +} - manager.SetFocus(pushButton1); - DALI_TEST_CHECK(pushButton1 == manager.GetCurrentFocusControl()); +int UtcDaliKeyInputFocusManagerRemoveFocus01(void) +{ + ToolkitTestApplication application; + Stage stage = Stage::GetCurrent(); - manager.SetFocus(pushButton2); - DALI_TEST_CHECK(pushButton2 == manager.GetCurrentFocusControl()); + tet_infoline(" Add 3 focus controls. Test that removing the topmost informs the next control that it now has focus, Test that the bottommost control doesn't receive anything. "); + + KeyInputFocusManager manager = KeyInputFocusManager::Get(); + DALI_TEST_CHECK(manager); + + DummyControl dummy1 = DummyControl::New(true); + DummyControlImplOverride& dummy1Impl = static_cast(dummy1.GetImplementation()); + dummy1.SetSize(100.0f, 100.0f); + stage.Add( dummy1 ); + DALI_TEST_CHECK( ! dummy1Impl.keyInputFocusGained ); + DALI_TEST_CHECK( ! dummy1Impl.keyInputFocusLost ); + + DummyControl dummy2 = DummyControl::New(true); + DummyControlImplOverride& dummy2Impl = static_cast(dummy2.GetImplementation()); + dummy2.SetSize(100.0f, 100.0f); + stage.Add( dummy2 ); + DALI_TEST_CHECK( ! dummy2Impl.keyInputFocusGained ); + DALI_TEST_CHECK( ! dummy2Impl.keyInputFocusLost ); + + manager.SetFocus(dummy1); + DALI_TEST_CHECK(dummy1 == manager.GetCurrentFocusControl()); + + manager.SetFocus(dummy2); + DALI_TEST_CHECK(dummy2 == manager.GetCurrentFocusControl()); + dummy1Impl.keyInputFocusGained = false; + dummy1Impl.keyInputFocusLost = false; + dummy2Impl.keyInputFocusGained = false; + dummy2Impl.keyInputFocusLost = false; + + manager.RemoveFocus(dummy2); + DALI_TEST_CHECK(dummy1 == manager.GetCurrentFocusControl()); + DALI_TEST_CHECK( dummy1Impl.keyInputFocusGained ); + DALI_TEST_CHECK( dummy2Impl.keyInputFocusLost ); + DALI_TEST_CHECK( ! dummy1Impl.keyInputFocusLost ); + DALI_TEST_CHECK( ! dummy2Impl.keyInputFocusGained ); + dummy1Impl.keyInputFocusGained = false; + dummy1Impl.keyInputFocusLost = false; + dummy2Impl.keyInputFocusGained = false; + dummy2Impl.keyInputFocusLost = false; + + manager.RemoveFocus(dummy1); + DALI_TEST_CHECK(Control() == manager.GetCurrentFocusControl()); + DALI_TEST_CHECK( dummy1Impl.keyInputFocusLost ); + DALI_TEST_CHECK( ! dummy2Impl.keyInputFocusLost ); + DALI_TEST_CHECK( ! dummy1Impl.keyInputFocusGained ); + DALI_TEST_CHECK( ! dummy2Impl.keyInputFocusGained ); - manager.SetFocus(pushButton1); - DALI_TEST_CHECK(pushButton1 == manager.GetCurrentFocusControl()); END_TEST; } -int UtcDaliKeyInputFocusManagerRemoveFocus(void) +int UtcDaliKeyInputFocusManagerRemoveFocus02(void) { ToolkitTestApplication application; Stage stage = Stage::GetCurrent(); - tet_infoline(" UtcDaliKeyInputFocusManagerRemoveFocus"); + tet_infoline(" Add 3 focus controls. Test that removing the bottommost doesn't change the focused control" ); KeyInputFocusManager manager = KeyInputFocusManager::Get(); DALI_TEST_CHECK(manager); + DummyControl dummy1 = DummyControl::New(true); + DummyControlImplOverride& dummy1Impl = static_cast(dummy1.GetImplementation()); + dummy1.SetSize(100.0f, 100.0f); + stage.Add( dummy1 ); + DALI_TEST_CHECK( ! dummy1Impl.keyInputFocusGained ); + DALI_TEST_CHECK( ! dummy1Impl.keyInputFocusLost ); + + DummyControl dummy2 = DummyControl::New(true); + DummyControlImplOverride& dummy2Impl = static_cast(dummy2.GetImplementation()); + dummy2.SetSize(100.0f, 100.0f); + stage.Add( dummy2 ); + DALI_TEST_CHECK( ! dummy2Impl.keyInputFocusGained ); + DALI_TEST_CHECK( ! dummy2Impl.keyInputFocusLost ); + + DummyControl dummy3 = DummyControl::New(true); + DummyControlImplOverride& dummy3Impl = static_cast(dummy3.GetImplementation()); + dummy3.SetSize(100.0f, 100.0f); + stage.Add( dummy3 ); + DALI_TEST_CHECK( ! dummy3Impl.keyInputFocusGained ); + DALI_TEST_CHECK( ! dummy3Impl.keyInputFocusLost ); + + manager.SetFocus(dummy1); + DALI_TEST_CHECK(dummy1 == manager.GetCurrentFocusControl()); + + manager.SetFocus(dummy2); + DALI_TEST_CHECK(dummy2 == manager.GetCurrentFocusControl()); + + manager.SetFocus(dummy3); + DALI_TEST_CHECK(dummy3 == manager.GetCurrentFocusControl()); + dummy1Impl.keyInputFocusGained = false; + dummy1Impl.keyInputFocusLost = false; + dummy2Impl.keyInputFocusGained = false; + dummy2Impl.keyInputFocusLost = false; + dummy3Impl.keyInputFocusGained = false; + dummy3Impl.keyInputFocusLost = false; + + manager.RemoveFocus(dummy1); + DALI_TEST_CHECK(dummy3 == manager.GetCurrentFocusControl()); + DALI_TEST_CHECK( dummy1Impl.keyInputFocusLost ); + DALI_TEST_CHECK( ! dummy1Impl.keyInputFocusGained ); + DALI_TEST_CHECK( ! dummy2Impl.keyInputFocusLost ); + DALI_TEST_CHECK( ! dummy2Impl.keyInputFocusGained ); + DALI_TEST_CHECK( ! dummy3Impl.keyInputFocusLost ); + DALI_TEST_CHECK( ! dummy3Impl.keyInputFocusGained ); + dummy1Impl.keyInputFocusGained = false; + dummy1Impl.keyInputFocusLost = false; + dummy2Impl.keyInputFocusGained = false; + dummy2Impl.keyInputFocusLost = false; + dummy3Impl.keyInputFocusGained = false; + dummy3Impl.keyInputFocusLost = false; + + END_TEST; +} + +int UtcDaliKeyInputFocusManagerRemoveFocus03(void) +{ + ToolkitTestApplication application; + Stage stage = Stage::GetCurrent(); + + tet_infoline(" Add 2 focus controls. Remove each of them from the bottom up. Test that the stack is now empty. Add a new control - check that it correctly has focus" ); + + KeyInputFocusManager manager = KeyInputFocusManager::Get(); + DALI_TEST_CHECK(manager); + + DummyControl dummy1 = DummyControl::New(true); + DummyControlImplOverride& dummy1Impl = static_cast(dummy1.GetImplementation()); + dummy1.SetSize(100.0f, 100.0f); + stage.Add( dummy1 ); + DALI_TEST_CHECK( ! dummy1Impl.keyInputFocusGained ); + DALI_TEST_CHECK( ! dummy1Impl.keyInputFocusLost ); + + DummyControl dummy2 = DummyControl::New(true); + DummyControlImplOverride& dummy2Impl = static_cast(dummy2.GetImplementation()); + dummy2.SetSize(100.0f, 100.0f); + stage.Add( dummy2 ); + DALI_TEST_CHECK( ! dummy2Impl.keyInputFocusGained ); + DALI_TEST_CHECK( ! dummy2Impl.keyInputFocusLost ); + + manager.SetFocus(dummy1); + DALI_TEST_CHECK(dummy1 == manager.GetCurrentFocusControl()); + + manager.SetFocus(dummy2); + DALI_TEST_CHECK(dummy2 == manager.GetCurrentFocusControl()); + + dummy1Impl.keyInputFocusGained = false; + dummy1Impl.keyInputFocusLost = false; + dummy2Impl.keyInputFocusGained = false; + dummy2Impl.keyInputFocusLost = false; + + manager.RemoveFocus(dummy1); + DALI_TEST_CHECK(dummy2 == manager.GetCurrentFocusControl()); + DALI_TEST_CHECK( dummy1Impl.keyInputFocusLost ); + DALI_TEST_CHECK( ! dummy1Impl.keyInputFocusGained ); + DALI_TEST_CHECK( ! dummy2Impl.keyInputFocusLost ); + DALI_TEST_CHECK( ! dummy2Impl.keyInputFocusGained ); + dummy1Impl.keyInputFocusGained = false; + dummy1Impl.keyInputFocusLost = false; + dummy2Impl.keyInputFocusGained = false; + dummy2Impl.keyInputFocusLost = false; + + manager.RemoveFocus(dummy2); + DALI_TEST_CHECK(Control() == manager.GetCurrentFocusControl()); + DALI_TEST_CHECK( dummy2Impl.keyInputFocusLost ); + DALI_TEST_CHECK( ! dummy2Impl.keyInputFocusGained ); + DALI_TEST_CHECK( ! dummy1Impl.keyInputFocusLost ); + DALI_TEST_CHECK( ! dummy1Impl.keyInputFocusGained ); + dummy1Impl.keyInputFocusGained = false; + dummy1Impl.keyInputFocusLost = false; + dummy2Impl.keyInputFocusGained = false; + dummy2Impl.keyInputFocusLost = false; + + PushButton pushButton1 = PushButton::New(); + stage.Add( pushButton1 ); + manager.SetFocus( pushButton1 ); + DALI_TEST_CHECK( ! dummy1Impl.keyInputFocusLost ); + DALI_TEST_CHECK( ! dummy2Impl.keyInputFocusLost ); + DALI_TEST_CHECK( pushButton1 == manager.GetCurrentFocusControl()); + END_TEST; +} + +int UtcDaliKeyInputFocusManagerRemoveFocus04(void) +{ + ToolkitTestApplication application; + Stage stage = Stage::GetCurrent(); + + tet_infoline(" Test what happens if the removed control is not on the focus stack"); + KeyInputFocusManager manager = KeyInputFocusManager::Get(); + DALI_TEST_CHECK(manager); + PushButton pushButton1 = PushButton::New(); PushButton pushButton2 = PushButton::New(); stage.Add( pushButton1 ); stage.Add( pushButton2 ); + manager.SetFocus( pushButton1 ); + manager.SetFocus( pushButton2 ); - manager.SetFocus(pushButton1); - DALI_TEST_CHECK(pushButton1 == manager.GetCurrentFocusControl()); + PushButton pushButton3 = PushButton::New(); + stage.Add( pushButton3 ); + manager.RemoveFocus( pushButton3 ); + DALI_TEST_CHECK( pushButton2 == manager.GetCurrentFocusControl()); + END_TEST; +} - manager.SetFocus(pushButton2); - DALI_TEST_CHECK(pushButton2 == manager.GetCurrentFocusControl()); +int UtcDaliKeyInputFocusManagerDestroyObject01(void) +{ + ToolkitTestApplication application; + Stage stage = Stage::GetCurrent(); - manager.RemoveFocus(pushButton2); - DALI_TEST_CHECK(pushButton1 == manager.GetCurrentFocusControl()); + tet_infoline(" Add 2 controls to the stack. Unparent and destroy the topmost. Check that it is removed from the stack, and that the bottommost is correctly focused" ); - manager.RemoveFocus(pushButton1); - DALI_TEST_CHECK(Control() == manager.GetCurrentFocusControl()); + KeyInputFocusManager manager = KeyInputFocusManager::Get(); + DALI_TEST_CHECK(manager); + + DummyControl dummy1 = DummyControl::New(true); + DummyControlImplOverride& dummy1Impl = static_cast(dummy1.GetImplementation()); + dummy1.SetSize(100.0f, 100.0f); + stage.Add( dummy1 ); + DALI_TEST_CHECK( ! dummy1Impl.keyInputFocusGained ); + DALI_TEST_CHECK( ! dummy1Impl.keyInputFocusLost ); + + { + DummyControl dummy2 = DummyControl::New(true); + DummyControlImplOverride& dummy2Impl = static_cast(dummy2.GetImplementation()); + dummy2.SetSize(100.0f, 100.0f); + stage.Add( dummy2 ); + DALI_TEST_CHECK( ! dummy2Impl.keyInputFocusGained ); + DALI_TEST_CHECK( ! dummy2Impl.keyInputFocusLost ); + + manager.SetFocus(dummy1); + DALI_TEST_CHECK(dummy1 == manager.GetCurrentFocusControl()); + + manager.SetFocus(dummy2); + DALI_TEST_CHECK(dummy2 == manager.GetCurrentFocusControl()); + + dummy1Impl.keyInputFocusGained = false; + dummy1Impl.keyInputFocusLost = false; + dummy2Impl.keyInputFocusGained = false; + dummy2Impl.keyInputFocusLost = false; + + stage.Remove(dummy2); + } + + DALI_TEST_CHECK(dummy1 == manager.GetCurrentFocusControl()); + DALI_TEST_CHECK( dummy1Impl.keyInputFocusGained ); + DALI_TEST_CHECK( ! dummy1Impl.keyInputFocusLost ); + END_TEST; +} + +int UtcDaliKeyInputFocusManagerDestroyObject02(void) +{ + ToolkitTestApplication application; + Stage stage = Stage::GetCurrent(); + + tet_infoline(" Add 2 controls to the stack. Destroy a different actor entirely. Check that the stack is un-affected."); + + KeyInputFocusManager manager = KeyInputFocusManager::Get(); + DALI_TEST_CHECK(manager); + + DummyControl dummy1 = DummyControl::New(true); + DummyControlImplOverride& dummy1Impl = static_cast(dummy1.GetImplementation()); + dummy1.SetSize(100.0f, 100.0f); + stage.Add( dummy1 ); + DALI_TEST_CHECK( ! dummy1Impl.keyInputFocusGained ); + DALI_TEST_CHECK( ! dummy1Impl.keyInputFocusLost ); + + + DummyControl dummy2 = DummyControl::New(true); + DummyControlImplOverride& dummy2Impl = static_cast(dummy2.GetImplementation()); + dummy2.SetSize(100.0f, 100.0f); + stage.Add( dummy2 ); + DALI_TEST_CHECK( ! dummy2Impl.keyInputFocusGained ); + DALI_TEST_CHECK( ! dummy2Impl.keyInputFocusLost ); + + manager.SetFocus(dummy1); + DALI_TEST_CHECK(dummy1 == manager.GetCurrentFocusControl()); + + manager.SetFocus(dummy2); + DALI_TEST_CHECK(dummy2 == manager.GetCurrentFocusControl()); + + dummy1Impl.keyInputFocusGained = false; + dummy1Impl.keyInputFocusLost = false; + dummy2Impl.keyInputFocusGained = false; + dummy2Impl.keyInputFocusLost = false; + + { + BitmapImage image = CreateBitmapImage(); + ImageActor imageActor = ImageActor::New( image ); + stage.Add( imageActor ); + imageActor.SetSize(100, 100); + + application.SendNotification(); + application.Render(); + + stage.Remove( imageActor ); + } + + DALI_TEST_CHECK( dummy2 == manager.GetCurrentFocusControl()); END_TEST; } @@ -296,7 +656,7 @@ int UtcDaliKeyInputFocusManagerSignalUnhandledKeyEvent(void) DALI_TEST_CHECK(event.keyName == data.receivedKeyEvent.keyPressedName ); DALI_TEST_CHECK(event.keyCode == data.receivedKeyEvent.keyCode); DALI_TEST_CHECK(event.keyString == data.receivedKeyEvent.keyPressed ); - DALI_TEST_CHECK(static_cast( event.state ) == static_cast( data.receivedKeyEvent.state ) ); + DALI_TEST_CHECK(event.state == static_cast(data.receivedKeyEvent.state) ); data.Reset(); diff --git a/base/dali-toolkit/internal/focus-manager/keyinput-focus-manager-impl.cpp b/base/dali-toolkit/internal/focus-manager/keyinput-focus-manager-impl.cpp index 954ce3a41d..65a9ec9cc3 100644 --- a/base/dali-toolkit/internal/focus-manager/keyinput-focus-manager-impl.cpp +++ b/base/dali-toolkit/internal/focus-manager/keyinput-focus-manager-impl.cpp @@ -39,52 +39,48 @@ KeyInputFocusManager::KeyInputFocusManager() : mSlotDelegate( this ) { Stage::GetCurrent().KeyEventSignal().Connect(mSlotDelegate, &KeyInputFocusManager::OnKeyEvent); + mObjectRegistry = Dali::Stage::GetCurrent().GetObjectRegistry(); + mObjectRegistry.ObjectDestroyedSignal().Connect( this, &KeyInputFocusManager::OnObjectDestroyed ); } KeyInputFocusManager::~KeyInputFocusManager() { } -void KeyInputFocusManager::SetFocus(Toolkit::Control control) +void KeyInputFocusManager::SetFocus( Toolkit::Control control ) { - if(!control) + if( !control ) { - //No-op + // No-op return; } - unsigned int actorID = control.GetId(); + FocusStackIterator pos = FindFocusControlInStack( control ); - ActorQueueIterator pos = std::find( mFocusActorsQueue.begin(), mFocusActorsQueue.end(), actorID); - - if((!mFocusActorsQueue.empty()) && (pos == mFocusActorsQueue.begin())) + if( ( mFocusStack.Count() != 0 ) && ( pos == mFocusStack.End()-1 ) ) { - //Actor allready in front, so No-op + // Control already in front, so No-op return; } - if(pos != mFocusActorsQueue.end()) + if( pos != mFocusStack.End() ) { - //A previously focused actor wants to regain focus - mFocusActorsQueue.erase(pos); + // A previously focused control wants to regain focus + mFocusStack.Erase( pos ); } else { - control.OffStageSignal().Connect( mSlotDelegate, &KeyInputFocusManager::OnFocusActorStageDisconnection ); + control.OffStageSignal().Connect( mSlotDelegate, &KeyInputFocusManager::OnFocusControlStageDisconnection ); } - Dali::Toolkit::Control previousFocusControl; - if(!mFocusActorsQueue.empty()) + Dali::Toolkit::Control previousFocusControl = GetCurrentFocusControl(); + if( previousFocusControl ) { - previousFocusControl = Dali::Toolkit::Control::DownCast(Stage::GetCurrent().GetRootLayer().FindChildById(mFocusActorsQueue.front())); - if(previousFocusControl) - { - // Notify the control that it has lost key input focus - previousFocusControl.GetImplementation().OnKeyInputFocusLost(); - } + // Notify the control that it has lost key input focus + previousFocusControl.GetImplementation().OnKeyInputFocusLost(); } - mFocusActorsQueue.push_front(actorID); + mFocusStack.PushBack( &control.GetBaseObject() ); // Tell the new actor that it has gained focus. control.GetImplementation().OnKeyInputFocusGained(); @@ -96,72 +92,60 @@ void KeyInputFocusManager::SetFocus(Toolkit::Control control) } } -Toolkit::Control KeyInputFocusManager::GetCurrentFocusControl() const -{ - Toolkit::Control currentFocusControl; - - if(!mFocusActorsQueue.empty()) - { - currentFocusControl = Dali::Toolkit::Control::DownCast(Stage::GetCurrent().GetRootLayer().FindChildById(mFocusActorsQueue.front())); - } - - return currentFocusControl; -} - -void KeyInputFocusManager::RemoveFocus(Toolkit::Control control) +void KeyInputFocusManager::RemoveFocus( Toolkit::Control control ) { - if(control) + if( control ) { - unsigned int actorId = control.GetId(); - ActorQueueIterator pos = std::find( mFocusActorsQueue.begin(), mFocusActorsQueue.end(), actorId); - - if(pos != mFocusActorsQueue.end()) + FocusStackIterator pos = FindFocusControlInStack( control ); + if( pos != mFocusStack.End() ) { - control.OffStageSignal().Disconnect( mSlotDelegate, &KeyInputFocusManager::OnFocusActorStageDisconnection ); + control.OffStageSignal().Disconnect( mSlotDelegate, &KeyInputFocusManager::OnFocusControlStageDisconnection ); // Notify the control that it has lost key input focus control.GetImplementation().OnKeyInputFocusLost(); - if(pos == mFocusActorsQueue.begin()) + // If this is the top-most actor, pop it and change focus to the previous control + if( pos == mFocusStack.End() - 1 ) { - Actor previousFocusActor; - - mFocusActorsQueue.erase(pos); - if(!mFocusActorsQueue.empty()) - { - previousFocusActor = Stage::GetCurrent().GetRootLayer().FindChildById(mFocusActorsQueue.front()); - } + mFocusStack.Erase( pos ); - Dali::Toolkit::Control previouscontrol = Dali::Toolkit::Control::DownCast(previousFocusActor); - if(previouscontrol) + Toolkit::Control previouslyFocusedControl = GetCurrentFocusControl(); + if( previouslyFocusedControl ) { - // Tell the new actor that it has gained focus. - previouscontrol.GetImplementation().OnKeyInputFocusGained(); + // Tell the control that it has gained focus. + previouslyFocusedControl.GetImplementation().OnKeyInputFocusGained(); } } else { - //If the removed actor is not currently focused, then no need to emit signal. - mFocusActorsQueue.erase(pos); + // If the removed control is not currently focused, then no need to emit signal. + mFocusStack.Erase( pos ); } - } } } -bool KeyInputFocusManager::IsKeyboardListener(Toolkit::Control control) const +Toolkit::Control KeyInputFocusManager::GetCurrentFocusControl() const { - bool result = false; + Toolkit::Control currentControl; - if(!mFocusActorsQueue.empty()) + FocusStack::SizeType count = mFocusStack.Count(); + if( count != 0 ) { - unsigned int actorId = control.GetId(); - ActorQueueConstIterator pos = std::find(mFocusActorsQueue.begin(), mFocusActorsQueue.end(), actorId); + BaseObject* object = mFocusStack[ count - 1 ]; + BaseHandle handle( object ); + currentControl = Dali::Toolkit::Control::DownCast( handle ); + } + return currentControl; +} - if(pos != mFocusActorsQueue.end()) - { - result = true; - } +bool KeyInputFocusManager::IsKeyboardListener( Toolkit::Control control ) const +{ + bool result = false; + + if( FindFocusControlInStack( control ) != mFocusStack.End() ) + { + result = true; } return result; @@ -177,27 +161,34 @@ Toolkit::KeyInputFocusManager::UnhandledKeyEventSignalV2& KeyInputFocusManager:: return mUnhandledKeyEventSignalV2; } -void KeyInputFocusManager::OnKeyEvent(const KeyEvent& event) +KeyInputFocusManager::FocusStackIterator KeyInputFocusManager::FindFocusControlInStack( Toolkit::Control control ) const { - bool consumed = false; - - ActorQueueIterator iter = mFocusActorsQueue.begin(); + BaseObject* controlObject = &control.GetBaseObject(); + return std::find( mFocusStack.Begin(), mFocusStack.End(), controlObject ); +} - Layer rootLayer = Stage::GetCurrent().GetRootLayer(); +void KeyInputFocusManager::OnKeyEvent( const KeyEvent& event ) +{ + bool consumed = false; - while(!mFocusActorsQueue.empty() && !consumed && (iter != mFocusActorsQueue.end())) + if( mFocusStack.Count() > 0 ) { - Actor actor = rootLayer.FindChildById(*iter); - Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor); - if(control) + FocusStack::SizeType index = mFocusStack.Count(); + while( mFocusStack.Count() != 0 && !consumed && index > 0 ) { - // Notify the control about the key event - consumed = control.GetImplementation().EmitKeyEventSignal(event); + --index; + BaseObject* object = mFocusStack[ index ]; + BaseHandle handle( object ); + Toolkit::Control control = Toolkit::Control::DownCast( object ); + if( control ) + { + // Notify the control about the key event + consumed = control.GetImplementation().EmitKeyEventSignal( event ); + } } - iter++; } - if(!consumed) + if( !consumed ) { // Emit signal to inform that a key event is not consumed. if( !mUnhandledKeyEventSignalV2.Empty() ) @@ -207,9 +198,21 @@ void KeyInputFocusManager::OnKeyEvent(const KeyEvent& event) } } -void KeyInputFocusManager::OnFocusActorStageDisconnection( Dali::Actor actor ) +void KeyInputFocusManager::OnFocusControlStageDisconnection( Dali::Actor actor ) { - RemoveFocus(Dali::Toolkit::Control::DownCast(actor)); + RemoveFocus( Dali::Toolkit::Control::DownCast( actor ) ); +} + +void KeyInputFocusManager::OnObjectDestroyed( const Dali::RefObject* object ) +{ + // The object is already destroyed. Don't create handles to it, or try sending + // signals to it. Remove it's pointer from the stack. + const BaseObject* baseObject = static_cast( object ); + FocusStackIterator pos = std::find( mFocusStack.Begin(), mFocusStack.End(), baseObject ); + if( pos != mFocusStack.End() ) + { + mFocusStack.Erase( pos ); + } } bool KeyInputFocusManager::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor ) diff --git a/base/dali-toolkit/internal/focus-manager/keyinput-focus-manager-impl.h b/base/dali-toolkit/internal/focus-manager/keyinput-focus-manager-impl.h index 43bd783c20..3db07439bd 100644 --- a/base/dali-toolkit/internal/focus-manager/keyinput-focus-manager-impl.h +++ b/base/dali-toolkit/internal/focus-manager/keyinput-focus-manager-impl.h @@ -20,8 +20,8 @@ // EXTERNAL INCLUDES #include -#include #include +#include // INTERNAL INCLUDES #include @@ -41,13 +41,11 @@ class KeyInputFocusManager; /** * @copydoc Toolkit::KeyInputFocusManager */ -class KeyInputFocusManager : public Dali::BaseObject +class KeyInputFocusManager : public Dali::BaseObject, public Dali::ConnectionTracker { public: - - typedef std::deque< unsigned int > ActorQueue; - typedef std::deque< unsigned int >::iterator ActorQueueIterator; - typedef std::deque< unsigned int >::const_iterator ActorQueueConstIterator; + typedef Dali::Vector< Dali::BaseObject* > FocusStack; + typedef FocusStack::Iterator FocusStackIterator; /** * Construct a new KeyInputFocusManager. @@ -60,14 +58,14 @@ public: void SetFocus(Toolkit::Control control); /** - * @copydoc Toolkit::GetCurrentFocusControl + * @copydoc Toolkit::RemoveFocus */ - Toolkit::Control GetCurrentFocusControl() const; + void RemoveFocus(Toolkit::Control control); /** - * @copydoc Toolkit::RemoveFocus + * @copydoc Toolkit::GetCurrentFocusControl */ - void RemoveFocus(Toolkit::Control control); + Toolkit::Control GetCurrentFocusControl() const; /** * @copydoc Toolkit::IsKeyboardListener @@ -106,6 +104,14 @@ protected: private: + /** + * Search for a control in the focus stack. + * @param[in] control The control for which to search + * @return An iterator to the control. If not found, this will equate to the + * mFocusStack.End() iterator. + */ + FocusStackIterator FindFocusControlInStack( Toolkit::Control control ) const; + /** * Callback for the key event when no actor in the stage has gained the key input focus * @param[in] event The KeyEvent event. @@ -113,10 +119,15 @@ private: void OnKeyEvent(const KeyEvent& event); /** - * Signal handler called when a focused Actor is removed from Stage. - * @param[in] actor The actor removed from stage. + * Signal handler called when a focused Control is removed from Stage. + * @param[in] control The control removed from stage. */ - void OnFocusActorStageDisconnection( Dali::Actor actor ); + void OnFocusControlStageDisconnection( Dali::Actor control ); + + /** + * Signal handler called when an actor is destroyed. + */ + void OnObjectDestroyed(const Dali::RefObject* object); private: @@ -134,9 +145,9 @@ private: Toolkit::KeyInputFocusManager::UnhandledKeyEventSignalV2 mUnhandledKeyEventSignalV2; // Keyboard events are sent to the current focus actor, which will be the actor on the top of the focus actors stack. - ActorQueue mFocusActorsQueue; - + FocusStack mFocusStack; SlotDelegate< KeyInputFocusManager > mSlotDelegate; + ObjectRegistry mObjectRegistry; }; } // namespace Internal -- 2.34.1