From c4d4f1b7cbef07fc1a02a27792e2e3317f4b4ed2 Mon Sep 17 00:00:00 2001 From: David Steele Date: Mon, 5 Dec 2016 12:30:27 +0000 Subject: [PATCH] Updating programming guide for control property registration There is nothing in the programming guide to indicate why the property ranges of a derived control should start at a particular value. Have updated the guides to describe this. Change-Id: I04c0948dd8a306ce99128c92f97174c373f2817c Signed-off-by: David Steele --- docs/content/programming-guide/properties.h | 7 +- docs/content/programming-guide/type-registration.h | 416 ++++++++++++--------- .../creating-custom-controls.md | 2 + 3 files changed, 248 insertions(+), 177 deletions(-) diff --git a/docs/content/programming-guide/properties.h b/docs/content/programming-guide/properties.h index 5e5dbd0..a1a95e9 100644 --- a/docs/content/programming-guide/properties.h +++ b/docs/content/programming-guide/properties.h @@ -89,15 +89,16 @@ Macros are used to define properties for the following reasons: Two different macros are provided depending on whether the property is to be an event-side only property or an animatable property. -There are two stages: +There are three stages: -- Define the properties as an enum in the public-api header file, along with a definition of the property ranges. +- Define the property ranges as an enum in the public-api header file. There are two ranges, one for event-side only properties, and one for animatable properties. Each range should follow on from the range defined in the parent class. +- Define the properties as an enum in the public-api header file - Define the property details using the pre-defined macros to perform the type-registering of the properties. This is done for signals and actions also. Example: ImageView Source file: image-view.h: -Note that the “PropertyRange” contents “PROPERTY_START_INDEX” & "ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX" are also used by the macro for order checking. + Note that the “PropertyRange” contents “PROPERTY_START_INDEX” & "ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX" are also used by the macro for order checking, so should always have these names. @code /** diff --git a/docs/content/programming-guide/type-registration.h b/docs/content/programming-guide/type-registration.h index e9912ef..ad7b5a4 100644 --- a/docs/content/programming-guide/type-registration.h +++ b/docs/content/programming-guide/type-registration.h @@ -6,23 +6,22 @@ DALi has a \link Dali::TypeRegistry type registration \endlink system which can a derived actor/control type along with specifying a method which is used to create this type. This type registration normally takes place at library load time. -Once a type is registered, signals, actions and properties can also be registered for all instances +Once a type is registered, properties, signals and actions can also be registered for all instances of this type. -This then allows the application writer to create instances using just the type name; connect to -signals using only the signal name; activate an action by just using the action name; and finally, -getting and setting properties using a property name or index. +This then allows the application writer to create instances using just the type name; getting and setting properties using a property name or index; connect to +signals using only the signal name; and activate an action by just using the action name. This topic covers: - @ref register-type + - @ref register-property - @ref register-signal - @ref register-action - - @ref register-property - @ref using-type + - @ref using-property - @ref using-signal - @ref using-action - - @ref using-property @section register-type Registering a Type @@ -37,22 +36,252 @@ within the source file of the deriving control as shown in the code below. namespace { -Dali::BaseHandle Create() +Dali::BaseHandle CreateMyControl() { // Create an instance of MyControl and return the handle. return MyControlImpl::New(); } -Dali::TypeRegistration type( - typeid( MyControl ), // Type ID of our Control - typeid( Dali::Toolkit::Control ), // Type ID of what our Control derives from - Create // Function which creates our Control, signature shown above -); +DALI_TYPE_REGISTRATION_BEGIN( MyControl, Toolkit::Control, CreateMyControl ); +DALI_TYPE_REGISTRATION_END() } // unnamed namespace @endcode -This registration informs DALi of the existence of MyControl type. +This registration macro informs DALi of the existence of MyControl type, which class it derives from, and a method for creating an instance of MyControl. + + +@section register-property Registering a Property + +DALi has a property system which can be extended by registering more properties through the type +registry. The property index is very important when registering these properties and +all property indices should be between Dali::PROPERTY_REGISTRATION_START_INDEX and +Dali::PROPERTY_REGISTRATION_MAX_INDEX. + +Furthermore, if deriving from a \link Dali::Toolkit::Control Control\endlink, the control +writer needs to be aware of their parent class's property range to avoid overlapping indices, so should start their property indices after their parent's range. +Control reserves a property range between +\link Dali::Toolkit::Control::CONTROL_PROPERTY_START_INDEX Control::CONTROL_PROPERTY_START_INDEX\endlink +and \link Dali::Toolkit::Control::CONTROL_PROPERTY_END_INDEX Control::CONTROL_PROPERTY_END_INDEX\endlink. + +Any control deriving from \link Dali::Toolkit::Control Control\endlink +should start at +\link Dali::Toolkit::Control::CONTROL_PROPERTY_END_INDEX Control::CONTROL_PROPERTY_END_INDEX\endlink + 1. +Controls deriving from an existing control such as \link Dali::Toolkit::Button Button\endlink should start at +\link Dali::Toolkit::Button::PROPERTY_END_INDEX Button::PROPERTY_END_INDEX\endlink + 1. + +Please have a look at \ref property-indices for more information. + +The following code shows how a property can be added to a type. + +@code +// Define the indices we will use for the properties: + +class MyControl : public Control +{ + /** + * @brief The start and end property ranges for this control. + */ + enum PropertyRange + { + PROPERTY_START_INDEX = Control::CONTROL_PROPERTY_END_INDEX + 1, + PROPERTY_END_INDEX = PROPERTY_START_INDEX + 1000, + + ANIMATABLE_PROPERTY_START_INDEX = ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX, + ANIMATABLE_PROPERTY_END_INDEX = ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX + 1000 + }; + + struct Property + { + enum + { + // Event side properties + + /** + * @brief name "propertyOne", type bool + * @details Enables the feature. + * @SINCE_1_0.0 + */ + PROPERTY_ONE = PROPERTY_START_INDEX, + + /** + * @brief name "propertyTwo", type float + * @details Controls the level of the feature + * @SINCE_1_0.0 + */ + PROPERTY_TWO, + + /** + * @brief name "propertyThree", type Vector4 + * @details The foreground color + * @SINCE_1_0.0 + */ + PROPERTY_THREE, + + // Animatable properties + + /** + * @brief name "propertyFour", type Vector4 + * @details Animatable parameters of the feature + * @SINCE_1_0.0 + */ + PROPERTY_FOUR = ANIMATABLE_PROPERTY_START_INDEX, + }; + }; + + /// ... +}; +@endcode + +The control and properties are registered with the TypeRegistry using the following macros: + +@code +DALI_TYPE_REGISTRATION_BEGIN( MyControl, Toolkit::Control, CreateMyControl ); +DALI_PROPERTY_REGISTRATION( AppNamespace, MyControl, "property1", BOOLEAN, PROPERTY_ONE ) +DALI_PROPERTY_REGISTRATION( AppNamespace, MyControl, "property2", FLOAT, PROPERTY_TWO ) +DALI_PROPERTY_REGISTRATION( AppNamespace, MyControl, "property3", VECTOR4, PROPERTY_THREE ) + +DALI_ANIMATABLE_PROPERTY_REGISTRATION_WITH_DEFAULT( AppNamespace, MyControl, "property4", Vector4(0.f, 0.f, 1.f, 1.f), PROPERTY_FOUR ) + +DALI_TYPE_REGISTRATION_END() +@endcode + +The DALI_PROPERTY_REGISTRATION macro requires that you define the class methods SetProperty() and GetProperty(). + +The DALI_ANIMATABLE_PROPERTY_REGISTRATION macros automatically create and handle scene-graph values, and do not need any code in your derived class. Just use the property index in animation or constraint methods. + +The SetProperty class method has to be static, and follows the format: + +@code +void MyControl::SetProperty( + Dali::BaseObject* object, // A pointer to an instance of MyControl + Dali::Property::Index index, // The index of the property to set + const Dali::Property::Value& value // The value to set the property to +) +{ + // DownCast to MyControl so that we can do the specific behaviour + MyControl control = MyControl::DownCast( Dali::BaseHandle ( object ) ); + + if ( control ) + { + MyControlImpl& controlImpl( GetImplementation( control ) ); + + switch ( index ) + { + case PROPERTY_ONE: + { + // Assume we already have a method in MyControl which sets the appropriate value and takes in a boolean + bool property; + if( value.Get( property ) ) + { + controlImpl.SetPropertyOne( property ); + } + break; + } + + case PROPERTY_TWO + { + // Assume we already have a method in MyControl which sets the appropriate value and takes in a float + float property; + if( value.Get( property ) ) + { + controlImpl.SetPropertyTwo( property ); + } + break; + } + + case PROPERTY_THREE + { + // Assume we already have a method in MyControl which sets the appropriate value and takes in a Vector4 + Vector4 property; + if( value.Get( property ) ) + { + controlImpl.SetPropertyThree( property ); + } + break; + } + } + } +} +@endcode + +And the GetProperty method also has to be static and takes the form: + +@code +Property::Value MyControl::GetProperty( + BaseObject* object, // A pointer to an instance of MyControl + Property::Index index ) // The index of the property to retrieve +{ + Property::Value value; + + // DownCast to MyControl so that we can do the specific behaviour + MyControl control = MyControl::DownCast( Dali::BaseHandle ( object ) ); + + if ( control ) + { + MyControlImpl& controlImpl( GetImplementation( control ) ); + + switch ( index ) + { + case PROPERTY_ONE: + { + // Assume we have a member variable that stores the value of this property + value = controlImpl.mPropertyOne; + break; + } + + case PROPERTY_TWO: + { + // Assume we have a member variable that stores the value of this property + value = controlImpl.mPropertyTwo; + break; + } + + case PROPERTY_THREE: + { + // Assume we have a member variable that stores the value of this property + value = controlImpl.mPropertyThree; + break; + } + } + } +} +@endcode + +@section using-property Setting & Getting Registered Properties + +Like other properties, type registered properties can also be set and their values can be retrieved +in a similar manner. The code below shows how this can be done. + +@code +Dali::TypeInfo type = Dali::TypeRegistry::Get().GetTypeInfo( "MyControl" ); + +if ( type ) +{ + Dali::BaseHandle baseHandle = type.CreateInstance(); + + if ( baseHandle ) + { + // Handle deals with properties, so DownCast + Dali::Handle handle = Dali::Handle::DownCast( baseHandle ); + + if ( handle ) + { + // Setting a property + handle.SetProperty( MyControl::Property::PROPERTY_ONE, 11.0f ); + + // Get the property name + std::cout << "Property1 name is: " << handle.GetPropertyName( MyControl::Property::PROPERTY_ONE ) << std::endl; + + // Get the property + bool propertyOne = handle.GetProperty< bool >( MyControl::Property::PROPERTY_ONE ); + + // Set the second property + handle.SetProperty( MyControl::Property::PROPERTY_TWO, 4.0f ); + } + } +} +@endcode @section register-signal Registering a Signal @@ -188,133 +417,6 @@ If the action is not performed by the derived class, it will be propagated to th For example, in the above case, MyControl can perform "action1" so should return true, but it cannot perform "action4" so should return false and propagate the action to Control. -@section register-property Registering a Property - -DALi has a property system which can be extended by registering more properties through the type -registry. The property index is very important when registering these properties and -all property indices should be between Dali::PROPERTY_REGISTRATION_START_INDEX and -Dali::PROPERTY_REGISTRATION_MAX_INDEX. - -Furthermore, if deriving from \link Dali::Toolkit::Control Control\endlink, the control writer -needs to be aware of their parent class's property range. Control reserves a property range between -\link Dali::Toolkit::Control::CONTROL_PROPERTY_START_INDEX ControlImpl::CONTROL_PROPERTY_START_INDEX\endlink -and \link Dali::Toolkit::Control::CONTROL_PROPERTY_END_INDEX Control::CONTROL_PROPERTY_END_INDEX\endlink. -Any deriving control should start their property indices from -\link Dali::Toolkit::Control::CONTROL_PROPERTY_END_INDEX Control::CONTROL_PROPERTY_END_INDEX\endlink + 1. - -Please have a look at \ref property-indices for more information. - -The following code shows how a property can be added to a type. - -@code -// Define the indices we will use for the properties -static const int PROPERTY_ONE( Dali::Toolkit::Internal::Control::CONTROL_PROPERTY_END_INDEX + 1 ); -static const int PROPERTY_TWO( Dali::Toolkit::Internal::Control::CONTROL_PROPERTY_END_INDEX + 2 ); -static const int PROPERTY_THREE( Dali::Toolkit::Internal::Control::CONTROL_PROPERTY_END_INDEX + 3 ); - -Dali::PropertyRegistration property1( - type, // Reference to type registration object (see above) - "property1", // Name of the property - PROPERTY_ONE, // Index of this property - Dali::Property::BOOLEAN, // The property type - &MyControl::SetProperty, // Method called when property is set - &MyControl::GetProperty // Method called when retrieving the value of the property -); - -// Register more properties -Dali::PropertyRegistration property2( - type, "property2", PROPERTY_TWO, Dali::Property::FLOAT, - NULL, // SetProperty is NULL, means that this property is a read-only property - &MyControl::GetProperty -); -Dali::PropertyRegistration property3( type, "property3", PROPERTY_THREE, Dali::Property::FLOAT, &MyControl::SetProperty, &MyControl::GetProperty); -@endcode - -It is recommended to use static members (of MyControl class) for the property indices. That way -applications can also use the static member as well. If they require the property name, they can -just call the Dali::Handle::GetPropertyName(). - -The method that deals with setting the property has to be static, and follows the format: - -@code -void MyControl::SetProperty( - Dali::BaseObject* object, // A pointer to an instance of MyControl - Dali::Property::Index index, // The index of the property to set - const Dali::Property::Value& value // The value to set the property to -) -{ - // DownCast to MyControl so that we can do the specific behaviour - MyControl control = MyControl::DownCast( Dali::BaseHandle ( object ) ); - - if ( control ) - { - MyControlImpl& controlImpl( GetImplementation( control ) ); - - switch ( index ) - { - case PROPERTY_ONE: - { - // Assume we already have a method in MyControl which sets the appropriate value and takes in a boolean - controlImpl.SetPropertyOne( value.Get< bool >() ); - break; - } - - // PROPERTY_TWO is read-only so does not need to be handled - - case PROPERTY_THREE - { - // Assume we already have a method in MyControl which sets the appropriate value and takes in a float - controlImpl.SetPropertyThree( value.Get< float >() ); - break; - } - } - } -} -@endcode - -And the function to retrieve the property value also has to be static and takes the form: - -@code -Property::Value MyControl::GetProperty( - BaseObject* object, // A pointer to an instance of MyControl - Property::Index index // The index of the property to retrieve -) -{ - Property::Value value; - - // DownCast to MyControl so that we can do the specific behaviour - MyControl control = MyControl::DownCast( Dali::BaseHandle ( object ) ); - - if ( control ) - { - MyControlImpl& controlImpl( GetImplementation( control ) ); - - switch ( index ) - { - case PROPERTY_ONE: - { - // Assume we have a member variable that stores the value of this property - value = controlImpl.mPropertyOne; - break; - } - - case PROPERTY_TWO: - { - // Assume we have a member variable that stores the value of this property - value = controlImpl.mPropertyTwo; - break; - } - - case PROPERTY_THREE: - { - // Assume we have a member variable that stores the value of this property - value = controlImpl.mPropertyThree; - break; - } - } - } -} -@endcode @section using-type Creating an instance of a Registered Type @@ -407,39 +509,5 @@ if ( type ) } @endcode -@section using-property Setting & Getting Registered Properties - -Like other properties, type registered properties can also be set and their values can be retrieved -in a similar manner. The code below shows how this can be done. - -@code -Dali::TypeInfo type = Dali::TypeRegistry::Get().GetTypeInfo( "MyControl" ); - -if ( type ) -{ - Dali::BaseHandle baseHandle = type.CreateInstance(); - - if ( baseHandle ) - { - // Handle deals with properties, so DownCast - Dali::Handle handle = Dali::Handle::DownCast( baseHandle ); - - if ( handle ) - { - // Setting a property - handle.SetProperty( PROPERTY_ONE, true ); // Assume Property indices are publicly accessible - - // Get the property name - std::cout << "Property1 name is: " << handle.GetPropertyName( PROPERTY_ONE ) << std::endl; - - // Get the property - bool propertyOne = handle.GetProperty< bool >( PROPERTY_ONE ); - - // Attempt to write a read-only property... - handle.SetProperty( PROPERTY_TWO, 4.0f ); // !!! Will assert as PROPERTY_TWO is read-only !!! - } - } -} -@endcode * */ diff --git a/docs/content/shared-javascript-and-cpp-documentation/creating-custom-controls.md b/docs/content/shared-javascript-and-cpp-documentation/creating-custom-controls.md index 82345bb..a1451ee 100644 --- a/docs/content/shared-javascript-and-cpp-documentation/creating-custom-controls.md +++ b/docs/content/shared-javascript-and-cpp-documentation/creating-custom-controls.md @@ -89,6 +89,8 @@ The TypeRegistry is used to register your custom control. This allows the creation of the control via a JSON file, as well as registering properties, signals and actions. To ensure your control is stylable, the process described in [Type Registration](@ref type-registration) should be followed. + +#### Properties To aid development, some macros are provided for registering properties which are described in the [Property](@ref properties) section. Control properties can be one of three types: -- 2.7.4