Added shader effect to render quadratic bezier curves and bounded regions on the GPU
[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/type-registry.h>
23
24 // INTERNAL INCLUDES
25
26 namespace Dali
27 {
28
29 namespace Toolkit
30 {
31
32 namespace Internal
33 {
34
35 namespace
36 {
37
38 //Type Registration
39 BaseHandle Create()
40 {
41   return Toolkit::Alignment::New();
42 }
43
44 TypeRegistration mType( typeid(Toolkit::Alignment), typeid(Toolkit::Control), Create );
45
46 struct ScaleToFillConstraint
47 {
48   /**
49    * @param padding to be added.
50    */
51   ScaleToFillConstraint( const Toolkit::Alignment::Padding& padding )
52   : mPadding( padding )
53   {}
54
55   /**
56    * Called by render thread
57    */
58   Vector3 operator()( const Vector3& currentSize,
59                       const PropertyInput& parentSizeProperty )
60   {
61     const Vector3& parentSize( parentSizeProperty.GetVector3() );
62     return GetSize( currentSize, parentSize );
63   }
64
65   inline Vector3 GetSize( const Vector3& currentSize, const Vector3& parentSize )
66   {
67     const float parentSizeWidth = parentSize.width - ( mPadding.left + mPadding.right );
68     const float parentSizeHeight = parentSize.height - ( mPadding.top + mPadding.bottom );
69
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 ) )
72     {
73       // no point trying to squeeze actors into this small size
74       return Vector3::ZERO;
75     }
76     return  Vector3( parentSizeWidth, parentSizeHeight, parentSize.depth );
77   }
78
79   const Toolkit::Alignment::Padding mPadding;
80 };
81
82 struct ScaleToFitKeepAspectConstraint
83 {
84   /**
85    * @param padding to be added.
86    */
87   ScaleToFitKeepAspectConstraint( const Toolkit::Alignment::Padding& padding )
88   : mPadding( padding ),
89     mSizeStored( false ),
90     mOriginalSize()
91   {}
92
93   /**
94    * Called by render thread
95    */
96   Vector3 operator()( const Vector3& currentSize,
97                       const PropertyInput& parentSizeProperty )
98   {
99     const Vector3& parentSize( parentSizeProperty.GetVector3() );
100     return GetSize( currentSize, parentSize );
101   }
102
103   inline Vector3 GetSize( const Vector3& currentSize, const Vector3& parentSize )
104   {
105     if( ( !mSizeStored ) && ( Vector3::ZERO != currentSize ) )
106     {
107       mOriginalSize = currentSize;
108       mSizeStored = true;
109     }
110
111     const float parentSizeWidth = parentSize.width - ( mPadding.left + mPadding.right );
112     const float parentSizeHeight = parentSize.height - ( mPadding.top + mPadding.bottom );
113
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 ) )
117     {
118       // no point trying to squeeze actors into this small size
119       return Vector3::ZERO;
120     }
121
122     return mOriginalSize * std::min( ( parentSizeWidth / mOriginalSize.width ), ( parentSizeHeight / mOriginalSize.height ) );
123   }
124
125   const Toolkit::Alignment::Padding mPadding;
126         bool                        mSizeStored;
127         Vector3                     mOriginalSize;
128 };
129
130 struct ScaleToFillKeepAspectConstraint
131 {
132   /**
133    * @param padding to be added.
134    */
135   ScaleToFillKeepAspectConstraint( const Toolkit::Alignment::Padding& padding )
136   : mPadding( padding ),
137     mSizeStored( false ),
138     mOriginalSize()
139   { }
140
141   /**
142    * Called by render thread
143    */
144   Vector3 operator()( const Vector3& currentSize,
145                       const PropertyInput& parentSizeProperty )
146   {
147     const Vector3& parentSize( parentSizeProperty.GetVector3() );
148     return GetSize( currentSize, parentSize );
149   }
150
151   Vector3 GetSize( const Vector3& currentSize, const Vector3& parentSize )
152   {
153     if( ( !mSizeStored ) && ( Vector3::ZERO != currentSize ) )
154     {
155       mOriginalSize = currentSize;
156       mSizeStored = true;
157     }
158
159     const float parentSizeWidth = parentSize.width - ( mPadding.left + mPadding.right );
160     const float parentSizeHeight = parentSize.height - ( mPadding.top + mPadding.bottom );
161
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 ) )
165     {
166       // no point trying to squeeze actors into this small size
167       return Vector3::ZERO;
168     }
169
170     return mOriginalSize * std::max( ( parentSizeWidth / mOriginalSize.width ), ( parentSizeHeight / mOriginalSize.height ) );
171   }
172
173   const Toolkit::Alignment::Padding mPadding;
174         bool                        mSizeStored;
175         Vector3                     mOriginalSize;
176 };
177
178 struct ShrinkToFitConstraint
179 {
180   /**
181    * @param padding to be added.
182    */
183   ShrinkToFitConstraint( const Toolkit::Alignment::Padding& padding )
184   : mPadding( padding ),
185     mSizeStored( false ),
186     mOriginalSize()
187   {}
188
189   /**
190    * Called by render thread
191    */
192   Vector3 operator()( const Vector3& currentSize,
193                       const PropertyInput& parentSizeProperty )
194   {
195     const Vector3& parentSize( parentSizeProperty.GetVector3() );
196     return GetSize( currentSize, parentSize );
197   }
198
199   Vector3 GetSize( const Vector3& currentSize, const Vector3& parentSize )
200   {
201     if( ( !mSizeStored ) && ( Vector3::ZERO != currentSize ) )
202     {
203       mOriginalSize = currentSize;
204       mSizeStored = true;
205     }
206
207     const float parentSizeWidth = parentSize.width - ( mPadding.left + mPadding.right );
208     const float parentSizeHeight = parentSize.height - ( mPadding.top + mPadding.bottom );
209
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 ) )
213     {
214       // no point trying to squeeze actors into this small size
215       return Vector3::ZERO;
216     }
217
218     return Vector3( std::min( parentSizeWidth, mOriginalSize.width ), std::min( parentSizeHeight, mOriginalSize.height ), std::min( parentSize.depth, mOriginalSize.depth ) );
219   }
220
221   const Toolkit::Alignment::Padding mPadding;
222         bool                        mSizeStored;
223         Vector3                     mOriginalSize;
224 };
225
226 /**
227  * Constraint that uses naturalSize if it fits inside parent and parent size if not. It also adds some padding pixels
228  */
229 struct ShrinkToFitKeepAspectConstraint
230 {
231   /**
232    * @param padding to be added.
233    */
234   ShrinkToFitKeepAspectConstraint( const Toolkit::Alignment::Padding& padding )
235   : mPadding( padding ),
236     mSizeStored( false ),
237     mOriginalSize()
238   {}
239
240   /**
241    * Called by render thread
242    */
243   Vector3 operator()( const Vector3& currentSize,
244                       const PropertyInput& parentSizeProperty )
245   {
246     const Vector3& parentSize( parentSizeProperty.GetVector3() );
247     return GetSize( currentSize, parentSize );
248   }
249
250   inline Vector3 GetSize( const Vector3& currentSize, const Vector3& parentSize )
251   {
252     if( ( !mSizeStored ) && ( Vector3::ZERO != currentSize ) )
253     {
254       mOriginalSize = currentSize;
255       mSizeStored = true;
256     }
257
258     const float parentSizeWidth = parentSize.width - ( mPadding.left + mPadding.right );
259     const float parentSizeHeight = parentSize.height - ( mPadding.top + mPadding.bottom );
260
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 ) )
264     {
265       // no point trying to squeeze actors into this small size
266       return Vector3::ZERO;
267     }
268
269     return Vector3( ShrinkInside( Vector2( parentSizeWidth, parentSizeHeight ), Vector2( mOriginalSize ) ) );
270   }
271
272   const Toolkit::Alignment::Padding mPadding;
273         bool                        mSizeStored;
274         Vector3                     mOriginalSize;
275 };
276
277 /**
278  * Constraint that modifies the contained actor taking into account the padding value.
279  */
280 struct PositionConstraint
281 {
282   /**
283    * @param padding The padding value
284    * @param horizontalAlignment The horizontal alignment.
285    * @param verticalAlignment The vertical alignment.
286    */
287   PositionConstraint( const Toolkit::Alignment::Padding& padding, Toolkit::Alignment::Type horizontalAlignment, Toolkit::Alignment::Type verticalAlignment )
288   : mPadding( padding ),
289     mHorizontalAlignment( horizontalAlignment ),
290     mVerticalAlignment( verticalAlignment )
291   {}
292
293   /**
294    * Called by render thread.
295    */
296   Vector3 operator()( const Vector3& currentPosition,
297                       const PropertyInput& currentSizeProperty,
298                       const PropertyInput& parentSizeProperty )
299   {
300     const Vector3& currentSize( currentSizeProperty.GetVector3() );
301     const Vector3& parentSize( parentSizeProperty.GetVector3() );
302
303     return GetPosition( currentSize, parentSize );
304   }
305
306   inline Vector3 GetPosition( const Vector3& currentSize, const Vector3& parentSize )
307   {
308     Vector3 position( 0.f, 0.f, 0.f );
309
310     switch( mHorizontalAlignment )
311     {
312     case Dali::Toolkit::Alignment::HorizontalLeft:
313     {
314       position.x += mPadding.left;
315       break;
316     }
317     case Dali::Toolkit::Alignment::HorizontalCenter:
318     {
319       if( currentSize.width + mPadding.left + mPadding.right >= parentSize.width )
320       {
321         position.x += 0.5f * ( mPadding.left - mPadding.right );
322       }
323       break;
324     }
325     case Dali::Toolkit::Alignment::HorizontalRight:
326     {
327       position.x -= mPadding.right;
328       break;
329     }
330     default:
331     {
332       DALI_ASSERT_ALWAYS( !"Wrong horizontal alignment value" );
333       break;
334     }
335     }
336
337     switch( mVerticalAlignment )
338     {
339     case Dali::Toolkit::Alignment::VerticalTop:
340     {
341       position.y += mPadding.top;
342       break;
343     }
344     case Dali::Toolkit::Alignment::VerticalCenter:
345     {
346       if( currentSize.height + mPadding.top + mPadding.bottom >= parentSize.height )
347       {
348         position.y += 0.5f * ( mPadding.top - mPadding.bottom );
349       }
350       break;
351     }
352     case Dali::Toolkit::Alignment::VerticalBottom:
353     {
354       position.y -= mPadding.bottom;
355       break;
356     }
357     default:
358     {
359       DALI_ASSERT_ALWAYS( !"Wrong vertical alignment value" );
360       break;
361     }
362     }
363
364     return position;
365   }
366
367   const Toolkit::Alignment::Padding mPadding;
368   const Toolkit::Alignment::Type mHorizontalAlignment;
369   const Toolkit::Alignment::Type mVerticalAlignment;
370 };
371 } // namespace
372
373 Toolkit::Alignment Alignment::New( Toolkit::Alignment::Type horizontal, Toolkit::Alignment::Type vertical )
374 {
375   // Create the implementation, temporarily owned on stack
376   IntrusivePtr< Alignment > internalAlignment = new Alignment( horizontal, vertical );
377
378   // Pass ownership to Toolkit::View
379   Toolkit::Alignment alignment( *internalAlignment );
380
381   // Second-phase init of the implementation
382   // This can only be done after the CustomActor connection has been made...
383   internalAlignment->Initialize();
384
385   return alignment;
386 }
387
388 void Alignment::SetAlignmentType( Toolkit::Alignment::Type type )
389 {
390   // Horizontal Alignment
391   if( type & Toolkit::Alignment::HorizontalRight )
392   {
393     mHorizontal = Toolkit::Alignment::HorizontalRight;
394   }
395   if( type & Toolkit::Alignment::HorizontalLeft )
396   {
397     mHorizontal = Toolkit::Alignment::HorizontalLeft;
398   }
399   if( type & Toolkit::Alignment::HorizontalCenter )
400   {
401     mHorizontal = Toolkit::Alignment::HorizontalCenter;
402   }
403
404   // Vertical Alignment
405   if( type & Toolkit::Alignment::VerticalBottom )
406   {
407     mVertical = Toolkit::Alignment::VerticalBottom;
408   }
409   if( type & Toolkit::Alignment::VerticalTop )
410   {
411     mVertical = Toolkit::Alignment::VerticalTop;
412   }
413   if( type & Toolkit::Alignment::VerticalCenter )
414   {
415     mVertical = Toolkit::Alignment::VerticalCenter;
416   }
417
418   RelayoutRequest();
419 }
420
421 Toolkit::Alignment::Type Alignment::GetAlignmentType() const
422 {
423   return Toolkit::Alignment::Type( mHorizontal | mVertical );
424 }
425
426 void Alignment::SetScaling( Toolkit::Alignment::Scaling scaling )
427 {
428   mScaling = scaling;
429
430   RelayoutRequest();
431 }
432
433 Toolkit::Alignment::Scaling Alignment::GetScaling() const
434 {
435   return mScaling;
436 }
437
438 void Alignment::SetPadding( const Toolkit::Alignment::Padding& padding )
439 {
440   DALI_ASSERT_ALWAYS( ( padding.left >= 0.f ) && ( padding.top >= 0.f ) && ( padding.right >= 0.f ) && ( padding.bottom >= 0.f ) );
441
442   mPadding = padding;
443
444   RelayoutRequest();
445 }
446
447 const Toolkit::Alignment::Padding& Alignment::GetPadding() const
448 {
449   return mPadding;
450 }
451
452 void Alignment::OnRelayout( const Vector2& size, ActorSizeContainer& container )
453 {
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 )
459   {
460     anchorPointAndParentOrigin.x = 0.5f;
461   }
462   else if( Toolkit::Alignment::HorizontalRight == mHorizontal )
463   {
464     anchorPointAndParentOrigin.x = 1.0f;
465   }
466   // anchorPoint.y is initialized to 0.0, which is VerticalTop
467   if( Toolkit::Alignment::VerticalCenter == mVertical )
468   {
469     anchorPointAndParentOrigin.y = 0.5f;
470   }
471   else if( Toolkit::Alignment::VerticalBottom == mVertical )
472   {
473     anchorPointAndParentOrigin.y = 1.0f;
474   }
475
476   unsigned int childCount = Self().GetChildCount();
477   for( unsigned int i=0; i<childCount; ++i )
478   {
479     Actor actor = Self().GetChildAt(i);
480
481     actor.SetAnchorPoint( anchorPointAndParentOrigin );
482     actor.SetParentOrigin( anchorPointAndParentOrigin );
483
484     Vector3 actorSize ( actor.GetSize() );
485     Toolkit::Control control( Toolkit::Control::DownCast( actor ) );
486     if ( actorSize == Vector3::ZERO && control )
487     {
488       actorSize = control.GetNaturalSize();
489     }
490
491     Vector3 childSize;
492
493     switch( mScaling )
494     {
495       case Toolkit::Alignment::ScaleNone:
496       {
497         // Nothing to do but needed just to not to jump to the default.
498         childSize = actorSize;
499         break;
500       }
501       case Toolkit::Alignment::ScaleToFill:
502       {
503         ScaleToFillConstraint constraint( mPadding );
504         childSize = constraint.GetSize( actorSize, Vector3(size) ) ;
505         break;
506       }
507       case Toolkit::Alignment::ScaleToFitKeepAspect:
508       {
509         ScaleToFitKeepAspectConstraint constraint( mPadding );
510         childSize = constraint.GetSize( actorSize, Vector3(size) ) ;
511         break;
512       }
513       case Toolkit::Alignment::ScaleToFillKeepAspect:
514       {
515         ScaleToFillKeepAspectConstraint constraint( mPadding );
516         childSize = constraint.GetSize( actorSize, Vector3(size) );
517         break;
518       }
519       case Toolkit::Alignment::ShrinkToFit:
520       {
521         ShrinkToFitConstraint constraint( mPadding );
522         childSize = constraint.GetSize( actorSize, Vector3(size) );
523         break;
524       }
525       case Toolkit::Alignment::ShrinkToFitKeepAspect:
526       {
527         ShrinkToFitKeepAspectConstraint constraint( mPadding );
528         childSize = constraint.GetSize( actorSize, Vector3(size) );
529         break;
530       }
531       default:
532       {
533         DALI_ASSERT_ALWAYS( !"Invalid Alignment::mGeometryScaling value" );
534         break;
535       }
536     }
537
538     PositionConstraint positionConstraint(mPadding, mHorizontal, mVertical);
539     actor.SetPosition( positionConstraint.GetPosition(childSize, actorSize) );
540
541     if( !control )
542     {
543       actor.SetScale(childSize / actorSize);
544     }
545
546     Relayout( actor, Vector2(childSize), container );
547   }
548 }
549
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 )
556 {
557 }
558
559 Alignment::~Alignment()
560 {
561 }
562
563 } // namespace Internal
564
565 } // namespace Toolkit
566
567 } // namespace Dali