Added terse syntax for Get/Set Property 33/209233/10
authorDavid Steele <david.steele@samsung.com>
Thu, 21 Apr 2016 15:47:04 +0000 (16:47 +0100)
committerDavid Steele <david.steele@samsung.com>
Fri, 21 Aug 2020 13:26:14 +0000 (14:26 +0100)
Added an IndirectValue which enables the setting and getting of property values
using the following syntax:

  actor["color"] = Color::BLACK;
  AngleAxis orientation = actor[Actor::Property::ORIENTATION];

Change-Id: I01088e5d7011a0b74bda1bf5a5f0f226c85a115c
Signed-off-by: David Steele <david.steele@samsung.com>
automated-tests/src/dali/dali-test-suite-utils/dali-test-suite-utils.h
automated-tests/src/dali/utc-Dali-Handle.cpp
dali/public-api/file.list
dali/public-api/object/handle.cpp
dali/public-api/object/handle.h
dali/public-api/object/indirect-value.cpp [new file with mode: 0644]
dali/public-api/object/indirect-value.h [new file with mode: 0644]

index 0c5efa3..ac9b214 100644 (file)
@@ -305,6 +305,17 @@ void DALI_TEST_EQUALS( const std::string &str1, const char* str2, const char* lo
 void DALI_TEST_EQUALS( const char* str1, const std::string &str2, const char* location);
 
 /**
+ * Test if a property value type is equal to a trivial type.
+ */
+template<typename Type>
+inline void DALI_TEST_VALUE_EQUALS( Property::Value&& value1, Type value2, float epsilon, const char* location)
+{
+  Property::Value value2b(value2);
+  DALI_TEST_EQUALS(value1, value2b, epsilon, location);
+}
+
+
+/**
  * Test whether one unsigned integer value is greater than another.
  * Test succeeds if value1 > value2
  * @param[in] value1 The first value
index 5f5e962..f406fd4 100644 (file)
@@ -16,7 +16,7 @@
  */
 
 #include <iostream>
-
+#include <typeinfo>
 #include <stdlib.h>
 #include <dali/public-api/dali-core.h>
 #include <dali/devel-api/actors/actor-devel.h>
@@ -1828,6 +1828,7 @@ int UtcDaliHandleGetProperties(void)
   END_TEST;
 }
 
+
 int UtcDaliHandleSetPropertyNegative(void)
 {
   TestApplication application;
@@ -2171,3 +2172,123 @@ int UtcDaliHandleSupportsNegative(void)
   }
   END_TEST;
 }
+
+
+int UtcDaliHandleIndexOperatorByIndexP01(void)
+{
+  TestApplication application;
+  Actor actor = Actor::New();
+
+  actor[Actor::Property::SIZE] = Vector3( 100.0f, 200.0f, 1.0f );
+
+  DALI_TEST_EQUALS( actor.GetProperty<Vector3>(Actor::Property::SIZE), Vector3( 100.0f, 200.0f, 1.0f ), 0.001f, TEST_LOCATION );
+
+
+  actor.SetProperty( Actor::Property::POSITION, Vector3( 10.0f, 20.0f, 0.0f ) );
+
+  Vector3 position = actor[ Actor::Property::POSITION ];
+  DALI_TEST_EQUALS( position, Vector3( 10.0f, 20.0f, 0.0f ), TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliHandleIndexOperatorByIndexP02(void)
+{
+  TestApplication application;
+  Actor actor = Actor::New();
+
+  const Vector4 defaultActorColor(1.0f, 1.0f, 1.0f, 1.0f);
+  actor.SetProperty(Actor::Property::COLOR, defaultActorColor);
+  actor[Actor::Property::COLOR_RED] = 0.5f;
+
+  DALI_TEST_EQUALS( actor.GetProperty<float>(Actor::Property::COLOR_RED), 0.5f, 0.001f, TEST_LOCATION);
+  DALI_TEST_EQUALS( actor.GetProperty<Vector4>(Actor::Property::COLOR), Vector4(0.5f, 1.0f, 1.0f, 1.0f), 0.001f, TEST_LOCATION);
+
+  actor.SetProperty( Actor::Property::POSITION, Vector3( 10.0f, 20.0f, 0.0f ) );
+
+  DALI_TEST_EQUALS( (float)actor[ Actor::Property::POSITION_Z ], 0.0f, 0.001f, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliHandleIndexOperatorByIndexP03(void)
+{
+  TestApplication application;
+  Actor actor = Actor::New();
+
+  const Vector4 defaultActorColor(1.0f, 1.0f, 1.0f, 1.0f);
+  actor.SetProperty(Actor::Property::COLOR, defaultActorColor);
+
+  // Value under test is second to allow compiler to deduce type
+  DALI_TEST_VALUE_EQUALS( actor[Actor::Property::COLOR_RED], 1.0f, 0.001f, TEST_LOCATION);
+
+  actor.SetProperty( Actor::Property::POSITION, Vector3( 10.0f, 20.0f, 0.0f ) );
+
+  DALI_TEST_EQUALS( (float)actor[ Actor::Property::POSITION_Z ], 0.0f, 0.001f, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliHandleIndexOperatorByNameP01(void)
+{
+  TestApplication application;
+  Actor actor = Actor::New();
+
+  actor["size"] = Vector3( 100.0f, 200.0f, 1.0f );
+
+  DALI_TEST_VALUE_EQUALS( actor.GetProperty(Actor::Property::SIZE), Vector3( 100.0f, 200.0f, 1.0f ), 0.001f, TEST_LOCATION );
+
+  actor.SetProperty( Actor::Property::POSITION, Vector3( 10.0f, 20.0f, 0.0f ) );
+  Vector3 position = actor[ "position" ];
+
+  DALI_TEST_EQUALS( position, Vector3( 10.0f, 20.0f, 0.0f ), 0.001f, TEST_LOCATION );
+
+  END_TEST;
+}
+
+
+int UtcDaliHandleIndexOperatorByNameP02(void)
+{
+  TestApplication application;
+  Actor actor = Actor::New();
+
+  const Vector4 defaultActorColor(1.0f, 1.0f, 1.0f, 1.0f);
+  actor.SetProperty(Actor::Property::COLOR, defaultActorColor);
+  actor["colorRed"] = 0.5f;
+
+  DALI_TEST_VALUE_EQUALS( actor.GetProperty(Actor::Property::COLOR_RED), 0.5f, 0.001f, TEST_LOCATION);
+  DALI_TEST_VALUE_EQUALS( actor.GetProperty(Actor::Property::COLOR), Vector4(0.5f, 1.0f, 1.0f, 1.0f), 0.001f, TEST_LOCATION);
+
+  actor.SetProperty( Actor::Property::POSITION, Vector3( 10.0f, 20.0f, 0.0f ) );
+
+  float positionY = actor[ "positionY" ];
+  DALI_TEST_EQUALS( positionY, 20.0f, 0.001f, TEST_LOCATION );
+
+  // Should automatically promote IndirectValue to Property::Value rvalue.
+  DALI_TEST_VALUE_EQUALS( actor["positionZ"], 0.0f, 0.001f, TEST_LOCATION );
+
+  END_TEST;
+}
+
+
+int UtcDaliHandleIndexOperatorNegative02(void)
+{
+  TestApplication application;
+
+  Actor actor;
+  try
+  {
+    Vector3 position = actor[Actor::Property::POSITION];
+    if( position == position )
+    {
+      DALI_TEST_CHECK(false); // Should throw before reaching here.
+    }
+    DALI_TEST_CHECK(false); // Should throw before reaching here.
+  }
+  catch(...)
+  {
+    DALI_TEST_CHECK(true); // Assert expected
+  }
+
+  END_TEST;
+}
index a9c0577..e3946ba 100644 (file)
@@ -47,8 +47,9 @@ SET( public_api_src_files
   ${public_api_src_dir}/math/vector4.cpp
   ${public_api_src_dir}/object/any.cpp
   ${public_api_src_dir}/object/base-handle.cpp
-  ${public_api_src_dir}/object/handle.cpp
   ${public_api_src_dir}/object/base-object.cpp
+  ${public_api_src_dir}/object/handle.cpp
+  ${public_api_src_dir}/object/indirect-value.cpp
   ${public_api_src_dir}/object/object-registry.cpp
   ${public_api_src_dir}/object/property.cpp
   ${public_api_src_dir}/object/property-array.cpp
@@ -181,6 +182,7 @@ SET( public_api_core_object_header_files
   ${public_api_src_dir}/object/base-handle.h
   ${public_api_src_dir}/object/base-object.h
   ${public_api_src_dir}/object/handle.h
+  ${public_api_src_dir}/object/indirect-value.h
   ${public_api_src_dir}/object/object-registry.h
   ${public_api_src_dir}/object/property-array.h
   ${public_api_src_dir}/object/property-conditions.h
index a22fc74..a067aee 100644 (file)
@@ -164,6 +164,18 @@ void Handle::RemoveConstraints( uint32_t tag )
   GetImplementation(*this).RemoveConstraints( tag );
 }
 
+IndirectValue Handle::operator[]( Property::Index index )
+{
+  // Will assert on access if handle is empty
+  return IndirectValue(*this, index);
+}
+
+IndirectValue Handle::operator[]( const std::string& name )
+{
+  // Will assert immediately when GetPropertyIndex is called if handle is empty
+  return IndirectValue(*this, GetPropertyIndex(name));
+}
+
 namespace WeightObject
 {
 
index 02ffd8d..540a04e 100644 (file)
 // INTERNAL INCLUDES
 #include <dali/public-api/common/dali-common.h>
 #include <dali/public-api/object/base-handle.h>
+#include <dali/public-api/object/indirect-value.h>
 #include <dali/public-api/object/property-types.h>
 #include <dali/public-api/object/property-value.h>
 #include <dali/public-api/object/property-notification-declarations.h>
 #include <dali/public-api/object/ref-object.h>
 
+
 namespace Dali
 {
 /**
@@ -409,6 +411,28 @@ public:
    * @pre The Object has been initialized.
    */
   void RemoveConstraints( uint32_t tag );
+
+  /**
+   * @brief Index operator, using integer lookup.
+   *
+   * Returns an object that can be assigned to or cast from, enabling
+   * the indexed property to be either read or written.
+   *
+   * @param[in] index The index of the property to access.
+   * @return indirect value. Should have shorter scope than the handle
+   */
+  IndirectValue operator[]( Property::Index index );
+
+  /**
+   * @brief Index operator, using name lookup.
+   *
+   * Returns an object that can be assigned to or cast from, enabling
+   * the named property to be either read or written.
+   *
+   * @param[in] name The name of the property to access.
+   * @return indirect value. Should have shorter scope than the handle
+   */
+  IndirectValue operator[]( const std::string& name );
 };
 
 /**
diff --git a/dali/public-api/object/indirect-value.cpp b/dali/public-api/object/indirect-value.cpp
new file mode 100644 (file)
index 0000000..321feaa
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#include <dali/public-api/object/indirect-value.h>
+#include <dali/public-api/object/handle.h>
+#include <dali/internal/event/common/object-impl.h>
+
+namespace Dali
+{
+
+IndirectValue::IndirectValue( Handle& handle, Property::Index index )
+: mHandle(handle.GetObjectPtr()),
+  mIndex(index),
+  mExtension(nullptr)
+{
+}
+
+void IndirectValue::operator= (Property::Value value)
+{
+  Handle(static_cast<Dali::Internal::Object*>(mHandle.Get())).SetProperty(mIndex, value);
+}
+
+Property::Value IndirectValue::GetProperty()
+{
+  return Handle(static_cast<Dali::Internal::Object*>(mHandle.Get())).GetProperty(mIndex);
+}
+
+IndirectValue& IndirectValue::operator=( IndirectValue&& ) = default;
+
+IndirectValue::IndirectValue( IndirectValue&& ) = default;
+
+
+} // namespace Dali
diff --git a/dali/public-api/object/indirect-value.h b/dali/public-api/object/indirect-value.h
new file mode 100644 (file)
index 0000000..39db23c
--- /dev/null
@@ -0,0 +1,140 @@
+#ifndef DALI_INDIRECT_VALUE_H
+#define DALI_INDIRECT_VALUE_H
+
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <dali/public-api/common/intrusive-ptr.h>
+#include <dali/public-api/object/property.h>
+#include <dali/public-api/object/property-value.h>
+#include <dali/public-api/object/ref-object.h>
+
+namespace Dali
+{
+/**
+ * @addtogroup dali_core_object
+ * @{
+ */
+
+class Handle;
+
+
+/**
+ * @brief Dali::IndirectValue is an intermediate object that enables a simpler
+ * syntax for addressing properties.
+ *
+ * @SINCE_1_9.27
+ * object["property"] = value;
+ * float value = object["property"];
+ *
+ * It is not intended to be directly instantiated, instead, any Handle type
+ * will generate a temporary object using the above syntax.
+ */
+class DALI_CORE_API IndirectValue
+{
+public:
+  /**
+   * @brief Assignment operator
+   *
+   * @SINCE_1_9.27
+   * Enables "handle[property] = value" syntax.
+   * @param[in] value The value to assign
+   */
+  void operator=(Property::Value value);
+
+  /**
+   * @brief Explicit cast operator for property value.
+   *
+   * @SINCE_1_9.27
+   * Enables implicit promotion of this to a Property::Value type parameter
+   * @return The property value
+   */
+  operator Property::Value()
+  {
+    return GetProperty();
+  }
+
+  /**
+   * @brief Cast operator
+   *
+   * @SINCE_1_9.27
+   * Enables "value = handle[property]" syntax.
+   * @tparam Type The type of the associated property
+   * @return The associated property cast to the desired type
+   */
+  template <typename Type>
+  inline operator Type()
+  {
+    Property::Value value = GetProperty();
+    return value.Get<Type>();
+  }
+
+private:
+  /// @cond internal
+
+  /**
+   * @brief Move constructor.
+   *
+   * @SINCE_1_9.27
+   * Making this private to prevent construction of auto type or IndirectValue type.
+   * @param[in] rhs The object to move
+   */
+  DALI_INTERNAL IndirectValue( IndirectValue&& rhs );
+
+  /**
+   * @brief Move assignment operator.
+   *
+   * @SINCE_1_9.27
+   * Making this private to prevent assignment to auto type or IndirectValue type.
+   * @param[in] rhs The object to move
+   */
+  DALI_INTERNAL IndirectValue& operator=( IndirectValue&& rhs );
+
+  /**
+   * @brief Accessor for handle property.
+   *
+   * @SINCE_1_9.27
+   * @return The handle's property value
+   * @note Asserts if the handle is empty
+   */
+  Property::Value GetProperty();
+
+  friend class Handle; ///< Only Handle types can construct this object
+
+  /**
+   * @brief Private constructor
+   *
+   * @SINCE_1_9.27
+   * @param[in] handle A reference to the associated handle
+   * @param[in] index The index to the associated property
+   */
+  DALI_INTERNAL IndirectValue( Handle& handle, Property::Index index );
+private:
+  IntrusivePtr<Dali::RefObject> mHandle; ///< A handle to the property owner
+  Property::Index mIndex; ///< Index of the property in the property owner.
+
+  struct Extension; ///< Reserved for future use
+  Extension* mExtension; ///< Reserved for future use
+
+  /// @endcond
+};
+
+/**
+ * @}
+ */
+} // Namespace Dali
+
+#endif // DALI_INDIRECT_VALUE_H