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.
20 #include "alignment-impl.h"
23 #include <dali/public-api/object/type-registry.h>
42 return Toolkit::Alignment::New();
45 TypeRegistration mType( typeid(Toolkit::Alignment), typeid(Toolkit::Control), Create );
47 struct ScaleToFillConstraint
50 * @param padding to be added.
52 ScaleToFillConstraint( const Toolkit::Alignment::Padding& padding )
57 * Called by render thread
59 Vector3 operator()( const Vector3& currentSize,
60 const PropertyInput& parentSizeProperty )
62 const Vector3& parentSize( parentSizeProperty.GetVector3() );
63 return GetSize( currentSize, parentSize );
66 inline Vector3 GetSize( const Vector3& currentSize, const Vector3& parentSize )
68 const float parentSizeWidth = parentSize.width - ( mPadding.left + mPadding.right );
69 const float parentSizeHeight = parentSize.height - ( mPadding.top + mPadding.bottom );
71 // prevent ridiculous sizes if parent is really small or if we don't have a proper size for the actor
72 if( ( parentSizeWidth < Math::MACHINE_EPSILON_1000 ) || ( parentSizeHeight < Math::MACHINE_EPSILON_1000 ) )
74 // no point trying to squeeze actors into this small size
77 return Vector3( parentSizeWidth, parentSizeHeight, parentSize.depth );
80 const Toolkit::Alignment::Padding mPadding;
83 struct ScaleToFitKeepAspectConstraint
86 * @param padding to be added.
88 ScaleToFitKeepAspectConstraint( const Toolkit::Alignment::Padding& padding )
89 : mPadding( padding ),
95 * Called by render thread
97 Vector3 operator()( const Vector3& currentSize,
98 const PropertyInput& parentSizeProperty )
100 const Vector3& parentSize( parentSizeProperty.GetVector3() );
101 return GetSize( currentSize, parentSize );
104 inline Vector3 GetSize( const Vector3& currentSize, const Vector3& parentSize )
106 if( ( !mSizeStored ) && ( Vector3::ZERO != currentSize ) )
108 mOriginalSize = currentSize;
112 const float parentSizeWidth = parentSize.width - ( mPadding.left + mPadding.right );
113 const float parentSizeHeight = parentSize.height - ( mPadding.top + mPadding.bottom );
115 // prevent ridiculous sizes if parent is really small or if we don't have a proper size for the actor
116 if( ( parentSizeWidth < Math::MACHINE_EPSILON_1000 ) || ( parentSizeHeight < Math::MACHINE_EPSILON_1000 )||
117 ( mOriginalSize.width < Math::MACHINE_EPSILON_1000 ) || ( mOriginalSize.height < Math::MACHINE_EPSILON_1000 ) )
119 // no point trying to squeeze actors into this small size
120 return Vector3::ZERO;
123 return mOriginalSize * std::min( ( parentSizeWidth / mOriginalSize.width ), ( parentSizeHeight / mOriginalSize.height ) );
126 const Toolkit::Alignment::Padding mPadding;
128 Vector3 mOriginalSize;
131 struct ScaleToFillKeepAspectConstraint
134 * @param padding to be added.
136 ScaleToFillKeepAspectConstraint( const Toolkit::Alignment::Padding& padding )
137 : mPadding( padding ),
138 mSizeStored( false ),
143 * Called by render thread
145 Vector3 operator()( const Vector3& currentSize,
146 const PropertyInput& parentSizeProperty )
148 const Vector3& parentSize( parentSizeProperty.GetVector3() );
149 return GetSize( currentSize, parentSize );
152 Vector3 GetSize( const Vector3& currentSize, const Vector3& parentSize )
154 if( ( !mSizeStored ) && ( Vector3::ZERO != currentSize ) )
156 mOriginalSize = currentSize;
160 const float parentSizeWidth = parentSize.width - ( mPadding.left + mPadding.right );
161 const float parentSizeHeight = parentSize.height - ( mPadding.top + mPadding.bottom );
163 // prevent ridiculous sizes if parent is really small or if we don't have a proper size for the actor
164 if( ( parentSizeWidth < Math::MACHINE_EPSILON_1000 ) || ( parentSizeHeight < Math::MACHINE_EPSILON_1000 )||
165 ( mOriginalSize.width < Math::MACHINE_EPSILON_1000 ) || ( mOriginalSize.height < Math::MACHINE_EPSILON_1000 ) )
167 // no point trying to squeeze actors into this small size
168 return Vector3::ZERO;
171 return mOriginalSize * std::max( ( parentSizeWidth / mOriginalSize.width ), ( parentSizeHeight / mOriginalSize.height ) );
174 const Toolkit::Alignment::Padding mPadding;
176 Vector3 mOriginalSize;
179 struct ShrinkToFitConstraint
182 * @param padding to be added.
184 ShrinkToFitConstraint( const Toolkit::Alignment::Padding& padding )
185 : mPadding( padding ),
186 mSizeStored( false ),
191 * Called by render thread
193 Vector3 operator()( const Vector3& currentSize,
194 const PropertyInput& parentSizeProperty )
196 const Vector3& parentSize( parentSizeProperty.GetVector3() );
197 return GetSize( currentSize, parentSize );
200 Vector3 GetSize( const Vector3& currentSize, const Vector3& parentSize )
202 if( ( !mSizeStored ) && ( Vector3::ZERO != currentSize ) )
204 mOriginalSize = currentSize;
208 const float parentSizeWidth = parentSize.width - ( mPadding.left + mPadding.right );
209 const float parentSizeHeight = parentSize.height - ( mPadding.top + mPadding.bottom );
211 // prevent ridiculous sizes if parent is really small or if we don't have a proper size for the actor
212 if( ( parentSizeWidth < Math::MACHINE_EPSILON_1000 ) || ( parentSizeHeight < Math::MACHINE_EPSILON_1000 )||
213 ( mOriginalSize.width < Math::MACHINE_EPSILON_1000 ) || ( mOriginalSize.height < Math::MACHINE_EPSILON_1000 ) )
215 // no point trying to squeeze actors into this small size
216 return Vector3::ZERO;
219 return Vector3( std::min( parentSizeWidth, mOriginalSize.width ), std::min( parentSizeHeight, mOriginalSize.height ), std::min( parentSize.depth, mOriginalSize.depth ) );
222 const Toolkit::Alignment::Padding mPadding;
224 Vector3 mOriginalSize;
228 * Constraint that uses naturalSize if it fits inside parent and parent size if not. It also adds some padding pixels
230 struct ShrinkToFitKeepAspectConstraint
233 * @param padding to be added.
235 ShrinkToFitKeepAspectConstraint( const Toolkit::Alignment::Padding& padding )
236 : mPadding( padding ),
237 mSizeStored( false ),
242 * Called by render thread
244 Vector3 operator()( const Vector3& currentSize,
245 const PropertyInput& parentSizeProperty )
247 const Vector3& parentSize( parentSizeProperty.GetVector3() );
248 return GetSize( currentSize, parentSize );
251 inline Vector3 GetSize( const Vector3& currentSize, const Vector3& parentSize )
253 if( ( !mSizeStored ) && ( Vector3::ZERO != currentSize ) )
255 mOriginalSize = currentSize;
259 const float parentSizeWidth = parentSize.width - ( mPadding.left + mPadding.right );
260 const float parentSizeHeight = parentSize.height - ( mPadding.top + mPadding.bottom );
262 // prevent ridiculous sizes if parent is really small or if we don't have a proper size for the actor
263 if( ( parentSizeWidth < Math::MACHINE_EPSILON_1000 ) || ( parentSizeHeight < Math::MACHINE_EPSILON_1000 )||
264 ( mOriginalSize.width < Math::MACHINE_EPSILON_1000 ) || ( mOriginalSize.height < Math::MACHINE_EPSILON_1000 ) )
266 // no point trying to squeeze actors into this small size
267 return Vector3::ZERO;
270 return Vector3( ShrinkInside( Vector2( parentSizeWidth, parentSizeHeight ), Vector2( mOriginalSize ) ) );
273 const Toolkit::Alignment::Padding mPadding;
275 Vector3 mOriginalSize;
279 * Constraint that modifies the contained actor taking into account the padding value.
281 struct PositionConstraint
284 * @param padding The padding value
285 * @param horizontalAlignment The horizontal alignment.
286 * @param verticalAlignment The vertical alignment.
288 PositionConstraint( const Toolkit::Alignment::Padding& padding, Toolkit::Alignment::Type horizontalAlignment, Toolkit::Alignment::Type verticalAlignment )
289 : mPadding( padding ),
290 mHorizontalAlignment( horizontalAlignment ),
291 mVerticalAlignment( verticalAlignment )
295 * Called by render thread.
297 Vector3 operator()( const Vector3& currentPosition,
298 const PropertyInput& currentSizeProperty,
299 const PropertyInput& parentSizeProperty )
301 const Vector3& currentSize( currentSizeProperty.GetVector3() );
302 const Vector3& parentSize( parentSizeProperty.GetVector3() );
304 Vector3 position( 0.f, 0.f, 0.f );
306 switch( mHorizontalAlignment )
308 case Dali::Toolkit::Alignment::HorizontalLeft:
310 position.x += mPadding.left;
313 case Dali::Toolkit::Alignment::HorizontalCenter:
315 if( currentSize.width + mPadding.left + mPadding.right >= parentSize.width )
317 position.x += 0.5f * ( mPadding.left - mPadding.right );
321 case Dali::Toolkit::Alignment::HorizontalRight:
323 position.x -= mPadding.right;
328 DALI_ASSERT_ALWAYS( !"Wrong horizontal alignment value" );
333 switch( mVerticalAlignment )
335 case Dali::Toolkit::Alignment::VerticalTop:
337 position.y += mPadding.top;
340 case Dali::Toolkit::Alignment::VerticalCenter:
342 if( currentSize.height + mPadding.top + mPadding.bottom >= parentSize.height )
344 position.y += 0.5f * ( mPadding.top - mPadding.bottom );
348 case Dali::Toolkit::Alignment::VerticalBottom:
350 position.y -= mPadding.bottom;
355 DALI_ASSERT_ALWAYS( !"Wrong vertical alignment value" );
363 const Toolkit::Alignment::Padding mPadding;
364 const Toolkit::Alignment::Type mHorizontalAlignment;
365 const Toolkit::Alignment::Type mVerticalAlignment;
368 void SetPositionConstraint( Actor actor, const Toolkit::Alignment::Padding& padding, Toolkit::Alignment::Type horizontal, Toolkit::Alignment::Type vertical )
370 Constraint constraint = Constraint::New<Vector3>( Actor::POSITION,
371 LocalSource( Actor::SIZE ),
372 ParentSource( Actor::SIZE ),
373 PositionConstraint( padding, horizontal, vertical ) );
374 actor.ApplyConstraint( constraint );
378 Toolkit::Alignment Alignment::New( Toolkit::Alignment::Type horizontal, Toolkit::Alignment::Type vertical )
380 // Create the implementation, temporarily owned on stack
381 IntrusivePtr< Alignment > internalAlignment = new Alignment( horizontal, vertical );
383 // Pass ownership to Toolkit::View
384 Toolkit::Alignment alignment( *internalAlignment );
386 // Second-phase init of the implementation
387 // This can only be done after the CustomActor connection has been made...
388 internalAlignment->Initialize();
393 void Alignment::SetAlignmentType( Toolkit::Alignment::Type type )
395 // Horizontal Alignment
396 if( type & Toolkit::Alignment::HorizontalRight )
398 mHorizontal = Toolkit::Alignment::HorizontalRight;
400 if( type & Toolkit::Alignment::HorizontalLeft )
402 mHorizontal = Toolkit::Alignment::HorizontalLeft;
404 if( type & Toolkit::Alignment::HorizontalCenter )
406 mHorizontal = Toolkit::Alignment::HorizontalCenter;
409 // Vertical Alignment
410 if( type & Toolkit::Alignment::VerticalBottom )
412 mVertical = Toolkit::Alignment::VerticalBottom;
414 if( type & Toolkit::Alignment::VerticalTop )
416 mVertical = Toolkit::Alignment::VerticalTop;
418 if( type & Toolkit::Alignment::VerticalCenter )
420 mVertical = Toolkit::Alignment::VerticalCenter;
426 Toolkit::Alignment::Type Alignment::GetAlignmentType() const
428 return Toolkit::Alignment::Type( mHorizontal | mVertical );
431 void Alignment::SetScaling( Toolkit::Alignment::Scaling scaling )
438 Toolkit::Alignment::Scaling Alignment::GetScaling() const
443 void Alignment::SetPadding( const Toolkit::Alignment::Padding& padding )
445 DALI_ASSERT_ALWAYS( ( padding.left >= 0.f ) && ( padding.top >= 0.f ) && ( padding.right >= 0.f ) && ( padding.bottom >= 0.f ) );
452 const Toolkit::Alignment::Padding& Alignment::GetPadding() const
457 void Alignment::OnRelayout( const Vector2& size, ActorSizeContainer& container )
459 // lay out the actors
460 Vector3 anchorPointAndParentOrigin = Vector3::ZERO;
461 anchorPointAndParentOrigin.z = 0.5f;
462 // anchorPoint.x is initialized to 0.0, which is HorizontalLeft
463 if( Toolkit::Alignment::HorizontalCenter == mHorizontal )
465 anchorPointAndParentOrigin.x = 0.5f;
467 else if( Toolkit::Alignment::HorizontalRight == mHorizontal )
469 anchorPointAndParentOrigin.x = 1.0f;
471 // anchorPoint.y is initialized to 0.0, which is VerticalTop
472 if( Toolkit::Alignment::VerticalCenter == mVertical )
474 anchorPointAndParentOrigin.y = 0.5f;
476 else if( Toolkit::Alignment::VerticalBottom == mVertical )
478 anchorPointAndParentOrigin.y = 1.0f;
481 unsigned int childCount = Self().GetChildCount();
482 for( unsigned int i=0; i<childCount; ++i )
484 Actor actor = Self().GetChildAt(i);
486 actor.SetAnchorPoint( anchorPointAndParentOrigin );
487 actor.SetParentOrigin( anchorPointAndParentOrigin );
489 if( Toolkit::Alignment::ScaleNone != mScaling )
491 actor.RemoveConstraints();
494 Vector3 actorSize ( actor.GetCurrentSize() );
495 Toolkit::Control control( Toolkit::Control::DownCast( actor ) );
496 if ( actorSize == Vector3::ZERO && control )
498 actorSize = control.GetNaturalSize();
505 case Toolkit::Alignment::ScaleNone:
507 // Nothing to do but needed just to not to jump to the default.
511 case Toolkit::Alignment::ScaleToFill:
513 ScaleToFillConstraint constraint( mPadding );
514 childSize = Vector2( constraint.GetSize( actorSize, Vector3(size) ) );
515 SetPositionConstraint( actor, mPadding, mHorizontal, mVertical );
518 case Toolkit::Alignment::ScaleToFitKeepAspect:
520 ScaleToFitKeepAspectConstraint constraint( mPadding );
521 childSize = Vector2( constraint.GetSize( actorSize, Vector3(size) ) );
522 SetPositionConstraint( actor, mPadding, mHorizontal, mVertical );
525 case Toolkit::Alignment::ScaleToFillKeepAspect:
527 ScaleToFillKeepAspectConstraint constraint( mPadding );
528 childSize = Vector2( constraint.GetSize( actorSize, Vector3(size) ) );
529 SetPositionConstraint( actor, mPadding, mHorizontal, mVertical );
532 case Toolkit::Alignment::ShrinkToFit:
534 ShrinkToFitConstraint constraint( mPadding );
535 childSize = Vector2( constraint.GetSize( actorSize, Vector3(size) ) );
536 SetPositionConstraint( actor, mPadding, mHorizontal, mVertical );
539 case Toolkit::Alignment::ShrinkToFitKeepAspect:
541 ShrinkToFitKeepAspectConstraint constraint( mPadding );
542 childSize = Vector2( constraint.GetSize( actorSize, Vector3(size) ) );
543 SetPositionConstraint( actor, mPadding, mHorizontal, mVertical );
548 DALI_ASSERT_ALWAYS( !"Invalid Alignment::mGeometryScaling value" );
553 Relayout( actor, childSize, container );
557 Alignment::Alignment( Toolkit::Alignment::Type horizontal, Toolkit::Alignment::Type vertical )
558 : Control( CONTROL_BEHAVIOUR_NONE ),
559 mHorizontal( horizontal ),
560 mVertical( vertical ),
561 mScaling( Toolkit::Alignment::ScaleNone ),
562 mPadding( 0.f, 0.f, 0.f, 0.f )
566 Alignment::~Alignment()
570 } // namespace Internal
572 } // namespace Toolkit