/*
* textarea.c -- portable gui library text area, platform independent
*/
#include "gui.h"
static void reflow_from(struct gui_ta *doc, unsigned int c, unsigned int w,
gui_window_id window_id, unsigned int x_offset, unsigned int y_offset, int newline);
#ifdef DEBUG
static int document_ok(const struct gui_ta *doc);
#endif
/*
* gui_ta -- return a new document with the specified width
*/
struct gui_ta *gui_ta(unsigned long width)
{
struct gui_ta *doc = malloc(sizeof(struct gui_ta));
#ifdef DEBUG
printf("gui_ta: width = %li\n", width);
fflush(stdout);
#endif
if (doc == NULL) return NULL;
doc->width = width;
doc->height = doc->contents = doc->styles = 0;
doc->content = malloc(0);
doc->style = malloc(0);
if (doc->content == NULL || doc->style == NULL) return NULL;
assert(document_ok(doc));
#ifdef DEBUG
printf("gui_ta: doc = %p\n", doc);
fflush(stdout);
#endif
return doc;
}
/*
* gui_ta_add_space -- add a space of the specified height to the document
* and return success
*/
long gui_ta_add_space(struct gui_ta *doc, unsigned long height)
{
struct gui_ta_content *con = malloc(sizeof(struct gui_ta_content));
struct gui_ta_content *(*new_content)[];
#ifdef DEBUG
printf("gui_ta_add_space: doc = %p, height = %li\n", doc, height);
fflush(stdout);
#endif
assert(document_ok(doc));
new_content = realloc(doc->content, (doc->contents + 1) * sizeof(struct gui_ta_content *));
if (con == NULL || new_content == NULL) return 0;
con->type = CONTENT_SPACE;
con->y0 = doc->height;
con->y1 = doc->height + height;
(*new_content)[doc->contents] = con;
doc->content = new_content;
doc->height += height;
doc->contents++;
assert(document_ok(doc));
return 1;
}
/*
* gui_ta_add_paragraph -- add a paragraph of text
*/
int gui_ta_add_paragraph(struct gui_ta *doc, unsigned long leading,
unsigned long base, wchar_t *text, unsigned long style, unsigned long align)
{
unsigned int words = 1; /* number of words added */
unsigned int w; /* word number */
wchar_t *text_pos = text; /* current position in text */
struct gui_ta_content *con = malloc(sizeof(struct gui_ta_content));
struct gui_ta_content *(*new_content)[];
struct gui_ta_word *word; /* current word structure */
unsigned int len; /* length of current word */
wchar_t *space; /* position of next space */
#ifdef DEBUG
printf("gui_ta_add_paragraph: doc = %p, leading = %li, base = %li, style = %li\n", doc, leading, base, style);
fflush(stdout);
#endif
assert(document_ok(doc));
new_content = realloc(doc->content, (doc->contents + 1) * sizeof(struct gui_ta_content *));
if (con == NULL || new_content == NULL) return 0;
/* set up new paragraph */
con->type = CONTENT_PARAGRAPH;
con->y0 = doc->height;
con->leading = leading;
con->base = base;
con->align = align;
/* count words and allocate space */
while (*text_pos) if (*text_pos++ == ' ') words++;
con->words = words;
con->word = calloc(words, sizeof(struct gui_ta_word *));
if (con->word == NULL) return 0;
/* add the words */
text_pos = text;
for (w = 0; w < words; w++)
{
space = wcschr(text_pos, ' ');
len = (space ? space - text_pos : wcslen(text_pos));
word = malloc(gui_SIZEOF_GUI_TA_WORD(len + 1));
if (word == NULL) return 0;
wcsncpy(word->text, text_pos, len);
word->text[len] = 0;
word->width = gui_ta_text_width(doc, word->text, style);
word->style = style;
(*con->word)[w] = word;
text_pos += len + 1;
}
doc->height = gui_ta_reformat_paragraph(doc, con, doc->height, doc->width, 0, 0);
/* add paragraph to document */
(*new_content)[doc->contents] = con;
doc->content = new_content;
doc->contents++;
assert(document_ok(doc));
return 1;
}
/*
* gui_ta_get_style -- get a style number, creating a new style if required
*/
unsigned long gui_ta_get_style(struct gui_ta *doc, unsigned long xsize,
unsigned long ysize, unsigned long fcolour, unsigned long bcolour, char *font)
{
unsigned int s; /* style number */
struct gui_ta_style *style; /* current style structure */
struct gui_ta_style *(*new_style)[]; /* new style pointer list */
wchar_t const space[] = { 0x0020, 0 };
#ifdef DEBUG
printf("gui_ta_get_style: doc = %p, font = '%s'\n", doc, font);
fflush(stdout);
#endif
assert(document_ok(doc));
/* search for existing style */
for (s = 0; s < doc->styles; s++)
{
style = (*doc->style)[s];
if (style->xsize == xsize &&
style->ysize == ysize &&
style->fcolour == fcolour &&
style->bcolour == bcolour &&
strcmp(style->font, font) == 0) return s;
}
/* create a new style */
style = malloc(gui_SIZEOF_GUI_TA_STYLE(strlen(font) + 1));
if (style == NULL) return 0;
new_style = realloc(doc->style, (doc->styles + 1) * sizeof(struct gui_ta_style *));
if (new_style == NULL) return 0;
style->xsize = xsize;
style->ysize = ysize;
style->fcolour = fcolour;
style->bcolour = bcolour;
strcpy(style->font, font);
gui_ta_fill_style(style);
(*new_style)[doc->styles] = style;
doc->style = new_style;
doc->styles++;
style->space = gui_ta_text_width(doc, space, doc->styles - 1);
assert(document_ok(doc));
return doc->styles - 1;
}
/*
* gui_ta_render -- render document to the screen
*/
void gui_ta_render(struct gui_ta *doc, unsigned long x, unsigned long y,
unsigned int invalid[], struct gui_ta_selection *sel)
{
unsigned int c;
unsigned int w;
unsigned int base;
const signed int x0 = (invalid[0] < x ? 0 : invalid[0] - x);
const unsigned int y0 = (invalid[1] < y ? 0 : invalid[1] - y);
const signed int x1 = (invalid[2] < x ? 0 : invalid[2] - x);
const unsigned int y1 = (invalid[3] < y ? 0 : invalid[3] - y);
struct gui_ta_content *con;
struct gui_ta_word *word;
#ifdef DEBUG
printf("gui_ta_render: doc = %p\n", doc);
fflush(stdout);
#endif
assert(document_ok(doc));
/* loop through document contents */
for (c = 0; c < doc->contents; c++)
{
con = (*doc->content)[c];
/* render content if it lies in invalid area */
if (!(con->y0 > y1 || con->y1 < y0))
{
switch (con->type)
{
case CONTENT_SPACE:
break;
case CONTENT_PARAGRAPH:
base = con->base;
/* loop through paragraph words */
for (w = 0; w < con->words; w++)
{
word = (*con->word)[w];;
/* continue if word is above or to right of invalid area */
if (word->y < y0 || word->box_x0 > x1) continue;
/* exit if word is below invalid area */
if (word->y - con->leading > y1) return;
assert((w < con->words - 1) || ((w == con->words - 1) && word->end));
/* render word if it lies in invalid area */
if (word->box_x1 >= x0)
gui_ta_render_text(doc, word->text, word->style, x + word->x, y + word->y - base,
x + word->box_x0, y + word->y - con->leading, x + word->box_x1, y + word->y,
sel &&
(c > sel->start.content || (c == sel->start.content && w >= sel->start.word)) &&
(c < sel->end.content || (c == sel->end.content && w <= sel->end.word)));
}
break;
}
}
}
}
/*
* gui_ta_position_xy -- update position from coordinates
*/
void gui_ta_position_xy(struct gui_ta *doc, struct gui_ta_position *pos,
signed long x, unsigned long y)
{
unsigned int c = 0; /* content number */
unsigned int w = 0; /* word number */
unsigned int word_y; /* y position of word */
struct gui_ta_content *con; /* current content structure */
#ifdef DEBUG
printf("gui_ta_position_xy: doc = %p\n", doc);
fflush(stdout);
#endif
assert(document_ok(doc));
if (doc->contents == 0) return;
if (y > doc->height)
c = doc->contents - 1;
else
while (y > (*doc->content)[c]->y1) c++;
if (x < 0) x = 0;
pos->content = c;
con = (*doc->content)[c];
switch (con->type)
{
case CONTENT_SPACE:
pos->word = pos->offset = pos->x = pos->y = 0xffffffffu;
break;
case CONTENT_PARAGRAPH:
word_y = con->y0 + con->leading;
while (y > word_y) word_y += con->leading;
if (word_y > con->y1) word_y = con->y1;
while ((*con->word)[w]->y != word_y) w++;
while (x > (signed long) ((*con->word)[w]->x + (*con->word)[w]->width))
{
if (w == con->words - 1 || (*con->word)[w + 1]->y != word_y)
{
pos->word = w;
pos->offset = wcslen((*con->word)[w]->text);
pos->x = (*con->word)[w]->x + (*con->word)[w]->width;
pos->y = word_y;
return;
}
w++;
}
pos->word = w;
pos->y = word_y;
x -= (*con->word)[w]->x;
pos->offset = gui_ta_position_x(doc, (*con->word)[w]->text,
(*con->word)[w]->style, &x);
pos->x = (*con->word)[w]->x + x;
break;
}
}
/*
* gui_ta_reformat -- change the width of the document
*/
void gui_ta_reformat(struct gui_ta *doc, unsigned long width)
{
unsigned int c; /* content number */
unsigned int y = 0; /* current y coordinate */
unsigned int h; /* height of space */
struct gui_ta_content *con; /* current content structure */
#ifdef DEBUG
printf("gui_ta_reformat: doc = %p\n", doc);
fflush(stdout);
#endif
for (c = 0; c < doc->contents; c++)
{
con = (*doc->content)[c];
switch (con->type)
{
case CONTENT_SPACE:
h = con->y1 - con->y0;
con->y0 = y;
con->y1 = y = y + h;
break;
case CONTENT_PARAGRAPH:
y = gui_ta_reformat_paragraph(doc, con, y, width, 0, 0);
break;
}
}
doc->width = width;
doc->height = y;
assert(document_ok(doc));
}
/*
* gui_ta_reformat_paragraph
*/
unsigned int gui_ta_reformat_paragraph(struct gui_ta *doc,
struct gui_ta_content *con, unsigned long y, unsigned long width,
unsigned long *y0_ret, unsigned long *y1_ret)
{
unsigned int x = 0; /* current x coordinate */
unsigned int x1 = 0; /* current x coordinate excluding last space */
unsigned int w; /* word number */
unsigned int w_start = 0; /* word at start of line */
unsigned int w_align; /* word when aligning */
unsigned int space;
unsigned int y0, y1;
unsigned int change = 0;
struct gui_ta_word *word; /* current word structure */
struct gui_ta_word *next_word;
if (y0_ret) y0 = *y0_ret;
if (y1_ret) y1 = *y1_ret;
con->y0 = y;
y += con->leading;
for (w = 0; w < con->words; w++)
{
word = (*con->word)[w];
if ((x + word->width > width) && (x != 0))
{
space = width - x1;
switch (con->align)
{
case ALIGN_LEFT:
for (w_align = w_start; w_align < w; w_align++)
(*con->word)[w_align]->x = (*con->word)[w_align]->lx;
break;
case ALIGN_CENTRE:
space /= 2;
case ALIGN_RIGHT:
for (w_align = w_start; w_align < w; w_align++)
(*con->word)[w_align]->x = (*con->word)[w_align]->lx + space;
break;
case ALIGN_FULL:
(*con->word)[w_start]->x = (*con->word)[w_start]->lx;
for (w_align = 1; w_align < w - w_start; w_align++)
(*con->word)[w_start + w_align]->x = (*con->word)[w_start + w_align]->lx +
w_align * space / (w - w_start - 1);
break;
}
(*con->word)[w_start]->start = 1;
(*con->word)[w - 1]->end = 1;
x = x1 = 0;
y += con->leading;
w_start = w;
}
if (change == 0 && (x != word->lx || y != word->y))
{
if (y < word->y) { y0 = y - con->leading; y1 = word->y; }
else { y0 = word->y - con->leading; y1 = y; }
change = 1;
}
else if (change == 1 && (x != word->lx || y != word->y)) y1 = y < word->y ? word->y : y;
else if (change == 1 && x == word->lx && y == word->y) change = 2;
word->lx = x;
word->y = y;
word->start = word->end = 0;
x1 = x + word->width;
x = x1 + (*doc->style)[word->style]->space;
}
space = width - x1;
switch (con->align)
{
case ALIGN_LEFT:
case ALIGN_FULL:
for (w_align = w_start; w_align < con->words; w_align++)
(*con->word)[w_align]->x = (*con->word)[w_align]->lx;
break;
case ALIGN_CENTRE:
space /= 2;
case ALIGN_RIGHT:
for (w_align = w_start; w_align < con->words; w_align++)
(*con->word)[w_align]->x = (*con->word)[w_align]->lx + space;
break;
}
(*con->word)[w_start]->start = 1;
word->end = 1;
next_word = (*con->word)[0];
for (w = 0; w < con->words; w++)
{
word = next_word;
next_word = (*con->word)[w + 1];
word->box_x0 = word->start ? 0 : word->x;
word->box_x1 = word->end ? width : next_word->x;
}
con->y1 = y;
if (y0_ret) *y0_ret = y0 < *y0_ret ? y0 : *y0_ret;
if (y1_ret) *y1_ret = y1 < *y1_ret ? *y1_ret : y1;
return y;
}
/*
* gui_ta_insert_char -- insert a character at the specified position
*/
void gui_ta_insert_char(struct gui_ta *doc, struct gui_ta_position *pos,
wchar_t text, gui_window_id window_id,
unsigned long x_offset, unsigned long y_offset)
{
struct gui_ta_content *con = (*doc->content)[pos->content];
struct gui_ta_word *word = (*con->word)[pos->word];
#ifdef DEBUG
printf("gui_ta_insert_char: doc = %p, char = %04x\n", doc, text);
fflush(stdout);
#endif
assert(document_ok(doc));
word = realloc(word, gui_SIZEOF_GUI_TA_WORD(wcslen(word->text) + 2));
if (word == NULL) return;
memmove(word->text + pos->offset + 1, word->text + pos->offset,
(wcslen(word->text + pos->offset) + 1) * sizeof(wchar_t));
word->text[pos->offset] = text;
word->width = gui_ta_text_width(doc, word->text, word->style);
(*con->word)[pos->word] = word;
reflow_from(doc, pos->content, pos->word, window_id, x_offset, y_offset, 0);
}
/*
* gui_ta_insert_split -- split a word into two words at the specified position
*/
void gui_ta_insert_split(struct gui_ta *doc, struct gui_ta_position *pos,
gui_window_id window_id, unsigned long x_offset, unsigned long y_offset)
{
struct gui_ta_content *con = (*doc->content)[pos->content];
struct gui_ta_word *word = (*con->word)[pos->word];
struct gui_ta_word *left = malloc(gui_SIZEOF_GUI_TA_WORD(pos->offset + 1));
struct gui_ta_word *right = malloc(gui_SIZEOF_GUI_TA_WORD(wcslen(word->text) - pos->offset + 1));
struct gui_ta_word *(*new_word)[] = malloc((con->words + 1) * sizeof(struct gui_ta_word *));
#ifdef DEBUG
printf("gui_ta_insert_split: doc = %p\n", doc);
fflush(stdout);
#endif
assert(document_ok(doc));
if (new_word == NULL || left == NULL || right == NULL) return;
memcpy(*new_word, *con->word, pos->word * sizeof(struct gui_ta_word *));
(*new_word)[pos->word] = left;
(*new_word)[pos->word + 1] = right;
memcpy(*new_word + pos->word + 2, *con->word + pos->word + 1,
(con->words - pos->word - 1) * sizeof(struct gui_ta_word *));
wcsncpy(left->text, word->text, pos->offset);
left->text[pos->offset] = 0;
left->style = word->style;
left->width = gui_ta_text_width(doc, left->text, left->style);
left->x = word->x;
left->lx = word->lx;
left->y = word->y;
wcscpy(right->text, word->text + pos->offset);
right->style = word->style;
right->width = gui_ta_text_width(doc, right->text, right->style);
right->x = right->y = 0;
left->lx = 0;
free(word);
free(con->word);
con->word = new_word;
con->words++;
if (pos->word && (*con->word)[pos->word - 1]->y != left->y)
{
left->x = left->y = 0;
reflow_from(doc, pos->content, pos->word - 1, window_id, x_offset, y_offset, 0);
}
else
reflow_from(doc, pos->content, pos->word, window_id, x_offset, y_offset, 0);
}
/*
* gui_ta_insert_newline -- split a paragraph into two paragraphs at the specified position
*/
void gui_ta_insert_newline(struct gui_ta *doc, struct gui_ta_position *pos,
gui_window_id window_id, unsigned long x_offset, unsigned long y_offset)
{
struct gui_ta_content *con = (*doc->content)[pos->content];
struct gui_ta_content *new_con = malloc(sizeof(struct gui_ta_content));
struct gui_ta_word *word = (*con->word)[pos->word];
struct gui_ta_word *left = malloc(gui_SIZEOF_GUI_TA_WORD(pos->offset + 1));
struct gui_ta_word *right = malloc(gui_SIZEOF_GUI_TA_WORD(wcslen(word->text) - pos->offset + 1));
struct gui_ta_word *(*new_word)[] = malloc((con->words - pos->word) * sizeof(struct gui_ta_word *));
struct gui_ta_content *(*content)[];
#ifdef DEBUG
printf("gui_ta_insert_newline: doc = %p\n", doc);
fflush(stdout);
#endif
assert(document_ok(doc));
content = realloc(doc->content, (doc->contents + 1) * sizeof(struct gui_ta_content *));
if (new_con == NULL || new_word == NULL || left == NULL || right == NULL || content == NULL) return;
doc->content = content;
new_con->type = con->type;
new_con->y0 = 0;
new_con->y1 = con->y1;
new_con->leading = con->leading;
new_con->base = con->base;
new_con->align = con->align;
new_con->words = con->words - pos->word;
new_con->word = new_word;
(*new_word)[0] = right;
memcpy(*new_word + 1, *con->word + pos->word + 1,
(con->words - pos->word - 1) * sizeof(struct gui_ta_word *));
wcsncpy(left->text, word->text, pos->offset);
left->text[pos->offset] = 0;
left->style = word->style;
left->width = gui_ta_text_width(doc, left->text, left->style);
left->x = word->x;
left->y = word->y;
wcscpy(right->text, word->text + pos->offset);
right->style = word->style;
right->width = gui_ta_text_width(doc, right->text, right->style);
right->x = right->y = 0;
free(word);
(*con->word)[pos->word] = left;
con->words = pos->word + 1;
memmove(*doc->content + pos->content + 2, *doc->content + pos->content + 1,
(doc->contents - pos->content - 1) * sizeof(struct gui_ta_content *));
(*doc->content)[pos->content + 1] = new_con;
doc->contents++;
if (pos->word && (*con->word)[pos->word - 1]->y != left->y)
{
left->x = left->lx = left->y = 0;
reflow_from(doc, pos->content, pos->word - 1, window_id, x_offset, y_offset, 1);
}
else
reflow_from(doc, pos->content, pos->word, window_id, x_offset, y_offset, 1);
}
/*
* reflow_from -- helper function to reflow document after insertion / deletion
*/
void reflow_from(struct gui_ta *doc, unsigned int c0, unsigned int w0,
gui_window_id window_id, unsigned int x_offset, unsigned int y_offset, int newline)
{
unsigned int y;
unsigned long y0, y1;
unsigned int old_y1;
unsigned int c, w;
struct gui_ta_content *con = (*doc->content)[c0];
y0 = (*con->word)[w0]->y - con->leading;
y1 = (*con->word)[w0]->y;
old_y1 = con->y1;
y = gui_ta_reformat_paragraph(doc, con, con->y0, doc->width, &y0, &y1);
if (y == old_y1 && !newline)
{
assert(document_ok(doc));
gui_refresh_box(window_id, x_offset, y_offset + y0,
x_offset + doc->width, y_offset + y1);
return;
}
if (c0 + 1 < doc->contents)
{
con = (*doc->content)[c0 + 1];
if (newline)
{
y = gui_ta_reformat_paragraph(doc, con, y, doc->width, 0, &y1);
if (c0 + 2 == doc->contents)
{
doc->height = y;
assert(document_ok(doc));
gui_refresh_box(window_id, x_offset, y_offset + y0,
x_offset + doc->width, y_offset + y1);
#ifdef DEBUG
printf("reflow_from: last content\n");
fflush(stdout);
#endif
return;
}
con = (*doc->content)[c0 + 2];
}
if (y != con->y0)
{
signed int move = y - con->y0;
gui_move_box(window_id, x_offset, y_offset + con->y0, x_offset + doc->width,
y_offset + doc->height, x_offset, y_offset + y);
for (c = c0 + 1 + newline; c < doc->contents; c++)
{
con = (*doc->content)[c];
con->y0 += move;
con->y1 += move;
switch (con->type)
{
case CONTENT_SPACE:
break;
case CONTENT_PARAGRAPH:
for (w = 0; w < con->words; w++) (*con->word)[w]->y += move;
break;
}
}
doc->height += move;
}
}
else
{
doc->height = y;
}
assert(document_ok(doc));
gui_refresh_box(window_id, x_offset, y_offset + y0,
x_offset + doc->width, y_offset + y1);
#ifdef DEBUG
printf("reflow_from: full\n");
fflush(stdout);
#endif
}
/*
* gui_ta_position_cwo -- update position from content, word, offset
*/
void gui_ta_position_cwo(struct gui_ta *doc, struct gui_ta_position *pos)
{
struct gui_ta_word *word = (*(*doc->content)[pos->content]->word)[pos->word];
#ifdef DEBUG
printf("gui_ta_position_cwo: doc = %p\n", doc);
fflush(stdout);
#endif
assert(document_ok(doc));
pos->x = word->x + gui_ta_position_o(doc, word->text, word->style, pos->offset);
pos->y = word->y;
}
/*
* gui_ta_delete -- delete a block of text
*
* There are two possible cases:
*
* 1. The block to be deleted lies within one word
* => remove those characters
* 2. The block is between different words
* => remove intervening words, and merge words
*/
void gui_ta_delete(struct gui_ta *doc, struct gui_ta_position *start,
struct gui_ta_position *end, gui_window_id window_id,
unsigned long x_offset, unsigned long y_offset)
{
unsigned int c = start->content;
unsigned int w = start->word;
// struct gui_ta_content *con = (*doc->content)[c];
struct gui_ta_content *start_con = (*doc->content)[c];
struct gui_ta_word *start_word = (*start_con->word)[w];
struct gui_ta_content *end_con = (*doc->content)[end->content];
struct gui_ta_word *end_word = (*end_con->word)[end->word];
void *mem;
assert(end->content > start->content ||
(end->content == start->content &&
(end->word > start->word || (end->word == start->word && end->offset > start->offset))));
/* case 1 */
if (start_word == end_word)
{
wcscpy(start_word->text + start->offset, end_word->text + end->offset);
start_word->width = gui_ta_text_width(doc, start_word->text, start_word->style);
reflow_from(doc, start->content, start->word, window_id, x_offset, y_offset, 0);
return;
}
/* case 2 */
mem = realloc(start_word, gui_SIZEOF_GUI_TA_WORD(start->offset + wcslen(end_word->text + end->offset) + 1));
if (mem == NULL) return;
start_word = (*start_con->word)[start->word] = mem;
if (start_con != end_con)
{
mem = realloc(start_con->word, (start->word + end_con->words - end->word) *
sizeof(struct gui_ta_word *));
if (mem == NULL) return;
start_con->word = mem;
}
wcscpy(start_word->text + start->offset, end_word->text + end->offset);
start_word->width = gui_ta_text_width(doc, start_word->text, start_word->style);
memcpy(*start_con->word + start->word + 1, *end_con->word + end->word + 1,
(end_con->words - end->word - 1) * sizeof(struct gui_ta_word *));
start_con->words = start->word + end_con->words - end->word;
if (start_con == end_con)
{
reflow_from(doc, start->content, start->word, window_id, x_offset, y_offset, 0);
return;
}
start_con->y1 = end_con->y1;
free(end_con->word);
free(end_con);
memcpy(*doc->content + start->content + 1, *doc->content + end->content + 1,
(doc->contents - end->content - 1) * sizeof(struct gui_ta_content *));
doc->contents = start->content + doc->contents - end->content;
mem = realloc(doc->content, doc->contents * sizeof(struct gui_ta_content *));
if (mem) doc->content = mem;
reflow_from(doc, start->content, start->word, window_id, x_offset, y_offset, 0);
}
/*
while (c < end->content || w < end->word)
{
w++;
if (w == con->words)
{
if (c > start->content && c < end->content)
{
free(con->word);
free(con);
}
c++;
w = 0;
con = (*doc->content)[c];
}
free((*con->word)[w]);
}
*/
/*
* gui_ta_remove -- free up resources associated with a document
*/
extern void gui_ta_remove(struct gui_ta *doc)
{
unsigned int c, w, s;
struct gui_ta_content *con;
for (c = 0; c < doc->contents; c++)
{
con = (*doc->content)[c];
switch (con->type)
{
case CONTENT_PARAGRAPH:
{
for (w = 0; w < con->words; w++)
free((*con->word)[w]);
break;
}
case CONTENT_SPACE:
;
}
free(con);
}
for (s = 0; s < doc->styles; s++)
{
gui_ta_empty_style((*doc->style)[s]);
free((*doc->style)[s]);
}
}
/*
* gui_ta_align
*/
void gui_ta_align(struct gui_ta *doc, unsigned int content, unsigned int align,
gui_window_id window_id, unsigned int x_offset, unsigned int y_offset)
{
struct gui_ta_content *con = (*doc->content)[content];
con->align = align;
gui_ta_reformat_paragraph(doc, con, con->y0, doc->width, 0, 0);
gui_refresh_box(window_id, x_offset, y_offset + con->y0,
x_offset + doc->width, y_offset + con->y1);
}
/*
* gui_ta_export -- export a document
*/
void gui_ta_export(struct gui_ta *doc, const char *path)
{
unsigned int c, w, s;
FILE *fp = fopen(path, "w");
struct gui_ta_style *style;
struct gui_ta_content *con;
struct gui_ta_word *word;
wfputc(0x74785457, fp);
wfputc(doc->contents, fp);
for (c = 0; c < doc->contents; c++)
{
con = (*doc->content)[c];
switch (con->type)
{
case CONTENT_SPACE:
wfputc(0x63617053, fp);
break;
case CONTENT_PARAGRAPH:
{
wfputc(0x61726150, fp);
wfputc(con->leading, fp);
wfputc(con->base, fp);
for (w = 0; w < con->words; w++)
{
word = (*con->word)[w];
if ((w == 0) || (word->style != s))
{
/* style = (*doc->style)[s]; */
/* fprintf(fp, " %s\n", style->font); */
/* fprintf(fp, " %d\n", style->xsize); */
/* fprintf(fp, " %d\n", style->ysize); */
/* fprintf(fp, " %x\n", style->fcolour); */
/* fprintf(fp, " %x\n", style->bcolour); */
wfputc(word->style, fp);
}
s = word->style;
wfputs(word->text, fp);
}
break;
}
}
}
fclose(fp);
}
#ifdef DEBUG
/*
* document_ok -- check document integrity
*/
int document_ok(const struct gui_ta *doc)
{
unsigned int c;
unsigned int w;
const struct gui_ta_content *con;
const struct gui_ta_word *word;
/* printf("%p [width %i, height %i, contents %i, styles %i]\n", */
/* doc, doc->width, doc->height, doc->contents, doc->styles); */
for (c = 0; c < doc->contents; c++)
{
con = (*doc->content)[c];
/* printf("%i %p\n", c, con); */
if (c && con->y0 != (*doc->content)[c - 1]->y1)
{
printf("content y coordinates don't match %i %li, %i %li\n", c - 1, (*doc->content)[c - 1]->y1,
c, con->y0);
fflush(stdout);
return 0;
}
if (con->y1 > doc->height)
{
printf("con->y1 %li greater than doc->height %li\n", con->y1, doc->height);
fflush(stdout);
return 0;
}
switch (con->type)
{
case CONTENT_SPACE:
/* printf("\n", */
/* con->y0, con->y1); */
break;
case CONTENT_PARAGRAPH:
/* printf("\n", */
/* con->y0, con->y1, con->leading, con->words); */
for (w = 0; w < con->words; w++)
{
word = (*con->word)[w];
/* printf(" \n", */
/* word->x, word->y, word->width, word->style, word->box_x0, word->box_x1); */
if (word->x > doc->width)
{
printf("word->x %li greater than doc->width %li\n", word->x, doc->width);
fflush(stdout);
return 0;
}
if ((word->x != 0) && (word->x + word->width > doc->width))
{
printf("word->x %li + word->width %li greater than doc->width %li\n", word->x,
word->width, doc->width);
fflush(stdout);
return 0;
}
if (word->y < con->y0 || word->y > con->y1)
{
printf("word->y %li not within content y %li %li\n", word->y, con->y0, con->y1);
fflush(stdout);
return 0;
}
if (word->style >= doc->styles)
{
printf("word->style %li greater than doc->styles %li\n", word->style, doc->styles);
fflush(stdout);
return 0;
}
}
break;
default:
printf("unknown document content type %li %li\n", c, con->type);
fflush(stdout);
return 0;
}
}
return 1;
}
#endif