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

Annotation of /archive/guilib/textarea.c

Parent Directory Parent Directory | Revision Log Revision Log


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

1 james 16 /*
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