summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorCyrille Bagard <nocbos@gmail.com>2016-05-01 01:35:26 (GMT)
committerCyrille Bagard <nocbos@gmail.com>2016-05-01 01:35:26 (GMT)
commitef68a3dd8ff259200ca7f088eecc9ce35e7ffe8f (patch)
treef89cccbe3d0ac421b41cc49a28bee32e8903e45a /src
parent89ceb1e27afed0bac789e33c2f10eade01747d88 (diff)
Handled all width measures per view in a dedicated manager.
Diffstat (limited to 'src')
-rw-r--r--src/glibext/Makefile.am6
-rw-r--r--src/glibext/gbufferline.c964
-rw-r--r--src/glibext/gbufferline.h50
-rw-r--r--src/glibext/gbufferview.c1330
-rw-r--r--src/glibext/gbufferview.h112
-rw-r--r--src/glibext/gcodebuffer.c2245
-rw-r--r--src/glibext/gcodebuffer.h89
-rw-r--r--src/glibext/gwidthtracker.c830
-rw-r--r--src/glibext/gwidthtracker.h85
-rw-r--r--src/gtkext/gtkbufferview-int.h2
-rw-r--r--src/gtkext/gtkbufferview.c8
-rw-r--r--src/gtkext/gtkbufferview.h2
12 files changed, 3367 insertions, 2356 deletions
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"