summaryrefslogtreecommitdiff
path: root/pages/docs/themes
diff options
context:
space:
mode:
authorAndy Williams <andy@andywilliams.me>2017-11-30 16:14:35 +0000
committerAndy Williams <andy@andywilliams.me>2017-11-30 16:14:35 +0000
commit68b39ed334a1caee0d6586ad01202fcd46286257 (patch)
treee894cfa7c7e881cd40058fddbbc607a5e77039d7 /pages/docs/themes
parent414d255946dad0e3f4346ae3d2886a6df1d4b3ec (diff)
navigation: Add nav to /docs/ and remove link lists from the text body
Diffstat (limited to 'pages/docs/themes')
-rw-r--r--pages/docs/themes/knob_example.txt254
-rw-r--r--pages/docs/themes/start.txt184
2 files changed, 438 insertions, 0 deletions
diff --git a/pages/docs/themes/knob_example.txt b/pages/docs/themes/knob_example.txt
new file mode 100644
index 000000000..ed69ad523
--- /dev/null
+++ b/pages/docs/themes/knob_example.txt
@@ -0,0 +1,254 @@
1~~Title: A knob theme for the Elementary slider widget (work in progress)~~
2
3==== Make an Elementary slider behave like a knob (work in progress)====
4
5Here is an example for an edje theme which makes an Elementary slider widget look and behave like a knob.
6
7It will look like this {{:themes:edje-knob.png?nolink}} and works by displaying one of 60 images, depending on how much you drag the knob (up and down). Each of the images corresponds to a different rotation of the knob.
8
9The important parts of the edc file for this theme will be described below.
10In the ''group'' block we define the name we will later use to load the theme from within a C program.
11<code>
12collections{
13 group{
14 name: "elm/slider/horizontal/knob";
15 alias: "elm/slider/horizontal/default";
16 min: 64 64;
17</code>
18Next we list the ''images'' we will be using
19<code>
20 images{
21 image: "0000.png" COMP;
22 image: "0001.png" COMP;
23 image: "0002.png" COMP
24
25 //Similar for 0003.png to 0059.png.
26
27 image: "0060.png" COMP;
28 image: "knobbg.png" COMP;
29 }
30</code>
31The ''script'' block contains global variables and functions. The function ''update_knob_state'' is used to load new images when the knob is turned. The variables are used to store the state of the knob.
32<code>
33 script{
34 public knob_pos;
35 public knob_ref;
36 public knob_last;
37 public knob_move;
38 public signal_from_dragger;
39
40
41 public update_knob_state(Float:frac){
42
43 new px, py, pw, ph;
44 get_geometry(PART:"knob", px, py, pw, ph);
45 new Float:step = ph/60;
46 if(frac > ph) { set_state(PART:"knob", "60", 0.0); return;}
47 if(frac <= 0) { set_state(PART:"knob", "default", 0.0); return;}
48 if(frac < step) { set_state(PART:"knob", "1", 0.0); return;}
49 if(frac < 2*step) { set_state(PART:"knob", "2", 0.0); return;}
50
51 //Similar "if" statments for frac < 3*step to 59*step.
52
53 if(frac < 60*step) { set_state(PART:"knob", "60", 0.0); return;}
54
55 }
56
57 public reset_dragger(){
58 set_drag(PART:"dragger", 0.0, 0.0);
59 set_int(signal_from_dragger, 0);
60 }
61 }
62</code>
63The ''parts'' block contains the functional parts of the knob.
64These are mostly geometric objects that may be moveable and/or visible.
65They may also emit signals which will be important in the ''programs'' block below.
66<code>
67 parts{
68 part{
69 name: "knobbase";
70 scale: 1;
71 description{
72 state: "default" 0.0;
73 min: 64 64;
74 image.normal: "knobbg.png";
75 }
76 }
77</code>
78Each part has a one or more descriptions, which represent states of the part.
79Here each state is associated with one image (position) of the knob.
80<code>
81 part{
82 name: "knob";
83 mouse_events: 0;
84 scale: 1;
85 description{
86 state: "default" 0.0;
87 min: 64 64;
88 rel.to: "knobbase";
89 image.normal: "0000.png";
90 }
91 description{
92 state: "1" 0.0;
93 inherit: "default" 0.0;
94 image.normal: "0001.png";
95 }
96 description{
97 state: "2" 0.0;
98 inherit: "default" 0.0;
99 image.normal: "0002.png";
100 }
101
102 //Descriptions for states "3" to "59" similar.
103
104 description {
105 state: "60" 0.0;
106 inherit: "default" 0.0;
107 image.normal: "0060.png";
108 }
109 }
110</code>
111The following ''part'' is needed so we can set the value of the knob from the C source via elm_slider_value_set.
112<code>
113 part{
114 //The real slider for elm_slider
115 name: "elm.dragable.slider";
116 scale: 1;
117 dragable.x: 1 1 0;
118 dragable.y: 1 1 0;
119 type: RECT;
120 description{
121 state: "default" 0.0;
122 visible: 0;
123 }
124 dragable{
125 x: 1 1 0;
126 y: 1 1 0;
127 }
128 }
129</code>
130This ''part'' named "dragger" is the actually draggable part of the slider.
131It's invisible but will measure how much the knob has been turned (or dragged).
132<code>
133 part{
134 name: "dragger";
135 type: RECT;
136 description{
137 state: "default" 0.0;
138 rel1.to: "knob";
139 rel2.to: "knob";
140 color: 0 0 0 0;
141 }
142 description{
143 state: "hoki" 0.0;
144 rel1.to: "knob";
145 rel2.to: "knob";
146 color: 0 0 0 0;
147 }
148 dragable{
149 x: 0 0 0;
150 y: 1 1 0;
151 }
152 }
153 }
154</code>
155Now the ''parts'' block is finished and we continue with the ''programs'' block which contains small scripts which control the behaviour of our knob. The programs are called when a certain signal
156from a certain source is received. Signals can be emitted from inside this edje
157or from outside (C source).
158<code>
159 programs{
160</code>
161The script part of the ''program'' named "on_drag_move" runs when the
162signal "drag" from source "dragger" (the part defined above) is received.
163<code>
164 program{
165 name: "on_drag_move";
166 signal: "drag";
167 source: "dragger";
168 script{
169 new Float:p1;
170 new Float:p2;
171
172 //The drag value is subtracted from the last knob position
173 //because a drag upwards yields negative values.
174
175 get_drag(PART:"dragger", p1, p2);
176 set_float(knob_pos, get_float(knob_last) - p2);
177
178 new px, py, pw, ph;
179 get_geometry(PART:"knob", px, py, pw, ph);
180 if(get_float(knob_pos) > ph) set_float(knob_pos, ph);
181 if(get_float(knob_pos) < 0) set_float(knob_pos, 0);
182
183 update_knob_state(get_float(knob_pos));
184 new Float:sl_val = get_float(knob_pos)/ph;
185
186 set_int(signal_from_dragger, 1);
187 set_drag(PART:"elm.dragable.slider", sl_val , sl_val);
188 }
189 }
190</code>
191The variable "signal_from_dragger" is used as a guard to distinguish if calls of set_drag for "elm.dragable.slider" are made from within the edje theme (then it is 1), ore from outside, e.g. C source, (then it is 0).
192
193Next are some more programs
194<code>
195 program{
196 name: "on_drag_stop";
197 signal: "drag,stop";
198 source: "dragger";
199 script{
200 set_float(knob_last, get_float(knob_pos));
201 reset_dragger();
202 }
203 }
204 program{
205 name: "on_wheel";
206 signal: "mouse,wheel*";
207 source: "dragger";
208 //after: "on_slider_set";
209 }
210 program{
211 signal: "elm,state,enabled";
212 source: "elm";
213 script {
214 set_int(signal_from_dragger, 0);
215 }
216 }
217</code>
218The following ''program'' is called when set_drag for elm.dragable.slider is called.
219<code>
220 program{
221
222 signal: "drag,set";
223 source: "elm.dragable.slider";
224 script {
225</code>
226If we were called because the part "dragger" was dragged, "signal_from_dragger" is 1 and nothing else
227will happen here except that "signal_from_dragger" will be set to 0.
228<code>
229 if(get_int(signal_from_dragger) == 0){
230 new Float:p1;
231 new Float:p2;
232 get_drag(PART:"elm.dragable.slider", p1, p2);
233
234 new px, py, pw, ph;
235 get_geometry(PART:"knob", px, py, pw, ph);
236 set_float(knob_pos, ph*p1);
237
238 if(get_float(knob_pos) > ph) set_float(knob_pos, ph);
239 if(get_float(knob_pos) < 0) set_float(knob_pos, 0);
240
241 set_float(knob_last, get_float(knob_pos));
242
243 update_knob_state(get_float(knob_pos));
244
245 new Float:sl_val = get_float(knob_pos)/ph;
246 set_drag(PART:"elm.dragable.slider", sl_val , sl_val);
247
248 }else{
249 set_int(signal_from_dragger, 0);
250 }
251 }
252 }
253 }
254</code> \ No newline at end of file
diff --git a/pages/docs/themes/start.txt b/pages/docs/themes/start.txt
new file mode 100644
index 000000000..1d367cab4
--- /dev/null
+++ b/pages/docs/themes/start.txt
@@ -0,0 +1,184 @@
1~~Title: Getting Started on Themed and Edje~~
2
3==== EDC File Basics ====
4
5Let's start with a "Hello World" example. This is going to be in verbose sytax to make it as easy as possible to break down before we start making it more compact. Start with a source "EDC" file like below:
6
7<code edc example.edc>
8collections {
9 group {
10 name: "example";
11 parts {
12 part {
13 name: "background";
14 type: RECT;
15 description {
16 state: "default";
17 color: 64 64 64 255;
18 }
19 }
20 part {
21 name: "label";
22 type: TEXT;
23 description {
24 state: "default";
25 color: 255 255 255 255;
26 text {
27 font: "Sans";
28 size: 10;
29 text: "Hello World";
30 }
31 }
32 }
33 }
34 }
35}
36</code>
37
38Compiling it is easy. The compiled EDJ file is portable. It can be used on any OS and any architecture. It's basically a structured archive of all of the source material packed into a single file that is compressed and usable "as-is" at runtime without installation or unpacking.
39
40<code bash>
41edje_cc example.edc
42</code>
43
44Now a quick way to see your result is with the ''edje_player'' tool that will load a specific group in a file or just use the first it finds. In our case here we have only a single group so it should load just this group within the collections and let us see it:
45
46<code bash>
47edje_player example.edj
48</code>
49
50You now should see something like this in a window:
51
52{{edje-hello.png?nolink}}
53
54The window will be resizable, so resize it to see what happens when your group is resized too. One of the key ideas behind Edje is to be able to make both resizable AND scaleable components that can adapt to sizing needs and UI/DPI scaling needs.
55
56=== The Anantomy of an Edje File ===
57
58An Edje file is compiled from a combination of source "EDC" files and other data (images, fonts, sound samples, ...) into a single stand-alone binary "EDJ" file that is used at runtime. These files are, by default, de-compileable again back to source with the ''edje_decc'' tool. These files do not execute code, and are system-independent. That may use various compression schemes based on options to ''edje_cc''. The source EDC files are passed through a C pre-processor so they can use CPP directives such as ''#include'', ''#define'', ''#ifdef'', the macros defined by ''#define'', etc. and this can be used to make your EDC files more maintainable by being able to generate content from smaller macros or included files, split your content up into many files that you ''#include'' together and so on. But let's get into the actual structure.
59
60An EDC file will look a bit like a mix of JSON and a C language structure definition. Everything has some kind of parent/child hierarchy with parent sections containing child sections and so on. It is also possible to skip a section and use periods (''.'') to declare a parent and child relationship directly on a line, so You could express:
61
62<code edc example.edc>
63text {
64 font: "Sans";
65 size: 10;
66 text: "Hello World";
67}
68</code>
69
70As
71
72<code edc example.edc>
73text.font: "Sans";
74text.size: 10;
75text.text: "Hello World";
76</code>
77
78You can also remove whitespace before keywords and after statement delimiters ('';''), so the above could also be done expressed as:
79
80<code edc example.edc>
81text { font: "Sans"; size: 10; }
82text.text: "Hello World";
83</code>
84
85You should take advantage of white-space compression to make your EDC files less lengthy and thus easier to read and maintain. So let's take the above hello world example and make it a bit more compact before we continue:
86
87<code edc example.edc>
88collections {
89 group { name: "example";
90 parts {
91 part { name: "background"; type: RECT;
92 description { state: "default";
93 color: 64 64 64 255;
94 }
95 }
96 part { name: "label"; type: TEXT;
97 description { state: "default";
98 color: 255 255 255 255;
99 text { font: "Sans"; size: 10; }
100 text.text: "Hello World";
101 }
102 }
103 }
104 }
105}
106</code>
107
108We will use this kind of white-space compression from now on to keep things more compact. Remember that the same declaration is able to be expressed in many different ways, so don't get confused when you see the same thing expressed with different white space or with different parent/child syntax as they are equivalent.
109
110Edje files generally contain several major sections. ''collections'' is the section where a series of ''group'' sections are declared. Each group is accessible by its ''name'' via Edje or Elementary API. A single EDJ file may contain 0, 10, 100, or 1000 groups ... or more. It depends on how much you pack in. The names of such groups is a free-form string, but generally there is a convention to use something like a file path so ''group/children/thing'' would be common. So a very basic EDC source file may begin as:
111
112<code edc example.edc>
113collections {
114 group { name: "example";
115 }
116}
117</code>
118
119We have a group in our collections, and this group has nothing in it. What exactly is a ''group'' then? It's a group of child objects, programs that respond to signals/events and other layout logic that define a single graphical element. Code can ask the Edje library to use this defined group from that file such as:
120
121<code c example.c>
122obj = elm_layout_add(win);
123elm_layout_file_set(obj, "example.edj", "example");
124elm_win_resize_object_add(win, obj);
125evas_object_show(obj);
126</code>
127
128Elementary and Enlightenment have code like this everywhere (or the lower level versions of it). Almost every Elementary widget actually creates such layout/Edje objects internally and sources them from theme files such as ''default.edj'' that ships with EFL. Every single widget will likely go back to this file and figure out which bit of data maps to this name, load it and instantiate the objects based on the design data in the EDJ file. This is mostly transparent to a user or programmer, other than when they wish to change the look of their UI ... they then can make their own themes and override the standard search for a theme with their own.
129
130This is how any application may provide a custom look/feel of its own (it's own Themes), as well as added layout elements that are not normal widgets, built out of such data files and much much more. Enlightenment even will only accept EDJ files as wallpapers because then it then doesn't need to know how to tile, scale or otherwise lay out the wallpaper content. Edje takes care of this. The Wallpaper import dialog is simply generating a sample EDC file that includes the selected image file with the layout options selected. An added bonus is that a single EDJ file can include multiple resolutions of an image to optimally load the best one, scale and adapt on the fly and even animate.
131
132So learning how Edje works is the key to the kingdom of Enlightenment. Master Edje and your UI can be changed from clean modern flat styles through to skeumorphic madness and anything else your imagination can come up with. So let's continue with the basic anatomy.
133
134Every ''group'' will likely have ''parts'', possibly ''programs'' and may even have it's own ''images'' section as well as a few others. The ''parts'' section defines a series of parts in stacking order from bottom to top that comprise the group object. So a small step forward with our example may become something like this:
135
136<code edc example.edc>
137collections {
138 group { name: "example";
139 parts {
140 part { name: "background"; type: RECT;
141 }
142 part { name: "label"; type: TEXT;
143 }
144 }
145 }
146}
147</code>
148
149We have 2 parts, one named "background" that is of type RECT (a basic rectangle) and one "label" that is of type TEXT (a simple single line text object with no markup etc.). You generally will want names for any part you wish to later access or address by changing its state or otherwise accessing it from outside Edje (i.e. from the calling application). Come up with names that are memorable. In EFL we generally namespace our names. If the part name is meant to be accessed from outside the group (e.g. from an app), then we will namespace something like "e.text" or "elm.text" etc. but using a dot (''.'') with a prefix of the namespace then following namespaces. A sign that a part is "official" and is expected to exist or be interacted with is that it has a dot in its name with a namespace.
150
151But these parts are pretty useless as Edje has no idea of their description - what color are they? What Font used? What sized font? We need to provide at LEAST a ''default'' description.
152
153<code edc example.edc>
154collections {
155 group { name: "example";
156 parts {
157 part { name: "background"; type: RECT;
158 description { state: "default";
159 color: 64 64 64 255;
160 }
161 }
162 part { name: "label"; type: TEXT;
163 description { state: "default";
164 color: 255 255 255 255;
165 text { font: "Sans"; size: 10; }
166 text.text: "Hello World";
167 }
168 }
169 }
170 }
171}
172</code>
173
174And now we have a basic example. The rectangle is a dim grey (color is in R G B A with values from 0 to 255 for the elements) normally, but you can also use html-style color notations like "#404040ff" instead of 64 64 64 255 like '' color: "#404040ff";''. We have a single line text label that uses the "Sans" font at size 10, is white in color and displays the text "Hello World" by default.
175
176----
177
178For a pretty complete Edje programming guide, please see:
179
180[[program_guide/edje_pg]]
181
182----
183
184~~DISCUSSIONS~~ \ No newline at end of file