Merge "Type registry helper: Toolkit change to correct Programming Guide for Custom...
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / alignment / alignment-impl.cpp
1 /*
2  * Copyright (c) 2014 Samsung Electronics Co., Ltd.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  *
16  */
17
18 // CLASS HEADER
19 #include "alignment-impl.h"
20
21 // EXTERNAL INCLUDES
22 #include <dali/public-api/object/property-input.h>
23 #include <dali/public-api/object/type-registry.h>
24 #include <dali/public-api/object/type-registry-helper.h>
25 #include <dali/public-api/size-negotiation/relayout-container.h>
26
27 namespace Dali
28 {
29
30 namespace Toolkit
31 {
32
33 namespace Internal
34 {
35
36 namespace
37 {
38
39 //Type Registration
40 BaseHandle Create()
41 {
42   return Toolkit::Alignment::New();
43 }
44
45 DALI_TYPE_REGISTRATION_BEGIN( Toolkit::Alignment, Toolkit::Control, Create )
46 DALI_TYPE_REGISTRATION_END()
47
48 /**
49  * @param padding The padding value
50  * @param horizontalAlignment The horizontal alignment.
51  * @param verticalAlignment The vertical alignment.
52  * @param currentSize of the object
53  * @param parentSize
54  */
55 inline Vector3 GetPosition( const Toolkit::Alignment::Padding& padding, Toolkit::Alignment::Type horizontalAlignment, Toolkit::Alignment::Type verticalAlignment,
56                             const Vector2& currentSize, const Vector2& parentSize )
57 {
58   Vector3 position( 0.f, 0.f, 0.f );
59
60   switch( horizontalAlignment )
61   {
62     case Dali::Toolkit::Alignment::HorizontalLeft:
63     {
64       position.x += padding.left;
65       break;
66     }
67     case Dali::Toolkit::Alignment::HorizontalRight:
68     {
69       position.x -= padding.right;
70       break;
71     }
72     case Dali::Toolkit::Alignment::HorizontalCenter: // FALLTHROUGH
73     default: // use center as default
74     {
75       if( currentSize.width + padding.left + padding.right >= parentSize.width )
76       {
77         position.x += 0.5f * ( padding.left - padding.right );
78       }
79       break;
80     }
81   }
82
83   switch( verticalAlignment )
84   {
85     case Dali::Toolkit::Alignment::VerticalTop:
86     {
87       position.y += padding.top;
88       break;
89     }
90     case Dali::Toolkit::Alignment::VerticalBottom:
91     {
92       position.y -= padding.bottom;
93       break;
94     }
95     case Dali::Toolkit::Alignment::VerticalCenter: // FALLTHROUGH
96     default: // use center as default
97     {
98       if( currentSize.height + padding.top + padding.bottom >= parentSize.height )
99       {
100         position.y += 0.5f * ( padding.top - padding.bottom );
101       }
102       break;
103     }
104   }
105
106   return position;
107 }
108
109 } // namespace
110
111 Toolkit::Alignment Alignment::New( Toolkit::Alignment::Type horizontal, Toolkit::Alignment::Type vertical )
112 {
113   // Create the implementation, temporarily owned on stack
114   IntrusivePtr< Alignment > internalAlignment = new Alignment( horizontal, vertical );
115
116   // Pass ownership to Toolkit::Alignment
117   Toolkit::Alignment alignment( *internalAlignment );
118
119   // Second-phase init of the implementation
120   // This can only be done after the CustomActor connection has been made...
121   internalAlignment->Initialize();
122
123   return alignment;
124 }
125
126 void Alignment::SetAlignmentType( Toolkit::Alignment::Type type )
127 {
128   // Horizontal Alignment
129   if( type & Toolkit::Alignment::HorizontalRight )
130   {
131     mHorizontal = Toolkit::Alignment::HorizontalRight;
132   }
133   if( type & Toolkit::Alignment::HorizontalLeft )
134   {
135     mHorizontal = Toolkit::Alignment::HorizontalLeft;
136   }
137   if( type & Toolkit::Alignment::HorizontalCenter )
138   {
139     mHorizontal = Toolkit::Alignment::HorizontalCenter;
140   }
141
142   // Vertical Alignment
143   if( type & Toolkit::Alignment::VerticalBottom )
144   {
145     mVertical = Toolkit::Alignment::VerticalBottom;
146   }
147   if( type & Toolkit::Alignment::VerticalTop )
148   {
149     mVertical = Toolkit::Alignment::VerticalTop;
150   }
151   if( type & Toolkit::Alignment::VerticalCenter )
152   {
153     mVertical = Toolkit::Alignment::VerticalCenter;
154   }
155
156   RelayoutRequest();
157 }
158
159 Toolkit::Alignment::Type Alignment::GetAlignmentType() const
160 {
161   return Toolkit::Alignment::Type( mHorizontal | mVertical );
162 }
163
164 void Alignment::SetScaling( Toolkit::Alignment::Scaling scaling )
165 {
166   mScaling = scaling;
167
168   RelayoutRequest();
169 }
170
171 Toolkit::Alignment::Scaling Alignment::GetScaling() const
172 {
173   return mScaling;
174 }
175
176 void Alignment::SetPadding( const Toolkit::Alignment::Padding& padding )
177 {
178   DALI_ASSERT_ALWAYS( ( padding.left >= 0.f ) && ( padding.top >= 0.f ) && ( padding.right >= 0.f ) && ( padding.bottom >= 0.f ) );
179
180   mPadding = padding;
181
182   RelayoutRequest();
183 }
184
185 const Toolkit::Alignment::Padding& Alignment::GetPadding() const
186 {
187   return mPadding;
188 }
189
190 void Alignment::OnRelayout( const Vector2& size, RelayoutContainer& container )
191 {
192   // lay out the actors
193   Vector3 anchorPointAndParentOrigin  = Vector3::ZERO;
194   anchorPointAndParentOrigin.z = 0.5f;
195   // anchorPoint.x is initialized to 0.0, which is HorizontalLeft
196   if( Toolkit::Alignment::HorizontalCenter == mHorizontal )
197   {
198     anchorPointAndParentOrigin.x = 0.5f;
199   }
200   else if( Toolkit::Alignment::HorizontalRight == mHorizontal )
201   {
202     anchorPointAndParentOrigin.x = 1.0f;
203   }
204   // anchorPoint.y is initialized to 0.0, which is VerticalTop
205   if( Toolkit::Alignment::VerticalCenter == mVertical )
206   {
207     anchorPointAndParentOrigin.y = 0.5f;
208   }
209   else if( Toolkit::Alignment::VerticalBottom == mVertical )
210   {
211     anchorPointAndParentOrigin.y = 1.0f;
212   }
213
214   for( unsigned int i = 0, childCount = Self().GetChildCount(); i < childCount; ++i )
215   {
216     Actor child = Self().GetChildAt(i);
217
218     child.SetAnchorPoint( anchorPointAndParentOrigin );
219     child.SetParentOrigin( anchorPointAndParentOrigin );
220
221     Vector2 currentChildSize( child.GetTargetSize().GetVectorXY() );
222     if( currentChildSize == Vector2::ZERO )
223     {
224       currentChildSize = child.GetNaturalSize();
225     }
226
227     bool renegotiate = true;
228     Vector2 newChildSize;
229     newChildSize.width  = size.width - ( mPadding.left + mPadding.right );
230     newChildSize.height = size.height- (  mPadding.top + mPadding.bottom );
231
232     // prevent ridiculous sizes if parent is really small or if we don't have a proper size for the actor
233     if( ( newChildSize.width > Math::MACHINE_EPSILON_1000 ) && ( newChildSize.height > Math::MACHINE_EPSILON_1000 ) &&
234         ( currentChildSize.width > Math::MACHINE_EPSILON_1000 ) && ( currentChildSize.height > Math::MACHINE_EPSILON_1000 ) )
235     {
236       // no point trying to squeeze actors into too small size
237       switch( mScaling )
238       {
239         case Toolkit::Alignment::ScaleNone:
240         {
241           // Nothing to do
242           renegotiate = false;
243           break;
244         }
245         case Toolkit::Alignment::ScaleToFill:
246         {
247           // Nothing to do, newChildSize is already full size minus padding
248           break;
249         }
250         case Toolkit::Alignment::ScaleToFitKeepAspect:
251         {
252           newChildSize = currentChildSize * std::min( ( newChildSize.width / currentChildSize.width ), ( newChildSize.height / currentChildSize.height ) );
253           break;
254         }
255         case Toolkit::Alignment::ScaleToFillKeepAspect:
256         {
257           newChildSize = currentChildSize * std::max( ( newChildSize.width / currentChildSize.width ), ( newChildSize.height / currentChildSize.height ) );
258           break;
259         }
260         case Toolkit::Alignment::ShrinkToFit:
261         {
262           newChildSize = Vector2( std::min( newChildSize.width, currentChildSize.width ), std::min( newChildSize.height, currentChildSize.height ) );
263           break;
264         }
265         case Toolkit::Alignment::ShrinkToFitKeepAspect:
266         {
267           // check source size vs target size to see if we need to shrink
268           float widthScale = ( newChildSize.width < currentChildSize.width ) ? (newChildSize.width / currentChildSize.width) : 1.f;
269           float heightScale = ( newChildSize.height < currentChildSize.height ) ? (newChildSize.height / currentChildSize.height) : 1.0f;
270           // use smaller of the scales
271           float scale = std::min( widthScale, heightScale );
272           // check if we need to scale
273           if( scale < 1.0f )
274           {
275             // scale natural size to fit inside
276             newChildSize *= scale;
277           }
278           break;
279         }
280       }
281     }
282
283     child.SetPosition( GetPosition( mPadding, mHorizontal, mVertical , newChildSize, currentChildSize ) );
284
285     if( renegotiate )
286     {
287       container.Add( child, newChildSize );
288     }
289   }
290 }
291
292 Alignment::Alignment( Toolkit::Alignment::Type horizontal, Toolkit::Alignment::Type vertical )
293 : Control( ControlBehaviour( ACTOR_BEHAVIOUR_NONE ) ),
294   mHorizontal( horizontal ),
295   mVertical( vertical ),
296   mScaling( Toolkit::Alignment::ScaleNone ),
297   mPadding( 0.f, 0.f, 0.f, 0.f )
298 {
299 }
300
301 Alignment::~Alignment()
302 {
303 }
304
305 } // namespace Internal
306
307 } // namespace Toolkit
308
309 } // namespace Dali