#include "../common/extstr.h"
/******************************************************************************
* *
* Paramètres : column = colonne de ligne à initialiser. *
* *
* Description : Initialise une colonne de ligne. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void init_line_column(line_column *column)
{
column->segments = NULL;
column->count = 0;
column->max_width = 0;
}
/******************************************************************************
* *
* Paramètres : column = colonne de ligne à mettre à jour. *
* *
* Description : Réinitialise une colonne de ligne. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void reset_line_column(line_column *column)
{
size_t i; /* Boucle de parcours */
for (i = 0; i < column->count; i++)
release_line_segment(column->segments[i]);
if (column->segments != NULL)
{
free(column->segments);
column->segments = NULL;
}
column->count = 0;
column->max_width = 0;
}
/******************************************************************************
* *
* Paramètres : column = colonne de ligne à mettre à jour. *
* *
* Description : Recalcule la largeur d'une colonne de segments. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void refresh_line_column_width(line_column *column)
{
size_t i; /* Boucle de parcours */
column->max_width = 0;
for (i = 0; i < column->count; i++)
column->max_width += get_line_segment_width(column->segments[i]);
}
/******************************************************************************
* *
* Paramètres : column = colonne de ligne à consulter. *
* *
* Description : Fournit la quantité de pixels requise pour l'impression. *
* *
* Retour : Largeur requise par la colonne, en pixel. *
* *
* Remarques : - *
* *
******************************************************************************/
gint get_column_width(const line_column *column)
{
return column->max_width;
}
/******************************************************************************
* *
* 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 : - *
* *
******************************************************************************/
size_t append_text_to_line_column(line_column *column, const char *text, size_t length, RenderingTagType type)
{
size_t result; /* Indice à retourner */
line_segment *segment; /* Contenu à représenter */
result = column->count;
segment = get_new_line_segment(type, text, length);
column->segments = realloc(column->segments, ++column->count * sizeof(line_segment *));
column->segments[result] = segment;
column->max_width += get_line_segment_width(segment);
return result;
}
/******************************************************************************
* *
* Paramètres : column = colonne de ligne à venir compléter. *
* index = indice du frament de texte à remplacer. *
* text = texte à insérer dans l'existant. *
* length = taille du texte à traiter. *
* *
* Description : Remplace un fragment de texte dans une colonne de ligne. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void replace_text_in_line_column(line_column *column, size_t index, const char *text, size_t length)
{
RenderingTagType type; /* Type de rendu à conserver */
line_segment *segment; /* Contenu à représenter */
assert(index < column->count);
/* Retrait */
segment = column->segments[index];
type = get_line_segment_type(segment);
release_line_segment(segment);
/* Ajout */
segment = get_new_line_segment(type, text, length);
column->segments[index] = segment;
refresh_line_column_width(column);
}
/******************************************************************************
* *
* 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 : - *
* *
******************************************************************************/
bool get_line_column_first_content_index(const 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 : - *
* *
******************************************************************************/
bool get_line_column_last_content_index(const 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. *
* index = indice à consulter puis renseigner. [OUT] *
* dir = orientation des recherches. *
* *
* Description : Fournit le segment voisin d'un autre segment identifié. *
* *
* Retour : Validité de l'indice renseigné. *
* *
* Remarques : - *
* *
******************************************************************************/
bool find_near_segment(const line_column *column, size_t *index, GdkScrollDirection dir)
{
bool result; /* Bilan à faire remonter */
result = false;
switch (dir)
{
case GDK_SCROLL_LEFT:
if (*index > 0)
{
(*index)--;
result = true;
}
break;
case GDK_SCROLL_RIGHT:
if ((*index + 1) < column->count)
{
(*index)++;
result = true;
}
break;
default:
break;
}
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 : Indique l'indice du contenu de colonne à une abscisse donnée.*
* *
* Retour : Validité de l'indice renseigné. *
* *
* Remarques : - *
* *
******************************************************************************/
bool get_line_column_content_index_at(const line_column *column, gint *x, GdkScrollDirection dir, gint *consumed, size_t *index)
{
bool result; /* Bilan à retourner */
size_t i; /* Boucle de parcours */
gint width; /* Largeur à retirer */
bool included; /* Appartenance à une largeur ?*/
result = false;
*consumed = 0;
for (i = 0; i < column->count && !result; i++)
{
width = get_line_segment_width(column->segments[i]);
/**
* Soit une limite entre deux segments A et B :
*
* - dans le cas d'un déplacement vers la gauche, on part de cette limite
* pour progresser à l'intérieur de A. Donc la limite fait partie de A.
*
* - dans le cas d'un déplacement vers la droite, on part de cette limite
* pour progresser à l'intérieur de B. Donc la limite ne fait pas partie de A.
*/
if (dir == GDK_SCROLL_LEFT) included = (width >= *x);
else included = (width > *x);
if (included)
{
*index = i;
result = true;
}
else if ((i + 1) == column->count)
{
*index = i;
result = true;
*x = width;
}
else
{
*x -= width;
*consumed += width;
}
}
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 : - *
* *
******************************************************************************/
line_segment *get_line_column_content_from_index(const line_column *column, size_t index)
{
line_segment *result; /* Trouvaille à retourner */
assert(index != -1 && index < column->count);
result = column->segments[index];
ref_line_segment(result);
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. *
* 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. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void draw_line_column_segments(const 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 */
x = x_init;
for (i = 0; i < column->count; i++)
draw_line_segment(column->segments[i], cairo, &x, y, list);
}
/******************************************************************************
* *
* Paramètres : column = colonne de ligne de texte à venir consulter. *
* markup = indique si le texte doit être décoré ou non. *
* *
* Description : Donne le texte représenté par une colonne de ligne de texte. *
* *
* Retour : Texte à libérer de la mémoire après usage. *
* *
* Remarques : - *
* *
******************************************************************************/
char *get_line_column_text(const line_column *column, bool markup)
{
char *result; /* Construction à retourner */
size_t i; /* Boucle de parcours */
char *extra; /* Contenu à intégrer au texte */
result = NULL;
for (i = 0; i < column->count; i++)
{
extra = get_line_segment_text(column->segments[i], markup);
if (result == NULL)
result = extra;
else
{
result = stradd(result, extra);
free(extra);
}
}
return result;
}
/******************************************************************************
* *
* Paramètres : column = colonne de ligne de texte à manipuler. *
* ctx = éléments à disposition pour l'exportation. *
* type = type d'exportation attendue. *
* span = fusion de colonnes au sein des cellules ? *
* *
* Description : Exporte la ligne de texte représentée. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void export_line_column_segments(const line_column *column, buffer_export_context *ctx, BufferExportType type, int span)
{
size_t i; /* Boucle de parcours */
switch (type)
{
case BET_HTML:
switch (span)
{
case 0:
break;
case 1:
dprintf(ctx->fd, "\t\t");
break;
default:
if (span > 0) dprintf(ctx->fd, "\t\t | ", span);
break;
}
break;
default:
break;
}
for (i = 0; i < column->count; i++)
export_line_segment(column->segments[i], ctx, type);
switch (type)
{
case BET_HTML:
if (span < 0 || span == 1) dprintf(ctx->fd, " | \n");
break;
default:
break;
}
}