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);
					}
				}
			}
		}
	}
}