Merge "Added TextLabel and TextField tests" into tizen
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / focus-manager / focus-manager-impl.cpp
index 80e5c2d..b1f3c14 100644 (file)
@@ -1,26 +1,37 @@
-//
-// Copyright (c) 2014 Samsung Electronics Co., Ltd.
-//
-// Licensed under the Flora License, Version 1.0 (the License);
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://floralicense.org/license/
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an AS IS BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
 
 // CLASS HEADER
 #include "focus-manager-impl.h"
 
+// EXTERNAL INCLUDES
+#include <cstring> // for strcmp
+#include <dali/public-api/actors/layer.h>
+#include <dali/public-api/adaptor-framework/accessibility-manager.h>
+#include <dali/public-api/adaptor-framework/sound-player.h>
+#include <dali/public-api/adaptor-framework/tts-player.h>
+#include <dali/public-api/animation/constraints.h>
+#include <dali/public-api/events/hit-test-algorithm.h>
+#include <dali/public-api/images/resource-image.h>
+#include <dali/integration-api/debug.h>
+
 // INTERNAL INCLUDES
 #include <dali-toolkit/public-api/controls/control.h>
 #include <dali-toolkit/public-api/controls/control-impl.h>
-#include <dali/integration-api/debug.h>
 
 namespace Dali
 {
@@ -34,16 +45,25 @@ namespace Internal
 namespace // unnamed namespace
 {
 
+// Signals
+
+const char* const SIGNAL_FOCUS_CHANGED =           "focus-changed";
+const char* const SIGNAL_FOCUS_OVERSHOT =          "focus-overshot";
+const char* const SIGNAL_FOCUSED_ACTOR_ACTIVATED = "focused-actor-activated";
+
 #if defined(DEBUG_ENABLED)
 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_FOCUS_MANAGER");
 #endif
 
-const char * const ACTOR_FOCUSABLE("focusable");
-const char * const IS_FOCUS_GROUP("is-focus-group");
+const char* const ACTOR_FOCUSABLE("focusable");
+const char* const IS_FOCUS_GROUP("is-focus-group");
 
 const char* FOCUS_BORDER_IMAGE_PATH = DALI_IMAGE_DIR "B16-8_TTS_focus.png";
 const Vector4 FOCUS_BORDER_IMAGE_BORDER = Vector4(7.0f, 7.0f, 7.0f, 7.0f);
 
+const char* FOCUS_SOUND_FILE = DALI_SOUND_DIR "Focus.ogg";
+const char* FOCUS_CHAIN_END_SOUND_FILE = DALI_SOUND_DIR "End_of_List.ogg";
+
 /**
  * The function to be used in the hit-test algorithm to check whether the actor is hittable.
  */
@@ -90,6 +110,8 @@ bool IsActorFocusableFunction(Actor actor, Dali::HitTestAlgorithm::TraverseType
 FocusManager::FocusManager()
 : mIsWrapped(false),
   mIsFocusWithinGroup(false),
+  mIsEndcapFeedbackEnabled(false),
+  mIsEndcapFeedbackPlayed(false),
   mCurrentFocusActor(FocusIDPair(0, 0)),
   mFocusIndicatorActor(Actor()),
   mRecursiveFocusMoveCounter(0),
@@ -324,13 +346,19 @@ bool FocusManager::DoSetCurrentFocusActor(const unsigned int actorID)
       }
 
       // Send notification for the change of focus actor
-      mFocusChangedSignalV2.Emit( GetCurrentFocusActor(), actor );
+      mFocusChangedSignal.Emit( GetCurrentFocusActor(), actor );
 
       // Save the current focused actor
       mCurrentFocusActor = FocusIDPair(GetFocusOrder(actor), actorID);
 
       if(mIsAccessibilityTtsEnabled)
       {
+        Dali::SoundPlayer soundPlayer = Dali::SoundPlayer::Get();
+        if(soundPlayer)
+        {
+          soundPlayer.PlaySound(FOCUS_SOUND_FILE);
+        }
+
         // Play the accessibility attributes with the TTS player.
         Dali::TtsPlayer player = Dali::TtsPlayer::Get(Dali::TtsPlayer::SCREEN_READER);
 
@@ -439,11 +467,11 @@ void FocusManager::DoActivate(Actor actor)
     if(control)
     {
       // Notify the control that it is activated
-      control.GetImplementation().OnActivated();
+      control.GetImplementation().Activate();
     }
 
     // Send notification for the activation of focused actor
-    mFocusedActorActivatedSignalV2.Emit(actor);
+    mFocusedActorActivatedSignal.Emit(actor);
   }
 }
 
@@ -458,7 +486,7 @@ void FocusManager::ClearFocus()
   mCurrentFocusActor = FocusIDPair(0, 0);
 
   // Send notification for the change of focus actor
-  mFocusChangedSignalV2.Emit(actor, Actor());
+  mFocusChangedSignal.Emit(actor, Actor());
 
   if(mIsAccessibilityTtsEnabled)
   {
@@ -483,7 +511,7 @@ void FocusManager::SetFocusGroup(Actor actor, bool isFocusGroup)
     Property::Index propertyIsFocusGroup = actor.GetPropertyIndex(IS_FOCUS_GROUP);
     if(propertyIsFocusGroup == Property::INVALID_INDEX)
     {
-      propertyIsFocusGroup = actor.RegisterProperty(IS_FOCUS_GROUP, isFocusGroup);
+      actor.RegisterProperty(IS_FOCUS_GROUP, isFocusGroup);
     }
     else
     {
@@ -558,6 +586,23 @@ bool FocusManager::DoMoveFocus(FocusIDIter focusIDIter, bool forward, bool wrapp
   if( (forward && ++focusIDIter == mFocusIDContainer.end())
     || (!forward && focusIDIter-- == mFocusIDContainer.begin()) )
   {
+    if(mIsEndcapFeedbackEnabled)
+    {
+      if(mIsEndcapFeedbackPlayed == false)
+      {
+        // play sound & skip moving once
+        Dali::SoundPlayer soundPlayer = Dali::SoundPlayer::Get();
+        if(soundPlayer)
+        {
+          soundPlayer.PlaySound(FOCUS_CHAIN_END_SOUND_FILE);
+        }
+
+        mIsEndcapFeedbackPlayed = true;
+        return true;
+      }
+      mIsEndcapFeedbackPlayed = false;
+    }
+
     if(wrapped)
     {
       if(forward)
@@ -574,7 +619,7 @@ bool FocusManager::DoMoveFocus(FocusIDIter focusIDIter, bool forward, bool wrapp
     {
       DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] Overshot\n", __FUNCTION__, __LINE__);
       // Send notification for handling overshooted situation
-      mFocusOvershotSignalV2.Emit(GetCurrentFocusActor(), forward ? Toolkit::FocusManager::OVERSHOT_NEXT : Toolkit::FocusManager::OVERSHOT_PREVIOUS);
+      mFocusOvershotSignal.Emit(GetCurrentFocusActor(), forward ? Toolkit::FocusManager::OVERSHOT_NEXT : Toolkit::FocusManager::OVERSHOT_PREVIOUS);
 
       return false; // Try to move the focus out of the scope
     }
@@ -609,7 +654,7 @@ void FocusManager::SetFocusable(Actor actor, bool focusable)
     Property::Index propertyActorFocusable = actor.GetPropertyIndex(ACTOR_FOCUSABLE);
     if(propertyActorFocusable == Property::INVALID_INDEX)
     {
-      propertyActorFocusable = actor.RegisterProperty(ACTOR_FOCUSABLE, focusable);
+      actor.RegisterProperty(ACTOR_FOCUSABLE, focusable);
     }
     else
     {
@@ -621,7 +666,7 @@ void FocusManager::SetFocusable(Actor actor, bool focusable)
 void FocusManager::CreateDefaultFocusIndicatorActor()
 {
   // Create a focus indicator actor shared by all the focusable actors
-  Image borderImage = Image::New(FOCUS_BORDER_IMAGE_PATH);
+  Image borderImage = ResourceImage::New(FOCUS_BORDER_IMAGE_PATH);
 
   ImageActor focusIndicator = ImageActor::New(borderImage);
   focusIndicator.SetPositionInheritanceMode( Dali::USE_PARENT_POSITION_PLUS_LOCAL_POSITION );
@@ -630,10 +675,7 @@ void FocusManager::CreateDefaultFocusIndicatorActor()
   focusIndicator.SetPosition(Vector3(0.0f, 0.0f, 1.0f));
 
   // Apply size constraint to the focus indicator
-  Constraint constraint = Constraint::New<Vector3>(Actor::SIZE,
-                                                   ParentSource(Actor::SIZE),
-                                                   EqualToConstraint());
-  focusIndicator.ApplyConstraint(constraint);
+  focusIndicator.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
 
   SetFocusIndicatorActor(focusIndicator);
 }
@@ -670,10 +712,11 @@ bool FocusManager::ChangeAccessibilityStatus()
   return true;
 }
 
-bool FocusManager::AccessibilityActionNext()
+bool FocusManager::AccessibilityActionNext(bool allowEndFeedback)
 {
   if(mIsAccessibilityTtsEnabled)
   {
+    mIsEndcapFeedbackEnabled = allowEndFeedback;
     return MoveFocusForward();
   }
   else
@@ -682,10 +725,11 @@ bool FocusManager::AccessibilityActionNext()
   }
 }
 
-bool FocusManager::AccessibilityActionPrevious()
+bool FocusManager::AccessibilityActionPrevious(bool allowEndFeedback)
 {
   if(mIsAccessibilityTtsEnabled)
   {
+    mIsEndcapFeedbackEnabled = allowEndFeedback;
     return MoveFocusBackward();
   }
   else
@@ -734,7 +778,7 @@ bool FocusManager::AccessibilityActionRead(bool allowReadAgain)
   return ret;
 }
 
-bool FocusManager::AccessibilityActionReadNext()
+bool FocusManager::AccessibilityActionReadNext(bool allowEndFeedback)
 {
   if(mIsAccessibilityTtsEnabled)
   {
@@ -746,7 +790,7 @@ bool FocusManager::AccessibilityActionReadNext()
   }
 }
 
-bool FocusManager::AccessibilityActionReadPrevious()
+bool FocusManager::AccessibilityActionReadPrevious(bool allowEndFeedback)
 {
   if(mIsAccessibilityTtsEnabled)
   {
@@ -820,25 +864,62 @@ bool FocusManager::AccessibilityActionBack()
   return mIsAccessibilityTtsEnabled;
 }
 
+bool FocusManager::AccessibilityActionTouch(const TouchEvent& touchEvent)
+{
+  bool handled = false;
+
+  // TODO: Need to convert the touchevent for the focused actor?
+
+  Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(GetCurrentFocusActor());
+  if(control)
+  {
+    handled = control.GetImplementation().OnAccessibilityTouch(touchEvent);
+  }
+
+  return handled;
+}
+
 bool FocusManager::HandlePanGesture(const Integration::PanGestureEvent& panEvent)
 {
   bool handled = false;
 
-  Actor currentGesturedActor = GetCurrentFocusActor();
+  if( panEvent.state == Gesture::Started )
+  {
+    // Find the focusable actor at the event position
+    Dali::HitTestAlgorithm::Results results;
+    AccessibilityManager manager = AccessibilityManager::Get();
+
+    Dali::HitTestAlgorithm::HitTest( Stage::GetCurrent(), panEvent.currentPosition, results, IsActorFocusableFunction );
+    mCurrentGesturedActor = results.actor;
+
+    if(!mCurrentGesturedActor)
+    {
+      DALI_LOG_ERROR("Gesture detected, but no hit actor");
+    }
+  }
+
+  // Gesture::Finished (Up) events are delivered with previous (Motion) event position
+  // Use the real previous position; otherwise we may incorrectly get a ZERO velocity
+  if ( Gesture::Finished != panEvent.state )
+  {
+    // Store the previous position for next Gesture::Finished iteration.
+    mPreviousPosition = panEvent.previousPosition;
+  }
+
   Actor rootActor = Stage::GetCurrent().GetRootLayer();
 
   Dali::PanGesture pan(panEvent.state);
   pan.time = panEvent.time;
   pan.numberOfTouches = panEvent.numberOfTouches;
   pan.screenPosition = panEvent.currentPosition;
-  pan.screenDisplacement = panEvent.previousPosition - panEvent.currentPosition;
+  pan.screenDisplacement = mPreviousPosition - panEvent.currentPosition;
   pan.screenVelocity.x = pan.screenDisplacement.x / panEvent.timeDelta;
   pan.screenVelocity.y = pan.screenDisplacement.y / panEvent.timeDelta;
 
   // Only handle the pan gesture when the current focused actor is scrollable or within a scrollable actor
-  while(currentGesturedActor && currentGesturedActor != rootActor && !handled)
+  while(mCurrentGesturedActor && mCurrentGesturedActor != rootActor && !handled)
   {
-    Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(currentGesturedActor);
+    Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(mCurrentGesturedActor);
     if(control)
     {
       Vector2 localCurrent;
@@ -846,7 +927,7 @@ bool FocusManager::HandlePanGesture(const Integration::PanGestureEvent& panEvent
       pan.position = localCurrent;
 
       Vector2 localPrevious;
-      control.ScreenToLocal( localPrevious.x, localPrevious.y, panEvent.previousPosition.x, panEvent.previousPosition.y );
+      control.ScreenToLocal( localPrevious.x, localPrevious.y, mPreviousPosition.x, mPreviousPosition.y );
 
       pan.displacement = localCurrent - localPrevious;
       pan.velocity.x = pan.displacement.x / panEvent.timeDelta;
@@ -858,7 +939,12 @@ bool FocusManager::HandlePanGesture(const Integration::PanGestureEvent& panEvent
     // If the gesture is not handled by the control, check its parent
     if(!handled)
     {
-      currentGesturedActor = currentGesturedActor.GetParent();
+      mCurrentGesturedActor = mCurrentGesturedActor.GetParent();
+
+      if(!mCurrentGesturedActor)
+      {
+        DALI_LOG_ERROR("no more gestured actor");
+      }
     }
     else
     {
@@ -870,19 +956,19 @@ bool FocusManager::HandlePanGesture(const Integration::PanGestureEvent& panEvent
   return handled;
 }
 
-Toolkit::FocusManager::FocusChangedSignalV2& FocusManager::FocusChangedSignal()
+Toolkit::FocusManager::FocusChangedSignalType& FocusManager::FocusChangedSignal()
 {
-  return mFocusChangedSignalV2;
+  return mFocusChangedSignal;
 }
 
-Toolkit::FocusManager::FocusOvershotSignalV2& FocusManager::FocusOvershotSignal()
+Toolkit::FocusManager::FocusOvershotSignalType& FocusManager::FocusOvershotSignal()
 {
-  return mFocusOvershotSignalV2;
+  return mFocusOvershotSignal;
 }
 
-Toolkit::FocusManager::FocusedActorActivatedSignalV2& FocusManager::FocusedActorActivatedSignal()
+Toolkit::FocusManager::FocusedActorActivatedSignalType& FocusManager::FocusedActorActivatedSignal()
 {
-  return mFocusedActorActivatedSignalV2;
+  return mFocusedActorActivatedSignal;
 }
 
 bool FocusManager::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
@@ -890,17 +976,17 @@ bool FocusManager::DoConnectSignal( BaseObject* object, ConnectionTrackerInterfa
   Dali::BaseHandle handle( object );
 
   bool connected( true );
-  FocusManager* manager = dynamic_cast<FocusManager*>(object);
+  FocusManager* manager = dynamic_cast<FocusManager*>( object );
 
-  if( Dali::Toolkit::FocusManager::SIGNAL_FOCUS_CHANGED == signalName )
+  if( 0 == strcmp( signalName.c_str(), SIGNAL_FOCUS_CHANGED ) )
   {
     manager->FocusChangedSignal().Connect( tracker, functor );
   }
-  else if( Dali::Toolkit::FocusManager::SIGNAL_FOCUS_OVERSHOT == signalName )
+  else if( 0 == strcmp( signalName.c_str(), SIGNAL_FOCUS_OVERSHOT ) )
   {
     manager->FocusOvershotSignal().Connect( tracker, functor );
   }
-  else if( Dali::Toolkit::FocusManager::SIGNAL_FOCUSED_ACTOR_ACTIVATED== signalName )
+  else if( 0 == strcmp( signalName.c_str(), SIGNAL_FOCUSED_ACTOR_ACTIVATED ) )
   {
     manager->FocusedActorActivatedSignal().Connect( tracker, functor );
   }