|
|
|
NavigationPersonal tools |
EWL IntroductionThis article is a simple introduction by example to EWL. When we're finished we'll have a simple image viewer that will exit when the user presses escape or 'q'. A fairly simple example but will show off some of the fundamental features of EWL. [edit] Code ExplanationWe're going to jump straight into the code explanation. There is a complete code listing at the end of the article to make it easier to copy and compile. #include <Ewl.h> #include <stdio.h> Every EWL application needs to include Ewl.h. Ewl.h will include all of the header files required by EWL. You should never have to include any of the other EWL related headers when writing an application. static void
cb_window_destroy(Ewl_Widget *w, void *ev, void *data)
{
ewl_main_quit();
}
EWL uses callbacks to signal the running application that an event has happened. When you register a callback, which we'll see later, you'll set a callback function to be executed when the event happens. These callback functions *always* have the same signature. void func(Ewl_Widget *w, void *ev, void *data), of course you can change the function name and the parameter names. The first parameter to the callback function is the widget the callback was attached to. The second parameter is either NULL or an event struct containing extra information. The final parameter is data that we can attach to the callback if we need to. In this case we don't care about any of the parameters. Later in the code we setup this callback to be triggered when the main window gets destroyed. Since EWL will handle destroying and cleaning up our windows we just signal EWL to break out of its main loop by calling ewl_main_quit(). This will cause the call to ewl_main(), which we'll see later, to return.
static void
cb_window_close(Ewl_Widget *w, void *ev, void *data)
{
ewl_widget_destroy(w);
}
Here we have another callback. It is triggered when the user requests the window to close. You could, at this point, pop up a dialog window to ask if the user is sure they want to quit. We don't have any data to save, thus we can simply destroy our window. Note: this doesn't stop the application. The whole application won't stop until we call ewl_main_quit().
static void
cb_key_down(Ewl_Widget *w, void *ev, void *data)
{
Ewl_Event_Key_Down *e;
e = ev;
if (!strcmp(e->base.keyname, "Escape")
|| !strcmp(e->base.keyname, "q"))
{
Ewl_Widget *win;
win = ewl_widget_name_find("main_win");
ewl_widget_destroy(win);
}
}
cb_key_down is the callback we'll assign to the window to handle keyboard input. The key event callbacks are passed an Ewl_Event_Key_Down event structure. In this example we take the event structure and look for either the Escape or q key name. (These names come from Ecore.) If either of those two keys have been pressed we'll lookup the widget named main_win using ewl_widget_name_find. It is possible to assign names to your widgets in EWL. Assigning names is optional, but can be handy in cases like this to remove the need for global variables. Once we've received our main window we call ewl_widget_destroy to tell EWL to destroy the widget. This will trigger the EWL_CALLBACK_DESTROY and hence, cause cb_window_destroy to be called. EWL makes extensive use of callbacks internally to signal changes between its widgets. This has the added benefit that you can override the internal EWL behavior by removing its callbacks and adding custom functions.
int
main(int argc, char ** argv)
{
Ewl_Widget *win, *scroll, *o;
if (!ewl_init(&argc, argv))
{
fprintf(stderr, "Unable to init EWL.\n");
return 1;
}
With the pre-amble out of the way we finally get to our main program. All of the widgets we create will be of type Ewl_Widget. EWL uses a simple single inheritance model in its widgets. Through this chain every widget has Ewl_Widget as a base widget. This means, with a simple cast, you can call Ewl_Widget methods in any widget in the hierarchy. This also holds true for other inheritance items. So, you can call Ewl_Container methods on Ewl_Box widgets. An example of this inheritance can be seen in the following image. Although this is a bit out of date it gives a good idea of how the system functions. To find out the actual inheritance trees it's probably best to refer to the header files. Before you can use EWL you have to initialize the system. This is done by calling ewl_init(). You can pass the programs argc and argv parameters to EWL if you wish to have EWL strip out any EWL specific options. (EWL takes flags like --ewl-print-theme-keys, --ewl-help). This will strip the EWL flags out of argv and decrement argc as needed. If you don't want to have EWL do this, just pass NULLs into ewl_init(). It'll do the right thing. ewl_init() will return TRUE if the system was successfully configured or FALSE otherwise. If something goes wrong there should be some helpful messages printed to the command line. if (argc < 2)
{
fprintf(stderr, "Need image to view.\n");
return 1;
}
Just making sure that we've still got an image file to display. This is done after the call to ewl_init() because, as I mentioned, ewl_init() may decrement the argc variable. win = ewl_window_new(); The first thing to do is create our main window. This is done by calling ewl_window_new(). All of the widget creation calls in EWL, either currently or in the future, accept no parameters and return an Ewl_Widget object. This keeps everything consistent. ewl_window_title_set(EWL_WINDOW(win), "EWL Image Viewer");
ewl_window_class_set(EWL_WINDOW(win), "ewl_image_viewer");
ewl_window_name_set(EWL_WINDOW(win), "ewl_image_viewer");
Once we've got our window we can set up some window manager properties. This includes setting the title of the window by calling ewl_window_title_set and setting its name and class. The ewl_window_* functions accept an Ewl_Window object as their first parameter. In this case we need to cast win from an Ewl_Widget to an Ewl_Window. Each widget in EWL has a corresponding macro to cast fromn a generic widget that is the widget name in upper case. In this example we want to cast to an Ewl_Window widget so we use EWL_WINDOW() to cast. You'll see this type of casting scattered around the code. ewl_object_fill_policy_set(EWL_OBJECT(win), EWL_FLAG_FILL_ALL);
ewl_object_size_request(EWL_OBJECT(win), 640, 480);
By default an Ewl_Window will become large enough to hold its children and won't allow you to resize below the preferred child size. For our application that isn't the behavior we want. We want to be able to shrink the window down and have scrollbars appear. In order to achieve this we need to change the fill policy of the window. This is done by calling ewl_object_fill_policy_set(). We need to pass an Ewl_Object widget into the ewl_object_* functions but since Ewl_Widget inherits from Ewl_Object, all EWL widgets inherit from Ewl_Object. An explanation of the EWL fill policies can be found at: Filler Up. Since we've now changed the fill policy to be all possible fill policies the window won't have any default size. In this case we need to request a size for the window. This is done by calling ewl_object_size_request() and providing the width and height for the object. ewl_callback_append(win, EWL_CALLBACK_DELETE_WINDOW, cb_window_close, NULL);
ewl_callback_append(win, EWL_CALLBACK_KEY_DOWN, cb_key_down, NULL);
ewl_callback_append(win, EWL_CALLBACK_DESTROY, cb_window_destroy, NULL);
We attach three callbacks onto the window. The first, EWL_CALLBACK_DELETE_WINDOW will be triggered when the user attempts to close the application. The second, EWL_CALLBACK_KEY_DOWN will be triggered when a keyboard event arrives on the window. The third will be called when the widget (here the window) is destroyed. In this example we are using ewl_callback_append() to attach the callbacks. There are several other ways to attach callbacks including; ewl_callback_prepend() and ewl_callback_insert(). The functions to add callbacks all have the same signature. The first parameter is the Ewl_Widget to attach the callback too. Second is the callback type. A listing of these types can be found in EWL Callback Information. Third is the function to be called as was explained above. Finally is the user data. This is data is what is passed as the third parameter to your callback function. This can be set to anything you want or need. ewl_widget_name_set(win, "main_win"); As I mentioned earlier you can set names on widgets. This is done by calling ewl_widget_name_set() and specifying the widget and the name so set. ewl_widget_show(win); Finally we show the widget. In order for a widget to be displayed it (and all of its parents) need to be displayed. This is done by calling ewl_widget_show() and passing in the widget. scroll = ewl_scrollpane_new();
ewl_container_child_append(EWL_CONTAINER(win), scroll);
ewl_widget_show(scroll);
With the main window out of the way we move onto the scroll pane. In EWL the Ewl_Window widget will place all children in the position they request, typically top left. This is usually not what you want. To get a better layout you'll need to pack a widget into Ewl_Window to handle the layout. This is typically something like Ewl_Scrollpane or Ewl_Box. In this case we're packing a scrollpane. As before we use the _new() call to create a new scrollpane which returns an Ewl_Widget object. We then add this object into its parent container. Beacuse the window inherits from Ewl_Container we are able to use the EWL_CONTAINER() cast to allow passing our window to ewl_container_child_append(). There are other ways to append a child to a containter, including ewl_container_child_prepend() and ewl_container_child_insert(). See the ewl_container.h header file for a list of available functions. o = ewl_image_new();
ewl_image_file_path_set(EWL_IMAGE(o), argv[1]);
ewl_container_child_append(EWL_CONTAINER(scroll), o);
ewl_widget_show(o);
The last widget to be created is our image. The sequence of calls is very similar to the window and scrollpane cases. The only extra piece is setting the image into the Ewl_Image object. This is done by calling ewl_image_file_path_set() and passing in the full path to the image. There is also ewl_image_file_set() which takes an extra group parameter, used when displaying Edje files. ewl_main();
return 0;
}
With all of the widgets created and initialized we're ready to kick off our program by calling ewl_main(). This will startup the main run loop and start calling the callbacks to your program. ewl_main() will return when ewl_main_quit() is called. ewl_main_quit() will handle the call to ewl_shutdown() so you can safely just return once ewl_main() is finished. Compiling the program is as simple as executing: dj2@cerberus [~/t] -> gcc -o eiv tut.c `pkg-config --cflags --libs ewl` EWL uses the pkg-config tool to provide all of the needed parameters to compile your program. You should now be able to run your application and display a provided image. As you've hopefully seen, EWL has been designed for simplicity and consistency. We've tried to get the maximal amount of flexibility out of the system while keeping the API consistent and minimizing code duplication. If you are now interested in EWL and want to learn more, then you can go on with the second part of the introduction: EWL Introduction II. [edit] Complete Code Listing
#include <Ewl.h>
#include <stdio.h>
static void
cb_window_destroy(Ewl_Widget *w, void *ev, void *data)
{
ewl_main_quit();
}
static void
cb_window_close(Ewl_Widget *w, void *ev, void *data)
{
ewl_widget_destroy(w);
}
static void
cb_key_down(Ewl_Widget *w, void *ev, void *data)
{
Ewl_Event_Key_Down *e;
e = ev;
if (!strcmp(e->base.keyname, "Escape")
|| !strcmp(e->base.keyname, "q"))
{
Ewl_Widget *win;
win = ewl_widget_name_find("main_win");
ewl_widget_destroy(win);
}
}
int
main(int argc, char ** argv)
{
Ewl_Widget *win, *scroll, *o;
if (!ewl_init(&argc, argv))
{
fprintf(stderr, "Unable to init EWL.\n");
return 1;
}
if (argc < 2)
{
fprintf(stderr, "Need image to view.\n");
return 1;
}
win = ewl_window_new();
ewl_window_title_set(EWL_WINDOW(win), "EWL Image Viewer");
ewl_window_class_set(EWL_WINDOW(win), "ewl_image_viewer");
ewl_window_name_set(EWL_WINDOW(win), "ewl_image_viewer");
ewl_object_fill_policy_set(EWL_OBJECT(win), EWL_FLAG_FILL_ALL);
ewl_object_size_request(EWL_OBJECT(win), 640, 480);
ewl_callback_append(win, EWL_CALLBACK_DELETE_WINDOW, cb_window_close, NULL);
ewl_callback_append(win, EWL_CALLBACK_KEY_DOWN, cb_key_down, NULL);
ewl_callback_append(win, EWL_CALLBACK_DESTROY, cb_window_destroy, NULL);
ewl_widget_name_set(win, "main_win");
ewl_widget_show(win);
scroll = ewl_scrollpane_new();
ewl_container_child_append(EWL_CONTAINER(win), scroll);
ewl_widget_show(scroll);
o = ewl_image_new();
ewl_image_file_path_set(EWL_IMAGE(o), argv[1]);
ewl_container_child_append(EWL_CONTAINER(scroll), o);
ewl_widget_show(o);
ewl_main();
return 0;
}
|