Page MenuHomePhabricator

How to write an enlightenment theme
Updated 1,922 Days AgoPublic

Introduction

Enlightenment has a powerful theme system. Its base is founded by edje. This means that the themer, has to learn the basics of [Edje] interface creation. Edje has two sides: one is the C-API which is used inside the applications, as in enlightenment. As a themer you can ignore this part of the Edje documentation. The interesting parts for you are the Edje Description Collections (edc files). In these files you describe how the single parts of your theme are arranged. This guide will not explain the syntax of edc files in detail. If you have never worked with them before you may want to read a tutorial about them first.

How E interacts with themes

All the different theme elements are named with a string "the name ...". To stress the difference between the elements, e uses several separator for the names. "/" for groups, "." for parts and "," for signals. So you see without looking a the context that "foo/bar" is a group name, whereas "foo.bar" is a part name.

The Groups

For each part of the theme, E17 loads a specific group from your collection. These parts may be large like the window border or small like a checkbox widget. It's important to name the groups in the right way. The names start with e/ followed by a sequence of more specifying words, e.g. e/widget/border/default/border.

If you miss one (or more) of those groups, your theme still will work. E will use the default theme as a fall-back. This makes it very easy to start writing a theme, because you can test it even if you have just written one or more groups.

The Parts

Each group consists of one or more parts. You can name the parts as you like, but there are some special parts that you must/should have. They serve E to interact with your theme, to get events from or to set the text, for example a button widget. The asterisk stands for group dependent word.

  • 'e.swallow.*' These parts must be of the type SWALLOW. Their aim is to place an outstanding evas object (That could be an image or another edje object) or other things like the content of a window.
  • 'e.event.*' These parts can be of any type. E is only interested of the geometry of this part. They are used for events to evaluate itself. An example for this is e.event.titlebar of the window groups. You have to only specify the geometry and e will do the rest of the magic. If you then scroll in this part the window get shaded and with the mouse pressed the window can be moved around.
  • 'e.text.*' These parts are used to set text like the name of the window title or the label of a button. You can use the font which is shipped with your theme, but it is advisable to add a text_class key, so that the user can change the font. There are valid reasons to do this, especially for language that doesn't use Latin characters.

The Signals

E does not only sends specific signals to your theme, but it also expects from your theme that you emit some signals. There are two types of signals your theme will receive (besides the signals it gets from edje directly like the mouse events).

  • 'e,action,*' These signals inform you about actions that are done with the widget or the window. Although they can be very useful, you can ignore them in many cases, if you want.
  • 'e,state,*' These signals are more important. They inform the theme if the widget enter another state. If you don't plan to confuse the users of your theme, you have to watch those signals. It is important for the user to know which widget has the focus, etc.

A short example

After the theoretical introduction we can now start to write our own little theme. As mentioned before we do not need to write the whole theme down before we can test it. In this little example we only write one widget, but an important one, the window border. The theme will be split into two files.

Here the first one (main.edc):

#define COLOR_FG 246 151 67 255
#define COLOR_BG 245 245 245 255

fonts {
/* we use here the fallback font */
}

collections {
#include "border.edc"
}

Not much happens here, but it makes it easier for us to add other files later. Let's go on to the more interesting file (border.edc). It is split here in small commented pieces. Don't expect a shiny funky window border. Since the aim of the example is more on the edc file side, we avoid using images, with the side effect that you don't have to download a picture collection before hand. For the font we will use the fallback font. The border will have a white titlebar with an orange border. The title text will be placed in the middle. On the left we have the application icon and on the right we have the icons for minimize, maximize and close.

So let's start with the interesting part, the actual theme border. Save this in a file named border.edc in the same directory as main.edc.

group {
    name, "e/widgets/border/default/border";

    parts {
        part {
            name, "main";
            type, RECT;
            description {
                state, "default" 0.0;
                color, COLOR_FG;
            }
        }
        part {
            name, "main_inner";
            type, RECT;
            description {
                state, "default" 0.0;
                color, COLOR_BG;
                rel1.offset, 1 1;
                rel2.offset, -2 -2;
            }
        }

This is our 1-pixel window border. Because the main_inner part hides all of the main parts, except for the one pixel border. We use color aliases, so you can change the color easily later.

part {
    name, "e.swallow.icon";
    type, SWALLOW;
    mouse_events, 0;
    description {
        state, "default" 0.0;
        align, 0.0 0.5;
        aspect, 1.0 1.0;
        aspect_preference, VERTICAL;
        visible, 1;
        rel1 {
            offset, 1 1;
            to, "main_inner";
        }
        rel2 {
            offset, 1 0;
            relative, 0.0 1.0;
            to_x, "main_inner";
            to_y, "e.text.title";
        }
    }
}

Here is the first part E will look up. It will hold the window icon. Note that this part must be of the type SWALLOW. The placement is a bit more difficult to understand. We only give it a height with the two rel-points, and a width of 0 pixels. With the aspect statement, we force it to be quadratic. So it will have the same width and height.

part {
    name, "e.text.title";
    type, TEXT;
    mouse_events, 0;
    description {
        state, "default" 0.0;
        color, COLOR_FG;
        align, 1.0 0.0;
        rel1 {
            to_x, "e.swallow.icon";
            to_y, "main_inner";
            relative, 1.0 0.0;
            offset, 3 2;
        }
        rel2 {
            to_x, "min_icon";
            to_y, "main_inner";
            relative, 0.0 0.0;
            offset, -4 2;
        }
        text {
            font, "Vera";
            size, 12;
            min, 0 1;
            text, "Xterm - gg - VIM";
            text_class: "title_bar";
        }
    }
}

Here comes the title. As you already now, the text will be set by E. The dummy text here is only for testing with an edje viewer. It will be placed between the window icon and the minimize icon. The y-coordinates of rel1 and rel2 section are the same, but with the text.min, 0 1; we force edje to use the height it needs. We can change the font size with out any other modifications. The text_class here is important. It gives the user of your theme the possibility to override the font (it might not have full support for the character set of the user's language).

#define RIGHT_ICON(__name, __symbol, __rel, __r) \
part {                            \
    name, __name;                 \
    type, TEXT;                   \
    description {                 \
        state, "default" 0.0;     \
        color, COLOR_FG;          \
        align, 1.0 0.0;           \
        rel1 {                    \
            relative, __r 0.0;    \
            offset, -4 0;         \
            to_x, __rel;          \
            to_y, "e.text.title"; \
        }                         \
        rel2 {                    \
            relative, __r 1.0;    \
            offset, -4 -1;        \
            to_x, __rel;          \
            to_y, "e.text.title"; \
        }                         \
        text {                    \
            align, 0.0 0.0;       \
            font, "Vera";         \
            size, 12;             \
            min, 1 1;             \
            text, __symbol;       \
        }                         \
    }                             \
}

Here we have a macro. edje_cc runs the edc-code first through the c-preprocessor. That means you can use any preprocessor construction. If you are curious about what that is, you can take a look into the GNU cpp manual. The macro is used to place the minimize, maximize and close icon. As you can see it is a simple text part - remember we don't use any pics in this theme. Here we have the same construction as in the title. The width of the part is set to 0 and edje will use the needed size, because of the set text minimum flag. Note: The value is a boolean and has nothing to do with a pixel size.

RIGHT_ICON("min_icon", "_", "max_icon", 0.0)
RIGHT_ICON("max_icon", "o", "close_icon", 0.0)
RIGHT_ICON("close_icon", "X", "main_inner", 1.0)

And now use this macro.

part {
    name, "e.swallow.client";
    type, SWALLOW;
    description {
        state, "default" 0.0;
        rel1 { 
            to_x, "main_inner";
            to_y, "e.text.title";
            relative, 0.0 1.0;
            offset, 0 1;
        }
        rel2.to, "main_inner";
    }	
}

E will use this part to determine where it has to place the actual window content. Now we have our theme almost ready. If you add two closing brackets at the end, you can actually compile it and use it as a theme. Simply copy the file into the ~/.e/e/themes directory and select the theme in the theme selector.

$ edje_cc main.edc
$ cp main.edj ~/.e/e/themes/my_theme.edj

You will notice that the theme looks fine, but it is not very usable since you cannot drag, resize, close, etc. the windows.

That's because we haven't added any events parts.

        //// Event parts
        part {
            name, "e.event.titlebar";
            type, RECT;
            description {
                state, "default" 0.0;
                rel1.to, "e.swallow.icon";
                rel1.relative, 1.0 0.0; 		
                rel2.to, "min_icon";
                rel2.relative, 0.0 1.0; 		
                color, 0 0 0 0;
            }	
        }
        part { 
            name, "e.event.close";
            type, RECT;
            description { 
                state, "default" 0.0;
                rel1.to, "close_icon";
                rel2.to, "close_icon";
                color, 0 0 0 0;
            }
        }
    }
}

Here are two parts as an example. They are all transparent, because we don't need/want them as decoration. Of course there are many more possibilities. For example: resizing, the icon menu, minimizing, etc. Here is a list of the possible event parts you can use.

  • e.event.titlebar
  • e.event.resize.t
  • e.event.resize.b
  • e.event.resize.tl
  • e.event.resize.tr
  • e.event.resize.bl
  • e.event.resize.br
  • e.event.icon
  • e.event.close
  • e.event.minimize
  • e.event.maximize

Try to add them to the theme as an exercise. Unfortunately there is no reference for all the parts and signals yet, which E expects or sends. So the best way to figure them out is to take a look at an existing theme. You may want to take a look at the new theme from raster, which has useful comments, but it is not complete at the moment.

Additional Info

Imported from https://trac.enlightenment.org/e/wiki/How_to_write_an_enlightenment_theme
History:
1 jt_a 2011-01-11 15:27:51 import from old wiki
2 jt_a 2011-01-11 15:30:09
3 jt_a 2011-01-11 15:38:15
4 jt_a 2011-01-12 10:32:46
5 obiwahn 2012-09-03 06:23:23

Last Author
beber
Last Edited
Sep 5 2013, 1:19 PM
Projects
None
Subscribers
None