From 90923fccb863075722d2ed17360e2c330b262e04 Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Sun, 12 Apr 2015 22:07:56 +0000
Subject: Highlighted the current segment on caret location changes.

git-svn-id: svn://svn.gna.org/svn/chrysalide/trunk@511 abbe820e-26c8-41b2-8c08-b7b2b41f8b0a
---
 ChangeLog                      |  21 ++++
 src/glibext/gbufferline.c      | 214 ++-------------------------------------
 src/glibext/gbufferline.h      |   5 +-
 src/glibext/gbuffersegment.c   | 222 +++++++++++++++++++++++++++++++++++------
 src/glibext/gbuffersegment.h   |  42 +++++---
 src/glibext/gcodebuffer.c      | 124 +++++++++++++----------
 src/glibext/gcodebuffer.h      |   2 +-
 src/gtkext/gtkblockview.c      |  36 ++++++-
 src/gtkext/gtkbufferview-int.h |   6 ++
 src/gtkext/gtkbufferview.c     |  81 +++++++++++++--
 10 files changed, 438 insertions(+), 315 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index d08796b..05c70ad 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,26 @@
 15-04-12  Cyrille Bagard <nocbos@gmail.com>
 
+	* src/glibext/gbufferline.c:
+	* src/glibext/gbufferline.h:
+	Update code.
+
+	* src/glibext/gbuffersegment.c:
+	* src/glibext/gbuffersegment.h:
+	Fix a bug when computing the segment hash: use the final text.
+	Create a list structure to identify segment contents by their hash.
+	Draw the segments according to this kind of list.
+
+	* src/glibext/gcodebuffer.c:
+	* src/glibext/gcodebuffer.h:
+	Keep track of each highlighted segment.
+
+	* src/gtkext/gtkblockview.c:
+	* src/gtkext/gtkbufferview.c:
+	* src/gtkext/gtkbufferview-int.h:
+	Highlight the current segment on caret location changes.
+
+15-04-12  Cyrille Bagard <nocbos@gmail.com>
+
 	* src/core/params.c:
 	* src/core/params.h:
 	Allow to configure the drawing of the selection line.
diff --git a/src/glibext/gbufferline.c b/src/glibext/gbufferline.c
index d763e9d..238bfb3 100644
--- a/src/glibext/gbufferline.c
+++ b/src/glibext/gbufferline.c
@@ -74,11 +74,8 @@ static GBufferSegment *get_segment_at(const buffer_line_column *, gint *, GdkScr
 /* Fournit le segment voisin d'un autre segment identifié. */
 static GBufferSegment *find_near_segment(const buffer_line_column *, GBufferSegment *, GdkScrollDirection);
 
-/* Met en surbrillance des segments similaires. */
-static GSList *highlight_all_same_segments(const buffer_line_column *, GSList *, const GBufferSegment *);
-
 /* Imprime le contenu d'une colonne de ligne de texte. */
-static void draw_segments_of_column(buffer_line_column *, cairo_t *, gint, gint);
+static void draw_segments_of_column(buffer_line_column *, cairo_t *, gint, gint, const segcnt_list *);
 
 /* Exporte la ligne de texte représentée. */
 static void export_segments_of_column(buffer_line_column *, buffer_export_context *, BufferExportType, int);
@@ -351,41 +348,11 @@ static GBufferSegment *find_near_segment(const buffer_line_column *column, GBuff
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : column = colonne de ligne de texte à consulter.              *
-*                list   = liste de segments identiques à constituer.          *
-*                ref    = segment de référence à comparer avec les autres.    *
-*                                                                             *
-*  Description : Met en surbrillance des segments similaires.                 *
-*                                                                             *
-*  Retour      : Liste de segments identiques complétée.                      *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static GSList *highlight_all_same_segments(const buffer_line_column *column, GSList *list, const GBufferSegment *ref)
-{
-    size_t i;                               /* Boucle de parcours          */
-
-    for (i = 0; i < column->count; i++)
-        if (g_buffer_segment_compare(column->segments[i], ref))
-        {
-            g_buffer_segment_set_style(column->segments[i], SRS_HIGHLIGHT_SAME);
-            g_object_ref(G_OBJECT(column->segments[i]));
-            list = g_slist_prepend(list, column->segments[i]);
-        }
-
-    return list;
-
-}
-
-
-/******************************************************************************
-*                                                                             *
 *  Paramètres  : column = colonne de ligne de texte à manipuler.              *
 *                cairo  = contexte graphique à utiliser pour les pinceaux.    *
 *                x_init = abscisse du point d'impression de départ.           *
 *                y      = ordonnée du point d'impression.                     *
+*                list   = liste de contenus à mettre en évidence.             *
 *                                                                             *
 *  Description : Imprime le contenu d'une colonne de ligne de texte.          *
 *                                                                             *
@@ -395,7 +362,7 @@ static GSList *highlight_all_same_segments(const buffer_line_column *column, GSL
 *                                                                             *
 ******************************************************************************/
 
-static void draw_segments_of_column(buffer_line_column *column, cairo_t *cairo, gint x_init, gint y)
+static void draw_segments_of_column(buffer_line_column *column, cairo_t *cairo, gint x_init, gint y, const segcnt_list *list)
 {
     gint x;                                 /* Abscisse d'impression       */
     size_t i;                               /* Boucle de parcours          */
@@ -403,7 +370,7 @@ static void draw_segments_of_column(buffer_line_column *column, cairo_t *cairo,
     x = x_init;
 
     for (i = 0; i < column->count; i++)
-        g_buffer_segment_draw(column->segments[i], cairo, &x, y);
+        g_buffer_segment_draw(column->segments[i], cairo, &x, y, list);
 
 }
 
@@ -933,148 +900,6 @@ GBufferSegment *g_buffer_line_get_segment_at(const GBufferLine *line, const gint
 }
 
 
-#if 0
-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      */
-    gint old;                               /* Valeur d'origine de position*/
-    BufferLineColumn last;                  /* Dernière colonne remplie    */
-    gint last_x;                            /* Dernière abscisse associée  */
-    gint sum;                               /* Somme de toutes les largeurs*/
-    BufferLineColumn i;                     /* Boucle de parcours          */
-    gint width;                             /* Largeur d'une colonne donnée*/
-    gint consumed;                          /* Distance vers le segment    */
-
-    result = NULL;
-
-    old = *x;
-    last = BLC_COUNT;
-    last_x = *x;    /* Pour GCC */
-
-    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, *x, 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_x = sum;
-        }
-
-        if (i < line->merge_start)
-        {
-            width = max_widths[i];
-            if ((i + 1) < BLC_COUNT) width += COL_MARGIN;
-
-            if (*x <= width) break;
-            else
-            {
-                *x -= width;
-                sum += width;
-            }
-
-        }
-        else
-        {
-            width = get_column_width(&line->columns[i]);
-
-            if (*x <= width) break;
-            else
-            {
-                *x -= width;
-                sum += 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)
-        {
-            result = get_segment_at(&line->columns[i], x, dir, &consumed);
-            *x += sum + consumed;
-        }
-
-        /* La position fournie tombe dans une colonne vide ! */
-        else
-        {
-            if (force || get_column_width(&line->columns[i]) == 0)
-            {
-                result = NULL;
-                *x = sum;
-
-                for (i++; i < BLC_COUNT && result == NULL; i++)
-                {
-                    printf(" -- update to col %u  -- x = %d\n", i, *x);
-
-                    if ((i - 1) < line->merge_start)
-                        *x += (max_widths[i - 1] + COL_MARGIN);
-                    else
-                        *x += get_column_width(&line->columns[i - 1]);
-
-                    result = get_first_segment(&line->columns[i]);
-
-                }
-
-                printf(" -- final x = %d (result=%p)\n", *x, result);
-
-                if (result == NULL)
-                    goto use_right_border;
-
-            }
-
-        }
-
-    }
-
-    else /* if (i == BLC_COUNT) */
-    {
-        if (force && last != BLC_COUNT)
-        {
- use_right_border:
-
-            result = get_last_segment(&line->columns[last]);
-            *x = last_x + get_column_width(&line->columns[last]);
-
-        }
-        else
-            result = NULL;
-
-    }
-
-    return result;
-
-}
-#endif
-
-
-
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : line    = ligne à venir consulter.                           *
@@ -1195,32 +1020,6 @@ GBufferSegment *g_buffer_line_find_near_segment(const GBufferLine *line, GBuffer
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : line = ligne à venir consulter.                              *
-*                list = liste de segments identiques à constituer.            *
-*                ref  = segment de référence à comparer avec tous les autres. *
-*                                                                             *
-*  Description : Met en surbrillance des segments similaires.                 *
-*                                                                             *
-*  Retour      : Liste de segments identiques complétée.                      *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-GSList *g_buffer_line_highlight_all_same_segments(const GBufferLine *line, GSList *list, const GBufferSegment *ref)
-{
-    BufferLineColumn i;                     /* Boucle de parcours          */
-
-    for (i = 0; i < BLC_COUNT; i++)
-        list = highlight_all_same_segments(&line->columns[i], list, ref);
-
-    return list;
-
-}
-
-
-/******************************************************************************
-*                                                                             *
 *  Paramètres  : line   = ligne à venir compléter.                            *
 *                column = colonne de la ligne visée par l'insertion.          *
 *                text   = texte à insérer dans l'existant.                    *
@@ -1470,6 +1269,7 @@ void g_buffer_line_remove_flag(GBufferLine *line, BufferLineFlags flag)
 *                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.                       *
 *                                                                             *
@@ -1479,7 +1279,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)
+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)
 {
     GBufferLineClass *class;                /* Stockage de briques de base */
     gint x;                                 /* Point de départ d'impression*/
@@ -1504,7 +1304,7 @@ void g_buffer_line_draw(GBufferLine *line, cairo_t *cairo, const gint max_widths
     {
         if (i < BLC_DISPLAY && !display[i]) continue;
 
-        draw_segments_of_column(&line->columns[i], cairo, x, y);
+        draw_segments_of_column(&line->columns[i], cairo, x, y, list);
 
         if (i < line->merge_start)
             x += max_widths[i] + COL_MARGIN;
diff --git a/src/glibext/gbufferline.h b/src/glibext/gbufferline.h
index e8916ac..6da36af 100644
--- a/src/glibext/gbufferline.h
+++ b/src/glibext/gbufferline.h
@@ -118,9 +118,6 @@ GBufferSegment *g_buffer_line_get_segment_at(const GBufferLine *, const gint [BL
 /* 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 *);
 
-/*  Met en surbrillance des segments similaires. */
-GSList *g_buffer_line_highlight_all_same_segments(const GBufferLine *, GSList *, const GBufferSegment *);
-
 /* Ajoute du texte à formater dans une ligne donnée. */
 GBufferSegment *g_buffer_line_insert_text(GBufferLine *, BufferLineColumn, const char *, size_t, RenderingTagType);
 
@@ -146,7 +143,7 @@ BufferLineFlags g_buffer_line_get_flags(const GBufferLine *);
 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 *);
+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 *);
diff --git a/src/glibext/gbuffersegment.c b/src/glibext/gbuffersegment.c
index d25d728..8e7613f 100644
--- a/src/glibext/gbuffersegment.c
+++ b/src/glibext/gbuffersegment.c
@@ -36,6 +36,9 @@
 
 
 
+/* -------------------- NATURE DE BASE POUR UN FRAGMENT DE TEXTE -------------------- */
+
+
 /* Propriétés de rendu */
 
 typedef struct _rendering_color_t
@@ -105,8 +108,6 @@ struct _GBufferSegment
 
     rendering_pattern_t *pattern;           /* Propriétés du rendu         */
 
-    SegRenderingStyle style;                /* Apparence du segment        */
-
     rendering_color_t cache_bg;             /* Fond d'impression           */
     rendering_color_t alt_fg;               /* Couleur d'impression bis    */
     const rendering_color_t *used_fg;       /* Couleur d'impression utile  */
@@ -144,6 +145,25 @@ static void g_buffer_segment_prepare(GBufferSegment *, size_t);
 
 
 
+
+/* -------------------- GESTION OPTIMALE D'UNE LISTE DE CONTENUS -------------------- */
+
+
+/* Liste identifiant un ensemble de segments */
+struct _segcnt_list
+{
+    fnv64_t *hashes;                        /* Empreinte pour comparaisons */
+    size_t count;                           /* Nommbre de ces empreintes   */
+
+};
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/*                      NATURE DE BASE POUR UN FRAGMENT DE TEXTE                      */
+/* ---------------------------------------------------------------------------------- */
+
+
 /* Détermine le type du fragment de caractères aux propriétés communes. */
 G_DEFINE_TYPE(GBufferSegment, g_buffer_segment, G_TYPE_OBJECT);
 
@@ -360,15 +380,13 @@ GBufferSegment *g_buffer_segment_new(RenderingTagType type, const char *text, si
     result = g_object_new(G_TYPE_BUFFER_SEGMENT, NULL);
 
     result->text = strndup(text, length);
-    result->hash = fnv_64a_hash(text);
+    result->hash = fnv_64a_hash(result->text);
 
     class = G_BUFFER_SEGMENT_GET_CLASS(result);
     result->pattern = &class->patterns[type];
 
     g_buffer_segment_prepare(result, length);
 
-    g_buffer_segment_set_style(result, SRS_CLASSIC);
-
     return result;
 
 }
@@ -702,9 +720,12 @@ bool g_buffer_segment_move_caret(const GBufferSegment *segment, gint *x, bool ct
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : segment = fragment de texte à manipuler.                     *
-*                style   = style de rendu pour le segment.                    *
+*                cairo   = contexte graphique à utiliser pour les pinceaux.   *
+*                x       = abscisse du point d'impression (à maj). [OUT]      *
+*                y       = ordonnée du point d'impression.                    *
+*                list    = liste de contenus à mettre en évidence.            *
 *                                                                             *
-*  Description : Module l'apparence finale du composant.                      *
+*  Description : Imprime le fragment de texte représenté.                     *
 *                                                                             *
 *  Retour      : -                                                            *
 *                                                                             *
@@ -712,10 +733,14 @@ bool g_buffer_segment_move_caret(const GBufferSegment *segment, gint *x, bool ct
 *                                                                             *
 ******************************************************************************/
 
-void g_buffer_segment_set_style(GBufferSegment *segment, SegRenderingStyle style)
+void g_buffer_segment_draw(GBufferSegment *segment, cairo_t *cairo, gint *x, gint y, const segcnt_list *list)
 {
-    segment->style = style;
+    bool selected;                          /* Marquer une sélection ?     */
 
+    cairo_font_extents_t extents;
+
+
+    /*
     switch (style)
     {
         default:
@@ -734,34 +759,28 @@ void g_buffer_segment_set_style(GBufferSegment *segment, SegRenderingStyle style
             break;
 
     }
+    */
 
-}
 
+    segment->used_fg = &segment->pattern->foreground;
 
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : segment = fragment de texte à manipuler.                     *
-*                cairo   = contexte graphique à utiliser pour les pinceaux.   *
-*                x       = abscisse du point d'impression (à maj). [OUT]      *
-*                y       = ordonnée du point d'impression.                    *
-*                                                                             *
-*  Description : Imprime le fragment de texte représenté.                     *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
 
-void g_buffer_segment_draw(GBufferSegment *segment, cairo_t *cairo, gint *x, gint y)
-{
+    selected = selection_list_has_segment_content(list, segment);
 
-    cairo_font_extents_t extents;
 
+    if (selected)
+    {
+        segment->cache_bg.color.red = 0.5;
+        segment->cache_bg.color.green = 0.5;
+        segment->cache_bg.color.blue = 0.5;
+
+        segment->used_fg = &segment->alt_fg;
+
+    }
 
 
     /* Fond du texte */
-    if (segment->style != SRS_CLASSIC)
+    if (selected)
     {
         cairo_set_source_rgb(cairo,
                              segment->cache_bg.color.red,
@@ -935,3 +954,150 @@ void g_buffer_segment_export(const GBufferSegment *segment, buffer_export_contex
     }
 
 }
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/*                      GESTION OPTIMALE D'UNE LISTE DE CONTENUS                      */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : -                                                            *
+*                                                                             *
+*  Description : Initilise une liste de contenus de segments.                 *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+segcnt_list *init_segment_content_list(void)
+{
+    segcnt_list *result;                    /* Structure à retourner       */
+
+    result = (segcnt_list *)calloc(1, sizeof(segcnt_list));
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : list = ensemble de références de contenus à traiter.         *
+*                                                                             *
+*  Description : Libère la mémoire occupée par une liste de contenus.         *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void exit_segment_content_list(segcnt_list *list)
+{
+    reset_segment_content_list(list);
+
+    free(list);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : list = ensemble de références de contenus à manipuler.       *
+*                                                                             *
+*  Description : Vide, si besoin est, une liste de contenus de segments.      *
+*                                                                             *
+*  Retour      : true si des éléments ont été purgés, false sinon.            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool reset_segment_content_list(segcnt_list *list)
+{
+    bool result;                            /* Bilan d'action à renvoyer   */
+
+    result = (list->count > 0);
+
+    if (list->hashes != NULL)
+    {
+        free(list->hashes);
+        list->hashes = NULL;
+    }
+
+    list->count = 0;
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : list    = ensemble de références de contenus à manipuler.    *
+*                segment = fragment de texte à conservr.                      *
+*                                                                             *
+*  Description : Marque le contenu d'un segment comme remarquable.            *
+*                                                                             *
+*  Retour      : true si la liste a été complétée, false sinon.               *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool add_segment_content_to_selection_list(segcnt_list *list, const GBufferSegment *segment)
+{
+    bool result;                            /* Bilan à retourner           */
+    size_t i;                               /* Boucle de parcours          */
+
+    static const char white_list[] = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+    result = false;
+
+    for (i = 0; i < (sizeof(white_list) - 1) && !result; i++)
+        result = (strchr(segment->text, white_list[i]) != NULL);
+
+    if (result)
+    {
+        list->hashes = (fnv64_t *)realloc(list->hashes, ++list->count * sizeof(fnv64_t));
+
+        list->hashes[list->count - 1] = segment->hash;
+
+    }
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : list    = ensemble de références de contenus à consulter.    *
+*                segment = fragment de texte à comparer.                      *
+*                                                                             *
+*  Description : Indique si le contenu d'un segment est notable ou non.       *
+*                                                                             *
+*  Retour      : true si le segment a un contenu présent dans la sélection.   *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool selection_list_has_segment_content(const segcnt_list *list, const GBufferSegment *segment)
+{
+    bool result;                            /* Bilan à retourner           */
+    size_t i;                               /* Boucle de parcours          */
+
+    result = false;
+
+    for (i = 0; i < list->count && !result; i++)
+        result = (cmp_fnv_64a(list->hashes[i], segment->hash) == 0);
+
+    return result;
+
+}
diff --git a/src/glibext/gbuffersegment.h b/src/glibext/gbuffersegment.h
index 51bfb2a..67091fb 100644
--- a/src/glibext/gbuffersegment.h
+++ b/src/glibext/gbuffersegment.h
@@ -32,6 +32,13 @@
 
 
 
+/* Liste identifiant un ensemble de segments */
+typedef struct _segcnt_list segcnt_list;
+
+
+/* -------------------- NATURE DE BASE POUR UN FRAGMENT DE TEXTE -------------------- */
+
+
 #define G_TYPE_BUFFER_SEGMENT                  (g_buffer_segment_get_type())
 #define G_BUFFER_SEGMENT(obj)                  (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_BUFFER_SEGMENT, GBufferSegment))
 #define G_BUFFER_SEGMENT_CLASS(klass)          (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_BUFFER_SEGMENT, GBufferSegmentClass))
@@ -81,16 +88,6 @@ typedef enum _RenderingTagType
 
 } RenderingTagType;
 
-/* Types de rendus */
-typedef enum _SegRenderingStyle
-{
-    SRS_CLASSIC,                            /* Comportement par défaut     */
-    SRS_HIGHLIGHT_SAME,                     /* Surlignage des identiques   */
-
-    SRS_COUNT
-
-} SegRenderingStyle;
-
 
 /* Fragment de caractères aux propriétés communes (instance) */
 typedef struct _GBufferSegment GBufferSegment;
@@ -127,11 +124,8 @@ gint g_buffer_segment_get_caret_position(const GBufferSegment *, gint);
 /* Déplace le curseur au sein d'un segment de tampon. */
 bool g_buffer_segment_move_caret(const GBufferSegment *, gint *, bool, GdkScrollDirection);
 
-/* Module l'apparence finale du composant. */
-void g_buffer_segment_set_style(GBufferSegment *, SegRenderingStyle);
-
 /* Imprime le fragment de texte représenté. */
-void g_buffer_segment_draw(GBufferSegment *, cairo_t *, gint *, gint);
+void g_buffer_segment_draw(GBufferSegment *, cairo_t *, gint *, gint, const segcnt_list *);
 
 /* Types d'exportation */
 typedef enum _BufferExportType
@@ -177,4 +171,24 @@ void g_buffer_segment_export(const GBufferSegment *, buffer_export_context *, Bu
 
 
 
+/* -------------------- GESTION OPTIMALE D'UNE LISTE DE CONTENUS -------------------- */
+
+
+/* Initilise une liste de contenus de segments. */
+segcnt_list *init_segment_content_list(void);
+
+/* Libère la mémoire occupée par une liste de contenus. */
+void exit_segment_content_list(segcnt_list *);
+
+/* Vide, si besoin est, une liste de contenus de segments. */
+bool reset_segment_content_list(segcnt_list *);
+
+/* Marque le contenu d'un segment comme remarquable. */
+bool add_segment_content_to_selection_list(segcnt_list *, const GBufferSegment *);
+
+/* Indique si le contenu d'un segment est notable ou non. */
+bool selection_list_has_segment_content(const segcnt_list *, const GBufferSegment *);
+
+
+
 #endif  /* _GLIBEXT_GBUFFERSEGMENT_H */
diff --git a/src/glibext/gcodebuffer.c b/src/glibext/gcodebuffer.c
index fd1330b..171ba09 100644
--- a/src/glibext/gcodebuffer.c
+++ b/src/glibext/gcodebuffer.c
@@ -154,7 +154,7 @@ struct _GBufferView
     gint last_width;                        /* Plus grande col. de fusion  */
     BufferLineColumn last_merge;            /* Colonne de fusion extrême   */
 
-    GSList *highlighted;                    /* Segments mis en évidence    */
+    segcnt_list *highlighted;               /* Segments mis en évidence    */
 
 };
 
@@ -180,6 +180,12 @@ 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éinitialise le cache de la hauteur des lignes. */
 static void g_buffer_view_reset_required_height(GBufferView *);
 
@@ -892,6 +898,13 @@ G_DEFINE_TYPE(GBufferView, g_buffer_view, G_TYPE_OBJECT);
 
 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;
+
     g_signal_new("need-redraw",
                  G_TYPE_BUFFER_VIEW,
                  G_SIGNAL_RUN_LAST,
@@ -922,6 +935,48 @@ static void g_buffer_view_init(GBufferView *buffer)
     g_buffer_view_reset_required_height(buffer);
     g_buffer_view_reset_required_widths(buffer);
 
+    buffer->highlighted = init_segment_content_list();
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  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_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)
+{
+    exit_segment_content_list(view->highlighted);
+
+    G_OBJECT_CLASS(g_buffer_view_parent_class)->finalize(G_OBJECT(view));
+
 }
 
 
@@ -1689,84 +1744,49 @@ const vmpa2t *g_buffer_view_move_caret(GBufferView *view, GdkRectangle *caret, b
 
 bool g_buffer_view_unhighlight_segments(GBufferView *view)
 {
-    GSList *iter;                           /* Boucle de parcours          */
-    GBufferSegment *segment;                /* Segment visé par le pointeur*/
+    bool result;                            /* Bilan d'action à renvoyer   */
 
-    if (g_slist_length(view->highlighted) == 0)
-        return false;
+    result = reset_segment_content_list(view->highlighted);
 
-    for (iter = view->highlighted; iter != NULL; iter = view->highlighted)
-    {
-        segment = G_BUFFER_SEGMENT(iter->data);
-        g_buffer_segment_set_style(segment, SRS_CLASSIC);
-
-        g_object_unref(G_OBJECT(segment));
-
-        view->highlighted = g_slist_remove_link(view->highlighted, iter);
-
-    }
-
-    return true;
+    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.            *
+*  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      : -                                                            *
+*  Retour      : true si un besoin d'actualisation d'affichage se fait sentir.*
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-void g_buffer_view_highlight_segments(GBufferView *view, gint x, gint y)
+bool g_buffer_view_highlight_segments(GBufferView *view, gint x, gint y, const bool *display)
 {
-#if 0   /* FIXME : inclusion des champs adresses/code */
-    GBufferLine *line;                      /* Ligne sous le pointeur      */
-    GBufferSegment *segment;                /* Segment visé par le pointeur*/
     bool need_redraw;                       /* Besoin d'actualisation ?    */
-    size_t first;                           /* Première ligne intégrée     */
-    size_t last;                            /* Dernière ligne intégrée     */
-    size_t i;                               /* Boucle de parcours          */
-
-    line = g_buffer_view_find_line_at(view, y, NULL);
-    if (line == NULL) return;
-
-    x -= view->left_text;
-    if (x < 0) return;
-
-    segment = g_buffer_line_get_segment_at(line, view->max_widths, &x, GDK_SCROLL_LEFT, false);
-    printf(" ... seg @%d ? %p\n", x, segment);
-    if (segment == NULL) return;
-
-
-    printf("text :: '%s'\n", g_buffer_segment_get_text(segment, false));
-
+    GBufferLine *line;                      /* Ligne ciblée                */
+    GBufferSegment *segment;                /* Segment sélectionnable      */
 
     if (view->highlighted != NULL)
         need_redraw = g_buffer_view_unhighlight_segments(view);
     else
         need_redraw = false;
 
-    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++)
-        view->highlighted = g_buffer_line_highlight_all_same_segments(view->buffer->lines[i],
-                                                                      view->highlighted, segment);
+    line = g_buffer_view_find_line_and_segment_at(view, &x, y, NULL, display, &segment);
 
-    if (g_slist_length(view->highlighted) > 0)
-        need_redraw = true;
+    if (segment)
+        need_redraw |= add_segment_content_to_selection_list(view->highlighted, segment);
 
     if (need_redraw)
         g_signal_emit_by_name(view, "need-redraw");
-#endif
+
 }
 
 
@@ -1837,7 +1857,7 @@ void g_buffer_view_draw(const GBufferView *view, cairo_t *cr, gint fake_x, gint
 
             }
 
-            g_buffer_line_draw(lines[i], cr, view->max_widths, real_x, y, display);
+            g_buffer_line_draw(lines[i], cr, view->max_widths, real_x, y, display, view->highlighted);
 
             y += view->line_height;
 
diff --git a/src/glibext/gcodebuffer.h b/src/glibext/gcodebuffer.h
index 339e0a0..846da64 100644
--- a/src/glibext/gcodebuffer.h
+++ b/src/glibext/gcodebuffer.h
@@ -144,7 +144,7 @@ const vmpa2t *g_buffer_view_move_caret(GBufferView *, GdkRectangle *, bool, GdkS
 bool g_buffer_view_unhighlight_segments(GBufferView *);
 
 /* Surligne tous les segments similaires à celui sous la souris. */
-void g_buffer_view_highlight_segments(GBufferView *, gint, gint);
+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 *);
diff --git a/src/gtkext/gtkblockview.c b/src/gtkext/gtkblockview.c
index 2584405..1c7ba43 100644
--- a/src/gtkext/gtkblockview.c
+++ b/src/gtkext/gtkblockview.c
@@ -52,6 +52,9 @@ static void gtk_block_view_class_init(GtkBlockViewClass *);
 /* Procède à l'initialisation de l'afficheur de bloc assembleur. */
 static void gtk_block_view_init(GtkBlockView *);
 
+/* Réagit à un déplacement de curseur. */
+static bool gtk_block_view_notify_caret_relocation(GtkBlockView *, const GdkRectangle *, const vmpa2t *);
+
 /* Assure la gestion des clics de souris sur le composant. */
 static gboolean gtk_block_view_button_press_event(GtkBlockView *, GdkEventButton *, gpointer);
 
@@ -87,11 +90,15 @@ G_DEFINE_TYPE(GtkBlockView, gtk_block_view, GTK_TYPE_BUFFER_VIEW)
 static void gtk_block_view_class_init(GtkBlockViewClass *class)
 {
     GtkViewPanelClass *panel_class;         /* Classe parente              */
+    GtkBufferViewClass *buffer_class;       /* Classe supérieure           */
 
     panel_class = GTK_VIEW_PANEL_CLASS(class);
+    buffer_class = GTK_BUFFER_VIEW_CLASS(class);
 
     panel_class->attach = (attach_binary_fc)gtk_block_view_attach_binary;
 
+    buffer_class->notify_caret = (notify_caret_relocation_fc)gtk_block_view_notify_caret_relocation;
+
 }
 
 
@@ -109,8 +116,35 @@ static void gtk_block_view_class_init(GtkBlockViewClass *class)
 
 static void gtk_block_view_init(GtkBlockView *view)
 {
+
+
+    /*
     g_signal_connect(G_OBJECT(view), "button_press_event",
                      G_CALLBACK(gtk_block_view_button_press_event), NULL);
+    */
+
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : view = composant GTK à manipuler.                            *
+*                area = emplacement pour le dessin d'un curseur.              *
+*                addr = position dans la mémoire représentée du curseur.      *
+*                                                                             *
+*  Description : Réagit à un déplacement de curseur.                          *
+*                                                                             *
+*  Retour      : true si un changement a été opéré.                           *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static bool gtk_block_view_notify_caret_relocation(GtkBlockView *view, const GdkRectangle *area, const vmpa2t *addr)
+{
+    return g_buffer_view_highlight_segments(GTK_BUFFER_VIEW(view)->buffer_view, area->x, area->y,
+                                            GTK_VIEW_PANEL(view)->display);
 
 }
 
@@ -174,7 +208,7 @@ static gboolean gtk_block_view_button_press_event(GtkBlockView *view, GdkEventBu
 
         gtk_buffer_view_compute_real_coord(bview, &real_x, &real_y);
 
-        g_buffer_view_highlight_segments(gtk_buffer_view_get_buffer(bview), real_x, real_y);
+        g_buffer_view_highlight_segments(gtk_buffer_view_get_buffer(bview), real_x, real_y, NULL);
 
 
 
diff --git a/src/gtkext/gtkbufferview-int.h b/src/gtkext/gtkbufferview-int.h
index a6d937b..e8e11a0 100644
--- a/src/gtkext/gtkbufferview-int.h
+++ b/src/gtkext/gtkbufferview-int.h
@@ -32,6 +32,10 @@
 
 
 
+/* Réagit à un déplacement de curseur. */
+typedef bool (* notify_caret_relocation_fc) (GtkBufferView *, const GdkRectangle *, const vmpa2t *);
+
+
 /* Composant d'affichage de tampon de lignes (instance) */
 struct _GtkBufferView
 {
@@ -56,6 +60,8 @@ struct _GtkBufferViewClass
 {
     GtkViewPanelClass parent;               /* A laisser en premier        */
 
+    notify_caret_relocation_fc notify_caret;/* Accompagne un déplacement   */
+
     /* Signaux */
 
     void (* caret_moved) (GtkBufferView *, const vmpa2t *);
diff --git a/src/gtkext/gtkbufferview.c b/src/gtkext/gtkbufferview.c
index 1c2c7a9..1a1f6f1 100644
--- a/src/gtkext/gtkbufferview.c
+++ b/src/gtkext/gtkbufferview.c
@@ -41,6 +41,12 @@ static void gtk_buffer_view_class_init(GtkBufferViewClass *);
 /* Procède à l'initialisation de l'afficheur de tampons. */
 static void gtk_buffer_view_init(GtkBufferView *);
 
+/* Supprime toutes les références externes. */
+static void gtk_buffer_view_dispose(GtkBufferView *);
+
+/* Procède à la libération totale de la mémoire. */
+static void gtk_buffer_view_finalize(GtkBufferView *);
+
 /* Intègre le focus dans le rendu du composant. */
 static gboolean gtk_buffer_view_focus(GtkWidget *, GtkDirectionType);
 
@@ -110,12 +116,17 @@ G_DEFINE_TYPE(GtkBufferView, gtk_buffer_view, GTK_TYPE_VIEW_PANEL)
 
 static void gtk_buffer_view_class_init(GtkBufferViewClass *class)
 {
+    GObjectClass *object;                   /* Autre version de la classe  */
     GtkWidgetClass *widget_class;           /* Classe version Widget       */
     GtkViewPanelClass *panel_class;         /* Classe parente              */
 
+    object = G_OBJECT_CLASS(class);
     widget_class = GTK_WIDGET_CLASS(class);
     panel_class = GTK_VIEW_PANEL_CLASS(class);
 
+    object->dispose = (GObjectFinalizeFunc/* ! */)gtk_buffer_view_dispose;
+    object->finalize = (GObjectFinalizeFunc)gtk_buffer_view_finalize;
+
     widget_class->focus = gtk_buffer_view_focus;
     widget_class->button_press_event = gtk_buffer_view_button_press;
     widget_class->draw = gtk_buffer_view_draw;
@@ -163,6 +174,44 @@ static void gtk_buffer_view_init(GtkBufferView *view)
 
 /******************************************************************************
 *                                                                             *
+*  Paramètres  : view = instance d'objet GLib à traiter.                      *
+*                                                                             *
+*  Description : Supprime toutes les références externes.                     *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void gtk_buffer_view_dispose(GtkBufferView *view)
+{
+    G_OBJECT_CLASS(gtk_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 gtk_buffer_view_finalize(GtkBufferView *view)
+{
+    G_OBJECT_CLASS(gtk_buffer_view_parent_class)->finalize(G_OBJECT(view));
+
+}
+
+
+/******************************************************************************
+*                                                                             *
 *  Paramètres  : widget = composant GTK visé par l'opération.                 *
 *                dir    = sens de l'opération : perte ou gain de focus.       *
 *                                                                             *
@@ -826,21 +875,37 @@ void gtk_buffer_view_compute_relative_coords(GtkBufferView *view, gint *x, gint
 
 static void gtk_buffer_view_relocate_caret(GtkBufferView *view, const GdkRectangle *area, const vmpa2t *addr)
 {
+    bool clear_old;                         /* Effacement chirurgical      */
+    GdkRectangle old_area;                  /* Mémorisation de l'ancien    */
+    bool need_redraw;                       /* Besoin de rafraîchissement ?*/
+
     if (view->caret_addr != NULL)
     {
-        gtk_buffer_view_compute_relative_coords(view, &view->caret.x, &view->caret.y);
+        clear_old = true;
+        old_area = view->caret;
+    }
+    else
+        clear_old = false;
+
+    view->caret = *area;
+    view->caret_addr = addr;
 
-        /*
-        gtk_widget_queue_draw_area(GTK_WIDGET(view), view->caret.x, view->caret.y,
-                                   view->caret.width, view->caret.height);
-        */
+    if (GTK_BUFFER_VIEW_GET_CLASS(view)->notify_caret != NULL)
+        need_redraw = GTK_BUFFER_VIEW_GET_CLASS(view)->notify_caret(view, area, addr);
+    else
+        need_redraw = false;
 
+    if (need_redraw)
         gtk_widget_queue_draw(GTK_WIDGET(view));
 
-    }
+    else if (clear_old)
+    {
+        gtk_buffer_view_compute_relative_coords(view, &old_area.x, &old_area.y);
 
-    view->caret = *area;
-    view->caret_addr = addr;
+        gtk_widget_queue_draw_area(GTK_WIDGET(view), old_area.x, old_area.y,
+                                   old_area.width, old_area.height);
+
+    }
 
     restart_caret_blinking(view);
 
-- 
cgit v0.11.2-87-g4458