Dali 3D User Interface Engine
creating-custom-controls

Table of Contents

Creating Custom UI Controls

DALi provides the ability to create custom UI controls. This can be done by extending Dali::Toolkit::Control and Dali::Toolkit::Internal::Control classes.

Custom controls are created using the handle/body idiom used in DALi.

control-handle-body.png

General Guidelines:


Rendering Content

To render content, the required actors can be created and added to the control itself as its children. However, this solution is not fully optimised and means extra actors will be added, and thus, need to be processed by DALi.

Controls should be as generic as possible so the recommendation is to re-use control renderers to create the content required as described in the Control Renderers section. Currently, this is devel-api though, so is subject to change.

rendering.png

Ensuring Control is Stylable

DALi's property system allows custom controls to be easily styled. The JSON Syntax is used in the stylesheets:

JSON Styling Syntax Example:

{
"styles":
{
"textfield":
{
"pointSize":18,
"primaryCursorColor":[0.0,0.72,0.9,1.0],
"secondaryCursorColor":[0.0,0.72,0.9,1.0],
"cursorWidth":1,
"selectionHighlightColor":[0.75,0.96,1.0,1.0],
"grabHandleImage" : "{DALI_STYLE_IMAGE_DIR}cursor_handler_drop_center.png",
"selectionHandleImageLeft" : {"filename":"{DALI_STYLE_IMAGE_DIR}selection_handle_drop_left.png" },
"selectionHandleImageRight": {"filename":"{DALI_STYLE_IMAGE_DIR}selection_handle_drop_right.png" }
}
}
}

Styling gives the UI designer the ability to change the look and feel of the control without any code changes.

Normal Style Customized Style
popup-normal.png
popup-styled.png

More information regarding styling can be found in the Styling section.


Type Registration

The TypeRegistry is used to register your custom control. This allows the creation of the control via a JSON file, as well as registering properties, signals and actions.

To ensure your control is stylable, the process described in Type Registration should be followed. To aid development, some macros are provided for registering properties which are described in the Property section.

Control properties can be one of three types:

Careful consideration must be taken when choosing which property type to use for the properties of the custom control. 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.


Control Services

Initialization

Controls are initialized in two steps: in the constructor, and then in the Initialize() method. This is so that a handle/body connection is made within DALi Core. See Dali::CustomActor & Dali::CustomActorImpl for more information.

It is recommended to do provide a New() method in the custom control implementation where the Initialize() method should be called.

// C++
MyUIControl MyUIControlImpl::New()
{
// Create the implementation, temporarily owned on stack
IntrusivePtr< MyUIControlImpl > controlImpl = new MyUIControlImpl;
// Pass ownership to handle
MyUIControl handle( *controlImpl );
// Second-phase init of the implementation
controlImpl->Initialize();
return handle;
}

Another advantage of using a New() method is that the constructor for MyUIControl can be made private (or protected).

This will trigger the Dali::Toolkit::Internal::Control Initialize() method which will in-turn, call the virtual method OnInitialize(). This should be overridden by the custom ui control.

// C++
void MyUIControlImpl::OnInitialize()
{
// Create renderers, register events etc.
}

Control Behaviour

Dali::Toolkit::Internal::Control provides several behaviours which are specified through its constructor (Dali::Toolkit::Internal::Control::Control()).

Behaviour Description
ACTOR_BEHAVIOUR_NONE No behaviour required.
REQUIRES_TOUCH_EVENTS If our control requires touch events.
REQUIRES_HOVER_EVENTS If our control requires hover events.
REQUIRES_WHEEL_EVENTS If our control requires wheel events.
REQUIRES_STYLE_CHANGE_SIGNALS True if need to monitor style change signals such as Theme/Font change.
REQUIRES_KEYBOARD_NAVIGATION_SUPPORT True if need to support keyboard navigation.

Touch, Hover & Wheel Events

If the control should needs to utilise these events, then the correct behaviour flag should be used when constructing the control.

Then the appropriate method should be overridden.

// C++
bool MyUIControlImpl::OnTouchEvent( const TouchEvent& event )
{
bool consumed = false;
// Handle touch event
// Return true if handled/consumed, false otherwise
return consumed;
}
// C++
bool MyUIControlImpl::OnHoverEvent( const HoverEvent& event )
{
bool consumed = false;
// Handle hover event
// Return true if handled/consumed, false otherwise
return consumed;
}
// C++
bool MyUIControlImpl::OnWheelEvent( const WheelEvent& event )
{
bool consumed = false;
// Handle wheel event
// Return true if handled/consumed, false otherwise
return consumed;
}

Gestures

DALi has a gesture system which analyses a stream of touch events and attempts to determine the intention of the user. The following gesture detectors are provided:

The control base class provides basic set up to detect these gestures. If any of these detectors are required then this can be specified in the OnInitialize() method (or as required).

// C++
void MyUIControlImpl::OnInitialize()
{
// Only enable pan gesture detection
EnableGestureDetection( Gesture::Pan );
// Or if several gestures are required
EnableGestureDetection( Gesture::Type( Gesture::Pinch | Gesture::Tap | Gesture::LongPress ) );
}

The above snippet of code will only enable the default gesture detection for each type. If customization of the gesture detection is required, then the gesture-detector can be retrieved and set up accordingly in the same method.

// C++
PanGestureDetector panGestureDetector = GetPanGestureDetector();
panGestureDetector.AddDirection( PanGestureDetector::DIRECTION_VERTICAL );

Finally, the appropriate method should be overridden:

// C++
void MyUIControlImpl::OnPan( const PanGesture& pan )
{
// Handle pan-gesture
}
// C++
void MyUIControlImpl::OnPinch( const PinchGesture& pinch )
{
// Handle pinch-event
}
// C++
void MyUIControlImpl::OnTap( const TapGesture& tap )
{
// Handle tap-gesture
}
// C++
void MyUIControlImpl::OnLongPress( const LongPressGesture& longPress )
{
// Handle long-press-gesture
}

Accessibility

Accessibility is functionality that has been designed to aid usage by the visually impaired. More information can be found in the Accessibility section.

Accessibility behaviour can be customized in the control by overriding certain virtual methods. This is detailed here.


Signals

If applications need to react to changes in the control state, controls can inform those applications using Dali::Signal.

First, create a signature of the function the signal will call in the handle header file:

// C++: my-ui-control.h
typedef Signal< void () > SignalType;

Then Create methods to get to the signal:

// C++: my-ui-control.h
MyUIControl::SignalType& MyCustomSignal();

The source file should just call the impl:

// C++: my-ui-control.cpp
MyUIControl::SignalType& MyUIControl::MyCustomSignal()
{
return Dali::Toolkit::GetImplementation( *this ).MyCustomSignal();
}

In the impl file, create an instance of the signal as follows and return it in the appropriate method:

// C++: my-ui-control-impl.h
public:
MyUIControl::SignalType MyUIControl::MyCustomSignal()
{
return mMyCustomSignal;
}
private:
MyUIControl::SignalType mMyCustomSignal;

Then, when you wish to emit this signal:

// C++: my-ui-control-impl.cpp
mMyCustomSignal.Emit();

There is no need to check if there is anything connected to this signal as this is done by the framework.

The application can then connect to the signal as follows:

void AppFunction()
{
// Do Something
}
...
customControl.MyCustomSignal.Connect( this, &AppFunction );

Other Features


Dali Docs Home
Read more about Dali