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