add drag&drop support in actor level
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / layouting / layout-controller-impl.cpp
1 /*
2  * Copyright (c) 2018 Samsung Electronics Co., Ltd.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
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>
26
27 using namespace Dali;
28
29 namespace
30 {
31
32 #if defined(DEBUG_ENABLED)
33 static Debug::Filter* gLogFilter = Debug::Filter::New( Debug::NoLogging, false, "LOG_LAYOUT" );
34 #endif
35
36 }
37
38 namespace Dali
39 {
40 namespace Toolkit
41 {
42 namespace Internal
43 {
44
45 LayoutController::LayoutController()
46 : mLayoutRequested( false ),
47   mSlotDelegate( this )
48 {
49 }
50
51 LayoutController::~LayoutController()
52 {
53 }
54
55 void LayoutController::Initialize()
56 {
57   mAnimation = Animation::New( 0.0f );
58 }
59
60 void LayoutController::RequestLayout( LayoutItem& layoutItem, int layoutTransitionType )
61 {
62   auto actor = Actor::DownCast( layoutItem.GetOwner() );
63   if ( actor )
64   {
65     DALI_LOG_INFO( gLogFilter, Debug::Concise, "LayoutController::RequestLayout owner[%s] layoutItem[%p] layoutAnimationType(%d)\n", actor.GetName().c_str(), &layoutItem, layoutTransitionType );
66   }
67   else
68   {
69     DALI_LOG_INFO( gLogFilter, Debug::Concise, "LayoutController::RequestLayout layoutItem[%p] layoutAnimationType(%d)\n", &layoutItem, layoutTransitionType );
70   }
71
72   mLayoutRequested = true;
73   if( layoutTransitionType != -1 )
74   {
75     LayoutTransition layoutTransition = LayoutTransition( layoutItem, layoutTransitionType );
76     if( std::find( mLayoutTransitions.begin(), mLayoutTransitions.end(), layoutTransition ) == mLayoutTransitions.end() && layoutItem.GetTransitionData( layoutTransitionType ).Get() )
77     {
78       mLayoutTransitions.push_back( layoutTransition );
79     }
80   }
81
82   // Go up the tree and mark all parents to relayout
83   LayoutParent* layoutParent = layoutItem.GetParent();
84   if( layoutParent )
85   {
86     LayoutGroup& layoutGroup = static_cast< LayoutGroup& >( *layoutParent );
87     if( ! layoutGroup.IsLayoutRequested() )
88     {
89       layoutGroup.RequestLayout();
90     }
91   }
92 }
93
94 void LayoutController::Process()
95 {
96   // Perform the full process.
97   DALI_LOG_INFO( gLogFilter, Debug::Concise, "LayoutController::Process\n" );
98
99   if( mLayoutRequested )
100   {
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;
105
106     MeasureSpec widthSpec( stageWidth, MeasureSpec::Mode::EXACTLY );
107     MeasureSpec heightSpec( stageHeight, MeasureSpec::Mode::EXACTLY );
108
109     // Test how to perform a measure on each control.
110     MeasureHierarchy( stage.GetRootLayer(), widthSpec, heightSpec );
111
112     LAYOUT_DEBUG_MEASURE_STATES( stage.GetRootLayer() );
113
114     LayoutTransition layoutTransition;
115     LayoutPositionDataArray layoutPositionDataArray;
116     LayoutDataArray layoutDataArray;
117     LayoutAnimatorArray layoutAnimatorArray;
118     layoutAnimatorArray.push_back( LayoutDataAnimator() );
119     PropertyAnimatorArray childrenPropertiesAnimators;
120
121     if ( mLayoutTransitions.size() )
122     {
123       layoutTransition = mLayoutTransitions.front();
124       mLayoutTransitions.pop_front();
125       mLayoutRequested = ( mLayoutTransitions.size() != 0 );
126     }
127     else
128     {
129       mLayoutRequested = false;
130     }
131
132     LayoutData layoutData( layoutTransition, layoutPositionDataArray, layoutDataArray, layoutAnimatorArray, childrenPropertiesAnimators );
133     LayoutItem::Impl::sLayoutData = &layoutData;
134     PerformLayout( stage.GetRootLayer(), 0, 0, stageWidth, stageHeight );
135
136     PerformLayoutPositioning( layoutPositionDataArray, false );
137
138     PerformLayoutAnimation( layoutTransition, layoutPositionDataArray, layoutDataArray, layoutAnimatorArray );
139     LayoutItem::Impl::sLayoutData = nullptr;
140
141     LAYOUT_DEBUG_AFTER_LAYOUT( stage.GetRootLayer() );
142   }
143 }
144
145 void LayoutController::MeasureHierarchy( Actor root, MeasureSpec widthSpec, MeasureSpec heightSpec )
146 {
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.
150   //
151   // If in a leaf actor with no layout, it's natural size is bubbled back up.
152   //
153   // What happens if nothing in the tree has a layout?
154
155   Toolkit::Control control = Toolkit::Control::DownCast( root );
156   if( control )
157   {
158     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "LayoutController::Measuring control:%s\n", control.GetName().c_str() );
159     Internal::Control& controlImpl = GetImplementation( control );
160
161     Internal::Control::Impl& controlDataImpl = Internal::Control::Impl::Get( controlImpl );
162     LayoutItemPtr layout = controlDataImpl.GetLayout();
163
164     if( layout )
165     {
166       layout->Measure( widthSpec, heightSpec );
167     }
168   }
169   else
170   {
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 )
174     {
175       Actor child = root.GetChildAt( i );
176       MeasureHierarchy( child, widthSpec, heightSpec );
177     }
178   }
179 }
180
181 void LayoutController::PerformLayout( Actor root, int left, int top, int right, int bottom )
182 {
183   Toolkit::Control control = Toolkit::Control::DownCast( root );
184   if( control )
185   {
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();
190
191     if( layout )
192     {
193       layout->Layout( left, top, right, bottom );
194     }
195   }
196   else
197   {
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 )
201     {
202       Actor child = root.GetChildAt( i );
203       PerformLayout( child, left, top, right, bottom );
204     }
205   }
206 }
207
208 void LayoutController::PerformLayoutPositioning( LayoutPositionDataArray& layoutPositionDataArray, bool all ) const
209 {
210   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "LayoutController::PerformLayoutPositioning %d\n", (int)all );
211
212   for( auto layoutPositionData : layoutPositionDataArray )
213   {
214     Actor actor = Actor::DownCast( layoutPositionData.handle );
215     if( actor && ( !layoutPositionData.animated || all ) )
216     {
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 );
220     }
221   }
222 }
223
224 void LayoutController::PerformLayoutAnimation( LayoutTransition& layoutTransition, LayoutPositionDataArray& layoutPositionDataArray, LayoutDataArray& layoutDataArray, LayoutAnimatorArray& layoutAnimatorArray )
225 {
226   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "LayoutController::PerformLayoutAnimation\n" );
227   Animation animation = Animation::New( 0 );
228   bool isAnimatorAdded = false;
229
230   for( auto layoutDataElement : layoutDataArray )
231   {
232     if ( layoutDataElement.animatorIndex >= 0 )
233     {
234       Actor actor = Actor::DownCast( layoutDataElement.handle );
235       if ( actor )
236       {
237         LayoutDataAnimator animator = layoutAnimatorArray[ layoutDataElement.animatorIndex ];
238         TimePeriod timePeriod = TimePeriod( 0, animation.GetDuration() );
239         if (animator.timePeriod.durationSeconds >= 0)
240         {
241           timePeriod = animator.timePeriod;
242         }
243
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 )
248         {
249           if ( layoutDataElement.positionDataIndex < 0)
250           {
251             auto result = std::find_if( layoutPositionDataArray.begin(), layoutPositionDataArray.end(), [&actor](const LayoutPositionData& iter)
252                           { return iter.handle == actor; } );
253             if( result == layoutPositionDataArray.end() )
254             {
255               continue;
256             }
257             layoutDataElement.positionDataIndex = std::distance(layoutPositionDataArray.begin(), result);
258           }
259
260           LayoutPositionData& positionData = layoutPositionDataArray[ layoutDataElement.positionDataIndex ];
261
262           switch ( layoutDataElement.propertyIndex )
263           {
264           case Actor::Property::POSITION:
265             value = Vector3( positionData.left, positionData.top, 0.0f );
266             break;
267           case Actor::Property::POSITION_X:
268             value = positionData.left;
269             break;
270           case Actor::Property::POSITION_Y:
271             value = positionData.top;
272             break;
273           case Actor::Property::SIZE:
274             value = Vector3( positionData.right - positionData.left, positionData.bottom - positionData.top, 0.0f );
275             break;
276           case Actor::Property::SIZE_WIDTH:
277             value = positionData.right - positionData.left;
278             break;
279           case Actor::Property::SIZE_HEIGHT:
280             value = positionData.bottom - positionData.top;
281             break;
282           default:
283             value = actor.GetProperty( layoutDataElement.propertyIndex );
284           }
285         }
286
287         // Failed to get target value, just move the next one
288         if( value.GetType() == Property::NONE )
289         {
290           continue;
291         }
292
293         // Set initial value
294         Property::Value initialValue = layoutDataElement.initialValue;
295         if( initialValue.GetType() != Property::NONE )
296         {
297           actor.SetProperty( layoutDataElement.propertyIndex, initialValue );
298         }
299
300         // Create an animator for the property
301         switch (animator.animatorType)
302         {
303         case LayoutDataAnimator::AnimatorType::ANIMATE_TO:
304         {
305           animation.AnimateTo( Property( actor, layoutDataElement.propertyIndex ), value, animator.alphaFunction, timePeriod );
306           break;
307         }
308         case LayoutDataAnimator::AnimatorType::ANIMATE_BY:
309         {
310           animation.AnimateBy( Property( actor, layoutDataElement.propertyIndex ), value, animator.alphaFunction, timePeriod );
311           break;
312         }
313         case LayoutDataAnimator::AnimatorType::ANIMATE_BETWEEN:
314         {
315           animation.AnimateBetween( Property( actor, layoutDataElement.propertyIndex ), animator.keyFrames, animator.alphaFunction, animator.interpolation );
316           break;
317         }
318         case LayoutDataAnimator::AnimatorType::ANIMATE_PATH:
319           animation.Animate( actor, animator.path, animator.forward, animator.alphaFunction, timePeriod );
320           break;
321         }
322       }
323       isAnimatorAdded = true;
324     }
325   }
326
327   if( isAnimatorAdded )
328   {
329     if( mAnimation.GetState() == Animation::PLAYING )
330     {
331       mAnimation.Clear();
332       if( mAnimationFinishedFunctors.size() != 0 )
333       {
334         mAnimationFinishedFunctors.front()( mAnimation );
335       }
336     }
337
338     mAnimation = animation;
339     mAnimationFinishedFunctors.push_back( AnimationFinishedFunctor( *this, layoutTransition, layoutPositionDataArray ) );
340     mAnimation.FinishedSignal().Connect( mSlotDelegate.GetConnectionTracker(), mAnimationFinishedFunctors.back() );
341     mAnimation.Play();
342   }
343 }
344
345 } // namespace Internal
346 } // namespace Toolkit
347 } // namespace Dali