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