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.c410
1 files changed, 390 insertions, 20 deletions
diff --git a/src/gtkext/graph/nodes/virtual.c b/src/gtkext/graph/nodes/virtual.c
index 2781644..e13dfc8 100644
--- a/src/gtkext/graph/nodes/virtual.c
+++ b/src/gtkext/graph/nodes/virtual.c
@@ -33,6 +33,40 @@
+/* ----------------------- MANIPULATION DES PORTES VERTICALES ----------------------- */
+
+
+/* Etendue verticale d'un lien */
+typedef struct _reserved_vspan
+{
+ unsigned int r1; /* Départ d'une ligne */
+ unsigned int r2; /* Arrivée de cette même ligne */
+
+} reserved_vspan;
+
+/* Lignes de liens verticales au sein d'un même groupe */
+typedef struct _vert_links
+{
+ reserved_vspan *vspans; /* Lignes sans chevauchement */
+ size_t count; /* Nombre de ces lignes */
+
+} vert_links;
+
+
+/* Initialise les futures portées d'un même niveau. */
+static void init_vertical_links(vert_links *);
+
+/* Regarde si des portées verticales se chevauchent ou non. */
+static bool is_intersection_with_vertical_spans(const vert_links *, const reserved_vspan *);
+
+/* Ajoute une réservation à un ensemble de portées verticales. */
+static void extend_vertical_links_spans(vert_links *, const reserved_vspan *);
+
+
+
+/* ---------------------- REPRESENTATIONS DES GROUPES LOGIQUES ---------------------- */
+
+
/* Encapsulation graphique d'un bloc virtuel (instance) */
struct _GVirtualNode
{
@@ -46,6 +80,11 @@ struct _GVirtualNode
GGraphNode **children; /* Noeuds englobés */
size_t count; /* Quantité de ces noeuds */
+ vert_links *left_padding; /* Espace à gauche pour liens */
+ vspan_slot_t left_count; /* Nombre de largeurs réservées*/
+ vert_links *right_padding; /* Espace à droite pour liens */
+ vspan_slot_t right_count; /* Nombre de largeurs réservées*/
+
};
/* Encapsulation graphique d'un bloc virtuel (classe) */
@@ -71,6 +110,9 @@ static void g_virtual_node_finalize(GVirtualNode *);
/* Fournit le rang du noeud dans le graphique. */
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 *);
@@ -83,11 +125,120 @@ static GtkAllocation g_virtual_node_get_allocation(const GVirtualNode *);
/* Parcourt tous les blocs d'instructions dans un ordre donné. */
static bool g_virtual_node_visit_flow_nodes(GVirtualNode *, graph_node_visitor_cb, void *);
+/* 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 *);
+/* ---------------------------------------------------------------------------------- */
+/* MANIPULATION DES PORTES VERTICALES */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : links = liste à initialiser. *
+* *
+* Description : Initialise les futures portées d'un même niveau. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void init_vertical_links(vert_links *links)
+{
+ links->vspans = NULL;
+ links->count = 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : links = liste de portées déjà en place. *
+* vspan = nouvelle portée à insérer quelque part. *
+* *
+* Description : Regarde si des portées verticales se chevauchent ou non. *
+* *
+* Retour : true si les portées peuvent cohabiter, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool is_intersection_with_vertical_spans(const vert_links *links, const reserved_vspan *vspan)
+{
+ bool result; /* Bilan d'analyse à retourner */
+ size_t i; /* Boucle de parcours */
+
+ result = false;
+
+ for (i = 0; i < links->count && !result; i++)
+ {
+ if (vspan->r1 < links->vspans[i].r1)
+ result = vspan->r2 >= links->vspans[i].r1;
+
+ else if (vspan->r1 > links->vspans[i].r2)
+ result = vspan->r2 <= links->vspans[i].r2;
+
+ else
+ {
+ result = links->vspans[i].r1 < vspan->r1 && vspan->r1 < links->vspans[i].r2;
+ result |= links->vspans[i].r1 < vspan->r2 && vspan->r2 < links->vspans[i].r2;
+ }
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : spans = liste de portées déjà en place. *
+* vspan = nouvelle portée à insérer quelque part. *
+* *
+* Description : Ajoute une réservation à un ensemble de portées verticales. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void extend_vertical_links_spans(vert_links *links, const reserved_vspan *new)
+{
+ links->vspans = (reserved_vspan *)realloc(links->vspans,
+ ++links->count * sizeof(reserved_vspan));
+
+ if (new->r1 <= new->r2)
+ links->vspans[links->count - 1] = *new;
+ else
+ {
+ links->vspans[links->count - 1].r1 = new->r2;
+ links->vspans[links->count - 1].r2 = new->r1;
+ }
+
+}
+
+
+
+
+
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* REPRESENTATIONS DES GROUPES LOGIQUES */
+/* ---------------------------------------------------------------------------------- */
+
+
/* Indique le type définit par la GLib pour l'encapsulation d'un bloc virtuel. */
G_DEFINE_TYPE(GVirtualNode, g_virtual_node, G_TYPE_GRAPH_NODE);
@@ -135,10 +286,12 @@ static void g_virtual_node_init(GVirtualNode *node)
base = G_GRAPH_NODE(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->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;
node->x = UNINITIALIZED_NODE_POS;
node->y = UNINITIALIZED_NODE_POS;
@@ -246,6 +399,26 @@ static unsigned int g_virtual_node_get_rank(const GVirtualNode *node)
/******************************************************************************
* *
* Paramètres : node = noeud graphique à manipuler. *
+* *
+* Description : Réinitialise la position d'un noeud d'encapsulation. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_virtual_node_reset_position(GVirtualNode *node)
+{
+ node->x = UNINITIALIZED_NODE_POS;
+ node->y = UNINITIALIZED_NODE_POS;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = noeud graphique à manipuler. *
* x = éventuelle abscisse à intégrer ou NULL. *
* y = éventuelle ordonnée à intégrer ou NULL. *
* *
@@ -302,6 +475,12 @@ static void g_virtual_node_get_position(const GVirtualNode *node, gint *x, gint
static GtkAllocation g_virtual_node_get_allocation(const GVirtualNode *node)
{
GtkAllocation result; /* Valeurs à retourner */
+ gint margins; /* Bordures gauche et droite */
+ unsigned int last_rank; /* Détection de saut de rangs */
+ size_t horiz_count; /* Quantité à l'horizontale */
+ size_t vert_count; /* Quantité à la verticale */
+ gint rank_width; /* Largeur d'un rang donné */
+ gint rank_height; /* Hauteur d'un rang donné */
size_t i; /* Boucle de parcours */
GtkAllocation alloc; /* Allocation d'un sous-noeud */
@@ -309,23 +488,72 @@ static GtkAllocation g_virtual_node_get_allocation(const GVirtualNode *node)
result.y = node->y;
result.width = 0;
+ margins = 0;
+ if (node->left_count > 0)
+ {
+ margins += EDGE_SLOT_HORIZ_MARGIN;
+ margins += (node->left_count - 1) * EDGE_HORIZONTAL_MIN_SEP;
+ }
+ if (node->right_count > 0)
+ {
+ margins += EDGE_SLOT_HORIZ_MARGIN;
+ margins += (node->right_count - 1) * EDGE_HORIZONTAL_MIN_SEP;
+ }
result.height = 0;
+ last_rank = -1;
+
+ horiz_count = 0;
+ vert_count = 0;
+
+ rank_width = 0;
+ rank_height = 0;
+
for (i = 0; i < node->count; i++)
{
alloc = g_graph_node_get_allocation(node->children[i]);
- result.width += alloc.width;
- result.height += alloc.height;
+ if (last_rank != g_graph_node_get_rank(node->children[i]))
+ {
+ last_rank = g_graph_node_get_rank(node->children[i]);
+
+ result.width = MAX(result.width, rank_width);
- }
+ /*
+ if (horiz_count > 0)
+ result.width = MAX(result.width, rank_width + (horiz_count - 1) * NODE_LEFT_MARGIN);
+ */
+
+ result.height += rank_height;
+
+ rank_width = 0;
+ rank_height = 0;
+
+ horiz_count = 0;
+ vert_count++;
+
+ }
+
+ //rank_width += alloc.width;
+ if (rank_width > 0) rank_width += NODE_LEFT_MARGIN;
+ rank_width += alloc.width;
+ rank_height = MAX(rank_height, alloc.height);
+
+ horiz_count++;
- if (node->count > 1)
- {
- result.width += (node->count - 1) * NODE_TOP_MARGIN;
- result.height += (node->count - 1) * NODE_TOP_MARGIN;
}
+ result.width = MAX(result.width, rank_width);
+ /*
+ if (horiz_count > 0)
+ result.width = MAX(result.width, rank_width + (horiz_count - 1) * NODE_LEFT_MARGIN);
+ */
+
+ result.width += margins;
+
+ if (vert_count > 1)
+ result.height += (vert_count - 1) * NODE_TOP_MARGIN;
+
return result;
}
@@ -350,10 +578,46 @@ static bool g_virtual_node_visit_flow_nodes(GVirtualNode *node, graph_node_visit
bool result; /* Bilan à retourner */
size_t i; /* Boucle de parcours */
- result = true;
+ result = callback(G_GRAPH_NODE(node), GVS_ENTER, data);
for (i = 0; i < node->count && result; i++)
- result = g_graph_node_visit_flow_nodes(node->children[i], callback, data);
+ result = g_graph_node_visit_nodes(node->children[i], callback, data);
+
+ if (result)
+ result = callback(G_GRAPH_NODE(node), GVS_EXIT, data);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : nodes = noeud à consulter. *
+* target = élément à retrouver dans l'ensemble de noeuds. *
+* *
+* Description : Recherche le noeud contenant un autre noeud. *
+* *
+* Retour : Noeud trouvé ou NULL si aucun. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static GGraphNode *g_virtual_node_find_container(GVirtualNode *node, GGraphNode *target)
+{
+ GGraphNode *result; /* Trouvaille à retourner */
+ size_t i; /* Boucle de parcours */
+
+ result = NULL;
+
+ for (i = 0; i < node->count && result == NULL; i++)
+ {
+ if (node->children[i] == target)
+ result = G_GRAPH_NODE(node);
+ else
+ result = g_graph_node_find_container(node->children[i], target);
+ }
return result;
@@ -430,6 +694,59 @@ GGraphNode *g_virtual_node_get_child(const GVirtualNode *node, size_t index)
/******************************************************************************
* *
+* Paramètres : node = groupe de noeuds à mettre à jour. *
+* r1 = début de la portée à réserver. *
+* r2 = fin de la portée à réserver. *
+* left = désignation de la zone à traiter. *
+* *
+* Description : Réserve une portion de largeur pour un lien. *
+* *
+* Retour : Indice de la largeur adaptée et réservée. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+vspan_slot_t g_virtual_node_reserve_span(GVirtualNode *node, unsigned int r1, unsigned int r2, bool left)
+{
+ vspan_slot_t result; /* Identifiant à retourner */
+ reserved_vspan vspan; /* Portée à constituer */
+ vert_links **list; /* Liste à parcourir */
+ vspan_slot_t *count; /* Taille de cette liste */
+
+ vspan.r1 = r1;
+ vspan.r2 = r2;
+
+ if (left)
+ {
+ list = &node->left_padding;
+ count = &node->left_count;
+ }
+ else
+ {
+ list = &node->right_padding;
+ count = &node->right_count;
+ }
+
+ for (result = 0; result < *count; result++)
+ if (!is_intersection_with_vertical_spans(&(*list)[result], &vspan))
+ break;
+
+ if (result == *count)
+ {
+ *list = (vert_links *)realloc(*list, ++(*count) * sizeof(vert_links));
+ init_vertical_links(&(*list)[result]);
+ }
+
+ extend_vertical_links_spans(&(*list)[result], &vspan);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
* Paramètres : node = noeud d'encapsulation à traiter. *
* *
* Description : Organise le contenu du noeud selon l'axe des abscisses. *
@@ -456,9 +773,8 @@ void g_virtual_node_organize_x_line(GVirtualNode *node)
min = MIN(min, x);
}
- printf("min =%d\n", min);
-
- min = -min + GRAPH_LEFT_MARGIN;
+ node->x += GRAPH_HORIZONTAL_MARGIN;
+ min = -min + GRAPH_HORIZONTAL_MARGIN;
g_virtual_node_offset_x_line(node, min);
@@ -494,7 +810,7 @@ static void g_virtual_node_setup_x_line(GVirtualNode *node)
if (rank_0 == rank_1)
{
- g_graph_node_set_position(node->children[0], (gint []) { -(alloc.width / 2) }, NULL);
+ g_graph_node_set_position(node->children[0], (gint []) { 0/*-(alloc.width / 2)*/ }, NULL);
for (i = 1; i < node->count; i++)
{
@@ -530,9 +846,6 @@ static void g_virtual_node_setup_x_line(GVirtualNode *node)
if (!g_graph_node_has_x_position(child))
{
alloc = g_graph_node_get_allocation(child);
-
- printf("alloc ? %d\n", alloc.width);
-
g_graph_node_set_position(child, (gint []) { -(alloc.width / 2) }, NULL);
}
@@ -571,23 +884,80 @@ static void g_virtual_node_setup_x_line(GVirtualNode *node)
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] old=%d... ", child, x);
-
- x += xoffset;
+ x += xoffset + padding;
g_graph_node_set_position(child, &x, NULL);
- printf("next=%d...\n", x);
+ }
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = conteneur de noeuds à consulter. *
+* slot = numérod de la réservation. *
+* left = désignation de la zone à traiter. *
+* *
+* Description : Fournit la position horizontale obtenue par réservation. *
+* *
+* Retour : Abscisse à utiliser. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+gint g_virtual_node_get_x_for_vspan_slot(const GVirtualNode *node, vspan_slot_t slot, bool left)
+{
+ gint result; /* Position à retourner */
+ GtkAllocation alloc; /* Taille totale requise */
+
+ alloc = g_virtual_node_get_allocation(node);
+
+ if (left)
+ {
+ /*BUG_ON(slot >= node->left_count) */
+
+ result = (node->left_count - 1) * EDGE_HORIZONTAL_MIN_SEP/* + EDGE_SLOT_HORIZ_MARGIN*/;
+ result -= (slot * EDGE_HORIZONTAL_MIN_SEP/* + EDGE_SLOT_HORIZ_MARGIN*/);
+
+ result += alloc.x;
}
+ else
+ {
+ /*BUG_ON(slot >= node->right_count) */
+
+ result = /*EDGE_SLOT_HORIZ_MARGIN + */slot * EDGE_HORIZONTAL_MIN_SEP;
+
+ result += alloc.x + alloc.width/* - EDGE_SLOT_HORIZ_MARGIN*/;
+ if (node->right_count > 0)
+ result -= (node->right_count - 1) * EDGE_HORIZONTAL_MIN_SEP;
+
+ /* On pense à la largeur du trait... */
+ result -= 2;
+
+ }
+
+ return result;
}