diff options
Diffstat (limited to 'src/gtkext')
-rw-r--r-- | src/gtkext/Makefile.am | 5 | ||||
-rw-r--r-- | src/gtkext/bufferview-int.h | 49 | ||||
-rw-r--r-- | src/gtkext/bufferview.c | 449 | ||||
-rw-r--r-- | src/gtkext/bufferview.h | 38 | ||||
-rw-r--r-- | src/gtkext/contentview-int.h | 52 | ||||
-rw-r--r-- | src/gtkext/contentview.c | 532 | ||||
-rw-r--r-- | src/gtkext/hexview-int.h | 71 | ||||
-rw-r--r-- | src/gtkext/hexview.c | 437 | ||||
-rw-r--r-- | src/gtkext/hexview.h | 8 | ||||
-rw-r--r-- | src/gtkext/hexview.ui | 7 |
10 files changed, 1134 insertions, 514 deletions
diff --git a/src/gtkext/Makefile.am b/src/gtkext/Makefile.am index e33e09e..c9445e6 100644 --- a/src/gtkext/Makefile.am +++ b/src/gtkext/Makefile.am @@ -11,8 +11,6 @@ libgtkext_la_SOURCES = \ easygtk.h easygtk.c \ gtkbinarystrip.h gtkbinarystrip.c \ gtkblockdisplay.h gtkblockdisplay.c \ - gtkbufferdisplay-int.h \ - gtkbufferdisplay.h gtkbufferdisplay.c \ gtkdockable-int.h \ gtkdockable.h gtkdockable.c \ gtkdockstation.h gtkdockstation.c \ @@ -39,8 +37,11 @@ RES_FILES = \ libgtkext4_la_SOURCES = \ area-int.h \ area.h area.c \ + bufferview-int.h \ + bufferview.h bufferview.c \ contentview-int.h \ contentview.h contentview.c \ + hexview-int.h \ hexview.h hexview.c \ resources.h resources.c diff --git a/src/gtkext/bufferview-int.h b/src/gtkext/bufferview-int.h index d02aa37..7c9c8e1 100644 --- a/src/gtkext/bufferview-int.h +++ b/src/gtkext/bufferview-int.h @@ -1,8 +1,8 @@ /* Chrysalide - Outil d'analyse de fichiers binaires - * gtkbufferdisplay-int.h - prototypes internes pour l'affichage de tampons de lignes + * bufferview-int.h - prototypes internes pour l'affichage de tampons de lignes * - * Copyright (C) 2016-2019 Cyrille Bagard + * Copyright (C) 2016-2024 Cyrille Bagard * * This file is part of Chrysalide. * @@ -21,27 +21,38 @@ */ -#ifndef _GTK_BUFFERDISPLAY_INT_H -#define _GTK_BUFFERDISPLAY_INT_H +#ifndef _GTKEXT_BUFFERVIEW_INT_H +#define _GTKEXT_BUFFERVIEW_INT_H -#include "gtkbufferdisplay.h" +#include "bufferview.h" +#include "contentview-int.h" -#include "gtkdisplaypanel-int.h" - +#if 0 /* Réagit à un déplacement de curseur. */ -typedef bool (* notify_caret_relocation_fc) (GtkBufferDisplay *, const GdkRectangle *); +typedef bool (* notify_caret_relocation_fc) (GtkBufferView *, const GdkRectangle *); +#endif + + /* Composant d'affichage de tampon de lignes (instance) */ -struct _GtkBufferDisplay +struct _GtkBufferView { - GtkDisplayPanel parent; /* A laisser en premier */ + GtkContentView parent; /* A laisser en premier */ + + GBufferView *view; /* Vue choisie sur un tampon */ + GTokenStyle *style; /* Centralisation des styles */ + + int virt_top; /* Première ordonnée affichée */ + - GBufferView *view; /* Vue sur le contenu affiché */ + + +#if 0 cairo_rectangle_int_t caret; /* Emplacement du curseur #1 */ GLineCursor *cursor; /* Emplacement du curseur #2 */ @@ -51,23 +62,29 @@ struct _GtkBufferDisplay GtkBuilder *builder; /* Constructeur à manipuler */ GtkWidget *bar; /* Barre d'outils intégrée */ +#endif + }; /* Composant d'affichage de tampon de lignes (classe) */ -struct _GtkBufferDisplayClass +struct _GtkBufferViewClass { - GtkDisplayPanelClass parent; /* A laisser en premier */ + GtkContentViewClass parent; /* A laisser en premier */ + +#if 0 notify_caret_relocation_fc notify_caret;/* Accompagne un déplacement */ /* Signaux */ - void (* reach_limit) (GtkBufferDisplay *, GdkScrollDirection); + void (* reach_limit) (GtkBufferView *, GdkScrollDirection); + + void (* prepare_collapsing) (GtkBufferView *, gboolean); - void (* prepare_collapsing) (GtkBufferDisplay *, gboolean); +#endif }; -#endif /* _GTK_BUFFERDISPLAY_INT_H */ +#endif /* _GTKEXT_BUFFERVIEW_INT_H */ diff --git a/src/gtkext/bufferview.c b/src/gtkext/bufferview.c index 4566cc5..4a700c3 100644 --- a/src/gtkext/bufferview.c +++ b/src/gtkext/bufferview.c @@ -1,8 +1,8 @@ /* Chrysalide - Outil d'analyse de fichiers binaires - * gtkbufferdisplay.c - affichage de tampons de lignes + * bufferview.c - affichage de tampons de lignes * - * Copyright (C) 2016-2019 Cyrille Bagard + * Copyright (C) 2016-2024 Cyrille Bagard * * This file is part of Chrysalide. * @@ -21,9 +21,418 @@ */ -#include "gtkbufferdisplay.h" +#include "bufferview.h" +#include "bufferview-int.h" + + + + + +/* ------------------------- BASES D'UN COMPOSANT GRAPHIQUE ------------------------- */ + + +/* Procède à l'initialisation de l'afficheur de tampons. */ +static void gtk_buffer_view_class_init(GtkBufferViewClass *); + +/* Procède à l'initialisation de l'afficheur de tampons. */ +static void gtk_buffer_view_init(GtkBufferView *); + +/* Supprime toutes les références externes. */ +static void gtk_buffer_view_dispose(GtkBufferView *); + +/* Procède à la libération totale de la mémoire. */ +static void gtk_buffer_view_finalize(GtkBufferView *); + + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Prend acte de la taille allouée au composant d'affichage. */ +static void gtk_buffer_view_size_allocate(GtkWidget *, int, int, int); + +/* Réagit à un défilement chez une barre associée au composant. */ +static void gtk_buffer_view_adjust_scroll_value(GtkBufferView *, GtkOrientation, GtkAdjustment *); + + + +/* ---------------------------------------------------------------------------------- */ +/* BASES D'UN COMPOSANT GRAPHIQUE */ +/* ---------------------------------------------------------------------------------- */ + + +/* Détermine le type du composant d'affichage générique. */ +G_DEFINE_TYPE(GtkBufferView, gtk_buffer_view, GTK_TYPE_CONTENT_VIEW); + + +/****************************************************************************** +* * +* Paramètres : class = classe GTK à initialiser. * +* * +* Description : Procède à l'initialisation de l'afficheur de tampons. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void gtk_buffer_view_class_init(GtkBufferViewClass *class) +{ + GObjectClass *object; /* Autre version de la classe */ + GtkWidgetClass *widget; /* Classe version Widget */ + GtkContentViewClass *content; /* Base d'affichage */ + + object = G_OBJECT_CLASS(class); + + object->dispose = (GObjectFinalizeFunc/* ! */)gtk_buffer_view_dispose; + object->finalize = (GObjectFinalizeFunc)gtk_buffer_view_finalize; + + widget = GTK_WIDGET_CLASS(class); + + widget->size_allocate = gtk_buffer_view_size_allocate; + + content = GTK_CONTENT_VIEW_CLASS(class); + + content->adjust = (adjust_scroll_value_fc)gtk_buffer_view_adjust_scroll_value; + + + +#if 0 + + widget_class->focus_in_event = gtk_buffer_view_focus; + widget_class->focus_out_event = gtk_buffer_view_focus; + widget_class->button_press_event = gtk_buffer_view_button_press; + widget_class->draw = gtk_buffer_view_draw; + widget_class->key_press_event = gtk_buffer_view_key_press; + + panel_class = GTK_DISPLAY_PANEL_CLASS(class); + + panel_class->compute_size = (compute_requested_size_fc)gtk_buffer_view_compute_requested_size; + panel_class->compute_inc = (compute_scroll_inc_fc)gtk_buffer_view_compute_scroll_inc; + panel_class->adjust = (adjust_scroll_value_fc)gtk_buffer_view_adjust_scroll_value; + panel_class->get_coordinates = (get_coordinates_fc)gtk_buffer_view_get_cursor_coordinates; + panel_class->get_active = (get_active_object_fc)gtk_buffer_view_get_active_object; + panel_class->move_caret_to = (move_caret_to_fc)_gtk_buffer_view_move_caret_to; + panel_class->cache_glance = (cache_glance_fc)gtk_buffer_view_cache_glance; + + panel_class->get_cursor = (get_cursor_fc)gtk_buffer_view_get_cursor; + + /* Signaux */ + + g_signal_new("reach-limit", + GTK_TYPE_BUFFER_DISPLAY, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(GtkBufferViewClass, reach_limit), + NULL, NULL, + g_cclosure_marshal_VOID__ENUM, + G_TYPE_NONE, 1, GTK_TYPE_SCROLL_TYPE); + + g_signal_new("prepare-collapsing", + GTK_TYPE_BUFFER_DISPLAY, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(GtkBufferViewClass, prepare_collapsing), + NULL, NULL, + g_cclosure_marshal_VOID__BOOLEAN, + G_TYPE_NONE, 1, G_TYPE_BOOLEAN); + +#endif + +} + + +/****************************************************************************** +* * +* Paramètres : display = composant GTK à initialiser. * +* * +* Description : Procède à l'initialisation de l'afficheur de tampons. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void gtk_buffer_view_init(GtkBufferView *view) +{ + view->view = NULL; + view->style = g_token_style_new(GTK_WIDGET(view)); + + view->virt_top = 0; + +} + + +/****************************************************************************** +* * +* Paramètres : display = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void gtk_buffer_view_dispose(GtkBufferView *view) +{ +#if 0 + + if (display->caret_timer != 0) + { + g_source_remove(display->caret_timer); + display->caret_timer = 0; + } + + g_clear_object(&display->cursor); + + g_clear_object(&display->builder); + g_clear_object(&display->bar); + +#endif + + + + + g_clear_object(&view->view); + g_clear_object(&view->style); + + G_OBJECT_CLASS(gtk_buffer_view_parent_class)->dispose(G_OBJECT(view)); + +} + + +/****************************************************************************** +* * +* Paramètres : display = instance d'objet Gtk à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void gtk_buffer_view_finalize(GtkBufferView *view) +{ + G_OBJECT_CLASS(gtk_buffer_view_parent_class)->finalize(G_OBJECT(view)); + +} + + +/****************************************************************************** +* * +* Paramètres : view = composant GTK à consulter. * +* * +* Description : Fournit la vue associée au tampon de lignes courant. * +* * +* Retour : Vue mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GBufferView *gtk_buffer_view_get_view(const GtkBufferView *view) +{ + GBufferView *result; /* Instance à retourner */ + + result = view->view; + + ref_object(result); + + return result; + +} + + + + + + + + + + + + + + + + + + + + + + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* 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 : Prend acte de la taille allouée au composant d'affichage. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void gtk_buffer_view_size_allocate(GtkWidget *widget, int width, int height, int baseline) +{ + GtkContentView *base; /* Version de base */ + GtkBufferView *view; /* Version spécialisée */ + int full_width; /* Largeur idéale complète */ + int full_height; /* Hauteur idéale complète */ + int *min_widths; /* Largeurs minimales imposées */ + int *min_heights; /* Hauteurs minimales imposées */ + size_t i; /* Boucle de parcours */ + int upper; /* Valeur maximale retenue */ + GtkAdjustment *adj; /* Ajustement à mettre à jour */ + int line_height; /* Hauteur d'une ligne unique */ + int lines_per_page; /* Nombre de lignes sur l'écran*/ + GtkAllocation allocated; /* Zone allouée */ + GWidthTracker *tracker; /* Collecteur de largeurs */ + + base = GTK_CONTENT_VIEW(widget); + view = GTK_BUFFER_VIEW(widget); + + /* Détermination de la surface idéale à afficher */ + + g_buffer_view_compute_size(view->view, &full_width, &full_height); + + min_widths = alloca(base->sub_count * sizeof(int)); + min_heights = alloca(base->sub_count * sizeof(int)); + + for (i = 0; i < base->sub_count; i++) + { + gtk_widget_measure(base->sub_children[i], GTK_ORIENTATION_HORIZONTAL, -1, + &min_widths[i], NULL, NULL, NULL); + full_width += min_widths[i]; + + gtk_widget_measure(base->sub_children[i], GTK_ORIENTATION_VERTICAL, -1, + &min_heights[i], NULL, NULL, NULL); + full_height += min_heights[i]; + + } + + /* Définition des besoins en défilement */ + + upper = MAX(width, full_width); + + adj = base->adjustments[GTK_ORIENTATION_HORIZONTAL]; + + gtk_adjustment_configure(adj, + gtk_adjustment_get_value(adj), + 0, upper, + 0.1 * width, + 0.9 * width, + width); + + upper = MAX(height, full_height); + + line_height = g_token_style_get_line_height(view->style); + + lines_per_page = height / line_height; + if (lines_per_page == 0) lines_per_page = 1; + + adj = base->adjustments[GTK_ORIENTATION_VERTICAL]; + + gtk_adjustment_configure(adj, + gtk_adjustment_get_value(adj), + 0, upper, + line_height * lines_per_page, + line_height * lines_per_page * 10, + height); + + /* Placement des composants d'affichage */ + + tracker = g_buffer_view_get_tracker(view->view); + + allocated.x = 0; + allocated.y = 0; + allocated.height = height; + + for (i = 0; i < base->sub_count; i++) + { + allocated.width = g_width_tracker_get_column_min_width(tracker, i); + + if ((i + 1) == base->sub_count && allocated.width < (width - allocated.x)) + allocated.width = width - allocated.x; + + gtk_widget_size_allocate(base->sub_children[i], &allocated, baseline); + + allocated.x += allocated.width; + + } + + unref_object(tracker); + + /* Mise à jour des éléments plus internes */ + + GTK_WIDGET_CLASS(gtk_buffer_view_parent_class)->size_allocate(widget, width, height, baseline); + +} + + +/****************************************************************************** +* * +* Paramètres : view = panneau d'affichage concerné. * +* orientation = indication sur le défilement à traiter. * +* adj = nouvel ajustement à prendre en compte. * +* * +* Description : Réagit à un défilement chez une barre associée au composant. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void gtk_buffer_view_adjust_scroll_value(GtkBufferView *view, GtkOrientation orientation, GtkAdjustment *adj) +{ + GtkContentView *base; /* Version de base */ + size_t i; /* Boucle de parcours */ + + base = GTK_CONTENT_VIEW(view); + + if (orientation == GTK_ORIENTATION_HORIZONTAL) + printf("TODO...\n"); + + else + { + view->virt_top = gtk_adjustment_get_value(adj); + + for (i = 0; i < base->sub_count; i++) + gtk_widget_queue_draw(base->sub_children[i]); + + } + +} + + + + + + + + +#if 0 + #include <assert.h> @@ -38,16 +447,16 @@ /* Procède à l'initialisation de l'afficheur de tampons. */ -static void gtk_buffer_display_class_init(GtkBufferDisplayClass *); +//static void gtk_buffer_display_class_init(GtkBufferDisplayClass *); /* Procède à l'initialisation de l'afficheur de tampons. */ -static void gtk_buffer_display_init(GtkBufferDisplay *); +//static void gtk_buffer_display_init(GtkBufferDisplay *); /* Supprime toutes les références externes. */ -static void gtk_buffer_display_dispose(GtkBufferDisplay *); +//static void gtk_buffer_display_dispose(GtkBufferDisplay *); /* Procède à la libération totale de la mémoire. */ -static void gtk_buffer_display_finalize(GtkBufferDisplay *); +//static void gtk_buffer_display_finalize(GtkBufferDisplay *); /* Intègre le focus dans le rendu du composant. */ static gboolean gtk_buffer_display_focus(GtkWidget *, GdkEventFocus *); @@ -882,30 +1291,6 @@ static GLineCursor *gtk_buffer_display_get_cursor(const GtkBufferDisplay *displa } -/****************************************************************************** -* * -* Paramètres : display = composant GTK à consulter. * -* * -* Description : Fournit la vue associée au tampon de lignes courant. * -* * -* Retour : Vue mise en place. * -* * -* Remarques : - * -* * -******************************************************************************/ - -GBufferView *gtk_buffer_display_get_view(const GtkBufferDisplay *display) -{ - GBufferView *result; /* Instance à retourner */ - - result = display->view; - - g_object_ref(G_OBJECT(result)); - - return result; - -} - /* ---------------------------------------------------------------------------------- */ @@ -1437,3 +1822,5 @@ static gboolean on_block_bar_collapsing_leave(GtkWidget *widget, GdkEventCrossin return FALSE; } + +#endif diff --git a/src/gtkext/bufferview.h b/src/gtkext/bufferview.h index 8f2d63c..1bdfc80 100644 --- a/src/gtkext/bufferview.h +++ b/src/gtkext/bufferview.h @@ -1,8 +1,8 @@ /* Chrysalide - Outil d'analyse de fichiers binaires - * gtkbufferdisplay.h - prototypes pour l'affichage de tampons de lignes + * bufferview.h - prototypes pour l'affichage de tampons de lignes * - * Copyright (C) 2016-2019 Cyrille Bagard + * Copyright (C) 2016-2024 Cyrille Bagard * * This file is part of Chrysalide. * @@ -21,41 +21,36 @@ */ -#ifndef _GTKEXT_GTKBUFFER_DISPLAY_H -#define _GTKEXT_GTKBUFFER_DISPLAY_H +#ifndef _GTKEXT_BUFFERVIEW_H +#define _GTKEXT_BUFFERVIEW_H -#include <glib-object.h> #include <gtk/gtk.h> #include "../glibext/bufferview.h" +#include "../glibext/helpers.h" -#define GTK_TYPE_BUFFER_DISPLAY (gtk_buffer_display_get_type()) -#define GTK_BUFFER_DISPLAY(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GTK_TYPE_BUFFER_DISPLAY, GtkBufferDisplay)) -#define GTK_BUFFER_DISPLAY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GTK_TYPE_BUFFER_DISPLAY, GtkBufferDisplayClass)) -#define GTK_IS_BUFFER_DISPLAY(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GTK_TYPE_BUFFER_DISPLAY)) -#define GTK_IS_BUFFER_DISPLAY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GTK_TYPE_BUFFER_DISPLAY)) -#define GTK_BUFFER_DISPLAY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GTK_TYPE_BUFFER_VIEW, GtkBufferDisplayClass)) +#define GTK_TYPE_BUFFER_VIEW (gtk_buffer_view_get_type()) +DECLARE_GTYPE(GtkBufferView, gtk_buffer_view, GTK, BUFFER_VIEW); -/* Composant d'affichage de tampon de lignes (instance) */ -typedef struct _GtkBufferDisplay GtkBufferDisplay; -/* Composant d'affichage de tampon de lignes (classe) */ -typedef struct _GtkBufferDisplayClass GtkBufferDisplayClass; + +/* Fournit la vue associée au tampon de lignes courant. */ +GBufferView *gtk_buffer_view_get_view(const GtkBufferView *); + -/* Détermine le type du composant d'affichage de tampon de lignes. */ -GType gtk_buffer_display_get_type(void); -/* Fournit la vue associée au tampon de lignes courant. */ -GBufferView *gtk_buffer_display_get_view(const GtkBufferDisplay *); + +#if 0 + /* ------------------------------ ANIMATION DU CURSEUR ------------------------------ */ @@ -73,6 +68,9 @@ bool gtk_buffer_display_move_caret_to(GtkBufferDisplay *, bool, gint *); /* Ajoute une nouvelle barre d'outils pour bloc au composant. */ void gtk_buffer_display_add_block_bar(GtkBufferDisplay *); +#endif + + -#endif /* _GTKEXT_GTKBUFFER_DISPLAY_H */ +#endif /* _GTKEXT_BUFFERVIEW_H */ diff --git a/src/gtkext/contentview-int.h b/src/gtkext/contentview-int.h index 25c9ddb..01c0c7a 100644 --- a/src/gtkext/contentview-int.h +++ b/src/gtkext/contentview-int.h @@ -28,11 +28,19 @@ #include "contentview.h" +#include "../glibext/bufferview.h" #include "../glibext/tokenstyle.h" +/* Réagit à un défilement chez une barre associée au composant. */ +typedef void (* adjust_scroll_value_fc) (GtkContentView *, GtkOrientation, GtkAdjustment *); + + + + + #if 0 #include <stdbool.h> @@ -52,10 +60,10 @@ typedef void (* compute_requested_size_fc) (GtkDisplayPanel *, gint *, gint *); /* Détermine la taille des bonds lors de défilements. */ -typedef void (* compute_scroll_inc_fc) (GtkDisplayPanel *, gint, GtkOrientation, gdouble *, gdouble *); +//typedef void (* compute_scroll_inc_fc) (GtkDisplayPanel *, gint, GtkOrientation, gdouble *, gdouble *); /* Réagit à un défilement chez une barre associée au composant. */ -typedef void (* adjust_scroll_value_fc) (GtkDisplayPanel *, GtkAdjustment *, GtkOrientation); +//typedef void (* adjust_scroll_value_fc) (GtkDisplayPanel *, GtkAdjustment *, GtkOrientation); /* Ajuste au besoin la zone affichée pour un curseur. */ typedef void (* prepare_for_cursor_fc) (GtkDisplayPanel *, const GLineCursor *); @@ -94,15 +102,18 @@ struct _GtkContentView { GtkWidget parent; /* A laisser en premier */ + GtkAdjustment *adjustments[2]; /* Barres de défilement h. & v.*/ + GtkScrollablePolicy scroll_policies[2]; /* Politiques de défilement */ + GDisplayOptions *options; /* Options de rendu */ - GTokenStyle *style; /* Centralisation des styles */ -#if 0 + /* Propriété des implémentations */ - GtkAdjustment *hadjustment; /* Barre de défilement horiz. */ - GtkAdjustment *vadjustment; /* Barre de défilement vert. */ - GtkScrollablePolicy hscroll_policy; /* Politique horizontale */ - GtkScrollablePolicy vscroll_policy; /* Politique verticale */ + GtkWidget * const *sub_children; /* Composants embarqués */ + size_t sub_count; /* Quantité de ces composants */ + + +#if 0 double scale; /* Echelle de l'affichage */ @@ -121,13 +132,14 @@ struct _GtkContentView /* Composant d'affichage générique (classe) */ struct _GtkContentViewClass { - GtkFixedClass parent; /* A laisser en premier */ + GtkWidgetClass parent; /* A laisser en premier */ #if 0 - compute_requested_size_fc compute_size; /* Calcul de la taille requise */ - compute_scroll_inc_fc compute_inc; /* Calcul des bonds */ +#endif adjust_scroll_value_fc adjust; /* Réaction à un défilement */ + +#if 0 prepare_for_cursor_fc prepare; /* Préparation de zone affichée*/ get_coordinates_fc get_coordinates; /* Conversion adresse <-> pos. */ get_active_object_fc get_active; /* Infos sur l'objet actif */ @@ -149,20 +161,20 @@ struct _GtkContentViewClass }; -#if 0 - /* Propriétés propres au composant d'affichage */ -typedef enum _ViewPanelProps +typedef enum _ContentViewProps { - VPP_0, - VPP_HADJUSTMENT, - VPP_VADJUSTMENT, - VPP_HSCROLL_POLICY, - VPP_VSCROLL_POLICY + CVP_0, + CVP_HADJUSTMENT, + CVP_VADJUSTMENT, + CVP_HSCROLL_POLICY, + CVP_VSCROLL_POLICY -} ViewPanelProps; +} ContentViewProps; +#if 0 + /* Définit un chemin décrivant la bordure autour du panneau. */ void gtk_display_panel_define_border_path(GtkDisplayPanel *, cairo_t *, const GtkAllocation *); diff --git a/src/gtkext/contentview.c b/src/gtkext/contentview.c index 4b7f79d..77bbb7b 100644 --- a/src/gtkext/contentview.c +++ b/src/gtkext/contentview.c @@ -59,22 +59,51 @@ static void gtk_content_view_dispose(GtkContentView *); /* Procède à la libération totale de la mémoire. */ static void gtk_content_view_finalize(GtkContentView *); + + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Définit une propriété du composant d'affichage. */ +static void gtk_content_view_set_property(GObject *, guint, const GValue *, GParamSpec *); + +/* Se débarrsse d'un ajustement pour un défilement donné. */ +static void _gtk_content_view_disconnect_adjustment(GtkContentView *, GtkOrientation); + +/* S'associe à un ajustement pour un défilement donné. */ +static void _gtk_content_view_set_adjustment(GtkContentView *, GtkOrientation, GtkAdjustment *); + +/* Réagit à un défilement chez une barre associée au composant. */ +static void _gtk_content_view_adjustment_value_changed(GtkAdjustment *, GtkContentView *); + +/* Fournit une propriété du composant d'affichage. */ +static void gtk_content_view_get_property(GObject *, guint, GValue *, GParamSpec *); + +/* Fournit les mesures mainimale et idéale du composant. */ +static void gtk_content_view_measure(GtkWidget *, GtkOrientation, int, int *, int *, int *, int *); + + + + + #if 0 /* Définit une propriété du composant d'affichage. */ -static void gtk_display_panel_set_property(GObject *, guint, const GValue *, GParamSpec *); +//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 *); +//static void gtk_display_panel_get_property(GObject *, guint, GValue *, GParamSpec *); /* Détruit un composant d'affichage. */ -static void gtk_display_panel_destroy(GtkWidget *); +//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 *); +//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 *); @@ -83,22 +112,22 @@ static void gtk_display_panel_get_preferred_height(GtkWidget *, gint *, gint *); 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 *); +//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); +//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 *); +//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); +//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 *); +//static void gtk_display_panel_adjustment_value_changed(GtkAdjustment *, GtkDisplayPanel *); @@ -136,8 +165,8 @@ G_DEFINE_TYPE_WITH_CODE(GtkDisplayPanel, gtk_display_panel, GTK_TYPE_FIXED, /* Détermine le type du composant d'affichage générique. */ -G_DEFINE_TYPE(GtkContentView, gtk_content_view, GTK_TYPE_WIDGET); - +G_DEFINE_TYPE_WITH_CODE(GtkContentView, gtk_content_view, GTK_TYPE_WIDGET, + G_IMPLEMENT_INTERFACE(GTK_TYPE_SCROLLABLE, NULL)); /****************************************************************************** @@ -155,35 +184,43 @@ G_DEFINE_TYPE(GtkContentView, gtk_content_view, GTK_TYPE_WIDGET); static void gtk_content_view_class_init(GtkContentViewClass *class) { GObjectClass *object; /* Plus haut niveau équivalent */ - //GtkWidgetClass *widget; /* Classe de haut niveau */ - //GtkContentViewClass *panel; /* Classe de lus bas niveau */ + GtkWidgetClass *widget; /* Classe de haut niveau */ object = G_OBJECT_CLASS(class); + object->set_property = gtk_content_view_set_property; + object->get_property = gtk_content_view_get_property; object->dispose = (GObjectFinalizeFunc/* ! */)gtk_content_view_dispose; object->finalize = (GObjectFinalizeFunc)gtk_content_view_finalize; + /* Implémentation de l'interface "GtkScrollable" */ + g_object_class_override_property(object, CVP_HADJUSTMENT, "hadjustment"); + g_object_class_override_property(object, CVP_VADJUSTMENT, "vadjustment"); + g_object_class_override_property(object, CVP_HSCROLL_POLICY, "hscroll-policy"); + g_object_class_override_property(object, CVP_VSCROLL_POLICY, "vscroll-policy"); + + + + + + widget = GTK_WIDGET_CLASS(class); + + widget->measure = gtk_content_view_measure; + + + + #if 0 - object->set_property = gtk_display_panel_set_property; - object->get_property = gtk_display_panel_get_property; - /* Implémentation de l'interface "GtkScrollable" */ - g_object_class_override_property(object, VPP_HADJUSTMENT, "hadjustment"); - g_object_class_override_property(object, VPP_VADJUSTMENT, "vadjustment"); - g_object_class_override_property(object, VPP_HSCROLL_POLICY, "hscroll-policy"); - g_object_class_override_property(object, VPP_VSCROLL_POLICY, "vscroll-policy"); widget = GTK_WIDGET_CLASS(class); - widget->destroy = gtk_display_panel_destroy; + //widget->destroy = gtk_display_panel_destroy; widget->realize = gtk_display_panel_realize; widget->size_allocate = gtk_display_panel_size_allocate; widget->get_preferred_height = gtk_display_panel_get_preferred_height; widget->get_preferred_width = gtk_display_panel_get_preferred_width; - panel = GTK_DISPLAY_PANEL_CLASS(class); - - panel->compute_inc = gtk_display_panel_compute_scroll_inc; /* Signaux */ @@ -214,8 +251,13 @@ static void gtk_content_view_class_init(GtkContentViewClass *class) static void gtk_content_view_init(GtkContentView *view) { + view->adjustments[GTK_ORIENTATION_HORIZONTAL] = NULL; + view->adjustments[GTK_ORIENTATION_VERTICAL] = NULL; + + view->scroll_policies[GTK_ORIENTATION_HORIZONTAL] = GTK_POLICY_AUTOMATIC; + view->scroll_policies[GTK_ORIENTATION_VERTICAL] = GTK_POLICY_AUTOMATIC; + view->options = NULL; - view->style = g_token_style_new(GTK_WIDGET(view)); @@ -272,13 +314,16 @@ static void gtk_display_panel_loaded_interface_init(GLoadedPanelInterface *iface static void gtk_content_view_dispose(GtkContentView *view) { + _gtk_content_view_disconnect_adjustment(view, GTK_ORIENTATION_HORIZONTAL); + _gtk_content_view_disconnect_adjustment(view, GTK_ORIENTATION_VERTICAL); + + g_clear_object(&view->adjustments[GTK_ORIENTATION_HORIZONTAL]); + g_clear_object(&view->adjustments[GTK_ORIENTATION_VERTICAL]); + g_clear_object(&view->options); - g_clear_object(&view->style); /* - g_clear_object(&panel->hadjustment); - g_clear_object(&panel->vadjustment); g_clear_object(&panel->options); @@ -309,7 +354,16 @@ static void gtk_content_view_finalize(GtkContentView *view) } -#if 0 + + + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + /****************************************************************************** * * * Paramètres : object = instance de composant GTK à manipuler. * @@ -325,25 +379,25 @@ static void gtk_content_view_finalize(GtkContentView *view) * * ******************************************************************************/ -static void gtk_display_panel_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) +static void gtk_content_view_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { - GtkDisplayPanel *panel; /* Autre vision de l'instance */ + GtkContentView *view; /* Autre vision de l'instance */ - panel = GTK_DISPLAY_PANEL(object); + view = GTK_CONTENT_VIEW(object); switch (prop_id) { - case VPP_HADJUSTMENT: - gtk_display_panel_set_adjustment(panel, GTK_ORIENTATION_HORIZONTAL, g_value_get_object(value)); + case CVP_HADJUSTMENT: + _gtk_content_view_set_adjustment(view, 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)); + case CVP_VADJUSTMENT: + _gtk_content_view_set_adjustment(view, GTK_ORIENTATION_VERTICAL, g_value_get_object(value)); break; - case VPP_HSCROLL_POLICY: + case CVP_HSCROLL_POLICY: //viewport->priv->hscroll_policy = g_value_get_enum (value); //gtk_widget_queue_resize (GTK_WIDGET (viewport)); break; - case VPP_VSCROLL_POLICY: + case CVP_VSCROLL_POLICY: //viewport->priv->vscroll_policy = g_value_get_enum (value); //gtk_widget_queue_resize (GTK_WIDGET (viewport)); break; @@ -357,6 +411,105 @@ static void gtk_display_panel_set_property(GObject *object, guint prop_id, const /****************************************************************************** * * +* Paramètres : view = 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_content_view_disconnect_adjustment(GtkContentView *view, GtkOrientation orientation) +{ + GtkAdjustment **adjp; /* Ajustement à manipuler */ + + adjp = &view->adjustments[orientation]; + + if (*adjp != NULL) + { + g_signal_handlers_disconnect_by_func(*adjp, _gtk_content_view_adjustment_value_changed, view); + g_clear_object(adjp); + } + +} + + +/****************************************************************************** +* * +* Paramètres : view = 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_content_view_set_adjustment(GtkContentView *view, GtkOrientation orientation, GtkAdjustment *adj) +{ + GtkAdjustment **adjp; /* Ajustement à manipuler */ + + adjp = &view->adjustments[orientation]; + + /* S'il n'y a rien à faire... */ + if (adj != NULL && adj == *adjp) + return; + + if (adj == NULL) + adj = gtk_adjustment_new(0.0, 0.0, 0.0, 0.0, 0.0, 0.0); + else + ref_object(adj); + + _gtk_content_view_disconnect_adjustment(view, orientation); + + *adjp = adj; + + g_signal_connect(adj, "value-changed", G_CALLBACK(_gtk_content_view_adjustment_value_changed), view); + + gtk_widget_queue_allocate(GTK_WIDGET(view)); + +} + + +/****************************************************************************** +* * +* Paramètres : adj = défilement dont une valeur a changé. * +* view = panneau d'affichage concerné. * +* * +* Description : Réagit à un défilement chez une barre associée au composant. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void _gtk_content_view_adjustment_value_changed(GtkAdjustment *adj, GtkContentView *view) +{ + GtkOrientation orientation; /* Indification de la barre */ + GtkContentViewClass *class; /* Classe de l'instance */ + + if (adj == view->adjustments[GTK_ORIENTATION_HORIZONTAL]) + orientation = GTK_ORIENTATION_HORIZONTAL; + else + orientation = GTK_ORIENTATION_VERTICAL; + + class = GTK_CONTENT_VIEW_GET_CLASS(view); + + if (class->adjust != NULL) + class->adjust(view, orientation, adj); + +} + + +/****************************************************************************** +* * * Paramètres : object = instance de composant GTK à manipuler. * * prop_id = identifiant de la propriété concernée. * * value = valeur à renvoyer. * @@ -370,25 +523,25 @@ static void gtk_display_panel_set_property(GObject *object, guint prop_id, const * * ******************************************************************************/ -static void gtk_display_panel_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +static void gtk_content_view_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { - GtkDisplayPanel *panel; /* Autre vision de l'instance */ + GtkContentView *view; /* Autre vision de l'instance */ - panel = GTK_DISPLAY_PANEL(object); + view = GTK_CONTENT_VIEW(object); switch (prop_id) { - case VPP_HADJUSTMENT: - g_value_set_object(value, panel->hadjustment); + case CVP_HADJUSTMENT: + g_value_set_object(value, view->adjustments[GTK_ORIENTATION_HORIZONTAL]); break; - case VPP_VADJUSTMENT: - g_value_set_object(value, panel->vadjustment); + case CVP_VADJUSTMENT: + g_value_set_object(value, view->adjustments[GTK_ORIENTATION_VERTICAL]); break; - case VPP_HSCROLL_POLICY: - g_value_set_enum(value, panel->hscroll_policy); + case CVP_HSCROLL_POLICY: + g_value_set_enum(value, view->scroll_policies[GTK_ORIENTATION_HORIZONTAL]); break; - case VPP_VSCROLL_POLICY: - g_value_set_enum(value, panel->vscroll_policy); + case CVP_VSCROLL_POLICY: + g_value_set_enum(value, view->scroll_policies[GTK_ORIENTATION_VERTICAL]); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); @@ -400,6 +553,88 @@ static void gtk_display_panel_get_property(GObject *object, guint prop_id, GValu /****************************************************************************** * * +* 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_content_view_measure(GtkWidget *widget, GtkOrientation orientation, int for_size, int *minimum, int *natural, int *min_baseline, int *nat_baseline) +{ + GtkContentView *view; /* Version spécialisée */ + size_t i; /* Boucle de parcours */ + int min; /* Valeur minimale locale */ + int nat; /* Valeur idéale locale */ + + view = GTK_CONTENT_VIEW(widget); + + if (minimum != NULL) *minimum = 0; + if (natural != NULL) *natural = 0; + + /* Demande de hauteur minimale / idéale */ + if (orientation == GTK_ORIENTATION_VERTICAL) + { + for (i = 0; i < view->sub_count; i++) + { + gtk_widget_measure(view->sub_children[i], GTK_ORIENTATION_VERTICAL, -1, &min, &nat, NULL, NULL); + + if (minimum != NULL && min > *minimum) + *minimum = min; + + if (natural != NULL && nat > *natural) + *natural = nat; + + } + + } + + /* Demande de largeur minimale / idéale */ + else + { + for (i = 0; i < view->sub_count; i++) + { + gtk_widget_measure(view->sub_children[i], GTK_ORIENTATION_HORIZONTAL, -1, &min, &nat, NULL, NULL); + + if (minimum != NULL) *minimum += min; + if (natural != NULL) *natural += nat; + + } + + } + + if (min_baseline != NULL) *min_baseline = -1; + if (nat_baseline != NULL) *nat_baseline = -1; + +} + + + + + + + + + + + + + + +#if 0 + + +/****************************************************************************** +* * * Paramètres : widget = composant GTK à détruire. * * * * Description : Détruit un composant d'affichage. * @@ -416,8 +651,11 @@ static void gtk_display_panel_destroy(GtkWidget *widget) panel = GTK_DISPLAY_PANEL(widget); - gtk_display_panel_disconnect_adjustment(panel, GTK_ORIENTATION_HORIZONTAL); - gtk_display_panel_disconnect_adjustment(panel, GTK_ORIENTATION_VERTICAL); + GtkContentView *view; /* Autre vision de l'instance */ + + view = GTK_CONTENT_VIEW(widget); + + GTK_WIDGET_CLASS(gtk_display_panel_parent_class)->destroy(widget); @@ -471,32 +709,6 @@ static void gtk_display_panel_realize(GtkWidget *widget) } -/****************************************************************************** -* * -* 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); - -} - /****************************************************************************** * * @@ -560,29 +772,6 @@ static void gtk_display_panel_get_preferred_width(GtkWidget *widget, gint *minim } -/****************************************************************************** -* * -* 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; - -} - /****************************************************************************** * * @@ -653,151 +842,8 @@ static void gtk_display_panel_compute_allocation(GtkDisplayPanel *panel, GtkAllo } -/****************************************************************************** -* * -* 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_widget_get_preferred_width(GTK_WIDGET(panel), &req, NULL); - allocated = allocation.width; - - } - else - { - adj = panel->vadjustment; - - gtk_widget_get_preferred_height(GTK_WIDGET(panel), &req, NULL); - 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); - -} /****************************************************************************** diff --git a/src/gtkext/hexview-int.h b/src/gtkext/hexview-int.h new file mode 100644 index 0000000..2b1c570 --- /dev/null +++ b/src/gtkext/hexview-int.h @@ -0,0 +1,71 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * hexview-int.h - définitions internes pour l'affichage de contenus de binaire + * + * Copyright (C) 2016-2024 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 Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _GTKEXT_HEXVIEW_INT_H +#define _GTKEXT_HEXVIEW_INT_H + + +#include "bufferview-int.h" +#include "hexview.h" +#include "../glibext/generators/hex.h" + + + +/* Composant d'affichage d'octets bruts et imprimables (instance) */ +struct _GtkHexView +{ + GtkBufferView parent; /* A laisser en premier */ + + union + { +#define _CHILDREN_COUNT 3 + + 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 */ + }; + + }; + + GHexGenerator *generator; /* Générateur unique dédié */ + +}; + +/* Composant d'affichage d'octets bruts et imprimables (classe) */ +struct _GtkHexViewClass +{ + GtkBufferViewClass parent; /* A laisser en premier */ + +}; + + +/* Met en place un nouveau composant d'affichage d'octets bruts. */ +bool gtk_hex_view_create(GtkHexView *, GBinContent *); + + + +#endif /* _GTKEXT_HEXVIEW_INT_H */ 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); } diff --git a/src/gtkext/hexview.h b/src/gtkext/hexview.h index 8d3129d..2199786 100644 --- a/src/gtkext/hexview.h +++ b/src/gtkext/hexview.h @@ -28,6 +28,7 @@ #include <gtk/gtk.h> +#include "../analysis/content.h" #include "../glibext/helpers.h" @@ -37,11 +38,8 @@ DECLARE_GTYPE(GtkHexView, gtk_hex_view, GTK, HEX_VIEW); - - - - - +/* Crée un composant d'affichage d'octets bruts et imprimables. */ +GtkHexView *gtk_hex_view_new(GBinContent *); diff --git a/src/gtkext/hexview.ui b/src/gtkext/hexview.ui index df657ca..ae4586c 100644 --- a/src/gtkext/hexview.ui +++ b/src/gtkext/hexview.ui @@ -1,5 +1,5 @@ <interface> - <template class="GtkHexView" parent="GtkContentView"> + <template class="GtkHexView" parent="GtkBufferView"> <property name="css-name">GtkHexView</property> <child> <object class="GtkComposingArea" id="offsets"> @@ -23,10 +23,5 @@ </style> </object> </child> - <child> - <object class="GtkScrollbar" id="vscroll"> - <property name="orientation">1</property> - </object> - </child> </template> </interface> |