diff options
Diffstat (limited to 'src/glibext/bufferview.c')
-rw-r--r-- | src/glibext/bufferview.c | 1285 |
1 files changed, 1285 insertions, 0 deletions
diff --git a/src/glibext/bufferview.c b/src/glibext/bufferview.c new file mode 100644 index 0000000..e40715e --- /dev/null +++ b/src/glibext/bufferview.c @@ -0,0 +1,1285 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * bufferview.c - affichage d'une vue particulière d'un tampon de lignes + * + * Copyright (C) 2016-2019 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/>. + */ + + +#include "bufferview.h" + + +#include <assert.h> + + + +/* Vue d'un tampon pour code désassemblé (instance) */ +struct _GBufferView +{ + GObject parent; /* A laisser en premier */ + + GBufferCache *cache; /* Tampon du contenu visualisé */ + + segcnt_list *highlighted; /* Segments mis en évidence */ + + bool unrestricted; /* Validité des informations */ + GLineCursor *start; /* Première ligne intégrée */ + GLineCursor *end; /* Dernière ligne intégrée */ + + size_t first; /* Indice de la première ligne */ + size_t last; /* Indice de la dernière ligne */ + + GWidthTracker *tracker; /* Suivi des largeurs */ + +}; + +/* Vue d'un tampon pour code désassemblé (classe) */ +struct _GBufferViewClass +{ + GObjectClass parent; /* A laisser en premier */ + + /* Signaux */ + + void (* need_redraw) (GBufferView *); + +}; + + +/* Procède à l'initialisation d'une classe de vue de tampon. */ +static void g_buffer_view_class_init(GBufferViewClass *); + +/* Procède à l'initialisation d'une vue d'un tampon pour code. */ +static void g_buffer_view_init(GBufferView *); + +/* Supprime toutes les références externes. */ +static void g_buffer_view_dispose(GBufferView *); + +/* Procède à la libération totale de la mémoire. */ +static void g_buffer_view_finalize(GBufferView *); + +/* Accompagne une variation de la quantité de lignes du tampon. */ +static void on_buffer_cache_size_changed(const GBufferCache *, bool, size_t, size_t, GBufferView *); + +/* Calcule la position idéale de curseur pour un point donné. */ +bool _g_buffer_view_compute_caret_full(GBufferView *, gint, GBufferLine *, size_t, const GDisplayOptions *, const line_width_summary *, cairo_rectangle_int_t *, GLineCursor **); + +/* Déplace le curseur au sein d'une vue de tampon. */ +static bool _g_buffer_view_move_caret(GBufferView *, const GBufferLine *, size_t, cairo_rectangle_int_t *, bool, GdkScrollDirection, const GDisplayOptions *, const line_width_summary *); + + +/* Fournit la ligne présente à une ordonnée donnée. */ +static GBufferLine *g_buffer_view_find_line_at(GBufferView *, gint, size_t *); + + + + + + + +/* Détermine le type de la vue d'un tampon pour code désassemblé. */ +G_DEFINE_TYPE(GBufferView, g_buffer_view, G_TYPE_OBJECT); + + +/****************************************************************************** +* * +* Paramètres : class = classe de composant GTK à initialiser. * +* * +* Description : Procède à l'initialisation d'une classe de vue de tampon. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_buffer_view_class_init(GBufferViewClass *class) +{ + GObjectClass *object; /* Autre version de la classe */ + + object = G_OBJECT_CLASS(class); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_buffer_view_dispose; + object->finalize = (GObjectFinalizeFunc)g_buffer_view_finalize; + + /* Sigaux */ + + g_signal_new("need-redraw", + G_TYPE_BUFFER_VIEW, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(GBufferViewClass, need_redraw), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + +} + + +/****************************************************************************** +* * +* Paramètres : view = composant GLib à initialiser. * +* * +* Description : Procède à l'initialisation d'une vue d'un tampon pour code. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_buffer_view_init(GBufferView *view) +{ + view->cache = NULL; + + view->highlighted = NULL; + + /** + * Inversion du statut pour forcer l'actualisation lors de la création. + */ + view->unrestricted = false; + + view->start = NULL; + view->end = NULL; + + view->first = 0; + view->last = 0; + + view->tracker = NULL; + +} + + +/****************************************************************************** +* * +* Paramètres : view = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_buffer_view_dispose(GBufferView *view) +{ + g_clear_object(&view->cache); + + g_clear_object(&view->start); + g_clear_object(&view->end); + + g_clear_object(&view->tracker); + + G_OBJECT_CLASS(g_buffer_view_parent_class)->dispose(G_OBJECT(view)); + +} + + +/****************************************************************************** +* * +* Paramètres : view = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_buffer_view_finalize(GBufferView *view) +{ + if (view->highlighted != NULL) + unref_segment_content_list(view->highlighted); + + G_OBJECT_CLASS(g_buffer_view_parent_class)->finalize(G_OBJECT(view)); + +} + + +/****************************************************************************** +* * +* Paramètres : buffer = tampon à représenter à l'écran. * +* highlighted = gestionnaire de surbrillance pour segments. * +* * +* Description : Crée une nouvelle vue d'un tampon pour code désassemblé. * +* * +* Retour : Composant GTK créé. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GBufferView *g_buffer_view_new(GBufferCache *cache, segcnt_list *highlighted) +{ + GBufferView *result; /* Composant à retourner */ + + result = g_object_new(G_TYPE_BUFFER_VIEW, NULL); + + result->cache = cache; + g_object_ref_sink(G_OBJECT(cache)); + + g_buffer_view_restrict(result, NULL, NULL); + + g_signal_connect(cache, "size-changed", G_CALLBACK(on_buffer_cache_size_changed), result); + + if (highlighted != NULL) + { + ref_segment_content_list(highlighted); + result->highlighted = highlighted; + } + else + result->highlighted = init_segment_content_list(); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : cache = tampon de lignes cohérentes à manipuler. * +* added = indication sur la variation de la taille du tampon. * +* index = indice de la première ligne à traiter. * +* count = nombre de lignes à traiter. * +* view = vue active du tampon de lignes concerné. * +* * +* Description : Accompagne une variation de la quantité de lignes du tampon. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void on_buffer_cache_size_changed(const GBufferCache *cache, bool added, size_t index, size_t count, GBufferView *view) +{ + //size_t i; /* Boucle de parcours */ + //GBufferLine *line; /* Ligne à manipuler */ + //const vmpa2t *addr; /* Localisation de ligne */ + + /** + * Il n'y a pas besoin de verrou ici car la fonction est appelée directement par le tampon. + * D'autre part, on considère qu'il y a toujours une ligne aux adresses de borne, si la vue est bornée. + */ + + if (added) + { + if (view->unrestricted) + view->last += count; + + else + { +#if 0 + + /* Avant la zone représentée ? */ + if (index < view->first) + { + view->first += count; + view->last += count; + } + + /* Juste avant la zone représentée ? */ + else if (view->first == index) + for (i = 0; i < count; i++) + { + g_buffer_cache_get_line_addr(const GBufferCache *, size_t, gint, vmpa2t *); + + line = g_code_buffer_find_line_by_index(buffer, index + i); + addr = get_mrange_addr(g_buffer_line_get_range(line)); + + if (cmp_vmpa(&view->start, addr) == 0) + { + view->first++; + view->last++; + } + else + break; + + } + + /* Dans la zone représentée ? */ + else if (view->first < index && index <= view->last) + view->last += count; + + /* Juste après la vue représentée ? */ + else if ((view->last + 1) == index) + for (i = 0; i < count; i++) + { + g_buffer_cache_get_line_addr(const GBufferCache *, size_t, gint, vmpa2t *); + + line = g_code_buffer_find_line_by_index(buffer, index + i); + addr = get_mrange_addr(g_buffer_line_get_range(line)); + + if (cmp_vmpa(&view->end, addr) == 0) + view->last++; + else + break; + + } + + //g_width_tracker_update_added(view->int_tracker, index, count); +#endif + + } + + } + + else + { + if (view->unrestricted) + view->last -= count; + + else + { + /* Avant la zone représentée ? */ + if (index <= view->first) + { + view->first -= count; + view->last -= count; + } + + /* Dans la zone représentée ? */ + else if (view->first < index && index <= view->last) + view->last -= count; + + } + + //g_width_tracker_update_deleted(view->int_tracker, index, index + count - 1); + + } + + //g_signal_emit_by_name(view, "need-redraw"); + +} + + +/****************************************************************************** +* * +* Paramètres : view = visualisateur à consulter. * +* * +* Description : Fournit le tampon de code lié à un visualisateur donné. * +* * +* Retour : Tampon de code associé au gestionnaire d'affichage. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GBufferCache *g_buffer_view_get_cache(const GBufferView *view) +{ + GBufferCache *result; /* Instance à retourner */ + + result = view->cache; + + g_object_ref(G_OBJECT(result)); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : view = visualisateur à mettre à jour. * +* first = première ligne à imprimer. * +* last = première ligne hors cadre. * +* * +* Description : Restreint le champ d'application de l'affichage. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_buffer_view_restrict(GBufferView *view, GLineCursor *start, GLineCursor *end) +{ + bool state; /* Nouvel état à proclamer */ + GWidthTracker *template; /* Suivi déjà en place */ + + state = (start == NULL || end == NULL); + + if (view->unrestricted != state) + { + view->unrestricted = state; + + template = g_buffer_cache_get_width_tracker(view->cache); + + /* Vérification pour le cas particulier du démarrage */ + if (view->tracker != NULL) + g_object_unref(G_OBJECT(view->tracker)); + + if (view->unrestricted) + { + view->first = 0; + view->last = g_buffer_cache_count_lines(view->cache) - 1; + + view->tracker = template; + + } + + else + { + g_object_ref_sink(G_OBJECT(start)); + g_object_ref_sink(G_OBJECT(end)); + + view->start = start; + view->end = end; + + view->first = g_buffer_cache_find_index_by_cursor(view->cache, start, true); + view->last = g_buffer_cache_find_index_by_cursor(view->cache, end, false); + + view->tracker = g_width_tracker_new_restricted(template, view->first, view->last); + + g_object_unref(G_OBJECT(template)); + + } + + } + +} + + +/****************************************************************************** +* * +* Paramètres : view = visualisateur à consulter. * +* first = première ligne à imprimer ou NULL. [OUT] * +* last = première ligne hors cadre ou NULL. [OUT] * +* * +* Description : Indique le champ d'application de l'affichage. * +* * +* Retour : true si des restrictions particulières sont en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_buffer_view_get_restrictions(const GBufferView *view, GLineCursor **start, GLineCursor **end) +{ + if (!view->unrestricted) + { + if (start != NULL) + { + *start = view->start; + g_object_ref(G_OBJECT(*start)); + } + + if (end != NULL) + { + *end = view->end; + g_object_ref(G_OBJECT(*end)); + } + + } + else + { + if (start != NULL) *start = NULL; + if (end != NULL) *end = NULL; + } + + return !view->unrestricted; + +} + + + + + + + + + +/****************************************************************************** +* * +* Paramètres : view = visualisation à consulter. * +* options = règles d'affichage des colonnes modulables. * +* * +* Description : Fournit la largeur requise par une visualisation. * +* * +* Retour : Dimension calculée. * +* * +* Remarques : - * +* * +******************************************************************************/ + +gint g_buffer_view_get_width(GBufferView *view, const GDisplayOptions *options) +{ + gint result; /* Taille à retourner */ + + result = g_buffer_cache_get_text_position(view->cache); + + result += g_width_tracker_get_width(view->tracker, options); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : view = visualisation à consulter. * +* options = règles d'affichage des colonnes modulables. * +* * +* Description : Fournit la largeur requise pour dépasser les marges gauches. * +* * +* Retour : Dimension calculée. * +* * +* Remarques : - * +* * +******************************************************************************/ + +gint g_buffer_view_get_margin(GBufferView *view, const GDisplayOptions *options) +{ + gint result; /* Taille à retourner */ + + result = g_buffer_cache_get_text_position(view->cache); + + result += g_width_tracker_get_margin(view->tracker, options); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : view = visualisation à consulter. * +* * +* Description : Fournit la hauteur requise par une visualisation. * +* * +* Retour : Dimension calculée. * +* * +* Remarques : - * +* * +******************************************************************************/ + +gint g_buffer_view_get_height(const GBufferView *view) +{ + gint result; /* Taille à retourner */ + + result = g_buffer_cache_get_line_height(view->cache); + + result *= (view->last - view->first + 1); + + return result; + +} + + + + + + + + + + + + + +/****************************************************************************** +* * +* Paramètres : view = vue de tampon à mettre à jour. * +* x = abscisse proposée pour le nouvel emplacement. * +* y = ordonnée proposée pour le nouvel emplacement. * +* options = règles d'affichage des colonnes modulables. * +* offsets = décalages supplémentaires à appliquer. * +* caret = position du curseur à construire. [OUT] * +* cursor = emplacement correspondant à cette position. [OUT] * +* * +* Description : Calcule la position idéale de curseur pour un point donné. * +* * +* Retour : true si les deux derniers arguments ont pu être constitués. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_buffer_view_compute_caret_full(GBufferView *view, gint x, gint y, const GDisplayOptions *options, const line_width_summary *offsets, cairo_rectangle_int_t *caret, GLineCursor **cursor) +{ + bool result; /* Bilan à retourner */ + gint lheight; /* Hauteur d'une ligne */ + size_t index; /* Indice de ligne de tampon */ + GBufferLine *line; /* Ligne à la position courante*/ + + result = false; + + /* Détermination de la ligne courante */ + + lheight = g_buffer_cache_get_line_height(view->cache); + index = y / lheight; + + index += view->first; + + if (index > view->last) + goto gbvccf_done; + + line = g_buffer_cache_find_line_by_index(view->cache, index); + + assert(line != NULL); + + /* Calcul d'une position */ + + result = _g_buffer_view_compute_caret_full(view, x, line, index, options, offsets, caret, cursor); + + g_object_unref(G_OBJECT(line)); + + gbvccf_done: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : view = vue de tampon à mettre à jour. * +* x = abscisse proposée pour le nouvel emplacement. * +* line = ligne correspondant à la position. * +* index = indice de cette même ligne dans le tampon. * +* options = règles d'affichage des colonnes modulables. * +* offsets = décalages supplémentaires à appliquer. * +* caret = position du curseur à construire. [OUT] * +* cursor = emplacement correspondant à cette position. [OUT] * +* * +* Description : Calcule la position idéale de curseur pour un point donné. * +* * +* Retour : true si les deux derniers arguments ont pu être constitués. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool _g_buffer_view_compute_caret_full(GBufferView *view, gint x, GBufferLine *line, size_t index, const GDisplayOptions *options, const line_width_summary *offsets, cairo_rectangle_int_t *caret, GLineCursor **cursor) +{ + bool result; /* Bilan à retourner */ + gint text_pos; /* Abscisse de départ du texte */ + line_width_summary summary; /* Résumé concis des largeurs */ + gint base; /* Position absolue de segment */ + bool status; /* Bilan de la localisation */ + gint lheight; /* Hauteur d'une ligne */ + + result = false; + + /* Zone d'intervention bornée ! */ + + text_pos = g_buffer_cache_get_text_position(view->cache); + + if (x < text_pos) + goto gbvccf_done; + + /* Calcul d'une position */ + + g_width_tracker_get_local_width_summary(view->tracker, index, &summary); + + x -= text_pos; + + status = g_buffer_line_get_coord_at(line, &summary, options, offsets, &base, &x, + GDK_SCROLL_LEFT, true, (col_coord_t []) { { 0 } }); + + if (!status) + goto gbvccf_done; + + /* Transmission des informations */ + + lheight = g_buffer_cache_get_line_height(view->cache); + + caret->x = text_pos + base + x; + + caret->y = (index - view->first) * lheight; + + caret->width = 2; + caret->height = lheight; + + g_buffer_cache_get_line_cursor(view->cache, index, caret->x, cursor); + + result = true; + + gbvccf_done: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : view = vue de tampon à manipuler. * +* line = ligne à venir consulter. * +* index = indice de cette même ligne dans le tampon. * +* caret = position du curseur à faire évoluer. * +* ctrl = indique la demande d'un parcours rapide. * +* dir = direction du parcours. * +* options = règles d'affichage des colonnes modulables. * +* offsets = décalages supplémentaires à appliquer. * +* * +* Description : Déplace le curseur au sein d'une vue de tampon. * +* * +* Retour : true si un déplacement a été effectué, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool _g_buffer_view_move_caret(GBufferView *view, const GBufferLine *line, size_t index, cairo_rectangle_int_t *caret, bool ctrl, GdkScrollDirection dir, const GDisplayOptions *options, const line_width_summary *offsets) +{ + bool result; /* Bilan à retourner */ + gint text_pos; /* Abscisse de départ du texte */ + gint offset; /* Point de travail modifiable */ + line_width_summary summary; /* Résumé concis des largeurs */ + gint base; /* Position absolue de segment */ + col_coord_t coord; /* Coordonnées en interne */ + line_segment *segment; /* Bribe de texte trouvée */ + + + result = false; + + /* Zone d'intervention bornée ! */ + + text_pos = g_buffer_cache_get_text_position(view->cache); + + if (caret->x < text_pos) + goto gbvmc_done; + + offset = caret->x - text_pos; + + g_width_tracker_get_local_width_summary(view->tracker, index, &summary); + + /* Déplacement au sein du segment courant ? */ + + result = g_buffer_line_get_coord_at(line, &summary, options, offsets, &base, &offset, dir, false, &coord); + + if (result) + { + segment = g_buffer_line_get_segment_from_coord(line, &coord); + + result = move_caret_on_line_segment(segment, &offset, ctrl, dir); + + release_line_segment(segment); + + } + + /* Tentative de déplacement chez le segment voisin ? */ + + if (!result) + { + base = 0; + + result = g_buffer_line_find_near_coord(line, &coord, &summary, options, offsets, dir, &offset); + + } + + /* Mise à jour éventuelle */ + + if (result) + caret->x = text_pos + base + offset; + + gbvmc_done: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : view = vue de tampon à mettre à jour. * +* ctrl = indique la demande d'un parcours rapide. * +* dir = direction du parcours. * +* options = règles d'affichage des colonnes modulables. * +* offsets = décalages supplémentaires à appliquer. * +* caret = position du curseur à faire évoluer. [OUT] * +* cursor = emplacement correspondant à cette position. [OUT] * +* * +* Description : Déplace le curseur au sein d'une vue de tampon. * +* * +* Retour : true si les deux derniers arguments ont pu être constitués. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_buffer_view_move_caret(GBufferView *view, bool ctrl, GdkScrollDirection dir, const GDisplayOptions *options, const line_width_summary *offsets, cairo_rectangle_int_t *caret, GLineCursor **cursor) +{ + bool result; /* Bilan à retourner */ + size_t index; /* Indice de ligne de tampon */ + GBufferLine *line; /* Ligne sous le pointeur */ + size_t first; /* Première ligne intégrée */ + size_t last; /* Dernière ligne intégrée */ + GBufferLine *other; /* Ligne voisine à visiter */ + bool moved; /* Mémorisation d'une évolut° */ + gint text_pos; /* Abscisse de départ du texte */ + + result = false; + + line = g_buffer_view_find_line_at(view, caret->y, &index); + if (line == NULL) goto gbvmc_done; + + first = view->first; + last = view->last; + + switch (dir) + { + case GDK_SCROLL_UP: + + if (index > first) + { + index--; + + other = g_buffer_cache_find_line_by_index(view->cache, index); + assert(other != NULL); + + result = _g_buffer_view_compute_caret_full(view, caret->x, other, index, + options, offsets, caret, cursor); + + g_object_unref(G_OBJECT(other)); + + } + + break; + + case GDK_SCROLL_DOWN: + + if (index < last) + { + index++; + + other = g_buffer_cache_find_line_by_index(view->cache, index); + assert(other != NULL); + + result = _g_buffer_view_compute_caret_full(view, caret->x, other, index, + options, offsets, caret, cursor); + + g_object_unref(G_OBJECT(other)); + + } + + break; + + case GDK_SCROLL_LEFT: + + moved = _g_buffer_view_move_caret(view, line, index, caret, ctrl, GDK_SCROLL_LEFT, options, offsets); + + if (moved) + { + g_buffer_cache_get_line_cursor(view->cache, index, caret->x, cursor); + result = true; + } + + else if (index > first) + { + index--; + + other = g_buffer_cache_find_line_by_index(view->cache, index); + assert(other != NULL); + + result = _g_buffer_view_compute_caret_full(view, INT_MAX, other, index, + options, offsets, caret, cursor); + + g_object_unref(G_OBJECT(other)); + + } + + break; + + case GDK_SCROLL_RIGHT: + + moved = _g_buffer_view_move_caret(view, line, index, caret, ctrl, GDK_SCROLL_RIGHT, options, offsets); + + if (moved) + { + g_buffer_cache_get_line_cursor(view->cache, index, caret->x, cursor); + result = true; + } + + else if (index < last) + { + index++; + + text_pos = g_buffer_cache_get_text_position(view->cache); + + other = g_buffer_cache_find_line_by_index(view->cache, index); + assert(other != NULL); + + result = _g_buffer_view_compute_caret_full(view, text_pos, other, index, + options, offsets, caret, cursor); + + g_object_unref(G_OBJECT(other)); + + } + + break; + + default: /* GDK_SCROLL_SMOOTH */ + break; + + } + + g_object_unref(G_OBJECT(line)); + + gbvmc_done: + + return result; + +} + + + + + + + + +/****************************************************************************** +* * +* Paramètres : view = vue de tampon à mettre à jour. * +* x = abscisse de la zone principale à traiter. * +* y = ordonnée de la zone principale à traiter. * +* options = règles d'affichage des colonnes modulables. * +* offsets = décalages supplémentaires à appliquer. * +* * +* Description : Trouve le créateur à l'origine d'un emplacement donné. * +* * +* Retour : Créateur trouvé ou NULL si aucun. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GObject *g_buffer_view_find_creator(GBufferView *view, gint x, gint y, const GDisplayOptions *options, const line_width_summary *offsets) +{ + GObject *result; /* Trouvaille à faire remonter */ + gint text_pos; /* Abscisse de départ du texte */ + gint lheight; /* Hauteur d'une ligne */ + size_t index; /* Indice de ligne de tampon */ + GBufferLine *line; /* Ligne à la position courante*/ + line_width_summary summary; /* Résumé concis des largeurs */ + + result = NULL; + + /* Zone d'intervention bornée ! */ + + text_pos = g_buffer_cache_get_text_position(view->cache); + + if (x < text_pos) + goto gbvfc_done; + + /* Détermination de la ligne concernée */ + + lheight = g_buffer_cache_get_line_height(view->cache); + index = y / lheight; + + index += view->first; + + if (index > view->last) + goto gbvfc_done; + + line = g_buffer_cache_find_line_by_index(view->cache, index); + + assert(line != NULL); + + /* Recherche d'un segment et de son empreinte */ + + g_width_tracker_get_local_width_summary(view->tracker, index, &summary); + + x -= text_pos; + + result = g_buffer_line_get_creator_at(line, &summary, options, offsets, + (gint []) { 0 }, &x, GDK_SCROLL_LEFT, false); + + g_object_unref(G_OBJECT(line)); + + gbvfc_done: + + return result; + +} + + + + + + + + +/****************************************************************************** +* * +* Paramètres : view = vue de tampon à mettre à jour. * +* * +* Description : Supprime toute mise en évidence de segments. * +* * +* Retour : true si un besoin d'actualisation d'affichage se fait sentir.* +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_buffer_view_unhighlight_segments(GBufferView *view) +{ + bool result; /* Bilan d'action à renvoyer */ + + result = reset_segment_content_list(view->highlighted); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : view = vue de tampon à mettre à jour. * +* x = abscisse de la zone principale à traiter. * +* y = ordonnée de la zone principale à traiter. * +* options = règles d'affichage des colonnes modulables. * +* offsets = décalages supplémentaires à appliquer. * +* * +* Description : Surligne tous les segments similaires à celui sous la souris.* +* * +* Retour : true si un besoin d'actualisation d'affichage se fait sentir.* +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_buffer_view_highlight_segments(GBufferView *view, gint x, gint y, const GDisplayOptions *options, const line_width_summary *offsets) +{ + bool result; /* Besoin à faire remonter */ + gint text_pos; /* Abscisse de départ du texte */ + gint lheight; /* Hauteur d'une ligne */ + size_t index; /* Indice de ligne de tampon */ + GBufferLine *line; /* Ligne à la position courante*/ + line_width_summary summary; /* Résumé concis des largeurs */ + line_segment *segment; /* Segment sélectionnable */ + + /* Réinitialisation */ + + if (view->highlighted != NULL) + result = g_buffer_view_unhighlight_segments(view); + else + result = false; + + /* Zone d'intervention bornée ! */ + + text_pos = g_buffer_cache_get_text_position(view->cache); + + if (x < text_pos) + goto gbvhs_done; + + /* Détermination de la ligne concernée */ + + lheight = g_buffer_cache_get_line_height(view->cache); + index = y / lheight; + + index += view->first; + + if (index > view->last) + goto gbvhs_done; + + line = g_buffer_cache_find_line_by_index(view->cache, index); + + assert(line != NULL); + + /* Recherche d'un segment et de son empreinte */ + + g_width_tracker_get_local_width_summary(view->tracker, index, &summary); + + x -= text_pos; + + segment = g_buffer_line_get_segment_at(line, &summary, options, offsets, + (gint []) { 0 }, &x, GDK_SCROLL_LEFT, true); + + g_object_unref(G_OBJECT(line)); + + /* Conclusion */ + + if (segment != NULL) + { + result |= add_segment_content_to_selection_list(view->highlighted, segment); + release_line_segment(segment); + } + + if (result) + g_signal_emit_by_name(view, "need-redraw"); + + gbvhs_done: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : view = visualisation à représenter. * +* cr = contexte graphique dédié à la procédure. * +* virt_y = ordonnée réelle du point 0 à l'écran. * +* area = position et surface à traiter. * +* options = règles d'affichage des colonnes modulables. * +* offsets = décalages supplémentaires à appliquer. * +* selected = ordonnée d'une ligne sélectionnée ou NULL. * +* scale = échelle appliquée à la surface de rendu. * +* export = indique si la vue est en cours d'exportation. * +* * +* Description : Imprime la visualisation du tampon de lignes quelconques. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_buffer_view_draw(const GBufferView *view, cairo_t *cr, gint virt_y, const cairo_rectangle_int_t *area, const GDisplayOptions *options, const line_width_summary *offsets, gint *selected, double scale, bool export) +{ + gint line_height; /* Hauteur d'une ligne */ + gint cr_y; /* Ordonnée pour le dessin */ + size_t first; /* Première ligne visée */ + size_t last; /* Dernière ligne visée */ + segcnt_list *highlighted; /* Segments mis en évidence */ + + line_height = g_buffer_cache_get_line_height(view->cache) * scale; + + line_height = MAX(line_height, 1); + + /* Indice et point de départ */ + + first = view->first; + first += (virt_y / line_height); + + cr_y = area->y - (virt_y % line_height); + + /* Indice de d'arrivée */ + + last = first + (area->height / line_height); + if (area->height % line_height > 0) last++; + + last = MIN(last, view->last); + + /* Phase de dessin ! */ + + /** + * Le contexte n'est pas sauvegardé avant modification ici car + * l'appelant l'a fait pour nous avant sa translation sur les abscisses. + */ + + cairo_translate(cr, 0, cr_y); + + if (selected != NULL) + *selected -= cr_y; + + if (export) + highlighted = init_segment_content_list(); + else + highlighted = view->highlighted; + + g_buffer_cache_draw(view->cache, cr, first, last, area, options, offsets, selected, highlighted); + + if (export) + unref_segment_content_list(highlighted); + +} + + + + + + + + + + + + + + + +/****************************************************************************** +* * +* Paramètres : view = visualisation à consulter. * +* y = ordonnée comprise dans la ligne recherchée. * +* idx = indice de la ligne trouvée ou NULL. [OUT] * +* * +* Description : Fournit la ligne présente à une ordonnée donnée. * +* * +* Retour : Ligne retrouvée ou NULL si aucune. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static GBufferLine *g_buffer_view_find_line_at(GBufferView *view, gint y, size_t *idx) +{ + GBufferLine *result; /* Ligne trouvée à retourner */ + gint lheight; /* Hauteur d'une ligne */ + size_t index; /* Indice attendu */ + + lheight = g_buffer_cache_get_line_height(view->cache); + index = y / lheight; + + index += view->first; + + if (index <= view->last) + result = g_buffer_cache_find_line_by_index(view->cache, index); + else + result = NULL; + + if (result != NULL && idx != NULL) + *idx = index; + + return result; + +} + + + + + + + + + + + + + + + +/****************************************************************************** +* * +* Paramètres : view = visualisation à consulter. * +* cursor = emplacement à présenter à l'écran. * +* code = s'arrête si possible à une ligne avec code. * +* x = position horizontale au sein du composant. [OUT] * +* y = position verticale au sein du composant. [OUT] * +* * +* Description : Indique la position d'affichage d'une adresse donnée. * +* * +* Retour : true si l'adresse fait partie du composant, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_buffer_view_get_cursor_coordinates(GBufferView *view, const GLineCursor *cursor, bool code, gint *x, gint *y) +{ + bool result; /* Bilan à retourner */ + + result = g_buffer_cache_get_cursor_coordinates(view->cache, cursor, view->first, view->last, code, x, y); + + return result; + +} |