/*
- * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
// CLASS HEADER
#include <dali/public-api/object/property-value.h>
+// EXTERNAL INCLUDES
+#include <ostream>
+
// INTERNAL INCLUDES
-#include <dali/public-api/object/any.h>
+#include <dali/public-api/common/extents.h>
#include <dali/public-api/math/angle-axis.h>
#include <dali/public-api/math/radian.h>
#include <dali/public-api/math/vector2.h>
#include <dali/public-api/math/rect.h>
#include <dali/public-api/math/quaternion.h>
#include <dali/public-api/object/property-map.h>
+#include <dali/public-api/object/property-array.h>
#include <dali/public-api/object/property-types.h>
#include <dali/integration-api/debug.h>
namespace Dali
{
+namespace
+{
+/**
+ * Helper to check if the property value can be read as int/bool
+ */
+inline bool IsIntegerType( Property::Type type )
+{
+ return ( Property::BOOLEAN == type )||( Property::INTEGER == type );
+}
+}
+
struct Property::Value::Impl
{
- Impl()
- : mType( Property::NONE )
- {
- }
+ Impl( bool booleanValue )
+ : type( Property::BOOLEAN ),
+ integerValue( booleanValue )
+ { }
+
+ Impl( float floatValue )
+ : type( Property::FLOAT ),
+ floatValue( floatValue )
+ { }
+
+ Impl( int32_t integerValue )
+ : type( Property::INTEGER ),
+ integerValue( integerValue )
+ { }
+
+ Impl( const Vector2& vectorValue )
+ : type( Property::VECTOR2 ),
+ vector2Value( new Vector2( vectorValue ) )
+ { }
- Impl(bool boolValue)
- : mType( PropertyTypes::Get<bool>() ),
- mValue( boolValue )
+ Impl( const Vector3& vectorValue )
+ : type( Property::VECTOR3 ),
+ vector3Value( new Vector3( vectorValue ) )
+ { }
+
+ Impl( const Vector4& vectorValue )
+ : type( Property::VECTOR4 ),
+ vector4Value( new Vector4( vectorValue ) )
+ { }
+
+ Impl( const Matrix3& matrixValue )
+ : type( Property::MATRIX3 ),
+ matrix3Value( new Matrix3( matrixValue ) )
{
}
- Impl(float floatValue)
- : mType( PropertyTypes::Get<float>() ),
- mValue( floatValue )
+ Impl( const Matrix& matrixValue )
+ : type( Property::MATRIX ),
+ matrixValue( new Matrix( matrixValue ) )
{
}
- Impl(int integerValue)
- : mType( PropertyTypes::Get<int>() ),
- mValue( integerValue )
+ Impl( const AngleAxis& angleAxisValue )
+ : type( Property::ROTATION ),
+ angleAxisValue( new AngleAxis(angleAxisValue) )
{
}
- Impl(unsigned int unsignedIntegerValue)
- : mType( PropertyTypes::Get<unsigned int>() ),
- mValue( unsignedIntegerValue )
+ Impl( const Quaternion& quaternionValue )
+ : type( Property::ROTATION ),
+ angleAxisValue( new AngleAxis() )
{
+ quaternionValue.ToAxisAngle( angleAxisValue->axis, angleAxisValue->angle );
}
- Impl(const Vector2& vectorValue)
- : mType( PropertyTypes::Get<Vector2>() ),
- mValue( vectorValue )
+ Impl( const std::string& stringValue )
+ : type( Property::STRING ),
+ stringValue( new std::string( stringValue ) )
{
}
- Impl(const Vector3& vectorValue)
- : mType( PropertyTypes::Get<Vector3>() ),
- mValue( vectorValue )
+ Impl( const Rect<int32_t>& rectValue )
+ : type( Property::RECTANGLE ),
+ rectValue( new Rect<int>( rectValue ) )
{
}
- Impl(const Vector4& vectorValue)
- : mType( PropertyTypes::Get<Vector4>() ),
- mValue( vectorValue )
+ Impl( const Rect<float>& rectValue )
+ : type( Property::VECTOR4 ),
+ vector4Value( new Vector4( rectValue.x, rectValue.y, rectValue.width, rectValue.height ) )
{
}
- Impl(const Matrix3& matrixValue)
- : mType(PropertyTypes::Get<Matrix3>()),
- mValue(matrixValue)
+ Impl( const Property::Array& arrayValue )
+ : type( Property::ARRAY ),
+ arrayValue( new Property::Array( arrayValue ) )
{
}
- Impl(const Matrix& matrixValue)
- : mType(PropertyTypes::Get<Matrix>()),
- mValue(matrixValue)
+ Impl( Property::Array&& arrayValue )
+ : type( Property::ARRAY ),
+ arrayValue( new Property::Array( std::move( arrayValue ) ) )
{
}
- Impl(const AngleAxis& angleAxisValue)
- : mType( PropertyTypes::Get<AngleAxis>() ),
- mValue( angleAxisValue )
+ Impl( const Property::Map& mapValue )
+ : type( Property::MAP ),
+ mapValue( new Property::Map( mapValue ) )
{
}
- Impl(const Quaternion& quaternionValue)
- : mType( PropertyTypes::Get<Quaternion>() ),
- mValue( quaternionValue )
+ Impl( Property::Map&& mapValue )
+ : type( Property::MAP ),
+ mapValue( new Property::Map( std::move( mapValue ) ) )
{
}
- Impl(const std::string& stringValue)
- : mType( PropertyTypes::Get<std::string>() ),
- mValue( stringValue )
+ Impl( const Extents& extentsValue )
+ : type( Property::EXTENTS ),
+ extentsValue( new Extents( extentsValue ) )
{
}
- Impl(const Rect<int>& rect)
- : mType( PropertyTypes::Get<Rect<int> >() ),
- mValue( rect )
+ Impl( const std::initializer_list< KeyValuePair >& values )
+ : type( Property::MAP ),
+ mapValue( new Property::Map( values ) )
{
}
- Impl(Property::Map container)
- : mType( PropertyTypes::Get<Property::Map >() ),
- mValue( container )
+ /**
+ * Destructor, takes care of releasing the dynamically allocated types
+ */
+ ~Impl()
{
+ switch( type )
+ {
+ case Property::NONE : // FALLTHROUGH
+ case Property::BOOLEAN : // FALLTHROUGH
+ case Property::FLOAT : // FALLTHROUGH
+ case Property::INTEGER :
+ {
+ break; // nothing to do
+ }
+ case Property::VECTOR2 :
+ {
+ delete vector2Value;
+ break;
+ }
+ case Property::VECTOR3:
+ {
+ delete vector3Value;
+ break;
+ }
+ case Property::VECTOR4:
+ {
+ delete vector4Value;
+ break;
+ }
+ case Property::MATRIX3:
+ {
+ delete matrix3Value;
+ break;
+ }
+ case Property::MATRIX:
+ {
+ delete matrixValue;
+ break;
+ }
+ case Property::RECTANGLE:
+ {
+ delete rectValue;
+ break;
+ }
+ case Property::ROTATION:
+ {
+ delete angleAxisValue;
+ break;
+ }
+ case Property::STRING:
+ {
+ delete stringValue;
+ break;
+ }
+ case Property::ARRAY:
+ {
+ delete arrayValue;
+ break;
+ }
+ case Property::MAP:
+ {
+ delete mapValue;
+ break;
+ }
+ case Property::EXTENTS:
+ {
+ delete extentsValue;
+ break;
+ }
+ }
}
- Impl(Property::Array container)
- : mType( PropertyTypes::Get<Property::Array >() ),
- mValue( container )
+public: // Data
+
+ Type type;
+ union
{
- }
+ int32_t integerValue;
+ float floatValue;
+ // must use pointers for any class value pre c++ 11
+ Vector2* vector2Value;
+ Vector3* vector3Value;
+ Vector4* vector4Value;
+ Matrix3* matrix3Value;
+ Matrix* matrixValue;
+ AngleAxis* angleAxisValue;
+ std::string* stringValue;
+ Rect<int32_t>* rectValue;
+ Property::Array* arrayValue;
+ Property::Map* mapValue;
+ Extents* extentsValue;
+ };
- Type mType;
+private:
+
+ // non-copyable
+ Impl( const Impl& ) = delete;
+ Impl& operator=( const Impl& ) = delete;
- typedef Any AnyValue;
- AnyValue mValue;
};
Property::Value::Value()
-: mImpl( NULL )
+: mImpl( nullptr )
+{
+}
+
+Property::Value::Value( bool booleanValue )
+: mImpl( new Impl( booleanValue ) )
+{
+}
+
+Property::Value::Value( float floatValue )
+: mImpl( new Impl( floatValue ) )
{
- mImpl = new Impl();
}
-Property::Value::Value(bool boolValue)
-: mImpl( NULL )
+Property::Value::Value( int32_t integerValue )
+: mImpl( new Impl( integerValue ) )
{
- mImpl = new Impl( boolValue );
}
-Property::Value::Value(float floatValue)
-: mImpl( NULL )
+Property::Value::Value( const Vector2& vectorValue )
+: mImpl( new Impl( vectorValue ) )
{
- mImpl = new Impl( floatValue );
}
-Property::Value::Value(int integerValue)
-: mImpl( NULL )
+Property::Value::Value( const Vector3& vectorValue )
+: mImpl( new Impl( vectorValue ) )
{
- mImpl = new Impl( integerValue );
}
-Property::Value::Value(unsigned int unsignedIntegerValue)
-: mImpl( NULL )
+Property::Value::Value( const Vector4& vectorValue )
+: mImpl( new Impl( vectorValue ) )
{
- mImpl = new Impl( unsignedIntegerValue );
}
-Property::Value::Value(const Vector2& vectorValue)
-: mImpl( NULL )
+Property::Value::Value( const Matrix3& matrixValue )
+: mImpl( new Impl( matrixValue ) )
{
- mImpl = new Impl( vectorValue );
}
-Property::Value::Value(const Vector3& vectorValue)
-: mImpl( NULL )
+Property::Value::Value( const Matrix& matrixValue )
+: mImpl( new Impl( matrixValue ) )
{
- mImpl = new Impl( vectorValue );
}
-Property::Value::Value(const Vector4& vectorValue)
-: mImpl( NULL )
+Property::Value::Value( const Rect<int32_t>& rectValue )
+: mImpl( new Impl( rectValue ) )
{
- mImpl = new Impl( vectorValue );
}
-Property::Value::Value(const Matrix3& matrixValue)
-: mImpl( NULL )
+Property::Value::Value( const Rect<float>& rectValue )
+: mImpl( new Impl( rectValue ) )
{
- mImpl = new Impl( matrixValue );
}
-Property::Value::Value(const Matrix& matrixValue)
-: mImpl( NULL )
+Property::Value::Value( const AngleAxis& angleAxisValue )
+: mImpl( new Impl( angleAxisValue ) )
{
- mImpl = new Impl( matrixValue );
}
-Property::Value::Value(const Rect<int>& rect)
-: mImpl( NULL )
+Property::Value::Value( const Quaternion& quaternionValue )
+: mImpl( new Impl( quaternionValue ) )
{
- mImpl = new Impl( rect );
}
-Property::Value::Value(const AngleAxis& angleAxisValue)
-: mImpl( NULL )
+Property::Value::Value( const std::string& stringValue )
+: mImpl( new Impl( stringValue ) )
{
- mImpl = new Impl( angleAxisValue );
}
-Property::Value::Value(const Quaternion& quaternionValue)
+Property::Value::Value( const char* stringValue )
+: mImpl( nullptr )
{
- mImpl = new Impl( quaternionValue );
+ if( stringValue ) // string constructor is undefined with nullptr
+ {
+ mImpl = new Impl( std::string(stringValue) );
+ }
+ else
+ {
+ mImpl = new Impl( std::string() );
+ }
}
-Property::Value::Value(const std::string& stringValue)
+Property::Value::Value( Property::Array& arrayValue )
+: mImpl( new Impl( arrayValue ) )
{
- mImpl = new Impl( stringValue );
}
-Property::Value::Value(const char *stringValue)
+Property::Value::Value( Property::Array&& arrayValue )
+: mImpl( new Impl( std::move( arrayValue ) ) )
{
- mImpl = new Impl( std::string(stringValue) );
}
-Property::Value::Value(Property::Array &arrayValue)
+Property::Value::Value( Property::Map& mapValue )
+: mImpl( new Impl( mapValue ) )
{
- mImpl = new Impl( arrayValue );
}
-Property::Value::Value(Property::Map &mapValue)
+Property::Value::Value( Property::Map&& mapValue )
+: mImpl( new Impl( std::move( mapValue ) ) )
{
- mImpl = new Impl( mapValue );
}
+Property::Value::Value( const Extents& extentsValue )
+: mImpl( new Impl( extentsValue ) )
+{
+}
-Property::Value::~Value()
+Property::Value::Value( const std::initializer_list< KeyValuePair >& values )
+: mImpl( new Impl( values ) )
{
- delete mImpl;
}
-Property::Value::Value(const Value& value)
+Property::Value::Value( Type type )
+: mImpl( nullptr )
{
- switch (value.GetType())
+ switch (type)
{
case Property::BOOLEAN:
{
- mImpl = new Impl( value.Get<bool>() );
+ mImpl = new Impl( false );
break;
}
-
case Property::FLOAT:
{
- mImpl = new Impl( value.Get<float>() );
+ mImpl = new Impl( 0.f );
break;
}
-
case Property::INTEGER:
{
- mImpl = new Impl( value.Get<int>() );
- break;
- }
-
- case Property::UNSIGNED_INTEGER:
- {
- mImpl = new Impl( value.Get<unsigned int>() );
+ mImpl = new Impl( 0 );
break;
}
-
case Property::VECTOR2:
{
- mImpl = new Impl( value.Get<Vector2>() );
+ mImpl = new Impl( Vector2::ZERO );
break;
}
-
case Property::VECTOR3:
{
- mImpl = new Impl( value.Get<Vector3>() );
+ mImpl = new Impl( Vector3::ZERO );
break;
}
-
case Property::VECTOR4:
{
- mImpl = new Impl( value.Get<Vector4>() );
+ mImpl = new Impl( Vector4::ZERO );
break;
}
-
case Property::RECTANGLE:
{
- mImpl = new Impl( value.Get<Rect<int> >() );
+ mImpl = new Impl( Rect<int32_t>(0,0,0,0) );
break;
}
-
case Property::ROTATION:
{
- mImpl = new Impl( value.Get<Quaternion>() );
+ mImpl = new Impl( AngleAxis() );
break;
}
-
- case Property::MATRIX3:
+ case Property::STRING:
{
- mImpl = new Impl( value.Get<Matrix3>());
+ mImpl = new Impl( std::string() );
break;
}
-
case Property::MATRIX:
{
- mImpl = new Impl( value.Get<Matrix>());
+ mImpl = new Impl( Matrix() );
break;
}
-
- case Property::STRING:
+ case Property::MATRIX3:
{
- mImpl = new Impl( value.Get<std::string>() );
+ mImpl = new Impl( Matrix3() );
+ break;
+ }
+ case Property::ARRAY:
+ {
+ mImpl = new Impl( Property::Array() );
break;
}
-
case Property::MAP:
{
- mImpl = new Impl( value.Get<Property::Map>() );
+ mImpl = new Impl( Property::Map() );
break;
}
-
- case Property::ARRAY:
+ case Property::EXTENTS:
{
- mImpl = new Impl( value.Get<Property::Array>() );
+ mImpl = new Impl( Extents() );
break;
}
-
- case Property::NONE: // fall
- default:
+ case Property::NONE:
{
- mImpl = new Impl();
+ // No need to create an Impl
break;
}
}
}
-Property::Value::Value(Type type)
+Property::Value::Value( const Property::Value& value )
+: mImpl( nullptr )
{
- switch (type)
+ // reuse assignment operator
+ operator=( value );
+}
+
+Property::Value::Value( Property::Value&& value )
+: mImpl( value.mImpl )
+{
+ value.mImpl = nullptr;
+}
+
+Property::Value& Property::Value::operator=( const Property::Value& value )
+{
+ if ( this == &value )
{
- case Property::BOOLEAN:
+ // skip self assignment
+ return *this;
+ }
+ // if we are assigned an empty value, just drop impl
+ if( !value.mImpl )
+ {
+ delete mImpl;
+ mImpl = nullptr;
+ return *this;
+ }
+ // first check if the type is the same, no need to change impl, just assign
+ if( mImpl && ( mImpl->type == value.mImpl->type ) )
+ {
+ switch( mImpl->type )
{
- mImpl = new Impl( false );
- break;
+ case Property::BOOLEAN:
+ {
+ mImpl->integerValue = value.mImpl->integerValue;
+ break;
+ }
+ case Property::FLOAT:
+ {
+ mImpl->floatValue = value.mImpl->floatValue;
+ break;
+ }
+ case Property::INTEGER:
+ {
+ mImpl->integerValue = value.mImpl->integerValue;
+ break;
+ }
+ case Property::VECTOR2:
+ {
+ *mImpl->vector2Value = *value.mImpl->vector2Value; // type cannot change in mImpl so vector is allocated
+ break;
+ }
+ case Property::VECTOR3:
+ {
+ *mImpl->vector3Value = *value.mImpl->vector3Value; // type cannot change in mImpl so vector is allocated
+ break;
+ }
+ case Property::VECTOR4:
+ {
+ *mImpl->vector4Value = *value.mImpl->vector4Value; // type cannot change in mImpl so vector is allocated
+ break;
+ }
+ case Property::RECTANGLE:
+ {
+ *mImpl->rectValue = *value.mImpl->rectValue; // type cannot change in mImpl so rect is allocated
+ break;
+ }
+ case Property::ROTATION:
+ {
+ *mImpl->angleAxisValue = *value.mImpl->angleAxisValue; // type cannot change in mImpl so quaternion is allocated
+ break;
+ }
+ case Property::STRING:
+ {
+ *mImpl->stringValue = *value.mImpl->stringValue; // type cannot change in mImpl so string is allocated
+ break;
+ }
+ case Property::MATRIX:
+ {
+ *mImpl->matrixValue = *value.mImpl->matrixValue; // type cannot change in mImpl so matrix is allocated
+ break;
+ }
+ case Property::MATRIX3:
+ {
+ *mImpl->matrix3Value = *value.mImpl->matrix3Value; // type cannot change in mImpl so matrix is allocated
+ break;
+ }
+ case Property::ARRAY:
+ {
+ *mImpl->arrayValue = *value.mImpl->arrayValue; // type cannot change in mImpl so array is allocated
+ break;
+ }
+ case Property::MAP:
+ {
+ *mImpl->mapValue = *value.mImpl->mapValue; // type cannot change in mImpl so map is allocated
+ break;
+ }
+ case Property::EXTENTS:
+ {
+ *mImpl->extentsValue = *value.mImpl->extentsValue; // type cannot change in mImpl so extents is allocated
+ break;
+ }
+ case Property::NONE:
+ { // mImpl will be a nullptr, there's no way to get to this case
+ }
}
-
- case Property::FLOAT:
+ }
+ else
+ {
+ // different type, release old impl and create new
+ Impl* newImpl( nullptr );
+ switch ( value.mImpl->type )
{
- mImpl = new Impl( 0.f );
- break;
+ case Property::BOOLEAN:
+ {
+ newImpl = new Impl( bool( value.mImpl->integerValue ) );
+ break;
+ }
+ case Property::FLOAT:
+ {
+ newImpl = new Impl( value.mImpl->floatValue );
+ break;
+ }
+ case Property::INTEGER:
+ {
+ newImpl = new Impl( value.mImpl->integerValue );
+ break;
+ }
+ case Property::VECTOR2:
+ {
+ newImpl = new Impl( *value.mImpl->vector2Value ); // type cannot change in mImpl so vector is allocated
+ break;
+ }
+ case Property::VECTOR3:
+ {
+ newImpl = new Impl( *value.mImpl->vector3Value ); // type cannot change in mImpl so vector is allocated
+ break;
+ }
+ case Property::VECTOR4:
+ {
+ newImpl = new Impl( *value.mImpl->vector4Value ); // type cannot change in mImpl so vector is allocated
+ break;
+ }
+ case Property::RECTANGLE:
+ {
+ newImpl = new Impl( *value.mImpl->rectValue ); // type cannot change in mImpl so rect is allocated
+ break;
+ }
+ case Property::ROTATION:
+ {
+ newImpl = new Impl( *value.mImpl->angleAxisValue ); // type cannot change in mImpl so quaternion is allocated
+ break;
+ }
+ case Property::MATRIX3:
+ {
+ newImpl = new Impl( *value.mImpl->matrix3Value ); // type cannot change in mImpl so matrix is allocated
+ break;
+ }
+ case Property::MATRIX:
+ {
+ newImpl = new Impl( *value.mImpl->matrixValue ); // type cannot change in mImpl so matrix is allocated
+ break;
+ }
+ case Property::STRING:
+ {
+ newImpl = new Impl( *value.mImpl->stringValue ); // type cannot change in mImpl so string is allocated
+ break;
+ }
+ case Property::ARRAY:
+ {
+ newImpl = new Impl( *value.mImpl->arrayValue ); // type cannot change in mImpl so array is allocated
+ break;
+ }
+ case Property::MAP:
+ {
+ newImpl = new Impl( *value.mImpl->mapValue ); // type cannot change in mImpl so map is allocated
+ break;
+ }
+ case Property::EXTENTS:
+ {
+ newImpl = new Impl( *value.mImpl->extentsValue ); // type cannot change in mImpl so extents is allocated
+ break;
+ }
+ case Property::NONE:
+ { // nullptr value will be used for "empty" value
+ }
}
+ delete mImpl;
+ mImpl = newImpl;
+ }
- case Property::INTEGER:
+ return *this;
+}
+
+Property::Value& Property::Value::operator=( Property::Value&& value )
+{
+ if( this != &value )
+ {
+ delete mImpl;
+ mImpl = value.mImpl;
+ value.mImpl = nullptr;
+ }
+
+ return *this;
+}
+
+Property::Value::~Value()
+{
+ delete mImpl;
+}
+
+Property::Type Property::Value::GetType() const
+{
+ Property::Type type( Property::NONE );
+ if( mImpl )
+ {
+ type = mImpl->type;
+ }
+ return type;
+}
+
+bool Property::Value::Get( bool& booleanValue ) const
+{
+ bool converted = false;
+ if( mImpl && IsIntegerType( mImpl->type ) )
+ {
+ booleanValue = mImpl->integerValue;
+ converted = true;
+ }
+ return converted;
+}
+
+bool Property::Value::Get( float& floatValue ) const
+{
+ bool converted = false;
+ if( mImpl )
+ {
+ if( mImpl->type == FLOAT )
{
- mImpl = new Impl( 0 );
- break;
+ floatValue = mImpl->floatValue;
+ converted = true;
}
-
- case Property::UNSIGNED_INTEGER:
+ else if( IsIntegerType( mImpl->type ) )
{
- mImpl = new Impl( 0U );
- break;
+ floatValue = static_cast< float >( mImpl->integerValue );
+ converted = true;
}
+ }
+ return converted;
+}
- case Property::VECTOR2:
+bool Property::Value::Get( int32_t& integerValue ) const
+{
+ bool converted = false;
+ if( mImpl )
+ {
+ if( IsIntegerType( mImpl->type ) )
{
- mImpl = new Impl( Vector2::ZERO );
- break;
+ integerValue = mImpl->integerValue;
+ converted = true;
}
-
- case Property::VECTOR3:
+ else if( mImpl->type == FLOAT )
{
- mImpl = new Impl( Vector3::ZERO );
- break;
+ integerValue = static_cast< int32_t >( mImpl->floatValue );
+ converted = true;
}
+ }
+ return converted;
+}
- case Property::VECTOR4:
+bool Property::Value::Get( Vector2& vectorValue ) const
+{
+ bool converted = false;
+ if( mImpl )
+ {
+ // type cannot change in mImpl so vector is allocated
+ if( mImpl->type == VECTOR2 || mImpl->type == VECTOR3 || mImpl->type == VECTOR4 )
{
- mImpl = new Impl( Vector4::ZERO );
- break;
+ vectorValue = *(mImpl->vector2Value); // if Vector3 or 4 only x and y are assigned
+ converted = true;
}
+ }
+ return converted;
+}
- case Property::RECTANGLE:
+bool Property::Value::Get( Vector3& vectorValue ) const
+{
+ bool converted = false;
+ if( mImpl )
+ {
+ // type cannot change in mImpl so vector is allocated
+ if ( mImpl->type == VECTOR3 || mImpl->type == VECTOR4 )
{
- mImpl = new Impl( Rect<int>(0,0,0,0) );
- break;
+ vectorValue = *(mImpl->vector3Value); // if Vector4 only x,y,z are assigned
+ converted = true;
}
-
- case Property::ROTATION:
+ else if( mImpl->type == VECTOR2 )
{
- mImpl = new Impl( Quaternion(0.f, Vector4::YAXIS) );
- break;
+ vectorValue = *(mImpl->vector2Value);
+ converted = true;
}
+ }
+ return converted;
+}
- case Property::STRING:
+bool Property::Value::Get( Vector4& vectorValue ) const
+{
+ bool converted = false;
+ if( mImpl )
+ {
+ if( mImpl->type == VECTOR4 ) // type cannot change in mImpl so vector is allocated
{
- mImpl = new Impl( std::string() );
- break;
+ vectorValue = *(mImpl->vector4Value);
+ converted = true;
}
-
- case Property::MAP:
+ else if( mImpl->type == VECTOR2 )
{
- mImpl = new Impl( Property::Map() );
- break;
+ vectorValue = *(mImpl->vector2Value);
+ converted = true;
}
-
- case Property::MATRIX:
+ else if( mImpl->type == VECTOR3 )
{
- mImpl = new Impl( Matrix() );
- break;
- }
-
- case Property::MATRIX3:
- {
- mImpl = new Impl( Matrix3() );
- break;
- }
-
- case Property::ARRAY:
- {
- mImpl = new Impl( Property::Array() );
- break;
- }
-
- case Property::NONE: // fall
- default:
- {
- mImpl = new Impl();
- break;
+ vectorValue = *(mImpl->vector3Value);
+ converted = true;
}
}
+ return converted;
}
-Property::Value& Property::Value::operator=(const Property::Value& value)
+bool Property::Value::Get( Matrix3& matrixValue ) const
{
- if (this == &value)
- {
- // skip self assignment
- return *this;
- }
-
- mImpl->mType = value.GetType();
-
- switch (mImpl->mType)
+ bool converted = false;
+ if( mImpl && (mImpl->type == MATRIX3) ) // type cannot change in mImpl so matrix is allocated
{
- case Property::BOOLEAN:
- {
- mImpl->mValue = value.Get<bool>();
- break;
- }
-
- case Property::FLOAT:
- {
- mImpl->mValue = value.Get<float>();
- break;
- }
-
- case Property::INTEGER:
- {
- mImpl->mValue = value.Get<int>();
- break;
- }
-
- case Property::UNSIGNED_INTEGER:
- {
- mImpl->mValue = value.Get<unsigned int>();
- break;
- }
-
- case Property::VECTOR2:
- {
- mImpl->mValue = value.Get<Vector2>();
- break;
- }
-
- case Property::VECTOR3:
- {
- mImpl->mValue = value.Get<Vector3>();
- break;
- }
-
- case Property::VECTOR4:
- {
- mImpl->mValue = value.Get<Vector4>();
- break;
- }
-
- case Property::RECTANGLE:
- {
- mImpl->mValue = value.Get<Rect<int> >();
- break;
- }
-
- case Property::ROTATION:
- {
- mImpl->mValue = value.Get<Quaternion>();
- break;
- }
-
- case Property::STRING:
- {
- mImpl->mValue = value.Get<std::string>();
- break;
- }
-
- case Property::MATRIX:
- {
- mImpl->mValue = value.Get<Matrix>();
- break;
- }
-
- case Property::MATRIX3:
- {
- mImpl->mValue = value.Get<Matrix3>();
- break;
- }
-
- case Property::MAP:
- {
- mImpl->mValue = value.Get<Property::Map>();
- break;
- }
-
- case Property::ARRAY:
- {
- mImpl->mValue = value.Get<Property::Array>();
- break;
- }
-
- case Property::NONE: // fall
- default:
- {
- mImpl->mValue = Impl::AnyValue(0);
- break;
- }
+ matrixValue = *(mImpl->matrix3Value);
+ converted = true;
}
-
- return *this;
-}
-
-Property::Type Property::Value::GetType() const
-{
- return mImpl->mType;
-}
-
-void Property::Value::Get(bool& boolValue) const
-{
- DALI_ASSERT_DEBUG( Property::BOOLEAN == GetType() && "Property type invalid" ); // AnyCast does asserted type checking
-
- boolValue = AnyCast<bool>(mImpl->mValue);
-}
-
-void Property::Value::Get(float& floatValue) const
-{
- DALI_ASSERT_DEBUG( Property::FLOAT == GetType() && "Property type invalid" );
-
- floatValue = AnyCast<float>(mImpl->mValue);
-}
-
-void Property::Value::Get(int& integerValue) const
-{
- DALI_ASSERT_DEBUG( Property::INTEGER == GetType() && "Property type invalid" );
-
- integerValue = AnyCast<int>(mImpl->mValue);
-}
-
-void Property::Value::Get(unsigned int& unsignedIntegerValue) const
-{
- DALI_ASSERT_DEBUG( Property::UNSIGNED_INTEGER == GetType() && "Property type invalid" );
-
- unsignedIntegerValue = AnyCast<unsigned int>(mImpl->mValue);
+ return converted;
}
-void Property::Value::Get(Vector2& vectorValue) const
+bool Property::Value::Get( Matrix& matrixValue ) const
{
- DALI_ASSERT_DEBUG( Property::VECTOR2 == GetType() && "Property type invalid" );
-
- vectorValue = AnyCast<Vector2>(mImpl->mValue);
-}
-
-void Property::Value::Get(Vector3& vectorValue) const
-{
- DALI_ASSERT_DEBUG( Property::VECTOR3 == GetType() && "Property type invalid" );
-
- vectorValue = AnyCast<Vector3>(mImpl->mValue);
-}
-
-void Property::Value::Get(Vector4& vectorValue) const
-{
- DALI_ASSERT_DEBUG( Property::VECTOR4 == GetType() && "Property type invalid" );
-
- vectorValue = AnyCast<Vector4>(mImpl->mValue);
-}
-
-void Property::Value::Get(Matrix3& matrixValue) const
-{
- DALI_ASSERT_DEBUG( Property::MATRIX3 == GetType() && "Property type invalid" );
- matrixValue = AnyCast<Matrix3>(mImpl->mValue);
-}
-
-void Property::Value::Get(Matrix& matrixValue) const
-{
- DALI_ASSERT_DEBUG( Property::MATRIX == GetType() && "Property type invalid" );
- matrixValue = AnyCast<Matrix>(mImpl->mValue);
+ bool converted = false;
+ if( mImpl && (mImpl->type == MATRIX) ) // type cannot change in mImpl so matrix is allocated
+ {
+ matrixValue = *(mImpl->matrixValue);
+ converted = true;
+ }
+ return converted;
}
-void Property::Value::Get(Rect<int>& rect) const
+bool Property::Value::Get( Rect<int32_t>& rectValue ) const
{
- DALI_ASSERT_DEBUG( Property::RECTANGLE == GetType() && "Property type invalid" );
-
- rect = AnyCast<Rect<int> >(mImpl->mValue);
+ bool converted = false;
+ if( mImpl && (mImpl->type == RECTANGLE) ) // type cannot change in mImpl so rect is allocated
+ {
+ rectValue = *(mImpl->rectValue);
+ converted = true;
+ }
+ return converted;
}
-void Property::Value::Get(AngleAxis& angleAxisValue) const
+bool Property::Value::Get( AngleAxis& angleAxisValue ) const
{
- DALI_ASSERT_ALWAYS( Property::ROTATION == GetType() && "Property type invalid" );
-
- // Orientations have two representations
- DALI_ASSERT_DEBUG( typeid(Quaternion) == mImpl->mValue.GetType() ||
- typeid(AngleAxis) == mImpl->mValue.GetType() );
-
- if ( typeid(Quaternion) == mImpl->mValue.GetType() )
- {
- Quaternion quaternion = AnyCast<Quaternion>(mImpl->mValue);
-
- Radian angleRadians(0.0f);
- quaternion.ToAxisAngle( angleAxisValue.axis, angleRadians );
- angleAxisValue.angle = angleRadians;
- }
- else
+ bool converted = false;
+ if( mImpl && (mImpl->type == ROTATION) ) // type cannot change in mImpl so angleAxis is allocated
{
- angleAxisValue = AnyCast<AngleAxis>(mImpl->mValue);
+ angleAxisValue = *(mImpl->angleAxisValue);
+ converted = true;
}
+ return converted;
}
-void Property::Value::Get(Quaternion& quaternionValue) const
+bool Property::Value::Get( Quaternion& quaternionValue ) const
{
- DALI_ASSERT_DEBUG( Property::ROTATION == GetType() && "Property type invalid" );
-
- // Orientations have two representations
- DALI_ASSERT_DEBUG( typeid(Quaternion) == mImpl->mValue.GetType() ||
- typeid(AngleAxis) == mImpl->mValue.GetType() );
-
- if ( typeid(Quaternion) == mImpl->mValue.GetType() )
- {
- quaternionValue = AnyCast<Quaternion>(mImpl->mValue);
- }
- else
+ bool converted = false;
+ if( mImpl && (mImpl->type == ROTATION) ) // type cannot change in mImpl so angleAxis is allocated
{
- AngleAxis angleAxis = AnyCast<AngleAxis>(mImpl->mValue);
-
- quaternionValue = Quaternion( Radian(angleAxis.angle), angleAxis.axis );
+ quaternionValue = Quaternion(mImpl->angleAxisValue->angle, mImpl->angleAxisValue->axis );
+ converted = true;
}
+ return converted;
}
-void Property::Value::Get(std::string &out) const
+bool Property::Value::Get( std::string& stringValue ) const
{
- DALI_ASSERT_DEBUG(Property::STRING == GetType() && "Property type invalid");
-
- out = AnyCast<std::string>(mImpl->mValue);
+ bool converted = false;
+ if( mImpl && (mImpl->type == STRING) ) // type cannot change in mImpl so string is allocated
+ {
+ stringValue.assign( *(mImpl->stringValue) );
+ converted = true;
+ }
+ return converted;
}
-void Property::Value::Get(Property::Array &out) const
+bool Property::Value::Get( Property::Array& arrayValue ) const
{
- DALI_ASSERT_DEBUG(Property::ARRAY == GetType() && "Property type invalid");
-
- out = AnyCast<Property::Array>(mImpl->mValue);
+ bool converted = false;
+ if( mImpl && (mImpl->type == ARRAY) ) // type cannot change in mImpl so array is allocated
+ {
+ arrayValue = *(mImpl->arrayValue);
+ converted = true;
+ }
+ return converted;
}
-void Property::Value::Get(Property::Map &out) const
+bool Property::Value::Get( Property::Map& mapValue ) const
{
- DALI_ASSERT_DEBUG(Property::MAP == GetType() && "Property type invalid");
-
- out = AnyCast<Property::Map>(mImpl->mValue);
+ bool converted = false;
+ if( mImpl && (mImpl->type == MAP) ) // type cannot change in mImpl so map is allocated
+ {
+ mapValue = *(mImpl->mapValue);
+ converted = true;
+ }
+ return converted;
}
-Property::Value& Property::Value::GetValue(const std::string& key) const
+Property::Array* Property::Value::GetArray() const
{
- DALI_ASSERT_DEBUG(Property::MAP == GetType() && "Property type invalid");
-
- Property::Map *container = AnyCast<Property::Map>(&(mImpl->mValue));
-
- DALI_ASSERT_DEBUG(container);
-
- if(container)
+ Property::Array* array = nullptr;
+ if( mImpl && (mImpl->type == ARRAY) ) // type cannot change in mImpl so array is allocated
{
- Property::Value* value = container->Find( key );
- if ( value )
- {
- return *value;
- }
+ array = mImpl->arrayValue;
}
-
- DALI_LOG_WARNING("Cannot find property map key %s", key.c_str());
- DALI_ASSERT_ALWAYS(!"Cannot find property map key");
+ return array;
}
-bool Property::Value::HasKey(const std::string& key) const
+Property::Map* Property::Value::GetMap() const
{
- bool has = false;
-
- if( Property::MAP == GetType() )
+ Property::Map* map = nullptr;
+ if( mImpl && (mImpl->type == MAP) ) // type cannot change in mImpl so map is allocated
{
- Property::Map *container = AnyCast<Property::Map>(&(mImpl->mValue));
-
- DALI_ASSERT_DEBUG(container && "Property::Map has no container?");
-
- if(container)
- {
- Property::Value* value = container->Find( key );
- if ( value )
- {
- has = true;
- }
- }
+ map = mImpl->mapValue;
}
-
- return has;
+ return map;
}
-
-const std::string& Property::Value::GetKey(const int index) const
+bool Property::Value::Get( Extents& extentsValue ) const
{
- switch( GetType() )
+ bool converted = false;
+ if( mImpl )
{
- case Property::MAP:
+ if( mImpl->type == EXTENTS )
{
- Property::Map *container = AnyCast<Property::Map>(&(mImpl->mValue));
- DALI_ASSERT_DEBUG(container && "Property::Map has no container?");
- if(container)
- {
- if(0 <= index && index < static_cast<int>(container->Count()))
- {
- return container->GetKey( index );
- }
- }
+ extentsValue = *(mImpl->extentsValue);
+ converted = true;
}
- break;
- case Property::NONE:
- case Property::ARRAY:
- case Property::BOOLEAN:
- case Property::FLOAT:
- case Property::UNSIGNED_INTEGER:
- case Property::INTEGER:
- case Property::VECTOR2:
- case Property::VECTOR3:
- case Property::VECTOR4:
- case Property::MATRIX:
- case Property::MATRIX3:
- case Property::RECTANGLE:
- case Property::ROTATION:
- case Property::STRING:
- case Property::TYPE_COUNT:
+ else if( mImpl->type == VECTOR4 )
{
- break;
+ extentsValue.start = static_cast< uint16_t >( mImpl->vector4Value->x );
+ extentsValue.end = static_cast< uint16_t >( mImpl->vector4Value->y );
+ extentsValue.top = static_cast< uint16_t >( mImpl->vector4Value->z );
+ extentsValue.bottom = static_cast< uint16_t >( mImpl->vector4Value->w );
+ converted = true;
}
}
-
-
- // should never return this
- static std::string null;
- return null;
+ return converted;
}
-
-void Property::Value::SetValue(const std::string& key, const Property::Value &value)
+std::ostream& operator<<( std::ostream& stream, const Property::Value& value )
{
- DALI_ASSERT_DEBUG(Property::MAP == GetType() && "Property type invalid");
-
- Property::Map *container = AnyCast<Property::Map>(&(mImpl->mValue));
-
- if(container)
+ if( value.mImpl )
{
- (*container)[ key ] = value;
- }
-}
+ const Property::Value::Impl& impl( *value.mImpl );
-Property::Value& Property::Value::GetItem(const int index) const
-{
- switch( GetType() )
- {
- case Property::MAP:
+ switch( impl.type )
{
- Property::Map *container = AnyCast<Property::Map>(&(mImpl->mValue));
-
- DALI_ASSERT_DEBUG(container && "Property::Map has no container?");
- if(container)
+ case Dali::Property::BOOLEAN:
{
- DALI_ASSERT_ALWAYS(index < static_cast<int>(container->Count()) && "Property array index invalid");
- DALI_ASSERT_ALWAYS(index >= 0 && "Property array index invalid");
-
- return container->GetValue( index );
+ stream << impl.integerValue;
+ break;
}
- }
- break;
-
- case Property::ARRAY:
- {
- int i = 0;
- Property::Array *container = AnyCast<Property::Array>(&(mImpl->mValue));
-
- DALI_ASSERT_DEBUG(container && "Property::Map has no container?");
- if(container)
+ case Dali::Property::FLOAT:
{
- DALI_ASSERT_ALWAYS(index < static_cast<int>(container->size()) && "Property array index invalid");
- DALI_ASSERT_ALWAYS(index >= 0 && "Property array index invalid");
-
- for(Property::Array::iterator iter = container->begin(); iter != container->end(); ++iter)
- {
- if(i++ == index)
- {
- return *iter;
- }
- }
+ stream << impl.floatValue;
+ break;
}
- }
- break;
-
- case Property::NONE:
- case Property::BOOLEAN:
- case Property::FLOAT:
- case Property::INTEGER:
- case Property::UNSIGNED_INTEGER:
- case Property::VECTOR2:
- case Property::VECTOR3:
- case Property::VECTOR4:
- case Property::MATRIX3:
- case Property::MATRIX:
- case Property::RECTANGLE:
- case Property::ROTATION:
- case Property::STRING:
- case Property::TYPE_COUNT:
- {
- DALI_ASSERT_ALWAYS(!"Cannot GetItem on property Type; not a container");
- break;
- }
-
- } // switch GetType()
-
-
- DALI_ASSERT_ALWAYS(!"Property value index not valid");
-}
-
-Property::Value& Property::Value::GetItem(const int index, std::string& key) const
-{
- Property::Value& ret( GetItem(index) );
-
- if( Property::MAP == GetType() )
- {
- Property::Map *container = AnyCast<Property::Map>(&(mImpl->mValue));
- if( index < static_cast<int>(container->Count()) )
- {
- key = container->GetKey( index );
- }
- }
-
- return ret;
-}
-
-void Property::Value::SetItem(const int index, const Property::Value &value)
-{
- switch( GetType() )
- {
- case Property::MAP:
- {
- Property::Map *container = AnyCast<Property::Map>(&(mImpl->mValue));
- if( container && index < static_cast<int>(container->Count()) )
+ case Dali::Property::INTEGER:
{
- Property::Value& indexValue = container->GetValue( index );
- indexValue = value;
+ stream << impl.integerValue;
+ break;
}
- }
- break;
-
- case Property::ARRAY:
- {
- Property::Array *container = AnyCast<Property::Array>(&(mImpl->mValue));
- if( container && index < static_cast<int>(container->size()) )
+ case Dali::Property::VECTOR2:
{
- (*container)[index] = value;
+ stream << *impl.vector2Value;
+ break;
}
- }
- break;
-
- case Property::NONE:
- case Property::BOOLEAN:
- case Property::FLOAT:
- case Property::INTEGER:
- case Property::UNSIGNED_INTEGER:
- case Property::VECTOR2:
- case Property::VECTOR3:
- case Property::VECTOR4:
- case Property::MATRIX3:
- case Property::MATRIX:
- case Property::RECTANGLE:
- case Property::ROTATION:
- case Property::STRING:
- case Property::TYPE_COUNT:
- {
- DALI_ASSERT_ALWAYS(!"Cannot SetItem on property Type; not a container");
- break;
- }
- }
-}
-
-int Property::Value::AppendItem(const Property::Value &value)
-{
- DALI_ASSERT_DEBUG(Property::ARRAY == GetType() && "Property type invalid");
-
- Property::Array *container = AnyCast<Property::Array>(&(mImpl->mValue));
-
- if(container)
- {
- container->push_back(value);
- return container->size() - 1;
- }
- else
- {
- return -1;
- }
-
-}
-
-int Property::Value::GetSize() const
-{
- int ret = 0;
-
- switch(GetType())
- {
- case Property::MAP:
- {
- Property::Map *container = AnyCast<Property::Map>(&(mImpl->mValue));
- if(container)
+ case Dali::Property::VECTOR3:
{
- ret = container->Count();
+ stream << *impl.vector3Value;
+ break;
}
- }
- break;
-
- case Property::ARRAY:
- {
- Property::Array *container = AnyCast<Property::Array>(&(mImpl->mValue));
- if(container)
+ case Dali::Property::VECTOR4:
{
- ret = container->size();
+ stream << *impl.vector4Value;
+ break;
+ }
+ case Dali::Property::MATRIX3:
+ {
+ stream << *impl.matrix3Value;
+ break;
+ }
+ case Dali::Property::MATRIX:
+ {
+ stream << *impl.matrixValue;
+ break;
+ }
+ case Dali::Property::RECTANGLE:
+ {
+ stream << *impl.rectValue;
+ break;
+ }
+ case Dali::Property::ROTATION:
+ {
+ stream << *impl.angleAxisValue;
+ break;
+ }
+ case Dali::Property::STRING:
+ {
+ stream << *impl.stringValue;
+ break;
+ }
+ case Dali::Property::ARRAY:
+ {
+ stream << *(value.GetArray());
+ break;
+ }
+ case Dali::Property::MAP:
+ {
+ stream << *(value.GetMap());
+ break;
+ }
+ case Dali::Property::EXTENTS:
+ {
+ stream << *impl.extentsValue;
+ break;
+ }
+ case Dali::Property::NONE:
+ { // mImpl will be a nullptr, there's no way to get to this case
}
}
- break;
-
- case Property::NONE:
- case Property::BOOLEAN:
- case Property::FLOAT:
- case Property::INTEGER:
- case Property::UNSIGNED_INTEGER:
- case Property::VECTOR2:
- case Property::VECTOR3:
- case Property::VECTOR4:
- case Property::MATRIX3:
- case Property::MATRIX:
- case Property::RECTANGLE:
- case Property::ROTATION:
- case Property::STRING:
- case Property::TYPE_COUNT:
- {
- break;
- }
-
}
-
- return ret;
-}
-
-std::ostream& operator<< (std::ostream& stream, const Property::Value& value )
-{
-
- const Property::Value::Impl& impl( *value.mImpl );
-
- switch( impl.mType )
+ else
{
- case Dali::Property::STRING:
- {
- stream << AnyCast<std::string>(impl.mValue).c_str();
- break;
- }
- case Dali::Property::VECTOR2:
- {
- stream << AnyCast<Vector2>(impl.mValue);
- break;
- }
- case Dali::Property::VECTOR3:
- {
- stream << AnyCast<Vector3>(impl.mValue);
- break;
- }
- case Dali::Property::VECTOR4:
- {
- stream << AnyCast<Vector4>(impl.mValue);
- break;
- }
- case Dali::Property::MATRIX:
- {
- stream << AnyCast<Matrix>(impl.mValue);
- break;
- }
- case Dali::Property::BOOLEAN:
- {
- stream << AnyCast<bool>(impl.mValue);
- break;
- }
- case Dali::Property::FLOAT:
- {
- stream << AnyCast<float>(impl.mValue);
- break;
- }
- case Dali::Property::INTEGER:
- {
- stream << AnyCast<int>(impl.mValue);
- break;
- }
- case Dali::Property::UNSIGNED_INTEGER:
- {
- stream << AnyCast<unsigned int>(impl.mValue);
- break;
- }
- case Dali::Property::RECTANGLE:
- {
- Dali::Rect<int> rect; // Propery Value rectangles are currently integer based
- value.Get( rect );
- stream << rect;
- break;
- }
- case Dali::Property::MATRIX3:
- {
- stream << AnyCast<Matrix3>(impl.mValue);
- break;
- }
- case Dali::Property::ROTATION:
- {
- // @todo this may change to Quaternion
- Dali::Quaternion q;
- value.Get( q );
- Dali::Vector4 v4 = q.EulerAngles();
- stream << v4;
- break;
- }
-
- case Dali::Property::ARRAY:
- {
- // @todo Need to think about the best way to support array
- // E.g Do we want to create a JSON style array like:
- // [ {"property-name-0":"property-value-0", "property-name-1":"property-value-1"} ]
- stream << "ARRAY unsupported";
- break;
- }
- case Dali::Property::MAP:
- {
- Dali::Property::Map map;
- value.Get( map );
- stream << "Map containing " << map.Count() << " elements";
- break;
- }
- case Dali::Property::TYPE_COUNT:
- {
- stream << "unsupported TYPE_COUNT";
- break;
- }
- default:
- {
- stream << "unsupported type = " << value.GetType();
- break;
- }
+ stream << "undefined type";
}
return stream;
}