diff options
Diffstat (limited to 'src/gui/panels/glance.c')
-rw-r--r-- | src/gui/panels/glance.c | 645 |
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; + +} |