/* Chrysalide - Outil d'analyse de fichiers binaires * edge.c - liens entre les noeuds d'un graphique * * Copyright (C) 2013-2014 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 Foobar. If not, see . */ #include "edge.h" #include #include #include #include /* Lien graphique entre deux noeuds graphiques (instance) */ struct _GGraphEdge { GObject parent; /* A laisser en premier */ EdgeColor color; /* Couleur du rendu */ const GdkPoint *start; /* Point de départ du lien */ GdkPoint *mid[2]; /* Etapes intermédiaires */ size_t m_count; /* Quantité de ces étapes */ const GdkPoint *end; /* Point d'arrivée du lien */ GdkPoint *points; /* Points de la ligne dessinée */ size_t count; /* Quantité de ces points */ }; /* Lien graphique entre deux noeuds graphiques (classe) */ struct _GGraphEdgeClass { GObjectClass parent; /* A laisser en premier */ }; /* Dimensions des flêches */ #define ARROW_LENGHT 10 #define ARROW_DEGREES 10 /* Initialise la classe des liens graphiques entre deux noeuds. */ static void g_graph_edge_class_init(GGraphEdgeClass *); /* Initialise une encapsulation de bloc virtuel. */ static void g_graph_edge_init(GGraphEdge *); /* Supprime toutes les références externes. */ static void g_graph_edge_dispose(GGraphEdge *); /* Procède à la libération totale de la mémoire. */ static void g_graph_edge_finalize(GGraphEdge *); /* Dessine une flèche au bout du lien représenté. */ static void draw_link_arrow(cairo_t *, gint, gint, gint, gint); /* Indique le type définit par la GLib pour les liens graphiques entre noeuds. */ G_DEFINE_TYPE(GGraphEdge, g_graph_edge, G_TYPE_OBJECT); /****************************************************************************** * * * Paramètres : klass = classe à initialiser. * * * * Description : Initialise la classe des liens graphiques entre deux noeuds. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_graph_edge_class_init(GGraphEdgeClass *klass) { GObjectClass *object; /* Autre version de la classe */ object = G_OBJECT_CLASS(klass); object->dispose = (GObjectFinalizeFunc/* ! */)g_graph_edge_dispose; object->finalize = (GObjectFinalizeFunc)g_graph_edge_finalize; } /****************************************************************************** * * * Paramètres : edge = instance à initialiser. * * * * Description : Initialise un lien graphique entre deux noeuds graphiques. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_graph_edge_init(GGraphEdge *edge) { } /****************************************************************************** * * * Paramètres : edge = instance d'objet GLib à traiter. * * * * Description : Supprime toutes les références externes. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_graph_edge_dispose(GGraphEdge *edge) { G_OBJECT_CLASS(g_graph_edge_parent_class)->dispose(G_OBJECT(edge)); } /****************************************************************************** * * * Paramètres : edge = instance d'objet GLib à traiter. * * * * Description : Procède à la libération totale de la mémoire. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_graph_edge_finalize(GGraphEdge *edge) { if (edge->points != NULL) free(edge->points); G_OBJECT_CLASS(g_graph_edge_parent_class)->finalize(G_OBJECT(edge)); } /****************************************************************************** * * * Paramètres : start = point de départ de la flêche. * * mid = points intermédiares variables. * * count = nombre de ces points fournis. * * end = point d'arrivée de la flêche. * * color = couleur de rendu à l'écran. * * * * Description : Etablit un lien graphique entre deux noeuds graphiques. * * * * Retour : Adresse de la structure mise en place. * * * * Remarques : - * * * ******************************************************************************/ GGraphEdge *_g_graph_edge_new(const GdkPoint *start, const GdkPoint **mid, size_t count, const GdkPoint *end, EdgeColor color) { GGraphEdge *result; /* Structure à retourner */ result = g_object_new(G_TYPE_GRAPH_EDGE, NULL); result->color = color; assert(count == 1 || count == 2); result->start = start; memcpy(result->mid, mid, count * sizeof(GdkPoint)); result->m_count = count; result->end = end; return G_GRAPH_EDGE(result); } /****************************************************************************** * * * Paramètres : edge = ligne de rendu à consulter. * * x1 = abscisse du point de départ de la ligne. [OUT] * * x2 = abscisse du point d'arrivée de la ligne. [OUT] * * * * Description : Fournit les abscisses des points extrèmes de la ligne. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_graph_edge_get_x_borders(const GGraphEdge *edge, gint *x1, gint *x2) { *x1 = edge->start->x; *x2 = edge->end->x; } /****************************************************************************** * * * Paramètres : edge = ligne de rendu à définir dans les détails. * * * * Description : Détermine les positions finales d'un lien graphique. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_graph_edge_resolve(GGraphEdge *edge) { edge->count = 2 + 2 * edge->m_count; edge->points = (GdkPoint *)calloc(edge->count, sizeof(GdkPoint)); edge->points[0] = *edge->start; edge->points[1].x = edge->start->x; edge->points[1].y = edge->mid[0]->y; if (edge->m_count == 1) { edge->points[2].x = edge->end->x; edge->points[2].y = edge->mid[0]->y; } else { memcpy(&edge->points[2], edge->mid, edge->m_count * sizeof(GdkPoint)); edge->points[4].x = edge->end->x; edge->points[4].y = edge->mid[3]->y; } edge->points[edge->count - 1] = *edge->end; } /****************************************************************************** * * * Paramètres : edge = ligne de rendu à manipuler. * * cairo = assistant pour le rendu graphique. * * arrow = indique le besoin en flèche à l'arrivée. * * * * Description : Dessine les liens graphiques enregistrés dans le moteur. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_graph_edge_draw(const GGraphEdge *edge, cairo_t *cairo, bool arrow) { size_t i; /* Boucle de parcours */ switch (edge->color) { default: case EGC_DEFAULT: cairo_set_source_rgb(cairo, 0, 0, 0); break; case EGC_GREEN: cairo_set_source_rgb(cairo, 0, 0.6, 0); break; case EGC_RED: cairo_set_source_rgb(cairo, 0.8, 0, 0); break; case EGC_BLUE: cairo_set_source_rgb(cairo, 0, 0, 0.8); break; case EGC_DASHED_GRAY: cairo_set_source_rgb(cairo, 0.4, 0.4, 0.4); break; } switch (edge->color) { default: case EGC_DEFAULT: case EGC_GREEN: case EGC_RED: case EGC_BLUE: cairo_set_dash(cairo, (double []) { 6.0 }, 0, 0.0); break; case EGC_DASHED_GRAY: cairo_set_dash(cairo, (double []) { 6.0 }, 1, 0.0); break; } /** * Si on ne veut pas de flèche, on doit se destiner à un aperçu... * Dans ce cas, pour plus de lisibilité, on double la taille d'impression. * Et pour faire ressortir les boucles, on double encore les liens associés. */ cairo_set_line_width(cairo, arrow ? 1 : (edge->color == EGC_BLUE ? 4 : 2)); cairo_move_to(cairo, edge->points[0].x + 0.5, edge->points[0].y); for (i = 1; i < edge->count; i++) cairo_line_to(cairo, edge->points[i].x + 0.5, edge->points[i].y); cairo_stroke(cairo); if (arrow) draw_link_arrow(cairo, edge->points[edge->count - 2].x, edge->points[edge->count - 2].y, edge->points[edge->count - 1].x, edge->points[edge->count - 1].y); } /****************************************************************************** * * * Paramètres : cairo = gestionnaire de rendu graphique. * * start_x = abscisse du début du segment final. * * start_y = ordonnée du début du segment final. * * end_x = abscisse de fin de segment et pointe de flèche. * * end_y = ordonnée de fin de segment et pointe de flèche. * * * * Description : Dessine une flèche au bout du lien représenté. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void draw_link_arrow(cairo_t *cairo, gint start_x, gint start_y, gint end_x, gint end_y) { double angle; /* Angle du triangle à remplir */ double factor_x; /* Direction de la flèche #1 */ double factor_y; /* Direction de la flèche #2 */ double x1; /* Abscisse du point n°1 */ double y1; /* Ordonnée du point n°1 */ double x2; /* Abscisse du point n°2 */ double y2; /* Ordonnée du point n°2 */ angle = atan2(end_y - start_y, end_x - start_x) + M_PI; factor_x = -1; factor_y = -1; x1 = end_x + factor_x * ARROW_LENGHT * cos(angle - ARROW_DEGREES); y1 = end_y + factor_y * ARROW_LENGHT * sin(angle - ARROW_DEGREES); x2 = end_x + factor_x * ARROW_LENGHT * cos(angle + ARROW_DEGREES); y2 = end_y + factor_y * ARROW_LENGHT * sin(angle + ARROW_DEGREES); cairo_move_to(cairo, end_x, end_y); cairo_line_to(cairo, x1, y1); cairo_line_to(cairo, x2, y2); cairo_move_to(cairo, end_x, end_y); cairo_fill(cairo); }