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