/* Chrysalide - Outil d'analyse de fichiers binaires
* easygtk.c - mise en place rapide de composants GTK
*
* Copyright (C) 2009-2018 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 "easygtk.h"
#include
#include "support.h"
/* Termine la construction d'un composant 'GtkButton'. */
static void _finish_button_with_img(GtkWidget *, GObject *, const char *, GtkWidget *, const char *);
/* Encadre certains raccourcis actionnés sur un menu. */
static gboolean handle_escape_on_menu(GtkWidget *, GdkEventKey *, GtkMenuItem *);
/******************************************************************************
* *
* Paramètres : widget = composant graphique visé par la procédure. *
* pt = espace imposé à la zone supérieure. *
* pb = espace imposé à la zone inférieure. *
* pl = espace imposé à la zone gauche. *
* pr = espace imposé à la zone droite. *
* *
* Description : Définit des bordures extérieures à appliquer à un composant. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void qck_set_margins(GtkWidget *widget, guint pt, guint pb, guint pl, guint pr)
{
gtk_widget_set_margin_top(widget, pt);
gtk_widget_set_margin_bottom(widget, pb);
gtk_widget_set_margin_start(widget, pl);
gtk_widget_set_margin_end(widget, pr);
}
/******************************************************************************
* *
* Paramètres : caption = contenu de l'étiqutte à placer. *
* content = composant en place à poser sur le conteneur. *
* pt = espace imposé à la zone supérieure. *
* pb = espace imposé à la zone inférieure. *
* pl = espace imposé à la zone gauche. *
* pr = espace imposé à la zone droite. *
* *
* Description : Met en place une frame. *
* *
* Retour : Composant 'GtkWidget' ici créé. *
* *
* Remarques : - *
* *
******************************************************************************/
GtkWidget *qck_create_frame(const char *caption, GtkWidget *content, guint pt, guint pb, guint pl, guint pr)
{
GtkWidget *result; /* Instance à renvoyer */
GtkWidget *label; /* Etiquette à utiliser */
result = gtk_frame_new(NULL);
gtk_widget_show(result);
gtk_frame_set_shadow_type(GTK_FRAME(result), GTK_SHADOW_NONE);
label = qck_create_label(NULL, NULL, caption);
gtk_frame_set_label_widget(GTK_FRAME(result), label);
gtk_label_set_use_markup(GTK_LABEL(label), TRUE);
qck_set_margins(content, pt, pb, pl, pr);
gtk_container_add(GTK_CONTAINER(result), content);
return result;
}
/******************************************************************************
* *
* Paramètres : object = espace dédié à l'inscription de références. *
* name = nom à donner au nouveau composant. *
* *
* Description : Met en place un support avec défilement automatique. *
* *
* Retour : Composant 'GtkWidget' ici créé. *
* *
* Remarques : - *
* *
******************************************************************************/
GtkWidget *qck_create_scrolled_window(GObject *object, const char *name)
{
GtkWidget *result; /* Instance à renvoyer */
result = gtk_scrolled_window_new(NULL, NULL);
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(result),
GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
if (G_IS_OBJECT(object) && name != NULL)
{
g_object_ref(G_OBJECT(result));
g_object_set_data_full(object, name, result, (GDestroyNotify)g_object_unref);
}
gtk_widget_show(result);
return result;
}
/******************************************************************************
* *
* Paramètres : object = espace dédié à l'inscription de références. *
* name = nom à donner au nouveau composant. *
* filename = chemin d'accès complet au fichier à afficher. *
* *
* Description : Crée un composant 'GtkImage'. *
* *
* Retour : Image mise en place. *
* *
* Remarques : Si le chemin est libérable, il est libéré de la mémoire. *
* *
******************************************************************************/
GtkWidget *qck_create_image(GObject *object, const char *name, gchar *filename)
{
GtkWidget *result; /* Résultat à renvoyer */
if (filename == NULL)
result = gtk_image_new();
else
{
result = gtk_image_new_from_file(filename);
g_free(filename);
}
if (G_IS_OBJECT(object) && name != NULL)
{
g_object_ref(G_OBJECT(result));
g_object_set_data_full(object, name, result, (GDestroyNotify)g_object_unref);
}
gtk_widget_show(result);
return result;
}
/******************************************************************************
* *
* Paramètres : object = espace dédié à l'inscription de références. *
* name = nom à donner au nouveau composant. *
* caption = intitulé apparaissant sur le composant. *
* *
* Description : Crée un composant 'GtkLabel'. *
* *
* Retour : Champ d'indication mis en place. *
* *
* Remarques : - *
* *
******************************************************************************/
GtkWidget *qck_create_label(GObject *object, const char *name, const char *caption)
{
GtkWidget *result; /* Résultat à renvoyer */
result = gtk_label_new(caption);
if (G_IS_OBJECT(object) && name != NULL)
{
g_object_ref(G_OBJECT(result));
g_object_set_data_full(object, name, result, (GDestroyNotify)g_object_unref);
}
gtk_widget_show(result);
gtk_widget_set_halign(result, GTK_ALIGN_START);
gtk_widget_set_valign(result, GTK_ALIGN_CENTER);
return result;
}
/******************************************************************************
* *
* Paramètres : object = espace dédié à l'inscription de références. *
* name = nom à donner au nouveau composant. *
* text = éventuel contenu initial du champ de saisie. *
* *
* Description : Crée et enregistre un composant 'GtkEntry'. *
* *
* Retour : Champ de saisie mis en place. *
* *
* Remarques : - *
* *
******************************************************************************/
GtkWidget *qck_create_entry(GObject *object, const char *name, const char *text)
{
GtkWidget *result; /* Résultat à renvoyer */
result = gtk_entry_new();
if (G_IS_OBJECT(object) && name != NULL)
{
g_object_ref(G_OBJECT(result));
g_object_set_data_full(object, name, result, (GDestroyNotify)g_object_unref);
}
gtk_widget_show(result);
if (text != NULL)
gtk_entry_set_text(GTK_ENTRY(result), text);
return result;
}
/******************************************************************************
* *
* Paramètres : object = espace dédié à l'inscription de références. *
* name = nom à donner au nouveau composant. *
* caption = intitulé du bouton à créer. *
* handler = éventuelle fonction de sélection associée. *
* data = données à transmettre avec l'événement si besoin. *
* *
* Description : Crée et enregistre un composant 'GtkButton'. *
* *
* Retour : Simple bouton mis en place. *
* *
* Remarques : - *
* *
******************************************************************************/
GtkWidget *qck_create_button(GObject *object, const char *name, const char *caption, GCallback handler, gpointer data)
{
GtkWidget *result; /* Résultat à renvoyer */
result = gtk_button_new_with_mnemonic(caption);
gtk_widget_set_can_default(result, TRUE);
if (G_IS_OBJECT(object) && name != NULL)
{
g_object_ref(G_OBJECT(result));
g_object_set_data_full(object, name, result, (GDestroyNotify)g_object_unref);
}
gtk_widget_show(result);
if (handler != NULL)
g_signal_connect(result, "clicked", handler, data);
return result;
}
/******************************************************************************
* *
* Paramètres : button = composant graphique dont la définition est à finir.*
* object = espace dédié à l'inscription de références. *
* name = nom à donner au nouveau composant. *
* picture = éventuelle image sous forme de composant GTK. *
* label = contenu de l'étiquette éventuelle associée. *
* *
* Description : Termine la construction d'un composant 'GtkButton'. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void _finish_button_with_img(GtkWidget *button, GObject *object, const char *name, GtkWidget *picture, const char *label)
{
GtkWidget *caption; /* Etiquette à coller */
GtkWidget *hbox; /* Séparation horizontale */
/* Création des éléments internes (2/2) */
if (label != NULL)
{
caption = gtk_label_new_with_mnemonic(label);
gtk_widget_show(caption);
}
/* Mise en place */
if (picture != NULL && label != NULL)
{
hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 2);
gtk_widget_show(hbox);
gtk_container_add(GTK_CONTAINER(button), hbox);
gtk_box_pack_start(GTK_BOX(hbox), picture, FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(hbox), caption, FALSE, FALSE, 0);
}
else if (picture != NULL)
gtk_container_add(GTK_CONTAINER(button), picture);
else if (label != NULL)
gtk_container_add(GTK_CONTAINER(button), caption);
else
assert(0);
/* Interactions GTK... */
if (G_IS_OBJECT(object) && name != NULL)
{
g_object_ref(G_OBJECT(button));
g_object_set_data_full(object, name, button, (GDestroyNotify)g_object_unref);
}
gtk_widget_show(button);
}
/******************************************************************************
* *
* Paramètres : object = espace dédié à l'inscription de références. *
* name = nom à donner au nouveau composant. *
* image = nom de l'image stockée dans GTK. *
* size = taille de l'image éventuelle à faire figurer. *
* label = contenu de l'étiquette éventuelle associée. *
* handler = éventuelle fonction de sélection associée. *
* data = données à transmettre avec l'événement si besoin. *
* *
* Description : Crée et enregistre un composant 'GtkButton'. *
* *
* Retour : Simple bouton mis en place. *
* *
* Remarques : - *
* *
******************************************************************************/
GtkWidget *qck_create_button_with_named_img(GObject *object, const char *name, const char *image, GtkIconSize size, const char *label, GCallback handler, gpointer data)
{
GtkWidget *result; /* Résultat à renvoyer */
GtkWidget *picture; /* Image de représentation */
result = gtk_button_new();
gtk_widget_set_can_default(result, TRUE);
/* Création des éléments internes (1/2) */
if (image != NULL)
{
picture = gtk_image_new_from_icon_name(image, size);
gtk_widget_show(picture);
}
else
picture = NULL;
_finish_button_with_img(result, object, name, picture, label);
if (handler != NULL)
g_signal_connect(result, "clicked", handler, data);
return result;
}
/******************************************************************************
* *
* Paramètres : object = espace dédié à l'inscription de références. *
* name = nom à donner au nouveau composant. *
* image = nom de l'image stockée dans GTK. *
* size = taille de l'image éventuelle à faire figurer. *
* label = contenu de l'étiquette éventuelle associée. *
* handler = éventuelle fonction de sélection associée. *
* data = données à transmettre avec l'événement si besoin. *
* *
* Description : Crée et enregistre un composant 'GtkCheckButton'. *
* *
* Retour : Simple bouton mis en place. *
* *
* Remarques : - *
* *
******************************************************************************/
GtkWidget *qck_create_toggle_button_with_named_img(GObject *object, const char *name, const char *image, GtkIconSize size, const char *label, GCallback handler, gpointer data)
{
GtkWidget *result; /* Résultat à renvoyer */
GtkWidget *picture; /* Image de représentation */
result = gtk_toggle_button_new();
gtk_widget_set_can_default(result, TRUE);
/* Création des éléments internes (1/2) */
if (image != NULL)
{
picture = gtk_image_new_from_icon_name(image, size);
gtk_widget_show(picture);
}
else
picture = NULL;
_finish_button_with_img(result, object, name, picture, label);
if (handler != NULL)
g_signal_connect(result, "toggled", handler, data);
return result;
}
/******************************************************************************
* *
* Paramètres : object = espace dédié à l'inscription de références. *
* name = nom à donner au nouveau composant. *
* caption = désignation apparaîssant sur le corps de l'objet. *
* handler = éventuelle fonction de sélection associée. *
* data = données à transmettre avec l'événement si besoin. *
* *
* Description : Crée et enregistre un composant 'GtkCheckButton'. *
* *
* Retour : Composant mis en place. *
* *
* Remarques : - *
* *
******************************************************************************/
GtkWidget *qck_create_check_button(GObject *object, const char *name, const char *caption, GCallback handler, gpointer data)
{
GtkWidget *result; /* Résultat à renvoyer */
result = gtk_check_button_new_with_label(caption);
if (G_IS_OBJECT(object) && name != NULL)
{
g_object_ref(G_OBJECT(result));
g_object_set_data_full(object, name, result, (GDestroyNotify)g_object_unref);
}
gtk_widget_show(result);
if (handler != NULL)
g_signal_connect(result, "toggled", handler, data);
return result;
}
/******************************************************************************
* *
* Paramètres : object = espace dédié à l'inscription de références. *
* name = nom à donner au nouveau composant. *
* caption = désignation apparaîssant sur le corps de l'objet. *
* member = membre de la liste des autres boutons. *
* handler = éventuelle fonction de sélection associée. *
* data = données à transmettre avec l'événement si besoin. *
* *
* Description : Crée et enregistre un composant 'GtkRadioButton'. *
* *
* Retour : Composant mis en place. *
* *
* Remarques : - *
* *
******************************************************************************/
GtkWidget *qck_create_radio_button(GObject *object, const char *name, const char *caption, GtkRadioButton *member, GCallback handler, gpointer data)
{
GtkWidget *result; /* Résultat à renvoyer */
result = gtk_radio_button_new_with_label_from_widget(member, caption);
if (G_IS_OBJECT(object) && name != NULL)
{
g_object_ref(G_OBJECT(result));
g_object_set_data_full(object, name, result, (GDestroyNotify)g_object_unref);
}
gtk_widget_show(result);
if (handler != NULL)
g_signal_connect(result, "toggled", handler, data);
return result;
}
/******************************************************************************
* *
* Paramètres : object = espace dédié à l'inscription de références. *
* name = nom à donner au nouveau composant. *
* handler = éventuelle fonction de sélection associée. *
* data = données à transmettre avec l'événement si besoin. *
* *
* Description : Crée et enregistre un composant 'GtkComboBox'. *
* *
* Retour : Composant mis en place. *
* *
* Remarques : - *
* *
******************************************************************************/
GtkWidget *qck_create_combobox(GObject *object, const char *name, GCallback handler, gpointer data)
{
GtkWidget *result; /* Résultat à renvoyer */
result = gtk_combo_box_text_new();
if (G_IS_OBJECT(object) && name != NULL)
{
g_object_ref(G_OBJECT(result));
g_object_set_data_full(object, name, result, (GDestroyNotify)g_object_unref);
}
gtk_widget_show(result);
if (handler != NULL)
g_signal_connect(result, "changed", handler, data);
return result;
}
/******************************************************************************
* *
* Paramètres : object = espace dédié à l'inscription de références. *
* name = nom à donner au nouveau composant. *
* handler = éventuelle fonction de sélection associée. *
* data = données à transmettre avec l'événement si besoin. *
* *
* Description : Crée et enregistre un composant 'GtkComboBox'. *
* *
* Retour : Composant mis en place. *
* *
* Remarques : - *
* *
******************************************************************************/
GtkWidget *qck_create_combobox_with_entry(GObject *object, const char *name, GCallback handler, gpointer data)
{
GtkWidget *result; /* Résultat à renvoyer */
result = gtk_combo_box_text_new_with_entry();
if (G_IS_OBJECT(object) && name != NULL)
{
g_object_ref(G_OBJECT(result));
g_object_set_data_full(object, name, result, (GDestroyNotify)g_object_unref);
}
gtk_widget_show(result);
if (handler != NULL)
g_signal_connect(result, "changed", handler, data);
return result;
}
/******************************************************************************
* *
* Paramètres : menu = composant actif pour la réception des touches. *
* event = informations liées à l'événement. *
* item = menu parent à manipuler au besoin. *
* *
* Description : Encadre certains raccourcis actionnés sur un menu. *
* *
* Retour : FALSE afin de poursuivre la propagation de l'événement. *
* *
* Remarques : - *
* *
******************************************************************************/
static gboolean handle_escape_on_menu(GtkWidget *menu, GdkEventKey *event, GtkMenuItem *item)
{
if (event->keyval == GDK_KEY_Escape)
{
gtk_widget_hide(menu);
gtk_menu_item_deselect(item);
}
return FALSE;
}
/******************************************************************************
* *
* Paramètres : item = élément de menu devant recevoir un sous-menu. *
* *
* Description : Met en place un support de menu 'GtkMenu'. *
* *
* Retour : Réceptacle pour sous-éléments de menu. *
* *
* Remarques : - *
* *
******************************************************************************/
GtkWidget *qck_create_menu(GtkMenuItem *item)
{
GtkWidget *result; /* Composant à retourner */
result = gtk_menu_new();
if (item != NULL)
{
gtk_menu_item_set_submenu(item, result);
g_signal_connect(result, "key-press-event", G_CALLBACK(handle_escape_on_menu), item);
}
return result;
}
/******************************************************************************
* *
* Paramètres : object = espace dédié à l'inscription de références. *
* name = nom à donner au nouveau composant. *
* caption = intitulé du menu à créer. *
* handler = éventuelle fonction de sélection associée. *
* data = données à transmettre avec l'événement si besoin. *
* *
* Description : Crée et enregistre un composant 'GtkMenuItem'. *
* *
* Retour : Simple élément de menu mis en place. *
* *
* Remarques : - *
* *
******************************************************************************/
GtkWidget *qck_create_menu_item(GObject *object, const char *name, const char *caption, GCallback handler, gpointer data)
{
GtkWidget *result; /* Résultat à renvoyer */
result = gtk_menu_item_new_with_mnemonic(caption);
if (G_IS_OBJECT(object) && name != NULL)
{
g_object_ref(G_OBJECT(result));
g_object_set_data_full(object, name, result, (GDestroyNotify)g_object_unref);
}
gtk_widget_show(result);
if (handler != NULL)
g_signal_connect(result, "activate", handler, data);
return result;
}
/******************************************************************************
* *
* Paramètres : object = espace dédié à l'inscription de références. *
* name = nom à donner au nouveau composant. *
* caption = intitulé du menu à créer. *
* handler = éventuelle fonction de sélection associée. *
* data = données à transmettre avec l'événement si besoin. *
* *
* Description : Crée et enregistre un composant 'GtkCheckMenuItem'. *
* *
* Retour : Simple élément de menu mis en place. *
* *
* Remarques : - *
* *
******************************************************************************/
GtkWidget *qck_create_check_menu_item(GObject *object, const char *name, const char *caption, GCallback handler, gpointer data)
{
GtkWidget *result; /* Résultat à renvoyer */
result = gtk_check_menu_item_new_with_mnemonic(caption);
if (G_IS_OBJECT(object) && name != NULL)
{
g_object_ref(G_OBJECT(result));
g_object_set_data_full(object, name, result, (GDestroyNotify)g_object_unref);
}
gtk_widget_show(result);
if (handler != NULL)
g_signal_connect(result, "toggled", handler, data);
return result;
}
/******************************************************************************
* *
* Paramètres : object = espace dédié à l'inscription de références. *
* name = nom à donner au nouveau composant. *
* rgroup = groupe d'apparatenance pour les radios. *
* caption = intitulé du menu à créer. *
* handler = éventuelle fonction de sélection associée. *
* data = données à transmettre avec l'événement si besoin. *
* *
* Description : Crée et enregistre un composant 'GtkRadioMenuItem'. *
* *
* Retour : Simple élément de menu mis en place. *
* *
* Remarques : - *
* *
******************************************************************************/
GtkWidget *qck_create_radio_menu_item(GObject *object, const char *name, GSList *rgroup, const char *caption, GCallback handler, gpointer data)
{
GtkWidget *result; /* Résultat à renvoyer */
result = gtk_radio_menu_item_new_with_mnemonic(rgroup, caption);
if (G_IS_OBJECT(object) && name != NULL)
{
g_object_ref(G_OBJECT(result));
g_object_set_data_full(object, name, result, (GDestroyNotify)g_object_unref);
}
gtk_widget_show(result);
if (handler != NULL)
g_signal_connect(result, "toggled", handler, data);
return result;
}
/******************************************************************************
* *
* Paramètres : - *
* *
* Description : Crée et enregistre un composant 'GtkSeparatorMenuItem'. *
* *
* Retour : Simple élément de menu mis en place. *
* *
* Remarques : - *
* *
******************************************************************************/
GtkWidget *qck_create_menu_separator(void)
{
GtkWidget *result; /* Résultat à renvoyer */
result = gtk_separator_menu_item_new();
gtk_widget_show(result);
return result;
}
/******************************************************************************
* *
* Paramètres : container = composant GTK contenant d'autres composants. *
* child = composant GTK à retrouver. *
* *
* Description : Détermine l'indice d'un composant dans un conteneur GTK. *
* *
* Retour : Indice du composant dans le conteneur ou -1 si non trouvé. *
* *
* Remarques : - *
* *
******************************************************************************/
gint find_contained_child_index(GtkContainer *container, GtkWidget *child)
{
gint result; /* Indice à retourner */
GList *list; /* Liste de composants contenus*/
gint counter; /* Décompte progressif */
GList *iter; /* Boucle de parcours */
result = -1;
list = gtk_container_get_children(container);
counter = 0;
for (iter = g_list_first(list); iter != NULL; iter = g_list_next(iter))
{
if (iter->data == child)
{
result = counter;
break;
}
counter++;
}
g_list_free(list);
return result;
}
/******************************************************************************
* *
* Paramètres : container = composant GTK contenant d'autres composants. *
* n = indice du composant à retrouver. *
* *
* Description : Récupère le nième composant d'un conteneur GTK. *
* *
* Retour : Composant à la position donnée ou NULL en cas d'absence. *
* *
* Remarques : - *
* *
******************************************************************************/
GtkWidget *get_nth_contained_child(GtkContainer *container, guint n)
{
GtkWidget *result; /* Résultat à retourner */
GList *list; /* Liste de composants contenus*/
result = NULL;
list = gtk_container_get_children(container);
result = g_list_nth_data(list, n);
if (result != NULL)
g_object_ref(G_OBJECT(result));
g_list_free(list);
return result;
}
/******************************************************************************
* *
* Paramètres : parent = fenêtre parente pour la modalité d'affichage. *
* title = titre de la boîte de dialogue. *
* question = teneur de la question posée. *
* *
* Description : Affiche une boîte de dialogue offrant un choix "Oui/Non". *
* *
* Retour : Identifiant de la réponse choisie. *
* *
* Remarques : - *
* *
******************************************************************************/
gint qck_show_question(GtkWindow *parent, const char *title, const char *question)
{
gint result; /* Choix arrêté à renvoyer */
GtkWidget *dialog; /* Boîte de dialogue affichée */
dialog = gtk_message_dialog_new(parent,
GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_QUESTION,
GTK_BUTTONS_YES_NO,
"%s", question);
gtk_window_set_title(GTK_WINDOW(dialog), title);
result = gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy(dialog);
return result;
}
/******************************************************************************
* *
* Paramètres : treeview = représentation graphique d'une liste à traiter. *
* model = gestionnaire des données de la liste. *
* iter = point à considérer pour l'opération. *
* *
* Description : Fait défiler une liste jusqu'à un point donné. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void scroll_to_treeview_iter(GtkTreeView *treeview, GtkTreeModel *model, GtkTreeIter *iter)
{
GtkTreePath *path; /* Chemin d'accès à la ligne */
path = gtk_tree_model_get_path(model, iter);
gtk_tree_view_scroll_to_cell(treeview, path, NULL, FALSE, 0.0, 0.0);
gtk_tree_path_free(path);
}