From f38d8af1713a2a46a8c2d4499081bd0d123af163 Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Thu, 9 Apr 2015 20:29:54 +0000
Subject: Fixed all known bugs with the keyboard-based navigation in buffer
 views.

git-svn-id: svn://svn.gna.org/svn/chrysalide/trunk@507 abbe820e-26c8-41b2-8c08-b7b2b41f8b0a
---
 ChangeLog                 |   7 ++
 src/glibext/gbufferline.c | 257 ++++++++++++++++++++++++++--------------------
 src/glibext/gcodebuffer.c |  38 ++++---
 src/glibext/gcodebuffer.h |   2 +-
 4 files changed, 178 insertions(+), 126 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 1b89b61..a65a813 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+15-04-09  Cyrille Bagard <nocbos@gmail.com>
+
+	* src/glibext/gbufferline.c:
+	* src/glibext/gcodebuffer.c:
+	* src/glibext/gcodebuffer.h:
+	Fix all known bugs with the keyboard-based navigation in buffer views.
+
 15-04-06  Cyrille Bagard <nocbos@gmail.com>
 
 	* src/analysis/block.c:
diff --git a/src/glibext/gbufferline.c b/src/glibext/gbufferline.c
index 0422af5..e34f86f 100644
--- a/src/glibext/gbufferline.c
+++ b/src/glibext/gbufferline.c
@@ -62,6 +62,9 @@ static gint get_column_width(const buffer_line_column *);
 /* Ajoute un fragment de texte à une colonne de ligne. */
 static void add_segment_to_column(buffer_line_column *, GBufferSegment *);
 
+/* Valide ou non la présence d'un segment dans une colonne. */
+static bool column_has_segment(const buffer_line_column *, const GBufferSegment *, size_t *);
+
 #define get_first_segment(col) ((col)->count > 0 ? (col)->segments[0] : NULL)
 #define get_last_segment(col) ((col)->count > 0 ? (col)->segments[(col)->count - 1] : NULL)
 
@@ -69,7 +72,7 @@ static void add_segment_to_column(buffer_line_column *, GBufferSegment *);
 static GBufferSegment *get_segment_at(const buffer_line_column *, gint *, GdkScrollDirection);
 
 /* Fournit le segment voisin d'un autre segment identifié. */
-static GBufferSegment *find_near_segment(const buffer_line_column *, GBufferSegment *, GdkScrollDirection, bool *);
+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 *);
@@ -202,6 +205,36 @@ static void add_segment_to_column(buffer_line_column *column, GBufferSegment *se
 
 /******************************************************************************
 *                                                                             *
+*  Paramètres  : column  = colonne de ligne à venir consulter.                *
+*                segment = fragment de texte à trouver dans la colonne.       *
+*                index   = indice du segment retrouvé ou NULL. [OUT]          *
+*                                                                             *
+*  Description : Valide ou non la présence d'un segment dans une colonne.     *
+*                                                                             *
+*  Retour      : Statut de présence du segment indiqué.                       *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static bool column_has_segment(const buffer_line_column *column, const GBufferSegment *segment, size_t *index)
+{
+    size_t i;                               /* Boucle de parcours          */
+
+    for (i = 0; i < column->count; i++)
+        if (column->segments[i] == segment)
+        {
+            if (index != NULL) *index = i;
+            break;
+        }
+
+    return (i < column->count);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
 *  Paramètres  : column = colonne de ligne de texte à consulter.              *
 *                x      = position de recherche à ajuster. [OUT]              *
 *                dir    = direction d'un éventuel déplacement en cours.       *
@@ -264,7 +297,6 @@ static GBufferSegment *get_segment_at(const buffer_line_column *column, gint *x,
 *  Paramètres  : column = colonne de ligne de texte à consulter.              *
 *                target = segment dont un voisin est à retourner.             *
 *                dir    = orientation des recherches.                         *
-*                out    = renvoie vers une bordure extérieur au besoin. [OUT] *
 *                                                                             *
 *  Description : Fournit le segment voisin d'un autre segment identifié.      *
 *                                                                             *
@@ -274,29 +306,25 @@ static GBufferSegment *get_segment_at(const buffer_line_column *column, gint *x,
 *                                                                             *
 ******************************************************************************/
 
-static GBufferSegment *find_near_segment(const buffer_line_column *column, GBufferSegment *target, GdkScrollDirection dir, bool *out)
+static GBufferSegment *find_near_segment(const buffer_line_column *column, GBufferSegment *target, GdkScrollDirection dir)
 {
     GBufferSegment *result;                 /* Trouvaille à retourner      */
     size_t i;                               /* Boucle de parcours          */
 
     result = NULL;
-    *out = false;
 
-    for (i = 0; i < column->count; i++)
-        if (column->segments[i] == target) break;
+    column_has_segment(column, target, &i);
 
     if (i < column->count)
         switch (dir)
         {
             case GDK_SCROLL_LEFT:
-                *out = (i == 0);
-                if (!*out)
+                if (i > 0)
                     result = column->segments[i - 1];
                 break;
 
             case GDK_SCROLL_RIGHT:
-                *out = ((i + 1) == column->count);
-                if (!*out)
+                if ((i + 1) < column->count)
                     result = column->segments[i + 1];
                 break;
 
@@ -743,6 +771,7 @@ GBufferSegment *g_buffer_line_get_segment_at(const GBufferLine *line, const gint
     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*/
 
@@ -752,10 +781,11 @@ GBufferSegment *g_buffer_line_get_segment_at(const GBufferLine *line, const gint
     last = BLC_COUNT;
     last_x = *x;    /* Pour GCC */
 
-    printf(" {{ ADDR }} 0x%08x\n", line->range.addr.physical);
-
+    sum = 0;
 
+    printf("---------------\n");
 
+    /* On cible déjà la colonne idéale */
 
     for (i = 0; i < BLC_COUNT; i++)
     {
@@ -769,7 +799,7 @@ GBufferSegment *g_buffer_line_get_segment_at(const GBufferLine *line, const gint
         if (get_column_width(&line->columns[i]) > 0)
         {
             last = i;
-            last_x = *x;
+            last_x = sum;
         }
 
         if (i < line->merge_start)
@@ -777,7 +807,11 @@ GBufferSegment *g_buffer_line_get_segment_at(const GBufferLine *line, const gint
             width = max_widths[i];
 
             if (*x <= width) break;
-            else *x -= (max_widths[i] + COL_MARGIN);
+            else
+            {
+                *x -= (max_widths[i] + COL_MARGIN);
+                sum += width + COL_MARGIN;
+            }
 
         }
         else
@@ -785,7 +819,11 @@ GBufferSegment *g_buffer_line_get_segment_at(const GBufferLine *line, const gint
             width = get_column_width(&line->columns[i]);
 
             if (*x <= width) break;
-            else *x -= width;
+            else
+            {
+                *x -= width;
+                sum += width;
+            }
 
         }
 
@@ -799,59 +837,57 @@ GBufferSegment *g_buffer_line_get_segment_at(const GBufferLine *line, const gint
 
 
 
-    if (force)
+
+
+    if (i < BLC_COUNT)
     {
-        if (i == BLC_COUNT)
-        {
 
-            /* Re-calcul des largeurs cumulées */
+        printf(" -- width @ %u : %d\n", i, get_column_width(&line->columns[i]));
 
-            if (last == BLC_COUNT) i = BLC_COUNT;
-            else
+        if (get_column_width(&line->columns[i]) > 0)
+            result = get_segment_at(&line->columns[i], x, dir);
+
+        /* La position fournie tombe dans une colonne vide ! */
+        else
+        {
+            if (force || get_column_width(&line->columns[i]) == 0)
             {
-                *x = old;
+                result = NULL;
+                *x = sum;
 
-                for (i = 0; i < last; i++)
+                for (i++; i < BLC_COUNT && result == NULL; i++)
                 {
-                    if (i < line->merge_start)
-                        *x -= (max_widths[i] + COL_MARGIN);
-                    else
-                        *x -= get_column_width(&line->columns[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(" -- get segment at -- last index %u (max=%u)   -->>  x = %d\n", i, BLC_COUNT, *x);
+                }
 
+                printf(" -- final x = %d (result=%p)\n", *x, result);
 
+            }
 
         }
 
-        /* Si on s'est arrêté sur un champ vide... */
-        else if (i != last)
+    }
+
+    else /* if (i == BLC_COUNT) */
+    {
+        if (force && last != BLC_COUNT)
         {
-            i = last;
-            *x = last_x;
+            result = get_last_segment(&line->columns[last]);
+            *x = last_x + get_column_width(&line->columns[last]);
         }
+        else
+            result = NULL;
 
     }
 
-
-
-
-
-    if (i < BLC_COUNT)
-        result = get_segment_at(&line->columns[i], x, dir);
-
-
-    if (result == NULL)
-        printf(" -- get segment at -- found nothing...\n");
-    else
-        printf(" -- get segment at -- found %p '%s'...\n", result, g_buffer_segment_get_text(result, false));
-
-
-
     return result;
 
 }
@@ -861,10 +897,10 @@ GBufferSegment *g_buffer_line_get_segment_at(const GBufferLine *line, const gint
 *                                                                             *
 *  Paramètres  : line    = ligne à venir consulter.                           *
 *                target  = segment dont un voisin est à retourner.            *
-*                max_widths = largeurs de colonne à respecter.            XXXXXXXXXXXXXXX    *
+*                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é voisine. [OUT]  *
+*                offset  = décalage pour amener à l'extrémité nouvelle. [OUT] *
 *                                                                             *
 *  Description : Fournit le segment voisin d'un autre segment identifié.      *
 *                                                                             *
@@ -877,93 +913,94 @@ GBufferSegment *g_buffer_line_get_segment_at(const GBufferLine *line, const gint
 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          */
-    bool out;                               /* Présence de cible en bordure*/
+    BufferLineColumn i;                     /* Boucle de parcours #1       */
+    bool displayed;                         /* Confort de lecture          */
+    BufferLineColumn k;                     /* Boucle de parcours #2       */
 
     result = NULL;
-    *offset = 0;
 
-    for (i = 0; i < BLC_COUNT && result == NULL; i++)
-    {
-        if (i < BLC_DISPLAY && !display[i]) continue;
+    /* Recherche dans la colonne de départ */
+
+    for (i = 0; i < BLC_COUNT; i++)
+        if (column_has_segment(&line->columns[i], target, NULL))
+            break;
 
-        result = find_near_segment(&line->columns[i], target, dir, &out);
+    if (i == BLC_COUNT) return NULL;
 
-        printf("   [%d] near seg = %p (out ? %d)\n", i, result, out);
+    result = find_near_segment(&line->columns[i], target, dir);
+    if (result != NULL) return result;
 
-        if (result != NULL) break;
+    /* Recherche dans la direction des colonnes voisines */
 
-        if (out)
+    if (result == NULL)
+        switch (dir)
         {
-            switch (dir)
-            {
-                case GDK_SCROLL_LEFT:
+            case GDK_SCROLL_LEFT:
+
+                /* Si on a atteint la première colonne sans trouver... */
+                if (i == 0) break;
 
- gblfns_loop_left:
+                /* 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);
 
-                    /* On s'assure que la colonne précédente est visible */
-                    if (i <= BLC_DISPLAY)
-                        for (; i > BLC_FIRST; i--)
-                            if (display[i - 1]) break;
+                    if (displayed)
+                        result = get_last_segment(&line->columns[i - 1]);
 
-                    if (i > BLC_FIRST) result = get_last_segment(&line->columns[i - 1]);
+                }
 
-                    printf("   [near] (%d) %p\n", i, result);
+                break;
 
-                    if (result == NULL && i > BLC_FIRST)
-                    {
-                        printf("   [loop] %u -> %u\n", i, i - 1);
-                        i--;
-                        *offset -= (max_widths[i] + COL_MARGIN);
-                        goto gblfns_loop_left;
-                    }
+            case GDK_SCROLL_RIGHT:
 
-                    if (result != NULL)
-                        *offset += g_buffer_segment_get_width(result) - max_widths[i - 1] - COL_MARGIN;
+                /* Si on a atteint la dernière colonne sans trouver... */
+                /*if (i == BLC_COUNT) break;*/
 
-                    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);
 
-                case GDK_SCROLL_RIGHT:
+                    if (displayed)
+                        result = get_first_segment(&line->columns[i + 1]);
 
- gblfns_loop_right:
+                }
 
-                    /* On s'assure que la colonne suivante est visible */
-                    for (; (i + 1) < BLC_DISPLAY; i++)
-                        if (display[i + 1]) break;
+                break;
 
-                    if ((i + 1) < BLC_COUNT) result = get_first_segment(&line->columns[i + 1]);
+        default:
+            break;
 
+    }
 
-                    printf("   [near] (%d) %p\n", i, result);
+    /* Calcul de la position finale */
 
-                    if (result == NULL && (i + 1) < BLC_COUNT)
-                    {
-                        printf("   [loop] %u -> %u\n", i, i + 1);
-                        *offset += (max_widths[i] + COL_MARGIN);
-                        printf("      -- add %d  ~>  %d\n", max_widths[i], *offset);
-                        i++;
-                        goto gblfns_loop_right;
-                    }
+    if (result != NULL)
+    {
+        *offset = 0;
 
-                    if (result != NULL)
-                    {
-                        *offset -= g_buffer_segment_get_width(target);
-                        *offset += max_widths[i] + COL_MARGIN;
-                        printf("      -- add %d  ~>  %d\n", max_widths[i], *offset);
-                    }
+        for (k = 0; k < i; k++)
+        {
+            displayed = (k < BLC_DISPLAY ? display[k] : true);
 
+            if (displayed)
+                *offset += max_widths[k] + COL_MARGIN;
 
-                    /*
-                    if (result != NULL)
-                        *offset += max_widths[i + 1] - g_buffer_segment_get_width(result) + COL_MARGIN;
-                        */
+        }
 
-                    break;
+        switch (dir)
+        {
+            case GDK_SCROLL_LEFT:
+                *offset += get_column_width(&line->columns[i]);
+                break;
 
-                default:
-                    break;
+            case GDK_SCROLL_RIGHT:
+                /**offset += 0;*/
+                break;
 
-            }
+            default:
+                break;
 
         }
 
diff --git a/src/glibext/gcodebuffer.c b/src/glibext/gcodebuffer.c
index 1d42b35..4b4b2a6 100644
--- a/src/glibext/gcodebuffer.c
+++ b/src/glibext/gcodebuffer.c
@@ -1301,7 +1301,10 @@ GBufferLine *g_buffer_view_find_line_and_segment_at(GBufferView *view, gint *x,
             *segment = NULL;
 
         else
+        {
+            *x -= view->left_text;
             *segment = g_buffer_line_get_segment_at(result, view->max_widths, display, x, GDK_SCROLL_LEFT, true);
+        }
 
     }
 
@@ -1345,8 +1348,8 @@ const vmpa2t *g_buffer_view_compute_caret(GBufferView *view, gint x, gint y, con
 
 
 
-    printf("\n[BASE]  tronc = %d   reste = %d   dernier = %d   largeur = %d\n",
-           x - remaining, remaining, g_buffer_segment_get_caret_position(segment, remaining),
+    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));
@@ -1354,7 +1357,7 @@ const vmpa2t *g_buffer_view_compute_caret(GBufferView *view, gint x, gint y, con
 
 
 
-    caret->x = (x - remaining) + g_buffer_segment_get_caret_position(segment, remaining);
+    caret->x = /*view->left_text +*/ (x - remaining) + g_buffer_segment_get_caret_position(segment, remaining);
 
     caret->y = (index - view->first_index) * view->line_height;
 
@@ -1383,7 +1386,7 @@ const vmpa2t *g_buffer_view_compute_caret(GBufferView *view, gint x, gint y, con
 *                                                                             *
 ******************************************************************************/
 
-const vmpa2t *g_buffer_view_compute_caret_old(GBufferView *view, GBufferLine *line, size_t index, gint x, const bool *display, GdkRectangle *caret)
+const vmpa2t *g_buffer_view_compute_caret_full(GBufferView *view, GBufferLine *line, size_t index, gint x, const bool *display, GdkRectangle *caret)
 {
     gint tmp_x;                             /* Copie de travail modifiable */
     GBufferSegment *segment;                /* Segment visé par le pointeur*/
@@ -1395,16 +1398,16 @@ const vmpa2t *g_buffer_view_compute_caret_old(GBufferView *view, GBufferLine *li
     if (tmp_x < 0) return NULL;
 
     segment = g_buffer_line_get_segment_at(line, view->max_widths, display, &tmp_x, GDK_SCROLL_LEFT, true);
-    if (segment == NULL) printf(" -- no segment\n");
+    if (segment == NULL) printf(" -- no segment OLD\n");
     if (segment == NULL) return NULL;
 
-    printf("\n[BASE]  tronc = %d   reste = %d   dernier = %d   largeur = %d\n",
+    printf("\n[BASE OLD]  tronc = %d   reste = %d   dernier = %d   largeur = %d\n",
            x - tmp_x, tmp_x, g_buffer_segment_get_caret_position(segment, tmp_x),
            g_buffer_segment_get_width(segment));
 
     printf("        '%s'\n", g_buffer_segment_get_text(segment, false));
 
-    caret->x = (x - tmp_x) + g_buffer_segment_get_caret_position(segment, tmp_x);
+    caret->x = view->left_text + tmp_x;//(x - tmp_x) + g_buffer_segment_get_caret_position(segment, tmp_x);
 
     first = g_code_buffer_get_index_from_address(view->buffer, view->start, true);
     caret->y = (index - first) * view->line_height;
@@ -1475,6 +1478,10 @@ static bool _g_buffer_view_move_caret(GBufferView *view, const GBufferLine *line
 
     printf(" ====== MOVE 1 ? %d\n", result);
 
+    if (result)
+        caret->x += (tmp_x - ref_x);
+
+    ///////////////////
 
     if (!result)
     {
@@ -1495,8 +1502,9 @@ static bool _g_buffer_view_move_caret(GBufferView *view, const GBufferLine *line
 
 
             ref_x = 0;
-            tmp_x = offset;
+            tmp_x = view->left_text + offset;
 
+            caret->x = tmp_x;
 
             result = true;
             //result = g_buffer_segment_move_caret(segment, &tmp_x, ctrl, dir);
@@ -1521,10 +1529,10 @@ static bool _g_buffer_view_move_caret(GBufferView *view, const GBufferLine *line
         printf(" ====== NO NEW CARET!\n");
 
 
-
+    /*
     if (result)
         caret->x += (tmp_x - ref_x);
-
+    */
 
 
     return result;
@@ -1640,7 +1648,7 @@ const vmpa2t *g_buffer_view_move_caret(GBufferView *view, GdkRectangle *caret, b
             if (index > first)
             {
                 line = view->buffer->lines[index - 1];
-                result = g_buffer_view_compute_caret_old(view, line, index - 1, caret->x, display, caret);
+                result = g_buffer_view_compute_caret_full(view, line, index - 1, caret->x, display, caret);
             }
 
             break;
@@ -1650,7 +1658,7 @@ const vmpa2t *g_buffer_view_move_caret(GBufferView *view, GdkRectangle *caret, b
             if (index < last)
             {
                 line = view->buffer->lines[index + 1];
-                result = g_buffer_view_compute_caret_old(view, line, index + 1, caret->x, display, caret);
+                result = g_buffer_view_compute_caret_full(view, line, index + 1, caret->x, display, caret);
             }
 
             break;
@@ -1665,7 +1673,7 @@ const vmpa2t *g_buffer_view_move_caret(GBufferView *view, GdkRectangle *caret, b
             if (!moved && index > first)
             {
                 line = view->buffer->lines[index - 1];
-                result = g_buffer_view_compute_caret_old(view, line, index - 1, INT_MAX, display, caret);
+                result = g_buffer_view_compute_caret_full(view, line, index - 1, INT_MAX, display, caret);
             }
 
             break;
@@ -1680,7 +1688,7 @@ const vmpa2t *g_buffer_view_move_caret(GBufferView *view, GdkRectangle *caret, b
             if (!moved && index < last)
             {
                 line = view->buffer->lines[index + 1];
-                result = g_buffer_view_compute_caret_old(view, line, index + 1, left_pos, display, caret);
+                result = g_buffer_view_compute_caret_full(view, line, index + 1, left_pos, display, caret);
             }
 
             break;
@@ -1698,7 +1706,7 @@ const vmpa2t *g_buffer_view_move_caret(GBufferView *view, GdkRectangle *caret, b
 
     /*
     if (result && !computed)
-        result = g_buffer_view_compute_caret_old(view, caret->x, caret->y, caret, display, NULL);
+        result = g_buffer_view_compute_caret_full(view, caret->x, caret->y, caret, display, NULL);
     */
 
     return result;
diff --git a/src/glibext/gcodebuffer.h b/src/glibext/gcodebuffer.h
index cb17821..0877ce8 100644
--- a/src/glibext/gcodebuffer.h
+++ b/src/glibext/gcodebuffer.h
@@ -135,7 +135,7 @@ GBufferLine *g_buffer_view_find_line_and_segment_at(GBufferView *, gint *, gint,
 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_old(GBufferView *, GBufferLine *, size_t, gint, const bool *, GdkRectangle *) __attribute__ ((deprecated));
+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 *);
-- 
cgit v0.11.2-87-g4458