/* Chrysalide - Outil d'analyse de fichiers binaires * vspace.c - encadrement des espaces verticaux réservés * * Copyright (C) 2019 Cyrille Bagard * * This file is part of Chrysalide. * * Chrysalide is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * Chrysalide is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Chrysalide. If not, see . */ #include "vspace.h" #include #include "cluster-int.h" /****************************************************************************** * * * Paramètres : manager = structure à initialiser. * * * * Description : Initialise les réservations liens verticaux. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void init_vspace_manager(vspace_manager_t *manager) { manager->pending = NULL; manager->pending_count = 0; manager->left = NULL; manager->left_count = 0; manager->right = NULL; manager->right_count = 0; } /****************************************************************************** * * * Paramètres : manager = structure à vider. * * * * Description : Termine les réservations liens verticaux. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void exit_vspace_manager(vspace_manager_t *manager) { size_t i; /* Boucle de parcours */ for (i = 0; i < manager->pending_count; i++) free(manager->pending[i].pts); if (manager->pending != NULL) free(manager->pending); if (manager->left != NULL) free(manager->left); if (manager->right != NULL) free(manager->right); } /****************************************************************************** * * * Paramètres : manager = structure à compléter. * * from = point de départ du lien concerné. * * to = point d'arrivée du lien concerné. * * pts = points intermédiaires du tracé complet final. * * external = précise une sortie du cadre du cluster premier. * * * * Description : Inscrit une nouvelle réservation d'espace latéral. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void extend_vspace_manager(vspace_manager_t *manager, leaving_link_t *from, incoming_link_t *to, GdkPoint *pts, bool external) { vspace_booking_t *new; /* Réservation à constituer */ manager->pending = realloc(manager->pending, ++manager->pending_count * sizeof(vspace_booking_t)); new = &manager->pending[manager->pending_count - 1]; new->from = from; new->to = to; new->pts = pts; new->external = external; } /****************************************************************************** * * * Paramètres : manager = gestion des espaces latéraux à consulter. * * external = précise une sortie du cadre du cluster premier. * * alloc = emplacement idéal pour l'affichage. [OUT] * * * * Description : Détermine l'emplacement requis pour les espaces latéraux. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void compute_vspace_manager_needed_alloc(const vspace_manager_t *manager, bool external, GtkAllocation *alloc) { gint width; /* Largeur supplémentaire */ size_t count; /* Nombre de liens retenus */ size_t i; /* Boucle de parcours */ width = 0; /* Extension de la largeur, à gauche */ count = 0; for (i = 0; i < manager->left_count; i++) if (manager->left[i]->external == external) count++; width += count * LINK_MARGIN; alloc->x -= width; /* Extension de la largeur, à droite */ count = 0; for (i = 0; i < manager->right_count; i++) if (manager->right[i]->external == external) count++; width += count * LINK_MARGIN; alloc->width += width; /* Extension de la hauteur */ if (!external) alloc->height += manager->pending_count * VERTICAL_MARGIN; } /****************************************************************************** * * * Paramètres : manager = gestion d'espaces latéraux à manipuler. * * * * Description : Réorganise au besoin les liens de boucle entre blocs. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void sort_incoming_links_for_vspace_manager(vspace_manager_t *manager) { size_t i; /* Boucle de parcours */ vspace_booking_t *pending; /* Elément traité */ gint x1; /* Abscisse de départ de lien */ size_t idx; /* Indice du lien entrant */ gint x2; /* Abscisse d'arrivée de lien */ bool for_left; /* Répartition par la gauche ? */ for (i = 0; i < manager->pending_count; i++) { pending = &manager->pending[i]; x1 = g_graph_cluster_compute_leaving_link_position(pending->from->owner, pending->from->index); idx = g_graph_cluster_find_incoming_link(pending->to->owner, pending->from); x2 = g_graph_cluster_compute_incoming_link_position(pending->to->owner, idx); /** * Prise en compte d'une boucle while (1); */ if (pending->from->owner == pending->to->owner) for_left = (x2 < x1); else for_left = (x1 < x2); if (for_left) { manager->left = realloc(manager->left, ++manager->left_count * sizeof(vspace_booking_t *)); manager->left[manager->left_count - 1] = pending; } else { manager->right = realloc(manager->right, ++manager->right_count * sizeof(vspace_booking_t *)); manager->right[manager->right_count - 1] = pending; } } } /****************************************************************************** * * * Paramètres : manager = structure à actualiser. * * offset = décalage à appliquer. * * * * Description : Décale vers la droite un ensemble de points. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void offset_x_vspace_manager(vspace_manager_t *manager, gint offset) { size_t i; /* Boucle de parcours */ vspace_booking_t *booking; /* Réservation à traiter */ for (i = 0; i < manager->left_count; i++) { booking = manager->left[i]; booking->pts[0].x += offset; booking->pts[1].x += offset; } for (i = 0; i < manager->right_count; i++) { booking = manager->right[i]; booking->pts[0].x += offset; booking->pts[1].x += offset; } } /****************************************************************************** * * * Paramètres : manager = structure à consulter. * * needed = espace nécessaire et alloué pour les blocs. * * external = précise une sortie du cadre du cluster premier. * * * * Description : Détermine les abscisses de tous les liens en place. * * * * Retour : Eventuelle marge à gauche devenue nécessaire. * * * * Remarques : - * * * ******************************************************************************/ gint compute_loop_link_x_with_vspace_manager(const vspace_manager_t *manager, const GtkAllocation *needed, bool external) { gint result; /* Eventuelle marge à renvoyer */ size_t count; /* Quantité de liens traités */ size_t i; /* Boucle de parcours */ vspace_booking_t *booking; /* Réservation à traiter */ gint x; /* Position à appliquer */ count = 0; for (i = 0; i < manager->left_count; i++) { booking = manager->left[i]; if (booking->external != external) continue; x = ++count * LINK_MARGIN; booking->pts[0].x = needed->x - x; booking->pts[1].x = needed->x - x; } result = count * LINK_MARGIN; count = 0; for (i = 0; i < manager->right_count; i++) { booking = manager->right[i]; if (booking->external != external) continue; x = ++count * LINK_MARGIN; booking->pts[0].x = needed->x + needed->width + x; booking->pts[1].x = needed->x + needed->width + x; } return result; } /****************************************************************************** * * * Paramètres : manager = structure à consulter. * * needed = espace nécessaire et alloué pour les blocs. * * * * Description : Détermine les ordonnées de tous les liens en place. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void compute_loop_link_y_with_vspace_manager(const vspace_manager_t *manager, const GtkAllocation *needed) { gint real_bottom; /* Point de départ réel */ size_t i; /* Boucle de parcours */ vspace_booking_t *booking; /* Réservation à traiter */ real_bottom = needed->y + needed->height - manager->pending_count * VERTICAL_MARGIN; for (i = 0; i < manager->pending_count; i++) { booking = &manager->pending[i]; /** * On corrige le raccourci pris sans distinction de type de lien dans * la fonction g_graph_cluster_compute_link_y_positions(). */ booking->from->start[1].y = real_bottom + (i + 1) * VERTICAL_MARGIN; /* Définition de l'ordonnée des points du lien */ booking->pts[0].y = booking->from->start[1].y; booking->pts[1].y = booking->to->end[0].y; } }