/* * ez-gtk.c : boite a outil EZ-Draw-GTK pour simplifier GTK+ * * Edouard.Thiel@lif.univ-mrs.fr - 23/03/2010 - version 0.9 * * This program is free software under the terms of the * GNU Lesser General Public License (LGPL) version 2.1. */ #include "ez-gtk.h" /*------------------- I N T E R F A C E P U B L I Q U E -------------------*/ /* * Cree une fenetre, donne une taille et un titre. */ GtkWidget *ezg_window_create (int width, int height, const char *titre) { GtkWidget *win; /* Cree une fenetre, donne un titre et une taille */ win = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_window_set_default_size (GTK_WINDOW (win), width, height); gtk_window_set_title (GTK_WINDOW (win), titre); return win; } /* * Cree un drawing area qui prend toute la place dans la fenetre. */ GtkWidget *ezg_area_create (GtkWidget *win) { GtkWidget *area, *align; /* On cree un conteneur qui prend toute la place dans la fenetre */ align = gtk_alignment_new (0, 0, 1, 1); gtk_container_add (GTK_CONTAINER (win), align); /* On cree une zone de dessin, qui prend toute la place grace au conteneur */ area = gtk_drawing_area_new (); gtk_container_add (GTK_CONTAINER (align), area); return area; } /* * Vide un drawing area avec un fond blanc. */ void ezg_area_clear (GtkWidget *area) { gdk_draw_rectangle (area->window, area->style->white_gc, TRUE, 0, 0, area->allocation.width, area->allocation.height); } /* * Envoie un evenement expose_event pour forcer le drawing area a se redessiner. */ void ezg_area_expose (GtkWidget *area) { gdk_window_invalidate_rect (area->window, NULL, TRUE); } /* * Recupere le contexte graphique associe' au widget */ GdkGC *ezg_get_gc (GtkWidget *widget) { return widget->style->fg_gc[GTK_WIDGET_STATE (widget)]; } /* * Affecte la couleur des prochains dessins, y compris l'affichage de texte. */ void ezg_set_color (GdkGC *gc, Ezg_color color) { GdkColor c = {0, 0, 0, 0}; /* On specifie les couleurs sur 16 bits */ switch (color) { case EZG_BLACK : c.red = 0 << 8; c.green = 0 << 8; c.blue = 0 << 8; break; case EZG_WHITE : c.red = 255 << 8; c.green = 255 << 8; c.blue = 255 << 8; break; case EZG_GREY : c.red = 150 << 8; c.green = 150 << 8; c.blue = 150 << 8; break; case EZG_RED : c.red = 255 << 8; c.green = 0 << 8; c.blue = 0 << 8; break; case EZG_GREEN : c.red = 0 << 8; c.green = 255 << 8; c.blue = 0 << 8; break; case EZG_BLUE : c.red = 0 << 8; c.green = 0 << 8; c.blue = 255 << 8; break; case EZG_YELLOW : c.red = 255 << 8; c.green = 255 << 8; c.blue = 0 << 8; break; case EZG_CYAN : c.red = 0 << 8; c.green = 255 << 8; c.blue = 255 << 8; break; case EZG_MAGENTA : c.red = 255 << 8; c.green = 0 << 8; c.blue = 255 << 8; break; } /* Change la couleur de dessin sans faire d'allocation */ gdk_gc_set_rgb_fg_color (gc, &c); } /* * Affecte l'epaisseur des lignes dans les prochains dessins. * Ne concerne pas gdk_draw_point(). */ void ezg_set_thick (GdkGC *gc, int thick) { gdk_gc_set_line_attributes (gc, thick, GDK_LINE_SOLID, GDK_CAP_ROUND, GDK_JOIN_ROUND); } /* * Dessine un triangle */ void ezg_draw_triangle (GdkDrawable *drawable, GdkGC *gc, gboolean filled, int x0, int y0, int x1, int y1, int x2, int y2) { GdkPoint p[] = { {x0, y0}, {x1, y1}, {x2, y2}}; gdk_draw_polygon (drawable, gc, filled, p, 3); } /* * Ecrit du texte, s'utilise comme printf. * * L'affichage de texte necessite un PangoLayout. * Si on fait peu d'affichages dans la meme callback, on peut demander * a la fonction de creer un layout temporaire en lui passant NULL : * * ezg_draw_text (widget, gc, NULL, EZG_TL, 10, 10, "Bonjour"); * * Si on fait beaucoup d'affichage de texte, il vaut mieux creer un * layout avant et le detruire apres : * * PangoLayout *layout = gtk_widget_create_pango_layout (widget, NULL); * ezg_draw_text (widget, gc, layout, EZG_TL, 10, 10, "Bonjour"); * ezg_draw_text (widget, gc, layout, EZG_TL, 10, 30, "Hello"); * g_object_unref (G_OBJECT (layout)); */ void ezg_draw_text (GtkWidget *widget, GdkGC *gc, PangoLayout *layout, Ezg_align align, int x, int y, const char *format, ...) { int valign, halign, layout_priv = 0; va_list ap; char buf[16384]; PangoRectangle extents; if (align <= EZG_AA || align >= EZG_BB) { fprintf (stderr, "ezg_draw_text: bad align\n"); return; } /* Decode align */ align -= EZG_AA + 1; halign = align % 3; valign = align / 3; /* Ecrit la chaine formatee dans buf */ va_start (ap, format); vsnprintf (buf, sizeof(buf)-1, format, ap); va_end (ap); buf[sizeof(buf)-1] = 0; if (buf[0] == 0) return; if (layout == NULL) { /* On cree un layout prive' pour dessiner du texte */ layout = gtk_widget_create_pango_layout (widget, NULL); layout_priv = 1; } /* On donne la chaine a afficher */ pango_layout_set_text (layout, buf, strlen(buf)); /* On recupere les dimensions */ pango_layout_get_pixel_extents (layout, &extents, NULL); /* Alignement horizontal dans le layout */ pango_layout_set_alignment (layout, halign == 0 ? PANGO_ALIGN_LEFT : halign == 1 ? PANGO_ALIGN_CENTER : PANGO_ALIGN_RIGHT); /* Debug : affichage de la bounding box */ if (FALSE) { ezg_set_color (gc, EZG_GREY); gdk_draw_rectangle (widget->window, gc, FALSE, x - extents.width * halign/2, y - extents.height * valign/2, extents.width, extents.height); ezg_set_color (gc, EZG_RED); gdk_draw_line (widget->window, gc, x-20, y, x+20, y); gdk_draw_line (widget->window, gc, x, y-20, x, y+20); ezg_set_color (gc, EZG_BLUE); } /* Affichage du layout */ gdk_draw_layout (widget->window, gc, x - extents.x - extents.width * halign/2, y - extents.y - extents.height * valign/2, layout); if (layout_priv) { g_object_unref (G_OBJECT (layout)); /* Libere la memoire */ } } /* * Chargement d'une fonte. * Il faut mettre une virgule pour separer le nom de la fonte des attributs, * par ex : ezg_font_set_name (layout, "Times, bold italic 20"); */ void ezg_set_font_name (PangoLayout *layout, char const *desc) { PangoFontDescription *d; d = pango_font_description_from_string (desc); pango_layout_set_font_description (layout, d); pango_font_description_free (d); } /* * Changer la taille de la fonte actuelle ; taille en pixels. */ void ezg_set_font_size (PangoLayout *layout, int size) { const PangoFontDescription *d1 = pango_layout_get_font_description (layout); PangoFontDescription *d2 = pango_font_description_copy (d1); pango_font_description_set_absolute_size (d2, size * PANGO_SCALE); pango_layout_set_font_description (layout, d2); pango_font_description_free (d2); } /* * Raccourci : fixe une fonte de taille fixe. */ void ezg_set_nfont (PangoLayout *layout, int num) { switch (num) { case 0 : ezg_set_font_name (layout, "Monospace, 8"); break; case 1 : ezg_set_font_name (layout, "Monospace, 11"); break; case 2 : ezg_set_font_name (layout, "Monospace, 14"); break; case 3 : ezg_set_font_name (layout, "Monospace, 18"); break; default : fprintf (stderr, "ezg_set_nfont: bad num\n"); } } /* * Renvoie un entier ale'atoire entre 0 et n-1 */ int ezg_random (int n) { static GRand *rand_ = NULL; /* On initialise le generateur aleatoire la premiere fois */ if (rand_ == NULL) rand_ = g_rand_new (); return g_rand_int_range (rand_, 0, n); } /*-------------------- F O N C T I O N S P R I V E E S --------------------*/