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 | |
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')
-rw-r--r-- | src/gtkext/graph/nodes/flow.c | 413 | ||||
-rw-r--r-- | src/gtkext/graph/nodes/flow.h | 3 | ||||
-rw-r--r-- | src/gtkext/graph/nodes/virtual.c | 480 | ||||
-rw-r--r-- | src/gtkext/graph/nodes/virtual.h | 6 |
4 files changed, 379 insertions, 523 deletions
diff --git a/src/gtkext/graph/nodes/flow.c b/src/gtkext/graph/nodes/flow.c index de434ab..fad520d 100644 --- a/src/gtkext/graph/nodes/flow.c +++ b/src/gtkext/graph/nodes/flow.c @@ -49,8 +49,6 @@ struct _GFlowNode GFlowBlock *block; /* Bloc d'exécution associé */ GtkBufferView *view; /* Représentation graphique */ - GtkAllocation alloc; /* Emplacement du bloc rattaché*/ - node_slot_t *entries; /* Positions des pts d'entrées */ size_t entries_count; /* Nombre de ces points */ node_slot_t *exits; /* Positions des pts de sorties*/ @@ -84,17 +82,8 @@ static void g_flow_node_finalize(GFlowNode *); /* Fournit le rang du noeud dans le graphique. */ static unsigned int g_flow_node_get_rank(const GFlowNode *); -/* Réinitialise la position d'un noeud d'encapsulation. */ -static void g_flow_node_reset_position(GFlowNode *); - -/* Altère la position du noeud d'encapsulation. */ -static void g_flow_node_set_position(GFlowNode *, gint *, gint *); - -/* Fournit la position du noeud d'encapsulation. */ -static void g_flow_node_get_position(const GFlowNode *, gint *, gint *); - -/* Indique l'espace requis pour un noeud d'encapsulation. */ -static GtkAllocation g_flow_node_get_allocation(const GFlowNode *); +/* Organise le contenu du noeud selon l'axe des abscisses. */ +static void g_flow_node_prepare_x_line(GFlowNode *, GGraphNode *); /* Parcourt tous les blocs d'instructions dans un ordre donné. */ static bool g_flow_node_visit_flow_nodes(GFlowNode *, graph_node_visitor_cb, void *); @@ -166,15 +155,9 @@ static void g_flow_node_init(GFlowNode *node) base = G_GRAPH_NODE(node); base->get_rank = (get_node_rank_fc)g_flow_node_get_rank; - base->reset_pos = (node_reset_pos_fc)g_flow_node_reset_position; - base->set_pos = (node_set_pos_fc)g_flow_node_set_position; - base->get_pos = (node_get_pos_fc)g_flow_node_get_position; - base->get_alloc = (node_get_alloc_fc)g_flow_node_get_allocation; + base->prepare_x = (node_prepare_x_fc)g_flow_node_prepare_x_line; base->visit = (visit_flow_nodes_fc)g_flow_node_visit_flow_nodes; - node->alloc.x = UNINITIALIZED_NODE_POS; - node->alloc.y = UNINITIALIZED_NODE_POS; - } @@ -261,8 +244,8 @@ GGraphNode *g_flow_node_new(GFlowBlock *block, GtkBufferView *view) gtk_widget_size_request(GTK_WIDGET(result->view), &requisition); - result->alloc.width = requisition.width; - result->alloc.height = requisition.height; + G_GRAPH_NODE(result)->alloc.width = requisition.width; + G_GRAPH_NODE(result)->alloc.height = requisition.height; g_flow_node_setup_entry_slots(result); g_flow_node_setup_exit_slots(result); @@ -293,9 +276,10 @@ static unsigned int g_flow_node_get_rank(const GFlowNode *node) /****************************************************************************** * * -* Paramètres : node = noeud graphique à manipuler. * +* Paramètres : node = noeud d'encapsulation à traiter. * +* nodes = ensemble des noeuds en place. * * * -* Description : Réinitialise la position d'un noeud d'encapsulation. * +* Description : Organise le contenu du noeud selon l'axe des abscisses. * * * * Retour : - * * * @@ -303,83 +287,113 @@ static unsigned int g_flow_node_get_rank(const GFlowNode *node) * * ******************************************************************************/ -static void g_flow_node_reset_position(GFlowNode *node) +static void g_flow_node_prepare_x_line(GFlowNode *node, GGraphNode *nodes) { - GtkRequisition requisition; /* Taille à l'écran actuelle */ + GGraphNode *base; /* Autre vision de l'instance */ + GArchInstruction *last; /* Dernière instr. du noeud */ + GFlowNode *target; /* Bloc visé par le lien */ + node_slot_t *dest_slot; /* Accrochage d'arrivée */ + pending_position pos; /* Position à transmettre */ + GFlowNode *target_a; /* Bloc visé par le lien #a */ + GFlowNode *target_b; /* Bloc visé par le lien #b */ + unsigned int rank_a; /* Indice du rang associé #a */ + unsigned int rank_b; /* Indice du rang associé #b */ + GGraphNode *container; /* Conteneur à positionner */ - node->alloc.x = UNINITIALIZED_NODE_POS; - node->alloc.y = UNINITIALIZED_NODE_POS; + base = G_GRAPH_NODE(node); - gtk_widget_size_request(GTK_WIDGET(node->view), &requisition); + g_flow_block_get_boundary(node->block, NULL, &last); - node->alloc.width = requisition.width; - node->alloc.height = requisition.height; + switch (node->exits_count) + { + case 0: + break; -} + case 1: -/****************************************************************************** -* * -* Paramètres : node = noeud graphique à manipuler. * -* x = éventuelle abscisse à intégrer ou NULL. * -* y = éventuelle ordonnée à intégrer ou NULL. * -* * -* Description : Altère la position du noeud d'encapsulation. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ + if (node->exits[0].type == ILT_LOOP) + break; -static void g_flow_node_set_position(GFlowNode *node, gint *x, gint *y) -{ - if (x != NULL) node->alloc.x = *x; - if (y != NULL) node->alloc.y = *y; + target = G_FLOW_NODE(find_node_for_instruction(nodes, node->exits[0].instr)); -} + dest_slot = g_flow_node_get_slot(target, true, + last, node->exits[0].group_index); + pos.direct_x = g_flow_node_get_slot_offset(target, true, dest_slot); + pos.direct_x = (G_GRAPH_NODE(target)->alloc.width / 2) - pos.direct_x; -/****************************************************************************** -* * -* Paramètres : node = noeud graphique à consulter. * -* x = éventuelle abscisse à recevoir ou NULL. [OUT] * -* y = éventuelle ordonnée à recevoir ou NULL. [OUT] * -* * -* Description : Fournit la position du noeud d'encapsulation. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ + if (target->entries_count == 1) + g_graph_node_set_pending_position(G_GRAPH_NODE(target), PPF_DIRECT_X, pos, base); -static void g_flow_node_get_position(const GFlowNode *node, gint *x, gint *y) -{ - if (x != NULL) *x = node->alloc.x; - if (y != NULL) *y = node->alloc.y; + break; -} + case 2: + target_a = G_FLOW_NODE(find_node_for_instruction(nodes, node->exits[0].instr)); + target_b = G_FLOW_NODE(find_node_for_instruction(nodes, node->exits[1].instr)); -/****************************************************************************** -* * -* Paramètres : node = noeud graphique à consulter. * -* * -* Description : Indique l'espace requis pour un noeud d'encapsulation. * -* * -* Retour : Espace constitué, entièrement ou non. * -* * -* Remarques : - * -* * -******************************************************************************/ + rank_a = g_flow_node_get_rank(target_a); + rank_b = g_flow_node_get_rank(target_b); -static GtkAllocation g_flow_node_get_allocation(const GFlowNode *node) -{ - GtkAllocation result; /* Valeurs à retourner */ + if (rank_a == rank_b) + break; - result = node->alloc; + /* Alignement d'un bloc lié */ - return result; + if (rank_a > rank_b) + { + /* Seuil vertical pour un côté */ + + container = g_graph_node_find_container_at_same_level(nodes, + G_GRAPH_NODE(node), + G_GRAPH_NODE(target_b)); + + if (container == NULL) container = G_GRAPH_NODE(target_b); + + pos.left_margin = g_flow_node_get_slot_offset(node, false, &node->exits[0]); + g_graph_node_set_pending_position(container, PPF_LEFT_MARGIN, pos, base); + + /* Trait vertical de l'autre côté... */ + + pos.direct_x = pos.left_margin; + + dest_slot = g_flow_node_get_slot(target_a, true, + last, node->exits[0].group_index); + + pos.direct_x -= g_flow_node_get_slot_offset(target_a, true, dest_slot); + + g_graph_node_set_pending_position(G_GRAPH_NODE(target_a), PPF_DIRECT_X, pos, base); + + } + else + { + /* Seuil vertical pour un côté */ + + container = g_graph_node_find_container_at_same_level(nodes, + G_GRAPH_NODE(node), + G_GRAPH_NODE(target_a)); + + if (container == NULL) container = G_GRAPH_NODE(target_a); + + pos.right_margin = g_flow_node_get_slot_offset(node, false, &node->exits[1]); + g_graph_node_set_pending_position(container, PPF_RIGHT_MARGIN, pos, base); + + /* Trait vertical de l'autre côté... */ + + pos.direct_x = pos.right_margin; + + dest_slot = g_flow_node_get_slot(target_b, true, + last, node->exits[1].group_index); + + pos.direct_x -= g_flow_node_get_slot_offset(target_b, true, dest_slot); + + g_graph_node_set_pending_position(G_GRAPH_NODE(target_b), PPF_DIRECT_X, pos, base); + + } + + break; + + } } @@ -463,7 +477,7 @@ void g_flow_node_register_rank(const GFlowNode *node, GGraphRanks *ranks) index = g_flow_node_get_rank(node); - g_graph_ranks_set_min_height(ranks, index, node->alloc.height); + g_graph_ranks_set_min_height(ranks, index, G_GRAPH_NODE(node)->alloc.height); } @@ -487,219 +501,7 @@ void g_flow_node_apply_rank(GFlowNode *node, GGraphRanks *ranks) index = g_flow_node_get_rank(node); - node->alloc.y = g_graph_ranks_get_y_for_rank(ranks, index); - -} - - -/****************************************************************************** -* * -* 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_flow_node_organize_x_line(GFlowNode *node, GGraphNode *nodes) -{ - GArchInstruction *last; /* Dernière instr. du noeud */ - GFlowNode *target; /* Bloc visé par le lien */ - node_slot_t *dest_slot; /* Accrochage d'arrivée */ - gint offset; /* Décallage d'une accroche */ - gint ref_pos; /* Position de référence */ - GdkPoint ref; /* Position de référence */ - GFlowNode *target_a; /* Bloc visé par le lien #a */ - GFlowNode *target_b; /* Bloc visé par le lien #b */ - unsigned int rank_a; /* Indice du rang associé #a */ - unsigned int rank_b; /* Indice du rang associé #b */ - GGraphNode *container; /* Conteneur à positionner */ - - g_flow_block_get_boundary(node->block, NULL, &last); - - switch (node->exits_count) - { - case 1: - - if (node->exits[0].type == ILT_LOOP) - break; - - target = G_FLOW_NODE(find_node_for_instruction(nodes, node->exits[0].instr)); - -#if 0 - /** - * La recherche ne se faisant que dans le sous-ensemble des blocs voisins, - * on écarte des recherches les cibles se situant dans des blocs virtuels parents. - */ - if (target == NULL) - break; -#endif - - if (g_graph_node_has_x_position(G_GRAPH_NODE(target))) - break; - - dest_slot = g_flow_node_get_slot(target, true, - last, node->exits[0].group_index); - - offset = g_flow_node_get_slot_offset(target, true, dest_slot); - offset = (target->alloc.width / 2) - offset; - - if (G_GRAPH_NODE(target)->pending_x == 0) - - g_graph_node_set_pending_position(G_GRAPH_NODE(target), (gint []) { offset }, NULL); - - break; - - case 2: - - target_a = G_FLOW_NODE(find_node_for_instruction(nodes, node->exits[0].instr)); - target_b = G_FLOW_NODE(find_node_for_instruction(nodes, node->exits[1].instr)); - -#if 0 - /** - * La recherche ne se faisant que dans le sous-ensemble des blocs voisins, - * on écarte des recherches les cibles se situant dans des blocs virtuels parents. - */ - if (target_a == NULL || target_b == NULL) - break; -#endif - - /* - if (g_graph_node_has_x_position(G_GRAPH_NODE(target_a)) - || g_graph_node_has_x_position(G_GRAPH_NODE(target_b))) - break; - */ - - rank_a = g_flow_node_get_rank(target_a); - rank_b = g_flow_node_get_rank(target_b); - - printf("\nRANKS : a=%d vs b=%d\n", rank_a, rank_b); - - if (rank_a == rank_b) - break; - - /* Alignement d'un bloc lié */ - - if (rank_a > rank_b) - { - - g_graph_node_get_position(G_GRAPH_NODE(node), &ref_pos, NULL); - ref_pos += (node->alloc.width / 2); - //printf("parent = %d mid = %d\n", ref_pos, (node->alloc.width / 2)); - - - ref_pos += g_flow_node_get_slot_offset(node, false, &node->exits[0]); - ref_pos -= (node->alloc.width / 2); - - //printf("ref_pos = %d mid = %d\n", ref_pos, node->alloc.width / 2); - - - dest_slot = g_flow_node_get_slot(target_a, true, - last, node->exits[0].group_index); - - offset = g_flow_node_get_slot_offset(target_a, true, dest_slot); - - //printf("offset = %d mid = %d\n", offset, (target_a->alloc.width / 2)); - - offset = (target_a->alloc.width / 2) - offset; - offset += ref_pos; - - //ref = g_flow_node_get_point_from_slot(node, false, &node->exits[0]); - - - - printf("> offset = %d\n", offset); - - - //offset += (ref.x < 0 ? - ref.x : ref.x); - -#if 1 - - if (!g_graph_node_has_x_position(G_GRAPH_NODE(target_a)) - && G_GRAPH_NODE(target_a)->pending_x == 0) - - g_graph_node_set_pending_position(G_GRAPH_NODE(target_a), - (gint []) { offset }, NULL); - - else printf("pending...\n"); - -#endif - - } - else - { - dest_slot = g_flow_node_get_slot(target_b, true, - last, node->exits[1].group_index); - - offset = g_flow_node_get_slot_offset(target_b, true, dest_slot); - offset = (target_b->alloc.width / 2) - offset; - - ref = g_flow_node_get_point_from_slot(node, false, &node->exits[1]); - //offset += (ref.x < 0 ? - ref.x : ref.x); - - - - if (G_GRAPH_NODE(target_b)->pending_x == 0) - - g_graph_node_set_pending_position(G_GRAPH_NODE(target_b), - (gint []) { offset }, NULL); - - } - - /* Balance du bloc non aligné */ - - if (rank_a > rank_b) - { - container = g_graph_node_find_container_at_same_level(nodes, - G_GRAPH_NODE(node), - G_GRAPH_NODE(target_b)); - - if (container == NULL) break; - - - printf("----\n"); - printf("node = %p (%d)\n", node, g_graph_node_get_rank(G_GRAPH_NODE(node))); - printf("target a = %p\n", target_a); - printf("target b = %p\n", target_b); - printf("container= %p (%d)\n", container, g_graph_node_get_rank(G_GRAPH_NODE(container))); - - printf("(%p) container %p --> %d\n", nodes, container, ref.x + 20); - - printf("has pos ? %d\n", g_graph_node_has_x_position(container)); - - - dest_slot = g_flow_node_get_slot(target_a, true, - last, node->exits[0].group_index); - - offset += g_flow_node_get_slot_offset(target_a, true, dest_slot); - - - offset += 200; - - //if (ref.x < -10000) - // printf(" !!!! REF.X = %d\n", ref.x); - - //g_graph_node_set_position(container, (gint []) { ref.x + 20 }, NULL); - - - printf(">> set offset : %d\n", offset + 50); - printf(">> pending :: %d\n", G_GRAPH_NODE(container)->pending_x); - - g_graph_node_set_pending_position(container, (gint []) { offset + 50 }, NULL); - - } - - - break; - - - } - - + G_GRAPH_NODE(node)->alloc.y = g_graph_ranks_get_y_for_rank(ranks, index); } @@ -779,7 +581,7 @@ void g_flow_node_link(GFlowNode *node, GGraphLayout *layout, GGraphNode *nodes) void g_flow_node_place(const GFlowNode *node, GtkGraphView *view) { - gtk_graph_view_put(view, GTK_WIDGET(node->view), &node->alloc); + gtk_graph_view_put(view, GTK_WIDGET(node->view), &G_GRAPH_NODE(node)->alloc); } @@ -954,7 +756,7 @@ static gint g_flow_node_get_slot_offset(const GFlowNode *node, bool entry, const } slots_width = (count - 1) * SPACE_BETWEEN_SLOT; - slots_left = (node->alloc.width - slots_width) / 2; + slots_left = (G_GRAPH_NODE(node)->alloc.width - slots_width) / 2; index = (slot - slots); /* BUG_ON(index >= count); */ @@ -982,6 +784,7 @@ static gint g_flow_node_get_slot_offset(const GFlowNode *node, bool entry, const GdkPoint g_flow_node_get_point_from_slot(const GFlowNode *node, bool entry, const node_slot_t *slot) { + GGraphNode *base; /* Accès rapides */ GdkPoint result; /* Position à retourner */ node_slot_t *slots; /* Accroches à parcourir */ size_t count; /* Nombre de ces points */ @@ -989,9 +792,11 @@ GdkPoint g_flow_node_get_point_from_slot(const GFlowNode *node, bool entry, cons gint slots_left; /* Abscisse de la première */ size_t index; /* Indice de l'accroche visée */ + base = G_GRAPH_NODE(node); + if (entry) { - result.y = node->alloc.y; + result.y = base->alloc.y; slots = node->entries; count = node->entries_count; @@ -999,7 +804,7 @@ GdkPoint g_flow_node_get_point_from_slot(const GFlowNode *node, bool entry, cons } else { - result.y = node->alloc.y + node->alloc.height; + result.y = base->alloc.y + base->alloc.height; slots = node->exits; count = node->exits_count; @@ -1008,7 +813,7 @@ GdkPoint g_flow_node_get_point_from_slot(const GFlowNode *node, bool entry, cons slots_width = (count - 1) * SPACE_BETWEEN_SLOT; - slots_left = node->alloc.x + (node->alloc.width - slots_width) / 2; + slots_left = base->alloc.x + (base->alloc.width - slots_width) / 2; index = (slot - slots)/* / sizeof(node_slot_t)*/; /* BUG_ON(index >= count); */ @@ -1019,7 +824,7 @@ GdkPoint g_flow_node_get_point_from_slot(const GFlowNode *node, bool entry, cons #if 0 slots_width = (count - 1) * SPACE_BETWEEN_SLOT; - slots_left = node->alloc.x + (node->alloc.width - slots_width) / 2; + slots_left = base->alloc.x + (base->alloc.width - slots_width) / 2; index = (slot - slots)/* / sizeof(node_slot_t)*/; /* BUG_ON(index >= count); */ diff --git a/src/gtkext/graph/nodes/flow.h b/src/gtkext/graph/nodes/flow.h index 5c99284..5a6268e 100644 --- a/src/gtkext/graph/nodes/flow.h +++ b/src/gtkext/graph/nodes/flow.h @@ -70,9 +70,6 @@ void g_flow_node_apply_rank(GFlowNode *, GGraphRanks *); /* Etablit les liaison entre un noeud et ses suivants. */ void g_flow_node_link(GFlowNode *, GGraphLayout *, GGraphNode *); -/* Organise le contenu du noeud selon l'axe des abscisses. */ -void g_flow_node_organize_x_line(GFlowNode *, GGraphNode *); - /* Place un noeud sur son support final. */ void g_flow_node_place(const GFlowNode *, GtkGraphView *); 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. * diff --git a/src/gtkext/graph/nodes/virtual.h b/src/gtkext/graph/nodes/virtual.h index a7a96d7..77e4a63 100644 --- a/src/gtkext/graph/nodes/virtual.h +++ b/src/gtkext/graph/nodes/virtual.h @@ -68,12 +68,6 @@ GGraphNode *g_virtual_node_get_child(const GVirtualNode *, size_t); /* Réserve une portion de largeur pour un lien. */ vspan_slot_t g_virtual_node_reserve_span(GVirtualNode *, unsigned int, unsigned int, bool); -/* Organise le contenu du noeud selon l'axe des abscisses. */ -void g_virtual_node_organize_x_line(GVirtualNode *, GGraphNode *); - -/* Procède à un décallage du contenu sur l'axe des abscisses. */ -void g_virtual_node_offset_x_line(GVirtualNode *, gint); - /* Fournit la position horizontale obtenue par réservation. */ gint g_virtual_node_get_x_for_vspan_slot(const GVirtualNode *, vspan_slot_t, bool); |