1 /*! \page type-registration Type Registration
5 DALi has a \link Dali::TypeRegistry type registration \endlink system which can be used to register
6 a derived actor/control type along with specifying a method which is used to create this type. This
7 type registration normally takes place at library load time.
9 Once a type is registered, properties, signals and actions can also be registered for all instances
12 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
13 signals using only the signal name; and activate an action by just using the action name.
18 - @ref register-property
19 - @ref register-signal
20 - @ref register-action
26 @section register-type Registering a Type
28 A type can be registered using Dali::TypeRegistration. This is normally done in an unnamed namespace
29 within the source file of the deriving control as shown in the code below.
31 <b>Please note:</b> This snippet assumes knowledge of the \link Dali::Toolkit::Control Control
32 \endlink / \link Dali::Toolkit::Internal::Control Internal::Control \endlink creation process where
33 <i><b>MyControl</b></i> derives from a Control and <i><b>MyControlImpl</b></i> derives from Internal::Control.
39 Dali::BaseHandle CreateMyControl()
41 // Create an instance of MyControl and return the handle.
42 return MyControlImpl::New();
45 DALI_TYPE_REGISTRATION_BEGIN( MyControl, Toolkit::Control, CreateMyControl );
46 DALI_TYPE_REGISTRATION_END()
48 } // unnamed namespace
51 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.
54 @section register-property Registering a Property
56 DALi has a property system which can be extended by registering more properties through the type
57 registry. The property index is <b><i>very important</i></b> when registering these properties and
58 all property indices should be between Dali::PROPERTY_REGISTRATION_START_INDEX and
59 Dali::PROPERTY_REGISTRATION_MAX_INDEX.
61 Furthermore, if deriving from a \link Dali::Toolkit::Control Control\endlink, the control
62 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.
63 Control reserves a property range between
64 \link Dali::Toolkit::Control::CONTROL_PROPERTY_START_INDEX Control::CONTROL_PROPERTY_START_INDEX\endlink
65 and \link Dali::Toolkit::Control::CONTROL_PROPERTY_END_INDEX Control::CONTROL_PROPERTY_END_INDEX\endlink.
67 Any control deriving from \link Dali::Toolkit::Control Control\endlink
69 \link Dali::Toolkit::Control::CONTROL_PROPERTY_END_INDEX Control::CONTROL_PROPERTY_END_INDEX\endlink + 1.
70 Controls deriving from an existing control such as \link Dali::Toolkit::Button Button\endlink should start at
71 \link Dali::Toolkit::Button::PROPERTY_END_INDEX Button::PROPERTY_END_INDEX\endlink + 1.
73 Please have a look at \ref property-indices for more information.
75 The following code shows how a property can be added to a type.
78 // Define the indices we will use for the properties:
80 class MyControl : public Control
83 * @brief The start and end property ranges for this control.
87 PROPERTY_START_INDEX = Control::CONTROL_PROPERTY_END_INDEX + 1,
88 PROPERTY_END_INDEX = PROPERTY_START_INDEX + 1000,
90 ANIMATABLE_PROPERTY_START_INDEX = ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX,
91 ANIMATABLE_PROPERTY_END_INDEX = ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX + 1000
98 // Event side properties
101 * @brief name "propertyOne", type bool
102 * @details Enables the feature.
105 PROPERTY_ONE = PROPERTY_START_INDEX,
108 * @brief name "propertyTwo", type float
109 * @details Controls the level of the feature
115 * @brief name "propertyThree", type Vector4
116 * @details The foreground color
121 // Animatable properties
124 * @brief name "propertyFour", type Vector4
125 * @details Animatable parameters of the feature
128 PROPERTY_FOUR = ANIMATABLE_PROPERTY_START_INDEX,
136 The control and properties are registered with the TypeRegistry using the following macros:
139 DALI_TYPE_REGISTRATION_BEGIN( MyControl, Toolkit::Control, CreateMyControl );
140 DALI_PROPERTY_REGISTRATION( AppNamespace, MyControl, "property1", BOOLEAN, PROPERTY_ONE )
141 DALI_PROPERTY_REGISTRATION( AppNamespace, MyControl, "property2", FLOAT, PROPERTY_TWO )
142 DALI_PROPERTY_REGISTRATION( AppNamespace, MyControl, "property3", VECTOR4, PROPERTY_THREE )
144 DALI_ANIMATABLE_PROPERTY_REGISTRATION_WITH_DEFAULT( AppNamespace, MyControl, "property4", Vector4(0.f, 0.f, 1.f, 1.f), PROPERTY_FOUR )
146 DALI_TYPE_REGISTRATION_END()
149 The DALI_PROPERTY_REGISTRATION macro requires that you define the class methods SetProperty() and GetProperty().
151 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.
153 The SetProperty class method has to be static, and follows the format:
156 void MyControl::SetProperty(
157 Dali::BaseObject* object, // A pointer to an instance of MyControl
158 Dali::Property::Index index, // The index of the property to set
159 const Dali::Property::Value& value // The value to set the property to
162 // DownCast to MyControl so that we can do the specific behaviour
163 MyControl control = MyControl::DownCast( Dali::BaseHandle ( object ) );
167 MyControlImpl& controlImpl( GetImplementation( control ) );
173 // Assume we already have a method in MyControl which sets the appropriate value and takes in a boolean
175 if( value.Get( property ) )
177 controlImpl.SetPropertyOne( property );
184 // Assume we already have a method in MyControl which sets the appropriate value and takes in a float
186 if( value.Get( property ) )
188 controlImpl.SetPropertyTwo( property );
195 // Assume we already have a method in MyControl which sets the appropriate value and takes in a Vector4
197 if( value.Get( property ) )
199 controlImpl.SetPropertyThree( property );
208 And the GetProperty method also has to be static and takes the form:
211 Property::Value MyControl::GetProperty(
212 BaseObject* object, // A pointer to an instance of MyControl
213 Property::Index index ) // The index of the property to retrieve
215 Property::Value value;
217 // DownCast to MyControl so that we can do the specific behaviour
218 MyControl control = MyControl::DownCast( Dali::BaseHandle ( object ) );
222 MyControlImpl& controlImpl( GetImplementation( control ) );
228 // Assume we have a member variable that stores the value of this property
229 value = controlImpl.mPropertyOne;
235 // Assume we have a member variable that stores the value of this property
236 value = controlImpl.mPropertyTwo;
242 // Assume we have a member variable that stores the value of this property
243 value = controlImpl.mPropertyThree;
251 @section using-property Setting & Getting Registered Properties
253 Like other properties, type registered properties can also be set and their values can be retrieved
254 in a similar manner. The code below shows how this can be done.
257 Dali::TypeInfo type = Dali::TypeRegistry::Get().GetTypeInfo( "MyControl" );
261 Dali::BaseHandle baseHandle = type.CreateInstance();
265 // Handle deals with properties, so DownCast
266 Dali::Handle handle = Dali::Handle::DownCast( baseHandle );
270 // Setting a property
271 handle.SetProperty( MyControl::Property::PROPERTY_ONE, 11.0f );
273 // Get the property name
274 std::cout << "Property1 name is: " << handle.GetPropertyName( MyControl::Property::PROPERTY_ONE ) << std::endl;
277 bool propertyOne = handle.GetProperty< bool >( MyControl::Property::PROPERTY_ONE );
279 // Set the second property
280 handle.SetProperty( MyControl::Property::PROPERTY_TWO, 4.0f );
286 @section register-signal Registering a Signal
288 Once we've registered a type, we can then inform the type-registry about any signals that our type has:
291 // Define the names of the signals
292 static const char * const SIGNAL_ONE( "signal1" );
293 static const char * const SIGNAL_TWO( "signal2" );
294 static const char * const SIGNAL_THREE( "signal3" );
296 Dali::SignalConnectorType signal1(
297 type, // Reference to type registration object (see above)
298 SIGNAL_ONE, // Name of our signal
299 &MyControl::DoConnectSignal // Function to call when a call to connect to this signal is received
302 // Register more signals
303 Dali::SignalConnectorType signal2( type, SIGNAL_TWO, &MyControl::DoConnectSignal );
304 Dali::SignalConnectorType signal3( type, SIGNAL_THREE, &MyControl::DoConnectSignal );
307 It is recommended to use static members (of MyControl class) for the signal names. That way
308 applications can also use the static member rather than have to look up the name.
310 The method that handles the signal connection has to be static and takes the form:
313 bool MyControl::DoConnectSignal(
314 Dali::BaseObject* object, // A pointer to an instance of MyControl
315 Dali::ConnectionTrackerInterface* tracker, // The object connecting to the signal
316 const std::string& signalName, // The name of the signal to connect to
317 Dali::FunctorDelegate* functor // The functor
320 bool connected( false );
322 // DownCast to MyControl so that we can call the signal connection methods
323 MyControl control = MyControl::DownCast( Dali::BaseHandle ( object ) );
327 if ( signalName == SIGNAL_ONE )
329 control.SignalOne().Connect( tracker, functor );
332 else if ( signalName == SIGNAL_TWO )
334 control.SignalTwo().Connect( tracker, functor );
337 else if ( signalName == SIGNAL_THREE )
339 control.SignalThree().Connect( tracker, functor );
344 return connected; // Return true if connection successfully created
348 @section register-action Registering an Action
350 Created controls are able to perform a variety of default actions. Registering an action with the
351 type registry allows application writers to perform this action by using the name.
353 An action can be added to a type as shown below:
356 // Define the names of the actions
357 static const char * const ACTION_ONE( "action1" );
358 static const char * const ACTION_TWO( "action2" );
359 static const char * const ACTION_THREE( "action3" );
361 Dali::TypeAction action1(
362 type, // Reference to type registration object (see above)
363 ACTION_ONE, // Name of the action
364 &MyControl::DoAction // Function to call when someone wants to perform this action
367 // Register mode actions
368 Dali::TypeAction action2( type, ACTION_TWO, &MyControl::DoAction );
369 Dali::TypeAction action3( type, ACTION_THREE, &MyControl::DoAction );
372 It is recommended to use static members (of MyControl class) for the action names. That way
373 applications can also use the static member rather than have to look up the name.
375 The method that handles the action has to be static and takes the form:
378 bool MyControl::DoAction(
379 Dali::BaseObject* object, // A pointer to an instance of MyControl
380 const std::string& actionName, // The name of the action to perform
381 const std::vector< Dali::Property::Value >& attributes // Any passed in attributes
384 bool performed( false );
386 Dali::BaseHandle handle(object);
388 // DownCast to MyControl so that we can do the specific behaviour
389 MyControl control = MyControl::DownCast( Dali::BaseHandle ( object ) );
393 if ( actionName == ACTION_ONE )
395 // Do action1 e.g. button click etc.
397 else if ( actionName == ACTION_TWO )
399 // Do action2, which can have attributes
400 if ( !attributes.empty() )
402 // Let's assume action2 expects a std::string as an attribute, here's how we'd extract that
403 std::cout << "action2 printing out: " << attributes[0].Get< std::string >() ) << std::endl;
406 else if ( actionName == ACTION_THREE )
412 return performed; // Return true if action successfully performed
416 If the action is not performed by the derived class, it will be propagated to the base class.
417 For example, in the above case, MyControl can perform "action1" so should return true, but it
418 cannot perform "action4" so should return false and propagate the action to Control.
421 @section using-type Creating an instance of a Registered Type
423 When a type is registered with the \link Dali::TypeRegistry type registry\endlink, it allows the
424 application writer to get information about the type and even create an instance of it.
427 Dali::TypeInfo type = Dali::TypeRegistry::Get().GetTypeInfo( "MyControl" );
429 // If type specified is not found, then type will be NULL.
432 Dali::BaseHandle handle = type.CreateInstance();
434 // Can use DownCast to change to MyControl type if required
437 MyControl control = MyControl::DownCast( handle );
442 Normally we would not do the DownCast, just utilise the signals, actions and properties.
444 @section using-signal Connecting to a Registered Signal
446 The advantage of registering a signal using the \link Dali::TypeRegistry type registry \endlink is
447 that you can connect to a particular signal using just the name of the signal.
449 The application code would look as follows:
456 // Assume this is called when creating MyApp
459 Dali::TypeInfo type = Dali::TypeRegistry::Get().GetTypeInfo( "MyControl" );
463 mHandle = type.CreateInstance();
467 // Connect to signal1 by using its name
468 handle.ConnectSignal( &mConnectionTracker, "signal1", &MyApp::SignalReceived ) )
473 // This method will be called when "signal1" is emitted
474 void SignalReceived()
476 // Do Something when "signal1" is received
477 std::cout << "signal1 received" << std::endl;
481 Dali::BaseHandle mHandle; // Handle to MyControl created via the type-registry
482 Dali::ConnectionTracker mConnectionTracker; // Used for automatic signal disconnection upon its destruction
486 @section using-action Performing a Registered Action
488 Once an action is registered, the application writer can perform that action using the action name:
491 Dali::TypeInfo type = Dali::TypeRegistry::Get().GetTypeInfo( "MyControl" );
495 Dali::BaseHandle handle = type.CreateInstance();
499 // Perform action1, no attributes
500 handle.DoAction( "action1", std::vector< Dali::Property::Value >() );
502 // Create an attribute vector for action2
503 std::vector< Dali::Property::Value > action2Attributes;
504 action2Attributes.push_back( Dali::Property::Value( "Hello-Action-2" ) );
506 // Perform action2, with attributes
507 handle.DoAction( "action2", action2Attributes );