From 4da5e662a7544e8ec0b440c322f934dd8c5e4058 Mon Sep 17 00:00:00 2001 From: Cyrille Bagard Date: Fri, 24 May 2024 06:41:11 +0200 Subject: Measure and allocate space from the GtkHexView widget code. --- src/gtkext/hexview.c | 349 ++++++++++++++++++++++++++++++++++--------------- src/gtkext/hexview.css | 10 +- src/gtkext/hexview.ui | 2 +- 3 files changed, 249 insertions(+), 112 deletions(-) diff --git a/src/gtkext/hexview.c b/src/gtkext/hexview.c index 56a167d..7acf131 100644 --- a/src/gtkext/hexview.c +++ b/src/gtkext/hexview.c @@ -28,6 +28,7 @@ +/* ------------------------- BASES D'UN COMPOSANT GRAPHIQUE ------------------------- */ /* Composant d'affichage générique (instance) */ @@ -35,9 +36,23 @@ struct _GtkHexView { GtkWidget parent; /* A laisser en premier */ - GtkWidget *offsets; /* Affichage des positions */ - GtkWidget *hex; /* Affichage des octets brut */ - GtkWidget *ascii; /* Affichage des imprimables */ + 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 ? */ }; @@ -63,17 +78,28 @@ static void gtk_hex_view_finalize(GtkHexView *); -void demo_snapshot (GtkWidget *widget, GtkSnapshot *snapshot); +void demo_snapshot (GtkWidget *widget, GtkSnapshot *snapshot, GtkWidget *parent); + + + -void demo_measure (GtkWidget *widget, - GtkOrientation orientation, - int for_size, - int *minimum_size, - int *natural_size, - int *minimum_baseline, - int *natural_baseline); +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ +/* Prend acte de la taille allouée au composant d'affichage. */ +static void gtk_hex_view_size_allocate(GtkWidget *, int, int, int); + +/* Fournit le mode de calcul pour déterminer la taille. */ +static GtkSizeRequestMode gtk_hex_view_get_request_mode(GtkWidget *); + +/* Fournit les mesures mainimale et idéale du composant. */ +static void gtk_hex_view_measure(GtkWidget *, GtkOrientation, int, int *, int *, int *, int *); + + + +/* ---------------------------------------------------------------------------------- */ +/* BASES D'UN COMPOSANT GRAPHIQUE */ +/* ---------------------------------------------------------------------------------- */ /* Détermine le type du composant d'affichage générique. */ @@ -106,8 +132,6 @@ static void gtk_hex_view_class_init(GtkHexViewClass *class) gtk_widget_class_set_css_name(widget, "GtkHexView"); - gtk_widget_class_set_layout_manager_type(widget, GTK_TYPE_BOX_LAYOUT); - g_type_ensure(GTK_TYPE_COMPOSING_AREA); gtk_widget_class_set_template_from_resource(widget, "/re/chrysalide/framework/gtkext/hexview.ui"); @@ -115,31 +139,11 @@ 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->snapshot = demo_snapshot; - - //widget->measure = demo_measure; - - - /* - - - - - - - */ - - - /* - widget->destroy = gtk_hex_view_destroy; - widget->realize = gtk_hex_view_realize; widget->size_allocate = gtk_hex_view_size_allocate; - widget->get_preferred_height = gtk_hex_view_get_preferred_height; - widget->get_preferred_width = gtk_hex_view_get_preferred_width; - */ + widget->get_request_mode = gtk_hex_view_get_request_mode; + widget->measure = gtk_hex_view_measure; } @@ -160,24 +164,13 @@ static void gtk_hex_view_init(GtkHexView *view) { gtk_widget_init_template(GTK_WIDGET(view)); - - - - - g_object_set(G_OBJECT(view->offsets), "width-request", 30, NULL); - - g_object_set(G_OBJECT(view->ascii), "width-request", 230, NULL); - - 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->hex), demo_snapshot, GTK_WIDGET(view)); g_raw_scan_cache_register_snapshot(GTK_COMPOSING_AREA(view->ascii), demo_snapshot, GTK_WIDGET(view)); - - - + view->need_vscrolling = true; } @@ -225,25 +218,11 @@ static void gtk_hex_view_finalize(GtkHexView *view) -void demo_measure (GtkWidget *widget, - GtkOrientation orientation, - int for_size, - int *minimum_size, - int *natural_size, - int *minimum_baseline, - int *natural_baseline) -{ - printf("set size\n"); - - *minimum_size = 100; - *natural_size = 200; -} - -void demo_snapshot (GtkWidget *widget, GtkSnapshot *snapshot) +void demo_snapshot (GtkWidget *widget, GtkSnapshot *snapshot, GtkWidget *parent) { GdkRGBA red, green, yellow, blue; float w, h; @@ -280,14 +259,82 @@ void demo_snapshot (GtkWidget *widget, GtkSnapshot *snapshot) -#if 0 + + + + + +bool g_buffer_view_allocate_widths(void *ptr, int width, int height, int fill, int *out); + +bool g_buffer_view_allocate_widths(void *ptr, int width, int height, int fill, int *out) +{ + + int i; /* Boucle de parcours */ + + + for (i = 0; i < fill; i++) + { + + if (i == 0) + { + out[0] = 40; + } + + else if ((i + 1) == fill) + { + out[i] = width; + } + + else + { + out[i] = 230; + } + + + width -= out[i]; + + + + } + + return false; + + +} + +int g_buffer_view_measure_height(void *ptr, int width); + +int g_buffer_view_measure_height(void *ptr, int width) +{ + int result; /* Mesure à retourner */ + + if (width == -1) + result = 1; + + else + result = 5000 / width; + + result *= 16; + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + /****************************************************************************** * * -* Paramètres : widget = composant GTK à examiner. * -* minimum = largeur minimale à préciser ou NULL. [OUT] * -* natural = largeur idéale à préciser ou NULL. [OUT] * +* Paramètres : widget = composant GTK à examiner. * +* width = largeur affectée au composant graphique. * +* height = hauteur affectée au composant graphique. * +* baseline = ligne de base affectée au composant graphique. * * * -* Description : Fournit la largeur idéale pour le composant d'affichage. * +* Description : Prend acte de la taille allouée au composant d'affichage. * * * * Retour : - * * * @@ -295,82 +342,166 @@ void demo_snapshot (GtkWidget *widget, GtkSnapshot *snapshot) * * ******************************************************************************/ -static void gtk_hex_view_get_preferred_width(GtkWidget *widget, gint *minimum, gint *natural) +static void gtk_hex_view_size_allocate(GtkWidget *widget, int width, int height, int baseline) { - GtkHexView *panel; /* Autre version du composant */ - gint req; /* Dimension requise */ + GtkHexView *view; /* Version spécialisée */ + int vscroll_width; /* Largeur idéale de la barre */ - panel = GTK_HEX_VIEW(widget); + GtkAllocation allocated; /* Zone allouée */ + size_t i; /* Boucle de parcours */ + int sub_widths[_CHILDREN_COUNT - 1]; /* Sous-largeurs calculées */ - GTK_HEX_VIEW_GET_CLASS(widget)->compute_size(panel, &req, NULL); + view = GTK_HEX_VIEW(widget); - req *= panel->scale; + allocated.y = 0; + allocated.height = height; - if (minimum != NULL) *minimum = req; - if (natural != NULL) *natural = req; + /* Barre de défilement ? */ -} + view->need_vscrolling = g_buffer_view_allocate_widths(NULL, width, height, _CHILDREN_COUNT - 1, sub_widths); + + gtk_widget_set_visible(view->vscroll, view->need_vscrolling); + + 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"); + } + + /** + * 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)); + + if (view->need_vscrolling) + { + gtk_widget_measure(view->vscroll, GTK_ORIENTATION_HORIZONTAL, height, &vscroll_width, NULL, NULL, NULL); + + allocated.x = width - vscroll_width; + allocated.width = vscroll_width; + + gtk_widget_size_allocate(view->vscroll, &allocated, baseline); + + width -= vscroll_width; + + } + /* Placement des composants d'affichage */ + g_buffer_view_allocate_widths(NULL, width, height, _CHILDREN_COUNT - 1, sub_widths); + + allocated.x = 0; + + for (i = 0; i < (_CHILDREN_COUNT - 1); i++) + { + allocated.width = sub_widths[i]; + + gtk_widget_size_allocate(view->children[i], &allocated, baseline); + + allocated.x += sub_widths[i]; + + } + +} /****************************************************************************** * * -* Paramètres : panel = composant GTK à venir consulter. * -* cr = contexte graphique associé à l'événement. * +* Paramètres : widget = composant GTK à consulter. * * * -* Description : Dessine si besoin est une bordure autour du composant. * +* Description : Fournit le mode de calcul pour déterminer la taille. * * * -* Retour : - * +* Retour : Mode de calcul adapté au composant graphique. * * * * Remarques : - * * * ******************************************************************************/ -void gtk_hex_view_draw_border(GtkHexView *panel, cairo_t *cr) +static GtkSizeRequestMode gtk_hex_view_get_request_mode(GtkWidget *widget) { - GtkWidget *widget; /* Autre version du composant */ - GtkStyleContext *context; /* Contexte du thème actuel */ - GdkRGBA color; /* Couleur de thème récupérée */ - GtkRequisition req; /* Taille allouée à l'élément */ - GtkAllocation area; /* Emplacement à considérer */ + GtkSizeRequestMode result; /* Configuration à remonter */ - if (panel->show_border) - { - widget = GTK_WIDGET(panel); + result = GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH; - gtk_widget_get_preferred_size(widget, NULL, &req); + return result; - context = gtk_widget_get_style_context(widget); +} - gtk_style_context_save(context); - gtk_style_context_add_class(context, GTK_STYLE_CLASS_FRAME); +/****************************************************************************** +* * +* Paramètres : widget = composant GTK à examiner. * +* orientation = direction à observer pour les calculs. * +* for_size = taille de la direction opposée. * +* minimum = taille minimale pour le composant. [OUT] * +* natural = taille idéale pour le composant. [OUT] * +* min_baseline = ligne de base minimale. [OUT] * +* nat_baseline = ligne de base idéale. [OUT] * +* * +* Description : Fournit les mesures mainimale et idéale du composant. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void gtk_hex_view_measure(GtkWidget *widget, GtkOrientation orientation, int for_size, int *minimum, int *natural, int *min_baseline, int *nat_baseline) +{ + 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 */ - gtk_style_context_get(gtk_widget_get_style_context(widget), - gtk_widget_get_state_flags(widget), - GTK_STYLE_PROPERTY_COLOR, &color, NULL); + view = GTK_HEX_VIEW(widget); - cairo_set_source_rgba(cr, color.red, color.green, color.blue, color.alpha); + /* Demande de hauteur minimale / idéale */ + if (orientation == GTK_ORIENTATION_VERTICAL) + { + requested = g_buffer_view_measure_height(NULL, for_size); - cairo_set_line_width(cr, 1.0); + if (minimum != NULL) *minimum = requested; + if (natural != NULL) *natural = requested; - gtk_widget_get_preferred_size(GTK_WIDGET(panel), NULL, &req); + for (i = 0; i < _CHILDREN_COUNT; i++) + { + gtk_widget_measure(view->children[i], GTK_ORIENTATION_VERTICAL, -1, &min, &nat, NULL, NULL); - area.x = 0; - area.y = 0; - area.width = req.width; - area.height = req.height; + if (minimum != NULL && min > *minimum) + *minimum = min; - gtk_hex_view_define_border_path(panel, cr, &area); - cairo_stroke(cr); + if (natural != NULL && nat > *natural) + *natural = nat; - gtk_style_context_restore(context); + } } -} + /* Demande de largeur minimale / idéale */ + else + { + if (minimum != NULL) *minimum = 0; + if (natural != NULL) *natural = 0; + for (i = 0; i < _CHILDREN_COUNT; i++) + { + gtk_widget_measure(view->children[i], GTK_ORIENTATION_HORIZONTAL, -1, &min, &nat, NULL, NULL); + if (minimum != NULL) *minimum += min; + if (natural != NULL) *natural += nat; -#endif + } + + } + + if (min_baseline != NULL) *min_baseline = -1; + if (nat_baseline != NULL) *nat_baseline = -1; + +} diff --git a/src/gtkext/hexview.css b/src/gtkext/hexview.css index fdde1cc..9725509 100644 --- a/src/gtkext/hexview.css +++ b/src/gtkext/hexview.css @@ -17,13 +17,19 @@ GtkHexView > :not(scrollbar) { } -GtkHexView > :nth-last-child(2) { +/* ASCII */ + +GtkHexView.with_vscroll > :nth-last-child(2), +GtkHexView.without_vscroll > :nth-last-child(1) { padding-right: 4px; } -GtkHexView > :nth-last-child(4) { +/* Offset */ + +GtkHexView.with_vscroll > :nth-last-child(4), +GtkHexView.without_vscroll > :nth-last-child(3) { border-right: 1px solid @borders; diff --git a/src/gtkext/hexview.ui b/src/gtkext/hexview.ui index f0dd8b0..d2f6849 100644 --- a/src/gtkext/hexview.ui +++ b/src/gtkext/hexview.ui @@ -1,6 +1,6 @@