summaryrefslogtreecommitdiff
path: root/src/gui/dialogs/preferences.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/dialogs/preferences.c')
-rw-r--r--src/gui/dialogs/preferences.c399
1 files changed, 219 insertions, 180 deletions
diff --git a/src/gui/dialogs/preferences.c b/src/gui/dialogs/preferences.c
index 4a3fb7c..aca562a 100644
--- a/src/gui/dialogs/preferences.c
+++ b/src/gui/dialogs/preferences.c
@@ -1,8 +1,8 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
- * preferences.c - (re)définition de l'identité de l'utilisateur
+ * preferences.c - boîte de dialogue d'édition des préférences de l'utilisateur
*
- * Copyright (C) 2019 Cyrille Bagard
+ * Copyright (C) 2019-2025 Cyrille Bagard
*
* This file is part of Chrysalide.
*
@@ -24,129 +24,160 @@
#include "preferences.h"
-#include <i18n.h>
+#include <assert.h>
+#include <math.h>
+#include <stdio.h>
+#include <gdk/gdkkeysyms.h>
-#include "prefs_fgraph.h"
-#include "prefs_labels.h"
-#include "../../core/params.h"
-#include "../../gtkext/easygtk.h"
+#include <config.h>
+#include "preferences-int.h"
+#include "prefs/security.h"
+#include "../../common/cpp.h"
+#include "../../gtkext/tweak.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 */
+/* --------------------------- BASES DE BOITE DE DIALOGUE --------------------------- */
- const char *name; /* Désignation interne */
- const char *title; /* Désignation humaine */
- GtkBuilder *builder; /* Constructeur GTK */
- GtkWidget *panel; /* Panneau GTK */
+/* Procède à l'initialisation de la fenêtre des paramètres. */
+static void gtk_preferences_dialog_class_init(GtkPreferencesDialogClass *);
- struct _pref_node_desc_t *children; /* Sous-arborescence */
+/* Procède à l'initialisation de la fenêtre des paramètres. */
+static void gtk_preferences_dialog_init(GtkPreferencesDialog *);
-} pref_node_desc_t;
+/* Supprime toutes les références externes. */
+static void gtk_preferences_dialog_dispose(GObject *);
+/* Procède à la libération totale de la mémoire. */
+static void gtk_preferences_dialog_finalize(GObject *);
-#define PREF_NODE_NULL_ENTRY { .title = NULL }
+/* Fournit la liste de section désignée par un nom. */
+static GtkListBox *gtk_preferences_dialog_get_navigation(GtkPreferencesDialog *, const char *, bool);
+/* Réagit à un changement de sélection dans les sections. */
+static void gtk_preferences_dialog_on_row_selected(GtkListBox *, GtkListBoxRow *, GtkPreferencesDialog *);
-/* Liste des paramétrages à afficher */
-static pref_node_desc_t _prefs_nodes[] = {
- {
- .create = NULL,
- .title = "Analysis",
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
- .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
+/* ---------------------------------------------------------------------------------- */
+/* BASES DE BOITE DE DIALOGUE */
+/* ---------------------------------------------------------------------------------- */
- }
- },
+/* Détermine le type du composant d'affichage générique. */
+G_DEFINE_TYPE(GtkPreferencesDialog, gtk_preferences_dialog, GTK_TYPE_WINDOW);
- {
- .create = NULL,
- .title = "Editor",
+/******************************************************************************
+* *
+* Paramètres : class = classe GTK à initialiser. *
+* *
+* Description : Procède à l'initialisation de la fenêtre des paramètres. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
- .children = (pref_node_desc_t []){
+static void gtk_preferences_dialog_class_init(GtkPreferencesDialogClass *class)
+{
+ GObjectClass *object; /* Plus haut niveau équivalent */
+ GtkWidgetClass *widget; /* Classe de haut niveau */
- {
- .create = create_fgraph_preferences,
- .load = load_fgraph_configuration,
- .store = store_fgraph_configuration,
+ object = G_OBJECT_CLASS(class);
- .name = "fgraph",
- .title = "Function graph",
+ object->dispose = gtk_preferences_dialog_dispose;
+ object->finalize = gtk_preferences_dialog_finalize;
- },
+ widget = GTK_WIDGET_CLASS(class);
- PREF_NODE_NULL_ENTRY
+ gtk_widget_class_set_template_from_resource(widget, "/re/chrysalide/framework/gui/dialogs/preferences.ui");
- }
+ gtk_widget_class_bind_template_child(widget, GtkPreferencesDialog, side_title);
+ gtk_widget_class_bind_template_child(widget, GtkPreferencesDialog, side_content);
+ gtk_widget_class_bind_template_child(widget, GtkPreferencesDialog, main_title);
+ gtk_widget_class_bind_template_child(widget, GtkPreferencesDialog, main_content);
- },
+ /* Active une action native (cf. https://docs.gtk.org/gtk4/class.Window.html#actions) */
+ gtk_widget_class_add_binding_action(widget, GDK_KEY_Escape, 0 /* GDK 4.14 : GDK_NO_MODIFIER_MASK */, "window.close", NULL);
- PREF_NODE_NULL_ENTRY
+}
-};
+/******************************************************************************
+* *
+* Paramètres : dialog = composant GTK à initialiser. *
+* *
+* Description : Procède à l'initialisation de la fenêtre des paramètres. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
-/* Eléments de la liste de sections */
-typedef enum _PrefListItem
+static void gtk_preferences_dialog_init(GtkPreferencesDialog *dialog)
{
- PLI_TITLE, /* Etiquette de la section */
- PLI_PANEL, /* Panneau graphique associé */
+ size_t i; /* Boucle de parcours */
+ const tweak_info_t *info; /* Informations à considérer */
+ GtkListBox *navigation; /* Liste de sections à afficher*/
+ GtkTweakSection *section; /* Nouvelle section à présenter*/
-} PrefListItem;
+ tweak_info_t infos[] = {
+ TWEAK_SIMPLE_DEF("root", "Basics",
+ "security-high-symbolic", "security", "Security", GTK_TYPE_SECURITY_TWEAK_PANEL),
+ };
+ gtk_widget_init_template(GTK_WIDGET(dialog));
-/* Ajoute un panneau de paramétrage à la boîte de dialogue. */
-static void add_preferences_node(GtkTreeStore *, GtkTreeIter *, GGenConfig *, GtkStack *, pref_node_desc_t *);
+ dialog->navigations = g_hash_table_new_full(g_str_hash, g_str_equal, free, g_object_unref);
-/* Affiche le panneau correspondant au noeud sélectionné. */
-static void on_prefs_selection_changed(GtkTreeSelection *, GtkBuilder *);
+ /* Chargement des sections fixes */
-/* Lance la sauvegarde d'éléments de paramétrage. */
-static void store_preferences_node(GGenConfig *, pref_node_desc_t *);
+ for (i = 0; i < ARRAY_SIZE(infos); i++)
+ {
+ info = &infos[i];
+
+ navigation = gtk_preferences_dialog_get_navigation(dialog, info->parent, true);
+ assert(navigation != NULL);
+
+ section = gtk_tweak_section_new(info);
+
+ gtk_list_box_append(navigation, GTK_WIDGET(section));
+
+ }
-/* Sauvegarde l'ensemble des paramètres de configuration. */
-static void on_prefs_apply_button_clicked(GtkButton *, GtkBuilder *);
+ /* Affichage de la liste racine */
+ navigation = gtk_preferences_dialog_get_navigation(dialog, "root", false);
+ assert(navigation != NULL);
+
+ g_signal_connect(navigation, "row-selected",
+ G_CALLBACK(gtk_preferences_dialog_on_row_selected), dialog);
+
+ gtk_scrolled_window_set_child(dialog->side_content, GTK_WIDGET(navigation));
+
+ unref_object(navigation);
+
+}
/******************************************************************************
* *
-* 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. *
+* Paramètres : object = instance d'objet GLib à traiter. *
* *
-* Description : Ajoute un panneau de paramétrage à la boîte de dialogue. *
+* Description : Supprime toutes les références externes. *
* *
* Retour : - *
* *
@@ -154,95 +185,96 @@ static void on_prefs_apply_button_clicked(GtkButton *, GtkBuilder *);
* *
******************************************************************************/
-static void add_preferences_node(GtkTreeStore *store, GtkTreeIter *parent, GGenConfig *config, GtkStack *stack, pref_node_desc_t *node)
+static void gtk_preferences_dialog_dispose(GObject *object)
{
- 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);
+ GtkPreferencesDialog *dialog; /* Version spécialisée */
- node->load(node->builder, config);
+ dialog = GTK_PREFERENCES_DIALOG(object);
- gtk_widget_show(node->panel);
+ if (dialog->navigations != NULL)
+ {
+ /**
+ * Cf. documentation de g_hash_table_new_full().
+ */
+ g_hash_table_remove_all(dialog->navigations);
- gtk_stack_add_named(stack, node->panel, node->name);
+ g_hash_table_unref(dialog->navigations);
+ dialog->navigations = NULL;
}
- gtk_tree_store_append(store, &iter, parent);
-
- gtk_tree_store_set(store, &iter,
- PLI_TITLE, _(node->title),
- PLI_PANEL, node->panel,
- -1);
+ gtk_widget_dispose_template(GTK_WIDGET(dialog), GTK_TYPE_PREFERENCES_DIALOG);
- if (node->children != NULL)
- for (child = node->children; child->title != NULL; child++)
- add_preferences_node(store, &iter, config, stack, child);
+ G_OBJECT_CLASS(gtk_preferences_dialog_parent_class)->dispose(object);
}
/******************************************************************************
* *
-* Paramètres : parent = fenêtre principale de l'éditeur. *
-* outb = constructeur à détruire après usage. [OUT] *
+* Paramètres : object = instance d'objet GLib à traiter. *
* *
-* Description : Propose une boîte de dialogue pour la configuration générale.*
+* Description : Procède à la libération totale de la mémoire. *
* *
-* Retour : Adresse de la fenêtre mise en place. *
+* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
-GtkWidget *create_preferences_dialog(GtkWindow *parent, GtkBuilder **outb)
+static void gtk_preferences_dialog_finalize(GObject *object)
{
- 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 */
+ G_OBJECT_CLASS(gtk_preferences_dialog_parent_class)->finalize(object);
- 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);
+/******************************************************************************
+* *
+* Paramètres : parent = fenêtre parente à surpasser. *
+* *
+* Description : Construit une boîte de dialogue pour les préférences. *
+* *
+* Retour : Adresse de la fenêtre mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
- /* Intégration des différentes sections */
+GtkWindow *gtk_preferences_dialog_new(GtkWindow *parent)
+{
+ GtkWindow *result; /* Boite de dialogue à renvoyer*/
- config = get_main_configuration();
+ result = g_object_new(GTK_TYPE_PREFERENCES_DIALOG, NULL);
- stack = GTK_STACK(gtk_builder_get_object(builder, "stack"));
+ if (!gtk_preferences_dialog_create(GTK_PREFERENCES_DIALOG(result), parent))
+ g_clear_object(&result);
- store = GTK_TREE_STORE(gtk_builder_get_object(builder, "pref_list"));
+ return result;
- 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);
+/******************************************************************************
+* *
+* Paramètres : dialog = boîte de dialogue à initialiser pleinement. *
+* parent = fenêtre parente à surpasser. *
+* *
+* Description : Met en place la boîte de dialogue pour les préférences. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
- /* Connexion des signaux */
+bool gtk_preferences_dialog_create(GtkPreferencesDialog *dialog, GtkWindow *parent)
+{
+ bool result; /* Bilan à retourner */
- gtk_builder_add_callback_symbols(builder,
- BUILDER_CALLBACK(on_prefs_selection_changed),
- BUILDER_CALLBACK(on_prefs_apply_button_clicked),
- NULL);
+ result = true;
- gtk_builder_connect_signals(builder, builder);
+ gtk_window_set_transient_for(GTK_WINDOW(dialog), parent);
return result;
@@ -251,52 +283,59 @@ GtkWidget *create_preferences_dialog(GtkWindow *parent, GtkBuilder **outb)
/******************************************************************************
* *
-* Paramètres : selection = sélection courante de l'arborescence des options.*
-* builder = constructeur GTK avec toutes les références. *
+* Paramètres : dialog = boîte de dialogue à initialiser pleinement. *
+* key = désignation de la liste à fournir. *
+* create = autorisation d'une création si besoin est. *
* *
-* Description : Affiche le panneau correspondant au noeud sélectionné. *
+* Description : Fournit la liste de section désignée par un nom. *
* *
-* Retour : - *
+* Retour : Composant graphique à utiliser. *
* *
* Remarques : - *
* *
******************************************************************************/
-static void on_prefs_selection_changed(GtkTreeSelection *selection, GtkBuilder *builder)
+static GtkListBox *gtk_preferences_dialog_get_navigation(GtkPreferencesDialog *dialog, const char *key, bool create)
{
- GtkTreeModel *model; /* Gestionnaire de données */
- GtkTreeIter iter; /* Position courante */
- GtkWidget *panel; /* Panneau à mettre en avant */
- GtkStack *stack; /* Pile à mettre à jour */
+ GtkListBox *result; /* Instance à retourner */
+#ifndef NDEBUG
+ gboolean status; /* Bilan d'une insertion */
+#endif
- if (gtk_tree_selection_get_selected(selection, &model, &iter))
- {
- gtk_tree_model_get(model, &iter, PLI_PANEL, &panel, -1);
+ result = g_hash_table_lookup(dialog->navigations, key);
- stack = GTK_STACK(gtk_builder_get_object(builder, "stack"));
+ if (result == NULL && create)
+ {
+ result = GTK_LIST_BOX(gtk_list_box_new());
+ g_object_ref_sink(G_OBJECT(result));
- if (panel == NULL)
- gtk_stack_set_visible_child_name(stack, "empty");
+ gtk_list_box_set_selection_mode(result, GTK_SELECTION_BROWSE);
+ gtk_widget_add_css_class(GTK_WIDGET(result), "navigation-sidebar");
- else
- {
- gtk_stack_set_visible_child(stack, panel);
+#ifndef NDEBUG
+ status = g_hash_table_insert(dialog->navigations, strdup(key), result);
+ assert(status);
+#else
+ g_hash_table_insert(dialog->navigations, key, result);
+#endif
- g_object_unref(G_OBJECT(panel));
+ }
- }
+ if (result != NULL)
+ ref_object(result);
- }
+ return result;
}
/******************************************************************************
* *
-* Paramètres : config = configuration globale à actualiser. *
-* node = noeud de description courant à traiter. *
+* Paramètres : navigation = liste concernée par l'événement. *
+* selected = élément sélectionné (voire NULL). *
+* dialog = boîte de dialogue à initialiser pleinement. *
* *
-* Description : Lance la sauvegarde d'éléments de paramétrage. *
+* Description : Réagit à un changement de sélection dans les sections. *
* *
* Retour : - *
* *
@@ -304,41 +343,41 @@ static void on_prefs_selection_changed(GtkTreeSelection *selection, GtkBuilder *
* *
******************************************************************************/
-static void store_preferences_node(GGenConfig *config, pref_node_desc_t *node)
+static void gtk_preferences_dialog_on_row_selected(GtkListBox *navigation, GtkListBoxRow *selected, GtkPreferencesDialog *dialog)
{
- pref_node_desc_t *child; /* Sous-élément à traiter */
+ GtkTweakSection *section; /* Nature réelle sélectionnée */
+ GType type; /* Type de panneau de config. */
+ GtkWidget *panel; /* Nouveau panneau à présenter */
- if (node->create != NULL)
- node->store(node->builder, config);
+ if (selected != NULL)
+ {
+ if (!gtk_tweak_section_has_sub_section(GTK_TWEAK_SECTION(selected)))
+ {
+ section = GTK_TWEAK_SECTION(selected);
- if (node->children != NULL)
- for (child = node->children; child->title != NULL; child++)
- store_preferences_node(config, child);
+ gtk_label_set_text(dialog->main_title, gtk_tweak_section_get_label(section));
-}
+ type = gtk_tweak_section_get_panel(section);
+ panel = g_object_new(type, NULL);
+ gtk_scrolled_window_set_child(dialog->main_content, panel);
-/******************************************************************************
-* *
-* 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 */
+ else
+ {
+
+ // TODO
- config = get_main_configuration();
+ }
- for (iter = _prefs_nodes; iter->title != NULL; iter++)
- store_preferences_node(config, iter);
+ }
}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+