Support
Contribute
Contact
Tracker
Navigation
Personal tools
 

Development with Edje: C API Digest


Since C is the language the Enlightenment Foundation Libraries are actually written in, its he most updated and stable of the available APIs.

Since a good API reference already exists, this article is intended only to complement it. You will not find exhaustive analysis of the form but a simple overview of the function along with rationale, notes and "gotchas".

I hope that as we review each function, diving straight into the API reference feels like a less daunting task, in fact, reading along you will find that the Edje API is quite small, this is because the main goal with Edje was to keep presentation as separate from logic as practically possible for both developer and designer.

Still, we can make the API even easier to learn (and this reference easier to maintain) by separating the available functions into several groups.

Contents

The environment outside the canvas

In the first chapter of the article we set up the canvas wrapper using the most common engine at the time (Software_X11), but the fact is that Evas can be compiled with support for multiple engines, and that this support can be tested at runtime, falling back from one engine to the other if one is not available:

    ...
    Ecore_Evas *ecore_evas;
    ...
    if(ecore_evas_engine_type_supported_get(ECORE_EVAS_ENGINE_GL_X11))
        ecore_evas = ecore_evas_gl_x11_new(NULL, 0, 0, 0, 800, 600);
    else if(ecore_evas_engine_type_supported_get(ECORE_EVAS_ENGINE_SOFTWARE_X11))
        ecore_evas = ecore_evas_software_x11_new(NULL, 0, 0, 0, 800, 600);
    else
        return EXIT_FAILURE;
    ...

We could just grab the first example in the article, drop this code and we could make the application powered by OpenGL if it is available, falling back to software or dieing in the worst case.

A example of usage can be found in the definition for e_canvas_engine_decide in e17/apps/e/src/bin/e_canvas.c, and then the usage during the creation of a new canvas in the definition of E_Win() in e17/apps/e/src/bin/e_win.c.

Once the canvas wrapper is setup there are a couple of additional functions depending on the type. For example, all X11 related engines have functions to control aspects of the windowing environment, like stickiness or resize, while the frame buffer engine does not. The complete list is found (as always) in the API Lists.

The environment inside the canvas

Transitions are what makes Edje interfaces become alive. But even then, for reasons like device resources, we need to exert some kind of control over the load in the interface regardless of theme specifics:

    ...
    edje_frametime_set(1.0 / 5.0);
    printf("Current frametime: %.0f FPS (Aprox.)", pow(edje_frametime_get(),-1));

    edje_freeze();
    printf("The whole interface is dead, Jim.");
    edje_thaw();
    printf("Hold it! it has come back to life.");
    ...

We begin by reducing the frame time to the measly five FPS that our underpowered device is capable of handling. In order to be sure we got it right we print the current value in the screen. This limitation will be applied to every Edje object rendered in the current process.

The last couple of functions will apply edje_object_freeze(object) and edje_object_thaw(object) (explained later) respectively to every object in the interface, it's worth noting that every _freeze call is nested and requires a equal number of _thaw calls to undo them.

Global style settings

Colors and typography might be elements of design but the remain critical to accessibility, the needs might vary from user to user. Manipulating color and text classes are the way for the developer and designer to address those needs, without stepping in each other's toes::

    ...
    Evas_List *color_classes; 
    Evas_List *text_classes; 
    Evas_List *e;

    printf("Changing button_background to color: red, text outline: green, text shadow: blue. \n");
    edje_color_class_set("button_background",255,0,0,255,0,255,0,255,0,0,255,255);

    color_classes = = edje_color_class_list();
    printf("List of color classes:\n");
    for (e = color_classes; e; e = e->next)
        printf("S: %s \n",e->data);

    printf("Deleting button_background color class. \n");
    edje_color_class_del("button_background");  

    printf("If I delete this text_class it will use the default values. \n");
    edje_text_class_del("titlebar");
 
    printf("Oh god! the defaults are so horrible... better set it back. \n");;
    edje_text_class_set("titlebar","Sans",24);

    text_classes = = edje_text_class_list();
    printf("List of text classes: \n");
    for (e = text_classes; e; e = e->next)
        printf("%s \n",e->data);
    ...

As usual, the former functions where pretty much self explanatory. When a theme file is loaded into memory Edje will try to use the text and color classes defined by the application, if none are found it will fall back to the default values set by the theme and in the worst case fallback to the default values set by the library.

Data file structure

Sometimes it is useful to extract information from a theme file before trying to load the theme itself. Among the functions available we find the edje_file_group_exists(file,group), which returns 1 if the group exists in the file.

In a parallel world were this function does not exists we could implement similar functionality with other functions in the same group:

    ...
    //Equivalent of edje_file_group_exists("path/to/file.edj","test")

    Evas_List *entries, *e;
    entries = edje_file_collection_list("path/to/file.edj");

    if (entries) {
        for (e = entries; e; e = e->next) {
            if(strcmp(e->data, "test") == 0) {
                edje_file_collection_list_free(entries);
                return 1;
            }
        }
    }

    edje_file_collection_list_free(entries);
    return 0;   
    ...

In the first line we can see a new data structure Evas_List (a specially formated linked list) along with two functions to load and unload the list from memory.

The remaining function of this group is edje_file_data_get("path/to/file.edj","keyword") and it allows us to extract a string of data under the "keyword" from EDC data block inside "path/to/file.edj" but outside the collections block.

Edje Object inclusion

Including a new object might seem to be a pretty straightforward process, we get a pointer for the object inside the canvas and we load the object from the theme file to it, but is not error free, thankfully control and diagnostic functions are included in the API as well.

    ...
    const char *file = "path/to/file.edj";
    const char *group = "group name";
    const char *test_file = "";
    const char *test_group = "";
    Evas_Object *my_edje_object;

    my_edje_object = edje_object_add(canvas);
    if(!edje_object_file_set(my_edje_object,file,group)) {
        printf("Error Number: %d while loading the theme. \n",edje_object_load_error_get(my_edje_object));
    }else{
        edje_object_file_get(my_edje_object,&test_file,&test_group);
        printf("Group %s successfully loaded from file %s. \n",test_group,test_file);
    }
    ...

The key element here is the Evas_Object pointer, passed as the first parameter in almost every function with the edje_object prefix. The first setup is to create the new object in the canvas using edje_object_add(canvas), the proper Edje Object is then loaded with edje_frametime_set(object,file,group) which returns the status of the operation.

Inside the control structure we can see the diagnostic functions. In case of failure edje_object_load_error_get(object) will return the error number of the last "file_set" operation performed, so we want to use it immediately after failure. In case of success edje_object_file_get(object,&string,&string) allow us to retrieve both the file name and the group name (respectively) of a given edje object in any moment during execution.

Edje Object manipulation

Edje Object anatomy

Even if the main goal of the library is to separate logic from presentation, this separation was done with space for possible changes, accessibility needs, specially colors, fonts and size constrictions.

Colors and font classes work as seen in the "Global style settings" section but affecting one particular object. That means the functions are prefixed with edje_object and receive an Edje Object as first parameter. Resulting in the format edje_object_color_class_del(object,"color_class") for the color class deletion function.

Minimal sizes can be a troublesome issue, on one hand we have the size the designer says his theme support through the EDC file, and on the other hand we have the minimal size the object actually supports. The designer can declare a bigger than necessary size for aesthetic reasons but if the declared size is actually smaller, using it could (most probably will) lead to rendering errors:

    ...
    Evas_Coord calculated_minw, calculated_minh;
    Evas_Coord declared_minw, declared_minh;
    Evas_Object *edje_object = edje_object_add(canvas);

    edje_object_size_min_calc(edje_object,
                              &calculated_minw,
                              &calculated_minh);
 
    edje_object_size_min_get(edje_object,
                             &declared_minw,
                             &declared_minh);
 
    if (calculated_minw > declared_minw || calculated_minh > declared_minh) {
        printf("Bad designer!, your theme does not fit within the minimal size you said it would\n" \
               "I changed the minimal size to the calculated size, just in case...\n");
        edje_extern_object_min_size_set(edje,calculated_minw,calculated_minh);
    }
    ...

Thankfully, neither the maximal size or the aspect relationship between width and height can cause this issue:

    ...
    Evas_Coord maxw,maxh;
    Evas_Object *edje_object;

    edje_object_size_max_get(edje_object,&maxw,&maxh);
    printf("The max width is: %d and the max height is: %d \n",maxw,maxh);

    maxw = 200
    maxh = 300
    edje_extern_object_max_size_set(edje_object,maxw,maxh);
    printf("Now it is %d and %s",maxw,maxh)

    edje_extern_object_aspect_set(edje_object,EDJE_ASPECT_CONTROL_VERTICAL,maxw,maxh);
    printf("The object will maintain a height proportional to %d on resize.",maxh);
    ...

It should be noted that any attribute altered through the API are applied to the object residing in memory and won't be saved on the actual theme file, hence the extern addition to the prefix.