/* Chrysalide - Outil d'analyse de fichiers binaires * gtkextstatusbar.h - prototypes pour la barre de statut améliorée * * Copyright (C) 2009-2013 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 Foobar. If not, see . */ #include "gtkextstatusbar.h" #include #include #include /* ------------------------- GESTION EXTERIEURE DE LA BARRE ------------------------- */ /* Elément de statut */ typedef struct _bar_item { char *message; /* Message à afficher */ bool is_progressive; /* Utilisations de progression */ double value; /* Valeur courante */ size_t index; /* Valeur pour l'identifiant */ } bar_item; /* Abstration d'une gestion de barre de statut (instance) */ struct _GtkExtStatusBar { GtkStatusbar bar; /* Présence obligatoire en 1er */ guint context; /* Nouvel identifiant */ guint cur_msg; /* Message courant */ GtkProgressBar *progress; /* Barre de progression */ bar_item *stack; /* Pile de statut de la barre */ size_t stack_size; /* Taille de la pile */ GMutex stack_access; /* Accès à la pile */ }; /* Abstration d'une gestion de barre de statut (classe) */ struct _GtkExtStatusBarClass { GtkStatusbarClass parent_class; /* Présence obligatoire en 1er */ }; /* Initialise la classe des barres de statut améliorées. */ static void gtk_extended_status_bar_class_init(GtkExtStatusBarClass *); /* Initialise une instance de barre de statut améliorée. */ static void gtk_extended_status_bar_init(GtkExtStatusBar *); /* ----------------------- MISES A JOUR EN CONTEXTE PRINCIPAL ----------------------- */ /* Type de commande */ typedef enum _DelayedUpdateCmd { DUC_CHANGE_CONTENT, /* Elément ajouté ou retiré */ DUC_UPDATE_ACTIVITY /* Mise à jour de progression */ } DelayedUpdateCmd; /* Transfert des commandes */ typedef struct _bar_update_info { GtkExtStatusBar *bar; /* Barre associée */ DelayedUpdateCmd cmd; /* Type de commande */ } bar_update_info; /* Met à jour la partie graphique de la barre de statut. */ static gboolean gtk_extended_status_update(bar_update_info *); /* Libère la mémoire occupée par la transmission. */ static void free_bar_update_info(bar_update_info *); /* Place un nouveau message dans la barre de statut. */ static void _gtk_extended_status_bar_change_content(GtkExtStatusBar *); /* Met à jour la barre de progression de la barre de statut. */ static void _gtk_extended_status_bar_update_activity(GtkExtStatusBar *); /* -------------------------- GESTION EN VUE MACROSCOPIQUE -------------------------- */ /* Concentré d'informations utiles */ struct _status_blob_info { GtkExtStatusBar *bar; /* Barre de statut utilisée */ bstatus_id_t id; /* Identifiant du message */ double current; /* Valeur courante représentée */ double max; /* Valeur maximale à atteindre */ }; /* ---------------------------------------------------------------------------------- */ /* GESTION EXTERIEURE DE LA BARRE */ /* ---------------------------------------------------------------------------------- */ /* Détermine le type de la barre de statut améliorée. */ G_DEFINE_TYPE(GtkExtStatusBar, gtk_extended_status_bar, GTK_TYPE_STATUSBAR) /****************************************************************************** * * * Paramètres : klass = classe GTK à initialiser. * * * * Description : Initialise la classe des barres de statut améliorées. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void gtk_extended_status_bar_class_init(GtkExtStatusBarClass *klass) { } /****************************************************************************** * * * Paramètres : bar = instance GTK à initialiser. * * * * Description : Initialise une instance de barre de statut améliorée. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void gtk_extended_status_bar_init(GtkExtStatusBar *bar) { bar->context = gtk_statusbar_get_context_id(GTK_STATUSBAR(bar), ""); bar->progress = GTK_PROGRESS_BAR(gtk_progress_bar_new()); gtk_widget_set_size_request(GTK_WIDGET(bar->progress), 200, -1); gtk_progress_bar_set_fraction(bar->progress, 0.5); gtk_progress_bar_set_text(bar->progress, "50%"); gtk_box_pack_start(GTK_BOX(bar), GTK_WIDGET(bar->progress), FALSE, FALSE, 4); g_mutex_init(&bar->stack_access); } /****************************************************************************** * * * Paramètres : - * * * * Description : Crée une nouvelle instance de barre de statut. * * * * Retour : Composant GTK mis en place. * * * * Remarques : - * * * ******************************************************************************/ GtkWidget *gtk_extended_status_bar_new(void) { return g_object_new(GTK_TYPE_EXT_STATUS_BAR, NULL); } /****************************************************************************** * * * Paramètres : bar = barre de statut à manipuler. * * message = message à afficher pour l'utilisateur. * * progressive = utilisation de la barre de progression. * * * * Description : Place un nouveau message dans la barre de statut. * * * * Retour : Identifiant du nouveau statut défini. * * * * Remarques : - * * * ******************************************************************************/ bstatus_id_t gtk_extended_status_bar_push(GtkExtStatusBar *bar, const char *message, bool progressive) { bstatus_id_t result; /* Identifiant à retourner */ size_t index; /* Indice du nouvel élément */ bar_update_info *info; /* Informations à mémoriser */ return 0; if (bar == NULL) return 0; /* Mise à jour de la pile */ g_mutex_lock(&bar->stack_access); bar->stack = (bar_item *)realloc(bar->stack, ++bar->stack_size * sizeof(bar_item)); index = bar->stack_size - 1; bar->stack[index].message = strdup(message); bar->stack[index].is_progressive = progressive; bar->stack[index].value = 0.0; bar->stack[index].index = index; result = &bar->stack[index].index; g_mutex_unlock(&bar->stack_access); /* Mise à jour de l'affichage */ info = (bar_update_info *)calloc(1, sizeof(bar_update_info)); info->bar = bar; g_object_ref(G_OBJECT(bar)); info->cmd = DUC_CHANGE_CONTENT; gdk_threads_add_idle_full(G_PRIORITY_HIGH_IDLE, (GSourceFunc)gtk_extended_status_update, info, (GDestroyNotify)free_bar_update_info); return result; } /****************************************************************************** * * * Paramètres : bar = barre de statut à manipuler. * * id = identifiant du message concerné. * * value = valeur actuelle de la progression. * * * * Description : Met à jour la barre de progression de la barre de statut. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void gtk_extended_status_bar_update_activity(GtkExtStatusBar *bar, bstatus_id_t id, double value) { bar_update_info *info; /* Informations à mémoriser */ return; if (bar == NULL) return; /* Mise à jour de la pile */ g_mutex_lock(&bar->stack_access); bar->stack[*id].value = value; g_mutex_unlock(&bar->stack_access); /* Mise à jour de l'affichage */ info = (bar_update_info *)calloc(1, sizeof(bar_update_info)); info->bar = bar; g_object_ref(G_OBJECT(bar)); info->cmd = DUC_UPDATE_ACTIVITY; gdk_threads_add_idle_full(G_PRIORITY_HIGH_IDLE, (GSourceFunc)gtk_extended_status_update, info, (GDestroyNotify)free_bar_update_info); } /****************************************************************************** * * * Paramètres : bar = barre de statut à manipuler. * * id = identifiant du statut à supprimer. * * * * Description : Retire de la barre un statut, visible ou non. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void gtk_extended_status_bar_remove(GtkExtStatusBar *bar, bstatus_id_t id) { size_t index; /* Indice de l'élément visé */ size_t i; /* Boucle de parcours */ bar_update_info *info; /* Informations à mémoriser */ return; if (bar == NULL) return; /* Mise à jour de la pile */ g_mutex_lock(&bar->stack_access); index = *id; free(bar->stack[index].message); if ((index + 1) < bar->stack_size) { memmove(&bar->stack[index], &bar->stack[index + 1], (bar->stack_size - index - 1) * sizeof(bar_item)); for (i = index; i < bar->stack_size; i++) bar->stack[i].index = i; } bar->stack = (bar_item *)realloc(bar->stack, --bar->stack_size * sizeof(bar_item)); g_mutex_unlock(&bar->stack_access); /* Mise à jour de l'affichage */ info = (bar_update_info *)calloc(1, sizeof(bar_update_info)); info->bar = bar; g_object_ref(G_OBJECT(bar)); info->cmd = DUC_CHANGE_CONTENT; gdk_threads_add_idle_full(G_PRIORITY_HIGH_IDLE, (GSourceFunc)gtk_extended_status_update, info, (GDestroyNotify)free_bar_update_info); } /* ---------------------------------------------------------------------------------- */ /* MISES A JOUR EN CONTEXTE PRINCIPAL */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * * Paramètres : info = informations à consulter pour l'opération. * * * * Description : Met à jour la partie graphique de la barre de statut. * * * * Retour : FALSE pour faire disparaître la mise à jour ensuite. * * * * Remarques : - * * * ******************************************************************************/ static gboolean gtk_extended_status_update(bar_update_info *info) { switch (info->cmd) { case DUC_CHANGE_CONTENT: _gtk_extended_status_bar_change_content(info->bar); /*break;*/ case DUC_UPDATE_ACTIVITY: _gtk_extended_status_bar_update_activity(info->bar); break; } return FALSE; } /****************************************************************************** * * * Paramètres : info = informations à libérer de la mémoire. * * * * Description : Libère la mémoire occupée par la transmission. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void free_bar_update_info(bar_update_info *info) { if (info->bar != NULL) g_object_unref(G_OBJECT(info->bar)); free(info); } /****************************************************************************** * * * Paramètres : bar = barre de statut à manipuler. * * * * Description : Place un nouveau message dans la barre de statut. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void _gtk_extended_status_bar_change_content(GtkExtStatusBar *bar) { size_t top; /* Indice de l'élément visé */ if (bar == NULL) return; g_mutex_lock(&bar->stack_access); if (bar->cur_msg > 0) gtk_statusbar_remove(GTK_STATUSBAR(bar), bar->context, bar->cur_msg); if (bar->stack_size == 0) gtk_widget_hide(GTK_WIDGET(bar->progress)); else { top = bar->stack_size - 1; bar->cur_msg = gtk_statusbar_push(GTK_STATUSBAR(bar), bar->context, bar->stack[top].message); if (bar->stack[top].is_progressive) gtk_widget_show(GTK_WIDGET(bar->progress)); else gtk_widget_hide(GTK_WIDGET(bar->progress)); } g_mutex_unlock(&bar->stack_access); } /****************************************************************************** * * * Paramètres : bar = barre de statut à manipuler. * * * * Description : Met à jour la barre de progression de la barre de statut. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void _gtk_extended_status_bar_update_activity(GtkExtStatusBar *bar) { size_t top; /* Indice de l'élément visé */ double value; /* Valeur à prendre en compte */ gchar percent[5]; /* Pourcentage en version txt. */ if (bar == NULL) return; g_mutex_lock(&bar->stack_access); if (bar->stack_size > 0) { top = bar->stack_size - 1; if (bar->stack[top].is_progressive) { value = bar->stack[top].value; if (value != 1.0 && value - gtk_progress_bar_get_fraction(bar->progress) < 0.01) goto gesbua_exit; g_snprintf(percent, 5, "%.0f%%", value * 100); gtk_progress_bar_set_fraction(bar->progress, value); gtk_progress_bar_set_text(bar->progress, percent); } } gesbua_exit: g_mutex_unlock(&bar->stack_access); } /* ---------------------------------------------------------------------------------- */ /* GESTION EN VUE MACROSCOPIQUE */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * * Paramètres : bar = barre de statut à manipuler. * * message = message à afficher pour l'utilisateur. * * val = valeur de départ à afficher initialement. * * max = valeur maximale de progression (négative = aucune).* * * * Description : Met en place rapidement un message progressiste de statut. * * * * Retour : Structure opaque contenant le nécessaire pour les opérations * * ultérieures. * * * * Remarques : - * * * ******************************************************************************/ status_blob_info *init_progessive_status(GtkExtStatusBar *bar, const char *message, double val, double max) { status_blob_info *result; /* Information à retourner */ return NULL; result = (status_blob_info *)calloc(1, sizeof(status_blob_info)); if (bar != NULL) g_object_ref(G_OBJECT(bar)); result->bar = bar; result->id = gtk_extended_status_bar_push(bar, message, max > 0.0); result->current = 0.0; result->max = max; return result; } /****************************************************************************** * * * Paramètres : info = regroupement d'informations à manipuler. * * * * Description : Fait disparaître la glue d'affichage de progression. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void fini_progessive_status(status_blob_info *info) { return; gtk_extended_status_bar_remove(info->bar, info->id); if (info->bar != NULL) g_object_unref(G_OBJECT(info->bar)); free(info); } /****************************************************************************** * * * Paramètres : info = regroupement d'informations à manipuler. * * * * Description : Indique la valeur courante utilisée pour la progression. * * * * Retour : Valeur courante. * * * * Remarques : - * * * ******************************************************************************/ double get_current_progessive_status(const status_blob_info *info) { return 0.0; return info->current; } /****************************************************************************** * * * Paramètres : info = regroupement d'informations à manipuler. * * inc = valeur de la progression à prendre en compte. * * * * Description : Augmente la progression visible dans la barre de statut. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void inc_progessive_status(status_blob_info *info, double inc) { return; assert((info->current + inc) < info->max); info->current += inc; gtk_extended_status_bar_update_activity(info->bar, info->id, info->current / info->max); }