diff options
Diffstat (limited to 'src/gtkext/hexview.c')
-rw-r--r-- | src/gtkext/hexview.c | 437 |
1 files changed, 266 insertions, 171 deletions
diff --git a/src/gtkext/hexview.c b/src/gtkext/hexview.c index 717c1bc..7363079 100644 --- a/src/gtkext/hexview.c +++ b/src/gtkext/hexview.c @@ -24,45 +24,17 @@ #include "hexview.h" -#include "area.h" -#include "contentview-int.h" - - - -/* ------------------------- BASES D'UN COMPOSANT GRAPHIQUE ------------------------- */ - +#include <alloca.h> +#include <sys/param.h> -/* Composant d'affichage d'octets bruts et imprimables (instance) */ -struct _GtkHexView -{ - GtkContentView parent; /* A laisser en premier */ - - union - { -#define _CHILDREN_COUNT 4 - - GtkWidget *children[_CHILDREN_COUNT];/* Sous-composants d'affichage*/ - - struct - { - GtkWidget *offsets; /* Affichage des positions */ - GtkWidget *hex; /* Affichage des octets brut */ - GtkWidget *ascii; /* Affichage des imprimables */ - GtkWidget *vscroll; /* Barre de défilement */ - }; - }; - - bool need_vscrolling; /* Besoin de défilement ? */ +#include "area.h" +#include "hexview-int.h" +#include "../glibext/options/hex.h" -}; -/* Composant d'affichage d'octets bruts et imprimables (classe) */ -struct _GtkHexViewClass -{ - GtkContentViewClass parent; /* A laisser en premier */ -}; +/* ------------------------- BASES D'UN COMPOSANT GRAPHIQUE ------------------------- */ /* Procède à l'initialisation de l'afficheur générique. */ @@ -77,6 +49,12 @@ static void gtk_hex_view_dispose(GtkHexView *); /* Procède à la libération totale de la mémoire. */ static void gtk_hex_view_finalize(GtkHexView *); +/* Procède à l'actualisation de l'affichage d'un sous-composant. */ +static void gtk_hex_view_dispatch_sub_snapshot(GtkWidget *, GtkSnapshot *, GtkWidget *); + +/* Adapte le cache de lignes hexadécimales à la taille courante. */ +static void gtk_hex_view_populate_cache(GtkHexView *); + void demo_snapshot (GtkWidget *widget, GtkSnapshot *snapshot, GtkWidget *parent); @@ -105,7 +83,7 @@ static void gtk_hex_view_measure(GtkWidget *, GtkOrientation, int, int *, int *, /* Détermine le type du composant d'affichage générique. */ -G_DEFINE_TYPE(GtkHexView, gtk_hex_view, GTK_TYPE_CONTENT_VIEW); +G_DEFINE_TYPE(GtkHexView, gtk_hex_view, GTK_TYPE_BUFFER_VIEW); /****************************************************************************** @@ -141,7 +119,6 @@ static void gtk_hex_view_class_init(GtkHexViewClass *class) gtk_widget_class_bind_template_child(widget, GtkHexView, offsets); gtk_widget_class_bind_template_child(widget, GtkHexView, hex); gtk_widget_class_bind_template_child(widget, GtkHexView, ascii); - gtk_widget_class_bind_template_child(widget, GtkHexView, vscroll); widget->size_allocate = gtk_hex_view_size_allocate; widget->get_request_mode = gtk_hex_view_get_request_mode; @@ -164,15 +141,31 @@ static void gtk_hex_view_class_init(GtkHexViewClass *class) static void gtk_hex_view_init(GtkHexView *view) { + GtkContentView *base; /* Base d'instance supérieure */ + + /* Niveau supérieur */ + + base = GTK_CONTENT_VIEW(view); + + base->options = G_DISPLAY_OPTIONS(g_hex_options_new()); + + base->sub_children = view->children; + base->sub_count = _CHILDREN_COUNT; + + /* Instance courante */ + gtk_widget_init_template(GTK_WIDGET(view)); - g_raw_scan_cache_register_snapshot(GTK_COMPOSING_AREA(view->offsets), demo_snapshot, GTK_WIDGET(view)); + g_raw_scan_cache_register_snapshot(GTK_COMPOSING_AREA(view->offsets), + gtk_hex_view_dispatch_sub_snapshot, GTK_WIDGET(view)); - g_raw_scan_cache_register_snapshot(GTK_COMPOSING_AREA(view->hex), demo_snapshot, GTK_WIDGET(view)); + g_raw_scan_cache_register_snapshot(GTK_COMPOSING_AREA(view->hex), + gtk_hex_view_dispatch_sub_snapshot, GTK_WIDGET(view)); - g_raw_scan_cache_register_snapshot(GTK_COMPOSING_AREA(view->ascii), demo_snapshot, GTK_WIDGET(view)); + g_raw_scan_cache_register_snapshot(GTK_COMPOSING_AREA(view->ascii), + gtk_hex_view_dispatch_sub_snapshot, GTK_WIDGET(view)); - view->need_vscrolling = true; + view->generator = NULL; } @@ -193,6 +186,8 @@ static void gtk_hex_view_dispose(GtkHexView *view) { gtk_widget_dispose_template(GTK_WIDGET(view), GTK_TYPE_HEX_VIEW); + g_clear_object(&view->generator); + G_OBJECT_CLASS(gtk_hex_view_parent_class)->dispose(G_OBJECT(view)); } @@ -217,130 +212,225 @@ static void gtk_hex_view_finalize(GtkHexView *view) } +/****************************************************************************** +* * +* Paramètres : content = contenu binaire à exposer de façon brute. * +* * +* Description : Crée un composant d'affichage d'octets bruts et imprimables. * +* * +* Retour : Centralisateur mis en place pour un composant GTK donné. * +* * +* Remarques : - * +* * +******************************************************************************/ +GtkHexView *gtk_hex_view_new(GBinContent *content) +{ + GtkHexView *result; /* Nouvelle instance à renvoyer*/ + result = g_object_new(GTK_TYPE_HEX_VIEW, NULL); + if (!gtk_hex_view_create(result, content)) + g_clear_object(&result); + return result; +} -void demo_snapshot (GtkWidget *widget, GtkSnapshot *snapshot, GtkWidget *parent) -{ - GdkRGBA red, green, yellow, blue; - float w, h; +/****************************************************************************** +* * +* Paramètres : view = composant d'affichage à initialiser pleinement. * +* content = contenu binaire à exposer de façon brute. * +* * +* Description : Met en place un nouveau composant d'affichage d'octets bruts.* +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ - gdk_rgba_parse (&red, "red"); - gdk_rgba_parse (&green, "green"); - gdk_rgba_parse (&yellow, "yellow"); - gdk_rgba_parse (&blue, "blue"); +bool gtk_hex_view_create(GtkHexView *view, GBinContent *content) +{ + bool result; /* Bilan à retourner */ + GtkBufferView *parent; /* Version parente du composant*/ + GBufferCache *cache; /* Tampon à représenter */ - w = gtk_widget_get_width (widget) / 2.0; - h = gtk_widget_get_height (widget) / 2.0; + result = true; - h /= 2.0; + assert(g_display_options_count(GTK_CONTENT_VIEW(view)->options) == 1); - gtk_snapshot_append_color (snapshot, &red, - &GRAPHENE_RECT_INIT(0, 0, w, h)); - gtk_snapshot_append_color (snapshot, &green, - &GRAPHENE_RECT_INIT(w, 0, w, h)); - gtk_snapshot_append_color (snapshot, &yellow, - &GRAPHENE_RECT_INIT(0, h, w, h)); - gtk_snapshot_append_color (snapshot, &blue, - &GRAPHENE_RECT_INIT(w, h, w, h)); + parent = GTK_BUFFER_VIEW(view); + cache = g_buffer_cache_new(1, 2); + parent->view = g_buffer_view_new(cache, parent->style); + unref_object(cache); - cairo_t *cr; - int x; + view->generator = g_hex_generator_new(content); - x = 0; + return result; - cr = gtk_snapshot_append_cairo(snapshot, &GRAPHENE_RECT_INIT(0, 0, w * 2, h * 2)); +} - g_token_style_draw_text(GTK_CONTENT_VIEW(parent)->style, - TRT_RAW_FULL, - cr, - &x, 0, - "A.A", 3); - g_token_style_draw_text(GTK_CONTENT_VIEW(parent)->style, - TRT_RAW_NULL, - cr, - &x, 0, - "A.A", 3); +/****************************************************************************** +* * +* Paramètres : widget = composant GTK à redessiner. * +* snapshot = gestionnaire de noeuds de rendu à solliciter. * +* parent = composant GTK parent et cadre de l'appel. * +* * +* Description : Procède à l'actualisation de l'affichage d'un sous-composant.* +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ - cairo_destroy(cr); +static void gtk_hex_view_dispatch_sub_snapshot(GtkWidget *widget, GtkSnapshot *snapshot, GtkWidget *parent) +{ + GtkHexView *view; /* Version spécialisée */ + size_t column; /* Indice de colonne à traiter */ + int width; /* Largeur à disposition */ + int height; /* Hauteur à disposition */ + cairo_t *cr; /* Pinceau pour les dessins */ + view = GTK_HEX_VIEW(parent); + if (widget == view->offsets) + column = HCO_OFFSET; -} + else if (widget == view->hex) + column = HCO_COUNT + 0; + else + { + assert(widget == view->ascii); + column = HCO_COUNT + 1; + } + width = gtk_widget_get_width(widget); + height = gtk_widget_get_height(widget); + cr = gtk_snapshot_append_cairo(snapshot, &GRAPHENE_RECT_INIT(0, 0, width, height)); + g_buffer_view_draw(GTK_BUFFER_VIEW(parent)->view, cr, column, GTK_BUFFER_VIEW(parent)->virt_top, height); + cairo_destroy(cr); +} -bool g_buffer_view_allocate_widths(void *ptr, int width, int height, int fill, int *out); +/****************************************************************************** +* * +* Paramètres : view = composant GTK à mettre à jour. * +* * +* Description : Adapte le cache de lignes hexadécimales à la taille courante.* +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ -bool g_buffer_view_allocate_widths(void *ptr, int width, int height, int fill, int *out) +static void gtk_hex_view_populate_cache(GtkHexView *view) { + GBinContent *content; /* Contenu binaire affiché */ + phys_t full; /* Taille totale à représenter */ + phys_t line; /* Taille représentée par ligne*/ + size_t needed; /* Nombre de lignes nécessaires*/ + GBufferCache *cache; /* Tampon à représenter */ + size_t count; /* Nombre actuel de lignes */ - int i; /* Boucle de parcours */ + /* Détermination du besoin */ + content = g_hex_generator_get_content(view->generator); - for (i = 0; i < fill; i++) - { + full = g_binary_content_compute_size(content); - if (i == 0) - { - out[0] = 40; - } + unref_object(content); - else if ((i + 1) == fill) - { - out[i] = width; - } + line = g_hex_generator_get_bytes_per_line(view->generator); - else - { - out[i] = 230; - } + needed = full / line; + if (full % line > 0) + needed++; - width -= out[i]; + /* Adaptation du tampon interne ? */ + cache = g_buffer_view_get_cache(GTK_BUFFER_VIEW(view)->view); + g_buffer_cache_wlock(cache); - } + count = g_buffer_cache_count_lines(cache); + + if (needed < count) + g_buffer_cache_truncate(cache, needed); + + else if (needed > count) + g_buffer_cache_extend_with(cache, needed, G_TOKEN_GENERATOR(view->generator)); - return false; + g_buffer_cache_wunlock(cache); + unref_object(cache); + + /* Mise à jour de l'affichage ? */ + + if (needed != count) + gtk_widget_queue_resize(GTK_WIDGET(view)); } -int g_buffer_view_measure_height(void *ptr, int width); -int g_buffer_view_measure_height(void *ptr, int width) + + + + + +void demo_snapshot (GtkWidget *widget, GtkSnapshot *snapshot, GtkWidget *parent) { - int result; /* Mesure à retourner */ + GdkRGBA red, green, yellow, blue; + float w, h; - if (width == -1) - result = 1; + gdk_rgba_parse (&red, "red"); + gdk_rgba_parse (&green, "green"); + gdk_rgba_parse (&yellow, "yellow"); + gdk_rgba_parse (&blue, "blue"); - else - result = 5000 / width; + w = gtk_widget_get_width (widget) / 2.0; + h = gtk_widget_get_height (widget) / 2.0; + + h /= 2.0; + + gtk_snapshot_append_color (snapshot, &red, + &GRAPHENE_RECT_INIT(0, 0, w, h)); + gtk_snapshot_append_color (snapshot, &green, + &GRAPHENE_RECT_INIT(w, 0, w, h)); + gtk_snapshot_append_color (snapshot, &yellow, + &GRAPHENE_RECT_INIT(0, h, w, h)); + gtk_snapshot_append_color (snapshot, &blue, + &GRAPHENE_RECT_INIT(w, h, w, h)); - result *= 16; - return result; } + + + + + + + + + + /* ---------------------------------------------------------------------------------- */ /* IMPLEMENTATION DES FONCTIONS DE CLASSE */ /* ---------------------------------------------------------------------------------- */ @@ -364,68 +454,56 @@ int g_buffer_view_measure_height(void *ptr, int width) static void gtk_hex_view_size_allocate(GtkWidget *widget, int width, int height, int baseline) { GtkHexView *view; /* Version spécialisée */ - int vscroll_width; /* Largeur idéale de la barre */ - - GtkAllocation allocated; /* Zone allouée */ + int *min_widths; /* Tailles minimales imposées */ + int *final_widths; /* Tailles finales retenues */ size_t i; /* Boucle de parcours */ - int sub_widths[_CHILDREN_COUNT - 1]; /* Sous-largeurs calculées */ + int available; /* Largeur disponible */ + bool changed; /* Détection de variation */ + GWidthTracker *tracker; /* Collecteur de largeurs */ view = GTK_HEX_VIEW(widget); - allocated.y = 0; - allocated.height = height; - - /* Barre de défilement ? */ - - view->need_vscrolling = g_buffer_view_allocate_widths(NULL, width, height, _CHILDREN_COUNT - 1, sub_widths); + min_widths = alloca(_CHILDREN_COUNT * sizeof(int)); + final_widths = alloca(_CHILDREN_COUNT * sizeof(int)); - gtk_widget_set_visible(view->vscroll, view->need_vscrolling); + for (i = 0; i < _CHILDREN_COUNT; i++) + gtk_widget_measure(view->children[i], GTK_ORIENTATION_HORIZONTAL, -1, &min_widths[i], NULL, NULL, NULL); - if (view->need_vscrolling) - { - gtk_widget_remove_css_class(widget, "without_vscroll"); - gtk_widget_add_css_class(widget, "with_vscroll"); - } - else - { - gtk_widget_remove_css_class(widget, "with_vscroll"); - gtk_widget_add_css_class(widget, "without_vscroll"); - } + /* Passe 1 : tentative sans défilement vertical */ - /** - * Validité de la consistence des feuilles CSS : le changement de classe - * ne doit pas faire évoluer les tailles. - */ - assert(view->need_vscrolling == g_buffer_view_allocate_widths(NULL, width, height, _CHILDREN_COUNT - 1, sub_widths)); + available = width; - if (view->need_vscrolling) - { - gtk_widget_measure(view->vscroll, GTK_ORIENTATION_HORIZONTAL, height, &vscroll_width, NULL, NULL, NULL); + for (i = 0; i < _CHILDREN_COUNT; i++) + available -= min_widths[i]; - allocated.x = width - vscroll_width; - allocated.width = vscroll_width; + changed = g_hex_generator_allocate(view->generator, + GTK_CONTENT_VIEW(view)->options, + GTK_BUFFER_VIEW(view)->style, + available, final_widths); - gtk_widget_size_allocate(view->vscroll, &allocated, baseline); + /* Application des largeurs calculées */ - width -= vscroll_width; + if (changed) + { + gtk_hex_view_populate_cache(view); - } + tracker = g_buffer_view_get_tracker(GTK_BUFFER_VIEW(view)->view); - /* Placement des composants d'affichage */ + for (i = 0; i < _CHILDREN_COUNT; i++) + { + final_widths[i] += min_widths[i]; - g_buffer_view_allocate_widths(NULL, width, height, _CHILDREN_COUNT - 1, sub_widths); + g_width_tracker_set_column_min_width(tracker, i, final_widths[i]); - allocated.x = 0; + } - for (i = 0; i < (_CHILDREN_COUNT - 1); i++) - { - allocated.width = sub_widths[i]; + unref_object(tracker); - gtk_widget_size_allocate(view->children[i], &allocated, baseline); + } - allocated.x += sub_widths[i]; + /* Mise à jour des éléments plus internes */ - } + GTK_WIDGET_CLASS(gtk_hex_view_parent_class)->size_allocate(widget, width, height, baseline); } @@ -453,6 +531,17 @@ static GtkSizeRequestMode gtk_hex_view_get_request_mode(GtkWidget *widget) } + + + + + + + + + + + /****************************************************************************** * * * Paramètres : widget = composant GTK à examiner. * @@ -473,54 +562,60 @@ static GtkSizeRequestMode gtk_hex_view_get_request_mode(GtkWidget *widget) static void gtk_hex_view_measure(GtkWidget *widget, GtkOrientation orientation, int for_size, int *minimum, int *natural, int *min_baseline, int *nat_baseline) { + bool processed; /* Calcul de hauteur effectué */ GtkHexView *view; /* Version spécialisée */ int requested; /* Taille requise à priori */ size_t i; /* Boucle de parcours */ int min; /* Valeur minimale locale */ int nat; /* Valeur idéale locale */ - view = GTK_HEX_VIEW(widget); + processed = false; /* Demande de hauteur minimale / idéale */ - if (orientation == GTK_ORIENTATION_VERTICAL) + if (orientation == GTK_ORIENTATION_VERTICAL && for_size != -1) { - requested = g_buffer_view_measure_height(NULL, for_size); + view = GTK_HEX_VIEW(widget); - if (minimum != NULL) *minimum = requested; - if (natural != NULL) *natural = requested; + requested = 0; for (i = 0; i < _CHILDREN_COUNT; i++) { - gtk_widget_measure(view->children[i], GTK_ORIENTATION_VERTICAL, -1, &min, &nat, NULL, NULL); + gtk_widget_measure(view->children[i], GTK_ORIENTATION_HORIZONTAL, -1, &min, NULL, NULL, NULL); + requested += min; + } - if (minimum != NULL && min > *minimum) - *minimum = min; + for_size -= requested; - if (natural != NULL && nat > *natural) - *natural = nat; + if (for_size > 0) + { + requested = g_hex_generator_mesure_height_for_width(view->generator, + GTK_CONTENT_VIEW(view)->options, + GTK_BUFFER_VIEW(view)->style, + for_size); - } + if (minimum != NULL) *minimum = 0; + if (natural != NULL) *natural = requested; - } + for (i = 0; i < _CHILDREN_COUNT; i++) + { + gtk_widget_measure(view->children[i], GTK_ORIENTATION_VERTICAL, -1, &min, &nat, NULL, NULL); - /* Demande de largeur minimale / idéale */ - else - { - if (minimum != NULL) *minimum = 0; - if (natural != NULL) *natural = 0; + if (minimum != NULL && min > *minimum) + *minimum = min; - for (i = 0; i < _CHILDREN_COUNT; i++) - { - gtk_widget_measure(view->children[i], GTK_ORIENTATION_HORIZONTAL, -1, &min, &nat, NULL, NULL); + if (natural != NULL && nat > *natural) + *natural = nat; + + } - if (minimum != NULL) *minimum += min; - if (natural != NULL) *natural += nat; + processed = true; } } - if (min_baseline != NULL) *min_baseline = -1; - if (nat_baseline != NULL) *nat_baseline = -1; + if (!processed) + GTK_WIDGET_CLASS(gtk_hex_view_parent_class)->measure(widget, orientation, for_size, + minimum, natural, min_baseline, nat_baseline); } |