fix Klocwork warning of unintialized data members, unneeded assignment & unreachable...
[platform/core/uifw/dali-toolkit.git] / base / dali-toolkit / internal / focus-manager / focus-manager-impl.cpp
index 80e5c2d..b72eb82 100644 (file)
@@ -1,22 +1,31 @@
-//
-// 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 <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>
+
 // INTERNAL INCLUDES
 #include <dali-toolkit/public-api/controls/control.h>
 #include <dali-toolkit/public-api/controls/control-impl.h>
@@ -44,6 +53,9 @@ 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 +102,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),
@@ -331,6 +345,12 @@ bool FocusManager::DoSetCurrentFocusActor(const unsigned int 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);
 
@@ -483,7 +503,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 +578,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)
@@ -609,7 +646,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
     {
@@ -670,10 +707,11 @@ bool FocusManager::ChangeAccessibilityStatus()
   return true;
 }
 
-bool FocusManager::AccessibilityActionNext()
+bool FocusManager::AccessibilityActionNext(bool allowEndFeedback)
 {
   if(mIsAccessibilityTtsEnabled)
   {
+    mIsEndcapFeedbackEnabled = allowEndFeedback;
     return MoveFocusForward();
   }
   else
@@ -682,10 +720,11 @@ bool FocusManager::AccessibilityActionNext()
   }
 }
 
-bool FocusManager::AccessibilityActionPrevious()
+bool FocusManager::AccessibilityActionPrevious(bool allowEndFeedback)
 {
   if(mIsAccessibilityTtsEnabled)
   {
+    mIsEndcapFeedbackEnabled = allowEndFeedback;
     return MoveFocusBackward();
   }
   else
@@ -734,7 +773,7 @@ bool FocusManager::AccessibilityActionRead(bool allowReadAgain)
   return ret;
 }
 
-bool FocusManager::AccessibilityActionReadNext()
+bool FocusManager::AccessibilityActionReadNext(bool allowEndFeedback)
 {
   if(mIsAccessibilityTtsEnabled)
   {
@@ -746,7 +785,7 @@ bool FocusManager::AccessibilityActionReadNext()
   }
 }
 
-bool FocusManager::AccessibilityActionReadPrevious()
+bool FocusManager::AccessibilityActionReadPrevious(bool allowEndFeedback)
 {
   if(mIsAccessibilityTtsEnabled)
   {
@@ -820,25 +859,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 +922,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 +934,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
     {