Layout changes for NUI support.
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / devel-api / layouting / layout-base-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-toolkit/devel-api/layouting/layout-base-impl.h>
23 #include <dali-toolkit/internal/layouting/layout-base-data-impl.h>
24
25 #if defined(DEBUG_ENABLED)
26     Debug::Filter* gLayoutFilter = Debug::Filter::New( Debug::Verbose, false, "LOG_LAYOUT" );
27 #endif
28
29 namespace
30 {
31 const char* WIDTH_SPECIFICATION_NAME( "widthSpecification" );
32 const char* HEIGHT_SPECIFICATION_NAME( "heightSpecification" );
33
34 const float DEFAULT_TRANSITION_DURATION( 0.5f );
35 }
36
37 namespace Dali
38 {
39 namespace Toolkit
40 {
41 namespace Internal
42 {
43
44 LayoutBase::LayoutBase()
45 : mImpl( new LayoutBase::Impl() ),
46   mSlotDelegate( this )
47 {
48 }
49
50 LayoutBasePtr LayoutBase::New( Handle& owner )
51 {
52   LayoutBasePtr layoutPtr = new LayoutBase();
53   return layoutPtr;
54 }
55
56 void LayoutBase::Initialize( Handle& owner, const std::string& containerType )
57 {
58   mImpl->mOwner = &(owner.GetBaseObject());
59   RegisterChildProperties( containerType );
60   OnInitialize(); // Ensure direct deriving class gets initialized
61   RequestLayout();
62 }
63
64 Handle LayoutBase::GetOwner() const
65 {
66   return Handle::DownCast(BaseHandle(mImpl->mOwner));
67 }
68
69 void LayoutBase::Unparent()
70 {
71   // Enable directly derived types to first remove children
72   OnUnparent();
73
74   // Last, clear owner
75   mImpl->mOwner = NULL;
76 }
77
78 void LayoutBase::SetAnimateLayout( bool animateLayout )
79 {
80   mImpl->mAnimated = animateLayout;
81 }
82
83 bool LayoutBase::IsLayoutAnimated() const
84 {
85   return mImpl->mAnimated;
86 }
87
88 void LayoutBase::RegisterChildProperties( const std::string& containerType )
89 {
90   // Call on derived types
91   auto typeInfo = TypeRegistry::Get().GetTypeInfo( containerType );
92   if( typeInfo )
93   {
94     Property::IndexContainer indices;
95     typeInfo.GetChildPropertyIndices( indices );
96
97     if( std::find( indices.Begin(), indices.End(), Toolkit::LayoutBase::ChildProperty::WIDTH_SPECIFICATION ) ==
98         indices.End() )
99     {
100       ChildPropertyRegistration( typeInfo.GetName(), WIDTH_SPECIFICATION_NAME,
101                                  Toolkit::LayoutBase::ChildProperty::WIDTH_SPECIFICATION, Property::INTEGER );
102
103       ChildPropertyRegistration( typeInfo.GetName(), HEIGHT_SPECIFICATION_NAME,
104                                  Toolkit::LayoutBase::ChildProperty::HEIGHT_SPECIFICATION, Property::INTEGER );
105     }
106
107     OnRegisterChildProperties( containerType );
108   }
109 }
110
111 void LayoutBase::OnRegisterChildProperties( const std::string& containerType )
112 {
113 }
114
115
116 void LayoutBase::Measure( MeasureSpec widthMeasureSpec, MeasureSpec heightMeasureSpec )
117 {
118   const bool forceLayout = mImpl->GetPrivateFlag( Impl::PRIVATE_FLAG_FORCE_LAYOUT );
119
120   const bool specChanged =
121     ( widthMeasureSpec  != mImpl->mOldWidthMeasureSpec ) ||
122     ( heightMeasureSpec != mImpl->mOldHeightMeasureSpec );
123
124   const bool isSpecExactly =
125     ( widthMeasureSpec.GetMode() == MeasureSpec::Mode::EXACTLY ) &&
126     ( heightMeasureSpec.GetMode() == MeasureSpec::Mode::EXACTLY );
127
128   const bool matchesSpecSize =
129     ( GetMeasuredWidth() == widthMeasureSpec.GetSize() ) &&
130     ( GetMeasuredHeight() == heightMeasureSpec.GetSize() );
131
132   const bool needsLayout = specChanged && ( !isSpecExactly || !matchesSpecSize );
133
134   if( forceLayout || needsLayout)
135   {
136     mImpl->ClearPrivateFlag( Impl::PRIVATE_FLAG_MEASURED_DIMENSION_SET );
137
138     //resolveRtlPropertiesIfNeeded();
139
140     int cacheIndex = -1;  // = forceLayout ? -1 : mMeasureCache.indexOfKey(key);
141     if( cacheIndex < 0 ) //|| sIgnoreMeasureCache )
142     {
143       // measure ourselves, this should set the measured dimension flag back
144       OnMeasure( widthMeasureSpec, heightMeasureSpec );
145       mImpl->ClearPrivateFlag( Impl::PRIVATE_FLAG_MEASURE_NEEDED_BEFORE_LAYOUT );
146     }
147     else
148     {
149       mImpl->SetPrivateFlag( Impl::PRIVATE_FLAG_MEASURE_NEEDED_BEFORE_LAYOUT );
150     }
151
152     // flag not set, setMeasuredDimension() was not invoked, we raise an exception to warn the developer
153     DALI_ASSERT_ALWAYS( mImpl->GetPrivateFlag( Impl::PRIVATE_FLAG_MEASURED_DIMENSION_SET ) &&
154                         "Layout's OnMeasure() did not set the measured dimension by calling setMeasuredDimension()" );
155     mImpl->SetPrivateFlag( Impl::PRIVATE_FLAG_LAYOUT_REQUIRED );
156   }
157
158   mImpl->mOldWidthMeasureSpec = widthMeasureSpec;
159   mImpl->mOldHeightMeasureSpec = heightMeasureSpec;
160
161   //mMeasureCache.put(key, ((long) mMeasuredWidth) << 32 | (long) mMeasuredHeight & 0xffffffffL); // suppress sign extension
162 }
163
164 void LayoutBase::Layout( LayoutLength l, LayoutLength t, LayoutLength r, LayoutLength b )
165 {
166   if( mImpl->GetPrivateFlag( Impl::PRIVATE_FLAG_MEASURE_NEEDED_BEFORE_LAYOUT ) )
167   {
168     OnMeasure( mImpl->mOldWidthMeasureSpec, mImpl->mOldHeightMeasureSpec );
169     mImpl->ClearPrivateFlag( Impl::PRIVATE_FLAG_MEASURE_NEEDED_BEFORE_LAYOUT );
170   }
171
172   bool changed = SetFrame( l, t, r, b );
173
174   if( changed || mImpl->GetPrivateFlag( Impl::PRIVATE_FLAG_LAYOUT_REQUIRED ) )
175   {
176     OnLayout( changed, l, t, r, b );
177     mImpl->ClearPrivateFlag( Impl::PRIVATE_FLAG_LAYOUT_REQUIRED );
178   }
179
180   mImpl->ClearPrivateFlag( Impl::PRIVATE_FLAG_FORCE_LAYOUT );
181   mImpl->SetPrivateFlag( Impl::PRIVATE_FLAG_IS_LAID_OUT );
182 }
183
184 LayoutLength LayoutBase::GetMinimumWidth() const
185 {
186   return mImpl->mMinimumSize.GetWidth();
187 }
188
189 LayoutLength LayoutBase::GetMinimumHeight() const
190 {
191   return mImpl->mMinimumSize.GetHeight();
192 }
193
194 void LayoutBase::SetMinimumWidth( LayoutLength minimumWidth )
195 {
196   mImpl->mMinimumSize.SetWidth( minimumWidth );
197   RequestLayout();
198 }
199
200 void LayoutBase::SetMinimumHeight( LayoutLength minimumHeight )
201 {
202   mImpl->mMinimumSize.SetHeight( minimumHeight );
203   RequestLayout();
204 }
205
206 Extents LayoutBase::GetPadding() const
207 {
208   return mImpl->mPadding;
209 }
210
211 LayoutLength LayoutBase::GetDefaultSize( LayoutLength size, MeasureSpec measureSpec )
212 {
213   LayoutLength result = size;
214   auto specMode = measureSpec.GetMode();
215   auto specSize = measureSpec.GetSize();
216
217   switch (specMode)
218   {
219     case MeasureSpec::Mode::UNSPECIFIED:
220     {
221       result = size;
222       break;
223     }
224     case MeasureSpec::Mode::AT_MOST:
225     case MeasureSpec::Mode::EXACTLY:
226     {
227       result = specSize;
228       break;
229     }
230   }
231   return result;
232 }
233
234 void LayoutBase::OnMeasure( MeasureSpec widthMeasureSpec, MeasureSpec heightMeasureSpec)
235 {
236   SetMeasuredDimensions( GetDefaultSize( GetSuggestedMinimumWidth(), widthMeasureSpec ),
237                          GetDefaultSize( GetSuggestedMinimumHeight(), heightMeasureSpec ) );
238 }
239
240 void LayoutBase::OnLayout( bool changed, LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom )
241 {
242 }
243
244 LayoutParent* LayoutBase::GetParent()
245 {
246   return mImpl->mLayoutParent;
247 }
248
249 void LayoutBase::RequestLayout()
250 {
251   // @todo Enforce failure if called in Measure/Layout passes.
252   mImpl->SetPrivateFlag( Impl::PRIVATE_FLAG_FORCE_LAYOUT );
253   Toolkit::LayoutController layoutController = Toolkit::LayoutController::Get();
254   layoutController.RequestLayout( Toolkit::LayoutBase(this) );
255 }
256
257 bool LayoutBase::IsLayoutRequested() const
258 {
259   return mImpl->GetPrivateFlag( Impl::PRIVATE_FLAG_FORCE_LAYOUT );
260 }
261
262 void LayoutBase::SetMeasuredDimensions( MeasuredSize measuredWidth, MeasuredSize measuredHeight )
263 {
264   mImpl->SetPrivateFlag( Impl::PRIVATE_FLAG_MEASURED_DIMENSION_SET );
265   mImpl->mMeasuredWidth = measuredWidth;
266   mImpl->mMeasuredHeight = measuredHeight;
267 }
268
269 LayoutLength LayoutBase::GetMeasuredWidth() const
270 {
271   // Get the size portion of the measured width
272   return  mImpl->mMeasuredWidth.GetSize();
273 }
274
275 LayoutLength LayoutBase::GetMeasuredHeight() const
276 {
277   return  mImpl->mMeasuredHeight.GetSize();
278 }
279
280 MeasuredSize LayoutBase::GetMeasuredWidthAndState() const
281 {
282   return mImpl->mMeasuredWidth;
283 }
284
285 MeasuredSize LayoutBase::GetMeasuredHeightAndState() const
286 {
287   return mImpl->mMeasuredHeight;
288 }
289
290 LayoutLength LayoutBase::GetSuggestedMinimumWidth() const
291 {
292   auto owner = GetOwner();
293   auto actor = Actor::DownCast(owner);
294   auto naturalSize = actor ? actor.GetNaturalSize() : Vector3::ZERO;
295
296   return std::max( mImpl->mMinimumSize.GetWidth(), LayoutLength::IntType( naturalSize.width ) );
297 }
298
299 LayoutLength LayoutBase::GetSuggestedMinimumHeight() const
300 {
301   auto owner = GetOwner();
302   auto actor = Actor::DownCast(owner);
303   auto naturalSize = actor ? actor.GetNaturalSize() : Vector3::ZERO;
304
305   return std::max( mImpl->mMinimumSize.GetHeight(), LayoutLength::IntType(naturalSize.height) );
306 }
307
308 MeasuredSize LayoutBase::ResolveSizeAndState( LayoutLength size, MeasureSpec measureSpec, MeasuredSize::State childMeasuredState )
309 {
310   auto specMode = measureSpec.GetMode();
311   LayoutLength specSize = measureSpec.GetSize();
312   MeasuredSize result;
313
314   switch( specMode )
315   {
316     case MeasureSpec::Mode::AT_MOST:
317     {
318       if (specSize < size)
319       {
320         result = MeasuredSize( specSize, MeasuredSize::MEASURED_SIZE_TOO_SMALL );
321       }
322       else
323       {
324         result.SetSize( size );
325       }
326       break;
327     }
328
329     case MeasureSpec::Mode::EXACTLY:
330     {
331       result.SetSize( specSize );
332       break;
333     }
334
335     case MeasureSpec::Mode::UNSPECIFIED:
336     default:
337     {
338       result.SetSize( size );
339       break;
340     }
341   }
342
343   result.SetState( childMeasuredState );
344   return result;
345 }
346
347
348 bool LayoutBase::SetFrame( LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom )
349 {
350   bool changed = false;
351
352   DALI_LOG_INFO( gLayoutFilter, Debug::Verbose, "LayoutBase::SetFrame(%d, %d, %d, %d)\n", left.mValue, top.mValue, right.mValue, bottom.mValue );
353
354   if( mImpl->mLeft != left || mImpl->mRight != right || mImpl->mTop != top || mImpl->mBottom != bottom )
355   {
356     changed = true;
357
358     auto oldWidth = mImpl->mRight - mImpl->mLeft;
359     auto oldHeight = mImpl->mBottom - mImpl->mTop;
360     auto newWidth = right - left;
361     auto newHeight = bottom - top;
362     bool sizeChanged = (newWidth != oldWidth) || (newHeight != oldHeight);
363
364     mImpl->mLeft = left;
365     mImpl->mTop = top;
366     mImpl->mRight = right;
367     mImpl->mBottom = bottom;
368
369     mImpl->SetPrivateFlag( Impl::PRIVATE_FLAG_HAS_BOUNDS );
370
371
372     // Reflect up to parent control
373     auto owner = GetOwner();
374     auto actor = Actor::DownCast(owner);
375     if( actor )
376     {
377       if( mImpl->mAnimated )
378       {
379         auto animation = Animation::New( 0.5f );
380         animation.AnimateTo( Property( actor, Actor::Property::POSITION ),
381                              Vector3( float(left.mValue), float(top.mValue), 0.0f ) );
382         animation.AnimateTo( Property( actor, Actor::Property::SIZE ),
383                              Vector3( right-left, bottom-top, 0.0f ) );
384         animation.FinishedSignal().Connect( mSlotDelegate, &LayoutBase::OnLayoutAnimationFinished );
385         animation.Play();
386       }
387       else
388       {
389         // @todo Collate into list of Property & Property::Value pairs.
390         actor.SetPosition( Vector3( float(left.mValue), float(top.mValue), 0.0f ) );
391         actor.SetSize( Vector3( right-left, bottom-top, 0.0f ) );
392       }
393     }
394
395     if( sizeChanged )
396     {
397       SizeChange( LayoutSize( newWidth, newHeight ), LayoutSize( oldWidth, oldHeight ) );
398     }
399   }
400   return changed;
401 }
402
403 void LayoutBase::OnLayoutAnimationFinished( Animation& animation )
404 {
405   auto owner = GetOwner();
406   auto actor = Actor::DownCast(owner);
407   if( actor )
408   {
409     actor.SetSize( Vector3( mImpl->mRight-mImpl->mLeft, mImpl->mBottom-mImpl->mTop, 0.0f ) );
410   }
411 }
412
413 void LayoutBase::SizeChange( LayoutSize newSize, LayoutSize oldSize)
414 {
415   OnSizeChanged( newSize, oldSize );
416 }
417
418
419 void LayoutBase::OnSizeChanged( LayoutSize newSize, LayoutSize oldSize )
420 {
421 }
422
423 void LayoutBase::OnInitialize()
424 {
425 }
426
427
428 } // namespace Internal
429 } // namespace Toolkit
430 } // namespace Dali