summaryrefslogtreecommitdiff
path: root/src/gtkext/graph
diff options
context:
space:
mode:
authorCyrille Bagard <nocbos@gmail.com>2019-01-07 07:52:28 (GMT)
committerCyrille Bagard <nocbos@gmail.com>2019-01-07 07:52:28 (GMT)
commite363028265c5d1ab9905dee4128b8d998dad06b1 (patch)
treef59f50386ed3e2df2fcf2c8b72aa9086e3af18b2 /src/gtkext/graph
parent7b580bd991c5218b8c7d24fa0b396c380810cc73 (diff)
Improved links computation and handled loops in the graph layout.
Diffstat (limited to 'src/gtkext/graph')
-rw-r--r--src/gtkext/graph/cluster.c783
-rw-r--r--src/gtkext/graph/edge.c71
-rw-r--r--src/gtkext/graph/edge.h18
3 files changed, 732 insertions, 140 deletions
diff --git a/src/gtkext/graph/cluster.c b/src/gtkext/graph/cluster.c
index d21818a..8053e54 100644
--- a/src/gtkext/graph/cluster.c
+++ b/src/gtkext/graph/cluster.c
@@ -46,7 +46,7 @@ typedef struct _leaving_link_t
{
GGraphCluster *owner; /* Propriétés du lien */
- GdkPoint start; /* Point de départ d'un lien */
+ GdkPoint start[2]; /* Point de départ d'un lien */
size_t index; /* Indice sur ligne de départ */
} leaving_link_t;
@@ -74,21 +74,20 @@ typedef struct _incoming_link_t
InstructionLinkType type; /* Complexité du tracé */
const size_t *hslot; /* Couche horizontale réservée */
- GdkPoint y; /* Position des décrochages */
- GdkPoint end; /* Point d'arrivée final */
+ GdkPoint end[2]; /* Point d'arrivée final */
GGraphEdge *edge; /* Lien complet en préparation */
- const leaving_link_t *other; /* Autre extrémité du lien */
+ leaving_link_t *other; /* Autre extrémité du lien */
} incoming_link_t;
/* Crée un point d'attache pour un lien entrant simple. */
-static incoming_link_t *create_incoming_link(GGraphCluster *, InstructionLinkType, const leaving_link_t *);
+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 leaving_link_t *);
+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 *);
@@ -141,6 +140,9 @@ 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 *);
@@ -165,6 +167,9 @@ 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(const graph_rank_t *);
+
/* Décale vers la droite un ensemble de blocs basiques. */
static void offset_x_graph_rank(const graph_rank_t *, gint);
@@ -182,7 +187,7 @@ 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[2]; /* Coordonnées des points */
+ GdkPoint *pts; /* Coordonnées des points */
} vspace_booking_t;
@@ -207,6 +212,21 @@ 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 *);
+
+/* Détermine l'emplacement requis pour les espaces latéraux. */
+static void compute_vspace_manager_needed_alloc(const vspace_manager_t *, bool, bool, GtkAllocation *);
+
+/* Réorganise au besoin les liens de boucle entre blocs. */
+static void sort_incoming_links_for_vspace_manager(vspace_manager_t *);
+
+/* Détermine les abscisses de tous les liens en place. */
+static void compute_loop_link_x_with_vspace_manager(vspace_manager_t *, bool, GGraphCluster *);
+
+/* Détermine les ordonnées de tous les liens en place. */
+static void compute_loop_link_y_with_vspace_manager(vspace_manager_t *, GGraphCluster *);
+
/* -------------------------- DEFINITION D'UN CHEF DE FILE -------------------------- */
@@ -217,6 +237,7 @@ struct _GGraphCluster
{
GObject parent; /* A laisser en premier */
+ GGraphCluster *owner; /* Ensemble lié parent */
size_t *parent_index; /* Indice du lien au départ */
////////////////////////////////////////
@@ -277,6 +298,9 @@ 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 *);
@@ -286,22 +310,30 @@ static void g_graph_cluster_define_links(GGraphCluster *, GHashTable *);
/* 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é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);
-
-
-
-
-/* Recherche le bloc basique à l'extrémité d'un lien. */
-//static GGraphCluster *g_graph_cluster_find_lower_dest_cluster(const GGraphCluster *, const GArchInstruction *);
+/* 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);
+
+/* 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 *);
@@ -428,7 +460,7 @@ static gint compute_leaving_link_position(const leaving_link_t *link)
* *
******************************************************************************/
-static incoming_link_t *create_incoming_link(GGraphCluster *owner, InstructionLinkType type, const leaving_link_t *other)
+static incoming_link_t *create_incoming_link(GGraphCluster *owner, InstructionLinkType type, leaving_link_t *other)
{
incoming_link_t *result; /* Structure à retourner */
@@ -439,13 +471,13 @@ static incoming_link_t *create_incoming_link(GGraphCluster *owner, InstructionLi
result->type = type;
if (type == ILT_JUMP_IF_TRUE)
- result->edge = g_graph_edge_new_true(&other->start, &result->y, &result->end);
+ result->edge = g_graph_edge_new_true(&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(&other->start, &result->y, &result->end);
+ result->edge = g_graph_edge_new_false(&other->start[0], &other->start[1], &result->end[0], &result->end[1]);
else
- result->edge = g_graph_edge_new(&other->start, &result->y, &result->end);
+ result->edge = g_graph_edge_new(&other->start[0], &other->start[1], &result->end[0], &result->end[1]);
result->other = other;
@@ -467,7 +499,7 @@ static incoming_link_t *create_incoming_link(GGraphCluster *owner, InstructionLi
* *
******************************************************************************/
-static incoming_link_t *create_incoming_loop_link(GGraphCluster *owner, const leaving_link_t *other)
+static incoming_link_t *create_incoming_loop_link(GGraphCluster *owner, const GdkPoint *midpts, leaving_link_t *other)
{
incoming_link_t *result; /* Structure à retourner */
@@ -477,7 +509,9 @@ static incoming_link_t *create_incoming_loop_link(GGraphCluster *owner, const le
result->type = ILT_LOOP;
- result->edge = g_graph_edge_new_loop(&other->start, &other->start, &result->y, &result->end);
+ result->edge = g_graph_edge_new_loop(&other->start[0], &other->start[1],
+ &midpts[0], &midpts[1],
+ &result->end[0], &result->end[1]);
result->other = other;
@@ -709,6 +743,28 @@ static void exit_graph_rank(graph_rank_t *grank)
* *
* 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. *
@@ -925,6 +981,39 @@ static void compute_graph_rank_needed_alloc(const graph_rank_t *grank, bool last
/******************************************************************************
* *
+* Paramètres : grank = ensemble de descendants d'un même rang. *
+* *
+* Description : Indique si un espace horizontal final est prévu en bas. *
+* *
+* Retour : true si l'étage comporte une zone pour liens de boucle. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool has_graph_rank_ending_vspace(const graph_rank_t *grank)
+{
+ bool result; /* Bilan à retourner */
+ size_t i; /* Boucle de parcours */
+ GGraphCluster *cluster; /* Bloc à analyser */
+
+ result = false;
+
+ for (i = 0; i < grank->count && !result; i++)
+ {
+ cluster = grank->clusters[i];
+
+ result = (cluster->vspaces.pending_count > 0);
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
* 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. *
@@ -1021,6 +1110,28 @@ static void dispatch_x_graph_rank(const graph_rank_t *grank)
/******************************************************************************
* *
* 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(const 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]);
+
+}
+
+
+/******************************************************************************
+* *
+* 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. *
@@ -1149,6 +1260,11 @@ static void init_vspace_manager(vspace_manager_t *manager)
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);
@@ -1161,6 +1277,261 @@ static void exit_vspace_manager(vspace_manager_t *manager)
}
+/******************************************************************************
+* *
+* 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. *
+* *
+* 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)
+{
+ 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;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : manager = gestion des espaces latéraux à consulter. *
+* top = le bloc courant est-il le principal ? *
+* concat = la zone inférieuse s'ajoute à une similaire ? *
+* 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 top, bool concat, GtkAllocation *alloc)
+{
+ gint width; /* Largeur supplémentaire */
+
+ /* Extension de la largeur */
+
+ width = 0;
+
+ if (manager->left_count > 0)
+ {
+ if (!top)
+ width += HORIZONTAL_MARGIN;
+
+ width += (manager->left_count - 1) * LINK_MARGIN;
+
+ width += HORIZONTAL_MARGIN;
+
+ }
+
+ if (manager->right_count > 0)
+ {
+ width += HORIZONTAL_MARGIN;
+
+ width += (manager->right_count - 1) * LINK_MARGIN;
+
+ if (!top)
+ width += HORIZONTAL_MARGIN;
+
+ }
+
+ alloc->x -= width / 2;
+ alloc->width += width;
+
+ /* Extension de la hauteur */
+
+ if (manager->pending_count > 0)
+ {
+ if (!concat)
+ alloc->height += VERTICAL_MARGIN;
+
+ alloc->height += (manager->pending_count - 1) * LINK_MARGIN;
+
+ alloc->height += 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 */
+
+ 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);
+
+ if (x1 < x2)
+ {
+ 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 à consulter. *
+* top = le bloc courant est-il le principal ? *
+* cluster = graphique de blocs sur lequel s'appuyer. *
+* *
+* Description : Détermine les abscisses de tous les liens en place. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void compute_loop_link_x_with_vspace_manager(vspace_manager_t *manager, bool top, GGraphCluster *cluster)
+{
+ GtkAllocation needed; /* Espace nécessaire et alloué */
+ size_t i; /* Boucle de parcours */
+ vspace_booking_t *booking; /* Réservation à traiter */
+ gint x; /* Position à appliquer */
+
+ g_graph_cluster_compute_needed_alloc(cluster, &needed);
+
+ for (i = 0; i < manager->left_count; i++)
+ {
+ booking = manager->left[i];
+
+ x = i * LINK_MARGIN;
+
+ if (!top)
+ x += HORIZONTAL_MARGIN;
+
+ booking->pts[0].x = needed.x + x;
+ booking->pts[1].x = needed.x + x;
+
+ }
+
+ if (manager->left_count > 0)
+ {
+ if (!top)
+ x = HORIZONTAL_MARGIN;
+ else
+ x = 0;
+
+ x += (manager->left_count - 1) * LINK_MARGIN;
+
+ x += HORIZONTAL_MARGIN;
+
+ /**
+ * Si la routine est une boucle sans fin,
+ * alors la boucle peut renvoyer vers le premier bloc.
+ */
+ if (cluster->owner != NULL)
+ g_graph_cluster_offset_x(cluster->owner, x);
+
+ }
+
+ for (i = 0; i < manager->right_count; i++)
+ {
+ booking = manager->right[i];
+
+ x = HORIZONTAL_MARGIN + i * LINK_MARGIN;
+
+ booking->pts[0].x = x;
+ booking->pts[1].x = x;
+
+ }
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : manager = structure à consulter. *
+* cluster = graphique de blocs sur lequel s'appuyer. *
+* *
+* Description : Détermine les ordonnées de tous les liens en place. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void compute_loop_link_y_with_vspace_manager(vspace_manager_t *manager, GGraphCluster *cluster)
+{
+ GtkAllocation needed; /* Espace nécessaire et alloué */
+ size_t i; /* Boucle de parcours */
+ vspace_booking_t *booking; /* Réservation à traiter */
+
+ g_graph_cluster_compute_needed_alloc(cluster, &needed);
+
+ 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 = needed.y + needed.height - 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;
+
+ }
+
+}
+
+
/* ---------------------------------------------------------------------------------- */
/* DEFINITION D'UN CHEF DE FILE */
@@ -1295,7 +1666,6 @@ GGraphCluster *g_graph_cluster_new(GCodeBlock *block, segcnt_list *highlighted,
{
GGraphCluster *result; /* Structure à retourner */
GBufferView *view; /* Partie affichée du tampon */
- GtkRequisition requisition; /* Taille à l'écran actuelle */
result = g_object_new(G_TYPE_GRAPH_CLUSTER, NULL);
@@ -1315,17 +1685,44 @@ GGraphCluster *g_graph_cluster_new(GCodeBlock *block, segcnt_list *highlighted,
gtk_display_panel_show_border(GTK_DISPLAY_PANEL(result->display), true);
+ g_graph_cluster_reset_allocation(result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : cluster = graphique de blocs à compléter. *
+* *
+* Description : Assigne à un bloc et son ensemble un emplacement initial. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_graph_cluster_reset_allocation(GGraphCluster *cluster)
+{
+ GtkRequisition requisition; /* Taille à l'écran actuelle */
+ size_t i; /* Boucle de parcours */
+
/* Détermination d'une position initiale centrée */
- gtk_widget_get_preferred_size(result->display, NULL, &requisition);
+ gtk_widget_get_preferred_size(cluster->display, NULL, &requisition);
- result->alloc.x = -requisition.width / 2;
- result->alloc.y = 0;
+ cluster->alloc.x = -requisition.width / 2;
+ cluster->alloc.y = 0;
- result->alloc.width = requisition.width;
- result->alloc.height = requisition.height;
+ cluster->alloc.width = requisition.width;
+ cluster->alloc.height = requisition.height;
- return result;
+ /* Propagation aux sous-blocs */
+
+ for (i = 0; i < cluster->ranks_count; i++)
+ reset_graph_rank_allocation(&cluster->ranks[i]);
}
@@ -1367,6 +1764,8 @@ static void g_graph_cluster_add_sub(GGraphCluster *cluster, GGraphCluster *sub)
else
extend_graph_rank(&cluster->ranks[i], sub);
+ sub->owner = cluster;
+
}
@@ -1391,6 +1790,7 @@ static void g_graph_cluster_define_links(GGraphCluster *cluster, GHashTable *all
GGraphCluster *target; /* Bloc ciblé par un lien */
leaving_link_t *leaving; /* Point de départ d'un lien */
incoming_link_t *incoming; /* Définitions d'arrivée */
+ GdkPoint *midpts; /* Points intermédiaires */
size_t j; /* Boucle de parcours #2 */
/* Au niveau du bloc courant */
@@ -1455,13 +1855,20 @@ static void g_graph_cluster_define_links(GGraphCluster *cluster, GHashTable *all
/* Point d'arrivée */
- incoming = create_incoming_loop_link(target, leaving);
+ midpts = malloc(2 * sizeof(GdkPoint));
+ midpts = calloc(2, sizeof(GdkPoint));//////////////// REMME
+
+ incoming = create_incoming_loop_link(target, midpts, leaving);
target->top_anchors = realloc(target->top_anchors,
++target->ta_count * sizeof(incoming_link_t *));
target->top_anchors[target->ta_count - 1] = incoming;
+ /* Réservation d'un espace latéral */
+
+ extend_vspace_manager(&target->vspaces, leaving, incoming, midpts);
+
/* Etablissement d'un embryon de lien */
for (j = 0; j < cluster->ranks_count; j++)
@@ -1483,8 +1890,30 @@ static void g_graph_cluster_define_links(GGraphCluster *cluster, GHashTable *all
+ /* Doit-on forcer un lien strictement vertical ? */
+
+ if (cluster->ba_count == 1)
+ {
+ assert(!cluster->has_straight);
+
+ /**
+ * Attention : les boucles aussi ont un seul lien sortant !
+ *
+ * S'il n'y a qu'un seul lien, on peut s'appuyer sur la variable 'incoming'
+ * manipulée dans la boucle : c'est forcément elle qui a été mise en place.
+ *
+ * Même chose pour 'target'.
+ */
+ if (incoming->type != ILT_LOOP)
+ {
+ cluster->has_straight = true;
+ cluster->straight_level = g_code_block_get_rank(target->block);
+ cluster->straight_index = 0;
+ }
+
+ }
- /* Déplacement d'un éventuel lien central */
+ /* Déplacement d'un éventuel lien central en position centrale */
if (cluster->has_straight)
{
@@ -1559,6 +1988,9 @@ static void g_graph_cluster_dispatch_x(GGraphCluster *cluster)
const graph_rank_t *rank; /* Accès confortable au rang */
size_t j; /* Boucle de parcours #2 */
gint start; /* Position initiale de départ */
+ GGraphCluster *target; /* Unique sous-bloc visé */
+ size_t idx; /* Indice du lien entrant */
+ gint end; /* Position initiale d'arrivée */
/**
* A ce point, tous les blocs parents sont placés.
@@ -1567,13 +1999,12 @@ static void g_graph_cluster_dispatch_x(GGraphCluster *cluster)
* de la gauche ne doit pas arriver tout à droite !
*/
- qsort(cluster->top_anchors, cluster->ta_count, sizeof(incoming_link_t *), (__compar_fn_t)cmp_incoming_links);
+ //qsort(cluster->top_anchors, cluster->ta_count, sizeof(incoming_link_t *), (__compar_fn_t)cmp_incoming_links);
/**
* Il est désormais temps de placer tous les blocs de code inférieurs.
*/
-
for (k = 0; k < cluster->ranks_count; k++)
{
rank = &cluster->ranks[k];
@@ -1607,6 +2038,32 @@ static void g_graph_cluster_dispatch_x(GGraphCluster *cluster)
}
+ else if (get_graph_rank(rank) == cluster->straight_level)
+ {
+ /**
+ * Si le bloc pointé en direct a plus d'un lien en entrée (comme
+ * dans le cas d'un bloc qui assure un début de boucle par exemple),
+ * le lien direct n'est pas centré sur le milieu de ce bloc pointé.
+ *
+ * On corrige ici le léger décalage.
+ */
+ assert(rank->count == 1);
+
+ target = rank->clusters[0];
+
+ idx = g_graph_cluster_find_incoming_link(target, cluster->bottom_anchors[cluster->straight_index]);
+
+ end = g_graph_cluster_compute_incoming_link_position(target, idx);
+
+ g_graph_cluster_offset_x(target, start - end);
+
+ dispatch_x_graph_rank(rank);
+
+ }
+
+ else
+ dispatch_x_graph_rank(rank);
+
}
/* Répartition homogène */
@@ -1620,6 +2077,60 @@ static void g_graph_cluster_dispatch_x(GGraphCluster *cluster)
/******************************************************************************
* *
+* Paramètres : cluster = graphique de blocs à manipuler. *
+* *
+* Description : Réorganise au besoin les liens entrants d'un bloc. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_graph_cluster_sort_incoming_links(GGraphCluster *cluster)
+{
+ size_t i; /* Boucle de parcours */
+
+ qsort(cluster->top_anchors, cluster->ta_count, sizeof(incoming_link_t *), (__compar_fn_t)cmp_incoming_links);
+
+ for (i = 0; i < cluster->ranks_count; i++)
+ sort_graph_rank_incoming_links(&cluster->ranks[i]);
+
+ sort_incoming_links_for_vspace_manager(&cluster->vspaces);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : cluster = graphique de blocs à consulter. *
+* incoming = adresse de l'autre bout du lien concerné. *
+* *
+* Description : Retrouve l'indice d'un lien entrant donné pour un bloc. *
+* *
+* Retour : Indice à priori toujours valide. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static size_t g_graph_cluster_find_incoming_link(const GGraphCluster *cluster, const leaving_link_t *leaving)
+{
+ size_t result; /* Indice à retourner */
+
+ for (result = 0; result < cluster->ta_count; result++)
+ if (cluster->top_anchors[result]->other == leaving)
+ break;
+
+ assert(cluster->ta_count);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
* Paramètres : cluster = graphique de blocs à actualiser. *
* offset = décalage à appliquer. *
* *
@@ -1686,12 +2197,23 @@ static void g_graph_cluster_set_y(GGraphCluster *cluster, gint base)
void g_graph_cluster_compute_needed_alloc(const GGraphCluster *cluster, GtkAllocation *alloc)
{
size_t i; /* Boucle de parcours */
+ size_t level; /* Niveau du nouvel ensemble */
+ bool concat; /* Redondance des espaces ? */
*alloc = cluster->alloc;
for (i = 0; i < cluster->ranks_count; i++)
compute_graph_rank_needed_alloc(&cluster->ranks[i], (i + 1) == cluster->ranks_count, alloc);
+ level = g_code_block_get_rank(cluster->block);
+
+ if (cluster->ranks_count == 0)
+ concat = false;
+ else
+ concat = has_graph_rank_ending_vspace(&cluster->ranks[cluster->ranks_count - 1]);
+
+ compute_vspace_manager_needed_alloc(&cluster->vspaces, level == 0, concat, alloc);
+
}
@@ -1754,62 +2276,86 @@ void g_graph_cluster_place(GGraphCluster *cluster, GtkGraphDisplay *display)
}
+/******************************************************************************
+* *
+* Paramètres : cluster = graphique de blocs à consulter. *
+* index = indice du lien à considérer. *
+* half = moitié du nombre de liens en présence. *
+* odd = le nombre de liens considérés est-il impair ? *
+* *
+* Description : Calcule l'abscisse d'un lien pour un bloc. *
+* *
+* Retour : Abscisse à attribuer au lien. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static 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 */
+ mid_x = cluster->alloc.x + (cluster->alloc.width / 2);
+ if (odd)
+ {
+ if (index < half)
+ result = mid_x - (half - index) * LINK_MARGIN;
+ else if (index == half)
+ result = mid_x;
+ else
+ result = mid_x + (index - half) * LINK_MARGIN;
+ }
-//////////////////////////////////////////////////////////
+ else
+ {
+ if (index < half)
+ result = mid_x - LINK_MARGIN / 2 - (half - index - 1) * LINK_MARGIN;
+ else
+ result = mid_x + LINK_MARGIN / 2 + (index - half) * LINK_MARGIN;
+ }
+ return result;
+}
/******************************************************************************
* *
-* Paramètres : cluster = graphique de blocs à consulter ou remonter. *
-* first = première instruction du bloc basique recherché. *
+* Paramètres : cluster = graphique de blocs à consulter. *
+* index = indice du lien à considérer. *
* *
-* Description : Recherche le bloc basique à l'extrémité d'un lien. *
+* Description : Calcule l'abscisse d'un lien à son départ d'un bloc. *
* *
-* Retour : Bloc graphique de destination pour un lien ou NULL si échec. *
+* Retour : Abscisse à attribuer à un départ de lien. *
* *
* Remarques : - *
* *
******************************************************************************/
-#if 0
-static GGraphCluster *g_graph_cluster_find_lower_dest_cluster(const GGraphCluster *cluster, const GArchInstruction *first)
-{
- GGraphCluster *result; /* Trouvaille à retourner */
- size_t i; /* Boucle de parcours #1 */
- const graph_rank_t *rank; /* Confort d'accès */
- size_t j; /* Boucle de parcours #2 */
- GArchInstruction *instr; /* Instruction à comparer */
- result = NULL;
-
- for (i = 0; i < cluster->ranks_count && result == NULL; i++)
- {
- rank = &cluster->ranks[i];
+static 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 */
+ bool odd; /* Partité du nombre de liens */
- for (j = 0; j < rank->count && result == NULL; j++)
- {
- g_basic_block_get_boundaries(rank->clusters[j]->block, &instr, NULL);
+ assert(index < cluster->ba_count);
- if (instr == first)
- result = rank->clusters[j];
+ half = cluster->ba_count / 2;
- }
+ odd = (cluster->ba_count % 2 == 1);
- }
+ result = _g_graph_cluster_compute_link_position(cluster, index, half, odd);
return result;
}
-#endif
-
/******************************************************************************
@@ -1817,50 +2363,59 @@ static GGraphCluster *g_graph_cluster_find_lower_dest_cluster(const GGraphCluste
* Paramètres : cluster = graphique de blocs à consulter. *
* index = indice du lien à considérer. *
* *
-* Description : Calcule l'abscisse d'un lien à son départ d'un bloc. *
+* Description : Calcule l'abscisse d'un lien à son arrivée à un bloc. *
* *
-* Retour : Abscisse à attribuer à un départ de lien. *
+* Retour : Abscisse à attribuer à une arrivée de lien. *
* *
* Remarques : - *
* *
******************************************************************************/
-static gint g_graph_cluster_compute_leaving_link_position(const GGraphCluster *cluster, size_t index)
+static gint g_graph_cluster_compute_incoming_link_position(const GGraphCluster *cluster, size_t index)
{
gint result; /* Position à retourner */
- gint mid_x; /* Abscisse centrale */
size_t half; /* Indice de répartition égale */
+ bool odd; /* Partité du nombre de liens */
- assert(index < cluster->ba_count);
+ assert(index < cluster->ta_count);
- mid_x = cluster->alloc.x + (cluster->alloc.width / 2);
+ half = cluster->ta_count / 2;
- half = cluster->ba_count / 2;
+ odd = (cluster->ta_count % 2 == 1);
- if (cluster->ba_count % 2 == 1)
- {
- if (index < half)
- result = mid_x - (half - index) * LINK_MARGIN;
+ result = _g_graph_cluster_compute_link_position(cluster, index, half, odd);
- else if (index == half)
- result = mid_x;
+ return result;
- else
- result = mid_x + (index - half) * LINK_MARGIN;
+}
- }
- else
- {
- if (index < half)
- result = mid_x - LINK_MARGIN / 2 - (half - index - 1) * LINK_MARGIN;
+/******************************************************************************
+* *
+* Paramètres : cluster = graphique de blocs à actualiser. *
+* *
+* Description : Détermine les abscisses des liens de boucle en place. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
- else
- result = mid_x + LINK_MARGIN / 2 + (index - half) * LINK_MARGIN;
+static void g_graph_cluster_compute_loop_link_x_positions(GGraphCluster *cluster)
+{
+ size_t i; /* Boucle de parcours #1 */
+ size_t j; /* Boucle de parcours #2 */
- }
+ /* Liens de boucle */
- return result;
+ compute_loop_link_x_with_vspace_manager(&cluster->vspaces, false /* FIXME */, cluster);
+
+ /* Propagation des déterminations */
+
+ for (i = 0; i < cluster->ranks_count; i++)
+ for (j = 0; j < cluster->ranks[i].count; j++)
+ g_graph_cluster_compute_loop_link_x_positions(cluster->ranks[i].clusters[j]);
}
@@ -1892,10 +2447,12 @@ static void g_graph_cluster_compute_link_x_positions(GGraphCluster *cluster)
if (cluster->ba_count > 0)
for (i = 0; i < cluster->ba_count; i++)
{
- pt = &cluster->bottom_anchors[i]->start;
+ pt = &cluster->bottom_anchors[i]->start[0];
pt->x = g_graph_cluster_compute_leaving_link_position(cluster, i);
+ cluster->bottom_anchors[i]->start[1].x = pt->x;
+
}
/* Du côté des arrivées... */
@@ -1908,17 +2465,17 @@ static void g_graph_cluster_compute_link_x_positions(GGraphCluster *cluster)
{
for (i = half; i > 0; i--)
{
- pt = &cluster->top_anchors[i - 1]->end;
+ pt = &cluster->top_anchors[i - 1]->end[1];
pt->x = mid_x - (half - i + 1) * LINK_MARGIN;
}
- cluster->top_anchors[half]->end.x = mid_x;
+ cluster->top_anchors[half]->end[1].x = mid_x;
for (i = half + 1; i < cluster->ta_count; i++)
{
- pt = &cluster->top_anchors[i]->end;
+ pt = &cluster->top_anchors[i]->end[1];
pt->x = mid_x + (i - half) * LINK_MARGIN;
@@ -1930,7 +2487,7 @@ static void g_graph_cluster_compute_link_x_positions(GGraphCluster *cluster)
{
for (i = half; i > 0; i--)
{
- pt = &cluster->top_anchors[i - 1]->end;
+ pt = &cluster->top_anchors[i - 1]->end[1];
pt->x = mid_x - LINK_MARGIN / 2 - (half - i) * LINK_MARGIN;
@@ -1938,7 +2495,7 @@ static void g_graph_cluster_compute_link_x_positions(GGraphCluster *cluster)
for (i = half; i < cluster->ta_count; i++)
{
- pt = &cluster->top_anchors[i]->end;
+ pt = &cluster->top_anchors[i]->end[1];
pt->x = mid_x + LINK_MARGIN / 2 + (half - i) * LINK_MARGIN;
@@ -1948,6 +2505,9 @@ static void g_graph_cluster_compute_link_x_positions(GGraphCluster *cluster)
}
+ for (i = 0; i < cluster->ta_count; i++)
+ cluster->top_anchors[i]->end[0].x = cluster->top_anchors[i]->end[1].x;
+
/* Propagation des déterminations */
for (i = 0; i < cluster->ranks_count; i++)
@@ -2058,7 +2618,7 @@ static void g_graph_cluster_compute_link_y_positions(GGraphCluster *cluster)
y = cluster->alloc.y + cluster->alloc.height;
for (i = 0; i < cluster->ba_count; i++)
- cluster->bottom_anchors[i]->start.y = y;
+ cluster->bottom_anchors[i]->start[0].y = y;
}
@@ -2072,17 +2632,23 @@ static void g_graph_cluster_compute_link_y_positions(GGraphCluster *cluster)
{
incoming = cluster->top_anchors[i];
- incoming->end.y = y;
+ incoming->end[1].y = y;
- incoming->y.y = incoming->end.y - VERTICAL_MARGIN;
+ incoming->end[0].y = incoming->end[1].y - VERTICAL_MARGIN;
if (incoming->hslot != NULL)
- incoming->y.y -= *incoming->hslot * LINK_MARGIN;
+ incoming->end[0].y -= *incoming->hslot * LINK_MARGIN;
+
+ incoming->other->start[1].y = incoming->end[0].y;
}
}
+ /* Définition des liens de boucle */
+
+ compute_loop_link_y_with_vspace_manager(&cluster->vspaces, cluster);
+
/* Propagation des déterminations */
for (i = 0; i < cluster->ranks_count; i++)
@@ -2326,6 +2892,26 @@ GGraphCluster *bootstrap_graph_cluster(GLoadedBinary *binary, const GBlockList *
g_graph_cluster_dispatch_x(result);
+ /**
+ * A ce point, tous les blocs sont placés.
+ * On est donc en mesure de réorganiser les points d'arrivée
+ * des liens afin d'éviter les croisements : un lien qui vient
+ * de la gauche ne doit pas arriver tout à droite !
+ *
+ * Cette consigne est valable pour les liens de boucle également, dont
+ * l'origine est toujours dans un bloc inférieur au bloc de destination.
+ * Le premier étant traité après le second, cela oblige à appeler
+ * g_graph_cluster_dispatch_x() deux fois donc, car on ne peut effectuer
+ * le tri des liens au début de cette fonction comme c'était fait
+ * dans les premières versions du code.
+ */
+
+ g_graph_cluster_sort_incoming_links(result);
+
+ g_graph_cluster_reset_allocation(result);
+
+ g_graph_cluster_dispatch_x(result);
+
/* Réajustement vers la droite */
g_graph_cluster_compute_needed_alloc(result, &needed);
@@ -2334,6 +2920,21 @@ GGraphCluster *bootstrap_graph_cluster(GLoadedBinary *binary, const GBlockList *
/* Application finale sur les liens */
+ /**
+ * Comme g_graph_cluster_offset_x() n'agit que sur les abscisses et non sur
+ * les largeurs, on ne peut pas définir les positions pour les liens de boucle
+ * en amont et les décaler ensuite.
+ *
+ * Et comme la mise en place de ce type de lien peut déplacer le bloc parent,
+ * ses repères pour ses propres liens peuvent être décaler. Il faut ainsi
+ * une procédure distincte de g_graph_cluster_compute_link_x_positions().
+ *
+ * On définit donc l'abscisse de ces liens ici, en redécalant encore un peu
+ * les blocs au besoin.
+ */
+
+ g_graph_cluster_compute_loop_link_x_positions(result);
+
g_graph_cluster_compute_link_x_positions(result);
g_graph_cluster_book_hspace_for_links(result);
diff --git a/src/gtkext/graph/edge.c b/src/gtkext/graph/edge.c
index c07c6c5..e3844f3 100644
--- a/src/gtkext/graph/edge.c
+++ b/src/gtkext/graph/edge.c
@@ -38,12 +38,11 @@ struct _GGraphEdge
EdgeColor color; /* Couleur du rendu */
- const GdkPoint *start; /* Point de départ du lien */
- GdkPoint *mid[2]; /* Etapes intermédiaires */
- size_t m_count; /* Quantité de ces étapes */
- const GdkPoint *end; /* Point d'arrivée du lien */
-
- GdkPoint *points; /* Points de la ligne dessinée */
+ union
+ {
+ const GdkPoint **templates; /* Inspirations de coordonnées */
+ GdkPoint *points; /* Points de la ligne dessinée */
+ };
size_t count; /* Quantité de ces points */
};
@@ -157,8 +156,7 @@ static void g_graph_edge_dispose(GGraphEdge *edge)
static void g_graph_edge_finalize(GGraphEdge *edge)
{
- if (edge->points != NULL)
- free(edge->points);
+ free(edge->points);
G_OBJECT_CLASS(g_graph_edge_parent_class)->finalize(G_OBJECT(edge));
@@ -167,11 +165,9 @@ static void g_graph_edge_finalize(GGraphEdge *edge)
/******************************************************************************
* *
-* Paramètres : start = point de départ de la flêche. *
-* mid = points intermédiares variables. *
-* count = nombre de ces points fournis. *
-* end = point d'arrivée de la flêche. *
-* color = couleur de rendu à l'écran. *
+* Paramètres : templates = coordonnées des futurs points. *
+* count = nombre de ces points fournis. *
+* color = couleur de rendu à l'écran. *
* *
* Description : Etablit un lien graphique entre deux noeuds graphiques. *
* *
@@ -181,7 +177,7 @@ static void g_graph_edge_finalize(GGraphEdge *edge)
* *
******************************************************************************/
-GGraphEdge *_g_graph_edge_new(const GdkPoint *start, const GdkPoint **mid, size_t count, const GdkPoint *end, EdgeColor color)
+GGraphEdge *_g_graph_edge_new(const GdkPoint **templates, size_t count, EdgeColor color)
{
GGraphEdge *result; /* Structure à retourner */
@@ -189,16 +185,14 @@ GGraphEdge *_g_graph_edge_new(const GdkPoint *start, const GdkPoint **mid, size_
result->color = color;
- assert(count == 1 || count == 2);
+ assert(count == 4 || count == 6);
- result->start = start;
+ result->templates = malloc(count * sizeof(GdkPoint *));
+ memcpy(result->templates, templates, count * sizeof(GdkPoint *));
- memcpy(result->mid, mid, count * sizeof(GdkPoint));
- result->m_count = count;
+ result->count = count;
- result->end = end;
-
- return G_GRAPH_EDGE(result);
+ return result;
}
@@ -219,8 +213,14 @@ GGraphEdge *_g_graph_edge_new(const GdkPoint *start, const GdkPoint **mid, size_
void g_graph_edge_get_x_borders(const GGraphEdge *edge, gint *x1, gint *x2)
{
- *x1 = edge->start->x;
- *x2 = edge->end->x;
+ /**
+ * A l'appel de cette fonction, les informations des points n'ont
+ * pas encore été fixées ni recopiées.
+ */
+
+ *x1 = edge->templates[0]->x;
+ *x2 = edge->templates[edge->count - 1]->x;
+
}
@@ -238,29 +238,20 @@ void g_graph_edge_get_x_borders(const GGraphEdge *edge, gint *x1, gint *x2)
void g_graph_edge_resolve(GGraphEdge *edge)
{
- edge->count = 2 + 2 * edge->m_count;
- edge->points = (GdkPoint *)calloc(edge->count, sizeof(GdkPoint));
+ const GdkPoint **templates; /* Inspirations de coordonnées */
+ size_t i; /* Boucle de parcours */
- edge->points[0] = *edge->start;
+ templates = edge->templates;
- edge->points[1].x = edge->start->x;
- edge->points[1].y = edge->mid[0]->y;
+ edge->points = malloc(edge->count * sizeof(GdkPoint));
- if (edge->m_count == 1)
- {
- edge->points[2].x = edge->end->x;
- edge->points[2].y = edge->mid[0]->y;
- }
- else
+ for (i = 0; i < edge->count; i++)
{
- memcpy(&edge->points[2], edge->mid, edge->m_count * sizeof(GdkPoint));
-
- edge->points[4].x = edge->end->x;
- edge->points[4].y = edge->mid[3]->y;
-
+ edge->points[i].x = templates[i]->x;
+ edge->points[i].y = templates[i]->y;
}
- edge->points[edge->count - 1] = *edge->end;
+ free(templates);
}
diff --git a/src/gtkext/graph/edge.h b/src/gtkext/graph/edge.h
index d000eb5..23fcf8d 100644
--- a/src/gtkext/graph/edge.h
+++ b/src/gtkext/graph/edge.h
@@ -64,19 +64,19 @@ typedef enum _EdgeColor
GType g_graph_edge_get_type(void);
/* Etablit un lien graphique entre deux noeuds graphiques. */
-GGraphEdge *_g_graph_edge_new(const GdkPoint *, const GdkPoint **, size_t, const GdkPoint *, EdgeColor);
+GGraphEdge *_g_graph_edge_new(const GdkPoint **, size_t, EdgeColor);
-#define g_graph_edge_new(start, y, end) \
- _g_graph_edge_new(start, (const GdkPoint *[]) { y }, 1, end, EGC_DEFAULT)
+#define g_graph_edge_new(pts0, pts1, pte0, pte1) \
+ _g_graph_edge_new((const GdkPoint *[]) { pts0, pts1, pte0, pte1 }, 4, EGC_DEFAULT)
-#define g_graph_edge_new_true(start, y, end) \
- _g_graph_edge_new(start, (const GdkPoint *[]) { y }, 1, end, EGC_GREEN)
+#define g_graph_edge_new_true(pts0, pts1, pte0, pte1) \
+ _g_graph_edge_new((const GdkPoint *[]) { pts0, pts1, pte0, pte1 }, 4, EGC_GREEN)
-#define g_graph_edge_new_false(start, y, end) \
- _g_graph_edge_new(start, (const GdkPoint *[]) { y }, 1, end, EGC_RED)
+#define g_graph_edge_new_false(pts0, pts1, pte0, pte1) \
+ _g_graph_edge_new((const GdkPoint *[]) { pts0, pts1, pte0, pte1 }, 4, EGC_RED)
-#define g_graph_edge_new_loop(start, yt, yb, end) \
- _g_graph_edge_new(start, (const GdkPoint *[]) { yt, yb }, 2, end, EGC_BLUE)
+#define g_graph_edge_new_loop(pts0, pts1, ptl0, ptl1, pte0, pte1) \
+ _g_graph_edge_new((const GdkPoint *[]) { pts0, pts1, ptl0, ptl1, pte0, pte1 }, 6, EGC_BLUE)
/* Fournit les abscisses des points extrèmes de la ligne. */
void g_graph_edge_get_x_borders(const GGraphEdge *, gint *, gint *);