2 * Copyright (c) 2014 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.
19 #include "alignment-impl.h"
22 #include <dali/public-api/object/property-input.h>
23 #include <dali/public-api/object/type-registry.h>
24 #include <dali/devel-api/object/type-registry-helper.h>
25 #include <dali/public-api/size-negotiation/relayout-container.h>
42 return Toolkit::Alignment::New();
45 DALI_TYPE_REGISTRATION_BEGIN( Toolkit::Alignment, Toolkit::Control, Create )
46 DALI_TYPE_REGISTRATION_END()
48 struct ScaleToFillConstraint
51 * @param padding to be added.
53 ScaleToFillConstraint( const Toolkit::Alignment::Padding& padding )
58 * Called by render thread
60 Vector3 operator()( const Vector3& currentSize,
61 const PropertyInput& parentSizeProperty )
63 const Vector3& parentSize( parentSizeProperty.GetVector3() );
64 return GetSize( currentSize, parentSize );
67 inline Vector3 GetSize( const Vector3& currentSize, const Vector3& parentSize )
69 const float parentSizeWidth = parentSize.width - ( mPadding.left + mPadding.right );
70 const float parentSizeHeight = parentSize.height - ( mPadding.top + mPadding.bottom );
72 // prevent ridiculous sizes if parent is really small or if we don't have a proper size for the actor
73 if( ( parentSizeWidth < Math::MACHINE_EPSILON_1000 ) || ( parentSizeHeight < Math::MACHINE_EPSILON_1000 ) )
75 // no point trying to squeeze actors into this small size
78 return Vector3( parentSizeWidth, parentSizeHeight, parentSize.depth );
81 const Toolkit::Alignment::Padding mPadding;
84 struct ScaleToFitKeepAspectConstraint
87 * @param padding to be added.
89 ScaleToFitKeepAspectConstraint( const Toolkit::Alignment::Padding& padding )
90 : mPadding( padding ),
96 * Called by render thread
98 Vector3 operator()( const Vector3& currentSize,
99 const PropertyInput& parentSizeProperty )
101 const Vector3& parentSize( parentSizeProperty.GetVector3() );
102 return GetSize( currentSize, parentSize );
105 inline Vector3 GetSize( const Vector3& currentSize, const Vector3& parentSize )
107 if( ( !mSizeStored ) && ( Vector3::ZERO != currentSize ) )
109 mOriginalSize = currentSize;
113 const float parentSizeWidth = parentSize.width - ( mPadding.left + mPadding.right );
114 const float parentSizeHeight = parentSize.height - ( mPadding.top + mPadding.bottom );
116 // prevent ridiculous sizes if parent is really small or if we don't have a proper size for the actor
117 if( ( parentSizeWidth < Math::MACHINE_EPSILON_1000 ) || ( parentSizeHeight < Math::MACHINE_EPSILON_1000 )||
118 ( mOriginalSize.width < Math::MACHINE_EPSILON_1000 ) || ( mOriginalSize.height < Math::MACHINE_EPSILON_1000 ) )
120 // no point trying to squeeze actors into this small size
121 return Vector3::ZERO;
124 return mOriginalSize * std::min( ( parentSizeWidth / mOriginalSize.width ), ( parentSizeHeight / mOriginalSize.height ) );
127 const Toolkit::Alignment::Padding mPadding;
129 Vector3 mOriginalSize;
132 struct ScaleToFillKeepAspectConstraint
135 * @param padding to be added.
137 ScaleToFillKeepAspectConstraint( const Toolkit::Alignment::Padding& padding )
138 : mPadding( padding ),
139 mSizeStored( false ),
144 * Called by render thread
146 Vector3 operator()( const Vector3& currentSize,
147 const PropertyInput& parentSizeProperty )
149 const Vector3& parentSize( parentSizeProperty.GetVector3() );
150 return GetSize( currentSize, parentSize );
153 Vector3 GetSize( const Vector3& currentSize, const Vector3& parentSize )
155 if( ( !mSizeStored ) && ( Vector3::ZERO != currentSize ) )
157 mOriginalSize = currentSize;
161 const float parentSizeWidth = parentSize.width - ( mPadding.left + mPadding.right );
162 const float parentSizeHeight = parentSize.height - ( mPadding.top + mPadding.bottom );
164 // prevent ridiculous sizes if parent is really small or if we don't have a proper size for the actor
165 if( ( parentSizeWidth < Math::MACHINE_EPSILON_1000 ) || ( parentSizeHeight < Math::MACHINE_EPSILON_1000 )||
166 ( mOriginalSize.width < Math::MACHINE_EPSILON_1000 ) || ( mOriginalSize.height < Math::MACHINE_EPSILON_1000 ) )
168 // no point trying to squeeze actors into this small size
169 return Vector3::ZERO;
172 return mOriginalSize * std::max( ( parentSizeWidth / mOriginalSize.width ), ( parentSizeHeight / mOriginalSize.height ) );
175 const Toolkit::Alignment::Padding mPadding;
177 Vector3 mOriginalSize;
180 struct ShrinkToFitConstraint
183 * @param padding to be added.
185 ShrinkToFitConstraint( const Toolkit::Alignment::Padding& padding )
186 : mPadding( padding ),
187 mSizeStored( false ),
192 * Called by render thread
194 Vector3 operator()( const Vector3& currentSize,
195 const PropertyInput& parentSizeProperty )
197 const Vector3& parentSize( parentSizeProperty.GetVector3() );
198 return GetSize( currentSize, parentSize );
201 Vector3 GetSize( const Vector3& currentSize, const Vector3& parentSize )
203 if( ( !mSizeStored ) && ( Vector3::ZERO != currentSize ) )
205 mOriginalSize = currentSize;
209 const float parentSizeWidth = parentSize.width - ( mPadding.left + mPadding.right );
210 const float parentSizeHeight = parentSize.height - ( mPadding.top + mPadding.bottom );
212 // prevent ridiculous sizes if parent is really small or if we don't have a proper size for the actor
213 if( ( parentSizeWidth < Math::MACHINE_EPSILON_1000 ) || ( parentSizeHeight < Math::MACHINE_EPSILON_1000 )||
214 ( mOriginalSize.width < Math::MACHINE_EPSILON_1000 ) || ( mOriginalSize.height < Math::MACHINE_EPSILON_1000 ) )
216 // no point trying to squeeze actors into this small size
217 return Vector3::ZERO;
220 return Vector3( std::min( parentSizeWidth, mOriginalSize.width ), std::min( parentSizeHeight, mOriginalSize.height ), std::min( parentSize.depth, mOriginalSize.depth ) );
223 const Toolkit::Alignment::Padding mPadding;
225 Vector3 mOriginalSize;
229 * Constraint that uses naturalSize if it fits inside parent and parent size if not. It also adds some padding pixels
231 struct ShrinkToFitKeepAspectConstraint
234 * @param padding to be added.
236 ShrinkToFitKeepAspectConstraint( const Toolkit::Alignment::Padding& padding )
237 : mPadding( padding ),
238 mSizeStored( false ),
243 * Called by render thread
245 Vector3 operator()( const Vector3& currentSize,
246 const PropertyInput& parentSizeProperty )
248 const Vector3& parentSize( parentSizeProperty.GetVector3() );
249 return GetSize( currentSize, parentSize );
252 inline Vector3 GetSize( const Vector3& currentSize, const Vector3& parentSize )
254 if( ( !mSizeStored ) && ( Vector3::ZERO != currentSize ) )
256 mOriginalSize = currentSize;
260 const float parentSizeWidth = parentSize.width - ( mPadding.left + mPadding.right );
261 const float parentSizeHeight = parentSize.height - ( mPadding.top + mPadding.bottom );
263 // prevent ridiculous sizes if parent is really small or if we don't have a proper size for the actor
264 if( ( parentSizeWidth < Math::MACHINE_EPSILON_1000 ) || ( parentSizeHeight < Math::MACHINE_EPSILON_1000 )||
265 ( mOriginalSize.width < Math::MACHINE_EPSILON_1000 ) || ( mOriginalSize.height < Math::MACHINE_EPSILON_1000 ) )
267 // no point trying to squeeze actors into this small size
268 return Vector3::ZERO;
271 return Vector3( ShrinkInside( Vector2( parentSizeWidth, parentSizeHeight ), Vector2( mOriginalSize ) ) );
274 const Toolkit::Alignment::Padding mPadding;
276 Vector3 mOriginalSize;
280 * Constraint that modifies the contained actor taking into account the padding value.
282 struct PositionConstraint
285 * @param padding The padding value
286 * @param horizontalAlignment The horizontal alignment.
287 * @param verticalAlignment The vertical alignment.
289 PositionConstraint( const Toolkit::Alignment::Padding& padding, Toolkit::Alignment::Type horizontalAlignment, Toolkit::Alignment::Type verticalAlignment )
290 : mPadding( padding ),
291 mHorizontalAlignment( horizontalAlignment ),
292 mVerticalAlignment( verticalAlignment )
296 * Called by render thread.
298 Vector3 operator()( const Vector3& currentPosition,
299 const PropertyInput& currentSizeProperty,
300 const PropertyInput& parentSizeProperty )
302 const Vector3& currentSize( currentSizeProperty.GetVector3() );
303 const Vector3& parentSize( parentSizeProperty.GetVector3() );
305 return GetPosition( currentSize, parentSize );
308 inline Vector3 GetPosition( const Vector3& currentSize, const Vector3& parentSize )
310 Vector3 position( 0.f, 0.f, 0.f );
312 switch( mHorizontalAlignment )
314 case Dali::Toolkit::Alignment::HorizontalLeft:
316 position.x += mPadding.left;
319 case Dali::Toolkit::Alignment::HorizontalCenter:
321 if( currentSize.width + mPadding.left + mPadding.right >= parentSize.width )
323 position.x += 0.5f * ( mPadding.left - mPadding.right );
327 case Dali::Toolkit::Alignment::HorizontalRight:
329 position.x -= mPadding.right;
334 DALI_ASSERT_ALWAYS( !"Wrong horizontal alignment value" );
339 switch( mVerticalAlignment )
341 case Dali::Toolkit::Alignment::VerticalTop:
343 position.y += mPadding.top;
346 case Dali::Toolkit::Alignment::VerticalCenter:
348 if( currentSize.height + mPadding.top + mPadding.bottom >= parentSize.height )
350 position.y += 0.5f * ( mPadding.top - mPadding.bottom );
354 case Dali::Toolkit::Alignment::VerticalBottom:
356 position.y -= mPadding.bottom;
361 DALI_ASSERT_ALWAYS( !"Wrong vertical alignment value" );
369 const Toolkit::Alignment::Padding mPadding;
370 const Toolkit::Alignment::Type mHorizontalAlignment;
371 const Toolkit::Alignment::Type mVerticalAlignment;
375 Toolkit::Alignment Alignment::New( Toolkit::Alignment::Type horizontal, Toolkit::Alignment::Type vertical )
377 // Create the implementation, temporarily owned on stack
378 IntrusivePtr< Alignment > internalAlignment = new Alignment( horizontal, vertical );
380 // Pass ownership to Toolkit::Alignment
381 Toolkit::Alignment alignment( *internalAlignment );
383 // Second-phase init of the implementation
384 // This can only be done after the CustomActor connection has been made...
385 internalAlignment->Initialize();
390 void Alignment::SetAlignmentType( Toolkit::Alignment::Type type )
392 // Horizontal Alignment
393 if( type & Toolkit::Alignment::HorizontalRight )
395 mHorizontal = Toolkit::Alignment::HorizontalRight;
397 if( type & Toolkit::Alignment::HorizontalLeft )
399 mHorizontal = Toolkit::Alignment::HorizontalLeft;
401 if( type & Toolkit::Alignment::HorizontalCenter )
403 mHorizontal = Toolkit::Alignment::HorizontalCenter;
406 // Vertical Alignment
407 if( type & Toolkit::Alignment::VerticalBottom )
409 mVertical = Toolkit::Alignment::VerticalBottom;
411 if( type & Toolkit::Alignment::VerticalTop )
413 mVertical = Toolkit::Alignment::VerticalTop;
415 if( type & Toolkit::Alignment::VerticalCenter )
417 mVertical = Toolkit::Alignment::VerticalCenter;
423 Toolkit::Alignment::Type Alignment::GetAlignmentType() const
425 return Toolkit::Alignment::Type( mHorizontal | mVertical );
428 void Alignment::SetScaling( Toolkit::Alignment::Scaling scaling )
435 Toolkit::Alignment::Scaling Alignment::GetScaling() const
440 void Alignment::SetPadding( const Toolkit::Alignment::Padding& padding )
442 DALI_ASSERT_ALWAYS( ( padding.left >= 0.f ) && ( padding.top >= 0.f ) && ( padding.right >= 0.f ) && ( padding.bottom >= 0.f ) );
449 const Toolkit::Alignment::Padding& Alignment::GetPadding() const
454 void Alignment::OnRelayout( const Vector2& size, RelayoutContainer& container )
456 // lay out the actors
457 Vector3 anchorPointAndParentOrigin = Vector3::ZERO;
458 anchorPointAndParentOrigin.z = 0.5f;
459 // anchorPoint.x is initialized to 0.0, which is HorizontalLeft
460 if( Toolkit::Alignment::HorizontalCenter == mHorizontal )
462 anchorPointAndParentOrigin.x = 0.5f;
464 else if( Toolkit::Alignment::HorizontalRight == mHorizontal )
466 anchorPointAndParentOrigin.x = 1.0f;
468 // anchorPoint.y is initialized to 0.0, which is VerticalTop
469 if( Toolkit::Alignment::VerticalCenter == mVertical )
471 anchorPointAndParentOrigin.y = 0.5f;
473 else if( Toolkit::Alignment::VerticalBottom == mVertical )
475 anchorPointAndParentOrigin.y = 1.0f;
478 for( unsigned int i = 0, childCount = Self().GetChildCount(); i < childCount; ++i )
480 Actor child = Self().GetChildAt(i);
482 child.SetAnchorPoint( anchorPointAndParentOrigin );
483 child.SetParentOrigin( anchorPointAndParentOrigin );
485 Vector3 currentChildSize( child.GetTargetSize() );
486 if( currentChildSize == Vector3::ZERO )
488 currentChildSize = child.GetNaturalSize();
491 bool renegotiate = true;
492 Vector3 newChildSize;
496 case Toolkit::Alignment::ScaleNone:
498 // Nothing to do but needed just to not to jump to the default.
499 newChildSize = currentChildSize;
503 case Toolkit::Alignment::ScaleToFill:
505 ScaleToFillConstraint constraint( mPadding );
506 newChildSize = constraint.GetSize( currentChildSize, Vector3(size) ) ;
509 case Toolkit::Alignment::ScaleToFitKeepAspect:
511 ScaleToFitKeepAspectConstraint constraint( mPadding );
512 newChildSize = constraint.GetSize( currentChildSize, Vector3(size) ) ;
515 case Toolkit::Alignment::ScaleToFillKeepAspect:
517 ScaleToFillKeepAspectConstraint constraint( mPadding );
518 newChildSize = constraint.GetSize( currentChildSize, Vector3(size) );
521 case Toolkit::Alignment::ShrinkToFit:
523 ShrinkToFitConstraint constraint( mPadding );
524 newChildSize = constraint.GetSize( currentChildSize, Vector3(size) );
527 case Toolkit::Alignment::ShrinkToFitKeepAspect:
529 ShrinkToFitKeepAspectConstraint constraint( mPadding );
530 newChildSize = constraint.GetSize( currentChildSize, Vector3(size) );
535 DALI_ASSERT_ALWAYS( !"Invalid Alignment::mGeometryScaling value" );
540 PositionConstraint positionConstraint(mPadding, mHorizontal, mVertical);
541 child.SetPosition( positionConstraint.GetPosition(newChildSize, currentChildSize) );
545 container.Add( child, Vector2(newChildSize) );
550 Alignment::Alignment( Toolkit::Alignment::Type horizontal, Toolkit::Alignment::Type vertical )
551 : Control( ControlBehaviour( ACTOR_BEHAVIOUR_NONE ) ),
552 mHorizontal( horizontal ),
553 mVertical( vertical ),
554 mScaling( Toolkit::Alignment::ScaleNone ),
555 mPadding( 0.f, 0.f, 0.f, 0.f )
559 Alignment::~Alignment()
563 } // namespace Internal
565 } // namespace Toolkit