0b638de5859a4a4fc33572393dbcfd7e6ea82ee0
[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.GetBaseObject());
70   RegisterChildProperties( containerType );
71   OnInitialize(); // Ensure direct deriving class gets initialized
72 }
73
74 Handle LayoutItem::GetOwner() const
75 {
76   return Handle::DownCast(BaseHandle(mImpl->mOwner));
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 = NULL;
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.childrenPropertyAnimators.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.childrenPropertyAnimators.size() )
288   {
289     layoutData.childrenPropertyAnimators.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( mImpl->mOwner );
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( mImpl->mOwner );
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( mImpl->mOwner );
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 void LayoutItem::RequestLayout( Dali::Toolkit::LayoutTransitionData::Type layoutAnimationType )
431 {
432   Toolkit::Control control = Toolkit::Control::DownCast( mImpl->mOwner );
433   if ( control )
434   {
435     DALI_LOG_INFO( gLayoutFilter, Debug::Verbose, "LayoutItem::RequestLayout control(%s) layoutTranstionType(%d)\n",
436         control.GetName().c_str(), (int)layoutAnimationType );
437   }
438   // @todo Enforce failure if called in Measure/Layout passes.
439   mImpl->SetPrivateFlag( Impl::PRIVATE_FLAG_FORCE_LAYOUT );
440   Toolkit::LayoutController layoutController = Toolkit::LayoutController::Get();
441   layoutController.RequestLayout( Toolkit::LayoutItem(this), layoutAnimationType );
442 }
443
444 void LayoutItem::RequestLayout( Dali::Toolkit::LayoutTransitionData::Type layoutAnimationType, Actor gainedChild, Actor lostChild )
445 {
446   Toolkit::Control control = Toolkit::Control::DownCast( mImpl->mOwner );
447   if ( control )
448   {
449     DALI_LOG_INFO( gLayoutFilter, Debug::Verbose, "LayoutItem::RequestLayout control(%s) layoutTranstionType(%d)\n",
450         control.GetName().c_str(), (int)layoutAnimationType );
451   }
452   // @todo Enforce failure if called in Measure/Layout passes.
453   mImpl->SetPrivateFlag( Impl::PRIVATE_FLAG_FORCE_LAYOUT );
454   Toolkit::LayoutController layoutController = Toolkit::LayoutController::Get();
455   layoutController.RequestLayout( Toolkit::LayoutItem(this), layoutAnimationType, gainedChild, lostChild );
456 }
457
458 bool LayoutItem::IsLayoutRequested() const
459 {
460   return mImpl->GetPrivateFlag( Impl::PRIVATE_FLAG_FORCE_LAYOUT );
461 }
462
463 void LayoutItem::SetLayoutRequested()
464 {
465   mImpl->SetPrivateFlag( Impl::PRIVATE_FLAG_FORCE_LAYOUT );
466 }
467
468 bool LayoutItem::IsResizePolicyRequired() const
469 {
470   return mImpl->GetPrivateFlag( Impl::PRIVATE_FLAG_USE_RESIZE_POLICY );
471 }
472
473 void LayoutItem::SetResizePolicyRequired( bool resizePolicyRequired )
474 {
475   if( resizePolicyRequired )
476   {
477     mImpl->SetPrivateFlag( Impl::PRIVATE_FLAG_USE_RESIZE_POLICY );
478   }
479   else
480   {
481     mImpl->ClearPrivateFlag( Impl::PRIVATE_FLAG_USE_RESIZE_POLICY );
482   }
483 }
484
485 void LayoutItem::SetMeasuredDimensions( MeasuredSize measuredWidth, MeasuredSize measuredHeight )
486 {
487
488   DALI_LOG_STREAM( gLayoutFilter, Debug::Verbose, "LayoutItem::SetMeasuredDimensions width(" << measuredWidth.GetSize() << ") height(" << measuredHeight.GetSize() << ") Control:" <<
489                         ( ( Actor::DownCast( GetOwner()) ) ? Actor::DownCast(GetOwner()).GetName().c_str() : "Invalid Actor" ) << "\n" );
490
491   mImpl->SetPrivateFlag( Impl::PRIVATE_FLAG_MEASURED_DIMENSION_SET );
492   mImpl->mMeasuredWidth = measuredWidth;
493   mImpl->mMeasuredHeight = measuredHeight;
494 }
495
496 LayoutLength LayoutItem::GetMeasuredWidth() const
497 {
498   // Get the size portion of the measured width
499   return  mImpl->mMeasuredWidth.GetSize();
500 }
501
502 LayoutLength LayoutItem::GetMeasuredHeight() const
503 {
504   return  mImpl->mMeasuredHeight.GetSize();
505 }
506
507 MeasuredSize LayoutItem::GetMeasuredWidthAndState() const
508 {
509   return mImpl->mMeasuredWidth;
510 }
511
512 MeasuredSize LayoutItem::GetMeasuredHeightAndState() const
513 {
514   return mImpl->mMeasuredHeight;
515 }
516
517 LayoutLength LayoutItem::GetSuggestedMinimumWidth() const
518 {
519   auto owner = GetOwner();
520   auto actor = Actor::DownCast(owner);
521   auto naturalSize = actor ? actor.GetNaturalSize() : Vector3::ZERO;
522
523   return std::max( mImpl->mMinimumSize.GetWidth(), LayoutLength( naturalSize.width ) );
524 }
525
526 LayoutLength LayoutItem::GetSuggestedMinimumHeight() const
527 {
528   auto owner = GetOwner();
529   auto actor = Actor::DownCast(owner);
530   auto naturalSize = actor ? actor.GetNaturalSize() : Vector3::ZERO;
531
532   return std::max( mImpl->mMinimumSize.GetHeight(), LayoutLength( naturalSize.height ) );
533 }
534
535 MeasuredSize LayoutItem::ResolveSizeAndState( LayoutLength size, MeasureSpec measureSpec, MeasuredSize::State childMeasuredState )
536 {
537   auto specMode = measureSpec.GetMode();
538   LayoutLength specSize = measureSpec.GetSize();
539   MeasuredSize result;
540
541   switch( specMode )
542   {
543     case MeasureSpec::Mode::AT_MOST:
544     {
545       if (specSize < size)
546       {
547         result = MeasuredSize( specSize, MeasuredSize::MEASURED_SIZE_TOO_SMALL );
548       }
549       else
550       {
551         result.SetSize( size );
552       }
553       break;
554     }
555
556     case MeasureSpec::Mode::EXACTLY:
557     {
558       result.SetSize( specSize );
559       break;
560     }
561
562     case MeasureSpec::Mode::UNSPECIFIED:
563     default:
564     {
565       result.SetSize( size );
566       break;
567     }
568   }
569
570   result.SetState( childMeasuredState );
571   return result;
572 }
573
574
575 bool LayoutItem::SetFrame( LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom )
576 {
577   bool changed = false;
578
579   DALI_LOG_STREAM( gLayoutFilter, Debug::Verbose, "LayoutItem::SetFrame enter(" << left << ", " << top << ", " << right << ", " << bottom << ")\n" );
580
581   if( mImpl->mLeft != left || mImpl->mRight != right || mImpl->mTop != top || mImpl->mBottom != bottom || mImpl->GetPrivateFlag( Impl::PRIVATE_FLAG_FORCE_SET_FRAME ) )
582   {
583     changed = true;
584     mImpl->ClearPrivateFlag( Impl::PRIVATE_FLAG_FORCE_SET_FRAME );
585   }
586
587   LayoutLength oldWidth = mImpl->mRight - mImpl->mLeft;
588   LayoutLength oldHeight = mImpl->mBottom - mImpl->mTop;
589   LayoutLength newWidth = right - left;
590   LayoutLength newHeight = bottom - top;
591   bool sizeChanged = ( newWidth != oldWidth ) || ( newHeight != oldHeight );
592
593   mImpl->mLeft = left;
594   mImpl->mTop = top;
595   mImpl->mRight = right;
596   mImpl->mBottom = bottom;
597
598   // Reflect up to parent control
599   auto owner = GetOwner();
600   auto actor = Actor::DownCast( owner );
601   LayoutData& layoutData = *mImpl->sLayoutData;
602   if( actor )
603   {
604     if( mImpl->mAnimated && !layoutData.speculativeLayout )
605     {
606       LayoutItem* transitionOwner = layoutData.layoutTransition.layoutItem.Get();
607       LayoutTransitionDataPtr layoutTransitionDataPtr = GetTransitionData( layoutData.layoutTransition.layoutTransitionType );
608
609       // Found transition owner
610       if( transitionOwner == this && layoutTransitionDataPtr.Get() )
611       {
612         DALI_LOG_INFO( gLayoutFilter, Debug::Verbose, "LayoutItem::SetFrame apply transition to (%s), transition type (%d)\n", actor.GetName().c_str(), layoutData.layoutTransition.layoutTransitionType );
613         layoutData.layoutPositionDataArray.push_back( LayoutPositionData( actor, left.AsDecimal(), top.AsDecimal(), right.AsDecimal(), bottom.AsDecimal(), true ) );
614         layoutTransitionDataPtr->ConvertToLayoutDataElements( actor, layoutData );
615         changed = true;
616       }
617       else
618       {
619         if( changed )
620         {
621           layoutTransitionDataPtr = GetTransitionData( Dali::Toolkit::LayoutTransitionData::ON_LAYOUT_CHANGE );
622           if ( layoutTransitionDataPtr )
623           {
624             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 );
625             layoutData.layoutPositionDataArray.push_back( LayoutPositionData( actor, left.AsDecimal(), top.AsDecimal(), right.AsDecimal(), bottom.AsDecimal(), true ) );
626             layoutTransitionDataPtr->ConvertToLayoutDataElements( actor, layoutData );
627           }
628           else
629           {
630             DALI_LOG_INFO( gLayoutFilter, Debug::Verbose, "LayoutItem::SetFrame apply default transition to (%s), transition type (%d)\n", actor.GetName().c_str(), layoutData.layoutTransition.layoutTransitionType );
631             layoutData.layoutPositionDataArray.push_back( LayoutPositionData( actor, left.AsDecimal(), top.AsDecimal(), right.AsDecimal(), bottom.AsDecimal(), true ) );
632             GetDefaultTransition()->ConvertToLayoutDataElements( actor, layoutData );
633           }
634         }
635         else
636         {
637           DALI_LOG_INFO( gLayoutFilter, Debug::Verbose, "LayoutItem::SetFrame apply children animators to (%s), transition type (%d)\n", actor.GetName().c_str(), layoutData.layoutTransition.layoutTransitionType );
638           layoutData.layoutPositionDataArray.push_back( LayoutPositionData( actor, left.AsDecimal(), top.AsDecimal(), right.AsDecimal(), bottom.AsDecimal(), true ) );
639           LayoutTransitionData::ConvertChildrenAnimatorsToLayoutDataElements( actor, layoutData );
640         }
641       }
642     }
643     else
644     {
645       if( changed )
646       {
647         layoutData.layoutPositionDataArray.push_back( LayoutPositionData( actor, left.AsDecimal(), top.AsDecimal(), right.AsDecimal(), bottom.AsDecimal(), false ) );
648       }
649     }
650   }
651
652   // TODO: do we need it
653   if( sizeChanged )
654   {
655     SizeChange( LayoutSize( newWidth, newHeight ), LayoutSize( oldWidth, oldHeight ) );
656   }
657
658   DALI_LOG_STREAM( gLayoutFilter, Debug::Verbose, "LayoutItem::SetFrame  exit(" << left << ", " << top << ", " << right << ", " << bottom << ")\n" );
659
660   return changed;
661 }
662
663 void LayoutItem::OnLayoutAnimationFinished( Animation& animation )
664 {
665   auto owner = GetOwner();
666   auto actor = Actor::DownCast(owner);
667   if( actor )
668   {
669     actor.SetSize( Vector3( mImpl->mRight.AsInteger() - mImpl->mLeft.AsInteger(), mImpl->mBottom.AsInteger() - mImpl->mTop.AsInteger(), 0.0f ) );
670   }
671 }
672
673 void LayoutItem::SizeChange( LayoutSize newSize, LayoutSize oldSize)
674 {
675   OnSizeChanged( newSize, oldSize );
676 }
677
678
679 void LayoutItem::OnSizeChanged( LayoutSize newSize, LayoutSize oldSize )
680 {
681 }
682
683 void LayoutItem::OnInitialize()
684 {
685 }
686
687
688 } // namespace Internal
689 } // namespace Toolkit
690 } // namespace Dali