UI Component Preferences
Customizing UI Components
Elementary UI components use the Edje library EDC themes to manage their look.
Elementary Theme
An Elementary theme is an Edje EDC file that contains groups composed of parts and programs. For more information about Edje, refer to the Edje guide.
Use Theme Styles
Elementary UI components provide a way to modify only some parts of the styles using the default theme. A style is a part of the EDC theme (a group) that concerns only one UI component. For example, you can create a new style for a button component to change its appearance without modifying the default theme.
Note |
---|
When creating a new style, knowledge of how each UI component is themed is required, because setting another style always replaces the entire group used by the UI component. Important signals and parts must be there for the object to behave properly. |
When several styles are loaded in the current theme, you can set a different style to a specific UI component using the elm_object_style_set() function. It is also possible to see the current style with the elm_object_style_get() function.
The default theme specifies several styles for the button component. The code below shows how to set the "anchor" style of a newly created button component.
Evas_Object *parent, *button; // Create a button object button = elm_button_add(parent); // Set its style to "anchor"" elm_object_style_set(button, "anchor");
Load Theme Styles
Once written and compiled with Edje tools, the Elementary provides two methods to load the style in the application theme:
- overlays
- extensions
When looking for a theme, the Elementary checks the list of overlays, if any are defined. Then it takes the default theme, and if it cannot find a theme for the UI component, it looks at the extensions list.
Overlay
An overlay can replace the look of all UI components by overriding the default style. If we create a new style called "default" for the button component and add it as an overlay, the Elementary uses the overlay for all button components overriding the default theme.
Here is how to add an overlay to your application's theme.
elm_theme_overlay_add(NULL, "./theme_button.edj");
Note |
---|
Here we assume that the "theme_button.edj" file only contains a new theme for the button component. |
Note |
---|
Doing this is not recommended. Adding a file as an overlay makes the Elementary use the new theme for all the button components defined in the application. You must make sure that the "theme_button.edj" file reimplements everything that was previously defined in the default theme concerning the button component. |
This is how to remove the previously added overlay to return to the default theme.
elm_theme_overlay_del(NULL, "./theme_button.edj");
Extension
With extensions, we can write styles that we can apply to some UI components (not all of them) by using the elm_object_style_set() function.
The application adds a theme to the list of extensions with the following call.
elm_theme_extension_add(NULL, "./theme_button_style_custom.edj");
Note |
---|
Here we assume that the "theme_button_style_custom.edj" file contains a new button style called "custom". |
This is how to use the new "custom" style on a button component.
Evas_Object *parent, *button; // Create a button object button = elm_button_add(parent); // Set its style to "custom" elm_object_style_set(button, "custom");
Note |
---|
When using elm_theme_extension_add or elm_theme_overlay_add to add a new theme extension or overlay to a Theme object (here called the default theme), the Elementary calls the elm_theme_flush function to flush Elementary theme caches. Thus, the theme of all UI components that use the default theme is reloaded. |
Create a New Theme
This is how to create a new theme object.
Elm_Theme *new_theme = elm_theme_new();
This function creates an empty specific theme that only uses the default theme. It has its own private set of extensions and overlays (which are empty by default). Specific themes do not fall back to the themes of parent objects. They are not intended for this use.
This is how to apply this theme to a UI component and its children (a button, for example).
// Create a button component Evas_Object *button = elm_button_add(); // Set the new theme to the button component elm_object_theme_set(button, new_theme);
Customizing a UI Component Style
UI component themes are written in Edje EDC source files (.edc). These files are compiled with Edje tools to make an .edj file that is used by the application. For more information on using the EDC language, see the Edje guide.
A new Edje style can be added for a UI component. The best way is to copy the existing "default" style, rename it, and update it to your needs.
Create a Customized Style for the Check Component
As an example, we show how to create a new style for the check component. The aim is to update the background and the main pictures of this UI component with custom pictures.
The EDC source file concerning the check component (check.edc file) is composed of several groups.
group { name: "elm/check/base/default"; } group { name: "elm/check/base/toggle"; }
Those two groups define two different styles for the check component (the "default" style and the "toggle" style).
We copy the group corresponding to the "default" style in a new file to create a new style called "custom". This new style is saved in the "check_custom.edc" file.
group { name: "elm/check/base/custom"; // Here is the copy of the content of "default" style }
In the new group ("elm/check/base/custom"), we have to find the parts we want to modify. Here, the appropriate parts are "bg" and "check" parts.
part { name: "bg"; mouse_events: 0; scale: 1; description { state: "default" 0.0; rel1.offset: 1 1; rel2.relative: 0.0 1.0; rel2.offset: 1 -2; align: 0.0 0.5; min: 16 16; max: 16 16; aspect: 1.0 1.0; aspect_preference: VERTICAL; image { normal: "check_base.png"; border: 5 5 5 5; middle: 0; } fill.smooth: 0; } } part { name: "check"; mouse_events: 0; scale: 1; description { state: "default" 0.0; rel1 { to: "bg"; offset: 1 1; } rel2 { to: "bg"; offset: -2 -2; } visible: 0; color: 255 255 255 255; image.normal: "check.png"; } description { state: "visible" 0.0; inherit: "default" 0.0; visible: 1; } description { state: "disabled" 0.0; inherit: "default" 0.0; visible: 0; color: 128 128 128 128; } description { state: "disabled_visible" 0.0; inherit: "default" 0.0; color: 128 128 128 128; visible: 1; } }
We do not detail all the options that can be modified here, but assume that the user is familiar with Edje and knows Edje basics.
Our custom pictures filenames are:
- check_base_custom.png for the bg part
- check_custom.png for the check part
We must update the image.normal attribute in both parts with our custom pictures filenames to modify the pictures of this style.
part { name: "bg"; description { state: "default" 0.0; image { normal: "check_base_custom.png"; border: 5 5 5 5; middle: 0; } } } part { name: "check"; description { state: "default" 0.0; image.normal: "check_custom.png"; } }
Note |
---|
Here, we assume that the custom images are the same size as the "default" images. |
Add the Theme File to Your Project
Once written, the check_custom.edc file is put in the /res/edje/. directory of the application project in the SDK.
When building the application, the SDK calls the Edje tools automatically to build the final check_custom.edj file. This file can be loaded from our application.
Use the New Style
This is how to add the new theme file as an extension in the application.
char edj_path[PATH_MAX] = {0, }; // Get the full path of the edj file app_get_resource("/edje/check_custom.edj", edj_path, (int)PATH_MAX); // Load check custom style as an extension elm_theme_extension_add(NULL, edj_path);
Use the "custom" style on a new check component.
Evas_Object *parent, *check; // Create a check object check = elm_check_add(parent); // Set its style to "custom" elm_object_style_set(check, "custom");
Special Theme Parts
Some parts of the EDC file can be interacted with the Elementary. The content of parts of the type TEXT are modified using the elm_object_part_set_text() function. The content of SWALLOW parts is updated using the elm_object_part_content_set() function.
Swallow Parts
In the previous example (the check component "default" style), there is a part called "elm.swallow.content" that is of the type SWALLOW.
part { name: "elm.swallow.content"; type: SWALLOW; scale: 1; description { state: "default" 0.0; fixed: 1 0; visible: 0; align: 0.0 0.5; rel1.to_x: "bg"; rel1.relative: 1.0 0.0; rel1.offset: 1 1; rel2.to_x: "bg"; rel2.offset: 1 -2; rel2.relative: 1.0 1.0; } description { state: "visible" 0.0; inherit: "default" 0.0; fixed: 1 0; visible: 1; aspect: 1.0 1.0; min: 16 16; } description { state: "disabled" 0.0; inherit: "default" 0.0; color: 255 255 255 128; } description { state: "disabled_visible" 0.0; inherit: "default" 0.0; color: 255 255 255 128; fixed: 1 0; visible: 1; aspect: 1.0 1.0; } }
We can push content (Evas_Object) to this part from the application anytime. The size and position of the content pushed is controlled by the EDC theme.
Evas_Object *parent, *check1, *content; // Create a check object check1 = elm_check_add(parent); // Set the content of the check object elm_object_part_content_set(check1, "elm.swallow.content", content);
Note |
---|
We can add new SWALLOW parts when customizing a UI component's style, if we want to be able to control more content from the application. Note that removing existing SWALLOW parts changes the UI component's behavior. |
Text Parts
The same is done with parts of the type TEXT. The check "default" style contains a part named "elm.text".
part { name: "elm.text"; type: TEXT; mouse_events: 0; scale: 1; description { state: "default" 0.0; visible: 0; rel1.to_x: "elm.swallow.content"; rel1.relative: 1.0 0.0; rel1.offset: 1 1; rel2.relative: 1.0 1.0; rel2.offset: -2 -2; color: 0 0 0 255; text { font: "Sans,Edje-Vera"; size: 10; min: 0 1; align: -1.0 0.5; } } description { state: "visible" 0.0; inherit: "default" 0.0; visible: 1; text.min: 1 1; } description { state: "disabled" 0.0; inherit: "default" 0.0; color: 0 0 0 128; color3: 0 0 0 0; } description { state: "disabled_visible" 0.0; inherit: "default" 0.0; color: 0 0 0 128; color3: 0 0 0 0; visible: 1; text.min: 1 1; } }
This is how to modify the content of the "elm.text" part from the application. The position of the text, its size, color, look and feel are managed by the EDC theme.
Evas_Object *parent, *check2; // Create a check object check2 = elm_check_add(parent); // Set the text of the check object elm_object_part_text_set(check2, "elm.text", "Test text");
Managing UI Component Focus
Focus Presentation
Concept of Focus
Focus is a graphical user interface concept. A component, for example, a UI component, has a focus when it is selected to receive input from the user. The input can be an event, such as mouse button click or key press.
Giving Focus
Focusing can be immediate (selected by the touchscreen or mouse) or relative (selected by a key press).
There are mainly two ways to set focus on a graphical elements:
- Direct selection: this is done by clicking on the element.
- Relative selection: this is done by moving the selection from a UI component to another, such as going to the previous or next one; this is done with a keyboard.
Direct selection does not really need any kind of special treatment as the user explicitly selects the UI component to interact with.
Relative selection' default order is the one the UI components have been added to the canvas. That may not be appropriate, if they are added programmatically in different order than they appear on-screen.
Moving Focus
Concept of Focus Chain
The order the focus goes from a UI component to another is called the focus chain. As said before, the default focus chain is set to the order the UI components have been added to the canvas.
Focusable Objects
An object can be focused if the following conditions apply:
- object is visible
- object is enabled
- object accepts focus
- object's subtree (if any) is focusable
- all of object's parents have their subtrees focusable
If any of these conditions do not apply, the object is unfocusable.
Handling Key Input
Handling of the keys is done automatically by Elementary. According to which key the user pressed, Elementary switches the focus in the selected direction. For example, using the Tab key the focus goes to the next object in the natural order, whereas using the direction keys the focus goes to the next object in the requested direction.
Hiding, Deleting or Disabling a Focused Object
When a UI component is hidden, deleted, or disabled, it becomes unfocusable.
When a focused object is unfocusable, the focus is moved to another object.
Selecting Next Object
When the user wants to switch the focus to the next object (i.e. cycle focus), Elementary searches the first object which is focusable.
If there is a disabled or read-only object in the focus chain, the focus goes to the following object in the requested direction.
Customizing Focus
There are several reasons why to customize the focus chain of an application, for example:
- If you have created a form with labels and text entries next to them, the focus moves to the entry field when the user clicks on the associated label.
- If you have created an interface with several columns (table), set the focus chain as you wish, for example, going horizontally instead of going vertically, regardless whatever the order the UI components are added.
Customizing Object's Focus Exit Chain
Set the object to focus after other object in a specific direction using elm_object_focus_next_object_set(object, next, direction). Use the following directions:
- ELM_FOCUS_NEXT: next UI component in natural order
- ELM_FOCUS_PREVIOUS: previous UI component in natural order
- ELM_FOCUS_UP: UI component to focus when going up
- ELM_FOCUS_DOWN: UI component to focus when going down
- ELM_FOCUS_RIGHT: UI component to focus when going right
- ELM_FOCUS_LEFT: UI component to focus when going left
Set the object next to another in a specific direction using elm_object_focus_next_object_get(object, direction).
Customizing Whole Application's Focus Chain
To customize the application's custom chain:
Evas_Object *main, obj1, obj2, obj3, obj4, obj5; Eina_List *focus_chain = NULL; focus_chain = eina_list_append(focus_chain, obj3); focus_chain = eina_list_append(focus_chain, obj2); // The chain is obj3, then obj2. We set it. elm_object_focus_custom_chain_set(main, focus_chain); // Here we prepend obj5 at the beginning of the chain. elm_object_focus_chain_prepend(main, NULL, obj5); // We append obj1 after obj3. elm_object_focus_chain_append(main, obj3, obj1); // We prepend obj4 before obj1. elm_object_focus_chain_prepend(main, obj1, obj4);
The focus chain is obj5, obj3, obj4, obj1, obj2.
This actually applies to any container: it is possible to set the focus chain of, for example, a box.
Customizing Collision of Both
If an object is part of a focus chain and has the next focused object defined, the next object takes precedence over the focus chain.
Following on the previous example, if obj4 has obj5 defined as its next object, the actual focus chain is obj5, obj3, obj4, and loop back to obj5.
Focus on UI Component
If your Evas object has several sub-objects, set its focus chain using the same functions as for the application. Elementary first follows the main focus chain, and then the focus chain of each UI component if applicable.
Use elm_object_focus_get(object) to set whether a specific object has the focus. Set the focus to an object using elm_object_focus_set(object, set), where set is a Boolean value. If it is set to EINA_TRUE, the focus is set to that given object. If it is set to EINA_False, the focus is unset and passed back to the previous element in the focus chain. Set the focus only after the object is shown, that is, after evas_object_show(object) has been called. Call the function back when the object receives or loses focus by registering on smart event "focused" or "unfocused"
Use elm_object_tree_focus_allow_set(object, focusable) to tell Elementary whether an object and its children are focusable, where focusable is a Boolean value. Get the current value using elm_object_tree_focus_allow_get(object).
The similar functions for a specific object are elm_object_focus_allow_set(object, focusable) and elm_object_focus_allow_get(object).
For more details about customizing the look and feel of the UI components with custom styles which are not provided as defaults, see the ThemeExtension sample.