/* OpenIDA - Outil d'analyse de fichiers binaires * edge.c - liens entre les noeuds d'un graphique * * Copyright (C) 2013 Cyrille Bagard * * This file is part of OpenIDA. * * OpenIDA 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. * * OpenIDA 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 /* Lien graphique entre deux noeuds graphiques (instance) */ struct _GGraphEdge { GObject parent; /* A laisser en premier */ GFlowNode *src_node; /* Bloc de départ du lien */ node_slot_t *src_slot; /* Numéro d'ancrage initial */ GFlowNode *dest_node; /* Bloc d'arrivée du lien */ node_slot_t *dest_slot; /* Numéro d'ancrage final */ EdgeColor color; /* Couleur du rendu */ 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 */ }; #define SLOT_VERT_SEP 20 #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_unref(G_OBJECT(edge->src_node)); g_object_unref(G_OBJECT(edge->dest_node)); 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) { G_OBJECT_CLASS(g_graph_edge_parent_class)->finalize(G_OBJECT(edge)); } /****************************************************************************** * * * Paramètres : src_node = bloc de départ du lien. * * src_slot = point d'ancrage associé. * * dest_node = bloc d'arrivée du lien. * * dest_slot = point d'ancrage associé. * * 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(GFlowNode *src_node, node_slot_t *src_slot, GFlowNode *dest_node, node_slot_t *dest_slot, EdgeColor color) { GGraphEdge *result; /* Structure à retourner */ result = g_object_new(G_TYPE_GRAPH_EDGE, NULL); g_object_ref(G_OBJECT(src_node)); g_object_ref(G_OBJECT(dest_node)); result->src_node = src_node; result->src_slot = src_slot; result->dest_node = dest_node; result->dest_slot = dest_slot; result->color = color; return G_GRAPH_EDGE(result); } /****************************************************************************** * * * Paramètres : edge = ligne de rendu à mettre à jour. * * * * Description : Etablit le tracé du lien graphique entre deux noeuds. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_graph_edge_compute(GGraphEdge *edge) { GdkPoint start; /* Point de départ */ GdkPoint end; /* Point d'arrivée */ start = g_flow_node_get_point_from_slot(edge->src_node, false, edge->src_slot); end = g_flow_node_get_point_from_slot(edge->dest_node, true, edge->dest_slot); printf(" -- (%d ; %d) - (%d ; %d)\n", start.x, start.y, end.x, end.y); /* Point de départ */ edge->count = 2; edge->points = (GdkPoint *)calloc(edge->count, sizeof(GdkPoint)); edge->points[0] = start; edge->points[1] = start; edge->points[1].y += SLOT_VERT_SEP; /* Points de jonction */ /* Point d'arrivée */ edge->count += 2; edge->points = (GdkPoint *)realloc(edge->points, edge->count * sizeof(GdkPoint)); edge->points[edge->count - 1] = end; edge->points[edge->count - 2] = end; edge->points[edge->count - 2].y -= SLOT_VERT_SEP; } /****************************************************************************** * * * Paramètres : edge = ligne de rendu à manipuler. * * drawable = surface de rendu à utiliser. * * gc = contexte graphique du dessin. * * * * Description : Dessine les liens graphiques enregistrés dans le moteur. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_graph_edge_draw(const GGraphEdge *edge, GdkDrawable *drawable, GdkGC *gc) { cairo_t *cairo; /* Gestionnaire de rendu */ cairo = gdk_cairo_create(drawable); _g_graph_edge_draw(edge, cairo, true); cairo_destroy(cairo); } /****************************************************************************** * * * 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); }