From: Anton Obzhirov Date: Mon, 17 Sep 2018 12:21:39 +0000 (+0100) Subject: Add Layout complex animation. X-Git-Tag: dali_1.3.47~5 X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git;a=commitdiff_plain;h=4fcbbea5dc1fb7667607f663f04e898f0e4086ae Add Layout complex animation. Change-Id: I34a0fa03030b3e897f418982ea7b54eb8ea0e418 --- diff --git a/CMakeLists.txt b/CMakeLists.txt index 931b3e6..9114e20 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -104,6 +104,7 @@ SET( SOURCES ${SOURCES} ${internal_src_dir}/layouting/layout-group-data-impl.cpp ${internal_src_dir}/layouting/layout-controller-impl.cpp ${internal_src_dir}/layouting/layout-controller-debug.cpp + ${internal_src_dir}/layouting/layout-transition-data-impl.cpp ${internal_src_dir}/visuals/animated-image/animated-image-visual.cpp ${internal_src_dir}/visuals/animated-image/image-cache.cpp ${internal_src_dir}/visuals/animated-image/fixed-image-cache.cpp diff --git a/automated-tests/src/dali-toolkit/CMakeLists.txt b/automated-tests/src/dali-toolkit/CMakeLists.txt index 369f9b0..6f1b55f 100755 --- a/automated-tests/src/dali-toolkit/CMakeLists.txt +++ b/automated-tests/src/dali-toolkit/CMakeLists.txt @@ -27,6 +27,7 @@ SET(TC_SOURCES utc-Dali-JsonParser.cpp utc-Dali-KeyInputFocusManager.cpp utc-Dali-Layouting.cpp + utc-Dali-LayoutingAnimation.cpp utc-Dali-LayoutingResizePolicy.cpp utc-Dali-LayoutingNesting.cpp utc-Dali-PageTurnView.cpp diff --git a/automated-tests/src/dali-toolkit/utc-Dali-LayoutingAnimation.cpp b/automated-tests/src/dali-toolkit/utc-Dali-LayoutingAnimation.cpp new file mode 100644 index 0000000..ead839d --- /dev/null +++ b/automated-tests/src/dali-toolkit/utc-Dali-LayoutingAnimation.cpp @@ -0,0 +1,1211 @@ +/* + * Copyright (c) 2018 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. + * + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include <../custom-layout.h> + +#include + +using namespace Dali; +using namespace Toolkit; + +void utc_dali_toolkit_layouting_animation_startup(void) +{ + test_return_value = TET_UNDEF; +} + +void utc_dali_toolkit_layouting_animation_cleanup(void) +{ + test_return_value = TET_PASS; +} + +namespace +{ + +// Functor to test whether a Finish signal is emitted +struct LayoutTransitionFinishCheck +{ + LayoutTransitionFinishCheck( bool& signalReceived ) + : mSignalReceived( signalReceived ) + { + } + + void operator()( LayoutTransitionData::LayoutTransitionType type, LayoutTransitionData& layoutTransitionData ) + { + mSignalReceived = true; + } + + void Reset() + { + mSignalReceived = false; + } + + void CheckSignalReceived() + { + if (!mSignalReceived) + { + tet_printf("Expected Finish signal was not received\n"); + tet_result(TET_FAIL); + } + else + { + tet_result(TET_PASS); + } + } + + void CheckSignalNotReceived() + { + if (mSignalReceived) + { + tet_printf("Unexpected Finish signal was received\n"); + tet_result(TET_FAIL); + } + else + { + tet_result(TET_PASS); + } + } + + bool& mSignalReceived; // owned by individual tests +}; + +} // anon namespace + +int UtcDaliLayouting_LayoutTransitionDataConstructorP(void) +{ + TestApplication application; + + LayoutTransitionData layoutTransitionData; + + DALI_TEST_CHECK( !layoutTransitionData ); + END_TEST; +} + +int UtcDaliLayouting_LayoutTransitionDataNewP(void) +{ + TestApplication application; + + LayoutTransitionData layoutTransitionData = LayoutTransitionData::New(); + + DALI_TEST_CHECK(layoutTransitionData); + END_TEST; +} + +int UtcDaliLayouting_LayoutTransitionDataDownCastP(void) +{ + TestApplication application; + + LayoutTransitionData layoutTransitionData = LayoutTransitionData::New(); + BaseHandle object(layoutTransitionData); + + LayoutTransitionData layoutTransitionData2 = LayoutTransitionData::DownCast(object); + DALI_TEST_CHECK(layoutTransitionData2); + + LayoutTransitionData layoutTransitionData3 = DownCast< LayoutTransitionData >(object); + DALI_TEST_CHECK(layoutTransitionData2); + END_TEST; +} + +int UtcDaliLayouting_LayoutTransitionDataDownCastN(void) +{ + TestApplication application; + + BaseHandle unInitializedObject; + + LayoutTransitionData layoutTransitionData1 = LayoutTransitionData::DownCast( unInitializedObject ); + DALI_TEST_CHECK( !layoutTransitionData1 ); + + LayoutTransitionData layoutTransitionData2 = DownCast< LayoutTransitionData >( unInitializedObject ); + DALI_TEST_CHECK( !layoutTransitionData2 ); + END_TEST; +} + +int UtcDaliLayouting_LayoutTransitionDataSetGetTransition(void) +{ + TestApplication application; + + auto layout = LinearLayout::New(); + auto layoutTransitionData = LayoutTransitionData::New(); + + layout.SetTransitionData( LayoutTransitionData::ON_OWNER_SET, layoutTransitionData ); + DALI_TEST_CHECK( layout.GetTransitionData( LayoutTransitionData::ON_OWNER_SET ) == layoutTransitionData ); + DALI_TEST_CHECK( layout.GetTransitionData( LayoutTransitionData::ON_CHILD_ADD ) == LayoutTransitionData() ); + DALI_TEST_CHECK( layout.GetTransitionData( LayoutTransitionData::ON_CHILD_REMOVE ) == LayoutTransitionData() ); + + layout.SetTransitionData( LayoutTransitionData::ON_OWNER_SET, LayoutTransitionData() ); + layout.SetTransitionData( LayoutTransitionData::ON_CHILD_ADD, layoutTransitionData ); + DALI_TEST_CHECK( layout.GetTransitionData( LayoutTransitionData::ON_OWNER_SET ) == LayoutTransitionData() ); + DALI_TEST_CHECK( layout.GetTransitionData( LayoutTransitionData::ON_CHILD_ADD ) == layoutTransitionData ); + DALI_TEST_CHECK( layout.GetTransitionData( LayoutTransitionData::ON_CHILD_REMOVE ) == LayoutTransitionData() ); + + layout.SetTransitionData( LayoutTransitionData::ON_CHILD_ADD, LayoutTransitionData() ); + layout.SetTransitionData( LayoutTransitionData::ON_CHILD_REMOVE, layoutTransitionData ); + DALI_TEST_CHECK( layout.GetTransitionData( LayoutTransitionData::ON_OWNER_SET ) == LayoutTransitionData() ); + DALI_TEST_CHECK( layout.GetTransitionData( LayoutTransitionData::ON_CHILD_ADD ) == LayoutTransitionData() ); + DALI_TEST_CHECK( layout.GetTransitionData( LayoutTransitionData::ON_CHILD_REMOVE ) == layoutTransitionData ); + + END_TEST; +} + +int UtcDaliLayouting_SetLayoutTransition01(void) +{ + ToolkitTestApplication application; + tet_infoline(" UtcDaliLayouting_SetLayoutTransition01"); + + Stage stage = Stage::GetCurrent(); + auto container = Control::New(); + auto horizontalLayout = LinearLayout::New(); + horizontalLayout.SetAnimateLayout( true ); + horizontalLayout.SetOrientation( LinearLayout::Orientation::HORIZONTAL ); + + auto verticalLayout = LinearLayout::New(); + verticalLayout.SetAnimateLayout( true ); + verticalLayout.SetOrientation( LinearLayout::Orientation::VERTICAL ); + + DevelControl::SetLayout( container, horizontalLayout ); + container.SetName( "Container"); + + std::vector< Control > controls; + controls.push_back( CreateLeafControl( 100, 100 ) ); + controls.push_back( CreateLeafControl( 100, 100 ) ); + for( auto&& iter : controls ) + { + container.Add( iter ); + } + + container.SetParentOrigin( ParentOrigin::CENTER ); + container.SetAnchorPoint( AnchorPoint::CENTER ); + stage.Add( container ); + + auto layoutTransitionData = LayoutTransitionData::New(); + { + // Instant resize for parent + Property::Map map; + map["property"] = "size"; + map["targetValue"] = Property::Value(); // capture from layout update + map["animator"] = Property::Map() + .Add("alphaFunction", "LINEAR") + .Add("timePeriod", Property::Map() + .Add("delay", 0.0f) + .Add("duration", 0.0f)); + layoutTransitionData.AddPropertyAnimator( container, map ); + } + { + Property::Map map; + map["property"] = "opacity"; + map["initialValue"] = 0.0f; + map["targetValue"] = 1.0f; + map["animator"] = Property::Map() + .Add("alphaFunction", "LINEAR") + .Add("timePeriod", Property::Map() + .Add("delay", 0.0f) + .Add("duration", 0.5f)); + layoutTransitionData.AddPropertyAnimator( container, map ); + } + { + // Instant position for children + Property::Map map; + map["property"] = "position"; + map["animator"] = Property::Map() + .Add("alphaFunction", "LINEAR") + .Add("timePeriod", Property::Map() + .Add("delay", 0.0f) + .Add("duration", 0.0f)); + layoutTransitionData.AddPropertyAnimator( Actor(), map ); // apply to all children except parent + } + { + // Grow children from (0,0) size to full size (captured) + Property::Map map; + map["property"] = "size"; + map["initialValue"] = Vector3( 0.0f, 0.0f, 0 ); + map["animator"] = Property::Map() + .Add("alphaFunction", "LINEAR") + .Add("timePeriod", Property::Map() + .Add("delay", 0.0f) + .Add("duration", 0.5f)); + layoutTransitionData.AddPropertyAnimator( Actor(), map ); + } + + // Ensure layouting happens + application.SendNotification(); + application.Render(); + + // First round, no animation + // TODO: container size (0, 0) after it is added to the stage should be fixed with HQ patch soon + DALI_TEST_EQUALS( container.GetProperty( Actor::Property::POSITION ), Vector3( 0.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[0].GetProperty( Actor::Property::POSITION ), Vector3( 0.0f, 350.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[1].GetProperty( Actor::Property::POSITION ), Vector3( 100.0f, 350.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + DALI_TEST_EQUALS( container.GetProperty( Actor::Property::SIZE ), Vector3( 0.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[0].GetProperty( Actor::Property::SIZE ), Vector3( 100.0f, 100.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[1].GetProperty( Actor::Property::SIZE ), Vector3( 100.0f, 100.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + bool signalReceived(false); + LayoutTransitionFinishCheck finishCheck(signalReceived); + layoutTransitionData.FinishedSignal().Connect(&application, finishCheck); + + // Change a layout, start transition + verticalLayout.SetTransitionData( LayoutTransitionData::ON_OWNER_SET, layoutTransitionData ); + DevelControl::SetLayout( container, verticalLayout ); + + application.SendNotification(); + application.Render( 1u /*just very beginning of the animation*/ ); + + finishCheck.CheckSignalNotReceived(); + // Second round, animation just started + DALI_TEST_EQUALS( container.GetCurrentPosition(), Vector3( 0.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( container.GetCurrentOpacity(), 0.0f, 0.1f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[0].GetCurrentPosition(), Vector3( 0.0f, 300.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[1].GetCurrentPosition(), Vector3( 0.0f, 400.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + DALI_TEST_EQUALS( container.GetCurrentSize(), Vector3( 480.0f, 800.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[0].GetCurrentSize(), Vector3( 0.0f, 0.0f, 0.0f ), 1.0f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[1].GetCurrentSize(), Vector3( 0.0f, 0.0f, 0.0f ), 1.0f, TEST_LOCATION ); + + application.SendNotification(); + application.Render(static_cast( 0.5f * 1000.0f ) + 1u /*just after the end of the animation*/ ); + + // Third round, animation just finished + DALI_TEST_EQUALS( container.GetCurrentPosition(), Vector3( 0.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( container.GetCurrentOpacity(), 1.0f, 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[0].GetCurrentPosition(), Vector3( 0.0f, 300.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[1].GetCurrentPosition(), Vector3( 0.0f, 400.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + DALI_TEST_EQUALS( container.GetCurrentSize(), Vector3( 480.0f, 800.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[0].GetCurrentSize(), Vector3( 100.0f, 100.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[1].GetCurrentSize(), Vector3( 100.0f, 100.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + application.SendNotification(); + application.Render( 10u /* wait a bit more for a signal */ ); + + finishCheck.CheckSignalReceived(); + + // Now sizes and positions are finally set + DALI_TEST_EQUALS( container.GetProperty( Actor::Property::POSITION ), Vector3( 0.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[0].GetProperty( Actor::Property::POSITION ), Vector3( 0.0f, 300.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[1].GetProperty( Actor::Property::POSITION ), Vector3( 0.0f, 400.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + DALI_TEST_EQUALS( container.GetProperty( Actor::Property::SIZE ), Vector3( 480.0f, 800.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[0].GetProperty( Actor::Property::SIZE ), Vector3( 100.0f, 100.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[1].GetProperty( Actor::Property::SIZE ), Vector3( 100.0f, 100.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + // Transition back now with default transition + DevelControl::SetLayout( container, horizontalLayout ); + + application.SendNotification(); + application.Render( 1u /*just very beginning of the animation*/ ); + + DALI_TEST_EQUALS( container.GetCurrentPosition(), Vector3( 0.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( container.GetCurrentOpacity(), 1.0f, 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[0].GetCurrentPosition(), Vector3( 0.0f, 300.0f, 0.0f ), 1.0f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[1].GetCurrentPosition(), Vector3( 0.0f, 400.0f, 0.0f ), 1.0f, TEST_LOCATION ); + + DALI_TEST_EQUALS( container.GetCurrentSize(), Vector3( 480.0f, 800.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[0].GetCurrentSize(), Vector3( 100.0f, 100.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[1].GetCurrentSize(), Vector3( 100.0f, 100.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + application.SendNotification(); + application.Render(static_cast( 0.5f * 1000.0f ) + 1u /*just after the end of the animation*/ ); + + DALI_TEST_EQUALS( container.GetCurrentPosition(), Vector3( 0.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( container.GetCurrentOpacity(), 1.0f, 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[0].GetCurrentPosition(), Vector3( 0.0f, 350.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[1].GetCurrentPosition(), Vector3( 100.0f, 350.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + DALI_TEST_EQUALS( container.GetCurrentSize(), Vector3( 480.0f, 800.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[0].GetCurrentSize(), Vector3( 100.0f, 100.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[1].GetCurrentSize(), Vector3( 100.0f, 100.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + application.SendNotification(); + application.Render( 10u /* wait a bit more for complete default animation */ ); + + // Now sizes and positions are finally set + DALI_TEST_EQUALS( container.GetProperty( Actor::Property::POSITION ), Vector3( 0.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[0].GetProperty( Actor::Property::POSITION ), Vector3( 0.0f, 350.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[1].GetProperty( Actor::Property::POSITION ), Vector3( 100.0f, 350.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + DALI_TEST_EQUALS( container.GetProperty( Actor::Property::SIZE ), Vector3( 480.0f, 800.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[0].GetProperty( Actor::Property::SIZE ), Vector3( 100.0f, 100.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[1].GetProperty( Actor::Property::SIZE ), Vector3( 100.0f, 100.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + END_TEST; +} + +int UtcDaliLayouting_AddChildLayoutTransition01(void) +{ + ToolkitTestApplication application; + tet_infoline(" UtcDaliLayouting_AddChildLayoutTransition01"); + + Stage stage = Stage::GetCurrent(); + auto container = Control::New(); + auto horizontalLayout = LinearLayout::New(); + horizontalLayout.SetAnimateLayout( true ); + horizontalLayout.SetOrientation( LinearLayout::Orientation::HORIZONTAL ); + + DevelControl::SetLayout( container, horizontalLayout ); + container.SetName( "Container"); + + std::vector< Control > controls; + controls.push_back( CreateLeafControl( 100, 100 ) ); + container.SetParentOrigin( ParentOrigin::CENTER ); + container.SetAnchorPoint( AnchorPoint::CENTER ); + stage.Add( container ); + + auto layoutTransitionData = LayoutTransitionData::New(); + { + // Instant resize for parent + Property::Map map; + map[ LayoutTransitionData::AnimatorKey::PROPERTY ] = "size"; + map[ LayoutTransitionData::AnimatorKey::TARGET_VALUE ] = Property::Value(); // capture from layout update + map[ LayoutTransitionData::AnimatorKey::ANIMATOR ] = Property::Map() + .Add( LayoutTransitionData::AnimatorKey::ALPHA_FUNCTION, "LINEAR" ) + .Add( LayoutTransitionData::AnimatorKey::TIME_PERIOD, Property::Map() + .Add( LayoutTransitionData::AnimatorKey::DELAY, 0.0f ) + .Add( LayoutTransitionData::AnimatorKey::DURATION, 0.0f ) ); + layoutTransitionData.AddPropertyAnimator( container, map ); + } + { + // Instant position for a child + Property::Map map; + map[ LayoutTransitionData::AnimatorKey::PROPERTY ] = "position"; + map[ LayoutTransitionData::AnimatorKey::ANIMATOR ] = Property::Map() + .Add( LayoutTransitionData::AnimatorKey::ALPHA_FUNCTION, "LINEAR") + .Add( LayoutTransitionData::AnimatorKey::TIME_PERIOD, Property::Map() + .Add( LayoutTransitionData::AnimatorKey::DELAY, 0.0f ) + .Add( LayoutTransitionData::AnimatorKey::DURATION, 0.0f ) ); + layoutTransitionData.AddPropertyAnimator( Actor(), map ); // apply to all children except parent + } + { + // Grow a child from (0,0) size to full size (captured) + Property::Map map; + map[ LayoutTransitionData::AnimatorKey::PROPERTY ] = "size"; + map[ LayoutTransitionData::AnimatorKey::INITIAL_VALUE ] = Vector3( 0.0f, 0.0f, 0 ); + map[ LayoutTransitionData::AnimatorKey::ANIMATOR ] = Property::Map() + .Add( LayoutTransitionData::AnimatorKey::ALPHA_FUNCTION, "LINEAR") + .Add( LayoutTransitionData::AnimatorKey::TIME_PERIOD, Property::Map() + .Add( LayoutTransitionData::AnimatorKey::DELAY, 0.0f) + .Add( LayoutTransitionData::AnimatorKey::DURATION, 0.5f)); + layoutTransitionData.AddPropertyAnimator( controls[0], map ); + } + + horizontalLayout.SetTransitionData( LayoutTransitionData::ON_CHILD_ADD, layoutTransitionData ); + container.Add( controls[0] ); + + bool signalReceived(false); + LayoutTransitionFinishCheck finishCheck(signalReceived); + layoutTransitionData.FinishedSignal().Connect(&application, finishCheck); + + application.SendNotification(); + application.Render( 1u /*just very beginning of the animation*/ ); + + finishCheck.CheckSignalNotReceived(); + // The animation just started + DALI_TEST_EQUALS( container.GetCurrentPosition(), Vector3( 0.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[0].GetCurrentPosition(), Vector3( 0.0f, 350.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + application.SendNotification(); + application.Render(static_cast( 0.5f * 1000.0f ) + 1u /*just after the end of the animation*/ ); + + // The animation just finished + DALI_TEST_EQUALS( container.GetCurrentPosition(), Vector3( 0.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[0].GetCurrentPosition(), Vector3( 0.0f, 350.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + DALI_TEST_EQUALS( container.GetCurrentSize(), Vector3( 480.0f, 800.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[0].GetCurrentSize(), Vector3( 100.0f, 100.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + application.SendNotification(); + application.Render( 10u /* wait a bit more for a signal */ ); + + // Now sizes and positions are finally set + DALI_TEST_EQUALS( container.GetProperty( Actor::Property::POSITION ), Vector3( 0.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[0].GetProperty( Actor::Property::POSITION ), Vector3( 0.0f, 350.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + DALI_TEST_EQUALS( container.GetProperty( Actor::Property::SIZE ), Vector3( 480.0f, 800.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[0].GetProperty( Actor::Property::SIZE ), Vector3( 100.0f, 100.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + finishCheck.CheckSignalReceived(); + + END_TEST; +} + +int UtcDaliLayouting_RemoveChildLayoutTransition01(void) +{ + ToolkitTestApplication application; + tet_infoline(" UtcDaliLayouting_RemoveChildLayoutTransition01"); + + Stage stage = Stage::GetCurrent(); + auto container = Control::New(); + auto horizontalLayout = LinearLayout::New(); + horizontalLayout.SetAnimateLayout( true ); + horizontalLayout.SetOrientation( LinearLayout::Orientation::HORIZONTAL ); + + DevelControl::SetLayout( container, horizontalLayout ); + container.SetName( "Container"); + + std::vector< Control > controls; + controls.push_back( CreateLeafControl( 100, 100 ) ); + controls.push_back( CreateLeafControl( 100, 100 ) ); + container.SetParentOrigin( ParentOrigin::CENTER ); + container.SetAnchorPoint( AnchorPoint::CENTER ); + stage.Add( container ); + container.Add( controls[0] ); + container.Add( controls[1] ); + + // Initial rendering done + application.SendNotification(); + application.Render(); + + auto layoutTransitionData = LayoutTransitionData::New(); + { + // Instant resize for parent width + Property::Map map; + map[ LayoutTransitionData::AnimatorKey::PROPERTY ] = Actor::Property::SIZE_WIDTH; + map[ LayoutTransitionData::AnimatorKey::TARGET_VALUE ] = Property::Value(); // capture from layout update + map[ LayoutTransitionData::AnimatorKey::ANIMATOR ] = Property::Map() + .Add( LayoutTransitionData::AnimatorKey::TYPE, "ANIMATE_TO" ) + .Add( LayoutTransitionData::AnimatorKey::ALPHA_FUNCTION, "LINEAR" ) + .Add( LayoutTransitionData::AnimatorKey::TIME_PERIOD, Property::Map() + .Add( LayoutTransitionData::AnimatorKey::DELAY, 0.0f ) + .Add( LayoutTransitionData::AnimatorKey::DURATION, 0.0f ) ); + layoutTransitionData.AddPropertyAnimator( container, map ); + } + { + // Instant resize for parent height + Property::Map map; + map[ LayoutTransitionData::AnimatorKey::PROPERTY ] = Actor::Property::SIZE_HEIGHT; + map[ LayoutTransitionData::AnimatorKey::TARGET_VALUE ] = Property::Value(); // capture from layout update + map[ LayoutTransitionData::AnimatorKey::ANIMATOR ] = Property::Map() + .Add( LayoutTransitionData::AnimatorKey::TYPE, "ANIMATE_TO" ) + .Add( LayoutTransitionData::AnimatorKey::ALPHA_FUNCTION, "LINEAR" ) + .Add( LayoutTransitionData::AnimatorKey::TIME_PERIOD, Property::Map() + .Add( LayoutTransitionData::AnimatorKey::DELAY, 0.0f ) + .Add( LayoutTransitionData::AnimatorKey::DURATION, 0.0f ) ); + layoutTransitionData.AddPropertyAnimator( container, map ); + } + { + // Instant position for parent X position + Property::Map map; + map[ LayoutTransitionData::AnimatorKey::PROPERTY ] = Actor::Property::POSITION_X; + map[ LayoutTransitionData::AnimatorKey::TARGET_VALUE ] = Property::Value(); // capture from layout update + map[ LayoutTransitionData::AnimatorKey::ANIMATOR ] = Property::Map() + .Add( LayoutTransitionData::AnimatorKey::TYPE, "ANIMATE_TO" ) + .Add( LayoutTransitionData::AnimatorKey::ALPHA_FUNCTION, "LINEAR" ) + .Add( LayoutTransitionData::AnimatorKey::TIME_PERIOD, Property::Map() + .Add( LayoutTransitionData::AnimatorKey::DELAY, 0.0f ) + .Add( LayoutTransitionData::AnimatorKey::DURATION, 0.0f ) ); + layoutTransitionData.AddPropertyAnimator( container, map ); + } + { + // Instant position for parent Y position + Property::Map map; + map[ LayoutTransitionData::AnimatorKey::PROPERTY ] = Actor::Property::POSITION_Y; + map[ LayoutTransitionData::AnimatorKey::TARGET_VALUE ] = Property::Value(); // capture from layout update + map[ LayoutTransitionData::AnimatorKey::ANIMATOR ] = Property::Map() + .Add( LayoutTransitionData::AnimatorKey::TYPE, "ANIMATE_TO" ) + .Add( LayoutTransitionData::AnimatorKey::ALPHA_FUNCTION, "LINEAR" ) + .Add( LayoutTransitionData::AnimatorKey::TIME_PERIOD, Property::Map() + .Add( LayoutTransitionData::AnimatorKey::DELAY, 0.0f ) + .Add( LayoutTransitionData::AnimatorKey::DURATION, 0.0f ) ); + layoutTransitionData.AddPropertyAnimator( container, map ); + } + { + // Shrink the children + Property::Map map; + map[ LayoutTransitionData::AnimatorKey::PROPERTY ] = Actor::Property::SIZE_WIDTH; + map[ LayoutTransitionData::AnimatorKey::TARGET_VALUE ] = 0.0f; + map[ LayoutTransitionData::AnimatorKey::ANIMATOR ] = Property::Map() + .Add( LayoutTransitionData::AnimatorKey::TYPE, "ANIMATE_TO" ) + .Add( LayoutTransitionData::AnimatorKey::ALPHA_FUNCTION, "LINEAR") + .Add( LayoutTransitionData::AnimatorKey::TIME_PERIOD, Property::Map() + .Add( LayoutTransitionData::AnimatorKey::DELAY, 0.0f) + .Add( LayoutTransitionData::AnimatorKey::DURATION, 0.5f)); + layoutTransitionData.AddPropertyAnimator( Actor(), map ); + } + { + // Shrink the children + Property::Map map; + map[ LayoutTransitionData::AnimatorKey::PROPERTY ] = Actor::Property::SIZE_HEIGHT; + map[ LayoutTransitionData::AnimatorKey::TARGET_VALUE ] = 0.0f; + map[ LayoutTransitionData::AnimatorKey::ANIMATOR ] = Property::Map() + .Add( LayoutTransitionData::AnimatorKey::TYPE, "ANIMATE_TO" ) + .Add( LayoutTransitionData::AnimatorKey::ALPHA_FUNCTION, "LINEAR") + .Add( LayoutTransitionData::AnimatorKey::TIME_PERIOD, Property::Map() + .Add( LayoutTransitionData::AnimatorKey::DELAY, 0.0f) + .Add( LayoutTransitionData::AnimatorKey::DURATION, 0.5f)); + layoutTransitionData.AddPropertyAnimator( Actor(), map ); + } + { + // Instant position for a child + Property::Map map; + map[ LayoutTransitionData::AnimatorKey::PROPERTY ] = Actor::Property::POSITION_X; + map[ LayoutTransitionData::AnimatorKey::ANIMATOR ] = Property::Map() + .Add( LayoutTransitionData::AnimatorKey::TYPE, "ANIMATE_TO" ) + .Add( LayoutTransitionData::AnimatorKey::ALPHA_FUNCTION, "LINEAR") + .Add( LayoutTransitionData::AnimatorKey::TIME_PERIOD, Property::Map() + .Add( LayoutTransitionData::AnimatorKey::DELAY, 0.0f ) + .Add( LayoutTransitionData::AnimatorKey::DURATION, 0.0f ) ); + layoutTransitionData.AddPropertyAnimator( Actor(), map ); // apply to all children except parent + } + { + // Instant position for a child + Property::Map map; + map[ LayoutTransitionData::AnimatorKey::PROPERTY ] = Actor::Property::POSITION_Y; + map[ LayoutTransitionData::AnimatorKey::ANIMATOR ] = Property::Map() + .Add( LayoutTransitionData::AnimatorKey::TYPE, "ANIMATE_TO" ) + .Add( LayoutTransitionData::AnimatorKey::ALPHA_FUNCTION, "LINEAR") + .Add( LayoutTransitionData::AnimatorKey::TIME_PERIOD, Property::Map() + .Add( LayoutTransitionData::AnimatorKey::DELAY, 0.0f ) + .Add( LayoutTransitionData::AnimatorKey::DURATION, 0.0f ) ); + layoutTransitionData.AddPropertyAnimator( Actor(), map ); // apply to all children except parent + } + + horizontalLayout.SetTransitionData( LayoutTransitionData::ON_CHILD_REMOVE, layoutTransitionData ); + container.Remove( controls[1] ); + + bool signalReceived(false); + LayoutTransitionFinishCheck finishCheck(signalReceived); + layoutTransitionData.FinishedSignal().Connect(&application, finishCheck); + + application.SendNotification(); + application.Render( 1u /*just very beginning of the animation*/ ); + + finishCheck.CheckSignalNotReceived(); + // Animation just started + DALI_TEST_EQUALS( container.GetCurrentPosition(), Vector3( 0.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[0].GetCurrentPosition(), Vector3( 0.0f, 350.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[1].GetCurrentPosition(), Vector3( 100.0f, 350.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + DALI_TEST_EQUALS( container.GetCurrentSize(), Vector3( 480.0f, 800.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[0].GetCurrentSize(), Vector3( 0.0f, 0.0f, 0.0f ), 1.0f, TEST_LOCATION ); + // this control is already removed from the tree. + DALI_TEST_EQUALS( controls[1].GetCurrentSize(), Vector3( 100.0f, 100.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + application.SendNotification(); + application.Render(static_cast( 0.5f * 1000.0f ) + 1u /*just after the end of the animation*/ ); + + // Animation just finished + DALI_TEST_EQUALS( container.GetCurrentPosition(), Vector3( 0.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[0].GetCurrentPosition(), Vector3( 0.0f, 350.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + // this control is already removed from the tree. + DALI_TEST_EQUALS( controls[1].GetCurrentPosition(), Vector3( 100.0f, 350.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + DALI_TEST_EQUALS( container.GetCurrentSize(), Vector3( 480.0f, 800.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[0].GetCurrentSize(), Vector3( 0.0f, 0.0f, 0.0f ), 1.0f, TEST_LOCATION ); + // this control is already removed from the tree. + DALI_TEST_EQUALS( controls[1].GetCurrentSize(), Vector3( 100.0f, 100.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + application.SendNotification(); + application.Render( 10u /* wait a bit more for a signal */ ); + + // Now sizes and positions are finally set + DALI_TEST_EQUALS( container.GetProperty( Actor::Property::POSITION ), Vector3( 0.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[0].GetProperty( Actor::Property::POSITION ), Vector3( 0.0f, 350.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + // this control is already removed from the tree. + DALI_TEST_EQUALS( controls[1].GetProperty( Actor::Property::POSITION ), Vector3( 100.0f, 350.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + DALI_TEST_EQUALS( container.GetProperty( Actor::Property::SIZE ), Vector3( 480.0f, 800.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[0].GetProperty( Actor::Property::SIZE ), Vector3( 100.0f, 100.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + // this control is already removed from the tree. + DALI_TEST_EQUALS( controls[1].GetProperty( Actor::Property::SIZE ), Vector3( 100.0f, 100.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + finishCheck.CheckSignalReceived(); + + END_TEST; +} + +int UtcDaliLayouting_AddChildLayoutTransition02_KeyFrames(void) +{ + ToolkitTestApplication application; + tet_infoline(" UtcDaliLayouting_AddChildLayoutTransition02_KeyFrames"); + + Stage stage = Stage::GetCurrent(); + auto container = Control::New(); + auto horizontalLayout = LinearLayout::New(); + horizontalLayout.SetAnimateLayout( true ); + horizontalLayout.SetOrientation( LinearLayout::Orientation::HORIZONTAL ); + + DevelControl::SetLayout( container, horizontalLayout ); + container.SetName( "Container"); + + std::vector< Control > controls; + controls.push_back( CreateLeafControl( 100, 100 ) ); + container.SetParentOrigin( ParentOrigin::CENTER ); + container.SetAnchorPoint( AnchorPoint::CENTER ); + stage.Add( container ); + + auto layoutTransitionData = LayoutTransitionData::New(); + { + // Instant resize for parent + Property::Map map; + map[ LayoutTransitionData::AnimatorKey::PROPERTY ] = Actor::Property::SIZE; + map[ LayoutTransitionData::AnimatorKey::TARGET_VALUE ] = Property::Value(); // capture from layout update + map[ LayoutTransitionData::AnimatorKey::ANIMATOR ] = Property::Map() + .Add( LayoutTransitionData::AnimatorKey::ALPHA_FUNCTION, "LINEAR" ) + .Add( LayoutTransitionData::AnimatorKey::TIME_PERIOD, Property::Map() + .Add( LayoutTransitionData::AnimatorKey::DELAY, 0.0f ) + .Add( LayoutTransitionData::AnimatorKey::DURATION, 0.0f ) ); + layoutTransitionData.AddPropertyAnimator( container, map ); + } + { + // Instant position for a child + Property::Map map; + map[ LayoutTransitionData::AnimatorKey::PROPERTY ] = Actor::Property::POSITION; + map[ LayoutTransitionData::AnimatorKey::ANIMATOR ] = Property::Map() + .Add( LayoutTransitionData::AnimatorKey::ALPHA_FUNCTION, "LINEAR") + .Add( LayoutTransitionData::AnimatorKey::TIME_PERIOD, Property::Map() + .Add( LayoutTransitionData::AnimatorKey::DELAY, 0.0f ) + .Add( LayoutTransitionData::AnimatorKey::DURATION, 0.0f ) ); + layoutTransitionData.AddPropertyAnimator( Actor(), map ); // apply to all children except parent + } + { + // Grow a child from (0,0) size to full size with key frames + KeyFrames keyFrames = KeyFrames::New(); + keyFrames.Add( 0.0f, Vector3( 0.0f, 0.0f, 0 ) ); + keyFrames.Add( 0.5f, Vector3( 100.0f, 100.0f, 0 ) ); + + Property::Map map; + map[ LayoutTransitionData::AnimatorKey::PROPERTY ] = Actor::Property::SIZE; + map[ LayoutTransitionData::AnimatorKey::ANIMATOR ] = Property::Map() + .Add( LayoutTransitionData::AnimatorKey::TYPE, "ANIMATE_BETWEEN") + .Add( LayoutTransitionData::AnimatorKey::ALPHA_FUNCTION, "LINEAR") + .Add( LayoutTransitionData::AnimatorKey::TIME_PERIOD, Property::Map() + .Add( LayoutTransitionData::AnimatorKey::DELAY, 0.0f) + .Add( LayoutTransitionData::AnimatorKey::DURATION, 0.5f)); + layoutTransitionData.AddPropertyAnimator( controls[0], map, keyFrames, Animation::Interpolation::Linear ); + } + + horizontalLayout.SetTransitionData( LayoutTransitionData::ON_CHILD_ADD, layoutTransitionData ); + container.Add( controls[0] ); + + bool signalReceived(false); + LayoutTransitionFinishCheck finishCheck(signalReceived); + layoutTransitionData.FinishedSignal().Connect(&application, finishCheck); + + application.SendNotification(); + application.Render( 1u /*just very beginning of the animation*/ ); + + finishCheck.CheckSignalNotReceived(); + // The animation just started + DALI_TEST_EQUALS( container.GetCurrentPosition(), Vector3( 0.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[0].GetCurrentPosition(), Vector3( 0.0f, 350.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + application.SendNotification(); + application.Render(static_cast( 0.5f * 1000.0f ) + 1u /*just after the end of the animation*/ ); + + // The animation just finished + DALI_TEST_EQUALS( container.GetCurrentPosition(), Vector3( 0.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[0].GetCurrentPosition(), Vector3( 0.0f, 350.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + DALI_TEST_EQUALS( container.GetCurrentSize(), Vector3( 480.0f, 800.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[0].GetCurrentSize(), Vector3( 100.0f, 100.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + application.SendNotification(); + application.Render( 10u /* wait a bit more for a signal */ ); + + // Now sizes and positions are finally set + DALI_TEST_EQUALS( container.GetProperty( Actor::Property::POSITION ), Vector3( 0.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[0].GetProperty( Actor::Property::POSITION ), Vector3( 0.0f, 350.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + DALI_TEST_EQUALS( container.GetProperty( Actor::Property::SIZE ), Vector3( 480.0f, 800.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[0].GetProperty( Actor::Property::SIZE ), Vector3( 100.0f, 100.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + finishCheck.CheckSignalReceived(); + + END_TEST; +} + +int UtcDaliLayouting_AddChildLayoutTransition03_Path(void) +{ + ToolkitTestApplication application; + tet_infoline(" UtcDaliLayouting_AddChildLayoutTransition03_Path"); + + Stage stage = Stage::GetCurrent(); + auto container = Control::New(); + auto horizontalLayout = LinearLayout::New(); + horizontalLayout.SetAnimateLayout( true ); + horizontalLayout.SetOrientation( LinearLayout::Orientation::HORIZONTAL ); + + DevelControl::SetLayout( container, horizontalLayout ); + container.SetName( "Container"); + + std::vector< Control > controls; + controls.push_back( CreateLeafControl( 100, 100 ) ); + container.SetParentOrigin( ParentOrigin::CENTER ); + container.SetAnchorPoint( AnchorPoint::CENTER ); + stage.Add( container ); + + auto layoutTransitionData = LayoutTransitionData::New(); + { + // Instant resize for parent + Property::Map map; + map[ LayoutTransitionData::AnimatorKey::PROPERTY ] = Actor::Property::SIZE; + map[ LayoutTransitionData::AnimatorKey::TARGET_VALUE ] = Property::Value(); // capture from layout update + map[ LayoutTransitionData::AnimatorKey::ANIMATOR ] = Property::Map() + .Add( LayoutTransitionData::AnimatorKey::ALPHA_FUNCTION, "LINEAR" ) + .Add( LayoutTransitionData::AnimatorKey::TIME_PERIOD, Property::Map() + .Add( LayoutTransitionData::AnimatorKey::DELAY, 0.0f ) + .Add( LayoutTransitionData::AnimatorKey::DURATION, 0.0f ) ); + layoutTransitionData.AddPropertyAnimator( container, map ); + } + + Dali::Path path = Dali::Path::New(); + { + // Curve position for a child + Property::Map map; + map[ LayoutTransitionData::AnimatorKey::PROPERTY ] = Actor::Property::POSITION; + map[ LayoutTransitionData::AnimatorKey::ANIMATOR ] = Property::Map() + .Add( LayoutTransitionData::AnimatorKey::TYPE, "ANIMATE_PATH") + .Add( LayoutTransitionData::AnimatorKey::ALPHA_FUNCTION, "LINEAR") + .Add( LayoutTransitionData::AnimatorKey::TIME_PERIOD, Property::Map() + .Add( LayoutTransitionData::AnimatorKey::DELAY, 0.0f ) + .Add( LayoutTransitionData::AnimatorKey::DURATION, 0.5f ) ); + + // Build the path + Vector3 position0( 30.0, 80.0, 0.0 ); + Vector3 position1( 70.0, 120.0, 0.0 ); + Vector3 position2( 0.0, 350.0, 0.0 ); + + //Dali::Path path = Dali::Path::New(); + path.AddPoint( position0 ); + path.AddPoint( position1 ); + path.AddPoint( position2 ); + + // Control points for first segment + path.AddControlPoint( Vector3( 39.0, 90.0, 0.0 ) ); + path.AddControlPoint( Vector3( 56.0, 119.0, 0.0 ) ); + + // Control points for second segment + path.AddControlPoint( Vector3( 78.0, 120.0, 0.0 ) ); + path.AddControlPoint( Vector3( 93.0, 104.0, 0.0 ) ); + + layoutTransitionData.AddPropertyAnimator( controls[0], map, path, Vector3::XAXIS ); + } + { + // Grow a child from (0,0) size to full size (captured) + Property::Map map; + map[ LayoutTransitionData::AnimatorKey::PROPERTY ] = "size"; + map[ LayoutTransitionData::AnimatorKey::INITIAL_VALUE ] = Vector3( 0.0f, 0.0f, 0 ); + map[ LayoutTransitionData::AnimatorKey::ANIMATOR ] = Property::Map() + .Add( LayoutTransitionData::AnimatorKey::ALPHA_FUNCTION, "LINEAR") + .Add( LayoutTransitionData::AnimatorKey::TIME_PERIOD, Property::Map() + .Add( LayoutTransitionData::AnimatorKey::DELAY, 0.0f) + .Add( LayoutTransitionData::AnimatorKey::DURATION, 0.5f)); + layoutTransitionData.AddPropertyAnimator( controls[0], map ); + } + + horizontalLayout.SetTransitionData( LayoutTransitionData::ON_CHILD_ADD, layoutTransitionData ); + container.Add( controls[0] ); + + bool signalReceived(false); + LayoutTransitionFinishCheck finishCheck(signalReceived); + layoutTransitionData.FinishedSignal().Connect(&application, finishCheck); + + application.SendNotification(); + application.Render( 0 ); + + finishCheck.CheckSignalNotReceived(); + // The animation just started + DALI_TEST_EQUALS( container.GetCurrentPosition(), Vector3( 0.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + Vector3 position, tangent; + Quaternion rotation; + path.Sample( 0.0f, position, tangent ); + rotation = Quaternion( Vector3::XAXIS, tangent ); + DALI_TEST_EQUALS( controls[0].GetCurrentPosition(), position, 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[0].GetCurrentOrientation(), rotation, 0.0001f, TEST_LOCATION ); + + application.SendNotification(); + application.Render(static_cast( 0.5f * 1000.0f ) + 1u /*just after the end of the animation*/ ); + + path.Sample( 1.0f, position, tangent ); + rotation = Quaternion( Vector3::XAXIS, tangent ); + DALI_TEST_EQUALS( controls[0].GetCurrentPosition(), position, 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[0].GetCurrentOrientation(), rotation, 0.0001f, TEST_LOCATION ); + + // The animation just finished + DALI_TEST_EQUALS( container.GetCurrentPosition(), Vector3( 0.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[0].GetCurrentPosition(), Vector3( 0.0f, 350.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + DALI_TEST_EQUALS( container.GetCurrentSize(), Vector3( 480.0f, 800.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[0].GetCurrentSize(), Vector3( 100.0f, 100.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + application.SendNotification(); + application.Render( 10u /* wait a bit more for a signal */ ); + + // Now sizes and positions are finally set + DALI_TEST_EQUALS( container.GetProperty( Actor::Property::POSITION ), Vector3( 0.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[0].GetProperty( Actor::Property::POSITION ), Vector3( 0.0f, 350.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + DALI_TEST_EQUALS( container.GetProperty( Actor::Property::SIZE ), Vector3( 480.0f, 800.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[0].GetProperty( Actor::Property::SIZE ), Vector3( 100.0f, 100.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + finishCheck.CheckSignalReceived(); + + END_TEST; +} + +int UtcDaliLayouting_AddChildLayoutTransition04_AnimateBy(void) +{ + ToolkitTestApplication application; + tet_infoline(" UtcDaliLayouting_AddChildLayoutTransition04_AnimateBy"); + + Stage stage = Stage::GetCurrent(); + auto container = Control::New(); + auto horizontalLayout = LinearLayout::New(); + horizontalLayout.SetAnimateLayout( true ); + horizontalLayout.SetOrientation( LinearLayout::Orientation::HORIZONTAL ); + + DevelControl::SetLayout( container, horizontalLayout ); + container.SetName( "Container"); + + std::vector< Control > controls; + controls.push_back( CreateLeafControl( 100, 100 ) ); + container.SetParentOrigin( ParentOrigin::CENTER ); + container.SetAnchorPoint( AnchorPoint::CENTER ); + stage.Add( container ); + + auto layoutTransitionData = LayoutTransitionData::New(); + { + // Instant resize for parent + Property::Map map; + map[ LayoutTransitionData::AnimatorKey::PROPERTY ] = Actor::Property::SIZE; + map[ LayoutTransitionData::AnimatorKey::TARGET_VALUE ] = Property::Value(); // capture from layout update + map[ LayoutTransitionData::AnimatorKey::ANIMATOR ] = Property::Map() + .Add( LayoutTransitionData::AnimatorKey::ALPHA_FUNCTION, "LINEAR" ) + .Add( LayoutTransitionData::AnimatorKey::TIME_PERIOD, Property::Map() + .Add( LayoutTransitionData::AnimatorKey::DELAY, 0.0f ) + .Add( LayoutTransitionData::AnimatorKey::DURATION, 0.0f ) ); + layoutTransitionData.AddPropertyAnimator( container, map ); + } + { + // Instant position for a child + Property::Map map; + map[ LayoutTransitionData::AnimatorKey::PROPERTY ] = Actor::Property::POSITION; + map[ LayoutTransitionData::AnimatorKey::ANIMATOR ] = Property::Map() + .Add( LayoutTransitionData::AnimatorKey::ALPHA_FUNCTION, "LINEAR") + .Add( LayoutTransitionData::AnimatorKey::TIME_PERIOD, Property::Map() + .Add( LayoutTransitionData::AnimatorKey::DELAY, 0.0f ) + .Add( LayoutTransitionData::AnimatorKey::DURATION, 0.0f ) ); + layoutTransitionData.AddPropertyAnimator( Actor(), map ); // apply to all children except parent + } + { + Property::Map map; + map[ LayoutTransitionData::AnimatorKey::PROPERTY ] = Actor::Property::SIZE; + map[ LayoutTransitionData::AnimatorKey::TARGET_VALUE ] = Vector3( 0.0f, 350.0f, 0 ); + map[ LayoutTransitionData::AnimatorKey::ANIMATOR ] = Property::Map() + .Add( LayoutTransitionData::AnimatorKey::TYPE, "ANIMATE_BY") + .Add( LayoutTransitionData::AnimatorKey::ALPHA_FUNCTION, "LINEAR") + .Add( LayoutTransitionData::AnimatorKey::TIME_PERIOD, Property::Map() + .Add( LayoutTransitionData::AnimatorKey::DELAY, 0.0f) + .Add( LayoutTransitionData::AnimatorKey::DURATION, 0.5f)); + layoutTransitionData.AddPropertyAnimator( controls[0], map ); + } + + horizontalLayout.SetTransitionData( LayoutTransitionData::ON_CHILD_ADD, layoutTransitionData ); + container.Add( controls[0] ); + + bool signalReceived(false); + LayoutTransitionFinishCheck finishCheck(signalReceived); + layoutTransitionData.FinishedSignal().Connect(&application, finishCheck); + + application.SendNotification(); + application.Render( 1u /*just very beginning of the animation*/ ); + + finishCheck.CheckSignalNotReceived(); + // The animation just started + DALI_TEST_EQUALS( container.GetCurrentPosition(), Vector3( 0.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[0].GetCurrentPosition(), Vector3( 0.0f, 350.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + application.SendNotification(); + application.Render( static_cast( 0.5f * 1000.0f ) + 1u /*just after the end of the animation*/ ); + + // The animation just finished + DALI_TEST_EQUALS( container.GetCurrentPosition(), Vector3( 0.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[0].GetCurrentPosition(), Vector3( 0.0f, 350.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + DALI_TEST_EQUALS( container.GetCurrentSize(), Vector3( 480.0f, 800.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[0].GetCurrentSize(), Vector3( 100.0f, 100.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + application.SendNotification(); + application.Render( 10u /* wait a bit more for a signal */ ); + + // Now sizes and positions are finally set + DALI_TEST_EQUALS( container.GetProperty( Actor::Property::POSITION ), Vector3( 0.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[0].GetProperty( Actor::Property::POSITION ), Vector3( 0.0f, 350.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + DALI_TEST_EQUALS( container.GetProperty( Actor::Property::SIZE ), Vector3( 480.0f, 800.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[0].GetProperty( Actor::Property::SIZE ), Vector3( 100.0f, 100.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + finishCheck.CheckSignalReceived(); + + END_TEST; +} + +int UtcDaliLayouting_AddChildLayoutTransition05(void) +{ + ToolkitTestApplication application; + tet_infoline(" UtcDaliLayouting_AddChildLayoutTransition05"); + + Stage stage = Stage::GetCurrent(); + auto container = Control::New(); + auto horizontalLayout = LinearLayout::New(); + horizontalLayout.SetAnimateLayout( true ); + horizontalLayout.SetOrientation( LinearLayout::Orientation::HORIZONTAL ); + + DevelControl::SetLayout( container, horizontalLayout ); + container.SetName( "Container"); + + std::vector< Control > controls; + controls.push_back( CreateLeafControl( 100, 100 ) ); + container.SetParentOrigin( ParentOrigin::CENTER ); + container.SetAnchorPoint( AnchorPoint::CENTER ); + stage.Add( container ); + + auto layoutTransitionData = LayoutTransitionData::New(); + { + // Instant resize for parent + Property::Map map; + map[ "property" ] = Actor::Property::SIZE; + map[ "targetValue" ] = Property::Value(); // capture from layout update + map[ "animator" ] = Property::Map() + .Add( "name", "InstantAnimator" ) + .Add( "type", "ANIMATE_TO") + .Add( "alphaFunction", "LINEAR" ) + .Add( "timePeriod", Property::Map() + .Add( "delay", 0.0f ) + .Add( "duration", 0.0f ) ); + layoutTransitionData.AddPropertyAnimator( container, map ); + } + { + // Instant position for a child + Property::Map map; + map[ LayoutTransitionData::AnimatorKey::PROPERTY ] = Actor::Property::COLOR_ALPHA; + map[ LayoutTransitionData::AnimatorKey::ANIMATOR ] = "InstantAnimator"; + layoutTransitionData.AddPropertyAnimator( Actor(), map ); // apply to all children except parent + } + { + // Grow a child from (0,0) size to full size (captured) + Property::Map map; + map[ LayoutTransitionData::AnimatorKey::PROPERTY ] = Actor::Property::SIZE; + map[ LayoutTransitionData::AnimatorKey::INITIAL_VALUE ] = Vector3( 0.0f, 0.0f, 0 ); + map[ LayoutTransitionData::AnimatorKey::ANIMATOR ] = std::string(); + layoutTransitionData.AddPropertyAnimator( controls[0], map ); + } + { + // Instant opacity for a child, for testing + Property::Map map; + map[ LayoutTransitionData::AnimatorKey::PROPERTY ] = Actor::Property::POSITION; + map[ LayoutTransitionData::AnimatorKey::ANIMATOR ] = "InstantAnimator"; + layoutTransitionData.AddPropertyAnimator( Actor(), map ); // apply to all children except parent + } + + // Just throw all other alpha functions in + { // no property, not going to be used, but going to be parsed + Property::Map map; + map[ LayoutTransitionData::AnimatorKey::ANIMATOR ] = Property::Map() + .Add( LayoutTransitionData::AnimatorKey::ALPHA_FUNCTION, "WRONG" ); + layoutTransitionData.AddPropertyAnimator( Actor(), map ); // apply to all children except parent + } + { // no property, not going to be used, but going to be parsed + Property::Map map; + map[ LayoutTransitionData::AnimatorKey::ANIMATOR ] = Property::Map() + .Add( LayoutTransitionData::AnimatorKey::ALPHA_FUNCTION, "LINEAR" ); + layoutTransitionData.AddPropertyAnimator( Actor(), map ); // apply to all children except parent + } + { // no property, not going to be used, but going to be parsed + Property::Map map; + map[ LayoutTransitionData::AnimatorKey::ANIMATOR ] = Property::Map() + .Add( LayoutTransitionData::AnimatorKey::ALPHA_FUNCTION, "REVERSE" ); + layoutTransitionData.AddPropertyAnimator( Actor(), map ); // apply to all children except parent + } + { // no property, not going to be used, but going to be parsed + Property::Map map; + map[ LayoutTransitionData::AnimatorKey::ANIMATOR ] = Property::Map() + .Add( LayoutTransitionData::AnimatorKey::ALPHA_FUNCTION, "EASE_IN_SQUARE" ); + layoutTransitionData.AddPropertyAnimator( Actor(), map ); // apply to all children except parent + } + { // no property, not going to be used, but going to be parsed + Property::Map map; + map[ LayoutTransitionData::AnimatorKey::ANIMATOR ] = Property::Map() + .Add( LayoutTransitionData::AnimatorKey::ALPHA_FUNCTION, "EASE_OUT_SQUARE" ); + layoutTransitionData.AddPropertyAnimator( Actor(), map ); // apply to all children except parent + } + { // no property, not going to be used, but going to be parsed + Property::Map map; + map[ LayoutTransitionData::AnimatorKey::ANIMATOR ] = Property::Map() + .Add( LayoutTransitionData::AnimatorKey::ALPHA_FUNCTION, "EASE_IN" ); + layoutTransitionData.AddPropertyAnimator( Actor(), map ); // apply to all children except parent + } + { // no property, not going to be used, but going to be parsed + Property::Map map; + map[ LayoutTransitionData::AnimatorKey::ANIMATOR ] = Property::Map() + .Add( LayoutTransitionData::AnimatorKey::ALPHA_FUNCTION, "EASE_IN" ); + layoutTransitionData.AddPropertyAnimator( Actor(), map ); // apply to all children except parent + } + { // no property, not going to be used, but going to be parsed + Property::Map map; + map[ LayoutTransitionData::AnimatorKey::ANIMATOR ] = Property::Map() + .Add( LayoutTransitionData::AnimatorKey::ALPHA_FUNCTION, "EASE_OUT" ); + layoutTransitionData.AddPropertyAnimator( Actor(), map ); // apply to all children except parent + } + { // no property, not going to be used, but going to be parsed + Property::Map map; + map[ LayoutTransitionData::AnimatorKey::ANIMATOR ] = Property::Map() + .Add( LayoutTransitionData::AnimatorKey::ALPHA_FUNCTION, "EASE_IN_OUT" ); + layoutTransitionData.AddPropertyAnimator( Actor(), map ); // apply to all children except parent + } + { // no property, not going to be used, but going to be parsed + Property::Map map; + map[ LayoutTransitionData::AnimatorKey::ANIMATOR ] = Property::Map() + .Add( LayoutTransitionData::AnimatorKey::ALPHA_FUNCTION, "EASE_IN_OUT_SINE" ); + layoutTransitionData.AddPropertyAnimator( Actor(), map ); // apply to all children except parent + } + { // no property, not going to be used, but going to be parsed + Property::Map map; + map[ LayoutTransitionData::AnimatorKey::ANIMATOR ] = Property::Map() + .Add( LayoutTransitionData::AnimatorKey::ALPHA_FUNCTION, "EASE_IN_SINE" ); + layoutTransitionData.AddPropertyAnimator( Actor(), map ); // apply to all children except parent + } + { // no property, not going to be used, but going to be parsed + Property::Map map; + map[ LayoutTransitionData::AnimatorKey::ANIMATOR ] = Property::Map() + .Add( LayoutTransitionData::AnimatorKey::ALPHA_FUNCTION, "EASE_OUT_SINE" ); + layoutTransitionData.AddPropertyAnimator( Actor(), map ); // apply to all children except parent + } + { // no property, not going to be used, but going to be parsed + Property::Map map; + map[ LayoutTransitionData::AnimatorKey::ANIMATOR ] = Property::Map() + .Add( LayoutTransitionData::AnimatorKey::ALPHA_FUNCTION, "BOUNCE" ); + layoutTransitionData.AddPropertyAnimator( Actor(), map ); // apply to all children except parent + } + { // no property, not going to be used, but going to be parsed + Property::Map map; + map[ LayoutTransitionData::AnimatorKey::ANIMATOR ] = Property::Map() + .Add( LayoutTransitionData::AnimatorKey::ALPHA_FUNCTION, "SIN" ); + layoutTransitionData.AddPropertyAnimator( Actor(), map ); // apply to all children except parent + } + { // no property, not going to be used, but going to be parsed + Property::Map map; + map[ LayoutTransitionData::AnimatorKey::ANIMATOR ] = Property::Map() + .Add( LayoutTransitionData::AnimatorKey::ALPHA_FUNCTION, "EASE_OUT_BACK" ); + layoutTransitionData.AddPropertyAnimator( Actor(), map ); // apply to all children except parent + } + { // no property, not going to be used, but going to be parsed + Property::Map map; + map[ LayoutTransitionData::AnimatorKey::ANIMATOR ] = Property::Map() + .Add( LayoutTransitionData::AnimatorKey::ALPHA_FUNCTION, Vector4( 0.0f, 1.0f, 2.0f, 3.0f ) ); + layoutTransitionData.AddPropertyAnimator( Actor(), map ); // apply to all children except parent + } + { // no property, not going to be used, but going to be parsed + Property::Map map; + // valid + Property::Array array; + array.Reserve( 4 ); + array.PushBack( 0.0f ); + array.PushBack( 1.0f ); + array.PushBack( 2.0f ); + array.PushBack( 3.0f ); + map[ LayoutTransitionData::AnimatorKey::ANIMATOR ] = Property::Map() + .Add( LayoutTransitionData::AnimatorKey::ALPHA_FUNCTION, array ); + layoutTransitionData.AddPropertyAnimator( Actor(), map ); // apply to all children except parent + } + { // no property, not going to be used, but going to be parsed + Property::Map map; + // invalid + Property::Array array; + array.Reserve( 3 ); + array.PushBack( 0.0f ); + array.PushBack( 1.0f ); + array.PushBack( 2.0f ); + map[ LayoutTransitionData::AnimatorKey::ANIMATOR ] = Property::Map() + .Add( LayoutTransitionData::AnimatorKey::ALPHA_FUNCTION, array ); + layoutTransitionData.AddPropertyAnimator( Actor(), map ); // apply to all children except parent + } + { // no property, not going to be used, but going to be parsed + Property::Map map; + // invalid + Property::Array array; + array.Reserve( 4 ); + array.PushBack( 0.0f ); + array.PushBack( 10 ); + array.PushBack( 2.0f ); + array.PushBack( 3.0f ); + map[ LayoutTransitionData::AnimatorKey::ANIMATOR ] = Property::Map() + .Add( LayoutTransitionData::AnimatorKey::ALPHA_FUNCTION, array ); + layoutTransitionData.AddPropertyAnimator( Actor(), map ); // apply to all children except parent + } + { // no property, not going to be used, but going to be parsed + Property::Map map; + map[ LayoutTransitionData::AnimatorKey::ANIMATOR ] = 0; // invalid + layoutTransitionData.AddPropertyAnimator( Actor(), map ); // apply to all children except parent + } + + horizontalLayout.SetTransitionData( LayoutTransitionData::ON_CHILD_ADD, layoutTransitionData ); + container.Add( controls[0] ); + + bool signalReceived(false); + LayoutTransitionFinishCheck finishCheck(signalReceived); + layoutTransitionData.FinishedSignal().Connect(&application, finishCheck); + + application.SendNotification(); + application.Render( 1u /*just very beginning of the animation*/ ); + + finishCheck.CheckSignalNotReceived(); + // The animation just started + DALI_TEST_EQUALS( container.GetCurrentPosition(), Vector3( 0.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[0].GetCurrentPosition(), Vector3( 0.0f, 350.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + DALI_TEST_EQUALS( container.GetCurrentSize(), Vector3( 480.0f, 800.0f, 0.0f ), 1.0f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[0].GetCurrentSize(), Vector3( 0.0f, 0.0f, 0.0f ), 1.0f, TEST_LOCATION ); + + application.SendNotification(); + application.Render(static_cast( 0.5f * 1000.0f ) + 1u /*just after the end of the animation*/ ); + + // The animation just finished + DALI_TEST_EQUALS( container.GetCurrentPosition(), Vector3( 0.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[0].GetCurrentPosition(), Vector3( 0.0f, 350.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + DALI_TEST_EQUALS( container.GetCurrentSize(), Vector3( 480.0f, 800.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[0].GetCurrentSize(), Vector3( 100.0f, 100.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + application.SendNotification(); + application.Render( 10u /* wait a bit more for a signal */ ); + + // Now sizes and positions are finally set + DALI_TEST_EQUALS( container.GetProperty( Actor::Property::POSITION ), Vector3( 0.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[0].GetProperty( Actor::Property::POSITION ), Vector3( 0.0f, 350.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + DALI_TEST_EQUALS( container.GetProperty( Actor::Property::SIZE ), Vector3( 480.0f, 800.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + DALI_TEST_EQUALS( controls[0].GetProperty( Actor::Property::SIZE ), Vector3( 100.0f, 100.0f, 0.0f ), 0.0001f, TEST_LOCATION ); + + finishCheck.CheckSignalReceived(); + + END_TEST; +} + diff --git a/dali-toolkit/devel-api/file.list b/dali-toolkit/devel-api/file.list index c3f68aa..1cad2f5 100755 --- a/dali-toolkit/devel-api/file.list +++ b/dali-toolkit/devel-api/file.list @@ -44,6 +44,7 @@ devel_api_src_files = \ $(devel_api_src_dir)/layouting/layout-group.cpp \ $(devel_api_src_dir)/layouting/layout-group-impl.cpp \ $(devel_api_src_dir)/layouting/linear-layout.cpp \ + $(devel_api_src_dir)/layouting/layout-transition-data.cpp \ $(devel_api_src_dir)/scripting/script.cpp \ $(devel_api_src_dir)/styling/style-manager-devel.cpp \ $(devel_api_src_dir)/transition-effects/cube-transition-cross-effect.cpp \ @@ -101,6 +102,7 @@ devel_api_layouting_header_files = \ $(devel_api_src_dir)/layouting/layout-length.h \ $(devel_api_src_dir)/layouting/layout-parent-impl.h \ $(devel_api_src_dir)/layouting/layout-size.h \ + $(devel_api_src_dir)/layouting/layout-transition-data.h \ $(devel_api_src_dir)/layouting/measured-size.h \ $(devel_api_src_dir)/layouting/measure-spec.h diff --git a/dali-toolkit/devel-api/layouting/layout-controller.cpp b/dali-toolkit/devel-api/layouting/layout-controller.cpp index 645fe48..ba87af2 100644 --- a/dali-toolkit/devel-api/layouting/layout-controller.cpp +++ b/dali-toolkit/devel-api/layouting/layout-controller.cpp @@ -68,7 +68,12 @@ LayoutController LayoutController::Get() void LayoutController::RequestLayout( LayoutItem layout ) { - GetImpl(*this).RequestLayout( GetImplementation( layout ) ); + GetImpl( *this ).RequestLayout( GetImplementation( layout ), -1 ); +} + +void LayoutController::RequestLayout( LayoutItem layout, Dali::Toolkit::LayoutTransitionData::LayoutTransitionType layoutTransitionType ) +{ + GetImpl( *this ).RequestLayout( GetImplementation( layout ), layoutTransitionType ); } LayoutController::LayoutController( Internal::LayoutController *impl ) diff --git a/dali-toolkit/devel-api/layouting/layout-controller.h b/dali-toolkit/devel-api/layouting/layout-controller.h index 2741829..062793d 100755 --- a/dali-toolkit/devel-api/layouting/layout-controller.h +++ b/dali-toolkit/devel-api/layouting/layout-controller.h @@ -62,10 +62,19 @@ public: static LayoutController Get(); /** - * @brief Request for a particular layout (wrapping a control or a visual) to be measured and laid out. + * @brief Request for a particular layout (wrapping a control or a visual) to be measured and laid out. A specified layout transition + * will be triggered during the layout. + * @param[in] layout The layout to measure & relayout. + */ + void RequestLayout( LayoutItem layout ); + + /** + * @brief Request for a particular layout (wrapping a control or a visual) to be measured and laid out. A specified layout transition + * will be triggered during the layout. * @param[in] layout The layout to measure & relayout. + * @param[in] layoutTransitionType The layout transition type. */ - void RequestLayout( LayoutItem layout ); + void RequestLayout( LayoutItem layout, Dali::Toolkit::LayoutTransitionData::LayoutTransitionType layoutTransitionType ); public: /// @cond internal diff --git a/dali-toolkit/devel-api/layouting/layout-group-impl.cpp b/dali-toolkit/devel-api/layouting/layout-group-impl.cpp index 35c682f..06305bd 100644 --- a/dali-toolkit/devel-api/layouting/layout-group-impl.cpp +++ b/dali-toolkit/devel-api/layouting/layout-group-impl.cpp @@ -507,7 +507,7 @@ void LayoutGroup::OnInitialize() // Take ownership of existing children for( unsigned int childIndex = 0 ; childIndex < control.GetChildCount(); ++childIndex ) { - ChildAddedToOwner( control.GetChildAt( childIndex ) ); + ChildAddedToOwnerImpl( control.GetChildAt( childIndex ) ); } DevelActor::ChildAddedSignal( control ).Connect( mSlotDelegate, &LayoutGroup::ChildAddedToOwner ); @@ -551,6 +551,8 @@ void LayoutGroup::OnInitialize() } } } + + RequestLayout( Dali::Toolkit::LayoutTransitionData::LayoutTransitionType::ON_OWNER_SET ); } } @@ -582,6 +584,12 @@ void LayoutGroup::RemoveChild( LayoutItem& item ) void LayoutGroup::ChildAddedToOwner( Actor child ) { + ChildAddedToOwnerImpl( child ); + RequestLayout( Dali::Toolkit::LayoutTransitionData::LayoutTransitionType::ON_CHILD_ADD ); +} + +void LayoutGroup::ChildAddedToOwnerImpl( Actor child ) +{ LayoutItemPtr childLayout; Toolkit::Control control = Toolkit::Control::DownCast( child ); @@ -662,6 +670,7 @@ void LayoutGroup::ChildRemovedFromOwner( Actor child ) if( childLayout ) { Remove( *childLayout.Get() ); + RequestLayout( Dali::Toolkit::LayoutTransitionData::LayoutTransitionType::ON_CHILD_REMOVE ); } } } diff --git a/dali-toolkit/devel-api/layouting/layout-group-impl.h b/dali-toolkit/devel-api/layouting/layout-group-impl.h index ee73c88..37aa90f 100644 --- a/dali-toolkit/devel-api/layouting/layout-group-impl.h +++ b/dali-toolkit/devel-api/layouting/layout-group-impl.h @@ -294,6 +294,11 @@ private: void ChildAddedToOwner( Actor child ); /** + * Implementation of ChildAddedToOwner + */ + void ChildAddedToOwnerImpl( Actor child ); + + /** * Callback when child is removed from owner */ void ChildRemovedFromOwner( Actor child ); diff --git a/dali-toolkit/devel-api/layouting/layout-item-impl.cpp b/dali-toolkit/devel-api/layouting/layout-item-impl.cpp index f70a5f1..cd4cf40 100644 --- a/dali-toolkit/devel-api/layouting/layout-item-impl.cpp +++ b/dali-toolkit/devel-api/layouting/layout-item-impl.cpp @@ -19,10 +19,14 @@ #include #include #include +#include #include #include +#include #include +#include + namespace { @@ -33,7 +37,6 @@ Debug::Filter* gLayoutFilter = Debug::Filter::New( Debug::NoLogging, false, "LOG const char* WIDTH_SPECIFICATION_NAME( "widthSpecification" ); const char* HEIGHT_SPECIFICATION_NAME( "heightSpecification" ); -const float DEFAULT_TRANSITION_DURATION( 0.5f ); } namespace Dali @@ -66,7 +69,6 @@ void LayoutItem::Initialize( Handle& owner, const std::string& containerType ) mImpl->mOwner = &(owner.GetBaseObject()); RegisterChildProperties( containerType ); OnInitialize(); // Ensure direct deriving class gets initialized - RequestLayout(); } Handle LayoutItem::GetOwner() const @@ -93,6 +95,35 @@ void LayoutItem::Unparent() mImpl->mOwner = NULL; } +LayoutTransitionDataPtr LayoutItem::GetDefaultTransition() +{ + DALI_LOG_INFO( gLayoutFilter, Debug::Verbose, "LayoutItem::GetDefaultTransition\n" ); + if ( !mImpl->mDefaultTransitionData.Get() ) + { + auto owner = GetOwner(); + auto actor = Actor::DownCast( owner ); + + mImpl->mDefaultTransitionData = LayoutTransitionData::New(); + { + Property::Map map; + map[ Dali::Toolkit::LayoutTransitionData::AnimatorKey::PROPERTY ] = Actor::Property::POSITION; + map[ Dali::Toolkit::LayoutTransitionData::AnimatorKey::TARGET_VALUE ] = Property::Value(); // capture from layout update + map[ Dali::Toolkit::LayoutTransitionData::AnimatorKey::ANIMATOR ] = std::string(); // default animator with default duration + // Capture calculated position after layout, apply default linear animation + mImpl->mDefaultTransitionData->AddPropertyAnimator( actor, map ); + } + { + Property::Map map; + map[ Dali::Toolkit::LayoutTransitionData::AnimatorKey::PROPERTY ] = Actor::Property::SIZE; + map[ Dali::Toolkit::LayoutTransitionData::AnimatorKey::TARGET_VALUE ] = Property::Value(); // capture from layout update + map[ Dali::Toolkit::LayoutTransitionData::AnimatorKey::ANIMATOR ] = std::string(); // default animator with default duration + // Capture calculated size after layout, apply default linear animation + mImpl->mDefaultTransitionData->AddPropertyAnimator( actor, map ); + } + } + return mImpl->mDefaultTransitionData; +} + void LayoutItem::SetAnimateLayout( bool animateLayout ) { auto owner = GetOwner(); @@ -111,6 +142,39 @@ bool LayoutItem::IsLayoutAnimated() const return mImpl->mAnimated; } +void LayoutItem::SetTransitionData( int layoutTransitionType, Internal::LayoutTransitionDataPtr layoutTransitionDataPtr ) +{ + switch ( layoutTransitionType ) + { + case Dali::Toolkit::LayoutTransitionData::ON_CHILD_ADD: + mImpl->mOnChildAddTransitionData = layoutTransitionDataPtr; + break; + case Dali::Toolkit::LayoutTransitionData::ON_CHILD_REMOVE: + mImpl->mOnChildRemoveTransitionData = layoutTransitionDataPtr; + break; + case Dali::Toolkit::LayoutTransitionData::ON_OWNER_SET: + mImpl->mOnOwnerSetTransitionData = layoutTransitionDataPtr; + break; + default: + break; + } +} + +Internal::LayoutTransitionDataPtr LayoutItem::GetTransitionData( int layoutTransitionType ) const +{ + switch ( layoutTransitionType ) + { + case Dali::Toolkit::LayoutTransitionData::ON_CHILD_ADD: + return mImpl->mOnChildAddTransitionData.Get(); + case Dali::Toolkit::LayoutTransitionData::ON_CHILD_REMOVE: + return mImpl->mOnChildRemoveTransitionData.Get(); + case Dali::Toolkit::LayoutTransitionData::ON_OWNER_SET: + return mImpl->mOnOwnerSetTransitionData.Get(); + default: + return LayoutTransitionDataPtr(); + } +} + void LayoutItem::RegisterChildProperties( const std::string& containerType ) { // Call on derived types @@ -198,14 +262,23 @@ void LayoutItem::Layout( LayoutLength l, LayoutLength t, LayoutLength r, LayoutL mImpl->ClearPrivateFlag( Impl::PRIVATE_FLAG_MEASURE_NEEDED_BEFORE_LAYOUT ); } + LayoutData& layoutData = *mImpl->sLayoutData; + size_t size = layoutData.childrenPropertyAnimators.size(); + bool changed = SetFrame( l, t, r, b ); if( changed || mImpl->GetPrivateFlag( Impl::PRIVATE_FLAG_LAYOUT_REQUIRED ) ) { + OnLayout( changed, l, t, r, b ); mImpl->ClearPrivateFlag( Impl::PRIVATE_FLAG_LAYOUT_REQUIRED ); } + if ( size != layoutData.childrenPropertyAnimators.size() ) + { + layoutData.childrenPropertyAnimators.resize( size ); + } + mImpl->ClearPrivateFlag( Impl::PRIVATE_FLAG_FORCE_LAYOUT ); mImpl->SetPrivateFlag( Impl::PRIVATE_FLAG_IS_LAID_OUT ); } @@ -333,14 +406,29 @@ LayoutParent* LayoutItem::GetParent() void LayoutItem::RequestLayout() { Toolkit::Control control = Toolkit::Control::DownCast( mImpl->mOwner ); + if( control ) + { + DALI_LOG_INFO( gLayoutFilter, Debug::Verbose, "LayoutItem::RequestLayout control(%s)\n", + control.GetName().c_str() ); + } + // @todo Enforce failure if called in Measure/Layout passes. + mImpl->SetPrivateFlag( Impl::PRIVATE_FLAG_FORCE_LAYOUT ); + Toolkit::LayoutController layoutController = Toolkit::LayoutController::Get(); + layoutController.RequestLayout( Toolkit::LayoutItem( this ) ); +} + +void LayoutItem::RequestLayout( Dali::Toolkit::LayoutTransitionData::LayoutTransitionType layoutAnimationType ) +{ + Toolkit::Control control = Toolkit::Control::DownCast( mImpl->mOwner ); if ( control ) { - DALI_LOG_INFO( gLayoutFilter, Debug::Verbose, "LayoutItem::RequestLayout %s\n", control.GetName().c_str()); + DALI_LOG_INFO( gLayoutFilter, Debug::Verbose, "LayoutItem::RequestLayout control(%s) layoutTranstionType(%d)\n", + control.GetName().c_str(), (int)layoutAnimationType ); } // @todo Enforce failure if called in Measure/Layout passes. mImpl->SetPrivateFlag( Impl::PRIVATE_FLAG_FORCE_LAYOUT ); Toolkit::LayoutController layoutController = Toolkit::LayoutController::Get(); - layoutController.RequestLayout( Toolkit::LayoutItem(this) ); + layoutController.RequestLayout( Toolkit::LayoutItem(this), layoutAnimationType ); } bool LayoutItem::IsLayoutRequested() const @@ -469,56 +557,65 @@ bool LayoutItem::SetFrame( LayoutLength left, LayoutLength top, LayoutLength rig if( mImpl->mLeft != left || mImpl->mRight != right || mImpl->mTop != top || mImpl->mBottom != bottom || mImpl->GetPrivateFlag( Impl::PRIVATE_FLAG_FORCE_SET_FRAME ) ) { changed = true; - - LayoutLength oldWidth = mImpl->mRight - mImpl->mLeft; - LayoutLength oldHeight = mImpl->mBottom - mImpl->mTop; - LayoutLength newWidth = right - left; - LayoutLength newHeight = bottom - top; - bool sizeChanged = (newWidth != oldWidth) || (newHeight != oldHeight); - - mImpl->mLeft = left; - mImpl->mTop = top; - mImpl->mRight = right; - mImpl->mBottom = bottom; - mImpl->ClearPrivateFlag( Impl::PRIVATE_FLAG_FORCE_SET_FRAME ); + } + LayoutLength oldWidth = mImpl->mRight - mImpl->mLeft; + LayoutLength oldHeight = mImpl->mBottom - mImpl->mTop; + LayoutLength newWidth = right - left; + LayoutLength newHeight = bottom - top; + bool sizeChanged = ( newWidth != oldWidth ) || ( newHeight != oldHeight ); - // Reflect up to parent control - auto owner = GetOwner(); - auto actor = Actor::DownCast(owner); - if( actor ) - { - DALI_LOG_STREAM( gLayoutFilter, Debug::Verbose, "LayoutItem::SetFrame owner(" << left << ", " << top << ", " << right << ", " << bottom << ")\n" ); + mImpl->mLeft = left; + mImpl->mTop = top; + mImpl->mRight = right; + mImpl->mBottom = bottom; - if( mImpl->mAnimated ) - { - auto animation = Animation::New( 0.5f ); - animation.AnimateTo( Property( actor, Actor::Property::POSITION_X ), left.AsInteger() ); - animation.AnimateTo( Property( actor, Actor::Property::POSITION_Y ), top.AsInteger() ); + // Reflect up to parent control + auto owner = GetOwner(); + auto actor = Actor::DownCast( owner ); + LayoutData& layoutData = *mImpl->sLayoutData; + if( actor ) + { + if( mImpl->mAnimated && !layoutData.speculativeLayout ) + { - animation.AnimateTo( Property( actor, Actor::Property::SIZE_WIDTH ), newWidth.AsInteger() ); - animation.AnimateTo( Property( actor, Actor::Property::SIZE_HEIGHT ), newHeight.AsInteger() ); + LayoutItem* transitionOwner = layoutData.layoutTransition.layoutItem.Get(); + LayoutTransitionDataPtr layoutTransitionDataPtr = GetTransitionData( layoutData.layoutTransition.layoutTransitionType ); - animation.FinishedSignal().Connect( mSlotDelegate, &LayoutItem::OnLayoutAnimationFinished ); - animation.Play(); + // Found transition owner + if( transitionOwner == this && layoutTransitionDataPtr.Get() ) + { + DALI_LOG_INFO( gLayoutFilter, Debug::Verbose, "LayoutItem::SetFrame apply transition to (%s), transition type (%d)\n", actor.GetName().c_str(), layoutData.layoutTransition.layoutTransitionType ); + layoutData.layoutPositionDataArray.push_back( LayoutPositionData( actor, left.AsDecimal(), top.AsDecimal(), right.AsDecimal(), bottom.AsDecimal(), true ) ); + layoutTransitionDataPtr->ConvertToLayoutDataElements( actor, layoutData ); + changed = true; } else { - // @todo Collate into list of Property & Property::Value pairs. - actor.SetX( left.AsInteger() ); - actor.SetY( top.AsInteger() ); - actor.SetProperty( Actor::Property::SIZE_WIDTH, newWidth.AsInteger() ); - actor.SetProperty( Actor::Property::SIZE_HEIGHT, newHeight.AsInteger() ); + if( changed ) + { + DALI_LOG_INFO( gLayoutFilter, Debug::Verbose, "LayoutItem::SetFrame apply default transition to (%s), transition type (%d)\n", actor.GetName().c_str(), layoutData.layoutTransition.layoutTransitionType ); + layoutData.layoutPositionDataArray.push_back( LayoutPositionData( actor, left.AsDecimal(), top.AsDecimal(), right.AsDecimal(), bottom.AsDecimal(), true ) ); + GetDefaultTransition()->ConvertToLayoutDataElements( actor, layoutData ); + } } } - - if( sizeChanged ) + else { - SizeChange( LayoutSize( newWidth, newHeight ), LayoutSize( oldWidth, oldHeight ) ); + if( changed ) + { + layoutData.layoutPositionDataArray.push_back( LayoutPositionData( actor, left.AsDecimal(), top.AsDecimal(), right.AsDecimal(), bottom.AsDecimal(), false ) ); + } } } + // TODO: do we need it + if( sizeChanged ) + { + SizeChange( LayoutSize( newWidth, newHeight ), LayoutSize( oldWidth, oldHeight ) ); + } + DALI_LOG_STREAM( gLayoutFilter, Debug::Verbose, "LayoutItem::SetFrame exit(" << left << ", " << top << ", " << right << ", " << bottom << ")\n" ); return changed; diff --git a/dali-toolkit/devel-api/layouting/layout-item-impl.h b/dali-toolkit/devel-api/layouting/layout-item-impl.h index 3850e5f..19b61d5 100644 --- a/dali-toolkit/devel-api/layouting/layout-item-impl.h +++ b/dali-toolkit/devel-api/layouting/layout-item-impl.h @@ -20,8 +20,10 @@ #include #include +#include #include #include +#include #include #include #include @@ -37,9 +39,13 @@ namespace Toolkit namespace Internal { +struct LayoutData; + class LayoutItem; using LayoutItemPtr = IntrusivePtr; +class LayoutTransitionData; +using LayoutTransitionDataPtr = IntrusivePtr; /** * Base class for layouts. @@ -114,6 +120,28 @@ public: bool IsLayoutAnimated() const; /** + * @brief Get the default transition + * + * @return The default transition + */ + LayoutTransitionDataPtr GetDefaultTransition(); + + /** + * @brief Set the layout transition data + * @param[in] layoutTransitionType The type of the transition + * @param[in] layoutTransitionDataPtr The transition data pointer + */ + void SetTransitionData( int layoutTransitionType, LayoutTransitionDataPtr layoutTransitionDataPtr ); + + /** + * @brief Get the transition data + * @param[in] layoutTransitionType The type of the transition + * + * @return The transition + */ + LayoutTransitionDataPtr GetTransitionData( int layoutTransitionType ) const; + + /** * @brief This is called to find out how big a layout should be. * * The parent supplies constraint information in the width and height parameters. @@ -176,6 +204,14 @@ public: void RequestLayout(); /** + * @brief Request that this layout is re-laid out with particular transition. + * @param[in] layoutTranstionType The transition type + * + * This will make this layout and all it's parent layouts dirty and set the transition queued. + */ + void RequestLayout( Dali::Toolkit::LayoutTransitionData::LayoutTransitionType layoutTranstionType ); + + /** * @brief Predicate to determine if this layout has been requested to re-layout * * @return True if a layout request has occured on this layout @@ -408,10 +444,9 @@ protected: MeasuredSize::State childMeasuredState ); /** - * @brief Sets the frame (the size and position) of the layout onto it's owner + * @brief Sets the frame (the size and position) of the layout onto it's owner. + * Collect all properties to animate after the layout update. * - * @todo Consider instead, collating properties into LayoutCollector in order to set/animate them all - * in one block. * @param[in] left The horizontal position of the left edge of this frame within the parent layout * @param[in] top The vertical position of the top edge of this frame within the parent layout * @param[in] right The horizontal position of the right edge of this frame within the parent layout @@ -466,7 +501,6 @@ private: public: class Impl; // Class declaration is public so we can add devel API's in the future - private: std::unique_ptr mImpl; ///< Implementation class holds all the data SlotDelegate mSlotDelegate; diff --git a/dali-toolkit/devel-api/layouting/layout-item.cpp b/dali-toolkit/devel-api/layouting/layout-item.cpp index 153c134..a84b45d 100644 --- a/dali-toolkit/devel-api/layouting/layout-item.cpp +++ b/dali-toolkit/devel-api/layouting/layout-item.cpp @@ -16,6 +16,8 @@ #include #include +#include +#include namespace Dali { @@ -53,6 +55,21 @@ bool LayoutItem::IsLayoutAnimated() const return GetImplementation( *this ).IsLayoutAnimated(); } +void LayoutItem::SetTransitionData( LayoutTransitionData::LayoutTransitionType layoutTransitionType, LayoutTransitionData layoutTransitionData ) +{ + Toolkit::Internal::LayoutTransitionDataPtr layoutTransitionDataPtr = Toolkit::Internal::LayoutTransitionDataPtr(); + if ( layoutTransitionData ) + { + layoutTransitionDataPtr = Toolkit::Internal::LayoutTransitionDataPtr( &Toolkit::GetImplementation( layoutTransitionData ) ); + } + GetImplementation( *this ).SetTransitionData( layoutTransitionType, layoutTransitionDataPtr ); +} + +LayoutTransitionData LayoutItem::GetTransitionData( LayoutTransitionData::LayoutTransitionType layoutTransitionType ) const +{ + return LayoutTransitionData( GetImplementation( *this ).GetTransitionData( layoutTransitionType ).Get() ); +} + } // namespace Toolkit } // namespace Dali diff --git a/dali-toolkit/devel-api/layouting/layout-item.h b/dali-toolkit/devel-api/layouting/layout-item.h index fc69e6d..1ad32ed 100755 --- a/dali-toolkit/devel-api/layouting/layout-item.h +++ b/dali-toolkit/devel-api/layouting/layout-item.h @@ -20,10 +20,13 @@ #include #include #include +#include #include #include +#include #include #include +#include #include namespace Dali @@ -38,7 +41,6 @@ class LayoutItem; using LayoutId = unsigned int; - /** * Base class for layouts. It is used to layout a control (or visual). * It can be laid out by a LayoutGroup. @@ -115,6 +117,23 @@ public: */ bool IsLayoutAnimated() const; + /** + * @brief Set the layout transition data + * + * @param[in] layoutTransitionType The type of the layout transition + * @param[in] layoutTransitionData The layout transition data + */ + void SetTransitionData( LayoutTransitionData::LayoutTransitionType layoutTransitionType, LayoutTransitionData layoutTransitionData ); + + /** + * @brief Get the layout transition data + * + * @param[in] layoutTransitionType The type of the layout transition + * + * @return The layout transition data + */ + LayoutTransitionData GetTransitionData( LayoutTransitionData::LayoutTransitionType layoutTransitionType ) const; + public: /// @cond internal /** diff --git a/dali-toolkit/devel-api/layouting/layout-transition-data.cpp b/dali-toolkit/devel-api/layouting/layout-transition-data.cpp new file mode 100644 index 0000000..c01b2dd --- /dev/null +++ b/dali-toolkit/devel-api/layouting/layout-transition-data.cpp @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2018 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. + */ + +#include +#include + +namespace Dali +{ +namespace Toolkit +{ + +LayoutTransitionData::LayoutTransitionData() +: BaseHandle() +{ +} + +LayoutTransitionData::LayoutTransitionData( Internal::LayoutTransitionData* layoutAnimationData ) +: BaseHandle( layoutAnimationData ) +{ +} + +LayoutTransitionData LayoutTransitionData::New() +{ + Internal::LayoutTransitionDataPtr layoutAnimationData = Internal::LayoutTransitionData::New(); + return LayoutTransitionData( layoutAnimationData.Get() ); +} + +LayoutTransitionData LayoutTransitionData::DownCast( BaseHandle handle ) +{ + return LayoutTransitionData( dynamic_cast(handle.GetObjectPtr()) ); +} + +void LayoutTransitionData::AddPropertyAnimator( Actor actor, Property::Map map ) +{ + GetImplementation( *this ).AddPropertyAnimator( actor, map ); +} + +void LayoutTransitionData::AddPropertyAnimator( Actor actor, Property::Map map, KeyFrames keyFrames, Animation::Interpolation interpolation ) +{ + GetImplementation( *this ).AddPropertyAnimator( actor, map, keyFrames, interpolation ); +} + +void LayoutTransitionData::AddPropertyAnimator( Actor actor, Property::Map map, Path path, Vector3 forward ) +{ + GetImplementation( *this ).AddPropertyAnimator( actor, map, path, forward ); +} + +LayoutTransitionData::LayoutTransitionSignalType& LayoutTransitionData::FinishedSignal() +{ + return GetImplementation(*this ).FinishedSignal(); +} + +} // namespace Toolkit +} // namespace Dali diff --git a/dali-toolkit/devel-api/layouting/layout-transition-data.h b/dali-toolkit/devel-api/layouting/layout-transition-data.h new file mode 100644 index 0000000..5bd509a --- /dev/null +++ b/dali-toolkit/devel-api/layouting/layout-transition-data.h @@ -0,0 +1,151 @@ +#ifndef DALI_TOOLKIT_LAYOUTING_LAYOUT_TRANSITION_DATA_H +#define DALI_TOOLKIT_LAYOUTING_LAYOUT_TRANSITION_DATA_H +/* + * Copyright (c) 2018 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Dali +{ +namespace Toolkit +{ + +namespace Internal +{ +class LayoutTransitionData; +} + +class DALI_TOOLKIT_API LayoutTransitionData final : public BaseHandle +{ +public: + + /** + * @brief Enumeration for property animator keys belonging to the LayoutTransitionData class. + */ + struct AnimatorKey + { + enum Type + { + PROPERTY, ///< A property to animate + INITIAL_VALUE, ///< Initial value of an animated property + TARGET_VALUE, ///< Target value of an animated property + ANIMATOR, ///< Animator for an animated property + TYPE, ///< Type of an animator + NAME, ///< Name of an animator + TIME_PERIOD, ///< Time period of an property animation + DURATION, ///< Duration of an property animation + DELAY, ///< Delay of an property animation + ALPHA_FUNCTION, ///< Alpha function of a property animation + }; + }; + + enum LayoutTransitionType + { + ON_CHILD_ADD, + ON_CHILD_REMOVE, + ON_OWNER_SET + }; + + typedef Signal< void (LayoutTransitionData::LayoutTransitionType, LayoutTransitionData&) > LayoutTransitionSignalType; ///< Transition finished signal + + /** + * Create an uninitialized handle + * + * @SINCE_1_2.12 + */ + LayoutTransitionData(); + + /** + * Destructor - non virtual + * + * @SINCE_1_2.12 + */ + ~LayoutTransitionData() = default; + + /** + * Create an initialized LayoutTransitionData + */ + static LayoutTransitionData New(); + + /** + * @brief Downcasts a handle to LayoutTransitionData handle. + * + * If handle points to an LayoutTransitionData object, the downcast produces valid handle. + * If not, the returned handle is left uninitialized. + * + * @param[in] handle Handle to an object + * @return Handle to an LayoutTransitionData object or an uninitialized handle + */ + static LayoutTransitionData DownCast( BaseHandle handle ); + + /** + * @brief Add a property animator for an actor + * + * @param[in] actor An owner of the animated property + * @param[in] map The animated property map including animator map + */ + void AddPropertyAnimator( Actor actor, Property::Map map ); + + /** + * @brief Add a property animator for an actor + * + * @param[in] actor An owner of the animated property + * @param[in] map The properties map + * @param[in] keyFrames key frames + * @param[in] interpolation An interpolation + */ + void AddPropertyAnimator( Actor actor, Property::Map map, KeyFrames keyFrames, Animation::Interpolation interpolation ); + + /** + * @brief Add a property animator for an actor + * + * @param[in] actor An owner of the animated property + * @param[in] map A properties map + * @param[in] path An animation path + * @param[in] forward A forward vector for the path + */ + void AddPropertyAnimator( Actor actor, Property::Map map, Path path, Vector3 forward ); + + /** + * @brief Connects to this signal to be notified when a transition animation have finished. + * + * @return A signal object to connect with + */ + LayoutTransitionSignalType& FinishedSignal(); + +public: + /// @cond internal + /** + * @brief This constructor is used by LayoutTransitionData::New() method. + * + * @param[in] layoutTransitonData A pointer to a newly allocated transition data resource + */ + DALI_INTERNAL explicit LayoutTransitionData( Internal::LayoutTransitionData* layoutTransitonData ); + /// @endcond +}; + +}//namespace Toolkit +}//namespace Dali + +#endif // DALI_TOOLKIT_LAYOUTING_LAYOUT_TRANSITION_DATA_H diff --git a/dali-toolkit/internal/controls/control/control-data-impl.cpp b/dali-toolkit/internal/controls/control/control-data-impl.cpp index 6468ad5..fcfb147 100755 --- a/dali-toolkit/internal/controls/control/control-data-impl.cpp +++ b/dali-toolkit/internal/controls/control/control-data-impl.cpp @@ -1457,6 +1457,7 @@ void Control::Impl::SetLayout( Toolkit::Internal::LayoutItem& layout ) void Control::Impl::RemoveLayout() { + DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Control::Impl::RemoveLayout\n"); if( mLayout ) { mLayout->Unparent(); diff --git a/dali-toolkit/internal/file.list b/dali-toolkit/internal/file.list index 6df2e9f..8fab9fd 100755 --- a/dali-toolkit/internal/file.list +++ b/dali-toolkit/internal/file.list @@ -21,6 +21,7 @@ toolkit_src_files = \ $(toolkit_src_dir)/layouting/layout-controller-debug.cpp \ $(toolkit_src_dir)/layouting/layout-controller-impl.cpp \ $(toolkit_src_dir)/layouting/linear-layout-impl.cpp \ + $(toolkit_src_dir)/layouting/layout-transition-data-impl.cpp \ $(toolkit_src_dir)/layouting/size-negotiation-mapper.cpp \ $(toolkit_src_dir)/visuals/animated-image/animated-image-visual.cpp \ $(toolkit_src_dir)/visuals/animated-image/image-cache.cpp \ diff --git a/dali-toolkit/internal/layouting/layout-controller-impl.cpp b/dali-toolkit/internal/layouting/layout-controller-impl.cpp index f912810..17a75a6 100644 --- a/dali-toolkit/internal/layouting/layout-controller-impl.cpp +++ b/dali-toolkit/internal/layouting/layout-controller-impl.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -42,7 +43,8 @@ namespace Internal { LayoutController::LayoutController() -: mLayoutRequested(false) +: mLayoutRequested( false ), + mSlotDelegate( this ) { } @@ -52,15 +54,33 @@ LayoutController::~LayoutController() void LayoutController::Initialize() { + mAnimation = Animation::New( 0.0f ); } -void LayoutController::RequestLayout( LayoutItem& LayoutItem ) +void LayoutController::RequestLayout( LayoutItem& layoutItem, int layoutTransitionType ) { - DALI_LOG_INFO( gLogFilter, Debug::Concise, "LayoutController::RequestLayout\n" ); + auto actor = Actor::DownCast( layoutItem.GetOwner() ); + if ( actor ) + { + DALI_LOG_INFO( gLogFilter, Debug::Concise, "LayoutController::RequestLayout owner[%s] layoutItem[%p] layoutAnimationType(%d)\n", actor.GetName().c_str(), &layoutItem, layoutTransitionType ); + } + else + { + DALI_LOG_INFO( gLogFilter, Debug::Concise, "LayoutController::RequestLayout layoutItem[%p] layoutAnimationType(%d)\n", &layoutItem, layoutTransitionType ); + } + mLayoutRequested = true; + if( layoutTransitionType != -1 ) + { + LayoutTransition layoutTransition = LayoutTransition( layoutItem, layoutTransitionType ); + if( std::find( mLayoutTransitions.begin(), mLayoutTransitions.end(), layoutTransition ) == mLayoutTransitions.end() && layoutItem.GetTransitionData( layoutTransitionType ).Get() ) + { + mLayoutTransitions.push_back( layoutTransition ); + } + } // Go up the tree and mark all parents to relayout - LayoutParent* layoutParent = LayoutItem.GetParent(); + LayoutParent* layoutParent = layoutItem.GetParent(); if( layoutParent ) { LayoutGroup& layoutGroup = static_cast< LayoutGroup& >( *layoutParent ); @@ -74,11 +94,10 @@ void LayoutController::RequestLayout( LayoutItem& LayoutItem ) void LayoutController::Process() { // Perform the full process. + DALI_LOG_INFO( gLogFilter, Debug::Concise, "LayoutController::Process\n" ); if( mLayoutRequested ) { - mLayoutRequested = false; - // If window size has changed, expect stage to have already been updated Stage stage = Stage::GetCurrent(); auto stageWidth = stage.GetSize().width; @@ -91,8 +110,34 @@ void LayoutController::Process() MeasureHierarchy( stage.GetRootLayer(), widthSpec, heightSpec ); LAYOUT_DEBUG_MEASURE_STATES( stage.GetRootLayer() ); + + LayoutTransition layoutTransition; + LayoutPositionDataArray layoutPositionDataArray; + LayoutDataArray layoutDataArray; + LayoutAnimatorArray layoutAnimatorArray; + layoutAnimatorArray.push_back( LayoutDataAnimator() ); + PropertyAnimatorArray childrenPropertiesAnimators; + + if ( mLayoutTransitions.size() ) + { + layoutTransition = mLayoutTransitions.front(); + mLayoutTransitions.pop_front(); + mLayoutRequested = ( mLayoutTransitions.size() != 0 ); + } + else + { + mLayoutRequested = false; + } + + LayoutData layoutData( layoutTransition, layoutPositionDataArray, layoutDataArray, layoutAnimatorArray, childrenPropertiesAnimators ); + LayoutItem::Impl::sLayoutData = &layoutData; PerformLayout( stage.GetRootLayer(), 0, 0, stageWidth, stageHeight ); + PerformLayoutPositioning( layoutPositionDataArray, false ); + + PerformLayoutAnimation( layoutTransition, layoutPositionDataArray, layoutDataArray, layoutAnimatorArray ); + LayoutItem::Impl::sLayoutData = nullptr; + LAYOUT_DEBUG_AFTER_LAYOUT( stage.GetRootLayer() ); } } @@ -145,7 +190,6 @@ void LayoutController::PerformLayout( Actor root, int left, int top, int right, if( layout ) { - DALI_LOG_INFO( gLogFilter, Debug::Verbose, "LayoutController::PerformLayout on layout\n" ); layout->Layout( left, top, right, bottom ); } } @@ -161,6 +205,142 @@ void LayoutController::PerformLayout( Actor root, int left, int top, int right, } } +void LayoutController::PerformLayoutPositioning( LayoutPositionDataArray& layoutPositionDataArray, bool all ) const +{ + DALI_LOG_INFO( gLogFilter, Debug::Verbose, "LayoutController::PerformLayoutPositioning %d\n", (int)all ); + + for( auto layoutPositionData : layoutPositionDataArray ) + { + Actor actor = Actor::DownCast( layoutPositionData.handle ); + if( actor && ( !layoutPositionData.animated || all ) ) + { + DALI_LOG_INFO( gLogFilter, Debug::Verbose, "LayoutController::PerformLayoutPositioning %s\n", actor.GetName().c_str() ); + actor.SetPosition( layoutPositionData.left, layoutPositionData.top ); + actor.SetSize( layoutPositionData.right - layoutPositionData.left, layoutPositionData.bottom - layoutPositionData.top ); + } + } +} + +void LayoutController::PerformLayoutAnimation( LayoutTransition& layoutTransition, LayoutPositionDataArray& layoutPositionDataArray, LayoutDataArray& layoutDataArray, LayoutAnimatorArray& layoutAnimatorArray ) +{ + DALI_LOG_INFO( gLogFilter, Debug::Verbose, "LayoutController::PerformLayoutAnimation\n" ); + Animation animation = Animation::New( 0 ); + bool isAnimatorAdded = false; + + for( auto layoutDataElement : layoutDataArray ) + { + if ( layoutDataElement.animatorIndex >= 0 ) + { + Actor actor = Actor::DownCast( layoutDataElement.handle ); + if ( actor ) + { + LayoutDataAnimator animator = layoutAnimatorArray[ layoutDataElement.animatorIndex ]; + TimePeriod timePeriod = TimePeriod( 0, animation.GetDuration() ); + if (animator.timePeriod.durationSeconds >= 0) + { + timePeriod = animator.timePeriod; + } + + Property::Value value = layoutDataElement.targetValue; + // Capture calculated position and size values after layout if target values are not set. + // Other values are set to current actor ones. + if( value.GetType() == Property::NONE ) + { + if ( layoutDataElement.positionDataIndex < 0) + { + auto result = std::find_if( layoutPositionDataArray.begin(), layoutPositionDataArray.end(), [&actor](const LayoutPositionData& iter) + { return iter.handle == actor; } ); + if( result == layoutPositionDataArray.end() ) + { + continue; + } + layoutDataElement.positionDataIndex = std::distance(layoutPositionDataArray.begin(), result); + } + + LayoutPositionData& positionData = layoutPositionDataArray[ layoutDataElement.positionDataIndex ]; + + switch ( layoutDataElement.propertyIndex ) + { + case Actor::Property::POSITION: + value = Vector3( positionData.left, positionData.top, 0.0f ); + break; + case Actor::Property::POSITION_X: + value = positionData.left; + break; + case Actor::Property::POSITION_Y: + value = positionData.top; + break; + case Actor::Property::SIZE: + value = Vector3( positionData.right - positionData.left, positionData.bottom - positionData.top, 0.0f ); + break; + case Actor::Property::SIZE_WIDTH: + value = positionData.right - positionData.left; + break; + case Actor::Property::SIZE_HEIGHT: + value = positionData.bottom - positionData.top; + break; + default: + value = actor.GetProperty( layoutDataElement.propertyIndex ); + } + } + + // Failed to get target value, just move the next one + if( value.GetType() == Property::NONE ) + { + continue; + } + + // Set initial value + Property::Value initialValue = layoutDataElement.initialValue; + if( initialValue.GetType() != Property::NONE ) + { + actor.SetProperty( layoutDataElement.propertyIndex, initialValue ); + } + + // Create an animator for the property + switch (animator.animatorType) + { + case LayoutDataAnimator::AnimatorType::ANIMATE_TO: + { + animation.AnimateTo( Property( actor, layoutDataElement.propertyIndex ), value, animator.alphaFunction, timePeriod ); + break; + } + case LayoutDataAnimator::AnimatorType::ANIMATE_BY: + { + animation.AnimateBy( Property( actor, layoutDataElement.propertyIndex ), value, animator.alphaFunction, timePeriod ); + break; + } + case LayoutDataAnimator::AnimatorType::ANIMATE_BETWEEN: + { + animation.AnimateBetween( Property( actor, layoutDataElement.propertyIndex ), animator.keyFrames, animator.alphaFunction, animator.interpolation ); + break; + } + case LayoutDataAnimator::AnimatorType::ANIMATE_PATH: + animation.Animate( actor, animator.path, animator.forward, animator.alphaFunction, timePeriod ); + break; + } + } + isAnimatorAdded = true; + } + } + + if( isAnimatorAdded ) + { + if( mAnimation.GetState() == Animation::PLAYING ) + { + mAnimation.Clear(); + if( mAnimationFinishedFunctors.size() != 0 ) + { + mAnimationFinishedFunctors.front()( mAnimation ); + } + } + + mAnimation = animation; + mAnimationFinishedFunctors.push_back( AnimationFinishedFunctor( *this, layoutTransition, layoutPositionDataArray ) ); + mAnimation.FinishedSignal().Connect( mSlotDelegate.GetConnectionTracker(), mAnimationFinishedFunctors.back() ); + mAnimation.Play(); + } +} } // namespace Internal } // namespace Toolkit diff --git a/dali-toolkit/internal/layouting/layout-controller-impl.h b/dali-toolkit/internal/layouting/layout-controller-impl.h index 08db259..1c3130d 100644 --- a/dali-toolkit/internal/layouting/layout-controller-impl.h +++ b/dali-toolkit/internal/layouting/layout-controller-impl.h @@ -16,13 +16,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - +#include #include #include #include #include #include #include +#include namespace Dali { @@ -54,9 +55,9 @@ public: void Initialize(); /** - * This marks the given layout and all its parents as dirty. + * This marks the given layout and all its parents as dirty and triggers a transition if set. */ - void RequestLayout( LayoutItem& layout ); + void RequestLayout( LayoutItem& layout, int layoutTransitionType ); /** * Measures next level of layouts in the actor hierarchy. @@ -68,6 +69,16 @@ public: */ void PerformLayout( Actor root, int left, int top, int right, int bottom ); + /** + * Perform positioning of actors after layout update + */ + void PerformLayoutPositioning( LayoutPositionDataArray& layoutPositionDataArray, bool all ) const; + + /** + * Perform animation of actors properties after layout update + */ + void PerformLayoutAnimation( LayoutTransition& layoutTransition, LayoutPositionDataArray& layoutPositionDataArray, LayoutDataArray& layoutDataArray, LayoutAnimatorArray& layoutAnimatorArray ); + protected: // Implementation of Processor /** @@ -76,7 +87,40 @@ protected: // Implementation of Processor virtual void Process(); private: + std::list< LayoutTransition > mLayoutTransitions; + struct AnimationFinishedFunctor + { + AnimationFinishedFunctor( LayoutController& layoutController, LayoutTransition& layoutTransition, LayoutPositionDataArray& array ) + : layoutController( layoutController ), + layoutDataPositionArray(), + layoutItem( layoutTransition.layoutItem ), + layoutTransitionType( layoutTransition.layoutTransitionType ) + { + layoutDataPositionArray.swap( array ); + } + + void operator()( Animation& animation ) + { + layoutController.PerformLayoutPositioning( layoutDataPositionArray, true ); + layoutController.mAnimationFinishedFunctors.pop_front(); + if (layoutTransitionType != -1) + { + LayoutTransitionDataPtr layoutTransitionDataPtr = layoutItem->GetTransitionData( layoutTransitionType ); + layoutTransitionDataPtr->EmitSignalFinish( layoutTransitionType ); + } + } + + LayoutController& layoutController; + LayoutPositionDataArray layoutDataPositionArray; + LayoutItemPtr layoutItem; + int layoutTransitionType; + }; + bool mLayoutRequested; + Animation mAnimation; + std::list< AnimationFinishedFunctor > mAnimationFinishedFunctors; + + SlotDelegate mSlotDelegate; }; } // namespace Internal diff --git a/dali-toolkit/internal/layouting/layout-item-data-impl.cpp b/dali-toolkit/internal/layouting/layout-item-data-impl.cpp index 0833b3b..c97a8df 100644 --- a/dali-toolkit/internal/layouting/layout-item-data-impl.cpp +++ b/dali-toolkit/internal/layouting/layout-item-data-impl.cpp @@ -24,8 +24,10 @@ namespace Toolkit namespace Internal { -bool LayoutItem::Impl::sUseZeroUnspecifiedMeasureSpec = false; +class LayoutData; +bool LayoutItem::Impl::sUseZeroUnspecifiedMeasureSpec = false; +LayoutData* LayoutItem::Impl::sLayoutData = nullptr; LayoutItem::Impl::Impl() : mOwner( nullptr ), diff --git a/dali-toolkit/internal/layouting/layout-item-data-impl.h b/dali-toolkit/internal/layouting/layout-item-data-impl.h index 2347d28..0e68977 100644 --- a/dali-toolkit/internal/layouting/layout-item-data-impl.h +++ b/dali-toolkit/internal/layouting/layout-item-data-impl.h @@ -20,6 +20,7 @@ #include #include #include +#include namespace Dali { @@ -27,8 +28,6 @@ namespace Toolkit { namespace Internal { -class LayoutParent; - class LayoutItem::Impl { @@ -81,6 +80,13 @@ public: static bool sUseZeroUnspecifiedMeasureSpec; + LayoutTransitionDataPtr mOnChildAddTransitionData; + LayoutTransitionDataPtr mOnChildRemoveTransitionData; + LayoutTransitionDataPtr mOnOwnerSetTransitionData; + LayoutTransitionDataPtr mDefaultTransitionData; + + // To pass layout data during perform layout + static LayoutData* sLayoutData; }; } // namespace Internal diff --git a/dali-toolkit/internal/layouting/layout-transition-data-impl.cpp b/dali-toolkit/internal/layouting/layout-transition-data-impl.cpp new file mode 100644 index 0000000..f43ee79 --- /dev/null +++ b/dali-toolkit/internal/layouting/layout-transition-data-impl.cpp @@ -0,0 +1,502 @@ +/* + * Copyright (c) 2018 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. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace +{ +// Key tokens +const char* TOKEN_PROPERTY("property"); +const char* TOKEN_INITIAL_VALUE("initialValue"); +const char* TOKEN_TARGET_VALUE("targetValue"); +const char* TOKEN_ANIMATOR("animator"); +const char* TOKEN_TYPE("type"); +const char* TOKEN_NAME("name"); +const char* TOKEN_TIME_PERIOD("timePeriod"); +const char* TOKEN_DURATION("duration"); +const char* TOKEN_DELAY("delay"); +const char* TOKEN_ALPHA_FUNCTION("alphaFunction"); + +DALI_ENUM_TO_STRING_TABLE_BEGIN( ALPHA_FUNCTION_BUILTIN ) +DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::AlphaFunction, LINEAR) +DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::AlphaFunction, REVERSE) +DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::AlphaFunction, EASE_IN) +DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::AlphaFunction, EASE_OUT) +DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::AlphaFunction, EASE_IN_OUT) +DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::AlphaFunction, EASE_IN_SQUARE) +DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::AlphaFunction, EASE_OUT_SQUARE) +DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::AlphaFunction, EASE_IN_SINE) +DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::AlphaFunction, EASE_OUT_SINE) +DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::AlphaFunction, EASE_IN_OUT_SINE) +DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::AlphaFunction, EASE_OUT_BACK) +DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::AlphaFunction, BOUNCE) +DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::AlphaFunction, SIN) +DALI_ENUM_TO_STRING_TABLE_END( ALPHA_FUNCTION_BUILTIN ) + +} + +namespace Dali +{ +namespace Toolkit +{ +namespace Internal +{ + +LayoutTransitionData::LayoutTransitionData() +{ +} + +LayoutTransitionData::~LayoutTransitionData() +{ +} + +LayoutTransitionDataPtr LayoutTransitionData::New() +{ + LayoutTransitionDataPtr layoutAnimationData( new LayoutTransitionData() ); + return layoutAnimationData; +} + +LayoutTransitionData::PropertyAnimator::PropertyAnimator( ) + : handle( Actor( ) ) + , map() + , interpolation( Animation::Linear ) +{ +} + +LayoutTransitionData::PropertyAnimator::PropertyAnimator( Actor actor, Property::Map map ) + : handle( actor ) + , map( map ) + , interpolation( Animation::Linear ) +{ +} + +LayoutTransitionData::PropertyAnimator::PropertyAnimator( Actor actor, Property::Map map, Path path, Vector3 forward ) + : handle( actor ) + , map( map ) + , interpolation( Animation::Linear ) + , path( path ) + , forward( forward ) +{ +} + +LayoutTransitionData::PropertyAnimator::PropertyAnimator( Actor actor, Property::Map map, KeyFrames keyFrames, Animation::Interpolation interpolation ) + : handle( actor ) + , map( map ) + , keyFrames( keyFrames ) + , interpolation( interpolation ) +{ +} + +void LayoutTransitionData::AddPropertyAnimator( Actor actor, Property::Map map ) +{ + mPropertyAnimators.push_back( PropertyAnimator( actor, map ) ); +} + +void LayoutTransitionData::AddPropertyAnimator( Actor actor, Property::Map map, KeyFrames keyFrames, Animation::Interpolation interpolation ) +{ + mPropertyAnimators.push_back( PropertyAnimator( actor, map, keyFrames, interpolation ) ); +} + +void LayoutTransitionData::AddPropertyAnimator( Actor actor, Property::Map map, Path path, Vector3 forward ) +{ + mPropertyAnimators.push_back( PropertyAnimator( actor, map, path, forward ) ); +} + +bool LayoutTransitionData::ConvertToLayoutAnimator( const Property::Map& animatorMap, const PropertyAnimator& propertyAnimator, LayoutDataAnimator& layoutDataAnimator ) +{ + bool valid = true; + + for ( size_t animatorMapIdx = 0; animatorMapIdx < animatorMap.Count(); ++animatorMapIdx ) + { + const KeyValuePair pair( animatorMap.GetKeyValue( animatorMapIdx ) ); + + Property::Index indexKey = Property::INVALID_INDEX; + if ( pair.first.type == Property::Key::STRING ) + { + const std::string& key(pair.first.stringKey); + if( key == TOKEN_TYPE ) + { + indexKey = Dali::Toolkit::LayoutTransitionData::AnimatorKey::TYPE; + } + else if( key == TOKEN_NAME ) + { + indexKey = Dali::Toolkit::LayoutTransitionData::AnimatorKey::NAME; + } + else if( key == TOKEN_TIME_PERIOD ) + { + indexKey = Dali::Toolkit::LayoutTransitionData::AnimatorKey::TIME_PERIOD; + } + else if( key == TOKEN_ALPHA_FUNCTION ) + { + indexKey = Dali::Toolkit::LayoutTransitionData::AnimatorKey::ALPHA_FUNCTION; + } + } + else + { + indexKey = pair.first.indexKey; + } + + const Property::Value& value( pair.second ); + + if ( indexKey == Dali::Toolkit::LayoutTransitionData::AnimatorKey::ALPHA_FUNCTION ) + { + if ( value.GetType() == Property::ARRAY ) + { + valid = true; + Vector4 controlPoints; + Property::Array *array = value.GetArray(); + if ( array && array->Count() >= 4 ) + { + for ( size_t vecIdx = 0; vecIdx < 4; ++vecIdx ) + { + Property::Value& v = array->GetElementAt( vecIdx ); + if ( v.GetType() == Property::FLOAT ) + { + controlPoints[vecIdx] = v.Get(); + } + else + { + valid = false; + break; + } + } + } + else + { + valid = false; + } + + if ( valid ) + { + Vector2 controlPoint1( controlPoints.x, controlPoints.y ); + Vector2 controlPoint2( controlPoints.z, controlPoints.w ); + layoutDataAnimator.alphaFunction = AlphaFunction( controlPoint1, controlPoint2 ); + } + else + { + valid = false; + } + } + else if ( value.GetType() == Property::VECTOR4 ) + { + Vector4 controlPoints = value.Get(); + Vector2 controlPoint1( controlPoints.x, controlPoints.y ); + Vector2 controlPoint2( controlPoints.z, controlPoints.w ); + layoutDataAnimator.alphaFunction = AlphaFunction( controlPoint1, controlPoint2 ); + } + else if ( value.GetType() == Property::STRING ) + { + std::string alphaFunctionValue = value.Get(); + + if ( alphaFunctionValue == "LINEAR" ) + { + layoutDataAnimator.alphaFunction = AlphaFunction( AlphaFunction::LINEAR ); + } + else if ( !alphaFunctionValue.compare( 0, 5, "EASE_" ) ) + { + if ( alphaFunctionValue == "EASE_IN" ) + { + layoutDataAnimator.alphaFunction = AlphaFunction( AlphaFunction::EASE_IN ); + } + else if ( alphaFunctionValue == "EASE_OUT" ) + { + layoutDataAnimator.alphaFunction = AlphaFunction( AlphaFunction::EASE_OUT ); + } + else if ( !alphaFunctionValue.compare( 5, 3, "IN_" ) ) + { + if ( !alphaFunctionValue.compare( 8, -1, "SQUARE" ) ) + { + layoutDataAnimator.alphaFunction = AlphaFunction( AlphaFunction::EASE_IN_SQUARE ); + } + else if ( !alphaFunctionValue.compare( 8, -1, "OUT" ) ) + { + layoutDataAnimator.alphaFunction = AlphaFunction( AlphaFunction::EASE_IN_OUT ); + } + else if ( !alphaFunctionValue.compare( 8, -1, "OUT_SINE" ) ) + { + layoutDataAnimator.alphaFunction = AlphaFunction( AlphaFunction::EASE_IN_OUT_SINE ); + } + else if ( !alphaFunctionValue.compare( 8, -1, "SINE" ) ) + { + layoutDataAnimator.alphaFunction = AlphaFunction( AlphaFunction::EASE_IN_SINE ); + } + } + else if ( !alphaFunctionValue.compare( 5, 4, "OUT_" ) ) + { + if ( !alphaFunctionValue.compare( 9, -1, "SQUARE" ) ) + { + layoutDataAnimator.alphaFunction = AlphaFunction( AlphaFunction::EASE_OUT_SQUARE ); + } + else if ( !alphaFunctionValue.compare( 9, -1, "SINE" ) ) + { + layoutDataAnimator.alphaFunction = AlphaFunction( AlphaFunction::EASE_OUT_SINE ); + } + else if ( !alphaFunctionValue.compare( 9, -1, "BACK" ) ) + { + layoutDataAnimator.alphaFunction = AlphaFunction( AlphaFunction::EASE_OUT_BACK ); + } + } + } + else if ( alphaFunctionValue == "REVERSE" ) + { + layoutDataAnimator.alphaFunction = AlphaFunction( AlphaFunction::REVERSE ); + } + else if ( alphaFunctionValue == "BOUNCE" ) + { + layoutDataAnimator.alphaFunction = AlphaFunction( AlphaFunction::BOUNCE ); + } + else if ( alphaFunctionValue == "SIN" ) + { + layoutDataAnimator.alphaFunction = AlphaFunction( AlphaFunction::SIN ); + } + else + { + valid = false; + } + } + else + { + valid = false; + } + } + else if ( indexKey == Dali::Toolkit::LayoutTransitionData::AnimatorKey::NAME ) + { + if( value.GetType() == Property::STRING ) + { + layoutDataAnimator.name = value.Get(); + } + } + else if ( indexKey == Dali::Toolkit::LayoutTransitionData::AnimatorKey::TYPE ) + { + if( value.GetType() == Property::STRING ) + { + std::string animatorType = value.Get(); + if( animatorType == "ANIMATE_TO" ) + { + layoutDataAnimator.animatorType = LayoutDataAnimator::AnimatorType::ANIMATE_TO; + } + else if( animatorType == "ANIMATE_BY" ) + { + layoutDataAnimator.animatorType = LayoutDataAnimator::AnimatorType::ANIMATE_BY; + } + else if( animatorType == "ANIMATE_BETWEEN" ) + { + layoutDataAnimator.animatorType = LayoutDataAnimator::AnimatorType::ANIMATE_BETWEEN; + layoutDataAnimator.keyFrames = propertyAnimator.keyFrames; + } + else if( animatorType == "ANIMATE_PATH" ) + { + layoutDataAnimator.animatorType = LayoutDataAnimator::AnimatorType::ANIMATE_PATH; + layoutDataAnimator.path = propertyAnimator.path; + layoutDataAnimator.forward = propertyAnimator.forward; + } + } + } + else if ( indexKey == Dali::Toolkit::LayoutTransitionData::AnimatorKey::TIME_PERIOD ) + { + Property::Map timeMap = value.Get(); + for ( size_t timeMapIdx = 0; timeMapIdx < timeMap.Count(); ++timeMapIdx ) + { + const KeyValuePair pair( timeMap.GetKeyValue( timeMapIdx ) ); + indexKey = Property::INVALID_INDEX; + + if ( pair.first.type == Property::Key::STRING) + { + const std::string& key( pair.first.stringKey ); + if( key == TOKEN_DURATION ) + { + indexKey = Dali::Toolkit::LayoutTransitionData::AnimatorKey::DURATION; + } + else if( key == TOKEN_DELAY ) + { + indexKey = Dali::Toolkit::LayoutTransitionData::AnimatorKey::DELAY; + } + } + else + { + indexKey = pair.first.indexKey; + } + + if ( indexKey == Dali::Toolkit::LayoutTransitionData::AnimatorKey::DELAY ) + { + layoutDataAnimator.timePeriod.delaySeconds = pair.second.Get(); + } + else if ( indexKey == Dali::Toolkit::LayoutTransitionData::AnimatorKey::DURATION ) + { + layoutDataAnimator.timePeriod.durationSeconds = pair.second.Get(); + } + } + } + } + + return valid; +} + +bool LayoutTransitionData::ConvertToLayoutDataElement( const PropertyAnimator& propertyAnimator, LayoutDataElement& layoutDataElement, LayoutData& layoutData ) +{ + const Property::Map& map = propertyAnimator.map; + bool propertyFound = false; + + for( unsigned int mapIdx = 0; mapIdx < map.Count(); ++mapIdx ) + { + const KeyValuePair pair( map.GetKeyValue( mapIdx ) ); + const Property::Value& value( pair.second ); + Property::Index indexKey = Property::INVALID_INDEX; + + if ( pair.first.type == Property::Key::STRING ) + { + const std::string& key( pair.first.stringKey ); + if ( key == TOKEN_PROPERTY ) + { + indexKey = Dali::Toolkit::LayoutTransitionData::AnimatorKey::PROPERTY; + } + else if( key == TOKEN_INITIAL_VALUE ) + { + indexKey = Dali::Toolkit::LayoutTransitionData::AnimatorKey::INITIAL_VALUE; + } + else if( key == TOKEN_TARGET_VALUE ) + { + indexKey = Dali::Toolkit::LayoutTransitionData::AnimatorKey::TARGET_VALUE; + } + else if( key == TOKEN_ANIMATOR ) + { + indexKey = Dali::Toolkit::LayoutTransitionData::AnimatorKey::ANIMATOR; + } + } + else + { + indexKey = pair.first.indexKey; + } + + if( indexKey == Dali::Toolkit::LayoutTransitionData::AnimatorKey::PROPERTY ) + { + if( value.GetType() == Property::STRING ) + { + Actor actor = Actor::DownCast( layoutDataElement.handle ); + layoutDataElement.propertyIndex = DevelHandle::GetPropertyIndex( actor, Property::Key( value.Get() ) ); + } + else + { + layoutDataElement.propertyIndex = value.Get(); + } + propertyFound = true; + } + else if( indexKey == Dali::Toolkit::LayoutTransitionData::AnimatorKey::INITIAL_VALUE ) + { + layoutDataElement.initialValue = value; + } + else if( indexKey == Dali::Toolkit::LayoutTransitionData::AnimatorKey::TARGET_VALUE ) + { + layoutDataElement.targetValue = value; + } + else if( indexKey == Dali::Toolkit::LayoutTransitionData::AnimatorKey::ANIMATOR ) + { + if( value.GetType() == Property::STRING ) + { + std::string animatorName = value.Get(); + if ( animatorName.empty() ) + { + layoutDataElement.animatorIndex = 0; + } + else + { + auto animator = std::find_if( layoutData.layoutAnimatorArray.begin(), layoutData.layoutAnimatorArray.end(), [&animatorName](const LayoutDataAnimator& iter) { + return (iter.name == animatorName); } ); + if( animator != layoutData.layoutAnimatorArray.end() ) + { + layoutDataElement.animatorIndex = std::distance( layoutData.layoutAnimatorArray.begin(), animator ); + } + } + } + else if ( value.GetType() == Property::MAP ) + { + Property::Map animatorMap = value.Get< Property::Map >(); + LayoutDataAnimator layoutDataAnimator; + if( ConvertToLayoutAnimator( animatorMap, propertyAnimator, layoutDataAnimator ) ) + { + layoutData.layoutAnimatorArray.push_back( layoutDataAnimator ); + layoutDataElement.animatorIndex = layoutData.layoutAnimatorArray.size()-1; + } + } + } + } + + return propertyFound; +} + +void LayoutTransitionData::ConvertToLayoutDataElements( Actor owner, LayoutData& layoutData ) +{ + LayoutDataArray& layoutDataArray = layoutData.layoutDataArray; + // Add the children animators + for( const PropertyAnimator& iter : layoutData.childrenPropertyAnimators ) + { + LayoutDataElement layoutDataElement; + layoutDataElement.handle = owner; + layoutDataElement.positionDataIndex = layoutData.layoutPositionDataArray.size() - 1; + + if( ConvertToLayoutDataElement( iter, layoutDataElement, layoutData ) ) + { + layoutDataArray.push_back( layoutDataElement ); + } + } + + // Add the transition animators + for( const PropertyAnimator& iter : mPropertyAnimators ) + { + if( iter.handle == nullptr ) + { + layoutData.childrenPropertyAnimators.push_back( iter ); + continue; + } + + LayoutDataElement layoutDataElement; + layoutDataElement.handle = iter.handle; + if( ConvertToLayoutDataElement( iter, layoutDataElement, layoutData ) ) + { + layoutDataArray.push_back( layoutDataElement ); + } + } +} + +Dali::Toolkit::LayoutTransitionData::LayoutTransitionSignalType& LayoutTransitionData::FinishedSignal() +{ + return mFinishedSignal; +} + +void LayoutTransitionData::EmitSignalFinish( int layoutTransitionType ) +{ + if ( !mFinishedSignal.Empty() ) + { + Dali::Toolkit::LayoutTransitionData handle( this ); + mFinishedSignal.Emit( static_cast(layoutTransitionType), handle ); + } +} + +} // namespace Internal +} // namespace Toolkit +} // namespace Dali diff --git a/dali-toolkit/internal/layouting/layout-transition-data-impl.h b/dali-toolkit/internal/layouting/layout-transition-data-impl.h new file mode 100644 index 0000000..eb9e9d9 --- /dev/null +++ b/dali-toolkit/internal/layouting/layout-transition-data-impl.h @@ -0,0 +1,246 @@ +#ifndef DALI_TOOLKIT_INTERNAL_LAYOUTING_LAYOUT_TRANSITION_DATA_IMPL_H +#define DALI_TOOLKIT_INTERNAL_LAYOUTING_LAYOUT_TRANSITION_DATA_IMPL_H +/* + * Copyright (c) 2018 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. + */ + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace Dali +{ +namespace Toolkit +{ +namespace Internal +{ + +struct LayoutTransition +{ + LayoutTransition( LayoutItem& layoutItem, int layoutTransitionType ) + : layoutItem( &layoutItem ) + , layoutTransitionType( layoutTransitionType ) + { + } + + LayoutTransition() + : layoutTransitionType( -1 ) + { + } + + bool operator==( const LayoutTransition& rhs ) + { + return ( ( layoutItem.Get() == rhs.layoutItem.Get() ) && layoutTransitionType == rhs.layoutTransitionType ); + } + + LayoutItemPtr layoutItem; + int layoutTransitionType; +}; + +const float DEFAULT_TRANSITION_DURATION( 0.5f ); + +struct LayoutDataAnimator +{ + enum class AnimatorType + { + ANIMATE_TO, + ANIMATE_BY, + ANIMATE_BETWEEN, + ANIMATE_PATH + }; + + LayoutDataAnimator() + : animatorType( AnimatorType::ANIMATE_TO ), + alphaFunction( AlphaFunction::LINEAR ), + timePeriod( 0.0f, DEFAULT_TRANSITION_DURATION ), + interpolation( Animation::Linear ) + { + } + + std::string name; + AnimatorType animatorType; + AlphaFunction alphaFunction; + TimePeriod timePeriod; + + KeyFrames keyFrames; + Animation::Interpolation interpolation; + + Path path; + Vector3 forward; +}; + +using LayoutAnimatorArray = std::vector< LayoutDataAnimator >; + +struct LayoutPositionData +{ + LayoutPositionData( Handle handle, float left, float top, float right, float bottom, bool animated ) : + handle( handle ), left( left ), top( top ), right( right ), bottom( bottom ), animated( animated ) + { + }; + + BaseHandle handle; + float left; + float top; + float right; + float bottom; + bool animated; +}; + +using LayoutPositionDataArray = std::vector< LayoutPositionData >; + +struct LayoutDataElement +{ + LayoutDataElement() + : propertyIndex( Property::INVALID_KEY ), animatorIndex( -1 ), positionDataIndex(-1 ) + { + }; + + LayoutDataElement( Actor actor, Property::Index propertyIndex, Property::Value value ) + : handle( actor ), + propertyIndex( propertyIndex ), + targetValue( value ), + animatorIndex( -1 ), + positionDataIndex( -1 ) + { + }; + + BaseHandle handle; + Property::Index propertyIndex; + Property::Value initialValue; + Property::Value targetValue; + int animatorIndex; + int positionDataIndex; +}; + +class LayoutTransitionData; +using LayoutTransitionDataPtr = IntrusivePtr; + +/** + * LayoutTransitionData implementation class. + */ +class DALI_TOOLKIT_API LayoutTransitionData : public BaseObject +{ +public: + struct PropertyAnimator + { + PropertyAnimator(); + PropertyAnimator( Actor actor, Property::Map map ); + PropertyAnimator( Actor actor, Property::Map map, Path path, Vector3 forward ); + PropertyAnimator( Actor actor, Property::Map map, KeyFrames keyFrames, Animation::Interpolation interpolation ); + + BaseHandle handle; + + Property::Map map; + + KeyFrames keyFrames; + Animation::Interpolation interpolation; + + Path path; + Vector3 forward; + }; + + using PropertyAnimatorArray = std::vector< PropertyAnimator >; + + static LayoutTransitionDataPtr New(); + + LayoutTransitionData( const LayoutTransitionData& ) = delete; + LayoutTransitionData& operator=( const LayoutTransitionData& ) = delete; + + void AddPropertyAnimator( Actor actor, Property::Map map ); + void AddPropertyAnimator( Actor actor, Property::Map map, KeyFrames keyFrames, Animation::Interpolation interpolation ); + void AddPropertyAnimator( Actor actor, Property::Map map, Path path, Vector3 forward ); + + void ConvertToLayoutDataElements( Actor, LayoutData& layoutData ); + + /** + * @copydoc Dali::Animation::FinishedSignal() + */ + Dali::Toolkit::LayoutTransitionData::LayoutTransitionSignalType& FinishedSignal(); + + void EmitSignalFinish( int layoutTransitionType ); + +private: + bool ConvertToLayoutAnimator( const Property::Map& animatorData, const PropertyAnimator& propertyAnimator, LayoutDataAnimator& layoutAnimator ); + bool ConvertToLayoutDataElement( const PropertyAnimator& propertyAnimator, LayoutDataElement& layoutDataElement, LayoutData& layoutData ); + + PropertyAnimatorArray mPropertyAnimators; + + /** + * Ref counted object - Only allow construction via New(). + */ + LayoutTransitionData(); + +protected: + /** + * A ref counted object may only be deleted by calling Unreference + */ + virtual ~LayoutTransitionData(); + + Dali::Toolkit::LayoutTransitionData::LayoutTransitionSignalType mFinishedSignal; +}; + +using PropertyAnimatorArray = std::vector< LayoutTransitionData::PropertyAnimator >; +using LayoutTransitionDataArray = std::vector< LayoutTransitionDataPtr >; +using LayoutDataArray = std::vector< LayoutDataElement >; + +struct LayoutData +{ + LayoutData( LayoutTransition& layoutTransition, LayoutPositionDataArray& layoutPositionDataArray, LayoutDataArray& layoutDataArray, + LayoutAnimatorArray& layoutAnimatorArray, PropertyAnimatorArray& childrenPropertyAnimators ) + : speculativeLayout( false ), + layoutTransition( layoutTransition ), + layoutPositionDataArray( layoutPositionDataArray ), + layoutDataArray( layoutDataArray), + layoutAnimatorArray( layoutAnimatorArray ), + childrenPropertyAnimators( childrenPropertyAnimators ) + { + }; + + bool speculativeLayout; + LayoutTransition& layoutTransition; + LayoutPositionDataArray& layoutPositionDataArray; + LayoutDataArray& layoutDataArray; + LayoutAnimatorArray& layoutAnimatorArray; + PropertyAnimatorArray& childrenPropertyAnimators; +}; + +} //namespace Internal + +inline Internal::LayoutTransitionData& GetImplementation( Dali::Toolkit::LayoutTransitionData& handle ) +{ + DALI_ASSERT_ALWAYS( handle && "LayoutTransitionData handle is empty" ); + BaseObject& object = handle.GetBaseObject(); + return static_cast< Internal::LayoutTransitionData& >( object ); +} + +inline const Internal::LayoutTransitionData& GetImplementation( const Dali::Toolkit::LayoutTransitionData& handle ) +{ + DALI_ASSERT_ALWAYS( handle && "LayoutTransitionData handle is empty" ); + const BaseObject& object = handle.GetBaseObject(); + return static_cast< const Internal::LayoutTransitionData& >( object ); +} + +} //namespace Toolkit +} //namespace Dali + +#endif // DALI_TOOLKIT_INTERNAL_LAYOUTING_LAYOUT_TRANSITION_DATA_IMPL_H