Control impl layout code for Margin removed
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / devel-api / layouting / layout-item-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/integration-api/debug.h>
18
19 #include <dali/public-api/animation/animation.h>
20 #include <dali/public-api/object/type-registry-helper.h>
21 #include <dali-toolkit/public-api/controls/control.h>
22 #include <dali/devel-api/object/handle-devel.h>
23 #include <dali-toolkit/devel-api/layouting/layout-item-impl.h>
24 #include <dali-toolkit/devel-api/layouting/layout-group-impl.h>
25 #include <dali-toolkit/internal/layouting/layout-transition-data-impl.h>
26 #include <dali-toolkit/internal/layouting/layout-item-data-impl.h>
27
28 #include <dali/devel-api/scripting/enum-helper.h>
29
30 namespace
31 {
32
33 #if defined(DEBUG_ENABLED)
34 Debug::Filter* gLayoutFilter = Debug::Filter::New( Debug::NoLogging, false, "LOG_LAYOUT" );
35 #endif
36
37 const char* WIDTH_SPECIFICATION_NAME( "widthSpecification" );
38 const char* HEIGHT_SPECIFICATION_NAME( "heightSpecification" );
39
40 }
41
42 namespace Dali
43 {
44 namespace Toolkit
45 {
46 namespace Internal
47 {
48
49 LayoutItem::LayoutItem()
50 : mImpl( new LayoutItem::Impl() ),
51   mSlotDelegate( this )
52 {
53 }
54
55 LayoutItem::~LayoutItem()
56 {
57   // An object with a unique_ptr to an opaque structure must define it's destructor in the translation unit
58   // where the opaque structure is defined. It cannot use the default method in the header file.
59 }
60
61 LayoutItemPtr LayoutItem::New( Handle& owner )
62 {
63   LayoutItemPtr layoutPtr = new LayoutItem();
64   return layoutPtr;
65 }
66
67 void LayoutItem::Initialize( Handle& owner, const std::string& containerType )
68 {
69   mImpl->mOwner = owner;
70   RegisterChildProperties( containerType );
71   OnInitialize(); // Ensure direct deriving class gets initialized
72 }
73
74 Handle LayoutItem::GetOwner() const
75 {
76   return mImpl->mOwner.GetHandle();
77 }
78
79 void LayoutItem::Unparent()
80 {
81   // Enable directly derived types to first remove children
82   OnUnparent();
83
84   // Remove myself from parent
85   LayoutParent* parent = GetParent();
86   if( parent )
87   {
88     parent->Remove( *this );
89   }
90
91   // Remove parent reference
92   SetParent(nullptr);
93
94   // Last, clear owner
95   mImpl->mOwner.Reset();
96 }
97
98 LayoutTransitionDataPtr LayoutItem::GetDefaultTransition()
99 {
100   DALI_LOG_INFO( gLayoutFilter, Debug::Verbose, "LayoutItem::GetDefaultTransition\n" );
101   if ( !mImpl->mDefaultTransitionData.Get() )
102   {
103     auto owner = GetOwner();
104     auto actor = Actor::DownCast( owner );
105
106     mImpl->mDefaultTransitionData = LayoutTransitionData::New();
107     {
108       Property::Map map;
109       map[ Dali::Toolkit::LayoutTransitionData::AnimatorKey::PROPERTY ] = Actor::Property::POSITION;
110       map[ Dali::Toolkit::LayoutTransitionData::AnimatorKey::TARGET_VALUE ] = Property::Value(); // capture from layout update
111       map[ Dali::Toolkit::LayoutTransitionData::AnimatorKey::ANIMATOR ] = std::string(); // default animator with default duration
112       // Capture calculated position after layout, apply default linear animation
113       mImpl->mDefaultTransitionData->AddPropertyAnimator( actor, map );
114     }
115     {
116       Property::Map map;
117       map[ Dali::Toolkit::LayoutTransitionData::AnimatorKey::PROPERTY ] = Actor::Property::SIZE;
118       map[ Dali::Toolkit::LayoutTransitionData::AnimatorKey::TARGET_VALUE ] = Property::Value(); // capture from layout update
119       map[ Dali::Toolkit::LayoutTransitionData::AnimatorKey::ANIMATOR ] = std::string(); // default animator with default duration
120       // Capture calculated size after layout, apply default linear animation
121       mImpl->mDefaultTransitionData->AddPropertyAnimator( actor, map );
122     }
123   }
124   return mImpl->mDefaultTransitionData;
125 }
126
127 void LayoutItem::SetAnimateLayout( bool animateLayout )
128 {
129   auto owner = GetOwner();
130   auto actor = Actor::DownCast(owner);
131
132   DALI_LOG_INFO( gLayoutFilter, Debug::Verbose, "LayoutItem::SetAnimateLayout animateLayout(%s) owner(%s)\n", (animateLayout)?"true":"false",
133                  ( ( Actor::DownCast( owner) ) ? Actor::DownCast(owner).GetName().c_str() : "Invalid Actor" ) );
134
135   mImpl->mAnimated = animateLayout;
136
137   OnAnimationStateChanged( animateLayout );
138 }
139
140 bool LayoutItem::IsLayoutAnimated() const
141 {
142   return mImpl->mAnimated;
143 }
144
145 void LayoutItem::SetTransitionData( int layoutTransitionType, Internal::LayoutTransitionDataPtr layoutTransitionDataPtr )
146 {
147   switch ( layoutTransitionType )
148   {
149   case Dali::Toolkit::LayoutTransitionData::ON_CHILD_ADD:
150     mImpl->mOnChildAddTransitionData = layoutTransitionDataPtr;
151     break;
152   case Dali::Toolkit::LayoutTransitionData::ON_CHILD_REMOVE:
153     mImpl->mOnChildRemoveTransitionData = layoutTransitionDataPtr;
154     break;
155   case Dali::Toolkit::LayoutTransitionData::ON_CHILD_FOCUS:
156     mImpl->mOnChildFocusTransitionData = layoutTransitionDataPtr;
157     break;
158   case Dali::Toolkit::LayoutTransitionData::ON_OWNER_SET:
159     mImpl->mOnOwnerSetTransitionData = layoutTransitionDataPtr;
160     break;
161   case Dali::Toolkit::LayoutTransitionData::ON_LAYOUT_CHANGE:
162     mImpl->mOnLayoutChangeTransitionData = layoutTransitionDataPtr;
163     break;
164   default:
165     break;
166   }
167 }
168
169 Internal::LayoutTransitionDataPtr LayoutItem::GetTransitionData( int layoutTransitionType ) const
170 {
171   switch ( layoutTransitionType )
172   {
173   case Dali::Toolkit::LayoutTransitionData::ON_CHILD_ADD:
174     return mImpl->mOnChildAddTransitionData.Get();
175   case Dali::Toolkit::LayoutTransitionData::ON_CHILD_REMOVE:
176     return mImpl->mOnChildRemoveTransitionData.Get();
177   case Dali::Toolkit::LayoutTransitionData::ON_CHILD_FOCUS:
178     return mImpl->mOnChildFocusTransitionData.Get();
179   case Dali::Toolkit::LayoutTransitionData::ON_OWNER_SET:
180     return mImpl->mOnOwnerSetTransitionData.Get();
181   case Dali::Toolkit::LayoutTransitionData::ON_LAYOUT_CHANGE:
182     return mImpl->mOnLayoutChangeTransitionData.Get();
183   default:
184     return LayoutTransitionDataPtr();
185   }
186 }
187
188 void LayoutItem::RegisterChildProperties( const std::string& containerType )
189 {
190   // Call on derived types
191   auto typeInfo = TypeRegistry::Get().GetTypeInfo( containerType );
192   if( typeInfo )
193   {
194     Property::IndexContainer indices;
195     typeInfo.GetChildPropertyIndices( indices );
196
197     if( std::find( indices.Begin(), indices.End(), Toolkit::LayoutItem::ChildProperty::WIDTH_SPECIFICATION ) ==
198         indices.End() )
199     {
200       ChildPropertyRegistration( typeInfo.GetName(), WIDTH_SPECIFICATION_NAME,
201                                  Toolkit::LayoutItem::ChildProperty::WIDTH_SPECIFICATION, Property::INTEGER );
202
203       ChildPropertyRegistration( typeInfo.GetName(), HEIGHT_SPECIFICATION_NAME,
204                                  Toolkit::LayoutItem::ChildProperty::HEIGHT_SPECIFICATION, Property::INTEGER );
205     }
206
207     OnRegisterChildProperties( containerType );
208   }
209 }
210
211 void LayoutItem::OnRegisterChildProperties( const std::string& containerType )
212 {
213 }
214
215
216 void LayoutItem::Measure( MeasureSpec widthMeasureSpec, MeasureSpec heightMeasureSpec )
217 {
218   DALI_LOG_TRACE_METHOD( gLayoutFilter );
219
220   const bool forceLayout = mImpl->GetPrivateFlag( Impl::PRIVATE_FLAG_FORCE_LAYOUT );
221
222   const bool specChanged =
223     ( widthMeasureSpec  != mImpl->mOldWidthMeasureSpec ) ||
224     ( heightMeasureSpec != mImpl->mOldHeightMeasureSpec );
225
226   const bool isSpecExactly =
227     ( widthMeasureSpec.GetMode() == MeasureSpec::Mode::EXACTLY ) &&
228     ( heightMeasureSpec.GetMode() == MeasureSpec::Mode::EXACTLY );
229
230   const bool matchesSpecSize =
231     ( GetMeasuredWidth() == widthMeasureSpec.GetSize() ) &&
232     ( GetMeasuredHeight() == heightMeasureSpec.GetSize() );
233
234   const bool needsLayout = specChanged && ( !isSpecExactly || !matchesSpecSize );
235
236   DALI_LOG_STREAM( gLayoutFilter, Debug::Verbose, "LayoutItem::Measure("<<widthMeasureSpec<<", "<<heightMeasureSpec<<") Owner:"
237                                                   <<Actor::DownCast(GetOwner()).GetName() <<"  forceLayout="<<forceLayout
238                                                   <<", specChanged="<<specChanged<<", isSpecExactly="<<isSpecExactly
239                                                   <<", matchesSpecSize="<<matchesSpecSize
240                                                   <<", needsLayout="<<needsLayout <<(forceLayout||needsLayout?"  Remeasuring":"  NoChange"));
241
242   if( forceLayout || needsLayout )
243   {
244     mImpl->ClearPrivateFlag( Impl::PRIVATE_FLAG_MEASURED_DIMENSION_SET );
245
246     // measure ourselves, this should set the measured dimension flag back
247 #if defined(DEBUG_ENABLED)
248     std::ostringstream o;
249     o<<widthMeasureSpec<<","<<heightMeasureSpec;
250     DALI_LOG_INFO( gLayoutFilter, Debug::General, "LayoutItem::Measure Calling %s OnMeasure( %s )\n", Actor::DownCast(GetOwner()).GetName().c_str(), o.str().c_str());
251 #endif
252     OnMeasure( widthMeasureSpec, heightMeasureSpec );
253     mImpl->ClearPrivateFlag( Impl::PRIVATE_FLAG_MEASURE_NEEDED_BEFORE_LAYOUT );
254
255     // flag not set, setMeasuredDimension() was not invoked, we raise an exception to warn the developer
256     DALI_ASSERT_ALWAYS( mImpl->GetPrivateFlag( Impl::PRIVATE_FLAG_MEASURED_DIMENSION_SET ) &&
257                         "Layout's OnMeasure() Measured dimension flag not set" );
258     mImpl->SetPrivateFlag( Impl::PRIVATE_FLAG_LAYOUT_REQUIRED );
259   }
260
261   mImpl->mOldWidthMeasureSpec = widthMeasureSpec;
262   mImpl->mOldHeightMeasureSpec = heightMeasureSpec;
263 }
264
265 void LayoutItem::Layout( LayoutLength l, LayoutLength t, LayoutLength r, LayoutLength b )
266 {
267   DALI_LOG_TRACE_METHOD( gLayoutFilter );
268
269   if( mImpl->GetPrivateFlag( Impl::PRIVATE_FLAG_MEASURE_NEEDED_BEFORE_LAYOUT ) )
270   {
271     OnMeasure( mImpl->mOldWidthMeasureSpec, mImpl->mOldHeightMeasureSpec );
272     mImpl->ClearPrivateFlag( Impl::PRIVATE_FLAG_MEASURE_NEEDED_BEFORE_LAYOUT );
273   }
274
275   LayoutData& layoutData = *mImpl->sLayoutData;
276   size_t size = layoutData.childrenLayoutDataArray.size();
277
278   bool changed = SetFrame( l, t, r, b );
279
280   if( changed || mImpl->GetPrivateFlag( Impl::PRIVATE_FLAG_LAYOUT_REQUIRED ) )
281   {
282
283     OnLayout( changed, l, t, r, b );
284     mImpl->ClearPrivateFlag( Impl::PRIVATE_FLAG_LAYOUT_REQUIRED );
285   }
286
287   if ( size != layoutData.childrenLayoutDataArray.size() )
288   {
289     layoutData.childrenLayoutDataArray.resize( size );
290   }
291
292   mImpl->ClearPrivateFlag( Impl::PRIVATE_FLAG_FORCE_LAYOUT );
293   mImpl->SetPrivateFlag( Impl::PRIVATE_FLAG_IS_LAID_OUT );
294 }
295
296 LayoutLength LayoutItem::GetMinimumWidth() const
297 {
298   return mImpl->mMinimumSize.GetWidth();
299 }
300
301 LayoutLength LayoutItem::GetMinimumHeight() const
302 {
303   return mImpl->mMinimumSize.GetHeight();
304 }
305
306 void LayoutItem::SetMinimumWidth( LayoutLength minimumWidth )
307 {
308   mImpl->mMinimumSize.SetWidth( minimumWidth );
309   RequestLayout();
310 }
311
312 void LayoutItem::SetMinimumHeight( LayoutLength minimumHeight )
313 {
314   mImpl->mMinimumSize.SetHeight( minimumHeight );
315   RequestLayout();
316 }
317
318 Extents LayoutItem::GetPadding() const
319 {
320   Toolkit::Control control = Toolkit::Control::DownCast( GetOwner() );
321   if( control )
322   {
323     Extents padding = control.GetProperty<Extents>( Toolkit::Control::Property::PADDING );
324
325     DALI_LOG_INFO( gLayoutFilter, Debug::Verbose, "LayoutItem::Padding for %s : (%d,%d,%d,%d) \n",
326                    control.GetName().c_str(),
327                    padding.start, padding.end, padding.top, padding.bottom
328                  );
329     return padding;
330   }
331   else
332   {
333     return Extents();
334   }
335 }
336
337 Extents LayoutItem::GetMargin() const
338 {
339   Toolkit::Control control = Toolkit::Control::DownCast( GetOwner() );
340   if ( control )
341   {
342     return control.GetProperty<Extents>( Toolkit::Control::Property::MARGIN );
343   }
344   else
345   {
346     return Extents();
347   }
348 }
349
350 LayoutLength LayoutItem::GetDefaultSize( LayoutLength size, MeasureSpec measureSpec )
351 {
352   LayoutLength result = size;
353   auto specMode = measureSpec.GetMode();
354   auto specSize = measureSpec.GetSize();
355
356   DALI_LOG_STREAM( gLayoutFilter, Debug::Verbose, "LayoutItem::GetDefaultSize MeasureSpec("<<measureSpec<< ") size:" << size << "\n" );
357
358   switch (specMode)
359   {
360     case MeasureSpec::Mode::UNSPECIFIED:
361     {
362       result = size;
363       break;
364     }
365     case MeasureSpec::Mode::AT_MOST:
366     {
367       // Ensure the default size does not exceed the spec size unless the default size is 0.
368       // Another container could provide a default size of 0.
369       LayoutLength tmp = specSize;
370
371       // Do not set size to 0, use specSize in this case as could be a legacy container
372       if( size < tmp && size > LayoutLength( 0 ) )
373       {
374         result = size;
375       }
376       else
377       {
378         result = specSize;
379       }
380       break;
381     }
382     case MeasureSpec::Mode::EXACTLY:
383     {
384       result = specSize;
385       break;
386     }
387   }
388   DALI_LOG_STREAM( gLayoutFilter, Debug::General, "LayoutItem::GetDefaultSize setting default size:" << result << "\n" );
389   return result;
390 }
391
392 void LayoutItem::OnMeasure( MeasureSpec widthMeasureSpec, MeasureSpec heightMeasureSpec)
393 {
394   DALI_LOG_INFO( gLayoutFilter, Debug::Verbose, "LayoutItem::OnMeasure\n");
395
396   // GetDefaultSize will limit the MeasureSpec to the suggested minimumWidth and minimumHeight
397   SetMeasuredDimensions( GetDefaultSize( GetSuggestedMinimumWidth(), widthMeasureSpec ),
398                          GetDefaultSize( GetSuggestedMinimumHeight(), heightMeasureSpec ) );
399 }
400
401 void LayoutItem::OnLayout( bool changed, LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom )
402 {
403 }
404
405 void LayoutItem::SetParent( LayoutParent* parent )
406 {
407   mImpl->mLayoutParent = parent;
408   mImpl->SetPrivateFlag( Impl::PRIVATE_FLAG_FORCE_SET_FRAME );
409 }
410
411 LayoutParent* LayoutItem::GetParent()
412 {
413   return mImpl->mLayoutParent;
414 }
415
416 void LayoutItem::RequestLayout()
417 {
418   Toolkit::Control control = Toolkit::Control::DownCast( GetOwner() );
419   if( control )
420   {
421     DALI_LOG_INFO( gLayoutFilter, Debug::Verbose, "LayoutItem::RequestLayout control(%s)\n",
422         control.GetName().c_str() );
423
424     // @todo Enforce failure if called in Measure/Layout passes.
425     mImpl->SetPrivateFlag( Impl::PRIVATE_FLAG_FORCE_LAYOUT );
426     Toolkit::LayoutController layoutController = Toolkit::LayoutController::Get();
427     layoutController.RequestLayout( Toolkit::LayoutItem( this ) );
428   }
429 }
430
431 void LayoutItem::RequestLayout( Dali::Toolkit::LayoutTransitionData::Type layoutAnimationType )
432 {
433   Toolkit::Control control = Toolkit::Control::DownCast( GetOwner() );
434   if ( control )
435   {
436     DALI_LOG_INFO( gLayoutFilter, Debug::Verbose, "LayoutItem::RequestLayout control(%s) layoutTranstionType(%d)\n",
437         control.GetName().c_str(), (int)layoutAnimationType );
438
439     // @todo Enforce failure if called in Measure/Layout passes.
440     mImpl->SetPrivateFlag( Impl::PRIVATE_FLAG_FORCE_LAYOUT );
441     Toolkit::LayoutController layoutController = Toolkit::LayoutController::Get();
442     layoutController.RequestLayout( Toolkit::LayoutItem(this), layoutAnimationType );
443   }
444 }
445
446 void LayoutItem::RequestLayout( Dali::Toolkit::LayoutTransitionData::Type layoutAnimationType, Actor gainedChild, Actor lostChild )
447 {
448   Toolkit::Control control = Toolkit::Control::DownCast( GetOwner() );
449   if ( control )
450   {
451     DALI_LOG_INFO( gLayoutFilter, Debug::Verbose, "LayoutItem::RequestLayout control(%s) layoutTranstionType(%d)\n",
452         control.GetName().c_str(), (int)layoutAnimationType );
453
454     // @todo Enforce failure if called in Measure/Layout passes.
455     mImpl->SetPrivateFlag( Impl::PRIVATE_FLAG_FORCE_LAYOUT );
456     Toolkit::LayoutController layoutController = Toolkit::LayoutController::Get();
457     layoutController.RequestLayout( Toolkit::LayoutItem(this), layoutAnimationType, gainedChild, lostChild );
458   }
459 }
460
461 bool LayoutItem::IsLayoutRequested() const
462 {
463   return mImpl->GetPrivateFlag( Impl::PRIVATE_FLAG_FORCE_LAYOUT );
464 }
465
466 void LayoutItem::SetLayoutRequested()
467 {
468   mImpl->SetPrivateFlag( Impl::PRIVATE_FLAG_FORCE_LAYOUT );
469 }
470
471 bool LayoutItem::IsResizePolicyRequired() const
472 {
473   return mImpl->GetPrivateFlag( Impl::PRIVATE_FLAG_USE_RESIZE_POLICY );
474 }
475
476 void LayoutItem::SetResizePolicyRequired( bool resizePolicyRequired )
477 {
478   if( resizePolicyRequired )
479   {
480     mImpl->SetPrivateFlag( Impl::PRIVATE_FLAG_USE_RESIZE_POLICY );
481   }
482   else
483   {
484     mImpl->ClearPrivateFlag( Impl::PRIVATE_FLAG_USE_RESIZE_POLICY );
485   }
486 }
487
488 void LayoutItem::SetMeasuredDimensions( MeasuredSize measuredWidth, MeasuredSize measuredHeight )
489 {
490
491   DALI_LOG_STREAM( gLayoutFilter, Debug::Verbose, "LayoutItem::SetMeasuredDimensions width(" << measuredWidth.GetSize() << ") height(" << measuredHeight.GetSize() << ") Control:" <<
492                         ( ( Actor::DownCast( GetOwner()) ) ? Actor::DownCast(GetOwner()).GetName().c_str() : "Invalid Actor" ) << "\n" );
493
494   mImpl->SetPrivateFlag( Impl::PRIVATE_FLAG_MEASURED_DIMENSION_SET );
495   mImpl->mMeasuredWidth = measuredWidth;
496   mImpl->mMeasuredHeight = measuredHeight;
497 }
498
499 LayoutLength LayoutItem::GetMeasuredWidth() const
500 {
501   // Get the size portion of the measured width
502   return mImpl->mMeasuredWidth.GetSize();
503 }
504
505 LayoutLength LayoutItem::GetMeasuredHeight() const
506 {
507   return  mImpl->mMeasuredHeight.GetSize();
508 }
509
510 MeasuredSize LayoutItem::GetMeasuredWidthAndState() const
511 {
512   return mImpl->mMeasuredWidth;
513 }
514
515 MeasuredSize LayoutItem::GetMeasuredHeightAndState() const
516 {
517   return mImpl->mMeasuredHeight;
518 }
519
520 LayoutLength LayoutItem::GetSuggestedMinimumWidth() const
521 {
522   auto owner = GetOwner();
523   auto actor = Actor::DownCast( owner );
524   auto naturalSize = actor ? actor.GetNaturalSize() : Vector3::ZERO;
525
526   return std::max( mImpl->mMinimumSize.GetWidth(), LayoutLength( naturalSize.width ) );
527 }
528
529 LayoutLength LayoutItem::GetSuggestedMinimumHeight() const
530 {
531   auto owner = GetOwner();
532   auto actor = Actor::DownCast( owner );
533   auto naturalSize = actor ? actor.GetNaturalSize() : Vector3::ZERO;
534
535   return std::max( mImpl->mMinimumSize.GetHeight(), LayoutLength( naturalSize.height ) );
536 }
537
538 MeasuredSize LayoutItem::ResolveSizeAndState( LayoutLength size, MeasureSpec measureSpec, MeasuredSize::State childMeasuredState )
539 {
540   auto specMode = measureSpec.GetMode();
541   LayoutLength specSize = measureSpec.GetSize();
542   MeasuredSize result;
543
544   switch( specMode )
545   {
546     case MeasureSpec::Mode::AT_MOST:
547     {
548       if (specSize < size)
549       {
550         result = MeasuredSize( specSize, MeasuredSize::MEASURED_SIZE_TOO_SMALL );
551       }
552       else
553       {
554         result.SetSize( size );
555       }
556       break;
557     }
558
559     case MeasureSpec::Mode::EXACTLY:
560     {
561       result.SetSize( specSize );
562       break;
563     }
564
565     case MeasureSpec::Mode::UNSPECIFIED:
566     default:
567     {
568       result.SetSize( size );
569       break;
570     }
571   }
572
573   result.SetState( childMeasuredState );
574   return result;
575 }
576
577
578 bool LayoutItem::SetFrame( LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom )
579 {
580   bool changed = false;
581
582   DALI_LOG_STREAM( gLayoutFilter, Debug::Verbose, "LayoutItem::SetFrame enter(" << left << ", " << top << ", " << right << ", " << bottom << ")\n" );
583
584   if( mImpl->mLeft != left || mImpl->mRight != right || mImpl->mTop != top || mImpl->mBottom != bottom || mImpl->GetPrivateFlag( Impl::PRIVATE_FLAG_FORCE_SET_FRAME ) )
585   {
586     changed = true;
587     mImpl->ClearPrivateFlag( Impl::PRIVATE_FLAG_FORCE_SET_FRAME );
588   }
589
590   LayoutLength oldWidth = mImpl->mRight - mImpl->mLeft;
591   LayoutLength oldHeight = mImpl->mBottom - mImpl->mTop;
592   LayoutLength newWidth = right - left;
593   LayoutLength newHeight = bottom - top;
594   bool sizeChanged = ( newWidth != oldWidth ) || ( newHeight != oldHeight );
595
596   mImpl->mLeft = left;
597   mImpl->mTop = top;
598   mImpl->mRight = right;
599   mImpl->mBottom = bottom;
600
601   // Reflect up to parent control
602   auto owner = GetOwner();
603   auto actor = Actor::DownCast( owner );
604   LayoutData& layoutData = *mImpl->sLayoutData;
605
606   if( actor )
607   {
608     if( changed || mImpl->mAnimated )
609     {
610       layoutData.layoutPositionDataArray.push_back(
611         LayoutPositionData( actor, left.AsDecimal(), top.AsDecimal(), right.AsDecimal(), bottom.AsDecimal(), mImpl->mAnimated ) );
612     }
613
614     if( mImpl->mAnimated && !layoutData.speculativeLayout )
615     {
616       if( layoutData.layoutTransition.layoutTransitionType != -1 )
617       {
618         LayoutItem* transitionOwner = layoutData.layoutTransition.layoutItem.Get();
619         LayoutTransitionDataPtr layoutTransitionDataPtr = GetTransitionData( layoutData.layoutTransition.layoutTransitionType );
620
621         // Found transition owner
622         if( transitionOwner == this && layoutTransitionDataPtr.Get() )
623         {
624           DALI_LOG_INFO( gLayoutFilter, Debug::Verbose, "LayoutItem::SetFrame apply transition to (%s), transition type (%d)\n", actor.GetName().c_str(), layoutData.layoutTransition.layoutTransitionType );
625           layoutTransitionDataPtr->CollectLayoutDataElements( actor, layoutData );
626           changed = true;
627         }
628         else
629         {
630           LayoutTransitionData::CollectChildrenLayoutDataElements( actor, layoutData );
631         }
632       }
633       else
634       {
635         if( changed )
636         {
637           LayoutTransitionDataPtr layoutTransitionDataPtr = GetTransitionData( Dali::Toolkit::LayoutTransitionData::ON_LAYOUT_CHANGE );
638           if( layoutTransitionDataPtr ) // has custom default animation and normal update
639           {
640             DALI_LOG_INFO( gLayoutFilter, Debug::Verbose, "LayoutItem::SetFrame apply custom default transition to (%s), transition type (%d)\n", actor.GetName().c_str(), Dali::Toolkit::LayoutTransitionData::ON_LAYOUT_CHANGE );
641             layoutTransitionDataPtr->CollectLayoutDataElements( actor, layoutData );
642           }
643           else
644           {
645             DALI_LOG_INFO( gLayoutFilter, Debug::Verbose, "LayoutItem::SetFrame apply default transition to (%s), transition type (%d)\n", actor.GetName().c_str(), layoutData.layoutTransition.layoutTransitionType );
646             GetDefaultTransition()->CollectLayoutDataElements( actor, layoutData );
647           }
648         }
649       }
650     }
651   }
652
653   // TODO: do we need it
654   if( sizeChanged )
655   {
656     SizeChange( LayoutSize( newWidth, newHeight ), LayoutSize( oldWidth, oldHeight ) );
657   }
658
659   DALI_LOG_STREAM( gLayoutFilter, Debug::Verbose, "LayoutItem::SetFrame  exit(" << left << ", " << top << ", " << right << ", " << bottom << ")\n" );
660
661   return changed;
662 }
663
664 void LayoutItem::OnLayoutAnimationFinished( Animation& animation )
665 {
666   auto owner = GetOwner();
667   auto actor = Actor::DownCast(owner);
668   if( actor )
669   {
670     actor.SetSize( Vector3( mImpl->mRight.AsInteger() - mImpl->mLeft.AsInteger(), mImpl->mBottom.AsInteger() - mImpl->mTop.AsInteger(), 0.0f ) );
671   }
672 }
673
674 void LayoutItem::SizeChange( LayoutSize newSize, LayoutSize oldSize)
675 {
676   OnSizeChanged( newSize, oldSize );
677 }
678
679
680 void LayoutItem::OnSizeChanged( LayoutSize newSize, LayoutSize oldSize )
681 {
682 }
683
684 void LayoutItem::OnInitialize()
685 {
686 }
687
688
689 } // namespace Internal
690 } // namespace Toolkit
691 } // namespace Dali