summaryrefslogtreecommitdiff
path: root/src/gtkext/graph/nodes
diff options
context:
space:
mode:
Diffstat (limited to 'src/gtkext/graph/nodes')
-rw-r--r--src/gtkext/graph/nodes/flow.c413
-rw-r--r--src/gtkext/graph/nodes/flow.h3
-rw-r--r--src/gtkext/graph/nodes/virtual.c480
-rw-r--r--src/gtkext/graph/nodes/virtual.h6
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);