Overall, EWL is similar in design and functionality to other common toolkits such as GTK+ and QT. The API's differ, but the overall concepts and ideas are similar. If you are familiar with these other toolkits, getting into EWL should be relatively simple.
EWL uses the concept of inheritance for describing it's widgets. When a class inherits from another class, the functions that operated on the base class can also operate on the inheriting class. For example, in EWL the class Ewl_Button inherits from Ewl_Box, which inherits from Ewl_Container. This means you can add widgets to the button, just like you could to the box or any other container by using ewl_container_append. Since EWL is written in C, it uses a very simple single inheritance system. The first field of the inheriting struct must be the inherited struct, and note, it's not a pointer to the inherited struct. For example:
struct Ewl_Foo { Ewl_Bar bar; int baz; };
Creates a new class of objects, Foo, which inherits from the Bar class and extends it by adding an integer baz. If the first line of the struct had been Ewl_Bar *bar; it would most likely result in some buffer overflows when initializing the widget.
The next step above the Ewl_Object is the Ewl_Widget. Again, these are never allocated by themselves, but are part of all the other widgets available in EWL. The Ewl_Widget class provides necessary information about a widget that relates to it's appearance, it's parent container, event handling, as well as a few miscellaneous tasks common to all widgets.
A necessary class that some widgets inherit from is Ewl_Container. This is used for holding collections of widgets and laying them out. Containers are the building blocks of the widget set, they allow for creating heirarchies of widgets that are bounded within their parent containers. The class inherits from Ewl_Widget, so that any container can also be treated as a widget, and thus you can put containers within other containers. Examples of inheriting classes are Ewl_Window and Ewl_Box. In the case of the Ewl_Window, widgets inside the window are given any position they request within the insets of the window. For the Ewl_Box, contained widgets are layed out either from top to bottom, or from left to right, depending on the box orientation.
One feature of EWL that is different from other toolkits is that it makes extensive use of internal callbacks. In fact, almost all appearance changes for widgets are actually callbacks, and most of the ewl_widget calls actually do very little work, but trigger specific callbacks. This feature allows for overriding specific actions on a widget, or for ordering user specified callbacks relative to internal ones. Example Application Walk-through
One of the easiest applications to build for EWL is a simple image viewer. The basic image viewer needs a window, and an image widget. The following app is a fully functional simple image viewer based on code written by Ben Rockwood of Cuddletech. The first part necessary for creating an EWL application is to include the necessary header Ewl.h. Following the include statements are global variable declarations.
Now declarations of function callbacks are made, normally when writing an application these are added after the GUI code is written. The next piece of code is common to most apps, the windows in EWL are not closed unless they are destroyed, so a callback must be attached for the windows delete callback.
void __destroy_main_window(Ewl_Widget *main_win, void *ev_data, void *user_data) { ewl_widget_destroy(main_win); ewl_main_quit(); return; }
For this simple application, that is the only necessary callback, now we have the main function. This is where EWL is initialized, widgets are created, and the main EWL loop is started. First, declare the main function and check to be sure that an image file was specified, then initialize the EWL library.
int main (int argc, char **argv) { if (argc < 2) { fprintf(stderr, "Usage: %s <image>\n", argv[0]); return 1; } ewl_init(&argc, argv);
Next allocate the window, set it's title and attach a callback to catch it's delete event. Also, set a minimum size on the window, also mark it to be auto-sized, and visible. Marking it auto-sized will cause the widget to resize to fit the contents.
main_win = ewl_window_new(); ewl_window_set_title(EWL_WINDOW(main_win), "EWL Simple Image Viewer"); ewl_callback_append(main_win, EWL_CALLBACK_DELETE_WINDOW, __destroy_main_window, NULL); ewl_object_set_minimum_size(EWL_OBJECT(main_win), 100, 100); ewl_widget_show(main_win);
Now we create a box for holding the image, this is not really necessary for this app, but it demonstrates further how to use containers, and makes it easier to add more widgets later.
main_box = ewl_vbox_new(); ewl_container_append_child(EWL_CONTAINER(main_win), main_box); ewl_widget_show(main_box);
Next, create the image widget, we just attempt to load the image file that was specified on the command line, and add it to the box in the window.
image = ewl_image_new(argv[1]); ewl_container_append_child(EWL_CONTAINER(main_box), image); ewl_widget_show(image);
Finally, we call the main function that starts the EWL event processing loop, and with that our app is complete.
ewl_main(); return 0; }
Now that the application source has been written, it must be compiled. This is fairly simple with EWL, if you name the app simple_viewer.c just use the command:
gcc -o simple_viewer `ewl-config --cflags --libs` simple_viewer.c
If you have questions, corrections, or improvements, please send them to RbdPngn.