-//
-// 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>
+#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
{
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.
*/
FocusManager::FocusManager()
: mIsWrapped(false),
mIsFocusWithinGroup(false),
+ mIsEndcapFeedbackEnabled(false),
+ mIsEndcapFeedbackPlayed(false),
mCurrentFocusActor(FocusIDPair(0, 0)),
mFocusIndicatorActor(Actor()),
mRecursiveFocusMoveCounter(0),
}
// 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);
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);
}
}
mCurrentFocusActor = FocusIDPair(0, 0);
// Send notification for the change of focus actor
- mFocusChangedSignalV2.Emit(actor, Actor());
+ mFocusChangedSignal.Emit(actor, Actor());
if(mIsAccessibilityTtsEnabled)
{
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
{
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)
{
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
}
Property::Index propertyActorFocusable = actor.GetPropertyIndex(ACTOR_FOCUSABLE);
if(propertyActorFocusable == Property::INVALID_INDEX)
{
- propertyActorFocusable = actor.RegisterProperty(ACTOR_FOCUSABLE, focusable);
+ actor.RegisterProperty(ACTOR_FOCUSABLE, focusable);
}
else
{
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 );
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.SetSizeMode( SIZE_EQUAL_TO_PARENT );
SetFocusIndicatorActor(focusIndicator);
}
return true;
}
-bool FocusManager::AccessibilityActionNext()
+bool FocusManager::AccessibilityActionNext(bool allowEndFeedback)
{
if(mIsAccessibilityTtsEnabled)
{
+ mIsEndcapFeedbackEnabled = allowEndFeedback;
return MoveFocusForward();
}
else
}
}
-bool FocusManager::AccessibilityActionPrevious()
+bool FocusManager::AccessibilityActionPrevious(bool allowEndFeedback)
{
if(mIsAccessibilityTtsEnabled)
{
+ mIsEndcapFeedbackEnabled = allowEndFeedback;
return MoveFocusBackward();
}
else
return ret;
}
-bool FocusManager::AccessibilityActionReadNext()
+bool FocusManager::AccessibilityActionReadNext(bool allowEndFeedback)
{
if(mIsAccessibilityTtsEnabled)
{
}
}
-bool FocusManager::AccessibilityActionReadPrevious()
+bool FocusManager::AccessibilityActionReadPrevious(bool allowEndFeedback)
{
if(mIsAccessibilityTtsEnabled)
{
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;
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;
// 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
{
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 )
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 );
}