diff options
author | Cyrille Bagard <nocbos@gmail.com> | 2016-05-01 01:35:26 (GMT) |
---|---|---|
committer | Cyrille Bagard <nocbos@gmail.com> | 2016-05-01 01:35:26 (GMT) |
commit | ef68a3dd8ff259200ca7f088eecc9ce35e7ffe8f (patch) | |
tree | f89cccbe3d0ac421b41cc49a28bee32e8903e45a | |
parent | 89ceb1e27afed0bac789e33c2f10eade01747d88 (diff) |
Handled all width measures per view in a dedicated manager.
-rw-r--r-- | ChangeLog | 28 | ||||
-rw-r--r-- | src/glibext/Makefile.am | 6 | ||||
-rw-r--r-- | src/glibext/gbufferline.c | 964 | ||||
-rw-r--r-- | src/glibext/gbufferline.h | 50 | ||||
-rw-r--r-- | src/glibext/gbufferview.c | 1330 | ||||
-rw-r--r-- | src/glibext/gbufferview.h | 112 | ||||
-rw-r--r-- | src/glibext/gcodebuffer.c | 2245 | ||||
-rw-r--r-- | src/glibext/gcodebuffer.h | 89 | ||||
-rw-r--r-- | src/glibext/gwidthtracker.c | 830 | ||||
-rw-r--r-- | src/glibext/gwidthtracker.h | 85 | ||||
-rw-r--r-- | src/gtkext/gtkbufferview-int.h | 2 | ||||
-rw-r--r-- | src/gtkext/gtkbufferview.c | 8 | ||||
-rw-r--r-- | src/gtkext/gtkbufferview.h | 2 |
13 files changed, 3395 insertions, 2356 deletions
@@ -1,3 +1,31 @@ +16-05-01 Cyrille Bagard <nocbos@gmail.com> + + * src/glibext/Makefile.am: + Add the 'gbufferview.[ch]' and 'gwidthtracker.[ch]' files to libglibext_la_SOURCES + + * src/glibext/gbufferline.c: + * src/glibext/gbufferline.h: + Move and clean code. + + * src/glibext/gbufferview.c: + * src/glibext/gbufferview.h: + New entries: extract all buffer view related functions into a separate file. + + * src/glibext/gcodebuffer.c: + * src/glibext/gcodebuffer.h: + Move and clean code. + + * src/glibext/gwidthtracker.c: + * src/glibext/gwidthtracker.h: + New entries: handle all width measures per view in a dedicated manager. + + * src/gtkext/gtkbufferview-int.h: + * src/gtkext/gtkbufferview.c: + Remove the useless reference to the current buffer. + + * src/gtkext/gtkbufferview.h: + Update the included header name. + 16-04-29 Cyrille Bagard <nocbos@gmail.com> * src/gtkext/gtkbufferview.c: diff --git a/src/glibext/Makefile.am b/src/glibext/Makefile.am index 192587d..a88b7d9 100644 --- a/src/glibext/Makefile.am +++ b/src/glibext/Makefile.am @@ -11,10 +11,12 @@ libglibext_la_SOURCES = \ gbinportion.h gbinportion.c \ gbufferline.h gbufferline.c \ gbuffersegment.h gbuffersegment.c \ + gbufferview.h gbufferview.c \ gcodebuffer.h gcodebuffer.c \ gnhash.h gnhash.c \ - signal.h signal.c \ - proto.h + gwidthtracker.h gwidthtracker.c \ + proto.h \ + signal.h signal.c libglibext_la_LDFLAGS = diff --git a/src/glibext/gbufferline.c b/src/glibext/gbufferline.c index 65e73d0..7e518cc 100644 --- a/src/glibext/gbufferline.c +++ b/src/glibext/gbufferline.c @@ -911,304 +911,6 @@ void g_buffer_line_fill_for_instr(GBufferLine *line, MemoryDataSize psize, Memor /****************************************************************************** * * -* Paramètres : line = ligne à venir consulter. * -* max_widths = largeurs de colonne à respecter. * -* display = règles d'affichage des colonnes modulables. * -* base = position jusqu'au segment trouvé. [OUT] * -* offset = position à la colonne visée. [OUT] * -* dir = direction d'un éventuel déplacement en cours. * -* force = accepte les segments en bordure au pire. * -* * -* Description : Donne le segment présent à une abscisse donnée. * -* * -* Retour : Segment trouvé ou NULL si hors borne. * -* * -* Remarques : - * -* * -******************************************************************************/ - -GBufferSegment *g_buffer_line_get_segment_at(const GBufferLine *line, const gint max_widths[BLC_COUNT], const bool *display, gint *base, gint *offset, GdkScrollDirection dir, bool force) -{ - GBufferSegment *result; /* Trouvaille à retourner */ - BufferLineColumn last; /* Dernière colonne remplie */ - gint last_base; /* Dernière abscisse associée */ - BufferLineColumn i; /* Boucle de parcours */ - gint width; /* Largeur d'une colonne donnée*/ - - gint limit; - - gint consumed; /* Distance vers le segment */ - gint old_base; /* Somme de toutes les largeurs*/ - - result = NULL; - - *base = 0; - - last = BLC_COUNT; - - //sum = 0; - - printf("---------------\n"); - - /* On cible déjà la colonne idéale */ - - for (i = 0; i < BLC_COUNT; i++) - { - printf(" @ (%d) x=%d width=%d max=%d display ? %d\n", - i, *offset, get_column_width(&line->columns[i]), max_widths[i], i < BLC_DISPLAY ? display[i] : true); - - - if (i < BLC_DISPLAY && !display[i]) continue; - - /* Mémorisation de la dernière colonne contenant quelque chose... */ - if (get_column_width(&line->columns[i]) > 0) - { - last = i; - last_base = *base; - } - - if (i < line->merge_start) - { - width = g_buffer_line_compute_max_width(line, i, max_widths); - - if ((i + 1) < BLC_COUNT) limit = width + COL_MARGIN / 2; - else limit = width; - - if (*offset <= limit) break; - else - { - *offset -= width + COL_MARGIN; - *base += width + COL_MARGIN; - } - - } - else - { - width = get_column_width(&line->columns[i]); - - if (*offset <= width) break; - else - { - *offset -= width; - *base += width; - } - - } - - - } - - printf(" -- get segment at -- found index %u (max=%u)\n", i, BLC_COUNT); - - - printf(" last seen = %u\n", last); - - - - - - if (i < BLC_COUNT) - { - - printf(" -- width @ %u : %d\n", i, get_column_width(&line->columns[i])); - - if (get_column_width(&line->columns[i]) > 0) - { - /** - * Si la position était au milieu d'une marge, la sélection a pu pousser - * jusqu'à la colonne suivante, plus proche. - * Relativment à la base de cette dernière, la position est donc devenue négative. - */ - if (*offset < 0) *offset = 0; - - result = get_segment_at(&line->columns[i], offset, dir, &consumed); - *base += consumed; - } - - /* La position fournie tombe dans une colonne vide ! */ - else - { - if (force || get_column_width(&line->columns[i]) == 0) - { - result = NULL; - *offset = 0; - - old_base = *base; - - for (i++; i < BLC_COUNT && result == NULL; i++) - { - printf(" -- update to col %u -- x = %d\n", i, *offset); - - if ((i - 1) < line->merge_start) - { - width = g_buffer_line_compute_max_width(line, i - 1, max_widths); - *base += (width + COL_MARGIN); - } - else - *base += get_column_width(&line->columns[i - 1]); - - result = get_first_segment(&line->columns[i]); - - } - - printf(" -- final x = %d (result=%p)\n", *offset, result); - - if (result == NULL) - { - *base = old_base; - goto use_right_border; - } - - } - - } - - } - - else /* if (i == BLC_COUNT) */ - { - if (force && last != BLC_COUNT) - { - use_right_border: - - result = get_last_segment(&line->columns[last]); - *base = last_base; - *offset = get_column_width(&line->columns[last]); - - } - else - result = NULL; - - } - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : line = ligne à venir consulter. * -* target = segment dont un voisin est à retourner. * -* max_widths = largeurs de colonne à respecter. * -* display = règles d'affichage des colonnes modulables. * -* dir = orientation des recherches. * -* offset = décalage pour amener à l'extrémité nouvelle. [OUT] * -* * -* Description : Fournit le segment voisin d'un autre segment identifié. * -* * -* Retour : Segment trouvé dans la ligne ou NULL. * -* * -* Remarques : - * -* * -******************************************************************************/ - -GBufferSegment *g_buffer_line_find_near_segment(const GBufferLine *line, GBufferSegment *target, const gint max_widths[BLC_COUNT], const bool *display, GdkScrollDirection dir, gint *offset) -{ - GBufferSegment *result; /* Trouvaille à retourner */ - BufferLineColumn i; /* Boucle de parcours #1 */ - bool displayed; /* Confort de lecture */ - BufferLineColumn k; /* Boucle de parcours #2 */ - - result = NULL; - - /* Recherche dans la colonne de départ */ - - for (i = 0; i < BLC_COUNT; i++) - if (column_has_segment(&line->columns[i], target, NULL)) - break; - - if (i == BLC_COUNT) return NULL; - - result = find_near_segment(&line->columns[i], target, dir); - if (result != NULL) return result; - - /* Recherche dans la direction des colonnes voisines */ - - if (result == NULL) - switch (dir) - { - case GDK_SCROLL_LEFT: - - /* Si on a atteint la première colonne sans trouver... */ - if (i == 0) break; - - /* On s'assure que la colonne précédente est visible et peuplée */ - for (; i > BLC_FIRST && result == NULL; i--) - { - displayed = (i <= BLC_DISPLAY ? display[i - 1] : true); - - if (displayed) - result = get_last_segment(&line->columns[i - 1]); - - } - - break; - - case GDK_SCROLL_RIGHT: - - /* Si on a atteint la dernière colonne sans trouver... */ - /*if (i == BLC_COUNT) break;*/ - - /* On s'assure que la colonne suivante est visible et peuplée */ - for (; (i + 1) < BLC_COUNT && result == NULL; i++) - { - displayed = ((i + 1) < BLC_DISPLAY ? display[i + 1] : true); - - if (displayed) - result = get_first_segment(&line->columns[i + 1]); - - } - - break; - - default: - break; - - } - - /* Calcul de la position finale */ - - if (result != NULL) - { - *offset = 0; - - for (k = 0; k < i; k++) - { - displayed = (k < BLC_DISPLAY ? display[k] : true); - - if (displayed) - { - *offset += g_buffer_line_compute_max_width(line, k, max_widths); - if (k < line->merge_start) *offset += COL_MARGIN; - } - - } - - switch (dir) - { - case GDK_SCROLL_LEFT: - *offset += get_column_width(&line->columns[i]); - break; - - case GDK_SCROLL_RIGHT: - /**offset += 0;*/ - break; - - default: - break; - - } - - } - - return result; - -} - - -/****************************************************************************** -* * * Paramètres : line = ligne à venir consulter. * * column = indice de la colonne visée par les recherches. * * * @@ -1456,111 +1158,97 @@ void g_buffer_line_delete_text(GBufferLine *line, BufferLineColumn first, Buffer /****************************************************************************** * * -* Paramètres : line = ligne à venir consulter/compléter. * -* manager = ligne de départ d'un groupe de ligne. * +* Paramètres : line = ligne à venir consulter. * * * -* Description : Retient les largeurs d'une ligne si maximales. * +* Description : Fournit la colonne à partir de laquelle une fusion opère. * * * -* Retour : - * +* Retour : Début de la première (et unique) zone globale. * * * * Remarques : - * * * ******************************************************************************/ -void g_buffer_line_update_max_widths(GBufferLine *line, GBufferLine *manager) +BufferLineColumn g_buffer_line_get_merge_start(const GBufferLine *line) { - BufferLineColumn i; /* Boucle de parcours */ - GBufferLine *old; /* Ancienne ligne associée */ - gint merged_width; /* Largeur cumulée avant fusion*/ - gint width; /* Largeur d'une colonne */ - - /* Réinitialisation ? */ + return line->merge_start; - if (line == manager) - { - assert(line->flags & BLF_WIDTH_MANAGER); +} - for (i = 0; i < BLC_COUNT; i++) - line->max_widths[i] = 0; - line->merged_width = 0; +/****************************************************************************** +* * +* Paramètres : line = ligne à venir compléter. * +* start = début de la première (et unique) zone globale. * +* * +* Description : Définit la colonne à partir de laquelle la fusion opère. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ - } +void g_buffer_line_start_merge_at(GBufferLine *line, BufferLineColumn start) +{ + if (start == BLC_LAST_USED) + line->merge_start = line->last_used; else - { - assert((line->flags & BLF_WIDTH_MANAGER) == 0); - - old = line->manager; - - g_object_ref(G_OBJECT(manager)); - line->manager = manager; - - if (old != NULL) - g_object_unref(G_OBJECT(old)); + line->merge_start = start; - } +} - /* Mises à jour */ - merged_width = 0; +/****************************************************************************** +* * +* Paramètres : line = ligne à venir compléter. * +* flag = propriété à intégrer. * +* * +* Description : Ajoute une propriété particulière à une ligne donnée. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ - for (i = 0; i < BLC_COUNT; i++) +void g_buffer_line_add_flag(GBufferLine *line, BufferLineFlags flag) +{ + if ((line->flags & flag) == 0) { - width = get_column_width(&line->columns[i]); - - if (i < line->merge_start) - manager->max_widths[i] = MAX(manager->max_widths[i], width); - - if (i >= BLC_DISPLAY) - { - merged_width += width; - - if (i < line->merge_start && (i + 1) < BLC_COUNT) - merged_width += COL_MARGIN; + g_signal_emit_by_name(line, "flip-flag", line->flags, flag); - } + line->flags |= flag; } - if (line->merge_start != BLC_COUNT) - manager->merged_width = MAX(manager->merged_width, merged_width); - } /****************************************************************************** * * -* Paramètres : line = ligne à venir consulter. * +* Paramètres : line = ligne à venir consulter. * * * -* Description : Renvoie la ligne comptabilisant les largeurs pour un groupe. * +* Description : Renseigne sur les propriétés particulières liées à une ligne.* * * -* Retour : Ligne considérée comme la gestionnaire d'un ensemble. * +* Retour : Propriétés intégrées. * * * * Remarques : - * * * ******************************************************************************/ -GBufferLine *g_buffer_line_get_width_manager(GBufferLine *line) +BufferLineFlags g_buffer_line_get_flags(const GBufferLine *line) { - GBufferLine *result; /* Gestionnaire à retourner */ - - if (line->flags & BLF_WIDTH_MANAGER) - result = line; - else - result = line->manager; - - return result; + return line->flags; } /****************************************************************************** * * -* Paramètres : line = ligne à venir consulter. * -* max_widths = tableau résumant les largeurs maximales. [OUT]* -* merged_width = largeur maximale en cas de fusion. |OUT] * +* Paramètres : line = ligne à venir compléter. * +* flag = propriété à supprimer. * * * -* Description : Filtre des largeurs de lignes et ne garde que les maximales. * +* Description : Retire une propriété particulière à une ligne donnée. * * * * Retour : - * * * @@ -1568,190 +1256,492 @@ GBufferLine *g_buffer_line_get_width_manager(GBufferLine *line) * * ******************************************************************************/ -void g_buffer_line_apply_max_widths(GBufferLine *line, gint *max_widths, gint *merged_width) +void g_buffer_line_remove_flag(GBufferLine *line, BufferLineFlags flag) { - GBufferLine *manager; /* Gestionnaire de groupe */ - BufferLineColumn i; /* Boucle de parcours */ - - manager = g_buffer_line_get_width_manager(line); + if ((line->flags & flag) != 0) + { + g_signal_emit_by_name(line, "flip-flag", line->flags, flag); - for (i = 0; i < BLC_COUNT; i++) - max_widths[i] = MAX(manager->max_widths[i], max_widths[i]); + line->flags &= ~flag; - *merged_width = MAX(manager->merged_width, *merged_width); + } } /****************************************************************************** * * -* Paramètres : line = ligne à venir consulter. * -* index = indice de la colonne visée. * -* max_widths = tableau résumant les largeurs maximales. * +* Paramètres : line = ligne de texte à manipuler. * +* ctx = éléments à disposition pour l'exportation. * +* type = type d'exportation attendue. * +* display = règles d'affichage des colonnes modulables. * * * -* Description : Fournit la largeur d'une colonne finalement appliquée. * +* Description : Exporte la ligne de texte représentée. * * * -* Retour : Largeur globale ou spécifique, selon l'indice communiqué. * +* Retour : - * * * * Remarques : - * * * ******************************************************************************/ -gint g_buffer_line_compute_max_width(const GBufferLine *line, BufferLineColumn index, const gint *max_widths) +void g_buffer_line_export(GBufferLine *line, buffer_export_context *ctx, BufferExportType type, const bool *display) { - gint result; /* Largeur à retourner */ - //GBufferLine *manager; /* Gestionnaire de groupe */ - - assert(index < BLC_COUNT); + BufferLineColumn i; /* Boucle de parcours */ + int col_span; /* Fusion de colonnes ? */ - if (index >= line->merge_start) - result = get_column_width(&line->columns[index]); + switch (type) + { + case BET_HTML: + dprintf(ctx->fd, "\t<TR>\n"); + break; + default: + break; + } - else + for (i = 0; i < BLC_COUNT; i++) { - if (index < BLC_ASSEMBLY) - result = max_widths[index]; + if (i < BLC_DISPLAY && !display[i]) continue; - else + switch (type) { - //manager = g_buffer_line_get_width_manager(line); + case BET_TEXT: + if (i > 0) dprintf(ctx->fd, "%s", ctx->sep); + break; + default: + break; + } - if (line->flags & BLF_WIDTH_MANAGER) - result = line->max_widths[index]; - else - result = line->manager->max_widths[index]; + /** + * Pour la signification des différentes valeurs assignées, + * se référer au code de export_segments_of_column(). + * + * En gros : + * - 1 = rien de spécial. + * - >1 = il s'agit de la première cellule fusionnée de la ligne. + * - 0 = fusion déjà faite, on ne peut que rajouter du contenu dedans. + * - <1 = il s'agit de la dernière cellule fusionnée de la ligne. + * + * On considère qu'une fusion ne peut pas se réaliser sur la dernière + * cellule uniquement (ce qui a du sens : c'est inutile). + */ - } + if (i < line->merge_start) + col_span = 1; + + else if (i == line->merge_start) + col_span = BLC_COUNT - i; + + else + col_span = ((i + 1) == BLC_COUNT ? -1 : 0); + + export_segments_of_column(&line->columns[i], ctx, type, col_span); } - return result; + switch (type) + { + case BET_TEXT: + dprintf(ctx->fd, "\n"); + break; + case BET_HTML: + dprintf(ctx->fd, "</TR>\n"); + break; + default: + break; + } } + +/*----------------------------------------------------------------------------------- */ +/* MANIPULATION DES LARGEURS REQUISES */ +/* ---------------------------------------------------------------------------------- */ + + /****************************************************************************** * * -* Paramètres : line = ligne à venir consulter. * +* Paramètres : line = ligne à venir consulter. * +* summary = largeurs maximales à faire évoluer. * * * -* Description : Fournit la colonne à partir de laquelle une fusion opère. * +* Description : Fait remonter les largeurs requises par une ligne donnée. * * * -* Retour : Début de la première (et unique) zone globale. * +* Retour : - * * * * Remarques : - * * * ******************************************************************************/ -BufferLineColumn g_buffer_line_get_merge_start(const GBufferLine *line) +void g_buffer_line_collect_widths(GBufferLine *line, line_width_summary *summary) { - return line->merge_start; + gint merged_width; /* Largeur cumulée avant fusion*/ + BufferLineColumn i; /* Boucle de parcours */ + gint width; /* Largeur d'une colonne */ + + merged_width = 0; + + for (i = 0; i < BLC_COUNT; i++) + { + width = get_column_width(&line->columns[i]); + + if (i < line->merge_start) + summary->max_widths[i] = MAX(summary->max_widths[i], width); + + if (i >= BLC_DISPLAY) + { + merged_width += width; + + if (i < line->merge_start && (i + 1) < BLC_COUNT) + merged_width += COL_MARGIN; + + } + + } + + if (line->merge_start != BLC_COUNT) + summary->merged_width = MAX(summary->merged_width, merged_width); } /****************************************************************************** * * -* Paramètres : line = ligne à venir compléter. * -* start = début de la première (et unique) zone globale. * +* Paramètres : line = ligne à venir consulter. * +* index = indice de la colonne visée. * +* summary = résumé des largeurs maximales. * * * -* Description : Définit la colonne à partir de laquelle la fusion opère. * +* Description : Fournit la largeur d'une colonne finalement appliquée. * * * -* Retour : - * +* Retour : Largeur globale ou spécifique, selon l'indice communiqué. * * * * Remarques : - * * * ******************************************************************************/ -void g_buffer_line_start_merge_at(GBufferLine *line, BufferLineColumn start) +gint g_buffer_line_compute_max_width(const GBufferLine *line, BufferLineColumn index, const line_width_summary *summary) { - if (start == BLC_LAST_USED) - line->merge_start = line->last_used; + gint result; /* Largeur à retourner */ + + assert(index < BLC_COUNT); + + if (index >= line->merge_start) + result = get_column_width(&line->columns[index]); + else - line->merge_start = start; + result = summary->max_widths[index]; + + return result; } /****************************************************************************** * * -* Paramètres : line = ligne à venir compléter. * -* flag = propriété à intégrer. * +* Paramètres : line = ligne à venir consulter. * +* summary = résumé des largeurs maximales. * +* display = règles d'affichage des colonnes modulables. * +* base = position jusqu'au segment trouvé. [OUT] * +* offset = position à la colonne visée. [OUT] * +* dir = direction d'un éventuel déplacement en cours. * +* force = accepte les segments en bordure au pire. * * * -* Description : Ajoute une propriété particulière à une ligne donnée. * +* Description : Donne le segment présent à une abscisse donnée. * * * -* Retour : - * +* Retour : Segment trouvé ou NULL si hors borne. * * * * Remarques : - * * * ******************************************************************************/ -void g_buffer_line_add_flag(GBufferLine *line, BufferLineFlags flag) +GBufferSegment *g_buffer_line_get_segment_at(const GBufferLine *line, const line_width_summary *summary, const bool *display, gint *base, gint *offset, GdkScrollDirection dir, bool force) { - if ((line->flags & flag) == 0) + GBufferSegment *result; /* Trouvaille à retourner */ + BufferLineColumn last; /* Dernière colonne remplie */ + gint last_base; /* Dernière abscisse associée */ + BufferLineColumn i; /* Boucle de parcours */ + gint width; /* Largeur d'une colonne donnée*/ + + gint limit; + + gint consumed; /* Distance vers le segment */ + gint old_base; /* Somme de toutes les largeurs*/ + + result = NULL; + + *base = 0; + + last = BLC_COUNT; + + //sum = 0; + + printf("---------------\n"); + + /* On cible déjà la colonne idéale */ + + for (i = 0; i < BLC_COUNT; i++) { - g_signal_emit_by_name(line, "flip-flag", line->flags, flag); + printf(" @ (%d) x=%d width=%d max=%d display ? %d\n", + i, *offset, get_column_width(&line->columns[i]), summary->max_widths[i], i < BLC_DISPLAY ? display[i] : true); + + + if (i < BLC_DISPLAY && !display[i]) continue; + + /* Mémorisation de la dernière colonne contenant quelque chose... */ + if (get_column_width(&line->columns[i]) > 0) + { + last = i; + last_base = *base; + } + + if (i < line->merge_start) + { + width = g_buffer_line_compute_max_width(line, i, summary); + + if ((i + 1) < BLC_COUNT) limit = width + COL_MARGIN / 2; + else limit = width; + + if (*offset <= limit) break; + else + { + *offset -= width + COL_MARGIN; + *base += width + COL_MARGIN; + } + + } + else + { + width = get_column_width(&line->columns[i]); + + if (*offset <= width) break; + else + { + *offset -= width; + *base += width; + } + + } - line->flags |= flag; } -} + printf(" -- get segment at -- found index %u (max=%u)\n", i, BLC_COUNT); -/****************************************************************************** -* * -* Paramètres : line = ligne à venir consulter. * -* * -* Description : Renseigne sur les propriétés particulières liées à une ligne.* -* * -* Retour : Propriétés intégrées. * -* * -* Remarques : - * -* * -******************************************************************************/ + printf(" last seen = %u\n", last); -BufferLineFlags g_buffer_line_get_flags(const GBufferLine *line) -{ - return line->flags; + + + + + if (i < BLC_COUNT) + { + + printf(" -- width @ %u : %d\n", i, get_column_width(&line->columns[i])); + + if (get_column_width(&line->columns[i]) > 0) + { + /** + * Si la position était au milieu d'une marge, la sélection a pu pousser + * jusqu'à la colonne suivante, plus proche. + * Relativment à la base de cette dernière, la position est donc devenue négative. + */ + if (*offset < 0) *offset = 0; + + result = get_segment_at(&line->columns[i], offset, dir, &consumed); + *base += consumed; + } + + /* La position fournie tombe dans une colonne vide ! */ + else + { + if (force || get_column_width(&line->columns[i]) == 0) + { + result = NULL; + *offset = 0; + + old_base = *base; + + for (i++; i < BLC_COUNT && result == NULL; i++) + { + printf(" -- update to col %u -- x = %d\n", i, *offset); + + if ((i - 1) < line->merge_start) + { + width = g_buffer_line_compute_max_width(line, i - 1, summary); + *base += (width + COL_MARGIN); + } + else + *base += get_column_width(&line->columns[i - 1]); + + result = get_first_segment(&line->columns[i]); + + } + + printf(" -- final x = %d (result=%p)\n", *offset, result); + + if (result == NULL) + { + *base = old_base; + goto use_right_border; + } + + } + + } + + } + + else /* if (i == BLC_COUNT) */ + { + if (force && last != BLC_COUNT) + { + use_right_border: + + result = get_last_segment(&line->columns[last]); + *base = last_base; + *offset = get_column_width(&line->columns[last]); + + } + else + result = NULL; + + } + + return result; } /****************************************************************************** * * -* Paramètres : line = ligne à venir compléter. * -* flag = propriété à supprimer. * +* Paramètres : line = ligne à venir consulter. * +* target = segment dont un voisin est à retourner. * +* summary = résumé des largeurs maximales. * +* display = règles d'affichage des colonnes modulables. * +* dir = orientation des recherches. * +* offset = décalage pour amener à l'extrémité nouvelle. [OUT] * * * -* Description : Retire une propriété particulière à une ligne donnée. * +* Description : Fournit le segment voisin d'un autre segment identifié. * * * -* Retour : - * +* Retour : Segment trouvé dans la ligne ou NULL. * * * * Remarques : - * * * ******************************************************************************/ -void g_buffer_line_remove_flag(GBufferLine *line, BufferLineFlags flag) +GBufferSegment *g_buffer_line_find_near_segment(const GBufferLine *line, GBufferSegment *target, const line_width_summary *summary, const bool *display, GdkScrollDirection dir, gint *offset) { - if ((line->flags & flag) != 0) + GBufferSegment *result; /* Trouvaille à retourner */ + BufferLineColumn i; /* Boucle de parcours #1 */ + bool displayed; /* Confort de lecture */ + BufferLineColumn k; /* Boucle de parcours #2 */ + + result = NULL; + + /* Recherche dans la colonne de départ */ + + for (i = 0; i < BLC_COUNT; i++) + if (column_has_segment(&line->columns[i], target, NULL)) + break; + + if (i == BLC_COUNT) return NULL; + + result = find_near_segment(&line->columns[i], target, dir); + if (result != NULL) return result; + + /* Recherche dans la direction des colonnes voisines */ + + if (result == NULL) + switch (dir) + { + case GDK_SCROLL_LEFT: + + /* Si on a atteint la première colonne sans trouver... */ + if (i == 0) break; + + /* On s'assure que la colonne précédente est visible et peuplée */ + for (; i > BLC_FIRST && result == NULL; i--) + { + displayed = (i <= BLC_DISPLAY ? display[i - 1] : true); + + if (displayed) + result = get_last_segment(&line->columns[i - 1]); + + } + + break; + + case GDK_SCROLL_RIGHT: + + /* Si on a atteint la dernière colonne sans trouver... */ + /*if (i == BLC_COUNT) break;*/ + + /* On s'assure que la colonne suivante est visible et peuplée */ + for (; (i + 1) < BLC_COUNT && result == NULL; i++) + { + displayed = ((i + 1) < BLC_DISPLAY ? display[i + 1] : true); + + if (displayed) + result = get_first_segment(&line->columns[i + 1]); + + } + + break; + + default: + break; + + } + + /* Calcul de la position finale */ + + if (result != NULL) { - g_signal_emit_by_name(line, "flip-flag", line->flags, flag); + *offset = 0; - line->flags &= ~flag; + for (k = 0; k < i; k++) + { + displayed = (k < BLC_DISPLAY ? display[k] : true); + + if (displayed) + { + *offset += g_buffer_line_compute_max_width(line, k, summary); + if (k < line->merge_start) *offset += COL_MARGIN; + } + + } + + switch (dir) + { + case GDK_SCROLL_LEFT: + *offset += get_column_width(&line->columns[i]); + break; + + case GDK_SCROLL_RIGHT: + /**offset += 0;*/ + break; + + default: + break; + + } } + return result; + } /****************************************************************************** * * -* Paramètres : line = ligne de texte à manipuler. * -* cairo = contexte graphique à utiliser pour les pinceaux.* -* max_widths = largeurs de colonne à respecter. * -* x_init = abscisse du point d'impression de départ. * -* y = ordonnée du point d'impression. * -* display = règles d'affichage des colonnes modulables. * -* list = liste de contenus à mettre en évidence. * +* Paramètres : line = ligne de texte à manipuler. * +* cairo = contexte graphique à utiliser pour les pinceaux. * +* summary = résumé des largeurs maximales. * +* x_init = abscisse du point d'impression de départ. * +* y = ordonnée du point d'impression. * +* display = règles d'affichage des colonnes modulables. * +* list = liste de contenus à mettre en évidence. * * * * Description : Imprime la ligne de texte représentée. * * * @@ -1761,7 +1751,7 @@ void g_buffer_line_remove_flag(GBufferLine *line, BufferLineFlags flag) * * ******************************************************************************/ -void g_buffer_line_draw(GBufferLine *line, cairo_t *cairo, const gint max_widths[BLC_COUNT], gint x_init, gint y, const bool *display, const segcnt_list *list) +void g_buffer_line_draw(GBufferLine *line, cairo_t *cairo, const line_width_summary *summary, gint x_init, gint y, const bool *display, const segcnt_list *list) { GBufferLineClass *class; /* Stockage de briques de base */ bool has_src_surface; /* Note une présence définie */ @@ -1801,7 +1791,7 @@ void g_buffer_line_draw(GBufferLine *line, cairo_t *cairo, const gint max_widths if (i < line->merge_start) { - max_width = g_buffer_line_compute_max_width(line, i, max_widths); + max_width = g_buffer_line_compute_max_width(line, i, summary); x += max_width + COL_MARGIN; @@ -1810,87 +1800,3 @@ void g_buffer_line_draw(GBufferLine *line, cairo_t *cairo, const gint max_widths } } - - -/****************************************************************************** -* * -* Paramètres : line = ligne de texte à manipuler. * -* ctx = éléments à disposition pour l'exportation. * -* type = type d'exportation attendue. * -* display = règles d'affichage des colonnes modulables. * -* * -* Description : Exporte la ligne de texte représentée. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -void g_buffer_line_export(GBufferLine *line, buffer_export_context *ctx, BufferExportType type, const bool *display) -{ - BufferLineColumn i; /* Boucle de parcours */ - int col_span; /* Fusion de colonnes ? */ - - switch (type) - { - case BET_HTML: - dprintf(ctx->fd, "\t<TR>\n"); - break; - default: - break; - } - - for (i = 0; i < BLC_COUNT; i++) - { - if (i < BLC_DISPLAY && !display[i]) continue; - - switch (type) - { - case BET_TEXT: - if (i > 0) dprintf(ctx->fd, "%s", ctx->sep); - break; - default: - break; - } - - /** - * Pour la signification des différentes valeurs assignées, - * se référer au code de export_segments_of_column(). - * - * En gros : - * - 1 = rien de spécial. - * - >1 = il s'agit de la première cellule fusionnée de la ligne. - * - 0 = fusion déjà faite, on ne peut que rajouter du contenu dedans. - * - <1 = il s'agit de la dernière cellule fusionnée de la ligne. - * - * On considère qu'une fusion ne peut pas se réaliser sur la dernière - * cellule uniquement (ce qui a du sens : c'est inutile). - */ - - if (i < line->merge_start) - col_span = 1; - - else if (i == line->merge_start) - col_span = BLC_COUNT - i; - - else - col_span = ((i + 1) == BLC_COUNT ? -1 : 0); - - export_segments_of_column(&line->columns[i], ctx, type, col_span); - - } - - switch (type) - { - case BET_TEXT: - dprintf(ctx->fd, "\n"); - break; - case BET_HTML: - dprintf(ctx->fd, "</TR>\n"); - break; - default: - break; - } - -} diff --git a/src/glibext/gbufferline.h b/src/glibext/gbufferline.h index e4c2da5..6b213e3 100644 --- a/src/glibext/gbufferline.h +++ b/src/glibext/gbufferline.h @@ -114,12 +114,6 @@ void g_buffer_line_fill_mrange(GBufferLine *, MemoryDataSize, MemoryDataSize); /* Construit le tronc commun d'une ligne d'instruction. */ void g_buffer_line_fill_for_instr(GBufferLine *, MemoryDataSize, MemoryDataSize, const GBinContent *, phys_t); -/* Donne le segment présent à une abscisse donnée. */ -GBufferSegment *g_buffer_line_get_segment_at(const GBufferLine *, const gint [BLC_COUNT], const bool *, gint *, gint *, GdkScrollDirection, bool); - -/* Fournit le segment voisin d'un autre segment identifié. */ -GBufferSegment *g_buffer_line_find_near_segment(const GBufferLine *, GBufferSegment *, const gint [BLC_COUNT], const bool *, GdkScrollDirection, gint *); - /* Recherche le premier créateur enregistré dans des segments. */ GObject *g_buffer_line_find_first_segment_creator(const GBufferLine *, BufferLineColumn); @@ -138,18 +132,6 @@ char *g_buffer_line_get_text(const GBufferLine *, BufferLineColumn, BufferLineCo /* Supprime du texte représenté par une ligne de tampon. */ void g_buffer_line_delete_text(GBufferLine *, BufferLineColumn, BufferLineColumn); -/* Retient les largeurs d'une ligne si maximales. */ -void g_buffer_line_update_max_widths(GBufferLine *, GBufferLine *); - -/* Renvoie la ligne comptabilisant les largeurs pour un groupe. */ -GBufferLine *g_buffer_line_get_width_manager(GBufferLine *); - -/* Filtre des largeurs de lignes et ne garde que les maximales. */ -void g_buffer_line_apply_max_widths(GBufferLine *, gint *, gint *); - -/* Fournit la largeur d'une colonne finalement appliquée. */ -gint g_buffer_line_compute_max_width(const GBufferLine *, BufferLineColumn, const gint *); - /* Fournit la colonne à partir de laquelle une fusion opère. */ BufferLineColumn g_buffer_line_get_merge_start(const GBufferLine *); @@ -165,9 +147,6 @@ BufferLineFlags g_buffer_line_get_flags(const GBufferLine *); /* Retire une propriété particulière à une ligne donnée. */ void g_buffer_line_remove_flag(GBufferLine *, BufferLineFlags); -/* Imprime la ligne de texte représentée. */ -void g_buffer_line_draw(GBufferLine *, cairo_t *, const gint [BLC_COUNT], gint, gint, const bool *, const segcnt_list *); - /* Exporte la ligne de texte représentée. */ void g_buffer_line_export(GBufferLine *, buffer_export_context *, BufferExportType, const bool *); @@ -184,4 +163,33 @@ void g_buffer_line_export(GBufferLine *, buffer_export_context *, BufferExportTy +/* ----------------------- MANIPULATION DES LARGEURS REQUISES ----------------------- */ + + +/* Mémorisation des largeurs pour un groupe de lignes */ +typedef struct _line_width_summary +{ + gint max_widths[BLC_COUNT]; /* Taille cachée des colonnes */ + gint merged_width; /* Largeur cumulée avant fusion*/ + +} line_width_summary; + + +/* Fait remonter les largeurs requises par une ligne donnée. */ +void g_buffer_line_collect_widths(GBufferLine *, line_width_summary *); + +/* Fournit la largeur d'une colonne finalement appliquée. */ +gint g_buffer_line_compute_max_width(const GBufferLine *, BufferLineColumn, const line_width_summary *); + +/* Donne le segment présent à une abscisse donnée. */ +GBufferSegment *g_buffer_line_get_segment_at(const GBufferLine *, const line_width_summary *, const bool *, gint *, gint *, GdkScrollDirection, bool); + +/* Fournit le segment voisin d'un autre segment identifié. */ +GBufferSegment *g_buffer_line_find_near_segment(const GBufferLine *, GBufferSegment *, const line_width_summary *, const bool *, GdkScrollDirection, gint *); + +/* Imprime la ligne de texte représentée. */ +void g_buffer_line_draw(GBufferLine *, cairo_t *, const line_width_summary *, gint, gint, const bool *, const segcnt_list *); + + + #endif /* _GLIBEXT_GBUFFERLINE_H */ diff --git a/src/glibext/gbufferview.c b/src/glibext/gbufferview.c new file mode 100644 index 0000000..214b212 --- /dev/null +++ b/src/glibext/gbufferview.c @@ -0,0 +1,1330 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * gbufferview.c - affichage d'une vue particulière d'un tampon de lignes + * + * Copyright (C) 2016 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * OpenIDA 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. + * + * OpenIDA 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 "gbufferview.h" + + + +/* Vue d'un tampon pour code désassemblé (instance) */ +struct _GBufferView +{ + GObject parent; /* A laisser en premier */ + + GCodeBuffer *buffer; /* Tampon de code visualisé */ + + vmpa2t start; /* Première ligne intégrée */ + vmpa2t 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 */ + + union + { + const GWidthTracker *ext_tracker; /* Suivi externe des largeurs */ + GWidthTracker *int_tracker; /* Suivi interne des largeurs */ + GWidthTracker *tracker; /* Suivi pour usage interne */ + }; + + bool unrestricted; /* Validité des informations */ + + segcnt_list *highlighted; /* Segments mis en évidence */ + bool external; /* Note l'origine de la liste */ + +}; + +/* Vue d'un tampon pour code désassemblé (classe) */ +struct _GBufferViewClass +{ + GObjectClass parent; /* A laisser en premier */ + + gint line_height; /* Hauteur maximale des lignes */ + gint left_margin; /* Marge gauche + espace */ + gint left_text; /* Début d'impression du code */ + + /* 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_size_changed(const GCodeBuffer *, bool, size_t, size_t, GBufferView *); + +/* Réagit à un changement de contenu d'une ligne donnée. */ +static void on_buffer_line_changed(GCodeBuffer *, GBufferLine *, GBufferSegment *, GBufferView *); + + + +/* 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; + + class->line_height = 17; + class->left_margin = 2 * class->line_height; + class->left_text = 2.5 * class->line_height; + + + 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__OBJECT, + 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->unrestricted = true; + +} + + +/****************************************************************************** +* * +* 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_object_unref(G_OBJECT(view->buffer)); + + 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->external) + exit_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. * +* widget = composant GTK de destination pour le rendu. * +* * +* Description : Crée une nouvelle vue d'un tampon pour code désassemblé. * +* * +* Retour : Composant GTK créé. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GBufferView *g_buffer_view_new(GCodeBuffer *buffer, segcnt_list *highlighted) +{ + GBufferView *result; /* Composant à retourner */ + + result = g_object_new(G_TYPE_BUFFER_VIEW, NULL); + + g_object_ref(G_OBJECT(buffer)); + result->buffer = buffer; + + g_buffer_view_restrict(result, NULL, NULL); + + g_code_buffer_register_view_callback(buffer, + (buffer_size_changed_cb)on_buffer_size_changed, + G_OBJECT(result)); + + g_signal_connect(buffer, "line-changed", G_CALLBACK(on_buffer_line_changed), result); + + if (highlighted != NULL) + result->highlighted = highlighted; + else + result->highlighted = init_segment_content_list(); + + result->external = (highlighted != NULL); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : buffer = 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_size_changed(const GCodeBuffer *buffer, 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 + { + /* 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++) + { + 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++) + { + 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); + + } + + } + + 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 : buffer = tampon de lignes cohérentes à manipuler. * +* line = ligne dont la définition vient d'évoluer. * +* segment = éventuel segment qui vient d'évoluer ou NULL. * +* view = vue active du tampon de lignes concerné. * +* * +* Description : Réagit à un changement de contenu d'une ligne donnée. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void on_buffer_line_changed(GCodeBuffer *buffer, GBufferLine *line, GBufferSegment *segment, GBufferView *view) +{ + const vmpa2t *addr; /* Localisation de ligne */ + + addr = get_mrange_addr(g_buffer_line_get_range(line)); + + if (cmp_vmpa(&view->start, addr) <= 0 && cmp_vmpa(addr, &view->end) <= 0) + g_signal_emit_by_name(view, "need-redraw"); + +} + + +/****************************************************************************** +* * +* 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, const vmpa2t *start, const vmpa2t *end) +{ + const GWidthTracker *template; /* Suivi déjà en place */ + + if (!view->unrestricted) + g_object_unref(G_OBJECT(view->int_tracker)); + + view->unrestricted = (start == NULL || end == NULL); + + template = g_code_buffer_get_width_tracker(view->buffer); + + if (view->unrestricted) + { + view->first = 0; + view->last = g_code_buffer_count_lines(view->buffer) - 1; + + view->ext_tracker = template; + + } + + else + { + copy_vmpa(&view->start, start); + copy_vmpa(&view->end, end); + + view->first = g_code_buffer_get_index_from_address(view->buffer, start, true); + view->last = g_code_buffer_get_index_from_address(view->buffer, end, false); + + view->ext_tracker = g_width_tracker_new_restricted(template, view->first, view->last); + + } + +} + + +/****************************************************************************** +* * +* Paramètres : view = visualisateur à mettre à jour. * +* 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(GBufferView *view, vmpa2t *start, vmpa2t *end) +{ + if (!view->unrestricted) + { + if (start != NULL) copy_vmpa(start, &view->start); + if (end != NULL) copy_vmpa(end, &view->end); + } + + return !view->unrestricted; + +} + + +/****************************************************************************** +* * +* 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 : - * +* * +******************************************************************************/ + +GCodeBuffer *g_buffer_view_get_buffer(const GBufferView *view) +{ + g_object_ref(G_OBJECT(view->buffer)); + + return view->buffer; + +} + + +/****************************************************************************** +* * +* Paramètres : view = visualisation à consulter. * +* * +* Description : Fournit la hauteur d'impression d'une ligne visualisée. * +* * +* Retour : Hauteur de ligne en pixel. * +* * +* Remarques : - * +* * +******************************************************************************/ + +gint g_buffer_view_get_line_height(GBufferView *view) +{ + return G_BUFFER_VIEW_GET_CLASS(view)->line_height; + +} + + +/****************************************************************************** +* * +* Paramètres : view = visualisation à consulter. * +* display = 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 bool *display) +{ + gint result; /* Taille à retourner */ + + result = G_BUFFER_VIEW_GET_CLASS(view)->left_text; + + result += g_width_tracker_get_width(view->tracker, display); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : view = visualisation à consulter. * +* display = 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 bool *display) +{ + gint result; /* Taille à retourner */ + + result = G_BUFFER_VIEW_GET_CLASS(view)->left_text; + + result += g_width_tracker_get_margin(view->tracker, display); + + 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_VIEW_GET_CLASS(view)->line_height; + + result *= (view->last - view->first + 1); + + 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. * +* display = règles d'affichage des colonnes modulables. * +* caret = position du curseur à construire. [OUT] * +* * +* Description : Calcule la position idéale de curseur pour un point donné. * +* * +* Retour : Adresse si une a pu être déterminée, NULL sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +const vmpa2t *g_buffer_view_compute_caret(GBufferView *view, gint x, gint y, const bool *display, GdkRectangle *caret) +{ + gint remaining; /* Copie de travail modifiable */ + size_t index; /* Indice de ligne de tampon */ + GBufferLine *line; /* Ligne à la position courante*/ + GBufferSegment *segment; /* Segment présent sur la place*/ + GBufferViewClass *class; /* Classe pour les vues */ + + remaining = x; + + line = g_buffer_view_find_line_and_segment_at(view, &remaining, y, &index, display, &segment); + + if (line == NULL) return NULL; + if (segment == NULL) printf(" -- no segment\n"); + if (segment == NULL) return NULL; + + + + + + printf("\n[BASE] orig = %d tronc = %d reste = %d dernier = %d largeur = %d\n", + x, x - remaining, remaining, g_buffer_segment_get_caret_position(segment, remaining), + g_buffer_segment_get_width(segment)); + + printf(" '%s'\n", g_buffer_segment_get_text(segment, false)); + + + class = G_BUFFER_VIEW_GET_CLASS(view); + + caret->x = /*view->left_text +*/ (x - remaining) + g_buffer_segment_get_caret_position(segment, remaining); + + caret->y = (index - view->first) * class->line_height; + + caret->width = 2; + caret->height = class->line_height; + + return get_mrange_addr(g_buffer_line_get_range(line)); + +} + + +/****************************************************************************** +* * +* Paramètres : view = vue de tampon à mettre à jour. * +* line = ligne correspondant à la position. * +* index = indice de cette même ligne dans le tampon. * +* x = abscisse de la zone principale à traiter. * +* display = règles d'affichage des colonnes modulables. * +* caret = position du curseur à construire. [OUT] * +* * +* Description : Calcule la position idéale de curseur pour un point donné. * +* * +* Retour : Adresse si une a pu être déterminée, NULL sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +const vmpa2t *g_buffer_view_compute_caret_full(GBufferView *view, GBufferLine *line, size_t index, gint x, const bool *display, GdkRectangle *caret) +{ + GBufferViewClass *class; /* Classe pour les vues */ + gint offset; /* Point de travail modifiable */ + const line_width_summary *summary; /* Résumé concis des largeurs */ + gint base; /* Position absolue de segment */ + GBufferSegment *segment; /* Segment visé par le pointeur*/ + + class = G_BUFFER_VIEW_GET_CLASS(view); + + offset = x; + + offset -= class->left_text; + if (offset < 0) return NULL; + + summary = g_width_tracker_get_width_summary(view->tracker); + + segment = g_buffer_line_get_segment_at(line, summary, display, &base, &offset, GDK_SCROLL_LEFT, true); + if (segment == NULL) return NULL; + + caret->x = class->left_text + base + offset; + + printf("caret Y : %zu -> %zu\n", view->first, index); + + caret->y = (index - view->first) * class->line_height; + + caret->width = 2; + caret->height = class->line_height; + + return get_mrange_addr(g_buffer_line_get_range(line)); + +} + + +/****************************************************************************** +* * +* Paramètres : line = ligne à venir consulter. * +* caret = position du curseur à faire évoluer. * +* ctrl = indique la demande d'un parcours rapide. * +* dir = direction du parcours. * +* display = règles d'affichage des colonnes modulables. * +* * +* 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, GdkRectangle *caret, bool ctrl, GdkScrollDirection dir, const bool *display) +{ + bool result; /* Bilan à retourner */ + gint offset; /* Point de travail modifiable */ + const line_width_summary *summary; /* Résumé concis des largeurs */ + gint base; /* Position absolue de segment */ + GBufferSegment *segment; /* Segment visé par le pointeur*/ + + + + offset = caret->x; + + offset -= G_BUFFER_VIEW_GET_CLASS(view)->left_text; + if (offset < 0) return false; + + summary = g_width_tracker_get_width_summary(view->tracker); + + segment = g_buffer_line_get_segment_at(line, summary, display, &base, &offset, dir, false); + + if (segment == NULL) printf(" ===== NO SEG...\n"); + + if (segment == NULL) return false; + + + printf(" ====== FIRST SEG :: %p ('%s')\n", segment, g_buffer_segment_get_text(segment, false)); + + + + + + + //if (dir == GDK_SCROLL_LEFT || dir == GDK_SCROLL_RIGHT) + result = g_buffer_segment_move_caret(segment, &offset, ctrl, dir); + //else + //result = true; + + printf(" ====== MOVE 1 ? %d\n", result); + + /////////////////// + + if (!result) + { + base = 0; + + segment = g_buffer_line_find_near_segment(line, segment, summary, display, dir, &offset); + + + printf(" ====== NEAR SEG :: %p ('%s')\n", segment, segment ? g_buffer_segment_get_text(segment, false) : NULL); + + if (segment != NULL) + { + + result = true; + //result = g_buffer_segment_move_caret(segment, &offset, ctrl, dir); + + /* + if (result) + caret->x -= COL_MARGIN; + */ + + printf(" ====== MOVE 2 ? %d (offset=%d)\n", result, offset); + + + } + + + } + + + if (result) + printf(" ====== NEW CARET: %d -> %d\n", caret->x, G_BUFFER_VIEW_GET_CLASS(view)->left_text + base + offset); + else + printf(" ====== NO NEW CARET!\n"); + + + + if (result) + caret->x = G_BUFFER_VIEW_GET_CLASS(view)->left_text + base + offset; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : view = vue de tampon à mettre à jour. * +* caret = position du curseur à faire évoluer. * +* ctrl = indique la demande d'un parcours rapide. * +* dir = direction du parcours. * +* display = règles d'affichage des colonnes modulables. * +* * +* Description : Déplace le curseur au sein d'une vue de tampon. * +* * +* Retour : Adresse si une a pu être déterminée, VMPA_INVALID sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +const vmpa2t *g_buffer_view_move_caret(GBufferView *view, GdkRectangle *caret, bool ctrl, GdkScrollDirection dir, const bool *display) +{ + const vmpa2t *result; /* Actualisation à renvoyer */ + size_t index; /* Indice de ligne de tampon */ + GBufferLine *line; /* Ligne sous le pointeur */ + + + const line_width_summary *summary; /* Résumé concis des largeurs */ + bool computed; /* Récursivité pris en compte */ + gint left_pos; /* Retour à la ligne */ + gint right_pos; /* Position d'extrème droite */ + BufferLineColumn i; /* Boucle de parcours */ + size_t first; /* Première ligne intégrée */ + size_t last; /* Dernière ligne intégrée */ + + + + + bool moved; /* Mémorisation d'une évolut° */ + + + + + + + + + + result = NULL; + + + + line = g_buffer_view_find_line_at(view, caret->y, &index); + if (line == NULL) return NULL; + + summary = g_width_tracker_get_width_summary(view->tracker); + + computed = false; + + switch (dir) + { + case GDK_SCROLL_UP: + case GDK_SCROLL_DOWN: + break; + case GDK_SCROLL_LEFT: + case GDK_SCROLL_RIGHT: + left_pos = G_BUFFER_VIEW_GET_CLASS(view)->left_text; + if (display[BLC_PHYSICAL]) left_pos += summary->max_widths[BLC_PHYSICAL] + COL_MARGIN; + if (display[BLC_VIRTUAL]) left_pos += summary->max_widths[BLC_VIRTUAL] + COL_MARGIN; + if (display[BLC_BINARY]) left_pos += summary->max_widths[BLC_BINARY] + COL_MARGIN; + right_pos = left_pos; + for (i = BLC_ASSEMBLY_HEAD; i < BLC_COUNT; i++) + right_pos += summary->max_widths[i] + COL_MARGIN; + + /* +gint g_buffer_line_compute_max_width(const GBufferLine *line, BufferLineColumn index, const gint *max_widths) + +BufferLineColumn g_buffer_line_get_merge_start(const GBufferLine *line) + */ + + left_pos = G_BUFFER_VIEW_GET_CLASS(view)->left_text; + + break; + default: /* GDK_SCROLL_SMOOTH */ + break; + } + + first = view->first; + last = view->last; + + switch (dir) + { + case GDK_SCROLL_UP: + + if (index > first) + { + line = g_code_buffer_find_line_by_index(view->buffer, index - 1); + result = g_buffer_view_compute_caret_full(view, line, index - 1, caret->x, display, caret); + } + + break; + + case GDK_SCROLL_DOWN: + + if (index < last) + { + line = g_code_buffer_find_line_by_index(view->buffer, index + 1); + result = g_buffer_view_compute_caret_full(view, line, index + 1, caret->x, display, caret); + } + + break; + + case GDK_SCROLL_LEFT: + + /* + line = g_buffer_view_find_line_at(view, caret->y, &index); + if (line == NULL) break; + */ + + moved = _g_buffer_view_move_caret(view, line, caret, ctrl, GDK_SCROLL_LEFT, display); + + if (moved) + result = get_mrange_addr(g_buffer_line_get_range(line)); + + else if (index > first) + { + line = g_code_buffer_find_line_by_index(view->buffer, index - 1); + result = g_buffer_view_compute_caret_full(view, line, index - 1, INT_MAX, display, caret); + } + + break; + + case GDK_SCROLL_RIGHT: + + /* + line = g_buffer_view_find_line_at(view, caret->y, &index); + if (line == NULL) break; + */ + + moved = _g_buffer_view_move_caret(view, line, caret, ctrl, GDK_SCROLL_RIGHT, display); + + if (moved) + result = get_mrange_addr(g_buffer_line_get_range(line)); + + else if (index < last) + { + line = g_code_buffer_find_line_by_index(view->buffer, index + 1); + result = g_buffer_view_compute_caret_full(view, line, index + 1, left_pos, display, caret); + } + + break; + + default: /* GDK_SCROLL_SMOOTH */ + break; + + } + + /* + printf(" --- CARET --- moved = %d index = %d result = %p\n", + moved, index, result); + */ + + + /* + if (result && !computed) + result = g_buffer_view_compute_caret_full(view, caret->x, caret->y, caret, display, NULL); + */ + + 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. * +* display = règles d'affichage des colonnes modulables. * +* * +* 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 bool *display) +{ + bool need_redraw; /* Besoin d'actualisation ? */ + GBufferSegment *segment; /* Segment sélectionnable */ + + if (view->highlighted != NULL) + need_redraw = g_buffer_view_unhighlight_segments(view); + else + need_redraw = false; + + g_buffer_view_find_line_and_segment_at(view, &x, y, NULL, display, &segment); + + if (segment) + need_redraw |= add_segment_content_to_selection_list(view->highlighted, segment); + + if (need_redraw) + g_signal_emit_by_name(view, "need-redraw"); + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : view = visualisation à représenter. * +* cr = contexte graphique dédié à la procédure. * +* fake_x = abscisse réelle du point 0 à l'écran. * +* fake_y = ordonnée réelle du point 0 à l'écran. * +* area = position et surface à traiter. * +* display = règles d'affichage des colonnes modulables. * +* selected = ordonnée d'une ligne sélectionnée ou NULL. * +* * +* Description : Imprime la visualisation du tampon de code désassemblé. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_buffer_view_draw(const GBufferView *view, cairo_t *cr, gint fake_x, gint fake_y, const cairo_rectangle_int_t *area, const bool *display, const gint *selected) +{ + GBufferViewClass *class; /* Classe pour les vues */ + gint real_x; /* Abscisse réelle pour tampon */ + gint real_y; /* Ordonnée réelle pour tampon */ + size_t first; /* Première ligne visée */ + size_t last; /* Dernière ligne visée + 1 */ + gint y; /* Point de départ + décallage */ + bool wait_selection; /* Sélection déjà passée ? */ + gint rel_selected; /* Position relative de sélect°*/ + size_t i; /* Boucle de parcours */ + GBufferLine *line; /* Ligne à dessiner à l'écran */ + line_width_summary summary; /* Résumé concis des largeurs */ + + class = G_BUFFER_VIEW_GET_CLASS(view); + + real_x = fake_x + class->left_text; + real_y = fake_y + area->y; + + first = view->first; + first += (real_y / class->line_height); + + last = first + (area->height / class->line_height); + if (area->height % class->line_height > 0) last++; + + last = MIN(last, view->last); + + y = area->y - (real_y % class->line_height); + + wait_selection = true; + + if (selected != NULL) + rel_selected = *selected - fake_y; + + if (g_code_buffer_count_lines(view->buffer) > 0) + for (i = first; i <= last; i++) + { + /* Si sélection, on sousligne la ligne concernée */ + if (wait_selection && selected != NULL && rel_selected == y) + { + cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 0.05); + + cairo_rectangle(cr, area->x, y, area->width, class->line_height); + cairo_fill(cr); + + wait_selection = false; + + } + + line = g_code_buffer_find_line_by_index(view->buffer, i); + + if (i == first || (g_buffer_line_get_flags(line) & BLF_WIDTH_MANAGER)) + g_width_tracker_get_local_width_summary(view->tracker, i, &summary); + + g_buffer_line_draw(line, cr, &summary, real_x, y, display, view->highlighted); + + y += class->line_height; + + } + +} + + +/****************************************************************************** +* * +* Paramètres : view = visualisation à consulter. * +* addr = adresse où retrouver la ligne recherchée. * +* flags = propriétés à vérifier en tout ou partie. * +* idx = indice de la ligne trouvée ou NULL. [OUT] * +* * +* Description : Retrouve une ligne au sein d'un tampon avec une adresse. * +* * +* Retour : Line retrouvée ou NULL en cas d'échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GBufferLine *g_buffer_view_find_line_by_addr(const GBufferView *view, const vmpa2t *addr, BufferLineFlags flags, size_t *idx) +{ + GBufferLine *result; /* Ligne trouvée à retourner */ + phys_t length; /* Taille de la vue */ + mrange_t vrange; /* Couverture de la vue */ + bool allowed; /* Rechercher validée ? */ + + /* Vérification des bornes */ + + if (!view->unrestricted) + { + length = compute_vmpa_diff(&view->start, &view->end); + + init_mrange(&vrange, &view->start, length); + + allowed = mrange_contains_addr_inclusive(&vrange, addr); + + } + else allowed = true; + + /* Lancement des recherches ? */ + + if (allowed) + result = g_code_buffer_find_line_by_addr(view->buffer, addr, flags, idx); + else + result = NULL; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : view = visualisation à consulter. * +* index = indice de la ligne recherchée. * +* * +* Description : Retrouve une ligne au sein d'un tampon avec un indice. * +* * +* Retour : Line retrouvée ou NULL en cas d'échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GBufferLine *g_buffer_view_find_line_by_index(const GBufferView *view, size_t index) +{ + GBufferLine *result; /* Ligne trouvée à retourner */ + bool allowed; /* Rechercher validée ? */ + + /* Vérification des bornes */ + + allowed = (view->first <= index && index <= view->last); + + /* Lancement des recherches ? */ + + if (allowed) + result = g_code_buffer_find_line_by_index(view->buffer, index); + else + result = NULL; + + return result; + +} + + +/****************************************************************************** +* * +* 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 : - * +* * +******************************************************************************/ + +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_view_get_line_height(view); + index = y / lheight; + + index += view->first; + + if (index <= view->last) + result = g_code_buffer_find_line_by_index(view->buffer, index); + + if (result != NULL && idx != NULL) + *idx = index; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : view = visualisation à consulter. * +* x = abscisse comprise dans le segment recherché. [OUT] * +* y = ordonnée comprise dans la ligne recherchée. * +* idx = indice de la ligne trouvée ou NULL. [OUT] * +* display = règles d'affichage des colonnes modulables. * +* segment = portion de texte recherchée ou NULL. [OUT] * +* * +* Description : Fournit la ligne et son segment présents à une position. * +* * +* Retour : Ligne retrouvée ou NULL si aucune. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GBufferLine *g_buffer_view_find_line_and_segment_at(GBufferView *view, gint *x, gint y, size_t *idx, const bool *display, GBufferSegment **segment) +{ + GBufferLine *result; /* Ligne trouvée à retourner */ + GBufferViewClass *class; /* Classe pour les vues */ + const line_width_summary *summary; /* Résumé concis des largeurs */ + + /* Recherche d'une ligne correspondante */ + + result = g_buffer_view_find_line_at(view, y, idx); + + /* Recherche du segment visé éventuel */ + + if (result != NULL && segment != NULL) + { + class = G_BUFFER_VIEW_GET_CLASS(view); + + if (*x < class->left_text) + *segment = NULL; + + else + { + summary = g_width_tracker_get_width_summary(view->tracker); + + *x -= class->left_text; + *segment = g_buffer_line_get_segment_at(result, summary, display, + (gint []) { 0 }, x, GDK_SCROLL_LEFT, true); + + } + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : view = 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] * +* code = s'arrête si possible à une ligne avec code. * +* * +* 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_address_coordinates(GBufferView *view, const vmpa2t *addr, gint *x, gint *y, bool code) +{ + bool result; /* Bilan à retourner */ + gint lheight; /* Hauteur d'une ligne */ + size_t i; /* Boucle de parcours */ + GBufferLine *line; /* Ligne à consulter */ + const mrange_t *range; /* Emplacement parcouru */ + + result = false; + + *x = 0; + *y = 0; + + lheight = g_buffer_view_get_line_height(view); + + for (i = view->first; i <= view->last; i++) + { + /** + * Si l'adresse recherchée est plus petite que l'adresse de départ, + * on va effectuer un parcours complet pour rien. + * + * On considère cependant que le seul cas où celà peut arriver + * est lorsque que des découpages en blocs sont impliqués. + * + * Les découpages conduisent alors à la formation de petites zones, + * rapides à parcourir. + */ + + line = g_code_buffer_find_line_by_index(view->buffer, i); + range = g_buffer_line_get_range(line); + + result = mrange_contains_addr(range, addr); + if (result) break; + + *y += lheight; + + } + + if (result && code) + for (; i <= view->last; i++) + { + line = g_code_buffer_find_line_by_index(view->buffer, i); + + if (g_buffer_line_get_flags(line) & BLF_HAS_CODE) break; + + if (i == view->last) break; + + line = g_code_buffer_find_line_by_index(view->buffer, i + 1); + + range = g_buffer_line_get_range(line); + if (!mrange_contains_addr(range, addr)) break; + + *y += lheight; + + } + + return result; + +} diff --git a/src/glibext/gbufferview.h b/src/glibext/gbufferview.h new file mode 100644 index 0000000..90c20bb --- /dev/null +++ b/src/glibext/gbufferview.h @@ -0,0 +1,112 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * gbufferview.h - prototypes pour l'affichage d'une vue particulière d'un tampon de lignes + * + * Copyright (C) 2016 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * OpenIDA 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. + * + * OpenIDA 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/>. + */ + + +#ifndef _GLIBEXT_GBUFFERVIEW_H +#define _GLIBEXT_GBUFFERVIEW_H + + +#include <glib-object.h> + + +#include "gcodebuffer.h" + + + +#define G_TYPE_BUFFER_VIEW (g_buffer_view_get_type()) +#define G_BUFFER_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_BUFFER_VIEW, GBufferView)) +#define G_BUFFER_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_BUFFER_VIEW, GBufferViewClass)) +#define G_IS_BUFFER_VIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_BUFFER_VIEW)) +#define G_IS_BUFFER_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_BUFFER_VIEW)) +#define G_BUFFER_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_BUFFER_VIEW, GBufferViewClass)) + + +/* Vue d'un tampon pour code désassemblé (instance) */ +typedef struct _GBufferView GBufferView; + +/* Vue d'un tampon pour code désassemblé (classe) */ +typedef struct _GBufferViewClass GBufferViewClass; + + +/* Détermine le type de la vue d'un tampon pour code désassemblé. */ +GType g_buffer_view_get_type(void); + +/* Crée une nouvelle vue d'un tampon pour code désassemblé. */ +GBufferView *g_buffer_view_new(GCodeBuffer *, segcnt_list *); + +/* Restreint le champ d'application de l'affichage. */ +void g_buffer_view_restrict(GBufferView *, const vmpa2t *, const vmpa2t *); + +/* Indique le champ d'application de l'affichage. */ +bool g_buffer_view_get_restrictions(GBufferView *, vmpa2t *, vmpa2t *); + +/* Fournit le tampon de code lié à un visualisateur donné. */ +GCodeBuffer *g_buffer_view_get_buffer(const GBufferView *); + +/* Fournit la hauteur d'impression d'une ligne visualisée. */ +gint g_buffer_view_get_line_height(GBufferView *); + +/* Fournit la largeur requise par une visualisation. */ +gint g_buffer_view_get_width(GBufferView *, const bool *); + +/* Fournit la largeur requise pour dépasser les marges gauches. */ +gint g_buffer_view_get_margin(GBufferView *, const bool *); + +/* Fournit la hauteur requise par une visualisation. */ +gint g_buffer_view_get_height(const GBufferView *); + +/* Calcule la position idéale de curseur pour un point donné. */ +const vmpa2t *g_buffer_view_compute_caret(GBufferView *, gint, gint, const bool *, GdkRectangle *); + +/* Calcule la position idéale de curseur pour un point donné. */ +const vmpa2t *g_buffer_view_compute_caret_full(GBufferView *, GBufferLine *, size_t, gint, const bool *, GdkRectangle *); + +/* Déplace le curseur au sein d'une vue de tampon. */ +const vmpa2t *g_buffer_view_move_caret(GBufferView *, GdkRectangle *, bool, GdkScrollDirection, const bool *); + +/* Supprime toute mise en évidence de segments. */ +bool g_buffer_view_unhighlight_segments(GBufferView *); + +/* Surligne tous les segments similaires à celui sous la souris. */ +bool g_buffer_view_highlight_segments(GBufferView *, gint, gint, const bool *); + +/* Imprime la visualisation du tampon de code désassemblé. */ +void g_buffer_view_draw(const GBufferView *, cairo_t *, gint, gint, const cairo_rectangle_int_t *, const bool *, const gint *); + +/* Retrouve une ligne au sein d'un tampon avec une adresse. */ +GBufferLine *g_buffer_view_find_line_by_addr(const GBufferView *, const vmpa2t *, BufferLineFlags, size_t *); + +/* Retrouve une ligne au sein d'un tampon avec un indice. */ +GBufferLine *g_buffer_view_find_line_by_index(const GBufferView *, size_t ); + +/* Fournit la ligne présente à une ordonnée donnée. */ +GBufferLine *g_buffer_view_find_line_at(GBufferView *, gint, size_t *); + +/* Fournit la ligne et son segment présents à une position. */ +GBufferLine *g_buffer_view_find_line_and_segment_at(GBufferView *, gint *, gint, size_t *, const bool *, GBufferSegment **); + +/* Indique la position d'affichage d'une adresse donnée. */ +bool g_buffer_view_get_address_coordinates(GBufferView *, const vmpa2t *, gint *, gint *, bool); + + + +#endif /* _GLIBEXT_GBUFFERVIEW_H */ diff --git a/src/glibext/gcodebuffer.c b/src/glibext/gcodebuffer.c index 346ce70..c3c5a78 100644 --- a/src/glibext/gcodebuffer.c +++ b/src/glibext/gcodebuffer.c @@ -1,6 +1,6 @@ /* Chrysalide - Outil d'analyse de fichiers binaires - * gcodebuffer.h - prototypes pour l'affichage d'un fragment de code d'assemblage + * gcodebuffer.c - affichage d'un fragment de code d'assemblage * * Copyright (C) 2010-2014 Cyrille Bagard * @@ -100,6 +100,15 @@ static void g_buffer_scan_process(GBufferScan *, GtkStatusStack *); /* -------------------------- TAMPON POUR CODE DESASSEMBLE -------------------------- */ +/* Suivi distant des évolutions */ +typedef struct _view_callback +{ + buffer_size_changed_cb size_changed; /* Evolution de taille */ + GObject *data; /* Données à associer */ + +} view_callback; + + /* Tampon pour code désassemblé (instance) */ struct _GCodeBuffer { @@ -111,8 +120,13 @@ struct _GCodeBuffer size_t count; /* Quantité en cache */ size_t used; /* Quantité utilisée */ + GWidthTracker *tracker; /* Suivi des largeurs */ + size_t indent; /* Indentation des lignes */ + view_callback *vcallbacks; /* Vues à mettre à jour */ + size_t vcount; /* Quantité de ces vues */ + }; /* Tampon pour code désassemblé (classe) */ @@ -137,12 +151,6 @@ static void g_code_buffer_class_init(GCodeBufferClass *); /* Procède à l'initialisation d'un tampon pour code désassemblé. */ static void g_code_buffer_init(GCodeBuffer *); -/* Convertit une adresse en indice de ligne. */ -static size_t g_code_buffer_get_index_from_address(const GCodeBuffer *, const vmpa2t *, bool); - -/* Actualise les largeurs maximales par groupes de lignes. */ -static void g_code_buffer_update_line_max_widths(const GCodeBuffer *, size_t, size_t); - /* Réagit à un changement de contenu d'une ligne donnée. */ static void on_line_content_change(GBufferLine *, GBufferSegment *, GCodeBuffer *); @@ -174,70 +182,11 @@ static bool _g_code_buffer_delete_lines_comment(GCodeBuffer *, GBufferLine *); -/* ---------------------- VUE PARTICULIERE D'UN TAMPON DE CODE ---------------------- */ - - -/* Vue d'un tampon pour code désassemblé (instance) */ -struct _GBufferView -{ - GObject parent; /* A laisser en premier */ - - GCodeBuffer *buffer; /* Tampon de code visualisé */ - vmpa2t *start; /* Première ligne intégrée */ - vmpa2t *end; /* Dernière ligne intégrée */ - size_t first_index; /* Indice de la première ligne */ /* FIXME : utiliser partout ? */ - size_t last_index; /* Indice de la dernière ligne */ /* FIXME : idem */ - - gint line_height; /* Hauteur maximale des lignes */ - gint left_margin; /* Marge gauche + espace */ - gint left_text; /* Début d'impression du code */ - gint max_widths[BLC_COUNT]; /* Taille cachée des colonnes */ - gint merged_width; /* Plus grande taille de fusion*/ - - segcnt_list *highlighted; /* Segments mis en évidence */ - bool external; /* Note l'origine de la liste */ - -}; - -/* Vue d'un tampon pour code désassemblé (classe) */ -struct _GBufferViewClass -{ - GObjectClass parent; /* A laisser en premier */ - - /* Signaux */ - - void (* need_redraw) (GBufferView *); - -}; - - -#define HEIGHT_CACHED(view) ((view)->line_height != -1) -#define WIDTHS_CACHED(view) ((view)->max_widths[0] != -1) - +/* ------------------------- SIGNAUX IMMEDIATS POUR UNE VUE ------------------------- */ -/* 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 *); - -/* Réagit à un changement de contenu d'une ligne donnée. */ -static void on_buffer_line_changed(GCodeBuffer *, GBufferLine *, GBufferSegment *, GBufferView *); - -/* Réinitialise le cache de la hauteur des lignes. */ -static void g_buffer_view_reset_required_height(GBufferView *); - -/* Réinitialise le cache des largeurs de colonne calculées. */ -static void g_buffer_view_reset_required_widths(GBufferView *); - -/* Calcule les largeurs requises par une visualisation. */ -static void g_buffer_view_compute_required_widths(GBufferView *, const bool *); +/* Fait suivre une variation de la quantité de lignes du tampon. */ +static void g_code_buffer_notify_size_changed(const GCodeBuffer *, bool, size_t, size_t); @@ -444,645 +393,6 @@ static void g_buffer_scan_process(GBufferScan *scan, GtkStatusStack *status) /* ---------------------------------------------------------------------------------- */ -/* CONFORTS POUR LES COMMENTAIRES */ -/* ---------------------------------------------------------------------------------- */ - - -/****************************************************************************** -* * -* Paramètres : buffer = tampon de lignes à consulter. * -* line = ligne à l'intérieur d'un commentaire. * -* comment = nouveau commentaire à inscrire à la ligne donnée. * -* creator = créateur à l'origine de la construction. * -* * -* Description : Affiche un commentaire sur une ligne de tampon donnée. * -* * -* Retour : Bilan de l'opération : ajout ou non ? * -* * -* Remarques : - * -* * -******************************************************************************/ - -static bool _g_code_buffer_write_inlined_comment(GCodeBuffer *buffer, GBufferLine *line, const char *comment, GObject *creator) -{ - bool result; /* Bilan à retourner */ - const mrange_t *range; /* Emplace de ligne à utiliser */ - char *wcopy; /* Copie de travail */ - GBufferLine **extra; /* Lignes supplémentaires */ - size_t extra_count; /* Quantité de ces lignes */ - char *saveptr; /* Sauvegarde pour la sécurité */ - char *token; /* Fragment à insérer */ - size_t len; /* Taille dudit fragment */ - GBufferSegment *segment; /* Segment à marquer au fer */ - GBufferLine *new; /* Nouvelle ligne créée */ - size_t i; /* Boucle de parcours */ - - assert(!g_buffer_line_has_comment(line)); - - result = false; - - range = g_buffer_line_get_range(line); - - wcopy = strdup(comment); - - extra = NULL; - extra_count = 0; - - for (token = strtok_r(wcopy, COMMENT_LINE_SEP, &saveptr); - token != NULL; - token = strtok_r(NULL, COMMENT_LINE_SEP, &saveptr)) - { - len = strlen(token); - - if (!result) - { - segment = g_buffer_line_insert_text(line, BLC_COMMENTS, token, len, RTT_COMMENT); - g_buffer_segment_set_creator(segment, creator); - } - - else - { - new = g_code_buffer_prepare_new_line(buffer, range); - - segment = g_buffer_line_insert_text(new, BLC_COMMENTS, token, len, RTT_COMMENT); - g_buffer_segment_set_creator(segment, creator); - - extra = (GBufferLine **)realloc(extra, ++extra_count * sizeof(GBufferLine *)); - - extra[extra_count - 1] = new; - - } - - result = true; - - } - - free(wcopy); - - if (extra_count > 0) - { - result &= g_code_buffer_insert_lines(buffer, extra, extra_count, line, false); - - if (!result) - for (i = 0; i < extra_count; i++) - g_object_unref(G_OBJECT(extra[i])); - - free(extra); - - } - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : buffer = tampon de lignes à consulter. * -* line = ligne à l'intérieur d'un commentaire. * -* comment = nouveau commentaire à inscrire à la ligne donnée. * -* creator = créateur à l'origine de la construction. * -* * -* Description : Affiche un commentaire sur une ligne de tampon donnée. * -* * -* Retour : Bilan de l'opération : ajout ou non ? * -* * -* Remarques : - * -* * -******************************************************************************/ - -bool g_code_buffer_update_inlined_comment(GCodeBuffer *buffer, GBufferLine *line, const char *comment, GObject *creator) -{ - bool result; /* Bilan à retourner */ - - if (g_buffer_line_has_comment(line)) - result = _g_code_buffer_delete_lines_comment(buffer, line); - else - result = true; - - if (result) - result = _g_code_buffer_write_inlined_comment(buffer, line, comment, creator); - - /* TODO : emit() */ - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : buffer = tampon de lignes à consulter. * -* line = ligne à l'intérieur d'un commentaire. * -* comment = nouveau commentaire à inscrire à la ligne donnée. * -* before = précise la position du commentaire. * -* creator = créateur à l'origine de la construction. * -* * -* Description : Affiche un commentaire sur une ligne de tampon dédiée. * -* * -* Retour : Bilan de l'opération : ajout ou non ? * -* * -* Remarques : - * -* * -******************************************************************************/ - -static bool _g_code_buffer_write_comment_area(GCodeBuffer *buffer, GBufferLine *line, const char *comment, bool before, GObject *creator) -{ - bool result; /* Bilan à retourner */ - const mrange_t *range; /* Emplace de ligne à utiliser */ - char *wcopy; /* Copie de travail */ - GBufferLine **extra; /* Lignes supplémentaires */ - size_t extra_count; /* Quantité de ces lignes */ - char *saveptr; /* Sauvegarde pour la sécurité */ - char *token; /* Fragment à insérer */ - size_t len; /* Taille dudit fragment */ - GBufferLine *new; /* Nouvelle ligne créée */ - GBufferSegment *segment; /* Segment à marquer au fer */ - size_t i; /* Boucle de parcours */ - - assert(!g_buffer_line_has_comment(line)); - - result = false; - - range = g_buffer_line_get_range(line); - - wcopy = strdup(comment); - - extra = NULL; - extra_count = 0; - - for (token = strtok_r(wcopy, COMMENT_LINE_SEP, &saveptr); - token != NULL; - token = strtok_r(NULL, COMMENT_LINE_SEP, &saveptr)) - { - len = strlen(token); - - new = g_code_buffer_prepare_new_line(buffer, range); - g_buffer_line_start_merge_at(new, BLC_DISPLAY); - - segment = g_buffer_line_insert_text(new, BLC_DISPLAY, token, len, RTT_COMMENT); - g_buffer_segment_set_creator(segment, creator); - - extra = (GBufferLine **)realloc(extra, ++extra_count * sizeof(GBufferLine *)); - - extra[extra_count - 1] = new; - - result = true; - - } - - free(wcopy); - - if (extra_count > 0) - { - result &= g_code_buffer_insert_lines(buffer, extra, extra_count, line, before); - - if (!result) - for (i = 0; i < extra_count; i++) - g_object_unref(G_OBJECT(extra[i])); - - free(extra); - - } - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : buffer = tampon de lignes à consulter. * -* line = ligne à l'intérieur d'un commentaire. * -* comment = nouveau commentaire à inscrire à la ligne donnée. * -* before = précise la position du commentaire. * -* creator = créateur à l'origine de la construction. * -* * -* Description : Affiche un commentaire sur une ligne de tampon dédiée. * -* * -* Retour : Bilan de l'opération : ajout ou non ? * -* * -* Remarques : - * -* * -******************************************************************************/ - -bool g_code_buffer_update_comment_area(GCodeBuffer *buffer, GBufferLine *line, const char *comment, bool before, GObject *creator) -{ - bool result; /* Bilan à retourner */ - - if (g_buffer_line_has_comment(line)) - result = _g_code_buffer_delete_lines_comment(buffer, line); - else - result = true; - - if (result) - result = _g_code_buffer_write_comment_area(buffer, line, comment, before, creator); - - /* TODO : emit() */ - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : buffer = tampon de lignes à consulter. * -* index = indice de ligne à l'intérieur d'un commentaire. * -* * -* Description : Retrouve la première ligne d'une zone de commentaire. * -* * -* Retour : Indice de l'adresse trouvée, ou le nombre de lignes sinon. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static size_t g_code_buffer_find_first_line_comment(const GCodeBuffer *buffer, size_t index) -{ - size_t result; /* Indice trouvé à retourner */ - GBufferLine *prev; /* Ligne précédente */ - - assert(index < buffer->used); - - bool is_first_line_of_comment(const GBufferLine *ln, const GBufferLine *pv) - { - bool first; /* Statut à renvoyer */ - BufferLineColumn merge_col; /* Colonne de fusion #1 */ - BufferLineColumn prev_merge_col; /* Colonne de fusion #2 */ - - merge_col = g_buffer_line_get_merge_start(ln); - - /** - * La ligne consultée contient toujours un commentaire. - * - * Deux cas de figures sont possibles ici : - * - * - soit du texte est présent dans la colonne "commentaires". - * Si du texte est présent avant, alors il s'agit forcément de - * la première (et unique ?) ligne de commentaire. - * - * - soit la ligne effectue une fusion des colonnes depuis BLC_DISPLAY. - * Si la ligne qui précède fait de même, il s'agit alors d'une étiquette - * ou de l'amont du commentaire. - * - */ - - if (g_buffer_line_has_text(ln, BLC_COMMENTS, BLC_COUNT)) - { - first = g_buffer_line_has_text(ln, BLC_DISPLAY, BLC_COMMENTS); - - if (!first) - { - /* La ligne d'avant doit avoir un commentaire ! */ - first = !g_buffer_line_has_text(pv, BLC_COMMENTS, BLC_COUNT); - } - - } - - else - { - /** - * Le prologue "merge_col == BLC_FIRST" n'étant pas éditable, - * la seule fusion possible ici est la suivante. - */ - assert(merge_col == BLC_DISPLAY); - - /** - * La première ligne d'un tampon est toujours un prologue. - */ - assert(pv != NULL); - - prev_merge_col = g_buffer_line_get_merge_start(pv); - - first = (prev_merge_col != BLC_DISPLAY); - - if (!first) - first = (g_buffer_line_get_flags(pv) & BLF_IS_LABEL); - - } - - return first; - - } - - for (result = index; result > 0; result--) - { - prev = (result > 0 ? buffer->lines[result - 1] : NULL); - - if (is_first_line_of_comment(buffer->lines[result], prev)) - break; - - } - - if (result == 0) - { - if (!is_first_line_of_comment(buffer->lines[0], NULL)) - result = buffer->used; - } - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : buffer = tampon de lignes à consulter. * -* index = indice de ligne à l'intérieur d'un commentaire. * -* * -* Description : Retrouve la dernière ligne d'une zone de commentaire. * -* * -* Retour : Indice de l'adresse trouvée, ou le nombre de lignes sinon. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static size_t g_code_buffer_find_last_line_comment(const GCodeBuffer *buffer, size_t index) -{ - size_t result; /* Indice trouvé à retourner */ - GBufferLine *next; /* Ligne suivante */ - - assert(index < buffer->used); - - bool is_last_line_of_comment(const GBufferLine *ln, const GBufferLine *nx) - { - bool last; /* Statut à renvoyer */ - BufferLineColumn merge_col; /* Colonne de fusion #1 */ - BufferLineColumn next_merge_col; /* Colonne de fusion #2 */ - - merge_col = g_buffer_line_get_merge_start(ln); - - /** - * La ligne consultée contient toujours un commentaire. - * - * Deux cas de figures sont possibles ici : - * - * - soit du texte est présent dans la colonne "commentaires". - * Si la ligne suivante est similaire et si du texte est présent avant, - * alors il s'agit forcément de d'un nouveau commentaire. S'il n'y a - * aucun texte, il s'agit de la suite du commentaire. - * - * - soit la ligne effectue une fusion des colonnes depuis BLC_DISPLAY. - * Si la ligne qui suit fait de même, il s'agit alors d'une étiquette - * ou de l'aval du commentaire. - * - */ - - if (g_buffer_line_has_text(ln, BLC_COMMENTS, BLC_COUNT)) - { - last = !g_buffer_line_has_text(nx, BLC_COMMENTS, BLC_COUNT); - - if (!last) - last = g_buffer_line_has_text(nx, BLC_DISPLAY, BLC_COMMENTS); - - } - - else - { - /** - * Le prologue "merge_col == BLC_FIRST" n'étant pas éditable, - * la seule fusion possible ici est la suivante. - */ - assert(merge_col == BLC_DISPLAY); - - if (nx == NULL) - last = true; - - else - { - next_merge_col = g_buffer_line_get_merge_start(nx); - - last = (next_merge_col != BLC_DISPLAY); - - if (!last) - last = (g_buffer_line_get_flags(nx) & BLF_IS_LABEL); - - } - - } - - return last; - - } - - for (result = index; result < buffer->used; result++) - { - next = ((result + 1) < buffer->used ? buffer->lines[result + 1] : NULL); - - if (is_last_line_of_comment(buffer->lines[result], next)) - break; - - } - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : buffer = tampon de lignes à consulter. * -* line = ligne à l'intérieur d'un commentaire. * -* * -* Description : Retrouve le créateur d'un commentaire existant. * -* * -* Retour : Instance trouvée à déréférencer ensuite ou NULL si aucune. * -* * -* Remarques : - * -* * -******************************************************************************/ - -GObject *g_code_buffer_get_comment_creator(const GCodeBuffer *buffer, const GBufferLine *line) -{ - GObject *result; /* Instance à retourner */ - BufferLineColumn merge_col; /* Colonne de fusion */ - - if (g_buffer_line_has_comment(line)) - { - merge_col = g_buffer_line_get_merge_start(line); - - if (merge_col == BLC_DISPLAY) - result = g_buffer_line_find_first_segment_creator(line, BLC_DISPLAY); - else - result = g_buffer_line_find_first_segment_creator(line, BLC_COMMENTS); - - } - - else - result = NULL; - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : buffer = tampon de lignes à consulter. * -* line = ligne à l'intérieur d'un commentaire. * -* * -* Description : Récupère le contenu d'un commentaire existant. * -* * -* Retour : Commentaire retrouver à libérer ou NULL en cas d'échec. * -* * -* Remarques : - * -* * -******************************************************************************/ - -char *g_code_buffer_get_lines_comment(const GCodeBuffer *buffer, const GBufferLine *line) -{ - char *result; /* Contenu à retourner */ - size_t index; /* Indice de la ligne fournie */ - size_t start; /* Ligne de départ */ - size_t end; /* Ligne d'arrivée */ - BufferLineColumn merge_col; /* Colonne de fusion */ - size_t i; /* Boucle de parcours */ - char *extra; /* Commentaire supplémentaire */ - - /* Pas de prologue ici ! */ - assert(g_buffer_line_has_comment(line)); - - result = NULL; - - index = g_code_buffer_find_index_by_line(buffer, line); - - if (index == buffer->used) - goto gcbglc_exit; - - start = g_code_buffer_find_first_line_comment(buffer, index); - - if (start == buffer->used) - goto gcbglc_exit; - - end = g_code_buffer_find_last_line_comment(buffer, index); - - if (end == buffer->used) - goto gcbglc_exit; - - merge_col = g_buffer_line_get_merge_start(line); - - for (i = start; i <= end; i++) - { - if (merge_col == BLC_DISPLAY) - extra = g_buffer_line_get_text(buffer->lines[i], BLC_DISPLAY, BLC_COUNT, false); - - else - extra = g_buffer_line_get_text(buffer->lines[i], BLC_COMMENTS, BLC_COUNT, false); - - assert(extra != NULL); - - if (result == NULL) - result = extra; - - else - { - result = stradd(result, extra); - free(extra); - } - - } - - gcbglc_exit: - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : buffer = tampon de lignes à modifier. * -* line = ligne à l'intérieur d'un commentaire. * -* * -* Description : Supprime un commentaire existant. * -* * -* Retour : Bilan de l'opération. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static bool _g_code_buffer_delete_lines_comment(GCodeBuffer *buffer, GBufferLine *line) -{ - bool result; /* Bilan à retourner */ - size_t index; /* Indice de la ligne fournie */ - size_t start; /* Ligne de départ */ - size_t end; /* Ligne d'arrivée */ - BufferLineColumn merge_col; /* Colonne de fusion */ - - /* Pas de prologue ici ! */ - assert(g_buffer_line_has_comment(line)); - - result = false; - - index = g_code_buffer_find_index_by_line(buffer, line); - - if (index == buffer->used) - goto gcbdlc_exit; - - start = g_code_buffer_find_first_line_comment(buffer, index); - - if (start == buffer->used) - goto gcbdlc_exit; - - end = g_code_buffer_find_last_line_comment(buffer, index); - - if (end == buffer->used) - goto gcbdlc_exit; - - result = true; - - merge_col = g_buffer_line_get_merge_start(line); - - if (merge_col == BLC_DISPLAY) - g_code_buffer_delete_lines(buffer, start, end); - - else - { - g_buffer_line_delete_text(buffer->lines[start], BLC_COMMENTS, BLC_COUNT); - - if (end > start) - g_code_buffer_delete_lines(buffer, start + 1, end); - - } - - gcbdlc_exit: - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : buffer = tampon de lignes à modifier. * -* line = ligne à l'intérieur d'un commentaire. * -* * -* Description : Supprime un commentaire existant. * -* * -* Retour : Bilan de l'opération. * -* * -* Remarques : - * -* * -******************************************************************************/ - -bool g_code_buffer_delete_lines_comment(GCodeBuffer *buffer, GBufferLine *line) -{ - bool result; /* Bilan à retourner */ - - result = _g_code_buffer_delete_lines_comment(buffer, line); - - /* TODO : emit() */ - - return result; - -} - - - -/* ---------------------------------------------------------------------------------- */ /* TAMPON POUR CODE DESASSEMBLE */ /* ---------------------------------------------------------------------------------- */ @@ -1130,6 +440,7 @@ static void g_code_buffer_class_init(GCodeBufferClass *class) static void g_code_buffer_init(GCodeBuffer *buffer) { + buffer->tracker = g_width_tracker_new(buffer); } @@ -1161,138 +472,38 @@ GCodeBuffer *g_code_buffer_new(BufferLineColumn main) /****************************************************************************** * * -* Paramètres : buffer = composant GTK à mettre à jour. * -* addr = adresse où va se situer la ligne. * -* first = indique si on l'arrête à la première ou la dernière.* +* Paramètres : buffer = composant GLib à consulter. * * * -* Description : Convertit une adresse en indice de ligne. * +* Description : Compte le nombre de lignes rassemblées dans un tampon. * * * -* Retour : Indice de l'adresse trouvée, ou le nombre de lignes sinon. * +* Retour : Nombre de lignes constituant le tampon. * * * * Remarques : - * * * ******************************************************************************/ -static size_t g_code_buffer_get_index_from_address(const GCodeBuffer *buffer, const vmpa2t *addr, bool first) +size_t g_code_buffer_count_lines(const GCodeBuffer *buffer) { - size_t result; /* Indice à retourner */ - GBufferLine **found; /* Renvoi vers une trouvaille */ - const mrange_t *range; /* Couverture d'une ligne */ - - /** - * Si aucune adresse (ie. aucune limite ?) n'est précisée, on se base sur - * la direction pour trouver le bon indice. - */ - - if (addr == NULL) - result = (first ? 0 : buffer->used - 1); - - /** - * Sinon on parcourt méthodiquement toutes les lignes ! - */ - - else - { - /* Recherche dichotomique grossière */ - - int cmp_addr_and_line(const vmpa2t *addr, const GBufferLine **line) - { - int status; /* Bilan d'une comparaison */ - const mrange_t *lrange; /* Couverture d'une ligne */ - - lrange = g_buffer_line_get_range(*line); - - status = cmp_mrange_with_vmpa(lrange, addr); - - return status; - - } - - found = bsearch(addr, buffer->lines, buffer->used, sizeof(GBufferLine *), - (__compar_fn_t)cmp_addr_and_line); - - /* Dernier raffinage pour approcher la cible réelle */ - - if (found == NULL) - result = buffer->used; - - else - { - result = found - buffer->lines; - - if (first) - for (; result > 0; result--) - { - range = g_buffer_line_get_range(buffer->lines[result - 1]); - if (!mrange_contains_addr(range, addr)) break; - } - - else - for (; (result + 1) < buffer->used; result++) - { - range = g_buffer_line_get_range(buffer->lines[result + 1]); - if (!mrange_contains_addr(range, addr)) break; - } - - } - - } - - return result; + return buffer->used; } /****************************************************************************** * * -* Paramètres : buffer = tampon contentenant un ensemble de lignes. * -* first = première ligne modifiée à considérer. * -* last = dernière ligne modifiée à considérer. * +* Paramètres : buffer = composant GLib à consulter. * * * -* Description : Actualise les largeurs maximales par groupes de lignes. * +* Description : Fournit un lien vers la structure de suivi de largeurs. * * * -* Retour : - * +* Retour : Gestionnaire de largeurs de lignes. * * * * Remarques : - * * * ******************************************************************************/ -static void g_code_buffer_update_line_max_widths(const GCodeBuffer *buffer, size_t first, size_t last) +const GWidthTracker *g_code_buffer_get_width_tracker(const GCodeBuffer *buffer) { - GBufferLine **lines; /* Liste des lignes à traiter */ - size_t start; /* Début de groupe de largeurs */ - size_t end; /* Fin de groupe de largeurs */ - GBufferLine *manager; /* Ligne de gestion de largeurs*/ - size_t i; /* Boucle de parcours */ - - assert(buffer->used > 0); - - lines = buffer->lines; - - /* Recherche des bornes du groupe de largeurs courant */ - - for (start = first; start > 0; start--) - if (g_buffer_line_get_flags(lines[start]) & BLF_WIDTH_MANAGER) - break; - - for (end = last; end < (buffer->used - 1); end++) - if (g_buffer_line_get_flags(lines[end + 1]) & BLF_WIDTH_MANAGER) - break; - - /* Réinitialisation ciblée des largeurs */ - - assert(g_buffer_line_get_flags(lines[start]) & BLF_WIDTH_MANAGER); - - manager = NULL; - - for (i = start; i <= end; i++) - { - if (g_buffer_line_get_flags(lines[i]) & BLF_WIDTH_MANAGER) - manager = lines[i]; - - g_buffer_line_update_max_widths(lines[i], manager); - - } + return buffer->tracker; } @@ -1424,11 +635,9 @@ static void g_code_buffer_insert_lines_at(GCodeBuffer *buffer, GBufferLine **lin /* Recueil initial des largeurs */ - /** - * Comme des optimisations reposant sur des cas particuliers peuvent être - * réalisées ici, c'est à l'appelant de prendre cette charge de calculs à - * son compte ! - */ + g_width_tracker_update_added(buffer->tracker, index, count); + + g_code_buffer_notify_size_changed(buffer, true, index, count); } @@ -1448,23 +657,8 @@ static void g_code_buffer_insert_lines_at(GCodeBuffer *buffer, GBufferLine **lin void g_code_buffer_append_new_line(GCodeBuffer *buffer, GBufferLine *line) { - GBufferLine *manager; /* Ligne de gestion de largeurs*/ - g_code_buffer_insert_lines_at(buffer, (GBufferLine *[]) { line }, 1, buffer->used); - /* Recueil initial des largeurs */ - - if (g_buffer_line_get_flags(line) & BLF_WIDTH_MANAGER) - manager = line; - - else - { - assert(buffer->used > 1); - manager = g_buffer_line_get_width_manager(buffer->lines[buffer->used - 2]); - } - - g_buffer_line_update_max_widths(line, manager); - } @@ -1502,7 +696,6 @@ bool g_code_buffer_insert_lines(GCodeBuffer *buffer, GBufferLine **lines, size_t g_code_buffer_insert_lines_at(buffer, lines, count, index); - g_code_buffer_update_line_max_widths(buffer, index, index + count); result = true; @@ -1547,8 +740,15 @@ void g_code_buffer_delete_lines(GCodeBuffer *buffer, size_t start, size_t end) } - memmove(&buffer->lines[start], &buffer->lines[end + 1], - (buffer->used - end - 1) * sizeof(GBufferLine *)); + if ((end + 1) < buffer->used) + memmove(&buffer->lines[start], &buffer->lines[end + 1], + (buffer->used - end - 1) * sizeof(GBufferLine *)); + + buffer->used -= (end - start + 1); + + g_width_tracker_update_deleted(buffer->tracker, start, end); + + g_code_buffer_notify_size_changed(buffer, false, start, end - start + 1); } @@ -1625,6 +825,8 @@ GBufferLine *g_code_buffer_find_line_by_index(const GCodeBuffer *buffer, size_t { GBufferLine *result; /* Ligne trouvée à retourner */ + /* TODO : ref */ + if (index < buffer->used) result = buffer->lines[index]; else @@ -1637,6 +839,90 @@ GBufferLine *g_code_buffer_find_line_by_index(const GCodeBuffer *buffer, size_t /****************************************************************************** * * +* Paramètres : buffer = composant GTK à mettre à jour. * +* addr = adresse où va se situer la ligne. * +* first = indique si on l'arrête à la première ou la dernière.* +* * +* Description : Convertit une adresse en indice de ligne. * +* * +* Retour : Indice de l'adresse trouvée, ou le nombre de lignes sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +size_t g_code_buffer_get_index_from_address(const GCodeBuffer *buffer, const vmpa2t *addr, bool first) +{ + size_t result; /* Indice à retourner */ + GBufferLine **found; /* Renvoi vers une trouvaille */ + const mrange_t *range; /* Couverture d'une ligne */ + + /** + * Si aucune adresse (ie. aucune limite ?) n'est précisée, on se base sur + * la direction pour trouver le bon indice. + */ + + if (addr == NULL) + result = (first ? 0 : buffer->used - 1); + + /** + * Sinon on parcourt méthodiquement toutes les lignes ! + */ + + else + { + /* Recherche dichotomique grossière */ + + int cmp_addr_and_line(const vmpa2t *addr, const GBufferLine **line) + { + int status; /* Bilan d'une comparaison */ + const mrange_t *lrange; /* Couverture d'une ligne */ + + lrange = g_buffer_line_get_range(*line); + + status = cmp_mrange_with_vmpa(lrange, addr); + + return status; + + } + + found = bsearch(addr, buffer->lines, buffer->used, sizeof(GBufferLine *), + (__compar_fn_t)cmp_addr_and_line); + + /* Dernier raffinage pour approcher la cible réelle */ + + if (found == NULL) + result = buffer->used; + + else + { + result = found - buffer->lines; + + if (first) + for (; result > 0; result--) + { + range = g_buffer_line_get_range(buffer->lines[result - 1]); + if (!mrange_contains_addr(range, addr)) break; + } + + else + for (; (result + 1) < buffer->used; result++) + { + range = g_buffer_line_get_range(buffer->lines[result + 1]); + if (!mrange_contains_addr(range, addr)) break; + } + + } + + } + + return result; + +} + + +/****************************************************************************** +* * * Paramètres : buffer = tampon de lignes à consulter. * * line = ligne dont l'indice est à retrouver. * * * @@ -1762,144 +1048,126 @@ GDelayedWork *g_buffer_code_scan(GCodeBuffer *buffer, const vmpa2t *start, const /* ---------------------------------------------------------------------------------- */ -/* VUE PARTICULIERE D'UN TAMPON DE CODE */ +/* CONFORTS POUR LES COMMENTAIRES */ /* ---------------------------------------------------------------------------------- */ -/* 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. * +* Paramètres : buffer = tampon de lignes à consulter. * +* line = ligne à l'intérieur d'un commentaire. * +* comment = nouveau commentaire à inscrire à la ligne donnée. * +* creator = créateur à l'origine de la construction. * * * -* Description : Procède à l'initialisation d'une classe de vue de tampon. * +* Description : Affiche un commentaire sur une ligne de tampon donnée. * * * -* Retour : - * +* Retour : Bilan de l'opération : ajout ou non ? * * * * Remarques : - * * * ******************************************************************************/ -static void g_buffer_view_class_init(GBufferViewClass *class) +static bool _g_code_buffer_write_inlined_comment(GCodeBuffer *buffer, GBufferLine *line, const char *comment, GObject *creator) { - GObjectClass *object; /* Autre version de la classe */ + bool result; /* Bilan à retourner */ + const mrange_t *range; /* Emplace de ligne à utiliser */ + char *wcopy; /* Copie de travail */ + GBufferLine **extra; /* Lignes supplémentaires */ + size_t extra_count; /* Quantité de ces lignes */ + char *saveptr; /* Sauvegarde pour la sécurité */ + char *token; /* Fragment à insérer */ + size_t len; /* Taille dudit fragment */ + GBufferSegment *segment; /* Segment à marquer au fer */ + GBufferLine *new; /* Nouvelle ligne créée */ + size_t i; /* Boucle de parcours */ - object = G_OBJECT_CLASS(class); + assert(!g_buffer_line_has_comment(line)); - object->dispose = (GObjectFinalizeFunc/* ! */)g_buffer_view_dispose; - object->finalize = (GObjectFinalizeFunc)g_buffer_view_finalize; + result = false; - 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__OBJECT, - G_TYPE_NONE, 0); + range = g_buffer_line_get_range(line); -} + wcopy = strdup(comment); + extra = NULL; + extra_count = 0; -/****************************************************************************** -* * -* Paramètres : buffer = composant GTK à initialiser. * -* * -* Description : Procède à l'initialisation d'une vue d'un tampon pour code. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ + for (token = strtok_r(wcopy, COMMENT_LINE_SEP, &saveptr); + token != NULL; + token = strtok_r(NULL, COMMENT_LINE_SEP, &saveptr)) + { + len = strlen(token); -static void g_buffer_view_init(GBufferView *buffer) -{ - buffer->first_index = 0; + if (!result) + { + segment = g_buffer_line_insert_text(line, BLC_COMMENTS, token, len, RTT_COMMENT); + g_buffer_segment_set_creator(segment, creator); + } - g_buffer_view_reset_required_height(buffer); - g_buffer_view_reset_required_widths(buffer); + else + { + new = g_code_buffer_prepare_new_line(buffer, range); -} + segment = g_buffer_line_insert_text(new, BLC_COMMENTS, token, len, RTT_COMMENT); + g_buffer_segment_set_creator(segment, creator); + extra = (GBufferLine **)realloc(extra, ++extra_count * sizeof(GBufferLine *)); -/****************************************************************************** -* * -* Paramètres : view = instance d'objet GLib à traiter. * -* * -* Description : Supprime toutes les références externes. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ + extra[extra_count - 1] = new; -static void g_buffer_view_dispose(GBufferView *view) -{ - g_object_unref(G_OBJECT(view->buffer)); + } - G_OBJECT_CLASS(g_buffer_view_parent_class)->dispose(G_OBJECT(view)); + result = true; -} + } + free(wcopy); -/****************************************************************************** -* * -* Paramètres : view = instance d'objet GLib à traiter. * -* * -* Description : Procède à la libération totale de la mémoire. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ + if (extra_count > 0) + { + result &= g_code_buffer_insert_lines(buffer, extra, extra_count, line, false); -static void g_buffer_view_finalize(GBufferView *view) -{ - if (!view->external) - exit_segment_content_list(view->highlighted); + if (!result) + for (i = 0; i < extra_count; i++) + g_object_unref(G_OBJECT(extra[i])); - G_OBJECT_CLASS(g_buffer_view_parent_class)->finalize(G_OBJECT(view)); + free(extra); + + } + + return result; } /****************************************************************************** * * -* Paramètres : buffer = tampon à représenter à l'écran. * -* widget = composant GTK de destination pour le rendu. * +* Paramètres : buffer = tampon de lignes à consulter. * +* line = ligne à l'intérieur d'un commentaire. * +* comment = nouveau commentaire à inscrire à la ligne donnée. * +* creator = créateur à l'origine de la construction. * * * -* Description : Crée une nouvelle vue d'un tampon pour code désassemblé. * +* Description : Affiche un commentaire sur une ligne de tampon donnée. * * * -* Retour : Composant GTK créé. * +* Retour : Bilan de l'opération : ajout ou non ? * * * * Remarques : - * * * ******************************************************************************/ -GBufferView *g_buffer_view_new(GCodeBuffer *buffer, segcnt_list *highlighted) +bool g_code_buffer_update_inlined_comment(GCodeBuffer *buffer, GBufferLine *line, const char *comment, GObject *creator) { - GBufferView *result; /* Composant à retourner */ - - result = g_object_new(G_TYPE_BUFFER_VIEW, NULL); - - g_object_ref(G_OBJECT(buffer)); - - result->buffer = buffer; - - g_buffer_view_restrict(result, NULL, NULL); - - g_signal_connect(buffer, "line-changed", G_CALLBACK(on_buffer_line_changed), result); + bool result; /* Bilan à retourner */ - if (highlighted != NULL) - result->highlighted = highlighted; + if (g_buffer_line_has_comment(line)) + result = _g_code_buffer_delete_lines_comment(buffer, line); else - result->highlighted = init_segment_content_list(); + result = true; + + if (result) + result = _g_code_buffer_write_inlined_comment(buffer, line, comment, creator); - result->external = (highlighted != NULL); + /* TODO : emit() */ return result; @@ -1908,314 +1176,213 @@ GBufferView *g_buffer_view_new(GCodeBuffer *buffer, segcnt_list *highlighted) /****************************************************************************** * * -* Paramètres : buffer = tampon de lignes cohérentes à manipuler. * -* line = ligne dont la définition vient d'évoluer. * -* segment = éventuel segment qui vient d'évoluer ou NULL. * -* view = vue active du tampon de lignes concerné. * +* Paramètres : buffer = tampon de lignes à consulter. * +* line = ligne à l'intérieur d'un commentaire. * +* comment = nouveau commentaire à inscrire à la ligne donnée. * +* before = précise la position du commentaire. * +* creator = créateur à l'origine de la construction. * * * -* Description : Réagit à un changement de contenu d'une ligne donnée. * +* Description : Affiche un commentaire sur une ligne de tampon dédiée. * * * -* Retour : - * +* Retour : Bilan de l'opération : ajout ou non ? * * * * Remarques : - * * * ******************************************************************************/ -static void on_buffer_line_changed(GCodeBuffer *buffer, GBufferLine *line, GBufferSegment *segment, GBufferView *view) +static bool _g_code_buffer_write_comment_area(GCodeBuffer *buffer, GBufferLine *line, const char *comment, bool before, GObject *creator) { - /* TODO : regarder si la vue et concernée et cibler d'avantage l'actualisation */ - - g_signal_emit_by_name(view, "need-redraw"); + bool result; /* Bilan à retourner */ + const mrange_t *range; /* Emplace de ligne à utiliser */ + char *wcopy; /* Copie de travail */ + GBufferLine **extra; /* Lignes supplémentaires */ + size_t extra_count; /* Quantité de ces lignes */ + char *saveptr; /* Sauvegarde pour la sécurité */ + char *token; /* Fragment à insérer */ + size_t len; /* Taille dudit fragment */ + GBufferLine *new; /* Nouvelle ligne créée */ + GBufferSegment *segment; /* Segment à marquer au fer */ + size_t i; /* Boucle de parcours */ -} + assert(!g_buffer_line_has_comment(line)); + result = false; -/****************************************************************************** -* * -* 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 : - * -* * -******************************************************************************/ + range = g_buffer_line_get_range(line); -void g_buffer_view_restrict(GBufferView *view, const vmpa2t *start, const vmpa2t *end) -{ - view->start = (start != NULL ? dup_vmpa(start) : NULL); - view->end = (end != NULL ? dup_vmpa(end) : NULL); + wcopy = strdup(comment); - view->first_index = g_code_buffer_get_index_from_address(view->buffer, start, true); - view->last_index = g_code_buffer_get_index_from_address(view->buffer, end, false); + extra = NULL; + extra_count = 0; -} + for (token = strtok_r(wcopy, COMMENT_LINE_SEP, &saveptr); + token != NULL; + token = strtok_r(NULL, COMMENT_LINE_SEP, &saveptr)) + { + len = strlen(token); + new = g_code_buffer_prepare_new_line(buffer, range); + g_buffer_line_start_merge_at(new, BLC_DISPLAY); -/****************************************************************************** -* * -* Paramètres : view = visualisateur à mettre à jour. * -* 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 : - * -* * -* Remarques : - * -* * -******************************************************************************/ + segment = g_buffer_line_insert_text(new, BLC_DISPLAY, token, len, RTT_COMMENT); + g_buffer_segment_set_creator(segment, creator); -void g_buffer_view_get_restrictions(GBufferView *view, vmpa2t *start, vmpa2t *end) -{ - /* FIXME view->xxx == NULL -> plantage */ + extra = (GBufferLine **)realloc(extra, ++extra_count * sizeof(GBufferLine *)); - if (start != NULL) copy_vmpa(start, view->start); - if (end != NULL) copy_vmpa(end, view->end); + extra[extra_count - 1] = new; -} + result = true; + } -/****************************************************************************** -* * -* 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 : - * -* * -******************************************************************************/ + free(wcopy); -GCodeBuffer *g_buffer_view_get_buffer(const GBufferView *view) -{ - return view->buffer; + if (extra_count > 0) + { + result &= g_code_buffer_insert_lines(buffer, extra, extra_count, line, before); -} + if (!result) + for (i = 0; i < extra_count; i++) + g_object_unref(G_OBJECT(extra[i])); + free(extra); -/****************************************************************************** -* * -* Paramètres : view = visualisation à consulter. * -* * -* Description : Réinitialise le cache de la hauteur des lignes. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ + } -static void g_buffer_view_reset_required_height(GBufferView *view) -{ - view->line_height = -1; + return result; } /****************************************************************************** * * -* Paramètres : view = visualisation à consulter. * +* Paramètres : buffer = tampon de lignes à consulter. * +* line = ligne à l'intérieur d'un commentaire. * +* comment = nouveau commentaire à inscrire à la ligne donnée. * +* before = précise la position du commentaire. * +* creator = créateur à l'origine de la construction. * * * -* Description : Réinitialise le cache des largeurs de colonne calculées. * +* Description : Affiche un commentaire sur une ligne de tampon dédiée. * * * -* Retour : - * +* Retour : Bilan de l'opération : ajout ou non ? * * * * Remarques : - * * * ******************************************************************************/ -static void g_buffer_view_reset_required_widths(GBufferView *view) +bool g_code_buffer_update_comment_area(GCodeBuffer *buffer, GBufferLine *line, const char *comment, bool before, GObject *creator) { - unsigned int i; /* Boucle de parcours */ - - for (i = 0; i < BLC_COUNT; i++) - view->max_widths[i] = -1; - - view->merged_width = 0; + bool result; /* Bilan à retourner */ -} + if (g_buffer_line_has_comment(line)) + result = _g_code_buffer_delete_lines_comment(buffer, line); + else + result = true; + if (result) + result = _g_code_buffer_write_comment_area(buffer, line, comment, before, creator); -/****************************************************************************** -* * -* Paramètres : view = visualisation à mettre à jour. * -* * -* Description : Calcule la hauteur requise par une visualisation. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ + /* TODO : emit() */ -static void g_buffer_view_compute_required_height(GBufferView *view) -{ - view->line_height = 17; + return result; } /****************************************************************************** * * -* Paramètres : view = visualisation à mettre à jour. * -* display = règles d'affichage des colonnes modulables. * +* Paramètres : buffer = tampon de lignes à consulter. * +* index = indice de ligne à l'intérieur d'un commentaire. * * * -* Description : Calcule les largeurs requises par une visualisation. * +* Description : Retrouve la première ligne d'une zone de commentaire. * * * -* Retour : - * +* Retour : Indice de l'adresse trouvée, ou le nombre de lignes sinon. * * * * Remarques : - * * * ******************************************************************************/ -static void g_buffer_view_compute_required_widths(GBufferView *view, const bool *display) +static size_t g_code_buffer_find_first_line_comment(const GCodeBuffer *buffer, size_t index) { - GBufferLine **lines; /* Liste des lignes à traiter */ - size_t first; /* Première ligne intégrée */ - size_t last; /* Dernière ligne intégrée */ - size_t i; /* Boucle de parcours */ - - if (!HEIGHT_CACHED(view)) - g_buffer_view_compute_required_height(view); - - lines = view->buffer->lines; - - first = g_code_buffer_get_index_from_address(view->buffer, view->start, true); - last = g_code_buffer_get_index_from_address(view->buffer, view->end, false); + size_t result; /* Indice trouvé à retourner */ + GBufferLine *prev; /* Ligne précédente */ - view->left_margin = 2 * view->line_height; - view->left_text = 2.5 * view->line_height; + assert(index < buffer->used); - if (view->buffer->used > 0) + bool is_first_line_of_comment(const GBufferLine *ln, const GBufferLine *pv) { - //g_code_buffer_update_line_max_widths(view->buffer, first, last); - - for (i = first; i <= last; i++) - g_buffer_line_apply_max_widths(lines[i], view->max_widths, &view->merged_width); - - } - -} - - -/****************************************************************************** -* * -* Paramètres : view = visualisation à consulter. * -* * -* Description : Fournit la hauteur d'impression d'une ligne visualisée. * -* * -* Retour : Hauteur de ligne en pixel. * -* * -* Remarques : - * -* * -******************************************************************************/ - -gint g_buffer_view_get_line_height(GBufferView *view) -{ - if (!HEIGHT_CACHED(view)) - g_buffer_view_compute_required_height(view); + bool first; /* Statut à renvoyer */ + BufferLineColumn merge_col; /* Colonne de fusion #1 */ + BufferLineColumn prev_merge_col; /* Colonne de fusion #2 */ - return view->line_height; + merge_col = g_buffer_line_get_merge_start(ln); -} + /** + * La ligne consultée contient toujours un commentaire. + * + * Deux cas de figures sont possibles ici : + * + * - soit du texte est présent dans la colonne "commentaires". + * Si du texte est présent avant, alors il s'agit forcément de + * la première (et unique ?) ligne de commentaire. + * + * - soit la ligne effectue une fusion des colonnes depuis BLC_DISPLAY. + * Si la ligne qui précède fait de même, il s'agit alors d'une étiquette + * ou de l'amont du commentaire. + * + */ + if (g_buffer_line_has_text(ln, BLC_COMMENTS, BLC_COUNT)) + { + first = g_buffer_line_has_text(ln, BLC_DISPLAY, BLC_COMMENTS); -/****************************************************************************** -* * -* Paramètres : view = visualisation à consulter. * -* display = règles d'affichage des colonnes modulables. * -* * -* Description : Fournit la largeur requise par une visualisation. * -* * -* Retour : Dimension calculée. * -* * -* Remarques : - * -* * -******************************************************************************/ + if (!first) + { + /* La ligne d'avant doit avoir un commentaire ! */ + first = !g_buffer_line_has_text(pv, BLC_COMMENTS, BLC_COUNT); + } -gint g_buffer_view_get_width(GBufferView *view, const bool *display) -{ - gint result; /* Taille à retourner */ - gint col_width; /* Calcul selon les colonnes */ - gint full_width; /* Calcul selon les fusions */ - BufferLineColumn i; /* Boucle de parcours */ + } - if (!WIDTHS_CACHED(view)) - g_buffer_view_compute_required_widths(view, display); + else + { + /** + * Le prologue "merge_col == BLC_FIRST" n'étant pas éditable, + * la seule fusion possible ici est la suivante. + */ + assert(merge_col == BLC_DISPLAY); - result = view->left_text; + /** + * La première ligne d'un tampon est toujours un prologue. + */ + assert(pv != NULL); - col_width = 0; - full_width = 0; + prev_merge_col = g_buffer_line_get_merge_start(pv); - /* Première méthode */ + first = (prev_merge_col != BLC_DISPLAY); - for (i = 0; i < BLC_COUNT; i++) - { - if (i < BLC_DISPLAY && !display[i]) continue; + if (!first) + first = (g_buffer_line_get_flags(pv) & BLF_IS_LABEL); - col_width += view->max_widths[i]; + } - if ((i + 1) < BLC_COUNT) - col_width += COL_MARGIN; + return first; } - /* Seconde méthode */ - - for (i = 0; i < BLC_DISPLAY; i++) + for (result = index; result > 0; result--) { - if (!display[i]) continue; + prev = (result > 0 ? buffer->lines[result - 1] : NULL); - full_width += view->max_widths[i] + COL_MARGIN; + if (is_first_line_of_comment(buffer->lines[result], prev)) + break; } - full_width += view->merged_width; - - /* Mise en concurrence et poursuite... */ - - result += + MAX(col_width, full_width); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : view = visualisation à consulter. * -* display = 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 bool *display) -{ - gint result; /* Taille à retourner */ - BufferLineColumn i; /* Boucle de parcours */ - - if (!WIDTHS_CACHED(view)) - g_buffer_view_compute_required_widths(view, display); - - result = view->left_text; - - for (i = 0; i < BLC_DISPLAY; i++) + if (result == 0) { - if (!display[i]) continue; - - result += view->max_widths[i] + COL_MARGIN; - + if (!is_first_line_of_comment(buffer->lines[0], NULL)) + result = buffer->used; } return result; @@ -2225,226 +1392,130 @@ gint g_buffer_view_get_margin(GBufferView *view, const bool *display) /****************************************************************************** * * -* 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 */ - size_t first; /* Première ligne intégrée */ - size_t last; /* Dernière ligne intégrée */ - - result = view->line_height; - - first = g_code_buffer_get_index_from_address(view->buffer, view->start, true); - last = g_code_buffer_get_index_from_address(view->buffer, view->end, false); - - result *= (last - first + 1); - - 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. * -* display = règles d'affichage des colonnes modulables. * -* caret = position du curseur à construire. [OUT] * +* Paramètres : buffer = tampon de lignes à consulter. * +* index = indice de ligne à l'intérieur d'un commentaire. * * * -* Description : Calcule la position idéale de curseur pour un point donné. * +* Description : Retrouve la dernière ligne d'une zone de commentaire. * * * -* Retour : Adresse si une a pu être déterminée, NULL sinon. * +* Retour : Indice de l'adresse trouvée, ou le nombre de lignes sinon. * * * * Remarques : - * * * ******************************************************************************/ -const vmpa2t *g_buffer_view_compute_caret(GBufferView *view, gint x, gint y, const bool *display, GdkRectangle *caret) +static size_t g_code_buffer_find_last_line_comment(const GCodeBuffer *buffer, size_t index) { - gint remaining; /* Copie de travail modifiable */ - size_t index; /* Indice de ligne de tampon */ - GBufferLine *line; /* Ligne à la position courante*/ - GBufferSegment *segment; /* Segment présent sur la place*/ - - remaining = x; - - line = g_buffer_view_find_line_and_segment_at(view, &remaining, y, &index, display, &segment); - - if (line == NULL) return NULL; - if (segment == NULL) printf(" -- no segment\n"); - if (segment == NULL) return NULL; - - - - - - printf("\n[BASE] orig = %d tronc = %d reste = %d dernier = %d largeur = %d\n", - x, x - remaining, remaining, g_buffer_segment_get_caret_position(segment, remaining), - g_buffer_segment_get_width(segment)); + size_t result; /* Indice trouvé à retourner */ + GBufferLine *next; /* Ligne suivante */ - printf(" '%s'\n", g_buffer_segment_get_text(segment, false)); + assert(index < buffer->used); + bool is_last_line_of_comment(const GBufferLine *ln, const GBufferLine *nx) + { + bool last; /* Statut à renvoyer */ + BufferLineColumn merge_col; /* Colonne de fusion #1 */ + BufferLineColumn next_merge_col; /* Colonne de fusion #2 */ + merge_col = g_buffer_line_get_merge_start(ln); + /** + * La ligne consultée contient toujours un commentaire. + * + * Deux cas de figures sont possibles ici : + * + * - soit du texte est présent dans la colonne "commentaires". + * Si la ligne suivante est similaire et si du texte est présent avant, + * alors il s'agit forcément de d'un nouveau commentaire. S'il n'y a + * aucun texte, il s'agit de la suite du commentaire. + * + * - soit la ligne effectue une fusion des colonnes depuis BLC_DISPLAY. + * Si la ligne qui suit fait de même, il s'agit alors d'une étiquette + * ou de l'aval du commentaire. + * + */ - caret->x = /*view->left_text +*/ (x - remaining) + g_buffer_segment_get_caret_position(segment, remaining); + if (g_buffer_line_has_text(ln, BLC_COMMENTS, BLC_COUNT)) + { + last = !g_buffer_line_has_text(nx, BLC_COMMENTS, BLC_COUNT); - caret->y = (index - view->first_index) * view->line_height; + if (!last) + last = g_buffer_line_has_text(nx, BLC_DISPLAY, BLC_COMMENTS); - caret->width = 2; - caret->height = view->line_height; + } - return get_mrange_addr(g_buffer_line_get_range(line)); + else + { + /** + * Le prologue "merge_col == BLC_FIRST" n'étant pas éditable, + * la seule fusion possible ici est la suivante. + */ + assert(merge_col == BLC_DISPLAY); -} + if (nx == NULL) + last = true; + else + { + next_merge_col = g_buffer_line_get_merge_start(nx); -/****************************************************************************** -* * -* Paramètres : view = vue de tampon à mettre à jour. * -* line = ligne correspondant à la position. * -* index = indice de cette même ligne dans le tampon. * -* x = abscisse de la zone principale à traiter. * -* display = règles d'affichage des colonnes modulables. * -* caret = position du curseur à construire. [OUT] * -* * -* Description : Calcule la position idéale de curseur pour un point donné. * -* * -* Retour : Adresse si une a pu être déterminée, NULL sinon. * -* * -* Remarques : - * -* * -******************************************************************************/ + last = (next_merge_col != BLC_DISPLAY); -const vmpa2t *g_buffer_view_compute_caret_full(GBufferView *view, GBufferLine *line, size_t index, gint x, const bool *display, GdkRectangle *caret) -{ - gint offset; /* Point de travail modifiable */ - gint base; /* Position absolue de segment */ - GBufferSegment *segment; /* Segment visé par le pointeur*/ + if (!last) + last = (g_buffer_line_get_flags(nx) & BLF_IS_LABEL); - offset = x; + } - offset -= view->left_text; - if (offset < 0) return NULL; + } - segment = g_buffer_line_get_segment_at(line, view->max_widths, display, &base, &offset, GDK_SCROLL_LEFT, true); - if (segment == NULL) return NULL; + return last; - caret->x = view->left_text + base + offset; + } - printf("caret Y : %zu -> %zu\n", view->first_index, index); + for (result = index; result < buffer->used; result++) + { + next = ((result + 1) < buffer->used ? buffer->lines[result + 1] : NULL); - caret->y = (index - view->first_index) * view->line_height; + if (is_last_line_of_comment(buffer->lines[result], next)) + break; - caret->width = 2; - caret->height = view->line_height; + } - return get_mrange_addr(g_buffer_line_get_range(line)); + return result; } /****************************************************************************** * * -* Paramètres : line = ligne à venir consulter. * -* caret = position du curseur à faire évoluer. * -* ctrl = indique la demande d'un parcours rapide. * -* dir = direction du parcours. * -* display = règles d'affichage des colonnes modulables. * +* Paramètres : buffer = tampon de lignes à consulter. * +* line = ligne à l'intérieur d'un commentaire. * * * -* Description : Déplace le curseur au sein d'une vue de tampon. * +* Description : Retrouve le créateur d'un commentaire existant. * * * -* Retour : true si un déplacement a été effectué, false sinon. * +* Retour : Instance trouvée à déréférencer ensuite ou NULL si aucune. * * * * Remarques : - * * * ******************************************************************************/ -static bool _g_buffer_view_move_caret(GBufferView *view, const GBufferLine *line, GdkRectangle *caret, bool ctrl, GdkScrollDirection dir, const bool *display) +GObject *g_code_buffer_get_comment_creator(const GCodeBuffer *buffer, const GBufferLine *line) { - bool result; /* Bilan à retourner */ - gint offset; /* Point de travail modifiable */ - gint base; /* Position absolue de segment */ - GBufferSegment *segment; /* Segment visé par le pointeur*/ - - - - offset = caret->x; - - offset -= view->left_text; - if (offset < 0) return false; - - segment = g_buffer_line_get_segment_at(line, view->max_widths, display, &base, &offset, dir, false); - - if (segment == NULL) printf(" ===== NO SEG...\n"); - - if (segment == NULL) return false; - - - printf(" ====== FIRST SEG :: %p ('%s')\n", segment, g_buffer_segment_get_text(segment, false)); - - - - - - - //if (dir == GDK_SCROLL_LEFT || dir == GDK_SCROLL_RIGHT) - result = g_buffer_segment_move_caret(segment, &offset, ctrl, dir); - //else - //result = true; - - printf(" ====== MOVE 1 ? %d\n", result); - - /////////////////// + GObject *result; /* Instance à retourner */ + BufferLineColumn merge_col; /* Colonne de fusion */ - if (!result) + if (g_buffer_line_has_comment(line)) { - base = 0; - - segment = g_buffer_line_find_near_segment(line, segment, view->max_widths, display, dir, &offset); - - - printf(" ====== NEAR SEG :: %p ('%s')\n", segment, segment ? g_buffer_segment_get_text(segment, false) : NULL); - - if (segment != NULL) - { - - result = true; - //result = g_buffer_segment_move_caret(segment, &offset, ctrl, dir); - - /* - if (result) - caret->x -= COL_MARGIN; - */ - - printf(" ====== MOVE 2 ? %d (offset=%d)\n", result, offset); - - - } + merge_col = g_buffer_line_get_merge_start(line); + if (merge_col == BLC_DISPLAY) + result = g_buffer_line_find_first_segment_creator(line, BLC_DISPLAY); + else + result = g_buffer_line_find_first_segment_creator(line, BLC_COMMENTS); } - - if (result) - printf(" ====== NEW CARET: %d -> %d\n", caret->x, view->left_text + base + offset); else - printf(" ====== NO NEW CARET!\n"); - - - - if (result) - caret->x = view->left_text + base + offset; + result = NULL; return result; @@ -2453,192 +1524,71 @@ static bool _g_buffer_view_move_caret(GBufferView *view, const GBufferLine *line /****************************************************************************** * * -* Paramètres : view = vue de tampon à mettre à jour. * -* caret = position du curseur à faire évoluer. * -* ctrl = indique la demande d'un parcours rapide. * -* dir = direction du parcours. * -* display = règles d'affichage des colonnes modulables. * +* Paramètres : buffer = tampon de lignes à consulter. * +* line = ligne à l'intérieur d'un commentaire. * * * -* Description : Déplace le curseur au sein d'une vue de tampon. * +* Description : Récupère le contenu d'un commentaire existant. * * * -* Retour : Adresse si une a pu être déterminée, VMPA_INVALID sinon. * +* Retour : Commentaire retrouver à libérer ou NULL en cas d'échec. * * * * Remarques : - * * * ******************************************************************************/ -const vmpa2t *g_buffer_view_move_caret(GBufferView *view, GdkRectangle *caret, bool ctrl, GdkScrollDirection dir, const bool *display) +char *g_code_buffer_get_lines_comment(const GCodeBuffer *buffer, const GBufferLine *line) { - const vmpa2t *result; /* Actualisation à renvoyer */ - size_t index; /* Indice de ligne de tampon */ - GBufferLine *line; /* Ligne sous le pointeur */ - - - bool computed; /* Récursivité pris en compte */ - gint lheight; /* Hauteur d'une ligne */ - gint left_pos; /* Retour à la ligne */ - gint right_pos; /* Position d'extrème droite */ - BufferLineColumn i; /* Boucle de parcours */ - size_t first; /* Première ligne intégrée */ - size_t last; /* Dernière ligne intégrée */ - - - - - bool moved; /* Mémorisation d'une évolut° */ - - - - - - - + char *result; /* Contenu à retourner */ + size_t index; /* Indice de la ligne fournie */ + size_t start; /* Ligne de départ */ + size_t end; /* Ligne d'arrivée */ + BufferLineColumn merge_col; /* Colonne de fusion */ + size_t i; /* Boucle de parcours */ + char *extra; /* Commentaire supplémentaire */ + /* Pas de prologue ici ! */ + assert(g_buffer_line_has_comment(line)); result = NULL; - computed = false; - - - - line = g_buffer_view_find_line_at(view, caret->y, &index); - if (line == NULL) return NULL; - - - lheight = g_buffer_view_get_line_height(view); + index = g_code_buffer_find_index_by_line(buffer, line); - switch (dir) - { - case GDK_SCROLL_UP: - case GDK_SCROLL_DOWN: - lheight = g_buffer_view_get_line_height(view); - break; - case GDK_SCROLL_LEFT: - case GDK_SCROLL_RIGHT: - left_pos = view->left_text; - if (display[BLC_PHYSICAL]) left_pos += view->max_widths[BLC_PHYSICAL] + COL_MARGIN; - if (display[BLC_VIRTUAL]) left_pos += view->max_widths[BLC_VIRTUAL] + COL_MARGIN; - if (display[BLC_BINARY]) left_pos += view->max_widths[BLC_BINARY] + COL_MARGIN; - right_pos = left_pos; - for (i = BLC_ASSEMBLY_HEAD; i < BLC_COUNT; i++) - right_pos += view->max_widths[i] + COL_MARGIN; + if (index == buffer->used) + goto gcbglc_exit; - /* -gint g_buffer_line_compute_max_width(const GBufferLine *line, BufferLineColumn index, const gint *max_widths) + start = g_code_buffer_find_first_line_comment(buffer, index); -BufferLineColumn g_buffer_line_get_merge_start(const GBufferLine *line) - */ + if (start == buffer->used) + goto gcbglc_exit; - left_pos = view->left_text; + end = g_code_buffer_find_last_line_comment(buffer, index); - break; - default: /* GDK_SCROLL_SMOOTH */ - break; - } + if (end == buffer->used) + goto gcbglc_exit; - first = view->first_index; - last = view->last_index; + merge_col = g_buffer_line_get_merge_start(line); - switch (dir) + for (i = start; i <= end; i++) { - case GDK_SCROLL_UP: - - if (index > first) - { - line = view->buffer->lines[index - 1]; - result = g_buffer_view_compute_caret_full(view, line, index - 1, caret->x, display, caret); - } - - break; - - case GDK_SCROLL_DOWN: - - if (index < last) - { - line = view->buffer->lines[index + 1]; - result = g_buffer_view_compute_caret_full(view, line, index + 1, caret->x, display, caret); - } - - break; - - case GDK_SCROLL_LEFT: - - /* - line = g_buffer_view_find_line_at(view, caret->y, &index); - if (line == NULL) break; - */ - - moved = _g_buffer_view_move_caret(view, line, caret, ctrl, GDK_SCROLL_LEFT, display); - - if (moved) - result = get_mrange_addr(g_buffer_line_get_range(line)); - - else if (index > first) - { - line = view->buffer->lines[index - 1]; - result = g_buffer_view_compute_caret_full(view, line, index - 1, INT_MAX, display, caret); - } - - break; - - case GDK_SCROLL_RIGHT: - - /* - line = g_buffer_view_find_line_at(view, caret->y, &index); - if (line == NULL) break; - */ - - moved = _g_buffer_view_move_caret(view, line, caret, ctrl, GDK_SCROLL_RIGHT, display); + if (merge_col == BLC_DISPLAY) + extra = g_buffer_line_get_text(buffer->lines[i], BLC_DISPLAY, BLC_COUNT, false); - if (moved) - result = get_mrange_addr(g_buffer_line_get_range(line)); + else + extra = g_buffer_line_get_text(buffer->lines[i], BLC_COMMENTS, BLC_COUNT, false); - else if (index < last) - { - line = view->buffer->lines[index + 1]; - result = g_buffer_view_compute_caret_full(view, line, index + 1, left_pos, display, caret); - } + assert(extra != NULL); - break; + if (result == NULL) + result = extra; - default: /* GDK_SCROLL_SMOOTH */ - break; + else + { + result = stradd(result, extra); + free(extra); + } } - /* - printf(" --- CARET --- moved = %d index = %d result = %p\n", - moved, index, result); - */ - - - /* - if (result && !computed) - result = g_buffer_view_compute_caret_full(view, caret->x, caret->y, caret, display, NULL); - */ - - 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); + gcbglc_exit: return result; @@ -2647,157 +1597,62 @@ bool g_buffer_view_unhighlight_segments(GBufferView *view) /****************************************************************************** * * -* Paramètres : view = vue de tampon à mettre à jour. * -* x = abscisse de la zone principale à traiter. * -* y = ordonnée de la zone principale à traiter. * -* display = règles d'affichage des colonnes modulables. * -* * -* 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 bool *display) -{ - bool need_redraw; /* Besoin d'actualisation ? */ - GBufferSegment *segment; /* Segment sélectionnable */ - - if (view->highlighted != NULL) - need_redraw = g_buffer_view_unhighlight_segments(view); - else - need_redraw = false; - - g_buffer_view_find_line_and_segment_at(view, &x, y, NULL, display, &segment); - - if (segment) - need_redraw |= add_segment_content_to_selection_list(view->highlighted, segment); - - if (need_redraw) - g_signal_emit_by_name(view, "need-redraw"); - - return true; - -} - - -/****************************************************************************** -* * -* Paramètres : view = visualisation à représenter. * -* cr = contexte graphique dédié à la procédure. * -* fake_x = abscisse réelle du point 0 à l'écran. * -* fake_y = ordonnée réelle du point 0 à l'écran. * -* area = position et surface à traiter. * -* display = règles d'affichage des colonnes modulables. * -* selected = ordonnée d'une ligne sélectionnée ou NULL. * +* Paramètres : buffer = tampon de lignes à modifier. * +* line = ligne à l'intérieur d'un commentaire. * * * -* Description : Imprime la visualisation du tampon de code désassemblé. * +* Description : Supprime un commentaire existant. * * * -* Retour : - * +* Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ -void g_buffer_view_draw(const GBufferView *view, cairo_t *cr, gint fake_x, gint fake_y, const cairo_rectangle_int_t *area, const bool *display, const gint *selected) +static bool _g_code_buffer_delete_lines_comment(GCodeBuffer *buffer, GBufferLine *line) { - gint real_x; /* Abscisse réelle pour tampon */ - gint real_y; /* Ordonnée réelle pour tampon */ - size_t first; /* Première ligne visée */ - size_t last; /* Dernière ligne visée + 1 */ - gint y; /* Point de départ + décallage */ - GBufferLine **lines; /* Liste des lignes à traiter */ - bool wait_selection; /* Sélection déjà passée ? */ - gint rel_selected; /* Position relative de sélect°*/ - size_t i; /* Boucle de parcours */ - - real_x = fake_x + view->left_text; - real_y = fake_y + area->y; - - first = view->first_index; - first += (real_y / view->line_height); - - last = first + (area->height / view->line_height); - if (area->height % view->line_height > 0) last++; - - last = MIN(last, view->last_index); - - y = area->y - (real_y % view->line_height); - - lines = view->buffer->lines; - - wait_selection = true; - - if (selected != NULL) - rel_selected = *selected - fake_y; - - if (view->buffer->used > 0) - for (i = first; i <= last; i++) - { - /* Si sélection, on sousligne la ligne concernée */ - if (wait_selection && selected != NULL && rel_selected == y) - { - cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 0.05); + bool result; /* Bilan à retourner */ + size_t index; /* Indice de la ligne fournie */ + size_t start; /* Ligne de départ */ + size_t end; /* Ligne d'arrivée */ + BufferLineColumn merge_col; /* Colonne de fusion */ - cairo_rectangle(cr, area->x, y, area->width, view->line_height); - cairo_fill(cr); + /* Pas de prologue ici ! */ + assert(g_buffer_line_has_comment(line)); - wait_selection = false; + result = false; - } + index = g_code_buffer_find_index_by_line(buffer, line); - g_buffer_line_draw(lines[i], cr, view->max_widths, real_x, y, display, view->highlighted); + if (index == buffer->used) + goto gcbdlc_exit; - y += view->line_height; + start = g_code_buffer_find_first_line_comment(buffer, index); - } + if (start == buffer->used) + goto gcbdlc_exit; -} + end = g_code_buffer_find_last_line_comment(buffer, index); + if (end == buffer->used) + goto gcbdlc_exit; -/****************************************************************************** -* * -* Paramètres : view = visualisation à consulter. * -* addr = adresse où retrouver la ligne recherchée. * -* flags = propriétés à vérifier en tout ou partie. * -* idx = indice de la ligne trouvée ou NULL. [OUT] * -* * -* Description : Retrouve une ligne au sein d'un tampon avec une adresse. * -* * -* Retour : Line retrouvée ou NULL en cas d'échec. * -* * -* Remarques : - * -* * -******************************************************************************/ + result = true; -GBufferLine *g_buffer_view_find_line_by_addr(const GBufferView *view, const vmpa2t *addr, BufferLineFlags flags, size_t *idx) -{ - GBufferLine *result; /* Ligne trouvée à retourner */ - phys_t length; /* Taille de la vue */ - mrange_t vrange; /* Couverture de la vue */ - bool allowed; /* Rechercher validée ? */ + merge_col = g_buffer_line_get_merge_start(line); - /* Vérification des bornes */ + if (merge_col == BLC_DISPLAY) + g_code_buffer_delete_lines(buffer, start, end); - if (view->start != NULL/* && view->end != NULL*/) + else { - length = compute_vmpa_diff(view->start, view->end); - - init_mrange(&vrange, view->start, length); + g_buffer_line_delete_text(buffer->lines[start], BLC_COMMENTS, BLC_COUNT); - allowed = mrange_contains_addr_inclusive(&vrange, addr); + if (end > start) + g_code_buffer_delete_lines(buffer, start + 1, end); } - else allowed = true; - /* Lancement des recherches ? */ - - if (allowed) - result = g_code_buffer_find_line_by_addr(view->buffer, addr, flags, idx); - else - result = NULL; + gcbdlc_exit: return result; @@ -2806,187 +1661,125 @@ GBufferLine *g_buffer_view_find_line_by_addr(const GBufferView *view, const vmpa /****************************************************************************** * * -* Paramètres : view = visualisation à consulter. * -* index = indice de la ligne recherchée. * +* Paramètres : buffer = tampon de lignes à modifier. * +* line = ligne à l'intérieur d'un commentaire. * * * -* Description : Retrouve une ligne au sein d'un tampon avec un indice. * +* Description : Supprime un commentaire existant. * * * -* Retour : Line retrouvée ou NULL en cas d'échec. * +* Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ -GBufferLine *g_buffer_view_find_line_by_index(const GBufferView *view, size_t index) +bool g_code_buffer_delete_lines_comment(GCodeBuffer *buffer, GBufferLine *line) { - GBufferLine *result; /* Ligne trouvée à retourner */ - bool allowed; /* Rechercher validée ? */ - - /* Vérification des bornes */ - - allowed = (view->first_index <= index && index < view->last_index); + bool result; /* Bilan à retourner */ - /* Lancement des recherches ? */ + result = _g_code_buffer_delete_lines_comment(buffer, line); - if (allowed) - result = view->buffer->lines[index]; - else - result = NULL; + /* TODO : emit() */ return result; } +/* ---------------------------------------------------------------------------------- */ +/* SIGNAUX IMMEDIATS POUR UNE VUE */ +/* ---------------------------------------------------------------------------------- */ + + /****************************************************************************** * * -* Paramètres : view = visualisation à consulter. * -* y = ordonnée comprise dans la ligne recherchée. * -* idx = indice de la ligne trouvée ou NULL. [OUT] * +* Paramètres : buffer = tampon de lignes à modifier. * +* cb = fonction à appeler au moment opportun. * +* data = object GLib à associer à l'appel. * * * -* Description : Fournit la ligne présente à une ordonnée donnée. * +* Description : Enregistre l'adresse d'une fonction de mise à jour de vue. * * * -* Retour : Ligne retrouvée ou NULL si aucune. * +* Retour : - * * * * Remarques : - * * * ******************************************************************************/ -GBufferLine *g_buffer_view_find_line_at(GBufferView *view, gint y, size_t *idx) +void g_code_buffer_register_view_callback(GCodeBuffer *buffer, buffer_size_changed_cb cb, GObject *data) { - gint lheight; /* Hauteur d'une ligne */ - size_t index; /* Indice attendu */ + view_callback *new; /* Informations sur l'appel */ - lheight = g_buffer_view_get_line_height(view); - index = y / lheight; + buffer->vcount++; - index += view->first_index; + buffer->vcallbacks = (view_callback *)realloc(buffer->vcallbacks, buffer->vcount * sizeof(view_callback)); - if (idx != NULL) - *idx = index; + new = &buffer->vcallbacks[buffer->vcount - 1]; - return (index < view->buffer->used ? view->buffer->lines[index] : NULL); + new->size_changed = cb; + new->data = data; } /****************************************************************************** * * -* Paramètres : view = visualisation à consulter. * -* x = abscisse comprise dans le segment recherché. [OUT] * -* y = ordonnée comprise dans la ligne recherchée. * -* idx = indice de la ligne trouvée ou NULL. [OUT] * -* display = règles d'affichage des colonnes modulables. * -* segment = portion de texte recherchée ou NULL. [OUT] * +* Paramètres : buffer = tampon de lignes à modifier. * +* data = object GLib à associer à l'appel. * * * -* Description : Fournit la ligne et son segment présents à une position. * +* Description : Supprime un élément des vues à contacter pour mises à jour. * * * -* Retour : Ligne retrouvée ou NULL si aucune. * +* Retour : - * * * * Remarques : - * * * ******************************************************************************/ -GBufferLine *g_buffer_view_find_line_and_segment_at(GBufferView *view, gint *x, gint y, size_t *idx, const bool *display, GBufferSegment **segment) +void g_code_buffer_unregister_view_callback(GCodeBuffer *buffer, GObject *data) { - GBufferLine *result; /* Ligne trouvée à retourner */ - - /* Recherche d'une ligne correspondante */ + size_t i; /* Boucle de parcours */ - result = g_buffer_view_find_line_at(view, y, idx); + for (i = 0; i < buffer->vcount; i++) + if (buffer->vcallbacks[i].data == data) + { + if ((i + 1) < buffer->vcount) + memmove(&buffer->vcallbacks[i], &buffer->vcallbacks[i + 1], + (buffer->vcount - i - 1) * sizeof(view_callback)); - /* Recherche du segment visé éventuel */ + buffer->vcount--; - if (result != NULL && segment != NULL) - { - if (*x < view->left_text) - *segment = NULL; + buffer->vcallbacks = (view_callback *)realloc(buffer->vcallbacks, + buffer->vcount * sizeof(view_callback)); - else - { - *x -= view->left_text; - *segment = g_buffer_line_get_segment_at(result, view->max_widths, display, - (gint []) { 0 }, x, GDK_SCROLL_LEFT, true); } - } - - return result; - } /****************************************************************************** * * -* Paramètres : view = 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] * -* code = s'arrête si possible à une ligne avec code. * +* Paramètres : buffer = tampon de lignes à diffuser. * +* added = indication sur la variation de la taille du tampon. * +* index = indice de la première ligne à traiter. * +* count = nombre de lignes à traiter. * * * -* Description : Indique la position d'affichage d'une adresse donnée. * +* Description : Fait suivre une variation de la quantité de lignes du tampon.* * * -* Retour : true si l'adresse fait partie du composant, false sinon. * +* Retour : - * * * * Remarques : - * * * ******************************************************************************/ -bool g_buffer_view_get_address_coordinates(GBufferView *view, const vmpa2t *addr, gint *x, gint *y, bool code) +static void g_code_buffer_notify_size_changed(const GCodeBuffer *buffer, bool added, size_t index, size_t count) { - bool result; /* Bilan à retourner */ - gint lheight; /* Hauteur d'une ligne */ - size_t first; /* Première ligne intégrée */ - size_t last; /* Dernière ligne intégrée */ size_t i; /* Boucle de parcours */ - const mrange_t *range; /* Emplacement parcouru */ - - result = false; + view_callback *cb; /* Informations sur l'appel */ - *x = 0; - *y = 0; - - lheight = g_buffer_view_get_line_height(view); - - first = g_code_buffer_get_index_from_address(view->buffer, view->start, true); - last = g_code_buffer_get_index_from_address(view->buffer, view->end, false); - - for (i = first; i <= last; i++) + for (i = 0; i < buffer->vcount; i++) { - /** - * Si l'adresse recherchée est plus petite que l'adresse de départ, - * on va effectuer un parcours complet pour rien. - * - * On considère cependant que le seul cas où celà peut arriver - * est lorsque que des découpages en blocs sont impliqués. - * - * Les découpages conduisent alors à la formation de petites zones, - * rapides à parcourir. - */ - - range = g_buffer_line_get_range(view->buffer->lines[i]); - - result = mrange_contains_addr(range, addr); - if (result) break; + cb = &buffer->vcallbacks[i]; - *y += lheight; + cb->size_changed(buffer, added, index, count, cb->data); } - if (result && code) - for (; i <= last; i++) - { - if (g_buffer_line_get_flags(view->buffer->lines[i]) & BLF_HAS_CODE) break; - - if (i == last) break; - - range = g_buffer_line_get_range(view->buffer->lines[i + 1]); - if (!mrange_contains_addr(range, addr)) break; - - *y += lheight; - - } - - return result; - } diff --git a/src/glibext/gcodebuffer.h b/src/glibext/gcodebuffer.h index 8bcbc4a..f0a7f8d 100644 --- a/src/glibext/gcodebuffer.h +++ b/src/glibext/gcodebuffer.h @@ -30,6 +30,7 @@ #include "delayed.h" #include "gbufferline.h" +#include "gwidthtracker.h" @@ -57,6 +58,12 @@ GType g_code_buffer_get_type(void); /* Crée un nouveau composant de tampon pour code désassemblé. */ GCodeBuffer *g_code_buffer_new(BufferLineColumn); +/* Compte le nombre de lignes rassemblées dans un tampon. */ +size_t g_code_buffer_count_lines(const GCodeBuffer *); + +/* Fournit un lien vers la structure de suivi de largeurs. */ +const GWidthTracker *g_code_buffer_get_width_tracker(const GCodeBuffer *); + /* Initie une nouvelle ligne devant être insérée dans le tampon. */ GBufferLine *g_code_buffer_prepare_new_line(GCodeBuffer *, const mrange_t *); @@ -86,6 +93,9 @@ GBufferLine *g_code_buffer_find_line_by_addr(const GCodeBuffer *, const vmpa2t * /* Retrouve une ligne au sein d'un tampon avec un indice. */ GBufferLine *g_code_buffer_find_line_by_index(const GCodeBuffer *, size_t); +/* Convertit une adresse en indice de ligne. */ +size_t g_code_buffer_get_index_from_address(const GCodeBuffer *, const vmpa2t *, bool); + /* Retrouve l'indice associé à une ligne au sein d'un tampon. */ size_t g_code_buffer_find_index_by_line(const GCodeBuffer *, const GBufferLine *); @@ -127,83 +137,18 @@ bool g_code_buffer_delete_lines_comment(GCodeBuffer *, GBufferLine *); -/* ---------------------- VUE PARTICULIERE D'UN TAMPON DE CODE ---------------------- */ - - -#define G_TYPE_BUFFER_VIEW (g_buffer_view_get_type()) -#define G_BUFFER_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_BUFFER_VIEW, GBufferView)) -#define G_BUFFER_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_BUFFER_VIEW, GBufferViewClass)) -#define G_IS_BUFFER_VIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_BUFFER_VIEW)) -#define G_IS_BUFFER_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_BUFFER_VIEW)) -#define G_BUFFER_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_BUFFER_VIEW, GBufferViewClass)) - - -/* Vue d'un tampon pour code désassemblé (instance) */ -typedef struct _GBufferView GBufferView; - -/* Vue d'un tampon pour code désassemblé (classe) */ -typedef struct _GBufferViewClass GBufferViewClass; - - -/* Détermine le type de la vue d'un tampon pour code désassemblé. */ -GType g_buffer_view_get_type(void); - -/* Crée une nouvelle vue d'un tampon pour code désassemblé. */ -GBufferView *g_buffer_view_new(GCodeBuffer *, segcnt_list *); - -/* Restreint le champ d'application de l'affichage. */ -void g_buffer_view_restrict(GBufferView *, const vmpa2t *, const vmpa2t *); - -/* Indique le champ d'application de l'affichage. */ -void g_buffer_view_get_restrictions(GBufferView *, vmpa2t *, vmpa2t *); +/* ------------------------- SIGNAUX IMMEDIATS POUR UNE VUE ------------------------- */ -/* Fournit le tampon de code lié à un visualisateur donné. */ -GCodeBuffer *g_buffer_view_get_buffer(const GBufferView *); -/* Fournit la hauteur d'impression d'une ligne visualisée. */ -gint g_buffer_view_get_line_height(GBufferView *); - -/* Fournit la largeur requise par une visualisation. */ -gint g_buffer_view_get_width(GBufferView *, const bool *); - -/* Fournit la largeur requise pour dépasser les marges gauches. */ -gint g_buffer_view_get_margin(GBufferView *, const bool *); - -/* Fournit la hauteur requise par une visualisation. */ -gint g_buffer_view_get_height(const GBufferView *); - -/* Calcule la position idéale de curseur pour un point donné. */ -const vmpa2t *g_buffer_view_compute_caret(GBufferView *, gint, gint, const bool *, GdkRectangle *); - -/* Calcule la position idéale de curseur pour un point donné. */ -const vmpa2t *g_buffer_view_compute_caret_full(GBufferView *, GBufferLine *, size_t, gint, const bool *, GdkRectangle *); - -/* Déplace le curseur au sein d'une vue de tampon. */ -const vmpa2t *g_buffer_view_move_caret(GBufferView *, GdkRectangle *, bool, GdkScrollDirection, const bool *); - -/* Supprime toute mise en évidence de segments. */ -bool g_buffer_view_unhighlight_segments(GBufferView *); - -/* Surligne tous les segments similaires à celui sous la souris. */ -bool g_buffer_view_highlight_segments(GBufferView *, gint, gint, const bool *); - -/* Imprime la visualisation du tampon de code désassemblé. */ -void g_buffer_view_draw(const GBufferView *, cairo_t *, gint, gint, const cairo_rectangle_int_t *, const bool *, const gint *); - -/* Retrouve une ligne au sein d'un tampon avec une adresse. */ -GBufferLine *g_buffer_view_find_line_by_addr(const GBufferView *, const vmpa2t *, BufferLineFlags, size_t *); - -/* Retrouve une ligne au sein d'un tampon avec un indice. */ -GBufferLine *g_buffer_view_find_line_by_index(const GBufferView *, size_t ); +/* Accompagne une variation de la quantité de lignes du tampon. */ +typedef void (* buffer_size_changed_cb) (const GCodeBuffer *, bool, size_t, size_t, GObject *); -/* Fournit la ligne présente à une ordonnée donnée. */ -GBufferLine *g_buffer_view_find_line_at(GBufferView *, gint, size_t *); -/* Fournit la ligne et son segment présents à une position. */ -GBufferLine *g_buffer_view_find_line_and_segment_at(GBufferView *, gint *, gint, size_t *, const bool *, GBufferSegment **); +/* Enregistre l'adresse d'une fonction de mise à jour de vue. */ +void g_code_buffer_register_view_callback(GCodeBuffer *, buffer_size_changed_cb, GObject *); -/* Indique la position d'affichage d'une adresse donnée. */ -bool g_buffer_view_get_address_coordinates(GBufferView *, const vmpa2t *, gint *, gint *, bool); +/* Supprime un élément des vues à contacter pour mises à jour. */ +void g_code_buffer_unregister_view_callback(GCodeBuffer *, GObject *); diff --git a/src/glibext/gwidthtracker.c b/src/glibext/gwidthtracker.c new file mode 100644 index 0000000..11ea0b1 --- /dev/null +++ b/src/glibext/gwidthtracker.c @@ -0,0 +1,830 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * gwidthtracker.c - suivi des largeurs associées à un ensemble de lignes + * + * Copyright (C) 2016 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * OpenIDA 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. + * + * OpenIDA 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 "gwidthtracker.h" + + +#include <assert.h> +#include <malloc.h> +#include <stdlib.h> +#include <string.h> + + +#include "gcodebuffer.h" + + + +/* Portions de largeurs communes */ +typedef struct _common_metrics +{ + size_t first; /* Premier indice de portion */ + size_t last; /* Dernier indice de portion */ + + line_width_summary summary; /* Compilation de largeurs */ + +} common_metrics; + + +/* Gestionnaire de largeurs associées aux lignes (instance) */ +struct _GWidthTracker +{ + GObject parent; /* A laisser en premier */ + + GCodeBuffer *buffer; /* Ensemble complet de lignes */ + + common_metrics *portions; /* Portions représentées */ + size_t count; /* Quantité de ces portions */ + + line_width_summary summary; /* Largeurs requises suivies */ + bool cached; /* Mise en cache des calculs */ + +}; + +/* Gestionnaire de largeurs associées aux lignes (classe) */ +struct _GWidthTrackerClass +{ + GObjectClass parent; /* A laisser en premier */ + +}; + + +/* Procède à l'initialisation d'une classe de suivi de largeurs. */ +static void g_width_tracker_class_init(GWidthTrackerClass *); + +/* Procède à l'initialisation d'un suivi de largeurs de lignes. */ +static void g_width_tracker_init(GWidthTracker *); + +/* Supprime toutes les références externes. */ +static void g_width_tracker_dispose(GWidthTracker *); + +/* Procède à la libération totale de la mémoire. */ +static void g_width_tracker_finalize(GWidthTracker *); + +/* Recherche la portion contenant un indice de ligne donné. */ +static size_t g_width_tracker_find_metrics(const GWidthTracker *, size_t); + +/* Prend en compte une évolution du volume de lignes. */ +static void g_width_tracker_update_ranges(GWidthTracker *, size_t, size_t); + +/* Recalcule les largeurs requises par une portion de lignes. */ +static void g_width_tracker_update_widths(GWidthTracker *, size_t); + +/* Calcule les largeurs requises par un ensemble de lignes. */ +static void g_width_tracker_ensure_valid_required_widths(GWidthTracker *); + + + +/* ---------------------------------------------------------------------------------- */ +/* TAMPON POUR CODE DESASSEMBLE */ +/* ---------------------------------------------------------------------------------- */ + + +/* Détermine le type du gestionnaire de largeurs associées aux lignes. */ +G_DEFINE_TYPE(GWidthTracker, g_width_tracker, G_TYPE_OBJECT); + + +/****************************************************************************** +* * +* Paramètres : class = classe de composant GTK à initialiser. * +* * +* Description : Procède à l'initialisation d'une classe de suivi de largeurs.* +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_width_tracker_class_init(GWidthTrackerClass *class) +{ + GObjectClass *object; /* Autre version de la classe */ + + object = G_OBJECT_CLASS(class); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_width_tracker_dispose; + object->finalize = (GObjectFinalizeFunc)g_width_tracker_finalize; + +} + + +/****************************************************************************** +* * +* Paramètres : tracker = composant GLib à initialiser. * +* * +* Description : Procède à l'initialisation d'un suivi de largeurs de lignes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_width_tracker_init(GWidthTracker *tracker) +{ + tracker->portions = NULL; + tracker->count = 0; + + memset(&tracker->summary, 0, sizeof(line_width_summary)); + tracker->cached = false; + +} + + +/****************************************************************************** +* * +* Paramètres : tracker = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_width_tracker_dispose(GWidthTracker *tracker) +{ + g_object_unref(G_OBJECT(tracker->buffer)); + + G_OBJECT_CLASS(g_width_tracker_parent_class)->dispose(G_OBJECT(tracker)); + +} + + +/****************************************************************************** +* * +* Paramètres : tracker = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_width_tracker_finalize(GWidthTracker *tracker) +{ + G_OBJECT_CLASS(g_width_tracker_parent_class)->finalize(G_OBJECT(tracker)); + +} + + +/****************************************************************************** +* * +* Paramètres : buffer = tampon contenant les lignes à surveiller. * +* first = adresse contenant l'indice de la première ligne. * +* last = adresse contenant l'indice de la dernière ligne. * +* * +* Description : Crée un nouveau suivi de largeurs au sein de lignes. * +* * +* Retour : Composant GLib créé. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GWidthTracker *g_width_tracker_new(GCodeBuffer *buffer) +{ + GWidthTracker *result; /* Composant à retourner */ + + result = g_object_new(G_TYPE_WIDTH_TRACKER, NULL); + + g_object_ref(G_OBJECT(buffer)); + result->buffer = buffer; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : buffer = tampon contenant les lignes à surveiller. * +* first = indice de la première ligne d'une zone réduite. * +* last = indice de la dernière ligne d'une zone réduite. * +* * +* Description : Crée un nouveau suivi de largeurs au sein de lignes. * +* * +* Retour : Composant GLib créé. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GWidthTracker *g_width_tracker_new_restricted(const GWidthTracker *template, size_t first, size_t last) +{ + GWidthTracker *result; /* Composant à retourner */ + size_t start; /* Début de la zone à copier */ + size_t end; /* Fin de cette même zone */ + size_t i; /* Boucle de parcours */ + + result = g_object_new(G_TYPE_WIDTH_TRACKER, NULL); + + g_object_ref(G_OBJECT(template->buffer)); + result->buffer = template->buffer; + + start = g_width_tracker_find_metrics(template, first); + assert(start < template->count); + + end = g_width_tracker_find_metrics(template, last); + assert(end < template->count); + + result->count = end - start + 1; + result->portions = (common_metrics *)calloc(result->count, sizeof(common_metrics)); + + for (i = 0; i < result->count; i++) + memcpy(&result->portions[i], &template->portions[start + i], sizeof(common_metrics)); + + if (result->portions[0].first != first) + { + result->portions[0].first = first; + g_width_tracker_update_widths(result, 0); + } + + if (result->portions[result->count - 1].last != last) + { + result->portions[result->count - 1].last = last; + g_width_tracker_update_widths(result, result->count - 1); + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : tracker = gestionnaire de suivi à consulter. * +* index = indice d'une ligne dont la portion est inconnue. * +* * +* Description : Recherche la portion contenant un indice de ligne donné. * +* * +* Retour : Indice de portion trouvée ou le nombre de portions sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static size_t g_width_tracker_find_metrics(const GWidthTracker *tracker, size_t index) +{ + size_t result; /* Indice trouvé à retourner */ + common_metrics *found; /* Portion trouvée ou NULL */ + + int look_for_metrics(const size_t *idx, const common_metrics *m) + { + int status; + + if (*idx < m->first) + status = -1; + + else if (*idx > m->last) + status = 1; + + else + status = 0; + + return status; + + } + + found = bsearch(&index, tracker->portions, tracker->count, + sizeof(common_metrics), (__compar_fn_t)look_for_metrics); + + if (found == NULL) + result = tracker->count; + else + result = found - tracker->portions; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : tracker = gestionnaire de largeurs de lignes à mettre jour. * +* start = première ligne à traiter. * +* diff = nombre de lignes ajoutées ou supprimées. * +* * +* Description : Prend en compte une évolution du volume de lignes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_width_tracker_update_ranges(GWidthTracker *tracker, size_t start, size_t diff) +{ + size_t i; /* Boucle de parcours */ + + for (i = start; i < tracker->count; i++) + { + tracker->portions[i].first += diff; + tracker->portions[i].last += diff; + } + +} + + +/****************************************************************************** +* * +* Paramètres : tracker = gestionnaire de largeurs de lignes à mettre jour. * +* index = indice de la portion à rafraîchir. * +* * +* Description : Recalcule les largeurs requises par une portion de lignes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_width_tracker_update_widths(GWidthTracker *tracker, size_t index) +{ + common_metrics *portion; /* Portion à actualiser */ + BufferLineColumn k; /* Boucle de parcours #1 */ + size_t i; /* Boucle de parcours #2 */ + GBufferLine *line; /* Ligne à manipuler */ + + assert(index < tracker->count); + + portion = &tracker->portions[index]; + + /* Réinitialisation globale ? */ + + for (k = 0; k < BLC_COUNT && tracker->cached; k++) + tracker->cached &= (tracker->summary.max_widths[k] != portion->summary.max_widths[k]); + + tracker->cached &= (tracker->summary.merged_width != portion->summary.merged_width); + + /* Réinitialisation locale */ + + memset(&portion->summary, 0, sizeof(line_width_summary)); + + /* Collecte */ + + for (i = portion->first; i <= portion->last; i++) + { + line = g_code_buffer_find_line_by_index(tracker->buffer, i); + + g_buffer_line_collect_widths(line, &portion->summary); + + } + +} + + +/****************************************************************************** +* * +* Paramètres : tracker = gestionnaire de largeurs de lignes à mettre jour. * +* index = position de la première des lignes à ajouter. * +* count = quantité de lignes devant être ajoutées. * +* * +* Description : Prend acte de l'ajout de lignes pour les largeurs. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_width_tracker_update_added(GWidthTracker *tracker, size_t index, size_t count) +{ + size_t current; /* Indice de portion visée */ + common_metrics *portion; /* Portion sélectionnée */ + size_t next; /* Prochaine portion à décaller*/ + size_t i; /* Boucle de parcours */ + GBufferLine *line; /* Ligne à manipuler */ + size_t dest; /* Destination d'une recopie */ + size_t src; /* Source d'une recopie */ + + /* Cas particulier du premier ajout */ + if (tracker->count == 0) + { + assert(index == 0); + + tracker->portions = (common_metrics *)calloc(1, sizeof(common_metrics)); + tracker->count = 1; + + tracker->portions[0].first = 0; + tracker->portions[0].last = count - 1; + + g_width_tracker_update_widths(tracker, 0); + + return; + + } + + current = g_width_tracker_find_metrics(tracker, index); + + /* Si la ligne est rajoutée en fin d'ensemble */ + if (current == tracker->count) + { + current = tracker->count - 1; + portion = &tracker->portions[current]; + + assert(index == (portion->last + 1)); + + } + else + portion = &tracker->portions[current]; + + portion->last += count; + + g_width_tracker_update_widths(tracker, current); + + next = current + 1; + + /* Un découpage s'impose-t-il quelque part ? */ + + for (i = index + count - 1; i >= index; i--) + { + line = g_code_buffer_find_line_by_index(tracker->buffer, i); + + if (g_buffer_line_get_flags(line) & BLF_WIDTH_MANAGER) + { + /* Insertion d'une nouvelle place */ + + tracker->count++; + + tracker->portions = (common_metrics *)realloc(tracker->portions, + tracker->count * sizeof(common_metrics)); + + dest = current + 2; + src = current + 1; + + if ((tracker->count - src) > 0) + memmove(&tracker->portions[dest], &tracker->portions[src], + (tracker->count - src - 1) * sizeof(common_metrics)); + + next++; + + /* Insertion au début */ + if (i == portion->first) + { + assert(i == index); + + tracker->portions[current + 1].first = portion->first + 1; + tracker->portions[current + 1].last = portion->last; + + portion->first = i; + portion->last = i; + + } + + /* Insertion au sein de la portion ou à la fin */ + else + { + tracker->portions[current + 1].first = i; + tracker->portions[current + 1].last = portion->last; + + portion->last = i - 1; + + } + + /* Mise à jour des largeurs */ + + g_width_tracker_update_widths(tracker, current); + + g_width_tracker_update_widths(tracker, current + 1); + + } + + } + + /* Suite impérative : accroître les indices ! */ + + g_width_tracker_update_ranges(tracker, next, 1); + +} + + +/****************************************************************************** +* * +* Paramètres : tracker = gestionnaire de largeurs de lignes à mettre jour. * +* start = première ligne devant être supprimée. * +* end = dernière ligne devant être supprimée. * +* * +* Description : Prend acte de la suppression de lignes pour les largeurs. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_width_tracker_update_deleted(GWidthTracker *tracker, size_t start, size_t end) +{ + size_t first; /* Première portion concernée */ + size_t last; /* Dernière portion concernée */ + size_t diff; /* Nombre de lignes supprimées */ + bool keep_first; /* Conservation de portion #1 */ + size_t dest; /* Destination du transfert */ + bool keep_last; /* Conservation de portion #2 */ + size_t src; /* Source du transfert */ + + first = g_width_tracker_find_metrics(tracker, start); + assert(first < tracker->count); + + last = g_width_tracker_find_metrics(tracker, end); + assert(last < tracker->count); + + diff = end - start + 1; + + /* Suppression de portions inutiles ? */ + + keep_first = (tracker->portions[first].first > start || end < tracker->portions[first].last); + + dest = (keep_first ? first + 1 : first); + + keep_last = (tracker->portions[last].first > start || end < tracker->portions[last].last); + + src = (keep_last ? last : last + 1); + + if (src > dest) + { + memmove(&tracker->portions[dest], &tracker->portions[src], + (tracker->count - src) * sizeof(common_metrics)); + + tracker->count -= (src - dest); + + tracker->portions = (common_metrics *)realloc(tracker->portions, + tracker->count * sizeof(common_metrics)); + + } + + /* Si une fusion s'impose */ + + if (keep_first && keep_last && last != first) + { + tracker->portions[first].last = tracker->portions[dest].last; + + memmove(&tracker->portions[first + 1], &tracker->portions[first + 2], + (tracker->count - first - 2) * sizeof(common_metrics)); + + tracker->count--; + + tracker->portions = (common_metrics *)realloc(tracker->portions, + tracker->count * sizeof(common_metrics)); + + keep_last = false; + + } + + /* Avant toute chose : faire décroître les indices ! */ + + if (keep_first) + { + if (end < tracker->portions[first].last) + tracker->portions[first].last -= diff; + else + tracker->portions[first].last = start; + } + + if (keep_last && last != first) + { + tracker->portions[dest].first = end + 1; + tracker->portions[dest].last -= diff; + } + + g_width_tracker_update_ranges(tracker, keep_last ? dest + 1 : dest, -diff); + + /* Mise à jour des largeurs aux extrémités */ + + if (keep_first) + g_width_tracker_update_widths(tracker, first); + + if (keep_last && last != first) + g_width_tracker_update_widths(tracker, dest); + +} + + +/****************************************************************************** +* * +* Paramètres : tracker = suivi de largeurs à mettre à jour si besoin est. * +* * +* Description : Calcule les largeurs requises par un ensemble de lignes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_width_tracker_ensure_valid_required_widths(GWidthTracker *tracker) +{ + line_width_summary *global; /* Valeurs collectées */ + size_t i; /* Boucle de parcours #1 */ + const line_width_summary *summary; /* Valeurs à intégrer */ + BufferLineColumn k; /* Boucle de parcours #2 */ + + if (!tracker->cached) + { + /* Réinitialisation */ + + memset(&tracker->summary, 0, sizeof(line_width_summary)); + + /* Collecte */ + + global = &tracker->summary; + + for (i = 0; i < tracker->count; i++) + { + summary = &tracker->portions[i].summary; + + for (k = 0; k < BLC_COUNT; k++) + global->max_widths[k] = MAX(global->max_widths[k], summary->max_widths[k]); + + global->merged_width = MAX(global->merged_width, summary->merged_width); + + } + + tracker->cached = true; + + } + +} + + +/****************************************************************************** +* * +* Paramètres : tracker = suivi de largeurs à consulter. * +* * +* Description : Fournit un bon résumé des largeurs en vigueur. * +* * +* Retour : Ensemble des largeurs collectées. * +* * +* Remarques : - * +* * +******************************************************************************/ + +const line_width_summary *g_width_tracker_get_width_summary(GWidthTracker *tracker) +{ + g_width_tracker_ensure_valid_required_widths(tracker); + + return &tracker->summary; + +} + + +/****************************************************************************** +* * +* Paramètres : tracker = suivi de largeurs à consulter. * +* index = indice de la ligne dont la portion est recherchée. * +* summary = ensemble ciblé de largeurs collectées. [OUT] * +* * +* Description : Fournit un résumé local des largeurs en vigueur. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_width_tracker_get_local_width_summary(GWidthTracker *tracker, size_t index, line_width_summary *summary) +{ + size_t current; /* Indice de portion visée */ + common_metrics *portion; /* Portion locale à consulter */ + BufferLineColumn i; /* Boucle de parcours */ + + g_width_tracker_ensure_valid_required_widths(tracker); + + current = g_width_tracker_find_metrics(tracker, index); + assert(current < tracker->count); + + portion = &tracker->portions[current]; + + for (i = BLC_FIRST; i < BLC_DISPLAY; i++) + summary->max_widths[i] = tracker->summary.max_widths[i]; + + for (i = BLC_DISPLAY; i < BLC_COUNT; i++) + summary->max_widths[i] = portion->summary.max_widths[i]; + + summary->merged_width = portion->summary.merged_width; + +} + + +/****************************************************************************** +* * +* Paramètres : tracker = suivi de largeurs à consulter. * +* display = règles d'affichage des colonnes modulables. * +* * +* Description : Fournit la largeur requise par une visualisation. * +* * +* Retour : Dimension calculée. * +* * +* Remarques : - * +* * +******************************************************************************/ + +gint g_width_tracker_get_width(GWidthTracker *tracker, const bool *display) +{ + gint result; /* Taille à retourner */ + const line_width_summary *summary; /* Accès rapide aux mesures */ + gint col_width; /* Calcul selon les colonnes */ + gint full_width; /* Calcul selon les fusions */ + BufferLineColumn i; /* Boucle de parcours */ + + g_width_tracker_ensure_valid_required_widths(tracker); + + result = 0; + + summary = &tracker->summary; + + col_width = 0; + full_width = 0; + + /* Première méthode */ + + for (i = 0; i < BLC_COUNT; i++) + { + if (i < BLC_DISPLAY && !display[i]) continue; + + col_width += summary->max_widths[i]; + + if ((i + 1) < BLC_COUNT) + col_width += COL_MARGIN; + + } + + /* Seconde méthode */ + + for (i = 0; i < BLC_DISPLAY; i++) + { + if (!display[i]) continue; + + full_width += summary->max_widths[i] + COL_MARGIN; + + } + + full_width += summary->merged_width; + + /* Mise en concurrence et poursuite... */ + + result += + MAX(col_width, full_width); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : tracker = suivi de largeurs à consulter. * +* display = 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_width_tracker_get_margin(GWidthTracker *tracker, const bool *display) +{ + gint result; /* Taille à retourner */ + const line_width_summary *summary; /* Accès rapide aux mesures */ + BufferLineColumn i; /* Boucle de parcours */ + + g_width_tracker_ensure_valid_required_widths(tracker); + + result = 0; + + summary = &tracker->summary; + + for (i = 0; i < BLC_DISPLAY; i++) + { + if (!display[i]) continue; + + result += summary->max_widths[i] + COL_MARGIN; + + } + + return result; + +} diff --git a/src/glibext/gwidthtracker.h b/src/glibext/gwidthtracker.h new file mode 100644 index 0000000..31168be --- /dev/null +++ b/src/glibext/gwidthtracker.h @@ -0,0 +1,85 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * gwidthtracker.h - prototypes pour le suivi des largeurs associées à un ensemble de lignes + * + * Copyright (C) 2016 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * OpenIDA 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. + * + * OpenIDA 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/>. + */ + + +#ifndef _GLIBEXT_GWIDTHTRACKER_H +#define _GLIBEXT_GWIDTHTRACKER_H + + +#include <glib-object.h> +#include <stdbool.h> + + +#include "gbufferline.h" + + + +/* gcodebuffer.h : Tampon pour code désassemblé (instance) */ +typedef struct _GCodeBuffer GCodeBuffer; + + + +#define G_TYPE_WIDTH_TRACKER (g_width_tracker_get_type()) +#define G_WIDTH_TRACKER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_WIDTH_TRACKER, GWidthTracker)) +#define G_WIDTH_TRACKER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_WIDTH_TRACKER, GWidthTrackerClass)) +#define G_IS_WIDTH_TRACKER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_WIDTH_TRACKER)) +#define G_IS_WIDTH_TRACKER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_WIDTH_TRACKER)) +#define G_WIDTH_TRACKER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_WIDTH_TRACKER, GWidthTrackerClass)) + + +/* Gestionnaire de largeurs associées aux lignes (instance) */ +typedef struct _GWidthTracker GWidthTracker; + +/* Gestionnaire de largeurs associées aux lignes (classe) */ +typedef struct _GWidthTrackerClass GWidthTrackerClass; + + +/* Détermine le type du gestionnaire de largeurs associées aux lignes. */ +GType g_width_tracker_get_type(void); + +/* Crée un nouveau suivi de largeurs au sein de lignes. */ +GWidthTracker *g_width_tracker_new(GCodeBuffer *); + +/* Crée un nouveau suivi de largeurs au sein de lignes. */ +GWidthTracker *g_width_tracker_new_restricted(const GWidthTracker *, size_t, size_t); + +/* Prend acte de l'ajout de lignes pour les largeurs. */ +void g_width_tracker_update_added(GWidthTracker *, size_t, size_t); + +/* Prend acte de la suppression de lignes pour les largeurs. */ +void g_width_tracker_update_deleted(GWidthTracker *, size_t, size_t); + +/* Fournit un bon résumé des largeurs en vigueur. */ +const line_width_summary *g_width_tracker_get_width_summary(GWidthTracker *); + +/* Fournit un résumé local des largeurs en vigueur. */ +void g_width_tracker_get_local_width_summary(GWidthTracker *, size_t, line_width_summary *); + +/* Fournit la largeur requise par une visualisation. */ +gint g_width_tracker_get_width(GWidthTracker *, const bool *); + +/* Fournit la largeur requise pour dépasser les marges gauches. */ +gint g_width_tracker_get_margin(GWidthTracker *, const bool *); + + + +#endif /* _GLIBEXT_GWIDTHTRACKER_H */ diff --git a/src/gtkext/gtkbufferview-int.h b/src/gtkext/gtkbufferview-int.h index ea181f9..2da069d 100644 --- a/src/gtkext/gtkbufferview-int.h +++ b/src/gtkext/gtkbufferview-int.h @@ -41,7 +41,7 @@ struct _GtkBufferView { GtkViewPanel parent; /* A laisser en premier */ - GCodeBuffer *buffer; /* Code sous forme de texte */ + //GCodeBuffer *buffer; /* Code sous forme de texte */ GBufferView *buffer_view; /* Affichage de cette forme */ gint line_height; /* Hauteur maximale des lignes */ diff --git a/src/gtkext/gtkbufferview.c b/src/gtkext/gtkbufferview.c index b56a170..f0efce0 100644 --- a/src/gtkext/gtkbufferview.c +++ b/src/gtkext/gtkbufferview.c @@ -892,14 +892,14 @@ void gtk_buffer_view_attach_buffer(GtkBufferView *view, GBufferView *buffer) gint width; /* Largeur de l'objet actuelle */ gint height; /* Hauteur de l'objet actuelle */ - if (view->buffer != NULL) + if (view->buffer_view != NULL) { - g_object_unref(G_OBJECT(view->buffer)); + //g_object_unref(G_OBJECT(view->buffer)); g_object_unref(G_OBJECT(view->buffer_view)); } - view->buffer = g_buffer_view_get_buffer(buffer); - g_object_ref(G_OBJECT(view->buffer)); + //view->buffer = g_buffer_view_get_buffer(buffer); + //g_object_ref(G_OBJECT(view->buffer)); view->buffer_view = buffer; diff --git a/src/gtkext/gtkbufferview.h b/src/gtkext/gtkbufferview.h index 06249cf..a46a9dd 100644 --- a/src/gtkext/gtkbufferview.h +++ b/src/gtkext/gtkbufferview.h @@ -29,7 +29,7 @@ #include <gtk/gtk.h> -#include "../glibext/gcodebuffer.h" +#include "../glibext/gbufferview.h" |