edje_cc -id images/ knob.edc knob.edj edje_player knob.edjYou need to install EFL to do this. As a quick overview, theming of Elementary widgets can be done like this:
- Write an .edc file and create an .edj from it - Use the edje file in your program roughly like this: elm_theme_extension_add(NULL, "./knob.edj"); // load the .edj file Evas_Object *knob_slider = elm_slider_add(win); // add a slider widget elm_object_style_set(knob_slider, "knob"); // set the theme ^^^^~~~~~~~~ This is the name of the group (see below)A demo program will be described here, but first we go through the knob.edc.
which here contains agroup block,
script,
andparts
programs block.
------------------------------------------------- knob.edc ----------------------- collections{ group{This is the name we will use in the C source to select this style in elm_object_style_set.
name: "elm/slider/horizontal/knob"; alias: "elm/slider/horizontal/default"; min: 64 64;Here we list the images we are using to display the knob. They will be supplied to edje_cc with -id PATH_TO_IMAGES.
images{ image: "0000.png" COMP; image: "0001.png" COMP; image: "0002.png" COMPSimilar for 0003.png to 0059.png.
image: "0060.png" COMP; image: "knobbg.png" COMP; } script{The script block contains global variables and functions. update_knob_state is used to load new images when the knob is turned.
public knob_pos; public knob_ref; public knob_last; public knob_move; public signal_from_dragger; public update_knob_state(Float:frac){ new px, py, pw, ph; get_geometry(PART:"knob", px, py, pw, ph); new Float:step = ph/60; if(frac > ph) { set_state(PART:"knob", "60", 0.0); return;} if(frac <= 0) { set_state(PART:"knob", "default", 0.0); return;} if(frac < step) { set_state(PART:"knob", "1", 0.0); return;} if(frac < 2*step) { set_state(PART:"knob", "2", 0.0); return;}Similar "if" statments for frac < 3*step to 59*step.
if(frac < 60*step) { set_state(PART:"knob", "60", 0.0); return;} } public reset_dragger(){ set_drag(PART:"dragger", 0.0, 0.0); set_int(signal_from_dragger, 0); } } parts{The parts block contains the functional parts of the knob.
part{ name: "knobbase"; scale: 1; description{ state: "default" 0.0; min: 64 64; image.normal: "knobbg.png"; } } part{ name: "knob"; mouse_events: 0; scale: 1;
These are mostly geometric objects that may be moveable and/or visible.
They may also emit signals which will be important in the programs block below.Each part has a one or more descriptions, which represent states of the part.
description{ state: "default" 0.0; min: 64 64; rel.to: "knobbase"; image.normal: "0000.png"; } description{ state: "1" 0.0; inherit: "default" 0.0; image.normal: "0001.png"; } description{ state: "2" 0.0; inherit: "default" 0.0; image.normal: "0002.png"; }
Here each state is associated with one image (position) of the knob.Descriptions for states "3" to "59" similar.
description { state: "60" 0.0; inherit: "default" 0.0; image.normal: "0060.png"; } } part{This part is needed, so we can set the value of the knob from the C source via elm_slider_value_set.
//The real slider for elm_slider name: "elm.dragable.slider"; scale: 1; dragable.x: 1 1 0; dragable.y: 1 1 0; type: RECT; description{ state: "default" 0.0; visible: 0; } dragable{ x: 1 1 0; y: 1 1 0; } } part{This part is the actually draggable part of the slider.
name: "dragger"; type: RECT; description{ state: "default" 0.0; rel1.to: "knob"; rel2.to: "knob"; color: 0 0 0 0; } description{ state: "hoki" 0.0; rel1.to: "knob"; rel2.to: "knob"; color: 0 0 0 0; } dragable{ x: 0 0 0; y: 1 1 0; } } } programs{
It's invisible but will measure, how much the knob has been turned (or dragged).The program block contains small scripts which define
program{
the behaviour of our knob.
The programs are called when a certain signal
from a certain source is received. Signals can be emitted from inside this edje
or from outside (C source).The script part of this program runs when
name: "on_drag_move"; signal: "drag"; source: "dragger"; script{ new Float:p1; new Float:p2;
signal "drag" from source "dragger" (the part defined above) is received.The drag value is subtracted from the last knob position, because a drag upwards yields negative values.
get_drag(PART:"dragger", p1, p2); set_float(knob_pos, get_float(knob_last) - p2); new px, py, pw, ph; get_geometry(PART:"knob", px, py, pw, ph); if(get_float(knob_pos) > ph) set_float(knob_pos, ph); if(get_float(knob_pos) < 0) set_float(knob_pos, 0); update_knob_state(get_float(knob_pos)); new Float:sl_val = get_float(knob_pos)/ph;The variable "signal_from_dragger" is used as a guard to distinguish if calls of set_drag for "elm.dragable.slider"
set_int(signal_from_dragger, 1); set_drag(PART:"elm.dragable.slider", sl_val , sl_val); } } program{ name: "on_drag_stop"; signal: "drag,stop"; source: "dragger"; script{ set_float(knob_last, get_float(knob_pos)); reset_dragger(); } } program{ name: "on_wheel"; signal: "mouse,wheel*"; source: "dragger"; //after: "on_slider_set"; } program{ signal: "elm,state,enabled"; source: "elm"; script { set_int(signal_from_dragger, 0); } } program{
are made from here (then it is 1), ore from outside, e.g. C source, (then it is 0).This program is called when set_drag for elm.dragable.slider is called.
signal: "drag,set"; source: "elm.dragable.slider"; script {If we were called because the part "dragger" was dragged, "signal_from_dragger" is 1 and nothing else
if(get_int(signal_from_dragger) == 0){ new Float:p1; new Float:p2; get_drag(PART:"elm.dragable.slider", p1, p2); new px, py, pw, ph; get_geometry(PART:"knob", px, py, pw, ph); set_float(knob_pos, ph*p1); if(get_float(knob_pos) > ph) set_float(knob_pos, ph); if(get_float(knob_pos) < 0) set_float(knob_pos, 0); set_float(knob_last, get_float(knob_pos)); update_knob_state(get_float(knob_pos)); new Float:sl_val = get_float(knob_pos)/ph; set_drag(PART:"elm.dragable.slider", sl_val , sl_val); }else{ set_int(signal_from_dragger, 0); } } } } } }
will happen here except that "signal_from_dragger" will be set to 0.