2 * Copyright (c) 2020 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <dali/public-api/object/property-value.h>
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>
46 * Helper to check if the property value can be read as int/bool
48 inline bool IsIntegerType( Property::Type type )
50 return ( Property::BOOLEAN == type )||( Property::INTEGER == type );
54 struct Property::Value::Impl
56 Impl( bool booleanValue )
57 : type( Property::BOOLEAN ),
58 integerValue( booleanValue )
61 Impl( float floatValue )
62 : type( Property::FLOAT ),
63 floatValue( floatValue )
66 Impl( int32_t integerValue )
67 : type( Property::INTEGER ),
68 integerValue( integerValue )
71 Impl( const Vector2& vectorValue )
72 : type( Property::VECTOR2 ),
73 vector2Value( new Vector2( vectorValue ) )
76 Impl( const Vector3& vectorValue )
77 : type( Property::VECTOR3 ),
78 vector3Value( new Vector3( vectorValue ) )
81 Impl( const Vector4& vectorValue )
82 : type( Property::VECTOR4 ),
83 vector4Value( new Vector4( vectorValue ) )
86 Impl( const Matrix3& matrixValue )
87 : type( Property::MATRIX3 ),
88 matrix3Value( new Matrix3( matrixValue ) )
92 Impl( const Matrix& matrixValue )
93 : type( Property::MATRIX ),
94 matrixValue( new Matrix( matrixValue ) )
98 Impl( const AngleAxis& angleAxisValue )
99 : type( Property::ROTATION ),
100 angleAxisValue( new AngleAxis(angleAxisValue) )
104 Impl( const Quaternion& quaternionValue )
105 : type( Property::ROTATION ),
106 angleAxisValue( new AngleAxis() )
108 quaternionValue.ToAxisAngle( angleAxisValue->axis, angleAxisValue->angle );
111 Impl( const std::string& stringValue )
112 : type( Property::STRING ),
113 stringValue( new std::string( stringValue ) )
117 Impl( const Rect<int32_t>& rectValue )
118 : type( Property::RECTANGLE ),
119 rectValue( new Rect<int>( rectValue ) )
123 Impl( const Rect<float>& rectValue )
124 : type( Property::VECTOR4 ),
125 vector4Value( new Vector4( rectValue.x, rectValue.y, rectValue.width, rectValue.height ) )
129 Impl( const Property::Array& arrayValue )
130 : type( Property::ARRAY ),
131 arrayValue( new Property::Array( arrayValue ) )
135 Impl( Property::Array&& arrayValue )
136 : type( Property::ARRAY ),
137 arrayValue( new Property::Array( std::move( arrayValue ) ) )
141 Impl( const Property::Map& mapValue )
142 : type( Property::MAP ),
143 mapValue( new Property::Map( mapValue ) )
147 Impl( Property::Map&& mapValue )
148 : type( Property::MAP ),
149 mapValue( new Property::Map( std::move( mapValue ) ) )
153 Impl( const Extents& extentsValue )
154 : type( Property::EXTENTS ),
155 extentsValue( new Extents( extentsValue ) )
159 Impl( const std::initializer_list< KeyValuePair >& values )
160 : type( Property::MAP ),
161 mapValue( new Property::Map( values ) )
166 * Destructor, takes care of releasing the dynamically allocated types
172 case Property::NONE : // FALLTHROUGH
173 case Property::BOOLEAN : // FALLTHROUGH
174 case Property::FLOAT : // FALLTHROUGH
175 case Property::INTEGER :
177 break; // nothing to do
179 case Property::VECTOR2 :
184 case Property::VECTOR3:
189 case Property::VECTOR4:
194 case Property::MATRIX3:
199 case Property::MATRIX:
204 case Property::RECTANGLE:
209 case Property::ROTATION:
211 delete angleAxisValue;
214 case Property::STRING:
219 case Property::ARRAY:
229 case Property::EXTENTS:
242 int32_t integerValue;
244 // must use pointers for any class value pre c++ 11
245 Vector2* vector2Value;
246 Vector3* vector3Value;
247 Vector4* vector4Value;
248 Matrix3* matrix3Value;
250 AngleAxis* angleAxisValue;
251 std::string* stringValue;
252 Rect<int32_t>* rectValue;
253 Property::Array* arrayValue;
254 Property::Map* mapValue;
255 Extents* extentsValue;
261 Impl( const Impl& ) = delete;
262 Impl& operator=( const Impl& ) = delete;
266 Property::Value::Value()
271 Property::Value::Value( bool booleanValue )
272 : mImpl( new Impl( booleanValue ) )
276 Property::Value::Value( float floatValue )
277 : mImpl( new Impl( floatValue ) )
281 Property::Value::Value( int32_t integerValue )
282 : mImpl( new Impl( integerValue ) )
286 Property::Value::Value( const Vector2& vectorValue )
287 : mImpl( new Impl( vectorValue ) )
291 Property::Value::Value( const Vector3& vectorValue )
292 : mImpl( new Impl( vectorValue ) )
296 Property::Value::Value( const Vector4& vectorValue )
297 : mImpl( new Impl( vectorValue ) )
301 Property::Value::Value( const Matrix3& matrixValue )
302 : mImpl( new Impl( matrixValue ) )
306 Property::Value::Value( const Matrix& matrixValue )
307 : mImpl( new Impl( matrixValue ) )
311 Property::Value::Value( const Rect<int32_t>& rectValue )
312 : mImpl( new Impl( rectValue ) )
316 Property::Value::Value( const Rect<float>& rectValue )
317 : mImpl( new Impl( rectValue ) )
321 Property::Value::Value( const AngleAxis& angleAxisValue )
322 : mImpl( new Impl( angleAxisValue ) )
326 Property::Value::Value( const Quaternion& quaternionValue )
327 : mImpl( new Impl( quaternionValue ) )
331 Property::Value::Value( const std::string& stringValue )
332 : mImpl( new Impl( stringValue ) )
336 Property::Value::Value( const char* stringValue )
339 if( stringValue ) // string constructor is undefined with nullptr
341 mImpl = new Impl( std::string(stringValue) );
345 mImpl = new Impl( std::string() );
349 Property::Value::Value( Property::Array& arrayValue )
350 : mImpl( new Impl( arrayValue ) )
354 Property::Value::Value( Property::Array&& arrayValue )
355 : mImpl( new Impl( std::move( arrayValue ) ) )
359 Property::Value::Value( Property::Map& mapValue )
360 : mImpl( new Impl( mapValue ) )
364 Property::Value::Value( Property::Map&& mapValue )
365 : mImpl( new Impl( std::move( mapValue ) ) )
369 Property::Value::Value( const Extents& extentsValue )
370 : mImpl( new Impl( extentsValue ) )
374 Property::Value::Value( const std::initializer_list< KeyValuePair >& values )
375 : mImpl( new Impl( values ) )
379 Property::Value::Value( Type type )
384 case Property::BOOLEAN:
386 mImpl = new Impl( false );
389 case Property::FLOAT:
391 mImpl = new Impl( 0.f );
394 case Property::INTEGER:
396 mImpl = new Impl( 0 );
399 case Property::VECTOR2:
401 mImpl = new Impl( Vector2::ZERO );
404 case Property::VECTOR3:
406 mImpl = new Impl( Vector3::ZERO );
409 case Property::VECTOR4:
411 mImpl = new Impl( Vector4::ZERO );
414 case Property::RECTANGLE:
416 mImpl = new Impl( Rect<int32_t>(0,0,0,0) );
419 case Property::ROTATION:
421 mImpl = new Impl( AngleAxis() );
424 case Property::STRING:
426 mImpl = new Impl( std::string() );
429 case Property::MATRIX:
431 mImpl = new Impl( Matrix() );
434 case Property::MATRIX3:
436 mImpl = new Impl( Matrix3() );
439 case Property::ARRAY:
441 mImpl = new Impl( Property::Array() );
446 mImpl = new Impl( Property::Map() );
449 case Property::EXTENTS:
451 mImpl = new Impl( Extents() );
456 // No need to create an Impl
462 Property::Value::Value( const Property::Value& value )
465 // reuse assignment operator
469 Property::Value::Value( Property::Value&& value )
470 : mImpl( value.mImpl )
472 value.mImpl = nullptr;
475 Property::Value& Property::Value::operator=( const Property::Value& value )
477 if ( this == &value )
479 // skip self assignment
482 // if we are assigned an empty value, just drop impl
489 // first check if the type is the same, no need to change impl, just assign
490 if( mImpl && ( mImpl->type == value.mImpl->type ) )
492 switch( mImpl->type )
494 case Property::BOOLEAN:
496 mImpl->integerValue = value.mImpl->integerValue;
499 case Property::FLOAT:
501 mImpl->floatValue = value.mImpl->floatValue;
504 case Property::INTEGER:
506 mImpl->integerValue = value.mImpl->integerValue;
509 case Property::VECTOR2:
511 *mImpl->vector2Value = *value.mImpl->vector2Value; // type cannot change in mImpl so vector is allocated
514 case Property::VECTOR3:
516 *mImpl->vector3Value = *value.mImpl->vector3Value; // type cannot change in mImpl so vector is allocated
519 case Property::VECTOR4:
521 *mImpl->vector4Value = *value.mImpl->vector4Value; // type cannot change in mImpl so vector is allocated
524 case Property::RECTANGLE:
526 *mImpl->rectValue = *value.mImpl->rectValue; // type cannot change in mImpl so rect is allocated
529 case Property::ROTATION:
531 *mImpl->angleAxisValue = *value.mImpl->angleAxisValue; // type cannot change in mImpl so quaternion is allocated
534 case Property::STRING:
536 *mImpl->stringValue = *value.mImpl->stringValue; // type cannot change in mImpl so string is allocated
539 case Property::MATRIX:
541 *mImpl->matrixValue = *value.mImpl->matrixValue; // type cannot change in mImpl so matrix is allocated
544 case Property::MATRIX3:
546 *mImpl->matrix3Value = *value.mImpl->matrix3Value; // type cannot change in mImpl so matrix is allocated
549 case Property::ARRAY:
551 *mImpl->arrayValue = *value.mImpl->arrayValue; // type cannot change in mImpl so array is allocated
556 *mImpl->mapValue = *value.mImpl->mapValue; // type cannot change in mImpl so map is allocated
559 case Property::EXTENTS:
561 *mImpl->extentsValue = *value.mImpl->extentsValue; // type cannot change in mImpl so extents is allocated
565 { // mImpl will be a nullptr, there's no way to get to this case
571 // different type, release old impl and create new
572 Impl* newImpl( nullptr );
573 switch ( value.mImpl->type )
575 case Property::BOOLEAN:
577 newImpl = new Impl( bool( value.mImpl->integerValue ) );
580 case Property::FLOAT:
582 newImpl = new Impl( value.mImpl->floatValue );
585 case Property::INTEGER:
587 newImpl = new Impl( value.mImpl->integerValue );
590 case Property::VECTOR2:
592 newImpl = new Impl( *value.mImpl->vector2Value ); // type cannot change in mImpl so vector is allocated
595 case Property::VECTOR3:
597 newImpl = new Impl( *value.mImpl->vector3Value ); // type cannot change in mImpl so vector is allocated
600 case Property::VECTOR4:
602 newImpl = new Impl( *value.mImpl->vector4Value ); // type cannot change in mImpl so vector is allocated
605 case Property::RECTANGLE:
607 newImpl = new Impl( *value.mImpl->rectValue ); // type cannot change in mImpl so rect is allocated
610 case Property::ROTATION:
612 newImpl = new Impl( *value.mImpl->angleAxisValue ); // type cannot change in mImpl so quaternion is allocated
615 case Property::MATRIX3:
617 newImpl = new Impl( *value.mImpl->matrix3Value ); // type cannot change in mImpl so matrix is allocated
620 case Property::MATRIX:
622 newImpl = new Impl( *value.mImpl->matrixValue ); // type cannot change in mImpl so matrix is allocated
625 case Property::STRING:
627 newImpl = new Impl( *value.mImpl->stringValue ); // type cannot change in mImpl so string is allocated
630 case Property::ARRAY:
632 newImpl = new Impl( *value.mImpl->arrayValue ); // type cannot change in mImpl so array is allocated
637 newImpl = new Impl( *value.mImpl->mapValue ); // type cannot change in mImpl so map is allocated
640 case Property::EXTENTS:
642 newImpl = new Impl( *value.mImpl->extentsValue ); // type cannot change in mImpl so extents is allocated
646 { // nullptr value will be used for "empty" value
656 Property::Value& Property::Value::operator=( Property::Value&& value )
662 value.mImpl = nullptr;
668 Property::Value::~Value()
673 Property::Type Property::Value::GetType() const
675 Property::Type type( Property::NONE );
683 bool Property::Value::Get( bool& booleanValue ) const
685 bool converted = false;
686 if( mImpl && IsIntegerType( mImpl->type ) )
688 booleanValue = mImpl->integerValue;
694 bool Property::Value::Get( float& floatValue ) const
696 bool converted = false;
699 if( mImpl->type == FLOAT )
701 floatValue = mImpl->floatValue;
704 else if( IsIntegerType( mImpl->type ) )
706 floatValue = static_cast< float >( mImpl->integerValue );
713 bool Property::Value::Get( int32_t& integerValue ) const
715 bool converted = false;
718 if( IsIntegerType( mImpl->type ) )
720 integerValue = mImpl->integerValue;
723 else if( mImpl->type == FLOAT )
725 integerValue = static_cast< int32_t >( mImpl->floatValue );
732 bool Property::Value::Get( Vector2& vectorValue ) const
734 bool converted = false;
737 // type cannot change in mImpl so vector is allocated
738 if( mImpl->type == VECTOR2 || mImpl->type == VECTOR3 || mImpl->type == VECTOR4 )
740 vectorValue = *(mImpl->vector2Value); // if Vector3 or 4 only x and y are assigned
747 bool Property::Value::Get( Vector3& vectorValue ) const
749 bool converted = false;
752 // type cannot change in mImpl so vector is allocated
753 if ( mImpl->type == VECTOR3 || mImpl->type == VECTOR4 )
755 vectorValue = *(mImpl->vector3Value); // if Vector4 only x,y,z are assigned
758 else if( mImpl->type == VECTOR2 )
760 vectorValue = *(mImpl->vector2Value);
767 bool Property::Value::Get( Vector4& vectorValue ) const
769 bool converted = false;
772 if( mImpl->type == VECTOR4 ) // type cannot change in mImpl so vector is allocated
774 vectorValue = *(mImpl->vector4Value);
777 else if( mImpl->type == VECTOR2 )
779 vectorValue = *(mImpl->vector2Value);
782 else if( mImpl->type == VECTOR3 )
784 vectorValue = *(mImpl->vector3Value);
791 bool Property::Value::Get( Matrix3& matrixValue ) const
793 bool converted = false;
794 if( mImpl && (mImpl->type == MATRIX3) ) // type cannot change in mImpl so matrix is allocated
796 matrixValue = *(mImpl->matrix3Value);
802 bool Property::Value::Get( Matrix& matrixValue ) const
804 bool converted = false;
805 if( mImpl && (mImpl->type == MATRIX) ) // type cannot change in mImpl so matrix is allocated
807 matrixValue = *(mImpl->matrixValue);
813 bool Property::Value::Get( Rect<int32_t>& rectValue ) const
815 bool converted = false;
816 if( mImpl && (mImpl->type == RECTANGLE) ) // type cannot change in mImpl so rect is allocated
818 rectValue = *(mImpl->rectValue);
824 bool Property::Value::Get( AngleAxis& angleAxisValue ) const
826 bool converted = false;
827 if( mImpl && (mImpl->type == ROTATION) ) // type cannot change in mImpl so angleAxis is allocated
829 angleAxisValue = *(mImpl->angleAxisValue);
835 bool Property::Value::Get( Quaternion& quaternionValue ) const
837 bool converted = false;
838 if( mImpl && (mImpl->type == ROTATION) ) // type cannot change in mImpl so angleAxis is allocated
840 quaternionValue = Quaternion(mImpl->angleAxisValue->angle, mImpl->angleAxisValue->axis );
846 bool Property::Value::Get( std::string& stringValue ) const
848 bool converted = false;
849 if( mImpl && (mImpl->type == STRING) ) // type cannot change in mImpl so string is allocated
851 stringValue.assign( *(mImpl->stringValue) );
857 bool Property::Value::Get( Property::Array& arrayValue ) const
859 bool converted = false;
860 if( mImpl && (mImpl->type == ARRAY) ) // type cannot change in mImpl so array is allocated
862 arrayValue = *(mImpl->arrayValue);
868 bool Property::Value::Get( Property::Map& mapValue ) const
870 bool converted = false;
871 if( mImpl && (mImpl->type == MAP) ) // type cannot change in mImpl so map is allocated
873 mapValue = *(mImpl->mapValue);
879 Property::Array* Property::Value::GetArray() const
881 Property::Array* array = nullptr;
882 if( mImpl && (mImpl->type == ARRAY) ) // type cannot change in mImpl so array is allocated
884 array = mImpl->arrayValue;
889 Property::Map* Property::Value::GetMap() const
891 Property::Map* map = nullptr;
892 if( mImpl && (mImpl->type == MAP) ) // type cannot change in mImpl so map is allocated
894 map = mImpl->mapValue;
899 bool Property::Value::Get( Extents& extentsValue ) const
901 bool converted = false;
904 if( mImpl->type == EXTENTS )
906 extentsValue = *(mImpl->extentsValue);
909 else if( mImpl->type == VECTOR4 )
911 extentsValue.start = static_cast< uint16_t >( mImpl->vector4Value->x );
912 extentsValue.end = static_cast< uint16_t >( mImpl->vector4Value->y );
913 extentsValue.top = static_cast< uint16_t >( mImpl->vector4Value->z );
914 extentsValue.bottom = static_cast< uint16_t >( mImpl->vector4Value->w );
921 std::ostream& operator<<( std::ostream& stream, const Property::Value& value )
925 const Property::Value::Impl& impl( *value.mImpl );
929 case Dali::Property::BOOLEAN:
931 stream << impl.integerValue;
934 case Dali::Property::FLOAT:
936 stream << impl.floatValue;
939 case Dali::Property::INTEGER:
941 stream << impl.integerValue;
944 case Dali::Property::VECTOR2:
946 stream << *impl.vector2Value;
949 case Dali::Property::VECTOR3:
951 stream << *impl.vector3Value;
954 case Dali::Property::VECTOR4:
956 stream << *impl.vector4Value;
959 case Dali::Property::MATRIX3:
961 stream << *impl.matrix3Value;
964 case Dali::Property::MATRIX:
966 stream << *impl.matrixValue;
969 case Dali::Property::RECTANGLE:
971 stream << *impl.rectValue;
974 case Dali::Property::ROTATION:
976 stream << *impl.angleAxisValue;
979 case Dali::Property::STRING:
981 stream << *impl.stringValue;
984 case Dali::Property::ARRAY:
986 stream << *(value.GetArray());
989 case Dali::Property::MAP:
991 stream << *(value.GetMap());
994 case Dali::Property::EXTENTS:
996 stream << *impl.extentsValue;
999 case Dali::Property::NONE:
1000 { // mImpl will be a nullptr, there's no way to get to this case
1006 stream << "undefined type";