2 * Copyright (c) 2014 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include "focus-manager-impl.h"
22 #include <cstring> // for strcmp
23 #include <dali/public-api/actors/layer.h>
24 #include <dali/devel-api/adaptor-framework/accessibility-manager.h>
25 #include <dali/devel-api/adaptor-framework/sound-player.h>
26 #include <dali/devel-api/adaptor-framework/tts-player.h>
27 #include <dali/public-api/animation/constraints.h>
28 #include <dali/devel-api/events/hit-test-algorithm.h>
29 #include <dali/public-api/images/resource-image.h>
30 #include <dali/integration-api/debug.h>
33 #include <dali-toolkit/public-api/controls/control.h>
34 #include <dali-toolkit/public-api/controls/control-impl.h>
45 namespace // unnamed namespace
50 const char* const SIGNAL_FOCUS_CHANGED = "focus-changed";
51 const char* const SIGNAL_FOCUS_OVERSHOT = "focus-overshot";
52 const char* const SIGNAL_FOCUSED_ACTOR_ACTIVATED = "focused-actor-activated";
54 #if defined(DEBUG_ENABLED)
55 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_FOCUS_MANAGER");
58 const char* const ACTOR_FOCUSABLE("focusable");
59 const char* const IS_FOCUS_GROUP("is-focus-group");
61 const char* FOCUS_BORDER_IMAGE_PATH = DALI_IMAGE_DIR "B16-8_TTS_focus.png";
62 const Vector4 FOCUS_BORDER_IMAGE_BORDER = Vector4(7.0f, 7.0f, 7.0f, 7.0f);
64 const char* FOCUS_SOUND_FILE = DALI_SOUND_DIR "Focus.ogg";
65 const char* FOCUS_CHAIN_END_SOUND_FILE = DALI_SOUND_DIR "End_of_List.ogg";
68 * The function to be used in the hit-test algorithm to check whether the actor is hittable.
70 bool IsActorFocusableFunction(Actor actor, Dali::HitTestAlgorithm::TraverseType type)
72 bool hittable = false;
76 case Dali::HitTestAlgorithm::CHECK_ACTOR:
78 // Check whether the actor is visible and not fully transparent.
80 && actor.GetCurrentWorldColor().a > 0.01f) // not FULLY_TRANSPARENT
82 // Check whether the actor is focusable
83 Property::Index propertyActorFocusable = actor.GetPropertyIndex(ACTOR_FOCUSABLE);
84 if(propertyActorFocusable != Property::INVALID_INDEX)
86 hittable = actor.GetProperty<bool>(propertyActorFocusable);
91 case Dali::HitTestAlgorithm::DESCEND_ACTOR_TREE:
93 if( actor.IsVisible() ) // Actor is visible, if not visible then none of its children are visible.
110 FocusManager::FocusManager()
112 mIsFocusWithinGroup(false),
113 mIsEndcapFeedbackEnabled(false),
114 mIsEndcapFeedbackPlayed(false),
115 mCurrentFocusActor(FocusIDPair(0, 0)),
116 mFocusIndicatorActor(Actor()),
117 mRecursiveFocusMoveCounter(0),
118 mIsAccessibilityTtsEnabled(false),
119 mIsFocusIndicatorEnabled(false)
121 CreateDefaultFocusIndicatorActor();
123 AccessibilityManager manager = AccessibilityManager::Get();
124 manager.SetActionHandler(*this);
125 manager.SetGestureHandler(*this);
127 ChangeAccessibilityStatus();
130 FocusManager::~FocusManager()
134 FocusManager::ActorAdditionalInfo FocusManager::GetActorAdditionalInfo(const unsigned int actorID) const
136 ActorAdditionalInfo data;
137 IDAdditionalInfoConstIter iter = mIDAdditionalInfoContainer.find(actorID);
138 if(iter != mIDAdditionalInfoContainer.end())
140 data = (*iter).second;
146 void FocusManager::SynchronizeActorAdditionalInfo(const unsigned int actorID, const unsigned int order)
148 ActorAdditionalInfo actorInfo = GetActorAdditionalInfo(actorID);
149 actorInfo.mFocusOrder = order;
150 mIDAdditionalInfoContainer.erase(actorID);
151 mIDAdditionalInfoContainer.insert(IDAdditionalInfoPair(actorID, actorInfo));
154 void FocusManager::SetAccessibilityAttribute(Actor actor, Toolkit::FocusManager::AccessibilityAttribute type, const std::string& text)
158 unsigned int actorID = actor.GetId();
160 ActorAdditionalInfo info = GetActorAdditionalInfo(actorID);
161 info.mAccessibilityAttributes[type] = text;
163 mIDAdditionalInfoContainer.erase(actorID);
164 mIDAdditionalInfoContainer.insert(IDAdditionalInfoPair(actorID, info));
168 std::string FocusManager::GetAccessibilityAttribute(Actor actor, Toolkit::FocusManager::AccessibilityAttribute type) const
174 ActorAdditionalInfo data = GetActorAdditionalInfo(actor.GetId());
175 text = data.mAccessibilityAttributes[type];
181 void FocusManager::SetFocusOrder(Actor actor, const unsigned int order)
183 // Do nothing if the focus order of the actor is not changed.
184 if(actor && GetFocusOrder(actor) != order)
186 // Firstly delete the actor from the focus chain if it's already there with a different focus order.
187 mFocusIDContainer.erase(GetFocusOrder(actor));
189 // Create actor focusable property if not already created.
190 Property::Index propertyActorFocusable = actor.GetPropertyIndex(ACTOR_FOCUSABLE);
191 if(propertyActorFocusable == Property::INVALID_INDEX)
193 propertyActorFocusable = actor.RegisterProperty(ACTOR_FOCUSABLE, true);
198 // The actor is not focusable without a defined focus order.
199 actor.SetProperty(propertyActorFocusable, false);
201 // If the actor is currently being focused, it should clear the focus
202 if(actor == GetCurrentFocusActor())
207 else // Insert the actor to the focus chain
209 // Check whether there is another actor in the focus chain with the same focus order already.
210 FocusIDIter focusIDIter = mFocusIDContainer.find(order);
211 if(focusIDIter != mFocusIDContainer.end())
213 // We need to increase the focus order of that actor and all the actors followed it
214 // in the focus chain.
215 FocusIDIter lastIter = mFocusIDContainer.end();
216 --lastIter;//We want forward iterator to the last element here
217 mFocusIDContainer.insert(FocusIDPair((*lastIter).first + 1, (*lastIter).second));
219 // Update the actor's focus order in its additional data
220 SynchronizeActorAdditionalInfo((*lastIter).second, (*lastIter).first + 1);
222 for(FocusIDIter iter = lastIter; iter != focusIDIter; iter--)
224 FocusIDIter previousIter = iter;
225 --previousIter;//We want forward iterator to the previous element here
226 unsigned int actorID = (*previousIter).second;
227 (*iter).second = actorID;
229 // Update the actor's focus order in its additional data
230 SynchronizeActorAdditionalInfo(actorID, (*iter).first);
233 mFocusIDContainer.erase(order);
236 // The actor is focusable
237 actor.SetProperty(propertyActorFocusable, true);
239 // Now we insert the actor into the focus chain with the specified focus order
240 mFocusIDContainer.insert(FocusIDPair(order, actor.GetId()));
243 // Update the actor's focus order in its additional data
244 SynchronizeActorAdditionalInfo(actor.GetId(), order);
248 unsigned int FocusManager::GetFocusOrder(Actor actor) const
250 unsigned int focusOrder = 0;
254 ActorAdditionalInfo data = GetActorAdditionalInfo(actor.GetId());
255 focusOrder = data.mFocusOrder;
261 unsigned int FocusManager::GenerateNewFocusOrder() const
263 unsigned int order = 1;
264 FocusIDContainer::const_reverse_iterator iter = mFocusIDContainer.rbegin();
266 if(iter != mFocusIDContainer.rend())
268 order = (*iter).first + 1;
274 Actor FocusManager::GetActorByFocusOrder(const unsigned int order)
276 Actor actor = Actor();
278 FocusIDIter focusIDIter = mFocusIDContainer.find(order);
279 if(focusIDIter != mFocusIDContainer.end())
281 Actor rootActor = Stage::GetCurrent().GetRootLayer();
282 actor = rootActor.FindChildById(mFocusIDContainer[order]);
288 bool FocusManager::SetCurrentFocusActor(Actor actor)
292 return DoSetCurrentFocusActor(actor.GetId());
298 bool FocusManager::DoSetCurrentFocusActor(const unsigned int actorID)
300 Actor rootActor = Stage::GetCurrent().GetRootLayer();
302 // If the group mode is enabled, check which focus group the current focused actor belongs to
304 if(mIsFocusWithinGroup)
306 focusGroup = GetFocusGroup(GetCurrentFocusActor());
311 focusGroup = rootActor;
314 Actor actor = focusGroup.FindChildById(actorID);
316 // Check whether the actor is in the stage
319 // Check whether the actor is focusable
320 bool actorFocusable = false;
321 Property::Index propertyActorFocusable = actor.GetPropertyIndex(ACTOR_FOCUSABLE);
322 if(propertyActorFocusable != Property::INVALID_INDEX)
324 actorFocusable = actor.GetProperty<bool>(propertyActorFocusable);
327 // Go through the actor's hierarchy to check whether the actor is visible
328 bool actorVisible = actor.IsVisible();
329 Actor parent = actor.GetParent();
330 while (actorVisible && parent && parent != rootActor)
332 actorVisible = parent.IsVisible();
333 parent = parent.GetParent();
336 // Check whether the actor is fully transparent
337 bool actorOpaque = actor.GetCurrentWorldColor().a > 0.01f;
339 // Set the focus only when the actor is focusable and visible and not fully transparent
340 if(actorVisible && actorFocusable && actorOpaque)
342 // Draw the focus indicator upon the focused actor
343 if(mIsFocusIndicatorEnabled && mFocusIndicatorActor)
345 actor.Add(mFocusIndicatorActor);
348 // Send notification for the change of focus actor
349 mFocusChangedSignal.Emit( GetCurrentFocusActor(), actor );
351 // Save the current focused actor
352 mCurrentFocusActor = FocusIDPair(GetFocusOrder(actor), actorID);
354 if(mIsAccessibilityTtsEnabled)
356 Dali::SoundPlayer soundPlayer = Dali::SoundPlayer::Get();
359 soundPlayer.PlaySound(FOCUS_SOUND_FILE);
362 // Play the accessibility attributes with the TTS player.
363 Dali::TtsPlayer player = Dali::TtsPlayer::Get(Dali::TtsPlayer::SCREEN_READER);
365 // Combine attribute texts to one text
366 std::string informationText;
367 for(int i = 0; i < Toolkit::FocusManager::ACCESSIBILITY_ATTRIBUTE_NUM; i++)
369 if(!GetActorAdditionalInfo(actorID).mAccessibilityAttributes[i].empty())
373 informationText += ", "; // for space time between each information
375 informationText += GetActorAdditionalInfo(actorID).mAccessibilityAttributes[i];
378 player.Play(informationText);
385 DALI_LOG_WARNING("[%s:%d] FAILED\n", __FUNCTION__, __LINE__);
389 Actor FocusManager::GetCurrentFocusActor()
391 Actor rootActor = Stage::GetCurrent().GetRootLayer();
392 return rootActor.FindChildById(mCurrentFocusActor.second);
395 Actor FocusManager::GetCurrentFocusGroup()
397 return GetFocusGroup(GetCurrentFocusActor());
400 unsigned int FocusManager::GetCurrentFocusOrder()
402 return mCurrentFocusActor.first;
405 bool FocusManager::MoveFocusForward()
408 mRecursiveFocusMoveCounter = 0;
410 FocusIDIter focusIDIter = mFocusIDContainer.find(mCurrentFocusActor.first);
411 if(focusIDIter != mFocusIDContainer.end())
413 DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] focus order : %d\n", __FUNCTION__, __LINE__, (*focusIDIter).first);
414 ret = DoMoveFocus(focusIDIter, true, mIsWrapped);
418 // TODO: if there is not focused actor, move first actor
419 if(!mFocusIDContainer.empty())
421 //if there is not focused actor, move 1st actor
422 focusIDIter = mFocusIDContainer.begin(); // TODO: I'm not sure it was sorted.
423 DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] focus order : %d\n", __FUNCTION__, __LINE__, (*focusIDIter).first);
424 ret = DoSetCurrentFocusActor((*focusIDIter).second);
428 DALI_LOG_INFO( gLogFilter, Debug::General, "[%s] %s\n", __FUNCTION__, ret?"SUCCEED!!!":"FAILED!!!");
433 bool FocusManager::MoveFocusBackward()
436 mRecursiveFocusMoveCounter = 0;
438 FocusIDIter focusIDIter = mFocusIDContainer.find(mCurrentFocusActor.first);
439 if(focusIDIter != mFocusIDContainer.end())
441 DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] focus order : %d\n", __FUNCTION__, __LINE__, (*focusIDIter).first);
442 ret = DoMoveFocus(focusIDIter, false, mIsWrapped);
446 // TODO: if there is not focused actor, move last actor
447 if(!mFocusIDContainer.empty())
449 //if there is not focused actor, move last actor
450 focusIDIter = mFocusIDContainer.end();
451 --focusIDIter;//We want forward iterator to the last element here
452 DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] focus order : %d\n", __FUNCTION__, __LINE__, (*focusIDIter).first);
453 ret = DoSetCurrentFocusActor((*focusIDIter).second);
457 DALI_LOG_INFO( gLogFilter, Debug::General, "[%s] %s\n", __FUNCTION__, ret?"SUCCEED!!!":"FAILED!!!");
462 void FocusManager::DoActivate(Actor actor)
466 Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor);
469 // Notify the control that it is activated
470 control.GetImplementation().Activate();
473 // Send notification for the activation of focused actor
474 mFocusedActorActivatedSignal.Emit(actor);
478 void FocusManager::ClearFocus()
480 Actor actor = GetCurrentFocusActor();
483 actor.Remove(mFocusIndicatorActor);
486 mCurrentFocusActor = FocusIDPair(0, 0);
488 // Send notification for the change of focus actor
489 mFocusChangedSignal.Emit(actor, Actor());
491 if(mIsAccessibilityTtsEnabled)
493 // Stop the TTS playing if any
494 Dali::TtsPlayer player = Dali::TtsPlayer::Get(Dali::TtsPlayer::SCREEN_READER);
499 void FocusManager::Reset()
502 mFocusIDContainer.clear();
503 mIDAdditionalInfoContainer.clear();
506 void FocusManager::SetFocusGroup(Actor actor, bool isFocusGroup)
510 // Create focus group property if not already created.
511 Property::Index propertyIsFocusGroup = actor.GetPropertyIndex(IS_FOCUS_GROUP);
512 if(propertyIsFocusGroup == Property::INVALID_INDEX)
514 actor.RegisterProperty(IS_FOCUS_GROUP, isFocusGroup);
518 actor.SetProperty(propertyIsFocusGroup, isFocusGroup);
523 bool FocusManager::IsFocusGroup(Actor actor) const
525 // Check whether the actor is a focus group
526 bool isFocusGroup = false;
530 Property::Index propertyIsFocusGroup = actor.GetPropertyIndex(IS_FOCUS_GROUP);
531 if(propertyIsFocusGroup != Property::INVALID_INDEX)
533 isFocusGroup = actor.GetProperty<bool>(propertyIsFocusGroup);
540 Actor FocusManager::GetFocusGroup(Actor actor)
542 // Go through the actor's hierarchy to check which focus group the actor belongs to
543 while (actor && !IsFocusGroup(actor))
545 actor = actor.GetParent();
551 void FocusManager::SetGroupMode(bool enabled)
553 mIsFocusWithinGroup = enabled;
556 bool FocusManager::GetGroupMode() const
558 return mIsFocusWithinGroup;
561 void FocusManager::SetWrapMode(bool wrapped)
563 mIsWrapped = wrapped;
566 bool FocusManager::GetWrapMode() const
571 void FocusManager::SetFocusIndicatorActor(Actor indicator)
573 mFocusIndicatorActor = indicator;
576 Actor FocusManager::GetFocusIndicatorActor()
578 return mFocusIndicatorActor;
581 bool FocusManager::DoMoveFocus(FocusIDIter focusIDIter, bool forward, bool wrapped)
583 DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] %d focusable actors\n", __FUNCTION__, __LINE__, mFocusIDContainer.size());
584 DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] focus order : %d\n", __FUNCTION__, __LINE__, (*focusIDIter).first);
586 if( (forward && ++focusIDIter == mFocusIDContainer.end())
587 || (!forward && focusIDIter-- == mFocusIDContainer.begin()) )
589 if(mIsEndcapFeedbackEnabled)
591 if(mIsEndcapFeedbackPlayed == false)
593 // play sound & skip moving once
594 Dali::SoundPlayer soundPlayer = Dali::SoundPlayer::Get();
597 soundPlayer.PlaySound(FOCUS_CHAIN_END_SOUND_FILE);
600 mIsEndcapFeedbackPlayed = true;
603 mIsEndcapFeedbackPlayed = false;
610 focusIDIter = mFocusIDContainer.begin();
614 focusIDIter = mFocusIDContainer.end();
615 --focusIDIter;//We want forward iterator to the last element here
620 DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] Overshot\n", __FUNCTION__, __LINE__);
621 // Send notification for handling overshooted situation
622 mFocusOvershotSignal.Emit(GetCurrentFocusActor(), forward ? Toolkit::FocusManager::OVERSHOT_NEXT : Toolkit::FocusManager::OVERSHOT_PREVIOUS);
624 return false; // Try to move the focus out of the scope
628 if((focusIDIter != mFocusIDContainer.end()) && !DoSetCurrentFocusActor((*focusIDIter).second))
630 mRecursiveFocusMoveCounter++;
631 if(mRecursiveFocusMoveCounter > mFocusIDContainer.size())
633 // We've attempted to focus all the actors in the whole focus chain and no actor
634 // can be focused successfully.
636 DALI_LOG_WARNING("[%s] There is no more focusable actor in %d focus chains\n", __FUNCTION__, mRecursiveFocusMoveCounter);
642 return DoMoveFocus(focusIDIter, forward, wrapped);
649 void FocusManager::SetFocusable(Actor actor, bool focusable)
653 // Create actor focusable property if not already created.
654 Property::Index propertyActorFocusable = actor.GetPropertyIndex(ACTOR_FOCUSABLE);
655 if(propertyActorFocusable == Property::INVALID_INDEX)
657 actor.RegisterProperty(ACTOR_FOCUSABLE, focusable);
661 actor.SetProperty(propertyActorFocusable, focusable);
666 void FocusManager::CreateDefaultFocusIndicatorActor()
668 // Create a focus indicator actor shared by all the focusable actors
669 Image borderImage = ResourceImage::New(FOCUS_BORDER_IMAGE_PATH);
671 ImageActor focusIndicator = ImageActor::New(borderImage);
672 focusIndicator.SetPositionInheritanceMode( Dali::USE_PARENT_POSITION_PLUS_LOCAL_POSITION );
673 focusIndicator.SetStyle( ImageActor::STYLE_NINE_PATCH );
674 focusIndicator.SetNinePatchBorder(FOCUS_BORDER_IMAGE_BORDER);
675 focusIndicator.SetPosition(Vector3(0.0f, 0.0f, 1.0f));
677 // Apply size constraint to the focus indicator
678 focusIndicator.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
680 SetFocusIndicatorActor(focusIndicator);
683 bool FocusManager::ChangeAccessibilityStatus()
685 AccessibilityManager manager = AccessibilityManager::Get();
686 mIsAccessibilityTtsEnabled = manager.IsEnabled();
688 if(mIsAccessibilityTtsEnabled)
690 // Show indicator when tts turned on if there is focused actor.
691 Actor actor = GetCurrentFocusActor();
694 if(mFocusIndicatorActor)
696 actor.Add(mFocusIndicatorActor);
699 mIsFocusIndicatorEnabled = true;
703 // Hide indicator when tts turned off
704 Actor actor = GetCurrentFocusActor();
707 actor.Remove(mFocusIndicatorActor);
709 mIsFocusIndicatorEnabled = false;
715 bool FocusManager::AccessibilityActionNext(bool allowEndFeedback)
717 if(mIsAccessibilityTtsEnabled)
719 mIsEndcapFeedbackEnabled = allowEndFeedback;
720 return MoveFocusForward();
728 bool FocusManager::AccessibilityActionPrevious(bool allowEndFeedback)
730 if(mIsAccessibilityTtsEnabled)
732 mIsEndcapFeedbackEnabled = allowEndFeedback;
733 return MoveFocusBackward();
741 bool FocusManager::AccessibilityActionActivate()
745 Actor actor = GetCurrentFocusActor();
755 bool FocusManager::AccessibilityActionRead(bool allowReadAgain)
759 if(mIsAccessibilityTtsEnabled)
761 // Find the focusable actor at the read position
762 AccessibilityManager manager = AccessibilityManager::Get();
763 Dali::HitTestAlgorithm::Results results;
764 Dali::HitTestAlgorithm::HitTest( Stage::GetCurrent(), manager.GetReadPosition(), results, IsActorFocusableFunction );
766 FocusIDIter focusIDIter = mFocusIDContainer.find(GetFocusOrder(results.actor));
767 if(focusIDIter != mFocusIDContainer.end())
769 if( allowReadAgain || (results.actor != GetCurrentFocusActor()) )
771 // Move the focus to the actor
772 ret = SetCurrentFocusActor(results.actor);
773 DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] SetCurrentFocusActor returns %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
781 bool FocusManager::AccessibilityActionReadNext(bool allowEndFeedback)
783 if(mIsAccessibilityTtsEnabled)
785 return MoveFocusForward();
793 bool FocusManager::AccessibilityActionReadPrevious(bool allowEndFeedback)
795 if(mIsAccessibilityTtsEnabled)
797 return MoveFocusBackward();
805 bool FocusManager::AccessibilityActionUp()
809 if(mIsAccessibilityTtsEnabled)
811 Actor actor = GetCurrentFocusActor();
814 Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor);
817 // Notify the control that it is activated
818 ret = control.GetImplementation().OnAccessibilityValueChange(true);
826 bool FocusManager::AccessibilityActionDown()
830 if(mIsAccessibilityTtsEnabled)
832 Actor actor = GetCurrentFocusActor();
835 Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor);
838 // Notify the control that it is activated
839 ret = control.GetImplementation().OnAccessibilityValueChange(false);
847 bool FocusManager::ClearAccessibilityFocus()
849 if(mIsAccessibilityTtsEnabled)
860 bool FocusManager::AccessibilityActionBack()
862 // TODO: Back to previous view
864 return mIsAccessibilityTtsEnabled;
867 bool FocusManager::AccessibilityActionTouch(const TouchEvent& touchEvent)
869 bool handled = false;
871 // TODO: Need to convert the touchevent for the focused actor?
873 Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(GetCurrentFocusActor());
876 handled = control.GetImplementation().OnAccessibilityTouch(touchEvent);
882 bool FocusManager::HandlePanGesture(const Integration::PanGestureEvent& panEvent)
884 bool handled = false;
886 if( panEvent.state == Gesture::Started )
888 // Find the focusable actor at the event position
889 Dali::HitTestAlgorithm::Results results;
890 AccessibilityManager manager = AccessibilityManager::Get();
892 Dali::HitTestAlgorithm::HitTest( Stage::GetCurrent(), panEvent.currentPosition, results, IsActorFocusableFunction );
893 mCurrentGesturedActor = results.actor;
895 if(!mCurrentGesturedActor)
897 DALI_LOG_ERROR("Gesture detected, but no hit actor");
901 // Gesture::Finished (Up) events are delivered with previous (Motion) event position
902 // Use the real previous position; otherwise we may incorrectly get a ZERO velocity
903 if ( Gesture::Finished != panEvent.state )
905 // Store the previous position for next Gesture::Finished iteration.
906 mPreviousPosition = panEvent.previousPosition;
909 Actor rootActor = Stage::GetCurrent().GetRootLayer();
911 Dali::PanGesture pan(panEvent.state);
912 pan.time = panEvent.time;
913 pan.numberOfTouches = panEvent.numberOfTouches;
914 pan.screenPosition = panEvent.currentPosition;
915 pan.screenDisplacement = mPreviousPosition - panEvent.currentPosition;
916 pan.screenVelocity.x = pan.screenDisplacement.x / panEvent.timeDelta;
917 pan.screenVelocity.y = pan.screenDisplacement.y / panEvent.timeDelta;
919 // Only handle the pan gesture when the current focused actor is scrollable or within a scrollable actor
920 while(mCurrentGesturedActor && mCurrentGesturedActor != rootActor && !handled)
922 Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(mCurrentGesturedActor);
925 Vector2 localCurrent;
926 control.ScreenToLocal( localCurrent.x, localCurrent.y, panEvent.currentPosition.x, panEvent.currentPosition.y );
927 pan.position = localCurrent;
929 Vector2 localPrevious;
930 control.ScreenToLocal( localPrevious.x, localPrevious.y, mPreviousPosition.x, mPreviousPosition.y );
932 pan.displacement = localCurrent - localPrevious;
933 pan.velocity.x = pan.displacement.x / panEvent.timeDelta;
934 pan.velocity.y = pan.displacement.y / panEvent.timeDelta;
936 handled = control.GetImplementation().OnAccessibilityPan(pan);
939 // If the gesture is not handled by the control, check its parent
942 mCurrentGesturedActor = mCurrentGesturedActor.GetParent();
944 if(!mCurrentGesturedActor)
946 DALI_LOG_ERROR("no more gestured actor");
951 // If handled, then update the pan gesture properties
952 PanGestureDetector::SetPanGestureProperties( pan );
959 Toolkit::FocusManager::FocusChangedSignalType& FocusManager::FocusChangedSignal()
961 return mFocusChangedSignal;
964 Toolkit::FocusManager::FocusOvershotSignalType& FocusManager::FocusOvershotSignal()
966 return mFocusOvershotSignal;
969 Toolkit::FocusManager::FocusedActorActivatedSignalType& FocusManager::FocusedActorActivatedSignal()
971 return mFocusedActorActivatedSignal;
974 bool FocusManager::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
976 Dali::BaseHandle handle( object );
978 bool connected( true );
979 FocusManager* manager = dynamic_cast<FocusManager*>( object );
981 if( 0 == strcmp( signalName.c_str(), SIGNAL_FOCUS_CHANGED ) )
983 manager->FocusChangedSignal().Connect( tracker, functor );
985 else if( 0 == strcmp( signalName.c_str(), SIGNAL_FOCUS_OVERSHOT ) )
987 manager->FocusOvershotSignal().Connect( tracker, functor );
989 else if( 0 == strcmp( signalName.c_str(), SIGNAL_FOCUSED_ACTOR_ACTIVATED ) )
991 manager->FocusedActorActivatedSignal().Connect( tracker, functor );
995 // signalName does not match any signal
1002 } // namespace Internal
1004 } // namespace Toolkit