summaryrefslogtreecommitdiff
path: root/src/gui/panels/glance.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/panels/glance.c')
-rw-r--r--src/gui/panels/glance.c645
1 files changed, 645 insertions, 0 deletions
diff --git a/src/gui/panels/glance.c b/src/gui/panels/glance.c
new file mode 100644
index 0000000..fb1723a
--- /dev/null
+++ b/src/gui/panels/glance.c
@@ -0,0 +1,645 @@
+
+/* OpenIDA - Outil d'analyse de fichiers binaires
+ * glance.c - panneau d'aperçu rapide
+ *
+ * Copyright (C) 2009-2012 Cyrille Bagard
+ *
+ * This file is part of OpenIDA.
+ *
+ * OpenIDA 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.
+ *
+ * OpenIDA 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "glance.h"
+
+
+#include <gtk/gtk.h>
+
+
+#include "panel-int.h"
+
+
+
+/* Panneau d'aperçu rapide (instance) */
+struct _GGlancePanel
+{
+ GPanelItem parent; /* A laisser en premier */
+
+ GtkViewPanel *view; /* Vue à représenter */
+ GtkRequisition req; /* Pleine taille de la source */
+ GtkScrolledWindow *support; /* Support défilant associé */
+
+ double scale; /* Ratio de réduction */
+
+ cairo_surface_t *cache; /* Cache grandeur nature */
+ GtkAllocation painting; /* Zone réservée pour l'aperçu */
+ GtkAllocation visible; /* Sous-partie visible */
+
+ double red; /* Conversion Gdk -> Cairo #1 */
+ double green; /* Conversion Gdk -> Cairo #2 */
+ double blue; /* Conversion Gdk -> Cairo #3 */
+
+ gdouble start_x; /* Abscisse du point de souris */
+ gdouble start_y; /* Ordonnée du point de souris */
+ bool valid; /* Point de départ visible ? */
+ gdouble ref_h; /* Position horizontale de ref.*/
+ gdouble ref_v; /* Position verticale de ref. */
+
+};
+
+
+/* Panneau d'aperçu rapide (classe) */
+struct _GGlancePanelClass
+{
+ GPanelItemClass parent; /* A laisser en premier */
+
+};
+
+
+
+/* Initialise la classe des panneaux d'aperçu rapide. */
+static void g_glance_panel_class_init(GGlancePanelClass *);
+
+/* Initialise une instance de panneau d'aperçu rapide. */
+static void g_glance_panel_init(GGlancePanel *);
+
+/* Définit une fois et au bon moment le fond de l'aperçu rapide. */
+static void define_glance_bg(GtkWidget *, GGlancePanel *);
+
+/* Lance une actualisation du fait d'un changement de support. */
+static void update_glance_panel_for_view(GGlancePanel *, GtkViewPanel *);
+
+/* Réagit à la préparation du défilement du support original. */
+static void on_view_scroll_setup(GtkAdjustment *, GGlancePanel *);
+
+/* Réagit à un défilement du support original. */
+static void on_view_scrolled(GtkAdjustment *, GGlancePanel *);
+
+/* Réagit à un changement de taille de l'espace de rendu. */
+static void on_glance_resize(GtkWidget *, GdkRectangle *, GGlancePanel *);
+
+/* Calcule l'emplacement du rendu maniature et son échelle. */
+static void compute_glance_scale(GGlancePanel *);
+
+/* Lance une actualisation du fait d'un changement de vue. */
+static void update_glance_panel_for_view_content(GGlancePanel *, GtkViewPanel *);
+
+/* Met à jour l'affichage de l'aperçu rapide à présenter. */
+static gboolean redraw_glance_area(GtkWidget *, GdkEventExpose *, GGlancePanel *);
+
+/* Assure la gestion des clics de souris sur l'aperçu. */
+static gboolean on_button_press_over_glance(GtkWidget *, GdkEventButton *, GGlancePanel *);
+
+/* Assure la gestion du déplacement de la souris sur l'aperçu. */
+static gboolean on_mouse_motion_over_glance(GtkWidget *, GdkEventMotion *, GGlancePanel *);
+
+
+
+/* Indique le type définit pour un panneau d'aperçu rapide. */
+G_DEFINE_TYPE(GGlancePanel, g_glance_panel, G_TYPE_PANEL_ITEM);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des panneaux d'aperçu rapide. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_glance_panel_class_init(GGlancePanelClass *klass)
+{
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : panel = instance à initialiser. *
+* *
+* Description : Initialise une instance de panneau d'aperçu rapide. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_glance_panel_init(GGlancePanel *panel)
+{
+ GEditorItem *base; /* Version basique d'instance */
+ GtkWidget *area; /* Surface de dessin réelle */
+
+ base = G_EDITOR_ITEM(panel);
+
+ base->name = _("Glance");
+
+ area = gtk_drawing_area_new();
+ g_signal_connect(G_OBJECT(area), "realize", G_CALLBACK(define_glance_bg), panel);
+ gtk_widget_show(area);
+
+ base->widget = gtk_event_box_new();
+ gtk_container_add(GTK_CONTAINER(base->widget), area);
+ gtk_widget_show(base->widget);
+
+ base->update_view = (update_item_view_fc)update_glance_panel_for_view;
+ base->update_content = (update_item_view_fc)update_glance_panel_for_view_content;
+
+ gtk_widget_set_size_request(base->widget, 300, 300);
+
+ g_signal_connect(G_OBJECT(area), "expose_event",
+ G_CALLBACK(redraw_glance_area), panel);
+ g_signal_connect(G_OBJECT(area), "size-allocate",
+ G_CALLBACK(on_glance_resize), panel);
+
+ g_signal_connect(G_OBJECT(base->widget), "button-press-event",
+ G_CALLBACK(on_button_press_over_glance), panel);
+ g_signal_connect(G_OBJECT(base->widget), "motion-notify-event",
+ G_CALLBACK(on_mouse_motion_over_glance), panel);
+
+}
+
+/******************************************************************************
+* *
+* Paramètres : ref = espace de référencement global. *
+* *
+* Description : Crée un panneau d'aperçu rapide. *
+* *
+* Retour : Adresse de la structure mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GEditorItem *g_glance_panel_new(GObject *ref)
+{
+ GEditorItem *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_GLANCE_PANEL, NULL);
+
+ g_panel_item_init_ext(G_PANEL_ITEM(result), ref, PANEL_GLANCE_ID,
+ _("Glance"), G_EDITOR_ITEM(result)->widget, "es");
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : widget = composant GTK en préparation. *
+* panel = informations liées au panneau associé. *
+* *
+* Description : Définit une fois et au bon moment le fond de l'aperçu rapide.*
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void define_glance_bg(GtkWidget *widget, GGlancePanel *panel)
+{
+ gtk_widget_modify_bg(widget, GTK_STATE_NORMAL,
+ &widget->style->mid[GTK_STATE_NORMAL]);
+
+ panel->red = widget->style->mid[GTK_STATE_NORMAL].red / USHRT_MAX;
+ panel->green = widget->style->mid[GTK_STATE_NORMAL].green / USHRT_MAX;
+ panel->blue = widget->style->mid[GTK_STATE_NORMAL].blue / USHRT_MAX;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : ref = espace de référencement global. *
+* *
+* Description : Construit et intègre un panneau d'affichage des symboles. *
+* *
+* Retour : Adresse du panneau mis en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GPanelItem *create_glance_panel(GObject *ref)
+{
+ GEditorItem *result; /* Elément réactif à renvoyer */
+
+ result = g_glance_panel_new(ref);
+
+ /* Enregistre correctement le tout */
+ register_editor_item(result);
+
+ return G_PANEL_ITEM(result);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : panel = panneau à actualiser. *
+* view = nouveau panneau d'affichage actif. *
+* *
+* Description : Lance une actualisation du fait d'un changement de support. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void update_glance_panel_for_view(GGlancePanel *panel, GtkViewPanel *view)
+{
+ GtkWidget *parent; /* Support défilant de la vue */
+ GtkAdjustment *adj; /* Gestionnaire du défilement */
+
+ if (panel->view != NULL)
+ {
+ g_object_unref(panel->view);
+ panel->view = NULL;
+
+ g_object_unref(panel->support);
+ panel->support = NULL;
+
+ if (panel->cache != NULL)
+ {
+ cairo_surface_destroy(panel->cache);
+ panel->cache = NULL;
+ }
+
+ }
+
+ parent = gtk_widget_get_parent(GTK_WIDGET(view));
+ if (!GTK_IS_SCROLLED_WINDOW(parent)) return;
+
+ panel->view = view;
+ g_object_ref(panel->view);
+
+ panel->support = GTK_SCROLLED_WINDOW(parent);
+ g_object_ref(panel->support);
+
+ adj = gtk_scrolled_window_get_hadjustment(panel->support);
+ g_signal_connect(G_OBJECT(adj), "changed", G_CALLBACK(on_view_scroll_setup), panel);
+ g_signal_connect(G_OBJECT(adj), "value-changed", G_CALLBACK(on_view_scrolled), panel);
+
+ adj = gtk_scrolled_window_get_vadjustment(panel->support);
+ g_signal_connect(G_OBJECT(adj), "changed", G_CALLBACK(on_view_scroll_setup), panel);
+ g_signal_connect(G_OBJECT(adj), "value-changed", G_CALLBACK(on_view_scrolled), panel);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : adj = contrôle du défilement modifié. *
+* panel = panneau de l'aperçu à actualiser. *
+* *
+* Description : Réagit à la préparation du défilement du support original. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void on_view_scroll_setup(GtkAdjustment *adj, GGlancePanel *panel)
+{
+ GtkAdjustment *hadj; /* Gestionnaire du défilement */
+ GtkAdjustment *vadj; /* Gestionnaire du défilement */
+
+ hadj = gtk_scrolled_window_get_hadjustment(panel->support);
+ vadj = gtk_scrolled_window_get_vadjustment(panel->support);
+
+ if (hadj->page_size == 0 || vadj->page_size == 0)
+ return;
+
+ compute_glance_scale(panel);
+
+ on_view_scrolled(adj, panel);
+
+ gtk_widget_size_request(GTK_WIDGET(panel->view), &panel->req);
+
+ panel->req.width += hadj->value;
+ panel->req.height += vadj->value;
+
+ update_glance_panel_for_view_content(panel, panel->view);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : adj = contrôle du défilement modifié. *
+* panel = panneau de l'aperçu à actualiser. *
+* *
+* Description : Réagit à un défilement du support original. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void on_view_scrolled(GtkAdjustment *adj, GGlancePanel *panel)
+{
+ GtkAdjustment *hadj; /* Gestionnaire du défilement */
+ GtkAdjustment *vadj; /* Gestionnaire du défilement */
+
+ hadj = gtk_scrolled_window_get_hadjustment(panel->support);
+ vadj = gtk_scrolled_window_get_vadjustment(panel->support);
+
+ if (hadj->page_size == 0 || vadj->page_size == 0)
+ return;
+
+ panel->visible.x = panel->painting.x + hadj->value * panel->scale;
+ panel->visible.y = panel->painting.y + vadj->value * panel->scale;
+ panel->visible.width = hadj->page_size * panel->scale;
+ panel->visible.height = vadj->page_size * panel->scale;
+
+ gtk_widget_queue_draw(G_EDITOR_ITEM(panel)->widget);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : widget = composant GTK ayant changé de taille. *
+* alloc = nouvel espace mis à disposition. *
+* panel = panneau de l'aperçu à actualiser. *
+* *
+* Description : Réagit à un changement de taille de l'espace de rendu. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void on_glance_resize(GtkWidget *widget, GdkRectangle *allocation, GGlancePanel *panel)
+{
+ if (panel->view != NULL)
+ {
+ on_view_scroll_setup(NULL, panel);
+ update_glance_panel_for_view_content(panel, panel->view);
+ }
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : panel = panneau à actualiser. *
+* *
+* Description : Calcule l'emplacement du rendu maniature et son échelle. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void compute_glance_scale(GGlancePanel *panel)
+{
+ GtkAllocation available; /* Surface disponible totale */
+ gint border; /* Taille de la bordure */
+ double sx; /* Echelle sur l'axe X */
+ double sy; /* Echelle sur l'axe Y */
+
+ /* Superficies niveau GTK... */
+
+ gtk_widget_get_allocation(G_EDITOR_ITEM(panel)->widget, &available);
+
+ border = MIN(2, G_EDITOR_ITEM(panel)->widget->style->xthickness);
+ if (border > 0)
+ {
+ available.x = border;
+ available.width -= 2 * border;
+ }
+
+ border = MIN(2, G_EDITOR_ITEM(panel)->widget->style->ythickness);
+ if (border > 0)
+ {
+ available.y = border;
+ available.height -= 2 * border;
+ }
+
+ /* Calcul des ratios et emplacements */
+
+ sx = (1.0 * available.width) / panel->req.width;
+ sy = (1.0 * available.height) / panel->req.height;
+
+ if (sx < sy)
+ {
+ panel->scale = sx;
+ panel->painting.width = available.width;
+ panel->painting.height = panel->req.height * panel->scale;
+ }
+ else
+ {
+ panel->scale = sy;
+ panel->painting.width = panel->req.width * panel->scale;
+ panel->painting.height = available.height;
+ }
+
+ panel->painting.x = available.x + (available.width - panel->painting.width) / 2;
+ panel->painting.y = available.y + (available.height - panel->painting.height) / 2;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : panel = panneau à actualiser. *
+* view = nouveau panneau d'affichage actif. *
+* *
+* Description : Lance une actualisation du fait d'un changement de vue. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void update_glance_panel_for_view_content(GGlancePanel *panel, GtkViewPanel *view)
+{
+ cairo_t *cairo; /* Assistant pour le dessin */
+
+ /* Mise en place d'un cache adapté */
+
+ if (panel->cache != NULL)
+ cairo_surface_destroy(panel->cache);
+
+ panel->cache = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
+ panel->painting.width,
+ panel->painting.height);
+
+ cairo = cairo_create(panel->cache);
+
+ cairo_scale(cairo, panel->scale, panel->scale);
+
+ /* Dessin de l'aperçu représentatif */
+
+ gtk_view_panel_cache_glance(view, cairo);
+
+ cairo_destroy(cairo);
+
+ gtk_widget_queue_draw(G_EDITOR_ITEM(panel)->widget);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : widget = composant GTK à redessiner. *
+* event = informations liées à l'événement. *
+* panel = informations liées au panneau associé. *
+* *
+* Description : Met à jour l'affichage de l'aperçu rapide à présenter. *
+* *
+* Retour : FALSE pour poursuivre la propagation de l'événement. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static gboolean redraw_glance_area(GtkWidget *widget, GdkEventExpose *event, GGlancePanel *panel)
+{
+ GtkAllocation available; /* Surface disponible totale */
+ cairo_t *cairo; /* Gestionnaire de rendu */
+
+ /* Dessin de la bordure */
+
+ gtk_widget_get_allocation(widget, &available);
+
+ gtk_paint_box(widget->style, event->window, widget->state,
+ GTK_SHADOW_IN, &event->area, NULL, NULL,
+ 0, 0, available.width, available.height);
+
+ /* Dessin de l'aperçu */
+
+ if (panel->cache != NULL)
+ {
+ cairo = gdk_cairo_create(widget->window);
+
+ cairo_rectangle(cairo, panel->visible.x, panel->visible.y,
+ panel->visible.width, panel->visible.height);
+
+ cairo_clip(cairo);
+
+ cairo_set_source_rgb(cairo, 1.0, 1.0, 1.0);
+
+ cairo_rectangle(cairo, panel->painting.x, panel->painting.y,
+ panel->painting.width, panel->painting.height);
+
+ cairo_fill(cairo);
+
+ cairo_reset_clip(cairo);
+
+ cairo_set_source_surface(cairo, panel->cache, panel->painting.x, panel->painting.y);
+ cairo_paint(cairo);
+
+ cairo_destroy(cairo);
+
+ }
+
+ return TRUE;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : widget = composant GTK visé par l'opération. *
+* event = informations liées à l'événement. *
+* panel = informations liées au panneau associé. *
+* *
+* Description : Assure la gestion des clics de souris sur l'aperçu. *
+* *
+* Retour : FALSE pour poursuivre la propagation de l'événement. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static gboolean on_button_press_over_glance(GtkWidget *widget, GdkEventButton *event, GGlancePanel *panel)
+{
+ GtkAdjustment *hadj; /* Gestionnaire du défilement */
+ GtkAdjustment *vadj; /* Gestionnaire du défilement */
+
+ if (panel->view != NULL && event->button == 1)
+ {
+ panel->start_x = event->x;
+ panel->start_y = event->y;
+
+ hadj = gtk_scrolled_window_get_hadjustment(panel->support);
+ vadj = gtk_scrolled_window_get_vadjustment(panel->support);
+
+ panel->ref_h = hadj->value;
+ panel->ref_v = vadj->value;
+
+ panel->valid = (panel->visible.x <= panel->start_x
+ && panel->start_x < (panel->visible.x + panel->visible.width)
+ && panel->visible.y <= panel->start_y
+ && panel->start_y < (panel->visible.y + panel->visible.height));
+
+ }
+
+ return FALSE;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : widget = composant GTK visé par l'opération. *
+* event = informations liées à l'événement. *
+* panel = informations liées au panneau associé. *
+* *
+* Description : Assure la gestion du déplacement de la souris sur l'aperçu. *
+* *
+* Retour : FALSE pour poursuivre la propagation de l'événement. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static gboolean on_mouse_motion_over_glance(GtkWidget *widget, GdkEventMotion *event, GGlancePanel *panel)
+{
+ gdouble diff_x; /* Evolution sur les abscisses */
+ gdouble diff_y; /* Evolution sur les ordonnées */
+ GtkAdjustment *hadj; /* Gestionnaire du défilement */
+ GtkAdjustment *vadj; /* Gestionnaire du défilement */
+
+ if (panel->view != NULL && event->state & GDK_BUTTON1_MASK && panel->valid)
+ {
+ diff_x = (event->x - panel->start_x) / panel->scale;
+ diff_y = (event->y - panel->start_y) / panel->scale;
+
+ hadj = gtk_scrolled_window_get_hadjustment(panel->support);
+ vadj = gtk_scrolled_window_get_vadjustment(panel->support);
+
+ gtk_adjustment_set_value(hadj, panel->ref_h + diff_x);
+ gtk_adjustment_set_value(vadj, panel->ref_v + diff_y);
+
+ }
+
+ return FALSE;
+
+}