Stop setting a max fixed size for the emojis.
[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, signals, actions and properties 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; connect to
13 signals using only the signal name; activate an action by just using the action name; and finally,
14 getting and setting properties using a property name or index.
15
16 This topic covers:
17
18  - @ref register-type
19  - @ref register-signal
20  - @ref register-action
21  - @ref register-property
22  - @ref using-type
23  - @ref using-signal
24  - @ref using-action
25  - @ref using-property
26
27 @section register-type Registering a Type
28
29 A type can be registered using Dali::TypeRegistration. This is normally done in an unnamed namespace
30 within the source file of the deriving control as shown in the code below.
31
32 <b>Please note:</b> This snippet assumes knowledge of the \link Dali::Toolkit::Control Control
33 \endlink / \link Dali::Toolkit::Internal::Control Internal::Control \endlink creation process where
34 <i><b>MyControl</b></i> derives from a Control and <i><b>MyControlImpl</b></i> derives from Internal::Control.
35
36 @code
37 namespace
38 {
39
40 Dali::BaseHandle Create()
41 {
42   // Create an instance of MyControl and return the handle.
43   return MyControlImpl::New();
44 }
45
46 Dali::TypeRegistration type(
47     typeid( MyControl ),              // Type ID of our Control
48     typeid( Dali::Toolkit::Control ), // Type ID of what our Control derives from
49     Create                            // Function which creates our Control, signature shown above
50 );
51
52 } // unnamed namespace
53 @endcode
54
55 This registration informs DALi of the existence of MyControl type.
56
57 @section register-signal Registering a Signal
58
59 Once we've registered a type, we can then inform the type-registry about any signals that our type has:
60
61 @code
62 // Define the names of the signals
63 static const char * const SIGNAL_ONE( "signal1" );
64 static const char * const SIGNAL_TWO( "signal2" );
65 static const char * const SIGNAL_THREE( "signal3" );
66
67 Dali::SignalConnectorType signal1(
68    type,                       // Reference to type registration object (see above)
69    SIGNAL_ONE,                 // Name of our signal
70    &MyControl::DoConnectSignal // Function to call when a call to connect to this signal is received
71 );
72
73 // Register more signals
74 Dali::SignalConnectorType signal2( type, SIGNAL_TWO,   &MyControl::DoConnectSignal );
75 Dali::SignalConnectorType signal3( type, SIGNAL_THREE, &MyControl::DoConnectSignal );
76 @endcode
77
78 It is recommended to use static members (of MyControl class) for the signal names. That way
79 applications can also use the static member rather than have to look up the name.
80
81 The method that handles the signal connection has to be static and takes the form:
82
83 @code
84 bool MyControl::DoConnectSignal(
85     Dali::BaseObject* object,                  // A pointer to an instance of MyControl
86     Dali::ConnectionTrackerInterface* tracker, // The object connecting to the signal
87     const std::string& signalName,             // The name of the signal to connect to
88     Dali::FunctorDelegate* functor             // The functor
89 )
90 {
91   bool connected( false );
92
93   // DownCast to MyControl so that we can call the signal connection methods
94   MyControl control = MyControl::DownCast( Dali::BaseHandle ( object ) );
95
96   if ( control )
97   {
98     if ( signalName == SIGNAL_ONE )
99     {
100       control.SignalOne().Connect( tracker, functor );
101       connected = true;
102     }
103     else if ( signalName == SIGNAL_TWO )
104     {
105       control.SignalTwo().Connect( tracker, functor );
106       connected = true;
107     }
108     else if ( signalName == SIGNAL_THREE )
109     {
110       control.SignalThree().Connect( tracker, functor );
111       connected = true;
112     }
113   }
114
115   return connected; // Return true if connection successfully created
116 }
117 @endcode
118
119 @section register-action Registering an Action
120
121 Created controls are able to perform a variety of default actions. Registering an action with the
122 type registry allows application writers to perform this action by using the name.
123
124 An action can be added to a type as shown below:
125
126 @code
127 // Define the names of the actions
128 static const char * const ACTION_ONE( "action1" );
129 static const char * const ACTION_TWO( "action2" );
130 static const char * const ACTION_THREE( "action3" );
131
132 Dali::TypeAction action1(
133     type,                // Reference to type registration object (see above)
134     ACTION_ONE,          // Name of the action
135     &MyControl::DoAction // Function to call when someone wants to perform this action
136 );
137
138 // Register mode actions
139 Dali::TypeAction action2( type, ACTION_TWO,   &MyControl::DoAction );
140 Dali::TypeAction action3( type, ACTION_THREE, &MyControl::DoAction );
141 @endcode
142
143 It is recommended to use static members (of MyControl class) for the action names. That way
144 applications can also use the static member rather than have to look up the name.
145
146 The method that handles the action has to be static and takes the form:
147
148 @code
149 bool MyControl::DoAction(
150     Dali::BaseObject* object,                              // A pointer to an instance of MyControl
151     const std::string& actionName,                         // The name of the action to perform
152     const std::vector< Dali::Property::Value >& attributes // Any passed in attributes
153 )
154 {
155   bool performed( false );
156
157   Dali::BaseHandle handle(object);
158
159   // DownCast to MyControl so that we can do the specific behaviour
160   MyControl control = MyControl::DownCast( Dali::BaseHandle ( object ) );
161
162   if ( control )
163   {
164     if ( actionName == ACTION_ONE )
165     {
166       // Do action1 e.g. button click etc.
167     }
168     else if ( actionName == ACTION_TWO )
169     {
170       // Do action2, which can have attributes
171       if ( !attributes.empty() )
172       {
173         // Let's assume action2 expects a std::string as an attribute, here's how we'd extract that
174         std::cout << "action2 printing out: " << attributes[0].Get< std::string >() ) << std::endl;
175       }
176     }
177     else if ( actionName == ACTION_THREE )
178     {
179       // Do action3
180     }
181   }
182
183   return performed; // Return true if action successfully performed
184 }
185 @endcode
186
187 If the action is not performed by the derived class, it will be propagated to the base class.
188 For example, in the above case, MyControl can perform "action1" so should return true, but it
189 cannot perform "action4" so should return false and propagate the action to Control.
190
191 @section register-property Registering a Property
192
193 DALi has a property system which can be extended by registering more properties through the type
194 registry. The property index is <b><i>very important</i></b> when registering these properties and
195 all property indices should be between Dali::PROPERTY_REGISTRATION_START_INDEX and
196 Dali::PROPERTY_REGISTRATION_MAX_INDEX.
197
198 Furthermore, if deriving from \link Dali::Toolkit::Control Control\endlink, the control writer
199 needs to be aware of their parent class's property range. Control reserves a property range between
200 \link Dali::Toolkit::Control::CONTROL_PROPERTY_START_INDEX ControlImpl::CONTROL_PROPERTY_START_INDEX\endlink
201 and \link Dali::Toolkit::Control::CONTROL_PROPERTY_END_INDEX Control::CONTROL_PROPERTY_END_INDEX\endlink.
202 Any deriving control should start their property indices from
203 \link Dali::Toolkit::Control::CONTROL_PROPERTY_END_INDEX Control::CONTROL_PROPERTY_END_INDEX\endlink + 1.
204
205 Please have a look at \ref property-indices for more information.
206
207 The following code shows how a property can be added to a type.
208
209 @code
210 // Define the indices we will use for the properties
211 static const int PROPERTY_ONE( Dali::Toolkit::Internal::Control::CONTROL_PROPERTY_END_INDEX + 1 );
212 static const int PROPERTY_TWO( Dali::Toolkit::Internal::Control::CONTROL_PROPERTY_END_INDEX + 2 );
213 static const int PROPERTY_THREE( Dali::Toolkit::Internal::Control::CONTROL_PROPERTY_END_INDEX + 3 );
214
215 Dali::PropertyRegistration property1(
216     type,                    // Reference to type registration object (see above)
217     "property1",             // Name of the property
218     PROPERTY_ONE,            // Index of this property
219     Dali::Property::BOOLEAN, // The property type
220     &MyControl::SetProperty, // Method called when property is set
221     &MyControl::GetProperty  // Method called when retrieving the value of the property
222 );
223
224 // Register more properties
225 Dali::PropertyRegistration property2(
226     type, "property2", PROPERTY_TWO, Dali::Property::FLOAT,
227     NULL, // SetProperty is NULL, means that this property is a read-only property
228     &MyControl::GetProperty
229 );
230 Dali::PropertyRegistration property3( type, "property3", PROPERTY_THREE, Dali::Property::FLOAT, &MyControl::SetProperty, &MyControl::GetProperty);
231 @endcode
232
233 It is recommended to use static members (of MyControl class) for the property indices. That way
234 applications can also use the static member as well. If they require the property name, they can
235 just call the Dali::Handle::GetPropertyName().
236
237 The method that deals with setting the property has to be static, and follows the format:
238
239 @code
240 void MyControl::SetProperty(
241     Dali::BaseObject* object,          // A pointer to an instance of MyControl
242     Dali::Property::Index index,       // The index of the property to set
243     const Dali::Property::Value& value // The value to set the property to
244 )
245 {
246   // DownCast to MyControl so that we can do the specific behaviour
247   MyControl control = MyControl::DownCast( Dali::BaseHandle ( object ) );
248
249   if ( control )
250   {
251     MyControlImpl& controlImpl( GetImplementation( control ) );
252
253     switch ( index )
254     {
255       case PROPERTY_ONE:
256       {
257         // Assume we already have a method in MyControl which sets the appropriate value and takes in a boolean
258         controlImpl.SetPropertyOne( value.Get< bool >() );
259         break;
260       }
261
262       // PROPERTY_TWO is read-only so does not need to be handled
263
264       case PROPERTY_THREE
265       {
266         // Assume we already have a method in MyControl which sets the appropriate value and takes in a float
267         controlImpl.SetPropertyThree( value.Get< float >() );
268         break;
269       }
270     }
271   }
272 }
273 @endcode
274
275 And the function to retrieve the property value also has to be static and takes the form:
276
277 @code
278 Property::Value MyControl::GetProperty(
279     BaseObject* object,   // A pointer to an instance of MyControl
280     Property::Index index // The index of the property to retrieve
281 )
282 {
283   Property::Value value;
284
285   // DownCast to MyControl so that we can do the specific behaviour
286   MyControl control = MyControl::DownCast( Dali::BaseHandle ( object ) );
287
288   if ( control )
289   {
290     MyControlImpl& controlImpl( GetImplementation( control ) );
291
292     switch ( index )
293     {
294       case PROPERTY_ONE:
295       {
296         // Assume we have a member variable that stores the value of this property
297         value = controlImpl.mPropertyOne;
298         break;
299       }
300
301       case PROPERTY_TWO:
302       {
303         // Assume we have a member variable that stores the value of this property
304         value = controlImpl.mPropertyTwo;
305         break;
306       }
307
308       case PROPERTY_THREE:
309       {
310         // Assume we have a member variable that stores the value of this property
311         value = controlImpl.mPropertyThree;
312         break;
313       }
314     }
315   }
316 }
317 @endcode
318
319 @section using-type Creating an instance of a Registered Type
320
321 When a type is registered with the \link Dali::TypeRegistry type registry\endlink, it allows the
322 application writer to get information about the type and even create an instance of it.
323
324 @code
325 Dali::TypeInfo type = Dali::TypeRegistry::Get().GetTypeInfo( "MyControl" );
326
327 // If type specified is not found, then type will be NULL.
328 if ( type )
329 {
330   Dali::BaseHandle handle = type.CreateInstance();
331
332   // Can use DownCast to change to MyControl type if required
333   if ( handle )
334   {
335     MyControl control = MyControl::DownCast( handle );
336   }
337 }
338 @endcode
339
340 Normally we would not do the DownCast, just utilise the signals, actions and properties.
341
342 @section using-signal Connecting to a Registered Signal
343
344 The advantage of registering a signal using the \link Dali::TypeRegistry type registry \endlink is
345 that you can connect to a particular signal using just the name of the signal.
346
347 The application code would look as follows:
348
349 @code
350 class MyApp
351 {
352 public:
353
354   // Assume this is called when creating MyApp
355   void Create()
356   {
357     Dali::TypeInfo type = Dali::TypeRegistry::Get().GetTypeInfo( "MyControl" );
358
359     if ( type )
360     {
361       mHandle = type.CreateInstance();
362
363       if ( mHandle )
364       {
365         // Connect to signal1 by using its name
366         handle.ConnectSignal( &mConnectionTracker, "signal1", &MyApp::SignalReceived ) )
367       }
368     }
369   }
370
371   // This method will be called when "signal1" is emitted
372   void SignalReceived()
373   {
374     // Do Something when "signal1" is received
375     std::cout << "signal1 received" << std::endl;
376   }
377
378 private:
379   Dali::BaseHandle mHandle; // Handle to MyControl created via the type-registry
380   Dali::ConnectionTracker mConnectionTracker; // Used for automatic signal disconnection upon its destruction
381 };
382 @endcode
383
384 @section using-action Performing a Registered Action
385
386 Once an action is registered, the application writer can perform that action using the action name:
387
388 @code
389 Dali::TypeInfo type = Dali::TypeRegistry::Get().GetTypeInfo( "MyControl" );
390
391 if ( type )
392 {
393   Dali::BaseHandle handle = type.CreateInstance();
394
395   if ( handle )
396   {
397     // Perform action1, no attributes
398     handle.DoAction( "action1", std::vector< Dali::Property::Value >() );
399
400     // Create an attribute vector for action2
401     std::vector< Dali::Property::Value > action2Attributes;
402     action2Attributes.push_back( Dali::Property::Value( "Hello-Action-2" ) );
403
404     // Perform action2, with attributes
405     handle.DoAction( "action2", action2Attributes );
406   }
407 }
408 @endcode
409
410 @section using-property Setting & Getting Registered Properties
411
412 Like other properties, type registered properties can also be set and their values can be retrieved
413 in a similar manner. The code below shows how this can be done.
414
415 @code
416 Dali::TypeInfo type = Dali::TypeRegistry::Get().GetTypeInfo( "MyControl" );
417
418 if ( type )
419 {
420   Dali::BaseHandle baseHandle = type.CreateInstance();
421
422   if ( baseHandle )
423   {
424     // Handle deals with properties, so DownCast
425     Dali::Handle handle = Dali::Handle::DownCast( baseHandle );
426
427     if ( handle )
428     {
429       // Setting a property
430       handle.SetProperty( PROPERTY_ONE, true ); // Assume Property indices are publicly accessible
431
432       // Get the property name
433       std::cout << "Property1 name is: " << handle.GetPropertyName( PROPERTY_ONE ) << std::endl;
434
435       // Get the property
436       bool propertyOne = handle.GetProperty< bool >( PROPERTY_ONE );
437
438       // Attempt to write a read-only property...
439       handle.SetProperty( PROPERTY_TWO, 4.0f ); // !!! Will assert as PROPERTY_TWO is read-only !!!
440     }
441   }
442 }
443 @endcode
444 *
445 */