Allow property conversions: float from int and int from float
[platform/core/uifw/dali-core.git] / dali / public-api / object / property-value.cpp
1 /*
2  * Copyright (c) 2015 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 <dali/public-api/object/property-value.h>
20
21 // EXTERNAL INCLUDES
22 #include <ostream>
23
24 // INTERNAL INCLUDES
25 #include <dali/public-api/math/angle-axis.h>
26 #include <dali/public-api/math/radian.h>
27 #include <dali/public-api/math/vector2.h>
28 #include <dali/public-api/math/vector3.h>
29 #include <dali/public-api/math/vector4.h>
30 #include <dali/public-api/math/matrix3.h>
31 #include <dali/public-api/math/matrix.h>
32 #include <dali/public-api/math/rect.h>
33 #include <dali/public-api/math/quaternion.h>
34 #include <dali/public-api/object/property-map.h>
35 #include <dali/public-api/object/property-array.h>
36 #include <dali/public-api/object/property-types.h>
37 #include <dali/integration-api/debug.h>
38
39 namespace Dali
40 {
41
42 namespace
43 {
44 /**
45  * Helper to check if the property value can be read as int/unsigned int/bool
46  */
47 inline bool IsIntegerType( Property::Type type )
48 {
49   return ( Property::BOOLEAN == type )||( Property::INTEGER == type )||(Property::UNSIGNED_INTEGER == type );
50 }
51 }
52
53 struct Property::Value::Impl
54 {
55   Impl()
56   : type( Property::NONE ),
57     integerValue( 0 )
58   { }
59
60   Impl( bool booleanValue )
61   : type( Property::BOOLEAN ),
62     integerValue( booleanValue )
63   { }
64
65   Impl( float floatValue )
66   : type( Property::FLOAT ),
67     floatValue( floatValue )
68   { }
69
70   Impl( int integerValue )
71   : type( Property::INTEGER ),
72     integerValue( integerValue )
73   { }
74
75   Impl( unsigned int unsignedIntegerValue )
76   : type( Property::UNSIGNED_INTEGER ),
77     unsignedIntegerValue( unsignedIntegerValue )
78   { }
79
80   Impl( const Vector2& vectorValue )
81   : type( Property::VECTOR2 ),
82     vector2Value( new Vector2( vectorValue ) )
83   { }
84
85   Impl( const Vector3& vectorValue )
86   : type( Property::VECTOR3 ),
87     vector3Value( new Vector3( vectorValue ) )
88   { }
89
90   Impl( const Vector4& vectorValue )
91   : type( Property::VECTOR4 ),
92     vector4Value( new Vector4( vectorValue ) )
93   { }
94
95   Impl( const Matrix3& matrixValue )
96   : type( Property::MATRIX3 ),
97     matrix3Value( new Matrix3( matrixValue ) )
98   {
99   }
100
101   Impl( const Matrix& matrixValue )
102   : type( Property::MATRIX ),
103     matrixValue( new Matrix( matrixValue ) )
104   {
105   }
106
107   Impl( const AngleAxis& angleAxisValue )
108   : type( Property::ROTATION ),
109     quaternionValue( new Quaternion( angleAxisValue.angle, angleAxisValue.axis ) )
110   {
111   }
112
113   Impl( const Quaternion& quaternionValue )
114   : type( Property::ROTATION ),
115     quaternionValue( new Quaternion( quaternionValue ) )
116   {
117   }
118
119   Impl(const std::string& stringValue)
120   : type( Property::STRING ),
121     stringValue( new std::string( stringValue ) )
122   {
123   }
124
125   Impl( const Rect<int>& rectValue )
126   : type( Property::RECTANGLE ),
127     rectValue( new Rect<int>( rectValue ) )
128   {
129   }
130
131   Impl( const Property::Array& arrayValue )
132   : type( Property::ARRAY ),
133     arrayValue( new Property::Array( arrayValue ) )
134   {
135   }
136
137   Impl( const Property::Map& mapValue )
138   : type( Property::MAP ),
139     mapValue( new Property::Map( mapValue ) )
140   {
141   }
142
143   /**
144    * Destructor, takes care of releasing the dynamically allocated types
145    */
146   ~Impl()
147   {
148     switch( type )
149     {
150       case Property::NONE :             // FALLTHROUGH
151       case Property::BOOLEAN :          // FALLTHROUGH
152       case Property::FLOAT :            // FALLTHROUGH
153       case Property::INTEGER :          // FALLTHROUGH
154       case Property::UNSIGNED_INTEGER :
155       {
156         break; // nothing to do
157       }
158       case Property::VECTOR2 :
159       {
160         delete vector2Value;
161         break;
162       }
163       case Property::VECTOR3:
164       {
165         delete vector3Value;
166         break;
167       }
168       case Property::VECTOR4:
169       {
170         delete vector4Value;
171         break;
172       }
173       case Property::MATRIX3:
174       {
175         delete matrix3Value;
176         break;
177       }
178       case Property::MATRIX:
179       {
180         delete matrixValue;
181         break;
182       }
183       case Property::RECTANGLE:
184       {
185         delete rectValue;
186         break;
187       }
188       case Property::ROTATION:
189       {
190         delete quaternionValue;
191         break;
192       }
193       case Property::STRING:
194       {
195         delete stringValue;
196         break;
197       }
198       case Property::ARRAY:
199       {
200         delete arrayValue;
201         break;
202       }
203       case Property::MAP:
204       {
205         delete mapValue;
206         break;
207       }
208     }
209   }
210
211 public: // Data
212
213   Type type;
214   union
215   {
216     int integerValue;
217     float floatValue;
218     unsigned int unsignedIntegerValue;
219     // must use pointers for any class value pre c++ 11
220     Vector2* vector2Value;
221     Vector3* vector3Value;
222     Vector4* vector4Value;
223     Matrix3* matrix3Value;
224     Matrix* matrixValue;
225     Quaternion* quaternionValue;
226     std::string* stringValue;
227     Rect<int>* rectValue;
228     Property::Array* arrayValue;
229     Property::Map* mapValue;
230   };
231 };
232
233 Property::Value::Value()
234 : mImpl( NULL )
235 {
236 }
237
238 Property::Value::Value( bool booleanValue )
239 : mImpl( new Impl( booleanValue ) )
240 {
241 }
242
243 Property::Value::Value( float floatValue )
244 : mImpl( new Impl( floatValue ) )
245 {
246 }
247
248 Property::Value::Value( int integerValue )
249 : mImpl( new Impl( integerValue ) )
250 {
251 }
252
253 Property::Value::Value( unsigned int unsignedIntegerValue )
254 : mImpl( new Impl( unsignedIntegerValue ) )
255 {
256 }
257
258 Property::Value::Value( const Vector2& vectorValue )
259 : mImpl( new Impl( vectorValue ) )
260 {
261 }
262
263 Property::Value::Value( const Vector3& vectorValue )
264 : mImpl( new Impl( vectorValue ) )
265 {
266 }
267
268 Property::Value::Value( const Vector4& vectorValue )
269 : mImpl( new Impl( vectorValue ) )
270 {
271 }
272
273 Property::Value::Value( const Matrix3& matrixValue )
274 : mImpl( new Impl( matrixValue ) )
275 {
276 }
277
278 Property::Value::Value( const Matrix& matrixValue )
279 : mImpl( new Impl( matrixValue ) )
280 {
281 }
282
283 Property::Value::Value( const Rect<int>& rectValue )
284 : mImpl( new Impl( rectValue ) )
285 {
286 }
287
288 Property::Value::Value( const AngleAxis& angleAxisValue )
289 : mImpl( new Impl( angleAxisValue ) )
290 {
291 }
292
293 Property::Value::Value( const Quaternion& quaternionValue )
294 : mImpl( new Impl( quaternionValue ) )
295 {
296 }
297
298 Property::Value::Value( const std::string& stringValue )
299 : mImpl( new Impl( stringValue ) )
300 {
301 }
302
303 Property::Value::Value( const char* stringValue )
304 : mImpl( NULL )
305 {
306   if( stringValue ) // string constructor is undefined with NULL pointer
307   {
308     mImpl = new Impl( std::string(stringValue) );
309   }
310   else
311   {
312     mImpl = new Impl( std::string() );
313   }
314 }
315
316 Property::Value::Value( Property::Array& arrayValue )
317 : mImpl( new Impl( arrayValue ) )
318 {
319 }
320
321 Property::Value::Value( Property::Map& mapValue )
322 : mImpl( new Impl( mapValue ) )
323 {
324 }
325
326 Property::Value::Value( Type type )
327 {
328   switch (type)
329   {
330     case Property::BOOLEAN:
331     {
332       mImpl = new Impl( false );
333       break;
334     }
335     case Property::FLOAT:
336     {
337       mImpl = new Impl( 0.f );
338       break;
339     }
340     case Property::INTEGER:
341     {
342       mImpl = new Impl( 0 );
343       break;
344     }
345     case Property::UNSIGNED_INTEGER:
346     {
347       mImpl = new Impl( 0U );
348       break;
349     }
350     case Property::VECTOR2:
351     {
352       mImpl = new Impl( Vector2::ZERO );
353       break;
354     }
355     case Property::VECTOR3:
356     {
357       mImpl = new Impl( Vector3::ZERO );
358       break;
359     }
360     case Property::VECTOR4:
361     {
362       mImpl = new Impl( Vector4::ZERO );
363       break;
364     }
365     case Property::RECTANGLE:
366     {
367       mImpl = new Impl( Rect<int>(0,0,0,0) );
368       break;
369     }
370     case Property::ROTATION:
371     {
372       mImpl = new Impl( Quaternion() );
373       break;
374     }
375     case Property::STRING:
376     {
377       mImpl = new Impl( std::string() );
378       break;
379     }
380     case Property::MATRIX:
381     {
382       mImpl = new Impl( Matrix() );
383       break;
384     }
385     case Property::MATRIX3:
386     {
387       mImpl = new Impl( Matrix3() );
388       break;
389     }
390     case Property::ARRAY:
391     {
392       mImpl = new Impl( Property::Array() );
393       break;
394     }
395     case Property::MAP:
396     {
397       mImpl = new Impl( Property::Map() );
398       break;
399     }
400     case Property::NONE:
401     {
402       mImpl = new Impl();
403       break;
404     }
405   }
406 }
407 Property::Value::Value( const Property::Value& value )
408 : mImpl( NULL )
409 {
410   // reuse assignment operator
411   operator=( value );
412 }
413
414 Property::Value& Property::Value::operator=( const Property::Value& value )
415 {
416   if ( this == &value )
417   {
418     // skip self assignment
419     return *this;
420   }
421   // if we are assigned an empty value, just drop impl
422   if( !value.mImpl )
423   {
424     delete mImpl;
425     mImpl = NULL;
426     return *this;
427   }
428   // first check if the type is the same, no need to change impl, just assign
429   if( mImpl && ( mImpl->type == value.mImpl->type ) )
430   {
431     switch( mImpl->type )
432     {
433       case Property::BOOLEAN:
434       {
435         mImpl->integerValue = value.mImpl->integerValue;
436         break;
437       }
438       case Property::FLOAT:
439       {
440         mImpl->floatValue = value.mImpl->floatValue;
441         break;
442       }
443       case Property::INTEGER:
444       {
445         mImpl->integerValue = value.mImpl->integerValue;
446         break;
447       }
448       case Property::UNSIGNED_INTEGER:
449       {
450         mImpl->unsignedIntegerValue = value.mImpl->unsignedIntegerValue;
451         break;
452       }
453       case Property::VECTOR2:
454       {
455         *mImpl->vector2Value = *value.mImpl->vector2Value; // type cannot change in mImpl so vector is allocated
456         break;
457       }
458       case Property::VECTOR3:
459       {
460         *mImpl->vector3Value = *value.mImpl->vector3Value; // type cannot change in mImpl so vector is allocated
461         break;
462       }
463       case Property::VECTOR4:
464       {
465         *mImpl->vector4Value = *value.mImpl->vector4Value; // type cannot change in mImpl so vector is allocated
466         break;
467       }
468       case Property::RECTANGLE:
469       {
470         *mImpl->rectValue = *value.mImpl->rectValue; // type cannot change in mImpl so rect is allocated
471         break;
472       }
473       case Property::ROTATION:
474       {
475         *mImpl->quaternionValue = *value.mImpl->quaternionValue; // type cannot change in mImpl so quaternion is allocated
476         break;
477       }
478       case Property::STRING:
479       {
480         *mImpl->stringValue = *value.mImpl->stringValue; // type cannot change in mImpl so string is allocated
481         break;
482       }
483       case Property::MATRIX:
484       {
485         *mImpl->matrixValue = *value.mImpl->matrixValue; // type cannot change in mImpl so matrix is allocated
486         break;
487       }
488       case Property::MATRIX3:
489       {
490         *mImpl->matrix3Value = *value.mImpl->matrix3Value; // type cannot change in mImpl so matrix is allocated
491         break;
492       }
493       case Property::ARRAY:
494       {
495         *mImpl->arrayValue = *value.mImpl->arrayValue; // type cannot change in mImpl so array is allocated
496         break;
497       }
498       case Property::MAP:
499       {
500         *mImpl->mapValue = *value.mImpl->mapValue; // type cannot change in mImpl so map is allocated
501         break;
502       }
503       case Property::NONE:
504       { // mImpl will be NULL, there's no way to get to this case
505       }
506     }
507   }
508   else
509   {
510     // different type, release old impl and create new
511     Impl* newImpl( NULL );
512     switch ( value.mImpl->type )
513     {
514       case Property::BOOLEAN:
515       {
516         newImpl = new Impl( bool( value.mImpl->integerValue ) );
517         break;
518       }
519       case Property::FLOAT:
520       {
521         newImpl = new Impl( value.mImpl->floatValue );
522         break;
523       }
524       case Property::INTEGER:
525       {
526         newImpl = new Impl( value.mImpl->integerValue );
527         break;
528       }
529       case Property::UNSIGNED_INTEGER:
530       {
531         newImpl = new Impl( value.mImpl->unsignedIntegerValue );
532         break;
533       }
534       case Property::VECTOR2:
535       {
536         newImpl = new Impl( *value.mImpl->vector2Value ); // type cannot change in mImpl so vector is allocated
537         break;
538       }
539       case Property::VECTOR3:
540       {
541         newImpl = new Impl( *value.mImpl->vector3Value ); // type cannot change in mImpl so vector is allocated
542         break;
543       }
544       case Property::VECTOR4:
545       {
546         newImpl = new Impl( *value.mImpl->vector4Value ); // type cannot change in mImpl so vector is allocated
547         break;
548       }
549       case Property::RECTANGLE:
550       {
551         newImpl = new Impl( *value.mImpl->rectValue ); // type cannot change in mImpl so rect is allocated
552         break;
553       }
554       case Property::ROTATION:
555       {
556         newImpl = new Impl( *value.mImpl->quaternionValue ); // type cannot change in mImpl so quaternion is allocated
557         break;
558       }
559       case Property::MATRIX3:
560       {
561         newImpl = new Impl( *value.mImpl->matrix3Value ); // type cannot change in mImpl so matrix is allocated
562         break;
563       }
564       case Property::MATRIX:
565       {
566         newImpl = new Impl( *value.mImpl->matrixValue ); // type cannot change in mImpl so matrix is allocated
567         break;
568       }
569       case Property::STRING:
570       {
571         newImpl = new Impl( *value.mImpl->stringValue ); // type cannot change in mImpl so string is allocated
572         break;
573       }
574       case Property::ARRAY:
575       {
576         newImpl = new Impl( *value.mImpl->arrayValue ); // type cannot change in mImpl so array is allocated
577         break;
578       }
579       case Property::MAP:
580       {
581         newImpl = new Impl( *value.mImpl->mapValue ); // type cannot change in mImpl so map is allocated
582         break;
583       }
584       case Property::NONE:
585       { // NULL value will be used for "empty" value
586       }
587     }
588     delete mImpl;
589     mImpl = newImpl;
590   }
591
592   return *this;
593 }
594
595 Property::Value::~Value()
596 {
597   delete mImpl;
598 }
599
600 Property::Type Property::Value::GetType() const
601 {
602   Property::Type type( Property::NONE );
603   if( mImpl )
604   {
605     type = mImpl->type;
606   }
607   return type;
608 }
609
610 bool Property::Value::Get( bool& booleanValue ) const
611 {
612   bool converted = false;
613   if( mImpl && IsIntegerType( mImpl->type ) )
614   {
615     booleanValue = mImpl->integerValue;
616     converted = true;
617   }
618   return converted;
619 }
620
621 bool Property::Value::Get( float& floatValue ) const
622 {
623   bool converted = false;
624   if( mImpl )
625   {
626     if( mImpl->type == FLOAT )
627     {
628       floatValue = mImpl->floatValue;
629       converted = true;
630     }
631     else if( IsIntegerType( mImpl->type ) )
632     {
633       floatValue = static_cast< float >( mImpl->integerValue );
634       converted = true;
635     }
636   }
637   return converted;
638 }
639
640 bool Property::Value::Get( int& integerValue ) const
641 {
642   bool converted = false;
643   if( mImpl )
644   {
645     if( IsIntegerType( mImpl->type ) )
646     {
647       integerValue = mImpl->integerValue;
648       converted = true;
649     }
650     else if( mImpl->type == FLOAT )
651     {
652       integerValue = static_cast< int >( mImpl->floatValue );
653       converted = true;
654     }
655   }
656   return converted;
657 }
658
659 bool Property::Value::Get( unsigned int& unsignedIntegerValue ) const
660 {
661   bool converted = false;
662   if( mImpl && IsIntegerType( mImpl->type ) )
663   {
664     unsignedIntegerValue = mImpl->unsignedIntegerValue;
665     converted = true;
666   }
667   return converted;
668 }
669
670 bool Property::Value::Get( Vector2& vectorValue ) const
671 {
672   bool converted = false;
673   if( mImpl && (mImpl->type == VECTOR2) ) // type cannot change in mImpl so vector is allocated
674   {
675     vectorValue = *(mImpl->vector2Value);
676     converted = true;
677   }
678   return converted;
679 }
680
681 bool Property::Value::Get( Vector3& vectorValue ) const
682 {
683   bool converted = false;
684   if( mImpl && (mImpl->type == VECTOR3) ) // type cannot change in mImpl so vector is allocated
685   {
686     vectorValue = *(mImpl->vector3Value);
687     converted = true;
688   }
689   return converted;
690 }
691
692 bool Property::Value::Get( Vector4& vectorValue ) const
693 {
694   bool converted = false;
695   if( mImpl && (mImpl->type == VECTOR4) ) // type cannot change in mImpl so vector is allocated
696   {
697     vectorValue = *(mImpl->vector4Value);
698     converted = true;
699   }
700   return converted;
701 }
702
703 bool Property::Value::Get( Matrix3& matrixValue ) const
704 {
705   bool converted = false;
706   if( mImpl && (mImpl->type == MATRIX3) ) // type cannot change in mImpl so matrix is allocated
707   {
708     matrixValue = *(mImpl->matrix3Value);
709     converted = true;
710   }
711   return converted;
712 }
713
714 bool Property::Value::Get( Matrix& matrixValue ) const
715 {
716   bool converted = false;
717   if( mImpl && (mImpl->type == MATRIX) ) // type cannot change in mImpl so matrix is allocated
718   {
719     matrixValue = *(mImpl->matrixValue);
720     converted = true;
721   }
722   return converted;
723 }
724
725 bool Property::Value::Get( Rect<int>& rectValue ) const
726 {
727   bool converted = false;
728   if( mImpl && (mImpl->type == RECTANGLE) ) // type cannot change in mImpl so rect is allocated
729   {
730     rectValue = *(mImpl->rectValue);
731     converted = true;
732   }
733   return converted;
734 }
735
736 bool Property::Value::Get( AngleAxis& angleAxisValue ) const
737 {
738   bool converted = false;
739   if( mImpl && (mImpl->type == ROTATION) ) // type cannot change in mImpl so quaternion is allocated
740   {
741     mImpl->quaternionValue->ToAxisAngle( angleAxisValue.axis, angleAxisValue.angle );
742     converted = true;
743   }
744   return converted;
745 }
746
747 bool Property::Value::Get( Quaternion& quaternionValue ) const
748 {
749   bool converted = false;
750   if( mImpl && (mImpl->type == ROTATION) ) // type cannot change in mImpl so quaternion is allocated
751   {
752     quaternionValue = *(mImpl->quaternionValue);
753     converted = true;
754   }
755   return converted;
756 }
757
758 bool Property::Value::Get( std::string& stringValue ) const
759 {
760   bool converted = false;
761   if( mImpl && (mImpl->type == STRING) ) // type cannot change in mImpl so string is allocated
762   {
763     stringValue.assign( *(mImpl->stringValue) );
764     converted = true;
765   }
766   return converted;
767 }
768
769 bool Property::Value::Get( Property::Array& arrayValue ) const
770 {
771   bool converted = false;
772   if( mImpl && (mImpl->type == ARRAY) ) // type cannot change in mImpl so array is allocated
773   {
774     arrayValue = *(mImpl->arrayValue);
775     converted = true;
776   }
777   return converted;
778 }
779
780 bool Property::Value::Get( Property::Map& mapValue ) const
781 {
782   bool converted = false;
783   if( mImpl && (mImpl->type == MAP) ) // type cannot change in mImpl so map is allocated
784   {
785     mapValue = *(mImpl->mapValue);
786     converted = true;
787   }
788   return converted;
789 }
790
791 Property::Array* Property::Value::GetArray() const
792 {
793   Property::Array* array = NULL;
794   if( mImpl && (mImpl->type == ARRAY) ) // type cannot change in mImpl so array is allocated
795   {
796     array = mImpl->arrayValue;
797   }
798   return array;
799 }
800
801 Property::Map* Property::Value::GetMap() const
802 {
803   Property::Map* map = NULL;
804   if( mImpl && (mImpl->type == MAP) ) // type cannot change in mImpl so map is allocated
805   {
806     map = mImpl->mapValue;
807   }
808   return map;
809 }
810
811 std::ostream& operator<<( std::ostream& stream, const Property::Value& value )
812 {
813   if( value.mImpl )
814   {
815     const Property::Value::Impl& impl( *value.mImpl );
816
817     switch( impl.type )
818     {
819       case Dali::Property::BOOLEAN:
820       {
821         stream << impl.integerValue;
822         break;
823       }
824       case Dali::Property::FLOAT:
825       {
826         stream << impl.floatValue;
827         break;
828       }
829       case Dali::Property::INTEGER:
830       {
831          stream << impl.integerValue;
832          break;
833       }
834       case Dali::Property::UNSIGNED_INTEGER:
835       {
836         stream << impl.unsignedIntegerValue;
837         break;
838       }
839       case Dali::Property::VECTOR2:
840       {
841         stream << *impl.vector2Value;
842         break;
843       }
844       case Dali::Property::VECTOR3:
845       {
846         stream << *impl.vector3Value;
847         break;
848       }
849       case Dali::Property::VECTOR4:
850       {
851         stream << *impl.vector4Value;
852         break;
853       }
854       case Dali::Property::MATRIX3:
855       {
856         stream << *impl.matrix3Value;
857         break;
858       }
859       case Dali::Property::MATRIX:
860       {
861         stream << *impl.matrixValue;
862         break;
863       }
864       case Dali::Property::RECTANGLE:
865       {
866         stream << *impl.rectValue;
867         break;
868       }
869       case Dali::Property::ROTATION:
870       {
871         stream << *impl.quaternionValue;
872         break;
873       }
874       case Dali::Property::STRING:
875       {
876         stream << *impl.stringValue;
877         break;
878       }
879       case Dali::Property::ARRAY:
880       {
881         stream << "Array containing" << impl.arrayValue->Count() << " elements"; // TODO add ostream<< operator in array
882         break;
883       }
884       case Dali::Property::MAP:
885       {
886         stream << "Map containing " << impl.mapValue->Count() << " elements"; // TODO add ostream<< operator in map
887         break;
888       }
889       case Dali::Property::NONE:
890       {
891         stream << "undefined type";
892         break;
893       }
894     }
895   }
896   else
897   {
898     stream << "empty type";
899   }
900   return stream;
901 }
902
903
904 } // namespace Dali