Il s'agit dans cet exemple de créer deux points A et B qu'on peut déplacer à l'aide de la souris puis de tracer la droite (AB).

/**
* droite.cpp
*
* On trace deux points libres A et B (on peut modifier leurs positions à l'aide de la souris
* puis on trace la droite (AB) lorsque A est différent de B
*/
#include "geo2D/geo2D.h"
#define W 800
#define H 600
#define W0 400
#define H0 300
class Donnees {
public:
GdkCursor *fleche;
GdkCursor *hand;
bool presse;
repere *R;
point_libre *A;
point_libre *B;
droite *AB;
};
Classe regroupant les différents données utilisées par le programme : les deux curseurs (flèche et main), le booléen presse utilisé pour des déplacements des points puis les quatre objets géométriques.
static void paint (GtkWidget *widget, GdkEventExpose *event, Donnees *D) {
cairo_t *cr;
cr = gdk_cairo_create (widget->window);
cairo_select_font_face (cr, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
cairo_set_font_size (cr, 12.0);
cairo_set_source_rgb (cr, 1,1,1);
cairo_paint (cr);
cairo_stroke (cr);
cairo_set_source_rgb (cr, 1, 0, 0);
cairo_set_line_width (cr, 1.0);
D->R->trace (cr);
cairo_set_source_rgb (cr, 0, 0, 1);
cairo_set_line_width (cr, 1.0);
D->A->trace (cr);
D->B->trace (cr);
D->AB->trace (cr);
cairo_stroke (cr);
cairo_destroy (cr);
}
On redessine ici la figure : on définit le support du dessin, on peint le fond en blanc, on trace le repère en rouge puis les points et enfin la droite en bleu..
static void event_press (GtkWidget *widget, GdkEventButton *event, Donnees *D) {
int X = event->x;
int Y = event->y;
D->presse = D->A->select (X, Y) || D->B->select (X, Y);
if (D->presse)
gdk_window_set_cursor (widget->window, D->hand);
}
Méthode appelée lorsque qu'on presse le bouton de la souris : on teste d'abord dans l'ordre la proximité des points A et B. Si c'est le cas on sélectionne le point et on modifie le curseur..
static void event_motion (GtkWidget *widget, GdkEventMotion *event, Donnees *D) {
int X = event->x;
int Y = event->y;
if (D->presse) {
D->A->bouge (X, Y);
D->B->bouge (X, Y);
D->AB->droite_pt_pt (D->A, D->B);
gtk_widget_queue_draw (widget);
Méthode appelée lors du déplacement de la souris. Si un point A ou B a été sélectionné on le bouge puis on recalcule la droite (AB) puis on retrace la figure (gtk_widget_queue_draw (widget)).
} else {
bool proche = D->A->zone (X, Y) || D->B->zone (X, Y);
gdk_window_set_cursor (widget->window, (proche) ? D->hand : D->fleche);
}
}
Si aucun point n'est sélectionné, on change uniquement le curseur à proximité des points A ou B.
static void event_release (GtkWidget *widget, GdkEventButton *bev, Donnees *D) {
D->A->stop ();
D->B->stop ();
D->presse = FALSE;
gdk_window_set_cursor (widget->window, D->fleche);
}
On relâche le bouton de la souris : On arrête le mouvement du point qu'on vient de déplacer, on modifie l'indicateur D->presse puis on remet le curseur par défaut.
int main (int argc, char *argv []) {
GtkWidget * fenetre;
Donnees *D;
D = new Donnees;
// D = (Donnees *) malloc (sizeof (Donnees));
D->R = new repere (W0, H0, W, H, 100.0, 100.0, 1.0, 1.0);
D->A = new point_libre (1.0, 0.0, "A", D->R);
D->B = new point_libre (0.0, 1.0, "B", D->R);
D->AB = new droite (D->A, D->B, NULL, D->R);
gtk_init (&argc, &argv);
D->fleche = gdk_cursor_new (GDK_LEFT_PTR);
D->hand = gdk_cursor_new (GDK_HAND1);
D->presse = FALSE;
On construit les différentes données, les curseurs devant être créés après l'initialisation.
fenetre = gtk_window_new (GTK_WINDOW_TOPLEVEL);
g_signal_connect (fenetre, "expose-event", G_CALLBACK (paint), D);
g_signal_connect (fenetre, "destroy", G_CALLBACK (gtk_main_quit), NULL);
On relie le signal de "retraçage" à la méthode paint et le signal de fermeture de la fenêtre à la méthode gtk_main_quit. La classe des données est passée en paramètre.
gtk_widget_add_events (fenetre, GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
g_signal_connect (G_OBJECT (fenetre), "button_press_event", G_CALLBACK (event_press), D);
g_signal_connect (G_OBJECT (fenetre), "button_release_event", G_CALLBACK (event_release), D);
g_signal_connect (G_OBJECT (fenetre), "motion_notify_event", G_CALLBACK (event_motion), D);
On relie les signaux envoyés par les mouvementss de la souris aux méthodes event_press, event_motion et event_release. La classe des données est passée en paramètre.
gtk_window_set_position (GTK_WINDOW (fenetre), GTK_WIN_POS_CENTER);
gtk_window_set_default_size (GTK_WINDOW (fenetre), W, H);
gtk_widget_set_app_paintable (fenetre, TRUE);
gtk_widget_show_all (fenetre);
gtk_main ();
return 0;
}
On initialise la fenêtre (position, taille et possibilité de "peindre") puis on lance l'application.