/* Chrysalide - Outil d'analyse de fichiers binaires
* preferences.c - boîte de dialogue d'édition des préférences de l'utilisateur
*
* Copyright (C) 2019-2025 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
#include
#include
#include
#include "preferences-int.h"
#include "prefs/security.h"
#include "../../common/cpp.h"
#include "../../gtkext/tweak.h"
/* --------------------------- BASES DE BOITE DE DIALOGUE --------------------------- */
/* Procède à l'initialisation de la fenêtre des paramètres. */
static void gtk_preferences_dialog_class_init(GtkPreferencesDialogClass *);
/* Procède à l'initialisation de la fenêtre des paramètres. */
static void gtk_preferences_dialog_init(GtkPreferencesDialog *);
/* 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 *);
/* 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 *);
/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
/* ---------------------------------------------------------------------------------- */
/* 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);
/******************************************************************************
* *
* Paramètres : class = classe GTK à initialiser. *
* *
* Description : Procède à l'initialisation de la fenêtre des paramètres. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void gtk_preferences_dialog_class_init(GtkPreferencesDialogClass *class)
{
GObjectClass *object; /* Plus haut niveau équivalent */
GtkWidgetClass *widget; /* Classe de haut niveau */
object = G_OBJECT_CLASS(class);
object->dispose = gtk_preferences_dialog_dispose;
object->finalize = gtk_preferences_dialog_finalize;
widget = GTK_WIDGET_CLASS(class);
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);
}
/******************************************************************************
* *
* Paramètres : dialog = composant GTK à initialiser. *
* *
* Description : Procède à l'initialisation de la fenêtre des paramètres. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void gtk_preferences_dialog_init(GtkPreferencesDialog *dialog)
{
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*/
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));
dialog->navigations = g_hash_table_new_full(g_str_hash, g_str_equal, free, g_object_unref);
/* Chargement des sections fixes */
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));
}
/* 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 : object = instance d'objet GLib à traiter. *
* *
* Description : Supprime toutes les références externes. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void gtk_preferences_dialog_dispose(GObject *object)
{
GtkPreferencesDialog *dialog; /* Version spécialisée */
dialog = GTK_PREFERENCES_DIALOG(object);
if (dialog->navigations != NULL)
{
/**
* Cf. documentation de g_hash_table_new_full().
*/
g_hash_table_remove_all(dialog->navigations);
g_hash_table_unref(dialog->navigations);
dialog->navigations = NULL;
}
gtk_widget_dispose_template(GTK_WIDGET(dialog), GTK_TYPE_PREFERENCES_DIALOG);
G_OBJECT_CLASS(gtk_preferences_dialog_parent_class)->dispose(object);
}
/******************************************************************************
* *
* Paramètres : object = instance d'objet GLib à traiter. *
* *
* Description : Procède à la libération totale de la mémoire. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void gtk_preferences_dialog_finalize(GObject *object)
{
G_OBJECT_CLASS(gtk_preferences_dialog_parent_class)->finalize(object);
}
/******************************************************************************
* *
* 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 : - *
* *
******************************************************************************/
GtkWindow *gtk_preferences_dialog_new(GtkWindow *parent)
{
GtkWindow *result; /* Boite de dialogue à renvoyer*/
result = g_object_new(GTK_TYPE_PREFERENCES_DIALOG, NULL);
if (!gtk_preferences_dialog_create(GTK_PREFERENCES_DIALOG(result), parent))
g_clear_object(&result);
return result;
}
/******************************************************************************
* *
* 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 : - *
* *
******************************************************************************/
bool gtk_preferences_dialog_create(GtkPreferencesDialog *dialog, GtkWindow *parent)
{
bool result; /* Bilan à retourner */
result = true;
gtk_window_set_transient_for(GTK_WINDOW(dialog), parent);
return result;
}
/******************************************************************************
* *
* 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 : Fournit la liste de section désignée par un nom. *
* *
* Retour : Composant graphique à utiliser. *
* *
* Remarques : - *
* *
******************************************************************************/
static GtkListBox *gtk_preferences_dialog_get_navigation(GtkPreferencesDialog *dialog, const char *key, bool create)
{
GtkListBox *result; /* Instance à retourner */
#ifndef NDEBUG
gboolean status; /* Bilan d'une insertion */
#endif
result = g_hash_table_lookup(dialog->navigations, key);
if (result == NULL && create)
{
result = GTK_LIST_BOX(gtk_list_box_new());
g_object_ref_sink(G_OBJECT(result));
gtk_list_box_set_selection_mode(result, GTK_SELECTION_BROWSE);
gtk_widget_add_css_class(GTK_WIDGET(result), "navigation-sidebar");
#ifndef NDEBUG
status = g_hash_table_insert(dialog->navigations, strdup(key), result);
assert(status);
#else
g_hash_table_insert(dialog->navigations, key, result);
#endif
}
if (result != NULL)
ref_object(result);
return result;
}
/******************************************************************************
* *
* 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 : Réagit à un changement de sélection dans les sections. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void gtk_preferences_dialog_on_row_selected(GtkListBox *navigation, GtkListBoxRow *selected, GtkPreferencesDialog *dialog)
{
GtkTweakSection *section; /* Nature réelle sélectionnée */
GType type; /* Type de panneau de config. */
GtkWidget *panel; /* Nouveau panneau à présenter */
if (selected != NULL)
{
if (!gtk_tweak_section_has_sub_section(GTK_TWEAK_SECTION(selected)))
{
section = GTK_TWEAK_SECTION(selected);
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);
}
else
{
// TODO
}
}
}
/* ---------------------------------------------------------------------------------- */
/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
/* ---------------------------------------------------------------------------------- */