summaryrefslogtreecommitdiff
path: root/src/gtkext
diff options
context:
space:
mode:
authorCyrille Bagard <nocbos@gmail.com>2019-03-05 21:15:36 (GMT)
committerCyrille Bagard <nocbos@gmail.com>2019-03-05 21:15:36 (GMT)
commit25811bc506ecca92d6b36fe739734121a872af4d (patch)
treede37d44153e0d4d30e2b9bb31abae1f342edaa08 /src/gtkext
parent63b4cb46d5f417798619c573be34104fea7acbae (diff)
Split the graph code into several files.
Diffstat (limited to 'src/gtkext')
-rw-r--r--src/gtkext/graph/Makefile.am8
-rw-r--r--src/gtkext/graph/cluster-int.h102
-rw-r--r--src/gtkext/graph/cluster.c1880
-rw-r--r--src/gtkext/graph/hspace.c125
-rw-r--r--src/gtkext/graph/hspace.h52
-rw-r--r--src/gtkext/graph/incoming.c184
-rw-r--r--src/gtkext/graph/incoming.h67
-rw-r--r--src/gtkext/graph/leaving.c107
-rw-r--r--src/gtkext/graph/leaving.h66
-rw-r--r--src/gtkext/graph/rank.c914
-rw-r--r--src/gtkext/graph/rank.h126
-rw-r--r--src/gtkext/graph/vspace.c374
-rw-r--r--src/gtkext/graph/vspace.h86
13 files changed, 2236 insertions, 1855 deletions
diff --git a/src/gtkext/graph/Makefile.am b/src/gtkext/graph/Makefile.am
index 310c13c..ee5eb19 100644
--- a/src/gtkext/graph/Makefile.am
+++ b/src/gtkext/graph/Makefile.am
@@ -2,8 +2,14 @@
noinst_LTLIBRARIES = libgtkextgraph.la
libgtkextgraph_la_SOURCES = \
+ cluster-int.h \
cluster.h cluster.c \
- edge.h edge.c
+ edge.h edge.c \
+ hspace.h hspace.c \
+ incoming.h incoming.c \
+ leaving.h leaving.c \
+ rank.h rank.c \
+ vspace.h vspace.c
libgtkextgraph_la_LIBADD =
diff --git a/src/gtkext/graph/cluster-int.h b/src/gtkext/graph/cluster-int.h
new file mode 100644
index 0000000..881a60a
--- /dev/null
+++ b/src/gtkext/graph/cluster-int.h
@@ -0,0 +1,102 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * cluster-int.h - prototypes pour les définitions internes de mise en place de graphiques
+ *
+ * Copyright (C) 2019 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 <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _GTKEXT_GRAPH_CLUSTER_INT_H
+#define _GTKEXT_GRAPH_CLUSTER_INT_H
+
+
+#include "cluster.h"
+#include "leaving.h"
+
+
+
+/* Espace minimal horizontal entre les blocs */
+#define HORIZONTAL_MARGIN 20
+
+/* Espace minimal vertical entre les blocs */
+#define VERTICAL_MARGIN 15
+
+
+/* Assigne à un bloc et son ensemble un emplacement initial. */
+void g_graph_cluster_reset_allocation(GGraphCluster *);
+
+/* Met en place les embryons de liens nécessaires. */
+void g_graph_cluster_define_links(GGraphCluster *, GHashTable *);
+
+/* Repère les liens marquants à destination d'autres blocs. */
+void g_graph_cluster_setup_links(GGraphCluster *);
+
+/* Organise la disposition d'un ensemble de blocs basiques. */
+void g_graph_cluster_dispatch_x(GGraphCluster *);
+
+/* Réorganise au besoin les liens entrants d'un bloc. */
+void g_graph_cluster_sort_incoming_links(GGraphCluster *);
+
+/* Retrouve l'indice d'un lien entrant donné pour un bloc. */
+size_t g_graph_cluster_find_incoming_link(const GGraphCluster *, const leaving_link_t *);
+
+/* Détermine si un cluster possède un lien sortant. */
+bool g_graph_cluster_has_exit_link(GGraphCluster *, bool *);
+
+/* Compare deux clusters avec lien sortant. */
+int g_graph_cluster_compare_by_exit(const GGraphCluster **, const GGraphCluster **, const bool *);
+
+/* Réordonne les blocs sortant du cluster au mieux. */
+void g_graph_cluster_reorder_exit_blocks(GGraphCluster *);
+
+/* Réordonne les blocs de départ de boucle au mieux. */
+void g_graph_cluster_reorder_loop_blocks(GGraphCluster *);
+
+/* Réordonne le départ des liens en entrée de bloc. */
+void g_graph_cluster_reorder_link_origins(GGraphCluster *, bool);
+
+/* Décale vers la droite un ensemble de blocs basiques. */
+void g_graph_cluster_offset_x(GGraphCluster *, gint);
+
+/* Décale vers le bas un ensemble de blocs basiques. */
+void g_graph_cluster_set_y(GGraphCluster *, gint);
+
+/* Calcule l'abscisse d'un lien pour un bloc. */
+gint _g_graph_cluster_compute_link_position(const GGraphCluster *, size_t, size_t, bool);
+
+/* Calcule l'abscisse d'un lien à son départ d'un bloc. */
+gint g_graph_cluster_compute_leaving_link_position(const GGraphCluster *, size_t);
+
+/* Calcule l'abscisse d'un lien à son arrivée à un bloc. */
+gint g_graph_cluster_compute_incoming_link_position(const GGraphCluster *, size_t);
+
+/* Détermine les abscisses des liens de boucle en place. */
+void g_graph_cluster_compute_loop_link_x_positions(GGraphCluster *);
+
+/* Détermine les ordonnées de tous les liens en place. */
+void g_graph_cluster_compute_link_y_positions(GGraphCluster *);
+
+/* Collecte tous les chefs de file de blocs de code. */
+GGraphCluster **g_graph_cluster_collect(GGraphCluster *, GGraphCluster **, size_t *);
+
+/* Collecte tous les liens de chefs de file de blocs de code. */
+GGraphEdge **g_graph_cluster_collect_edges(GGraphCluster *, GGraphEdge **, size_t *);
+
+
+
+#endif
diff --git a/src/gtkext/graph/cluster.c b/src/gtkext/graph/cluster.c
index 6284029..41392a2 100644
--- a/src/gtkext/graph/cluster.c
+++ b/src/gtkext/graph/cluster.c
@@ -31,6 +31,12 @@
#include <string.h>
+#include "cluster-int.h"
+#include "hspace.h"
+#include "incoming.h"
+#include "leaving.h"
+#include "rank.h"
+#include "vspace.h"
#include "../gtkblockdisplay.h"
#include "../gtkbufferdisplay.h"
#include "../gtkdisplaypanel.h"
@@ -39,248 +45,6 @@
-/* Définition du tracé d'un lien */
-typedef struct _incoming_link_t incoming_link_t;
-
-
-/* ------------------------- LIEN SORTANT D'UN BLOC DE CODE ------------------------- */
-
-
-/* Détails sur le départ d'un lien */
-typedef struct _leaving_link_t
-{
- GGraphCluster *owner; /* Propriétaire du lien */
-
- GdkPoint start[2]; /* Point de départ d'un lien */
- size_t index; /* Indice sur ligne de départ */
-
- bool straight; /* Présence d'une ligne droite */
- bool forced_straight; /* Forçage de verticalité */
- size_t straight_level; /* Rang atteint en ligne droite*/
- bool cluster_exit; /* Sortie du cluster d'origine */
-
- incoming_link_t *other; /* Autre extrémité du lien */
-
-} leaving_link_t;
-
-
-#define SHOULD_BE_VERTICAL(l) ((l)->straight || (l)->forced_straight || (l)->cluster_exit)
-
-
-/* Crée un point d'attache pour un lien sortant. */
-static leaving_link_t *create_leaving_link(GGraphCluster *, size_t);
-
-/* Détruit un point d'attache pour un lien sortant. */
-static void delete_leaving_link(leaving_link_t *);
-
-/* Calcule l'abscisse d'un lien à son départ d'un bloc. */
-static gint compute_leaving_link_position(const leaving_link_t *);
-
-
-
-/* ------------------------- LIEN ENTRANT D'UN BLOC DE CODE ------------------------- */
-
-
-/* Définition du tracé d'un lien */
-struct _incoming_link_t
-{
- GGraphCluster *owner; /* Propriétaire du lien */
-
- InstructionLinkType type; /* Complexité du tracé */
-
- const size_t *hslot; /* Couche horizontale réservée */
- GdkPoint end[2]; /* Point d'arrivée final */
-
- GGraphEdge *edge; /* Lien complet en préparation */
-
- leaving_link_t *other; /* Autre extrémité du lien */
-
-};
-
-
-/* Crée un point d'attache pour un lien entrant simple. */
-static incoming_link_t *create_incoming_link(GGraphCluster *, InstructionLinkType, leaving_link_t *);
-
-/* Crée un point d'attache pour un lien entrant de boucle. */
-static incoming_link_t *create_incoming_loop_link(GGraphCluster *, const GdkPoint *, leaving_link_t *);
-
-/* Détruit un point d'attache pour un lien entrant. */
-static void delete_incoming_link(incoming_link_t *);
-
-/* Compare deux liens entrants. */
-static int cmp_incoming_links(const incoming_link_t **, const incoming_link_t **);
-
-
-
-/* ------------------------ ENCADREMENTS D'ESPACES VERTICAUX ------------------------ */
-
-
-/* Réservations d'espaces latéraux */
-typedef struct _vspace_booking_t
-{
- leaving_link_t *from; /* Bloc de départ du lien */
- incoming_link_t *to; /* Bloc d'arrivée du lien */
-
- GdkPoint *pts; /* Coordonnées des points */
-
- bool external; /* Lien vers un cluster parent */
-
-} vspace_booking_t;
-
-/* Réservations d'espaces latéraux */
-typedef struct _vspace_manager_t
-{
- vspace_booking_t *pending; /* Besoins exprimés */
- size_t pending_count; /* Nombre de ces besoins */
-
- vspace_booking_t **left; /* Lignes disposées à gauche */
- size_t left_count; /* Quantité de ces lignes */
-
- vspace_booking_t **right; /* Lignes disposées à droite */
- size_t right_count; /* Quantité de ces lignes */
-
-} vspace_manager_t;
-
-
-/* Initialise les réservations liens verticaux. */
-static void init_vspace_manager(vspace_manager_t *);
-
-/* Termine les réservations liens verticaux. */
-static void exit_vspace_manager(vspace_manager_t *);
-
-/* Inscrit une nouvelle réservation d'espace latéral. */
-static void extend_vspace_manager(vspace_manager_t *, leaving_link_t *, incoming_link_t *, GdkPoint *, bool);
-
-/* Détermine l'emplacement requis pour les espaces latéraux. */
-static void compute_vspace_manager_needed_alloc(const vspace_manager_t *, bool, GtkAllocation *);
-
-/* Réorganise au besoin les liens de boucle entre blocs. */
-static void sort_incoming_links_for_vspace_manager(vspace_manager_t *);
-
-/* Décale vers la droite un ensemble de points. */
-static void offset_x_vspace_manager(vspace_manager_t *, gint);
-
-/* Détermine les abscisses de tous les liens en place. */
-static gint compute_loop_link_x_with_vspace_manager(const vspace_manager_t *, const GtkAllocation *, bool);
-
-/* Détermine les ordonnées de tous les liens en place. */
-static void compute_loop_link_y_with_vspace_manager(const vspace_manager_t *, const GtkAllocation *);
-
-
-
-/* ---------------------- DESCENDANTS DIRECTS CLASSES PAR RANG ---------------------- */
-
-
-/* Réservation pour les lignes horizontales */
-typedef struct _hspace_booking
-{
- gint start; /* Abscisse de départ de ligne */
- size_t index; /* Indice de rangée verticale */
-
-} hspace_booking;
-
-
-/* Prépare une réservation d'espace pour ligne horizontale. */
-static hspace_booking *create_hspace_booking(gint);
-
-/* Compare deux réservations d'espace. */
-static int cmp_hspace_booking_r2l(const hspace_booking **, const hspace_booking **);
-
-/* Compare deux réservations d'espace. */
-static int cmp_hspace_booking_l2r(const hspace_booking **, const hspace_booking **);
-
-
-/* Découpage vertical */
-typedef struct _graph_rank_t
-{
- hspace_booking **right2left; /* Réservations de D -> G */
- size_t r2l_count; /* Quantité de ces réservations*/
-
- hspace_booking **left2right; /* Réservations de G -> D */
- size_t l2r_count; /* Quantité de ces réservations*/
-
- GGraphCluster **clusters; /* Ensembles de blocs */
- size_t count; /* Nombre de ces ensembles */
-
- vspace_manager_t vspaces; /* Gestion des liens latéraux */
-
-} graph_rank_t;
-
-
-/* Initialise la gestion d'un ensemble de blocs de même rang. */
-static void init_graph_rank(graph_rank_t *, GGraphCluster *);
-
-/* Termine la gestion d'un ensemble de blocs de même rang. */
-static void exit_graph_rank(graph_rank_t *);
-
-/* Assigne à un ensemble de blocs un emplacement initial. */
-static void reset_graph_rank_allocation(const graph_rank_t *);
-
-/* Fournit le rang d'un ensemble de blocs. */
-static size_t get_graph_rank(const graph_rank_t *);
-
-/* Compare deux rangées de blocs de code. */
-static int cmp_graph_rank(const graph_rank_t *, const graph_rank_t *);
-
-/* Etend un ensemble de blocs de même rang. */
-static void extend_graph_rank(graph_rank_t *, GGraphCluster *);
-
-/* Détermine si un groupe de blocs contient un bloc particulier. */
-static bool has_graph_rank_cluster(const graph_rank_t *, GGraphCluster *);
-
-/* Inscrit à l'endroit idéal une réservation d'espace latéral. */
-static bool extend_graph_rank_vspace_manager(graph_rank_t *, leaving_link_t *, incoming_link_t *, GdkPoint *, bool);
-
-/* Met en place les embryons de liens nécessaires. */
-static void define_graph_rank_links(const graph_rank_t *, GHashTable *);
-
-/* Repère les liens marquants à destination d'autres blocs. */
-static void setup_graph_rank_links(const graph_rank_t *);
-
-/* Détermine l'emplacement requis d'un ensemble de blocs. */
-static void compute_graph_rank_needed_alloc(const graph_rank_t *, bool, GtkAllocation *);
-
-/* Affine l'abscisse d'un ensemble de blocs de même rang. */
-static void _place_graph_rank_clusters(GGraphCluster **, size_t, gint, int);
-
-/* Organise la disposition d'un ensemble de blocs basiques. */
-static void dispatch_x_graph_rank(const graph_rank_t *);
-
-/* Réorganise au besoin les liens entrants un ensemble de blocs. */
-static void sort_graph_rank_incoming_links(graph_rank_t *);
-
-/* Réordonne les blocs sortant d'un ensemble. */
-static void reorder_graph_rank_exit_blocks(graph_rank_t *);
-
-/* Réordonne les blocs de départ de boucle d'un ensemble. */
-static void reorder_graph_rank_loop_blocks(graph_rank_t *);
-
-/* Décale vers la droite un ensemble de blocs basiques. */
-static void offset_x_graph_rank(graph_rank_t *, gint);
-
-/* Détermine les abscisses des liens de boucle en place. */
-static gint compute_loop_link_x_positions_with_graph_rank(const graph_rank_t *, const GtkAllocation *);
-
-/* Décale vers le bas un ensemble de blocs basiques. */
-static void set_y_for_graph_rank(const graph_rank_t *, gint *);
-
-/* Détermine les ordonnées de tous les liens en place. */
-static void compute_loop_link_with_graph_rank(const graph_rank_t *, const GtkAllocation *);
-
-/* Recherche le groupe de blocs avec un bloc donné comme chef. */
-static GGraphCluster *find_cluster_by_block_in_graph_rank(const graph_rank_t *, GCodeBlock *);
-
-/* Recherche le groupe de blocs avec un composant comme chef. */
-static GGraphCluster *find_cluster_by_widget_in_graph_rank(const graph_rank_t *, GtkWidget *);
-
-/* Collecte tous les chefs de file de blocs de code. */
-static GGraphCluster **collect_graph_ranks_clusters(const graph_rank_t *, GGraphCluster **, size_t *);
-
-/* Collecte tous les liens de chefs de file de blocs de code. */
-static GGraphEdge **collect_graph_ranks_cluster_edges(const graph_rank_t *, GGraphEdge **, size_t *);
-
-
-
/* -------------------------- DEFINITION D'UN CHEF DE FILE -------------------------- */
@@ -330,12 +94,6 @@ struct _GGraphClusterClass
};
-/* Espace minimal horizontal entre les blocs */
-#define HORIZONTAL_MARGIN 20
-
-/* Espace minimal vertical entre les blocs */
-#define VERTICAL_MARGIN 15
-
/* Initialise la classe des mises en disposition graphique. */
static void g_graph_cluster_class_init(GGraphClusterClass *);
@@ -349,9 +107,6 @@ static void g_graph_cluster_dispose(GGraphCluster *);
/* Procède à la libération totale de la mémoire. */
static void g_graph_cluster_finalize(GGraphCluster *);
-/* Assigne à un bloc et son ensemble un emplacement initial. */
-static void g_graph_cluster_reset_allocation(GGraphCluster *);
-
/* Complète un graphique avec un sous-ensemble de blocs. */
static void g_graph_cluster_add_sub(GGraphCluster *, GGraphCluster *);
@@ -361,75 +116,18 @@ static void g_graph_cluster_setup_link_for_target(GGraphCluster *, GGraphCluster
/* Inscrit à l'endroit idéal une réservation d'espace latéral. */
static void g_graph_cluster_extend_vspace_manager(GGraphCluster *, leaving_link_t *, incoming_link_t *, GdkPoint *);
-/* Met en place les embryons de liens nécessaires. */
-static void g_graph_cluster_define_links(GGraphCluster *, GHashTable *);
-
-/* Repère les liens marquants à destination d'autres blocs. */
-static void g_graph_cluster_setup_links(GGraphCluster *);
-
-/* Organise la disposition d'un ensemble de blocs basiques. */
-static void g_graph_cluster_dispatch_x(GGraphCluster *);
-
-/* Réorganise au besoin les liens entrants d'un bloc. */
-static void g_graph_cluster_sort_incoming_links(GGraphCluster *);
-
-/* Retrouve l'indice d'un lien entrant donné pour un bloc. */
-static size_t g_graph_cluster_find_incoming_link(const GGraphCluster *, const leaving_link_t *);
-
-/* Détermine si un cluster possède un lien sortant. */
-static bool g_graph_cluster_has_exit_link(GGraphCluster *, bool *);
-
-/* Compare deux clusters avec lien sortant. */
-static int g_graph_cluster_compare_by_exit(const GGraphCluster **, const GGraphCluster **, const bool *);
-
-/* Réordonne les blocs sortant du cluster au mieux. */
-static void g_graph_cluster_reorder_exit_blocks(GGraphCluster *);
-
-/* Réordonne les blocs de départ de boucle au mieux. */
-static void g_graph_cluster_reorder_loop_blocks(GGraphCluster *);
-
-/* Réordonne le départ des liens en entrée de bloc. */
-static void g_graph_cluster_reorder_link_origins(GGraphCluster *, bool);
-
-/* Décale vers la droite un ensemble de blocs basiques. */
-static void g_graph_cluster_offset_x(GGraphCluster *, gint);
-
-/* Décale vers le bas un ensemble de blocs basiques. */
-static void g_graph_cluster_set_y(GGraphCluster *, gint);
-
-/* Calcule l'abscisse d'un lien pour un bloc. */
-static gint _g_graph_cluster_compute_link_position(const GGraphCluster *, size_t, size_t, bool);
-
-/* Calcule l'abscisse d'un lien à son départ d'un bloc. */
-static gint g_graph_cluster_compute_leaving_link_position(const GGraphCluster *, size_t);
-
-/* Calcule l'abscisse d'un lien à son arrivée à un bloc. */
-static gint g_graph_cluster_compute_incoming_link_position(const GGraphCluster *, size_t);
-
/* Ajoute une marge à gauche pour les liens remontants. */
static void g_graph_cluster_insert_left_margin(GGraphCluster *, gint);
-/* Détermine les abscisses des liens de boucle en place. */
-static void g_graph_cluster_compute_loop_link_x_positions(GGraphCluster *);
-
/* Détermine les abscisses de tous les liens en place. */
static void g_graph_cluster_compute_link_x_positions(GGraphCluster *);
/* Réserve de l'espace vertical pour les lignes horizontales. */
static void g_graph_cluster_book_hspace_for_links(GGraphCluster *);
-/* Détermine les ordonnées de tous les liens en place. */
-static void g_graph_cluster_compute_link_y_positions(GGraphCluster *);
-
/* Applique les positions calculées pour chaque lien graphique. */
static void g_graph_cluster_resolve_links(const GGraphCluster *);
-/* Collecte tous les chefs de file de blocs de code. */
-static GGraphCluster **g_graph_cluster_collect(GGraphCluster *, GGraphCluster **, size_t *);
-
-/* Collecte tous les liens de chefs de file de blocs de code. */
-static GGraphEdge **g_graph_cluster_collect_edges(GGraphCluster *, GGraphEdge **, size_t *);
-
/* ------------------------- CALCUL DE REPARTITION DE BLOCS ------------------------- */
@@ -454,80 +152,6 @@ static GGraphCluster *setup_graph_clusters(GLoadedBinary *, const GBlockList *,
/* ---------------------------------------------------------------------------------- */
-/******************************************************************************
-* *
-* Paramètres : owner = propriétaire du bloc de rattachement. *
-* index = indice dans les liens de sortie. *
-* *
-* Description : Crée un point d'attache pour un lien sortant. *
-* *
-* Retour : Structure mise en place. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static leaving_link_t *create_leaving_link(GGraphCluster *owner, size_t index)
-{
- leaving_link_t *result; /* Structure à retourner */
-
- result = malloc(sizeof(leaving_link_t));
-
- result->owner = owner;
-
- result->index = index;
-
- result->straight = false;
- result->forced_straight = false;
- result->straight_level = SIZE_MAX;
- result->cluster_exit = false;
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : link = structure à libérer de la mémoire. *
-* *
-* Description : Détruit un point d'attache pour un lien sortant. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void delete_leaving_link(leaving_link_t *link)
-{
- free(link);
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : link = information sur un lien à consulter. *
-* *
-* Description : Calcule l'abscisse d'un lien à son départ d'un bloc. *
-* *
-* Retour : Abscisse à attribuer à un départ de lien. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static gint compute_leaving_link_position(const leaving_link_t *link)
-{
- gint result; /* Position à retourner */
-
- result = g_graph_cluster_compute_leaving_link_position(link->owner, link->index);
-
- return result;
-
-}
-
/* ---------------------------------------------------------------------------------- */
@@ -535,152 +159,6 @@ static gint compute_leaving_link_position(const leaving_link_t *link)
/* ---------------------------------------------------------------------------------- */
-/******************************************************************************
-* *
-* Paramètres : owner = propriétaire du bloc de rattachement. *
-* type = type de lien simple attendu. *
-* other = point de départ du lien formé. *
-* *
-* Description : Crée un point d'attache pour un lien entrant simple. *
-* *
-* Retour : Structure mise en place. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static incoming_link_t *create_incoming_link(GGraphCluster *owner, InstructionLinkType type, leaving_link_t *other)
-{
- incoming_link_t *result; /* Structure à retourner */
- GCodeBlock *src; /* Bloc d'origine du lien */
- GCodeBlock *dst; /* Bloc de destination du lien */
-
- result = malloc(sizeof(incoming_link_t));
-
- result->owner = owner;
-
- result->type = type;
-
- src = other->owner->block;
- dst = owner->block;
-
- if (type == ILT_JUMP_IF_TRUE)
- result->edge = g_graph_edge_new_true(src, dst,
- &other->start[0], &other->start[1],
- &result->end[0], &result->end[1]);
-
- else if (type == ILT_JUMP_IF_FALSE)
- result->edge = g_graph_edge_new_false(src, dst,
- &other->start[0], &other->start[1],
- &result->end[0], &result->end[1]);
-
- else
- result->edge = g_graph_edge_new(src, dst,
- &other->start[0], &other->start[1],
- &result->end[0], &result->end[1]);
-
- result->other = other;
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : owner = propriétaire du bloc de rattachement. *
-* other = point de départ du lien formé. *
-* *
-* Description : Crée un point d'attache pour un lien entrant de boucle. *
-* *
-* Retour : Structure mise en place. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static incoming_link_t *create_incoming_loop_link(GGraphCluster *owner, const GdkPoint *midpts, leaving_link_t *other)
-{
- incoming_link_t *result; /* Structure à retourner */
- GCodeBlock *src; /* Bloc d'origine du lien */
- GCodeBlock *dst; /* Bloc de destination du lien */
-
- result = malloc(sizeof(incoming_link_t));
-
- result->owner = owner;
-
- result->type = ILT_LOOP;
-
- src = other->owner->block;
- dst = owner->block;
-
- result->edge = g_graph_edge_new_loop(src, dst,
- &other->start[0], &other->start[1],
- &midpts[0], &midpts[1],
- &result->end[0], &result->end[1]);
-
- result->other = other;
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : link = structure à libérer de la mémoire. *
-* *
-* Description : Détruit un point d'attache pour un lien entrant. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void delete_incoming_link(incoming_link_t *link)
-{
- free(link);
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : a = premier lien entrant à comparer. *
-* b = second lien entrant à comparer. *
-* *
-* Description : Compare deux liens entrants. *
-* *
-* Retour : Bilan de comparaison. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static int cmp_incoming_links(const incoming_link_t **a, const incoming_link_t **b)
-{
- int result; /* Bilan à retourner */
- gint pos_a; /* Point de départ pour A */
- gint pos_b; /* Point de départ pour B */
-
- pos_a = compute_leaving_link_position((*a)->other);
-
- pos_b = compute_leaving_link_position((*b)->other);
-
- if (pos_a < pos_b)
- result = -1;
-
- else if (pos_a > pos_b)
- result = 1;
-
- else
- result = 0;
-
- return result;
-
-}
-
/* ---------------------------------------------------------------------------------- */
@@ -688,347 +166,6 @@ static int cmp_incoming_links(const incoming_link_t **a, const incoming_link_t *
/* ---------------------------------------------------------------------------------- */
-/******************************************************************************
-* *
-* Paramètres : manager = structure à initialiser. *
-* *
-* Description : Initialise les réservations liens verticaux. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void init_vspace_manager(vspace_manager_t *manager)
-{
- manager->pending = NULL;
- manager->pending_count = 0;
-
- manager->left = NULL;
- manager->left_count = 0;
-
- manager->right = NULL;
- manager->right_count = 0;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : manager = structure à vider. *
-* *
-* Description : Termine les réservations liens verticaux. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void exit_vspace_manager(vspace_manager_t *manager)
-{
- size_t i; /* Boucle de parcours */
-
- for (i = 0; i < manager->pending_count; i++)
- free(manager->pending[i].pts);
-
- if (manager->pending != NULL)
- free(manager->pending);
-
- if (manager->left != NULL)
- free(manager->left);
-
- if (manager->right != NULL)
- free(manager->right);
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : manager = structure à compléter. *
-* from = point de départ du lien concerné. *
-* to = point d'arrivée du lien concerné. *
-* pts = points intermédiaires du tracé complet final. *
-* external = précise une sortie du cadre du cluster premier. *
-* *
-* Description : Inscrit une nouvelle réservation d'espace latéral. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void extend_vspace_manager(vspace_manager_t *manager, leaving_link_t *from, incoming_link_t *to, GdkPoint *pts, bool external)
-{
- vspace_booking_t *new; /* Réservation à constituer */
-
- manager->pending = realloc(manager->pending, ++manager->pending_count * sizeof(vspace_booking_t));
-
- new = &manager->pending[manager->pending_count - 1];
-
- new->from = from;
- new->to = to;
-
- new->pts = pts;
-
- new->external = external;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : manager = gestion des espaces latéraux à consulter. *
-* external = précise une sortie du cadre du cluster premier. *
-* alloc = emplacement idéal pour l'affichage. [OUT] *
-* *
-* Description : Détermine l'emplacement requis pour les espaces latéraux. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void compute_vspace_manager_needed_alloc(const vspace_manager_t *manager, bool external, GtkAllocation *alloc)
-{
- gint width; /* Largeur supplémentaire */
- size_t count; /* Nombre de liens retenus */
- size_t i; /* Boucle de parcours */
-
- width = 0;
-
- /* Extension de la largeur, à gauche */
-
- count = 0;
-
- for (i = 0; i < manager->left_count; i++)
- if (manager->left[i]->external == external)
- count++;
-
- width += count * LINK_MARGIN;
-
- alloc->x -= width;
-
- /* Extension de la largeur, à droite */
-
- count = 0;
-
- for (i = 0; i < manager->right_count; i++)
- if (manager->right[i]->external == external)
- count++;
-
- width += count * LINK_MARGIN;
-
- alloc->width += width;
-
- /* Extension de la hauteur */
-
- if (!external)
- alloc->height += manager->pending_count * VERTICAL_MARGIN;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : manager = gestion d'espaces latéraux à manipuler. *
-* *
-* Description : Réorganise au besoin les liens de boucle entre blocs. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void sort_incoming_links_for_vspace_manager(vspace_manager_t *manager)
-{
- size_t i; /* Boucle de parcours */
- vspace_booking_t *pending; /* Elément traité */
- gint x1; /* Abscisse de départ de lien */
- size_t idx; /* Indice du lien entrant */
- gint x2; /* Abscisse d'arrivée de lien */
- bool for_left; /* Répartition par la gauche ? */
-
- for (i = 0; i < manager->pending_count; i++)
- {
- pending = &manager->pending[i];
-
- x1 = g_graph_cluster_compute_leaving_link_position(pending->from->owner, pending->from->index);
-
- idx = g_graph_cluster_find_incoming_link(pending->to->owner, pending->from);
-
- x2 = g_graph_cluster_compute_incoming_link_position(pending->to->owner, idx);
-
- /**
- * Prise en compte d'une boucle while (1);
- */
- if (pending->from->owner == pending->to->owner)
- for_left = (x2 < x1);
- else
- for_left = (x1 < x2);
-
- if (for_left)
- {
- manager->left = realloc(manager->left, ++manager->left_count * sizeof(vspace_booking_t *));
- manager->left[manager->left_count - 1] = pending;
- }
- else
- {
- manager->right = realloc(manager->right, ++manager->right_count * sizeof(vspace_booking_t *));
- manager->right[manager->right_count - 1] = pending;
- }
-
- }
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : manager = structure à actualiser. *
-* offset = décalage à appliquer. *
-* *
-* Description : Décale vers la droite un ensemble de points. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void offset_x_vspace_manager(vspace_manager_t *manager, gint offset)
-{
- size_t i; /* Boucle de parcours */
- vspace_booking_t *booking; /* Réservation à traiter */
-
- for (i = 0; i < manager->left_count; i++)
- {
- booking = manager->left[i];
-
- booking->pts[0].x += offset;
- booking->pts[1].x += offset;
-
- }
-
- for (i = 0; i < manager->right_count; i++)
- {
- booking = manager->right[i];
-
- booking->pts[0].x += offset;
- booking->pts[1].x += offset;
-
- }
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : manager = structure à consulter. *
-* needed = espace nécessaire et alloué pour les blocs. *
-* external = précise une sortie du cadre du cluster premier. *
-* *
-* Description : Détermine les abscisses de tous les liens en place. *
-* *
-* Retour : Eventuelle marge à gauche devenue nécessaire. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static gint compute_loop_link_x_with_vspace_manager(const vspace_manager_t *manager, const GtkAllocation *needed, bool external)
-{
- gint result; /* Eventuelle marge à renvoyer */
- size_t count; /* Quantité de liens traités */
- size_t i; /* Boucle de parcours */
- vspace_booking_t *booking; /* Réservation à traiter */
- gint x; /* Position à appliquer */
-
- count = 0;
-
- for (i = 0; i < manager->left_count; i++)
- {
- booking = manager->left[i];
-
- if (booking->external != external)
- continue;
-
- x = ++count * LINK_MARGIN;
-
- booking->pts[0].x = needed->x - x;
- booking->pts[1].x = needed->x - x;
-
- }
-
- result = count * LINK_MARGIN;
-
- count = 0;
-
- for (i = 0; i < manager->right_count; i++)
- {
- booking = manager->right[i];
-
- if (booking->external != external)
- continue;
-
- x = ++count * LINK_MARGIN;
-
- booking->pts[0].x = needed->x + needed->width + x;
- booking->pts[1].x = needed->x + needed->width + x;
-
- }
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : manager = structure à consulter. *
-* needed = espace nécessaire et alloué pour les blocs. *
-* *
-* Description : Détermine les ordonnées de tous les liens en place. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void compute_loop_link_y_with_vspace_manager(const vspace_manager_t *manager, const GtkAllocation *needed)
-{
- gint real_bottom; /* Point de départ réel */
- size_t i; /* Boucle de parcours */
- vspace_booking_t *booking; /* Réservation à traiter */
-
- real_bottom = needed->y + needed->height - manager->pending_count * VERTICAL_MARGIN;
-
- for (i = 0; i < manager->pending_count; i++)
- {
- booking = &manager->pending[i];
-
- /**
- * On corrige le raccourci pris sans distinction de type de lien dans
- * la fonction g_graph_cluster_compute_link_y_positions().
- */
-
- booking->from->start[1].y = real_bottom + (i + 1) * VERTICAL_MARGIN;
-
- /* Définition de l'ordonnée des points du lien */
-
- booking->pts[0].y = booking->from->start[1].y;
-
- booking->pts[1].y = booking->to->end[0].y;
-
- }
-
-}
@@ -1037,971 +174,6 @@ static void compute_loop_link_y_with_vspace_manager(const vspace_manager_t *mana
/* ---------------------------------------------------------------------------------- */
-/******************************************************************************
-* *
-* Paramètres : start = abscisse de départ de ligne. *
-* *
-* Description : Prépare une réservation d'espace pour ligne horizontale. *
-* *
-* Retour : Structure mise en place pour la conservation d'informations. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static hspace_booking *create_hspace_booking(gint start)
-{
- hspace_booking *result; /* Structure à retourner */
-
- result = malloc(sizeof(hspace_booking));
-
- result->start = start;
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : a = première réservation d'espace à comparer. *
-* b = seconde réservation d'espace à comparer. *
-* *
-* Description : Compare deux réservations d'espace. *
-* *
-* Retour : Bilan de comparaison. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static int cmp_hspace_booking_r2l(const hspace_booking **a, const hspace_booking **b)
-{
- int result; /* Bilan à retourner */
-
- if ((*a)->start > (*b)->start)
- result = -1;
-
- else if ((*a)->start < (*b)->start)
- result = 1;
-
- else
- {
- assert(false);
- result = 0;
- }
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : a = première réservation d'espace à comparer. *
-* b = seconde réservation d'espace à comparer. *
-* *
-* Description : Compare deux réservations d'espace. *
-* *
-* Retour : Bilan de comparaison. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static int cmp_hspace_booking_l2r(const hspace_booking **a, const hspace_booking **b)
-{
- int result; /* Bilan à retourner */
-
- if ((*a)->start < (*b)->start)
- result = -1;
-
- else if ((*a)->start > (*b)->start)
- result = 1;
-
- else
- {
- assert(false);
- result = 0;
- }
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : grank = structure à initialiser. [OUT] *
-* cluster = chef de file d'un ensemble de blocs. *
-* *
-* Description : Initialise la gestion d'un ensemble de blocs de même rang. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void init_graph_rank(graph_rank_t *grank, GGraphCluster *cluster)
-{
- grank->right2left = NULL;
- grank->r2l_count = 0;
-
- grank->left2right = NULL;
- grank->l2r_count = 0;
-
- grank->clusters = malloc(sizeof(GGraphCluster *));
- grank->count = 1;
-
- grank->clusters[0] = cluster;
-
- init_vspace_manager(&grank->vspaces);
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : grank = structure à vider. *
-* *
-* Description : Termine la gestion d'un ensemble de blocs de même rang. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void exit_graph_rank(graph_rank_t *grank)
-{
- size_t i; /* Boucle de parcours */
-
- for (i = 0; i < grank->r2l_count; i++)
- free(grank->right2left[i]);
-
- if (grank->right2left != NULL)
- free(grank->right2left);
-
- for (i = 0; i < grank->l2r_count; i++)
- free(grank->left2right[i]);
-
- if (grank->left2right != NULL)
- free(grank->left2right);
-
- assert(grank->clusters != NULL);
-
- free(grank->clusters);
-
- exit_vspace_manager(&grank->vspaces);
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : grank = ensemble de même rang à consulter. *
-* *
-* Description : Assigne à un ensemble de blocs un emplacement initial. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void reset_graph_rank_allocation(const graph_rank_t *grank)
-{
- size_t i; /* Boucle de parcours */
-
- for (i = 0; i < grank->count; i++)
- g_graph_cluster_reset_allocation(grank->clusters[i]);
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : grank = ensemble de même rang à consulter. *
-* *
-* Description : Fournit le rang d'un ensemble de blocs. *
-* *
-* Retour : Rang d'un ensemble de blocs de même rang. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static size_t get_graph_rank(const graph_rank_t *grank)
-{
- size_t result; /* Rang à retourner */
-
- result = g_code_block_get_rank(grank->clusters[0]->block);
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : a = premier ensemble de même rang à comparer. *
-* b = second ensemble de même rang à comparer. *
-* *
-* Description : Compare deux rangées de blocs de code. *
-* *
-* Retour : Bilan de comparaison. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static int cmp_graph_rank(const graph_rank_t *a, const graph_rank_t *b)
-{
- int result; /* Bilan à retourner */
- size_t level_a; /* Niveau de l'ensemble A */
- size_t level_b; /* Niveau de l'ensemble B */
-
- level_a = get_graph_rank(a);
- level_b = get_graph_rank(b);
-
- if (level_a < level_b)
- result = -1;
-
- else if (level_a > level_b)
- result = 1;
-
- else
- result = 0;
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : grank = structure à compléter. *
-* cluster = chef de file d'un ensemble de blocs. *
-* *
-* Description : Etend un ensemble de blocs de même rang. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void extend_graph_rank(graph_rank_t *grank, GGraphCluster *cluster)
-{
- grank->count++;
- grank->clusters = realloc(grank->clusters, sizeof(GGraphCluster *) * grank->count);
-
- grank->clusters[grank->count - 1] = cluster;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : grank = structure à compléter. *
-* cluster = chef de file d'un ensemble de blocs. *
-* *
-* Description : Détermine si un groupe de blocs contient un bloc particulier.*
-* *
-* Retour : true si le chef est bien contenu, false sinon. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static bool has_graph_rank_cluster(const graph_rank_t *grank, GGraphCluster *cluster)
-{
- bool result; /* Bilan à renvoyer */
- size_t i; /* Boucle de parcours */
-
- result = false;
-
- for (i = 0; i < grank->count && !result; i++)
- result = (grank->clusters[i] == cluster);
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : grank = ensemble de descendants d'un même rang. *
-* from = point de départ du lien concerné. *
-* to = point d'arrivée du lien concerné. *
-* pts = points intermédiaires du tracé complet final. *
-* external = précise une sortie du cadre du cluster premier. *
-* *
-* Description : Inscrit à l'endroit idéal une réservation d'espace latéral. *
-* *
-* Retour : true si la demande a bien été traitée. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static bool extend_graph_rank_vspace_manager(graph_rank_t *grank, leaving_link_t *from, incoming_link_t *to, GdkPoint *pts, bool external)
-{
- bool result; /* Bilan à renvoyer */
-
- result = has_graph_rank_cluster(grank, from->owner);
-
- if (result)
- extend_vspace_manager(&grank->vspaces, from, to, pts, external);
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : grank = ensemble de descendants d'un même rang. *
-* all = table regroupant tous les groupes créés. *
-* *
-* Description : Met en place les embryons de liens nécessaires. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void define_graph_rank_links(const graph_rank_t *grank, GHashTable *all)
-{
- size_t i; /* Boucle de parcours */
-
- for (i = 0; i < grank->count; i++)
- g_graph_cluster_define_links(grank->clusters[i], all);
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : grank = ensemble de descendants d'un même rang. *
-* *
-* Description : Repère les liens marquants à destination d'autres blocs. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void setup_graph_rank_links(const graph_rank_t *grank)
-{
- size_t i; /* Boucle de parcours */
-
- for (i = 0; i < grank->count; i++)
- g_graph_cluster_setup_links(grank->clusters[i]);
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : grank = ensemble de descendants d'un même rang. *
-* last = indique s'il s'agit du dernier étage de l'ensemble. *
-* alloc = emplacement idéal pour l'affichage. [OUT] *
-* *
-* Description : Détermine l'emplacement requis d'un ensemble de blocs. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void compute_graph_rank_needed_alloc(const graph_rank_t *grank, bool last, GtkAllocation *alloc)
-{
- GtkAllocation needed; /* Taille requise */
-
- switch (grank->count)
- {
- case 1:
-
- g_graph_cluster_compute_needed_alloc(grank->clusters[0], &needed);
-
- if (needed.x < alloc->x)
- {
- alloc->width += (alloc->x - needed.x);
- alloc->x = needed.x;
- }
-
- if ((needed.x + needed.width) > (alloc->x + alloc->width))
- alloc->width += needed.x + needed.width - alloc->x - alloc->width;
-
- /* La hauteur maximale n'est présente qu'avec le dernier morceau */
- if (last)
- {
- if ((needed.y + needed.height) > (alloc->y + alloc->height))
- alloc->height += needed.y + needed.height - alloc->y - alloc->height;
- }
-
- break;
-
- default:
-
- assert(grank->count >= 2);
-
- g_graph_cluster_compute_needed_alloc(grank->clusters[0], &needed);
-
- if (needed.x < alloc->x)
- {
- alloc->width += (alloc->x - needed.x);
- alloc->x = needed.x;
- }
-
- /* La hauteur maximale n'est présente qu'avec le dernier morceau */
- if (last)
- {
- if ((needed.y + needed.height) > (alloc->y + alloc->height))
- alloc->height += needed.y + needed.height - alloc->y - alloc->height;
- }
-
- g_graph_cluster_compute_needed_alloc(grank->clusters[grank->count - 1], &needed);
-
- if ((needed.x + needed.width) > (alloc->x + alloc->width))
- alloc->width += needed.x + needed.width - alloc->x - alloc->width;
-
- /* La hauteur maximale n'est présente qu'avec le dernier morceau */
- if (last)
- {
- if ((needed.y + needed.height) > (alloc->y + alloc->height))
- alloc->height += needed.y + needed.height - alloc->y - alloc->height;
- }
-
- break;
-
- }
-
- compute_vspace_manager_needed_alloc(&grank->vspaces, false, alloc);
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : iter = début de la boucle de parcours. *
-* loop = nombre d'itérations à mener. *
-* base = position de base sur l'axe des abscisses. *
-* dir = direction du parcours. *
-* *
-* Description : Affine l'abscisse d'un ensemble de blocs de même rang. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void _place_graph_rank_clusters(GGraphCluster **iter, size_t loop, gint base, int dir)
-{
- size_t i; /* Boucle de parcours */
- GtkAllocation needed; /* Taille requise */
-
- assert(dir == -1 || dir == 1);
-
- for (i = 0; i < loop; i++, iter += dir)
- {
- g_graph_cluster_dispatch_x(*iter);
-
- g_graph_cluster_compute_needed_alloc(*iter, &needed);
-
- if (dir > 0)
- g_graph_cluster_offset_x(*iter, base - needed.x);
- else
- g_graph_cluster_offset_x(*iter, base - needed.x - needed.width);
-
- base += dir * (needed.width + HORIZONTAL_MARGIN);
-
- }
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : grank = ensemble de blocs de même rang à manipuler. *
-* *
-* Description : Organise la disposition d'un ensemble de blocs basiques. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void dispatch_x_graph_rank(const graph_rank_t *grank)
-{
- size_t mid; /* Position centrale de départ */
- gint start; /* Position initiale de départ */
-
- if (grank->count % 2 == 1)
- {
- if (grank->count > 1)
- {
- mid = grank->count / 2;
-
- start = grank->clusters[mid]->alloc.x - HORIZONTAL_MARGIN;
-
- _place_graph_rank_clusters(grank->clusters + mid - 1, mid, start, -1);
-
- start *= -1;
-
- _place_graph_rank_clusters(grank->clusters + mid + 1, mid, start, 1);
-
- }
-
- else
- g_graph_cluster_dispatch_x(grank->clusters[0]);
-
- }
-
- else
- {
- mid = grank->count / 2 - 1;
-
- start = - HORIZONTAL_MARGIN / 2;
-
- _place_graph_rank_clusters(grank->clusters + mid, mid + 1, start, -1);
-
- start *= -1;
-
- _place_graph_rank_clusters(grank->clusters + mid + 1, mid + 1, start, 1);
-
- }
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : grank = ensemble de blocs de même rang à actualiser. *
-* *
-* Description : Réorganise au besoin les liens entrants un ensemble de blocs.*
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void sort_graph_rank_incoming_links(graph_rank_t *grank)
-{
- size_t i; /* Boucle de parcours */
-
- for (i = 0; i < grank->count; i++)
- g_graph_cluster_sort_incoming_links(grank->clusters[i]);
-
- sort_incoming_links_for_vspace_manager(&grank->vspaces);
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : grank = ensemble de blocs de même rang à actualiser. *
-* *
-* Description : Réordonne les blocs sortant d'un ensemble. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void reorder_graph_rank_exit_blocks(graph_rank_t *grank)
-{
- GGraphCluster **exit_2_left; /* Liste avec sortie à gauche */
- GGraphCluster **exit_2_right; /* Liste avec sortie à droite */
- GGraphCluster **no_exit; /* Liste sans sortie */
- size_t count_2_left; /* Quantité de présents */
- size_t count_2_right; /* Quantité de présents */
- size_t count_no; /* Quantité de présents */
- size_t i; /* Boucle de parcours */
- bool l2r; /* Détermination de catégorie */
-
- if (grank->count > 1)
- {
- exit_2_left = malloc(grank->count * sizeof(GGraphCluster *));
- exit_2_right = malloc(grank->count * sizeof(GGraphCluster *));
- no_exit = malloc(grank->count * sizeof(GGraphCluster *));
-
- count_2_left = 0;
- count_2_right = 0;
- count_no = 0;
-
- for (i = 0; i < grank->count; i++)
- {
- if (g_graph_cluster_has_exit_link(grank->clusters[i], &l2r))
- {
- if (l2r)
- exit_2_right[count_2_right++] = grank->clusters[i];
- else
- exit_2_left[count_2_left++] = grank->clusters[i];
- }
- else
- no_exit[count_no++] = grank->clusters[i];
-
- }
-
- assert((count_2_left + count_2_right + count_no) == grank->count);
-
- qsort_r(exit_2_left, count_2_left, sizeof(GGraphCluster *),
- (__compar_d_fn_t)g_graph_cluster_compare_by_exit, (bool []){ false });
-
- qsort_r(exit_2_right, count_2_right, sizeof(GGraphCluster *),
- (__compar_d_fn_t)g_graph_cluster_compare_by_exit, (bool []){ true });
-
- grank->count = 0;
-
- for (i = 0; i < count_2_left; i++)
- grank->clusters[grank->count++] = exit_2_left[i];
-
- for (i = 0; i < count_no; i++)
- grank->clusters[grank->count++] = no_exit[i];
-
- for (i = 0; i < count_2_right; i++)
- grank->clusters[grank->count++] = exit_2_right[i];
-
- }
-
- for (i = 0; i < grank->count; i++)
- g_graph_cluster_reorder_exit_blocks(grank->clusters[i]);
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : grank = ensemble de blocs de même rang à actualiser. *
-* *
-* Description : Réordonne les blocs de départ de boucle d'un ensemble. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void reorder_graph_rank_loop_blocks(graph_rank_t *grank)
-{
- size_t i; /* Boucle de parcours #1 */
- size_t k; /* Boucle de parcours #2 */
- GGraphCluster *tmp; /* Stockage temporaire */
-
- for (i = 0; i < grank->count; i++)
- g_graph_cluster_reorder_loop_blocks(grank->clusters[i]);
-
- if (grank->count > 1)
- {
- /* Placement des départs de boucle à gauche ! */
-
- for (i = 0; i < grank->vspaces.left_count; i++)
- {
- tmp = grank->vspaces.left[i]->from->owner;
-
- for (k = 0; k < grank->count; k++)
- if (grank->clusters[k] == tmp)
- break;
-
- assert(k < grank->count);
-
- memmove(&grank->clusters[1], &grank->clusters[0],
- k * sizeof(GGraphCluster *));
-
- grank->clusters[0] = tmp;
-
- g_graph_cluster_reorder_link_origins(tmp, true);
-
- }
-
- /* Placement des départs de boucle à droite ! */
-
- for (i = 0; i < grank->vspaces.right_count; i++)
- {
- tmp = grank->vspaces.right[i]->from->owner;
-
- for (k = 0; k < grank->count; k++)
- if (grank->clusters[k] == tmp)
- break;
-
- assert(k < grank->count);
-
- memmove(&grank->clusters[k], &grank->clusters[k + 1],
- (grank->count - k - 1) * sizeof(GGraphCluster *));
-
- grank->clusters[grank->count - 1] = tmp;
-
- g_graph_cluster_reorder_link_origins(tmp, false);
-
- }
-
- }
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : grank = ensemble de blocs de même rang à actualiser. *
-* offset = décalage à appliquer. *
-* *
-* Description : Décale vers la droite un ensemble de blocs basiques. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void offset_x_graph_rank(graph_rank_t *grank, gint offset)
-{
- size_t i; /* Boucle de parcours */
-
- for (i = 0; i < grank->count; i++)
- g_graph_cluster_offset_x(grank->clusters[i], offset);
-
- offset_x_vspace_manager(&grank->vspaces, offset);
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : grank = ensemble de blocs de même rang à actualiser. *
-* needed = espace nécessaire et alloué pour les blocs. *
-* *
-* Description : Détermine les abscisses des liens de boucle en place. *
-* *
-* Retour : Eventuelle marge à gauche devenue nécessaire. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static gint compute_loop_link_x_positions_with_graph_rank(const graph_rank_t *grank, const GtkAllocation *needed)
-{
- gint result; /* Eventuelle marge à renvoyer */
- size_t i; /* Boucle de parcours */
-
- for (i = 0; i < grank->count; i++)
- g_graph_cluster_compute_loop_link_x_positions(grank->clusters[i]);
-
- result = compute_loop_link_x_with_vspace_manager(&grank->vspaces, needed, false);
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : grank = ensemble de blocs de même rang à actualiser. *
-* base = position ordonnée à appliquer. *
-* *
-* Description : Décale vers le bas un ensemble de blocs basiques. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void set_y_for_graph_rank(const graph_rank_t *grank, gint *base)
-{
- gint max; /* Hauteur maximale rencontrée */
- size_t i; /* Boucle de parcours */
- GGraphCluster *sub; /* Sous-ensemble traité */
- GtkAllocation alloc; /* Allocation courante */
-
- /* On ajoute l'espace vertical pour les lignes horizontales */
-
- if (grank->r2l_count > grank->l2r_count)
- max = grank->r2l_count;
- else
- max = grank->l2r_count;
-
- *base += VERTICAL_MARGIN;
-
- /**
- * Comme les liens purement verticaux n'entrainent pas de réservation,
- * il n'y a potentiellement pas toujours d'espace à ajouter.
- */
-
- if (max > 0)
- {
- *base += ((max - 1) * LINK_MARGIN);
- *base += VERTICAL_MARGIN;
- }
-
- /* On ajoute l'espace requis pour l'affichage des blocs */
-
- max = 0;
-
- for (i = 0; i < grank->count; i++)
- {
- sub = grank->clusters[i];
-
- g_graph_cluster_set_y(sub, *base);
-
- g_graph_cluster_compute_needed_alloc(sub, &alloc);
-
- if ((alloc.y + alloc.height) > max)
- max = alloc.y + alloc.height;
-
- }
-
- *base = max;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : grank = ensemble de blocs de même rang à actualiser. *
-* needed = espace nécessaire et alloué pour les blocs. *
-* *
-* Description : Détermine les ordonnées de tous les liens en place. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void compute_loop_link_with_graph_rank(const graph_rank_t *grank, const GtkAllocation *needed)
-{
- size_t i; /* Boucle de parcours */
-
- for (i = 0; i < grank->count; i++)
- g_graph_cluster_compute_link_y_positions(grank->clusters[i]);
-
- compute_loop_link_y_with_vspace_manager(&grank->vspaces, needed);
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : grank = ensemble de blocs de même rang à analyser. *
-* block = bloc de code à retrouver. *
-* *
-* Description : Recherche le groupe de blocs avec un bloc donné comme chef. *
-* *
-* Retour : Groupe trouvé ou NULL en cas d'échec. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static GGraphCluster *find_cluster_by_block_in_graph_rank(const graph_rank_t *grank, GCodeBlock *block)
-{
- GGraphCluster *result; /* Trouvaille à retourner */
- size_t i; /* Boucle de parcours */
-
- result = NULL;
-
- for (i = 0; i < grank->count && result == NULL; i++)
- result = g_graph_cluster_find_by_block(grank->clusters[i], block);
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : grank = ensemble de blocs de même rang à analyser. *
-* widget = composant graphique à retrouver. *
-* *
-* Description : Recherche le groupe de blocs avec un composant comme chef. *
-* *
-* Retour : Groupe trouvé ou NULL en cas d'échec. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static GGraphCluster *find_cluster_by_widget_in_graph_rank(const graph_rank_t *grank, GtkWidget *widget)
-{
- GGraphCluster *result; /* Trouvaille à retourner */
- size_t i; /* Boucle de parcours */
-
- result = NULL;
-
- for (i = 0; i < grank->count && result == NULL; i++)
- result = g_graph_cluster_find_by_widget(grank->clusters[i], widget);
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : grank = ensemble de blocs de même rang à analyser. *
-* list = liste en cours de constitution. [OUT] *
-* count = taille de cette liste. [OUT] *
-* *
-* Description : Collecte tous les chefs de file de blocs de code. *
-* *
-* Retour : Liste de graphiques de blocs rassemblés. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static GGraphCluster **collect_graph_ranks_clusters(const graph_rank_t *grank, GGraphCluster **list, size_t *count)
-{
- GGraphCluster **result; /* Liste complétée à renvoyer */
- size_t i; /* Boucle de parcours */
-
- result = list;
-
- for (i = 0; i < grank->count; i++)
- result = g_graph_cluster_collect(grank->clusters[i], result, count);
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : grank = ensemble de blocs de même rang à analyser. *
-* list = liste en cours de constitution. [OUT] *
-* count = taille de cette liste. [OUT] *
-* *
-* Description : Collecte tous les liens de chefs de file de blocs de code. *
-* *
-* Retour : Liste de liens graphiques de blocs rassemblés. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static GGraphEdge **collect_graph_ranks_cluster_edges(const graph_rank_t *grank, GGraphEdge **list, size_t *count)
-{
- GGraphEdge **result; /* Liste complétée à renvoyer */
- size_t i; /* Boucle de parcours */
-
- result = list;
-
- for (i = 0; i < grank->count; i++)
- result = g_graph_cluster_collect_edges(grank->clusters[i], result, count);
-
- return result;
-
-}
@@ -2178,7 +350,7 @@ GGraphCluster *g_graph_cluster_new(GCodeBlock *block, segcnt_list *highlighted,
* *
******************************************************************************/
-static void g_graph_cluster_reset_allocation(GGraphCluster *cluster)
+void g_graph_cluster_reset_allocation(GGraphCluster *cluster)
{
GtkRequisition requisition; /* Taille à l'écran actuelle */
size_t i; /* Boucle de parcours */
@@ -2344,7 +516,7 @@ static void g_graph_cluster_extend_vspace_manager(GGraphCluster *target, leaving
* *
******************************************************************************/
-static void g_graph_cluster_define_links(GGraphCluster *cluster, GHashTable *all)
+void g_graph_cluster_define_links(GGraphCluster *cluster, GHashTable *all)
{
size_t dcount; /* Nombre de liens de dest. */
block_link_t *links; /* Liens associés au bloc */
@@ -2539,7 +711,7 @@ static void g_graph_cluster_define_links(GGraphCluster *cluster, GHashTable *all
* *
******************************************************************************/
-static void g_graph_cluster_setup_links(GGraphCluster *cluster)
+void g_graph_cluster_setup_links(GGraphCluster *cluster)
{
size_t i; /* Boucle de parcours #1 */
leaving_link_t *leaving; /* Départ de lien */
@@ -2633,7 +805,7 @@ static void g_graph_cluster_setup_links(GGraphCluster *cluster)
* *
******************************************************************************/
-static void g_graph_cluster_dispatch_x(GGraphCluster *cluster)
+void g_graph_cluster_dispatch_x(GGraphCluster *cluster)
{
size_t i; /* Boucle de parcours #1 */
leaving_link_t *straight_leaving; /* Lien à présenter vertical */
@@ -2786,7 +958,7 @@ static void g_graph_cluster_dispatch_x(GGraphCluster *cluster)
* *
******************************************************************************/
-static void g_graph_cluster_sort_incoming_links(GGraphCluster *cluster)
+void g_graph_cluster_sort_incoming_links(GGraphCluster *cluster)
{
size_t i; /* Boucle de parcours */
@@ -2813,7 +985,7 @@ static void g_graph_cluster_sort_incoming_links(GGraphCluster *cluster)
* *
******************************************************************************/
-static size_t g_graph_cluster_find_incoming_link(const GGraphCluster *cluster, const leaving_link_t *leaving)
+size_t g_graph_cluster_find_incoming_link(const GGraphCluster *cluster, const leaving_link_t *leaving)
{
size_t result; /* Indice à retourner */
@@ -2841,7 +1013,7 @@ static size_t g_graph_cluster_find_incoming_link(const GGraphCluster *cluster, c
* *
******************************************************************************/
-static bool g_graph_cluster_has_exit_link(GGraphCluster *cluster, bool *l2r)
+bool g_graph_cluster_has_exit_link(GGraphCluster *cluster, bool *l2r)
{
bool result; /* Bilan à retourner */
size_t i; /* Boucle de parcours */
@@ -2891,7 +1063,7 @@ static bool g_graph_cluster_has_exit_link(GGraphCluster *cluster, bool *l2r)
* *
******************************************************************************/
-static int g_graph_cluster_compare_by_exit(const GGraphCluster **cluster, const GGraphCluster **other, const bool *l2r)
+int g_graph_cluster_compare_by_exit(const GGraphCluster **cluster, const GGraphCluster **other, const bool *l2r)
{
int result; /* Bilan à renvoyer */
size_t i; /* Boucle de parcours */
@@ -2959,7 +1131,7 @@ static int g_graph_cluster_compare_by_exit(const GGraphCluster **cluster, const
* *
******************************************************************************/
-static void g_graph_cluster_reorder_exit_blocks(GGraphCluster *cluster)
+void g_graph_cluster_reorder_exit_blocks(GGraphCluster *cluster)
{
size_t i; /* Boucle de parcours */
@@ -2981,7 +1153,7 @@ static void g_graph_cluster_reorder_exit_blocks(GGraphCluster *cluster)
* *
******************************************************************************/
-static void g_graph_cluster_reorder_loop_blocks(GGraphCluster *cluster)
+void g_graph_cluster_reorder_loop_blocks(GGraphCluster *cluster)
{
size_t i; /* Boucle de parcours */
@@ -3005,7 +1177,7 @@ static void g_graph_cluster_reorder_loop_blocks(GGraphCluster *cluster)
* *
******************************************************************************/
-static void g_graph_cluster_reorder_link_origins(GGraphCluster *cluster, bool left)
+void g_graph_cluster_reorder_link_origins(GGraphCluster *cluster, bool left)
{
size_t i; /* Boucle de parcours #1 */
leaving_link_t *origin; /* Autre extrémité du lien */
@@ -3058,7 +1230,7 @@ static void g_graph_cluster_reorder_link_origins(GGraphCluster *cluster, bool le
* *
******************************************************************************/
-static void g_graph_cluster_offset_x(GGraphCluster *cluster, gint offset)
+void g_graph_cluster_offset_x(GGraphCluster *cluster, gint offset)
{
size_t i; /* Boucle de parcours */
@@ -3085,7 +1257,7 @@ static void g_graph_cluster_offset_x(GGraphCluster *cluster, gint offset)
* *
******************************************************************************/
-static void g_graph_cluster_set_y(GGraphCluster *cluster, gint base)
+void g_graph_cluster_set_y(GGraphCluster *cluster, gint base)
{
size_t i; /* Boucle de parcours */
@@ -3265,7 +1437,7 @@ void g_graph_cluster_place(GGraphCluster *cluster, GtkGraphDisplay *display)
* *
******************************************************************************/
-static gint _g_graph_cluster_compute_link_position(const GGraphCluster *cluster, size_t index, size_t half, bool odd)
+gint _g_graph_cluster_compute_link_position(const GGraphCluster *cluster, size_t index, size_t half, bool odd)
{
gint result; /* Position à retourner */
gint mid_x; /* Abscisse centrale */
@@ -3313,7 +1485,7 @@ static gint _g_graph_cluster_compute_link_position(const GGraphCluster *cluster,
* *
******************************************************************************/
-static gint g_graph_cluster_compute_leaving_link_position(const GGraphCluster *cluster, size_t index)
+gint g_graph_cluster_compute_leaving_link_position(const GGraphCluster *cluster, size_t index)
{
gint result; /* Position à retourner */
size_t half; /* Indice de répartition égale */
@@ -3345,7 +1517,7 @@ static gint g_graph_cluster_compute_leaving_link_position(const GGraphCluster *c
* *
******************************************************************************/
-static gint g_graph_cluster_compute_incoming_link_position(const GGraphCluster *cluster, size_t index)
+gint g_graph_cluster_compute_incoming_link_position(const GGraphCluster *cluster, size_t index)
{
gint result; /* Position à retourner */
size_t half; /* Indice de répartition égale */
@@ -3441,7 +1613,7 @@ static void g_graph_cluster_insert_left_margin(GGraphCluster *cluster, gint marg
* *
******************************************************************************/
-static void g_graph_cluster_compute_loop_link_x_positions(GGraphCluster *cluster)
+void g_graph_cluster_compute_loop_link_x_positions(GGraphCluster *cluster)
{
GtkAllocation alloc; /* Emplacement à faire évoluer */
gint margin; /* Marge à gauche éventuelle */
@@ -3680,7 +1852,7 @@ static void g_graph_cluster_book_hspace_for_links(GGraphCluster *cluster)
* *
******************************************************************************/
-static void g_graph_cluster_compute_link_y_positions(GGraphCluster *cluster)
+void g_graph_cluster_compute_link_y_positions(GGraphCluster *cluster)
{
gint y; /* Ordonnée d'application */
size_t i; /* Boucle de parcours */
@@ -3855,7 +2027,7 @@ GGraphCluster *g_graph_cluster_find_by_widget(GGraphCluster *cluster, GtkWidget
* *
******************************************************************************/
-static GGraphCluster **g_graph_cluster_collect(GGraphCluster *cluster, GGraphCluster **list, size_t *count)
+GGraphCluster **g_graph_cluster_collect(GGraphCluster *cluster, GGraphCluster **list, size_t *count)
{
GGraphCluster **result; /* Liste complétée à renvoyer */
size_t i; /* Boucle de parcours */
@@ -3887,7 +2059,7 @@ static GGraphCluster **g_graph_cluster_collect(GGraphCluster *cluster, GGraphClu
* *
******************************************************************************/
-static GGraphEdge **g_graph_cluster_collect_edges(GGraphCluster *cluster, GGraphEdge **list, size_t *count)
+GGraphEdge **g_graph_cluster_collect_edges(GGraphCluster *cluster, GGraphEdge **list, size_t *count)
{
GGraphEdge **result; /* Liste complétée à renvoyer */
size_t i; /* Boucle de parcours */
diff --git a/src/gtkext/graph/hspace.c b/src/gtkext/graph/hspace.c
new file mode 100644
index 0000000..4294050
--- /dev/null
+++ b/src/gtkext/graph/hspace.c
@@ -0,0 +1,125 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * hspace.c - encadrement des espaces horizontaux réservés
+ *
+ * Copyright (C) 2019 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 <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "hspace.h"
+
+
+#include <assert.h>
+#include <malloc.h>
+#ifndef NDEBUG
+# include <stdbool.h>
+#endif
+
+
+
+/******************************************************************************
+* *
+* Paramètres : start = abscisse de départ de ligne. *
+* *
+* Description : Prépare une réservation d'espace pour ligne horizontale. *
+* *
+* Retour : Structure mise en place pour la conservation d'informations. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+hspace_booking *create_hspace_booking(gint start)
+{
+ hspace_booking *result; /* Structure à retourner */
+
+ result = malloc(sizeof(hspace_booking));
+
+ result->start = start;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : a = première réservation d'espace à comparer. *
+* b = seconde réservation d'espace à comparer. *
+* *
+* Description : Compare deux réservations d'espace. *
+* *
+* Retour : Bilan de comparaison. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+int cmp_hspace_booking_r2l(const hspace_booking **a, const hspace_booking **b)
+{
+ int result; /* Bilan à retourner */
+
+ if ((*a)->start > (*b)->start)
+ result = -1;
+
+ else if ((*a)->start < (*b)->start)
+ result = 1;
+
+ else
+ {
+ assert(false);
+ result = 0;
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : a = première réservation d'espace à comparer. *
+* b = seconde réservation d'espace à comparer. *
+* *
+* Description : Compare deux réservations d'espace. *
+* *
+* Retour : Bilan de comparaison. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+int cmp_hspace_booking_l2r(const hspace_booking **a, const hspace_booking **b)
+{
+ int result; /* Bilan à retourner */
+
+ if ((*a)->start < (*b)->start)
+ result = -1;
+
+ else if ((*a)->start > (*b)->start)
+ result = 1;
+
+ else
+ {
+ assert(false);
+ result = 0;
+ }
+
+ return result;
+
+}
diff --git a/src/gtkext/graph/hspace.h b/src/gtkext/graph/hspace.h
new file mode 100644
index 0000000..ee0b778
--- /dev/null
+++ b/src/gtkext/graph/hspace.h
@@ -0,0 +1,52 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * hspace.h - prototypes pour l'encadrement des espaces horizontaux réservés
+ *
+ * Copyright (C) 2019 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 <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _GTKEXT_GRAPH_HSPACE_H
+#define _GTKEXT_GRAPH_HSPACE_H
+
+
+#include <glib.h>
+
+
+
+/* Réservation pour les lignes horizontales */
+typedef struct _hspace_booking
+{
+ gint start; /* Abscisse de départ de ligne */
+ size_t index; /* Indice de rangée verticale */
+
+} hspace_booking;
+
+
+/* Prépare une réservation d'espace pour ligne horizontale. */
+hspace_booking *create_hspace_booking(gint);
+
+/* Compare deux réservations d'espace. */
+int cmp_hspace_booking_r2l(const hspace_booking **, const hspace_booking **);
+
+/* Compare deux réservations d'espace. */
+int cmp_hspace_booking_l2r(const hspace_booking **, const hspace_booking **);
+
+
+
+#endif /* _GTKEXT_GRAPH_HSPACE_H */
diff --git a/src/gtkext/graph/incoming.c b/src/gtkext/graph/incoming.c
new file mode 100644
index 0000000..8e25b8d
--- /dev/null
+++ b/src/gtkext/graph/incoming.c
@@ -0,0 +1,184 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * incoming.c - liens entrants d'un bloc de code dans une représentation graphique
+ *
+ * Copyright (C) 2019 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 <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "incoming.h"
+
+
+#include <malloc.h>
+
+
+#include "leaving.h"
+
+
+
+/******************************************************************************
+* *
+* Paramètres : owner = propriétaire du bloc de rattachement. *
+* type = type de lien simple attendu. *
+* other = point de départ du lien formé. *
+* *
+* Description : Crée un point d'attache pour un lien entrant simple. *
+* *
+* Retour : Structure mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+incoming_link_t *create_incoming_link(GGraphCluster *owner, InstructionLinkType type, leaving_link_t *other)
+{
+ incoming_link_t *result; /* Structure à retourner */
+ GCodeBlock *src; /* Bloc d'origine du lien */
+ GCodeBlock *dst; /* Bloc de destination du lien */
+
+ result = malloc(sizeof(incoming_link_t));
+
+ result->owner = owner;
+
+ result->type = type;
+
+ src = g_graph_cluster_get_block(other->owner);
+ dst = g_graph_cluster_get_block(owner);
+
+ if (type == ILT_JUMP_IF_TRUE)
+ result->edge = g_graph_edge_new_true(src, dst,
+ &other->start[0], &other->start[1],
+ &result->end[0], &result->end[1]);
+
+ else if (type == ILT_JUMP_IF_FALSE)
+ result->edge = g_graph_edge_new_false(src, dst,
+ &other->start[0], &other->start[1],
+ &result->end[0], &result->end[1]);
+
+ else
+ result->edge = g_graph_edge_new(src, dst,
+ &other->start[0], &other->start[1],
+ &result->end[0], &result->end[1]);
+
+ g_object_unref(G_OBJECT(src));
+ g_object_unref(G_OBJECT(dst));
+
+ result->other = other;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : owner = propriétaire du bloc de rattachement. *
+* other = point de départ du lien formé. *
+* *
+* Description : Crée un point d'attache pour un lien entrant de boucle. *
+* *
+* Retour : Structure mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+incoming_link_t *create_incoming_loop_link(GGraphCluster *owner, const GdkPoint *midpts, leaving_link_t *other)
+{
+ incoming_link_t *result; /* Structure à retourner */
+ GCodeBlock *src; /* Bloc d'origine du lien */
+ GCodeBlock *dst; /* Bloc de destination du lien */
+
+ result = malloc(sizeof(incoming_link_t));
+
+ result->owner = owner;
+
+ result->type = ILT_LOOP;
+
+ src = g_graph_cluster_get_block(other->owner);
+ dst = g_graph_cluster_get_block(owner);
+
+ result->edge = g_graph_edge_new_loop(src, dst,
+ &other->start[0], &other->start[1],
+ &midpts[0], &midpts[1],
+ &result->end[0], &result->end[1]);
+
+ g_object_unref(G_OBJECT(src));
+ g_object_unref(G_OBJECT(dst));
+
+ result->other = other;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : link = structure à libérer de la mémoire. *
+* *
+* Description : Détruit un point d'attache pour un lien entrant. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void delete_incoming_link(incoming_link_t *link)
+{
+ free(link);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : a = premier lien entrant à comparer. *
+* b = second lien entrant à comparer. *
+* *
+* Description : Compare deux liens entrants. *
+* *
+* Retour : Bilan de comparaison. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+int cmp_incoming_links(const incoming_link_t **a, const incoming_link_t **b)
+{
+ int result; /* Bilan à retourner */
+ gint pos_a; /* Point de départ pour A */
+ gint pos_b; /* Point de départ pour B */
+
+ pos_a = compute_leaving_link_position((*a)->other);
+
+ pos_b = compute_leaving_link_position((*b)->other);
+
+ if (pos_a < pos_b)
+ result = -1;
+
+ else if (pos_a > pos_b)
+ result = 1;
+
+ else
+ result = 0;
+
+ return result;
+
+}
diff --git a/src/gtkext/graph/incoming.h b/src/gtkext/graph/incoming.h
new file mode 100644
index 0000000..d08eb46
--- /dev/null
+++ b/src/gtkext/graph/incoming.h
@@ -0,0 +1,67 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * incoming.h - prototypes pour les liens entrants d'un bloc de code dans une représentation graphique
+ *
+ * Copyright (C) 2019 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 <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _GTKEXT_GRAPH_INCOMING_H
+#define _GTKEXT_GRAPH_INCOMING_H
+
+
+#include "cluster.h"
+#include "edge.h"
+
+
+
+/* Depuis leaving.h : détails sur le départ d'un lien */
+typedef struct _leaving_link_t leaving_link_t;
+
+/* Définition du tracé d'un lien */
+typedef struct _incoming_link_t
+{
+ GGraphCluster *owner; /* Propriétaire du lien */
+
+ InstructionLinkType type; /* Complexité du tracé */
+
+ const size_t *hslot; /* Couche horizontale réservée */
+ GdkPoint end[2]; /* Point d'arrivée final */
+
+ GGraphEdge *edge; /* Lien complet en préparation */
+
+ leaving_link_t *other; /* Autre extrémité du lien */
+
+} incoming_link_t;
+
+
+/* Crée un point d'attache pour un lien entrant simple. */
+incoming_link_t *create_incoming_link(GGraphCluster *, InstructionLinkType, leaving_link_t *);
+
+/* Crée un point d'attache pour un lien entrant de boucle. */
+incoming_link_t *create_incoming_loop_link(GGraphCluster *, const GdkPoint *, leaving_link_t *);
+
+/* Détruit un point d'attache pour un lien entrant. */
+void delete_incoming_link(incoming_link_t *);
+
+/* Compare deux liens entrants. */
+int cmp_incoming_links(const incoming_link_t **, const incoming_link_t **);
+
+
+
+#endif /* _GTKEXT_GRAPH_INCOMING_H */
diff --git a/src/gtkext/graph/leaving.c b/src/gtkext/graph/leaving.c
new file mode 100644
index 0000000..ad07f04
--- /dev/null
+++ b/src/gtkext/graph/leaving.c
@@ -0,0 +1,107 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * leaving.c - liens sortants d'un bloc de code dans une représentation graphique
+ *
+ * Copyright (C) 2019 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 <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "leaving.h"
+
+
+#include <malloc.h>
+
+
+#include "cluster-int.h"
+#include "incoming.h"
+
+
+
+/******************************************************************************
+* *
+* Paramètres : owner = propriétaire du bloc de rattachement. *
+* index = indice dans les liens de sortie. *
+* *
+* Description : Crée un point d'attache pour un lien sortant. *
+* *
+* Retour : Structure mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+leaving_link_t *create_leaving_link(GGraphCluster *owner, size_t index)
+{
+ leaving_link_t *result; /* Structure à retourner */
+
+ result = malloc(sizeof(leaving_link_t));
+
+ result->owner = owner;
+
+ result->index = index;
+
+ result->straight = false;
+ result->forced_straight = false;
+ result->straight_level = SIZE_MAX;
+ result->cluster_exit = false;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : link = structure à libérer de la mémoire. *
+* *
+* Description : Détruit un point d'attache pour un lien sortant. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void delete_leaving_link(leaving_link_t *link)
+{
+ free(link);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : link = information sur un lien à consulter. *
+* *
+* Description : Calcule l'abscisse d'un lien à son départ d'un bloc. *
+* *
+* Retour : Abscisse à attribuer à un départ de lien. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+gint compute_leaving_link_position(const leaving_link_t *link)
+{
+ gint result; /* Position à retourner */
+
+ result = g_graph_cluster_compute_leaving_link_position(link->owner, link->index);
+
+ return result;
+
+}
diff --git a/src/gtkext/graph/leaving.h b/src/gtkext/graph/leaving.h
new file mode 100644
index 0000000..c91f232
--- /dev/null
+++ b/src/gtkext/graph/leaving.h
@@ -0,0 +1,66 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * leaving.h - prototypes pour les liens sortants d'un bloc de code dans une représentation graphique
+ *
+ * Copyright (C) 2019 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 <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _GTKEXT_GRAPH_LEAVING_H
+#define _GTKEXT_GRAPH_LEAVING_H
+
+
+#include "cluster.h"
+
+
+/* Depuis incoming.h : définition du tracé d'un lien */
+typedef struct _incoming_link_t incoming_link_t;
+
+/* Détails sur le départ d'un lien */
+typedef struct _leaving_link_t
+{
+ GGraphCluster *owner; /* Propriétaire du lien */
+
+ GdkPoint start[2]; /* Point de départ d'un lien */
+ size_t index; /* Indice sur ligne de départ */
+
+ bool straight; /* Présence d'une ligne droite */
+ bool forced_straight; /* Forçage de verticalité */
+ size_t straight_level; /* Rang atteint en ligne droite*/
+ bool cluster_exit; /* Sortie du cluster d'origine */
+
+ incoming_link_t *other; /* Autre extrémité du lien */
+
+} leaving_link_t;
+
+
+#define SHOULD_BE_VERTICAL(l) ((l)->straight || (l)->forced_straight || (l)->cluster_exit)
+
+
+/* Crée un point d'attache pour un lien sortant. */
+leaving_link_t *create_leaving_link(GGraphCluster *, size_t);
+
+/* Détruit un point d'attache pour un lien sortant. */
+void delete_leaving_link(leaving_link_t *);
+
+/* Calcule l'abscisse d'un lien à son départ d'un bloc. */
+gint compute_leaving_link_position(const leaving_link_t *);
+
+
+
+#endif /* _GTKEXT_GRAPH_LEAVING_H */
diff --git a/src/gtkext/graph/rank.c b/src/gtkext/graph/rank.c
new file mode 100644
index 0000000..0fadb27
--- /dev/null
+++ b/src/gtkext/graph/rank.c
@@ -0,0 +1,914 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * rank.c - classement par rang des descendants directs
+ *
+ * Copyright (C) 2019 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 <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "rank.h"
+
+
+#include <assert.h>
+#include <malloc.h>
+
+
+#include "cluster-int.h"
+
+
+
+/******************************************************************************
+* *
+* Paramètres : grank = structure à initialiser. [OUT] *
+* cluster = chef de file d'un ensemble de blocs. *
+* *
+* Description : Initialise la gestion d'un ensemble de blocs de même rang. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void init_graph_rank(graph_rank_t *grank, GGraphCluster *cluster)
+{
+ grank->right2left = NULL;
+ grank->r2l_count = 0;
+
+ grank->left2right = NULL;
+ grank->l2r_count = 0;
+
+ grank->clusters = malloc(sizeof(GGraphCluster *));
+ grank->count = 1;
+
+ grank->clusters[0] = cluster;
+
+ init_vspace_manager(&grank->vspaces);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : grank = structure à vider. *
+* *
+* Description : Termine la gestion d'un ensemble de blocs de même rang. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void exit_graph_rank(graph_rank_t *grank)
+{
+ size_t i; /* Boucle de parcours */
+
+ for (i = 0; i < grank->r2l_count; i++)
+ free(grank->right2left[i]);
+
+ if (grank->right2left != NULL)
+ free(grank->right2left);
+
+ for (i = 0; i < grank->l2r_count; i++)
+ free(grank->left2right[i]);
+
+ if (grank->left2right != NULL)
+ free(grank->left2right);
+
+ assert(grank->clusters != NULL);
+
+ free(grank->clusters);
+
+ exit_vspace_manager(&grank->vspaces);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : grank = ensemble de même rang à consulter. *
+* *
+* Description : Assigne à un ensemble de blocs un emplacement initial. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void reset_graph_rank_allocation(const graph_rank_t *grank)
+{
+ size_t i; /* Boucle de parcours */
+
+ for (i = 0; i < grank->count; i++)
+ g_graph_cluster_reset_allocation(grank->clusters[i]);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : grank = ensemble de même rang à consulter. *
+* *
+* Description : Fournit le rang d'un ensemble de blocs. *
+* *
+* Retour : Rang d'un ensemble de blocs de même rang. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+size_t get_graph_rank(const graph_rank_t *grank)
+{
+ size_t result; /* Rang à retourner */
+ GCodeBlock *block; /* Bloc de code de référence */
+
+ block = g_graph_cluster_get_block(grank->clusters[0]);
+
+ result = g_code_block_get_rank(block);
+
+ g_object_unref(G_OBJECT(block));
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : a = premier ensemble de même rang à comparer. *
+* b = second ensemble de même rang à comparer. *
+* *
+* Description : Compare deux rangées de blocs de code. *
+* *
+* Retour : Bilan de comparaison. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+int cmp_graph_rank(const graph_rank_t *a, const graph_rank_t *b)
+{
+ int result; /* Bilan à retourner */
+ size_t level_a; /* Niveau de l'ensemble A */
+ size_t level_b; /* Niveau de l'ensemble B */
+
+ level_a = get_graph_rank(a);
+ level_b = get_graph_rank(b);
+
+ if (level_a < level_b)
+ result = -1;
+
+ else if (level_a > level_b)
+ result = 1;
+
+ else
+ result = 0;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : grank = structure à compléter. *
+* cluster = chef de file d'un ensemble de blocs. *
+* *
+* Description : Etend un ensemble de blocs de même rang. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void extend_graph_rank(graph_rank_t *grank, GGraphCluster *cluster)
+{
+ grank->count++;
+ grank->clusters = realloc(grank->clusters, sizeof(GGraphCluster *) * grank->count);
+
+ grank->clusters[grank->count - 1] = cluster;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : grank = structure à compléter. *
+* cluster = chef de file d'un ensemble de blocs. *
+* *
+* Description : Détermine si un groupe de blocs contient un bloc particulier.*
+* *
+* Retour : true si le chef est bien contenu, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool has_graph_rank_cluster(const graph_rank_t *grank, GGraphCluster *cluster)
+{
+ bool result; /* Bilan à renvoyer */
+ size_t i; /* Boucle de parcours */
+
+ result = false;
+
+ for (i = 0; i < grank->count && !result; i++)
+ result = (grank->clusters[i] == cluster);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : grank = ensemble de descendants d'un même rang. *
+* from = point de départ du lien concerné. *
+* to = point d'arrivée du lien concerné. *
+* pts = points intermédiaires du tracé complet final. *
+* external = précise une sortie du cadre du cluster premier. *
+* *
+* Description : Inscrit à l'endroit idéal une réservation d'espace latéral. *
+* *
+* Retour : true si la demande a bien été traitée. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool extend_graph_rank_vspace_manager(graph_rank_t *grank, leaving_link_t *from, incoming_link_t *to, GdkPoint *pts, bool external)
+{
+ bool result; /* Bilan à renvoyer */
+
+ result = has_graph_rank_cluster(grank, from->owner);
+
+ if (result)
+ extend_vspace_manager(&grank->vspaces, from, to, pts, external);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : grank = ensemble de descendants d'un même rang. *
+* all = table regroupant tous les groupes créés. *
+* *
+* Description : Met en place les embryons de liens nécessaires. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void define_graph_rank_links(const graph_rank_t *grank, GHashTable *all)
+{
+ size_t i; /* Boucle de parcours */
+
+ for (i = 0; i < grank->count; i++)
+ g_graph_cluster_define_links(grank->clusters[i], all);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : grank = ensemble de descendants d'un même rang. *
+* *
+* Description : Repère les liens marquants à destination d'autres blocs. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void setup_graph_rank_links(const graph_rank_t *grank)
+{
+ size_t i; /* Boucle de parcours */
+
+ for (i = 0; i < grank->count; i++)
+ g_graph_cluster_setup_links(grank->clusters[i]);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : grank = ensemble de descendants d'un même rang. *
+* last = indique s'il s'agit du dernier étage de l'ensemble. *
+* alloc = emplacement idéal pour l'affichage. [OUT] *
+* *
+* Description : Détermine l'emplacement requis d'un ensemble de blocs. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void compute_graph_rank_needed_alloc(const graph_rank_t *grank, bool last, GtkAllocation *alloc)
+{
+ GtkAllocation needed; /* Taille requise */
+
+ switch (grank->count)
+ {
+ case 1:
+
+ g_graph_cluster_compute_needed_alloc(grank->clusters[0], &needed);
+
+ if (needed.x < alloc->x)
+ {
+ alloc->width += (alloc->x - needed.x);
+ alloc->x = needed.x;
+ }
+
+ if ((needed.x + needed.width) > (alloc->x + alloc->width))
+ alloc->width += needed.x + needed.width - alloc->x - alloc->width;
+
+ /* La hauteur maximale n'est présente qu'avec le dernier morceau */
+ if (last)
+ {
+ if ((needed.y + needed.height) > (alloc->y + alloc->height))
+ alloc->height += needed.y + needed.height - alloc->y - alloc->height;
+ }
+
+ break;
+
+ default:
+
+ assert(grank->count >= 2);
+
+ g_graph_cluster_compute_needed_alloc(grank->clusters[0], &needed);
+
+ if (needed.x < alloc->x)
+ {
+ alloc->width += (alloc->x - needed.x);
+ alloc->x = needed.x;
+ }
+
+ /* La hauteur maximale n'est présente qu'avec le dernier morceau */
+ if (last)
+ {
+ if ((needed.y + needed.height) > (alloc->y + alloc->height))
+ alloc->height += needed.y + needed.height - alloc->y - alloc->height;
+ }
+
+ g_graph_cluster_compute_needed_alloc(grank->clusters[grank->count - 1], &needed);
+
+ if ((needed.x + needed.width) > (alloc->x + alloc->width))
+ alloc->width += needed.x + needed.width - alloc->x - alloc->width;
+
+ /* La hauteur maximale n'est présente qu'avec le dernier morceau */
+ if (last)
+ {
+ if ((needed.y + needed.height) > (alloc->y + alloc->height))
+ alloc->height += needed.y + needed.height - alloc->y - alloc->height;
+ }
+
+ break;
+
+ }
+
+ compute_vspace_manager_needed_alloc(&grank->vspaces, false, alloc);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : iter = début de la boucle de parcours. *
+* loop = nombre d'itérations à mener. *
+* base = position de base sur l'axe des abscisses. *
+* dir = direction du parcours. *
+* *
+* Description : Affine l'abscisse d'un ensemble de blocs de même rang. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void _place_graph_rank_clusters(GGraphCluster **iter, size_t loop, gint base, int dir)
+{
+ size_t i; /* Boucle de parcours */
+ GtkAllocation needed; /* Taille requise */
+
+ assert(dir == -1 || dir == 1);
+
+ for (i = 0; i < loop; i++, iter += dir)
+ {
+ g_graph_cluster_dispatch_x(*iter);
+
+ g_graph_cluster_compute_needed_alloc(*iter, &needed);
+
+ if (dir > 0)
+ g_graph_cluster_offset_x(*iter, base - needed.x);
+ else
+ g_graph_cluster_offset_x(*iter, base - needed.x - needed.width);
+
+ base += dir * (needed.width + HORIZONTAL_MARGIN);
+
+ }
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : grank = ensemble de blocs de même rang à manipuler. *
+* *
+* Description : Organise la disposition d'un ensemble de blocs basiques. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void dispatch_x_graph_rank(const graph_rank_t *grank)
+{
+ size_t mid; /* Position centrale de départ */
+ GtkAllocation alloc; /* Emplacement de cluster */
+ gint start; /* Position initiale de départ */
+
+ if (grank->count % 2 == 1)
+ {
+ if (grank->count > 1)
+ {
+ mid = grank->count / 2;
+
+ g_graph_cluster_get_allocation(grank->clusters[mid], &alloc);
+
+ start = alloc.x - HORIZONTAL_MARGIN;
+
+ _place_graph_rank_clusters(grank->clusters + mid - 1, mid, start, -1);
+
+ start *= -1;
+
+ _place_graph_rank_clusters(grank->clusters + mid + 1, mid, start, 1);
+
+ }
+
+ else
+ g_graph_cluster_dispatch_x(grank->clusters[0]);
+
+ }
+
+ else
+ {
+ mid = grank->count / 2 - 1;
+
+ start = - HORIZONTAL_MARGIN / 2;
+
+ _place_graph_rank_clusters(grank->clusters + mid, mid + 1, start, -1);
+
+ start *= -1;
+
+ _place_graph_rank_clusters(grank->clusters + mid + 1, mid + 1, start, 1);
+
+ }
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : grank = ensemble de blocs de même rang à actualiser. *
+* *
+* Description : Réorganise au besoin les liens entrants un ensemble de blocs.*
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void sort_graph_rank_incoming_links(graph_rank_t *grank)
+{
+ size_t i; /* Boucle de parcours */
+
+ for (i = 0; i < grank->count; i++)
+ g_graph_cluster_sort_incoming_links(grank->clusters[i]);
+
+ sort_incoming_links_for_vspace_manager(&grank->vspaces);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : grank = ensemble de blocs de même rang à actualiser. *
+* *
+* Description : Réordonne les blocs sortant d'un ensemble. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void reorder_graph_rank_exit_blocks(graph_rank_t *grank)
+{
+ GGraphCluster **exit_2_left; /* Liste avec sortie à gauche */
+ GGraphCluster **exit_2_right; /* Liste avec sortie à droite */
+ GGraphCluster **no_exit; /* Liste sans sortie */
+ size_t count_2_left; /* Quantité de présents */
+ size_t count_2_right; /* Quantité de présents */
+ size_t count_no; /* Quantité de présents */
+ size_t i; /* Boucle de parcours */
+ bool l2r; /* Détermination de catégorie */
+
+ if (grank->count > 1)
+ {
+ exit_2_left = malloc(grank->count * sizeof(GGraphCluster *));
+ exit_2_right = malloc(grank->count * sizeof(GGraphCluster *));
+ no_exit = malloc(grank->count * sizeof(GGraphCluster *));
+
+ count_2_left = 0;
+ count_2_right = 0;
+ count_no = 0;
+
+ for (i = 0; i < grank->count; i++)
+ {
+ if (g_graph_cluster_has_exit_link(grank->clusters[i], &l2r))
+ {
+ if (l2r)
+ exit_2_right[count_2_right++] = grank->clusters[i];
+ else
+ exit_2_left[count_2_left++] = grank->clusters[i];
+ }
+ else
+ no_exit[count_no++] = grank->clusters[i];
+
+ }
+
+ assert((count_2_left + count_2_right + count_no) == grank->count);
+
+ qsort_r(exit_2_left, count_2_left, sizeof(GGraphCluster *),
+ (__compar_d_fn_t)g_graph_cluster_compare_by_exit, (bool []){ false });
+
+ qsort_r(exit_2_right, count_2_right, sizeof(GGraphCluster *),
+ (__compar_d_fn_t)g_graph_cluster_compare_by_exit, (bool []){ true });
+
+ grank->count = 0;
+
+ for (i = 0; i < count_2_left; i++)
+ grank->clusters[grank->count++] = exit_2_left[i];
+
+ for (i = 0; i < count_no; i++)
+ grank->clusters[grank->count++] = no_exit[i];
+
+ for (i = 0; i < count_2_right; i++)
+ grank->clusters[grank->count++] = exit_2_right[i];
+
+ }
+
+ for (i = 0; i < grank->count; i++)
+ g_graph_cluster_reorder_exit_blocks(grank->clusters[i]);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : grank = ensemble de blocs de même rang à actualiser. *
+* *
+* Description : Réordonne les blocs de départ de boucle d'un ensemble. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void reorder_graph_rank_loop_blocks(graph_rank_t *grank)
+{
+ size_t i; /* Boucle de parcours #1 */
+ size_t k; /* Boucle de parcours #2 */
+ GGraphCluster *tmp; /* Stockage temporaire */
+
+ for (i = 0; i < grank->count; i++)
+ g_graph_cluster_reorder_loop_blocks(grank->clusters[i]);
+
+ if (grank->count > 1)
+ {
+ /* Placement des départs de boucle à gauche ! */
+
+ for (i = 0; i < grank->vspaces.left_count; i++)
+ {
+ tmp = grank->vspaces.left[i]->from->owner;
+
+ for (k = 0; k < grank->count; k++)
+ if (grank->clusters[k] == tmp)
+ break;
+
+ assert(k < grank->count);
+
+ memmove(&grank->clusters[1], &grank->clusters[0],
+ k * sizeof(GGraphCluster *));
+
+ grank->clusters[0] = tmp;
+
+ g_graph_cluster_reorder_link_origins(tmp, true);
+
+ }
+
+ /* Placement des départs de boucle à droite ! */
+
+ for (i = 0; i < grank->vspaces.right_count; i++)
+ {
+ tmp = grank->vspaces.right[i]->from->owner;
+
+ for (k = 0; k < grank->count; k++)
+ if (grank->clusters[k] == tmp)
+ break;
+
+ assert(k < grank->count);
+
+ memmove(&grank->clusters[k], &grank->clusters[k + 1],
+ (grank->count - k - 1) * sizeof(GGraphCluster *));
+
+ grank->clusters[grank->count - 1] = tmp;
+
+ g_graph_cluster_reorder_link_origins(tmp, false);
+
+ }
+
+ }
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : grank = ensemble de blocs de même rang à actualiser. *
+* offset = décalage à appliquer. *
+* *
+* Description : Décale vers la droite un ensemble de blocs basiques. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void offset_x_graph_rank(graph_rank_t *grank, gint offset)
+{
+ size_t i; /* Boucle de parcours */
+
+ for (i = 0; i < grank->count; i++)
+ g_graph_cluster_offset_x(grank->clusters[i], offset);
+
+ offset_x_vspace_manager(&grank->vspaces, offset);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : grank = ensemble de blocs de même rang à actualiser. *
+* needed = espace nécessaire et alloué pour les blocs. *
+* *
+* Description : Détermine les abscisses des liens de boucle en place. *
+* *
+* Retour : Eventuelle marge à gauche devenue nécessaire. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+gint compute_loop_link_x_positions_with_graph_rank(const graph_rank_t *grank, const GtkAllocation *needed)
+{
+ gint result; /* Eventuelle marge à renvoyer */
+ size_t i; /* Boucle de parcours */
+
+ for (i = 0; i < grank->count; i++)
+ g_graph_cluster_compute_loop_link_x_positions(grank->clusters[i]);
+
+ result = compute_loop_link_x_with_vspace_manager(&grank->vspaces, needed, false);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : grank = ensemble de blocs de même rang à actualiser. *
+* base = position ordonnée à appliquer. *
+* *
+* Description : Décale vers le bas un ensemble de blocs basiques. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void set_y_for_graph_rank(const graph_rank_t *grank, gint *base)
+{
+ gint max; /* Hauteur maximale rencontrée */
+ size_t i; /* Boucle de parcours */
+ GGraphCluster *sub; /* Sous-ensemble traité */
+ GtkAllocation alloc; /* Allocation courante */
+
+ /* On ajoute l'espace vertical pour les lignes horizontales */
+
+ if (grank->r2l_count > grank->l2r_count)
+ max = grank->r2l_count;
+ else
+ max = grank->l2r_count;
+
+ *base += VERTICAL_MARGIN;
+
+ /**
+ * Comme les liens purement verticaux n'entrainent pas de réservation,
+ * il n'y a potentiellement pas toujours d'espace à ajouter.
+ */
+
+ if (max > 0)
+ {
+ *base += ((max - 1) * LINK_MARGIN);
+ *base += VERTICAL_MARGIN;
+ }
+
+ /* On ajoute l'espace requis pour l'affichage des blocs */
+
+ max = 0;
+
+ for (i = 0; i < grank->count; i++)
+ {
+ sub = grank->clusters[i];
+
+ g_graph_cluster_set_y(sub, *base);
+
+ g_graph_cluster_compute_needed_alloc(sub, &alloc);
+
+ if ((alloc.y + alloc.height) > max)
+ max = alloc.y + alloc.height;
+
+ }
+
+ *base = max;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : grank = ensemble de blocs de même rang à actualiser. *
+* needed = espace nécessaire et alloué pour les blocs. *
+* *
+* Description : Détermine les ordonnées de tous les liens en place. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void compute_loop_link_with_graph_rank(const graph_rank_t *grank, const GtkAllocation *needed)
+{
+ size_t i; /* Boucle de parcours */
+
+ for (i = 0; i < grank->count; i++)
+ g_graph_cluster_compute_link_y_positions(grank->clusters[i]);
+
+ compute_loop_link_y_with_vspace_manager(&grank->vspaces, needed);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : grank = ensemble de blocs de même rang à analyser. *
+* block = bloc de code à retrouver. *
+* *
+* Description : Recherche le groupe de blocs avec un bloc donné comme chef. *
+* *
+* Retour : Groupe trouvé ou NULL en cas d'échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GGraphCluster *find_cluster_by_block_in_graph_rank(const graph_rank_t *grank, GCodeBlock *block)
+{
+ GGraphCluster *result; /* Trouvaille à retourner */
+ size_t i; /* Boucle de parcours */
+
+ result = NULL;
+
+ for (i = 0; i < grank->count && result == NULL; i++)
+ result = g_graph_cluster_find_by_block(grank->clusters[i], block);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : grank = ensemble de blocs de même rang à analyser. *
+* widget = composant graphique à retrouver. *
+* *
+* Description : Recherche le groupe de blocs avec un composant comme chef. *
+* *
+* Retour : Groupe trouvé ou NULL en cas d'échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GGraphCluster *find_cluster_by_widget_in_graph_rank(const graph_rank_t *grank, GtkWidget *widget)
+{
+ GGraphCluster *result; /* Trouvaille à retourner */
+ size_t i; /* Boucle de parcours */
+
+ result = NULL;
+
+ for (i = 0; i < grank->count && result == NULL; i++)
+ result = g_graph_cluster_find_by_widget(grank->clusters[i], widget);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : grank = ensemble de blocs de même rang à analyser. *
+* list = liste en cours de constitution. [OUT] *
+* count = taille de cette liste. [OUT] *
+* *
+* Description : Collecte tous les chefs de file de blocs de code. *
+* *
+* Retour : Liste de graphiques de blocs rassemblés. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GGraphCluster **collect_graph_ranks_clusters(const graph_rank_t *grank, GGraphCluster **list, size_t *count)
+{
+ GGraphCluster **result; /* Liste complétée à renvoyer */
+ size_t i; /* Boucle de parcours */
+
+ result = list;
+
+ for (i = 0; i < grank->count; i++)
+ result = g_graph_cluster_collect(grank->clusters[i], result, count);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : grank = ensemble de blocs de même rang à analyser. *
+* list = liste en cours de constitution. [OUT] *
+* count = taille de cette liste. [OUT] *
+* *
+* Description : Collecte tous les liens de chefs de file de blocs de code. *
+* *
+* Retour : Liste de liens graphiques de blocs rassemblés. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GGraphEdge **collect_graph_ranks_cluster_edges(const graph_rank_t *grank, GGraphEdge **list, size_t *count)
+{
+ GGraphEdge **result; /* Liste complétée à renvoyer */
+ size_t i; /* Boucle de parcours */
+
+ result = list;
+
+ for (i = 0; i < grank->count; i++)
+ result = g_graph_cluster_collect_edges(grank->clusters[i], result, count);
+
+ return result;
+
+}
diff --git a/src/gtkext/graph/rank.h b/src/gtkext/graph/rank.h
new file mode 100644
index 0000000..1a149fc
--- /dev/null
+++ b/src/gtkext/graph/rank.h
@@ -0,0 +1,126 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * rank.h - prototypes pour le classement par rang des descendants directs
+ *
+ * Copyright (C) 2019 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 <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _GTKEXT_GRAPH_RANK_H
+#define _GTKEXT_GRAPH_RANK_H
+
+
+#include "cluster.h"
+#include "edge.h"
+#include "hspace.h"
+#include "vspace.h"
+
+
+
+/* Découpage vertical */
+typedef struct _graph_rank_t
+{
+ hspace_booking **right2left; /* Réservations de D -> G */
+ size_t r2l_count; /* Quantité de ces réservations*/
+
+ hspace_booking **left2right; /* Réservations de G -> D */
+ size_t l2r_count; /* Quantité de ces réservations*/
+
+ GGraphCluster **clusters; /* Ensembles de blocs */
+ size_t count; /* Nombre de ces ensembles */
+
+ vspace_manager_t vspaces; /* Gestion des liens latéraux */
+
+} graph_rank_t;
+
+
+/* Initialise la gestion d'un ensemble de blocs de même rang. */
+void init_graph_rank(graph_rank_t *, GGraphCluster *);
+
+/* Termine la gestion d'un ensemble de blocs de même rang. */
+void exit_graph_rank(graph_rank_t *);
+
+/* Assigne à un ensemble de blocs un emplacement initial. */
+void reset_graph_rank_allocation(const graph_rank_t *);
+
+/* Fournit le rang d'un ensemble de blocs. */
+size_t get_graph_rank(const graph_rank_t *);
+
+/* Compare deux rangées de blocs de code. */
+int cmp_graph_rank(const graph_rank_t *, const graph_rank_t *);
+
+/* Etend un ensemble de blocs de même rang. */
+void extend_graph_rank(graph_rank_t *, GGraphCluster *);
+
+/* Détermine si un groupe de blocs contient un bloc particulier. */
+bool has_graph_rank_cluster(const graph_rank_t *, GGraphCluster *);
+
+/* Inscrit à l'endroit idéal une réservation d'espace latéral. */
+bool extend_graph_rank_vspace_manager(graph_rank_t *, leaving_link_t *, incoming_link_t *, GdkPoint *, bool);
+
+/* Met en place les embryons de liens nécessaires. */
+void define_graph_rank_links(const graph_rank_t *, GHashTable *);
+
+/* Repère les liens marquants à destination d'autres blocs. */
+void setup_graph_rank_links(const graph_rank_t *);
+
+/* Détermine l'emplacement requis d'un ensemble de blocs. */
+void compute_graph_rank_needed_alloc(const graph_rank_t *, bool, GtkAllocation *);
+
+/* Affine l'abscisse d'un ensemble de blocs de même rang. */
+void _place_graph_rank_clusters(GGraphCluster **, size_t, gint, int);
+
+/* Organise la disposition d'un ensemble de blocs basiques. */
+void dispatch_x_graph_rank(const graph_rank_t *);
+
+/* Réorganise au besoin les liens entrants un ensemble de blocs. */
+void sort_graph_rank_incoming_links(graph_rank_t *);
+
+/* Réordonne les blocs sortant d'un ensemble. */
+void reorder_graph_rank_exit_blocks(graph_rank_t *);
+
+/* Réordonne les blocs de départ de boucle d'un ensemble. */
+void reorder_graph_rank_loop_blocks(graph_rank_t *);
+
+/* Décale vers la droite un ensemble de blocs basiques. */
+void offset_x_graph_rank(graph_rank_t *, gint);
+
+/* Détermine les abscisses des liens de boucle en place. */
+gint compute_loop_link_x_positions_with_graph_rank(const graph_rank_t *, const GtkAllocation *);
+
+/* Décale vers le bas un ensemble de blocs basiques. */
+void set_y_for_graph_rank(const graph_rank_t *, gint *);
+
+/* Détermine les ordonnées de tous les liens en place. */
+void compute_loop_link_with_graph_rank(const graph_rank_t *, const GtkAllocation *);
+
+/* Recherche le groupe de blocs avec un bloc donné comme chef. */
+GGraphCluster *find_cluster_by_block_in_graph_rank(const graph_rank_t *, GCodeBlock *);
+
+/* Recherche le groupe de blocs avec un composant comme chef. */
+GGraphCluster *find_cluster_by_widget_in_graph_rank(const graph_rank_t *, GtkWidget *);
+
+/* Collecte tous les chefs de file de blocs de code. */
+GGraphCluster **collect_graph_ranks_clusters(const graph_rank_t *, GGraphCluster **, size_t *);
+
+/* Collecte tous les liens de chefs de file de blocs de code. */
+GGraphEdge **collect_graph_ranks_cluster_edges(const graph_rank_t *, GGraphEdge **, size_t *);
+
+
+
+#endif /* _GTKEXT_GRAPH_RANK_H */
diff --git a/src/gtkext/graph/vspace.c b/src/gtkext/graph/vspace.c
new file mode 100644
index 0000000..8327759
--- /dev/null
+++ b/src/gtkext/graph/vspace.c
@@ -0,0 +1,374 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * vspace.c - encadrement des espaces verticaux réservés
+ *
+ * Copyright (C) 2019 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 <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "vspace.h"
+
+
+#include <malloc.h>
+
+
+#include "cluster-int.h"
+
+
+
+/******************************************************************************
+* *
+* Paramètres : manager = structure à initialiser. *
+* *
+* Description : Initialise les réservations liens verticaux. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void init_vspace_manager(vspace_manager_t *manager)
+{
+ manager->pending = NULL;
+ manager->pending_count = 0;
+
+ manager->left = NULL;
+ manager->left_count = 0;
+
+ manager->right = NULL;
+ manager->right_count = 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : manager = structure à vider. *
+* *
+* Description : Termine les réservations liens verticaux. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void exit_vspace_manager(vspace_manager_t *manager)
+{
+ size_t i; /* Boucle de parcours */
+
+ for (i = 0; i < manager->pending_count; i++)
+ free(manager->pending[i].pts);
+
+ if (manager->pending != NULL)
+ free(manager->pending);
+
+ if (manager->left != NULL)
+ free(manager->left);
+
+ if (manager->right != NULL)
+ free(manager->right);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : manager = structure à compléter. *
+* from = point de départ du lien concerné. *
+* to = point d'arrivée du lien concerné. *
+* pts = points intermédiaires du tracé complet final. *
+* external = précise une sortie du cadre du cluster premier. *
+* *
+* Description : Inscrit une nouvelle réservation d'espace latéral. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void extend_vspace_manager(vspace_manager_t *manager, leaving_link_t *from, incoming_link_t *to, GdkPoint *pts, bool external)
+{
+ vspace_booking_t *new; /* Réservation à constituer */
+
+ manager->pending = realloc(manager->pending, ++manager->pending_count * sizeof(vspace_booking_t));
+
+ new = &manager->pending[manager->pending_count - 1];
+
+ new->from = from;
+ new->to = to;
+
+ new->pts = pts;
+
+ new->external = external;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : manager = gestion des espaces latéraux à consulter. *
+* external = précise une sortie du cadre du cluster premier. *
+* alloc = emplacement idéal pour l'affichage. [OUT] *
+* *
+* Description : Détermine l'emplacement requis pour les espaces latéraux. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void compute_vspace_manager_needed_alloc(const vspace_manager_t *manager, bool external, GtkAllocation *alloc)
+{
+ gint width; /* Largeur supplémentaire */
+ size_t count; /* Nombre de liens retenus */
+ size_t i; /* Boucle de parcours */
+
+ width = 0;
+
+ /* Extension de la largeur, à gauche */
+
+ count = 0;
+
+ for (i = 0; i < manager->left_count; i++)
+ if (manager->left[i]->external == external)
+ count++;
+
+ width += count * LINK_MARGIN;
+
+ alloc->x -= width;
+
+ /* Extension de la largeur, à droite */
+
+ count = 0;
+
+ for (i = 0; i < manager->right_count; i++)
+ if (manager->right[i]->external == external)
+ count++;
+
+ width += count * LINK_MARGIN;
+
+ alloc->width += width;
+
+ /* Extension de la hauteur */
+
+ if (!external)
+ alloc->height += manager->pending_count * VERTICAL_MARGIN;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : manager = gestion d'espaces latéraux à manipuler. *
+* *
+* Description : Réorganise au besoin les liens de boucle entre blocs. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void sort_incoming_links_for_vspace_manager(vspace_manager_t *manager)
+{
+ size_t i; /* Boucle de parcours */
+ vspace_booking_t *pending; /* Elément traité */
+ gint x1; /* Abscisse de départ de lien */
+ size_t idx; /* Indice du lien entrant */
+ gint x2; /* Abscisse d'arrivée de lien */
+ bool for_left; /* Répartition par la gauche ? */
+
+ for (i = 0; i < manager->pending_count; i++)
+ {
+ pending = &manager->pending[i];
+
+ x1 = g_graph_cluster_compute_leaving_link_position(pending->from->owner, pending->from->index);
+
+ idx = g_graph_cluster_find_incoming_link(pending->to->owner, pending->from);
+
+ x2 = g_graph_cluster_compute_incoming_link_position(pending->to->owner, idx);
+
+ /**
+ * Prise en compte d'une boucle while (1);
+ */
+ if (pending->from->owner == pending->to->owner)
+ for_left = (x2 < x1);
+ else
+ for_left = (x1 < x2);
+
+ if (for_left)
+ {
+ manager->left = realloc(manager->left, ++manager->left_count * sizeof(vspace_booking_t *));
+ manager->left[manager->left_count - 1] = pending;
+ }
+ else
+ {
+ manager->right = realloc(manager->right, ++manager->right_count * sizeof(vspace_booking_t *));
+ manager->right[manager->right_count - 1] = pending;
+ }
+
+ }
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : manager = structure à actualiser. *
+* offset = décalage à appliquer. *
+* *
+* Description : Décale vers la droite un ensemble de points. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void offset_x_vspace_manager(vspace_manager_t *manager, gint offset)
+{
+ size_t i; /* Boucle de parcours */
+ vspace_booking_t *booking; /* Réservation à traiter */
+
+ for (i = 0; i < manager->left_count; i++)
+ {
+ booking = manager->left[i];
+
+ booking->pts[0].x += offset;
+ booking->pts[1].x += offset;
+
+ }
+
+ for (i = 0; i < manager->right_count; i++)
+ {
+ booking = manager->right[i];
+
+ booking->pts[0].x += offset;
+ booking->pts[1].x += offset;
+
+ }
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : manager = structure à consulter. *
+* needed = espace nécessaire et alloué pour les blocs. *
+* external = précise une sortie du cadre du cluster premier. *
+* *
+* Description : Détermine les abscisses de tous les liens en place. *
+* *
+* Retour : Eventuelle marge à gauche devenue nécessaire. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+gint compute_loop_link_x_with_vspace_manager(const vspace_manager_t *manager, const GtkAllocation *needed, bool external)
+{
+ gint result; /* Eventuelle marge à renvoyer */
+ size_t count; /* Quantité de liens traités */
+ size_t i; /* Boucle de parcours */
+ vspace_booking_t *booking; /* Réservation à traiter */
+ gint x; /* Position à appliquer */
+
+ count = 0;
+
+ for (i = 0; i < manager->left_count; i++)
+ {
+ booking = manager->left[i];
+
+ if (booking->external != external)
+ continue;
+
+ x = ++count * LINK_MARGIN;
+
+ booking->pts[0].x = needed->x - x;
+ booking->pts[1].x = needed->x - x;
+
+ }
+
+ result = count * LINK_MARGIN;
+
+ count = 0;
+
+ for (i = 0; i < manager->right_count; i++)
+ {
+ booking = manager->right[i];
+
+ if (booking->external != external)
+ continue;
+
+ x = ++count * LINK_MARGIN;
+
+ booking->pts[0].x = needed->x + needed->width + x;
+ booking->pts[1].x = needed->x + needed->width + x;
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : manager = structure à consulter. *
+* needed = espace nécessaire et alloué pour les blocs. *
+* *
+* Description : Détermine les ordonnées de tous les liens en place. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void compute_loop_link_y_with_vspace_manager(const vspace_manager_t *manager, const GtkAllocation *needed)
+{
+ gint real_bottom; /* Point de départ réel */
+ size_t i; /* Boucle de parcours */
+ vspace_booking_t *booking; /* Réservation à traiter */
+
+ real_bottom = needed->y + needed->height - manager->pending_count * VERTICAL_MARGIN;
+
+ for (i = 0; i < manager->pending_count; i++)
+ {
+ booking = &manager->pending[i];
+
+ /**
+ * On corrige le raccourci pris sans distinction de type de lien dans
+ * la fonction g_graph_cluster_compute_link_y_positions().
+ */
+
+ booking->from->start[1].y = real_bottom + (i + 1) * VERTICAL_MARGIN;
+
+ /* Définition de l'ordonnée des points du lien */
+
+ booking->pts[0].y = booking->from->start[1].y;
+
+ booking->pts[1].y = booking->to->end[0].y;
+
+ }
+
+}
diff --git a/src/gtkext/graph/vspace.h b/src/gtkext/graph/vspace.h
new file mode 100644
index 0000000..de83141
--- /dev/null
+++ b/src/gtkext/graph/vspace.h
@@ -0,0 +1,86 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * vspace.h - prototypes pour l'encadrement des espaces verticaux réservés
+ *
+ * Copyright (C) 2019 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 <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _GTKEXT_GRAPH_VSPACE_H
+#define _GTKEXT_GRAPH_VSPACE_H
+
+
+#include "incoming.h"
+#include "leaving.h"
+
+
+
+/* Réservations d'espaces latéraux */
+typedef struct _vspace_booking_t
+{
+ leaving_link_t *from; /* Bloc de départ du lien */
+ incoming_link_t *to; /* Bloc d'arrivée du lien */
+
+ GdkPoint *pts; /* Coordonnées des points */
+
+ bool external; /* Lien vers un cluster parent */
+
+} vspace_booking_t;
+
+/* Réservations d'espaces latéraux */
+typedef struct _vspace_manager_t
+{
+ vspace_booking_t *pending; /* Besoins exprimés */
+ size_t pending_count; /* Nombre de ces besoins */
+
+ vspace_booking_t **left; /* Lignes disposées à gauche */
+ size_t left_count; /* Quantité de ces lignes */
+
+ vspace_booking_t **right; /* Lignes disposées à droite */
+ size_t right_count; /* Quantité de ces lignes */
+
+} vspace_manager_t;
+
+
+/* Initialise les réservations liens verticaux. */
+void init_vspace_manager(vspace_manager_t *);
+
+/* Termine les réservations liens verticaux. */
+void exit_vspace_manager(vspace_manager_t *);
+
+/* Inscrit une nouvelle réservation d'espace latéral. */
+void extend_vspace_manager(vspace_manager_t *, leaving_link_t *, incoming_link_t *, GdkPoint *, bool);
+
+/* Détermine l'emplacement requis pour les espaces latéraux. */
+void compute_vspace_manager_needed_alloc(const vspace_manager_t *, bool, GtkAllocation *);
+
+/* Réorganise au besoin les liens de boucle entre blocs. */
+void sort_incoming_links_for_vspace_manager(vspace_manager_t *);
+
+/* Décale vers la droite un ensemble de points. */
+void offset_x_vspace_manager(vspace_manager_t *, gint);
+
+/* Détermine les abscisses de tous les liens en place. */
+gint compute_loop_link_x_with_vspace_manager(const vspace_manager_t *, const GtkAllocation *, bool);
+
+/* Détermine les ordonnées de tous les liens en place. */
+void compute_loop_link_y_with_vspace_manager(const vspace_manager_t *, const GtkAllocation *);
+
+
+
+#endif /* _GTKEXT_GRAPH_VSPACE_H */