diff options
Diffstat (limited to 'src/gtkext/graph/nodes')
-rw-r--r-- | src/gtkext/graph/nodes/flow.c | 41 | ||||
-rw-r--r-- | src/gtkext/graph/nodes/virtual.c | 410 | ||||
-rw-r--r-- | src/gtkext/graph/nodes/virtual.h | 12 |
3 files changed, 435 insertions, 28 deletions
diff --git a/src/gtkext/graph/nodes/flow.c b/src/gtkext/graph/nodes/flow.c index d4506ea..1848048 100644 --- a/src/gtkext/graph/nodes/flow.c +++ b/src/gtkext/graph/nodes/flow.c @@ -84,6 +84,9 @@ 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 *); @@ -159,6 +162,7 @@ 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; @@ -286,6 +290,32 @@ static unsigned int g_flow_node_get_rank(const GFlowNode *node) /****************************************************************************** * * * Paramètres : node = noeud graphique à manipuler. * +* * +* Description : Réinitialise la position d'un noeud d'encapsulation. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_flow_node_reset_position(GFlowNode *node) +{ + GtkRequisition requisition; /* Taille à l'écran actuelle */ + + node->alloc.x = UNINITIALIZED_NODE_POS; + node->alloc.y = UNINITIALIZED_NODE_POS; + + gtk_widget_size_request(GTK_WIDGET(node->view), &requisition); + + node->alloc.width = requisition.width; + node->alloc.height = requisition.height; + +} + +/****************************************************************************** +* * +* Paramètres : node = noeud graphique à manipuler. * * x = éventuelle abscisse à intégrer ou NULL. * * y = éventuelle ordonnée à intégrer ou NULL. * * * @@ -366,7 +396,7 @@ static GtkAllocation g_flow_node_get_allocation(const GFlowNode *node) static bool g_flow_node_visit_flow_nodes(GFlowNode *node, graph_node_visitor_cb callback, void *data) { - return callback(G_GRAPH_NODE(node), data); + return callback(G_GRAPH_NODE(node), GVS_NODE, data); } @@ -427,7 +457,7 @@ void g_flow_node_register_rank(const GFlowNode *node, GGraphRanks *ranks) { unsigned int index; /* Indice du rang associé */ - index = g_flow_block_get_next_rank(node->block); + index = g_flow_node_get_rank(node); g_graph_ranks_set_min_height(ranks, index, node->alloc.height); @@ -451,7 +481,7 @@ void g_flow_node_apply_rank(GFlowNode *node, GGraphRanks *ranks) { unsigned int index; /* Indice du rang associé */ - index = g_flow_block_get_next_rank(node->block); + index = g_flow_node_get_rank(node); node->alloc.y = g_graph_ranks_get_y_for_rank(ranks, index); @@ -534,11 +564,6 @@ void g_flow_node_link(GFlowNode *node, GGraphLayout *layout, GGraphNode *nodes) void g_flow_node_place(const GFlowNode *node, GtkGraphView *view) { - printf("alloc %p :: (%d ; %d) - (%d ; %d)\n", - node->view, - node->alloc.x, node->alloc.y, - node->alloc.width, node->alloc.height); - gtk_graph_view_put(view, GTK_WIDGET(node->view), &node->alloc); } 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; } diff --git a/src/gtkext/graph/nodes/virtual.h b/src/gtkext/graph/nodes/virtual.h index 440c675..20106b6 100644 --- a/src/gtkext/graph/nodes/virtual.h +++ b/src/gtkext/graph/nodes/virtual.h @@ -29,6 +29,12 @@ #include "../../../analysis/blocks/virtual.h" +/* Indice d'une hauteur au sein des rangs */ +typedef size_t vspan_slot_t; + +/* Indice non initilisé */ +#define UNINITIALIZED_VSPAN_SLOT (~((vspan_slot_t)0)) + #define G_TYPE_VIRTUAL_NODE g_virtual_node_get_type() #define G_VIRTUAL_NODE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), g_virtual_node_get_type(), GVirtualNode)) @@ -59,12 +65,18 @@ size_t g_virtual_node_count_children(const GVirtualNode *); /* Renvoie un des noeuds contenus dans le groupe courant. */ 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 *); /* 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); + #endif /* _GTKEXT_GRAPH_NODES_VIRTUAL_H */ |