summaryrefslogtreecommitdiff
path: root/src/gtkext/graph/cluster.c
diff options
context:
space:
mode:
authorCyrille Bagard <nocbos@gmail.com>2019-02-18 22:54:29 (GMT)
committerCyrille Bagard <nocbos@gmail.com>2019-02-18 22:54:29 (GMT)
commit8ff2fec3c71e156391304361631e0a306a4a9afd (patch)
tree77687ce585f16688ee8737bcca4e25706c81668e /src/gtkext/graph/cluster.c
parente87b3e8dbe619182d280c33bc7bed1c2913b7b0f (diff)
Saved some improvements for graph views.
Diffstat (limited to 'src/gtkext/graph/cluster.c')
-rw-r--r--src/gtkext/graph/cluster.c375
1 files 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);
}