summaryrefslogtreecommitdiff
path: root/src/gtkext/hexview.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/gtkext/hexview.c')
-rw-r--r--src/gtkext/hexview.c437
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);
}