Theme - Using extensions

Using extensions is extremely easy, discarding the part where you have to write the theme for them.

In the following example we'll be creating two buttons, one to load or unload our extension theme and one to cycle around three possible styles, one of which we created.

After including our one and only header we'll jump to the callback for the buttons. First one takes care of loading or unloading our extension file, relative to the default theme set (thus the NULL in the functions first parameter).

#include <Elementary.h>
static void
btn_extension_click_cb(void *data EINA_UNUSED, Evas_Object *btn, void *ev EINA_UNUSED)
{
const char *lbl = elm_object_text_get(btn);
if (!strncmp(lbl, "Load", 4))
{
elm_theme_extension_add(NULL, edj_path);
elm_object_text_set(btn, "Unload extension");
}
#define EINA_UNUSED
Used to indicate that a function parameter is purposely unused.
Definition: eina_types.h:339
void elm_theme_extension_add(Elm_Theme *th, const char *item)
Appends a theme extension to the list of extensions.
Definition: elm_theme.c:769
Efl_Canvas_Object Evas_Object
An Evas Object handle.
Definition: Evas_Common.h:185
else if (!strncmp(lbl, "Unload", 6))
{
elm_theme_extension_del(NULL, edj_path);
elm_object_text_set(btn, "Load extension");
}
void elm_theme_extension_del(Elm_Theme *th, const char *item)
Deletes a theme extension from the list of extensions.
Definition: elm_theme.c:777
}

The second button, as we said before, will just switch around different styles. In this case we have three of them. The first one is our custom style, named after something very unlikely to find in the default theme. The other two styles are the standard and one more, anchor, which exists in the default and is similar to the default, except the button vanishes when the mouse is not over it.

static void
btn_style_click_cb(void *data EINA_UNUSED, Evas_Object *btn, void *ev EINA_UNUSED)
{
const char *styles[] = {
"chucknorris",
"default",
"anchor"
};
static int sel_style = 0;
sel_style = (sel_style + 1) % 3;
elm_object_style_set(btn, styles[sel_style]);
}
Eina_Bool elm_object_style_set(Evas_Object *obj, const char *style)
Set the style to used by a given widget.
Definition: elm_main.c:1583

So what happens if the style switches to our custom one when the extension is loaded? Elementary falls back to the default for the widget.

And the main function, simply enough, will create the window, set the buttons and their callbacks, and just to begin with our button styled we're also loading our extension at the beginning.

EAPI_MAIN int
elm_main(int argc EINA_UNUSED, char **argv EINA_UNUSED)
{
Evas_Object *win, *box, *btn;
#ifdef PACKAGE_DATA_DIR
elm_app_compile_data_dir_set(PACKAGE_DATA_DIR);
#endif
if (ecore_file_exists("./theme_example.edj"))
{
strcpy(edj_path, "./theme_example.edj");
}
else
{
elm_app_info_set(elm_main, "elementary", "examples/theme_example.edj");
snprintf(edj_path, sizeof(edj_path), "%s/examples/theme_example.edj",
}
elm_theme_extension_add(NULL, edj_path);
win = elm_win_util_standard_add("theme", "Theme example");
box = elm_box_add(win);
btn = elm_button_add(win);
elm_object_text_set(btn, "Unload extension");
elm_box_pack_end(box, btn);
evas_object_smart_callback_add(btn, "clicked", btn_extension_click_cb, NULL);
btn = elm_button_add(win);
elm_object_text_set(btn, "Switch style");
elm_object_style_set(btn, "chucknorris");
elm_box_pack_end(box, btn);
evas_object_smart_callback_add(btn, "clicked", btn_style_click_cb, NULL);
evas_object_resize(win, 300, 320);
return 0;
}
#define EVAS_HINT_EXPAND
Use with evas_object_size_hint_weight_set(), evas_object_size_hint_weight_get(), evas_object_size_hin...
Definition: Evas_Common.h:297
Eina_Bool ecore_file_exists(const char *file)
Checks if the given file exists.
Definition: ecore_file.c:165
#define EINA_TRUE
boolean value TRUE (numerical value 1)
Definition: eina_types.h:539
void elm_app_info_set(void *mainfunc, const char *dom, const char *checkfile)
Re-locate the application somewhere else after compilation, if the developer wishes for easier distri...
Definition: elm_main.c:496
void elm_app_compile_data_dir_set(const char *dir)
Provide information on the fallback application's data directory, on scenarios where they get overrid...
Definition: elm_main.c:528
const char * elm_app_data_dir_get(void)
Get the application's run time data prefix directory, as set by elm_app_info_set() and the way (envir...
Definition: elm_main.c:586
Evas_Object * elm_box_add(Evas_Object *parent)
Add a new box to the parent.
Definition: elm_box.c:363
void elm_box_pack_end(Elm_Box *obj, Efl_Canvas_Object *subobj)
Add an object at the end of the pack list.
Definition: elm_box_eo.legacy.c:57
Evas_Object * elm_button_add(Evas_Object *parent)
Add a new button to the parent's canvas.
Definition: efl_ui_button.c:459
#define ELM_MAIN()
macro to be used after the elm_main() function
Definition: elm_general.h:556
Eina_Bool elm_policy_set(unsigned int policy, int value)
Set a new policy's value (for a given policy group/identifier).
Definition: elm_main.c:1380
void elm_run(void)
Run Elementary's main loop.
Definition: elm_main.c:1357
@ ELM_POLICY_QUIT_LAST_WINDOW_CLOSED
quit when the application's last window is closed
Definition: elm_general.h:248
@ ELM_POLICY_QUIT
under which circumstances the application should quit automatically.
Definition: elm_general.h:227
Evas_Object * elm_win_util_standard_add(const char *name, const char *title)
Adds a window object with standard setup.
Definition: efl_ui_win.c:9582
void elm_win_resize_object_add(Eo *obj, Evas_Object *subobj)
Add subobj as a resize object of window obj.
Definition: efl_ui_win.c:8997
void elm_win_autodel_set(Eo *obj, Eina_Bool autodel)
Set the window's autodel state.
Definition: efl_ui_win.c:6194
EVAS_API void evas_object_show(Evas_Object *eo_obj)
Makes the given Evas object visible.
Definition: evas_object_main.c:1814
EVAS_API void evas_object_size_hint_weight_set(Evas_Object *obj, double x, double y)
Sets the hints for an object's weight.
Definition: evas_object_main.c:2638
EVAS_API void evas_object_resize(Evas_Object *obj, Evas_Coord w, Evas_Coord h)
Changes the size of the given Evas object.
Definition: evas_object_main.c:1236
EVAS_API void evas_object_smart_callback_add(Evas_Object *eo_obj, const char *event, Evas_Smart_Cb func, const void *data)
Add (register) a callback function to the smart event specified by event on the smart object obj.
Definition: evas_object_smart.c:1040

In this case we wanted to easily remove extensions, but all adding an extension does is tell Elementary where else it should look for themes when it can't find them in the default theme. Another way to do this is to set the theme search order using elm_theme_set(), but this requires that the developer is careful not to override any user configuration. That can be helped by adding our theme to the end of whatever is already set, like in the following snippet.

char buf[4096];
snprintf(buf, sizeof(buf), "%s:./theme_example.edj", elme_theme_get(NULL);
elm_theme_set(NULL, buf);
void elm_theme_set(Elm_Theme *th, const char *theme)
Set the theme search order for the given theme.
Definition: elm_theme.c:825

If we were using overlays instead of extensions, the same thing applies, but the custom theme must be added to the front of the search path.

In the end, we should be looking at something like this:

That's all. Boringly simple, and the full code in one piece can be found here.

And the code for our extension is here.