[Tizen] Store LayoutItem target size when set explictly
[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 size:" << size <<  "MeasureSpec(" << measureSpec << ") \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
370       // Do not set size to 0, use specSize in this case as could be a legacy container
371       if( ( size < specSize ) && ( size > LayoutLength( 0 ) )  )
372       {
373         result = size;
374       }
375       else
376       {
377         result = specSize;
378       }
379       break;
380     }
381     case MeasureSpec::Mode::EXACTLY:
382     {
383       result = specSize;
384       break;
385     }
386   }
387   DALI_LOG_STREAM( gLayoutFilter, Debug::General, "LayoutItem::GetDefaultSize setting default size:" << result << "\n" );
388   return result;
389 }
390
391 void LayoutItem::OnMeasure( MeasureSpec widthMeasureSpec, MeasureSpec heightMeasureSpec)
392 {
393   DALI_LOG_INFO( gLayoutFilter, Debug::Verbose, "LayoutItem::OnMeasure\n");
394
395   // GetDefaultSize will limit the MeasureSpec to the suggested minimumWidth and minimumHeight
396   auto minimumWidth = GetSuggestedMinimumWidth();
397   auto minimumHeight = GetSuggestedMinimumHeight();
398   DALI_LOG_INFO( gLayoutFilter, Debug::Verbose, "LayoutItem::OnMeasure minimumWidth(%f) minimumHeight(%f)\n",
399                  minimumWidth.AsInteger(), minimumHeight.AsInteger() );
400
401   SetMeasuredDimensions( GetDefaultSize( minimumWidth, widthMeasureSpec ),
402                          GetDefaultSize( minimumHeight, heightMeasureSpec ) );
403 }
404
405 void LayoutItem::OnLayout( bool changed, LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom )
406 {
407 }
408
409 void LayoutItem::SetParent( LayoutParent* parent )
410 {
411   mImpl->mLayoutParent = parent;
412   mImpl->SetPrivateFlag( Impl::PRIVATE_FLAG_FORCE_SET_FRAME );
413 }
414
415 LayoutParent* LayoutItem::GetParent()
416 {
417   return mImpl->mLayoutParent;
418 }
419
420 void LayoutItem::RequestLayout()
421 {
422   Toolkit::Control control = Toolkit::Control::DownCast( mImpl->mOwner );
423   if( control )
424   {
425     DALI_LOG_INFO( gLayoutFilter, Debug::Verbose, "LayoutItem::RequestLayout control(%s)\n",
426         control.GetName().c_str() );
427   }
428   // @todo Enforce failure if called in Measure/Layout passes.
429   mImpl->SetPrivateFlag( Impl::PRIVATE_FLAG_FORCE_LAYOUT );
430   Toolkit::LayoutController layoutController = Toolkit::LayoutController::Get();
431   layoutController.RequestLayout( Toolkit::LayoutItem( this ) );
432 }
433
434 void LayoutItem::RequestLayout( Dali::Toolkit::LayoutTransitionData::Type layoutAnimationType )
435 {
436   Toolkit::Control control = Toolkit::Control::DownCast( mImpl->mOwner );
437   if ( control )
438   {
439     DALI_LOG_INFO( gLayoutFilter, Debug::Verbose, "LayoutItem::RequestLayout control(%s) layoutTranstionType(%d)\n",
440         control.GetName().c_str(), (int)layoutAnimationType );
441   }
442   // @todo Enforce failure if called in Measure/Layout passes.
443   mImpl->SetPrivateFlag( Impl::PRIVATE_FLAG_FORCE_LAYOUT );
444   Toolkit::LayoutController layoutController = Toolkit::LayoutController::Get();
445   layoutController.RequestLayout( Toolkit::LayoutItem(this), layoutAnimationType );
446 }
447
448 void LayoutItem::RequestLayout( Dali::Toolkit::LayoutTransitionData::Type layoutAnimationType, Actor gainedChild, Actor lostChild )
449 {
450   Toolkit::Control control = Toolkit::Control::DownCast( mImpl->mOwner );
451   if ( control )
452   {
453     DALI_LOG_INFO( gLayoutFilter, Debug::Verbose, "LayoutItem::RequestLayout control(%s) layoutTranstionType(%d)\n",
454         control.GetName().c_str(), (int)layoutAnimationType );
455   }
456   // @todo Enforce failure if called in Measure/Layout passes.
457   mImpl->SetPrivateFlag( Impl::PRIVATE_FLAG_FORCE_LAYOUT );
458   Toolkit::LayoutController layoutController = Toolkit::LayoutController::Get();
459   layoutController.RequestLayout( Toolkit::LayoutItem(this), layoutAnimationType, gainedChild, lostChild );
460 }
461
462 bool LayoutItem::IsLayoutRequested() const
463 {
464   return mImpl->GetPrivateFlag( Impl::PRIVATE_FLAG_FORCE_LAYOUT );
465 }
466
467 void LayoutItem::SetLayoutRequested()
468 {
469   mImpl->SetPrivateFlag( Impl::PRIVATE_FLAG_FORCE_LAYOUT );
470 }
471
472 bool LayoutItem::IsResizePolicyRequired() const
473 {
474   return mImpl->GetPrivateFlag( Impl::PRIVATE_FLAG_USE_RESIZE_POLICY );
475 }
476
477 void LayoutItem::SetResizePolicyRequired( bool resizePolicyRequired )
478 {
479   if( resizePolicyRequired )
480   {
481     mImpl->SetPrivateFlag( Impl::PRIVATE_FLAG_USE_RESIZE_POLICY );
482   }
483   else
484   {
485     mImpl->ClearPrivateFlag( Impl::PRIVATE_FLAG_USE_RESIZE_POLICY );
486   }
487 }
488
489 void LayoutItem::SetMeasuredDimensions( MeasuredSize measuredWidth, MeasuredSize measuredHeight )
490 {
491
492   DALI_LOG_STREAM( gLayoutFilter, Debug::Verbose, "LayoutItem::SetMeasuredDimensions width(" << measuredWidth.GetSize() << ") height(" << measuredHeight.GetSize() << ") Control:" <<
493                         ( ( Actor::DownCast( GetOwner()) ) ? Actor::DownCast(GetOwner()).GetName().c_str() : "Invalid Actor" ) << "\n" );
494
495   mImpl->SetPrivateFlag( Impl::PRIVATE_FLAG_MEASURED_DIMENSION_SET );
496   mImpl->mMeasuredWidth = measuredWidth;
497   mImpl->mMeasuredHeight = measuredHeight;
498 }
499
500 LayoutLength LayoutItem::GetMeasuredWidth() const
501 {
502   // Get the size portion of the measured width
503   return  mImpl->mMeasuredWidth.GetSize();
504 }
505
506 LayoutLength LayoutItem::GetMeasuredHeight() const
507 {
508   return  mImpl->mMeasuredHeight.GetSize();
509 }
510
511 MeasuredSize LayoutItem::GetMeasuredWidthAndState() const
512 {
513   return mImpl->mMeasuredWidth;
514 }
515
516 MeasuredSize LayoutItem::GetMeasuredHeightAndState() const
517 {
518   return mImpl->mMeasuredHeight;
519 }
520
521 LayoutLength LayoutItem::GetSuggestedMinimumWidth() const
522 {
523   auto owner = GetOwner();
524   auto actor = Actor::DownCast(owner);
525   auto naturalSize = actor ? actor.GetNaturalSize() : Vector3::ZERO;
526   LayoutLength layoutMinimumWidth = GetMinimumWidth();
527
528   // Set minimum size takes precedence over natural size.
529   LayoutLength result = std::max( layoutMinimumWidth, LayoutLength( naturalSize.width ) );
530
531   if( actor.GetChildCount() == 0 ) // If not a container
532   {
533     LayoutLength targetWidth = GetTargetWidth();
534     DALI_LOG_INFO( gLayoutFilter, Debug::Verbose, "LayoutItem::GetSuggestedMinimumWidth targetWidth(%f)\n", targetWidth.AsInteger() );
535     result = (result > 0 && (targetWidth < 1 ) ) ? result : targetWidth;  // Use size set if no mininum width and control has no natural size.
536   }
537
538   DALI_LOG_INFO( gLayoutFilter, Debug::Verbose, "LayoutItem::GetSuggestedMinimumWidth control(%s) naturalWidth(%f) minimumSize.width(%f) targetWidth(%f) result(%f)\n",
539         actor.GetName().c_str(), LayoutLength( naturalSize.width ).AsInteger(), layoutMinimumWidth.AsInteger(), actor.GetTargetSize().width, result.AsInteger() );
540   return result;
541 }
542
543 LayoutLength LayoutItem::GetSuggestedMinimumHeight() const
544 {
545   auto owner = GetOwner();
546   auto actor = Actor::DownCast(owner);
547   auto naturalSize = actor ? actor.GetNaturalSize() : Vector3::ZERO;
548   LayoutLength layoutMinimumHeight = GetMinimumHeight();
549
550   // Set minimum size takes precedence over natural size.
551   LayoutLength result = std::max( layoutMinimumHeight, LayoutLength( naturalSize.height ) );
552
553   if( actor.GetChildCount() == 0 ) // If not a container
554   {
555     LayoutLength targetHeight = GetTargetHeight();
556     result = (result > 0 && (targetHeight < 1 ) )?result : targetHeight; // Use size set if no mininum width and control has no natural size.
557   }
558
559   DALI_LOG_INFO( gLayoutFilter, Debug::Verbose, "LayoutItem::GetSuggestedMinimumHeight control(%s) naturalHeight(%f) minimumHeight(%f) targetHeight(%f) result(%f)\n",
560           actor.GetName().c_str(), naturalSize.height, layoutMinimumHeight.AsInteger(), actor.GetTargetSize().height, result.AsInteger() );
561   return result;
562 }
563
564 MeasuredSize LayoutItem::ResolveSizeAndState( LayoutLength size, MeasureSpec measureSpec, MeasuredSize::State childMeasuredState )
565 {
566   auto specMode = measureSpec.GetMode();
567   LayoutLength specSize = measureSpec.GetSize();
568   MeasuredSize result;
569
570   switch( specMode )
571   {
572     case MeasureSpec::Mode::AT_MOST:
573     {
574       if (specSize < size)
575       {
576         result = MeasuredSize( specSize, MeasuredSize::MEASURED_SIZE_TOO_SMALL );
577       }
578       else
579       {
580         result.SetSize( size );
581       }
582       break;
583     }
584
585     case MeasureSpec::Mode::EXACTLY:
586     {
587       result.SetSize( specSize );
588       break;
589     }
590
591     case MeasureSpec::Mode::UNSPECIFIED:
592     default:
593     {
594       result.SetSize( size );
595       break;
596     }
597   }
598
599   result.SetState( childMeasuredState );
600   return result;
601 }
602
603
604 bool LayoutItem::SetFrame( LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom )
605 {
606   bool changed = false;
607
608   DALI_LOG_STREAM( gLayoutFilter, Debug::Verbose, "LayoutItem::SetFrame enter(" << left << ", " << top << ", " << right << ", " << bottom << ")\n" );
609
610   if( mImpl->mLeft != left || mImpl->mRight != right || mImpl->mTop != top || mImpl->mBottom != bottom || mImpl->GetPrivateFlag( Impl::PRIVATE_FLAG_FORCE_SET_FRAME ) )
611   {
612     changed = true;
613     mImpl->ClearPrivateFlag( Impl::PRIVATE_FLAG_FORCE_SET_FRAME );
614   }
615
616   DALI_LOG_INFO( gLayoutFilter, Debug::Verbose, "LayoutItem::SetFrame %s changed size(%s)\n",
617         Actor::DownCast( GetOwner() ).GetName().c_str(), (changed)?"yes":"no" );
618
619   LayoutLength oldWidth = mImpl->mRight - mImpl->mLeft;
620   LayoutLength oldHeight = mImpl->mBottom - mImpl->mTop;
621   LayoutLength newWidth = right - left;
622   LayoutLength newHeight = bottom - top;
623   bool sizeChanged = ( newWidth != oldWidth ) || ( newHeight != oldHeight );
624
625   mImpl->mLeft = left;
626   mImpl->mTop = top;
627   mImpl->mRight = right;
628   mImpl->mBottom = bottom;
629
630   // Reflect up to parent control
631   auto owner = GetOwner();
632   auto actor = Actor::DownCast( owner );
633   LayoutData& layoutData = *mImpl->sLayoutData;
634   if( actor )
635   {
636     if( mImpl->mAnimated && !layoutData.speculativeLayout )
637     {
638       LayoutItem* transitionOwner = layoutData.layoutTransition.layoutItem.Get();
639       LayoutTransitionDataPtr layoutTransitionDataPtr = GetTransitionData( layoutData.layoutTransition.layoutTransitionType );
640
641       // Found transition owner
642       if( transitionOwner == this && layoutTransitionDataPtr.Get() )
643       {
644         DALI_LOG_INFO( gLayoutFilter, Debug::Verbose, "LayoutItem::SetFrame apply transition to (%s), transition type (%d)\n", actor.GetName().c_str(), layoutData.layoutTransition.layoutTransitionType );
645         layoutData.layoutPositionDataArray.push_back( LayoutPositionData( actor, left.AsDecimal(), top.AsDecimal(), right.AsDecimal(), bottom.AsDecimal(), true ) );
646         layoutTransitionDataPtr->ConvertToLayoutDataElements( actor, layoutData );
647         changed = true;
648       }
649       else
650       {
651         if( changed )
652         {
653           layoutTransitionDataPtr = GetTransitionData( Dali::Toolkit::LayoutTransitionData::ON_LAYOUT_CHANGE );
654           if ( layoutTransitionDataPtr )
655           {
656             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 );
657             layoutData.layoutPositionDataArray.push_back( LayoutPositionData( actor, left.AsDecimal(), top.AsDecimal(), right.AsDecimal(), bottom.AsDecimal(), true ) );
658             layoutTransitionDataPtr->ConvertToLayoutDataElements( actor, layoutData );
659           }
660           else
661           {
662             DALI_LOG_INFO( gLayoutFilter, Debug::Verbose, "LayoutItem::SetFrame apply default transition to (%s), transition type (%d)\n", actor.GetName().c_str(), layoutData.layoutTransition.layoutTransitionType );
663             layoutData.layoutPositionDataArray.push_back( LayoutPositionData( actor, left.AsDecimal(), top.AsDecimal(), right.AsDecimal(), bottom.AsDecimal(), true ) );
664             GetDefaultTransition()->ConvertToLayoutDataElements( actor, layoutData );
665           }
666         }
667         else
668         {
669           DALI_LOG_INFO( gLayoutFilter, Debug::Verbose, "LayoutItem::SetFrame apply children animators to (%s), transition type (%d)\n", actor.GetName().c_str(), layoutData.layoutTransition.layoutTransitionType );
670           layoutData.layoutPositionDataArray.push_back( LayoutPositionData( actor, left.AsDecimal(), top.AsDecimal(), right.AsDecimal(), bottom.AsDecimal(), true ) );
671           LayoutTransitionData::ConvertChildrenAnimatorsToLayoutDataElements( actor, layoutData );
672         }
673       }
674     }
675     else
676     {
677       if( changed )
678       {
679         layoutData.layoutPositionDataArray.push_back( LayoutPositionData( actor, left.AsDecimal(), top.AsDecimal(), right.AsDecimal(), bottom.AsDecimal(), false ) );
680       }
681     }
682   }
683
684   // TODO: do we need it
685   if( sizeChanged )
686   {
687     SizeChange( LayoutSize( newWidth, newHeight ), LayoutSize( oldWidth, oldHeight ) );
688   }
689
690   DALI_LOG_STREAM( gLayoutFilter, Debug::Verbose, "LayoutItem::SetFrame  exit(" << left << ", " << top << ", " << right << ", " << bottom << ")\n" );
691
692   return changed;
693 }
694
695 LayoutLength LayoutItem::GetTargetWidth() const
696 {
697   return mImpl->mTargetWidth;
698 }
699
700 LayoutLength LayoutItem::GetTargetHeight() const
701 {
702   return mImpl->mTargetHeight;
703 }
704
705 void LayoutItem::SetTargetWidth( LayoutLength width )
706 {
707   mImpl->mTargetWidth = width;
708 }
709
710 void LayoutItem::SetTargetHeight( LayoutLength height )
711 {
712   mImpl->mTargetHeight = height;
713 }
714
715 void LayoutItem::OnLayoutAnimationFinished( Animation& animation )
716 {
717   auto owner = GetOwner();
718   auto actor = Actor::DownCast(owner);
719   if( actor )
720   {
721     actor.SetSize( Vector3( mImpl->mRight.AsInteger() - mImpl->mLeft.AsInteger(), mImpl->mBottom.AsInteger() - mImpl->mTop.AsInteger(), 0.0f ) );
722   }
723 }
724
725 void LayoutItem::SizeChange( LayoutSize newSize, LayoutSize oldSize)
726 {
727   OnSizeChanged( newSize, oldSize );
728 }
729
730
731 void LayoutItem::OnSizeChanged( LayoutSize newSize, LayoutSize oldSize )
732 {
733 }
734
735 void LayoutItem::OnInitialize()
736 {
737 }
738
739
740 } // namespace Internal
741 } // namespace Toolkit
742 } // namespace Dali