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/type-registry.h>
41 return Toolkit::Alignment::New();
44 TypeRegistration mType( typeid(Toolkit::Alignment), typeid(Toolkit::Control), Create );
46 struct ScaleToFillConstraint
49 * @param padding to be added.
51 ScaleToFillConstraint( const Toolkit::Alignment::Padding& padding )
56 * Called by render thread
58 Vector3 operator()( const Vector3& currentSize,
59 const PropertyInput& parentSizeProperty )
61 const Vector3& parentSize( parentSizeProperty.GetVector3() );
62 return GetSize( currentSize, parentSize );
65 inline Vector3 GetSize( const Vector3& currentSize, const Vector3& parentSize )
67 const float parentSizeWidth = parentSize.width - ( mPadding.left + mPadding.right );
68 const float parentSizeHeight = parentSize.height - ( mPadding.top + mPadding.bottom );
70 // prevent ridiculous sizes if parent is really small or if we don't have a proper size for the actor
71 if( ( parentSizeWidth < Math::MACHINE_EPSILON_1000 ) || ( parentSizeHeight < Math::MACHINE_EPSILON_1000 ) )
73 // no point trying to squeeze actors into this small size
76 return Vector3( parentSizeWidth, parentSizeHeight, parentSize.depth );
79 const Toolkit::Alignment::Padding mPadding;
82 struct ScaleToFitKeepAspectConstraint
85 * @param padding to be added.
87 ScaleToFitKeepAspectConstraint( const Toolkit::Alignment::Padding& padding )
88 : mPadding( padding ),
94 * Called by render thread
96 Vector3 operator()( const Vector3& currentSize,
97 const PropertyInput& parentSizeProperty )
99 const Vector3& parentSize( parentSizeProperty.GetVector3() );
100 return GetSize( currentSize, parentSize );
103 inline Vector3 GetSize( const Vector3& currentSize, const Vector3& parentSize )
105 if( ( !mSizeStored ) && ( Vector3::ZERO != currentSize ) )
107 mOriginalSize = currentSize;
111 const float parentSizeWidth = parentSize.width - ( mPadding.left + mPadding.right );
112 const float parentSizeHeight = parentSize.height - ( mPadding.top + mPadding.bottom );
114 // prevent ridiculous sizes if parent is really small or if we don't have a proper size for the actor
115 if( ( parentSizeWidth < Math::MACHINE_EPSILON_1000 ) || ( parentSizeHeight < Math::MACHINE_EPSILON_1000 )||
116 ( mOriginalSize.width < Math::MACHINE_EPSILON_1000 ) || ( mOriginalSize.height < Math::MACHINE_EPSILON_1000 ) )
118 // no point trying to squeeze actors into this small size
119 return Vector3::ZERO;
122 return mOriginalSize * std::min( ( parentSizeWidth / mOriginalSize.width ), ( parentSizeHeight / mOriginalSize.height ) );
125 const Toolkit::Alignment::Padding mPadding;
127 Vector3 mOriginalSize;
130 struct ScaleToFillKeepAspectConstraint
133 * @param padding to be added.
135 ScaleToFillKeepAspectConstraint( const Toolkit::Alignment::Padding& padding )
136 : mPadding( padding ),
137 mSizeStored( false ),
142 * Called by render thread
144 Vector3 operator()( const Vector3& currentSize,
145 const PropertyInput& parentSizeProperty )
147 const Vector3& parentSize( parentSizeProperty.GetVector3() );
148 return GetSize( currentSize, parentSize );
151 Vector3 GetSize( const Vector3& currentSize, const Vector3& parentSize )
153 if( ( !mSizeStored ) && ( Vector3::ZERO != currentSize ) )
155 mOriginalSize = currentSize;
159 const float parentSizeWidth = parentSize.width - ( mPadding.left + mPadding.right );
160 const float parentSizeHeight = parentSize.height - ( mPadding.top + mPadding.bottom );
162 // prevent ridiculous sizes if parent is really small or if we don't have a proper size for the actor
163 if( ( parentSizeWidth < Math::MACHINE_EPSILON_1000 ) || ( parentSizeHeight < Math::MACHINE_EPSILON_1000 )||
164 ( mOriginalSize.width < Math::MACHINE_EPSILON_1000 ) || ( mOriginalSize.height < Math::MACHINE_EPSILON_1000 ) )
166 // no point trying to squeeze actors into this small size
167 return Vector3::ZERO;
170 return mOriginalSize * std::max( ( parentSizeWidth / mOriginalSize.width ), ( parentSizeHeight / mOriginalSize.height ) );
173 const Toolkit::Alignment::Padding mPadding;
175 Vector3 mOriginalSize;
178 struct ShrinkToFitConstraint
181 * @param padding to be added.
183 ShrinkToFitConstraint( const Toolkit::Alignment::Padding& padding )
184 : mPadding( padding ),
185 mSizeStored( false ),
190 * Called by render thread
192 Vector3 operator()( const Vector3& currentSize,
193 const PropertyInput& parentSizeProperty )
195 const Vector3& parentSize( parentSizeProperty.GetVector3() );
196 return GetSize( currentSize, parentSize );
199 Vector3 GetSize( const Vector3& currentSize, const Vector3& parentSize )
201 if( ( !mSizeStored ) && ( Vector3::ZERO != currentSize ) )
203 mOriginalSize = currentSize;
207 const float parentSizeWidth = parentSize.width - ( mPadding.left + mPadding.right );
208 const float parentSizeHeight = parentSize.height - ( mPadding.top + mPadding.bottom );
210 // prevent ridiculous sizes if parent is really small or if we don't have a proper size for the actor
211 if( ( parentSizeWidth < Math::MACHINE_EPSILON_1000 ) || ( parentSizeHeight < Math::MACHINE_EPSILON_1000 )||
212 ( mOriginalSize.width < Math::MACHINE_EPSILON_1000 ) || ( mOriginalSize.height < Math::MACHINE_EPSILON_1000 ) )
214 // no point trying to squeeze actors into this small size
215 return Vector3::ZERO;
218 return Vector3( std::min( parentSizeWidth, mOriginalSize.width ), std::min( parentSizeHeight, mOriginalSize.height ), std::min( parentSize.depth, mOriginalSize.depth ) );
221 const Toolkit::Alignment::Padding mPadding;
223 Vector3 mOriginalSize;
227 * Constraint that uses naturalSize if it fits inside parent and parent size if not. It also adds some padding pixels
229 struct ShrinkToFitKeepAspectConstraint
232 * @param padding to be added.
234 ShrinkToFitKeepAspectConstraint( const Toolkit::Alignment::Padding& padding )
235 : mPadding( padding ),
236 mSizeStored( false ),
241 * Called by render thread
243 Vector3 operator()( const Vector3& currentSize,
244 const PropertyInput& parentSizeProperty )
246 const Vector3& parentSize( parentSizeProperty.GetVector3() );
247 return GetSize( currentSize, parentSize );
250 inline Vector3 GetSize( const Vector3& currentSize, const Vector3& parentSize )
252 if( ( !mSizeStored ) && ( Vector3::ZERO != currentSize ) )
254 mOriginalSize = currentSize;
258 const float parentSizeWidth = parentSize.width - ( mPadding.left + mPadding.right );
259 const float parentSizeHeight = parentSize.height - ( mPadding.top + mPadding.bottom );
261 // prevent ridiculous sizes if parent is really small or if we don't have a proper size for the actor
262 if( ( parentSizeWidth < Math::MACHINE_EPSILON_1000 ) || ( parentSizeHeight < Math::MACHINE_EPSILON_1000 )||
263 ( mOriginalSize.width < Math::MACHINE_EPSILON_1000 ) || ( mOriginalSize.height < Math::MACHINE_EPSILON_1000 ) )
265 // no point trying to squeeze actors into this small size
266 return Vector3::ZERO;
269 return Vector3( ShrinkInside( Vector2( parentSizeWidth, parentSizeHeight ), Vector2( mOriginalSize ) ) );
272 const Toolkit::Alignment::Padding mPadding;
274 Vector3 mOriginalSize;
278 * Constraint that modifies the contained actor taking into account the padding value.
280 struct PositionConstraint
283 * @param padding The padding value
284 * @param horizontalAlignment The horizontal alignment.
285 * @param verticalAlignment The vertical alignment.
287 PositionConstraint( const Toolkit::Alignment::Padding& padding, Toolkit::Alignment::Type horizontalAlignment, Toolkit::Alignment::Type verticalAlignment )
288 : mPadding( padding ),
289 mHorizontalAlignment( horizontalAlignment ),
290 mVerticalAlignment( verticalAlignment )
294 * Called by render thread.
296 Vector3 operator()( const Vector3& currentPosition,
297 const PropertyInput& currentSizeProperty,
298 const PropertyInput& parentSizeProperty )
300 const Vector3& currentSize( currentSizeProperty.GetVector3() );
301 const Vector3& parentSize( parentSizeProperty.GetVector3() );
303 return GetPosition( currentSize, parentSize );
306 inline Vector3 GetPosition( const Vector3& currentSize, const Vector3& parentSize )
308 Vector3 position( 0.f, 0.f, 0.f );
310 switch( mHorizontalAlignment )
312 case Dali::Toolkit::Alignment::HorizontalLeft:
314 position.x += mPadding.left;
317 case Dali::Toolkit::Alignment::HorizontalCenter:
319 if( currentSize.width + mPadding.left + mPadding.right >= parentSize.width )
321 position.x += 0.5f * ( mPadding.left - mPadding.right );
325 case Dali::Toolkit::Alignment::HorizontalRight:
327 position.x -= mPadding.right;
332 DALI_ASSERT_ALWAYS( !"Wrong horizontal alignment value" );
337 switch( mVerticalAlignment )
339 case Dali::Toolkit::Alignment::VerticalTop:
341 position.y += mPadding.top;
344 case Dali::Toolkit::Alignment::VerticalCenter:
346 if( currentSize.height + mPadding.top + mPadding.bottom >= parentSize.height )
348 position.y += 0.5f * ( mPadding.top - mPadding.bottom );
352 case Dali::Toolkit::Alignment::VerticalBottom:
354 position.y -= mPadding.bottom;
359 DALI_ASSERT_ALWAYS( !"Wrong vertical alignment value" );
367 const Toolkit::Alignment::Padding mPadding;
368 const Toolkit::Alignment::Type mHorizontalAlignment;
369 const Toolkit::Alignment::Type mVerticalAlignment;
373 Toolkit::Alignment Alignment::New( Toolkit::Alignment::Type horizontal, Toolkit::Alignment::Type vertical )
375 // Create the implementation, temporarily owned on stack
376 IntrusivePtr< Alignment > internalAlignment = new Alignment( horizontal, vertical );
378 // Pass ownership to Toolkit::View
379 Toolkit::Alignment alignment( *internalAlignment );
381 // Second-phase init of the implementation
382 // This can only be done after the CustomActor connection has been made...
383 internalAlignment->Initialize();
388 void Alignment::SetAlignmentType( Toolkit::Alignment::Type type )
390 // Horizontal Alignment
391 if( type & Toolkit::Alignment::HorizontalRight )
393 mHorizontal = Toolkit::Alignment::HorizontalRight;
395 if( type & Toolkit::Alignment::HorizontalLeft )
397 mHorizontal = Toolkit::Alignment::HorizontalLeft;
399 if( type & Toolkit::Alignment::HorizontalCenter )
401 mHorizontal = Toolkit::Alignment::HorizontalCenter;
404 // Vertical Alignment
405 if( type & Toolkit::Alignment::VerticalBottom )
407 mVertical = Toolkit::Alignment::VerticalBottom;
409 if( type & Toolkit::Alignment::VerticalTop )
411 mVertical = Toolkit::Alignment::VerticalTop;
413 if( type & Toolkit::Alignment::VerticalCenter )
415 mVertical = Toolkit::Alignment::VerticalCenter;
421 Toolkit::Alignment::Type Alignment::GetAlignmentType() const
423 return Toolkit::Alignment::Type( mHorizontal | mVertical );
426 void Alignment::SetScaling( Toolkit::Alignment::Scaling scaling )
433 Toolkit::Alignment::Scaling Alignment::GetScaling() const
438 void Alignment::SetPadding( const Toolkit::Alignment::Padding& padding )
440 DALI_ASSERT_ALWAYS( ( padding.left >= 0.f ) && ( padding.top >= 0.f ) && ( padding.right >= 0.f ) && ( padding.bottom >= 0.f ) );
447 const Toolkit::Alignment::Padding& Alignment::GetPadding() const
452 void Alignment::OnRelayout( const Vector2& size, ActorSizeContainer& container )
454 // lay out the actors
455 Vector3 anchorPointAndParentOrigin = Vector3::ZERO;
456 anchorPointAndParentOrigin.z = 0.5f;
457 // anchorPoint.x is initialized to 0.0, which is HorizontalLeft
458 if( Toolkit::Alignment::HorizontalCenter == mHorizontal )
460 anchorPointAndParentOrigin.x = 0.5f;
462 else if( Toolkit::Alignment::HorizontalRight == mHorizontal )
464 anchorPointAndParentOrigin.x = 1.0f;
466 // anchorPoint.y is initialized to 0.0, which is VerticalTop
467 if( Toolkit::Alignment::VerticalCenter == mVertical )
469 anchorPointAndParentOrigin.y = 0.5f;
471 else if( Toolkit::Alignment::VerticalBottom == mVertical )
473 anchorPointAndParentOrigin.y = 1.0f;
476 unsigned int childCount = Self().GetChildCount();
477 for( unsigned int i=0; i<childCount; ++i )
479 Actor actor = Self().GetChildAt(i);
481 actor.SetAnchorPoint( anchorPointAndParentOrigin );
482 actor.SetParentOrigin( anchorPointAndParentOrigin );
484 Vector3 actorSize ( actor.GetSize() );
485 Toolkit::Control control( Toolkit::Control::DownCast( actor ) );
486 if ( actorSize == Vector3::ZERO && control )
488 actorSize = control.GetNaturalSize();
495 case Toolkit::Alignment::ScaleNone:
497 // Nothing to do but needed just to not to jump to the default.
498 childSize = actorSize;
501 case Toolkit::Alignment::ScaleToFill:
503 ScaleToFillConstraint constraint( mPadding );
504 childSize = constraint.GetSize( actorSize, Vector3(size) ) ;
507 case Toolkit::Alignment::ScaleToFitKeepAspect:
509 ScaleToFitKeepAspectConstraint constraint( mPadding );
510 childSize = constraint.GetSize( actorSize, Vector3(size) ) ;
513 case Toolkit::Alignment::ScaleToFillKeepAspect:
515 ScaleToFillKeepAspectConstraint constraint( mPadding );
516 childSize = constraint.GetSize( actorSize, Vector3(size) );
519 case Toolkit::Alignment::ShrinkToFit:
521 ShrinkToFitConstraint constraint( mPadding );
522 childSize = constraint.GetSize( actorSize, Vector3(size) );
525 case Toolkit::Alignment::ShrinkToFitKeepAspect:
527 ShrinkToFitKeepAspectConstraint constraint( mPadding );
528 childSize = constraint.GetSize( actorSize, Vector3(size) );
533 DALI_ASSERT_ALWAYS( !"Invalid Alignment::mGeometryScaling value" );
538 PositionConstraint positionConstraint(mPadding, mHorizontal, mVertical);
539 actor.SetPosition( positionConstraint.GetPosition(childSize, actorSize) );
543 actor.SetScale(childSize / actorSize);
546 Relayout( actor, Vector2(childSize), container );
550 Alignment::Alignment( Toolkit::Alignment::Type horizontal, Toolkit::Alignment::Type vertical )
551 : Control( CONTROL_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