diff options
author | Cyrille Bagard <nocbos@gmail.com> | 2013-08-17 21:54:56 (GMT) |
---|---|---|
committer | Cyrille Bagard <nocbos@gmail.com> | 2013-08-17 21:54:56 (GMT) |
commit | e53684bebd74d0a8ade79082c618ebb21bdea361 (patch) | |
tree | 1a9e772134f2fea48ec06c78de1d2ceaef6b69ad /src/gtkext/graph/nodes/virtual.c | |
parent | a7d77562cd63f6cf0856b4cc19e245072af86f69 (diff) |
Replaced some parts of the graph computing for better results.
git-svn-id: svn://svn.gna.org/svn/chrysalide/trunk@356 abbe820e-26c8-41b2-8c08-b7b2b41f8b0a
Diffstat (limited to 'src/gtkext/graph/nodes/virtual.c')
-rw-r--r-- | src/gtkext/graph/nodes/virtual.c | 480 |
1 files changed, 270 insertions, 210 deletions
diff --git a/src/gtkext/graph/nodes/virtual.c b/src/gtkext/graph/nodes/virtual.c index 05a7063..48cc1fb 100644 --- a/src/gtkext/graph/nodes/virtual.c +++ b/src/gtkext/graph/nodes/virtual.c @@ -67,6 +67,16 @@ static void extend_vertical_links_spans(vert_links *, const reserved_vspan *); /* ---------------------- REPRESENTATIONS DES GROUPES LOGIQUES ---------------------- */ +/* Représentation d'un étage */ +typedef struct _virtual_level +{ + unsigned int rank; /* Rang associé à l'étage */ + + GGraphNode **children; /* Noeuds englobés */ + size_t count; /* Quantité de ces noeuds */ + +} virtual_level; + /* Encapsulation graphique d'un bloc virtuel (instance) */ struct _GVirtualNode { @@ -79,6 +89,8 @@ struct _GVirtualNode GGraphNode **children; /* Noeuds englobés */ size_t count; /* Quantité de ces noeuds */ + virtual_level *levels; /* Différents étages de noeuds */ + size_t lcount; /* Nombre de ces étages */ vert_links *left_padding; /* Espace à gauche pour liens */ vspan_slot_t left_count; /* Nombre de largeurs réservées*/ @@ -113,14 +125,20 @@ static unsigned int g_virtual_node_get_rank(const GVirtualNode *); /* Réinitialise la position d'un noeud d'encapsulation. */ static void g_virtual_node_reset_position(GVirtualNode *); -/* Altère la position du noeud d'encapsulation. */ -static void g_virtual_node_set_position(GVirtualNode *, gint *, gint *); +/* Définit les abscisses relatives du contenu d'un noeud. */ +static void g_virtual_node_prepare_x_line(GVirtualNode *, GGraphNode *); -/* Fournit la position du noeud d'encapsulation. */ -static void g_virtual_node_get_position(const GVirtualNode *, gint *, gint *); +/* Applique une position finale au noeud. */ +static void g_virtual_node_apply_position(GVirtualNode *); -/* Indique l'espace requis pour un noeud d'encapsulation. */ -static GtkAllocation g_virtual_node_get_allocation(const GVirtualNode *); +/* Définit les abscisses relatives du contenu d'un noeud. */ +static void g_virtual_node_apply_x_line(GVirtualNode *); + +/* Met à jour la largeur interne du noeud. */ +static void g_virtual_node_compute_width(GVirtualNode *); + +/* Altère la position du noeud d'encapsulation. */ +static void g_virtual_node_set_position(GVirtualNode *, gint); /* Parcourt tous les blocs d'instructions dans un ordre donné. */ static bool g_virtual_node_visit_flow_nodes(GVirtualNode *, graph_node_visitor_cb, void *); @@ -128,9 +146,6 @@ static bool g_virtual_node_visit_flow_nodes(GVirtualNode *, graph_node_visitor_c /* Recherche le noeud contenant un autre noeud. */ static GGraphNode *g_virtual_node_find_container(GVirtualNode *, GGraphNode *); -/* Définit les abscisses relatives du contenu d'un noeud. */ -static void g_virtual_node_setup_x_line(GVirtualNode *, GGraphNode *); - /* ---------------------------------------------------------------------------------- */ @@ -287,9 +302,9 @@ static void g_virtual_node_init(GVirtualNode *node) base->get_rank = (get_node_rank_fc)g_virtual_node_get_rank; base->reset_pos = (node_reset_pos_fc)g_virtual_node_reset_position; + base->prepare_x = (node_prepare_x_fc)g_virtual_node_prepare_x_line; + base->apply_pos = (node_apply_pos_fc)g_virtual_node_apply_position; base->set_pos = (node_set_pos_fc)g_virtual_node_set_position; - base->get_pos = (node_get_pos_fc)g_virtual_node_get_position; - base->get_alloc = (node_get_alloc_fc)g_virtual_node_get_allocation; base->visit = (visit_flow_nodes_fc)g_virtual_node_visit_flow_nodes; base->contain = (find_container_fc)g_virtual_node_find_container; @@ -410,19 +425,20 @@ static unsigned int g_virtual_node_get_rank(const GVirtualNode *node) static void g_virtual_node_reset_position(GVirtualNode *node) { - node->x = UNINITIALIZED_NODE_POS; - node->y = UNINITIALIZED_NODE_POS; + size_t i; /* Boucle de parcours */ + + for (i = 0; i < node->count; i++) + g_graph_node_reset_position(node->children[i]); } /****************************************************************************** * * -* Paramètres : node = noeud graphique à manipuler. * -* x = éventuelle abscisse à intégrer ou NULL. * -* y = éventuelle ordonnée à intégrer ou NULL. * +* Paramètres : node = noeud d'encapsulation à traiter. * +* nodes = ensemble des noeuds en place. * * * -* Description : Altère la position du noeud d'encapsulation. * +* Description : Définit les abscisses relatives du contenu d'un noeud. * * * * Retour : - * * * @@ -430,58 +446,167 @@ static void g_virtual_node_reset_position(GVirtualNode *node) * * ******************************************************************************/ -static void g_virtual_node_set_position(GVirtualNode *node, gint *x, gint *y) +static void g_virtual_node_prepare_x_line(GVirtualNode *node, GGraphNode *nodes) { - gint old_x; /* Sauvegarde des abscisses */ - gint old_y; /* Sauvegarde des ordonnées */ - gint off_x; /* Décallage sur les abscisses */ - gint off_y; /* Décallage sur les ordonnées */ - gint pos_x; /* Nouvelle position #1 */ - gint pos_y; /* Nouvelle position #2 */ size_t i; /* Boucle de parcours */ + for (i = 0; i < node->count; i++) + g_graph_node_prepare_x_line(node->children[i], nodes); - //if (x != NULL) printf("-- setX -- %p -> %d (old=%d)\n", node, *x, node->x); +} - old_x = node->x; - old_y = node->y; +/****************************************************************************** +* * +* Paramètres : node = noeud d'encapsulation à traiter. * +* * +* Description : Applique une position finale au noeud. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ - if (x != NULL) node->x = *x; - if (y != NULL) node->y = *y; +static void g_virtual_node_apply_position(GVirtualNode *node) +{ + gint min; /* Valeur minimale rencontrée */ + size_t i; /* Boucle de parcours */ + gint pos_x; /* Nouvelle position #1 */ + gint offset; /* Décallage à faire suivre */ - off_x = (old_x != UNINITIALIZED_NODE_POS && node->x != UNINITIALIZED_NODE_POS ? node->x - old_x : 0); - off_y = (old_y != UNINITIALIZED_NODE_POS ? node->y - old_y : node->y); + g_virtual_node_apply_x_line(node); - //printf("offx = %d\n", off_x); + /* Collecte de l'ensemble des positions */ + min = 0; for (i = 0; i < node->count; i++) { - g_graph_node_get_position(node->children[i], &pos_x, &pos_y); + g_graph_node_get_position(node->children[i], &pos_x, NULL); + min = MIN(min, pos_x); + } + /* Espace pour les liens remontants */ + if (node->left_count > 0) + offset = EDGE_SLOT_HORIZ_MARGIN + EDGE_HORIZONTAL_MIN_SEP * (node->left_count - 1); + else + offset = 0; + + /* Ajout du décallage le plus grand */ + offset += -min; - if (x != NULL) pos_x += off_x; + /* Traitement des sous-noeuds */ + for (i = 0; i < node->count; i++) + { + /* BUG_ON(node->children[i]->alloc.x != UNINITIALIZED_NODE_POS); */ - g_graph_node_set_position(node->children[i], &pos_x, &pos_y); + g_graph_node_get_position(node->children[i], &pos_x, NULL); + pos_x += offset; + g_graph_node_set_x_position(node->children[i], pos_x); } + g_virtual_node_compute_width(node); + +} + +/****************************************************************************** +* * +* Paramètres : node = noeud d'encapsulation à traiter. * +* * +* Description : Définit les abscisses relatives du contenu d'un noeud. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_virtual_node_apply_x_line(GVirtualNode *node) +{ + size_t i; /* Boucle de parcours #1 */ + virtual_level *level; /* Accès rapide */ + size_t j; /* Boucle de parcours #2 */ + gint width_sum; /* Largeur d'un étage traité */ + gint x_pos; /* Abscisse à attribuer */ + + for (i = 0; i < node->lcount; i++) + { + level = &node->levels[i]; + + /* Si l'ensemble de l'étage doit être aligné */ + if (level->children[0]->pending_flag == PPF_NONE) + { + width_sum = 0; + + for (j = 0; j < level->count; j++) + { + /* BUG_ON(level->children[j]->pending_flag != PPF_NONE); */ + + g_graph_node_apply_position(level->children[j]); + width_sum += level->children[j]->alloc.width; + + } + + width_sum += NODE_HORIZONTAL_MARGIN * (level->count - 1); + + x_pos = - width_sum / 2; + + for (j = 0; j < level->count; j++) + { + g_graph_node_set_x_position(level->children[j], x_pos); + x_pos += level->children[j]->alloc.width + NODE_HORIZONTAL_MARGIN; + } + + } + + /* On traite les noeuds individuellement */ + else + { + void _apply_rel_position(GGraphNode *child) + { + switch (node->children[0]->pending_flag) + { + case PPF_LEFT_NODE: + if (!g_graph_node_has_x_position(child->pending_pos.left_node)) + _apply_rel_position(child->pending_pos.left_node); + break; + + case PPF_RIGHT_NODE: + if (!g_graph_node_has_x_position(child->pending_pos.right_node)) + _apply_rel_position(child->pending_pos.right_node); + break; + + default: + break; + + } + + g_graph_node_apply_position(child); + + } + + for (j = 0; j < level->count; j++) + if (!g_graph_node_has_x_position(level->children[j])) + _apply_rel_position(level->children[j]); + + } + + } } /****************************************************************************** * * -* Paramètres : node = noeud graphique à consulter. * -* x = éventuelle abscisse à recevoir ou NULL. [OUT] * -* y = éventuelle ordonnée à recevoir ou NULL. [OUT] * +* Paramètres : node = noeud graphique à mettre à jour. * * * -* Description : Fournit la position du noeud d'encapsulation. * +* Description : Met à jour la largeur interne du noeud. * * * * Retour : - * * * @@ -489,10 +614,80 @@ static void g_virtual_node_set_position(GVirtualNode *node, gint *x, gint *y) * * ******************************************************************************/ -static void g_virtual_node_get_position(const GVirtualNode *node, gint *x, gint *y) +static void g_virtual_node_compute_width(GVirtualNode *node) { - if (x != NULL) *x = node->x; - if (y != NULL) *y = node->y; + GGraphNode *base; /* Accès rapides */ + size_t i; /* Boucle de parcours */ + GGraphNode *child; /* Raccourci confortable */ + + base = G_GRAPH_NODE(node); + + /* Largeur maximale des niveaux */ + + base->alloc.width = 0; + + for (i = 0; i < node->lcount; i++) + { + child = node->levels[i].children[node->levels[i].count - 1]; + + base->alloc.width = MAX(base->alloc.width, child->alloc.x + child->alloc.width); + + } + + /* Bordures gauche et droite */ + + if (node->left_count > 0) + { + base->alloc.width += EDGE_SLOT_HORIZ_MARGIN; + base->alloc.width += (node->left_count - 1) * EDGE_HORIZONTAL_MIN_SEP; + } + + if (node->right_count > 0) + { + base->alloc.width += EDGE_SLOT_HORIZ_MARGIN; + base->alloc.width += (node->right_count - 1) * EDGE_HORIZONTAL_MIN_SEP; + } + +} + + +/****************************************************************************** +* * +* Paramètres : node = noeud graphique à manipuler. * +* x = éventuelle abscisse à intégrer. * +* * +* Description : Altère la position du noeud d'encapsulation. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_virtual_node_set_position(GVirtualNode *node, gint x) +{ + GGraphNode *base; /* Autre version de l'instance */ + gint offset; /* Décallage à faire suivre */ + size_t i; /* Boucle de parcours */ + gint x_pos; /* Nouvelle position #1 */ + + base = G_GRAPH_NODE(node); + + if (base->alloc.x == UNINITIALIZED_NODE_POS) + offset = x; + else + offset = x - base->alloc.x; + + for (i = 0; i < node->count; i++) + { + /* BUG_ON(node->children[i]->alloc.x != UNINITIALIZED_NODE_POS); */ + + g_graph_node_get_position(node->children[i], &x_pos, NULL); + x_pos += offset; + + g_graph_node_set_x_position(node->children[i], x_pos); + + } } @@ -669,6 +864,12 @@ static GGraphNode *g_virtual_node_find_container(GVirtualNode *node, GGraphNode void g_virtual_node_add_child(GVirtualNode *node, GGraphNode *child) { + unsigned int rank; /* Rang de l'enfant */ + virtual_level *level; /* Niveau d'intégration */ + size_t i; /* Boucle de parcours */ + + /* Liste globale */ + node->children = (GGraphNode **)realloc(node->children, ++node->count * sizeof(GGraphNode *)); @@ -676,6 +877,33 @@ void g_virtual_node_add_child(GVirtualNode *node, GGraphNode *child) g_object_ref(G_OBJECT(child)); + /* Intégration dans l'étage correspondant */ + + rank = g_graph_node_get_rank(child); + + level = NULL; + + for (i = 0; i < node->lcount && level == NULL; i++) + if (node->levels[i].rank == rank) + level = &node->levels[i]; + + if (level == NULL) + { + node->levels = (virtual_level *)realloc(node->levels, + ++node->lcount * sizeof(virtual_level)); + level = &node->levels[node->lcount - 1]; + + level->rank = rank; + level->children = NULL; + level->count = 0; + + } + + level->children = (GGraphNode **)realloc(level->children, + ++level->count * sizeof(GGraphNode *)); + + level->children[level->count - 1] = child; + } @@ -777,174 +1005,6 @@ vspan_slot_t g_virtual_node_reserve_span(GVirtualNode *node, unsigned int r1, un /****************************************************************************** * * -* Paramètres : node = noeud d'encapsulation à traiter. * -* nodes = ensemble des noeuds en place. * -* * -* Description : Organise le contenu du noeud selon l'axe des abscisses. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -void g_virtual_node_organize_x_line(GVirtualNode *node, GGraphNode *nodes) -{ - size_t i; /* Boucle de parcours */ - gint min; /* Valeur minimale rencontrée */ - gint x; /* Position d'un sous-noeud */ - - g_virtual_node_setup_x_line(node, nodes); - - min = 0; - - for (i = 0; i < node->count; i++) - { - g_graph_node_get_position(node->children[i], &x, NULL); - min = MIN(min, x); - } - - node->x += GRAPH_HORIZONTAL_MARGIN; - min = -min + GRAPH_HORIZONTAL_MARGIN; - - g_virtual_node_offset_x_line(node, min); - -} - - -/****************************************************************************** -* * -* Paramètres : node = noeud d'encapsulation à traiter. * -* nodes = ensemble des noeuds en place. * -* * -* Description : Définit les abscisses relatives du contenu d'un noeud. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_virtual_node_setup_x_line(GVirtualNode *node, GGraphNode *nodes) -{ - unsigned int rank_0; /* Rang du premier sous-noeud */ - unsigned int rank_1; /* Rang du second sous-noeud */ - size_t i; /* Boucle de parcours */ - GGraphNode *child; /* Raccourci confortable */ - gint last_pos; /* Dernière position */ - GtkAllocation alloc; /* Espace pour l'affichage */ - - /* Si le rang d'entrée contient tous les éléments... */ - if (node->count > 1) - { - rank_0 = g_graph_node_get_rank(node->children[0]); - rank_1 = g_graph_node_get_rank(node->children[1]); - - if (rank_0 == rank_1) - { - g_graph_node_set_position(node->children[0], (gint []) { 0/*-(alloc.width / 2)*/ }, NULL); - - for (i = 1; i < node->count; i++) - { - /* Récupération de la position précédente */ - - child = node->children[i - 1]; - - g_graph_node_get_position(child, &last_pos, NULL); - alloc = g_graph_node_get_allocation(child); - - last_pos += alloc.width + NODE_LEFT_MARGIN; - - /* Application sur le noeud courant */ - - child = node->children[i]; - - alloc = g_graph_node_get_allocation(child); - - g_graph_node_set_position(child, &last_pos, NULL); - - } - - } - - } - - for (i = 0; i < node->count; i++) - { - child = node->children[i]; - - /* Emplacement du fils */ - - if (!g_graph_node_has_x_position(child)) - { - alloc = g_graph_node_get_allocation(child); - g_graph_node_set_position(child, (gint []) { -(alloc.width / 2) }, NULL); - } - - /* Définitions éventuelles des emplacements liés */ - - if (G_IS_FLOW_NODE(child)) - g_flow_node_organize_x_line(G_FLOW_NODE(child), nodes); - - else if (G_IS_VIRTUAL_NODE(child)) - g_virtual_node_organize_x_line(G_VIRTUAL_NODE(child), nodes); - - /*else BUG_ON(1); */ - - } - -} - - -/****************************************************************************** -* * -* Paramètres : node = noeud d'encapsulation à traiter. * -* xoffset = valeur du décallage. * -* * -* Description : Procède à un décallage du contenu sur l'axe des abscisses. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -void g_virtual_node_offset_x_line(GVirtualNode *node, gint xoffset) -{ - gint padding; /* Décallage supplémentaire */ - size_t i; /* Boucle de parcours */ - gint x; /* Position d'un sous-noeud */ - GGraphNode *child; /* Raccourci confortable */ - - /* Espace pour les liens remontants */ - - if (node->left_count > 0) - padding = EDGE_SLOT_HORIZ_MARGIN + EDGE_HORIZONTAL_MIN_SEP * (node->left_count - 1); - else - padding = 0; - - /* Traitement de sous-noeuds */ - - for (i = 0; i < node->count; i++) - { - child = node->children[i]; - - g_graph_node_get_position(child, &x, NULL); - - printf("+++ [%p-%d/%p] offsetting %d(%d) + (%d / %d)\n", - node, g_graph_node_get_rank(G_GRAPH_NODE(node)), child, - node->x, G_GRAPH_NODE(node)->pending_x, x, x + xoffset + padding); - - x += node->x + xoffset + padding; - g_graph_node_set_position(child, &x, NULL); - - } - -} - - -/****************************************************************************** -* * * Paramètres : node = conteneur de noeuds à consulter. * * slot = numérod de la réservation. * * left = désignation de la zone à traiter. * |