2 * Copyright (c) 2018 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #include <dali/public-api/common/stage.h>
18 #include <dali/public-api/actors/layer.h>
19 #include <dali-toolkit/internal/layouting/layout-controller-impl.h>
20 #include <dali-toolkit/internal/layouting/layout-item-data-impl.h>
21 #include <dali-toolkit/devel-api/layouting/layout-group-impl.h>
22 #include <dali-toolkit/public-api/controls/control.h>
23 #include <dali-toolkit/public-api/controls/control-impl.h>
24 #include <dali-toolkit/internal/controls/control/control-data-impl.h>
25 #include <dali-toolkit/internal/layouting/layout-controller-debug.h>
32 #if defined(DEBUG_ENABLED)
33 static Debug::Filter* gLogFilter = Debug::Filter::New( Debug::NoLogging, false, "LOG_LAYOUT" );
45 LayoutController::LayoutController()
46 : mLayoutRequested( false ),
51 LayoutController::~LayoutController()
55 void LayoutController::Initialize()
57 mAnimation = Animation::New( 0.0f );
60 void LayoutController::RequestLayout( LayoutItem& layoutItem, int layoutTransitionType )
62 auto actor = Actor::DownCast( layoutItem.GetOwner() );
65 DALI_LOG_INFO( gLogFilter, Debug::Concise, "LayoutController::RequestLayout owner[%s] layoutItem[%p] layoutAnimationType(%d)\n", actor.GetName().c_str(), &layoutItem, layoutTransitionType );
69 DALI_LOG_INFO( gLogFilter, Debug::Concise, "LayoutController::RequestLayout layoutItem[%p] layoutAnimationType(%d)\n", &layoutItem, layoutTransitionType );
72 mLayoutRequested = true;
73 if( layoutTransitionType != -1 )
75 LayoutTransition layoutTransition = LayoutTransition( layoutItem, layoutTransitionType );
76 if( std::find( mLayoutTransitions.begin(), mLayoutTransitions.end(), layoutTransition ) == mLayoutTransitions.end() && layoutItem.GetTransitionData( layoutTransitionType ).Get() )
78 mLayoutTransitions.push_back( layoutTransition );
82 // Go up the tree and mark all parents to relayout
83 LayoutParent* layoutParent = layoutItem.GetParent();
86 LayoutGroup& layoutGroup = static_cast< LayoutGroup& >( *layoutParent );
87 if( ! layoutGroup.IsLayoutRequested() )
89 layoutGroup.RequestLayout();
94 void LayoutController::Process()
96 // Perform the full process.
97 DALI_LOG_INFO( gLogFilter, Debug::Concise, "LayoutController::Process\n" );
99 if( mLayoutRequested )
101 // If window size has changed, expect stage to have already been updated
102 Stage stage = Stage::GetCurrent();
103 auto stageWidth = stage.GetSize().width;
104 auto stageHeight = stage.GetSize().height;
106 MeasureSpec widthSpec( stageWidth, MeasureSpec::Mode::EXACTLY );
107 MeasureSpec heightSpec( stageHeight, MeasureSpec::Mode::EXACTLY );
109 // Test how to perform a measure on each control.
110 MeasureHierarchy( stage.GetRootLayer(), widthSpec, heightSpec );
112 LAYOUT_DEBUG_MEASURE_STATES( stage.GetRootLayer() );
114 LayoutTransition layoutTransition;
115 LayoutPositionDataArray layoutPositionDataArray;
116 LayoutDataArray layoutDataArray;
117 LayoutAnimatorArray layoutAnimatorArray;
118 layoutAnimatorArray.push_back( LayoutDataAnimator() );
119 PropertyAnimatorArray childrenPropertiesAnimators;
121 if ( mLayoutTransitions.size() )
123 layoutTransition = mLayoutTransitions.front();
124 mLayoutTransitions.pop_front();
125 mLayoutRequested = ( mLayoutTransitions.size() != 0 );
129 mLayoutRequested = false;
132 LayoutData layoutData( layoutTransition, layoutPositionDataArray, layoutDataArray, layoutAnimatorArray, childrenPropertiesAnimators );
133 LayoutItem::Impl::sLayoutData = &layoutData;
134 PerformLayout( stage.GetRootLayer(), 0, 0, stageWidth, stageHeight );
136 PerformLayoutPositioning( layoutPositionDataArray, false );
138 PerformLayoutAnimation( layoutTransition, layoutPositionDataArray, layoutDataArray, layoutAnimatorArray );
139 LayoutItem::Impl::sLayoutData = nullptr;
141 LAYOUT_DEBUG_AFTER_LAYOUT( stage.GetRootLayer() );
145 void LayoutController::MeasureHierarchy( Actor root, MeasureSpec widthSpec, MeasureSpec heightSpec )
147 // Does this actor have a layout?
148 // Yes - measure the layout. It will call this method again for each of it's children.
149 // No - recurse through actor children.
151 // If in a leaf actor with no layout, it's natural size is bubbled back up.
153 // What happens if nothing in the tree has a layout?
155 Toolkit::Control control = Toolkit::Control::DownCast( root );
158 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "LayoutController::Measuring control:%s\n", control.GetName().c_str() );
159 Internal::Control& controlImpl = GetImplementation( control );
161 Internal::Control::Impl& controlDataImpl = Internal::Control::Impl::Get( controlImpl );
162 LayoutItemPtr layout = controlDataImpl.GetLayout();
166 layout->Measure( widthSpec, heightSpec );
171 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "LayoutController::Measuring (%u) children\n", root.GetChildCount() );
172 // Depth first descent through actor children
173 for( unsigned int i = 0, count = root.GetChildCount(); i < count; ++i )
175 Actor child = root.GetChildAt( i );
176 MeasureHierarchy( child, widthSpec, heightSpec );
181 void LayoutController::PerformLayout( Actor root, int left, int top, int right, int bottom )
183 Toolkit::Control control = Toolkit::Control::DownCast( root );
186 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "LayoutController::PerformLayout on control[%s]\n", control.GetName().c_str() );
187 Internal::Control& controlImpl = GetImplementation( control );
188 Internal::Control::Impl& controlDataImpl = Internal::Control::Impl::Get( controlImpl );
189 LayoutItemPtr layout = controlDataImpl.GetLayout();
193 layout->Layout( left, top, right, bottom );
198 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "LayoutController::PerformLayout (%u) children\n", root.GetChildCount() );
199 // Depth first descent through actor children
200 for( unsigned int i = 0, count = root.GetChildCount(); i < count; ++i )
202 Actor child = root.GetChildAt( i );
203 PerformLayout( child, left, top, right, bottom );
208 void LayoutController::PerformLayoutPositioning( LayoutPositionDataArray& layoutPositionDataArray, bool all ) const
210 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "LayoutController::PerformLayoutPositioning %d\n", (int)all );
212 for( auto layoutPositionData : layoutPositionDataArray )
214 Actor actor = Actor::DownCast( layoutPositionData.handle );
215 if( actor && ( !layoutPositionData.animated || all ) )
217 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "LayoutController::PerformLayoutPositioning %s\n", actor.GetName().c_str() );
218 actor.SetPosition( layoutPositionData.left, layoutPositionData.top );
219 actor.SetSize( layoutPositionData.right - layoutPositionData.left, layoutPositionData.bottom - layoutPositionData.top );
224 void LayoutController::PerformLayoutAnimation( LayoutTransition& layoutTransition, LayoutPositionDataArray& layoutPositionDataArray, LayoutDataArray& layoutDataArray, LayoutAnimatorArray& layoutAnimatorArray )
226 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "LayoutController::PerformLayoutAnimation\n" );
227 Animation animation = Animation::New( 0 );
228 bool isAnimatorAdded = false;
230 for( auto layoutDataElement : layoutDataArray )
232 if ( layoutDataElement.animatorIndex >= 0 )
234 Actor actor = Actor::DownCast( layoutDataElement.handle );
237 LayoutDataAnimator animator = layoutAnimatorArray[ layoutDataElement.animatorIndex ];
238 TimePeriod timePeriod = TimePeriod( 0, animation.GetDuration() );
239 if (animator.timePeriod.durationSeconds >= 0)
241 timePeriod = animator.timePeriod;
244 Property::Value value = layoutDataElement.targetValue;
245 // Capture calculated position and size values after layout if target values are not set.
246 // Other values are set to current actor ones.
247 if( value.GetType() == Property::NONE )
249 if ( layoutDataElement.positionDataIndex < 0)
251 auto result = std::find_if( layoutPositionDataArray.begin(), layoutPositionDataArray.end(), [&actor](const LayoutPositionData& iter)
252 { return iter.handle == actor; } );
253 if( result == layoutPositionDataArray.end() )
257 layoutDataElement.positionDataIndex = std::distance(layoutPositionDataArray.begin(), result);
260 LayoutPositionData& positionData = layoutPositionDataArray[ layoutDataElement.positionDataIndex ];
262 switch ( layoutDataElement.propertyIndex )
264 case Actor::Property::POSITION:
265 value = Vector3( positionData.left, positionData.top, 0.0f );
267 case Actor::Property::POSITION_X:
268 value = positionData.left;
270 case Actor::Property::POSITION_Y:
271 value = positionData.top;
273 case Actor::Property::SIZE:
274 value = Vector3( positionData.right - positionData.left, positionData.bottom - positionData.top, 0.0f );
276 case Actor::Property::SIZE_WIDTH:
277 value = positionData.right - positionData.left;
279 case Actor::Property::SIZE_HEIGHT:
280 value = positionData.bottom - positionData.top;
283 value = actor.GetProperty( layoutDataElement.propertyIndex );
287 // Failed to get target value, just move the next one
288 if( value.GetType() == Property::NONE )
294 Property::Value initialValue = layoutDataElement.initialValue;
295 if( initialValue.GetType() != Property::NONE )
297 actor.SetProperty( layoutDataElement.propertyIndex, initialValue );
300 // Create an animator for the property
301 switch (animator.animatorType)
303 case LayoutDataAnimator::AnimatorType::ANIMATE_TO:
305 animation.AnimateTo( Property( actor, layoutDataElement.propertyIndex ), value, animator.alphaFunction, timePeriod );
308 case LayoutDataAnimator::AnimatorType::ANIMATE_BY:
310 animation.AnimateBy( Property( actor, layoutDataElement.propertyIndex ), value, animator.alphaFunction, timePeriod );
313 case LayoutDataAnimator::AnimatorType::ANIMATE_BETWEEN:
315 animation.AnimateBetween( Property( actor, layoutDataElement.propertyIndex ), animator.keyFrames, animator.alphaFunction, animator.interpolation );
318 case LayoutDataAnimator::AnimatorType::ANIMATE_PATH:
319 animation.Animate( actor, animator.path, animator.forward, animator.alphaFunction, timePeriod );
323 isAnimatorAdded = true;
327 if( isAnimatorAdded )
329 if( mAnimation.GetState() == Animation::PLAYING )
332 if( mAnimationFinishedFunctors.size() != 0 )
334 mAnimationFinishedFunctors.front()( mAnimation );
338 mAnimation = animation;
339 mAnimationFinishedFunctors.push_back( AnimationFinishedFunctor( *this, layoutTransition, layoutPositionDataArray ) );
340 mAnimation.FinishedSignal().Connect( mSlotDelegate.GetConnectionTracker(), mAnimationFinishedFunctors.back() );
345 } // namespace Internal
346 } // namespace Toolkit