diff options
Diffstat (limited to 'src/gui/editor.c')
-rw-r--r-- | src/gui/editor.c | 777 |
1 files changed, 774 insertions, 3 deletions
diff --git a/src/gui/editor.c b/src/gui/editor.c index 6f5ef7a..bcbdfe1 100644 --- a/src/gui/editor.c +++ b/src/gui/editor.c @@ -25,6 +25,10 @@ #include "editor.h" +#include <assert.h> +#include <ctype.h> + + #include <i18n.h> @@ -34,6 +38,7 @@ #include "tb/portions.h" #include "tb/source.h" #include "../analysis/project.h" +#include "../common/extstr.h" #include "../core/params.h" #include "../gtkext/easygtk.h" #include "../gtkext/gtkdockable.h" @@ -80,6 +85,95 @@ static GtkWidget *build_editor_toolbar(GObject *); +/* -------------------- MECANISMES DE (DE)PLACEMENT DES PANNEAUX -------------------- */ + + +/* Elément de la hiérarchie des panneaux */ +typedef struct _panel_node +{ + struct _panel_node *parent; /* Noeud parent */ + + union + { + GtkWidget *widget; /* Accès généraliste */ + GtkWidget *station; /* Station d'accueil simple */ + GtkWidget *paned; /* Station d'accueil composée */ + + }; + + union + { + /* Version simple */ + struct + { + char *path; /* Chemin du nom courant */ + }; + + /* Version composée */ + struct + { + struct _panel_node *first; /* Premier sous élément */ + struct _panel_node *second; /* Second sous élément */ + }; + + }; + +} panel_node; + + +#define IS_SIMPLE_NODE(nd) \ + ({ \ + bool __result; \ + __result = GTK_IS_DOCK_STATION(nd->station); \ + assert(__result || GTK_IS_PANED(nd->paned)); \ + __result; \ + }) + + +/* Support de fond pour les composants. */ +static GObject *_global_ref = NULL; +static GtkWidget *_support = NULL; +static panel_node *_nodes = NULL; + + +/* Crée un nouveau noeud pour un panneau particulier. */ +static panel_node *create_simple_panel_node_for_item(GPanelItem *, const char *); + +/* 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); + +/* 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 *); + +/* 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 *); + + + +/* ------------------- INTERACTIONS GRAPHIQUES LIEES AUX PANNEAUX ------------------- */ + + +/* Réagit à une demande de placement d'un panneau d'affichage. */ +void on_panel_item_dock_request(GPanelItem *, void *); + +/* Réagit à une demande de suppression d'un panneau d'affichage. */ +void on_panel_item_undock_request(GPanelItem *, void *); + + + + /****************************************************************************** * * @@ -204,10 +298,12 @@ GtkWidget *create_editor(void) do { - GtkWidget *support; + _global_ref = ref; + _support = gtk_event_box_new(); + gtk_widget_show(_support); - support = init_panels2(G_CALLBACK(on_dock_item_switch), ref); - gtk_box_pack_start(GTK_BOX(vbox1), support, TRUE, TRUE, 0); + //_support = init_panels2(G_CALLBACK(on_dock_item_switch), ref); + gtk_box_pack_start(GTK_BOX(vbox1), _support, TRUE, TRUE, 0); load_main_panels(ref); @@ -324,6 +420,11 @@ static void on_destroy_editor(GtkWidget *widget, gpointer data) project = get_current_project(); if (project != NULL) g_object_unref(G_OBJECT(project)); + //if (!result) + save_panel_nodes(); + + + /* Fermeture propre */ /* ... */ @@ -448,3 +549,673 @@ static GtkWidget *build_editor_toolbar(GObject *ref) return result; } + + + + + + + + + + + + + + + + + + +/* ---------------------------------------------------------------------------------- */ +/* MECANISMES DE (DE)PLACEMENT DES PANNEAUX */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* 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", G_CALLBACK(on_dock_item_switch), _global_ref); + 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 à 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 : 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 : 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 + + + + + +/* ---------------------------------------------------------------------------------- */ +/* INTERACTIONS GRAPHIQUES LIEES AUX PANNEAUX */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : item = composant à retirer de l'affichage. * +* unused = adresse non utilisée ici. * +* * +* Description : Réagit à une demande de placement d'un panneau d'affichage. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void on_panel_item_dock_request(GPanelItem *item, void *unused) +{ + const char *path; /* Chemin d'accès */ + + path = gtk_panel_item_get_path(item); + + /* Tout est à faire... */ + if (_nodes == NULL) + { + _nodes = create_simple_panel_node_for_item(item, path); + gtk_container_add(GTK_CONTAINER(_support), _nodes->widget); + } + else insert_item_as_panel_node(item, _nodes, path, 0); + + g_panel_item_set_dock_status(item, true); + +} + + +/****************************************************************************** +* * +* Paramètres : item = composant à retirer de l'affichage. * +* unused = adresse non utilisée ici. * +* * +* Description : Réagit à une demande de suppression d'un panneau d'affichage.* +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void on_panel_item_undock_request(GPanelItem *item, void *unused) +{ + GtkWidget *station; /* Support courant */ + panel_node *node; /* Noeud à supprimer */ + + 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); + + } + + g_panel_item_set_dock_status(item, false); + +} |