1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
| #include <gtk/gtk.h>
/* Structure qui va nous servir à atteindre les différentes images à dessiner
* ainsi que différentes données nécessaire à la position de l'image
* courante déplacée.
*/
typedef struct
{
GdkPixbuf *MainPixbuf;
GdkPixbuf *SecondPixbuf;
gint XCurrentPosition; // Position X courante de SecondPixbuf
gint YCurrentPosition; // Position Y courante de SecondPixbuf
gint XPointer; // Position x de la souris lors du clic
gint YPointer; // Position y de la souris lors du clic.
gboolean ButtonPressedInPixbuf;
} MainData;
/* Fonction d'affichage du drawingarea. */
gboolean callback_expose_event(GtkWidget *widget, GdkEventExpose *event,
MainData *data)
{
/* On crée un nouveau contexte graphique. Permet de changer la couleur
* d'avant plan pour écrire du texte par exemple. Ici on n'en a besoin
* pour afficher les pixbuf.
*/
GdkGC *gc = gdk_gc_new (widget->window);
/* On commence par afficher l'image de fond qui est MainPixbuf de data. */
gdk_draw_pixbuf(widget->window, gc, data->MainPixbuf, 0, 0, 0, 0,
gdk_pixbuf_get_width(data->MainPixbuf),
gdk_pixbuf_get_height(data->MainPixbuf),
GDK_RGB_DITHER_MAX, 0, 0);
/* On ajoute maintenant par dessus la deuxième image à sa nouvelle position.
*/
gdk_draw_pixbuf(widget->window, gc, data->SecondPixbuf, 0, 0,
data->XCurrentPosition, data->YCurrentPosition,
gdk_pixbuf_get_width(data->SecondPixbuf),
gdk_pixbuf_get_height(data->SecondPixbuf),
GDK_RGB_DITHER_MAX, 0, 0);
/* Destruction du contexte graphique devenu inutile. */
g_object_unref (gc);
return FALSE;
}
/* Fonction de gestion du déplacement de la souris.*/
gboolean callback_mouse_moved (GtkWidget *drawingarea, GdkEventMotion *event,
MainData *data)
{
gint XOffset, YOffset; // Contiendra le décalage à effectuer.
/* On commence par voir si le bouton gauche de la souris est enfoncé.
* Pour ca on regarde la variable "states" de l'event transmis au callback.
*/
if (event->state>>8)
{
/* Si le bouton de la gauche de la souris est enfoncé et que le curseur
* est dans le carré noir alors on le déplace. */
if (data->ButtonPressedInPixbuf)
{
/* On calcule le décalage. */
XOffset = (gint)event->x - data->XPointer;
YOffset = (gint)event->y - data->YPointer;
data->XPointer = (gint)event->x;
data->YPointer = (gint)event->y;
/* Déplace le carré noir. */
data->XCurrentPosition += XOffset;
data->YCurrentPosition += YOffset;
/* Il ne nous reste plus qu'à demander à rafraichir la fenêtre.
* Pour se faire on simplement quelle partie il faut redessiner. Je
* spécifie ici l'ancienne position du rectangle qui sera redessiné
* en blanc.
*/
gtk_widget_queue_draw_area(drawingarea,
data->XCurrentPosition - XOffset,
data->YCurrentPosition - YOffset,
gdk_pixbuf_get_width(data->SecondPixbuf),
gdk_pixbuf_get_height(data->SecondPixbuf));
}
else
g_print("pas dans le carré \n");
}
return FALSE;
}
/* Fonction de gestion du clic de souris. */
gboolean callback_button_pressed (GtkWidget *widget, GdkEventButton *event,
MainData *data)
{
GdkRectangle zone; // permet de savoir si on est dans le rectangle.
GdkRegion *region = NULL;
/* On commence par voir si le bouton gauche de la souris est enfoncé.
*/
if (event->button == 1)
{
/* La deuxième étape maintenant doit nous assurer que le pointeur est
* bien sur le carré noir à déplacr.
*/
zone.x=data->XCurrentPosition;
zone.y=data->YCurrentPosition;
zone.width = gdk_pixbuf_get_width(data->SecondPixbuf);
zone.height = gdk_pixbuf_get_height(data->SecondPixbuf);
region = gdk_region_rectangle (&zone);
if (gdk_region_point_in(region, (gint)event->x,(gint)event->y))
{
data->ButtonPressedInPixbuf=TRUE;
data->XPointer = (gint)event->x;
data->YPointer = (gint)event->y;
}
else
data->ButtonPressedInPixbuf=FALSE;
gdk_region_destroy (region);
}
return FALSE;
}
gint main (gint argc, gchar *argv[])
{
GtkWidget *window = NULL;
GtkWidget *drawingarea= NULL;
MainData data;
gtk_init (&argc, &argv);
/* Création de la fenêtre principale. Rien de bien compliqué ici. */
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_default_size (GTK_WINDOW(window), 400, 400);
/* On crée deux images. L'image de fond est blanche et l'image déplacé est
* un cube noir de 40 de côté. Il est bien sûr possible d'utiliser
* la fonction gdk_pixbuf_new_from_file(); à la place.
*/
data.MainPixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, 400, 400);
gdk_pixbuf_fill(data.MainPixbuf, 0xFFFFFFFF);
data.SecondPixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, 40, 40);
gdk_pixbuf_fill(data.SecondPixbuf, 0x00000000);
/* On positionne la deuxième image au centre de la fenêtre. */
data.XCurrentPosition = 180;
data.YCurrentPosition = 180;
/* On initialise le reste des données. */
data.ButtonPressedInPixbuf = FALSE;
/* Création d'un GtkWidgetArea qui va nous servir de support. On y déposera
* par la suite une image de fond sur laquelle se déplacera une autre image
* à l'aide de la souris.
*/
drawingarea = gtk_drawing_area_new();
gtk_container_add(GTK_CONTAINER(window), drawingarea);
/* Maintenant un GtkDrawingArea n'écoute pas tous les signaux émis. Si tel
* était le cas il ralentirait lourdement l'application. En partant de là
* il nous faut lui indiquer quels signaux écoutés.
* GDK_POINTER_MOTION_MASK : est émis lorsque la souris se déplace sur le
* drawingarea
* GDK_BUTTON_PRESS_MASK : est émis lorsqu'un bouton de la souris est
* enfoncé
*/
gtk_widget_set_events(drawingarea, GDK_POINTER_MOTION_MASK|GDK_BUTTON_PRESS_MASK);
/* Enfin on connecte le signal écouté à une fonction CallBack. C'est dans
* ces fonctions que le calcul de déplacement s'effectuera.
*/
g_signal_connect (G_OBJECT(drawingarea), "motion-notify-event", G_CALLBACK(callback_mouse_moved), &data);
g_signal_connect (G_OBJECT(drawingarea), "button-press-event", G_CALLBACK(callback_button_pressed), &data);
g_signal_connect (G_OBJECT(drawingarea), "expose_event", G_CALLBACK(callback_expose_event), &data);
/* On connecte la fermeture de la fenêtre principale à l'arrêt du programme.
*/
g_signal_connect (window, "delete-event", G_CALLBACK(gtk_main_quit), NULL);
/* On affiche le tout */
gtk_widget_show_all (window);
/* On lance la boucle principale gtk. */
gtk_main ();
return 0;
} |