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 bool horizontalSet(false);
398 if( type & Toolkit::Alignment::HorizontalLeft )
400 mHorizontal = Toolkit::Alignment::HorizontalLeft;
401 horizontalSet = true;
403 if( type & Toolkit::Alignment::HorizontalCenter )
405 DALI_ASSERT_ALWAYS(!horizontalSet);
406 mHorizontal = Toolkit::Alignment::HorizontalCenter;
407 horizontalSet = true;
409 if( type & Toolkit::Alignment::HorizontalRight )
411 DALI_ASSERT_ALWAYS(!horizontalSet);
412 mHorizontal = Toolkit::Alignment::HorizontalRight;
415 // Vertical Alignment
416 bool verticalSet(false);
418 if( type & Toolkit::Alignment::VerticalTop )
420 mVertical = Toolkit::Alignment::VerticalTop;
423 if( type & Toolkit::Alignment::VerticalCenter )
425 DALI_ASSERT_ALWAYS(!verticalSet);
426 mVertical = Toolkit::Alignment::VerticalCenter;
429 if( type & Toolkit::Alignment::VerticalBottom )
431 DALI_ASSERT_ALWAYS(!verticalSet);
432 mVertical = Toolkit::Alignment::VerticalBottom;
438 Toolkit::Alignment::Type Alignment::GetAlignmentType() const
440 return Toolkit::Alignment::Type( mHorizontal | mVertical );
443 void Alignment::SetScaling( Toolkit::Alignment::Scaling scaling )
450 Toolkit::Alignment::Scaling Alignment::GetScaling() const
455 void Alignment::SetPadding( const Toolkit::Alignment::Padding& padding )
457 DALI_ASSERT_ALWAYS( ( padding.left >= 0.f ) && ( padding.top >= 0.f ) && ( padding.right >= 0.f ) && ( padding.bottom >= 0.f ) );
464 const Toolkit::Alignment::Padding& Alignment::GetPadding() const
469 void Alignment::OnRelaidOut( Vector2 size, ActorSizeContainer& container )
471 // lay out the actors
472 Vector3 anchorPointAndParentOrigin = Vector3::ZERO;
473 anchorPointAndParentOrigin.z = 0.5f;
474 // anchorPoint.x is initialized to 0.0, which is HorizontalLeft
475 if( Toolkit::Alignment::HorizontalCenter == mHorizontal )
477 anchorPointAndParentOrigin.x = 0.5f;
479 else if( Toolkit::Alignment::HorizontalRight == mHorizontal )
481 anchorPointAndParentOrigin.x = 1.0f;
483 // anchorPoint.y is initialized to 0.0, which is VerticalTop
484 if( Toolkit::Alignment::VerticalCenter == mVertical )
486 anchorPointAndParentOrigin.y = 0.5f;
488 else if( Toolkit::Alignment::VerticalBottom == mVertical )
490 anchorPointAndParentOrigin.y = 1.0f;
493 unsigned int childCount = Self().GetChildCount();
494 for( unsigned int i=0; i<childCount; ++i )
496 Actor actor = Self().GetChildAt(i);
498 actor.SetAnchorPoint( anchorPointAndParentOrigin );
499 actor.SetParentOrigin( anchorPointAndParentOrigin );
501 if( Toolkit::Alignment::ScaleNone != mScaling )
503 actor.RemoveConstraints();
506 Vector3 actorSize ( actor.GetCurrentSize() );
507 Toolkit::Control control( Toolkit::Control::DownCast( actor ) );
508 if ( actorSize == Vector3::ZERO && control )
510 actorSize = control.GetNaturalSize();
517 case Toolkit::Alignment::ScaleNone:
519 // Nothing to do but needed just to not to jump to the default.
523 case Toolkit::Alignment::ScaleToFill:
525 ScaleToFillConstraint constraint( mPadding );
526 childSize = Vector2( constraint.GetSize( actorSize, Vector3(size) ) );
527 SetPositionConstraint( actor, mPadding, mHorizontal, mVertical );
530 case Toolkit::Alignment::ScaleToFitKeepAspect:
532 ScaleToFitKeepAspectConstraint constraint( mPadding );
533 childSize = Vector2( constraint.GetSize( actorSize, Vector3(size) ) );
534 SetPositionConstraint( actor, mPadding, mHorizontal, mVertical );
537 case Toolkit::Alignment::ScaleToFillKeepAspect:
539 ScaleToFillKeepAspectConstraint constraint( mPadding );
540 childSize = Vector2( constraint.GetSize( actorSize, Vector3(size) ) );
541 SetPositionConstraint( actor, mPadding, mHorizontal, mVertical );
544 case Toolkit::Alignment::ShrinkToFit:
546 ShrinkToFitConstraint constraint( mPadding );
547 childSize = Vector2( constraint.GetSize( actorSize, Vector3(size) ) );
548 SetPositionConstraint( actor, mPadding, mHorizontal, mVertical );
551 case Toolkit::Alignment::ShrinkToFitKeepAspect:
553 ShrinkToFitKeepAspectConstraint constraint( mPadding );
554 childSize = Vector2( constraint.GetSize( actorSize, Vector3(size) ) );
555 SetPositionConstraint( actor, mPadding, mHorizontal, mVertical );
560 DALI_ASSERT_ALWAYS( !"Invalid Alignment::mGeometryScaling value" );
565 Relayout( actor, childSize, container );
569 Alignment::Alignment( Toolkit::Alignment::Type horizontal, Toolkit::Alignment::Type vertical )
570 : Control( CONTROL_BEHAVIOUR_NONE ),
571 mHorizontal( horizontal ),
572 mVertical( vertical ),
573 mScaling( Toolkit::Alignment::ScaleNone ),
574 mPadding( 0.f, 0.f, 0.f, 0.f )
578 Alignment::~Alignment()
582 } // namespace Internal
584 } // namespace Toolkit