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>
31 #include <dali-toolkit/public-api/controls/control.h>
32 #include <dali-toolkit/public-api/controls/control-impl.h>
33 #include <dali/integration-api/debug.h>
44 namespace // unnamed namespace
47 #if defined(DEBUG_ENABLED)
48 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_FOCUS_MANAGER");
51 const char * const ACTOR_FOCUSABLE("focusable");
52 const char * const IS_FOCUS_GROUP("is-focus-group");
54 const char* FOCUS_BORDER_IMAGE_PATH = DALI_IMAGE_DIR "B16-8_TTS_focus.png";
55 const Vector4 FOCUS_BORDER_IMAGE_BORDER = Vector4(7.0f, 7.0f, 7.0f, 7.0f);
57 const char* FOCUS_SOUND_FILE = DALI_SOUND_DIR "Focus.ogg";
58 const char* FOCUS_CHAIN_END_SOUND_FILE = DALI_SOUND_DIR "End_of_List.ogg";
61 * The function to be used in the hit-test algorithm to check whether the actor is hittable.
63 bool IsActorFocusableFunction(Actor actor, Dali::HitTestAlgorithm::TraverseType type)
65 bool hittable = false;
69 case Dali::HitTestAlgorithm::CHECK_ACTOR:
71 // Check whether the actor is visible and not fully transparent.
73 && actor.GetCurrentWorldColor().a > 0.01f) // not FULLY_TRANSPARENT
75 // Check whether the actor is focusable
76 Property::Index propertyActorFocusable = actor.GetPropertyIndex(ACTOR_FOCUSABLE);
77 if(propertyActorFocusable != Property::INVALID_INDEX)
79 hittable = actor.GetProperty<bool>(propertyActorFocusable);
84 case Dali::HitTestAlgorithm::DESCEND_ACTOR_TREE:
86 if( actor.IsVisible() ) // Actor is visible, if not visible then none of its children are visible.
103 FocusManager::FocusManager()
105 mIsFocusWithinGroup(false),
106 mIsEndcapFeedbackEnabled(false),
107 mIsEndcapFeedbackPlayed(false),
108 mCurrentFocusActor(FocusIDPair(0, 0)),
109 mFocusIndicatorActor(Actor()),
110 mRecursiveFocusMoveCounter(0),
111 mIsAccessibilityTtsEnabled(false),
112 mIsFocusIndicatorEnabled(false)
114 CreateDefaultFocusIndicatorActor();
116 AccessibilityManager manager = AccessibilityManager::Get();
117 manager.SetActionHandler(*this);
118 manager.SetGestureHandler(*this);
120 ChangeAccessibilityStatus();
123 FocusManager::~FocusManager()
127 FocusManager::ActorAdditionalInfo FocusManager::GetActorAdditionalInfo(const unsigned int actorID) const
129 ActorAdditionalInfo data;
130 IDAdditionalInfoConstIter iter = mIDAdditionalInfoContainer.find(actorID);
131 if(iter != mIDAdditionalInfoContainer.end())
133 data = (*iter).second;
139 void FocusManager::SynchronizeActorAdditionalInfo(const unsigned int actorID, const unsigned int order)
141 ActorAdditionalInfo actorInfo = GetActorAdditionalInfo(actorID);
142 actorInfo.mFocusOrder = order;
143 mIDAdditionalInfoContainer.erase(actorID);
144 mIDAdditionalInfoContainer.insert(IDAdditionalInfoPair(actorID, actorInfo));
147 void FocusManager::SetAccessibilityAttribute(Actor actor, Toolkit::FocusManager::AccessibilityAttribute type, const std::string& text)
151 unsigned int actorID = actor.GetId();
153 ActorAdditionalInfo info = GetActorAdditionalInfo(actorID);
154 info.mAccessibilityAttributes[type] = text;
156 mIDAdditionalInfoContainer.erase(actorID);
157 mIDAdditionalInfoContainer.insert(IDAdditionalInfoPair(actorID, info));
161 std::string FocusManager::GetAccessibilityAttribute(Actor actor, Toolkit::FocusManager::AccessibilityAttribute type) const
167 ActorAdditionalInfo data = GetActorAdditionalInfo(actor.GetId());
168 text = data.mAccessibilityAttributes[type];
174 void FocusManager::SetFocusOrder(Actor actor, const unsigned int order)
176 // Do nothing if the focus order of the actor is not changed.
177 if(actor && GetFocusOrder(actor) != order)
179 // Firstly delete the actor from the focus chain if it's already there with a different focus order.
180 mFocusIDContainer.erase(GetFocusOrder(actor));
182 // Create actor focusable property if not already created.
183 Property::Index propertyActorFocusable = actor.GetPropertyIndex(ACTOR_FOCUSABLE);
184 if(propertyActorFocusable == Property::INVALID_INDEX)
186 propertyActorFocusable = actor.RegisterProperty(ACTOR_FOCUSABLE, true);
191 // The actor is not focusable without a defined focus order.
192 actor.SetProperty(propertyActorFocusable, false);
194 // If the actor is currently being focused, it should clear the focus
195 if(actor == GetCurrentFocusActor())
200 else // Insert the actor to the focus chain
202 // Check whether there is another actor in the focus chain with the same focus order already.
203 FocusIDIter focusIDIter = mFocusIDContainer.find(order);
204 if(focusIDIter != mFocusIDContainer.end())
206 // We need to increase the focus order of that actor and all the actors followed it
207 // in the focus chain.
208 FocusIDIter lastIter = mFocusIDContainer.end();
209 --lastIter;//We want forward iterator to the last element here
210 mFocusIDContainer.insert(FocusIDPair((*lastIter).first + 1, (*lastIter).second));
212 // Update the actor's focus order in its additional data
213 SynchronizeActorAdditionalInfo((*lastIter).second, (*lastIter).first + 1);
215 for(FocusIDIter iter = lastIter; iter != focusIDIter; iter--)
217 FocusIDIter previousIter = iter;
218 --previousIter;//We want forward iterator to the previous element here
219 unsigned int actorID = (*previousIter).second;
220 (*iter).second = actorID;
222 // Update the actor's focus order in its additional data
223 SynchronizeActorAdditionalInfo(actorID, (*iter).first);
226 mFocusIDContainer.erase(order);
229 // The actor is focusable
230 actor.SetProperty(propertyActorFocusable, true);
232 // Now we insert the actor into the focus chain with the specified focus order
233 mFocusIDContainer.insert(FocusIDPair(order, actor.GetId()));
236 // Update the actor's focus order in its additional data
237 SynchronizeActorAdditionalInfo(actor.GetId(), order);
241 unsigned int FocusManager::GetFocusOrder(Actor actor) const
243 unsigned int focusOrder = 0;
247 ActorAdditionalInfo data = GetActorAdditionalInfo(actor.GetId());
248 focusOrder = data.mFocusOrder;
254 unsigned int FocusManager::GenerateNewFocusOrder() const
256 unsigned int order = 1;
257 FocusIDContainer::const_reverse_iterator iter = mFocusIDContainer.rbegin();
259 if(iter != mFocusIDContainer.rend())
261 order = (*iter).first + 1;
267 Actor FocusManager::GetActorByFocusOrder(const unsigned int order)
269 Actor actor = Actor();
271 FocusIDIter focusIDIter = mFocusIDContainer.find(order);
272 if(focusIDIter != mFocusIDContainer.end())
274 Actor rootActor = Stage::GetCurrent().GetRootLayer();
275 actor = rootActor.FindChildById(mFocusIDContainer[order]);
281 bool FocusManager::SetCurrentFocusActor(Actor actor)
285 return DoSetCurrentFocusActor(actor.GetId());
291 bool FocusManager::DoSetCurrentFocusActor(const unsigned int actorID)
293 Actor rootActor = Stage::GetCurrent().GetRootLayer();
295 // If the group mode is enabled, check which focus group the current focused actor belongs to
297 if(mIsFocusWithinGroup)
299 focusGroup = GetFocusGroup(GetCurrentFocusActor());
304 focusGroup = rootActor;
307 Actor actor = focusGroup.FindChildById(actorID);
309 // Check whether the actor is in the stage
312 // Check whether the actor is focusable
313 bool actorFocusable = false;
314 Property::Index propertyActorFocusable = actor.GetPropertyIndex(ACTOR_FOCUSABLE);
315 if(propertyActorFocusable != Property::INVALID_INDEX)
317 actorFocusable = actor.GetProperty<bool>(propertyActorFocusable);
320 // Go through the actor's hierarchy to check whether the actor is visible
321 bool actorVisible = actor.IsVisible();
322 Actor parent = actor.GetParent();
323 while (actorVisible && parent && parent != rootActor)
325 actorVisible = parent.IsVisible();
326 parent = parent.GetParent();
329 // Check whether the actor is fully transparent
330 bool actorOpaque = actor.GetCurrentWorldColor().a > 0.01f;
332 // Set the focus only when the actor is focusable and visible and not fully transparent
333 if(actorVisible && actorFocusable && actorOpaque)
335 // Draw the focus indicator upon the focused actor
336 if(mIsFocusIndicatorEnabled && mFocusIndicatorActor)
338 actor.Add(mFocusIndicatorActor);
341 // Send notification for the change of focus actor
342 mFocusChangedSignal.Emit( GetCurrentFocusActor(), actor );
344 // Save the current focused actor
345 mCurrentFocusActor = FocusIDPair(GetFocusOrder(actor), actorID);
347 if(mIsAccessibilityTtsEnabled)
349 Dali::SoundPlayer soundPlayer = Dali::SoundPlayer::Get();
352 soundPlayer.PlaySound(FOCUS_SOUND_FILE);
355 // Play the accessibility attributes with the TTS player.
356 Dali::TtsPlayer player = Dali::TtsPlayer::Get(Dali::TtsPlayer::SCREEN_READER);
358 // Combine attribute texts to one text
359 std::string informationText;
360 for(int i = 0; i < Toolkit::FocusManager::ACCESSIBILITY_ATTRIBUTE_NUM; i++)
362 if(!GetActorAdditionalInfo(actorID).mAccessibilityAttributes[i].empty())
366 informationText += ", "; // for space time between each information
368 informationText += GetActorAdditionalInfo(actorID).mAccessibilityAttributes[i];
371 player.Play(informationText);
378 DALI_LOG_WARNING("[%s:%d] FAILED\n", __FUNCTION__, __LINE__);
382 Actor FocusManager::GetCurrentFocusActor()
384 Actor rootActor = Stage::GetCurrent().GetRootLayer();
385 return rootActor.FindChildById(mCurrentFocusActor.second);
388 Actor FocusManager::GetCurrentFocusGroup()
390 return GetFocusGroup(GetCurrentFocusActor());
393 unsigned int FocusManager::GetCurrentFocusOrder()
395 return mCurrentFocusActor.first;
398 bool FocusManager::MoveFocusForward()
401 mRecursiveFocusMoveCounter = 0;
403 FocusIDIter focusIDIter = mFocusIDContainer.find(mCurrentFocusActor.first);
404 if(focusIDIter != mFocusIDContainer.end())
406 DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] focus order : %d\n", __FUNCTION__, __LINE__, (*focusIDIter).first);
407 ret = DoMoveFocus(focusIDIter, true, mIsWrapped);
411 // TODO: if there is not focused actor, move first actor
412 if(!mFocusIDContainer.empty())
414 //if there is not focused actor, move 1st actor
415 focusIDIter = mFocusIDContainer.begin(); // TODO: I'm not sure it was sorted.
416 DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] focus order : %d\n", __FUNCTION__, __LINE__, (*focusIDIter).first);
417 ret = DoSetCurrentFocusActor((*focusIDIter).second);
421 DALI_LOG_INFO( gLogFilter, Debug::General, "[%s] %s\n", __FUNCTION__, ret?"SUCCEED!!!":"FAILED!!!");
426 bool FocusManager::MoveFocusBackward()
429 mRecursiveFocusMoveCounter = 0;
431 FocusIDIter focusIDIter = mFocusIDContainer.find(mCurrentFocusActor.first);
432 if(focusIDIter != mFocusIDContainer.end())
434 DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] focus order : %d\n", __FUNCTION__, __LINE__, (*focusIDIter).first);
435 ret = DoMoveFocus(focusIDIter, false, mIsWrapped);
439 // TODO: if there is not focused actor, move last actor
440 if(!mFocusIDContainer.empty())
442 //if there is not focused actor, move last actor
443 focusIDIter = mFocusIDContainer.end();
444 --focusIDIter;//We want forward iterator to the last element here
445 DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] focus order : %d\n", __FUNCTION__, __LINE__, (*focusIDIter).first);
446 ret = DoSetCurrentFocusActor((*focusIDIter).second);
450 DALI_LOG_INFO( gLogFilter, Debug::General, "[%s] %s\n", __FUNCTION__, ret?"SUCCEED!!!":"FAILED!!!");
455 void FocusManager::DoActivate(Actor actor)
459 Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor);
462 // Notify the control that it is activated
463 control.GetImplementation().Activate();
466 // Send notification for the activation of focused actor
467 mFocusedActorActivatedSignal.Emit(actor);
471 void FocusManager::ClearFocus()
473 Actor actor = GetCurrentFocusActor();
476 actor.Remove(mFocusIndicatorActor);
479 mCurrentFocusActor = FocusIDPair(0, 0);
481 // Send notification for the change of focus actor
482 mFocusChangedSignal.Emit(actor, Actor());
484 if(mIsAccessibilityTtsEnabled)
486 // Stop the TTS playing if any
487 Dali::TtsPlayer player = Dali::TtsPlayer::Get(Dali::TtsPlayer::SCREEN_READER);
492 void FocusManager::Reset()
495 mFocusIDContainer.clear();
496 mIDAdditionalInfoContainer.clear();
499 void FocusManager::SetFocusGroup(Actor actor, bool isFocusGroup)
503 // Create focus group property if not already created.
504 Property::Index propertyIsFocusGroup = actor.GetPropertyIndex(IS_FOCUS_GROUP);
505 if(propertyIsFocusGroup == Property::INVALID_INDEX)
507 actor.RegisterProperty(IS_FOCUS_GROUP, isFocusGroup);
511 actor.SetProperty(propertyIsFocusGroup, isFocusGroup);
516 bool FocusManager::IsFocusGroup(Actor actor) const
518 // Check whether the actor is a focus group
519 bool isFocusGroup = false;
523 Property::Index propertyIsFocusGroup = actor.GetPropertyIndex(IS_FOCUS_GROUP);
524 if(propertyIsFocusGroup != Property::INVALID_INDEX)
526 isFocusGroup = actor.GetProperty<bool>(propertyIsFocusGroup);
533 Actor FocusManager::GetFocusGroup(Actor actor)
535 // Go through the actor's hierarchy to check which focus group the actor belongs to
536 while (actor && !IsFocusGroup(actor))
538 actor = actor.GetParent();
544 void FocusManager::SetGroupMode(bool enabled)
546 mIsFocusWithinGroup = enabled;
549 bool FocusManager::GetGroupMode() const
551 return mIsFocusWithinGroup;
554 void FocusManager::SetWrapMode(bool wrapped)
556 mIsWrapped = wrapped;
559 bool FocusManager::GetWrapMode() const
564 void FocusManager::SetFocusIndicatorActor(Actor indicator)
566 mFocusIndicatorActor = indicator;
569 Actor FocusManager::GetFocusIndicatorActor()
571 return mFocusIndicatorActor;
574 bool FocusManager::DoMoveFocus(FocusIDIter focusIDIter, bool forward, bool wrapped)
576 DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] %d focusable actors\n", __FUNCTION__, __LINE__, mFocusIDContainer.size());
577 DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] focus order : %d\n", __FUNCTION__, __LINE__, (*focusIDIter).first);
579 if( (forward && ++focusIDIter == mFocusIDContainer.end())
580 || (!forward && focusIDIter-- == mFocusIDContainer.begin()) )
582 if(mIsEndcapFeedbackEnabled)
584 if(mIsEndcapFeedbackPlayed == false)
586 // play sound & skip moving once
587 Dali::SoundPlayer soundPlayer = Dali::SoundPlayer::Get();
590 soundPlayer.PlaySound(FOCUS_CHAIN_END_SOUND_FILE);
593 mIsEndcapFeedbackPlayed = true;
596 mIsEndcapFeedbackPlayed = false;
603 focusIDIter = mFocusIDContainer.begin();
607 focusIDIter = mFocusIDContainer.end();
608 --focusIDIter;//We want forward iterator to the last element here
613 DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] Overshot\n", __FUNCTION__, __LINE__);
614 // Send notification for handling overshooted situation
615 mFocusOvershotSignal.Emit(GetCurrentFocusActor(), forward ? Toolkit::FocusManager::OVERSHOT_NEXT : Toolkit::FocusManager::OVERSHOT_PREVIOUS);
617 return false; // Try to move the focus out of the scope
621 if((focusIDIter != mFocusIDContainer.end()) && !DoSetCurrentFocusActor((*focusIDIter).second))
623 mRecursiveFocusMoveCounter++;
624 if(mRecursiveFocusMoveCounter > mFocusIDContainer.size())
626 // We've attempted to focus all the actors in the whole focus chain and no actor
627 // can be focused successfully.
629 DALI_LOG_WARNING("[%s] There is no more focusable actor in %d focus chains\n", __FUNCTION__, mRecursiveFocusMoveCounter);
635 return DoMoveFocus(focusIDIter, forward, wrapped);
642 void FocusManager::SetFocusable(Actor actor, bool focusable)
646 // Create actor focusable property if not already created.
647 Property::Index propertyActorFocusable = actor.GetPropertyIndex(ACTOR_FOCUSABLE);
648 if(propertyActorFocusable == Property::INVALID_INDEX)
650 actor.RegisterProperty(ACTOR_FOCUSABLE, focusable);
654 actor.SetProperty(propertyActorFocusable, focusable);
659 void FocusManager::CreateDefaultFocusIndicatorActor()
661 // Create a focus indicator actor shared by all the focusable actors
662 Image borderImage = ResourceImage::New(FOCUS_BORDER_IMAGE_PATH);
664 ImageActor focusIndicator = ImageActor::New(borderImage);
665 focusIndicator.SetPositionInheritanceMode( Dali::USE_PARENT_POSITION_PLUS_LOCAL_POSITION );
666 focusIndicator.SetStyle( ImageActor::STYLE_NINE_PATCH );
667 focusIndicator.SetNinePatchBorder(FOCUS_BORDER_IMAGE_BORDER);
668 focusIndicator.SetPosition(Vector3(0.0f, 0.0f, 1.0f));
670 // Apply size constraint to the focus indicator
671 focusIndicator.SetSizeMode( SIZE_EQUAL_TO_PARENT );
673 SetFocusIndicatorActor(focusIndicator);
676 bool FocusManager::ChangeAccessibilityStatus()
678 AccessibilityManager manager = AccessibilityManager::Get();
679 mIsAccessibilityTtsEnabled = manager.IsEnabled();
681 if(mIsAccessibilityTtsEnabled)
683 // Show indicator when tts turned on if there is focused actor.
684 Actor actor = GetCurrentFocusActor();
687 if(mFocusIndicatorActor)
689 actor.Add(mFocusIndicatorActor);
692 mIsFocusIndicatorEnabled = true;
696 // Hide indicator when tts turned off
697 Actor actor = GetCurrentFocusActor();
700 actor.Remove(mFocusIndicatorActor);
702 mIsFocusIndicatorEnabled = false;
708 bool FocusManager::AccessibilityActionNext(bool allowEndFeedback)
710 if(mIsAccessibilityTtsEnabled)
712 mIsEndcapFeedbackEnabled = allowEndFeedback;
713 return MoveFocusForward();
721 bool FocusManager::AccessibilityActionPrevious(bool allowEndFeedback)
723 if(mIsAccessibilityTtsEnabled)
725 mIsEndcapFeedbackEnabled = allowEndFeedback;
726 return MoveFocusBackward();
734 bool FocusManager::AccessibilityActionActivate()
738 Actor actor = GetCurrentFocusActor();
748 bool FocusManager::AccessibilityActionRead(bool allowReadAgain)
752 if(mIsAccessibilityTtsEnabled)
754 // Find the focusable actor at the read position
755 AccessibilityManager manager = AccessibilityManager::Get();
756 Dali::HitTestAlgorithm::Results results;
757 Dali::HitTestAlgorithm::HitTest( Stage::GetCurrent(), manager.GetReadPosition(), results, IsActorFocusableFunction );
759 FocusIDIter focusIDIter = mFocusIDContainer.find(GetFocusOrder(results.actor));
760 if(focusIDIter != mFocusIDContainer.end())
762 if( allowReadAgain || (results.actor != GetCurrentFocusActor()) )
764 // Move the focus to the actor
765 ret = SetCurrentFocusActor(results.actor);
766 DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] SetCurrentFocusActor returns %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
774 bool FocusManager::AccessibilityActionReadNext(bool allowEndFeedback)
776 if(mIsAccessibilityTtsEnabled)
778 return MoveFocusForward();
786 bool FocusManager::AccessibilityActionReadPrevious(bool allowEndFeedback)
788 if(mIsAccessibilityTtsEnabled)
790 return MoveFocusBackward();
798 bool FocusManager::AccessibilityActionUp()
802 if(mIsAccessibilityTtsEnabled)
804 Actor actor = GetCurrentFocusActor();
807 Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor);
810 // Notify the control that it is activated
811 ret = control.GetImplementation().OnAccessibilityValueChange(true);
819 bool FocusManager::AccessibilityActionDown()
823 if(mIsAccessibilityTtsEnabled)
825 Actor actor = GetCurrentFocusActor();
828 Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor);
831 // Notify the control that it is activated
832 ret = control.GetImplementation().OnAccessibilityValueChange(false);
840 bool FocusManager::ClearAccessibilityFocus()
842 if(mIsAccessibilityTtsEnabled)
853 bool FocusManager::AccessibilityActionBack()
855 // TODO: Back to previous view
857 return mIsAccessibilityTtsEnabled;
860 bool FocusManager::AccessibilityActionTouch(const TouchEvent& touchEvent)
862 bool handled = false;
864 // TODO: Need to convert the touchevent for the focused actor?
866 Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(GetCurrentFocusActor());
869 handled = control.GetImplementation().OnAccessibilityTouch(touchEvent);
875 bool FocusManager::HandlePanGesture(const Integration::PanGestureEvent& panEvent)
877 bool handled = false;
879 if( panEvent.state == Gesture::Started )
881 // Find the focusable actor at the event position
882 Dali::HitTestAlgorithm::Results results;
883 AccessibilityManager manager = AccessibilityManager::Get();
885 Dali::HitTestAlgorithm::HitTest( Stage::GetCurrent(), panEvent.currentPosition, results, IsActorFocusableFunction );
886 mCurrentGesturedActor = results.actor;
888 if(!mCurrentGesturedActor)
890 DALI_LOG_ERROR("Gesture detected, but no hit actor");
894 // Gesture::Finished (Up) events are delivered with previous (Motion) event position
895 // Use the real previous position; otherwise we may incorrectly get a ZERO velocity
896 if ( Gesture::Finished != panEvent.state )
898 // Store the previous position for next Gesture::Finished iteration.
899 mPreviousPosition = panEvent.previousPosition;
902 Actor rootActor = Stage::GetCurrent().GetRootLayer();
904 Dali::PanGesture pan(panEvent.state);
905 pan.time = panEvent.time;
906 pan.numberOfTouches = panEvent.numberOfTouches;
907 pan.screenPosition = panEvent.currentPosition;
908 pan.screenDisplacement = mPreviousPosition - panEvent.currentPosition;
909 pan.screenVelocity.x = pan.screenDisplacement.x / panEvent.timeDelta;
910 pan.screenVelocity.y = pan.screenDisplacement.y / panEvent.timeDelta;
912 // Only handle the pan gesture when the current focused actor is scrollable or within a scrollable actor
913 while(mCurrentGesturedActor && mCurrentGesturedActor != rootActor && !handled)
915 Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(mCurrentGesturedActor);
918 Vector2 localCurrent;
919 control.ScreenToLocal( localCurrent.x, localCurrent.y, panEvent.currentPosition.x, panEvent.currentPosition.y );
920 pan.position = localCurrent;
922 Vector2 localPrevious;
923 control.ScreenToLocal( localPrevious.x, localPrevious.y, mPreviousPosition.x, mPreviousPosition.y );
925 pan.displacement = localCurrent - localPrevious;
926 pan.velocity.x = pan.displacement.x / panEvent.timeDelta;
927 pan.velocity.y = pan.displacement.y / panEvent.timeDelta;
929 handled = control.GetImplementation().OnAccessibilityPan(pan);
932 // If the gesture is not handled by the control, check its parent
935 mCurrentGesturedActor = mCurrentGesturedActor.GetParent();
937 if(!mCurrentGesturedActor)
939 DALI_LOG_ERROR("no more gestured actor");
944 // If handled, then update the pan gesture properties
945 PanGestureDetector::SetPanGestureProperties( pan );
952 Toolkit::FocusManager::FocusChangedSignalType& FocusManager::FocusChangedSignal()
954 return mFocusChangedSignal;
957 Toolkit::FocusManager::FocusOvershotSignalType& FocusManager::FocusOvershotSignal()
959 return mFocusOvershotSignal;
962 Toolkit::FocusManager::FocusedActorActivatedSignalType& FocusManager::FocusedActorActivatedSignal()
964 return mFocusedActorActivatedSignal;
967 bool FocusManager::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
969 Dali::BaseHandle handle( object );
971 bool connected( true );
972 FocusManager* manager = dynamic_cast<FocusManager*>(object);
974 if( Dali::Toolkit::FocusManager::SIGNAL_FOCUS_CHANGED == signalName )
976 manager->FocusChangedSignal().Connect( tracker, functor );
978 else if( Dali::Toolkit::FocusManager::SIGNAL_FOCUS_OVERSHOT == signalName )
980 manager->FocusOvershotSignal().Connect( tracker, functor );
982 else if( Dali::Toolkit::FocusManager::SIGNAL_FOCUSED_ACTOR_ACTIVATED== signalName )
984 manager->FocusedActorActivatedSignal().Connect( tracker, functor );
988 // signalName does not match any signal
995 } // namespace Internal
997 } // namespace Toolkit