/* OpenIDA - Outil d'analyse de fichiers binaires
* gtklinkrenderer.c - liens graphiques entre différents morceaux de code
*
* Copyright (C) 2009-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 "gtklinkrenderer.h"
#include
/* Lien entre morceaux de code (instance) */
struct _GtkLinkRenderer
{
GtkObject parent; /* A laisser en premier */
LinkColor color; /* Couleur d'impression */
GdkPoint *points; /* Points de la ligne dessinée */
size_t count; /* Quantité de ces points */
};
/* Lien entre morceaux de code (classe) */
struct _GtkLinkRendererClass
{
GtkObjectClass parent; /* A laisser en premier */
};
#define ARROW_LENGHT 10
#define ARROW_DEGREES 10
/* Initialise la classe générique des liens graphiques. */
static void gtk_link_renderer_class_init(GtkLinkRendererClass *);
/* Initialise une instance de lien graphique entre codes. */
static void gtk_link_renderer_init(GtkLinkRenderer *);
/* Dessine une flèche au bout du lien représenté. */
static void draw_link_arrow(cairo_t *, gint, gint, gint, gint);
/* Détermine le type du moteur de rendu pour les liens graphiques. */
G_DEFINE_TYPE(GtkLinkRenderer, gtk_link_renderer, GTK_TYPE_OBJECT)
/******************************************************************************
* *
* Paramètres : class = classe GTK à initialiser. *
* *
* Description : Initialise la classe générique des liens graphiques. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void gtk_link_renderer_class_init(GtkLinkRendererClass *class)
{
}
/******************************************************************************
* *
* Paramètres : view = instance GTK à initialiser. *
* *
* Description : Initialise une instance de lien graphique entre codes. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void gtk_link_renderer_init(GtkLinkRenderer *view)
{
}
/******************************************************************************
* *
* Paramètres : color = couleur d'impression. *
ù points = points consituant la ligne à représenter. *
* count = nombre de ces points. *
* *
* Description : Crée un nouveau moteur de rendu pour les liens graphiques. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
GtkObject *gtk_link_renderer_new(LinkColor color, GdkPoint *points, size_t count)
{
GtkLinkRenderer *result; /* Moteur de rendu à retourner */
result = g_object_new(GTK_TYPE_LINK_RENDERER, NULL);
result->color = color;
result->points = points;
result->count = count;
return GTK_OBJECT(result);
}
/******************************************************************************
* *
* Paramètres : renderer = moteur de rendu à manipuler. *
* requisition = dimensions adaptées validées. [OUT] *
* *
* Description : S'assure qu'une zone sera assez grande pour tout contenir. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void gtk_link_renderer_size_request(const GtkLinkRenderer *renderer, GtkRequisition *requisition)
{
size_t i; /* Boucle de parcours */
for (i = 0; i < renderer->count; i++)
{
requisition->width = MAX(requisition->width, renderer->points[i].x);
requisition->height = MAX(requisition->height, renderer->points[i].y);
}
}
/******************************************************************************
* *
* Paramètres : renderer = moteur 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 gtk_link_renderer_draw(const GtkLinkRenderer *renderer, GdkDrawable *drawable, GdkGC *gc)
{
cairo_t *cairo; /* Gestionnaire de rendu */
cairo = gdk_cairo_create(drawable);
_gtk_link_renderer_draw(renderer, cairo, true);
cairo_destroy(cairo);
}
/******************************************************************************
* *
* Paramètres : renderer = moteur 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 _gtk_link_renderer_draw(const GtkLinkRenderer *renderer, cairo_t *cairo, bool arrow)
{
size_t i; /* Boucle de parcours */
switch (renderer->color)
{
default:
case LKC_DEFAULT:
cairo_set_source_rgb(cairo, 0, 0, 0);
break;
case LKC_GREEN:
cairo_set_source_rgb(cairo, 0, 0.6, 0);
break;
case LKC_RED:
cairo_set_source_rgb(cairo, 0.8, 0, 0);
break;
case LKC_BLUE:
cairo_set_source_rgb(cairo, 0, 0, 0.8);
break;
case LKC_DASHED_GRAY:
cairo_set_source_rgb(cairo, 0.4, 0.4, 0.4);
break;
}
switch (renderer->color)
{
default:
case LKC_DEFAULT:
case LKC_GREEN:
case LKC_RED:
case LKC_BLUE:
cairo_set_dash(cairo, (double []) { 6.0 }, 0, 0.0);
break;
case LKC_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 : (renderer->color == LKC_BLUE ? 4 : 2));
cairo_move_to(cairo, renderer->points[0].x + 0.5, renderer->points[0].y);
for (i = 1; i < renderer->count; i++)
cairo_line_to(cairo, renderer->points[i].x + 0.5, renderer->points[i].y);
cairo_stroke(cairo);
if (arrow)
draw_link_arrow(cairo,
renderer->points[renderer->count - 2].x,
renderer->points[renderer->count - 2].y,
renderer->points[renderer->count - 1].x,
renderer->points[renderer->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);
}