From 8ff2fec3c71e156391304361631e0a306a4a9afd Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Mon, 18 Feb 2019 23:54:29 +0100
Subject: Saved some improvements for graph views.

---
 src/gtkext/graph/cluster.c | 375 +++++++++++++++++++++++++++++++++++++--------
 1 file changed, 307 insertions(+), 68 deletions(-)

diff --git a/src/gtkext/graph/cluster.c b/src/gtkext/graph/cluster.c
index 16afe57..51d73c7 100644
--- a/src/gtkext/graph/cluster.c
+++ b/src/gtkext/graph/cluster.c
@@ -140,11 +140,14 @@ static void compute_vspace_manager_needed_alloc(const vspace_manager_t *, GtkAll
 /* 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 void compute_loop_link_x_with_vspace_manager(vspace_manager_t *, GGraphCluster *);
+static gint compute_loop_link_x_with_vspace_manager(const vspace_manager_t *, const GtkAllocation *);
 
 /* Détermine les ordonnées de tous les liens en place. */
-static void compute_loop_link_y_with_vspace_manager(vspace_manager_t *, GGraphCluster *);
+static void compute_loop_link_y_with_vspace_manager(const vspace_manager_t *, const GtkAllocation *);
 
 
 
@@ -182,6 +185,8 @@ typedef struct _graph_rank_t
     GGraphCluster **clusters;               /* Ensembles de blocs          */
     size_t count;                           /* Nombre de ces ensembles     */
 
+    vspace_manager_t vspaces;               /* Gestion des liens latéraux  */
+
 } graph_rank_t;
 
 
@@ -206,6 +211,9 @@ 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 *);
 
+/* 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 *);
+
 /* Détermine l'emplacement requis d'un ensemble de blocs. */
 static void compute_graph_rank_needed_alloc(const graph_rank_t *, bool, GtkAllocation *);
 
@@ -216,14 +224,20 @@ static void _place_graph_rank_clusters(GGraphCluster **, size_t, gint, int);
 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 *);
+static void sort_graph_rank_incoming_links(graph_rank_t *);
 
 /* Décale vers la droite un ensemble de blocs basiques. */
-static void offset_x_graph_rank(const graph_rank_t *, gint);
+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 *);
+
 
 
 /* -------------------------- DEFINITION D'UN CHEF DE FILE -------------------------- */
@@ -301,6 +315,9 @@ static void g_graph_cluster_add_sub(GGraphCluster *, GGraphCluster *);
 /* Etablit les connexions entre blocs selon les rangs. */
 static void g_graph_cluster_setup_link_for_target(GGraphCluster *, GGraphCluster *, leaving_link_t *);
 
+/* 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 *);
 
@@ -328,6 +345,9 @@ static gint g_graph_cluster_compute_leaving_link_position(const GGraphCluster *,
 /* 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 *);
 
@@ -707,9 +727,10 @@ static void compute_vspace_manager_needed_alloc(const vspace_manager_t *manager,
 
     width += manager->left_count * LINK_MARGIN;
 
+    alloc->x -= width;
+
     width += manager->right_count * LINK_MARGIN;
 
-    alloc->x -= width / 2;
     alloc->width += width;
 
     /* Extension de la hauteur */
@@ -738,6 +759,7 @@ static void sort_incoming_links_for_vspace_manager(vspace_manager_t *manager)
     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++)
     {
@@ -749,7 +771,15 @@ static void sort_incoming_links_for_vspace_manager(vspace_manager_t *manager)
 
         x2 = g_graph_cluster_compute_incoming_link_position(pending->to->owner, idx);
 
-        if (x1 < x2)
+        /**
+         * 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;
@@ -767,10 +797,10 @@ static void sort_incoming_links_for_vspace_manager(vspace_manager_t *manager)
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : manager = structure à consulter.                             *
-*                cluster = graphique de blocs sur lequel s'appuyer.           *
+*  Paramètres  : manager = structure à actualiser.                            *
+*                offset = décalage à appliquer.                               *
 *                                                                             *
-*  Description : Détermine les abscisses de tous les liens en place.          *
+*  Description : Décale vers la droite un ensemble de points.                 *
 *                                                                             *
 *  Retour      : -                                                            *
 *                                                                             *
@@ -778,59 +808,60 @@ static void sort_incoming_links_for_vspace_manager(vspace_manager_t *manager)
 *                                                                             *
 ******************************************************************************/
 
-static void compute_loop_link_x_with_vspace_manager(vspace_manager_t *manager, GGraphCluster *cluster)
+static void offset_x_vspace_manager(vspace_manager_t *manager, gint offset)
 {
-    GtkAllocation needed;                   /* Espace nécessaire et alloué */
     size_t i;                               /* Boucle de parcours          */
     vspace_booking_t *booking;              /* Réservation à traiter       */
-    gint x;                                 /* Position à appliquer        */
-    GGraphCluster *container;               /* Parent direct à décaler     */
-
-    g_graph_cluster_compute_needed_alloc(cluster, &needed);
 
     for (i = 0; i < manager->left_count; i++)
     {
         booking = manager->left[i];
 
-        x = i * LINK_MARGIN;
-
-        booking->pts[0].x = needed.x + x;
-        booking->pts[1].x = needed.x + x;
+        booking->pts[0].x += offset;
+        booking->pts[1].x += offset;
 
     }
 
-    if (manager->left_count > 0)
+    for (i = 0; i < manager->right_count; i++)
     {
-        x = manager->left_count * LINK_MARGIN;
+        booking = manager->right[i];
 
-        /**
-         * Si la routine est une boucle sans fin,
-         * alors la boucle peut renvoyer vers le premier bloc.
-         */
-        if (cluster->owner != NULL)
-        {
-            container = cluster->owner;
+        booking->pts[0].x += offset;
+        booking->pts[1].x += offset;
 
-            /**
-             * On recherche le plus haut propritétaire bénéficiant d'une chaîne
-             * de liens directs et droits, histoire de transmettre le décalage
-             * et de garder ces liens bien verticaux.
-             */
-            while (container->owner != NULL)
-            {
-                if (!container->owner->has_straight)
-                    break;
+    }
 
-                if (container->owner->straight_index != *container->parent_index)
-                    break;
+}
 
-                container = container->owner;
 
-            }
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : manager = structure à consulter.                             *
+*                needed  = espace nécessaire et alloué pour les blocs.        *
+*                                                                             *
+*  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)
+{
+    gint result;                            /* Eventuelle marge à renvoyer */
+    size_t i;                               /* Boucle de parcours          */
+    vspace_booking_t *booking;              /* Réservation à traiter       */
+    gint x;                                 /* Position à appliquer        */
+
+    for (i = 0; i < manager->left_count; i++)
+    {
+        booking = manager->left[i];
 
-            g_graph_cluster_offset_x(container, x);
+        x = (i + 1) * LINK_MARGIN;
 
-        }
+        booking->pts[0].x = needed->x - x;
+        booking->pts[1].x = needed->x - x;
 
     }
 
@@ -840,18 +871,22 @@ static void compute_loop_link_x_with_vspace_manager(vspace_manager_t *manager, G
 
         x = (i + 1) * LINK_MARGIN;
 
-        booking->pts[0].x = x;
-        booking->pts[1].x = x;
+        booking->pts[0].x = needed->x + needed->width + x;
+        booking->pts[1].x = needed->x + needed->width + x;
 
     }
 
+    result = manager->left_count * LINK_MARGIN;
+
+    return result;
+
 }
 
 
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : manager = structure à consulter.                             *
-*                cluster = graphique de blocs sur lequel s'appuyer.           *
+*                needed  = espace nécessaire et alloué pour les blocs.        *
 *                                                                             *
 *  Description : Détermine les ordonnées de tous les liens en place.          *
 *                                                                             *
@@ -861,13 +896,13 @@ static void compute_loop_link_x_with_vspace_manager(vspace_manager_t *manager, G
 *                                                                             *
 ******************************************************************************/
 
-static void compute_loop_link_y_with_vspace_manager(vspace_manager_t *manager, GGraphCluster *cluster)
+static void compute_loop_link_y_with_vspace_manager(const vspace_manager_t *manager, const GtkAllocation *needed)
 {
-    GtkAllocation needed;                   /* Espace nécessaire et alloué */
+    gint real_bottom;                       /* Point de départ réel        */
     size_t i;                               /* Boucle de parcours          */
     vspace_booking_t *booking;              /* Réservation à traiter       */
 
-    g_graph_cluster_compute_needed_alloc(cluster, &needed);
+    real_bottom = needed->y + needed->height - manager->pending_count * VERTICAL_MARGIN;
 
     for (i = 0; i < manager->pending_count; i++)
     {
@@ -878,7 +913,7 @@ static void compute_loop_link_y_with_vspace_manager(vspace_manager_t *manager, G
          * la fonction g_graph_cluster_compute_link_y_positions().
          */
 
-        booking->from->start[1].y = needed.y + needed.height;
+        booking->from->start[1].y = real_bottom +  (i + 1) * VERTICAL_MARGIN;
 
         /* Définition de l'ordonnée des points du lien */
 
@@ -1016,6 +1051,8 @@ static void init_graph_rank(graph_rank_t *grank, GGraphCluster *cluster)
 
     grank->clusters[0] = cluster;
 
+    init_vspace_manager(&grank->vspaces);
+
 }
 
 
@@ -1051,6 +1088,8 @@ static void exit_graph_rank(graph_rank_t *grank)
 
     free(grank->clusters);
 
+    exit_vspace_manager(&grank->vspaces);
+
 }
 
 
@@ -1161,6 +1200,39 @@ static void extend_graph_rank(graph_rank_t *grank, GGraphCluster *cluster)
 /******************************************************************************
 *                                                                             *
 *  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.        *
+*                                                                             *
+*  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 result;                            /* Bilan à renvoyer            */
+    size_t i;                               /* Boucle de parcours          */
+
+    result = false;
+
+    for (i = 0; i < grank->count && !result; i++)
+        result = (grank->clusters[i] == from->owner);
+
+    if (result)
+        extend_vspace_manager(&grank->vspaces, from, to, pts);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  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]            *
 *                                                                             *
@@ -1235,6 +1307,8 @@ static void compute_graph_rank_needed_alloc(const graph_rank_t *grank, bool last
 
     }
 
+    compute_vspace_manager_needed_alloc(&grank->vspaces, alloc);
+
 }
 
 
@@ -1345,13 +1419,15 @@ static void dispatch_x_graph_rank(const graph_rank_t *grank)
 *                                                                             *
 ******************************************************************************/
 
-static void sort_graph_rank_incoming_links(const graph_rank_t *grank)
+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);
+
 }
 
 
@@ -1368,13 +1444,43 @@ static void sort_graph_rank_incoming_links(const graph_rank_t *grank)
 *                                                                             *
 ******************************************************************************/
 
-static void offset_x_graph_rank(const graph_rank_t *grank, gint offset)
+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);
+
+    return result;
+
 }
 
 
@@ -1440,6 +1546,31 @@ static void set_y_for_graph_rank(const graph_rank_t *grank, gint *base)
 }
 
 
+/******************************************************************************
+*                                                                             *
+*  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 #1       */
+
+    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);
+
+}
+
+
 
 /* ---------------------------------------------------------------------------------- */
 /*                            DEFINITION D'UN CHEF DE FILE                            */
@@ -1720,6 +1851,40 @@ static void g_graph_cluster_setup_link_for_target(GGraphCluster *source, GGraphC
 
 /******************************************************************************
 *                                                                             *
+*  Paramètres  : target = 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.       *
+*                                                                             *
+*  Description : Inscrit à l'endroit idéal une réservation d'espace latéral.  *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_graph_cluster_extend_vspace_manager(GGraphCluster *target, leaving_link_t *from, incoming_link_t *to, GdkPoint *pts)
+{
+    bool done;                              /* Bilan des traitements       */
+    size_t i;                               /* Boucle de parcours          */
+
+    assert(target == to->owner);
+
+    done = false;
+
+    for (i = 0; i < target->ranks_count && !done; i++)
+        done = extend_graph_rank_vspace_manager(&target->ranks[i], from, to, pts);
+
+    if (!done)
+        extend_vspace_manager(&target->vspaces, from, to, pts);
+
+}
+
+
+
+/******************************************************************************
+*                                                                             *
 *  Paramètres  : cluster = graphique de blocs à actualiser.                   *
 *                all     = table regroupant tous les groupes créés.           *
 *                                                                             *
@@ -1813,7 +1978,7 @@ static void g_graph_cluster_define_links(GGraphCluster *cluster, GHashTable *all
 
                 /* Réservation d'un espace latéral */
 
-                extend_vspace_manager(&target->vspaces, leaving, incoming, midpts);
+                g_graph_cluster_extend_vspace_manager(target, leaving, incoming, midpts);
 
                 /* Etablissement d'un embryon de lien */
 
@@ -2083,6 +2248,8 @@ static void g_graph_cluster_offset_x(GGraphCluster *cluster, gint offset)
     for (i = 0; i < cluster->ranks_count; i++)
         offset_x_graph_rank(&cluster->ranks[i], offset);
 
+    offset_x_vspace_manager(&cluster->vspaces, offset);
+
 }
 
 
@@ -2316,6 +2483,59 @@ static gint g_graph_cluster_compute_incoming_link_position(const GGraphCluster *
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : cluster = graphique de blocs à actualiser.                   *
+*                margin  = espace nécessaire à gauche aux liens de boucle.    *
+*                                                                             *
+*  Description : Ajoute une marge à gauche pour les liens remontants.         *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_graph_cluster_insert_left_margin(GGraphCluster *cluster, gint margin)
+{
+    GGraphCluster *container;               /* Parent direct à décaler     */
+
+    if (margin > 0)
+    {
+        /**
+         * Si la routine est une boucle sans fin,
+         * alors la boucle peut renvoyer vers le premier bloc.
+         */
+        if (cluster->owner != NULL)
+        {
+            container = cluster->owner;
+
+            /**
+             * On recherche le plus haut propritétaire bénéficiant d'une chaîne
+             * de liens directs et droits, histoire de transmettre le décalage
+             * et de garder ces liens bien verticaux.
+             */
+            while (container->owner != NULL)
+            {
+                if (!container->owner->has_straight)
+                    break;
+
+                if (container->owner->straight_index != *container->parent_index)
+                    break;
+
+                container = container->owner;
+
+            }
+
+            g_graph_cluster_offset_x(container, margin);
+
+        }
+
+    }
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : cluster = graphique de blocs à actualiser.                   *
 *                                                                             *
 *  Description : Détermine les abscisses des liens de boucle en place.        *
 *                                                                             *
@@ -2327,18 +2547,31 @@ static gint g_graph_cluster_compute_incoming_link_position(const GGraphCluster *
 
 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       */
+    GtkAllocation alloc;                    /* Emplacement à faire évoluer */
+    gint margin;                            /* Marge à gauche éventuelle   */
+    size_t i;                               /* Boucle de parcours          */
+
+    /* Propagation des déterminations */
+
+    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);
+
+        margin = compute_loop_link_x_positions_with_graph_rank(&cluster->ranks[i], &alloc);
+
+        g_graph_cluster_insert_left_margin(cluster, margin);
+
+    }
 
     /* Liens de boucle */
 
-    compute_loop_link_x_with_vspace_manager(&cluster->vspaces, cluster);
+    g_graph_cluster_compute_needed_alloc(cluster, &alloc);
 
-    /* Propagation des déterminations */
+    margin = compute_loop_link_x_with_vspace_manager(&cluster->vspaces, &alloc);
 
-    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]);
+    g_graph_cluster_insert_left_margin(cluster, margin);
 
 }
 
@@ -2530,9 +2763,9 @@ static void g_graph_cluster_book_hspace_for_links(GGraphCluster *cluster)
 static void g_graph_cluster_compute_link_y_positions(GGraphCluster *cluster)
 {
     gint y;                                 /* Ordonnée d'application      */
-    size_t i;                               /* Boucle de parcours #1       */
+    size_t i;                               /* Boucle de parcours          */
     incoming_link_t *incoming;              /* Raccourci pour le confort   */
-    size_t j;                               /* Boucle de parcours #2       */
+    GtkAllocation alloc;                    /* Emplacement à faire évoluer */
 
     /* Du côté des départs... */
 
@@ -2568,15 +2801,21 @@ static void g_graph_cluster_compute_link_y_positions(GGraphCluster *cluster)
 
     }
 
-    /* Définition des liens de boucle */
-
-    compute_loop_link_y_with_vspace_manager(&cluster->vspaces, cluster);
-
     /* Propagation des déterminations */
 
+    alloc = cluster->alloc;
+
     for (i = 0; i < cluster->ranks_count; i++)
-        for (j = 0; j < cluster->ranks[i].count; j++)
-            g_graph_cluster_compute_link_y_positions(cluster->ranks[i].clusters[j]);
+    {
+        compute_graph_rank_needed_alloc(&cluster->ranks[i], (i + 1) == cluster->ranks_count, &alloc);
+        compute_loop_link_with_graph_rank(&cluster->ranks[i], &alloc);
+    }
+
+    /* Définition des liens de boucle */
+
+    g_graph_cluster_compute_needed_alloc(cluster, &alloc);
+
+    compute_loop_link_y_with_vspace_manager(&cluster->vspaces, &alloc);
 
 }
 
-- 
cgit v0.11.2-87-g4458