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>
30 #include <dali-toolkit/public-api/controls/control.h>
31 #include <dali-toolkit/public-api/controls/control-impl.h>
32 #include <dali/integration-api/debug.h>
43 namespace // unnamed namespace
46 #if defined(DEBUG_ENABLED)
47 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_FOCUS_MANAGER");
50 const char * const ACTOR_FOCUSABLE("focusable");
51 const char * const IS_FOCUS_GROUP("is-focus-group");
53 const char* FOCUS_BORDER_IMAGE_PATH = DALI_IMAGE_DIR "B16-8_TTS_focus.png";
54 const Vector4 FOCUS_BORDER_IMAGE_BORDER = Vector4(7.0f, 7.0f, 7.0f, 7.0f);
56 const char* FOCUS_SOUND_FILE = DALI_SOUND_DIR "Focus.ogg";
57 const char* FOCUS_CHAIN_END_SOUND_FILE = DALI_SOUND_DIR "End_of_List.ogg";
60 * The function to be used in the hit-test algorithm to check whether the actor is hittable.
62 bool IsActorFocusableFunction(Actor actor, Dali::HitTestAlgorithm::TraverseType type)
64 bool hittable = false;
68 case Dali::HitTestAlgorithm::CHECK_ACTOR:
70 // Check whether the actor is visible and not fully transparent.
72 && actor.GetCurrentWorldColor().a > 0.01f) // not FULLY_TRANSPARENT
74 // Check whether the actor is focusable
75 Property::Index propertyActorFocusable = actor.GetPropertyIndex(ACTOR_FOCUSABLE);
76 if(propertyActorFocusable != Property::INVALID_INDEX)
78 hittable = actor.GetProperty<bool>(propertyActorFocusable);
83 case Dali::HitTestAlgorithm::DESCEND_ACTOR_TREE:
85 if( actor.IsVisible() ) // Actor is visible, if not visible then none of its children are visible.
102 FocusManager::FocusManager()
104 mIsFocusWithinGroup(false),
105 mIsEndcapFeedbackEnabled(false),
106 mIsEndcapFeedbackPlayed(false),
107 mCurrentFocusActor(FocusIDPair(0, 0)),
108 mFocusIndicatorActor(Actor()),
109 mRecursiveFocusMoveCounter(0),
110 mIsAccessibilityTtsEnabled(false),
111 mIsFocusIndicatorEnabled(false)
113 CreateDefaultFocusIndicatorActor();
115 AccessibilityManager manager = AccessibilityManager::Get();
116 manager.SetActionHandler(*this);
117 manager.SetGestureHandler(*this);
119 ChangeAccessibilityStatus();
122 FocusManager::~FocusManager()
126 FocusManager::ActorAdditionalInfo FocusManager::GetActorAdditionalInfo(const unsigned int actorID) const
128 ActorAdditionalInfo data;
129 IDAdditionalInfoConstIter iter = mIDAdditionalInfoContainer.find(actorID);
130 if(iter != mIDAdditionalInfoContainer.end())
132 data = (*iter).second;
138 void FocusManager::SynchronizeActorAdditionalInfo(const unsigned int actorID, const unsigned int order)
140 ActorAdditionalInfo actorInfo = GetActorAdditionalInfo(actorID);
141 actorInfo.mFocusOrder = order;
142 mIDAdditionalInfoContainer.erase(actorID);
143 mIDAdditionalInfoContainer.insert(IDAdditionalInfoPair(actorID, actorInfo));
146 void FocusManager::SetAccessibilityAttribute(Actor actor, Toolkit::FocusManager::AccessibilityAttribute type, const std::string& text)
150 unsigned int actorID = actor.GetId();
152 ActorAdditionalInfo info = GetActorAdditionalInfo(actorID);
153 info.mAccessibilityAttributes[type] = text;
155 mIDAdditionalInfoContainer.erase(actorID);
156 mIDAdditionalInfoContainer.insert(IDAdditionalInfoPair(actorID, info));
160 std::string FocusManager::GetAccessibilityAttribute(Actor actor, Toolkit::FocusManager::AccessibilityAttribute type) const
166 ActorAdditionalInfo data = GetActorAdditionalInfo(actor.GetId());
167 text = data.mAccessibilityAttributes[type];
173 void FocusManager::SetFocusOrder(Actor actor, const unsigned int order)
175 // Do nothing if the focus order of the actor is not changed.
176 if(actor && GetFocusOrder(actor) != order)
178 // Firstly delete the actor from the focus chain if it's already there with a different focus order.
179 mFocusIDContainer.erase(GetFocusOrder(actor));
181 // Create actor focusable property if not already created.
182 Property::Index propertyActorFocusable = actor.GetPropertyIndex(ACTOR_FOCUSABLE);
183 if(propertyActorFocusable == Property::INVALID_INDEX)
185 propertyActorFocusable = actor.RegisterProperty(ACTOR_FOCUSABLE, true);
190 // The actor is not focusable without a defined focus order.
191 actor.SetProperty(propertyActorFocusable, false);
193 // If the actor is currently being focused, it should clear the focus
194 if(actor == GetCurrentFocusActor())
199 else // Insert the actor to the focus chain
201 // Check whether there is another actor in the focus chain with the same focus order already.
202 FocusIDIter focusIDIter = mFocusIDContainer.find(order);
203 if(focusIDIter != mFocusIDContainer.end())
205 // We need to increase the focus order of that actor and all the actors followed it
206 // in the focus chain.
207 FocusIDIter lastIter = mFocusIDContainer.end();
208 --lastIter;//We want forward iterator to the last element here
209 mFocusIDContainer.insert(FocusIDPair((*lastIter).first + 1, (*lastIter).second));
211 // Update the actor's focus order in its additional data
212 SynchronizeActorAdditionalInfo((*lastIter).second, (*lastIter).first + 1);
214 for(FocusIDIter iter = lastIter; iter != focusIDIter; iter--)
216 FocusIDIter previousIter = iter;
217 --previousIter;//We want forward iterator to the previous element here
218 unsigned int actorID = (*previousIter).second;
219 (*iter).second = actorID;
221 // Update the actor's focus order in its additional data
222 SynchronizeActorAdditionalInfo(actorID, (*iter).first);
225 mFocusIDContainer.erase(order);
228 // The actor is focusable
229 actor.SetProperty(propertyActorFocusable, true);
231 // Now we insert the actor into the focus chain with the specified focus order
232 mFocusIDContainer.insert(FocusIDPair(order, actor.GetId()));
235 // Update the actor's focus order in its additional data
236 SynchronizeActorAdditionalInfo(actor.GetId(), order);
240 unsigned int FocusManager::GetFocusOrder(Actor actor) const
242 unsigned int focusOrder = 0;
246 ActorAdditionalInfo data = GetActorAdditionalInfo(actor.GetId());
247 focusOrder = data.mFocusOrder;
253 unsigned int FocusManager::GenerateNewFocusOrder() const
255 unsigned int order = 1;
256 FocusIDContainer::const_reverse_iterator iter = mFocusIDContainer.rbegin();
258 if(iter != mFocusIDContainer.rend())
260 order = (*iter).first + 1;
266 Actor FocusManager::GetActorByFocusOrder(const unsigned int order)
268 Actor actor = Actor();
270 FocusIDIter focusIDIter = mFocusIDContainer.find(order);
271 if(focusIDIter != mFocusIDContainer.end())
273 Actor rootActor = Stage::GetCurrent().GetRootLayer();
274 actor = rootActor.FindChildById(mFocusIDContainer[order]);
280 bool FocusManager::SetCurrentFocusActor(Actor actor)
284 return DoSetCurrentFocusActor(actor.GetId());
290 bool FocusManager::DoSetCurrentFocusActor(const unsigned int actorID)
292 Actor rootActor = Stage::GetCurrent().GetRootLayer();
294 // If the group mode is enabled, check which focus group the current focused actor belongs to
296 if(mIsFocusWithinGroup)
298 focusGroup = GetFocusGroup(GetCurrentFocusActor());
303 focusGroup = rootActor;
306 Actor actor = focusGroup.FindChildById(actorID);
308 // Check whether the actor is in the stage
311 // Check whether the actor is focusable
312 bool actorFocusable = false;
313 Property::Index propertyActorFocusable = actor.GetPropertyIndex(ACTOR_FOCUSABLE);
314 if(propertyActorFocusable != Property::INVALID_INDEX)
316 actorFocusable = actor.GetProperty<bool>(propertyActorFocusable);
319 // Go through the actor's hierarchy to check whether the actor is visible
320 bool actorVisible = actor.IsVisible();
321 Actor parent = actor.GetParent();
322 while (actorVisible && parent && parent != rootActor)
324 actorVisible = parent.IsVisible();
325 parent = parent.GetParent();
328 // Check whether the actor is fully transparent
329 bool actorOpaque = actor.GetCurrentWorldColor().a > 0.01f;
331 // Set the focus only when the actor is focusable and visible and not fully transparent
332 if(actorVisible && actorFocusable && actorOpaque)
334 // Draw the focus indicator upon the focused actor
335 if(mIsFocusIndicatorEnabled && mFocusIndicatorActor)
337 actor.Add(mFocusIndicatorActor);
340 // Send notification for the change of focus actor
341 mFocusChangedSignal.Emit( GetCurrentFocusActor(), actor );
343 // Save the current focused actor
344 mCurrentFocusActor = FocusIDPair(GetFocusOrder(actor), actorID);
346 if(mIsAccessibilityTtsEnabled)
348 Dali::SoundPlayer soundPlayer = Dali::SoundPlayer::Get();
351 soundPlayer.PlaySound(FOCUS_SOUND_FILE);
354 // Play the accessibility attributes with the TTS player.
355 Dali::TtsPlayer player = Dali::TtsPlayer::Get(Dali::TtsPlayer::SCREEN_READER);
357 // Combine attribute texts to one text
358 std::string informationText;
359 for(int i = 0; i < Toolkit::FocusManager::ACCESSIBILITY_ATTRIBUTE_NUM; i++)
361 if(!GetActorAdditionalInfo(actorID).mAccessibilityAttributes[i].empty())
365 informationText += ", "; // for space time between each information
367 informationText += GetActorAdditionalInfo(actorID).mAccessibilityAttributes[i];
370 player.Play(informationText);
377 DALI_LOG_WARNING("[%s:%d] FAILED\n", __FUNCTION__, __LINE__);
381 Actor FocusManager::GetCurrentFocusActor()
383 Actor rootActor = Stage::GetCurrent().GetRootLayer();
384 return rootActor.FindChildById(mCurrentFocusActor.second);
387 Actor FocusManager::GetCurrentFocusGroup()
389 return GetFocusGroup(GetCurrentFocusActor());
392 unsigned int FocusManager::GetCurrentFocusOrder()
394 return mCurrentFocusActor.first;
397 bool FocusManager::MoveFocusForward()
400 mRecursiveFocusMoveCounter = 0;
402 FocusIDIter focusIDIter = mFocusIDContainer.find(mCurrentFocusActor.first);
403 if(focusIDIter != mFocusIDContainer.end())
405 DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] focus order : %d\n", __FUNCTION__, __LINE__, (*focusIDIter).first);
406 ret = DoMoveFocus(focusIDIter, true, mIsWrapped);
410 // TODO: if there is not focused actor, move first actor
411 if(!mFocusIDContainer.empty())
413 //if there is not focused actor, move 1st actor
414 focusIDIter = mFocusIDContainer.begin(); // TODO: I'm not sure it was sorted.
415 DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] focus order : %d\n", __FUNCTION__, __LINE__, (*focusIDIter).first);
416 ret = DoSetCurrentFocusActor((*focusIDIter).second);
420 DALI_LOG_INFO( gLogFilter, Debug::General, "[%s] %s\n", __FUNCTION__, ret?"SUCCEED!!!":"FAILED!!!");
425 bool FocusManager::MoveFocusBackward()
428 mRecursiveFocusMoveCounter = 0;
430 FocusIDIter focusIDIter = mFocusIDContainer.find(mCurrentFocusActor.first);
431 if(focusIDIter != mFocusIDContainer.end())
433 DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] focus order : %d\n", __FUNCTION__, __LINE__, (*focusIDIter).first);
434 ret = DoMoveFocus(focusIDIter, false, mIsWrapped);
438 // TODO: if there is not focused actor, move last actor
439 if(!mFocusIDContainer.empty())
441 //if there is not focused actor, move last actor
442 focusIDIter = mFocusIDContainer.end();
443 --focusIDIter;//We want forward iterator to the last element here
444 DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] focus order : %d\n", __FUNCTION__, __LINE__, (*focusIDIter).first);
445 ret = DoSetCurrentFocusActor((*focusIDIter).second);
449 DALI_LOG_INFO( gLogFilter, Debug::General, "[%s] %s\n", __FUNCTION__, ret?"SUCCEED!!!":"FAILED!!!");
454 void FocusManager::DoActivate(Actor actor)
458 Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor);
461 // Notify the control that it is activated
462 control.GetImplementation().Activate();
465 // Send notification for the activation of focused actor
466 mFocusedActorActivatedSignal.Emit(actor);
470 void FocusManager::ClearFocus()
472 Actor actor = GetCurrentFocusActor();
475 actor.Remove(mFocusIndicatorActor);
478 mCurrentFocusActor = FocusIDPair(0, 0);
480 // Send notification for the change of focus actor
481 mFocusChangedSignal.Emit(actor, Actor());
483 if(mIsAccessibilityTtsEnabled)
485 // Stop the TTS playing if any
486 Dali::TtsPlayer player = Dali::TtsPlayer::Get(Dali::TtsPlayer::SCREEN_READER);
491 void FocusManager::Reset()
494 mFocusIDContainer.clear();
495 mIDAdditionalInfoContainer.clear();
498 void FocusManager::SetFocusGroup(Actor actor, bool isFocusGroup)
502 // Create focus group property if not already created.
503 Property::Index propertyIsFocusGroup = actor.GetPropertyIndex(IS_FOCUS_GROUP);
504 if(propertyIsFocusGroup == Property::INVALID_INDEX)
506 actor.RegisterProperty(IS_FOCUS_GROUP, isFocusGroup);
510 actor.SetProperty(propertyIsFocusGroup, isFocusGroup);
515 bool FocusManager::IsFocusGroup(Actor actor) const
517 // Check whether the actor is a focus group
518 bool isFocusGroup = false;
522 Property::Index propertyIsFocusGroup = actor.GetPropertyIndex(IS_FOCUS_GROUP);
523 if(propertyIsFocusGroup != Property::INVALID_INDEX)
525 isFocusGroup = actor.GetProperty<bool>(propertyIsFocusGroup);
532 Actor FocusManager::GetFocusGroup(Actor actor)
534 // Go through the actor's hierarchy to check which focus group the actor belongs to
535 while (actor && !IsFocusGroup(actor))
537 actor = actor.GetParent();
543 void FocusManager::SetGroupMode(bool enabled)
545 mIsFocusWithinGroup = enabled;
548 bool FocusManager::GetGroupMode() const
550 return mIsFocusWithinGroup;
553 void FocusManager::SetWrapMode(bool wrapped)
555 mIsWrapped = wrapped;
558 bool FocusManager::GetWrapMode() const
563 void FocusManager::SetFocusIndicatorActor(Actor indicator)
565 mFocusIndicatorActor = indicator;
568 Actor FocusManager::GetFocusIndicatorActor()
570 return mFocusIndicatorActor;
573 bool FocusManager::DoMoveFocus(FocusIDIter focusIDIter, bool forward, bool wrapped)
575 DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] %d focusable actors\n", __FUNCTION__, __LINE__, mFocusIDContainer.size());
576 DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] focus order : %d\n", __FUNCTION__, __LINE__, (*focusIDIter).first);
578 if( (forward && ++focusIDIter == mFocusIDContainer.end())
579 || (!forward && focusIDIter-- == mFocusIDContainer.begin()) )
581 if(mIsEndcapFeedbackEnabled)
583 if(mIsEndcapFeedbackPlayed == false)
585 // play sound & skip moving once
586 Dali::SoundPlayer soundPlayer = Dali::SoundPlayer::Get();
589 soundPlayer.PlaySound(FOCUS_CHAIN_END_SOUND_FILE);
592 mIsEndcapFeedbackPlayed = true;
595 mIsEndcapFeedbackPlayed = false;
602 focusIDIter = mFocusIDContainer.begin();
606 focusIDIter = mFocusIDContainer.end();
607 --focusIDIter;//We want forward iterator to the last element here
612 DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] Overshot\n", __FUNCTION__, __LINE__);
613 // Send notification for handling overshooted situation
614 mFocusOvershotSignal.Emit(GetCurrentFocusActor(), forward ? Toolkit::FocusManager::OVERSHOT_NEXT : Toolkit::FocusManager::OVERSHOT_PREVIOUS);
616 return false; // Try to move the focus out of the scope
620 if((focusIDIter != mFocusIDContainer.end()) && !DoSetCurrentFocusActor((*focusIDIter).second))
622 mRecursiveFocusMoveCounter++;
623 if(mRecursiveFocusMoveCounter > mFocusIDContainer.size())
625 // We've attempted to focus all the actors in the whole focus chain and no actor
626 // can be focused successfully.
628 DALI_LOG_WARNING("[%s] There is no more focusable actor in %d focus chains\n", __FUNCTION__, mRecursiveFocusMoveCounter);
634 return DoMoveFocus(focusIDIter, forward, wrapped);
641 void FocusManager::SetFocusable(Actor actor, bool focusable)
645 // Create actor focusable property if not already created.
646 Property::Index propertyActorFocusable = actor.GetPropertyIndex(ACTOR_FOCUSABLE);
647 if(propertyActorFocusable == Property::INVALID_INDEX)
649 actor.RegisterProperty(ACTOR_FOCUSABLE, focusable);
653 actor.SetProperty(propertyActorFocusable, focusable);
658 void FocusManager::CreateDefaultFocusIndicatorActor()
660 // Create a focus indicator actor shared by all the focusable actors
661 Image borderImage = Image::New(FOCUS_BORDER_IMAGE_PATH);
663 ImageActor focusIndicator = ImageActor::New(borderImage);
664 focusIndicator.SetPositionInheritanceMode( Dali::USE_PARENT_POSITION_PLUS_LOCAL_POSITION );
665 focusIndicator.SetStyle( ImageActor::STYLE_NINE_PATCH );
666 focusIndicator.SetNinePatchBorder(FOCUS_BORDER_IMAGE_BORDER);
667 focusIndicator.SetPosition(Vector3(0.0f, 0.0f, 1.0f));
669 // Apply size constraint to the focus indicator
670 Constraint constraint = Constraint::New<Vector3>(Actor::SIZE,
671 ParentSource(Actor::SIZE),
672 EqualToConstraint());
673 focusIndicator.ApplyConstraint(constraint);
675 SetFocusIndicatorActor(focusIndicator);
678 bool FocusManager::ChangeAccessibilityStatus()
680 AccessibilityManager manager = AccessibilityManager::Get();
681 mIsAccessibilityTtsEnabled = manager.IsEnabled();
683 if(mIsAccessibilityTtsEnabled)
685 // Show indicator when tts turned on if there is focused actor.
686 Actor actor = GetCurrentFocusActor();
689 if(mFocusIndicatorActor)
691 actor.Add(mFocusIndicatorActor);
694 mIsFocusIndicatorEnabled = true;
698 // Hide indicator when tts turned off
699 Actor actor = GetCurrentFocusActor();
702 actor.Remove(mFocusIndicatorActor);
704 mIsFocusIndicatorEnabled = false;
710 bool FocusManager::AccessibilityActionNext(bool allowEndFeedback)
712 if(mIsAccessibilityTtsEnabled)
714 mIsEndcapFeedbackEnabled = allowEndFeedback;
715 return MoveFocusForward();
723 bool FocusManager::AccessibilityActionPrevious(bool allowEndFeedback)
725 if(mIsAccessibilityTtsEnabled)
727 mIsEndcapFeedbackEnabled = allowEndFeedback;
728 return MoveFocusBackward();
736 bool FocusManager::AccessibilityActionActivate()
740 Actor actor = GetCurrentFocusActor();
750 bool FocusManager::AccessibilityActionRead(bool allowReadAgain)
754 if(mIsAccessibilityTtsEnabled)
756 // Find the focusable actor at the read position
757 AccessibilityManager manager = AccessibilityManager::Get();
758 Dali::HitTestAlgorithm::Results results;
759 Dali::HitTestAlgorithm::HitTest( Stage::GetCurrent(), manager.GetReadPosition(), results, IsActorFocusableFunction );
761 FocusIDIter focusIDIter = mFocusIDContainer.find(GetFocusOrder(results.actor));
762 if(focusIDIter != mFocusIDContainer.end())
764 if( allowReadAgain || (results.actor != GetCurrentFocusActor()) )
766 // Move the focus to the actor
767 ret = SetCurrentFocusActor(results.actor);
768 DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] SetCurrentFocusActor returns %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
776 bool FocusManager::AccessibilityActionReadNext(bool allowEndFeedback)
778 if(mIsAccessibilityTtsEnabled)
780 return MoveFocusForward();
788 bool FocusManager::AccessibilityActionReadPrevious(bool allowEndFeedback)
790 if(mIsAccessibilityTtsEnabled)
792 return MoveFocusBackward();
800 bool FocusManager::AccessibilityActionUp()
804 if(mIsAccessibilityTtsEnabled)
806 Actor actor = GetCurrentFocusActor();
809 Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor);
812 // Notify the control that it is activated
813 ret = control.GetImplementation().OnAccessibilityValueChange(true);
821 bool FocusManager::AccessibilityActionDown()
825 if(mIsAccessibilityTtsEnabled)
827 Actor actor = GetCurrentFocusActor();
830 Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor);
833 // Notify the control that it is activated
834 ret = control.GetImplementation().OnAccessibilityValueChange(false);
842 bool FocusManager::ClearAccessibilityFocus()
844 if(mIsAccessibilityTtsEnabled)
855 bool FocusManager::AccessibilityActionBack()
857 // TODO: Back to previous view
859 return mIsAccessibilityTtsEnabled;
862 bool FocusManager::AccessibilityActionTouch(const TouchEvent& touchEvent)
864 bool handled = false;
866 // TODO: Need to convert the touchevent for the focused actor?
868 Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(GetCurrentFocusActor());
871 handled = control.GetImplementation().OnAccessibilityTouch(touchEvent);
877 bool FocusManager::HandlePanGesture(const Integration::PanGestureEvent& panEvent)
879 bool handled = false;
881 if( panEvent.state == Gesture::Started )
883 // Find the focusable actor at the event position
884 Dali::HitTestAlgorithm::Results results;
885 AccessibilityManager manager = AccessibilityManager::Get();
887 Dali::HitTestAlgorithm::HitTest( Stage::GetCurrent(), panEvent.currentPosition, results, IsActorFocusableFunction );
888 mCurrentGesturedActor = results.actor;
890 if(!mCurrentGesturedActor)
892 DALI_LOG_ERROR("Gesture detected, but no hit actor");
896 // Gesture::Finished (Up) events are delivered with previous (Motion) event position
897 // Use the real previous position; otherwise we may incorrectly get a ZERO velocity
898 if ( Gesture::Finished != panEvent.state )
900 // Store the previous position for next Gesture::Finished iteration.
901 mPreviousPosition = panEvent.previousPosition;
904 Actor rootActor = Stage::GetCurrent().GetRootLayer();
906 Dali::PanGesture pan(panEvent.state);
907 pan.time = panEvent.time;
908 pan.numberOfTouches = panEvent.numberOfTouches;
909 pan.screenPosition = panEvent.currentPosition;
910 pan.screenDisplacement = mPreviousPosition - panEvent.currentPosition;
911 pan.screenVelocity.x = pan.screenDisplacement.x / panEvent.timeDelta;
912 pan.screenVelocity.y = pan.screenDisplacement.y / panEvent.timeDelta;
914 // Only handle the pan gesture when the current focused actor is scrollable or within a scrollable actor
915 while(mCurrentGesturedActor && mCurrentGesturedActor != rootActor && !handled)
917 Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(mCurrentGesturedActor);
920 Vector2 localCurrent;
921 control.ScreenToLocal( localCurrent.x, localCurrent.y, panEvent.currentPosition.x, panEvent.currentPosition.y );
922 pan.position = localCurrent;
924 Vector2 localPrevious;
925 control.ScreenToLocal( localPrevious.x, localPrevious.y, mPreviousPosition.x, mPreviousPosition.y );
927 pan.displacement = localCurrent - localPrevious;
928 pan.velocity.x = pan.displacement.x / panEvent.timeDelta;
929 pan.velocity.y = pan.displacement.y / panEvent.timeDelta;
931 handled = control.GetImplementation().OnAccessibilityPan(pan);
934 // If the gesture is not handled by the control, check its parent
937 mCurrentGesturedActor = mCurrentGesturedActor.GetParent();
939 if(!mCurrentGesturedActor)
941 DALI_LOG_ERROR("no more gestured actor");
946 // If handled, then update the pan gesture properties
947 PanGestureDetector::SetPanGestureProperties( pan );
954 Toolkit::FocusManager::FocusChangedSignalType& FocusManager::FocusChangedSignal()
956 return mFocusChangedSignal;
959 Toolkit::FocusManager::FocusOvershotSignalType& FocusManager::FocusOvershotSignal()
961 return mFocusOvershotSignal;
964 Toolkit::FocusManager::FocusedActorActivatedSignalType& FocusManager::FocusedActorActivatedSignal()
966 return mFocusedActorActivatedSignal;
969 bool FocusManager::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
971 Dali::BaseHandle handle( object );
973 bool connected( true );
974 FocusManager* manager = dynamic_cast<FocusManager*>(object);
976 if( Dali::Toolkit::FocusManager::SIGNAL_FOCUS_CHANGED == signalName )
978 manager->FocusChangedSignal().Connect( tracker, functor );
980 else if( Dali::Toolkit::FocusManager::SIGNAL_FOCUS_OVERSHOT == signalName )
982 manager->FocusOvershotSignal().Connect( tracker, functor );
984 else if( Dali::Toolkit::FocusManager::SIGNAL_FOCUSED_ACTOR_ACTIVATED== signalName )
986 manager->FocusedActorActivatedSignal().Connect( tracker, functor );
990 // signalName does not match any signal
997 } // namespace Internal
999 } // namespace Toolkit