[dali_1.2.19] Merge branch 'devel/master'
[platform/core/uifw/dali-toolkit.git] / docs / content / programming-guide / type-registration.h
1 /*! \page type-registration Type Registration
2  *
3 @section Overview
4
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.
8
9 Once a type is registered, properties, signals and actions can also be registered for all instances
10 of this type.
11
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.
14
15 This topic covers:
16
17  - @ref register-type
18  - @ref register-property
19  - @ref register-signal
20  - @ref register-action
21  - @ref using-type
22  - @ref using-property
23  - @ref using-signal
24  - @ref using-action
25
26 @section register-type Registering a Type
27
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.
30
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.
34
35 @code
36 namespace
37 {
38
39 Dali::BaseHandle CreateMyControl()
40 {
41   // Create an instance of MyControl and return the handle.
42   return MyControlImpl::New();
43 }
44
45 DALI_TYPE_REGISTRATION_BEGIN( MyControl, Toolkit::Control, CreateMyControl );
46 DALI_TYPE_REGISTRATION_END()
47
48 } // unnamed namespace
49 @endcode
50
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.
52
53
54 @section register-property Registering a Property
55
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.
60
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.
66
67 Any control deriving from \link Dali::Toolkit::Control Control\endlink
68 should start at
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.
72
73 Please have a look at \ref property-indices for more information.
74
75 The following code shows how a property can be added to a type.
76
77 @code
78 // Define the indices we will use for the properties:
79
80 class MyControl : public Control
81 {
82   /**
83    * @brief The start and end property ranges for this control.
84    */
85   enum PropertyRange
86   {
87     PROPERTY_START_INDEX = Control::CONTROL_PROPERTY_END_INDEX + 1,
88     PROPERTY_END_INDEX =   PROPERTY_START_INDEX + 1000,
89
90     ANIMATABLE_PROPERTY_START_INDEX = ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX,
91     ANIMATABLE_PROPERTY_END_INDEX =   ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX + 1000
92   };
93
94   struct Property
95   {
96     enum
97     {
98       // Event side properties
99
100       /**
101        * @brief name "propertyOne", type bool
102        * @details Enables the feature.
103        * @SINCE_1_0.0
104        */
105       PROPERTY_ONE = PROPERTY_START_INDEX,
106
107       /**
108        * @brief name "propertyTwo", type float
109        * @details Controls the level of the feature
110        * @SINCE_1_0.0
111        */
112       PROPERTY_TWO,
113
114       /**
115        * @brief name "propertyThree", type Vector4
116        * @details The foreground color
117        * @SINCE_1_0.0
118        */
119       PROPERTY_THREE,
120
121       // Animatable properties
122
123       /**
124        * @brief name "propertyFour", type Vector4
125        * @details Animatable parameters of the feature
126        * @SINCE_1_0.0
127        */
128       PROPERTY_FOUR = ANIMATABLE_PROPERTY_START_INDEX,
129     };
130   };
131
132   /// ...
133 };
134 @endcode
135
136 The control and properties are registered with the TypeRegistry using the following macros:
137
138 @code
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 )
143
144 DALI_ANIMATABLE_PROPERTY_REGISTRATION_WITH_DEFAULT( AppNamespace, MyControl, "property4", Vector4(0.f, 0.f, 1.f, 1.f), PROPERTY_FOUR )
145
146 DALI_TYPE_REGISTRATION_END()
147 @endcode
148
149 The DALI_PROPERTY_REGISTRATION macro requires that you define the class methods SetProperty() and GetProperty().
150
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.
152
153 The SetProperty class method has to be static, and follows the format:
154
155 @code
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
160 )
161 {
162   // DownCast to MyControl so that we can do the specific behaviour
163   MyControl control = MyControl::DownCast( Dali::BaseHandle ( object ) );
164
165   if ( control )
166   {
167     MyControlImpl& controlImpl( GetImplementation( control ) );
168
169     switch ( index )
170     {
171       case PROPERTY_ONE:
172       {
173         // Assume we already have a method in MyControl which sets the appropriate value and takes in a boolean
174         bool property;
175         if( value.Get( property ) )
176         {
177           controlImpl.SetPropertyOne( property );
178         }
179         break;
180       }
181
182       case PROPERTY_TWO
183       {
184         // Assume we already have a method in MyControl which sets the appropriate value and takes in a float
185         float property;
186         if( value.Get( property ) )
187         {
188           controlImpl.SetPropertyTwo( property );
189         }
190         break;
191       }
192
193       case PROPERTY_THREE
194       {
195         // Assume we already have a method in MyControl which sets the appropriate value and takes in a Vector4
196         Vector4 property;
197         if( value.Get( property ) )
198         {
199           controlImpl.SetPropertyThree( property );
200         }
201         break;
202       }
203     }
204   }
205 }
206 @endcode
207
208 And the GetProperty method also has to be static and takes the form:
209
210 @code
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
214 {
215   Property::Value value;
216
217   // DownCast to MyControl so that we can do the specific behaviour
218   MyControl control = MyControl::DownCast( Dali::BaseHandle ( object ) );
219
220   if ( control )
221   {
222     MyControlImpl& controlImpl( GetImplementation( control ) );
223
224     switch ( index )
225     {
226       case PROPERTY_ONE:
227       {
228         // Assume we have a member variable that stores the value of this property
229         value = controlImpl.mPropertyOne;
230         break;
231       }
232
233       case PROPERTY_TWO:
234       {
235         // Assume we have a member variable that stores the value of this property
236         value = controlImpl.mPropertyTwo;
237         break;
238       }
239
240       case PROPERTY_THREE:
241       {
242         // Assume we have a member variable that stores the value of this property
243         value = controlImpl.mPropertyThree;
244         break;
245       }
246     }
247   }
248 }
249 @endcode
250
251 @section using-property Setting & Getting Registered Properties
252
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.
255
256 @code
257 Dali::TypeInfo type = Dali::TypeRegistry::Get().GetTypeInfo( "MyControl" );
258
259 if ( type )
260 {
261   Dali::BaseHandle baseHandle = type.CreateInstance();
262
263   if ( baseHandle )
264   {
265     // Handle deals with properties, so DownCast
266     Dali::Handle handle = Dali::Handle::DownCast( baseHandle );
267
268     if ( handle )
269     {
270       // Setting a property
271       handle.SetProperty( MyControl::Property::PROPERTY_ONE, 11.0f );
272
273       // Get the property name
274       std::cout << "Property1 name is: " << handle.GetPropertyName( MyControl::Property::PROPERTY_ONE ) << std::endl;
275
276       // Get the property
277       bool propertyOne = handle.GetProperty< bool >( MyControl::Property::PROPERTY_ONE );
278
279       // Set the second property
280       handle.SetProperty( MyControl::Property::PROPERTY_TWO, 4.0f );
281     }
282   }
283 }
284 @endcode
285
286 @section register-signal Registering a Signal
287
288 Once we've registered a type, we can then inform the type-registry about any signals that our type has:
289
290 @code
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" );
295
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
300 );
301
302 // Register more signals
303 Dali::SignalConnectorType signal2( type, SIGNAL_TWO,   &MyControl::DoConnectSignal );
304 Dali::SignalConnectorType signal3( type, SIGNAL_THREE, &MyControl::DoConnectSignal );
305 @endcode
306
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.
309
310 The method that handles the signal connection has to be static and takes the form:
311
312 @code
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
318 )
319 {
320   bool connected( false );
321
322   // DownCast to MyControl so that we can call the signal connection methods
323   MyControl control = MyControl::DownCast( Dali::BaseHandle ( object ) );
324
325   if ( control )
326   {
327     if ( signalName == SIGNAL_ONE )
328     {
329       control.SignalOne().Connect( tracker, functor );
330       connected = true;
331     }
332     else if ( signalName == SIGNAL_TWO )
333     {
334       control.SignalTwo().Connect( tracker, functor );
335       connected = true;
336     }
337     else if ( signalName == SIGNAL_THREE )
338     {
339       control.SignalThree().Connect( tracker, functor );
340       connected = true;
341     }
342   }
343
344   return connected; // Return true if connection successfully created
345 }
346 @endcode
347
348 @section register-action Registering an Action
349
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.
352
353 An action can be added to a type as shown below:
354
355 @code
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" );
360
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
365 );
366
367 // Register mode actions
368 Dali::TypeAction action2( type, ACTION_TWO,   &MyControl::DoAction );
369 Dali::TypeAction action3( type, ACTION_THREE, &MyControl::DoAction );
370 @endcode
371
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.
374
375 The method that handles the action has to be static and takes the form:
376
377 @code
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
382 )
383 {
384   bool performed( false );
385
386   Dali::BaseHandle handle(object);
387
388   // DownCast to MyControl so that we can do the specific behaviour
389   MyControl control = MyControl::DownCast( Dali::BaseHandle ( object ) );
390
391   if ( control )
392   {
393     if ( actionName == ACTION_ONE )
394     {
395       // Do action1 e.g. button click etc.
396     }
397     else if ( actionName == ACTION_TWO )
398     {
399       // Do action2, which can have attributes
400       if ( !attributes.empty() )
401       {
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;
404       }
405     }
406     else if ( actionName == ACTION_THREE )
407     {
408       // Do action3
409     }
410   }
411
412   return performed; // Return true if action successfully performed
413 }
414 @endcode
415
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.
419
420
421 @section using-type Creating an instance of a Registered Type
422
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.
425
426 @code
427 Dali::TypeInfo type = Dali::TypeRegistry::Get().GetTypeInfo( "MyControl" );
428
429 // If type specified is not found, then type will be NULL.
430 if ( type )
431 {
432   Dali::BaseHandle handle = type.CreateInstance();
433
434   // Can use DownCast to change to MyControl type if required
435   if ( handle )
436   {
437     MyControl control = MyControl::DownCast( handle );
438   }
439 }
440 @endcode
441
442 Normally we would not do the DownCast, just utilise the signals, actions and properties.
443
444 @section using-signal Connecting to a Registered Signal
445
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.
448
449 The application code would look as follows:
450
451 @code
452 class MyApp
453 {
454 public:
455
456   // Assume this is called when creating MyApp
457   void Create()
458   {
459     Dali::TypeInfo type = Dali::TypeRegistry::Get().GetTypeInfo( "MyControl" );
460
461     if ( type )
462     {
463       mHandle = type.CreateInstance();
464
465       if ( mHandle )
466       {
467         // Connect to signal1 by using its name
468         handle.ConnectSignal( &mConnectionTracker, "signal1", &MyApp::SignalReceived ) )
469       }
470     }
471   }
472
473   // This method will be called when "signal1" is emitted
474   void SignalReceived()
475   {
476     // Do Something when "signal1" is received
477     std::cout << "signal1 received" << std::endl;
478   }
479
480 private:
481   Dali::BaseHandle mHandle; // Handle to MyControl created via the type-registry
482   Dali::ConnectionTracker mConnectionTracker; // Used for automatic signal disconnection upon its destruction
483 };
484 @endcode
485
486 @section using-action Performing a Registered Action
487
488 Once an action is registered, the application writer can perform that action using the action name:
489
490 @code
491 Dali::TypeInfo type = Dali::TypeRegistry::Get().GetTypeInfo( "MyControl" );
492
493 if ( type )
494 {
495   Dali::BaseHandle handle = type.CreateInstance();
496
497   if ( handle )
498   {
499     // Perform action1, no attributes
500     handle.DoAction( "action1", std::vector< Dali::Property::Value >() );
501
502     // Create an attribute vector for action2
503     std::vector< Dali::Property::Value > action2Attributes;
504     action2Attributes.push_back( Dali::Property::Value( "Hello-Action-2" ) );
505
506     // Perform action2, with attributes
507     handle.DoAction( "action2", action2Attributes );
508   }
509 }
510 @endcode
511
512 *
513 */