1. Tutorial¶
The easiest way to proceed is to work directly in the EZ-Draw directory, starting from an example, and to complete the provided Makefile, see section Compilation.
1.1. First program with a window¶
Let us write our first program that opens a window, and name it demo-01.c
.
We first include ez-draw.h (line 1, see below):
this file defines the types and prototypes of the main EZ-Draw module,
and it also includes the standard headers such as <stdio.h>
, <stdlib.h>
,
<string.h>
, so we don’t need to worry about.
In main
, we initialize the module and the graphic mode by calling
ez_init()
; if the initialization fails, the function print
an error message in the terminal, then return -1.
In this case, we must terminate the program by exit(1)
.
Next we create one (or several) window(s) using function
ez_window_create()
. These windows are displayed when the program
reaches ez_main_loop()
: that is this function which “gives life” to the
windows. It stops when one calls ez_quit()
, or when all windows are
destroyed.
Here is the file demo-01.c :
1
2#include "ez-draw.h"
3
4
5int main ()
6{
7 if (ez_init() < 0) exit(1);
8
9 ez_window_create (400, 300, "Demo 01: Hello World", NULL);
10
11 ez_main_loop ();
12 exit(0);
13}
14
This window is obtained:
1.2. Compilation¶
To compile demo-01.c
in a terminal on Unix, type
gcc -Wall demo-01.c ez-draw.c -o demo-01 -lX11 -lXext
or on Windows, type
gcc -Wall demo-01.c ez-draw.c -o demo-01.exe -lgdi32
To run the program in a terminal on Unix, type
./demo-01
or on Windows, type
demo-01
It is more handy to use the command make
instead of typing over
and over the gcc
command line.
The command make
use the same Makefile on Unix and on Windows.
To compile everything the first time, or to compile again the modified C files, it is sufficient to type in the terminal, whichever your system is:
make all
On error, see chapter Installation.
If everything is up to date, make
will display:
make: Nothing to be done for `all'.
You can always force a general re-compilation by typing:
make clean all
Finally if you want to clean your directory, for instance before making a backup, type:
make distclean
This will erase all executable and temporary files, and will keep only the source files.
- Exercise :
Edit the file
demo-01.c
, and change the title with"My first program"
. Compile withmake
then run the program.
Let us see now how to add a new program. Just edit the file
Makefile , and add in section C the name of the executable in the list
EXECS
, EXECS_M
or EXECS_IM
, then save.
We can then type make all
to compile the new program.
There are several lists to distinguish between cases:
EXECS
: to compile only with ez-draw.c ;EXECS_M
: to compile with ez-draw.c and-lm
(the math library);EXECS_IM
: to compile with ez-draw.c,-lm
and ez-image.c (to display images).
Here are the current lists in the Makefile :
EXECS = demo-01 demo-02 demo-03 demo-04 demo-05 demo-06 demo-07 demo-08 \
demo-09 demo-11 jeu-sudoku jeu-nim jeu-vie jeu-taquin jeu-2048 \
jeu-tetris
EXECS_M = demo-10 jeu-laby jeu-ezen jeu-heziom jeu-tangram
EXECS_IM = demo-12 demo-13 demo-14 demo-15 demo-16 demo-17 \
As you can see, when a list is on several lines, the intermediary lines
are ended by a \
.
- Exercise :
Copy the file
demo-01.c
astrial1.c
, and addtrial1
in the Makefile. Compile withmake
then run the program.
You can use the provided Makefile for more advanced projects
divided in several modules. Suppose that your executable is named myappli
,
that your project uses the modules ez-draw.c
, ez-image.c
, myprog.c
and misc.c
, and that you need the libraries -lm
and -lgomp
.
You just have to complete the fields EXECS_PRO
, OBJS_PRO
and
LIBS_PRO
in the Makefile section D like that:
EXECS_PRO = myappli
OBJS_PRO = ez-draw.o ez-image.o myprog.o misc.o
LIBS_PRO = -lm -lgomp
Finally, if you want to create your project in a new directory, here are the files that you have to copy in it:
ez-image.h and ez-image.c (if you plan to display images),
Just clear the EXECS
lists in the Makefile and fill the necessary fields.
1.3. Event handler¶
We will now take a look at the handling of events in the windows.
The parameters of the function ez_window_create()
which is
responsible of a window creation are:
Ez_window ez_window_create (int w, int h, const char *name, Ez_func on_event);
w
is the width of the interior of the window in pixels,
h
is the height,
name
is the window title;
on_event
is the event handler of the window, see below.
The result of ez_window_create()
has type Ez_window
;
it is used to identify the window, and can be printed in the terminal
as an hexadecimal value:
Ez_window win1;
win1 = ez_window_create (400, 300, "Demo 0: Hello World", NULL);
printf ("win1 = 0x%x\n", ez_window_get_id(win1));
To be able to interact with the user (key press and release, mouse moves and
click, etc) we have to realize a so-called event handling;
that is why we give the function on_event
as a fourth parameter of
ez_window_create()
.
The event handler on_event
(also named callback), is a function of
your program (or NULL
as in example demo-01
).
This function will be automatically called by ez_main_loop()
for each event that involves the window.
The function on_event
has the following prototype:
void on_event (Ez_event *ev);
The parameter ev
is the address of a struct whose fields describe
the event; in particular, ev->win
tells which window is involved.
The other fields are detailed in section Tracing events.
We study two events in the following example demo-02.c :
The window manager tells to your program if the windows must be redrawn (the first time they appear, when another window is passing ahead, etc). When this happens, an
Expose
event is generated and the event handler is called. At this time you have to redraw the whole content of the windowev->win
.
When the user press a key, the
KeyPress
event is generated. The key code is available inev->key_sym
(for key symbol). Each key code is expressed as a constant prefixed byXK_
, for instanceXK_q
stands for the key “q”.
1
2#include "ez-draw.h"
3
4
5void win1_on_event (Ez_event *ev) /* Called by ez_main_loop() */
6{ /* for each event on win1 */
7 switch (ev->type) {
8
9 case Expose : /* We must redraw everything */
10 ez_set_color (ez_red);
11 ez_draw_text (ev->win, EZ_MC, 200, 150,
12 "To quit, press the key 'q', or click\n"
13 "on the Close button of the window");
14 break;
15
16 case KeyPress : /* A key was pressed */
17 switch (ev->key_sym) {
18 case XK_q : ez_quit (); break;
19 }
20 break;
21 }
22}
23
24
25int main ()
26{
27 if (ez_init() < 0) exit(1);
28
29 ez_window_create (400, 300, "Demo 02: Window and events", win1_on_event);
30
31 ez_main_loop ();
32 exit(0);
33}
34
This window is obtained:
This example demo-02.c is a first attempt to manage the events, using a big
switch
into win1_on_event
.
The drawback of this method is the rapid growing of the switch
when
enhancing the program, leading the program potentially unreadable.
That is why it is better to split win1_on_event
in functions
(still using a switch
),
each of them being specialized for an event; we do it in the next section.
1.4. Drawings and colors¶
As explained in the previous section, the Expose
event
means that the whole content of the windows must be redrawn.
In the next example we redraw by calling win1_on_expose
.
Note: for each Expose
event, EZ-Draw empties the window
(with a white background) before passing the event to your program.
The list of drawings is given in section Drawings.
The coordinates are relative to the Origin, which is the top left
corner inside the window; x
goes to the right and y
goes down.
The drawings are automatically cut by the window border, so that there is no need to worry if a drawing fits or not.
The drawings are performed using the current thickness (1 pixel by default).
you can change the thickness with ez_set_thick()
,
see Drawings.
The drawings are done in the current color (black by default).
To change color, call ez_set_color()
by giving it the color number.
Some colors are predefined:
ez_black
, ez_white
, ez_grey
, ez_red
, ez_green
, ez_blue
,
ez_yellow
, ez_cyan
, ez_magenta
.
It is possible to create other colors, see Colors.
Here is the file demo-03.c :
1
2#include "ez-draw.h"
3
4
5void win1_on_expose (Ez_event *ev)
6{
7 ez_set_color (ez_magenta);
8 ez_draw_text (ev->win, EZ_BL, 10, 20, "Thickness 1");
9 ez_set_thick (1);
10 ez_draw_point (ev->win, 30, 50);
11 ez_draw_line (ev->win, 60, 35, 130, 70);
12 ez_draw_rectangle (ev->win, 160, 30, 220, 70);
13 ez_draw_circle (ev->win, 240, 30, 300, 70);
14 ez_draw_triangle (ev->win, 320, 30, 380, 40, 350, 70);
15
16 ez_set_color (ez_black);
17 ez_draw_text (ev->win, EZ_BL, 10, 100, "Thickness 2");
18 ez_set_color (ez_cyan);
19 ez_set_thick (2);
20 ez_draw_point (ev->win, 30, 130);
21 ez_draw_line (ev->win, 60, 115, 130, 150);
22 ez_draw_rectangle (ev->win, 160, 110, 220, 150);
23 ez_draw_circle (ev->win, 240, 110, 300, 150);
24 ez_draw_triangle (ev->win, 320, 110, 380, 120, 350, 150);
25
26 ez_set_color (ez_blue);
27 ez_draw_text (ev->win, EZ_BL, 10, 180, "Thickness 9");
28 ez_set_color (ez_green);
29 ez_set_thick (9);
30 ez_draw_point (ev->win, 30, 210);
31 ez_draw_line (ev->win, 60, 195, 130, 230);
32 ez_draw_rectangle (ev->win, 160, 190, 220, 230);
33 ez_draw_circle (ev->win, 240, 190, 300, 230);
34 ez_draw_triangle (ev->win, 320, 190, 380, 200, 350, 230);
35
36 ez_set_color (ez_red);
37 ez_draw_text (ev->win, EZ_BL, 10, 260, "Fill");
38 ez_set_color (ez_yellow);
39 ez_fill_rectangle (ev->win, 160, 270, 220, 310);
40 ez_fill_circle (ev->win, 240, 270, 300, 310);
41 ez_fill_triangle (ev->win, 320, 270, 380, 280, 350, 310);
42}
43
44
45void win1_on_key_press (Ez_event *ev)
46{
47 switch (ev->key_sym) {
48 case XK_q : ez_quit (); break;
49 }
50
51}
52
53
54void win1_on_event (Ez_event *ev) /* Called by ez_main_loop() */
55{ /* for each event on win1 */
56 switch (ev->type) {
57 case Expose : win1_on_expose (ev); break;
58 case KeyPress : win1_on_key_press (ev); break;
59 }
60}
61
62
63int main ()
64{
65 if (ez_init() < 0) exit(1);
66
67 ez_window_create (400, 320, "Demo 03: All drawings", win1_on_event);
68
69 ez_main_loop ();
70 exit(0);
71}
72
This window is obtained:
1.5. Displaying text¶
It is possible to draw text at any place in the window, thanks to
the function ez_draw_text()
. It takes as arguments: the window,
the kind of alignment align
, the coordinates x1,y1
,
finally a string to draw, or as in printf
, a format and parameters.
Everything is detailed in section Text and fonts.
The string can contain some \n
, causing line breaks in the display.
The text drawing is performed in the current color, modifiable by
ez_set_color()
.
In the next example demo-04.c we illustrate this, as well as the use of
ez_window_get_size()
to kindly adapt the drawing to the window
size changes.
1
2#include "ez-draw.h"
3
4
5void win1_on_expose (Ez_event *ev)
6{
7 int i, w, h;
8
9 ez_window_get_size (ev->win, &w, &h);
10
11 ez_set_color (ez_black);
12 for (i = 0; i <= 3; i++) {
13 ez_set_nfont (i);
14 ez_draw_text (ev->win, EZ_TC, w/2, h/2 + 25*(i-2),
15 "Font number %d", i); /* like a printf */
16 }
17
18 ez_set_nfont (0);
19 ez_set_color (ez_red);
20
21 ez_draw_text (ev->win, EZ_TL, 2, 1, "Top\nLeft");
22 ez_draw_text (ev->win, EZ_TC, w/2, 1, "Top\nCenter");
23 ez_draw_text (ev->win, EZ_TR, w-2, 1, "Top\nRight");
24 ez_draw_text (ev->win, EZ_ML, 2, h/2, "Middle\nLeft");
25 ez_draw_text (ev->win, EZ_MR, w-2, h/2, "Middle\nRight");
26 ez_draw_text (ev->win, EZ_BL, 2, h-2, "Bottom\nLeft");
27 ez_draw_text (ev->win, EZ_BC, w/2, h-2, "Bottom\nCenter");
28 ez_draw_text (ev->win, EZ_BR, w-2, h-2, "Bottom\nRight");
29}
30
31
32void win1_on_key_press (Ez_event *ev)
33{
34 switch (ev->key_sym) {
35 case XK_q : ez_quit (); break;
36 }
37
38}
39
40
41void win1_on_event (Ez_event *ev)
42{
43 switch (ev->type) {
44 case Expose : win1_on_expose (ev); break;
45 case KeyPress : win1_on_key_press (ev); break;
46 }
47}
48
49
50int main ()
51{
52 if (ez_init() < 0) exit(1);
53
54 ez_window_create (400, 300, "Demo 04: Displaying text", win1_on_event);
55
56 ez_main_loop ();
57 exit(0);
58}
59
This window is obtained:
1.6. Tracing events¶
In the next example we list all possible events, and we trace in the terminal
the ev
variable fields that are usable (the other ones are set to 0).
See also section Events.
By default, the “Close” button in the title bar of one of the application
windows causes the termination of the program. We can change this behavior
by calling ez_auto_quit(0)
:
from now on, the “Close” button will cause a WindowClose
event, as in the
following example.
Here is the file demo-05.c :
1
2#include "ez-draw.h"
3
4
5void win1_on_expose (Ez_event *ev) /* We must redraw everything */
6{
7 ez_draw_text (ev->win, EZ_MC, 200, 150,
8 "Events are traced\nin the terminal.\n\n"
9 "Type 'q' to quit.");
10 printf ("Expose win = 0x%x\n", ez_window_get_id(ev->win));
11}
12
13
14void win1_on_button_press (Ez_event *ev) /* Mouse button pressed */
15{
16 printf ("ButtonPress win = 0x%x mx = %d my = %d mb = %d\n",
17 ez_window_get_id(ev->win), ev->mx, ev->my, ev->mb);
18}
19
20
21void win1_on_button_release (Ez_event *ev) /* Mouse button released */
22{
23 printf ("ButtonRelease win = 0x%x mx = %d my = %d mb = %d\n",
24 ez_window_get_id(ev->win), ev->mx, ev->my, ev->mb);
25}
26
27
28void win1_on_motion_notify (Ez_event *ev) /* Mouse moved */
29{
30 printf ("MotionNotify win = 0x%x mx = %d my = %d mb = %d\n",
31 ez_window_get_id(ev->win), ev->mx, ev->my, ev->mb);
32}
33
34
35void win1_on_key_press (Ez_event *ev) /* Key pressed */
36{
37 printf ("KeyPress win = 0x%x mx = %d my = %d "
38 "key_sym = 0x%x key_name = %s key_count = %d key_string = \"%s\"\n",
39 ez_window_get_id(ev->win), ev->mx, ev->my,
40 (int) ev->key_sym, ev->key_name, ev->key_count,
41 ev->key_sym == XK_Return || ev->key_sym == XK_KP_Enter ? "" : ev->key_string);
42}
43
44
45void win1_on_key_release (Ez_event *ev) /* Key released */
46{
47 printf ("KeyRelease win = 0x%x mx = %d my = %d "
48 "key_sym = 0x%x key_name = %s key_count = %d key_string = \"%s\"\n",
49 ez_window_get_id(ev->win), ev->mx, ev->my,
50 (int) ev->key_sym, ev->key_name, ev->key_count,
51 ev->key_sym == XK_Return || ev->key_sym == XK_KP_Enter ? "" : ev->key_string);
52 switch (ev->key_sym) {
53 case XK_q : ez_quit (); break;
54 }
55}
56
57
58void win1_on_configure_notify (Ez_event *ev) /* Window size changed */
59{
60 printf ("ConfigureNotify win = 0x%x width = %d height = %d\n",
61 ez_window_get_id(ev->win), ev->width, ev->height);
62}
63
64
65void win1_on_window_close (Ez_event *ev) /* Close button pressed */
66{
67 printf ("WindowClose win = 0x%x\n", ez_window_get_id(ev->win));
68}
69
70
71void win1_on_event (Ez_event *ev) /* Called by ez_main_loop() */
72{ /* for each event on win1 */
73 switch (ev->type) {
74 case Expose : win1_on_expose (ev); break;
75 case ButtonPress : win1_on_button_press (ev); break;
76 case ButtonRelease : win1_on_button_release (ev); break;
77 case MotionNotify : win1_on_motion_notify (ev); break;
78 case KeyPress : win1_on_key_press (ev); break;
79 case KeyRelease : win1_on_key_release (ev); break;
80 case ConfigureNotify : win1_on_configure_notify (ev); break;
81 case WindowClose : win1_on_window_close (ev); break;
82 default :
83 printf ("Unknown event: %d\n", ev->type);
84 }
85}
86
87
88int main ()
89{
90 if (ez_init() < 0) exit(1);
91
92 ez_window_create (400, 300, "Demo 05: Tracing events", win1_on_event);
93
94 ez_auto_quit (0); /* to get WindowClose event */
95
96 ez_main_loop ();
97 exit(0);
98}
99
This window is obtained:
Note: the TimerNotify
events are not treated here, see Timers.
1.7. Drawing with the mouse¶
The example shown in this section allows to draw a polygonal line with the mouse. The coordinates of the vertices are stored in global variables (we could also avoid global variables, see Client-data). Each time the mouse button is clicked, a new vertex is inserted; for each mouse move with a pressed button (drag), the last vertex is moved.
By principle (and for technical reasons), the drawings must only be done
for the Expose
event. If you want to update the drawings of a window for another
event, it is sufficient to send an Expose
event using the function
ez_send_expose()
.
We do this here, for ButtonPress
, MotionNotify
and KeyPress
events.
Here is the file demo-06.c :
1
2#include "ez-draw.h"
3
4#define VER_MAX 100
5int ver_nb = 0, ver_x[VER_MAX], ver_y[VER_MAX];
6
7
8void vertex_clear ()
9{
10 ver_nb = 0;
11}
12
13
14void vertex_insert (int x, int y)
15{
16 if (ver_nb >= VER_MAX) return;
17 ver_x[ver_nb] = x;
18 ver_y[ver_nb] = y;
19 ver_nb++;
20}
21
22
23void vertex_move (int x, int y)
24{
25 if (ver_nb <= 0 || ver_nb >= VER_MAX) return;
26 ver_x[ver_nb-1] = x;
27 ver_y[ver_nb-1] = y;
28}
29
30
31void draw_vertices (Ez_window win)
32{
33 int i;
34
35 ez_set_color (ez_blue);
36 for (i = 0; i < ver_nb; i++)
37 ez_draw_rectangle (win, ver_x[i]-2, ver_y[i]-2, ver_x[i]+2, ver_y[i]+2);
38}
39
40void draw_segments (Ez_window win)
41{
42 int i;
43
44 ez_set_color (ez_grey);
45 for (i = 1; i < ver_nb; i++)
46 ez_draw_line (win, ver_x[i-1], ver_y[i-1], ver_x[i], ver_y[i]);
47}
48
49
50void win1_on_expose (Ez_event *ev)
51{
52 ez_set_color (ez_black);
53 ez_draw_text (ev->win, EZ_TL, 10, 10,
54 "Click and drag the mouse in the window to draw.\n"
55 "Type Space to clear the window, 'q' to quit.");
56 draw_segments (ev->win);
57 draw_vertices (ev->win);
58}
59
60
61void win1_on_button_press (Ez_event *ev)
62{
63 vertex_insert (ev->mx, ev->my);
64 ez_send_expose (ev->win);
65}
66
67
68void win1_on_motion_notify (Ez_event *ev)
69{
70 if (ev->mb == 0) return; /* No button pressed */
71 vertex_move (ev->mx, ev->my);
72 ez_send_expose (ev->win);
73}
74
75
76void win1_on_key_press (Ez_event *ev)
77{
78 switch (ev->key_sym) {
79 case XK_q :
80 ez_quit ();
81 break;
82 case XK_space :
83 vertex_clear ();
84 ez_send_expose (ev->win);
85 break;
86 }
87}
88
89
90void win1_on_event (Ez_event *ev)
91{
92 switch (ev->type) {
93 case Expose : win1_on_expose (ev); break;
94 case ButtonPress : win1_on_button_press (ev); break;
95 case MotionNotify : win1_on_motion_notify (ev); break;
96 case KeyPress : win1_on_key_press (ev); break;
97 }
98}
99
100
101int main ()
102{
103 Ez_window win1;
104
105 if (ez_init() < 0) exit(1);
106
107 win1 = ez_window_create (400, 300, "Demo 06: Drawing wih the mouse", win1_on_event);
108
109 /* Enable double buffer to prevent window flashes */
110 ez_window_dbuf (win1, 1);
111
112 ez_main_loop ();
113 exit(0);
114}
115
This window is obtained:
1.8. Managing several windows¶
You can create as much windows that you want, by calling
ez_window_create()
. Each window that is created is immediately displayed
on top of the existing windows.
To destroy a window win
(and thus hide it from screen),
use ez_window_destroy(win)
.
It is possible to hide a window win
(it still exists but is not displayed) by calling
ez_window_show(win, 0)
, then show it again (on top of the
other ones) by calling ez_window_show(win, 1)
.
In the next example, the main loop is configured by
ez_auto_quit(0)
,
which means that pressing the “Close” button of the window title bar will not end the
program, but send in place a WindowClose
event.
According to the window involved, we hide the window, destroy the window
or exit the program.
Here is the file demo-07.c :
1
2#include "ez-draw.h"
3
4/* Global variables */
5Ez_window win1, win2, win3 = None; int show2 = 0;
6
7
8void win3_on_expose (Ez_event *ev)
9{
10 ez_draw_text (ev->win, EZ_TL, 10, 10,
11 "If you close this window, it will be destroyed.");
12}
13
14
15/* The user has clicked on the Close button of the window */
16
17void win3_on_window_close (Ez_event *ev)
18{
19 (void) ev; /* Tell the compiler that ev is unused */
20 ez_window_destroy (win3); win3 = None;
21}
22
23
24void win3_on_event (Ez_event *ev)
25{
26 switch (ev->type) {
27 case Expose : win3_on_expose (ev); break;
28 case WindowClose : win3_on_window_close (ev); break;
29 }
30}
31
32
33void win2_on_expose (Ez_event *ev)
34{
35 ez_draw_text (ev->win, EZ_TL, 10, 10,
36 "If you close this window, it will be hidden.");
37}
38
39
40void win2_on_window_close (Ez_event *ev)
41{
42 (void) ev;
43 ez_window_show (win2, 0); show2 = 0;
44}
45
46
47void win2_on_event (Ez_event *ev)
48{
49 switch (ev->type) {
50 case Expose : win2_on_expose (ev); break;
51 case WindowClose : win2_on_window_close (ev); break;
52 }
53}
54
55
56void win1_on_expose (Ez_event *ev)
57{
58 ez_draw_text (ev->win, EZ_TL, 10, 10,
59 "Click in this window (to get the keyboard focus),\n"
60 "then type :\n"
61 " - on 'm' to show or hide window 2;\n"
62 " - on 'c' to create or destroy window 3;\n"
63 " - on 'q' to quit.\n"
64 "\n"
65 "If you close this window, the program will end.");
66}
67
68
69void win1_on_key_press (Ez_event *ev)
70{
71 switch (ev->key_sym) {
72 case XK_q : ez_quit (); break;
73
74 case XK_m :
75 show2 = !show2; /* show or hide the window */
76 ez_window_show (win2, show2);
77 break;
78
79 case XK_c :
80 if (win3 == None) /* if the window doesn't exist, create it */
81 win3 = ez_window_create (380, 220, "Window 3", win3_on_event);
82 else { ez_window_destroy (win3); win3 = None; }
83 break;
84 }
85}
86
87
88void win1_on_window_close (Ez_event *ev)
89{
90 (void) ev;
91 ez_quit ();
92}
93
94
95void win1_on_event (Ez_event *ev)
96{
97 switch (ev->type) {
98 case Expose : win1_on_expose (ev); break;
99 case KeyPress : win1_on_key_press (ev); break;
100 case WindowClose : win1_on_window_close (ev); break;
101 }
102}
103
104
105int main ()
106{
107 if (ez_init() < 0) exit(1);
108
109 win1 = ez_window_create (400, 300, "Demo 07: Several windows", win1_on_event);
110 win2 = ez_window_create (400, 200, "Window 2", win2_on_event);
111 ez_window_show (win2, show2);
112
113 /* By default, closing any window will cause the end of the program.
114 We change this behaviour: for now on, closing any window will send
115 a WindowClose event for this window. */
116 ez_auto_quit (0);
117
118 ez_main_loop ();
119 exit(0);
120}
121
This window is obtained:
1.9. Text input¶
The next example demo-08.c demonstrates how to read a string on keyboard, suppress some characters using the Backspace, and detect the Enter key to trigger an action.
1
2#include "ez-draw.h"
3
4#define BUF_MAX 80
5char buf1[BUF_MAX] = "", buf2[BUF_MAX] = "";
6
7
8/* Return 1 if text must be displayed again, 2 if text is validated, else 0 */
9
10int text_input (Ez_event *ev, char *s)
11{
12 int i;
13
14 switch (ev->key_sym) {
15
16 case XK_BackSpace : /* Backspace key */
17 i = strlen (s);
18 if (i == 0) break;
19 s[i-1] = 0;
20 return 1;
21
22 case XK_Return : /* Enter key */
23 return 2;
24
25 default : /* Insert a character */
26 if (ev->key_count != 1) break;
27 i = strlen (s);
28 if (i >= BUF_MAX-1) break;
29 s[i] = ev->key_string[0]; s[i+1] = 0;
30 return 1;
31 }
32 return 0;
33}
34
35
36void text_display (Ez_window win, int x, int y, char *s1, char *s2)
37{
38 ez_set_color (ez_black);
39 ez_draw_text (win, EZ_TL, x, y, "Text: %s_", s1);
40
41 if (strcmp (buf2, "") != 0) {
42 ez_set_color (ez_blue);
43 ez_draw_text (win, EZ_TC, 200, 70,
44 "You have validated this text:\n%s", s2);
45 }
46}
47
48
49void win1_on_expose (Ez_event *ev)
50{
51 text_display (ev->win, 10, 10, buf1, buf2);
52}
53
54
55void win1_on_key_press (Ez_event *ev)
56{
57 int k = text_input (ev, buf1);
58 if (k == 2) strncpy (buf2, buf1, BUF_MAX);
59 if (k > 0) ez_send_expose (ev->win);
60}
61
62
63void win1_on_event (Ez_event *ev)
64{
65 switch (ev->type) {
66 case Expose : win1_on_expose (ev); break;
67 case KeyPress : win1_on_key_press (ev); break;
68 }
69}
70
71
72int main ()
73{
74 if (ez_init() < 0) exit(1);
75
76 ez_window_create (400, 200, "Demo 08: Text input", win1_on_event);
77
78 ez_main_loop ();
79 exit(0);
80}
81
This window is obtained:
1.10. Animations¶
To perform animations, two additional ingredients are needed: a timer (see Timers) to maintain the temporal sequence, and double buffering (see Double buffering) to prevent display flashing.
- Warning:
Never ever employ
sleep
orusleep
, because these functions prevent the callbacks to restore the control toez_main_loop()
, and thus they freeze the display and the interface (or at least severely disrupt them).
The principle of an animation is the following:
start a timer in
main
, which will cause aTimerNotify
event few milliseconds later;
upon receipt of this
TimerNotify
event in the window callback, we do three things:we increment a counter (or coordinates, or whatever) in order to change the position of the object to animate;
we send an
Expose
event to refresh display;last, we restart the timer such that there will be a next
TimerNotify
event (what we obtain is a kind of timed loop ofTimerNotify
events);
each time an
Expose
event is received, we redraw the window content tacking account of the counter (or the coordinates) to draw the animated object in its current position. Never draw for another event, you would disturb the double display buffer. Moreover, EZ-Draw optimize displaying by eliminating uselessExpose
events.
Here is a first example demo-09.c below. The animation shows a growing circle at the middle of the window; it also adapts the drawings to the window size changes.
1
2#include "ez-draw.h"
3
4#define MAX_CPT1 100
5
6/* We can avoid global variables by using ez_set_data(), see demo-10.c
7 and the next examples */
8int count1 = 0, win1_w = 300, win1_h = 200, delay1 = 30;
9
10
11void win1_on_expose (Ez_event *ev)
12{
13 /* We draw based on count1 */
14 int xc = win1_w/2, rx = xc * count1 / MAX_CPT1,
15 yc = win1_h/2, ry = yc * count1 / MAX_CPT1;
16
17 ez_set_color (ez_magenta);
18 ez_set_thick (3);
19 ez_draw_circle (ev->win, xc-rx, yc-ry, xc+rx, yc+ry);
20
21 ez_set_color (ez_black); ez_set_nfont (0);
22 ez_draw_text (ev->win, EZ_BL, 8, win1_h-8, "q: quit");
23}
24
25
26void win1_on_key_press (Ez_event *ev)
27{
28 switch (ev->key_sym) {
29 case XK_q : ez_quit (); break;
30 }
31}
32
33
34void win1_on_configure_notify (Ez_event *ev)
35{
36 win1_w = ev->width; win1_h = ev->height;
37}
38
39
40void win1_on_timer_notify (Ez_event *ev) /* The timer has expired */
41{
42 /* We increment the counter count1 so as to modify the position of the
43 object to animate */
44 count1 = (count1 + 1) % MAX_CPT1;
45 /* We send an Expose event so that the window will be displayed again */
46 ez_send_expose (ev->win);
47 /* We restart the timer to maintain a "loop" or TimerNotify events,
48 which is iterated each delay1 milliseconds */
49 ez_start_timer (ev->win, delay1);
50}
51
52
53void win1_on_event (Ez_event *ev)
54{
55 switch (ev->type) {
56 case Expose : win1_on_expose (ev); break;
57 case KeyPress : win1_on_key_press (ev); break;
58 case ConfigureNotify : win1_on_configure_notify (ev); break;
59 case TimerNotify : win1_on_timer_notify (ev); break;
60 }
61}
62
63
64int main ()
65{
66 Ez_window win1;
67
68 if (ez_init() < 0) exit(1);
69
70 win1 = ez_window_create (win1_w, win1_h, "Demo 09: Hypnosis", win1_on_event);
71
72 /* Enable double buffer to prevent window flashes */
73 ez_window_dbuf (win1, 1);
74
75 /* Start a timer to get a TimerNotify event in delay1 milliseconds:
76 this is the starting point of the "loop" of TimerNotify events. */
77 ez_start_timer (win1, delay1);
78
79 ez_main_loop ();
80 exit(0);
81}
82
This window is obtained:
Another example is provided by demo-10.c to illustrate multiple animations: in one window we turn the hands of a watch (type space for pause), while in another window a ball is bouncing on a racket (the window can be enlarged).
These windows are obtained:
This example demo-10.c demonstrates also how to attach an information
(e.g. a struct
) to a window, so as to avoid global variables.
For more explanations, see Client-data.
We use this possibility in the whole next part.
1.11. Images¶
In the previous sections we have seen what we can do with the basic module.
EZ-Draw comes with a second module, ez-image.c, that allows to load and display color images in PNG, JPEG, GIF or BMP format, or create an image in memory and draw into. These possibilities are detailed in sections The image type and following.
To use this module, just include ez-image.h. Here is the example demo-13.c where we get a file name as argument of the command line, then we load the image and display it:
1
2#include "ez-draw.h"
3#include "ez-image.h"
4
5
6typedef struct {
7 Ez_image *image1;
8 Ez_window win1;
9} App_data;
10
11
12void app_data_init (App_data *a, char *filename)
13{
14 a->image1 = ez_image_load (filename); /* Load an image */
15 if (a->image1 == NULL) exit (1);
16}
17
18
19void app_data_destroy (App_data *a)
20{
21 ez_image_destroy (a->image1); /* Destroy image */
22}
23
24
25void win1_on_expose (Ez_event *ev)
26{
27 App_data *a = ez_get_data (ev->win);
28
29 ez_image_paint (a->win1, a->image1, 0, 0); /* Display image */
30}
31
32
33void win1_on_key_press (Ez_event *ev)
34{
35 switch (ev->key_sym) {
36 case XK_q : ez_quit (); break;
37 }
38}
39
40
41void win1_on_event (Ez_event *ev)
42{
43 switch (ev->type) {
44 case Expose : win1_on_expose (ev); break;
45 case KeyPress : win1_on_key_press (ev); break;
46 }
47}
48
49
50int main (int argc, char *argv[])
51{
52 char *filename = "images/tux2.gif";
53 App_data a;
54
55 if (argc-1 != 1)
56 fprintf (stderr, "Usage: %s image\n", argv[0]);
57 else filename = argv[1];
58
59 if (ez_init() < 0) exit (1);
60 app_data_init (&a, filename);
61
62 a.win1 = ez_window_create ( /* Resize window for image */
63 a.image1->width, a.image1->height,
64 filename, win1_on_event);
65 ez_set_data (a.win1, &a);
66 ez_window_dbuf(a.win1, 1);
67
68 ez_main_loop ();
69
70 app_data_destroy (&a);
71 exit(0);
72}
73
This window is obtained:
To compile this file demo-13.c
on Unix, type:
gcc -Wall demo-13.c ez-draw.c ez-image.c -o demo-13 -lX11 -lXext -lm
or on Windows, type:
gcc -Wall demo-13.c ez-draw.c ez-image.c -o demo-13.exe -lgdi32 -lmsimg32 -lm
You can also append the executable file name at the end of EXECS_IM =
in the Makefile; then type make all
to compile.
The formats PNG, GIF and BMP allow to store a transparency level, in what is called the alpha channel. The formats GIF and BMP store the alpha channel over 1 bit; the pixels are either transparent (0), or opaque (255). The PNG format stores the alpha channel over 8 bits (from 0 for transparent, to 255 for opaque).
The module ez-image
is able to display an image by taking in account
the transparency, using an opacity threshold on the alpha channel:
the pixels are either opaques (displayed) or transparents (not displayed).
The next example demo-14.c gets two file names as arguments of the command line,
then superimpose both images.
You can move the second image using arrow keys, or change the opacity threshold
using keys +
and -
.
1
2#include "ez-draw.h"
3#include "ez-image.h"
4
5
6typedef struct {
7 int i2_x, i2_y;
8 Ez_image *image1, *image2;
9 Ez_window win1;
10} App_data;
11
12
13void app_data_init (App_data *a, char *filename1, char *filename2)
14{
15 a->image1 = ez_image_load (filename1);
16 if (a->image1 == NULL) exit (1);
17
18 a->image2 = ez_image_load (filename2);
19 if (a->image2 == NULL) exit (1);
20
21 /* Initial position is centered */
22 a->i2_x = (a->image1->width - a->image2->width ) / 2;
23 a->i2_y = (a->image1->height - a->image2->height) / 2;
24}
25
26
27void app_data_destroy (App_data *a)
28{
29 ez_image_destroy (a->image1);
30 ez_image_destroy (a->image2);
31}
32
33
34void win1_on_expose (Ez_event *ev)
35{
36 App_data *a = ez_get_data (ev->win);
37
38 ez_image_paint (a->win1, a->image1, 0, 0);
39 ez_image_paint (a->win1, a->image2, a->i2_x, a->i2_y);
40 ez_draw_text (a->win1, EZ_BLF, 10, a->image1->height+15,
41 "[Arrows] to move");
42 ez_draw_text (a->win1, EZ_BRF, a->image1->width-10, a->image1->height+15,
43 "Opacity [+-] : %d", a->image2->opacity);
44}
45
46
47void win1_on_key_press (Ez_event *ev)
48{
49 App_data *a = ez_get_data (ev->win);
50
51 switch (ev->key_sym) {
52 case XK_q : ez_quit (); break;
53 case XK_Left :
54 case XK_KP_Left : a->i2_x-- ; break;
55 case XK_Right :
56 case XK_KP_Right : a->i2_x++ ; break;
57 case XK_Up :
58 case XK_KP_Up : a->i2_y-- ; break;
59 case XK_Down :
60 case XK_KP_Down : a->i2_y++ ; break;
61 case XK_minus :
62 case XK_KP_Subtract : a->image2->opacity--; break;
63 case XK_plus :
64 case XK_KP_Add : a->image2->opacity++; break;
65 default : return;
66 }
67 ez_send_expose (a->win1);
68}
69
70
71void win1_on_event (Ez_event *ev)
72{
73 switch (ev->type) {
74 case Expose : win1_on_expose (ev); break;
75 case KeyPress : win1_on_key_press (ev); break;
76 }
77}
78
79
80int main (int argc, char *argv[])
81{
82 char *file1 = "images/paper1.jpg", *file2 = "images/tux1.png";
83 App_data a;
84
85 if (argc-1 != 2)
86 fprintf (stderr, "Usage: %s image1 image2\n", argv[0]);
87 else { file1 = argv[1]; file2 = argv[2]; }
88
89 if (ez_init() < 0) exit(1);
90 app_data_init (&a, file1, file2);
91
92 a.win1 = ez_window_create (a.image1->width, a.image1->height+15,
93 "Demo 14: Images with transparency", win1_on_event);
94 ez_set_data (a.win1, &a);
95 ez_window_dbuf(a.win1, 1);
96
97 ez_main_loop ();
98
99 app_data_destroy (&a);
100 exit(0);
101}
102
This window is obtained:
It is also possible to create an image in memory, then set the pixels colors. The example demo-12.c displays the HSV palette computed in this manner.
This window is obtained:
You will find more informations about images in the Reference manual.