summaryrefslogtreecommitdiff
path: root/src/gui/editor.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/editor.c')
-rw-r--r--src/gui/editor.c777
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);
+
+}