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-toolkit/public-api/controls/control.h>
23 #include <dali-toolkit/public-api/controls/control-impl.h>
24 #include <dali/integration-api/debug.h>
35 namespace // unnamed namespace
38 #if defined(DEBUG_ENABLED)
39 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_FOCUS_MANAGER");
42 const char * const ACTOR_FOCUSABLE("focusable");
43 const char * const IS_FOCUS_GROUP("is-focus-group");
45 const char* FOCUS_BORDER_IMAGE_PATH = DALI_IMAGE_DIR "B16-8_TTS_focus.png";
46 const Vector4 FOCUS_BORDER_IMAGE_BORDER = Vector4(7.0f, 7.0f, 7.0f, 7.0f);
48 const char* FOCUS_SOUND_FILE = DALI_SOUND_DIR "Focus.ogg";
49 const char* FOCUS_CHAIN_END_SOUND_FILE = DALI_SOUND_DIR "End_of_List.ogg";
52 * The function to be used in the hit-test algorithm to check whether the actor is hittable.
54 bool IsActorFocusableFunction(Actor actor, Dali::HitTestAlgorithm::TraverseType type)
56 bool hittable = false;
60 case Dali::HitTestAlgorithm::CHECK_ACTOR:
62 // Check whether the actor is visible and not fully transparent.
64 && actor.GetCurrentWorldColor().a > 0.01f) // not FULLY_TRANSPARENT
66 // Check whether the actor is focusable
67 Property::Index propertyActorFocusable = actor.GetPropertyIndex(ACTOR_FOCUSABLE);
68 if(propertyActorFocusable != Property::INVALID_INDEX)
70 hittable = actor.GetProperty<bool>(propertyActorFocusable);
75 case Dali::HitTestAlgorithm::DESCEND_ACTOR_TREE:
77 if( actor.IsVisible() ) // Actor is visible, if not visible then none of its children are visible.
94 FocusManager::FocusManager()
96 mIsFocusWithinGroup(false),
97 mIsEndcapFeedbackEnabled(true),
98 mIsEndcapFeedbackPlayed(false),
99 mCurrentFocusActor(FocusIDPair(0, 0)),
100 mFocusIndicatorActor(Actor()),
101 mRecursiveFocusMoveCounter(0),
102 mIsAccessibilityTtsEnabled(false),
103 mIsFocusIndicatorEnabled(false)
105 CreateDefaultFocusIndicatorActor();
107 AccessibilityManager manager = AccessibilityManager::Get();
108 manager.SetActionHandler(*this);
109 manager.SetGestureHandler(*this);
111 ChangeAccessibilityStatus();
114 FocusManager::~FocusManager()
118 FocusManager::ActorAdditionalInfo FocusManager::GetActorAdditionalInfo(const unsigned int actorID) const
120 ActorAdditionalInfo data;
121 IDAdditionalInfoConstIter iter = mIDAdditionalInfoContainer.find(actorID);
122 if(iter != mIDAdditionalInfoContainer.end())
124 data = (*iter).second;
130 void FocusManager::SynchronizeActorAdditionalInfo(const unsigned int actorID, const unsigned int order)
132 ActorAdditionalInfo actorInfo = GetActorAdditionalInfo(actorID);
133 actorInfo.mFocusOrder = order;
134 mIDAdditionalInfoContainer.erase(actorID);
135 mIDAdditionalInfoContainer.insert(IDAdditionalInfoPair(actorID, actorInfo));
138 void FocusManager::SetAccessibilityAttribute(Actor actor, Toolkit::FocusManager::AccessibilityAttribute type, const std::string& text)
142 unsigned int actorID = actor.GetId();
144 ActorAdditionalInfo info = GetActorAdditionalInfo(actorID);
145 info.mAccessibilityAttributes[type] = text;
147 mIDAdditionalInfoContainer.erase(actorID);
148 mIDAdditionalInfoContainer.insert(IDAdditionalInfoPair(actorID, info));
152 std::string FocusManager::GetAccessibilityAttribute(Actor actor, Toolkit::FocusManager::AccessibilityAttribute type) const
158 ActorAdditionalInfo data = GetActorAdditionalInfo(actor.GetId());
159 text = data.mAccessibilityAttributes[type];
165 void FocusManager::SetFocusOrder(Actor actor, const unsigned int order)
167 // Do nothing if the focus order of the actor is not changed.
168 if(actor && GetFocusOrder(actor) != order)
170 // Firstly delete the actor from the focus chain if it's already there with a different focus order.
171 mFocusIDContainer.erase(GetFocusOrder(actor));
173 // Create actor focusable property if not already created.
174 Property::Index propertyActorFocusable = actor.GetPropertyIndex(ACTOR_FOCUSABLE);
175 if(propertyActorFocusable == Property::INVALID_INDEX)
177 propertyActorFocusable = actor.RegisterProperty(ACTOR_FOCUSABLE, true);
182 // The actor is not focusable without a defined focus order.
183 actor.SetProperty(propertyActorFocusable, false);
185 // If the actor is currently being focused, it should clear the focus
186 if(actor == GetCurrentFocusActor())
191 else // Insert the actor to the focus chain
193 // Check whether there is another actor in the focus chain with the same focus order already.
194 FocusIDIter focusIDIter = mFocusIDContainer.find(order);
195 if(focusIDIter != mFocusIDContainer.end())
197 // We need to increase the focus order of that actor and all the actors followed it
198 // in the focus chain.
199 FocusIDIter lastIter = mFocusIDContainer.end();
200 --lastIter;//We want forward iterator to the last element here
201 mFocusIDContainer.insert(FocusIDPair((*lastIter).first + 1, (*lastIter).second));
203 // Update the actor's focus order in its additional data
204 SynchronizeActorAdditionalInfo((*lastIter).second, (*lastIter).first + 1);
206 for(FocusIDIter iter = lastIter; iter != focusIDIter; iter--)
208 FocusIDIter previousIter = iter;
209 --previousIter;//We want forward iterator to the previous element here
210 unsigned int actorID = (*previousIter).second;
211 (*iter).second = actorID;
213 // Update the actor's focus order in its additional data
214 SynchronizeActorAdditionalInfo(actorID, (*iter).first);
217 mFocusIDContainer.erase(order);
220 // The actor is focusable
221 actor.SetProperty(propertyActorFocusable, true);
223 // Now we insert the actor into the focus chain with the specified focus order
224 mFocusIDContainer.insert(FocusIDPair(order, actor.GetId()));
227 // Update the actor's focus order in its additional data
228 SynchronizeActorAdditionalInfo(actor.GetId(), order);
232 unsigned int FocusManager::GetFocusOrder(Actor actor) const
234 unsigned int focusOrder = 0;
238 ActorAdditionalInfo data = GetActorAdditionalInfo(actor.GetId());
239 focusOrder = data.mFocusOrder;
245 unsigned int FocusManager::GenerateNewFocusOrder() const
247 unsigned int order = 1;
248 FocusIDContainer::const_reverse_iterator iter = mFocusIDContainer.rbegin();
250 if(iter != mFocusIDContainer.rend())
252 order = (*iter).first + 1;
258 Actor FocusManager::GetActorByFocusOrder(const unsigned int order)
260 Actor actor = Actor();
262 FocusIDIter focusIDIter = mFocusIDContainer.find(order);
263 if(focusIDIter != mFocusIDContainer.end())
265 Actor rootActor = Stage::GetCurrent().GetRootLayer();
266 actor = rootActor.FindChildById(mFocusIDContainer[order]);
272 bool FocusManager::SetCurrentFocusActor(Actor actor)
276 return DoSetCurrentFocusActor(actor.GetId());
282 bool FocusManager::DoSetCurrentFocusActor(const unsigned int actorID)
284 Actor rootActor = Stage::GetCurrent().GetRootLayer();
286 // If the group mode is enabled, check which focus group the current focused actor belongs to
288 if(mIsFocusWithinGroup)
290 focusGroup = GetFocusGroup(GetCurrentFocusActor());
295 focusGroup = rootActor;
298 Actor actor = focusGroup.FindChildById(actorID);
300 // Check whether the actor is in the stage
303 // Check whether the actor is focusable
304 bool actorFocusable = false;
305 Property::Index propertyActorFocusable = actor.GetPropertyIndex(ACTOR_FOCUSABLE);
306 if(propertyActorFocusable != Property::INVALID_INDEX)
308 actorFocusable = actor.GetProperty<bool>(propertyActorFocusable);
311 // Go through the actor's hierarchy to check whether the actor is visible
312 bool actorVisible = actor.IsVisible();
313 Actor parent = actor.GetParent();
314 while (actorVisible && parent && parent != rootActor)
316 actorVisible = parent.IsVisible();
317 parent = parent.GetParent();
320 // Check whether the actor is fully transparent
321 bool actorOpaque = actor.GetCurrentWorldColor().a > 0.01f;
323 // Set the focus only when the actor is focusable and visible and not fully transparent
324 if(actorVisible && actorFocusable && actorOpaque)
326 // Draw the focus indicator upon the focused actor
327 if(mIsFocusIndicatorEnabled && mFocusIndicatorActor)
329 actor.Add(mFocusIndicatorActor);
332 // Send notification for the change of focus actor
333 mFocusChangedSignalV2.Emit( GetCurrentFocusActor(), actor );
335 // Save the current focused actor
336 mCurrentFocusActor = FocusIDPair(GetFocusOrder(actor), actorID);
338 if(mIsAccessibilityTtsEnabled)
340 Dali::SoundPlayer soundPlayer = Dali::SoundPlayer::Get();
343 soundPlayer.PlaySound(FOCUS_SOUND_FILE);
346 // Play the accessibility attributes with the TTS player.
347 Dali::TtsPlayer player = Dali::TtsPlayer::Get(Dali::TtsPlayer::SCREEN_READER);
349 // Combine attribute texts to one text
350 std::string informationText;
351 for(int i = 0; i < Toolkit::FocusManager::ACCESSIBILITY_ATTRIBUTE_NUM; i++)
353 if(!GetActorAdditionalInfo(actorID).mAccessibilityAttributes[i].empty())
357 informationText += ", "; // for space time between each information
359 informationText += GetActorAdditionalInfo(actorID).mAccessibilityAttributes[i];
362 player.Play(informationText);
369 DALI_LOG_WARNING("[%s:%d] FAILED\n", __FUNCTION__, __LINE__);
373 Actor FocusManager::GetCurrentFocusActor()
375 Actor rootActor = Stage::GetCurrent().GetRootLayer();
376 return rootActor.FindChildById(mCurrentFocusActor.second);
379 Actor FocusManager::GetCurrentFocusGroup()
381 return GetFocusGroup(GetCurrentFocusActor());
384 unsigned int FocusManager::GetCurrentFocusOrder()
386 return mCurrentFocusActor.first;
389 bool FocusManager::MoveFocusForward()
392 mRecursiveFocusMoveCounter = 0;
394 FocusIDIter focusIDIter = mFocusIDContainer.find(mCurrentFocusActor.first);
395 if(focusIDIter != mFocusIDContainer.end())
397 DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] focus order : %d\n", __FUNCTION__, __LINE__, (*focusIDIter).first);
398 ret = DoMoveFocus(focusIDIter, true, mIsWrapped);
402 // TODO: if there is not focused actor, move first actor
403 if(!mFocusIDContainer.empty())
405 //if there is not focused actor, move 1st actor
406 focusIDIter = mFocusIDContainer.begin(); // TODO: I'm not sure it was sorted.
407 DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] focus order : %d\n", __FUNCTION__, __LINE__, (*focusIDIter).first);
408 ret = DoSetCurrentFocusActor((*focusIDIter).second);
412 DALI_LOG_INFO( gLogFilter, Debug::General, "[%s] %s\n", __FUNCTION__, ret?"SUCCEED!!!":"FAILED!!!");
417 bool FocusManager::MoveFocusBackward()
420 mRecursiveFocusMoveCounter = 0;
422 FocusIDIter focusIDIter = mFocusIDContainer.find(mCurrentFocusActor.first);
423 if(focusIDIter != mFocusIDContainer.end())
425 DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] focus order : %d\n", __FUNCTION__, __LINE__, (*focusIDIter).first);
426 ret = DoMoveFocus(focusIDIter, false, mIsWrapped);
430 // TODO: if there is not focused actor, move last actor
431 if(!mFocusIDContainer.empty())
433 //if there is not focused actor, move last actor
434 focusIDIter = mFocusIDContainer.end();
435 --focusIDIter;//We want forward iterator to the last element here
436 DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] focus order : %d\n", __FUNCTION__, __LINE__, (*focusIDIter).first);
437 ret = DoSetCurrentFocusActor((*focusIDIter).second);
441 DALI_LOG_INFO( gLogFilter, Debug::General, "[%s] %s\n", __FUNCTION__, ret?"SUCCEED!!!":"FAILED!!!");
446 void FocusManager::DoActivate(Actor actor)
450 Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor);
453 // Notify the control that it is activated
454 control.GetImplementation().OnActivated();
457 // Send notification for the activation of focused actor
458 mFocusedActorActivatedSignalV2.Emit(actor);
462 void FocusManager::ClearFocus()
464 Actor actor = GetCurrentFocusActor();
467 actor.Remove(mFocusIndicatorActor);
470 mCurrentFocusActor = FocusIDPair(0, 0);
472 // Send notification for the change of focus actor
473 mFocusChangedSignalV2.Emit(actor, Actor());
475 if(mIsAccessibilityTtsEnabled)
477 // Stop the TTS playing if any
478 Dali::TtsPlayer player = Dali::TtsPlayer::Get(Dali::TtsPlayer::SCREEN_READER);
483 void FocusManager::Reset()
486 mFocusIDContainer.clear();
487 mIDAdditionalInfoContainer.clear();
490 void FocusManager::SetFocusGroup(Actor actor, bool isFocusGroup)
494 // Create focus group property if not already created.
495 Property::Index propertyIsFocusGroup = actor.GetPropertyIndex(IS_FOCUS_GROUP);
496 if(propertyIsFocusGroup == Property::INVALID_INDEX)
498 propertyIsFocusGroup = actor.RegisterProperty(IS_FOCUS_GROUP, isFocusGroup);
502 actor.SetProperty(propertyIsFocusGroup, isFocusGroup);
507 bool FocusManager::IsFocusGroup(Actor actor) const
509 // Check whether the actor is a focus group
510 bool isFocusGroup = false;
514 Property::Index propertyIsFocusGroup = actor.GetPropertyIndex(IS_FOCUS_GROUP);
515 if(propertyIsFocusGroup != Property::INVALID_INDEX)
517 isFocusGroup = actor.GetProperty<bool>(propertyIsFocusGroup);
524 Actor FocusManager::GetFocusGroup(Actor actor)
526 // Go through the actor's hierarchy to check which focus group the actor belongs to
527 while (actor && !IsFocusGroup(actor))
529 actor = actor.GetParent();
535 void FocusManager::SetGroupMode(bool enabled)
537 mIsFocusWithinGroup = enabled;
540 bool FocusManager::GetGroupMode() const
542 return mIsFocusWithinGroup;
545 void FocusManager::SetWrapMode(bool wrapped)
547 mIsWrapped = wrapped;
550 bool FocusManager::GetWrapMode() const
555 void FocusManager::SetFocusIndicatorActor(Actor indicator)
557 mFocusIndicatorActor = indicator;
560 Actor FocusManager::GetFocusIndicatorActor()
562 return mFocusIndicatorActor;
565 bool FocusManager::DoMoveFocus(FocusIDIter focusIDIter, bool forward, bool wrapped)
567 DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] %d focusable actors\n", __FUNCTION__, __LINE__, mFocusIDContainer.size());
568 DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] focus order : %d\n", __FUNCTION__, __LINE__, (*focusIDIter).first);
570 if( (forward && ++focusIDIter == mFocusIDContainer.end())
571 || (!forward && focusIDIter-- == mFocusIDContainer.begin()) )
573 if(mIsEndcapFeedbackEnabled)
575 if(mIsEndcapFeedbackPlayed == false)
577 // play sound & skip moving once
578 Dali::SoundPlayer soundPlayer = Dali::SoundPlayer::Get();
581 soundPlayer.PlaySound(FOCUS_CHAIN_END_SOUND_FILE);
584 mIsEndcapFeedbackPlayed = true;
587 mIsEndcapFeedbackPlayed = false;
594 focusIDIter = mFocusIDContainer.begin();
598 focusIDIter = mFocusIDContainer.end();
599 --focusIDIter;//We want forward iterator to the last element here
604 DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] Overshot\n", __FUNCTION__, __LINE__);
605 // Send notification for handling overshooted situation
606 mFocusOvershotSignalV2.Emit(GetCurrentFocusActor(), forward ? Toolkit::FocusManager::OVERSHOT_NEXT : Toolkit::FocusManager::OVERSHOT_PREVIOUS);
608 return false; // Try to move the focus out of the scope
612 if((focusIDIter != mFocusIDContainer.end()) && !DoSetCurrentFocusActor((*focusIDIter).second))
614 mRecursiveFocusMoveCounter++;
615 if(mRecursiveFocusMoveCounter > mFocusIDContainer.size())
617 // We've attempted to focus all the actors in the whole focus chain and no actor
618 // can be focused successfully.
620 DALI_LOG_WARNING("[%s] There is no more focusable actor in %d focus chains\n", __FUNCTION__, mRecursiveFocusMoveCounter);
626 return DoMoveFocus(focusIDIter, forward, wrapped);
633 void FocusManager::SetFocusable(Actor actor, bool focusable)
637 // Create actor focusable property if not already created.
638 Property::Index propertyActorFocusable = actor.GetPropertyIndex(ACTOR_FOCUSABLE);
639 if(propertyActorFocusable == Property::INVALID_INDEX)
641 propertyActorFocusable = actor.RegisterProperty(ACTOR_FOCUSABLE, focusable);
645 actor.SetProperty(propertyActorFocusable, focusable);
650 void FocusManager::CreateDefaultFocusIndicatorActor()
652 // Create a focus indicator actor shared by all the focusable actors
653 Image borderImage = Image::New(FOCUS_BORDER_IMAGE_PATH);
655 ImageActor focusIndicator = ImageActor::New(borderImage);
656 focusIndicator.SetPositionInheritanceMode( Dali::USE_PARENT_POSITION_PLUS_LOCAL_POSITION );
657 focusIndicator.SetStyle( ImageActor::STYLE_NINE_PATCH );
658 focusIndicator.SetNinePatchBorder(FOCUS_BORDER_IMAGE_BORDER);
659 focusIndicator.SetPosition(Vector3(0.0f, 0.0f, 1.0f));
661 // Apply size constraint to the focus indicator
662 Constraint constraint = Constraint::New<Vector3>(Actor::SIZE,
663 ParentSource(Actor::SIZE),
664 EqualToConstraint());
665 focusIndicator.ApplyConstraint(constraint);
667 SetFocusIndicatorActor(focusIndicator);
670 bool FocusManager::ChangeAccessibilityStatus()
672 AccessibilityManager manager = AccessibilityManager::Get();
673 mIsAccessibilityTtsEnabled = manager.IsEnabled();
675 if(mIsAccessibilityTtsEnabled)
677 // Show indicator when tts turned on if there is focused actor.
678 Actor actor = GetCurrentFocusActor();
681 if(mFocusIndicatorActor)
683 actor.Add(mFocusIndicatorActor);
686 mIsFocusIndicatorEnabled = true;
690 // Hide indicator when tts turned off
691 Actor actor = GetCurrentFocusActor();
694 actor.Remove(mFocusIndicatorActor);
696 mIsFocusIndicatorEnabled = false;
702 bool FocusManager::AccessibilityActionNext(bool allowEndFeedback)
704 if(mIsAccessibilityTtsEnabled)
706 mIsEndcapFeedbackEnabled = allowEndFeedback;
707 return MoveFocusForward();
715 bool FocusManager::AccessibilityActionPrevious(bool allowEndFeedback)
717 if(mIsAccessibilityTtsEnabled)
719 mIsEndcapFeedbackEnabled = allowEndFeedback;
720 return MoveFocusBackward();
728 bool FocusManager::AccessibilityActionActivate()
732 Actor actor = GetCurrentFocusActor();
742 bool FocusManager::AccessibilityActionRead(bool allowReadAgain)
746 if(mIsAccessibilityTtsEnabled)
748 // Find the focusable actor at the read position
749 AccessibilityManager manager = AccessibilityManager::Get();
750 Dali::HitTestAlgorithm::Results results;
751 Dali::HitTestAlgorithm::HitTest( Stage::GetCurrent(), manager.GetReadPosition(), results, IsActorFocusableFunction );
753 FocusIDIter focusIDIter = mFocusIDContainer.find(GetFocusOrder(results.actor));
754 if(focusIDIter != mFocusIDContainer.end())
756 if( allowReadAgain || (results.actor != GetCurrentFocusActor()) )
758 // Move the focus to the actor
759 ret = SetCurrentFocusActor(results.actor);
760 DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] SetCurrentFocusActor returns %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
768 bool FocusManager::AccessibilityActionReadNext(bool allowEndFeedback)
770 if(mIsAccessibilityTtsEnabled)
772 return MoveFocusForward();
780 bool FocusManager::AccessibilityActionReadPrevious(bool allowEndFeedback)
782 if(mIsAccessibilityTtsEnabled)
784 return MoveFocusBackward();
792 bool FocusManager::AccessibilityActionUp()
796 if(mIsAccessibilityTtsEnabled)
798 Actor actor = GetCurrentFocusActor();
801 Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor);
804 // Notify the control that it is activated
805 ret = control.GetImplementation().OnAccessibilityValueChange(true);
813 bool FocusManager::AccessibilityActionDown()
817 if(mIsAccessibilityTtsEnabled)
819 Actor actor = GetCurrentFocusActor();
822 Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor);
825 // Notify the control that it is activated
826 ret = control.GetImplementation().OnAccessibilityValueChange(false);
834 bool FocusManager::ClearAccessibilityFocus()
836 if(mIsAccessibilityTtsEnabled)
847 bool FocusManager::AccessibilityActionBack()
849 // TODO: Back to previous view
851 return mIsAccessibilityTtsEnabled;
854 bool FocusManager::AccessibilityActionTouch(const TouchEvent& touchEvent)
856 bool handled = false;
858 // TODO: Need to convert the touchevent for the focused actor?
860 Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(GetCurrentFocusActor());
863 handled = control.GetImplementation().OnAccessibilityTouch(touchEvent);
869 bool FocusManager::HandlePanGesture(const Integration::PanGestureEvent& panEvent)
871 bool handled = false;
873 if( panEvent.state == Gesture::Started )
875 // Find the focusable actor at the event position
876 Dali::HitTestAlgorithm::Results results;
877 AccessibilityManager manager = AccessibilityManager::Get();
879 Dali::HitTestAlgorithm::HitTest( Stage::GetCurrent(), panEvent.currentPosition, results, IsActorFocusableFunction );
880 mCurrentGesturedActor = results.actor;
882 if(!mCurrentGesturedActor)
884 DALI_LOG_ERROR("Gesture detected, but no hit actor");
888 // Gesture::Finished (Up) events are delivered with previous (Motion) event position
889 // Use the real previous position; otherwise we may incorrectly get a ZERO velocity
890 if ( Gesture::Finished != panEvent.state )
892 // Store the previous position for next Gesture::Finished iteration.
893 mPreviousPosition = panEvent.previousPosition;
896 Actor rootActor = Stage::GetCurrent().GetRootLayer();
898 Dali::PanGesture pan(panEvent.state);
899 pan.time = panEvent.time;
900 pan.numberOfTouches = panEvent.numberOfTouches;
901 pan.screenPosition = panEvent.currentPosition;
902 pan.screenDisplacement = mPreviousPosition - panEvent.currentPosition;
903 pan.screenVelocity.x = pan.screenDisplacement.x / panEvent.timeDelta;
904 pan.screenVelocity.y = pan.screenDisplacement.y / panEvent.timeDelta;
906 // Only handle the pan gesture when the current focused actor is scrollable or within a scrollable actor
907 while(mCurrentGesturedActor && mCurrentGesturedActor != rootActor && !handled)
909 Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(mCurrentGesturedActor);
912 Vector2 localCurrent;
913 control.ScreenToLocal( localCurrent.x, localCurrent.y, panEvent.currentPosition.x, panEvent.currentPosition.y );
914 pan.position = localCurrent;
916 Vector2 localPrevious;
917 control.ScreenToLocal( localPrevious.x, localPrevious.y, mPreviousPosition.x, mPreviousPosition.y );
919 pan.displacement = localCurrent - localPrevious;
920 pan.velocity.x = pan.displacement.x / panEvent.timeDelta;
921 pan.velocity.y = pan.displacement.y / panEvent.timeDelta;
923 handled = control.GetImplementation().OnAccessibilityPan(pan);
926 // If the gesture is not handled by the control, check its parent
929 mCurrentGesturedActor = mCurrentGesturedActor.GetParent();
931 if(!mCurrentGesturedActor)
933 DALI_LOG_ERROR("no more gestured actor");
938 // If handled, then update the pan gesture properties
939 PanGestureDetector::SetPanGestureProperties( pan );
946 Toolkit::FocusManager::FocusChangedSignalV2& FocusManager::FocusChangedSignal()
948 return mFocusChangedSignalV2;
951 Toolkit::FocusManager::FocusOvershotSignalV2& FocusManager::FocusOvershotSignal()
953 return mFocusOvershotSignalV2;
956 Toolkit::FocusManager::FocusedActorActivatedSignalV2& FocusManager::FocusedActorActivatedSignal()
958 return mFocusedActorActivatedSignalV2;
961 bool FocusManager::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
963 Dali::BaseHandle handle( object );
965 bool connected( true );
966 FocusManager* manager = dynamic_cast<FocusManager*>(object);
968 if( Dali::Toolkit::FocusManager::SIGNAL_FOCUS_CHANGED == signalName )
970 manager->FocusChangedSignal().Connect( tracker, functor );
972 else if( Dali::Toolkit::FocusManager::SIGNAL_FOCUS_OVERSHOT == signalName )
974 manager->FocusOvershotSignal().Connect( tracker, functor );
976 else if( Dali::Toolkit::FocusManager::SIGNAL_FOCUSED_ACTOR_ACTIVATED== signalName )
978 manager->FocusedActorActivatedSignal().Connect( tracker, functor );
982 // signalName does not match any signal
989 } // namespace Internal
991 } // namespace Toolkit