2 * Copyright (c) 2018 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include <dali/integration-api/debug.h>
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>
25 #if defined(DEBUG_ENABLED)
26 Debug::Filter* gLayoutFilter = Debug::Filter::New( Debug::Verbose, false, "LOG_LAYOUT" );
31 const char* WIDTH_SPECIFICATION_NAME( "widthSpecification" );
32 const char* HEIGHT_SPECIFICATION_NAME( "heightSpecification" );
34 const float DEFAULT_TRANSITION_DURATION( 0.5f );
44 LayoutBase::LayoutBase()
45 : mImpl( new LayoutBase::Impl() ),
50 LayoutBasePtr LayoutBase::New( Handle& owner )
52 LayoutBasePtr layoutPtr = new LayoutBase();
56 void LayoutBase::Initialize( Handle& owner, const std::string& containerType )
58 mImpl->mOwner = &(owner.GetBaseObject());
59 RegisterChildProperties( containerType );
60 OnInitialize(); // Ensure direct deriving class gets initialized
64 Handle LayoutBase::GetOwner() const
66 return Handle::DownCast(BaseHandle(mImpl->mOwner));
69 void LayoutBase::Unparent()
71 // Enable directly derived types to first remove children
78 void LayoutBase::SetAnimateLayout( bool animateLayout )
80 mImpl->mAnimated = animateLayout;
83 bool LayoutBase::IsLayoutAnimated() const
85 return mImpl->mAnimated;
88 void LayoutBase::RegisterChildProperties( const std::string& containerType )
90 // Call on derived types
91 auto typeInfo = TypeRegistry::Get().GetTypeInfo( containerType );
94 Property::IndexContainer indices;
95 typeInfo.GetChildPropertyIndices( indices );
97 if( std::find( indices.Begin(), indices.End(), Toolkit::LayoutBase::ChildProperty::WIDTH_SPECIFICATION ) ==
100 ChildPropertyRegistration( typeInfo.GetName(), WIDTH_SPECIFICATION_NAME,
101 Toolkit::LayoutBase::ChildProperty::WIDTH_SPECIFICATION, Property::INTEGER );
103 ChildPropertyRegistration( typeInfo.GetName(), HEIGHT_SPECIFICATION_NAME,
104 Toolkit::LayoutBase::ChildProperty::HEIGHT_SPECIFICATION, Property::INTEGER );
107 OnRegisterChildProperties( containerType );
111 void LayoutBase::OnRegisterChildProperties( const std::string& containerType )
116 void LayoutBase::Measure( MeasureSpec widthMeasureSpec, MeasureSpec heightMeasureSpec )
118 const bool forceLayout = mImpl->GetPrivateFlag( Impl::PRIVATE_FLAG_FORCE_LAYOUT );
120 const bool specChanged =
121 ( widthMeasureSpec != mImpl->mOldWidthMeasureSpec ) ||
122 ( heightMeasureSpec != mImpl->mOldHeightMeasureSpec );
124 const bool isSpecExactly =
125 ( widthMeasureSpec.GetMode() == MeasureSpec::Mode::EXACTLY ) &&
126 ( heightMeasureSpec.GetMode() == MeasureSpec::Mode::EXACTLY );
128 const bool matchesSpecSize =
129 ( GetMeasuredWidth() == widthMeasureSpec.GetSize() ) &&
130 ( GetMeasuredHeight() == heightMeasureSpec.GetSize() );
132 const bool needsLayout = specChanged && ( !isSpecExactly || !matchesSpecSize );
134 if( forceLayout || needsLayout)
136 mImpl->ClearPrivateFlag( Impl::PRIVATE_FLAG_MEASURED_DIMENSION_SET );
138 //resolveRtlPropertiesIfNeeded();
140 int cacheIndex = -1; // = forceLayout ? -1 : mMeasureCache.indexOfKey(key);
141 if( cacheIndex < 0 ) //|| sIgnoreMeasureCache )
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 );
149 mImpl->SetPrivateFlag( Impl::PRIVATE_FLAG_MEASURE_NEEDED_BEFORE_LAYOUT );
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 );
158 mImpl->mOldWidthMeasureSpec = widthMeasureSpec;
159 mImpl->mOldHeightMeasureSpec = heightMeasureSpec;
161 //mMeasureCache.put(key, ((long) mMeasuredWidth) << 32 | (long) mMeasuredHeight & 0xffffffffL); // suppress sign extension
164 void LayoutBase::Layout( LayoutLength l, LayoutLength t, LayoutLength r, LayoutLength b )
166 if( mImpl->GetPrivateFlag( Impl::PRIVATE_FLAG_MEASURE_NEEDED_BEFORE_LAYOUT ) )
168 OnMeasure( mImpl->mOldWidthMeasureSpec, mImpl->mOldHeightMeasureSpec );
169 mImpl->ClearPrivateFlag( Impl::PRIVATE_FLAG_MEASURE_NEEDED_BEFORE_LAYOUT );
172 bool changed = SetFrame( l, t, r, b );
174 if( changed || mImpl->GetPrivateFlag( Impl::PRIVATE_FLAG_LAYOUT_REQUIRED ) )
176 OnLayout( changed, l, t, r, b );
177 mImpl->ClearPrivateFlag( Impl::PRIVATE_FLAG_LAYOUT_REQUIRED );
180 mImpl->ClearPrivateFlag( Impl::PRIVATE_FLAG_FORCE_LAYOUT );
181 mImpl->SetPrivateFlag( Impl::PRIVATE_FLAG_IS_LAID_OUT );
184 LayoutLength LayoutBase::GetMinimumWidth() const
186 return mImpl->mMinimumSize.GetWidth();
189 LayoutLength LayoutBase::GetMinimumHeight() const
191 return mImpl->mMinimumSize.GetHeight();
194 void LayoutBase::SetMinimumWidth( LayoutLength minimumWidth )
196 mImpl->mMinimumSize.SetWidth( minimumWidth );
200 void LayoutBase::SetMinimumHeight( LayoutLength minimumHeight )
202 mImpl->mMinimumSize.SetHeight( minimumHeight );
206 Extents LayoutBase::GetPadding() const
208 return mImpl->mPadding;
211 LayoutLength LayoutBase::GetDefaultSize( LayoutLength size, MeasureSpec measureSpec )
213 LayoutLength result = size;
214 auto specMode = measureSpec.GetMode();
215 auto specSize = measureSpec.GetSize();
219 case MeasureSpec::Mode::UNSPECIFIED:
224 case MeasureSpec::Mode::AT_MOST:
225 case MeasureSpec::Mode::EXACTLY:
234 void LayoutBase::OnMeasure( MeasureSpec widthMeasureSpec, MeasureSpec heightMeasureSpec)
236 SetMeasuredDimensions( GetDefaultSize( GetSuggestedMinimumWidth(), widthMeasureSpec ),
237 GetDefaultSize( GetSuggestedMinimumHeight(), heightMeasureSpec ) );
240 void LayoutBase::OnLayout( bool changed, LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom )
244 LayoutParent* LayoutBase::GetParent()
246 return mImpl->mLayoutParent;
249 void LayoutBase::RequestLayout()
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) );
257 bool LayoutBase::IsLayoutRequested() const
259 return mImpl->GetPrivateFlag( Impl::PRIVATE_FLAG_FORCE_LAYOUT );
262 void LayoutBase::SetMeasuredDimensions( MeasuredSize measuredWidth, MeasuredSize measuredHeight )
264 mImpl->SetPrivateFlag( Impl::PRIVATE_FLAG_MEASURED_DIMENSION_SET );
265 mImpl->mMeasuredWidth = measuredWidth;
266 mImpl->mMeasuredHeight = measuredHeight;
269 LayoutLength LayoutBase::GetMeasuredWidth() const
271 // Get the size portion of the measured width
272 return mImpl->mMeasuredWidth.GetSize();
275 LayoutLength LayoutBase::GetMeasuredHeight() const
277 return mImpl->mMeasuredHeight.GetSize();
280 MeasuredSize LayoutBase::GetMeasuredWidthAndState() const
282 return mImpl->mMeasuredWidth;
285 MeasuredSize LayoutBase::GetMeasuredHeightAndState() const
287 return mImpl->mMeasuredHeight;
290 LayoutLength LayoutBase::GetSuggestedMinimumWidth() const
292 auto owner = GetOwner();
293 auto actor = Actor::DownCast(owner);
294 auto naturalSize = actor ? actor.GetNaturalSize() : Vector3::ZERO;
296 return std::max( mImpl->mMinimumSize.GetWidth(), LayoutLength::IntType( naturalSize.width ) );
299 LayoutLength LayoutBase::GetSuggestedMinimumHeight() const
301 auto owner = GetOwner();
302 auto actor = Actor::DownCast(owner);
303 auto naturalSize = actor ? actor.GetNaturalSize() : Vector3::ZERO;
305 return std::max( mImpl->mMinimumSize.GetHeight(), LayoutLength::IntType(naturalSize.height) );
308 MeasuredSize LayoutBase::ResolveSizeAndState( LayoutLength size, MeasureSpec measureSpec, MeasuredSize::State childMeasuredState )
310 auto specMode = measureSpec.GetMode();
311 LayoutLength specSize = measureSpec.GetSize();
316 case MeasureSpec::Mode::AT_MOST:
320 result = MeasuredSize( specSize, MeasuredSize::MEASURED_SIZE_TOO_SMALL );
324 result.SetSize( size );
329 case MeasureSpec::Mode::EXACTLY:
331 result.SetSize( specSize );
335 case MeasureSpec::Mode::UNSPECIFIED:
338 result.SetSize( size );
343 result.SetState( childMeasuredState );
348 bool LayoutBase::SetFrame( LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom )
350 bool changed = false;
352 DALI_LOG_INFO( gLayoutFilter, Debug::Verbose, "LayoutBase::SetFrame(%d, %d, %d, %d)\n", left.mValue, top.mValue, right.mValue, bottom.mValue );
354 if( mImpl->mLeft != left || mImpl->mRight != right || mImpl->mTop != top || mImpl->mBottom != bottom )
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);
366 mImpl->mRight = right;
367 mImpl->mBottom = bottom;
369 mImpl->SetPrivateFlag( Impl::PRIVATE_FLAG_HAS_BOUNDS );
372 // Reflect up to parent control
373 auto owner = GetOwner();
374 auto actor = Actor::DownCast(owner);
377 if( mImpl->mAnimated )
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 );
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 ) );
397 SizeChange( LayoutSize( newWidth, newHeight ), LayoutSize( oldWidth, oldHeight ) );
403 void LayoutBase::OnLayoutAnimationFinished( Animation& animation )
405 auto owner = GetOwner();
406 auto actor = Actor::DownCast(owner);
409 actor.SetSize( Vector3( mImpl->mRight-mImpl->mLeft, mImpl->mBottom-mImpl->mTop, 0.0f ) );
413 void LayoutBase::SizeChange( LayoutSize newSize, LayoutSize oldSize)
415 OnSizeChanged( newSize, oldSize );
419 void LayoutBase::OnSizeChanged( LayoutSize newSize, LayoutSize oldSize )
423 void LayoutBase::OnInitialize()
428 } // namespace Internal
429 } // namespace Toolkit