From ae7ceae08e2ef0fc2588992e3e53765f3fd47b8e Mon Sep 17 00:00:00 2001 From: Cyrille Bagard Date: Mon, 20 Aug 2018 23:59:58 +0200 Subject: Created a new GTK widget to draw diagrams. --- src/gtkext/Makefile.am | 1 + src/gtkext/diagram.c | 783 +++++++++++++++++++++++++++++++++++++++++++++++++ src/gtkext/diagram.h | 82 ++++++ 3 files changed, 866 insertions(+) create mode 100644 src/gtkext/diagram.c create mode 100644 src/gtkext/diagram.h diff --git a/src/gtkext/Makefile.am b/src/gtkext/Makefile.am index 00ce40b..158e591 100644 --- a/src/gtkext/Makefile.am +++ b/src/gtkext/Makefile.am @@ -2,6 +2,7 @@ noinst_LTLIBRARIES = libgtkext.la libgtkext_la_SOURCES = \ + diagram.h diagram.c \ easygtk.h easygtk.c \ gtkbinarystrip.h gtkbinarystrip.c \ gtkblockdisplay.h gtkblockdisplay.c \ diff --git a/src/gtkext/diagram.c b/src/gtkext/diagram.c new file mode 100644 index 0000000..760e3ae --- /dev/null +++ b/src/gtkext/diagram.c @@ -0,0 +1,783 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * diagram.c - composant d'affichage avec de digrammes + * + * Copyright (C) 2018 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see . + */ + + +#include "diagram.h" + + +#include +#include +#include + + + +/* Composant de dessin de diagramme (instance) */ +struct _GtkDiagram +{ + GtkDrawingArea parent; /* A laisser en premier */ + + DiagramRenderingType rendering; /* Type de représentation */ + GdkRGBA fore_color; /* Couleur principale */ + + diagram_stat_t *stats; /* Statistiques fournies */ + size_t count; /* Quantité de ces éléments */ + +}; + +/* Composant de dessin de diagramme (classe) */ +struct _GtkDiagramClass +{ + GtkDrawingAreaClass parent; /* A laisser en premier */ + +}; + + +/* Initialise la classe des dessins de diagramme. */ +static void gtk_diagram_class_init(GtkDiagramClass *); + +/* Initialise une instance de dessin de diagramme. */ +static void gtk_diagram_init(GtkDiagram *); + +/* Supprime toutes les références externes. */ +static void gtk_diagram_dispose(GtkDiagram *); + +/* Procède à la libération totale de la mémoire. */ +static void gtk_diagram_finalize(GtkDiagram *); + +/* Applique une police choisie à un contexte de rendu. */ +static void gtk_diagram_set_font(GtkWidget *, cairo_t *); + +/* Assure le dessin du diagramme courant. */ +static gboolean gtk_diagram_draw(GtkWidget *, cairo_t *); + +/* Dessine un diagramme en camembert. */ +static void gtk_diagram_draw_pie(GtkWidget *, cairo_t *, const GdkRGBA *, const diagram_stat_t *, size_t); + +/* Dessine un diagramme en barres. */ +static void gtk_diagram_draw_histo(GtkWidget *, cairo_t *, const GdkRGBA *, const diagram_stat_t *, size_t); + +/* Indique le mode privilégié pour la détermination de taille. */ +static GtkSizeRequestMode gtk_diagram_get_request_mode(GtkWidget *); + +/* Indique le mode privilégié pour la détermination de taille. */ +static void gtk_diagram_get_preferred_width_for_height(GtkWidget *, gint, gint *, gint *); + + + +/* Détermine le type de l'afficheur de diagramme. */ +G_DEFINE_TYPE(GtkDiagram, gtk_diagram, GTK_TYPE_DRAWING_AREA) + + +/****************************************************************************** +* * +* Paramètres : klass = classe GTK à initialiser. * +* * +* Description : Initialise la classe des dessins de diagramme. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void gtk_diagram_class_init(GtkDiagramClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GtkWidgetClass *widget; /* Composant GTK générique */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)gtk_diagram_dispose; + object->finalize = (GObjectFinalizeFunc)gtk_diagram_finalize; + + widget = GTK_WIDGET_CLASS(klass); + + widget->draw = gtk_diagram_draw; + widget->get_request_mode = gtk_diagram_get_request_mode; + widget->get_preferred_width_for_height = gtk_diagram_get_preferred_width_for_height; + +} + + +/****************************************************************************** +* * +* Paramètres : diag = instance GTK à initialiser. * +* * +* Description : Initialise une instance de dessin de diagramme. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void gtk_diagram_init(GtkDiagram *diagram) +{ + diagram->stats = NULL; + diagram->count = 0; + +} + + +/****************************************************************************** +* * +* Paramètres : diag = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void gtk_diagram_dispose(GtkDiagram *diagram) +{ + G_OBJECT_CLASS(gtk_diagram_parent_class)->dispose(G_OBJECT(diagram)); + +} + + +/****************************************************************************** +* * +* Paramètres : diag = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void gtk_diagram_finalize(GtkDiagram *diagram) +{ + size_t i; /* Boucle de parcours */ + + for (i = 0; i < diagram->count; i++) + if (diagram->stats[i].desc != NULL) + free(diagram->stats[i].desc); + + if (diagram->stats != NULL) + free(diagram->stats); + + G_OBJECT_CLASS(gtk_diagram_parent_class)->finalize(G_OBJECT(diagram)); + +} + + +/****************************************************************************** +* * +* Paramètres : rendering = type de rendu des données. * +* color = couleur complémentaire pour le dessin. * +* * +* Description : Crée une nouvelle instance de dessinateur de diagramme. * +* * +* Retour : Composant GTK mis en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GtkWidget *gtk_diagram_new(DiagramRenderingType rendering, const GdkRGBA *color) +{ + GtkDiagram *result; /* Composant à retourner */ + + result = g_object_new(GTK_TYPE_DIAGRAM, NULL); + + result->rendering = rendering; + result->fore_color = *color; + + return GTK_WIDGET(result); + +} + + +/****************************************************************************** +* * +* Paramètres : widget = composant graphique à redessiner. * +* cr = contexte graphique à utiliser. * +* * +* Description : Applique une police choisie à un contexte de rendu. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void gtk_diagram_set_font(GtkWidget *widget, cairo_t *cr) +{ + GtkStyleContext *context; /* Contexte du style courant */ + const PangoFontDescription *fdesc; /* Description de police */ + double dpi; /* Résolution de l'écran */ + + context = gtk_widget_get_style_context(widget); + + gtk_style_context_save(context); + + gtk_style_context_add_class(context, GTK_STYLE_CLASS_LABEL); + + gtk_style_context_get(context, gtk_style_context_get_state(context), + GTK_STYLE_PROPERTY_FONT, &fdesc, NULL); + + cairo_select_font_face(cr, pango_font_description_get_family(fdesc), + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_BOLD); + + dpi = gdk_screen_get_resolution(gtk_widget_get_screen(widget)); + + cairo_set_font_size(cr, (pango_font_description_get_size(fdesc) * dpi) / (PANGO_SCALE * 72.0)); + + gtk_style_context_restore(context); + + +} + + +/****************************************************************************** +* * +* Paramètres : widget = composant graphique à redessiner. * +* cr = contexte graphique à utiliser. * +* * +* Description : Assure le dessin du diagramme courant. * +* * +* Retour : FALSE pour poursuivre la propagation de l'événement. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static gboolean gtk_diagram_draw(GtkWidget *widget, cairo_t *cr) +{ + GtkDiagram *diagram; /* Autre version du composant */ + + diagram = GTK_DIAGRAM(widget); + + gtk_diagram_set_font(widget, cr); + + if (diagram->count > 0) + switch (diagram->rendering) + { + case DRT_PIE: + gtk_diagram_draw_pie(widget, cr, &diagram->fore_color, diagram->stats, diagram->count); + break; + + case DRT_HISTO: + gtk_diagram_draw_histo(widget, cr, &diagram->fore_color, diagram->stats, diagram->count); + break; + + } + + return FALSE; + +} + + +/****************************************************************************** +* * +* Paramètres : widget = composant graphique à redessiner. * +* cr = contexte graphique à utiliser. * +* color = couleur d'impression principale. * +* stats = élements statistiques à présenter. * +* count = quantité de ces éléments. * +* * +* Description : Dessine un diagramme en camembert. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void gtk_diagram_draw_pie(GtkWidget *widget, cairo_t *cr, const GdkRGBA *color, const diagram_stat_t *stats, size_t count) +{ + guint height; /* Hauteur de l'espace dispo */ + double cx; /* Centre du camember #1 */ + double cy; /* Centre du camember #2 */ + double radius; /* Taille dudit camember */ + double sum; /* Somme de toutes les valeurs */ + size_t i; /* Boucle de parcours */ + double init_angle; /* Angle de départ */ + double last_angle; /* Dernier angle utilisé */ + const diagram_stat_t *stat; /* Statistique courante */ + double angle_1; /* Angle de départ */ + double angle_2; /* Angle d'arrivée */ + GdkRGBA tmp; /* Stockage temporaire */ + double tx; /* Abscisse du texte de légende*/ + cairo_text_extents_t extents; /* Taille de la police */ + double ty; /* Ordonnée du texte de légende*/ + + /* Préparatifs */ + + height = gtk_widget_get_allocated_height(widget); + + cx = height / 2; + cy = height / 2; + + radius = (height - 2 * DIAGRAM_MARGIN) / 2; + + sum = 0; + + for (i = 0; i < count; i++) + sum += stats[i].value; + + init_angle = 0; + + for (i = 0; i < count; i++) + { + init_angle = G_PI - (stats[i].value * 2 * G_PI) / 200; + + if (stats[i].value != 0) + break; + + } + + assert(i < count); + + /* Contenu */ + + cairo_set_line_width(cr, 2.0); + + last_angle = init_angle; + + for (; i < count; i++) + { + stat = &stats[i]; + + if (stat->value > 0) + { + angle_1 = last_angle; + + if ((i + 1) == count) + angle_2 = (init_angle != 0 ? init_angle : G_PI); + else + angle_2 = angle_1 + (stat->value * 2 * G_PI) / sum; + + cairo_move_to(cr, cx, cy); + cairo_arc(cr, cx, cy, radius, angle_1, angle_2); + cairo_line_to(cr, cx, cy); + + tmp = stat->color; + tmp.alpha /= 2; + + gdk_cairo_set_source_rgba(cr, &tmp); + cairo_fill_preserve(cr); + + gdk_cairo_set_source_rgba(cr, color); + cairo_stroke(cr); + + last_angle = angle_2; + + } + + } + + /* Bordures */ + + cairo_set_line_width(cr, 10.0); + + last_angle = init_angle; + + for (i = 0; i < count; i++) + { + stat = &stats[i]; + + if (stat->value > 0) + { + angle_1 = last_angle; + + if ((i + 1) == count) + angle_2 = (init_angle != 0 ? init_angle : G_PI); + else + angle_2 = angle_1 + (stat->value * 2 * G_PI) / sum; + + cairo_arc(cr, cx, cy, radius, angle_1, angle_2); + + gdk_cairo_set_source_rgba(cr, &stat->color); + cairo_stroke(cr); + + last_angle = angle_2; + + } + + } + + /* Légende */ + + cairo_set_line_width(cr, 2.0); + + tx = height + DIAGRAM_MARGIN; + + cairo_text_extents(cr, "A", &extents); + + ty = (height - extents.height - 3 * extents.height * (count - 1)) / 2; + + for (i = 0; i < count; i++) + { + stat = &stats[i]; + + cairo_rectangle(cr, tx, ty, 2 * extents.height, extents.height); + + tmp = stat->color; + tmp.alpha /= 2; + + gdk_cairo_set_source_rgba(cr, &tmp); + cairo_fill_preserve(cr); + + gdk_cairo_set_source_rgba(cr, &stat->color); + cairo_stroke(cr); + + cairo_move_to(cr, tx + 3 * extents.height, ty - extents.y_bearing); + cairo_show_text(cr, stat->desc); + + ty += 3 * extents.height; + + } + +} + + +/****************************************************************************** +* * +* Paramètres : widget = composant graphique à redessiner. * +* cr = contexte graphique à utiliser. * +* color = couleur d'impression principale. * +* stats = élements statistiques à présenter. * +* count = quantité de ces éléments. * +* * +* Description : Dessine un diagramme en barres. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void gtk_diagram_draw_histo(GtkWidget *widget, cairo_t *cr, const GdkRGBA *color, const diagram_stat_t *stats, size_t count) +{ + guint height; /* Hauteur de l'espace dispo */ + cairo_text_extents_t extents; /* Taille de la police */ + guint graph_height; /* Hauteur du graphique */ + guint zero_x; /* Abscisse de l'origine */ + guint zero_y; /* Ordonnée de l'origine */ + double sum; /* Somme de toutes les valeurs */ + guint graph_width; /* Largeur du graphique */ + size_t i; /* Boucle de parcours */ + const diagram_stat_t *stat; /* Statistique courante */ + double ty; /* Ordonnée du texte de légende*/ + double tx; /* Abscisse du texte de légende*/ + + static const char *scale[4] = { "0% ", "25% ", "50% ", "100% " }; + + /* Préparatifs */ + + height = gtk_widget_get_allocated_height(widget); + + cairo_text_extents(cr, scale[3], &extents); + + graph_height = height - DIAGRAM_MARGIN * 2 - extents.height; + + zero_x = extents.x_advance; + zero_y = DIAGRAM_MARGIN + graph_height; + + sum = 0; + + graph_width = 0; + + for (i = 0; i < count; i++) + { + stat = &stats[i]; + + sum += stat->value; + + cairo_text_extents(cr, stat->desc, &extents); + + graph_width += extents.x_advance + DIAGRAM_MARGIN; + + } + + /* Echelles et légende */ + + gdk_cairo_set_source_rgba(cr, color); + + cairo_move_to(cr, zero_x, zero_y); + cairo_line_to(cr, zero_x, zero_y - graph_height); + + cairo_stroke(cr); + + cairo_move_to(cr, zero_x, zero_y); + cairo_line_to(cr, zero_x + graph_width, zero_y); + + cairo_stroke(cr); + + for (i = 0; i < 4; i++) + { + ty = zero_y - (i * graph_height) / 3; + + cairo_move_to(cr, zero_x - 2, ty); + cairo_line_to(cr, zero_x + 2, ty); + + cairo_stroke(cr); + + cairo_text_extents(cr, scale[i], &extents); + + cairo_move_to(cr, zero_x - extents.x_advance, ty - extents.y_bearing / 2); + cairo_show_text(cr, scale[i]); + + } + + tx = zero_x; + + ty = zero_y + DIAGRAM_MARGIN / 2; + + for (i = 0; i < count; i++) + { + stat = &stats[i]; + + cairo_text_extents(cr, stat->desc, &extents); + + gdk_cairo_set_source_rgba(cr, color); + + cairo_move_to(cr, tx + DIAGRAM_MARGIN / 2 + extents.x_advance / 2, zero_y - 2); + cairo_line_to(cr, tx + DIAGRAM_MARGIN / 2 + extents.x_advance / 2, zero_y + 2); + + cairo_stroke(cr); + + gdk_cairo_set_source_rgba(cr, &stat->color); + + cairo_move_to(cr, tx + DIAGRAM_MARGIN / 2, ty - extents.y_bearing); + cairo_show_text(cr, stat->desc); + + tx += extents.x_advance + DIAGRAM_MARGIN; + + } + + /* Représentation des valeurs */ + + tx = zero_x; + + ty = zero_y + DIAGRAM_MARGIN / 2; + + cairo_set_line_width(cr, 8); + cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND); + + for (i = 0; i < count; i++) + { + stat = &stats[i]; + + cairo_text_extents(cr, stat->desc, &extents); + + if (stat->value > 0) + { + gdk_cairo_set_source_rgba(cr, &stat->color); + + cairo_move_to(cr, tx + DIAGRAM_MARGIN / 2 + extents.x_advance / 2, zero_y); + cairo_line_to(cr, tx + DIAGRAM_MARGIN / 2 + extents.x_advance / 2, + zero_y - (stat->value * graph_height) / sum); + + cairo_stroke(cr); + + } + + tx += extents.x_advance + DIAGRAM_MARGIN; + + } + +} + + +/****************************************************************************** +* * +* Paramètres : widget = composant graphique à consulter. * +* * +* Description : Indique le mode privilégié pour la détermination de taille. * +* * +* Retour : Toujours la largeur à partir de la hauteur. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static GtkSizeRequestMode gtk_diagram_get_request_mode(GtkWidget *widget) +{ + return GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT; + +} + + +/****************************************************************************** +* * +* Paramètres : widget = composant graphique à consulter. * +* height = hauteur à considérer. * +* minimum = largeur minimale correspondante. * +* natural = largeur idéale correspondante. * +* * +* Description : Indique le mode privilégié pour la détermination de taille. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void gtk_diagram_get_preferred_width_for_height(GtkWidget *widget, gint height, gint *minimum, gint *natural) +{ + GtkDiagram *diagram; /* Autre version du composant */ + gint text_width; /* Plus grande longueur */ + cairo_surface_t *surface; /* Espace graphique de support */ + cairo_t *cr; /* Contexte de rendu */ + size_t i; /* Boucle de parcours */ + cairo_text_extents_t extents; /* Taille de la police */ + + diagram = GTK_DIAGRAM(widget); + + text_width = 0; + + surface = gdk_window_create_similar_surface(gtk_widget_get_window(widget), CAIRO_CONTENT_COLOR, 1, 1); + + cr = cairo_create(surface); + + gtk_diagram_set_font(widget, cr); + + switch (diagram->rendering) + { + case DRT_PIE: + + for (i = 0; i < diagram->count; i++) + { + if (diagram->stats[i].desc == NULL) + continue; + + cairo_text_extents(cr, diagram->stats[i].desc, &extents); + + if (extents.width > text_width) + text_width = extents.width; + + } + + if (text_width > 0) + *minimum = height + 2 * DIAGRAM_MARGIN + 3 * extents.height + text_width; + else + *minimum = 0; + + break; + + case DRT_HISTO: + + cairo_text_extents(cr, "100% ", &extents); + + *minimum = extents.x_advance; + + for (i = 0; i < diagram->count; i++) + { + cairo_text_extents(cr, diagram->stats[i].desc, &extents); + + *minimum += extents.x_advance + DIAGRAM_MARGIN; + + } + + *minimum += DIAGRAM_MARGIN; + + } + + cairo_destroy(cr); + cairo_surface_destroy(surface); + + /* Répercution */ + + *natural = *minimum; + +} + + +/****************************************************************************** +* * +* Paramètres : diagram = diagramme à vider. * +* * +* Description : Supprime tous les éléments représentés dans le diagramme. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void gtk_diagram_clear_stats(GtkDiagram *diagram) +{ + size_t i; /* Boucle de parcours */ + + for (i = 0; i < diagram->count; i++) + { + if (diagram->stats[i].desc != NULL) + free(diagram->stats[i].desc); + } + + if (diagram->stats != NULL) + free(diagram->stats); + + diagram->stats = NULL; + diagram->count = 0; + +} + + +/****************************************************************************** +* * +* Paramètres : diagram = diagramme à compléter. * +* stats = nouvelles statistiques à intégrer. * +* count = quantité de ces statistiques. * +* * +* Description : Ajoute des éléments à représenter dans le diagramme. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void gtk_diagram_add_stats(GtkDiagram *diagram, const diagram_stat_t *stats, size_t count) +{ + size_t i; /* Boucle de parcours */ + diagram_stat_t *dest; /* Destination d'une copie */ + + diagram->stats = (diagram_stat_t *)realloc(diagram->stats, (diagram->count + count) * sizeof(diagram_stat_t)); + + for (i = 0; i < count; i++) + { + dest = &diagram->stats[diagram->count + i]; + + dest->value = stats[i].value; + + dest->color = stats[i].color; + + if (stats[i].desc == NULL) + dest->desc = NULL; + + else + dest->desc = strdup(stats[i].desc); + + } + + diagram->count += count; + +} diff --git a/src/gtkext/diagram.h b/src/gtkext/diagram.h new file mode 100644 index 0000000..70f6756 --- /dev/null +++ b/src/gtkext/diagram.h @@ -0,0 +1,82 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * diagram.h - prototypes pour un composant d'affichage avec de digrammes + * + * Copyright (C) 2018 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see . + */ + + +#ifndef _GTKEXT_DIAGRAM_H +#define _GTKEXT_DIAGRAM_H + + +#include + + + +#define GTK_TYPE_DIAGRAM gtk_diagram_get_type() +#define GTK_DIAGRAM(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GTK_TYPE_DIAGRAM, GtkDiagram)) +#define GTK_IS_DIAGRAM(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GTK_TYPE_DIAGRAM)) +#define GTK_DIAGRAM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GTK_TYPE_DIAGRAM, GtkDiagramClass)) +#define GTK_IS_DIAGRAM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GTK_TYPE_DIAGRAM)) +#define GTK_DIAGRAM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GTK_TYPE_DIAGRAM, GtkDiagramClass)) + + +/* Composant de dessin de diagramme (instance) */ +typedef struct _GtkDiagram GtkDiagram; + +/* Composant de dessin de diagramme (classe) */ +typedef struct _GtkDiagramClass GtkDiagramClass; + +/* Types de diagrammes supportés */ +typedef enum _DiagramRenderingType +{ + DRT_PIE, /* En camembert */ + DRT_HISTO /* En barres */ + +} DiagramRenderingType; + +/* Transmission de statistiques */ +typedef struct _diagram_stat_t +{ + double value; /* Valeur à représenter */ + GdkRGBA color; /* Couleur de représentation */ + + char *desc; /* Eventuelle description */ + +} diagram_stat_t; + + +#define DIAGRAM_MARGIN 20 + + +/* Détermine le type de l'afficheur de diagramme. */ +GType gtk_diagram_get_type(void); + +/* Crée une nouvelle instance de dessinateur de diagramme. */ +GtkWidget *gtk_diagram_new(DiagramRenderingType, const GdkRGBA *); + +/* Supprime tous les éléments représentés dans le diagramme. */ +void gtk_diagram_clear_stats(GtkDiagram *); + +/* Ajoute des éléments à représenter dans le diagramme. */ +void gtk_diagram_add_stats(GtkDiagram *, const diagram_stat_t *, size_t); + + + +#endif /* _GTKEXT_DIAGRAM_H */ -- cgit v0.11.2-87-g4458