Whether the children of this actor can be focusable by keyboard navigation.
2. If DISPATCH_KEY_EVENTS property is false, the KeyEvent is not received.
Change-Id: I58c07ac04b90ce41c7b944c49a672a81be5bb574
#include <dali-toolkit-test-suite-utils.h>
#include <dali-toolkit/dali-toolkit.h>
#include <dali/integration-api/events/key-event-integ.h>
+#include <dali-toolkit/devel-api/controls/control-devel.h>
#include <dali-toolkit/devel-api/focus-manager/keyinput-focus-manager.h>
#include <dali/devel-api/common/stage-devel.h>
END_TEST;
}
+int UtcDaliKeyInputFocusManagerDispatchKeyEvents(void)
+{
+
+ ToolkitTestApplication application;
+ Integration::Scene stage = application.GetScene();
+
+ tet_infoline("Test KeyEvents propagation. If DISPATCH_KEY_EVENTS property is false, the KeyEvent is also not received.");
+
+ KeyInputFocusManager manager = KeyInputFocusManager::Get();
+ DALI_TEST_CHECK(manager);
+
+ DummyControl dummy1 = DummyControl::New(true);
+ dummy1.SetProperty( Actor::Property::SIZE, Vector2(100.0f, 100.0f) );
+ KeyEventCallback callback1( false );
+ dummy1.KeyEventSignal().Connect( &callback1, &KeyEventCallback::Callback );
+ stage.Add( dummy1 );
+
+ DummyControl dummy2 = DummyControl::New(true);
+ dummy2.SetProperty( Actor::Property::SIZE, Vector2(100.0f, 100.0f) );
+ KeyEventCallback callback2( false );
+ dummy2.KeyEventSignal().Connect( &callback2, &KeyEventCallback::Callback );
+ // dummy2 set DISPATCH_KEY_EVENTS property to false.
+ dummy2.SetProperty( Toolkit::DevelControl::Property::DISPATCH_KEY_EVENTS, false);
+ dummy1.Add( dummy2 );
+
+ DummyControl dummy3 = DummyControl::New(true);
+ Impl::DummyControl& dummy3Impl = static_cast<Impl::DummyControl&>(dummy3.GetImplementation());
+ dummy3.SetProperty( Actor::Property::SIZE, Vector2(100.0f, 100.0f) );
+ KeyEventCallback callback3( false );
+ dummy3.KeyEventSignal().Connect( &callback3, &KeyEventCallback::Callback );
+ dummy2.Add( dummy3 );
+ DALI_TEST_CHECK( ! dummy3Impl.keyInputFocusGained );
+ DALI_TEST_CHECK( ! dummy3Impl.keyInputFocusLost );
+
+ manager.SetFocus( dummy3 );
+ DALI_TEST_CHECK( dummy3Impl.keyInputFocusGained );
+
+ Integration::KeyEvent event( "a", "", "a", 0, 0, 0, Integration::KeyEvent::UP, "", "", Device::Class::TOUCH, Device::Subclass::NONE );
+ application.ProcessEvent(event);
+
+ DALI_TEST_CHECK( !callback1.mIsCalled );
+ DALI_TEST_CHECK( !callback2.mIsCalled );
+ DALI_TEST_CHECK( !callback3.mIsCalled );
+
+ END_TEST;
+}
+
int UtcDaliKeyInputFocusManagerGetCurrentFocusControl(void)
{
ToolkitTestApplication application;
DALI_TEST_CHECK(manager.GetCurrentFocusActor() == second);
END_TEST;
+}
+
+int UtcDaliKeyboardFocusManagerEnableDefaultAlgorithm(void)
+{
+ ToolkitTestApplication application;
+
+ tet_infoline(" UtcDaliKeyboardFocusManagerEnableDefaultAlgorithm");
+
+ // Register Type
+ TypeInfo type;
+ type = TypeRegistry::Get().GetTypeInfo( "KeyboardFocusManager" );
+ DALI_TEST_CHECK( type );
+ BaseHandle handle = type.CreateInstance();
+ DALI_TEST_CHECK( handle );
+
+ KeyboardFocusManager manager = KeyboardFocusManager::Get();
+ DALI_TEST_CHECK(manager);
+
+ bool focusChangedSignalVerified = false;
+ FocusChangedCallback focusChangedCallback(focusChangedSignalVerified);
+ manager.FocusChangedSignal().Connect( &focusChangedCallback, &FocusChangedCallback::Callback );
+
+ PushButton button1 = PushButton::New();
+ PushButton button2 = PushButton::New();
+
+ button1.SetProperty(Actor::Property::SIZE, Vector2(50, 50));
+ button2.SetProperty(Actor::Property::SIZE, Vector2(50, 50));
+
+ button1.SetProperty(Actor::Property::KEYBOARD_FOCUSABLE,true);
+ button2.SetProperty(Actor::Property::KEYBOARD_FOCUSABLE,true);
+
+ application.GetScene().Add(button1);
+ application.GetScene().Add(button2);
+
+ // set position
+ // button1 -- button2
+ button1.SetProperty(Actor::Property::POSITION, Vector2(0.0f, 0.0f));
+ button2.SetProperty(Actor::Property::POSITION, Vector2(100.0f, 0.0f));
+
+ // flush the queue and render once
+ application.SendNotification();
+ application.Render();
+
+ // Set the focus to the button1
+ // [button1] -- button2
+ DALI_TEST_CHECK(manager.SetCurrentFocusActor(button1) == true);
+ DALI_TEST_CHECK(manager.GetCurrentFocusActor() == button1);
+ DALI_TEST_CHECK(focusChangedCallback.mSignalVerified);
+ DALI_TEST_CHECK(focusChangedCallback.mOriginalFocusedActor == Actor());
+ DALI_TEST_CHECK(focusChangedCallback.mCurrentFocusedActor == button1);
+ focusChangedCallback.Reset();
+
+ // without set the navigation properties, but we can focus move
+ // enable the default algorithm
+ Dali::Toolkit::DevelKeyboardFocusManager::EnableDefaultAlgorithm(manager, true);
+ DALI_TEST_CHECK( Dali::Toolkit::DevelKeyboardFocusManager::IsDefaultAlgorithmEnabled(manager) );
+
+ // Move the focus towards right
+ // button1 -- [button2]
+ DALI_TEST_CHECK(manager.MoveFocus(Control::KeyboardFocus::RIGHT) == true);
+
+ // Confirm whether focus is moved to button2
+ DALI_TEST_EQUALS(button2.GetProperty<int>(DevelControl::Property::STATE), (int)DevelControl::FOCUSED, TEST_LOCATION);
+ DALI_TEST_CHECK(focusChangedCallback.mSignalVerified);
+ DALI_TEST_CHECK(focusChangedCallback.mOriginalFocusedActor == button1);
+ DALI_TEST_CHECK(focusChangedCallback.mCurrentFocusedActor == button2);
+ focusChangedCallback.Reset();
+
+ // disable the default algorithm
+ Dali::Toolkit::DevelKeyboardFocusManager::EnableDefaultAlgorithm(manager, false);
+ DALI_TEST_CHECK( !Dali::Toolkit::DevelKeyboardFocusManager::IsDefaultAlgorithmEnabled(manager) );
+
+ // Move the focus towards left, The focus move will fail because the default algorithm is disabled.
+ DALI_TEST_CHECK(manager.MoveFocus(Control::KeyboardFocus::LEFT) == false);
+
+ // enable the default algorithm
+ Dali::Toolkit::DevelKeyboardFocusManager::EnableDefaultAlgorithm(manager, true);
+ DALI_TEST_CHECK( Dali::Toolkit::DevelKeyboardFocusManager::IsDefaultAlgorithmEnabled(manager) );
+
+ // Move the focus towards left, The focus move will success because the default algorithm is enabled.
+ // [button1] -- button2
+ DALI_TEST_CHECK(manager.MoveFocus(Control::KeyboardFocus::LEFT) == true);
+ // Confirm whether focus is moved to button2
+ DALI_TEST_EQUALS(button1.GetProperty<int>(DevelControl::Property::STATE), (int)DevelControl::FOCUSED, TEST_LOCATION);
+ DALI_TEST_CHECK(focusChangedCallback.mSignalVerified);
+ DALI_TEST_CHECK(focusChangedCallback.mOriginalFocusedActor == button2);
+ DALI_TEST_CHECK(focusChangedCallback.mCurrentFocusedActor == button1);
+ focusChangedCallback.Reset();
+
+
+ END_TEST;
+}
+
+
+int UtcDaliKeyboardFocusManagerWithKeyboardFocusableChildren(void)
+{
+ ToolkitTestApplication application;
+
+ tet_infoline(" UtcDaliKeyboardFocusManagerWithKeyboardFocusableChildren");
+
+ KeyboardFocusManager manager = KeyboardFocusManager::Get();
+ DALI_TEST_CHECK(manager);
+
+ // Create the first actor and add it to the stage
+ Actor first = Actor::New();
+ first.SetProperty( Actor::Property::KEYBOARD_FOCUSABLE, true);
+ application.GetScene().Add(first);
+
+ // Create the second actor and add it to the first actor.
+ Actor second = Actor::New();
+ second.SetProperty( Actor::Property::KEYBOARD_FOCUSABLE, true);
+ first.Add(second);
+
+ // Check that no actor is being focused yet.
+ DALI_TEST_CHECK(manager.GetCurrentFocusActor() == Actor());
+
+ // Check that the focus is set on the first actor
+ DALI_TEST_CHECK(manager.SetCurrentFocusActor(first) == true);
+ DALI_TEST_CHECK(manager.GetCurrentFocusActor() == first);
+
+ // Set KeyboardFocusableChildren false.
+ first.SetProperty( DevelActor::Property::KEYBOARD_FOCUSABLE_CHILDREN, false);
+
+ // Check that it will fail to set focus on the second actor as it's not focusable
+ DALI_TEST_CHECK(manager.SetCurrentFocusActor(second) == false);
+ DALI_TEST_CHECK(manager.GetCurrentFocusActor() == first);
+
+ // Set KeyboardFocusableChildren true.
+ first.SetProperty( DevelActor::Property::KEYBOARD_FOCUSABLE_CHILDREN, true);
+
+ // Check that the focus is set on the second actor
+ DALI_TEST_CHECK(manager.SetCurrentFocusActor(second) == true);
+ DALI_TEST_CHECK(manager.GetCurrentFocusActor() == second);
+
+ END_TEST;
}
\ No newline at end of file
* @brief The shadow of the control.
* @details Name "shadow", type Property::MAP.
*/
- SHADOW = PADDING + 8
+ SHADOW = PADDING + 8,
+
+ /**
+ * @brief Whether a Control and its descendants can emit key signals.
+ * @details Name "dispatchKeyEvents", type Property::BOOLEAN
+ * @note If a control's dispatchKeyEvents is set to false, then it's children will not emit a key event signal either.
+ */
+ DISPATCH_KEY_EVENTS,
};
} // namespace Property
Actor FindNextFocus(Actor& actor, Actor& focusedActor, Rect<float>& focusedRect, Rect<float>& bestCandidateRect, Toolkit::Control::KeyboardFocus::Direction direction)\r
{\r
Actor nearestActor;\r
- if(actor && actor.GetProperty<bool>(Actor::Property::VISIBLE))\r
+ if(actor && actor.GetProperty<bool>(Actor::Property::VISIBLE) && actor.GetProperty<bool>(DevelActor::Property::KEYBOARD_FOCUSABLE_CHILDREN))\r
{\r
// Recursively children\r
const auto childCount = actor.GetChildCount();\r
// Properties registered without macro to use specific member variables.
-const PropertyRegistration Control::Impl::PROPERTY_1( typeRegistration, "styleName", Toolkit::Control::Property::STYLE_NAME, Property::STRING, &Control::Impl::SetProperty, &Control::Impl::GetProperty );
-const PropertyRegistration Control::Impl::PROPERTY_4( typeRegistration, "keyInputFocus", Toolkit::Control::Property::KEY_INPUT_FOCUS, Property::BOOLEAN, &Control::Impl::SetProperty, &Control::Impl::GetProperty );
-const PropertyRegistration Control::Impl::PROPERTY_5( typeRegistration, "background", Toolkit::Control::Property::BACKGROUND, Property::MAP, &Control::Impl::SetProperty, &Control::Impl::GetProperty );
-const PropertyRegistration Control::Impl::PROPERTY_6( typeRegistration, "margin", Toolkit::Control::Property::MARGIN, Property::EXTENTS, &Control::Impl::SetProperty, &Control::Impl::GetProperty );
-const PropertyRegistration Control::Impl::PROPERTY_7( typeRegistration, "padding", Toolkit::Control::Property::PADDING, Property::EXTENTS, &Control::Impl::SetProperty, &Control::Impl::GetProperty );
-const PropertyRegistration Control::Impl::PROPERTY_8( typeRegistration, "tooltip", Toolkit::DevelControl::Property::TOOLTIP, Property::MAP, &Control::Impl::SetProperty, &Control::Impl::GetProperty );
-const PropertyRegistration Control::Impl::PROPERTY_9( typeRegistration, "state", Toolkit::DevelControl::Property::STATE, Property::STRING, &Control::Impl::SetProperty, &Control::Impl::GetProperty );
-const PropertyRegistration Control::Impl::PROPERTY_10( typeRegistration, "subState", Toolkit::DevelControl::Property::SUB_STATE, Property::STRING, &Control::Impl::SetProperty, &Control::Impl::GetProperty );
-const PropertyRegistration Control::Impl::PROPERTY_11( typeRegistration, "leftFocusableActorId", Toolkit::DevelControl::Property::LEFT_FOCUSABLE_ACTOR_ID, Property::INTEGER, &Control::Impl::SetProperty, &Control::Impl::GetProperty );
-const PropertyRegistration Control::Impl::PROPERTY_12( typeRegistration, "rightFocusableActorId", Toolkit::DevelControl::Property::RIGHT_FOCUSABLE_ACTOR_ID,Property::INTEGER, &Control::Impl::SetProperty, &Control::Impl::GetProperty );
-const PropertyRegistration Control::Impl::PROPERTY_13( typeRegistration, "upFocusableActorId", Toolkit::DevelControl::Property::UP_FOCUSABLE_ACTOR_ID, Property::INTEGER, &Control::Impl::SetProperty, &Control::Impl::GetProperty );
-const PropertyRegistration Control::Impl::PROPERTY_14( typeRegistration, "downFocusableActorId", Toolkit::DevelControl::Property::DOWN_FOCUSABLE_ACTOR_ID, Property::INTEGER, &Control::Impl::SetProperty, &Control::Impl::GetProperty );
-const PropertyRegistration Control::Impl::PROPERTY_15( typeRegistration, "shadow", Toolkit::DevelControl::Property::SHADOW, Property::MAP, &Control::Impl::SetProperty, &Control::Impl::GetProperty );
-
-Control::Impl::Impl( Control& controlImpl )
-: mControlImpl( controlImpl ),
- mState( Toolkit::DevelControl::NORMAL ),
+const PropertyRegistration Control::Impl::PROPERTY_1(typeRegistration, "styleName", Toolkit::Control::Property::STYLE_NAME, Property::STRING, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
+const PropertyRegistration Control::Impl::PROPERTY_4(typeRegistration, "keyInputFocus", Toolkit::Control::Property::KEY_INPUT_FOCUS, Property::BOOLEAN, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
+const PropertyRegistration Control::Impl::PROPERTY_5(typeRegistration, "background", Toolkit::Control::Property::BACKGROUND, Property::MAP, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
+const PropertyRegistration Control::Impl::PROPERTY_6(typeRegistration, "margin", Toolkit::Control::Property::MARGIN, Property::EXTENTS, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
+const PropertyRegistration Control::Impl::PROPERTY_7(typeRegistration, "padding", Toolkit::Control::Property::PADDING, Property::EXTENTS, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
+const PropertyRegistration Control::Impl::PROPERTY_8(typeRegistration, "tooltip", Toolkit::DevelControl::Property::TOOLTIP, Property::MAP, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
+const PropertyRegistration Control::Impl::PROPERTY_9(typeRegistration, "state", Toolkit::DevelControl::Property::STATE, Property::STRING, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
+const PropertyRegistration Control::Impl::PROPERTY_10(typeRegistration, "subState", Toolkit::DevelControl::Property::SUB_STATE, Property::STRING, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
+const PropertyRegistration Control::Impl::PROPERTY_11(typeRegistration, "leftFocusableActorId", Toolkit::DevelControl::Property::LEFT_FOCUSABLE_ACTOR_ID, Property::INTEGER, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
+const PropertyRegistration Control::Impl::PROPERTY_12(typeRegistration, "rightFocusableActorId", Toolkit::DevelControl::Property::RIGHT_FOCUSABLE_ACTOR_ID, Property::INTEGER, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
+const PropertyRegistration Control::Impl::PROPERTY_13(typeRegistration, "upFocusableActorId", Toolkit::DevelControl::Property::UP_FOCUSABLE_ACTOR_ID, Property::INTEGER, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
+const PropertyRegistration Control::Impl::PROPERTY_14(typeRegistration, "downFocusableActorId", Toolkit::DevelControl::Property::DOWN_FOCUSABLE_ACTOR_ID, Property::INTEGER, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
+const PropertyRegistration Control::Impl::PROPERTY_15(typeRegistration, "shadow", Toolkit::DevelControl::Property::SHADOW, Property::MAP, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
+const PropertyRegistration Control::Impl::PROPERTY_16(typeRegistration, "dispatchKeyEvents", Toolkit::DevelControl::Property::DISPATCH_KEY_EVENTS, Property::BOOLEAN, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
+
+// clang-format on
+
+Control::Impl::Impl(Control& controlImpl)
+: mControlImpl(controlImpl),
+ mState(Toolkit::DevelControl::NORMAL),
mSubStateName(""),
mLeftFocusableActorId( -1 ),
mRightFocusableActorId( -1 ),
mIsKeyboardFocusGroup( false ),
mIsEmittingResourceReadySignal(false),
mNeedToEmitResourceReady(false),
- mIsAutofillEnabled( false )
+ mIsAutofillEnabled( false ),
+ mDispatchKeyEvents(true)
{
}
break;
}
+ case Toolkit::DevelControl::Property::DISPATCH_KEY_EVENTS:
+ {
+ bool dispatch;
+ if(value.Get(dispatch))
+ {
+ controlImpl.mImpl->mDispatchKeyEvents = dispatch;
+ }
+ break;
+ }
+
}
}
}
value = map;
break;
}
+
+ case Toolkit::DevelControl::Property::DISPATCH_KEY_EVENTS:
+ {
+ value = controlImpl.mImpl->mDispatchKeyEvents;
+ break;
+ }
}
}
bool mIsEmittingResourceReadySignal :1; ///< True during ResourceReady().
bool mNeedToEmitResourceReady :1; ///< True if need to emit the resource ready signal again.
bool mIsAutofillEnabled : 1; ///< Stroes whether the Autofill functionality is enabled.
+ bool mDispatchKeyEvents : 1; ///< Whether the actor emits key event signals
RegisteredVisualContainer mRemoveVisuals; ///< List of visuals that are being replaced by another visual once ready
static const PropertyRegistration PROPERTY_13;
static const PropertyRegistration PROPERTY_14;
static const PropertyRegistration PROPERTY_15;
+ static const PropertyRegistration PROPERTY_16;
};
bool KeyboardFocusManager::DoSetCurrentFocusActor( Actor actor )
{
bool success = false;
- if( actor && actor.GetProperty< bool >( Actor::Property::KEYBOARD_FOCUSABLE ) && actor.GetProperty< bool >( Actor::Property::CONNECTED_TO_SCENE ) )
+
+ // If the parent's KEYBOARD_FOCUSABLE_CHILDREN is false, it cannot have focus.
+ if(actor)
+ {
+ Actor parent = actor.GetParent();
+ while(parent)
+ {
+ if(!parent.GetProperty<bool>(DevelActor::Property::KEYBOARD_FOCUSABLE_CHILDREN))
+ {
+ DALI_LOG_INFO(gLogFilter, Debug::General, "[%s:%d] Parent Actor has KEYBOARD_FOCUSABLE_CHILDREN false,\n", __FUNCTION__, __LINE__);
+ return false;
+ }
+ parent = parent.GetParent();
+ }
+ }
+
+ if(actor && actor.GetProperty<bool>(Actor::Property::KEYBOARD_FOCUSABLE) && actor.GetProperty<bool>(Actor::Property::CONNECTED_TO_SCENE))
{
Integration::SceneHolder currentWindow = Integration::SceneHolder::Get( actor );
#include <dali/integration-api/adaptor-framework/adaptor.h>
#include <dali/integration-api/adaptor-framework/scene-holder.h>
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/controls/control-devel.h>
+
namespace Dali
{
Toolkit::Control control = GetCurrentFocusControl();
if( control )
{
+ Dali::Actor dispatch = control;
+ while(dispatch)
+ {
+ // If the DISPATCH_KEY_EVENTS is false, it cannot emit key event.
+ Toolkit::Control dispatchControl = Toolkit::Control::DownCast(dispatch);
+ if(dispatchControl && !dispatchControl.GetProperty<bool>(Toolkit::DevelControl::Property::DISPATCH_KEY_EVENTS))
+ {
+ return true;
+ }
+ dispatch = dispatch.GetParent();
+ }
+
// Notify the control about the key event
consumed = EmitKeyEventSignal( control, event );
}
* @return Whether the focus is successful or not
* @pre The KeyboardFocusManager has been initialized.
* @pre The Actor has been initialized.
+ * @note If the parent of this actor has the KEYBOARD FOCUSABLE CHILDREN property set to false, it will not be focused.
*/
bool SetCurrentFocusActor(Actor actor);