/[james]/archive/guilib/textarea.c
ViewVC logotype

Contents of /archive/guilib/textarea.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 16 - (show annotations) (download) (as text)
Mon Feb 10 22:56:40 2003 UTC (21 years, 10 months ago) by james
File MIME type: text/x-csrc
File size: 29266 byte(s)
Initial import.

1 /*
2 * textarea.c -- portable gui library text area, platform independent
3 */
4
5 #include "gui.h"
6
7
8 static void reflow_from(struct gui_ta *doc, unsigned int c, unsigned int w,
9 gui_window_id window_id, unsigned int x_offset, unsigned int y_offset, int newline);
10
11 #ifdef DEBUG
12 static int document_ok(const struct gui_ta *doc);
13 #endif
14
15
16 /*
17 * gui_ta -- return a new document with the specified width
18 */
19
20 struct gui_ta *gui_ta(unsigned long width)
21 {
22 struct gui_ta *doc = malloc(sizeof(struct gui_ta));
23
24 #ifdef DEBUG
25 printf("gui_ta: width = %li\n", width);
26 fflush(stdout);
27 #endif
28
29 if (doc == NULL) return NULL;
30
31 doc->width = width;
32 doc->height = doc->contents = doc->styles = 0;
33 doc->content = malloc(0);
34 doc->style = malloc(0);
35
36 if (doc->content == NULL || doc->style == NULL) return NULL;
37
38 assert(document_ok(doc));
39
40 #ifdef DEBUG
41 printf("gui_ta: doc = %p\n", doc);
42 fflush(stdout);
43 #endif
44
45 return doc;
46 }
47
48
49 /*
50 * gui_ta_add_space -- add a space of the specified height to the document
51 * and return success
52 */
53
54 long gui_ta_add_space(struct gui_ta *doc, unsigned long height)
55 {
56 struct gui_ta_content *con = malloc(sizeof(struct gui_ta_content));
57 struct gui_ta_content *(*new_content)[];
58
59 #ifdef DEBUG
60 printf("gui_ta_add_space: doc = %p, height = %li\n", doc, height);
61 fflush(stdout);
62 #endif
63
64 assert(document_ok(doc));
65
66 new_content = realloc(doc->content, (doc->contents + 1) * sizeof(struct gui_ta_content *));
67 if (con == NULL || new_content == NULL) return 0;
68
69 con->type = CONTENT_SPACE;
70 con->y0 = doc->height;
71 con->y1 = doc->height + height;
72
73 (*new_content)[doc->contents] = con;
74 doc->content = new_content;
75 doc->height += height;
76 doc->contents++;
77
78 assert(document_ok(doc));
79
80 return 1;
81 }
82
83
84 /*
85 * gui_ta_add_paragraph -- add a paragraph of text
86 */
87
88 int gui_ta_add_paragraph(struct gui_ta *doc, unsigned long leading,
89 unsigned long base, wchar_t *text, unsigned long style, unsigned long align)
90 {
91 unsigned int words = 1; /* number of words added */
92 unsigned int w; /* word number */
93 wchar_t *text_pos = text; /* current position in text */
94 struct gui_ta_content *con = malloc(sizeof(struct gui_ta_content));
95 struct gui_ta_content *(*new_content)[];
96 struct gui_ta_word *word; /* current word structure */
97 unsigned int len; /* length of current word */
98 wchar_t *space; /* position of next space */
99
100 #ifdef DEBUG
101 printf("gui_ta_add_paragraph: doc = %p, leading = %li, base = %li, style = %li\n", doc, leading, base, style);
102 fflush(stdout);
103 #endif
104
105 assert(document_ok(doc));
106
107 new_content = realloc(doc->content, (doc->contents + 1) * sizeof(struct gui_ta_content *));
108 if (con == NULL || new_content == NULL) return 0;
109
110 /* set up new paragraph */
111 con->type = CONTENT_PARAGRAPH;
112 con->y0 = doc->height;
113 con->leading = leading;
114 con->base = base;
115 con->align = align;
116
117 /* count words and allocate space */
118 while (*text_pos) if (*text_pos++ == ' ') words++;
119
120 con->words = words;
121 con->word = calloc(words, sizeof(struct gui_ta_word *));
122 if (con->word == NULL) return 0;
123
124 /* add the words */
125 text_pos = text;
126 for (w = 0; w < words; w++)
127 {
128 space = wcschr(text_pos, ' ');
129 len = (space ? space - text_pos : wcslen(text_pos));
130
131 word = malloc(gui_SIZEOF_GUI_TA_WORD(len + 1));
132 if (word == NULL) return 0;
133
134 wcsncpy(word->text, text_pos, len);
135 word->text[len] = 0;
136
137 word->width = gui_ta_text_width(doc, word->text, style);
138 word->style = style;
139
140 (*con->word)[w] = word;
141
142 text_pos += len + 1;
143 }
144
145 doc->height = gui_ta_reformat_paragraph(doc, con, doc->height, doc->width, 0, 0);
146
147 /* add paragraph to document */
148 (*new_content)[doc->contents] = con;
149 doc->content = new_content;
150 doc->contents++;
151
152 assert(document_ok(doc));
153
154 return 1;
155 }
156
157
158 /*
159 * gui_ta_get_style -- get a style number, creating a new style if required
160 */
161
162 unsigned long gui_ta_get_style(struct gui_ta *doc, unsigned long xsize,
163 unsigned long ysize, unsigned long fcolour, unsigned long bcolour, char *font)
164 {
165 unsigned int s; /* style number */
166 struct gui_ta_style *style; /* current style structure */
167 struct gui_ta_style *(*new_style)[]; /* new style pointer list */
168 wchar_t const space[] = { 0x0020, 0 };
169
170 #ifdef DEBUG
171 printf("gui_ta_get_style: doc = %p, font = '%s'\n", doc, font);
172 fflush(stdout);
173 #endif
174
175 assert(document_ok(doc));
176
177 /* search for existing style */
178 for (s = 0; s < doc->styles; s++)
179 {
180 style = (*doc->style)[s];
181
182 if (style->xsize == xsize &&
183 style->ysize == ysize &&
184 style->fcolour == fcolour &&
185 style->bcolour == bcolour &&
186 strcmp(style->font, font) == 0) return s;
187 }
188
189 /* create a new style */
190 style = malloc(gui_SIZEOF_GUI_TA_STYLE(strlen(font) + 1));
191 if (style == NULL) return 0;
192
193 new_style = realloc(doc->style, (doc->styles + 1) * sizeof(struct gui_ta_style *));
194 if (new_style == NULL) return 0;
195
196 style->xsize = xsize;
197 style->ysize = ysize;
198 style->fcolour = fcolour;
199 style->bcolour = bcolour;
200 strcpy(style->font, font);
201 gui_ta_fill_style(style);
202
203 (*new_style)[doc->styles] = style;
204 doc->style = new_style;
205 doc->styles++;
206
207 style->space = gui_ta_text_width(doc, space, doc->styles - 1);
208
209 assert(document_ok(doc));
210
211 return doc->styles - 1;
212 }
213
214
215 /*
216 * gui_ta_render -- render document to the screen
217 */
218
219 void gui_ta_render(struct gui_ta *doc, unsigned long x, unsigned long y,
220 unsigned int invalid[], struct gui_ta_selection *sel)
221 {
222 unsigned int c;
223 unsigned int w;
224 unsigned int base;
225 const signed int x0 = (invalid[0] < x ? 0 : invalid[0] - x);
226 const unsigned int y0 = (invalid[1] < y ? 0 : invalid[1] - y);
227 const signed int x1 = (invalid[2] < x ? 0 : invalid[2] - x);
228 const unsigned int y1 = (invalid[3] < y ? 0 : invalid[3] - y);
229 struct gui_ta_content *con;
230 struct gui_ta_word *word;
231
232 #ifdef DEBUG
233 printf("gui_ta_render: doc = %p\n", doc);
234 fflush(stdout);
235 #endif
236
237 assert(document_ok(doc));
238
239 /* loop through document contents */
240 for (c = 0; c < doc->contents; c++)
241 {
242 con = (*doc->content)[c];
243
244 /* render content if it lies in invalid area */
245 if (!(con->y0 > y1 || con->y1 < y0))
246 {
247 switch (con->type)
248 {
249 case CONTENT_SPACE:
250 break;
251
252 case CONTENT_PARAGRAPH:
253 base = con->base;
254
255 /* loop through paragraph words */
256 for (w = 0; w < con->words; w++)
257 {
258 word = (*con->word)[w];;
259
260 /* continue if word is above or to right of invalid area */
261 if (word->y < y0 || word->box_x0 > x1) continue;
262
263 /* exit if word is below invalid area */
264 if (word->y - con->leading > y1) return;
265
266 assert((w < con->words - 1) || ((w == con->words - 1) && word->end));
267
268 /* render word if it lies in invalid area */
269 if (word->box_x1 >= x0)
270 gui_ta_render_text(doc, word->text, word->style, x + word->x, y + word->y - base,
271 x + word->box_x0, y + word->y - con->leading, x + word->box_x1, y + word->y,
272 sel &&
273 (c > sel->start.content || (c == sel->start.content && w >= sel->start.word)) &&
274 (c < sel->end.content || (c == sel->end.content && w <= sel->end.word)));
275 }
276 break;
277 }
278 }
279 }
280 }
281
282
283 /*
284 * gui_ta_position_xy -- update position from coordinates
285 */
286
287 void gui_ta_position_xy(struct gui_ta *doc, struct gui_ta_position *pos,
288 signed long x, unsigned long y)
289 {
290 unsigned int c = 0; /* content number */
291 unsigned int w = 0; /* word number */
292 unsigned int word_y; /* y position of word */
293 struct gui_ta_content *con; /* current content structure */
294
295 #ifdef DEBUG
296 printf("gui_ta_position_xy: doc = %p\n", doc);
297 fflush(stdout);
298 #endif
299
300 assert(document_ok(doc));
301
302 if (doc->contents == 0) return;
303
304 if (y > doc->height)
305 c = doc->contents - 1;
306 else
307 while (y > (*doc->content)[c]->y1) c++;
308
309 if (x < 0) x = 0;
310
311 pos->content = c;
312 con = (*doc->content)[c];
313
314 switch (con->type)
315 {
316 case CONTENT_SPACE:
317 pos->word = pos->offset = pos->x = pos->y = 0xffffffffu;
318 break;
319
320 case CONTENT_PARAGRAPH:
321 word_y = con->y0 + con->leading;
322 while (y > word_y) word_y += con->leading;
323 if (word_y > con->y1) word_y = con->y1;
324 while ((*con->word)[w]->y != word_y) w++;
325
326 while (x > (signed long) ((*con->word)[w]->x + (*con->word)[w]->width))
327 {
328 if (w == con->words - 1 || (*con->word)[w + 1]->y != word_y)
329 {
330 pos->word = w;
331 pos->offset = wcslen((*con->word)[w]->text);
332 pos->x = (*con->word)[w]->x + (*con->word)[w]->width;
333 pos->y = word_y;
334 return;
335 }
336 w++;
337 }
338
339 pos->word = w;
340 pos->y = word_y;
341 x -= (*con->word)[w]->x;
342 pos->offset = gui_ta_position_x(doc, (*con->word)[w]->text,
343 (*con->word)[w]->style, &x);
344 pos->x = (*con->word)[w]->x + x;
345 break;
346 }
347 }
348
349
350 /*
351 * gui_ta_reformat -- change the width of the document
352 */
353
354 void gui_ta_reformat(struct gui_ta *doc, unsigned long width)
355 {
356 unsigned int c; /* content number */
357 unsigned int y = 0; /* current y coordinate */
358 unsigned int h; /* height of space */
359 struct gui_ta_content *con; /* current content structure */
360
361 #ifdef DEBUG
362 printf("gui_ta_reformat: doc = %p\n", doc);
363 fflush(stdout);
364 #endif
365
366 for (c = 0; c < doc->contents; c++)
367 {
368 con = (*doc->content)[c];
369
370 switch (con->type)
371 {
372 case CONTENT_SPACE:
373 h = con->y1 - con->y0;
374 con->y0 = y;
375 con->y1 = y = y + h;
376 break;
377
378 case CONTENT_PARAGRAPH:
379 y = gui_ta_reformat_paragraph(doc, con, y, width, 0, 0);
380 break;
381 }
382 }
383
384 doc->width = width;
385 doc->height = y;
386
387 assert(document_ok(doc));
388 }
389
390
391 /*
392 * gui_ta_reformat_paragraph
393 */
394
395 unsigned int gui_ta_reformat_paragraph(struct gui_ta *doc,
396 struct gui_ta_content *con, unsigned long y, unsigned long width,
397 unsigned long *y0_ret, unsigned long *y1_ret)
398 {
399 unsigned int x = 0; /* current x coordinate */
400 unsigned int x1 = 0; /* current x coordinate excluding last space */
401 unsigned int w; /* word number */
402 unsigned int w_start = 0; /* word at start of line */
403 unsigned int w_align; /* word when aligning */
404 unsigned int space;
405 unsigned int y0, y1;
406 unsigned int change = 0;
407 struct gui_ta_word *word; /* current word structure */
408 struct gui_ta_word *next_word;
409
410 if (y0_ret) y0 = *y0_ret;
411 if (y1_ret) y1 = *y1_ret;
412
413 con->y0 = y;
414 y += con->leading;
415
416 for (w = 0; w < con->words; w++)
417 {
418 word = (*con->word)[w];
419
420 if ((x + word->width > width) && (x != 0))
421 {
422 space = width - x1;
423 switch (con->align)
424 {
425 case ALIGN_LEFT:
426 for (w_align = w_start; w_align < w; w_align++)
427 (*con->word)[w_align]->x = (*con->word)[w_align]->lx;
428 break;
429
430 case ALIGN_CENTRE:
431 space /= 2;
432 case ALIGN_RIGHT:
433 for (w_align = w_start; w_align < w; w_align++)
434 (*con->word)[w_align]->x = (*con->word)[w_align]->lx + space;
435 break;
436
437 case ALIGN_FULL:
438 (*con->word)[w_start]->x = (*con->word)[w_start]->lx;
439 for (w_align = 1; w_align < w - w_start; w_align++)
440 (*con->word)[w_start + w_align]->x = (*con->word)[w_start + w_align]->lx +
441 w_align * space / (w - w_start - 1);
442 break;
443 }
444 (*con->word)[w_start]->start = 1;
445 (*con->word)[w - 1]->end = 1;
446 x = x1 = 0;
447 y += con->leading;
448 w_start = w;
449 }
450
451 if (change == 0 && (x != word->lx || y != word->y))
452 {
453 if (y < word->y) { y0 = y - con->leading; y1 = word->y; }
454 else { y0 = word->y - con->leading; y1 = y; }
455 change = 1;
456 }
457 else if (change == 1 && (x != word->lx || y != word->y)) y1 = y < word->y ? word->y : y;
458 else if (change == 1 && x == word->lx && y == word->y) change = 2;
459
460 word->lx = x;
461 word->y = y;
462 word->start = word->end = 0;
463 x1 = x + word->width;
464 x = x1 + (*doc->style)[word->style]->space;
465 }
466
467 space = width - x1;
468 switch (con->align)
469 {
470 case ALIGN_LEFT:
471 case ALIGN_FULL:
472 for (w_align = w_start; w_align < con->words; w_align++)
473 (*con->word)[w_align]->x = (*con->word)[w_align]->lx;
474 break;
475
476 case ALIGN_CENTRE:
477 space /= 2;
478 case ALIGN_RIGHT:
479 for (w_align = w_start; w_align < con->words; w_align++)
480 (*con->word)[w_align]->x = (*con->word)[w_align]->lx + space;
481 break;
482 }
483 (*con->word)[w_start]->start = 1;
484 word->end = 1;
485
486 next_word = (*con->word)[0];
487 for (w = 0; w < con->words; w++)
488 {
489 word = next_word;
490 next_word = (*con->word)[w + 1];
491 word->box_x0 = word->start ? 0 : word->x;
492 word->box_x1 = word->end ? width : next_word->x;
493 }
494
495 con->y1 = y;
496
497 if (y0_ret) *y0_ret = y0 < *y0_ret ? y0 : *y0_ret;
498 if (y1_ret) *y1_ret = y1 < *y1_ret ? *y1_ret : y1;
499
500 return y;
501 }
502
503
504
505 /*
506 * gui_ta_insert_char -- insert a character at the specified position
507 */
508
509 void gui_ta_insert_char(struct gui_ta *doc, struct gui_ta_position *pos,
510 wchar_t text, gui_window_id window_id,
511 unsigned long x_offset, unsigned long y_offset)
512 {
513 struct gui_ta_content *con = (*doc->content)[pos->content];
514 struct gui_ta_word *word = (*con->word)[pos->word];
515
516 #ifdef DEBUG
517 printf("gui_ta_insert_char: doc = %p, char = %04x\n", doc, text);
518 fflush(stdout);
519 #endif
520
521 assert(document_ok(doc));
522
523 word = realloc(word, gui_SIZEOF_GUI_TA_WORD(wcslen(word->text) + 2));
524 if (word == NULL) return;
525
526 memmove(word->text + pos->offset + 1, word->text + pos->offset,
527 (wcslen(word->text + pos->offset) + 1) * sizeof(wchar_t));
528 word->text[pos->offset] = text;
529 word->width = gui_ta_text_width(doc, word->text, word->style);
530
531 (*con->word)[pos->word] = word;
532
533 reflow_from(doc, pos->content, pos->word, window_id, x_offset, y_offset, 0);
534 }
535
536
537 /*
538 * gui_ta_insert_split -- split a word into two words at the specified position
539 */
540
541 void gui_ta_insert_split(struct gui_ta *doc, struct gui_ta_position *pos,
542 gui_window_id window_id, unsigned long x_offset, unsigned long y_offset)
543 {
544 struct gui_ta_content *con = (*doc->content)[pos->content];
545 struct gui_ta_word *word = (*con->word)[pos->word];
546 struct gui_ta_word *left = malloc(gui_SIZEOF_GUI_TA_WORD(pos->offset + 1));
547 struct gui_ta_word *right = malloc(gui_SIZEOF_GUI_TA_WORD(wcslen(word->text) - pos->offset + 1));
548 struct gui_ta_word *(*new_word)[] = malloc((con->words + 1) * sizeof(struct gui_ta_word *));
549
550 #ifdef DEBUG
551 printf("gui_ta_insert_split: doc = %p\n", doc);
552 fflush(stdout);
553 #endif
554
555 assert(document_ok(doc));
556
557 if (new_word == NULL || left == NULL || right == NULL) return;
558
559 memcpy(*new_word, *con->word, pos->word * sizeof(struct gui_ta_word *));
560 (*new_word)[pos->word] = left;
561 (*new_word)[pos->word + 1] = right;
562 memcpy(*new_word + pos->word + 2, *con->word + pos->word + 1,
563 (con->words - pos->word - 1) * sizeof(struct gui_ta_word *));
564
565 wcsncpy(left->text, word->text, pos->offset);
566 left->text[pos->offset] = 0;
567 left->style = word->style;
568 left->width = gui_ta_text_width(doc, left->text, left->style);
569 left->x = word->x;
570 left->lx = word->lx;
571 left->y = word->y;
572
573 wcscpy(right->text, word->text + pos->offset);
574 right->style = word->style;
575 right->width = gui_ta_text_width(doc, right->text, right->style);
576 right->x = right->y = 0;
577 left->lx = 0;
578
579 free(word);
580 free(con->word);
581 con->word = new_word;
582 con->words++;
583
584 if (pos->word && (*con->word)[pos->word - 1]->y != left->y)
585 {
586 left->x = left->y = 0;
587 reflow_from(doc, pos->content, pos->word - 1, window_id, x_offset, y_offset, 0);
588 }
589 else
590 reflow_from(doc, pos->content, pos->word, window_id, x_offset, y_offset, 0);
591 }
592
593
594 /*
595 * gui_ta_insert_newline -- split a paragraph into two paragraphs at the specified position
596 */
597
598 void gui_ta_insert_newline(struct gui_ta *doc, struct gui_ta_position *pos,
599 gui_window_id window_id, unsigned long x_offset, unsigned long y_offset)
600 {
601 struct gui_ta_content *con = (*doc->content)[pos->content];
602 struct gui_ta_content *new_con = malloc(sizeof(struct gui_ta_content));
603 struct gui_ta_word *word = (*con->word)[pos->word];
604 struct gui_ta_word *left = malloc(gui_SIZEOF_GUI_TA_WORD(pos->offset + 1));
605 struct gui_ta_word *right = malloc(gui_SIZEOF_GUI_TA_WORD(wcslen(word->text) - pos->offset + 1));
606 struct gui_ta_word *(*new_word)[] = malloc((con->words - pos->word) * sizeof(struct gui_ta_word *));
607 struct gui_ta_content *(*content)[];
608
609 #ifdef DEBUG
610 printf("gui_ta_insert_newline: doc = %p\n", doc);
611 fflush(stdout);
612 #endif
613
614 assert(document_ok(doc));
615
616 content = realloc(doc->content, (doc->contents + 1) * sizeof(struct gui_ta_content *));
617
618 if (new_con == NULL || new_word == NULL || left == NULL || right == NULL || content == NULL) return;
619
620 doc->content = content;
621
622 new_con->type = con->type;
623 new_con->y0 = 0;
624 new_con->y1 = con->y1;
625 new_con->leading = con->leading;
626 new_con->base = con->base;
627 new_con->align = con->align;
628 new_con->words = con->words - pos->word;
629 new_con->word = new_word;
630
631 (*new_word)[0] = right;
632 memcpy(*new_word + 1, *con->word + pos->word + 1,
633 (con->words - pos->word - 1) * sizeof(struct gui_ta_word *));
634
635 wcsncpy(left->text, word->text, pos->offset);
636 left->text[pos->offset] = 0;
637 left->style = word->style;
638 left->width = gui_ta_text_width(doc, left->text, left->style);
639 left->x = word->x;
640 left->y = word->y;
641
642 wcscpy(right->text, word->text + pos->offset);
643 right->style = word->style;
644 right->width = gui_ta_text_width(doc, right->text, right->style);
645 right->x = right->y = 0;
646
647 free(word);
648
649 (*con->word)[pos->word] = left;
650 con->words = pos->word + 1;
651
652 memmove(*doc->content + pos->content + 2, *doc->content + pos->content + 1,
653 (doc->contents - pos->content - 1) * sizeof(struct gui_ta_content *));
654 (*doc->content)[pos->content + 1] = new_con;
655 doc->contents++;
656
657 if (pos->word && (*con->word)[pos->word - 1]->y != left->y)
658 {
659 left->x = left->lx = left->y = 0;
660 reflow_from(doc, pos->content, pos->word - 1, window_id, x_offset, y_offset, 1);
661 }
662 else
663 reflow_from(doc, pos->content, pos->word, window_id, x_offset, y_offset, 1);
664 }
665
666
667 /*
668 * reflow_from -- helper function to reflow document after insertion / deletion
669 */
670
671 void reflow_from(struct gui_ta *doc, unsigned int c0, unsigned int w0,
672 gui_window_id window_id, unsigned int x_offset, unsigned int y_offset, int newline)
673 {
674 unsigned int y;
675 unsigned long y0, y1;
676 unsigned int old_y1;
677 unsigned int c, w;
678 struct gui_ta_content *con = (*doc->content)[c0];
679
680 y0 = (*con->word)[w0]->y - con->leading;
681 y1 = (*con->word)[w0]->y;
682
683 old_y1 = con->y1;
684 y = gui_ta_reformat_paragraph(doc, con, con->y0, doc->width, &y0, &y1);
685 if (y == old_y1 && !newline)
686 {
687 assert(document_ok(doc));
688 gui_refresh_box(window_id, x_offset, y_offset + y0,
689 x_offset + doc->width, y_offset + y1);
690 return;
691 }
692
693 if (c0 + 1 < doc->contents)
694 {
695 con = (*doc->content)[c0 + 1];
696
697 if (newline)
698 {
699 y = gui_ta_reformat_paragraph(doc, con, y, doc->width, 0, &y1);
700
701 if (c0 + 2 == doc->contents)
702 {
703 doc->height = y;
704 assert(document_ok(doc));
705 gui_refresh_box(window_id, x_offset, y_offset + y0,
706 x_offset + doc->width, y_offset + y1);
707
708 #ifdef DEBUG
709 printf("reflow_from: last content\n");
710 fflush(stdout);
711 #endif
712
713 return;
714 }
715
716 con = (*doc->content)[c0 + 2];
717 }
718
719 if (y != con->y0)
720 {
721 signed int move = y - con->y0;
722
723 gui_move_box(window_id, x_offset, y_offset + con->y0, x_offset + doc->width,
724 y_offset + doc->height, x_offset, y_offset + y);
725
726 for (c = c0 + 1 + newline; c < doc->contents; c++)
727 {
728 con = (*doc->content)[c];
729 con->y0 += move;
730 con->y1 += move;
731
732 switch (con->type)
733 {
734 case CONTENT_SPACE:
735 break;
736
737 case CONTENT_PARAGRAPH:
738 for (w = 0; w < con->words; w++) (*con->word)[w]->y += move;
739 break;
740 }
741 }
742 doc->height += move;
743 }
744 }
745 else
746 {
747 doc->height = y;
748 }
749
750 assert(document_ok(doc));
751 gui_refresh_box(window_id, x_offset, y_offset + y0,
752 x_offset + doc->width, y_offset + y1);
753
754 #ifdef DEBUG
755 printf("reflow_from: full\n");
756 fflush(stdout);
757 #endif
758 }
759
760
761 /*
762 * gui_ta_position_cwo -- update position from content, word, offset
763 */
764
765 void gui_ta_position_cwo(struct gui_ta *doc, struct gui_ta_position *pos)
766 {
767 struct gui_ta_word *word = (*(*doc->content)[pos->content]->word)[pos->word];
768
769 #ifdef DEBUG
770 printf("gui_ta_position_cwo: doc = %p\n", doc);
771 fflush(stdout);
772 #endif
773
774 assert(document_ok(doc));
775
776 pos->x = word->x + gui_ta_position_o(doc, word->text, word->style, pos->offset);
777 pos->y = word->y;
778 }
779
780
781 /*
782 * gui_ta_delete -- delete a block of text
783 *
784 * There are two possible cases:
785 *
786 * 1. The block to be deleted lies within one word
787 * => remove those characters
788 * 2. The block is between different words
789 * => remove intervening words, and merge words
790 */
791
792 void gui_ta_delete(struct gui_ta *doc, struct gui_ta_position *start,
793 struct gui_ta_position *end, gui_window_id window_id,
794 unsigned long x_offset, unsigned long y_offset)
795 {
796 unsigned int c = start->content;
797 unsigned int w = start->word;
798 // struct gui_ta_content *con = (*doc->content)[c];
799 struct gui_ta_content *start_con = (*doc->content)[c];
800 struct gui_ta_word *start_word = (*start_con->word)[w];
801 struct gui_ta_content *end_con = (*doc->content)[end->content];
802 struct gui_ta_word *end_word = (*end_con->word)[end->word];
803 void *mem;
804
805 assert(end->content > start->content ||
806 (end->content == start->content &&
807 (end->word > start->word || (end->word == start->word && end->offset > start->offset))));
808
809 /* case 1 */
810 if (start_word == end_word)
811 {
812 wcscpy(start_word->text + start->offset, end_word->text + end->offset);
813 start_word->width = gui_ta_text_width(doc, start_word->text, start_word->style);
814 reflow_from(doc, start->content, start->word, window_id, x_offset, y_offset, 0);
815 return;
816 }
817
818 /* case 2 */
819 mem = realloc(start_word, gui_SIZEOF_GUI_TA_WORD(start->offset + wcslen(end_word->text + end->offset) + 1));
820 if (mem == NULL) return;
821 start_word = (*start_con->word)[start->word] = mem;
822
823 if (start_con != end_con)
824 {
825 mem = realloc(start_con->word, (start->word + end_con->words - end->word) *
826 sizeof(struct gui_ta_word *));
827 if (mem == NULL) return;
828 start_con->word = mem;
829 }
830
831 wcscpy(start_word->text + start->offset, end_word->text + end->offset);
832 start_word->width = gui_ta_text_width(doc, start_word->text, start_word->style);
833
834 memcpy(*start_con->word + start->word + 1, *end_con->word + end->word + 1,
835 (end_con->words - end->word - 1) * sizeof(struct gui_ta_word *));
836 start_con->words = start->word + end_con->words - end->word;
837
838 if (start_con == end_con)
839 {
840 reflow_from(doc, start->content, start->word, window_id, x_offset, y_offset, 0);
841 return;
842 }
843 start_con->y1 = end_con->y1;
844
845 free(end_con->word);
846 free(end_con);
847
848 memcpy(*doc->content + start->content + 1, *doc->content + end->content + 1,
849 (doc->contents - end->content - 1) * sizeof(struct gui_ta_content *));
850 doc->contents = start->content + doc->contents - end->content;
851
852 mem = realloc(doc->content, doc->contents * sizeof(struct gui_ta_content *));
853 if (mem) doc->content = mem;
854
855 reflow_from(doc, start->content, start->word, window_id, x_offset, y_offset, 0);
856 }
857
858 /*
859 while (c < end->content || w < end->word)
860 {
861 w++;
862 if (w == con->words)
863 {
864 if (c > start->content && c < end->content)
865 {
866 free(con->word);
867 free(con);
868 }
869 c++;
870 w = 0;
871 con = (*doc->content)[c];
872 }
873 free((*con->word)[w]);
874 }
875 */
876
877
878 /*
879 * gui_ta_remove -- free up resources associated with a document
880 */
881
882 extern void gui_ta_remove(struct gui_ta *doc)
883 {
884 unsigned int c, w, s;
885 struct gui_ta_content *con;
886
887 for (c = 0; c < doc->contents; c++)
888 {
889 con = (*doc->content)[c];
890
891 switch (con->type)
892 {
893 case CONTENT_PARAGRAPH:
894 {
895 for (w = 0; w < con->words; w++)
896 free((*con->word)[w]);
897
898 break;
899 }
900 case CONTENT_SPACE:
901 ;
902 }
903
904 free(con);
905 }
906
907 for (s = 0; s < doc->styles; s++)
908 {
909 gui_ta_empty_style((*doc->style)[s]);
910 free((*doc->style)[s]);
911 }
912 }
913
914
915 /*
916 * gui_ta_align
917 */
918
919 void gui_ta_align(struct gui_ta *doc, unsigned int content, unsigned int align,
920 gui_window_id window_id, unsigned int x_offset, unsigned int y_offset)
921 {
922 struct gui_ta_content *con = (*doc->content)[content];
923 con->align = align;
924
925 gui_ta_reformat_paragraph(doc, con, con->y0, doc->width, 0, 0);
926 gui_refresh_box(window_id, x_offset, y_offset + con->y0,
927 x_offset + doc->width, y_offset + con->y1);
928 }
929
930
931 /*
932 * gui_ta_export -- export a document
933 */
934
935 void gui_ta_export(struct gui_ta *doc, const char *path)
936 {
937 unsigned int c, w, s;
938 FILE *fp = fopen(path, "w");
939 struct gui_ta_style *style;
940 struct gui_ta_content *con;
941 struct gui_ta_word *word;
942
943 wfputc(0x74785457, fp);
944 wfputc(doc->contents, fp);
945
946 for (c = 0; c < doc->contents; c++)
947 {
948 con = (*doc->content)[c];
949
950 switch (con->type)
951 {
952 case CONTENT_SPACE:
953 wfputc(0x63617053, fp);
954 break;
955
956 case CONTENT_PARAGRAPH:
957 {
958 wfputc(0x61726150, fp);
959 wfputc(con->leading, fp);
960 wfputc(con->base, fp);
961
962 for (w = 0; w < con->words; w++)
963 {
964 word = (*con->word)[w];
965
966 if ((w == 0) || (word->style != s))
967 {
968 /* style = (*doc->style)[s]; */
969 /* fprintf(fp, " <font>%s</font>\n", style->font); */
970 /* fprintf(fp, " <xsize>%d</xsize>\n", style->xsize); */
971 /* fprintf(fp, " <ysize>%d</ysize>\n", style->ysize); */
972 /* fprintf(fp, " <fcolour>%x</fcolour>\n", style->fcolour); */
973 /* fprintf(fp, " <bcolour>%x</bcolour>\n", style->bcolour); */
974 wfputc(word->style, fp);
975 }
976 s = word->style;
977
978 wfputs(word->text, fp);
979 }
980
981 break;
982 }
983 }
984 }
985
986 fclose(fp);
987 }
988
989
990 #ifdef DEBUG
991
992 /*
993 * document_ok -- check document integrity
994 */
995
996 int document_ok(const struct gui_ta *doc)
997 {
998 unsigned int c;
999 unsigned int w;
1000 const struct gui_ta_content *con;
1001 const struct gui_ta_word *word;
1002
1003 /* printf("%p [width %i, height %i, contents %i, styles %i]\n", */
1004 /* doc, doc->width, doc->height, doc->contents, doc->styles); */
1005
1006 for (c = 0; c < doc->contents; c++)
1007 {
1008 con = (*doc->content)[c];
1009
1010 /* printf("%i %p\n", c, con); */
1011
1012 if (c && con->y0 != (*doc->content)[c - 1]->y1)
1013 {
1014 printf("content y coordinates don't match %i %li, %i %li\n", c - 1, (*doc->content)[c - 1]->y1,
1015 c, con->y0);
1016 fflush(stdout);
1017 return 0;
1018 }
1019
1020 if (con->y1 > doc->height)
1021 {
1022 printf("con->y1 %li greater than doc->height %li\n", con->y1, doc->height);
1023 fflush(stdout);
1024 return 0;
1025 }
1026
1027 switch (con->type)
1028 {
1029 case CONTENT_SPACE:
1030 /* printf("<space %i to %i>\n", */
1031 /* con->y0, con->y1); */
1032 break;
1033
1034 case CONTENT_PARAGRAPH:
1035 /* printf("<paragraph %i to %i, leading %i, words %i>\n", */
1036 /* con->y0, con->y1, con->leading, con->words); */
1037 for (w = 0; w < con->words; w++)
1038 {
1039 word = (*con->word)[w];
1040 /* printf(" <word at %i %i, width %i, style %i, box %i %i>\n", */
1041 /* word->x, word->y, word->width, word->style, word->box_x0, word->box_x1); */
1042
1043 if (word->x > doc->width)
1044 {
1045 printf("word->x %li greater than doc->width %li\n", word->x, doc->width);
1046 fflush(stdout);
1047 return 0;
1048 }
1049 if ((word->x != 0) && (word->x + word->width > doc->width))
1050 {
1051 printf("word->x %li + word->width %li greater than doc->width %li\n", word->x,
1052 word->width, doc->width);
1053 fflush(stdout);
1054 return 0;
1055 }
1056 if (word->y < con->y0 || word->y > con->y1)
1057 {
1058 printf("word->y %li not within content y %li %li\n", word->y, con->y0, con->y1);
1059 fflush(stdout);
1060 return 0;
1061 }
1062 if (word->style >= doc->styles)
1063 {
1064 printf("word->style %li greater than doc->styles %li\n", word->style, doc->styles);
1065 fflush(stdout);
1066 return 0;
1067 }
1068 }
1069 break;
1070
1071 default:
1072 printf("unknown document content type %li %li\n", c, con->type);
1073 fflush(stdout);
1074 return 0;
1075 }
1076 }
1077
1078 return 1;
1079 }
1080
1081 #endif

  ViewVC Help
Powered by ViewVC 1.1.26