EZ-Draw fonctionne à la fois sous X11 (Linux, MacOS, et autres Unix) et Windows (Seven, Vista, XP, etc) ; en interne il est basé respectivement sur la librairie Xlib et sur l'API win32, et il masque tous leurs aspects techniques.
(*) Normes C ANSI et C99.
Vous pouvez aussi programmer directement dans le répertoire de EZ-Draw et rajouter les noms des exécutables dans le fichier Makefile (sous Unix) ou Makefile.win (sous Windows).
"demo0.c". Il faut commencer par inclure "ez-draw.h" :
ce fichier décrit les types et prototypes du module, et il inclut aussi les
fichiers .h standards tels que <stdio.h>, <stdlib.h>,
<string.h>.
Dans le main, on initialise le module et le mode graphique
en appelant ez_init() ; si l'initialisation du mode graphique échoue,
la fonction affiche un message d'erreur dans la console, puis renvoie -1.
Dans ce cas, il faut sortir du programme en faisant exit(1) .
Ensuite on crée une (ou plusieurs) fenêtres avec la fonction
ez_window_create. Ces fenêtres sont affichées quand le programme
atteint ez_main_loop(). C'est cette fonction qui fait
"vivre" les fenêtres par une boucle sans fin, qui peut être interrompue
par un appel à ez_quit(), ou qui s'arrête lorsque toutes les fenêtres sont
détruites.
#include "ez-draw.h"
int main ()
{
Window win1;
if (ez_init() < 0) exit(1);
win1 = ez_window_create (400, 300, "Demo 0 : Hello World", NULL);
ez_main_loop ();
exit(0);
}
On obtient cette fenêtre :
demo0.c, sous Unix taper :
gcc -Wall demo0.c ez-draw.c -o demo0 -L/usr/X11R6/lib -lX11 -lXext
ou sous Windows taper :
gcc -Wall demo0.c ez-draw.c -o demo0.exe -lgdi32
On peut aussi rajouter le nom de l'exécutable à la fin de EXECS =
dans le Makefile sous Unix
(ou Makefile.win pour Windows),
puis taper make all pour compiler.
ez_window_create.
Ses paramètres sont :
Window ez_window_create (int w, int h, const char *name, Ez_func func);
w est la largeur (width) de l'intérieur de la fenêtre en pixels,
h est la hauteur (height),
name est le titre de la fenêtre ;
func est la fonction d'évènement de la fenêtre, voir ci-dessous.
Le résultat de ez_window_create est le numéro qui identifie la
fenêtre, de type Window ; on peut afficher une variable
Window win dans la console par printf ("win = 0x%x\n", (int) win);
La fonction d'évènement func, encore appelée callback,
est une fonction de votre programme (ou NULL comme dans l'exemple
demo0). Cette fonction sera automatiquement
appelée par ez_main_loop() lors de chaque évènement concernant la
fenêtre.
La fonction func
doit obligatoirement avoir le prototype suivant :
void func (Ez_event *ev);
La variable ev pointe sur un struct dont les champs décrivent
l'évènement. On détaille ces champs dans la section 1.6. Tous les évènements.
Découvrons deux évènements dans l'exemple suivant :
Expose est déclenché. Vous devez
alors redessiner l'ensemble du contenu de la fenêtre ev->win.
KeyPress est
déclenché. Le code de la touche est disponible dans ev->key_sym
(pour key symbol). Chaque code de touche correspond à une constante
préfixée par XK_, par exemple ici XK_q pour la touche "q".
#include "ez-draw.h"
void win1_event (Ez_event *ev) /* Appele'e a chaque evenement sur win1 */
{ /* par ez_main_loop() */
switch (ev->type) {
case Expose : /* Il faut tout redessiner */
ez_set_color (ez_red);
ez_draw_text (ev->win, EZ_MC, 200, 150,
"Pour quitter, tapez sur la touche 'q', ou\n"
"cliquez sur l'icone fermeture de la fenetre");
break;
case KeyPress : /* Une touche a ete pressee */
switch (ev->key_sym) {
case XK_q : ez_quit (); break;
}
break;
}
}
int main ()
{
Window win1;
if (ez_init() < 0) exit(1);
win1 = ez_window_create (400, 300, "Demo 1 : fenetre et evenements", win1_event);
ez_main_loop ();
exit(0);
}
On obtient cette fenêtre :
Expose signifie qu'il faut redessiner le contenu
de la fenêtre, ce qu'on fait dans l'exemple suivant en appelant
win1_redessiner. À noter, pour chaque Expose, EZ-Draw
vide entièrement la fenêtre (avec un fond blanc) avant de passer
l'évènement à votre programme.
La liste des dessins est donné dans 2.4. Dessins.
Les coordonnées sont relatives à l'origine, qui est le coin en haut à gauche
de l'intérieur de la fenêtre, avec x vers la droite et y
vers le bas.
Les dessins sont automatiquements coupés par le bord de la fenêtre, il n'y a donc pas à se préoccuper de savoir si un dessin risque de dépasser ou pas.
Les dessins sont fait dans l'épaisseur courante (par défaut 1 pixel).
On peut changer l'épaisseur courante avec ez_set_thick,
voir 2.4..
Les dessins sont fait dans la couleur courante (par défaut en noir).
Pour changer la couleur courante, on appelle ez_set_color en lui
donnant un numéro de couleur. Quelques couleurs sont prédéfinies :
ez_black, ez_white, ez_grey, ez_red, ez_green, ez_blue, ez_yellow, ez_cyan, ez_magenta.
On peut créer d'autres couleurs, voir 2.3. Couleurs.
#include "ez-draw.h"
void win1_redessiner (Window win)
{
ez_set_color (ez_magenta);
ez_draw_text (win, EZ_BL, 10, 20, "draw epaisseur 1 :");
ez_set_thick (1);
ez_draw_point (win, 30, 50);
ez_draw_line (win, 60, 35, 130, 70);
ez_draw_rectangle (win, 160, 30, 220, 70);
ez_draw_circle (win, 240, 30, 300, 70);
ez_draw_triangle (win, 320, 30, 380, 40, 350, 70);
ez_set_color (ez_black);
ez_draw_text (win, EZ_BL, 10, 100, "draw epaisseur 2 :");
ez_set_color (ez_cyan);
ez_set_thick (2);
ez_draw_point (win, 30, 130);
ez_draw_line (win, 60, 115, 130, 150);
ez_draw_rectangle (win, 160, 110, 220, 150);
ez_draw_circle (win, 240, 110, 300, 150);
ez_draw_triangle (win, 320, 110, 380, 120, 350, 150);
ez_set_color (ez_blue);
ez_draw_text (win, EZ_BL, 10, 180, "draw epaisseur 9 :");
ez_set_color (ez_green);
ez_set_thick (9);
ez_draw_point (win, 30, 210);
ez_draw_line (win, 60, 195, 130, 230);
ez_draw_rectangle (win, 160, 190, 220, 230);
ez_draw_circle (win, 240, 190, 300, 230);
ez_draw_triangle (win, 320, 190, 380, 200, 350, 230);
ez_set_color (ez_red);
ez_draw_text (win, EZ_BL, 10, 260, "fill :");
ez_set_color (ez_yellow);
ez_fill_rectangle (win, 160, 270, 220, 310);
ez_fill_circle (win, 240, 270, 300, 310);
ez_fill_triangle (win, 320, 270, 380, 280, 350, 310);
}
void win1_event (Ez_event *ev) /* Appele'e a chaque evenement sur win1 */
{
switch (ev->type) {
case Expose : /* Il faut tout redessiner */
win1_redessiner (ev->win);
break;
case KeyPress : /* Une touche a ete pressee */
switch (ev->key_sym) {
case XK_q : ez_quit (); break;
}
break;
}
}
int main ()
{
Window win1;
if (ez_init() < 0) exit(1);
win1 = ez_window_create (400, 320, "Demo 2 : tous les dessins", win1_event);
ez_main_loop ();
exit(0);
}
On obtient cette fenêtre :
ez_draw_text. Elle prend en paramètre la fenêtre,
le type d'alignement align,
puis des coordonnées x1,y1, enfin une chaîne de caractères
à imprimer, ou comme dans printf, un format et des arguments.
Tout est détaillé dans 2.5. Texte et fontes.
Le résultat peut comporter des \n, provoquant des saut de lignes
dans l'affichage.
L'affichage de texte se fait dans la couleur courante, modifiable par
ez_set_color.
On profite de l'exemple suivant pour montrer aussi l'usage de
ez_window_get_size pour faire un dessin qui s'adapte
aux changements de taille de la fenêtre.
#include "ez-draw.h"
void win1_redessiner (Window win)
{
int i, w, h;
ez_window_get_size (win, &w, &h);
ez_set_color (ez_black);
for (i = 0; i <= 3; i++) {
ez_set_nfont (i);
ez_draw_text (win, EZ_TC, w/2, h/2 + 25*(i-2),
"Fonte numero %d", i); /* comme un printf */
}
ez_set_nfont (0);
ez_set_color (ez_red);
ez_draw_text (win, EZ_TL, 2, 1, "Top\nLeft");
ez_draw_text (win, EZ_TC, w/2, 1, "Top\nCenter");
ez_draw_text (win, EZ_TR, w-2, 1, "Top\nRight");
ez_draw_text (win, EZ_ML, 2, h/2, "Middle\nLeft");
ez_draw_text (win, EZ_MR, w-2, h/2, "Middle\nRight");
ez_draw_text (win, EZ_BL, 2, h-2, "Bottom\nLeft");
ez_draw_text (win, EZ_BC, w/2, h-2, "Bottom\nCenter");
ez_draw_text (win, EZ_BR, w-2, h-2, "Bottom\nRight");
}
void win1_event (Ez_event *ev) /* Appele'e a chaque evenement sur win1 */
{
switch (ev->type) {
case Expose : /* Il faut tout redessiner */
win1_redessiner (ev->win);
break;
case KeyPress : /* Une touche a ete pressee */
switch (ev->key_sym) {
case XK_q : ez_quit (); break;
}
break;
}
}
int main ()
{
Window win1;
if (ez_init() < 0) exit(1);
win1 = ez_window_create (400, 300, "Demo 3 : affichage de texte", win1_event);
ez_main_loop ();
exit(0);
}
On obtient cette fenêtre :
ev
(les autres champs sont réinitialisés à 0).
Par défaut, le bouton "Fermer" dans la barre de titre d'une des fenêtres de
l'application provoque la fin du programme. On peut changer ce réglage
d'origine en faisant ez_auto_quit(0) : le bouton "Fermer" provoquera
l'évènement WindowClose, comme dans l'exemple suivant :
#include "ez-draw.h"
void win1_event (Ez_event *ev) /* Appele'e a chaque evenement sur win1 */
{
switch (ev->type) {
/* Il faut tout redessiner */
case Expose :
ez_draw_text (ev->win, EZ_MC, 200, 150,
"L'affichage des evenements\nest fait dans la console.\n\n"
"Tapez 'q' pour quitter.");
printf ("Expose win = 0x%x\n", (int) ev->win);
break;
/* Un bouton de la souris a ete enfonce ou relache */
case ButtonPress :
printf ("ButtonPress win = 0x%x mx = %d my = %d mb = %d\n",
(int) ev->win, ev->mx, ev->my, ev->mb);
break;
case ButtonRelease :
printf ("ButtonRelease win = 0x%x mx = %d my = %d mb = %d\n",
(int) ev->win, ev->mx, ev->my, ev->mb);
break;
/* La souris a ete deplacee dans la fenetre */
case MotionNotify :
printf ("MotionNotify win = 0x%x mx = %d my = %d mb = %d\n",
(int) ev->win, ev->mx, ev->my, ev->mb);
break;
/* Une touche du clavier a ete enfoncee ou relachee */
case KeyPress :
printf ("KeyPress win = 0x%x mx = %d my = %d "
"key_sym = 0x%x key_name = %s key_count = %d key_string = \"%s\"\n",
(int) ev->win, ev->mx, ev->my,
(int) ev->key_sym, ev->key_name, ev->key_count,
ev->key_sym == XK_Return || ev->key_sym == XK_KP_Enter ? "" : ev->key_string);
break;
case KeyRelease :
printf ("KeyRelease win = 0x%x mx = %d my = %d "
"key_sym = 0x%x key_name = %s key_count = %d key_string = \"%s\"\n",
(int) ev->win, ev->mx, ev->my,
(int) ev->key_sym, ev->key_name, ev->key_count,
ev->key_sym == XK_Return || ev->key_sym == XK_KP_Enter ? "" : ev->key_string);
switch (ev->key_sym) {
case XK_q : ez_quit (); break;
}
break;
/* La geometrie de la fenetre a change */
case ConfigureNotify :
printf ("ConfigureNotify win = 0x%x width = %d height = %d\n",
(int) ev->win, ev->width, ev->height);
break;
/* La fermeture de la fenetre est interceptee */
case WindowClose :
printf ("WindowClose win = 0x%x\n", (int) ev->win);
break;
default :
printf ("Evenement inconnu : %d\n", ev->type);
}
}
int main ()
{
Window win1;
if (ez_init() < 0) exit(1);
win1 = ez_window_create (400, 300, "Demo 4 : trace les evenements", win1_event);
ez_auto_quit (0); /* pour capter l'evenement WindowClose */
ez_main_loop ();
exit(0);
}
On obtient cette fenêtre :
Seul les évènements TimerNotify ne sont pas traités ici,
voir 2.7..
Par principe (et pour des raisons techniques), les dessins ne peuvent
être faits que lors de l'évènement Expose. Si l'on veut mettre à jour
le dessin dans la fenêtre lors d'un autre évènement, il suffit d'envoyer
l'évènement Expose avec la fonction ez_send_expose.
C'est ce que l'on fait ici pour les évènements
ButtonPress, MotionNotify et KeyPress.
#include "ez-draw.h"
#define SOM_MAX 100
int som_nb = 0, som_x[SOM_MAX], som_y[SOM_MAX];
void sommet_vider ()
{
som_nb = 0;
}
void sommet_ajouter (int x, int y)
{
if (som_nb >= SOM_MAX) return;
som_x[som_nb] = x;
som_y[som_nb] = y;
som_nb++;
}
void sommet_deplacer (int x, int y)
{
if (som_nb <= 0 || som_nb >= SOM_MAX) return;
som_x[som_nb-1] = x;
som_y[som_nb-1] = y;
}
void sommet_dessiner (Window win)
{
int i;
/* On dessine les sommets */
ez_set_color (ez_blue);
for (i = 0; i < som_nb; i++)
ez_draw_rectangle (win, som_x[i]-2, som_y[i]-2, som_x[i]+2, som_y[i]+2);
/* On relie les sommets par des segments */
ez_set_color (ez_grey);
for (i = 1; i < som_nb; i++)
ez_draw_line (win, som_x[i-1], som_y[i-1], som_x[i], som_y[i]);
}
/* Fonction appelee a chaque evenement sur win1 */
void win1_event (Ez_event *ev)
{
switch (ev->type) {
case Expose :
ez_set_color (ez_black);
ez_draw_text (ev->win, EZ_TL, 10, 10,
"Cliquez et tirez la souris dans la fenetre pour dessiner.\n"
"Tapez sur espace pour vider la fenetre, 'q' pour quitter.");
sommet_dessiner (ev->win);
break;
case ButtonPress :
sommet_ajouter (ev->mx, ev->my);
ez_send_expose (ev->win);
break;
case MotionNotify :
if (ev->mb == 0) break; /* pas de bouton enfonce' */
sommet_deplacer (ev->mx, ev->my);
ez_send_expose (ev->win);
break;
case ButtonRelease :
break;
case KeyPress :
switch (ev->key_sym) {
case XK_q :
ez_quit ();
break;
case XK_space :
sommet_vider ();
ez_send_expose (ev->win);
break;
}
break;
}
}
int main ()
{
Window win1;
if (ez_init() < 0) exit(1);
win1 = ez_window_create (400, 300, "Demo 5 : dessin a la souris", win1_event);
/* On associe un double-buffer d'affichage pour eviter tout clignotement */
ez_window_dbuf (win1, 1);
ez_main_loop ();
exit(0);
}
On obtient cette fenêtre :
ez_window_create. Chaque fenêtre créée est immédiatement affichée
par dessus les autres fenêtres. Pour faire détruire une fenêtre win (et donc
la faire disparaître de l'écran), utiliser ez_window_destroy (win).
On peut cacher une fenêtre win (c'est-à-dire la rendre invisible)
avec ez_window_show (win, 0) puis la rendre visible (par dessus
les autres fenêtres) avec ez_window_show (win, 1).
Dans cet exemple, on paramètre la boucle principale en faisant
ez_auto_quit(0) : le bouton "Fermer" de la barre de titre d'une fenêtre
ne provoquera plus la fin du programme, mais provoquera l'évènement WindowClose.
Selon la fenêtre incriminée, on cache la fenêtre, détruit la fenêtre ou
quitte le programme.
#include "ez-draw.h"
/* En global */
Window win1, win2, win3 = None; int show2 = 0;
void win3_event (Ez_event *ev) /* Appele'e a chaque evenement sur win3 */
{
switch (ev->type) {
case Expose :
ez_draw_text (ev->win, EZ_TL, 10, 10,
"Si vous fermez cette fenetre, elle sera detruite.");
break;
case WindowClose :
ez_window_destroy (win3); win3 = None;
break;
}
}
void win2_event (Ez_event *ev) /* Appele'e a chaque evenement sur win2 */
{
switch (ev->type) {
case Expose :
ez_draw_text (ev->win, EZ_TL, 10, 10,
"Si vous fermez cette fenetre, elle sera simplement cachee.");
break;
case WindowClose :
ez_window_show (win2, 0); show2 = 0;
break;
}
}
void win1_event (Ez_event *ev) /* Appele'e a chaque evenement sur win1 */
{
switch (ev->type) {
case Expose :
ez_draw_text (ev->win, EZ_TL, 10, 10,
"Cliquez dans cette fenetre (pour donner le focus clavier),\n"
"puis tapez :\n"
" - sur 'm' pour montrer ou cacher la fenetre 2 ;\n"
" - sur 'c' pour creer ou detruire la fenetre 3 ;\n"
" - sur 'q' pour quitter.\n"
"\n"
"Si vous fermez cette fenetre, le programme se terminera.");
break;
case KeyPress :
switch (ev->key_sym) {
case XK_q : ez_quit (); break;
case XK_m :
show2 = !show2; /* on affiche ou on cache la fenetre */
ez_window_show (win2, show2);
break;
case XK_c :
if (win3 == None) /* si la fenetre n'existe pas, on la cree */
win3 = ez_window_create (380, 220, "Fenetre 3", win3_event);
else { ez_window_destroy (win3); win3 = None; }
break;
}
break;
/* L'utilisateur a clique' sur le bouton de fermeture de la fenetre */
case WindowClose : ez_quit (); break;
}
}
int main ()
{
if (ez_init() < 0) exit(1);
win1 = ez_window_create (400, 300, "Demo 6 : plusieurs fenetres", win1_event);
win2 = ez_window_create (400, 200, "Fenetre 2", win2_event);
ez_window_show (win2, show2);
/* Par defaut, fermer n'importe quelle fenetre provoque la fin du programme.
On desactive cette fin automatique ; fermer une fenetre provoquera alors
l'evenement WindowClose pour ce window. */
ez_auto_quit (0);
ez_main_loop ();
exit(0);
}
On obtient cette fenêtre :
#include "ez-draw.h"
#define BUF_MAX 80
char buf1[BUF_MAX] = "", buf2[BUF_MAX] = "";
/* Renvoie 1 si l'affichage doit etre refait, 2 si texte valide', 0 sinon */
int saisie_texte (Ez_event *ev, char *s)
{
int i;
switch (ev->key_sym) {
case XK_BackSpace : /* Touche backspace */
i = strlen (s);
if (i == 0) break;
s[i-1] = 0;
return 1;
case XK_Return : /* Touche Entree */
return 2;
default : /* Insertion d'un caractere */
if (ev->key_count != 1) break;
i = strlen (s);
if (i >= BUF_MAX-1) break;
s[i] = ev->key_string[0]; s[i+1] = 0;
return 1;
}
return 0;
}
void affi_texte (Window win, int x, int y, char *s1, char *s2)
{
ez_set_color (ez_black);
ez_draw_text (win, EZ_TL, x, y, "Texte : %s_", s1);
if (strcmp (buf2, "") != 0) {
ez_set_color (ez_red);
ez_draw_text (win, EZ_TC, 200, 70,
"Vous avez valide le texte :\n%s", s2);
}
}
void win1_event (Ez_event *ev) /* Appele'e a chaque evenement sur win1 */
{
int k;
switch (ev->type) {
case Expose :
affi_texte (ev->win, 10, 10, buf1, buf2);
break;
case KeyPress :
k = saisie_texte (ev, buf1);
if (k == 2) strncpy (buf2, buf1, BUF_MAX);
if (k > 0) ez_send_expose (ev->win);
break;
}
}
int main ()
{
Window win1;
if (ez_init() < 0) exit(1);
win1 = ez_window_create (400, 200, "Demo 7 : saisie de texte", win1_event);
ez_main_loop ();
exit(0);
}
On obtient cette fenêtre :
Attention, il ne faut surtout pas employer sleep ou usleep car
ces fonction empêchent les callbacks de "rendre la main" à ez_main_loop, et donc
elles figent l'affichage et l'interface (ou les perturbent fortement).
Le principe d'une animation est le suivant :
main, qui provoque un évènement TimerNotify
quelques millisecondes plus tard ;
TimerNotify dans la callback de la fenêtre,
on fait trois choses :
Expose pour que l'affichage soit fait ;
TimerNotify
(on obtient une espèce de "boucle" de TimerNotify temporisée) ;
Expose est reçu, on redessine la fenêtre
en tenant compte du compteur (ou des coordonnées) pour dessiner l'objet animé
dans sa position courante. Il ne faut pas dessiner pour un autre évènement,
car cela perturberait le double-buffer d'affichage.
De plus, EZ-Draw optimise l'affichage en éliminant les évènements Expose
inutiles.
Voici un premier exemple simple, où l'animation consiste à faire grossir un
cercle au milieu de la fenêtre (que l'on peut agrandir) :
#include "ez-draw.h"
#define MAX_CPT1 100
int cpt1 = 0, win1_w = 300, win1_h = 200, delay1 = 30;
void win1_redessiner (Window win)
{
/* On fait le dessin en fonction de cpt1 */
int xc = win1_w/2, rx = xc * cpt1 / MAX_CPT1,
yc = win1_h/2, ry = yc * cpt1 / MAX_CPT1;
ez_set_color (ez_magenta);
ez_set_thick (3);
ez_draw_circle (win, xc-rx, yc-ry, xc+rx, yc+ry);
ez_set_color (ez_black); ez_set_nfont (0);
ez_draw_text (win, EZ_BL, 8, win1_h-8, "q : quitter");
}
void win1_event (Ez_event *ev) /* Callback appele'e a chaque evenement sur win1 */
{
switch (ev->type) {
/* Lorsqu'on recoit cet evenement, il faut tout redessiner */
case Expose :
win1_redessiner (ev->win);
break;
/* Le timer est arrive' a echance */
case TimerNotify :
/* On incremente le compteur cpt1 pour modifier la position de l'objet
que l'on veut animer */
cpt1 = (cpt1 + 1) % MAX_CPT1;
/* On envoie l'evenement Expose pour que la fenetre soit redessinee */
ez_send_expose (ev->win);
/* On re'arme le timer, pour entretenir une "boucle" de TimerNotify
qui est iteree tous les delay1 millisecondes */
ez_start_timer (ev->win, delay1);
break;
/* Une touche a ete pressee */
case KeyPress :
switch (ev->key_sym) {
case XK_q : ez_quit (); break;
}
break;
/* On memorise la nouvelle taille de la fenetre */
case ConfigureNotify :
win1_w = ev->width; win1_h = ev->height;
break;
}
}
int main ()
{
Window win1;
if (ez_init() < 0) exit(1);
win1 = ez_window_create (win1_w, win1_h, "Demo 8a : hypnose", win1_event);
/* On associe un double-buffer d'affichage pour eviter tout clignotement */
ez_window_dbuf (win1, 1);
/* Provoque l'envoie d'un evenement TimerNotify dans delay1 millisecondes :
c'est le point de depart de la "boucle" de TimerNotify */
ez_start_timer (win1, delay1);
ez_main_loop ();
exit(0);
}
On obtient cette fenêtre :
L'exemple suivant demo8b.c illustre les animations
multiples : on fait tourner les aiguilles d'une montre dans une
fenêtre (on peut faire pause avec la touche espace), tandis qu'une balle rebondit
sur une raquette dans une seconde fenêtre (que l'on peut agrandir).
On obtient ces fenêtres :
Initialisation générale. Renvoie 0 succès, -1 échec.
int ez_init ();
Boucle principale.
void ez_main_loop ();
Cette fonction affiche les fenêtres créées, puis attend les évènements et appelle
au fur et à mesure la fonction d'évènements correspondante (callback)
de la fenêtre concernée.
ez_quit() dans une callback.
Une fois revenu de cette fonction, il ne faut plus faire aucun graphisme.
Cette fonction fait sortir de ez_main_loop().
void ez_quit ();
Modifie l'effet du bouton "Fermer" de la barre de titre d'une fenêtre,
pour toutes les fenêtres du programme.
void ez_auto_quit (int val);
Par défaut (cas où val = 1), si on clique sur le bouton "Fermer" de n'importe
quelle fenêtre d'un programme, il se termine immédiatement.
ez_auto_quit avec val = 0 :
si ensuite l'utilisateur clique sur le bouton "Fermer" d'une fenêtre,
le programme (au lieu de se terminer) recevra l'évènement WindowClose pour cette fenêtre ;
libre alors à votre programme de décider ce qu'il veut faire :
ez_window_destroy ;
ez_window_show ;
ez_quit ;
Crée et affiche une fenêtre, de largeur w et hauteur h,
avec un titre name, et une fonction func appelée pour chaque évènement.
Renvoie l'identifiant entier de la fenêtre, de type Window.
Window ez_window_create (int w, int h, const char *name, Ez_func func);
Détruit une fenêtre win.
void ez_window_destroy (Window win);
Rend visible (val = 1) ou cache (val = 0) une fenêtre win.
void ez_window_show (Window win, int val);
Change ou récupère la taille d'une fenêtre.
void ez_window_set_size (Window win, int w, int h);
void ez_window_get_size (Window win, int *w, int *h);
Vide une fenêtre (fond blanc ) et réinitialise aux valeurs par défaut
les paramètres de dessin { couleur, épaisseur, fonte }.
ez_window_clear (Window win);
Envoie un évènement Expose a la fenêtre, pour la vider
et la forcer à se redessiner.
void ez_send_expose (Window win);
Affecte la couleur des prochains dessins, y compris l'affichage de texte.
void ez_set_color (unsigned long color);
Les couleurs suivantes sont prédéfinies :
ez_black, ez_white, ez_grey, ez_red, ez_green, ez_blue, ez_yellow, ez_cyan, ez_magenta.
Calcule une couleur à partir des niveaux R,G,B entre 0 et 255.
unsigned long ez_get_RGB (unsigned char R, unsigned char G, unsigned char B);
Calcule une couleur grise à partir de son niveau g entre 0 et 255.
unsigned long ez_get_grey (unsigned long g);
Dessins de base. Les coordonnées sont relatives à l'origine, qui est le point
en haut à gauche de l'intérieur de la fenêtre ; x va vers la droite
et y va vers le bas.
void ez_draw_point (Window win, int x1, int y1);
void ez_draw_line (Window win, int x1, int y1, int x2, int y2);
void ez_draw_rectangle (Window win, int x1, int y1, int x2, int y2);
void ez_fill_rectangle (Window win, int x1, int y1, int x2, int y2);
void ez_draw_triangle (Window win, int x1, int y1, int x2, int y2, int x3, int y3);
void ez_fill_triangle (Window win, int x1, int y1, int x2, int y2, int x3, int y3);
void ez_draw_circle (Window win, int x1, int y1, int x2, int y2);
void ez_fill_circle (Window win, int x1, int y1, int x2, int y2);
Pour les rectangles et les cercles, x1,y1 et y2,y2 sont les
coordonnées en haut à gauche et en bas à droite de la boîte englobante.
Par défaut, la couleur est le noir ; se change avec ez_set_color.
Change l'épaisseur courante des traits. thick est la nouvelle épaisseur en pixels.
void ez_set_thick (int thick);
Par défaut, les traits ont une épaisseur de 1 pixel.
On peut fixer une épaisseur plus grande pour les dessins réalisés par :
ez_draw_point,
ez_draw_line, ez_draw_rectangle,
ez_draw_triangle, ez_draw_circle.
Charge une fonte à partir de son nom (exemple "6x13") et la stocke
pour le numéro num.
Renvoie 0 succès, -1 erreur.
int ez_font_load (int num, const char *name);
Le numéro de fonte doit être inférieur à EZ_FONT_MAX.
Fontes préchargées :
"6x13"
"8x16"
"10x20"
"12x24"
xhauteur" (une fonte approchante de taille fixe
est obtenue).
Affecte le numéro de fonte pour les prochains affichages de texte.
void ez_set_nfont (int num);
Affiche du texte, s'utilise comme printf.
void ez_draw_text (Window win, Ez_Align align, int x1, int y1,
const char *format, ...);
Exemple :
ez_draw_text (win, EZ_TL, 10, 10, "Largeur = %d\nHauteur = %d", w, h);
Les coordonnées x1,y1 sont données par rapport à align,
qui prend pour valeurs :
EZ_TL (Top Left),
EZ_TC (Top Center),
EZ_TR (Top Right),
EZ_ML (Middle Left),
EZ_MC (Middle Center),
EZ_MR (Middle Right),
EZ_BL (Bottom Left),
EZ_BC (Bottom Center),
EZ_BR (Bottom Right).
Le texte est tracé par dessus le dessin actuel ; on peut aussi faire effacer
le fond en même temps (avec du blanc) en utilisant pour align les
constantes
EZ_TLF (Top Left Filled),
EZ_TCF (Top Center Filled),
EZ_TRF (Top Right Filled),
EZ_MLF (Middle Left Filled),
EZ_MCF (Middle Center Filled),
EZ_MRF (Middle Right Filled),
EZ_BLF (Bottom Left Filled),
EZ_BCF (Bottom Center Filled),
EZ_BRF (Bottom Right Filled).
Par défaut :
"6x13") ;
se change avec ez_set_nfont.
ez_set_color.
Active ou inactive l'affichage double-buffer pour le window win.
void ez_window_dbuf (Window win, int val);
Par défaut, l'affichage double-buffer est désactivé (val = 0).
Si l'affichage double-buffer est activé (val = 1) pour un window,
les dessins dans ce window doivent obligatoirement être faits uniquement
lors des évènements Expose de ce window.
Si le double-buffer est inactivé, ce n'est plus une obligation, mais cela
reste fortement conseillé.
Comme exemple, voir dans jeu-nim.c
les fonctions gui_init(), win1_onKeyPress(), win1_onExpose().
Dans ce jeu, on peut tester l'affichage avec et sans le double-buffer (presser la lettre 'd' pour basculer entre l'un et l'autre) :
Chaque fenêtre peut être associée à (au plus) un timer.
À l'échéance du timer, l'application reçoit un évènement unique
TimerNotify pour le window concerné, puis le timer est supprimé.
Arme un timer pour le window win avec un délai delay en millisecondes.
void ez_start_timer (Window win, int delay);
Tout rappel de cette fonction avant l'échéance du timer annule et remplace le timer.
Si de plus delay vaut -1, alors le timer est supprimé
(remarque : ce n'est pas une erreur de supprimer un timer déjà supprimé ou inexistant).
Comme exemple, voir demo8a.c.
struct.
On peut ensuite récupérer cette donnée à tout moment dans le programme.
Ce mécanisme permet ainsi d'éviter l'emploi de variables globales.
Mémorise la donnée data dans la fenêtre win.
void ez_set_data (Window win, void *data);
Retrouve la donnée à partir de la fenêtre win.
void *ez_get_data (Window win);
La fonction renvoie la donnée.
Voici un exemple de programme qui affiche un cercle, dont les coordonnées
sont placées dans une variable globale md :
#include "ez-draw.h"
typedef struct {
int x, y, r;
} Mes_donnees;
Mes_donnees md; /* 1. Variable globale */
void win1_event (Ez_event *ev)
{
switch (ev->type) {
case Expose :
/* 3. Utilisation */
ez_draw_circle (ev->win, md.x-md.r, md.y-md.r, md.x+md.r, md.y+md.r);
break;
}
}
int main ()
{
Window win1;
if (ez_init() < 0) exit(1);
/* 2. Initialisation */
md.x = 200; md.y = 100; md.r = 50;
win1 = ez_window_create (400, 300, "Demo client-data 1", win1_event);
ez_main_loop ();
exit(0);
}
Voici maintenant le même programme sans variable globale,
en mémorisant la donnée dans la fenêtre :
#include "ez-draw.h"
typedef struct {
int x, y, r;
} Mes_donnees;
void win1_event (Ez_event *ev)
{
/* 4. On retrouve les données attachées à la fenêtre */
Mes_donnees *md = ez_get_data (ev->win);
switch (ev->type) {
case Expose :
/* 5. Utilisation */
ez_draw_circle (ev->win, md->x-md->r, md->y-md->r, md->x+md->r, md->y+md->r);
break;
}
}
int main ()
{
Window win1;
Mes_donnees md; /* 1. Variable locale à main() */
if (ez_init() < 0) exit(1);
/* 2. Initialisation */
md.x = 200; md.y = 100; md.r = 50;
win1 = ez_window_create (400, 300, "Demo client-data 2", win1_event);
/* 3. On mémorise la donnée dans la fenêtre */
ez_set_data (win1, &md);
ez_main_loop ();
exit(0);
}
Comme autre exemple, voir jeu-taquin.c.
Renvoie un entier aléatoire entre 0 et n-1.
int ez_random (int n);
Remarque : le générateur de nombres aléatoires est initialisé par ez_init.