Edje Color Class Tutorial
Huh? Color class?
A color class is simply a mapping between a name and a set of RGBA values, that can be used to make color-agnostic themes using Edje. Basically, you begin with a greyscale theme, and allow certain bits of it to be colored an arbitrary color. For example, the default winter theme is an icy blue color, but there's no reason it shouldn't be green or red or puce or whatever others can dream up. Although the concept is fairly simple, not many people are using color classes yet, so heres a quick run through of the basic steps.
Draw the images
Before we can build an edje theme, we need some images. So, fire up the gimp and grab your 1px pencil. Begin with an basic frame:
Next, we draw the parts that will eventually be colored. For the winter theme, these are just simple greyscale gradients. In your own themes, you will want to use shades of grey, but the exact shades to use take a bit of trial and error. Keep this on a separate layer to ease the cutting-up-into-little-pngs step that comes later.
Now, duplicate your 'to-be-colored' layer, check the little preserve transparency box, and fill it with a nice bright solid color.
Change the blending mode to 'Multiply', and voila, instant mock-colorclass. You will probably need to play with the fill color a bit (and maybe the underlying greyscale layer) to get a good looking combination. I find that low saturation and high value usually look pretty good. Add a little shadow for effect, and we're done with the drawing.
All that's left to do in the gimp is to cut the drawing up into individual images. Notice, you only need th greyscale images. The multiply layer is only used to find some color values that looks decent (and to make sure the greyscale part works with various colors).
The EDC
Now, turn your images into a full blown scalable edje object using the following edc. Note the key 'color_class: "border";' lines in the grad.top and grad.bot parts. The rest is just standard edc. I only used a single color class, named "border", but you may use as many as you want. (However, its up to the application loading this edje to actually set the colors, so, use the classes that the app expects.)
images {
image: "fr.png" LOSSY 98;
image: "gt.png" LOSSY 98;
image: "gb.png" LOSSY 98;
image: "sh.png" LOSSY 98;
}
collections {
group {
name: "example";
parts {
part {
name: "frame";
description {
state: "default" 0.0;
image.normal: "fr.png";
image.border: 10 10 10 10;
}
}
part {
name: "grad.top";
description {
state: "default" 0.0;
min: 14 7;
max: 9999 7;
color_class: "border";
rel1 {
to: "frame";
relative: 0 0;
offset: 1 1;
}
rel2 {
to: "frame";
relative: 1 0;
offset: -2 8;
}
image.normal: "gt.png";
image.border: 10 10 0 0;
}
}
part {
name: "grad.bot";
description {
state: "default" 0.0;
min: 14 7;
max: 9999 7;
color_class: "border";
rel1 {
to: "frame";
relative: 0 1;
offset: 1 -8;
}
rel2 {
to: "frame";
relative: 1 1;
offset: -2 -2;
}
image.normal: "gb.png";
image.border: 10 10 0 0;
}
}
part {
name: "bg";
type: RECT;
description {
state: "default" 0.0;
rel1.to: "frame";
rel1.offset: 1 9;
rel2.to: "frame";
rel2.offset: -2 -10;
}
}
part {
name: "shadow";
description {
state: "default" 0.0;
color: 255 255 255 120;
min: 14 5;
max: 9999 5;
color_class: "border";
rel1 {
to: "bg";
relative: 0 0;
offset: 0 0;
}
rel2 {
to: "bg";
relative: 1 0;
offset: -1 4;
}
image.normal: "sh.png";
}
}
}
}
}
Save this as cc.edc in the same directory as your images, and compile it using:
edje_cc cc.edc
The c code
All that's left to do is add the edje to an evas and set its color class. I'll leave the first part to you. To se the color class you simply need to:
edje_object_color_class_set(obj, "border", r, g, b, 255, 0, 0, 0, 0, 0, 0, 0, 0);
where r, g, and b are the red, green and blue values of the color you want (e.g the color of the solid layer we drew in the gimp). All the 0's are in there because text color classes have two extra colors (one for a border and one for a shadow). Image objects don't use these values, so I just set them to 0.
Ideally, your application would provide some way for the user to select the color values to use here. (Otherwise, what would be the point of colorclassing?)
a hint:
If you're just a themer and don't want to write any c code, you can test out the coloring by changing the 'color_class: "border";' lines in the edc to 'color: r g b 255' where r, g, and b are again the color you want it to be. The blue i used above is (r, g, b) = (229, 239, 255). Recompile and view the colored result with:
edje cc.edj
a note:
If you have both color: and color_class: set, the color class will apply on top of the color, which is probably not what you intended. (i.e. you can't use color: to set a default color, expecting it to be overriden if the colorclass is set).
The final product
Some thoughts
Currently, the only application I know of that implements edje color classes is elicit. However, e17 will definitely include support eventually. Hopefully as result of this tutorial, some other applications will also add support.
Of course, to fully support color classes, you need some method for the user to pick the colors. Since elicit is all about picking colors, it was a prime candidate for color classing. For other applications, we probably need some sort of color picker smart object (along the lines of the file dialog smartobj).
Also, I know some themers (like me) would prefer to at least have some default colors for people to choose from (e.g. colors that they know look good with their theme). Some generic method of supporting this would be nice. One possibility would be to stick things in the data{} block of an edje.
data {
item: "cc_border" "229 249 255 255";
}
Of course, really, we'd need all 3 color sets, for a total of 12 values. Also, we'd need to parse the actual color class name out of the data item name. So, this would be a bit clunky.
A better alternative would be to add a color_classes block at the group level. Maybe something like this (where any values not set (like color2 and color3 below), would default to white (255 255 255 255) ):
color_classes {
color_class {
name: "border";
description {
name: "default";
color1: 229 249 255 255;
}
description {
name: "red";
color1: 255 185 185 255;
}
}
}
Then, an application could easily get a list of available color class descripitions for a theme. In addition to allowing a set of nice values to pick from, this would eliminate the need for the app to define color class names, giving the themer much more flexibility (as if we didn't have enough already...).
