summaryrefslogtreecommitdiff
path: root/src/gtkext/gtkbufferdisplay.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/gtkext/gtkbufferdisplay.c')
-rw-r--r--src/gtkext/gtkbufferdisplay.c1104
1 files changed, 1104 insertions, 0 deletions
diff --git a/src/gtkext/gtkbufferdisplay.c b/src/gtkext/gtkbufferdisplay.c
new file mode 100644
index 0000000..b510c8f
--- /dev/null
+++ b/src/gtkext/gtkbufferdisplay.c
@@ -0,0 +1,1104 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * gtkbufferdisplay.c - affichage de tampons de lignes
+ *
+ * Copyright (C) 2016 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "gtkbufferdisplay.h"
+
+
+#include "gtkbufferdisplay-int.h"
+
+
+#include "../core/params.h"
+
+
+
+/* -------------------------- INTERACTION DIRECTE AVEC GTK -------------------------- */
+
+
+/* Procède à l'initialisation de l'afficheur de tampons. */
+static void gtk_buffer_display_class_init(GtkBufferDisplayClass *);
+
+/* Procède à l'initialisation de l'afficheur de tampons. */
+static void gtk_buffer_display_init(GtkBufferDisplay *);
+
+/* Supprime toutes les références externes. */
+static void gtk_buffer_display_dispose(GtkBufferDisplay *);
+
+/* Procède à la libération totale de la mémoire. */
+static void gtk_buffer_display_finalize(GtkBufferDisplay *);
+
+/* Intègre le focus dans le rendu du composant. */
+static gboolean gtk_buffer_display_focus(GtkWidget *, GdkEventFocus *);
+
+/* Assure la gestion des clics de souris sur le composant. */
+static gboolean gtk_buffer_display_button_press(GtkWidget *, GdkEventButton *);
+
+/* Met à jour l'affichage de la visualisation de code buffer. */
+static gboolean gtk_buffer_display_draw(GtkWidget *, cairo_t *);
+
+/* Prend en compte une frappe de touche sur le composant. */
+static gboolean gtk_buffer_display_key_press(GtkWidget *, GdkEventKey *);
+
+/* Indique les dimensions de travail du composant d'affichage. */
+static void gtk_buffer_display_compute_requested_size(GtkBufferDisplay *, gint *, gint *);
+
+/* Détermine la taille des bonds lors de défilements. */
+static void gtk_buffer_display_compute_scroll_inc(GtkBufferDisplay *, gint, GtkOrientation, gdouble *, gdouble *);
+
+/* Réagit à un défilement chez une barre associée au composant. */
+static void gtk_buffer_display_adjust_scroll_value(GtkBufferDisplay *, GtkAdjustment *, GtkOrientation);
+
+/* Indique la position courante du curseur. */
+static const vmpa2t *gtk_buffer_display_get_caret_location(const GtkBufferDisplay *);
+
+/* Indique la position d'affichage d'une adresse donnée. */
+static bool gtk_buffer_display_get_address_coordinates(const GtkBufferDisplay *, const vmpa2t *, gint *, gint *, ScrollPositionTweak);
+
+/* Place en cache un rendu destiné à l'aperçu graphique rapide. */
+static void gtk_buffer_display_cache_glance(GtkBufferDisplay *, cairo_t *, const GtkAllocation *, double);
+
+
+
+/* ------------------------------ ANIMATION DU CURSEUR ------------------------------ */
+
+
+/* Déplace le curseur à un emplacement défini. */
+static bool _gtk_buffer_display_move_caret_to(GtkBufferDisplay *, gint, gint);
+
+/* Déplace le curseur en effaçant son éventuelle position. */
+static void gtk_buffer_display_relocate_caret(GtkBufferDisplay *, const GdkRectangle *, const vmpa2t *);
+
+/* Redémarre l'affichage du curseur à l'emplacement courant. */
+static void gtk_buffer_display_restart_caret_blinking(GtkBufferDisplay *);
+
+/* Bascule et relance l'affichage du curseur. */
+static gboolean gtk_buffer_display_refresh_caret(GtkBufferDisplay *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* INTERACTION DIRECTE AVEC GTK */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Détermine le type du composant d'affichage de tampon de lignes. */
+G_DEFINE_TYPE(GtkBufferDisplay, gtk_buffer_display, GTK_TYPE_DISPLAY_PANEL)
+
+
+/******************************************************************************
+* *
+* Paramètres : class = classe GTK à initialiser. *
+* *
+* Description : Procède à l'initialisation de l'afficheur de tampons. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_buffer_display_class_init(GtkBufferDisplayClass *class)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GtkWidgetClass *widget_class; /* Classe version Widget */
+ GtkDisplayPanelClass *panel_class; /* Classe parente */
+
+ object = G_OBJECT_CLASS(class);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)gtk_buffer_display_dispose;
+ object->finalize = (GObjectFinalizeFunc)gtk_buffer_display_finalize;
+
+ widget_class = GTK_WIDGET_CLASS(class);
+
+ widget_class->focus_in_event = gtk_buffer_display_focus;
+ widget_class->focus_out_event = gtk_buffer_display_focus;
+ widget_class->button_press_event = gtk_buffer_display_button_press;
+ widget_class->draw = gtk_buffer_display_draw;
+ widget_class->key_press_event = gtk_buffer_display_key_press;
+
+ panel_class = GTK_DISPLAY_PANEL_CLASS(class);
+
+ panel_class->compute_size = (compute_requested_size_fc)gtk_buffer_display_compute_requested_size;
+ panel_class->compute_inc = (compute_scroll_inc_fc)gtk_buffer_display_compute_scroll_inc;
+ panel_class->adjust = (adjust_scroll_value_fc)gtk_buffer_display_adjust_scroll_value;
+ panel_class->get_caret_loc = (get_caret_location_fc)gtk_buffer_display_get_caret_location;
+ panel_class->get_coordinates = (get_addr_coordinates_fc)gtk_buffer_display_get_address_coordinates;
+ panel_class->move_caret_to = (move_caret_to_fc)_gtk_buffer_display_move_caret_to;
+ panel_class->cache_glance = (cache_glance_fc)gtk_buffer_display_cache_glance;
+
+ /* Signaux */
+
+ g_signal_new("reach-limit",
+ GTK_TYPE_BUFFER_DISPLAY,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET(GtkBufferDisplayClass, reach_limit),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__ENUM,
+ G_TYPE_NONE, 1, GTK_TYPE_SCROLL_TYPE);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : display = composant GTK à initialiser. *
+* *
+* Description : Procède à l'initialisation de l'afficheur de tampons. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_buffer_display_init(GtkBufferDisplay *display)
+{
+ init_vmpa(&display->caret_addr, VMPA_NO_PHYSICAL, VMPA_NO_VIRTUAL);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : display = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_buffer_display_dispose(GtkBufferDisplay *display)
+{
+ if (display->view != NULL)
+ g_object_unref(G_OBJECT(display->view));
+
+ G_OBJECT_CLASS(gtk_buffer_display_parent_class)->dispose(G_OBJECT(display));
+
+}
+
+
+/******************************************************************************
+* *
+* 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_display_finalize(GtkBufferDisplay *display)
+{
+ G_OBJECT_CLASS(gtk_buffer_display_parent_class)->finalize(G_OBJECT(display));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : widget = composant GTK visé par l'opération. *
+* event = informations liées à l'événement. *
+* *
+* Description : Intègre le focus dans le rendu du composant. *
+* *
+* Retour : FALSE pour poursuivre la propagation de l'événement. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static gboolean gtk_buffer_display_focus(GtkWidget *widget, GdkEventFocus *event)
+{
+ GtkBufferDisplay *display; /* Autre version du composant */
+ gboolean has_focus; /* Etat courant */
+
+ display = GTK_BUFFER_DISPLAY(widget);
+ has_focus = event->in;
+
+ if (has_focus)
+ gtk_buffer_display_restart_caret_blinking(display);
+
+ else if (display->caret_timer != 0)
+ {
+ g_source_remove(display->caret_timer);
+ display->caret_timer = 0;
+
+ display->show_caret = true;
+ gtk_buffer_display_refresh_caret(display);
+
+ }
+
+ return TRUE;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : widget = composant GTK visé par l'opération. *
+* event = informations liées à l'événement. *
+* *
+* Description : Assure la gestion des clics de souris sur le composant. *
+* *
+* Retour : FALSE pour poursuivre la propagation de l'événement. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static gboolean gtk_buffer_display_button_press(GtkWidget *widget, GdkEventButton *event)
+{
+ GtkBufferDisplay *display; /* Autre version du composant */
+ GBufferCache *cache; /* Contenu représenté */
+ gint left_margin; /* Limite entre zones réactives*/
+ gint real_x; /* Abscisse absolue réelle */
+ gint real_y; /* Ordonnée absolue réelle */
+
+ display = GTK_BUFFER_DISPLAY(widget);
+
+ real_x = event->x;
+ real_y = event->y;
+ gtk_display_panel_compute_real_coord(GTK_DISPLAY_PANEL(display), &real_x, &real_y);
+
+ cache = g_buffer_view_get_cache(display->view);
+
+ left_margin = g_buffer_cache_get_left_margin(cache);
+
+ g_object_unref(G_OBJECT(cache));
+
+ if (real_x < left_margin)
+ {
+ /* TODO */
+ }
+ else
+ _gtk_buffer_display_move_caret_to(display, real_x, real_y);
+
+ gtk_widget_grab_focus(widget);
+
+ return FALSE;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : widget = composant GTK à redessiner. *
+* cr = contexte graphique associé à l'événement. *
+* *
+* Description : Met à jour l'affichage de la visualisation de code buffer. *
+* *
+* Retour : FALSE pour poursuivre la propagation de l'événement. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static gboolean gtk_buffer_display_draw(GtkWidget *widget, cairo_t *cr)
+{
+ GtkBufferDisplay *display; /* Autre version du composant */
+ GtkDisplayPanel *parent; /* Autre version du composant */
+ GdkWindow *window; /* Fenêtre à redessiner */
+ cairo_region_t *region; /* Région visible à redessiner */
+ cairo_rectangle_int_t area; /* Surface correspondante */
+ GtkStyleContext *context; /* Contexte du thème actuel */
+ gint virt_x; /* Abscisse virtuelle */
+ gint virt_y; /* Ordonnée virtuelle */
+ GBufferCache *cache; /* Contenu représenté */
+ gint left_margin; /* Marge gauche + espace */
+ GdkRGBA color; /* Couleur de thème récupérée */
+ bool sel_line; /* Souslignage de la sélection */
+ gint *selected; /* Ordonnée d'une sélection */
+
+
+ //gboolean status;
+
+
+ GtkStyleContext *other;
+ GtkWidgetPath *path;
+
+
+ other = gtk_style_context_new();
+
+
+ path = gtk_widget_path_new ();
+ gtk_widget_path_append_type (path, GTK_TYPE_SCALE);
+ //gtk_widget_path_iter_add_class (path, 0, "slider");
+ //gtk_widget_path_iter_add_class (path, 0, "scale");
+ gtk_style_context_set_path (other, path);
+ gtk_widget_path_free (path);
+
+
+
+
+ //context = gtk_widget_get_style_context(widget);
+
+
+ //gtk_render_background(context, cr, 0, 0, 1000, 1000);
+
+
+ //status = GTK_WIDGET_CLASS(gtk_buffer_display_parent_class)->draw(widget, cr);
+
+ //printf("status: %d\n", status);
+
+ //return TRUE;
+
+
+
+
+ display = GTK_BUFFER_DISPLAY(widget);
+ parent = GTK_DISPLAY_PANEL(widget);
+
+ window = gtk_widget_get_window(widget);
+
+ cairo_save(cr);
+ gtk_cairo_transform_to_window(cr, widget, window);
+
+ region = gdk_window_get_clip_region(window);
+ cairo_region_get_extents(region, &area);
+ cairo_region_destroy(region);
+
+ context = gtk_widget_get_style_context(widget);
+
+ if (parent->show_border)
+ {
+ gtk_display_panel_define_border_path(parent, cr, 0, 0);
+ cairo_clip(cr);
+ }
+
+
+
+ gtk_render_background(context, cr, area.x, area.y, area.width, area.height);
+
+
+
+ /* Décallage pour le défilement horizontal */
+
+ virt_x = 0;
+ virt_y = 0;
+ gtk_display_panel_compute_fake_coord(parent, &virt_x, &virt_y);
+
+ cairo_save(cr);
+
+ cairo_translate(cr, virt_x, 0);
+
+ /* Récupération de la limite utile */
+
+ cache = g_buffer_view_get_cache(display->view);
+
+ left_margin = g_buffer_cache_get_left_margin(cache);
+
+ g_object_unref(G_OBJECT(cache));
+
+
+ /* Dessin de la marge gauche */
+
+ gtk_style_context_save(context);
+
+ gtk_style_context_add_class(other, GTK_STYLE_CLASS_TOOLBAR);
+
+ gtk_style_context_get_background_color(other, GTK_STATE_FLAG_ACTIVE, &color);
+
+ cairo_set_source_rgba(cr, color.red, color.green, color.blue, color.alpha);
+ //cairo_set_source_rgba(cr, 1.0, 0.0, 0.0, 1.0);
+
+ cairo_rectangle(cr, 0, area.y, left_margin, area.height);
+ cairo_fill(cr);
+
+ gtk_style_context_restore(context);
+
+ /* Fond de la zone de texte */
+
+#if 1
+ gtk_style_context_save(context);
+
+ gtk_style_context_add_class(context, GTK_STYLE_CLASS_VIEW);
+
+ gtk_style_context_get_background_color(context, GTK_STATE_FLAG_ACTIVE, &color);
+
+ cairo_set_source_rgba(cr, color.red, color.green, color.blue, color.alpha * 0.7);
+
+ cairo_rectangle(cr, left_margin, area.y, area.width, area.height);
+ cairo_fill(cr);
+
+ gtk_style_context_restore(context);
+#endif
+
+ /* Ligne de séparation */
+
+ gtk_style_context_save(context);
+
+ gtk_style_context_add_class(context, GTK_STYLE_CLASS_FRAME);
+
+ gtk_style_context_get_border_color(context, GTK_STATE_FLAG_ACTIVE, &color);
+
+ cairo_set_source_rgba(cr, color.red, color.green, color.blue, color.alpha);
+
+ cairo_set_line_width(cr, 1.0);
+
+ cairo_move_to(cr, left_margin + 0.5, area.y - 0.5);
+ cairo_line_to(cr, left_margin + 0.5, area.y + area.height + 0.5);
+ cairo_stroke(cr);
+
+ gtk_style_context_restore(context);
+
+ /* Eventuelle bordure globale */
+
+ if (parent->show_border)
+ gtk_display_panel_draw_border(parent, cr);
+
+ /* Impression du désassemblage */
+
+ if (display->view != NULL)
+ {
+ g_generic_config_get_value(get_main_configuration(), MPK_SELECTION_LINE, &sel_line);
+ sel_line &= gtk_widget_has_focus(widget);
+
+ if (!sel_line || is_invalid_vmpa(&display->caret_addr))
+ selected = NULL;
+ else
+ {
+ selected = (gint []) { display->caret.y };
+ gtk_display_panel_compute_relative_coords(parent, NULL, selected);
+ }
+
+ area.x -= virt_x;
+ virt_y += area.y;
+
+ g_buffer_view_draw(display->view, cr, virt_y, &area, parent->display, selected);
+
+ }
+
+ cairo_restore(cr);
+
+ /* Curseur clignotant ? */
+
+ /*
+ if (gtk_widget_is_focus(widget))
+ {
+ view->show_caret = !view->show_caret;
+ gtk_buffer_view_refresh_caret(view);
+ }
+ */
+
+ cairo_restore(cr);
+
+ return TRUE;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : widget = composant visé par l'opération. *
+* event = informations liées à l'événement. *
+* *
+* Description : Prend en compte une frappe de touche sur le composant. *
+* *
+* Retour : FALSE pour poursuivre la propagation de l'événement. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static gboolean gtk_buffer_display_key_press(GtkWidget *widget, GdkEventKey *event)
+{
+ gboolean result; /* Suites à renvoyer */
+ GdkScrollDirection dir; /* Direction du déplacement */
+ GtkBufferDisplay *display; /* Autre version du composant */
+ GtkDisplayPanel *panel; /* Autre version du composant */
+ bool ctrl; /* Statut de la touche Contrôle*/
+ GdkRectangle area; /* Emplacement de curseur */
+ vmpa2t addr; /* Adresse du nouveau curseur */
+ bool status; /* Validité d'un déplacement */
+
+ switch (event->keyval)
+ {
+ case GDK_KEY_Left:
+ dir = GDK_SCROLL_LEFT;
+ result = TRUE;
+ break;
+
+ case GDK_KEY_Up:
+ dir = GDK_SCROLL_UP;
+ result = TRUE;
+ break;
+
+ case GDK_KEY_Right:
+ dir = GDK_SCROLL_RIGHT;
+ result = TRUE;
+ break;
+
+ case GDK_KEY_Down:
+ dir = GDK_SCROLL_DOWN;
+ result = TRUE;
+ break;
+
+ default:
+ result = FALSE;
+ break;
+
+ }
+
+ if (result)
+ {
+ display = GTK_BUFFER_DISPLAY(widget);
+ panel = GTK_DISPLAY_PANEL(widget);
+
+ ctrl = (event->state & GDK_CONTROL_MASK);
+ area = display->caret;
+
+ status = g_buffer_view_move_caret(display->view, ctrl, dir, panel->display, &area, &addr);
+
+ if (status)
+ {
+ gtk_buffer_display_relocate_caret(display, &area, &addr);
+ _gtk_display_panel_scroll_to_address(panel, &addr, SPT_RAW, false);
+ }
+ else
+ g_signal_emit_by_name(display, "reach-limit", dir);
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : display = composant GTK à consulter. *
+* width = largeur requise à renseigner ou NULL. [OUT] *
+* height = hauteur requise à renseigner ou NULL. [OUT] *
+* *
+* Description : Indique les dimensions de travail du composant d'affichage. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_buffer_display_compute_requested_size(GtkBufferDisplay *display, gint *width, gint *height)
+{
+ if (width != NULL)
+ {
+ if (display->view != NULL)
+ *width = g_buffer_view_get_width(display->view, GTK_DISPLAY_PANEL(display)->display);
+ else
+ *width = 0;
+ }
+
+ if (height != NULL)
+ {
+ if (display->view != NULL)
+ *height = g_buffer_view_get_height(display->view);
+ else
+ *height = 0;
+ }
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : display = composant GTK d'affichage à consulter. *
+* 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_buffer_display_compute_scroll_inc(GtkBufferDisplay *display, gint size, GtkOrientation orientation, gdouble *step, gdouble *page)
+{
+ GBufferCache *cache; /* Gestionnaire de lignes */
+
+ if (orientation == GTK_ORIENTATION_VERTICAL && display->view != NULL)
+ {
+ cache = g_buffer_view_get_cache(display->view);
+
+ *step = g_buffer_cache_get_line_height(cache);
+ *page = *step * 10;
+
+ g_object_unref(G_OBJECT(cache));
+
+ }
+
+ else
+ GTK_DISPLAY_PANEL_CLASS(gtk_buffer_display_parent_class)->compute_inc(GTK_DISPLAY_PANEL(display),
+ size, orientation, step, page);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : display = panneau d'affichage concerné. *
+* adj = défilement dont une valeur a changé. *
+* orientation = indication sur le défilement à traiter. *
+* *
+* Description : Réagit à un défilement chez une barre associée au composant. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_buffer_display_adjust_scroll_value(GtkBufferDisplay *display, GtkAdjustment *adj, GtkOrientation orientation)
+{
+ GtkWidget *widget; /* Autre vision du composant */
+
+ widget = GTK_WIDGET(display);
+
+ if (gtk_widget_get_realized(widget))
+ gdk_window_invalidate_rect(gtk_widget_get_window(widget), NULL, FALSE);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : display = composant GTK à manipuler. *
+* *
+* Description : Indique la position courante du curseur. *
+* *
+* Retour : Emplacement courant du curseur ou NULL si aucun. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static const vmpa2t *gtk_buffer_display_get_caret_location(const GtkBufferDisplay *display)
+{
+ return &display->caret_addr;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : display = composant GTK à consulter. *
+* addr = adresse à présenter à l'écran. *
+* x = position horizontale au sein du composant. [OUT] *
+* y = position verticale au sein du composant. [OUT] *
+* tweak = adaptation finale à effectuer. *
+* *
+* Description : Indique la position d'affichage d'une adresse donnée. *
+* *
+* Retour : true si l'adresse fait partie du composant, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool gtk_buffer_display_get_address_coordinates(const GtkBufferDisplay *display, const vmpa2t *addr, gint *x, gint *y, ScrollPositionTweak tweak)
+{
+ bool result; /* Bilan à remonter */
+ bool need_code; /* Recherche plus raffinée */
+ GBufferCache *cache; /* Gestionnaire de lignes */
+ int height; /* Hauteur allouée */
+
+ need_code = (tweak == SPT_BOTTOM);
+
+ cache = g_buffer_view_get_cache(display->view);
+
+ result = g_buffer_view_get_address_coordinates(display->view, addr, need_code, x, y);
+
+ if (result)
+ {
+ *x += g_buffer_view_get_margin(display->view, GTK_DISPLAY_PANEL(display)->display);
+
+ height = gtk_widget_get_allocated_height(GTK_WIDGET(display));
+
+ switch (tweak)
+ {
+ case SPT_RAW:
+ break;
+
+ case SPT_TOP:
+ break;
+
+ case SPT_CENTER:
+ *y -= (height / 2);
+ break;
+
+ case SPT_BOTTOM:
+ *y -= height;
+ *y += g_buffer_cache_get_line_height(cache);
+ break;
+
+ }
+
+ }
+
+ g_object_unref(G_OBJECT(cache));
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : display = composant GTK à manipuler. *
+* cairo = assistant pour la création de rendus. *
+* area = taille de la surface réduite à disposition. *
+* scale = échelle vis à vis de la taille réelle. *
+* *
+* Description : Place en cache un rendu destiné à l'aperçu graphique rapide. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_buffer_display_cache_glance(GtkBufferDisplay *display, cairo_t *cairo, const GtkAllocation *area, double scale)
+{
+ cairo_set_line_width(cairo, 1);
+ cairo_set_source_rgb(cairo, 0.4, 0.4, 0.4);
+
+ cairo_rectangle(cairo, area->x + 0.5, area->y + 0.5, area->width - 1, area->height - 1);
+
+ cairo_stroke(cairo);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : display = instance d'objet Gtk à actualiser. *
+* view = nouvelle vue à associer au composant. *
+* *
+* Description : Lie une vue au composant d'affichage de tampon. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void gtk_buffer_display_set_view(GtkBufferDisplay *display, GBufferView *view)
+{
+ if (display->view != NULL)
+ g_object_unref(G_OBJECT(display->view));
+
+ display->view = view;
+
+}
+
+
+/******************************************************************************
+* *
+* 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;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* ANIMATION DU CURSEUR */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : display = composant GTK à manipuler. *
+* x = abscisse proposée pour le nouvel emplacement. *
+* y = ordonnée proposée pour le nouvel emplacement. *
+* *
+* Description : Déplace le curseur à un emplacement défini. *
+* *
+* Retour : true si un traitement a été effectué, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool _gtk_buffer_display_move_caret_to(GtkBufferDisplay *display, gint x, gint y)
+{
+ bool result; /* Bilan à retourner */
+ GtkDisplayPanel *panel; /* Autre version du composant */
+ vmpa2t addr; /* Position mémoire associée */
+ GdkRectangle new; /* Nouvel emplacement calculé */
+
+ panel = GTK_DISPLAY_PANEL(display);
+
+ result = g_buffer_view_compute_caret_full(display->view, x, y, panel->display, &new, &addr);
+
+ if (result)
+ gtk_buffer_display_relocate_caret(display, &new, &addr);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : display = composant GTK à manipuler. *
+* beginning = précise le coin où se retrouvera le curseur. *
+* same_x = tente de conserver une même abscisse ou NULL ? *
+* *
+* Description : Déplace le curseur à un emplacement en extrémité. *
+* *
+* Retour : true si un traitement a été effectué, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool gtk_buffer_display_move_caret_to(GtkBufferDisplay *display, bool beginning, gint *same_x)
+{
+ bool result; /* Bilan à remonter */
+ GBufferCache *cache; /* Contenu représenté */
+ gint left_margin; /* Limite entre zones réactives*/
+ gint x; /* Abscisse d'emplacement */
+ gint y; /* Ordonnée d'emplacement */
+
+ if (beginning)
+ {
+ cache = g_buffer_view_get_cache(display->view);
+
+ left_margin = g_buffer_cache_get_left_margin(cache);
+
+ g_object_unref(G_OBJECT(cache));
+
+ x = same_x != NULL ? *same_x : left_margin * 2;
+ y = 0;
+
+ }
+ else
+ {
+ if (same_x != NULL)
+ x = *same_x;
+ else
+ gtk_widget_get_preferred_width(GTK_WIDGET(display), NULL, &x);
+
+ gtk_widget_get_preferred_height(GTK_WIDGET(display), NULL, &y);
+ y--;
+
+ }
+
+ result = _gtk_buffer_display_move_caret_to(display, x, y);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : display = composant GTK à manipuler. *
+* area = emplacement pour le dessin d'un curseur. *
+* addr = position dans la mémoire représentée du curseur. *
+* *
+* Description : Déplace le curseur en effaçant son éventuelle position. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_buffer_display_relocate_caret(GtkBufferDisplay *display, const GdkRectangle *area, const vmpa2t *addr)
+{
+ bool clear_old; /* Effacement chirurgical */
+ GdkRectangle old_area; /* Mémorisation de l'ancien */
+ bool need_redraw; /* Besoin de rafraîchissement ?*/
+
+ if (!is_invalid_vmpa(&display->caret_addr))
+ {
+ clear_old = true;
+ old_area = display->caret;
+ }
+ else
+ clear_old = false;
+
+ display->caret = *area;
+ copy_vmpa(&display->caret_addr, addr);
+
+ if (GTK_BUFFER_DISPLAY_GET_CLASS(display)->notify_caret != NULL)
+ need_redraw = GTK_BUFFER_DISPLAY_GET_CLASS(display)->notify_caret(display, area, addr);
+ else
+ need_redraw = false;
+
+ if (need_redraw)
+ gtk_widget_queue_draw(GTK_WIDGET(display));
+
+ else if (clear_old)
+ {
+ gtk_display_panel_compute_relative_coords(GTK_DISPLAY_PANEL(display), &old_area.x, &old_area.y);
+
+ gtk_widget_queue_draw_area(GTK_WIDGET(display), old_area.x, old_area.y,
+ old_area.width, old_area.height);
+
+ }
+
+ gtk_buffer_display_restart_caret_blinking(display);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : display = composant GTK à manipuler. *
+* *
+* Description : Redémarre l'affichage du curseur à l'emplacement courant. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_buffer_display_restart_caret_blinking(GtkBufferDisplay *display)
+{
+
+ GtkSettings *settings; /* Propriétés du système */
+ guint interval; /* Fréquence d'actualisation */
+
+ if (display->caret_timer != 0)
+ {
+ g_source_remove(display->caret_timer);
+ display->caret_timer = 0;
+ }
+
+ if (!is_invalid_vmpa(&display->caret_addr))
+ {
+ display->show_caret = false;
+ gtk_buffer_display_refresh_caret(display);
+
+ settings = gtk_settings_get_default();
+
+ g_object_get(settings, "gtk-cursor-blink-time", &interval, NULL);
+
+ g_object_ref(G_OBJECT(display));
+
+ display->caret_timer = g_timeout_add_full(G_PRIORITY_DEFAULT, interval,
+ (GSourceFunc)gtk_buffer_display_refresh_caret,
+ display, g_object_unref);
+
+ }
+
+ g_signal_emit_by_name(display, "caret-moved", &display->caret_addr);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : display = composant GTK à manipuler. *
+* *
+* Description : Bascule et relance l'affichage du curseur. *
+* *
+* Retour : TRUE pour poursuivre les basculements automatiques. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static gboolean gtk_buffer_display_refresh_caret(GtkBufferDisplay *display)
+{
+ GtkWidget *widget; /* Autre version du composant */
+ GdkWindow *window; /* Fenêtre de support associée */
+ GdkRectangle area; /* Région adaptée à traiter */
+ cairo_t *cr; /* Contexte graphique */
+ GdkRGBA *color; /* Couleur du curseur */
+
+ widget = GTK_WIDGET(display);
+ window = gtk_widget_get_window(widget);
+
+ /**
+ * Si le composant n'est pas encore réalisé (ou caché, en cas de
+ * basculement entre les types de vues), gdk_cairo_create() ne va
+ * pas apprécier l'argument NULL. Donc on écourte l'opération.
+ */
+ if (window == NULL)
+ {
+ display->show_caret = !display->show_caret;
+ return TRUE;
+ }
+
+ area = display->caret;
+ gtk_display_panel_compute_relative_coords(GTK_DISPLAY_PANEL(display), &area.x, &area.y);
+
+ /* Réinitialisation de la surface */
+ if (display->show_caret)
+ {
+ display->show_caret = false;
+ gtk_widget_queue_draw_area(widget, area.x, area.y, area.width, area.height);
+ }
+
+ /* Dessin */
+ else
+ {
+ display->show_caret = true;
+
+ cr = gdk_cairo_create(gtk_widget_get_window(widget));
+
+ gtk_style_context_get(gtk_widget_get_style_context(widget),
+ gtk_widget_get_state_flags(widget),
+ GTK_STYLE_PROPERTY_COLOR, &color, NULL);
+
+ cairo_set_source_rgb(cr, color->red, color->green, color->blue);
+
+ cairo_rectangle(cr, area.x, area.y, area.width, area.height);
+ cairo_fill(cr);
+
+ cairo_destroy(cr);
+
+ }
+
+ return TRUE;
+
+}