/* Chrysalide - Outil d'analyse de fichiers binaires * panel.c - prototypes pour la gestion des éléments réactifs spécifiques aux panneaux * * Copyright (C) 2012-2014 Cyrille Bagard * * This file is part of Chrysalide. * * OpenIDA 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. * * OpenIDA 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "panel.h" #include #include #include #include #include "bookmarks.h" #include "glance.h" #include "history.h" #include "log.h" #include "panel-int.h" #include "regedit.h" #include "strings.h" #include "symbols.h" #include "../../common/extstr.h" #include "../../gtkext/easygtk.h" #include "../../gtkext/gtkdockable-int.h" #include "../../gtkext/gtkdockstation.h" /* Support de fond pour les composants. */ static GtkWidget *_support; static panel_node *_nodes = NULL; /* Procédure à appeler lors des changements de panneaux. */ static GCallback _handler; static gpointer _data; /* Liste des panneaux en place. */ static GPanelItem *_panels_list = NULL; /* Initialise la classe des éléments réactifs de l'éditeur. */ static void g_panel_item_class_init(GPanelItemClass *); /* Initialise une instance d'élément réactif pour l'éditeur. */ static void g_panel_item_init(GPanelItem *); /* Procède à l'initialisation de l'interface de rassemblement. */ static void g_panel_item_dockable_interface_init(GtkDockableInterface *); /* Fournit le nom court du composant encapsulable. */ static const char *gtk_panel_item_get_name(const GPanelItem *); /* Fournit le nom long du composant encapsulable. */ static const char *gtk_panel_item_get_desc(const GPanelItem *); /* Fournit le composant graphique intégrable dans un ensemble. */ static GtkWidget *gtk_panel_item_get_widget(GPanelItem *); /* ---------------------- MECANISMES DE PLACEMENT DES PANNEAUX ---------------------- */ /* Crée un nouveau noeud pour un panneau particulier. */ //static panel_node *create_simple_panel_node_for_item(GPanelItem *, const char *, size_t); /* Prépare une nouvelle sous-division pour deux panneaux. */ static void switch_panel_node_into_paned(panel_node *, bool, bool); /* Met en place un nouveau noeud dans une division. */ static void attach_panel_node_to_paned(panel_node *, panel_node *, bool); /* Crée un nouveau noeud pour un panneau particulier. */ static panel_node *create_simple_panel_node_for_item(GPanelItem *, const char *); /* Obtient la désignation d'un élément hiérarchie des noeuds. */ static char *get_panel_node_path(const panel_node *); /* Détermine la plus grande longueur commune entre éléments. */ static size_t compute_path_common_length(const panel_node *, const char *); /* Détermine la plus grande profondeur d'un noeud de panneaux. */ static unsigned int compute_deepest_depth(const panel_node *); /* Place au bon endroit un panneau donné. */ static void insert_item_as_panel_node(GPanelItem *, panel_node *, const char *, size_t); /* Tente de mettre la main sur une station d'accueil. */ static panel_node *find_node_for_station(panel_node *, GtkWidget *); /* Efface de l'organisation un noeud donné en place. */ static void delete_panel_node(panel_node *); /* Indique le type défini pour un élément destiné à un panneau. */ G_DEFINE_TYPE_WITH_CODE(GPanelItem, g_panel_item, G_TYPE_EDITOR_ITEM, G_IMPLEMENT_INTERFACE(GTK_TYPE_DOCKABLE, g_panel_item_dockable_interface_init)) /****************************************************************************** * * * Paramètres : klass = classe à initialiser. * * * * Description : Initialise la classe des éléments réactifs de l'éditeur. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_panel_item_class_init(GPanelItemClass *klass) { } /****************************************************************************** * * * Paramètres : item = instance à initialiser. * * * * Description : Initialise une instance d'élément réactif pour l'éditeur. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_panel_item_init(GPanelItem *item) { DL_LIST_ITEM_INIT(&item->link); item->personality = PIP_INVALID; } /****************************************************************************** * * * Paramètres : iface = interface GTK à initialiser. * * * * Description : Procède à l'initialisation de l'interface de rassemblement. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_panel_item_dockable_interface_init(GtkDockableInterface *iface) { iface->can_search = false; iface->can_be_closed = true; iface->get_name = (get_dockable_name_fc)gtk_panel_item_get_name; iface->get_desc = (get_dockable_desc_fc)gtk_panel_item_get_desc; iface->get_widget = (get_dockable_widget_fc)gtk_panel_item_get_widget; iface->update_filtered = (update_filtered_data_fc)NULL; } /****************************************************************************** * * * Paramètres : item = composant à présenter à l'affichage. * * ref = espace de référencement global. * * name = nom associé à l'élément. * * lname = description longue du panneau. * * widget = composant à présenter à l'affichage. * * path = chemin vers la place idéale pour le futur panneau. * * * * Description : Initialise dynamique les propriétés de l'instance. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_panel_item_init_ext(GPanelItem *item, GObject *ref, const char *name, const char *lname, GtkWidget *widget, const char *path) { GEditorItem *parent; /* Autre version de l'élément */ parent = G_EDITOR_ITEM(item); g_object_ref(ref); parent->ref = ref; parent->name = name; item->lname = lname; g_object_ref(widget); parent->widget = widget; g_object_set_data(G_OBJECT(widget), "pitem", item); item->path = path; panels_list_add_tail(item, &_panels_list); gtk_dockable_setup_dnd(GTK_DOCKABLE(item)); } /****************************************************************************** * * * Paramètres : personality = nature du panneau à mettre en place. * * ref = espace de référencement global. * * name = nom associé à l'élément. * * lname = description longue du panneau. * * widget = composant à présenter à l'affichage. * * path = chemin vers la place idéale pour le futur panneau. * * * * Description : Crée un élément de panneau réactif. * * * * Retour : Adresse de la structure mise en place. * * * * Remarques : - * * * ******************************************************************************/ GEditorItem *g_panel_item_new(PanelItemPersonality personality, GObject *ref, const char *name, const char *lname, GtkWidget *widget, const char *path) { GPanelItem *result; /* Structure à retourner */ result = g_object_new(G_TYPE_PANEL_ITEM, NULL); assert(personality > PIP_INVALID && personality < PIP_COUNT); result->personality = personality; g_panel_item_init_ext(result, ref, name, lname, widget, path); return G_EDITOR_ITEM(result); } /****************************************************************************** * * * Paramètres : item = instance GTK dont l'interface est à consulter. * * * * Description : Fournit le nom court du composant encapsulable. * * * * Retour : Désignation humaine pour titre d'onglet ou de fenêtre. * * * * Remarques : - * * * ******************************************************************************/ static const char *gtk_panel_item_get_name(const GPanelItem *item) { return G_EDITOR_ITEM(item)->name; } /****************************************************************************** * * * Paramètres : item = instance GTK dont l'interface est à consulter. * * * * Description : Fournit le nom long du composant encapsulable. * * * * Retour : Désignation humaine pour titre d'onglet ou de fenêtre. * * * * Remarques : - * * * ******************************************************************************/ static const char *gtk_panel_item_get_desc(const GPanelItem *item) { return item->lname; } /****************************************************************************** * * * Paramètres : item = instance GTK dont l'interface est à consulter. * * * * Description : Fournit le composant graphique intégrable dans un ensemble. * * * * Retour : Composant graphique prêt à emploi. * * * * Remarques : - * * * ******************************************************************************/ static GtkWidget *gtk_panel_item_get_widget(GPanelItem *item) { return G_EDITOR_ITEM(item)->widget; } /****************************************************************************** * * * Paramètres : item = instance GTK à consulter. * * * * Description : Fournit une indication sur la personnalité du panneau. * * * * Retour : Identifiant lié à la nature du panneau. * * * * Remarques : - * * * ******************************************************************************/ PanelItemPersonality gtk_panel_item_get_personality(const GPanelItem *item) { return item->personality; } /****************************************************************************** * * * Paramètres : item = instance GTK dont l'interface est à consulter. * * * * Description : Indique la définition d'un éventuel raccourci clavier. * * * * Retour : Description d'un raccourci ou NULL si aucun de défini. * * * * Remarques : - * * * ******************************************************************************/ const char *gtk_panel_item_get_key_bindings(const GPanelItem *item) { return G_PANEL_ITEM_GET_CLASS(item)->bindings; } /****************************************************************************** * * * Paramètres : name = désignation courte servant de clef. * * * * Description : Recherche un panneau à partir de son nom court. * * * * Retour : Panneau trouvé ou NULL si aucun. * * * * Remarques : Le parcours peut se faire aussi depuis la classe parente, * * mais il est plus rapide par ici. * * * ******************************************************************************/ GPanelItem *g_panel_item_get(const char *name) { GPanelItem *iter; /* Boucle de parcours */ panels_list_for_each(iter, _panels_list) { if (strcmp(G_EDITOR_ITEM(iter)->name, name) == 0) return iter; } return NULL; } /****************************************************************************** * * * Paramètres : item = composant à présenter à l'affichage. * * * * Description : Place un panneau dans l'ensemble affiché. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void dump_tree(GtkWidget *root, unsigned int level) { unsigned int i; GList *list; GList *iter; if (strcmp(G_OBJECT_TYPE_NAME(G_OBJECT(root)), "GtkButton") == 0) return; for (i = 0; i < level; i++) fprintf(stderr, " "); fprintf(stderr, "%s (%p)\n", G_OBJECT_TYPE_NAME(G_OBJECT(root)), root); if (GTK_IS_CONTAINER(root)) { list = gtk_container_get_children(GTK_CONTAINER(root)); for (iter = list; iter != NULL; iter = g_list_next(iter)) dump_tree(GTK_WIDGET(iter->data), level + 1); } } void dump_node(panel_node *node, unsigned int level) { unsigned i; for (i = 0; i < level; i++) fprintf(stderr, " "); fprintf(stderr, "%p %p -- widget %p -- '%s'\n", node->parent, node, node->station, IS_SIMPLE_NODE(node) ? node->path : "-"); if (!IS_SIMPLE_NODE(node)) { dump_node(node->first, level + 1); dump_node(node->second, level + 1); } } void g_panel_item_dock(GPanelItem *item) { assert(!item->docked); fprintf(stderr, "\n---------\n\n"); /* Tout est à faire... */ if (_nodes == NULL) { _nodes = create_simple_panel_node_for_item(item, item->path); gtk_container_add(GTK_CONTAINER(_support), _nodes->widget); } else insert_item_as_panel_node(item, _nodes, item->path, 0); item->docked = true; dump_tree(_support, 0); fprintf(stderr, "\n"); dump_node(_nodes, 0); } /****************************************************************************** * * * Paramètres : item = composant d'affichage à consulter. * * * * Description : Indique si le composant repose sur un support de l'éditeur. * * * * Retour : true si le composant est bien incrusté quelque part. * * * * Remarques : - * * * ******************************************************************************/ bool g_panel_item_is_docked(const GPanelItem *item) { return item->docked; } /****************************************************************************** * * * Paramètres : item = composant à retirer de l'affichage. * * * * Description : Supprime un panneau de l'ensemble affiché. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_panel_item_undock(GPanelItem *item) { GtkWidget *station; /* Support courant */ panel_node *node; /* Noeud à supprimer */ assert(item->docked); gtk_dockable_decompose(GTK_DOCKABLE(item), &station); gtk_dock_station_remove_dockable(GTK_DOCK_STATION(station), GTK_DOCKABLE(item)); if (gtk_notebook_get_n_pages(GTK_NOTEBOOK(station)) == 0) { node = find_node_for_station(_nodes, station); assert(node != NULL); delete_panel_node(node); } item->docked = false; } /* ---------------------------------------------------------------------------------- */ /* PLACEMENTS DES DIFFERENTS PANNEAUX */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * * Paramètres : handler = procédure à réveiller en cas de changements. * * data = donnée à faire suivre. * * * * Description : Prépare le terrain pour l'affichage central. * * * * Retour : Composant de support sur lequel tout va se placer. * * * * Remarques : - * * * ******************************************************************************/ GtkWidget *init_panels2(GCallback handler, gpointer data) { GtkWidget *result; /* Support à retourner */ result = gtk_event_box_new(); gtk_widget_show(result); //g_signal_connect(result, "size-allocate", G_CALLBACK(auto_resize_panels), NULL); _support = result; _handler = handler; _data = data; return result; } /****************************************************************************** * * * Paramètres : ref = espace de référencement global. * * * * Description : Charge les principaux panneaux de l'éditeur. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void load_main_panels(GObject *ref) { GPanelItem *item; /* Panneau de base à charger */ item = create_log_panel(ref); g_panel_item_dock(item); item = create_regedit_panel(ref); g_panel_item_dock(item); item = create_symbols_panel(ref); g_panel_item_dock(item); item = create_history_panel(ref); g_panel_item_dock(item); item = create_strings_panel(ref); g_panel_item_dock(item); item = create_glance_panel(ref); g_panel_item_dock(item); item = create_bookmarks_panel(ref); g_panel_item_dock(item); } /****************************************************************************** * * * Paramètres : handle = routine à appeler pour chaque panneau. * * data = données fournies pour accompagner cet appel. * * * * Description : Effectue le parcours de tous les panneaux chargés. * * * * Retour : true si le parcours a été total, false sinon. * * * * Remarques : - * * * ******************************************************************************/ bool browse_all_item_panels(handle_panel_item_fc handle, void *data) { bool result; /* Résultat à renvoyer */ GPanelItem *iter; /* Boucle de parcours */ result = true; panels_list_for_each(iter, _panels_list) { result = handle(iter, data); if (!result) break; } return result; } /* ---------------------------------------------------------------------------------- */ /* MECANISMES DE PLACEMENT DES PANNEAUX */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * * Paramètres : node = noeud à diviser. * * horiz = indique le type d'orientation désiré. * * first = indication sur l'emplacement à utiliser. * * * * Description : Prépare une nouvelle sous-division pour deux panneaux. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void switch_panel_node_into_paned(panel_node *node, bool horiz, bool first) { GtkWidget *widget; /* Composant à traiter */ panel_node *parent; /* Lien de parenté à conserver */ panel_node *moved; /* Noeud descendu d'un étage */ /* Décroche graphiquement le support */ widget = node->widget; g_object_ref(G_OBJECT(widget)); gtk_container_remove(GTK_CONTAINER(gtk_widget_get_parent(widget)), widget); /* Descend l'élément actuel */ parent = node->parent; moved = (panel_node *)calloc(1, sizeof(panel_node)); memcpy(moved, node, sizeof(panel_node)); if (!IS_SIMPLE_NODE(moved)) { moved->first->parent = moved; moved->second->parent = moved; } /* Création du nouveau niveau intermédiaire */ if (horiz) node->paned = gtk_paned_new(GTK_ORIENTATION_HORIZONTAL); else node->paned = gtk_paned_new(GTK_ORIENTATION_VERTICAL); gtk_widget_show(node->paned); if (parent == NULL) attach_panel_node_to_paned(parent, node, true); else attach_panel_node_to_paned(parent, node, parent->first == node); /* Premier ajustement */ void split_paned_support(GtkWidget *support, GdkRectangle *alloc, gpointer data) { GtkOrientation orientation; gint position; orientation = gtk_orientable_get_orientation(GTK_ORIENTABLE(support)); if (orientation == GTK_ORIENTATION_HORIZONTAL) position = alloc->width / 2; else position = alloc->height / 2; /* if (position < 50) position *= 2; */ gtk_paned_set_position(GTK_PANED(support), position); fprintf(stderr, "widget size is currently %dx%d\n", alloc->width, alloc->height); fprintf(stderr, "position = %d\n", position); fprintf(stderr, "---\n"); g_signal_handlers_disconnect_by_func(support, G_CALLBACK(split_paned_support), NULL); } //g_signal_connect(current->paned, "size-allocate", G_CALLBACK(split_paned_support), NULL); static int __counter = 0; if (++__counter == 4) gtk_paned_set_position(GTK_PANED(node->paned), 100); /* Replace le composant d'origine */ attach_panel_node_to_paned(node, moved, first); } /****************************************************************************** * * * Paramètres : parent = noeud d'accueil pour le nouveau noeud. * * node = nouveau noeud à intégrer dans l'ensemble. * * first = indication sur l'emplacement à utiliser. * * * * Description : Met en place un nouveau noeud dans une division. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void attach_panel_node_to_paned(panel_node *parent, panel_node *node, bool first) { node->parent = parent; /* On se trouve à la racine... */ if (parent == NULL) gtk_container_add(GTK_CONTAINER(_support), node->widget); else { /* Raccordement hiérarchique */ if (first) parent->first = node; else parent->second = node; /* Raccordement graphique */ assert(!IS_SIMPLE_NODE(parent)); if (first) gtk_paned_pack1(GTK_PANED(parent->paned), node->widget, TRUE, FALSE); else gtk_paned_pack2(GTK_PANED(parent->paned), node->widget, TRUE, FALSE); } } ////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////// /****************************************************************************** * * * Paramètres : item = composant à présenter à l'affichage. * * path = partie du chemin représentée ici. * * * * Description : Crée un nouveau noeud pour un panneau particulier. * * * * Retour : Structure d'accueil mise en place. * * * * Remarques : - * * * ******************************************************************************/ static panel_node *create_simple_panel_node_for_item(GPanelItem *item, const char *path) { panel_node *result; /* Structure à retourner */ GtkWidget *station; /* Premier support concentré */ /* Partie graphique */ station = gtk_dock_station_new(); g_signal_connect(station, "switch-widget", _handler, _data); gtk_widget_show(station); gtk_dock_station_add_dockable(GTK_DOCK_STATION(station), GTK_DOCKABLE(item)); /* Partie invisible */ result = (panel_node *)calloc(1, sizeof(panel_node)); result->station = station; result->path = strdup(path); return result; } /****************************************************************************** * * * Paramètres : node = noeud dont la désignation est à obtenir. * * * * Description : Obtient la désignation d'un élément hiérarchie des noeuds. * * * * Retour : Chaîne construite à libérer de la mémoire après usage. * * * * Remarques : - * * * ******************************************************************************/ static char *get_panel_node_path(const panel_node *node) { char *result; /* Valeur à retourner */ char *extra; /* Complément à ajouter */ if (IS_SIMPLE_NODE(node)) result = strdup(node->path); else { result = get_panel_node_path(node->first); extra = get_panel_node_path(node->second); result = stradd(result, "-"); result = stradd(result, extra); free(extra); result = strprep(result, "("); result = stradd(result, ")"); } return result; } /****************************************************************************** * * * Paramètres : node = noeud d'où lancer les recherches. * * target = identifiant de la position visée. * * * * Description : Détermine la plus grande longueur commune entre éléments. * * * * Retour : Bilan de l'évaluation. * * * * Remarques : - * * * ******************************************************************************/ static size_t compute_path_common_length(const panel_node *node, const char *target) { size_t result; /* Taille à retourner */ size_t len; /* Longueur de comparaison */ size_t common1; /* Tron common avec le côté #1 */ size_t common2; /* Tron common avec le côté #2 */ if (IS_SIMPLE_NODE(node)) { len = MIN(strlen(node->path), strlen(target)); /** * Il n'y a pas forcément de base commune entre deux branches, * donc on parcourt les chemins depuis leur base respective. */ for (result = 0; result < len; result++) if (node->path[result] != target[result]) break; } else { common1 = compute_path_common_length(node->first, target); common2 = compute_path_common_length(node->second, target); result = MAX(common1, common2); } return result; } /****************************************************************************** * * * Paramètres : node = noeud d'où lancer les mesures. * * * * Description : Détermine la plus grande profondeur d'un noeud de panneaux. * * * * Retour : Valeur strictement positive. * * * * Remarques : - * * * ******************************************************************************/ static unsigned int compute_deepest_depth(const panel_node *node) { unsigned int result; /* Profondeur à renvoyer */ unsigned int depth1; /* Profondeur du côté #1 */ unsigned int depth2; /* Profondeur du côté #2 */ if (IS_SIMPLE_NODE(node)) result = 1; else { depth1 = compute_deepest_depth(node->first); depth2 = compute_deepest_depth(node->second); result = MAX(depth1, depth2); } return result; } /****************************************************************************** * * * Paramètres : item = composant à présenter à l'affichage. * * node = point d'insertion courant. * * path = partie du chemin représentée ici. * * consumed = profondeur du chemin utilisé. * * * * Description : Place au bon endroit un panneau donné. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void insert_item_as_panel_node(GPanelItem *item, panel_node *node, const char *path, size_t consumed) { char div; /* Division demandée */ bool horiz; /* Traduction en composant */ bool first; /* Point d'insertion */ panel_node *new; /* Nouveau noeud créé */ size_t common1; /* Tron common avec le côté #1 */ size_t common2; /* Tron common avec le côté #2 */ fprintf(stderr, "=== INSERTING '%s' (%zu)... -> '%s'\n", path, consumed, IS_SIMPLE_NODE(node) ? node->path : "-"); if (IS_SIMPLE_NODE(node)) { /* Le parcours s'arrête ici ! */ if (strcmp(node->path, path) == 0) gtk_dock_station_add_dockable(GTK_DOCK_STATION(node->station), GTK_DOCKABLE(item)); /* On ne peut aller plus loin, on doit diviser... */ else { div = toupper(path[consumed]); first = (div == 'W' || div == 'N'); horiz = (div == 'W' || div == 'E'); fprintf(stderr, "---%%<--- first=%d horiz=%d\n", first, horiz); fprintf(stderr, "--- cutting %p\n", node->station); switch_panel_node_into_paned(node, horiz, !first); new = create_simple_panel_node_for_item(item, path); attach_panel_node_to_paned(node, new, first); fprintf(stderr, "1# [%p] widget = %p --- split :: %p // %p\n", node, node->station, node->first, node->second); } } /* On regarde des autres côtés... */ else { common1 = compute_path_common_length(node->first, path); common2 = compute_path_common_length(node->second, path); fprintf(stderr, " - L1 :: %zu <-> '%s'\n", common1, get_panel_node_path(node->first)); fprintf(stderr, " - L2 :: %zu <-> '%s'\n", common2, get_panel_node_path(node->second)); /* Si une descente est possible... */ if (common1 > 0 || common2 > 0) { if (common1 > common2) insert_item_as_panel_node(item, node->first, path, common1); else insert_item_as_panel_node(item, node->second, path, common2); } /* Sinon, on doit diviser qqch... */ else { div = toupper(path[consumed]); first = (div == 'W' || div == 'N'); horiz = (div == 'W' || div == 'E'); fprintf(stderr, "---%%<--- first=%d horiz=%d\n", first, horiz); switch_panel_node_into_paned(node, horiz, !first); new = create_simple_panel_node_for_item(item, path); attach_panel_node_to_paned(node, new, first); fprintf(stderr, "2# [%p] split :: %p-%p // %p-%p\n", node, node->first, node->first->widget, node->second, node->second->widget); } } } /****************************************************************************** * * * Paramètres : node = point de départ des recherches locales. * * * * Description : Tente de mettre la main sur une station d'accueil. * * * * Retour : Eventuel noeud trouvé ou NULL. * * * * Remarques : - * * * ******************************************************************************/ static panel_node *find_node_for_station(panel_node *node, GtkWidget *station) { panel_node *result; /* Bilan à remonter */ if (IS_SIMPLE_NODE(node)) result = (node->station == station ? node : NULL); else { result = find_node_for_station(node->first, station); if (result == NULL) result = find_node_for_station(node->second, station); } return result; } /****************************************************************************** * * * Paramètres : node = noeud à supprimer de l'arbre des noeuds. * * * * Description : Efface de l'organisation un noeud donné en place. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void delete_panel_node(panel_node *node) { panel_node *parent; /* Noeud parent à transformer */ GtkWidget *widget; /* Composant à traiter */ panel_node *grandparent; /* Noeud supérieur au parent */ panel_node *remaining; /* Noeud restant */ assert(IS_SIMPLE_NODE(node)); parent = node->parent; /* Destruction du noeud */ widget = node->station; gtk_container_remove(GTK_CONTAINER(gtk_widget_get_parent(widget)), widget); free(node->path); free(node); /* Suppression du niveau intermédiaire */ if (parent != NULL) { remaining = (node == parent->first ? parent->second : parent->first); /* Décroche graphiquement le support */ widget = remaining->widget; g_object_ref(G_OBJECT(widget)); gtk_container_remove(GTK_CONTAINER(parent->paned), widget); /* Supprime le composant graphique intermédiaire */ gtk_container_remove(GTK_CONTAINER(gtk_widget_get_parent(parent->paned)), parent->paned); /* Réinsère la partie restante */ grandparent = parent->parent; memcpy(parent, remaining, sizeof(panel_node)); if (!IS_SIMPLE_NODE(parent)) { parent->first->parent = parent; parent->second->parent = parent; } free(remaining); if (grandparent == NULL) attach_panel_node_to_paned(grandparent, parent, true); else attach_panel_node_to_paned(grandparent, parent, grandparent->first == parent); } } #if 1 #include "../../core/params.h" /****************************************************************************** * * * Paramètres : current = point de départ de la réorganisation graphique. * * * * Description : Met à jour l'affichage suite à un changement hiérarchique. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void save_panel_nodes(void) { fprintf(stderr, "Passage avec %p\n", _nodes); return; void store_handle_position(panel_node *node, GGenConfig *config) { size_t i; for (i = 0; i < 0/*node->depth*/; i++) fprintf(stderr, " "); ///fprintf(stderr, "[%s] %s\n", node->path, node->simple ? "[+]" : ">>"); if (0/*!node->simple*/) { store_handle_position(node->first, config); store_handle_position(node->second, config); } } //get_main_configuration() store_handle_position(_nodes, NULL); fflush(NULL); } #endif