diff options
Diffstat (limited to 'src/gtkext/graph')
-rw-r--r-- | src/gtkext/graph/cluster.c | 375 |
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); } |