summaryrefslogtreecommitdiff
path: root/src/glibext/gbufferline.c
diff options
context:
space:
mode:
authorCyrille Bagard <nocbos@gmail.com>2016-10-23 11:59:26 (GMT)
committerCyrille Bagard <nocbos@gmail.com>2016-10-23 11:59:26 (GMT)
commit3f05bacd4fec23824489b51d964a7ce3565bb85b (patch)
tree486cb1d96c11a33385a2155d2f326b88aae08e16 /src/glibext/gbufferline.c
parentfa30b0fb42d2e229de9f760bfa842f25738efc18 (diff)
Memorized all creators of line content at the line level and saved memory.
Diffstat (limited to 'src/glibext/gbufferline.c')
-rw-r--r--src/glibext/gbufferline.c508
1 files changed, 374 insertions, 134 deletions
diff --git a/src/glibext/gbufferline.c b/src/glibext/gbufferline.c
index 0593748..a33817b 100644
--- a/src/glibext/gbufferline.c
+++ b/src/glibext/gbufferline.c
@@ -25,6 +25,7 @@
#include <assert.h>
+#include <malloc.h>
#include <string.h>
#include <gtk/gtk.h> /* Récupération du langage par défaut ; FIXME ? */
@@ -34,10 +35,6 @@
#include "../gtkext/support.h"
-#include <malloc.h> /* FIXME : à virer */
-
-
-
/* ---------------------------- REGROUPEMENT PAR COLONNE ---------------------------- */
@@ -63,26 +60,32 @@ static void refresh_column_width(buffer_line_column *);
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 *);
+static void add_segment_to_column(buffer_line_column *, GBufferSegment *) __attribute__ ((deprecated));
+
+/* Ajoute un fragment de texte à une colonne de ligne. */
+static size_t append_text_to_line_column(buffer_line_column *, const char *, size_t, RenderingTagType);
/* 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 *);
+/* Indique l'indice du premier contenu de la colonne. */
+static bool get_column_first_content_index(const buffer_line_column *, size_t *);
+
+/* Indique l'indice du dernier contenu de la colonne. */
+static bool get_column_last_content_index(const buffer_line_column *, 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)
-/* Donne le segment d'une colonne présent à une abscisse donnée. */
-static GBufferSegment *get_segment_at(const buffer_line_column *, gint *, GdkScrollDirection, gint *);
+/* Indique l'indice du contenu de colonne à une abscisse donnée. */
+static bool get_column_content_index_at(const buffer_line_column *, gint *, GdkScrollDirection, gint *, size_t *);
+
+/* Donne le segment d'une colonne présent à un indice donné. */
+static GBufferSegment *get_column_content_from_index(const buffer_line_column *, size_t);
/* Fournit le segment voisin d'un autre segment identifié. */
static GBufferSegment *find_near_segment(const buffer_line_column *, GBufferSegment *, GdkScrollDirection);
-/* Fournit le segment créé par un objet particulier. */
-static GObject *find_first_segment_creator(const buffer_line_column *);
-
-/* Fournit le segment créé par un objet particulier. */
-static GBufferSegment *find_segment_from_creator(const buffer_line_column *, GObject *);
-
/* Imprime le contenu d'une colonne de ligne de texte. */
static void draw_segments_of_column(buffer_line_column *, cairo_t *, gint, gint, const segcnt_list *);
@@ -94,6 +97,23 @@ static void export_segments_of_column(buffer_line_column *, buffer_export_contex
/* ---------------------------- GESTION DE LINE COMPLETE ---------------------------- */
+/* Identification d'un contenu de colonne */
+typedef struct _col_coord_t
+{
+ BufferLineColumn column; /* Colonne concernée */
+ size_t index; /* Indice d'insertion */
+
+} col_coord_t;
+
+/* Mémorisation des origines de texte */
+typedef struct _content_origin
+{
+ col_coord_t coord; /* Localisation d'attachement */
+
+ GObject *creator; /* Origine de la création */
+
+} content_origin;
+
/* Représentation de fragments de texte en ligne (instance) */
struct _GBufferLine
{
@@ -108,6 +128,9 @@ struct _GBufferLine
BufferLineFlags flags; /* Drapeaux particuliers */
+ content_origin *origins; /* Mémorisation des origines */
+ size_t ocount; /* Nombre de ces mémorisations */
+
union
{
struct
@@ -152,6 +175,9 @@ static void g_buffer_line_finalize(GBufferLine *);
/* Réagit au changement de contenu d'un segment encapsulé. */
static void on_line_segment_changed(GBufferSegment *, GBufferLine *);
+/* Fournit les coordonnées correspondant à une abscisse donnée. */
+static bool g_buffer_line_get_coord_at(const GBufferLine *, const line_width_summary *, const bool *, gint *, gint *, GdkScrollDirection, bool, col_coord_t *);
+
/* ---------------------------------------------------------------------------------- */
@@ -266,6 +292,41 @@ static void add_segment_to_column(buffer_line_column *column, GBufferSegment *se
/******************************************************************************
* *
+* Paramètres : column = colonne de ligne à venir compléter. *
+* text = texte à insérer dans l'existant. *
+* length = taille du texte à traiter. *
+* type = type de décorateur à utiliser. *
+* *
+* Description : Ajoute un fragment de texte à une colonne de ligne. *
+* *
+* Retour : Indice du point d'insertion. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static size_t append_text_to_line_column(buffer_line_column *column, const char *text, size_t length, RenderingTagType type)
+{
+ size_t result; /* Indice à retourner */
+ GBufferSegment *content; /* Contenu à représenter */
+
+ result = column->count;
+
+ content = g_buffer_segment_new(type, text, length);
+
+ column->segments = (GBufferSegment **)realloc(column->segments, ++column->count * sizeof(GBufferSegment *));
+
+ column->segments[result] = content;
+
+ column->max_width += g_buffer_segment_get_width(content);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
* Paramètres : column = colonne de ligne à venir consulter. *
* segment = fragment de texte à trouver dans la colonne. *
* index = indice du segment retrouvé ou NULL. [OUT] *
@@ -296,38 +357,88 @@ static bool column_has_segment(const buffer_line_column *column, const GBufferSe
/******************************************************************************
* *
+* Paramètres : column = colonne de ligne de texte à consulter. *
+* index = indice du contenu enregistré à la position. [OUT] *
+* *
+* Description : Indique l'indice du premier contenu de la colonne. *
+* *
+* Retour : Validité de l'indice renseigné. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool get_column_first_content_index(const buffer_line_column *column, size_t *index)
+{
+ bool result; /* Bilan à retourner */
+
+ result = (column->count > 0);
+
+ if (result)
+ *index = 0;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : column = colonne de ligne de texte à consulter. *
+* index = indice du contenu enregistré à la position. [OUT] *
+* *
+* Description : Indique l'indice du dernier contenu de la colonne. *
+* *
+* Retour : Validité de l'indice renseigné. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool get_column_last_content_index(const buffer_line_column *column, size_t *index)
+{
+ bool result; /* Bilan à retourner */
+
+ result = (column->count > 0);
+
+ if (result)
+ *index = column->count - 1;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
* Paramètres : column = colonne de ligne de texte à consulter. *
* x = position de recherche, puis position locale. [OUT]*
* dir = direction d'un éventuel déplacement en cours. *
* consumed = distance pour arriver à la base du segment. [OUT] *
+* index = indice du contenu enregistré à la position. [OUT] *
* *
-* Description : Donne le segment d'une colonne présent à une abscisse donnée.*
+* Description : Indique l'indice du contenu de colonne à une abscisse donnée.*
* *
-* Retour : Segment trouvé ou NULL si hors borne. *
+* Retour : Validité de l'indice renseigné. *
* *
* Remarques : - *
* *
******************************************************************************/
-static GBufferSegment *get_segment_at(const buffer_line_column *column, gint *x, GdkScrollDirection dir, gint *consumed)
+static bool get_column_content_index_at(const buffer_line_column *column, gint *x, GdkScrollDirection dir, gint *consumed, size_t *index)
{
- GBufferSegment *result; /* Trouvaille à retourner */
+ bool result; /* Bilan à retourner */
size_t i; /* Boucle de parcours */
gint width; /* Largeur à retirer */
bool included; /* Appartenance à une largeur ?*/
- result = NULL;
+ result = false;
*consumed = 0;
- printf(" == gs@ == count = %d width = %d\n",
- column->count, get_column_width(column));
-
- for (i = 0; i < column->count && result == NULL; i++)
+ for (i = 0; i < column->count && !result; i++)
{
width = g_buffer_segment_get_width(column->segments[i]);
- printf(" -s- |%d| -> x=%d w=%d\n", i, *x, width);
-
/**
* Soit une limite entre deux segments A et B :
*
@@ -341,11 +452,15 @@ static GBufferSegment *get_segment_at(const buffer_line_column *column, gint *x,
else included = (width > *x);
if (included)
- result = column->segments[i];
+ {
+ *index = i;
+ result = true;
+ }
else if ((i + 1) == column->count)
{
- result = column->segments[i];
+ *index = i;
+ result = true;
*x = width;
}
@@ -357,7 +472,31 @@ static GBufferSegment *get_segment_at(const buffer_line_column *column, gint *x,
}
- printf(" == gs@ == > segment = %p\n", result);
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : column = colonne de ligne de texte à consulter. *
+* index = indice du contenu à fournir. *
+* *
+* Description : Donne le segment d'une colonne présent à un indice donné. *
+* *
+* Retour : Segment trouvé ou NULL si hors borne. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static GBufferSegment *get_column_content_from_index(const buffer_line_column *column, size_t index)
+{
+ GBufferSegment *result; /* Trouvaille à retourner */
+
+ assert(index < column->count);
+
+ result = column->segments[index];
return result;
@@ -413,68 +552,6 @@ static GBufferSegment *find_near_segment(const buffer_line_column *column, GBuff
/******************************************************************************
* *
-* Paramètres : column = colonne de ligne de texte à consulter. *
-* *
-* Description : Fournit le segment créé par un objet particulier. *
-* *
-* Retour : Créateur trouvé à déréférencer par la suite ou NULL si échec.*
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static GObject *find_first_segment_creator(const buffer_line_column *column)
-{
- GObject *result; /* Trouvaille à retourner */
- size_t i; /* Boucle de parcours */
-
- result = NULL;
-
- for (i = 0; i < column->count && result == NULL; i++)
- result = g_buffer_segment_get_creator(column->segments[i]);
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : column = colonne de ligne de texte à consulter. *
-* creator = créateur à l'origine du segment recherché. *
-* *
-* Description : Fournit le segment créé par un objet particulier. *
-* *
-* Retour : Segment trouvé ou NULL. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static GBufferSegment *find_segment_from_creator(const buffer_line_column *column, GObject *creator)
-{
- GBufferSegment *result; /* Trouvaille à retourner */
- size_t i; /* Boucle de parcours #1 */
- GBufferSegment *iter; /* Boucle de parcours #2 */
-
- result = NULL;
-
- for (i = 0; i < column->count && result == NULL; i++)
- {
- iter = column->segments[i];
-
- if (g_buffer_segment_get_creator(iter) == creator)
- result = iter;
-
- }
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
* 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. *
@@ -660,9 +737,14 @@ static void g_buffer_line_init(GBufferLine *line)
static void g_buffer_line_dispose(GBufferLine *line)
{
+ size_t i; /* Boucle de parcours */
+
if (line->flags & BLF_WIDTH_MANAGER)
g_object_unref(G_OBJECT(line->manager));
+ for (i = 0; i < line->ocount; i++)
+ g_object_unref(G_OBJECT(line->origins[i].creator));
+
G_OBJECT_CLASS(g_buffer_line_parent_class)->dispose(G_OBJECT(line));
}
@@ -684,6 +766,10 @@ static void g_buffer_line_finalize(GBufferLine *line)
{
/* TODO : segments des colonnes... */
+
+ if (line->origins != NULL)
+ free(line->origins);
+
G_OBJECT_CLASS(g_buffer_line_parent_class)->finalize(G_OBJECT(line));
}
@@ -925,10 +1011,17 @@ void g_buffer_line_fill_for_instr(GBufferLine *line, MemoryDataSize psize, Memor
GObject *g_buffer_line_find_first_segment_creator(const GBufferLine *line, BufferLineColumn column)
{
GObject *result; /* Trouvaille à retourner */
+ size_t i; /* Boucle de parcours */
assert(column < BLC_COUNT);
- result = find_first_segment_creator(&line->columns[column]);
+ result = NULL;
+
+ for (i = 0; i < line->ocount && result == NULL; i++)
+ {
+ if (line->origins[i].coord.column == column)
+ result = line->origins[i].creator;
+ }
if (result != NULL)
g_object_ref(G_OBJECT(result));
@@ -954,12 +1047,24 @@ GObject *g_buffer_line_find_first_segment_creator(const GBufferLine *line, Buffe
GBufferSegment *g_buffer_line_find_segment_from_creator(const GBufferLine *line, GObject *creator)
{
GBufferSegment *result; /* Trouvaille à retourner */
- BufferLineColumn i; /* Boucle de parcours */
+ size_t i; /* Boucle de parcours */
+ const col_coord_t *coord; /* Emplacement du contenu visé */
result = NULL;
- for (i = 0; i < BLC_COUNT && result == NULL; i++)
- result = find_segment_from_creator(&line->columns[i], creator);
+ for (i = 0; i < line->ocount; i++)
+ {
+ if (line->origins[i].creator == creator)
+ {
+ coord = &line->origins[i].coord;
+
+ result = get_column_content_from_index(&line->columns[coord->column], coord->index);
+
+ break;
+
+ }
+
+ }
if (result != NULL)
g_object_ref(G_OBJECT(result));
@@ -1049,6 +1154,57 @@ GBufferSegment *g_buffer_line_insert_text(GBufferLine *line, BufferLineColumn co
/******************************************************************************
* *
+* Paramètres : line = ligne à venir compléter. *
+* column = colonne de la ligne visée par l'insertion. *
+* text = texte à insérer dans l'existant. *
+* length = taille du texte à traiter. *
+* type = type de décorateur à utiliser. *
+* creator = instance GLib quelconque à associer. *
+* *
+* Description : Ajoute du texte à formater dans une ligne donnée. *
+* *
+* Retour : Portion de texte mis en place, voire NULL. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_buffer_line_append_text(GBufferLine *line, BufferLineColumn column, const char *text, size_t length, RenderingTagType type, GObject *creator)
+{
+ size_t index; /* Indice d'insertion */
+ content_origin *origin; /* Définition d'une origine */
+
+ assert(length > 0);
+
+ if (column == BLC_MAIN)
+ column = line->main_column;
+
+ if (column == BLC_LAST_USED)
+ column = line->last_used;
+ else
+ line->last_used = column;
+
+ index = append_text_to_line_column(&line->columns[column], text, length, type);
+
+ if (creator != NULL)
+ {
+ line->origins = (content_origin *)realloc(line->origins, ++line->ocount * sizeof(content_origin));
+
+ origin = &line->origins[line->ocount - 1];
+
+ origin->coord.column = column;
+ origin->coord.index = index;
+
+ origin->creator = creator;
+ g_object_ref(G_OBJECT(creator));
+
+ }
+
+}
+
+
+/******************************************************************************
+* *
* Paramètres : line = ligne à venir consulter. *
* first = première colonne à parcourir. *
* end = colonne de fin de parcours. *
@@ -1444,46 +1600,38 @@ gint g_buffer_line_compute_max_width(const GBufferLine *line, BufferLineColumn i
* offset = position à la colonne visée. [OUT] *
* dir = direction d'un éventuel déplacement en cours. *
* force = accepte les segments en bordure au pire. *
+* coord = cordonnées à usage interne à renseigner. [OUT] *
* *
-* Description : Donne le segment présent à une abscisse donnée. *
+* Description : Fournit les coordonnées correspondant à une abscisse donnée. *
* *
-* Retour : Segment trouvé ou NULL si hors borne. *
+* Retour : true si des coordonnées valides ont été renseignées. *
* *
* Remarques : - *
* *
******************************************************************************/
-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)
+static bool g_buffer_line_get_coord_at(const GBufferLine *line, const line_width_summary *summary, const bool *display, gint *base, gint *offset, GdkScrollDirection dir, bool force, col_coord_t *coord)
{
- GBufferSegment *result; /* Trouvaille à retourner */
+ bool result; /* Bilan à 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 limit; /* Limite d'appartenance */
gint consumed; /* Distance vers le segment */
gint old_base; /* Somme de toutes les largeurs*/
- result = NULL;
+ result = false;
*base = 0;
last = BLC_COUNT;
-
- //sum = 0;
-
- printf("---------------\n");
+ last_base = 0;
/* 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]), 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... */
@@ -1524,19 +1672,11 @@ GBufferSegment *g_buffer_line_get_segment_at(const GBufferLine *line, const line
}
- printf(" -- get segment at -- found index %u (max=%u)\n", i, BLC_COUNT);
-
-
- printf(" last seen = %u\n", last);
-
-
-
-
+ /* Si l'abscisse fournie tombe encore dans une colonne... */
if (i < BLC_COUNT)
{
-
- printf(" -- width @ %u : %d\n", i, get_column_width(&line->columns[i]));
+ /* Il y a bien du contenu dans cette colonne */
if (get_column_width(&line->columns[i]) > 0)
{
@@ -1547,25 +1687,31 @@ GBufferSegment *g_buffer_line_get_segment_at(const GBufferLine *line, const line
*/
if (*offset < 0) *offset = 0;
- result = get_segment_at(&line->columns[i], offset, dir, &consumed);
- *base += consumed;
+ result = get_column_content_index_at(&line->columns[i], offset, dir, &consumed, &coord->index);
+
+ if (result)
+ {
+ coord->column = i;
+
+ *base += consumed;
+
+ }
}
/* La position fournie tombe dans une colonne vide ! */
+
else
{
if (force || get_column_width(&line->columns[i]) == 0)
{
- result = NULL;
+ result = false;
*offset = 0;
old_base = *base;
- for (i++; i < BLC_COUNT && result == NULL; i++)
+ for (i++; i < BLC_COUNT && !result; 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);
@@ -1574,13 +1720,14 @@ GBufferSegment *g_buffer_line_get_segment_at(const GBufferLine *line, const line
else
*base += get_column_width(&line->columns[i - 1]);
- result = get_first_segment(&line->columns[i]);
+ result = get_column_first_content_index(&line->columns[i], &coord->index);
- }
+ if (result)
+ coord->column = i;
- printf(" -- final x = %d (result=%p)\n", *offset, result);
+ }
- if (result == NULL)
+ if (!result)
{
*base = old_base;
goto use_right_border;
@@ -1600,16 +1747,109 @@ GBufferSegment *g_buffer_line_get_segment_at(const GBufferLine *line, const line
if (last != BLC_COUNT)
{
- result = get_last_segment(&line->columns[last]);
- *base = last_base;
- *offset = get_column_width(&line->columns[last]);
+ result = get_column_last_content_index(&line->columns[last], &coord->index);
+
+ if (result)
+ {
+ coord->column = last;
+
+ *base = last_base;
+ *offset = get_column_width(&line->columns[last]);
+
+ }
+
}
else
- result = NULL;
+ result = false;
}
else
- result = NULL;
+ result = false;
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* 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 : 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 line_width_summary *summary, const bool *display, gint *base, gint *offset, GdkScrollDirection dir, bool force)
+{
+ GBufferSegment *result; /* Trouvaille à retourner */
+ col_coord_t coord; /* Emplacement du contenu visé */
+ bool status; /* Bilan de la localisation */
+
+ status = g_buffer_line_get_coord_at(line, summary, display, base, offset, dir, force, &coord);
+
+ if (status)
+ result = get_column_content_from_index(&line->columns[coord.column], coord.index);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* 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 : Donne le créateur présent à une abscisse donnée. *
+* *
+* Retour : Créateur trouvé ou NULL si hors borne. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GObject *g_buffer_line_get_creator_at(const GBufferLine *line, const line_width_summary *summary, const bool *display, gint *base, gint *offset, GdkScrollDirection dir, bool force)
+{
+ GObject *result; /* Trouvaille à retourner */
+ col_coord_t target; /* Emplacement du contenu visé */
+ bool status; /* Bilan de la localisation */
+ size_t i; /* Boucle de parcours */
+ const col_coord_t *coord; /* Emplacement du contenu visé */
+
+ result = NULL;
+
+ status = g_buffer_line_get_coord_at(line, summary, display, base, offset, dir, force, &target);
+
+ if (status)
+ {
+ for (i = 0; i < line->ocount && result == NULL; i++)
+ {
+ coord = &line->origins[i].coord;
+
+ if (coord->column == target.column && coord->index == target.index)
+ result = line->origins[i].creator;
+
+ }
+
+ if (result != NULL)
+ g_object_ref(G_OBJECT(result));
}