/*
- * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2019 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.
static const float ROTATION_EPSILON = 0.0001f;
static const float VECTOR4_EPSILON = 0.0001f;
+static const float VECTOR3_EPSILON = 0.0001f;
// Functor to test whether a Finish signal is emitted
struct AnimationFinishCheck
END_TEST;
}
-int UtcDaliAnimationSetEndActioN(void)
+int UtcDaliAnimationSetEndActionN(void)
{
TestApplication application;
END_TEST;
}
+
+namespace // Purposefully left this in the middle as the values in this namespace are only used for the subsequent two test cases
+{
+enum TestFunction
+{
+ STOP,
+ CLEAR
+};
+
+void CheckPropertyValuesWhenCallingAnimationMethod( TestFunction functionToTest, const char * testName )
+{
+ tet_printf( "Testing %s\n", testName );
+
+ // When an Animation::Stop() or Animation::Clear() is called, the event-side property needs to be updated appropriately
+ // This test checks that that is being done
+
+ const float durationSeconds( 1.0f );
+ unsigned int halfAnimationDuration( static_cast< unsigned int >( durationSeconds * 1000.0f * 0.5f ) );
+ const Vector3 originalPosition( Vector3::ZERO );
+ const Vector3 targetPosition( 10.0f, 10.0f, 10.0f );
+ const Vector3 halfWayToTarget( targetPosition * 0.5f );
+
+ struct ExpectedValue
+ {
+ Animation::EndAction endAction;
+ Vector3 expectedGetPropertyValue;
+ };
+
+ ExpectedValue expectedValueTable[] =
+ {
+ { Animation::Bake, halfWayToTarget }, // When baking, the current value is the final value.
+ { Animation::BakeFinal, targetPosition }, // When BakeFinal, we should jump to the final value when clearing or stopping.
+ { Animation::Discard, originalPosition }, // When discarding, we should jump back to the original value when clearing or stopping.
+ };
+ const auto expectedValueTableCount = sizeof( expectedValueTable ) / sizeof( ExpectedValue );
+
+ for( auto i = 0u; i < expectedValueTableCount; ++i )
+ {
+ TestApplication application;
+
+ Actor actor = Actor::New();
+ Stage::GetCurrent().Add(actor);
+
+ // Build the animation
+ Animation animation = Animation::New( durationSeconds );
+ animation.SetEndAction( expectedValueTable[ i ].endAction );
+ animation.AnimateTo( Property( actor, Actor::Property::POSITION ), targetPosition, AlphaFunction::LINEAR );
+
+ // Start the animation
+ animation.Play();
+
+ application.SendNotification();
+ application.Render( halfAnimationDuration );
+
+ // Stop or Clear the animation early, both have the same effect
+ if( functionToTest == TestFunction::STOP )
+ {
+ animation.Stop();
+ }
+ else
+ {
+ animation.Clear();
+ }
+
+ // The event side property should be set the expected value immediately, the update side property will still only be halfway as we haven't run an update yet
+ DALI_TEST_EQUALS( actor.GetProperty( Actor::Property::POSITION ).Get< Vector3 >(), expectedValueTable[ i ].expectedGetPropertyValue, VECTOR3_EPSILON, TEST_LOCATION );
+ DALI_TEST_EQUALS( actor.GetCurrentProperty( Actor::Property::POSITION ).Get< Vector3 >(), halfWayToTarget, VECTOR3_EPSILON, TEST_LOCATION );
+
+ // After one frame, both values should match regardless of the End Action
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS( actor.GetProperty( Actor::Property::POSITION ).Get< Vector3 >(), expectedValueTable[ i ].expectedGetPropertyValue, VECTOR3_EPSILON, TEST_LOCATION );
+ DALI_TEST_EQUALS( actor.GetCurrentProperty( Actor::Property::POSITION ).Get< Vector3 >(), expectedValueTable[ i ].expectedGetPropertyValue, VECTOR3_EPSILON, TEST_LOCATION );
+ }
+}
+} // unnamed namespace
+
+int UtcDaliAnimationStopPropertyValue(void)
+{
+ CheckPropertyValuesWhenCallingAnimationMethod( TestFunction::STOP, "UtcDaliAnimationStopPropertyValue" );
+ END_TEST;
+}
+
+int UtcDaliAnimationClearPropertyValue(void)
+{
+ CheckPropertyValuesWhenCallingAnimationMethod( TestFunction::CLEAR, "UtcDaliAnimationStopPropertyValue" );
+ END_TEST;
+}
+
+int UtcDaliAnimationPausePropertyValue(void)
+{
+ const float durationSeconds( 1.0f );
+ unsigned int halfAnimationDuration( static_cast< unsigned int >( durationSeconds * 1000.0f * 0.5f ) );
+ const Vector3 originalPosition( Vector3::ZERO );
+ const Vector3 targetPosition( 10.0f, 10.0f, 10.0f );
+ const Vector3 halfWayToTarget( targetPosition * 0.5f );
+
+ Animation::EndAction endActions[] =
+ {
+ Animation::Bake,
+ Animation::BakeFinal,
+ Animation::Discard,
+ };
+ const auto endActionCount = sizeof( endActions ) / sizeof( endActions[0] );
+
+ // For all end actions, when pausing, we stay at the current value
+ for( auto i = 0u; i < endActionCount; ++i )
+ {
+ TestApplication application;
+
+ Actor actor = Actor::New();
+ Stage::GetCurrent().Add(actor);
+
+ // Build the animation
+ Animation animation = Animation::New( durationSeconds );
+ animation.SetEndAction( endActions[ i ] );
+ animation.AnimateTo( Property( actor, Actor::Property::POSITION ), targetPosition, AlphaFunction::LINEAR );
+
+ // Start the animation
+ animation.Play();
+
+ application.SendNotification();
+ application.Render( halfAnimationDuration );
+
+ // Puase the animation early
+ animation.Pause();
+
+ // The event side property should be set the current value immediately, the update side property will still only be halfway
+ DALI_TEST_EQUALS( actor.GetProperty( Actor::Property::POSITION ).Get< Vector3 >(), halfWayToTarget, VECTOR3_EPSILON, TEST_LOCATION );
+ DALI_TEST_EQUALS( actor.GetCurrentProperty( Actor::Property::POSITION ).Get< Vector3 >(), halfWayToTarget, VECTOR3_EPSILON, TEST_LOCATION );
+
+ // After one frame, both values should match regardless of the End Action
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS( actor.GetProperty( Actor::Property::POSITION ).Get< Vector3 >(), halfWayToTarget, VECTOR3_EPSILON, TEST_LOCATION );
+ DALI_TEST_EQUALS( actor.GetCurrentProperty( Actor::Property::POSITION ).Get< Vector3 >(), halfWayToTarget, VECTOR3_EPSILON, TEST_LOCATION );
+ }
+
+ END_TEST;
+}
/*
- * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2019 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.
DALI_TEST_CHECK( value.Get( opacity ) );
DALI_TEST_EQUALS( opacity, 0.0f, Dali::Math::MACHINE_EPSILON_1, TEST_LOCATION );
+ // Need to clear the animation before setting the property as the animation value is baked and will override any previous setters
+ animation.Clear();
renderer.SetProperty( DevelRenderer::Property::OPACITY, 0.1f );
- animation.Clear();
animation.AnimateBy( Property( renderer, DevelRenderer::Property::OPACITY ), 0.5f );
animation.Play();
value = renderer.GetProperty( DevelRenderer::Property::OPACITY );
DALI_TEST_CHECK( value.Get( opacity ) );
DALI_TEST_EQUALS( opacity, 0.6f, Dali::Math::MACHINE_EPSILON_1, TEST_LOCATION );
+ DALI_TEST_EQUALS( opacity, renderer.GetCurrentProperty( DevelRenderer::Property::OPACITY ).Get< float >(), Dali::Math::MACHINE_EPSILON_1, TEST_LOCATION );
END_TEST;
}
WheelEventSignalData& signalData;
};
+// Stores data that is populated in the KeyEventGeneratedSignal callback and will be read by the TET cases
+struct KeyEventGeneratedSignalData
+{
+ KeyEventGeneratedSignalData()
+ : functorCalled(false)
+ {}
+
+ void Reset()
+ {
+ functorCalled = false;
+
+ receivedKeyEvent.keyModifier = 0;
+ receivedKeyEvent.keyPressedName.clear();
+ receivedKeyEvent.keyPressed.clear();
+ }
+
+ bool functorCalled;
+ KeyEvent receivedKeyEvent;
+};
+
+// Functor that sets the data when called
+struct KeyEventGeneratedReceivedFunctor
+{
+ KeyEventGeneratedReceivedFunctor( KeyEventGeneratedSignalData& data )
+ : signalData( data )
+ {}
+
+ bool operator()( const KeyEvent& keyEvent )
+ {
+ signalData.functorCalled = true;
+ signalData.receivedKeyEvent = keyEvent;
+
+ return true;
+ }
+
+ bool operator()()
+ {
+ signalData.functorCalled = true;
+ return true;
+ }
+
+ KeyEventGeneratedSignalData& signalData;
+};
+
void GenerateTouch( TestApplication& application, PointState::Type state, const Vector2& screenPosition )
{
Integration::TouchEvent touchEvent;
END_TEST;
}
+
+int UtcDaliSceneKeyEventGeneratedSignalP(void)
+{
+ TestApplication application;
+ Dali::Integration::Scene scene = application.GetScene();
+
+ KeyEventGeneratedSignalData data;
+ KeyEventGeneratedReceivedFunctor functor( data );
+ scene.KeyEventGeneratedSignal().Connect( &application, functor );
+
+ Integration::KeyEvent event( "a", "", "a", 0, 0, 0, Integration::KeyEvent::Up, "a", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE );
+ application.ProcessEvent( event );
+
+ DALI_TEST_EQUALS( true, data.functorCalled, TEST_LOCATION );
+ DALI_TEST_CHECK( event.keyModifier == data.receivedKeyEvent.keyModifier );
+ DALI_TEST_CHECK( event.keyName == data.receivedKeyEvent.keyPressedName );
+ DALI_TEST_CHECK( event.keyString == data.receivedKeyEvent.keyPressed );
+ DALI_TEST_CHECK( event.state == static_cast<Integration::KeyEvent::State>( data.receivedKeyEvent.state ) );
+
+ data.Reset();
+
+ Integration::KeyEvent event2( "i", "", "i", 0, 0, 0, Integration::KeyEvent::Up, "i", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE );
+ application.ProcessEvent( event2 );
+
+ DALI_TEST_EQUALS( true, data.functorCalled, TEST_LOCATION );
+ DALI_TEST_CHECK( event2.keyModifier == data.receivedKeyEvent.keyModifier );
+ DALI_TEST_CHECK( event2.keyName == data.receivedKeyEvent.keyPressedName );
+ DALI_TEST_CHECK( event2.keyString == data.receivedKeyEvent.keyPressed );
+ DALI_TEST_CHECK( event2.state == static_cast<Integration::KeyEvent::State>( data.receivedKeyEvent.state ) );
+
+ data.Reset();
+
+ Integration::KeyEvent event3( "a", "", "a", 0, 0, 0, Integration::KeyEvent::Down, "a", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE );
+ application.ProcessEvent( event3 );
+
+ DALI_TEST_EQUALS( true, data.functorCalled, TEST_LOCATION );
+ DALI_TEST_CHECK( event3.keyModifier == data.receivedKeyEvent.keyModifier );
+ DALI_TEST_CHECK( event3.keyName == data.receivedKeyEvent.keyPressedName );
+ DALI_TEST_CHECK( event3.keyString == data.receivedKeyEvent.keyPressed );
+ DALI_TEST_CHECK( event3.state == static_cast<Integration::KeyEvent::State>( data.receivedKeyEvent.state ) );
+
+ data.Reset();
+
+ Integration::KeyEvent event4( "a", "", "a", 0, 0, 0, Integration::KeyEvent::Up, "a", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE );
+ application.ProcessEvent( event4 );
+
+ DALI_TEST_EQUALS( true, data.functorCalled, TEST_LOCATION );
+ DALI_TEST_CHECK( event4.keyModifier == data.receivedKeyEvent.keyModifier );
+ DALI_TEST_CHECK( event4.keyName == data.receivedKeyEvent.keyPressedName );
+ DALI_TEST_CHECK( event4.keyString == data.receivedKeyEvent.keyPressed );
+ DALI_TEST_CHECK( event4.state == static_cast<Integration::KeyEvent::State>( data.receivedKeyEvent.state ) );
+ END_TEST;
+}
return GetImplementation(*this).KeyEventSignal();
}
+Scene::KeyEventGeneratedSignalType& Scene::KeyEventGeneratedSignal()
+{
+ return GetImplementation(*this).KeyEventGeneratedSignal();
+}
+
Scene::TouchSignalType& Scene::TouchSignal()
{
return GetImplementation(*this).TouchSignal();
public:
typedef Signal< void () > EventProcessingFinishedSignalType; ///< Event Processing finished signal type
typedef Signal< void (const Dali::KeyEvent&) > KeyEventSignalType; ///< Key event signal type
+ typedef Signal< bool (const Dali::KeyEvent&) > KeyEventGeneratedSignalType; ///< key event generated signal type
typedef Signal< void (const Dali::TouchData&) > TouchSignalType; ///< Touch signal type
typedef Signal< void (const Dali::WheelEvent&) > WheelEventSignalType; ///< Touched signal type
KeyEventSignalType& KeyEventSignal();
/**
+ * @brief The user would connect to this signal to get a KeyEvent when KeyEvent is generated.
+ *
+ * If the control already consumed key event, KeyEventProcessor do not need to Emit keyEvent.
+ * Therefore, KeyinputManager first checks whether KeyEvent is generated as KeyEventGeneratedSignal.
+ * After that keyEventProcessor must invoke KeyEvent only if KeyEventGeneratedSignal () is not consumed.
+ *
+ * A callback of the following type may be connected:
+ * @code
+ * bool YourCallbackName(const KeyEvent& event);
+ * @endcode
+ *
+ * @return The return is true if KeyEvent is consumed, otherwise false.
+ */
+ KeyEventGeneratedSignalType& KeyEventGeneratedSignal();
+
+ /**
* @brief This signal is emitted when the screen is touched and when the touch ends
* (i.e. the down & up touch events only).
*
/*
- * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2019 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.
mState = Dali::Animation::PLAYING;
- NotifyObjects();
+ NotifyObjects( Notify::USE_TARGET_VALUE );
SendFinalProgressNotificationMessage();
mState = Dali::Animation::PLAYING;
- NotifyObjects();
+ NotifyObjects( Notify::USE_TARGET_VALUE );
SendFinalProgressNotificationMessage();
mState = Dali::Animation::PLAYING;
- NotifyObjects();
+ NotifyObjects( Notify::USE_TARGET_VALUE );
SendFinalProgressNotificationMessage();
// mAnimation is being used in a separate thread; queue a Pause message
PauseAnimationMessage( mEventThreadServices, *mAnimation );
+
+ // Notify the objects with the _paused_, i.e. current values
+ NotifyObjects( Notify::FORCE_CURRENT_VALUE );
}
Dali::Animation::State Animation::GetState() const
// mAnimation is being used in a separate thread; queue a Stop message
StopAnimationMessage( mEventThreadServices.GetUpdateManager(), *mAnimation );
+
+ // Only notify the objects with the _stopped_, i.e. current values if the end action is set to BAKE
+ if( mEndAction == EndAction::Bake )
+ {
+ NotifyObjects( Notify::USE_CURRENT_VALUE );
+ }
}
void Animation::Clear()
{
DALI_ASSERT_DEBUG(mAnimation);
+ // Only notify the objects with the current values if the end action is set to BAKE
+ if( mEndAction == EndAction::Bake )
+ {
+ NotifyObjects( Notify::USE_CURRENT_VALUE );
+ }
+
// Remove all the connectors
mConnectors.Clear();
return ( ( lhs.timePeriod.delaySeconds + lhs.timePeriod.durationSeconds ) < ( rhs.timePeriod.delaySeconds + rhs.timePeriod.durationSeconds ) );
}
-void Animation::NotifyObjects()
+void Animation::NotifyObjects( Animation::Notify notifyValueType )
{
- if( mEndAction != EndAction::Discard ) // If the animation is discarded, then we do not want to change the target values
+ // If the animation is discarded, then we do not want to change the target values unless we want to force the current values
+ if( mEndAction != EndAction::Discard || notifyValueType == Notify::FORCE_CURRENT_VALUE )
{
// Sort according to end time with earlier end times coming first, if the end time is the same, then the connectors are not moved
- std::stable_sort( mConnectorTargetValues.begin(), mConnectorTargetValues.end(), CompareConnectorEndTimes );
+ // Only do this if we're using the target value
+ if( notifyValueType == Notify::USE_TARGET_VALUE )
+ {
+ std::stable_sort( mConnectorTargetValues.begin(), mConnectorTargetValues.end(), CompareConnectorEndTimes );
+ }
// Loop through all connector target values sorted by increasing end time
ConnectorTargetValuesContainer::const_iterator iter = mConnectorTargetValues.begin();
Object* object = connector->GetObject();
if( object )
{
- object->NotifyPropertyAnimation( *this, connector->GetPropertyIndex(), iter->targetValue, iter->animatorType );
+ const auto propertyIndex = connector->GetPropertyIndex();
+ object->NotifyPropertyAnimation(
+ *this,
+ propertyIndex,
+ ( notifyValueType == Notify::USE_TARGET_VALUE ) ? iter->targetValue : object->GetCurrentProperty( propertyIndex ),
+ iter->animatorType );
}
}
}
Animation::Type animatorType;
};
+ enum class Notify
+ {
+ USE_CURRENT_VALUE, ///< Set the current value for the property
+ USE_TARGET_VALUE, ///< Set the animator's target value for the property
+ FORCE_CURRENT_VALUE, ///< Set the current value for the property even if the end action is to discard
+ };
+
private:
/**
/**
* Notifies all the objects whose properties are being animated.
+ * @param[in] notifyValueType Whether we should set the current or target value
*/
- void NotifyObjects();
+ void NotifyObjects( Notify notifyValueType );
/**
* Sends message to SceneGraph with final progress value
}
}
+bool Scene::EmitKeyEventGeneratedSignal(const KeyEvent& event)
+{
+ // Emit the KeyEventGenerated signal when KeyEvent is generated
+ return mKeyEventGeneratedSignal.Emit( event );
+}
+
void Scene::EmitEventProcessingFinishedSignal()
{
if ( !mEventProcessingFinishedSignal.Empty() )
return mKeyEventSignal;
}
+Integration::Scene::KeyEventGeneratedSignalType& Scene::KeyEventGeneratedSignal()
+{
+ return mKeyEventGeneratedSignal;
+}
+
Integration::Scene::EventProcessingFinishedSignalType& Scene::EventProcessingFinishedSignal()
{
return mEventProcessingFinishedSignal;
void EmitKeyEventSignal(const KeyEvent& event);
/**
+ * Used by the KeyEventProcessor to emit KeyEventGenerated signals.
+ * @param[in] event The key event.
+ * @return The return is true if KeyEvent is consumed, otherwise false.
+ */
+ bool EmitKeyEventGeneratedSignal(const KeyEvent& event);
+
+ /**
* Emits the event processing finished signal.
*
* @see Dali::Scene::SignalEventProcessingFinished()
*/
Integration::Scene::KeyEventSignalType& KeyEventSignal();
+ /**
+ * @copydoc Integration::Scene::KeyEventGeneratedSignal()
+ */
+ Integration::Scene::KeyEventGeneratedSignalType& KeyEventGeneratedSignal();
+
/**
* @copydoc Integration::Scene::SignalEventProcessingFinished()
*/
// The key event signal
Integration::Scene::KeyEventSignalType mKeyEventSignal;
+ Integration::Scene::KeyEventGeneratedSignalType mKeyEventGeneratedSignal;
// The event processing finished signal
Integration::Scene::EventProcessingFinishedSignalType mEventProcessingFinishedSignal;
GetImplementation( &keyEvent )->SetDeviceSubclass( event.deviceSubclass );
// Emit the key event signal from the scene.
- mScene.EmitKeyEventSignal( keyEvent );
+ bool consumed = mScene.EmitKeyEventGeneratedSignal( keyEvent );
+ if( !consumed )
+ {
+ mScene.EmitKeyEventSignal(keyEvent);
+ }
+
}
} // namespace Internal
const uint32_t CORE_MAJOR_VERSION = 1;
const uint32_t CORE_MINOR_VERSION = 4;
-const uint32_t CORE_MICRO_VERSION = 32;
+const uint32_t CORE_MICRO_VERSION = 33;
const char * const CORE_BUILD_DATE = __DATE__ " " __TIME__;
#ifdef DEBUG_ENABLED
Name: dali
Summary: DALi 3D Engine
-Version: 1.4.32
+Version: 1.4.33
Release: 1
Group: System/Libraries
License: Apache-2.0 and BSD-3-Clause and MIT