/* Chrysalide - Outil d'analyse de fichiers binaires
* preferences.c - (re)définition de l'identité de l'utilisateur
*
* 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 "preferences.h"
#include
#include "prefs_fgraph.h"
#include "prefs_labels.h"
#include "../../core/params.h"
/* Constructeur de panneau de paramétrage */
typedef GtkWidget * (* prefs_panel_creation_cb) (GtkBuilder **);
/* Chargement de la configuration */
typedef void (* prefs_config_update_cb) (GtkBuilder *, GGenConfig *);
/* Description d'un noeud de préférences */
typedef struct _pref_node_desc_t
{
prefs_panel_creation_cb create; /* Procédure de création */
prefs_config_update_cb load; /* Procédure de chargement */
prefs_config_update_cb store; /* Procédure d'enregistrement */
const char *name; /* Désignation interne */
const char *title; /* Désignation humaine */
GtkBuilder *builder; /* Constructeur GTK */
GtkWidget *panel; /* Panneau GTK */
struct _pref_node_desc_t *children; /* Sous-arborescence */
} pref_node_desc_t;
#define PREF_NODE_NULL_ENTRY { .title = NULL }
/* Liste des paramétrages à afficher */
static pref_node_desc_t _prefs_nodes[] = {
{
.create = NULL,
.title = "Analysis",
.children = (pref_node_desc_t []){
{
.create = create_labels_preferences,
.load = load_labels_configuration,
.store = store_labels_configuration,
.name = "labels",
.title = "Colored labels",
},
PREF_NODE_NULL_ENTRY
}
},
{
.create = NULL,
.title = "Editor",
.children = (pref_node_desc_t []){
{
.create = create_fgraph_preferences,
.load = load_fgraph_configuration,
.store = store_fgraph_configuration,
.name = "fgraph",
.title = "Function graph",
},
PREF_NODE_NULL_ENTRY
}
},
PREF_NODE_NULL_ENTRY
};
/* Eléments de la liste de sections */
typedef enum _PrefListItem
{
PLI_TITLE, /* Etiquette de la section */
PLI_PANEL, /* Panneau graphique associé */
} PrefListItem;
/* Ajoute un panneau de paramétrage à la boîte de dialogue. */
static void add_preferences_node(GtkTreeStore *, GtkTreeIter *, GGenConfig *, GtkStack *, pref_node_desc_t *);
/* Affiche le panneau correspondant au noeud sélectionné. */
static void on_prefs_selection_changed(GtkTreeSelection *, GtkBuilder *);
/* Lance la sauvegarde d'éléments de paramétrage. */
static void store_preferences_node(GGenConfig *, pref_node_desc_t *);
/* Sauvegarde l'ensemble des paramètres de configuration. */
static void on_prefs_apply_button_clicked(GtkButton *, GtkBuilder *);
/******************************************************************************
* *
* Paramètres : store = arborescence des sections à compléter. *
* parent = point d'insertion du parent. *
* config = configuration globale à charger. *
* stack = pile de composants GTK à constituer. *
* node = noeud de description courant à traiter. *
* *
* Description : Ajoute un panneau de paramétrage à la boîte de dialogue. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void add_preferences_node(GtkTreeStore *store, GtkTreeIter *parent, GGenConfig *config, GtkStack *stack, pref_node_desc_t *node)
{
GtkTreeIter iter; /* Point d'insertion */
pref_node_desc_t *child; /* Sous-élément à traiter */
if (node->create == NULL)
{
node->builder = NULL;
node->panel = NULL;
}
else
{
node->panel = node->create(&node->builder);
node->load(node->builder, config);
gtk_widget_show(node->panel);
gtk_stack_add_named(stack, node->panel, node->name);
}
gtk_tree_store_append(store, &iter, parent);
gtk_tree_store_set(store, &iter,
PLI_TITLE, _(node->title),
PLI_PANEL, node->panel,
-1);
if (node->children != NULL)
for (child = node->children; child->title != NULL; child++)
add_preferences_node(store, &iter, config, stack, child);
}
/******************************************************************************
* *
* Paramètres : parent = fenêtre principale de l'éditeur. *
* outb = constructeur à détruire après usage. [OUT] *
* *
* Description : Propose une boîte de dialogue pour la configuration générale.*
* *
* Retour : Adresse de la fenêtre mise en place. *
* *
* Remarques : - *
* *
******************************************************************************/
GtkWidget *create_preferences_dialog(GtkWindow *parent, GtkBuilder **outb)
{
GtkWidget *result; /* Fenêtre à renvoyer */
GtkBuilder *builder; /* Constructeur utilisé */
GGenConfig *config; /* Configuration globale */
GtkStack *stack; /* Pile à mettre à jour */
GtkTreeStore *store; /* Arborescence des sections */
pref_node_desc_t *iter; /* Boucle de parcours */
GtkTreeView *treeview; /* Arborescence principale */
builder = gtk_builder_new_from_resource("/org/chrysalide/gui/dialogs/preferences.ui");
*outb = builder;
result = GTK_WIDGET(gtk_builder_get_object(builder, "window"));
gtk_window_set_transient_for(GTK_WINDOW(result), parent);
/* Intégration des différentes sections */
config = get_main_configuration();
stack = GTK_STACK(gtk_builder_get_object(builder, "stack"));
store = GTK_TREE_STORE(gtk_builder_get_object(builder, "pref_list"));
for (iter = _prefs_nodes; iter->title != NULL; iter++)
add_preferences_node(store, NULL, config, stack, iter);
treeview = GTK_TREE_VIEW(gtk_builder_get_object(builder, "treeview"));
gtk_tree_view_expand_all(treeview);
/* Connexion des signaux */
gtk_builder_add_callback_symbols(builder,
"on_prefs_selection_changed", G_CALLBACK(on_prefs_selection_changed),
"on_prefs_apply_button_clicked", G_CALLBACK(on_prefs_apply_button_clicked),
NULL);
gtk_builder_connect_signals(builder, builder);
return result;
}
/******************************************************************************
* *
* Paramètres : selection = sélection courante de l'arborescence des options.*
* builder = constructeur GTK avec toutes les références. *
* *
* Description : Affiche le panneau correspondant au noeud sélectionné. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void on_prefs_selection_changed(GtkTreeSelection *selection, GtkBuilder *builder)
{
GtkTreeModel *model; /* Gestionnaire de données */
GtkTreeIter iter; /* Position courante */
GtkWidget *panel; /* Panneau à mettre en avant */
GtkStack *stack; /* Pile à mettre à jour */
if (gtk_tree_selection_get_selected(selection, &model, &iter))
{
gtk_tree_model_get(model, &iter, PLI_PANEL, &panel, -1);
stack = GTK_STACK(gtk_builder_get_object(builder, "stack"));
if (panel == NULL)
gtk_stack_set_visible_child_name(stack, "empty");
else
{
gtk_stack_set_visible_child(stack, panel);
g_object_unref(G_OBJECT(panel));
}
}
}
/******************************************************************************
* *
* Paramètres : config = configuration globale à actualiser. *
* node = noeud de description courant à traiter. *
* *
* Description : Lance la sauvegarde d'éléments de paramétrage. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void store_preferences_node(GGenConfig *config, pref_node_desc_t *node)
{
pref_node_desc_t *child; /* Sous-élément à traiter */
if (node->create != NULL)
node->store(node->builder, config);
if (node->children != NULL)
for (child = node->children; child->title != NULL; child++)
store_preferences_node(config, child);
}
/******************************************************************************
* *
* Paramètres : button = bouton GTK à l'origine de l'opération. *
* builder = constructeur GTK avec toutes les références. *
* *
* Description : Sauvegarde l'ensemble des paramètres de configuration. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void on_prefs_apply_button_clicked(GtkButton *button, GtkBuilder *builder)
{
GGenConfig *config; /* Configuration globale */
pref_node_desc_t *iter; /* Boucle de parcours */
config = get_main_configuration();
for (iter = _prefs_nodes; iter->title != NULL; iter++)
store_preferences_node(config, iter);
}