|
|
|
NavigationPersonal tools |
Development with Edje: Introduction
The following text is quoted directly from the introduction in the Edje API Reference by Carsten 'rasterman' Haitzler: Edje is a complex graphical design & layout library.
[edit] Meet EvasFrom a developer's point of view, we can't expect to understand how Edje works without going through a brief introduction about Evas first. Evas is canvas library that can be used to render various types of graphical elements (text, lines, images, etc.) through different back ends (Frame buffer devices, X11, OpenGL, etc.) using almost the same code and independently of the platform. Once a canvas is created, each of these graphical elements is included in the form of an Evas object while the canvas itself keeps track of a list of objects it contains along with their state, events and rendering taking a big load off the developer's shoulders. Evas is not limited to the rendering of primitive objects, the developer can define new object types by assembling multiple primitives, these objects are know as smart objects and they can be included to a canvas and manipulated through the same API like any other object. When a developer wants to build an interface consisting of elements defined using Edje, he does so through the Edje API which in itself could be seen as a method for creating smart objects with a specific format. Edje objects can be seen as just an specific type of Evas smart objects. [edit] Meet EcoreReading through the introduction of the Ecore API Reference you can find it described as a "library of convenience functions". Ecore provides shortcuts to common methods of interaction between different members of the EFL and system resources like dbus. In which way is Ecore relevant to Edje? Simply put, we need an Evas canvas to render our Edje objects and Ecore is the simplest way to get an Evas canvas up and running. Throw in the convenience of several already wrapped functions and we can imagine several reasons for using it alongside Evas and Edje. The name of the Ecore library dealing with Evas is named (conveniently) Ecore_Evas and the name of every function included in it uses the ecore_evas prefix. Ecore_Evas is a "canvas wrapper" and its used to setup the drawing device for the canvas to render the objects. This wrapper is intended to support each backend that Evas supports with its respective (and sometimes unique) attributes, for example, a regular window in a common windowing environment might have a "title" attribute while a frame buffer device normally does not. [edit] API BasicsNow that we understood the reasons to include the Ecore and Evas libraries in an article about Edje, we can finally get our hands dirty with some code. If you read through the API of any Enlightenment Foundation Library, you will
probably see that every function has the same format: a library_name_
prefix, followed by an action (or method) to apply to an instance of an
object created with said library, passed as the first parameter of the function, for example, Including and displaying an Edje object in a window is a process of a few, well defined steps. [edit] Setting up the canvasFirst things first, we need to include the header files and initialize the libraries:
#include <stdlib.h>
#include <Evas.h>
#include <Ecore.h>
#include <Ecore_Evas.h>
int main() {
if (!ecore_init()) return EXIT_FAILURE;
if (!ecore_evas_init()) return EXIT_FAILURE;
...
All initialize-able Enlightenment Foundation Libraries do it with a function in
the format: In order to render a canvas its necessary to create a canvas wrapper that will host it and to store a pointer to it for future reference:
...
Ecore_Evas *ecore_evas = NULL;
ecore_evas = ecore_evas_software_x11_new(NULL, 0, 0, 0, 800, 600);
if (!ecore_evas) return EXIT_FAILURE;
...
While the software_x11 engine is being used in this example, its possible to
use any other supported engine by simply changing the second line to
Once the canvas wrapper has been setup we need to change its state to visible:
...
ecore_evas_title_set(ecore_evas, "Example Application");
ecore_evas_name_class_set(ecore_evas, "testapp", "Testapp");
ecore_evas_show(ecore_evas);
...
While the first two lines are optional, it is useful to see the way we set the title name and class of the window that will host our canvas. The third function sets the given canvas wrapper to visible, this can be reversed later with ``ecore_evas_hide(..)``. The canvas wrapper is ready to go, but the actual canvas that will be used to draw our Edje objects is nowhere to be found:
...
Evas *evas = NULL;
evas = ecore_evas_get(ecore_evas);
...
The function The execution loop for the program can also be conveniently handled by Ecore:
...
ecore_main_loop_begin();
...
Once Once the execution of the main loop has finished it's a good practice to shut down any library we initiated:
...
ecore_evas_shutdown();
ecore_shutdown();
}
...
[edit] Including the Edje ObjectNow that we know how to create the necessary environment for our Edje objects to thrive we need to create an object and include it in our application. As usual we begin by including the necessary files and initializing the library:
...
#include <Edje.h>
...
int main() {
...
if (!edje_init()) return EXIT_FAILURE;
...
Once a pointer to our canvas has been setup, we need a pointer to a valid Evas object to insert our Edje object:
...
Evas_Object *edje = NULL;
...
edje = edje_object_add(evas);
edje_object_file_set(edje, "testfile.edj", "testgroup");
...
Both functions are specific to Edje, in the first case we use
As with any other Evas object we need to instruct Evas to make it visible, but not before adjusting the object inside the canvas or since we are only showing one object, adjust the canvas to the size of our object:
...
Evas_Coord width, height;
...
evas_object_move(edje, 0, 0);
edje_object_size_min_get(edje, &width, &height);
evas_object_resize(edje, width, height);
ecore_evas_resize(ecore_evas, width, height);
evas_object_show(edje);
...
First we use Before the end, we resize the canvas to the same values the object has with
[edit] Events with EcoreThe Ecore loop maintains a list of event "types" and a list of event "handlers" (both extensible). And remains idle until a listed signal is detected. For example, we could create an additional function to handle the process of shutting down the libraries when closing the application:
...
int
good_bye(void *data, int type, void *event)
{
//Remove the handler for no practical reason but showoff API
if (ecore_event_handler_del(close)) printf("Handler deleted\n");
printf("Good bye! \n");
ecore_main_loop_quit();
ecore_evas_shutdown();
ecore_shutdown();
}
...
And we could just plug it into our app using:
...
Ecore_Event_Handler* close = NULL;
...
close = ecore_event_handler_add(ECORE_EVENT_SIGNAL_EXIT,good_bye,"data");
...
The next time a signal of type ECORE_EVENT_SIGNAL_EXIT is received, the function good_bye will be executed. [edit] Events with EvasEach Evas object is capable of having its own list of accepted events, these list function similarly to the Ecore lists. Using the function [edit] Events with EdjeWe have established that Edje objects are rendered inside an Evas canvas where they behave like Evas objects, it makes sense to think they are capable of maintaining their own callback list as Evas objects do. The API for maintaining the callbacks is pretty similar to the analogous Evas functions. For example, an alteration of the previous Ecore example, this one implements closing the application as a result of an event in the Edje Object:
...
void
good_bye(void *data, Evas_Object *o, const char *emission, const char *source)
{
//More API showoff
if(edje_object_signal_callback_del(edje,emission,source,good_bye))
printf("Deleted the handler: %s -> %s\n",source,emission);
printf("Good bye! \n");
ecore_main_loop_quit();
ecore_evas_shutdown();
ecore_shutdown();
}
...
edje_object_signal_callback_add(edje, "closeme!", "arbitrary_source", good_bye, "data");
...
As we can see, the parameter list of both, the creator and deletion functions is longer than before, in this case, the signal "type" is replaced by a couple of strings, emission, the signal content, in this case "closeme!" and source, the element in the Edje object that emitted the signal, in this case "arbitrary_source". Plainly, the result is that the function good_bye will be executed when the "arbitrary_source" element inside the Evas_Object "edje", emits the "closeme!" signal. [edit] The "data" parameterIt is important to notice the last parameter in every event related function, this is an pointer to any type of data you want to pass to the callback function. When we delete the callback, in every case, the return value will be the same pointer or NULL in case of failure. [edit] References
[edit] Assembled ExamplesThe Enlightenment Foundation Libraries use pkg-config to store the necessary
compilation data. Unix users with the libraries properly installed can compile
these examples with: [edit] API Basics
#include <stdlib.h>
#include <Evas.h>
#include <Ecore.h>
#include <Ecore_Evas.h>
#include <Edje.h>
//The pointer to a canvas wrapper
Ecore_Evas *ecore_evas = NULL;
//The pointer to an Evas canvas
Evas *evas = NULL;
//The pointer to a given Edje object
Evas_Object *edje = NULL;
//Width and height for resizing Evas/Edje objects
Evas_Coord width, height;
int main() {
//Control that the libraries are properly initialized
if (!ecore_init()) return EXIT_FAILURE;
if (!ecore_evas_init()) return EXIT_FAILURE;
if (!edje_init()) return EXIT_FAILURE;
//Check the canvas wrapper (800x600 X11 window) is created correctly
ecore_evas = ecore_evas_software_x11_new(NULL, 0, 0, 0, 800, 600);
if (!ecore_evas) return EXIT_FAILURE;
//We set some window attributes and make the wrapper visible
ecore_evas_title_set(ecore_evas, "Example Application");
ecore_evas_name_class_set(ecore_evas, "testapp", "Testapp");
ecore_evas_show(ecore_evas);
//Get the pointer to the canvas and add tan object
evas = ecore_evas_get(ecore_evas);
edje = edje_object_add(evas);
edje_object_file_set(edje, "testfile.edj", "testgroup");
//Setting the object and canvas to the minimal size of the object
evas_object_move(edje, 0, 0);
edje_object_size_min_get(edje, &width, &height);
evas_object_resize(edje, width, height);
ecore_evas_resize(ecore_evas, width, height);
evas_object_show(edje);
//Starting the main application loop
ecore_main_loop_begin();
//Once the window is closed (ending the loop) we clean up our mess
ecore_evas_shutdown();
ecore_shutdown();
edje_shutdown();
}
[edit] Events in Ecore
#include <stdlib.h>
#include <stdio.h>
#include <Ecore.h>
#include <Ecore_Evas.h>
//The pointer to a canvas wrapper
Ecore_Evas *ecore_evas = NULL;
//Pointers to Ecore handlers
Ecore_Event_Handler* close = NULL;
//Handles cleaning up and closing the application
int
good_bye(void *data, int type, void *event)
{
//Remove the handler for no practical reason but showoff API
if (ecore_event_handler_del(close)) printf("Handler deleted\n");
printf("Good bye! \n");
ecore_main_loop_quit();
ecore_evas_shutdown();
ecore_shutdown();
}
int main() {
//Control that the libraries are properly initialized
if (!ecore_init()) return EXIT_FAILURE;
if (!ecore_evas_init()) return EXIT_FAILURE;
if (!edje_init()) return EXIT_FAILURE;
//Check the canvas wrapper (800x600 X11 window) is created correctly
ecore_evas = ecore_evas_software_x11_new(NULL, 0, 0, 0, 800, 600);
if (!ecore_evas) return EXIT_FAILURE;
//We set some window attributes and make the wrapper visible
ecore_evas_title_set(ecore_evas, "Example Application");
ecore_evas_name_class_set(ecore_evas, "testapp", "Testapp");
ecore_evas_show(ecore_evas);
//Add the handler for the exit signal before starting the loop
close = ecore_event_handler_add(ECORE_EVENT_SIGNAL_EXIT,good_bye,"data");
//Starting the main application loop
ecore_main_loop_begin();
}
[edit] Events in Edje
#include <stdlib.h>
#include <stdio.h>
#include <Evas.h>
#include <Ecore.h>
#include <Ecore_Evas.h>
#include <Edje.h>
//The pointer to a canvas wrapper
Ecore_Evas *ecore_evas = NULL;
//The pointer to an Evas canvas
Evas *evas = NULL;
//The pointer to a given Edje object
Evas_Object *edje = NULL;
//Width and height for resizing Evas/Edje objects
Evas_Coord width, height;
//Pointers to Ecore handlers
Ecore_Event_Handler* close = NULL;
//Handles cleaning up and closing the application
void
good_bye(void *data, Evas_Object *o, const char *emission, const char *source)
{
if(edje_object_signal_callback_del(edje,emission,source,good_bye))
printf("Deleted the handler: %s -> %s\n",source,emission);
printf("Good bye! \n");
ecore_main_loop_quit();
ecore_evas_shutdown();
ecore_shutdown();
}
int main() {
//Control that the libraries are properly initialized
if (!ecore_init()) return EXIT_FAILURE;
if (!ecore_evas_init()) return EXIT_FAILURE;
if (!edje_init()) return EXIT_FAILURE;
//Check the canvas wrapper (800x600 X11 window) is created correctly
ecore_evas = ecore_evas_software_x11_new(NULL, 0, 0, 0, 800, 600);
if (!ecore_evas) return EXIT_FAILURE;
//We set some window attributes and make the wrapper visible
ecore_evas_title_set(ecore_evas, "Example Application");
ecore_evas_name_class_set(ecore_evas, "testapp", "Testapp");
ecore_evas_show(ecore_evas);
//Get the pointer to the canvas and add tan object
evas = ecore_evas_get(ecore_evas);
edje = edje_object_add(evas);
edje_object_file_set(edje, "testfile.edj", "testgroup");
//Setting the object and canvas to the minimal size of the object
evas_object_move(edje, 0, 0);
edje_object_size_min_get(edje, &width, &height);
evas_object_resize(edje, width, height);
ecore_evas_resize(ecore_evas, width, height);
evas_object_show(edje);
//Add the handler for the exit signal before starting the loop
edje_object_signal_callback_add(edje, "closeme!", "arbitrary_source", good_bye, "data");
//Starting the main application loop
ecore_main_loop_begin();
}
[edit] EDC SourceAll the examples use the same EDC source code compilable with ``edje_cc``.
data {
item: "test" "value";
}
collections {
group {
name: "testgroup";
min: 250 250;
max: 500 500;
parts {
part {
name: "test";
type: RECT;
description {
color: 128 128 128 255;
}
}
part {
name: "i_just_sit_here";
type: RECT;
description {
color: 190 70 70 255;
rel1.relative: 0.25 0.25;
rel2.relative: 0.75 0.75;
}
}
}
programs {
program {
name: "i_actually_talk_to_the_app";
signal: "mouse,clicked,1";
source: "i_just_sit_here";
action: SIGNAL_EMIT "closeme!" "arbitrary_source";
}
}
}
}
|