diff options
author | Cyrille Bagard <nocbos@gmail.com> | 2016-12-30 10:38:52 (GMT) |
---|---|---|
committer | Cyrille Bagard <nocbos@gmail.com> | 2016-12-30 10:38:52 (GMT) |
commit | 932ea7c83c07d3982fee605c6dd9895fd2753874 (patch) | |
tree | 766ad53bab9e3e3005334c30e823493de8e84168 /src/gtkext/gtkbufferdisplay.c | |
parent | 1b5d39bfbc48c33a0ea0924b60e48448c8b45dd4 (diff) |
Rewritten the line buffers using generators and on-demand building to save memory.
Diffstat (limited to 'src/gtkext/gtkbufferdisplay.c')
-rw-r--r-- | src/gtkext/gtkbufferdisplay.c | 1104 |
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; + +} |