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