/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
mFocusedActorEnterKeySignal(),
mCurrentFocusActor(),
mFocusIndicatorActor(),
+ mFocusFinderRootActor(),
mFocusHistory(),
mSlotDelegate(this),
mCustomAlgorithmInterface(NULL),
mFocusGroupLoopEnabled(false),
mIsWaitingKeyboardFocusChangeCommit(false),
mClearFocusOnTouch(true),
- mEnableDefaultAlgorithm(false)
+ mEnableDefaultAlgorithm(false),
+ mCurrentWindowId(0)
{
// TODO: Get FocusIndicatorEnable constant from stylesheet to set mIsFocusIndicatorShown.
(*iter).TouchedSignal().Connect(mSlotDelegate, &KeyboardFocusManager::OnTouch);
(*iter).WheelEventGeneratedSignal().Connect(mSlotDelegate, &KeyboardFocusManager::OnCustomWheelEvent);
(*iter).WheelEventSignal().Connect(mSlotDelegate, &KeyboardFocusManager::OnWheelEvent);
- Dali::Window window = DevelWindow::DownCast(*iter);
+ Window window = Window::DownCast(*iter);
if(window)
{
window.FocusChangeSignal().Connect(mSlotDelegate, &KeyboardFocusManager::OnWindowFocusChanged);
sceneHolder.TouchedSignal().Connect(mSlotDelegate, &KeyboardFocusManager::OnTouch);
sceneHolder.WheelEventGeneratedSignal().Connect(mSlotDelegate, &KeyboardFocusManager::OnCustomWheelEvent);
sceneHolder.WheelEventSignal().Connect(mSlotDelegate, &KeyboardFocusManager::OnWheelEvent);
- Dali::Window window = DevelWindow::DownCast(sceneHolder);
+ Window window = Window::DownCast(sceneHolder);
if(window)
{
window.FocusChangeSignal().Connect(mSlotDelegate, &KeyboardFocusManager::OnWindowFocusChanged);
Toolkit::StyleManager styleManager = Toolkit::StyleManager::Get();
if(styleManager)
{
- Property::Map config = Toolkit::DevelStyleManager::GetConfigurations(styleManager);
- mAlwaysShowIndicator = config["alwaysShowFocus"].Get<bool>() ? ALWAYS_SHOW : NONE;
+ const auto alwaysShowFocusValue = Toolkit::DevelStyleManager::GetConfigurations(styleManager).Find("alwaysShowFocus", Property::Type::BOOLEAN);
+
+ mAlwaysShowIndicator = (alwaysShowFocusValue && alwaysShowFocusValue->Get<bool>()) ? ALWAYS_SHOW : NONE;
mIsFocusIndicatorShown = (mAlwaysShowIndicator == ALWAYS_SHOW) ? SHOW : HIDE;
mClearFocusOnTouch = (mIsFocusIndicatorShown == SHOW) ? false : true;
}
bool KeyboardFocusManager::DoSetCurrentFocusActor(Actor actor)
{
- bool success = false;
+ bool success = false;
+ Integration::SceneHolder currentWindow;
// Check whether the actor is in the stage and is keyboard focusable.
if(actor &&
actor.GetProperty<bool>(Actor::Property::KEYBOARD_FOCUSABLE) &&
actor.GetProperty<bool>(DevelActor::Property::USER_INTERACTION_ENABLED) &&
actor.GetProperty<bool>(Actor::Property::CONNECTED_TO_SCENE) &&
- actor.GetProperty<bool>(Actor::Property::VISIBLE))
+ (currentWindow = Integration::SceneHolder::Get(actor))) ///< Note : SceneHolder might not be valid even if actor is connected to scene.
+ /// (e.g. Adaptor Stopped, SceneHolder removed but Scene is still alive)
{
- // If the parent's KEYBOARD_FOCUSABLE_CHILDREN is false or VISIBLE is false, it cannot have focus.
+ // If the parent's KEYBOARD_FOCUSABLE_CHILDREN is false, it cannot have focus.
Actor parent = actor.GetParent();
while(parent)
{
- if(!parent.GetProperty<bool>(DevelActor::Property::KEYBOARD_FOCUSABLE_CHILDREN) || !parent.GetProperty<bool>(Actor::Property::VISIBLE))
+ if(!parent.GetProperty<bool>(DevelActor::Property::KEYBOARD_FOCUSABLE_CHILDREN))
{
- DALI_LOG_INFO(gLogFilter, Debug::General, "[%s:%d] Parent Actor has KEYBOARD_FOCUSABLE_CHILDREN false or VISIBLE false,\n", __FUNCTION__, __LINE__);
+ DALI_LOG_DEBUG_INFO("Parent Actor has KEYBOARD_FOCUSABLE_CHILDREN false\n");
return false;
}
parent = parent.GetParent();
// If developer set focus on same actor, doing nothing
Actor currentFocusedActor = GetCurrentFocusActor();
+ DALI_LOG_DEBUG_INFO("current focused actor : [%p] new focused actor : [%p]\n", currentFocusedActor.GetObjectPtr(), actor.GetObjectPtr());
if(actor == currentFocusedActor)
{
return true;
}
- Integration::SceneHolder currentWindow = Integration::SceneHolder::Get(actor);
if(currentWindow.GetRootLayer() != mCurrentFocusedWindow.GetHandle())
{
Layer rootLayer = currentWindow.GetRootLayer();
mCurrentFocusedWindow = rootLayer;
+ mCurrentWindowId = static_cast<uint32_t>(currentWindow.GetNativeId());
}
if((mIsFocusIndicatorShown == SHOW) && (mEnableFocusIndicator == ENABLE))
actor.Add(GetFocusIndicatorActor());
}
- Toolkit::Control currentlyFocusedControl = Toolkit::Control::DownCast(currentFocusedActor);
- if(currentlyFocusedControl)
- {
- // Do we need it to remember if it was previously DISABLED?
- currentlyFocusedControl.SetProperty(DevelControl::Property::STATE, DevelControl::NORMAL);
- currentlyFocusedControl.ClearKeyInputFocus();
- }
+ actor.OffSceneSignal().Connect(mSlotDelegate, &KeyboardFocusManager::OnSceneDisconnection);
// Save the current focused actor
mCurrentFocusActor = actor;
mCurrentFocusActors.push_back(std::pair<WeakHandle<Layer>, WeakHandle<Actor> >(mCurrentFocusedWindow, actor));
}
+ // Send notification for the change of focus actor
+ if(!mFocusChangedSignal.Empty())
+ {
+ mFocusChangedSignal.Emit(currentFocusedActor, actor);
+ }
+
+ Toolkit::Control currentlyFocusedControl = Toolkit::Control::DownCast(currentFocusedActor);
+ if(currentlyFocusedControl)
+ {
+ // Do we need it to remember if it was previously DISABLED?
+ currentlyFocusedControl.SetProperty(DevelControl::Property::STATE, DevelControl::NORMAL);
+ currentlyFocusedControl.ClearKeyInputFocus();
+ }
+
Toolkit::Control newlyFocusedControl = Toolkit::Control::DownCast(actor);
if(newlyFocusedControl)
{
mFocusHistory.erase(beginPos);
}
- // Send notification for the change of focus actor
- if(!mFocusChangedSignal.Empty())
- {
- mFocusChangedSignal.Emit(currentFocusedActor, actor);
- }
DALI_LOG_INFO(gLogFilter, Debug::General, "[%s:%d] SUCCEED\n", __FUNCTION__, __LINE__);
success = true;
}
bool succeed = false;
// Go through the actor's hierarchy until we find a layout control that knows how to move the focus
- Toolkit::Control parentLayoutControl = GetParentLayoutControl(currentFocusActor);
- while(parentLayoutControl && !succeed)
+ Toolkit::Control layoutControl = IsLayoutControl(currentFocusActor) ? Toolkit::Control::DownCast(currentFocusActor) : GetParentLayoutControl(currentFocusActor);
+ while(layoutControl && !succeed)
{
- succeed = DoMoveFocusWithinLayoutControl(parentLayoutControl, currentFocusActor, direction);
- parentLayoutControl = GetParentLayoutControl(parentLayoutControl);
+ succeed = DoMoveFocusWithinLayoutControl(layoutControl, currentFocusActor, direction);
+ layoutControl = GetParentLayoutControl(layoutControl);
}
if(!succeed)
nextFocusableActor = mPreFocusChangeSignal.Emit(currentFocusActor, Actor(), direction);
mIsWaitingKeyboardFocusChangeCommit = false;
}
- else if (mEnableDefaultAlgorithm)
+ else if(mEnableDefaultAlgorithm)
{
- Layer rootLayer;
- if (currentFocusActor)
+ Actor rootActor = mFocusFinderRootActor.GetHandle();
+ if(!rootActor)
{
- // Find the window of the focused actor.
- Integration::SceneHolder window = Integration::SceneHolder::Get(currentFocusActor);
- if (window)
+ if(currentFocusActor)
{
- rootLayer = window.GetRootLayer();
+ // Find the window of the focused actor.
+ Integration::SceneHolder window = Integration::SceneHolder::Get(currentFocusActor);
+ if(window)
+ {
+ rootActor = window.GetRootLayer();
+ }
+ }
+ else
+ {
+ // Searches from the currently focused window.
+ rootActor = mCurrentFocusedWindow.GetHandle();
}
}
- else
- {
- // Searches from the currently focused window.
- rootLayer = mCurrentFocusedWindow.GetHandle();
- }
- if (rootLayer)
+ if(rootActor)
{
// We should find it among the actors nearby.
- nextFocusableActor = Toolkit::FocusFinder::GetNearestFocusableActor(rootLayer, currentFocusActor, direction);
+ nextFocusableActor = Toolkit::FocusFinder::GetNearestFocusableActor(rootActor, currentFocusActor, direction);
}
}
}
Toolkit::Control layoutControl = Toolkit::Control::DownCast(nextFocusableActor);
succeed = DoMoveFocusWithinLayoutControl(layoutControl, currentFocusActor, direction);
}
- else
+ if(!succeed)
{
- // Otherwise, just set focus to the next focusable actor
+ // Just set focus to the next focusable actor
succeed = SetCurrentFocusActor(nextFocusableActor);
}
}
if(committedFocusActor && committedFocusActor.GetProperty<bool>(Actor::Property::KEYBOARD_FOCUSABLE) && committedFocusActor.GetProperty<bool>(DevelActor::Property::USER_INTERACTION_ENABLED))
{
// Whether the commited focusable actor is a layout control
- if(IsLayoutControl(committedFocusActor))
+ if(IsLayoutControl(committedFocusActor) && committedFocusActor != control)
{
// If so, move the focus inside it.
Toolkit::Control layoutControl = Toolkit::Control::DownCast(committedFocusActor);
}
}
-void KeyboardFocusManager::ClearFocus()
+void KeyboardFocusManager::ClearFocus(Actor actor)
{
- ClearFocusIndicator();
- Actor actor = GetCurrentFocusActor();
if(actor)
{
+ DALI_LOG_RELEASE_INFO("ClearFocus id:(%d)\n", actor.GetProperty<int32_t>(Dali::Actor::Property::ID));
+ actor.OffSceneSignal().Disconnect(mSlotDelegate, &KeyboardFocusManager::OnSceneDisconnection);
// Send notification for the change of focus actor
if(!mFocusChangedSignal.Empty())
{
mCurrentFocusActor.Reset();
}
-void KeyboardFocusManager::ClearFocusIndicator()
+void KeyboardFocusManager::ClearFocusIndicator(Actor actor)
{
- Actor actor = GetCurrentFocusActor();
if(actor)
{
if(mFocusIndicatorActor)
mIsFocusIndicatorShown = (mAlwaysShowIndicator == ALWAYS_SHOW) ? SHOW : HIDE;
}
+void KeyboardFocusManager::ClearFocus()
+{
+ Actor actor = GetCurrentFocusActor();
+ ClearFocusIndicator(actor);
+ ClearFocus(actor);
+}
+
void KeyboardFocusManager::SetFocusGroupLoop(bool enabled)
{
mFocusGroupLoopEnabled = enabled;
return mFocusIndicatorActor;
}
+uint32_t KeyboardFocusManager::GetCurrentWindowId() const
+{
+ return mCurrentWindowId;
+}
+
void KeyboardFocusManager::OnKeyEvent(const KeyEvent& event)
{
- const std::string& keyName = event.GetKeyName();
+ if(mCurrentFocusedWindow.GetHandle())
+ {
+ // If it is a key event that occurred in another window, it returns.
+ uint32_t eventWindowId = event.GetWindowId();
+ if(eventWindowId > 0 && GetCurrentWindowId() != eventWindowId)
+ {
+ DALI_LOG_RELEASE_INFO("CurrentFocusedWindow id %d, window ID where key event occurred %d : key event skip\n", GetCurrentWindowId(), eventWindowId);
+ return;
+ }
+ }
+
+ const std::string& keyName = event.GetKeyName();
const std::string& deviceName = event.GetDeviceName();
if(mIsFocusIndicatorShown == UNKNOWN)
actor.Add(GetFocusIndicatorActor());
}
}
- else
+ else if(!mEnableDefaultAlgorithm)
{
// No actor is focused but keyboard focus is activated by the key press
// Let's try to move the initial focus
{
return;
}
+ // If mClearFocusOnTouch is false, do not clear the focus indicator even if user touch the screen.
+ if(mClearFocusOnTouch)
+ {
+ ClearFocusIndicator(GetCurrentFocusActor());
+ }
+
// If KEYBOARD_FOCUSABLE and TOUCH_FOCUSABLE is true, set focus actor
if(hitActor && hitActor.GetProperty<bool>(Actor::Property::KEYBOARD_FOCUSABLE) && hitActor.GetProperty<bool>(DevelActor::Property::TOUCH_FOCUSABLE))
{
- // If mClearFocusOnTouch is false, do not clear the focus
- if(mClearFocusOnTouch)
- {
- ClearFocus();
- }
SetCurrentFocusActor(hitActor);
}
- else
- {
- // If mClearFocusOnTouch is false, do not clear the focus indicator even if user touch the screen.
- if(mClearFocusOnTouch)
- {
- ClearFocusIndicator();
- }
- }
}
}
bool KeyboardFocusManager::OnCustomWheelEvent(const WheelEvent& event)
{
- bool consumed = false;
- Actor actor = GetCurrentFocusActor();
+ bool consumed = false;
+ Actor actor = GetCurrentFocusActor();
if(actor)
{
// Notify the actor about the wheel event
// Change Current Focused Window
Layer rootLayer = window.GetRootLayer();
mCurrentFocusedWindow = rootLayer;
+ mCurrentWindowId = static_cast<uint32_t>(Integration::SceneHolder::Get(rootLayer).GetNativeId());
// Get Current Focused Actor from window
Actor currentFocusedActor = GetFocusActorFromCurrentWindow();
- SetCurrentFocusActor(currentFocusedActor);
-
- if(currentFocusedActor && (mEnableFocusIndicator == ENABLE))
+ if(currentFocusedActor)
{
- // Make sure the focused actor is highlighted
- currentFocusedActor.Add(GetFocusIndicatorActor());
- mIsFocusIndicatorShown = SHOW;
+ SetCurrentFocusActor(currentFocusedActor);
+
+ if(mEnableFocusIndicator == ENABLE)
+ {
+ // Make sure the focused actor is highlighted
+ currentFocusedActor.Add(GetFocusIndicatorActor());
+ mIsFocusIndicatorShown = SHOW;
+ }
}
}
}
return mEnableDefaultAlgorithm;
}
+void KeyboardFocusManager::SetFocusFinderRootActor(Actor actor)
+{
+ mFocusFinderRootActor = actor;
+}
+
+void KeyboardFocusManager::ResetFocusFinderRootActor()
+{
+ mFocusFinderRootActor.Reset();
+}
+
+void KeyboardFocusManager::OnSceneDisconnection(Dali::Actor actor)
+{
+ if(actor && actor == mCurrentFocusActor.GetHandle())
+ {
+ DALI_LOG_RELEASE_INFO("ClearFocus due to actor id:(%d) removed from scene\n", actor.GetProperty<int32_t>(Dali::Actor::Property::ID));
+ ClearFocusIndicator(actor);
+ ClearFocus(actor);
+ }
+}
+
} // namespace Internal
} // namespace Toolkit