/* Chrysalide - Outil d'analyse de fichiers binaires
* gtkdisplaypanel.c - affichage de contenus de binaire
*
* Copyright (C) 2016-2017 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 "gtkdisplaypanel.h"
#include
#include "gtkdisplaypanel-int.h"
#include "../glibext/gloadedpanel-int.h"
/* Amplitude de l'arrondi pour les coins */
#define BORDER_CORNER_RADIUS 10.0
/* Procède à l'initialisation de l'afficheur générique. */
static void gtk_display_panel_class_init(GtkDisplayPanelClass *);
/* Procède à l'initialisation de l'afficheur générique. */
static void gtk_display_panel_init(GtkDisplayPanel *);
/* Procède à l'initialisation de l'interface d'affichage. */
static void gtk_display_panel_loaded_interface_init(GLoadedPanelInterface *);
/* Définit une propriété du composant d'affichage. */
static void gtk_display_panel_set_property(GObject *, guint, const GValue *, GParamSpec *);
/* Fournit une propriété du composant d'affichage. */
static void gtk_display_panel_get_property(GObject *, guint, GValue *, GParamSpec *);
/* Détruit un composant d'affichage. */
static void gtk_display_panel_destroy(GtkWidget *);
/* Encadre la construction graphique initiale de l'affichage. */
static void gtk_display_panel_realize(GtkWidget *);
/* S'adapte à la surface concédée par le composant parent. */
static void gtk_display_panel_size_allocate(GtkWidget *, GtkAllocation *);
/* Fournit la hauteur idéale pour le composant d'affichage. */
static void gtk_display_panel_get_preferred_height(GtkWidget *, gint *, gint *);
/* Fournit la largeur idéale pour le composant d'affichage. */
static void gtk_display_panel_get_preferred_width(GtkWidget *, gint *, gint *);
/* Détermine la taille des bonds lors de défilements. */
static void gtk_display_panel_compute_scroll_inc(GtkDisplayPanel *, gint, GtkOrientation, gdouble *, gdouble *);
/* Détermine la taille allouée pour le contenu. */
static void gtk_display_panel_compute_allocation(GtkDisplayPanel *, GtkAllocation *);
/* Se débarrsse d'un ajustement pour un défilement donné. */
static void gtk_display_panel_disconnect_adjustment(GtkDisplayPanel *, GtkOrientation);
/* S'associe à un ajustement pour un défilement donné. */
static void gtk_display_panel_set_adjustment(GtkDisplayPanel *, GtkOrientation, GtkAdjustment *);
/* Ajuste les paramètres de défilement du composant. */
static void gtk_display_panel_update_adjustment(GtkDisplayPanel *, GtkOrientation);
/* Réagit à un défilement chez une barre associée au composant.*/
static void gtk_display_panel_adjustment_value_changed(GtkAdjustment *, GtkDisplayPanel *);
/* Réagit à un changement des règles d'affichage. */
static void on_view_panel_binary_display_change(GLoadedBinary *, BinaryView, BufferLineColumn, GtkDisplayPanel *);
/* ----------------------- INTERFACE DE PANNEAU DE CHARGEMENT ----------------------- */
/* Associe à un panneau d'affichage un binaire chargé. */
static void gtk_display_panel_set_content(GtkDisplayPanel *, GLoadedContent *);
/* Fournit le contenu associé à un panneau de chargement. */
static GLoadedContent *gtk_display_panel_get_content(const GtkDisplayPanel *);
/* Place en cache un rendu destiné à l'aperçu graphique rapide. */
static void gtk_display_panel_cache_glance(GtkDisplayPanel *, cairo_t *, const GtkAllocation *, double);
/* Détermine le type du composant d'affichage générique. */
G_DEFINE_TYPE_WITH_CODE(GtkDisplayPanel, gtk_display_panel, GTK_TYPE_FIXED,
G_IMPLEMENT_INTERFACE(GTK_TYPE_SCROLLABLE, NULL)
G_IMPLEMENT_INTERFACE(G_TYPE_LOADED_PANEL, gtk_display_panel_loaded_interface_init));
/******************************************************************************
* *
* Paramètres : class = classe GTK à initialiser. *
* *
* Description : Procède à l'initialisation de l'afficheur générique. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void gtk_display_panel_class_init(GtkDisplayPanelClass *class)
{
GObjectClass *gobject_class; /* Plus haut niveau équivalent */
GtkWidgetClass *widget_class; /* Classe de haut niveau */
GtkDisplayPanelClass *panel_class; /* Classe de lus bas niveau */
gobject_class = G_OBJECT_CLASS(class);
widget_class = GTK_WIDGET_CLASS(class);
panel_class = GTK_DISPLAY_PANEL_CLASS(class);
gobject_class->set_property = gtk_display_panel_set_property;
gobject_class->get_property = gtk_display_panel_get_property;
/* Implémentation de l'interface "GtkScrollable" */
g_object_class_override_property(gobject_class, VPP_HADJUSTMENT, "hadjustment");
g_object_class_override_property(gobject_class, VPP_VADJUSTMENT, "vadjustment");
g_object_class_override_property(gobject_class, VPP_HSCROLL_POLICY, "hscroll-policy");
g_object_class_override_property(gobject_class, VPP_VSCROLL_POLICY, "vscroll-policy");
widget_class->destroy = gtk_display_panel_destroy;
widget_class->realize = gtk_display_panel_realize;
widget_class->size_allocate = gtk_display_panel_size_allocate;
widget_class->get_preferred_height = gtk_display_panel_get_preferred_height;
widget_class->get_preferred_width = gtk_display_panel_get_preferred_width;
panel_class->compute_inc = gtk_display_panel_compute_scroll_inc;
g_signal_new("move-request",
GTK_TYPE_DISPLAY_PANEL,
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET(GtkDisplayPanelClass, move_request),
NULL, NULL,
g_cclosure_marshal_VOID__POINTER,
G_TYPE_NONE, 1, G_TYPE_POINTER);
g_signal_new("caret-moved",
GTK_TYPE_DISPLAY_PANEL,
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET(GtkDisplayPanelClass, caret_moved),
NULL, NULL,
g_cclosure_marshal_VOID__POINTER,
G_TYPE_NONE, 1, G_TYPE_POINTER);
}
/******************************************************************************
* *
* Paramètres : panel = composant GTK à initialiser. *
* *
* Description : Procède à l'initialisation de l'afficheur générique. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void gtk_display_panel_init(GtkDisplayPanel *panel)
{
gtk_widget_set_has_window(GTK_WIDGET(panel), TRUE);
gtk_widget_set_can_focus(GTK_WIDGET(panel), TRUE);
}
/******************************************************************************
* *
* Paramètres : iface = interface GLib à initialiser. *
* *
* Description : Procède à l'initialisation de l'interface d'affichage. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void gtk_display_panel_loaded_interface_init(GLoadedPanelInterface *iface)
{
iface->set_content = (set_loaded_panel_content_fc)gtk_display_panel_set_content;
iface->get_content = (get_loaded_panel_content_fc)gtk_display_panel_get_content;
iface->cache_glance = (cache_loaded_glance_fc)gtk_display_panel_cache_glance;
}
/******************************************************************************
* *
* Paramètres : object = instance de composant GTK à manipuler. *
* prop_id = identifiant de la propriété concernée. *
* value = valeur attribuée. *
* pspec = spécification de la propriété visée. *
* *
* Description : Définit une propriété du composant d'affichage. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void gtk_display_panel_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
{
GtkDisplayPanel *panel; /* Autre vision de l'instance */
panel = GTK_DISPLAY_PANEL(object);
switch (prop_id)
{
case VPP_HADJUSTMENT:
gtk_display_panel_set_adjustment(panel, GTK_ORIENTATION_HORIZONTAL, g_value_get_object(value));
break;
case VPP_VADJUSTMENT:
gtk_display_panel_set_adjustment(panel, GTK_ORIENTATION_VERTICAL, g_value_get_object(value));
break;
case VPP_HSCROLL_POLICY:
//viewport->priv->hscroll_policy = g_value_get_enum (value);
//gtk_widget_queue_resize (GTK_WIDGET (viewport));
break;
case VPP_VSCROLL_POLICY:
//viewport->priv->vscroll_policy = g_value_get_enum (value);
//gtk_widget_queue_resize (GTK_WIDGET (viewport));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
break;
}
}
/******************************************************************************
* *
* Paramètres : object = instance de composant GTK à manipuler. *
* prop_id = identifiant de la propriété concernée. *
* value = valeur à renvoyer. *
* pspec = spécification de la propriété visée. *
* *
* Description : Fournit une propriété du composant d'affichage. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void gtk_display_panel_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
{
GtkDisplayPanel *panel; /* Autre vision de l'instance */
panel = GTK_DISPLAY_PANEL(object);
switch (prop_id)
{
case VPP_HADJUSTMENT:
g_value_set_object(value, panel->hadjustment);
break;
case VPP_VADJUSTMENT:
g_value_set_object(value, panel->vadjustment);
break;
case VPP_HSCROLL_POLICY:
g_value_set_enum(value, panel->hscroll_policy);
break;
case VPP_VSCROLL_POLICY:
g_value_set_enum(value, panel->vscroll_policy);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
break;
}
}
/******************************************************************************
* *
* Paramètres : widget = composant GTK à détruire. *
* *
* Description : Détruit un composant d'affichage. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void gtk_display_panel_destroy(GtkWidget *widget)
{
GtkDisplayPanel *panel; /* Autre version du composant */
panel = GTK_DISPLAY_PANEL(widget);
gtk_display_panel_disconnect_adjustment(panel, GTK_ORIENTATION_HORIZONTAL);
gtk_display_panel_disconnect_adjustment(panel, GTK_ORIENTATION_VERTICAL);
GTK_WIDGET_CLASS(gtk_display_panel_parent_class)->destroy(widget);
}
/******************************************************************************
* *
* Paramètres : widget = composant GTK à préparer. *
* *
* Description : Encadre la construction graphique initiale de l'affichage. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void gtk_display_panel_realize(GtkWidget *widget)
{
GtkAllocation allocation; /* Disposition du composant */
GdkWindowAttr attributes; /* Propriétés du composant */
guint attributes_mask; /* Masque de prise en compte */
GdkWindow *window; /* Fenêtre du composant */
gtk_widget_get_allocation(widget, &allocation);
gtk_widget_set_realized(widget, TRUE);
attributes.window_type = GDK_WINDOW_CHILD;
attributes.x = allocation.x;
attributes.y = allocation.y;
attributes.width = allocation.width;
attributes.height = allocation.height;
attributes.wclass = GDK_INPUT_OUTPUT;
attributes.event_mask = gtk_widget_get_events(widget)
| GDK_EXPOSURE_MASK
| GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK
| GDK_FOCUS_CHANGE_MASK
| GDK_SCROLL_MASK | GDK_SMOOTH_SCROLL_MASK;
attributes_mask = GDK_WA_X | GDK_WA_Y;
window = gdk_window_new(gtk_widget_get_parent_window(widget),
&attributes, attributes_mask);
gtk_widget_set_window(widget, window);
gtk_widget_register_window(widget, window);
}
/******************************************************************************
* *
* Paramètres : widget = composant GTK à mettre à jour. *
* allocation = étendue accordée à la vue. *
* *
* Description : S'adapte à la surface concédée par le composant parent. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void gtk_display_panel_size_allocate(GtkWidget *widget, GtkAllocation *allocation)
{
GtkDisplayPanel *panel; /* Autre version du composant */
GTK_WIDGET_CLASS(gtk_display_panel_parent_class)->size_allocate(widget, allocation);
panel = GTK_DISPLAY_PANEL(widget);
gtk_display_panel_update_adjustment(panel, GTK_ORIENTATION_HORIZONTAL);
gtk_display_panel_update_adjustment(panel, GTK_ORIENTATION_VERTICAL);
}
/******************************************************************************
* *
* Paramètres : widget = composant GTK à examiner. *
* minimum = hauteur minimale à préciser ou NULL. [OUT] *
* natural = hauteur idéale à préciser ou NULL. [OUT] *
* *
* Description : Fournit la hauteur idéale pour le composant d'affichage. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void gtk_display_panel_get_preferred_height(GtkWidget *widget, gint *minimum, gint *natural)
{
gint req; /* Dimension requise */
GTK_DISPLAY_PANEL_GET_CLASS(widget)->compute_size(GTK_DISPLAY_PANEL(widget), NULL, &req);
if (minimum != NULL) *minimum = req;
if (natural != NULL) *natural = req;
}
/******************************************************************************
* *
* Paramètres : widget = composant GTK à examiner. *
* minimum = largeur minimale à préciser ou NULL. [OUT] *
* natural = largeur idéale à préciser ou NULL. [OUT] *
* *
* Description : Fournit la largeur idéale pour le composant d'affichage. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void gtk_display_panel_get_preferred_width(GtkWidget *widget, gint *minimum, gint *natural)
{
gint req; /* Dimension requise */
GTK_DISPLAY_PANEL_GET_CLASS(widget)->compute_size(GTK_DISPLAY_PANEL(widget), &req, NULL);
if (minimum != NULL) *minimum = req;
if (natural != NULL) *natural = req;
}
/******************************************************************************
* *
* Paramètres : panel = composant GTK d'affichage à mettre à jour. *
* size = taille de l'espace dans la direction donnée. *
* orientation = indication sur le défilement à traiter. *
* step = valeur d'un petit pas de défilement. [OUT] *
* page = valeur d'un grand pas de défilement. [OUT] *
* *
* Description : Détermine la taille des bonds lors de défilements. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void gtk_display_panel_compute_scroll_inc(GtkDisplayPanel *panel, gint size, GtkOrientation orientation, gdouble *step, gdouble *page)
{
*step = size * 0.1;
*page = size * 0.9;
}
/******************************************************************************
* *
* Paramètres : panel = composant GTK à consulter. *
* alloc = emplacement à déterminer. [OUT] *
* *
* Description : Détermine la taille allouée pour le contenu. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void gtk_display_panel_compute_allocation(GtkDisplayPanel *panel, GtkAllocation *alloc)
{
GtkWidget *widget; /* Autre vision du composant */
GtkAllocation allocation; /* Emplacement du composant */
GtkStyleContext *context; /* Contexte du style */
GtkStateFlags state; /* Etat du composant */
GtkBorder padding; /* Espace d'un espacement */
GtkBorder border; /* Espace d'une bordure */
widget = GTK_WIDGET(panel);
gtk_widget_get_allocation(widget, &allocation);
context = gtk_widget_get_style_context(widget);
state = gtk_widget_get_state_flags(widget);
gtk_style_context_save(context);
gtk_style_context_add_class(context, GTK_STYLE_CLASS_FRAME);
gtk_style_context_get_padding(context, state, &padding);
gtk_style_context_get_border(context, state, &border);
gtk_style_context_restore(context);
/* Positions */
if (panel->show_border)
{
alloc->x = border.left;
alloc->y = border.top;
}
else
{
alloc->x = 0;
alloc->y = 0;
}
alloc->x += padding.left;
alloc->y += padding.top;
/* Dimensions */
if (panel->show_border)
{
alloc->width = MAX (1, allocation.width - alloc->x - padding.right - border.right);
alloc->height = MAX (1, allocation.height - alloc->y - padding.bottom - border.bottom);
}
else
{
alloc->width = MAX (1, allocation.width - alloc->x - padding.right);
alloc->height = MAX (1, allocation.height - alloc->y - padding.bottom);
}
}
/******************************************************************************
* *
* Paramètres : panel = composant GTK d'affichage à mettre à jour. *
* orientation = indication sur le défilement à traiter. *
* *
* Description : Se débarrsse d'un ajustement pour un défilement donné. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void gtk_display_panel_disconnect_adjustment(GtkDisplayPanel *panel, GtkOrientation orientation)
{
GtkAdjustment **adjp; /* Ajustement à manipuler */
adjp = orientation == GTK_ORIENTATION_HORIZONTAL ? &panel->hadjustment : &panel->vadjustment;
if (*adjp != NULL)
{
g_signal_handlers_disconnect_by_func(*adjp, gtk_display_panel_adjustment_value_changed, panel);
g_object_unref(G_OBJECT(*adjp));
*adjp = NULL;
}
}
/******************************************************************************
* *
* Paramètres : panel = composant GTK d'affichage à mettre à jour. *
* orientation = indication sur le défilement à traiter. *
* adj = nouvel ajustement à prendre en compte. *
* *
* Description : S'associe à un ajustement pour un défilement donné. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void gtk_display_panel_set_adjustment(GtkDisplayPanel *panel, GtkOrientation orientation, GtkAdjustment *adj)
{
GtkAdjustment **adjp; /* Ajustement à manipuler */
adjp = orientation == GTK_ORIENTATION_HORIZONTAL ? &panel->hadjustment : &panel->vadjustment;
/* S'il n'y a rien à faire... */
if (adj != NULL && adj == *adjp)
return;
if (!adj)
adj = gtk_adjustment_new(0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
gtk_display_panel_disconnect_adjustment(panel, orientation);
*adjp = adj;
g_object_ref_sink(adj);
gtk_display_panel_update_adjustment(panel, orientation);
g_signal_connect(adj, "value-changed", G_CALLBACK(gtk_display_panel_adjustment_value_changed), panel);
gtk_display_panel_adjustment_value_changed(adj, panel);
}
/******************************************************************************
* *
* Paramètres : panel = composant GTK d'affichage à mettre à jour. *
* orientation = indication sur le défilement à traiter. *
* *
* Description : Ajuste les paramètres de défilement du composant. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void gtk_display_panel_update_adjustment(GtkDisplayPanel *panel, GtkOrientation orientation)
{
GtkAllocation allocation; /* Emplacement du contenu */
GtkAdjustment *adj; /* Ajustement à manipuler */
gint req; /* Dimension requise */
gint allocated; /* Dimension allouée */
gdouble step_inc; /* Pas de défilement */
gdouble page_inc; /* ENjambée de défilement */
gtk_display_panel_compute_allocation(panel, &allocation);
if (orientation == GTK_ORIENTATION_HORIZONTAL)
{
adj = panel->hadjustment;
GTK_DISPLAY_PANEL_GET_CLASS(panel)->compute_size(panel, &req, NULL);
allocated = allocation.width;
}
else
{
adj = panel->vadjustment;
GTK_DISPLAY_PANEL_GET_CLASS(panel)->compute_size(panel, NULL, &req);
allocated = allocation.height;
}
GTK_DISPLAY_PANEL_GET_CLASS(panel)->compute_inc(panel, allocated, orientation, &step_inc, &page_inc);
gtk_adjustment_configure(adj, gtk_adjustment_get_value(adj),
0, MAX(req, allocated),
step_inc,
page_inc,
allocated);
}
/******************************************************************************
* *
* Paramètres : adj = défilement dont une valeur a changé. *
* panel = panneau d'affichage concerné. *
* *
* Description : Réagit à un défilement chez une barre associée au composant. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void gtk_display_panel_adjustment_value_changed(GtkAdjustment *adj, GtkDisplayPanel *panel)
{
GtkOrientation orientation; /* Indification de la barre */
orientation = (adj == panel->hadjustment ? GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL);
if (GTK_DISPLAY_PANEL_GET_CLASS(panel)->adjust != NULL)
GTK_DISPLAY_PANEL_GET_CLASS(panel)->adjust(panel, adj, orientation);
}
/******************************************************************************
* *
* Paramètres : panel = composant GTK à mettre à jour. *
* show = état de l'affichage auquel parvenir. *
* *
* Description : Définit si une bordure est à afficher. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void gtk_display_panel_show_border(GtkDisplayPanel *panel, bool show)
{
panel->show_border = show;
}
/******************************************************************************
* *
* Paramètres : panel = composant GTK à venir consulter. *
* cr = contexte graphique associé à l'événement. *
* offset = décallage éventuel à appliquer. *
* *
* Description : Définit un chemin décrivant la bordure autour du panneau. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void gtk_display_panel_define_border_path(GtkDisplayPanel *panel, cairo_t *cr, gint off_x, gint off_y)
{
GtkRequisition req; /* Taille allouée à l'élément */
double degrees; /* Conversion en degrés */
gtk_widget_get_preferred_size(GTK_WIDGET(panel), NULL, &req);
degrees = M_PI / 180.0;
cairo_new_sub_path(cr);
cairo_arc(cr,
off_x + req.width - BORDER_CORNER_RADIUS - 0.5,
off_y + BORDER_CORNER_RADIUS + 0.5,
BORDER_CORNER_RADIUS, -90 * degrees, 0 * degrees);
cairo_arc(cr,
off_x + req.width - BORDER_CORNER_RADIUS - 0.5,
off_y + req.height - BORDER_CORNER_RADIUS - 0.5,
BORDER_CORNER_RADIUS, 0 * degrees, 90 * degrees);
cairo_arc(cr,
off_x + BORDER_CORNER_RADIUS + 0.5,
off_y + req.height - BORDER_CORNER_RADIUS - 0.5,
BORDER_CORNER_RADIUS, 90 * degrees, 180 * degrees);
cairo_arc(cr,
off_x + BORDER_CORNER_RADIUS + 0.5,
off_y + BORDER_CORNER_RADIUS + 0.5,
BORDER_CORNER_RADIUS, 180 * degrees, 270 * degrees);
cairo_close_path(cr);
}
/******************************************************************************
* *
* Paramètres : panel = composant GTK à venir consulter. *
* cr = contexte graphique associé à l'événement. *
* *
* Description : Dessine si besoin est une bordure autour du composant. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void gtk_display_panel_draw_border(GtkDisplayPanel *panel, cairo_t *cr)
{
GtkWidget *widget; /* Autre version du composant */
GtkRequisition req; /* Taille allouée à l'élément */
GtkStyleContext *context; /* Contexte du thème actuel */
GdkRGBA color; /* Couleur de thème récupérée */
if (panel->show_border)
{
widget = GTK_WIDGET(panel);
gtk_widget_get_preferred_size(widget, NULL, &req);
context = gtk_widget_get_style_context(widget);
gtk_style_context_save(context);
gtk_style_context_add_class(context, GTK_STYLE_CLASS_FRAME);
gtk_style_context_get(gtk_widget_get_style_context(widget),
gtk_widget_get_state_flags(widget),
GTK_STYLE_PROPERTY_COLOR, &color, NULL);
cairo_set_source_rgba(cr, color.red, color.green, color.blue, color.alpha);
cairo_set_line_width(cr, 1.0);
gtk_display_panel_define_border_path(panel, cr, 0, 0);
cairo_stroke(cr);
gtk_style_context_restore(context);
}
}
/******************************************************************************
* *
* Paramètres : binary = bianire dont les consignes d'affichage ont évolué. *
* view = type d'affichage à considérer. *
* col = colonne dont le statut a changé. *
* panel = composant GTK à consulter. *
* *
* Description : Réagit à un changement des règles d'affichage. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void on_view_panel_binary_display_change(GLoadedBinary *binary, BinaryView view, BufferLineColumn col, GtkDisplayPanel *panel)
{
if (panel->view_index == view)
{
gtk_widget_queue_resize(gtk_widget_get_parent(GTK_WIDGET(panel)));
gtk_widget_queue_resize(GTK_WIDGET(panel));
gtk_widget_queue_draw(GTK_WIDGET(panel));
}
}
/******************************************************************************
* *
* Paramètres : panel = composant GTK à consulter. *
* *
* Description : Fournit le binaire associé à la représentation. *
* *
* Retour : Représentation de contenu binaire. *
* *
* Remarques : - *
* *
******************************************************************************/
GLoadedBinary *gtk_display_panel_get_binary(const GtkDisplayPanel *panel)
{
g_object_ref(G_OBJECT(panel->binary));
return panel->binary;
}
/******************************************************************************
* *
* Paramètres : panel = composant GTK à consulter. *
* *
* Description : Indique la position courante du curseur. *
* *
* Retour : Emplacement courant du curseur ou NULL si aucun. *
* *
* Remarques : - *
* *
******************************************************************************/
const vmpa2t *gtk_display_panel_get_caret_location(const GtkDisplayPanel *panel)
{
const vmpa2t *result; /* Adresse à retourner */
result = GTK_DISPLAY_PANEL_GET_CLASS(panel)->get_caret_loc(panel);
return result;
}
/******************************************************************************
* *
* Paramètres : panel = composant GTK à manipuler. *
* addr = adresse à présenter à l'écran. *
* tweak = adaptation finale à effectuer. *
* move = doit-on déplacer le curseur à l'adresse indiquée ? *
* *
* Description : S'assure qu'une adresse donnée est visible à l'écran. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void _gtk_display_panel_scroll_to_address(GtkDisplayPanel *panel, const vmpa2t *addr, ScrollPositionTweak tweak, bool move)
{
GtkWidget *parent; /* Support parent à valider */
gint x; /* Abscisse à garantir */
gint y; /* Ordonnée à garantir */
GtkWidget *viewport; /* Parent avec défilement */
GtkAdjustment *adj; /* Défilement à mettre à jour */
gdouble step_inc; /* Valeur d'un petit pas */
gdouble page_size; /* Taille de l'affichage */
double value; /* Valeur courante */
/**
* Si une vue partielle se déplace via cette fonction, il faut potentiellement
* rediriger l'appel vers la vue en graphiques parente.
*/
parent = gtk_widget_get_parent(GTK_WIDGET(panel));
parent = gtk_widget_get_parent(GTK_WIDGET(parent));
if (GTK_IS_DISPLAY_PANEL(parent))
panel = GTK_DISPLAY_PANEL(parent);
if (GTK_DISPLAY_PANEL_GET_CLASS(panel)->define != NULL)
GTK_DISPLAY_PANEL_GET_CLASS(panel)->define(panel, addr);
if (GTK_DISPLAY_PANEL_GET_CLASS(panel)->get_coordinates(panel, addr, &x, &y, tweak))
{
viewport = gtk_widget_get_parent(GTK_WIDGET(panel));
/* Eventuel défilement horizontal */
g_object_get(G_OBJECT(viewport), "hadjustment", &adj, NULL);
step_inc = gtk_adjustment_get_step_increment(adj);
page_size = gtk_adjustment_get_page_size(adj);
value = gtk_adjustment_get_value(adj);
if (x < value)
gtk_adjustment_set_value(adj, x);
else if ((x + step_inc) > (value + page_size))
gtk_adjustment_set_value(adj, x + step_inc - page_size);
/* Eventuel défilement vertical */
g_object_get(G_OBJECT(viewport), "vadjustment", &adj, NULL);
step_inc = gtk_adjustment_get_step_increment(adj);
page_size = gtk_adjustment_get_page_size(adj);
value = gtk_adjustment_get_value(adj);
if (y < value || tweak != SPT_RAW)
gtk_adjustment_set_value(adj, y);
else if ((y + step_inc) > (value + page_size))
gtk_adjustment_set_value(adj, y + step_inc - page_size);
/* Déplacement du curseur */
if (move && GTK_DISPLAY_PANEL_GET_CLASS(panel)->get_coordinates(panel, addr, &x, &y, SPT_RAW))
GTK_DISPLAY_PANEL_GET_CLASS(panel)->move_caret_to(panel, x, y);
}
}
/******************************************************************************
* *
* Paramètres : panel = composant GTK à manipuler. *
* addr = adresse à présenter à l'écran. *
* *
* Description : Demande à qui veut répondre un déplacement du curseur. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void gtk_display_panel_request_move(GtkDisplayPanel *panel, const vmpa2t *addr)
{
g_signal_emit_by_name(panel, "move-request", addr);
}
/******************************************************************************
* *
* Paramètres : panel = composant GTK à consulter. *
* line = ligne de tampon où se trouve le curseur. [OUT] *
* segment = eventuel segment de ligne actif. [OUT] *
* *
* Description : Fournit des éléments liés à la position courante dans la vue.*
* *
* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
bool gtk_display_panel_get_position(const GtkDisplayPanel *panel, GBufferLine **line, GObject **creator)
{
bool result; /* Bilan de l'opération */
*line = NULL;
if (creator != NULL) *creator = NULL;
if (GTK_DISPLAY_PANEL_GET_CLASS(panel)->get_position == NULL)
return false;
result = GTK_DISPLAY_PANEL_GET_CLASS(panel)->get_position(panel, line, creator);
if (result)
{
g_object_ref(G_OBJECT(*line));
if (creator != NULL && *creator != NULL)
g_object_ref(G_OBJECT(*creator));
}
return result;
}
/******************************************************************************
* *
* Paramètres : panel = composant GTK à consulter. *
* event = informations liées à l'événement. *
* *
* Description : Transcrit les coordonnées à l'écran en coordonnées absolues. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void gtk_display_panel_compute_fake_coord(GtkDisplayPanel *panel, gint *x, gint *y)
{
if (panel->hadjustment != NULL)
*x -= gtk_adjustment_get_value(panel->hadjustment);
if (panel->vadjustment != NULL)
*y += gtk_adjustment_get_value(panel->vadjustment);
}
/******************************************************************************
* *
* Paramètres : panel = composant GTK à consulter. *
* event = informations liées à l'événement. *
* *
* Description : Transcrit les coordonnées absolues en coordonnées à l'écran. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void gtk_display_panel_compute_real_coord(GtkDisplayPanel *panel, gint *x, gint *y)
{
if (x != NULL && panel->hadjustment != NULL)
*x += gtk_adjustment_get_value(panel->hadjustment);
if (y != NULL && panel->vadjustment != NULL)
*y += gtk_adjustment_get_value(panel->vadjustment);
}
/******************************************************************************
* *
* Paramètres : panel = composant GTK à consulter. *
* x = abscisse à ajuster. [OUT] *
* x = ordonnée à ajuster. [OUT] *
* *
* Description : Transcrit les coordonnées absolues en coordonnées à l'écran. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void gtk_display_panel_compute_relative_coords(GtkDisplayPanel *panel, gint *x, gint *y)
{
if (x != NULL && panel->hadjustment != NULL)
*x -= gtk_adjustment_get_value(panel->hadjustment);
if (y != NULL && panel->vadjustment != NULL)
*y -= gtk_adjustment_get_value(panel->vadjustment);
}
/* ---------------------------------------------------------------------------------- */
/* INTERFACE DE PANNEAU DE CHARGEMENT */
/* ---------------------------------------------------------------------------------- */
/******************************************************************************
* *
* Paramètres : panel = composant GTK à mettre à jour. *
* content = binaire associé à intégrer. *
* *
* Description : Associe à un panneau d'affichage un binaire chargé. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void gtk_display_panel_set_content(GtkDisplayPanel *panel, GLoadedContent *content)
{
panel->view_index = g_loaded_content_get_view_index(content, GTK_WIDGET(panel));
panel->display_options = g_loaded_content_get_all_display_options(content, panel->view_index);
panel->binary = G_LOADED_BINARY(content);
if (GTK_DISPLAY_PANEL_GET_CLASS(panel)->attach != NULL) /* REMME */
GTK_DISPLAY_PANEL_GET_CLASS(panel)->attach(panel, panel->binary);
g_signal_connect(content, "display-changed", G_CALLBACK(on_view_panel_binary_display_change), panel);
}
/******************************************************************************
* *
* Paramètres : panel = composant GTK à consulter. *
* *
* Description : Fournit le contenu associé à un panneau de chargement. *
* *
* Retour : Contenu quelconque chargé en mémoire. *
* *
* Remarques : - *
* *
******************************************************************************/
static GLoadedContent *gtk_display_panel_get_content(const GtkDisplayPanel *panel)
{
GLoadedContent *result; /* Contenu à retourner */
result = G_LOADED_CONTENT(panel->binary);
return result;
}
/******************************************************************************
* *
* Paramètres : panel = composant GTK à manipuler. *
* cairo = assistant pour la création de rendus. *
* area = taille de la surface réduite à disposition. *
* scale = échelle vis à vis de la taille réelle. *
* *
* Description : Place en cache un rendu destiné à l'aperçu graphique rapide. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void gtk_display_panel_cache_glance(GtkDisplayPanel *panel, cairo_t *cairo, const GtkAllocation *area, double scale)
{
if (GTK_DISPLAY_PANEL_GET_CLASS(panel)->cache_glance != NULL)
GTK_DISPLAY_PANEL_GET_CLASS(panel)->cache_glance(panel, cairo, area, scale);
}