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 <dali/public-api/actors/layer.h>
23 #include <dali/public-api/adaptor-framework/accessibility-manager.h>
24 #include <dali/public-api/adaptor-framework/sound-player.h>
25 #include <dali/public-api/adaptor-framework/tts-player.h>
26 #include <dali/public-api/animation/constraints.h>
27 #include <dali/public-api/events/hit-test-algorithm.h>
28 #include <dali/public-api/images/resource-image.h>
29 #include <dali/integration-api/debug.h>
32 #include <dali-toolkit/public-api/controls/control.h>
33 #include <dali-toolkit/public-api/controls/control-impl.h>
44 namespace // unnamed namespace
49 const char* const SIGNAL_FOCUS_CHANGED = "focus-changed";
50 const char* const SIGNAL_FOCUS_OVERSHOT = "focus-overshot";
51 const char* const SIGNAL_FOCUSED_ACTOR_ACTIVATED = "focused-actor-activated";
53 #if defined(DEBUG_ENABLED)
54 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_FOCUS_MANAGER");
57 const char* const ACTOR_FOCUSABLE("focusable");
58 const char* const IS_FOCUS_GROUP("is-focus-group");
60 const char* FOCUS_BORDER_IMAGE_PATH = DALI_IMAGE_DIR "B16-8_TTS_focus.png";
61 const Vector4 FOCUS_BORDER_IMAGE_BORDER = Vector4(7.0f, 7.0f, 7.0f, 7.0f);
63 const char* FOCUS_SOUND_FILE = DALI_SOUND_DIR "Focus.ogg";
64 const char* FOCUS_CHAIN_END_SOUND_FILE = DALI_SOUND_DIR "End_of_List.ogg";
67 * The function to be used in the hit-test algorithm to check whether the actor is hittable.
69 bool IsActorFocusableFunction(Actor actor, Dali::HitTestAlgorithm::TraverseType type)
71 bool hittable = false;
75 case Dali::HitTestAlgorithm::CHECK_ACTOR:
77 // Check whether the actor is visible and not fully transparent.
79 && actor.GetCurrentWorldColor().a > 0.01f) // not FULLY_TRANSPARENT
81 // Check whether the actor is focusable
82 Property::Index propertyActorFocusable = actor.GetPropertyIndex(ACTOR_FOCUSABLE);
83 if(propertyActorFocusable != Property::INVALID_INDEX)
85 hittable = actor.GetProperty<bool>(propertyActorFocusable);
90 case Dali::HitTestAlgorithm::DESCEND_ACTOR_TREE:
92 if( actor.IsVisible() ) // Actor is visible, if not visible then none of its children are visible.
109 FocusManager::FocusManager()
111 mIsFocusWithinGroup(false),
112 mIsEndcapFeedbackEnabled(false),
113 mIsEndcapFeedbackPlayed(false),
114 mCurrentFocusActor(FocusIDPair(0, 0)),
115 mFocusIndicatorActor(Actor()),
116 mRecursiveFocusMoveCounter(0),
117 mIsAccessibilityTtsEnabled(false),
118 mIsFocusIndicatorEnabled(false)
120 CreateDefaultFocusIndicatorActor();
122 AccessibilityManager manager = AccessibilityManager::Get();
123 manager.SetActionHandler(*this);
124 manager.SetGestureHandler(*this);
126 ChangeAccessibilityStatus();
129 FocusManager::~FocusManager()
133 FocusManager::ActorAdditionalInfo FocusManager::GetActorAdditionalInfo(const unsigned int actorID) const
135 ActorAdditionalInfo data;
136 IDAdditionalInfoConstIter iter = mIDAdditionalInfoContainer.find(actorID);
137 if(iter != mIDAdditionalInfoContainer.end())
139 data = (*iter).second;
145 void FocusManager::SynchronizeActorAdditionalInfo(const unsigned int actorID, const unsigned int order)
147 ActorAdditionalInfo actorInfo = GetActorAdditionalInfo(actorID);
148 actorInfo.mFocusOrder = order;
149 mIDAdditionalInfoContainer.erase(actorID);
150 mIDAdditionalInfoContainer.insert(IDAdditionalInfoPair(actorID, actorInfo));
153 void FocusManager::SetAccessibilityAttribute(Actor actor, Toolkit::FocusManager::AccessibilityAttribute type, const std::string& text)
157 unsigned int actorID = actor.GetId();
159 ActorAdditionalInfo info = GetActorAdditionalInfo(actorID);
160 info.mAccessibilityAttributes[type] = text;
162 mIDAdditionalInfoContainer.erase(actorID);
163 mIDAdditionalInfoContainer.insert(IDAdditionalInfoPair(actorID, info));
167 std::string FocusManager::GetAccessibilityAttribute(Actor actor, Toolkit::FocusManager::AccessibilityAttribute type) const
173 ActorAdditionalInfo data = GetActorAdditionalInfo(actor.GetId());
174 text = data.mAccessibilityAttributes[type];
180 void FocusManager::SetFocusOrder(Actor actor, const unsigned int order)
182 // Do nothing if the focus order of the actor is not changed.
183 if(actor && GetFocusOrder(actor) != order)
185 // Firstly delete the actor from the focus chain if it's already there with a different focus order.
186 mFocusIDContainer.erase(GetFocusOrder(actor));
188 // Create actor focusable property if not already created.
189 Property::Index propertyActorFocusable = actor.GetPropertyIndex(ACTOR_FOCUSABLE);
190 if(propertyActorFocusable == Property::INVALID_INDEX)
192 propertyActorFocusable = actor.RegisterProperty(ACTOR_FOCUSABLE, true);
197 // The actor is not focusable without a defined focus order.
198 actor.SetProperty(propertyActorFocusable, false);
200 // If the actor is currently being focused, it should clear the focus
201 if(actor == GetCurrentFocusActor())
206 else // Insert the actor to the focus chain
208 // Check whether there is another actor in the focus chain with the same focus order already.
209 FocusIDIter focusIDIter = mFocusIDContainer.find(order);
210 if(focusIDIter != mFocusIDContainer.end())
212 // We need to increase the focus order of that actor and all the actors followed it
213 // in the focus chain.
214 FocusIDIter lastIter = mFocusIDContainer.end();
215 --lastIter;//We want forward iterator to the last element here
216 mFocusIDContainer.insert(FocusIDPair((*lastIter).first + 1, (*lastIter).second));
218 // Update the actor's focus order in its additional data
219 SynchronizeActorAdditionalInfo((*lastIter).second, (*lastIter).first + 1);
221 for(FocusIDIter iter = lastIter; iter != focusIDIter; iter--)
223 FocusIDIter previousIter = iter;
224 --previousIter;//We want forward iterator to the previous element here
225 unsigned int actorID = (*previousIter).second;
226 (*iter).second = actorID;
228 // Update the actor's focus order in its additional data
229 SynchronizeActorAdditionalInfo(actorID, (*iter).first);
232 mFocusIDContainer.erase(order);
235 // The actor is focusable
236 actor.SetProperty(propertyActorFocusable, true);
238 // Now we insert the actor into the focus chain with the specified focus order
239 mFocusIDContainer.insert(FocusIDPair(order, actor.GetId()));
242 // Update the actor's focus order in its additional data
243 SynchronizeActorAdditionalInfo(actor.GetId(), order);
247 unsigned int FocusManager::GetFocusOrder(Actor actor) const
249 unsigned int focusOrder = 0;
253 ActorAdditionalInfo data = GetActorAdditionalInfo(actor.GetId());
254 focusOrder = data.mFocusOrder;
260 unsigned int FocusManager::GenerateNewFocusOrder() const
262 unsigned int order = 1;
263 FocusIDContainer::const_reverse_iterator iter = mFocusIDContainer.rbegin();
265 if(iter != mFocusIDContainer.rend())
267 order = (*iter).first + 1;
273 Actor FocusManager::GetActorByFocusOrder(const unsigned int order)
275 Actor actor = Actor();
277 FocusIDIter focusIDIter = mFocusIDContainer.find(order);
278 if(focusIDIter != mFocusIDContainer.end())
280 Actor rootActor = Stage::GetCurrent().GetRootLayer();
281 actor = rootActor.FindChildById(mFocusIDContainer[order]);
287 bool FocusManager::SetCurrentFocusActor(Actor actor)
291 return DoSetCurrentFocusActor(actor.GetId());
297 bool FocusManager::DoSetCurrentFocusActor(const unsigned int actorID)
299 Actor rootActor = Stage::GetCurrent().GetRootLayer();
301 // If the group mode is enabled, check which focus group the current focused actor belongs to
303 if(mIsFocusWithinGroup)
305 focusGroup = GetFocusGroup(GetCurrentFocusActor());
310 focusGroup = rootActor;
313 Actor actor = focusGroup.FindChildById(actorID);
315 // Check whether the actor is in the stage
318 // Check whether the actor is focusable
319 bool actorFocusable = false;
320 Property::Index propertyActorFocusable = actor.GetPropertyIndex(ACTOR_FOCUSABLE);
321 if(propertyActorFocusable != Property::INVALID_INDEX)
323 actorFocusable = actor.GetProperty<bool>(propertyActorFocusable);
326 // Go through the actor's hierarchy to check whether the actor is visible
327 bool actorVisible = actor.IsVisible();
328 Actor parent = actor.GetParent();
329 while (actorVisible && parent && parent != rootActor)
331 actorVisible = parent.IsVisible();
332 parent = parent.GetParent();
335 // Check whether the actor is fully transparent
336 bool actorOpaque = actor.GetCurrentWorldColor().a > 0.01f;
338 // Set the focus only when the actor is focusable and visible and not fully transparent
339 if(actorVisible && actorFocusable && actorOpaque)
341 // Draw the focus indicator upon the focused actor
342 if(mIsFocusIndicatorEnabled && mFocusIndicatorActor)
344 actor.Add(mFocusIndicatorActor);
347 // Send notification for the change of focus actor
348 mFocusChangedSignal.Emit( GetCurrentFocusActor(), actor );
350 // Save the current focused actor
351 mCurrentFocusActor = FocusIDPair(GetFocusOrder(actor), actorID);
353 if(mIsAccessibilityTtsEnabled)
355 Dali::SoundPlayer soundPlayer = Dali::SoundPlayer::Get();
358 soundPlayer.PlaySound(FOCUS_SOUND_FILE);
361 // Play the accessibility attributes with the TTS player.
362 Dali::TtsPlayer player = Dali::TtsPlayer::Get(Dali::TtsPlayer::SCREEN_READER);
364 // Combine attribute texts to one text
365 std::string informationText;
366 for(int i = 0; i < Toolkit::FocusManager::ACCESSIBILITY_ATTRIBUTE_NUM; i++)
368 if(!GetActorAdditionalInfo(actorID).mAccessibilityAttributes[i].empty())
372 informationText += ", "; // for space time between each information
374 informationText += GetActorAdditionalInfo(actorID).mAccessibilityAttributes[i];
377 player.Play(informationText);
384 DALI_LOG_WARNING("[%s:%d] FAILED\n", __FUNCTION__, __LINE__);
388 Actor FocusManager::GetCurrentFocusActor()
390 Actor rootActor = Stage::GetCurrent().GetRootLayer();
391 return rootActor.FindChildById(mCurrentFocusActor.second);
394 Actor FocusManager::GetCurrentFocusGroup()
396 return GetFocusGroup(GetCurrentFocusActor());
399 unsigned int FocusManager::GetCurrentFocusOrder()
401 return mCurrentFocusActor.first;
404 bool FocusManager::MoveFocusForward()
407 mRecursiveFocusMoveCounter = 0;
409 FocusIDIter focusIDIter = mFocusIDContainer.find(mCurrentFocusActor.first);
410 if(focusIDIter != mFocusIDContainer.end())
412 DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] focus order : %d\n", __FUNCTION__, __LINE__, (*focusIDIter).first);
413 ret = DoMoveFocus(focusIDIter, true, mIsWrapped);
417 // TODO: if there is not focused actor, move first actor
418 if(!mFocusIDContainer.empty())
420 //if there is not focused actor, move 1st actor
421 focusIDIter = mFocusIDContainer.begin(); // TODO: I'm not sure it was sorted.
422 DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] focus order : %d\n", __FUNCTION__, __LINE__, (*focusIDIter).first);
423 ret = DoSetCurrentFocusActor((*focusIDIter).second);
427 DALI_LOG_INFO( gLogFilter, Debug::General, "[%s] %s\n", __FUNCTION__, ret?"SUCCEED!!!":"FAILED!!!");
432 bool FocusManager::MoveFocusBackward()
435 mRecursiveFocusMoveCounter = 0;
437 FocusIDIter focusIDIter = mFocusIDContainer.find(mCurrentFocusActor.first);
438 if(focusIDIter != mFocusIDContainer.end())
440 DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] focus order : %d\n", __FUNCTION__, __LINE__, (*focusIDIter).first);
441 ret = DoMoveFocus(focusIDIter, false, mIsWrapped);
445 // TODO: if there is not focused actor, move last actor
446 if(!mFocusIDContainer.empty())
448 //if there is not focused actor, move last actor
449 focusIDIter = mFocusIDContainer.end();
450 --focusIDIter;//We want forward iterator to the last element here
451 DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] focus order : %d\n", __FUNCTION__, __LINE__, (*focusIDIter).first);
452 ret = DoSetCurrentFocusActor((*focusIDIter).second);
456 DALI_LOG_INFO( gLogFilter, Debug::General, "[%s] %s\n", __FUNCTION__, ret?"SUCCEED!!!":"FAILED!!!");
461 void FocusManager::DoActivate(Actor actor)
465 Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor);
468 // Notify the control that it is activated
469 control.GetImplementation().Activate();
472 // Send notification for the activation of focused actor
473 mFocusedActorActivatedSignal.Emit(actor);
477 void FocusManager::ClearFocus()
479 Actor actor = GetCurrentFocusActor();
482 actor.Remove(mFocusIndicatorActor);
485 mCurrentFocusActor = FocusIDPair(0, 0);
487 // Send notification for the change of focus actor
488 mFocusChangedSignal.Emit(actor, Actor());
490 if(mIsAccessibilityTtsEnabled)
492 // Stop the TTS playing if any
493 Dali::TtsPlayer player = Dali::TtsPlayer::Get(Dali::TtsPlayer::SCREEN_READER);
498 void FocusManager::Reset()
501 mFocusIDContainer.clear();
502 mIDAdditionalInfoContainer.clear();
505 void FocusManager::SetFocusGroup(Actor actor, bool isFocusGroup)
509 // Create focus group property if not already created.
510 Property::Index propertyIsFocusGroup = actor.GetPropertyIndex(IS_FOCUS_GROUP);
511 if(propertyIsFocusGroup == Property::INVALID_INDEX)
513 actor.RegisterProperty(IS_FOCUS_GROUP, isFocusGroup);
517 actor.SetProperty(propertyIsFocusGroup, isFocusGroup);
522 bool FocusManager::IsFocusGroup(Actor actor) const
524 // Check whether the actor is a focus group
525 bool isFocusGroup = false;
529 Property::Index propertyIsFocusGroup = actor.GetPropertyIndex(IS_FOCUS_GROUP);
530 if(propertyIsFocusGroup != Property::INVALID_INDEX)
532 isFocusGroup = actor.GetProperty<bool>(propertyIsFocusGroup);
539 Actor FocusManager::GetFocusGroup(Actor actor)
541 // Go through the actor's hierarchy to check which focus group the actor belongs to
542 while (actor && !IsFocusGroup(actor))
544 actor = actor.GetParent();
550 void FocusManager::SetGroupMode(bool enabled)
552 mIsFocusWithinGroup = enabled;
555 bool FocusManager::GetGroupMode() const
557 return mIsFocusWithinGroup;
560 void FocusManager::SetWrapMode(bool wrapped)
562 mIsWrapped = wrapped;
565 bool FocusManager::GetWrapMode() const
570 void FocusManager::SetFocusIndicatorActor(Actor indicator)
572 mFocusIndicatorActor = indicator;
575 Actor FocusManager::GetFocusIndicatorActor()
577 return mFocusIndicatorActor;
580 bool FocusManager::DoMoveFocus(FocusIDIter focusIDIter, bool forward, bool wrapped)
582 DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] %d focusable actors\n", __FUNCTION__, __LINE__, mFocusIDContainer.size());
583 DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] focus order : %d\n", __FUNCTION__, __LINE__, (*focusIDIter).first);
585 if( (forward && ++focusIDIter == mFocusIDContainer.end())
586 || (!forward && focusIDIter-- == mFocusIDContainer.begin()) )
588 if(mIsEndcapFeedbackEnabled)
590 if(mIsEndcapFeedbackPlayed == false)
592 // play sound & skip moving once
593 Dali::SoundPlayer soundPlayer = Dali::SoundPlayer::Get();
596 soundPlayer.PlaySound(FOCUS_CHAIN_END_SOUND_FILE);
599 mIsEndcapFeedbackPlayed = true;
602 mIsEndcapFeedbackPlayed = false;
609 focusIDIter = mFocusIDContainer.begin();
613 focusIDIter = mFocusIDContainer.end();
614 --focusIDIter;//We want forward iterator to the last element here
619 DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] Overshot\n", __FUNCTION__, __LINE__);
620 // Send notification for handling overshooted situation
621 mFocusOvershotSignal.Emit(GetCurrentFocusActor(), forward ? Toolkit::FocusManager::OVERSHOT_NEXT : Toolkit::FocusManager::OVERSHOT_PREVIOUS);
623 return false; // Try to move the focus out of the scope
627 if((focusIDIter != mFocusIDContainer.end()) && !DoSetCurrentFocusActor((*focusIDIter).second))
629 mRecursiveFocusMoveCounter++;
630 if(mRecursiveFocusMoveCounter > mFocusIDContainer.size())
632 // We've attempted to focus all the actors in the whole focus chain and no actor
633 // can be focused successfully.
635 DALI_LOG_WARNING("[%s] There is no more focusable actor in %d focus chains\n", __FUNCTION__, mRecursiveFocusMoveCounter);
641 return DoMoveFocus(focusIDIter, forward, wrapped);
648 void FocusManager::SetFocusable(Actor actor, bool focusable)
652 // Create actor focusable property if not already created.
653 Property::Index propertyActorFocusable = actor.GetPropertyIndex(ACTOR_FOCUSABLE);
654 if(propertyActorFocusable == Property::INVALID_INDEX)
656 actor.RegisterProperty(ACTOR_FOCUSABLE, focusable);
660 actor.SetProperty(propertyActorFocusable, focusable);
665 void FocusManager::CreateDefaultFocusIndicatorActor()
667 // Create a focus indicator actor shared by all the focusable actors
668 Image borderImage = ResourceImage::New(FOCUS_BORDER_IMAGE_PATH);
670 ImageActor focusIndicator = ImageActor::New(borderImage);
671 focusIndicator.SetPositionInheritanceMode( Dali::USE_PARENT_POSITION_PLUS_LOCAL_POSITION );
672 focusIndicator.SetStyle( ImageActor::STYLE_NINE_PATCH );
673 focusIndicator.SetNinePatchBorder(FOCUS_BORDER_IMAGE_BORDER);
674 focusIndicator.SetPosition(Vector3(0.0f, 0.0f, 1.0f));
676 // Apply size constraint to the focus indicator
677 focusIndicator.SetSizeMode( SIZE_EQUAL_TO_PARENT );
679 SetFocusIndicatorActor(focusIndicator);
682 bool FocusManager::ChangeAccessibilityStatus()
684 AccessibilityManager manager = AccessibilityManager::Get();
685 mIsAccessibilityTtsEnabled = manager.IsEnabled();
687 if(mIsAccessibilityTtsEnabled)
689 // Show indicator when tts turned on if there is focused actor.
690 Actor actor = GetCurrentFocusActor();
693 if(mFocusIndicatorActor)
695 actor.Add(mFocusIndicatorActor);
698 mIsFocusIndicatorEnabled = true;
702 // Hide indicator when tts turned off
703 Actor actor = GetCurrentFocusActor();
706 actor.Remove(mFocusIndicatorActor);
708 mIsFocusIndicatorEnabled = false;
714 bool FocusManager::AccessibilityActionNext(bool allowEndFeedback)
716 if(mIsAccessibilityTtsEnabled)
718 mIsEndcapFeedbackEnabled = allowEndFeedback;
719 return MoveFocusForward();
727 bool FocusManager::AccessibilityActionPrevious(bool allowEndFeedback)
729 if(mIsAccessibilityTtsEnabled)
731 mIsEndcapFeedbackEnabled = allowEndFeedback;
732 return MoveFocusBackward();
740 bool FocusManager::AccessibilityActionActivate()
744 Actor actor = GetCurrentFocusActor();
754 bool FocusManager::AccessibilityActionRead(bool allowReadAgain)
758 if(mIsAccessibilityTtsEnabled)
760 // Find the focusable actor at the read position
761 AccessibilityManager manager = AccessibilityManager::Get();
762 Dali::HitTestAlgorithm::Results results;
763 Dali::HitTestAlgorithm::HitTest( Stage::GetCurrent(), manager.GetReadPosition(), results, IsActorFocusableFunction );
765 FocusIDIter focusIDIter = mFocusIDContainer.find(GetFocusOrder(results.actor));
766 if(focusIDIter != mFocusIDContainer.end())
768 if( allowReadAgain || (results.actor != GetCurrentFocusActor()) )
770 // Move the focus to the actor
771 ret = SetCurrentFocusActor(results.actor);
772 DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] SetCurrentFocusActor returns %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
780 bool FocusManager::AccessibilityActionReadNext(bool allowEndFeedback)
782 if(mIsAccessibilityTtsEnabled)
784 return MoveFocusForward();
792 bool FocusManager::AccessibilityActionReadPrevious(bool allowEndFeedback)
794 if(mIsAccessibilityTtsEnabled)
796 return MoveFocusBackward();
804 bool FocusManager::AccessibilityActionUp()
808 if(mIsAccessibilityTtsEnabled)
810 Actor actor = GetCurrentFocusActor();
813 Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor);
816 // Notify the control that it is activated
817 ret = control.GetImplementation().OnAccessibilityValueChange(true);
825 bool FocusManager::AccessibilityActionDown()
829 if(mIsAccessibilityTtsEnabled)
831 Actor actor = GetCurrentFocusActor();
834 Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor);
837 // Notify the control that it is activated
838 ret = control.GetImplementation().OnAccessibilityValueChange(false);
846 bool FocusManager::ClearAccessibilityFocus()
848 if(mIsAccessibilityTtsEnabled)
859 bool FocusManager::AccessibilityActionBack()
861 // TODO: Back to previous view
863 return mIsAccessibilityTtsEnabled;
866 bool FocusManager::AccessibilityActionTouch(const TouchEvent& touchEvent)
868 bool handled = false;
870 // TODO: Need to convert the touchevent for the focused actor?
872 Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(GetCurrentFocusActor());
875 handled = control.GetImplementation().OnAccessibilityTouch(touchEvent);
881 bool FocusManager::HandlePanGesture(const Integration::PanGestureEvent& panEvent)
883 bool handled = false;
885 if( panEvent.state == Gesture::Started )
887 // Find the focusable actor at the event position
888 Dali::HitTestAlgorithm::Results results;
889 AccessibilityManager manager = AccessibilityManager::Get();
891 Dali::HitTestAlgorithm::HitTest( Stage::GetCurrent(), panEvent.currentPosition, results, IsActorFocusableFunction );
892 mCurrentGesturedActor = results.actor;
894 if(!mCurrentGesturedActor)
896 DALI_LOG_ERROR("Gesture detected, but no hit actor");
900 // Gesture::Finished (Up) events are delivered with previous (Motion) event position
901 // Use the real previous position; otherwise we may incorrectly get a ZERO velocity
902 if ( Gesture::Finished != panEvent.state )
904 // Store the previous position for next Gesture::Finished iteration.
905 mPreviousPosition = panEvent.previousPosition;
908 Actor rootActor = Stage::GetCurrent().GetRootLayer();
910 Dali::PanGesture pan(panEvent.state);
911 pan.time = panEvent.time;
912 pan.numberOfTouches = panEvent.numberOfTouches;
913 pan.screenPosition = panEvent.currentPosition;
914 pan.screenDisplacement = mPreviousPosition - panEvent.currentPosition;
915 pan.screenVelocity.x = pan.screenDisplacement.x / panEvent.timeDelta;
916 pan.screenVelocity.y = pan.screenDisplacement.y / panEvent.timeDelta;
918 // Only handle the pan gesture when the current focused actor is scrollable or within a scrollable actor
919 while(mCurrentGesturedActor && mCurrentGesturedActor != rootActor && !handled)
921 Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(mCurrentGesturedActor);
924 Vector2 localCurrent;
925 control.ScreenToLocal( localCurrent.x, localCurrent.y, panEvent.currentPosition.x, panEvent.currentPosition.y );
926 pan.position = localCurrent;
928 Vector2 localPrevious;
929 control.ScreenToLocal( localPrevious.x, localPrevious.y, mPreviousPosition.x, mPreviousPosition.y );
931 pan.displacement = localCurrent - localPrevious;
932 pan.velocity.x = pan.displacement.x / panEvent.timeDelta;
933 pan.velocity.y = pan.displacement.y / panEvent.timeDelta;
935 handled = control.GetImplementation().OnAccessibilityPan(pan);
938 // If the gesture is not handled by the control, check its parent
941 mCurrentGesturedActor = mCurrentGesturedActor.GetParent();
943 if(!mCurrentGesturedActor)
945 DALI_LOG_ERROR("no more gestured actor");
950 // If handled, then update the pan gesture properties
951 PanGestureDetector::SetPanGestureProperties( pan );
958 Toolkit::FocusManager::FocusChangedSignalType& FocusManager::FocusChangedSignal()
960 return mFocusChangedSignal;
963 Toolkit::FocusManager::FocusOvershotSignalType& FocusManager::FocusOvershotSignal()
965 return mFocusOvershotSignal;
968 Toolkit::FocusManager::FocusedActorActivatedSignalType& FocusManager::FocusedActorActivatedSignal()
970 return mFocusedActorActivatedSignal;
973 bool FocusManager::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
975 Dali::BaseHandle handle( object );
977 bool connected( true );
978 FocusManager* manager = dynamic_cast<FocusManager*>( object );
980 if( 0 == strcmp( signalName.c_str(), SIGNAL_FOCUS_CHANGED ) )
982 manager->FocusChangedSignal().Connect( tracker, functor );
984 else if( 0 == strcmp( signalName.c_str(), SIGNAL_FOCUS_OVERSHOT ) )
986 manager->FocusOvershotSignal().Connect( tracker, functor );
988 else if( 0 == strcmp( signalName.c_str(), SIGNAL_FOCUSED_ACTOR_ACTIVATED ) )
990 manager->FocusedActorActivatedSignal().Connect( tracker, functor );
994 // signalName does not match any signal
1001 } // namespace Internal
1003 } // namespace Toolkit