Merge "Deleted Move/Copy operators & constructors from Internal::Control" into devel...
[platform/core/uifw/dali-toolkit.git] / docs / content / programming-guide / creating-custom-controls.md
1 <!--
2 /**-->
3
4 [TOC]
5
6 # Creating Custom UI Controls {#creating-custom-controls}
7
8 DALi provides the ability to create custom UI controls.
9 This can be done by extending Dali::Toolkit::Control and Dali::Toolkit::Internal::Control classes.
10  
11 Custom controls are created using the [handle/body idiom](@ref handle-body-idiom) used in DALi.
12  
13 ![ ](creating-custom-controls/control-handle-body.png)
14  
15 Namespaces are important
16 + The handle & body classes should have the same name but in different namespaces
17 + TypeRegistry relies on this convention
18 + Here our custom control requires
19   + MyUIControl
20   + Internal::MyUIControl
21  
22 ### General Guidelines:
23 + Try to avoid adding C++ APIs as they become difficult to maintain.
24   + Use **properties** as much as possible as Controls should be data driven.
25   + These controls will be used through JSON files so need to be compatible.
26 + Bear in mind that the Control can be updated when the properties change (e.g. style change)
27   + Ensure control deals with these property changes gracefully
28   + Not just the first time they are set
29 + Use Visuals rather than creating several child Actors
30   + DALi rendering pipeline more efficient
31 + Accessibility actions should be considered when designing the Control.
32 + Consider using signals if the application needs to be react to changes in the control state.
33 + Use of Gestures should be preferred over analysing raw touch events
34 + Check if you need to chain up to base class if overriding certain methods
35  
36 ___________________________________________________________________________________________________
37
38 ## Rendering Content {#creating-controls-rendering-content}
39
40 To render content, the required actors can be created and added to the control itself as its children.
41 However, this solution is not fully optimised and means extra actors will be added, and thus, need to be processed by DALi.
42  
43 Controls should be as generic as possible so the recommendation is to re-use visuals to create the content required as described in the [Visuals](@ref visuals) section.
44 Currently, this is devel-api though, so is subject to change.
45  
46 ![ ](creating-custom-controls/rendering.png)
47
48 To add a visual to a control, first create a Property for the visual of type MAP, and ensure the name has a suffix of "_VISUAL". Then the visual is normally defined in the stylesheet, and the definition sent via SetProperty(), where you would then create the visual:
49
50 ~~~{.cpp}
51 // C++
52 void Internal::MyUIControl::SetProperty( BaseObject* object, Property::Index index, const Property::Value& value )
53 {
54   MyUIControl control = MyUIControl::DownCast( Dali::BaseHandle( object ) );
55   switch( index )
56   {
57     case MyUIControl::Property::MY_VISUAL:
58     {
59       Toolkit::VisualFactory visualFactory = Toolkit::VisualFactory::Get();
60       const Property::Map *map = value.GetMap();
61       if( map && !map->Empty() )
62       {
63         Toolkit::Visual::Base visual = visualFactory.CreateVisual( *map );
64         GetImplementation( control ).RegisterVisual( index, visual );
65       }
66       break;
67     }
68     //...
69   }
70 }
71 ~~~
72
73 The [Visuals](@ref visuals) section describes the property maps that can be used for each visual type.
74
75 ___________________________________________________________________________________________________
76
77 ## Ensuring Control is Stylable {#creating-controls-stylable}
78
79 DALi's property system allows custom controls to be easily styled.
80 The [JSON Syntax](@ref script-json-specification) is used in the stylesheets:
81  
82 **JSON Styling Syntax Example:**
83 ~~~
84 {
85   "styles":
86   {
87     "textfield":
88     {
89       "pointSize":18,
90       "primaryCursorColor":[0.0,0.72,0.9,1.0],
91       "secondaryCursorColor":[0.0,0.72,0.9,1.0],
92       "cursorWidth":1,
93       "selectionHighlightColor":[0.75,0.96,1.0,1.0],
94       "grabHandleImage" : "{DALI_STYLE_IMAGE_DIR}cursor_handler_drop_center.png",
95       "selectionHandleImageLeft" : {"filename":"{DALI_STYLE_IMAGE_DIR}selection_handle_drop_left.png" },
96       "selectionHandleImageRight": {"filename":"{DALI_STYLE_IMAGE_DIR}selection_handle_drop_right.png" }
97     }
98   }
99 }
100 ~~~
101  
102 Styling gives the UI designer the ability to change the look and feel of the control without any code changes.
103  
104 | Normal Style | Customized Style |
105 |:------------:|:----------------:|
106 |![ ](creating-custom-controls/popup-normal.png) | ![ ](creating-custom-controls/popup-styled.png)|
107  
108 More information regarding styling can be found in the [Styling](@ref styling) section.
109 ___________________________________________________________________________________________________
110
111 ### Type Registration {#creating-controls-type-registration}
112
113 The TypeRegistry is used to register your custom control.
114 This allows the creation of the control via a JSON file, as well as registering properties, signals and actions.
115  
116 To ensure your control is stylable, the process described in [Type Registration](@ref type-registration) should be followed.
117
118 #### Properties
119 To aid development, some macros are provided for registering properties which are described in the [Property](@ref properties) section.
120  
121 Control properties can be one of three types:
122  + **Event-side only:** A function is called to set this property or to retrieve the value of this property.
123                         Usually, the value is stored as a member parameter of the Impl class.
124                         Other operations can also be done, as required, in this called function.
125  + **Animatable Properties:** These are double-buffered properties that can be animated.
126  + **Custom Properties:** These are dynamic properties that are created for every single instance of the control.
127                           Therefore, these tend to take a lot of memory and are usually used by applications or other controls to dynamically set certain attributes on their children.
128                           The index for these properties can also be different for every instance.
129  
130 Careful consideration must be taken when choosing which property type to use for the properties of the custom control.
131 For example, an Animatable property type can be animated but requires a lot more resources (both in its execution and memory footprint) compared to an event-side only property.
132 ___________________________________________________________________________________________________
133
134 ## Control Services {#creating-controls-control-services}
135
136 ### Initialization {#creating-controls-init}
137
138 Controls are initialized in two steps: in the constructor, and then in the Initialize() method.
139 This is so that a handle/body connection is made within DALi Core.
140 See Dali::CustomActor & Dali::CustomActorImpl for more information.
141  
142 It is recommended to do provide a New() method in the custom control implementation where the Initialize() method should be called.
143
144 ~~~{.cpp}
145 // C++
146 MyUIControl Internal::MyUIControl::New()
147 {
148   // Create the implementation, temporarily owned on stack
149   IntrusivePtr< Internal::MyUIControl > controlImpl = new Internal::MyUIControl;
150
151   // Pass ownership to handle
152   MyUIControl handle( *controlImpl );
153
154   // Second-phase init of the implementation
155   controlImpl->Initialize();
156
157   return handle;
158 }
159 ~~~
160 Another advantage of using a New() method is that the constructor for MyUIControl can be made private (or protected).
161  
162 This will trigger the Dali::Toolkit::Internal::Control Initialize() method which will in-turn, call the virtual method OnInitialize().
163 This should be overridden by the custom ui control.
164 ~~~{.cpp}
165 // C++
166 void Internal::MyUIControl::OnInitialize()
167 {
168   // Create visuals using the VisualFactory, register events etc.
169   // Register any created visuals with Control base class
170 }
171 ~~~
172 ___________________________________________________________________________________________________
173
174 ### Control Behaviour {#creating-controls-behaviour}
175
176 Dali::Toolkit::Internal::Control provides several behaviours which are specified through its constructor (@ref Dali::Toolkit::Internal::Control::Control()).
177  
178 | Behaviour                            | Description                                                                                                    |
179 |--------------------------------------|----------------------------------------------------------------------------------------------------------------|
180 | CONTROL_BEHAVIOUR_DEFAULT              | Default behavior (size negotiation is on, style change is monitored, event callbacks are not called.                                      |
181 | DISABLE_SIZE_NEGOTIATION             | If our control does not need size negotiation, i.e. control will be skipped by the size negotiation algorithm. |
182 | REQUIRES_HOVER_EVENTS                | If our control requires [hover events](@ref creating-controls-events).                                         |
183 | REQUIRES_WHEEL_EVENTS                | If our control requires [wheel events](@ref creating-controls-events).                                         |
184 | DISABLE_STYLE_CHANGE_SIGNALS         | True if control should not monitor style change signals such as Theme/Font change.                                         |
185 | REQUIRES_KEYBOARD_NAVIGATION_SUPPORT | True if need to support keyboard navigation.                                                                   |
186 ___________________________________________________________________________________________________
187
188 ### Touch, Hover & Wheel Events {#creating-controls-events}
189
190 + A **touch event** is when any touch occurs within the bounds of the custom actor. Connect to Dali::Actor::TouchedSignal().
191 + A **hover event** is when a pointer moves within the bounds of a custom actor (e.g. mouse pointer or hover pointer).
192 + A **wheel event** is when the mouse wheel (or similar) is moved while hovering over an actor (via a mouse pointer or hover pointer).
193  
194 If the control needs to utilize hover and wheel events, then the correct behaviour flag should be used when constructing the control and then the appropriate method should be overridden.
195 ~~~{.cpp}
196 // C++
197 bool Internal::MyUIControl::OnHoverEvent( const HoverEvent& event )
198 {
199   bool consumed = false;
200
201   // Handle hover event
202
203   // Return true if handled/consumed, false otherwise
204   return consumed;
205 }
206 ~~~
207 ~~~{.cpp}
208 // C++
209 bool Internal::MyUIControl::OnWheelEvent( const WheelEvent& event )
210 {
211   bool consumed = false;
212
213   // Handle wheel event
214
215   // Return true if handled/consumed, false otherwise
216   return consumed;
217 }
218 ~~~
219 ___________________________________________________________________________________________________
220
221 ### Gestures {#creating-controls-gestures}
222
223 DALi has a gesture system which analyses a stream of touch events and attempts to determine the intention of the user.
224 The following gesture detectors are provided:
225  
226  + **Pan:** When the user starts panning (or dragging) one or more fingers.
227             The panning should start from within the bounds of the control.
228  + **Pinch:** Detects when two touch points move towards or away from each other.
229               The center point of the pinch should be within the bounds of the control.
230  + **Tap:** When the user taps within the bounds of the control.
231  + **LongPress:** When the user presses and holds on a certain point within the bounds of a control.
232  
233 The control base class provides basic set up to detect these gestures.
234 If any of these detectors are required then this can be specified in the OnInitialize() method (or as required).
235  
236 ~~~{.cpp}
237 // C++
238 void Internal::MyUIControl::OnInitialize()
239 {
240   // Only enable pan gesture detection
241   EnableGestureDetection( Gesture::Pan );
242
243   // Or if several gestures are required
244   EnableGestureDetection( Gesture::Type( Gesture::Pinch | Gesture::Tap | Gesture::LongPress ) );
245 }
246 ~~~
247  
248 The above snippet of code will only enable the default gesture detection for each type.
249 If customization of the gesture detection is required, then the gesture-detector can be retrieved and set up accordingly in the same method.
250  
251 ~~~{.cpp}
252 // C++
253 PanGestureDetector panGestureDetector = GetPanGestureDetector();
254 panGestureDetector.AddDirection( PanGestureDetector::DIRECTION_VERTICAL );
255 ~~~
256  
257 Finally, the appropriate method should be overridden:
258 ~~~{.cpp}
259 // C++
260 void Internal::MyUIControl::OnPan( const PanGesture& pan )
261 {
262   // Handle pan-gesture
263 }
264 ~~~
265 ~~~{.cpp}
266 // C++
267 void Internal::MyUIControl::OnPinch( const PinchGesture& pinch )
268 {
269   // Handle pinch-event
270 }
271 ~~~
272 ~~~{.cpp}
273 // C++
274 void Internal::MyUIControl::OnTap( const TapGesture& tap )
275 {
276   // Handle tap-gesture
277 }
278 ~~~
279 ~~~{.cpp}
280 // C++
281 void Internal::MyUIControl::OnLongPress( const LongPressGesture& longPress )
282 {
283   // Handle long-press-gesture
284 }
285 ~~~
286  
287 ___________________________________________________________________________________________________
288
289 ### Accessibility {#creating-controls-accessibility}
290
291 Accessibility is functionality that has been designed to aid usage by the visually impaired.
292 More information can be found in the [Accessibility](@ref accessibility) section.
293  
294 Accessibility behaviour can be customized in the control by overriding certain virtual methods.
295 This is detailed [here](@ref accessibilitycustomcontrol).
296  
297 ___________________________________________________________________________________________________
298
299 ### Signals {#creating-controls-signals}
300
301 If applications need to react to changes in the control state, controls can inform those applications using Dali::Signal.
302
303 First, create a signature of the function the signal will call in the handle header file:
304 ~~~{.cpp}
305 // C++: my-ui-control.h
306 typedef Signal< void () > SignalType;
307 ~~~
308  
309 Then Create methods to get to the signal:
310 ~~~{.cpp}
311 // C++: my-ui-control.h
312 MyUIControl::SignalType& MyCustomSignal();
313 ~~~
314
315 The source file should just call the impl:
316 ~~~{.cpp}
317 // C++: my-ui-control.cpp
318 MyUIControl::SignalType& MyUIControl::MyCustomSignal()
319 {
320   return Dali::Toolkit::GetImplementation( *this ).MyCustomSignal();
321 }
322 ~~~
323  
324 In the impl file, create an instance of the signal as follows and return it in the appropriate method:
325 ~~~{.cpp}
326 // C++: my-ui-control-impl.h
327 public:
328
329   MyUIControl::SignalType MyUIControl::MyCustomSignal()
330   {
331     return mMyCustomSignal;
332   }
333
334 private:
335
336   MyUIControl::SignalType mMyCustomSignal;
337 ~~~
338  
339 Then, when you wish to emit this signal:
340 ~~~{.cpp}
341 // C++: my-ui-control-impl.cpp
342 mMyCustomSignal.Emit();
343 ~~~
344 There is no need to check if there is anything connected to this signal as this is done by the framework.
345  
346 The application can then connect to the signal as follows:
347 ~~~{.cpp}
348 void AppFunction()
349 {
350   // Do Something
351 }
352
353 ...
354
355 customControl.MyCustomSignal.Connect( this, &AppFunction );
356 ~~~
357  
358 ___________________________________________________________________________________________________
359
360 ### Children Added/Removed {#creating-controls-children}
361
362 Methods are provided that can be overridden if notification is required when a child is added or removed from our control.
363 An up call to the Control class is necessary if these methods are overridden.
364  
365 ~~~{.cpp}
366 // C++
367 void Internal::MyUIControl::OnChildAdd( Actor& child );
368 {
369   // Do any other operations required upon child addition
370
371   // Up call to Control at the end
372   Control::OnChildAdd( child );
373 }
374 ~~~
375 ~~~{.cpp}
376 // C++
377 void Internal::MyUIControl::OnChildRemove( Actor& child );
378 {
379   // Do any other operations required upon child removal
380
381   // Up call to Control at the end
382   Control::OnChildRemove( child );
383 }
384 ~~~
385  
386 Avoid adding or removing the child again within these methods.
387  
388 ___________________________________________________________________________________________________
389
390 ### Scene Connection {#creating-controls-scene}
391
392 Methods are provided that can be overridden if notification is required when our control is connected to or disconnected from the scene.
393 An up call to the Control class is necessary if these methods are overridden.
394  
395 ~~~{.cpp}
396 // C++
397 void Internal::MyUIControl::OnSceneConnection( int depth )
398 {
399   // Do any other operations required upon scene connection
400
401   // Up call to Control at the end
402   Control::OnSceneConnection( depth );
403 }
404 ~~~
405 ~~~{.cpp}
406 // C++
407 void Internal::MyUIControl::OnSceneDisconnection()
408 {
409   // Do any other operations required upon scene disconnection
410
411   // Up call to Control at the end
412   Control::OnSceneDisconnection();
413 }
414 ~~~
415  
416 ___________________________________________________________________________________________________
417
418 ### Size Negotiation {#creating-controls-size-negotiation}
419
420 The following methods must be overridden for size negotiation to work correctly with a custom control.
421  
422 ~~~{.cpp}
423 // C++
424 Vector3 Internal::MyUIControl::GetNaturalSize()
425 {
426   // Return the natural size of the control
427   // This depends on our layout
428   // If we have one visual, then we can return the natural size of that
429   // If we have more visuals, then we need to calculate their positions within our control and work out the overall size we would like our control to be
430
431   // After working out the natural size of visuals that belong to this control,
432   // should also chain up to ensure other visuals belonging to the base class are
433   // also taken into account:
434   Vector2 baseSize = Control::GetNaturalSize(); // returns the size of the background.
435 }
436 ~~~
437 ~~~{.cpp}
438 // C++
439 float Internal::MyUIControl::GetHeightForWidth( float width )
440 {
441   // Called by the size negotiation algorithm if we have a fixed width
442   // We should calculate the height we would like our control to be for that width
443
444   // Should also chain up to determine the base class's preferred height:
445   float baseHeight = Control::GetHeightForWidth( width );
446
447 }
448 ~~~
449 ~~~{.cpp}
450 // C++
451 float Internal::MyUIControl::GetWidthForHeight( float height )
452 {
453   // Called by the size negotiation algorithm if we have a fixed height
454   // We should calculate the width we would like our control to be for that height
455
456   // Should also chain up to determine the base class's preferred width:
457   float baseWidth = Control::GetWidth( height );
458 }
459 ~~~
460 ~~~{.cpp}
461 // C++
462 void Internal::MyUIControl::OnRelayout( const Vector2& size, RelayoutContainer& container )
463 {
464   // The size is what we have been given and what our control needs to fit into
465   // Here, we need to set the position and the size of our visuals
466   // If we have other controls/actors as children
467   //  - Add the control/actor to the container paired with the size required
468   //  - To ensure this works, you need to set up the control with a relayout policy of USE_ASSIGNED_SIZE
469   //  - DO NOT CALL SetSize on this control: This will trigger another size negotiation calculation
470   // DO NOT chain up to base class.
471 }
472 ~~~
473 More information on size negotiation can be found [here](@ref size-negotiation-controls).
474  
475 ___________________________________________________________________________________________________
476
477 ### Clipping Support {#creating-controls-clipping}
478
479 When an Actor is set to clip its children, the renderers have to be added manually in order to specify what its children need to clip to.
480 The Control base class automates the creation of the visuals when it is set to clip its children.
481  
482 This is only done if the application or custom control writer has not
483 added any Renderers to the Control or registered any visuals
484 (regardless of whether these visuals are enabled or not).
485  
486 If custom control writers want to define the clipping visuals themselves, then they should register all required visuals before the control is staged.
487  
488 ___________________________________________________________________________________________________
489
490 ### Other Features {#creating-controls-other}
491
492  + [Background](@ref background)
493  
494 ___________________________________________________________________________________________________
495
496
497 */