and works by displaying one of 60 images, depending on how much you drag the knob (up and down), and each of the images shows a different rotation of the knob. The images are here as zip and tar.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" COMP
Similar 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.
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.
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;
Each part has a one or more descriptions, which represent states of the part.
Here each state is associated with one image (position) of the knob.
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";
}
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.
It's invisible but will measure, how much the knob has been turned (or dragged).
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{
The program block contains small scripts which define
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).
program{
The script part of this program runs when
signal "drag" from source "dragger" (the part defined above) is received.
name: "on_drag_move";
signal: "drag";
source: "dragger";
script{
new Float:p1;
new Float:p2;
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"
are made from here (then it is 1), ore from outside, e.g. C source, (then it is 0).
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{
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
will happen here except that "signal_from_dragger" will be set to 0.
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);
}
}
}
}
}
}