Merge "Removed invalid handle assignments from Builder/TextInput" into tizen
[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 @section register-property Registering a Property
188
189 DALi has a property system which can be extended by registering more properties through the type
190 registry. The property index is <b><i>very important</i></b> when registering these properties and
191 all property indices should be between Dali::PROPERTY_REGISTRATION_START_INDEX and
192 Dali::PROPERTY_REGISTRATION_MAX_INDEX.
193
194 Furthermore, if deriving from \link Dali::Toolkit::Control Control\endlink, the control writer
195 needs to be aware of their parent class's property range. Control reserves a property range between
196 \link Dali::Toolkit::Internal::Control::CONTROL_PROPERTY_START_INDEX ControlImpl::CONTROL_PROPERTY_START_INDEX\endlink
197 and \link Dali::Toolkit::Internal::Control::CONTROL_PROPERTY_END_INDEX Internal::Control::CONTROL_PROPERTY_END_INDEX\endlink.
198 Any deriving control should start their property indices from
199 \link Dali::Toolkit::Internal::Control::CONTROL_PROPERTY_END_INDEX Internal::Control::CONTROL_PROPERTY_END_INDEX\endlink + 1.
200
201 Please have a look at \ref property-indices for more information.
202
203 The following code shows how a property can be added to a type.
204
205 @code
206 // Define the indices we will use for the properties
207 static const int PROPERTY_ONE( Dali::Toolkit::Internal::Control::CONTROL_PROPERTY_END_INDEX + 1 );
208 static const int PROPERTY_TWO( Dali::Toolkit::Internal::Control::CONTROL_PROPERTY_END_INDEX + 2 );
209 static const int PROPERTY_THREE( Dali::Toolkit::Internal::Control::CONTROL_PROPERTY_END_INDEX + 3 );
210
211 Dali::PropertyRegistration property1(
212     type,                    // Reference to type registration object (see above)
213     "property1",             // Name of the property
214     PROPERTY_ONE,            // Index of this property
215     Dali::Property::BOOLEAN, // The property type
216     &MyControl::SetProperty, // Method called when property is set
217     &MyControl::GetProperty  // Method called when retrieving the value of the property
218 );
219
220 // Register more properties
221 Dali::PropertyRegistration property2(
222     type, "property2", PROPERTY_TWO, Dali::Property::FLOAT,
223     NULL, // SetProperty is NULL, means that this property is a read-only property
224     &MyControl::GetProperty
225 );
226 Dali::PropertyRegistration property3( type, "property3", PROPERTY_THREE, Dali::Property::FLOAT, &MyControl::SetProperty, &MyControl::GetProperty);
227 @endcode
228
229 It is recommended to use static members (of MyControl class) for the property indices. That way
230 applications can also use the static member as well. If they require the property name, they can
231 just call the Dali::Handle::GetPropertyName().
232
233 The method that deals with setting the property has to be static, and follows the format:
234
235 @code
236 void MyControl::SetProperty(
237     Dali::BaseObject* object,          // A pointer to an instance of MyControl
238     Dali::Property::Index index,       // The index of the property to set
239     const Dali::Property::Value& value // The value to set the property to
240 )
241 {
242   // DownCast to MyControl so that we can do the specific behaviour
243   MyControl control = MyControl::DownCast( Dali::BaseHandle ( object ) );
244
245   if ( control )
246   {
247     MyControlImpl& controlImpl( GetImplementation( control ) );
248
249     switch ( index )
250     {
251       case PROPERTY_ONE:
252       {
253         // Assume we already have a method in MyControl which sets the appropriate value and takes in a boolean
254         controlImpl.SetPropertyOne( value.Get< bool >() );
255         break;
256       }
257
258       // PROPERTY_TWO is read-only so does not need to be handled
259
260       case PROPERTY_THREE
261       {
262         // Assume we already have a method in MyControl which sets the appropriate value and takes in a float
263         controlImpl.SetPropertyThree( value.Get< float >() );
264         break;
265       }
266     }
267   }
268 }
269 @endcode
270
271 And the function to retrieve the property value also has to be static and takes the form:
272
273 @code
274 Property::Value MyControl::GetProperty(
275     BaseObject* object,   // A pointer to an instance of MyControl
276     Property::Index index // The index of the property to retrieve
277 )
278 {
279   Property::Value value;
280
281   // DownCast to MyControl so that we can do the specific behaviour
282   MyControl control = MyControl::DownCast( Dali::BaseHandle ( object ) );
283
284   if ( control )
285   {
286     MyControlImpl& controlImpl( GetImplementation( control ) );
287
288     switch ( index )
289     {
290       case PROPERTY_ONE:
291       {
292         // Assume we have a member variable that stores the value of this property
293         value = controlImpl.mPropertyOne;
294         break;
295       }
296
297       case PROPERTY_TWO:
298       {
299         // Assume we have a member variable that stores the value of this property
300         value = controlImpl.mPropertyTwo;
301         break;
302       }
303
304       case PROPERTY_THREE:
305       {
306         // Assume we have a member variable that stores the value of this property
307         value = controlImpl.mPropertyThree;
308         break;
309       }
310     }
311   }
312 }
313 @endcode
314
315 @section using-type Creating an instance of a Registered Type
316
317 When a type is registered with the \link Dali::TypeRegistry type registry\endlink, it allows the
318 application writer to get information about the type and even create an instance of it.
319
320 @code
321 Dali::TypeInfo type = Dali::TypeRegistry::Get().GetTypeInfo( "MyControl" );
322
323 // If type specified is not found, then type will be NULL.
324 if ( type )
325 {
326   Dali::BaseHandle handle = type.CreateInstance();
327
328   // Can use DownCast to change to MyControl type if required
329   if ( handle )
330   {
331     MyControl control = MyControl::DownCast( handle );
332   }
333 }
334 @endcode
335
336 Normally we would not do the DownCast, just utilise the signals, actions and properties.
337
338 @section using-signal Connecting to a Registered Signal
339
340 The advantage of registering a signal using the \link Dali::TypeRegistry type registry \endlink is
341 that you can connect to a particular signal using just the name of the signal.
342
343 The application code would look as follows:
344
345 @code
346 class MyApp
347 {
348 public:
349
350   // Assume this is called when creating MyApp
351   void Create()
352   {
353     Dali::TypeInfo type = Dali::TypeRegistry::Get().GetTypeInfo( "MyControl" );
354
355     if ( type )
356     {
357       mHandle = type.CreateInstance();
358
359       if ( mHandle )
360       {
361         // Connect to signal1 by using its name
362         handle.ConnectSignal( &mConnectionTracker, "signal1", &MyApp::SignalReceived ) )
363       }
364     }
365   }
366
367   // This method will be called when "signal1" is emitted
368   void SignalReceived()
369   {
370     // Do Something when "signal1" is received
371     std::cout << "signal1 received" << std::endl;
372   }
373
374 private:
375   Dali::BaseHandle mHandle; // Handle to MyControl created via the type-registry
376   Dali::ConnectionTracker mConnectionTracker; // Used for automatic signal disconnection upon its destruction
377 };
378 @endcode
379
380 @section using-action Performing a Registered Action
381
382 Once an action is registered, the application writer can perform that action using the action name:
383
384 @code
385 Dali::TypeInfo type = Dali::TypeRegistry::Get().GetTypeInfo( "MyControl" );
386
387 if ( type )
388 {
389   Dali::BaseHandle handle = type.CreateInstance();
390
391   if ( handle )
392   {
393     // Perform action1, no attributes
394     handle.DoAction( "action1", std::vector< Dali::Property::Value >() );
395
396     // Create an attribute vector for action2
397     std::vector< Dali::Property::Value > action2Attributes;
398     action2Attributes.push_back( Dali::Property::Value( "Hello-Action-2" ) );
399
400     // Perform action2, with attributes
401     handle.DoAction( "action2", action2Attributes );
402   }
403 }
404 @endcode
405
406 @section using-property Setting & Getting Registered Properties
407
408 Like other properties, type registered properties can also be set and their values can be retrieved
409 in a similar manner. The code below shows how this can be done.
410
411 @code
412 Dali::TypeInfo type = Dali::TypeRegistry::Get().GetTypeInfo( "MyControl" );
413
414 if ( type )
415 {
416   Dali::BaseHandle baseHandle = type.CreateInstance();
417
418   if ( baseHandle )
419   {
420     // Handle deals with properties, so DownCast
421     Dali::Handle handle = Dali::Handle::DownCast( baseHandle );
422
423     if ( handle )
424     {
425       // Setting a property
426       handle.SetProperty( PROPERTY_ONE, true ); // Assume Property indices are publicly accessible
427
428       // Get the property name
429       std::cout << "Property1 name is: " << handle.GetPropertyName( PROPERTY_ONE ) << std::endl;
430
431       // Get the property
432       bool propertyOne = handle.GetProperty< bool >( PROPERTY_ONE );
433
434       // Attempt to write a read-only property...
435       handle.SetProperty( PROPERTY_TWO, 4.0f ); // !!! Will assert as PROPERTY_TWO is read-only !!!
436     }
437   }
438 }
439 @endcode
440 *
441 */