1 /*         ______   ___    ___
2  *        /\  _  \ /\_ \  /\_ \
3  *        \ \ \L\ \\//\ \ \//\ \      __     __   _ __   ___
4  *         \ \  __ \ \ \ \  \ \ \   /'__`\ /'_ `\/\`'__\/ __`\
5  *          \ \ \/\ \ \_\ \_ \_\ \_/\  __//\ \L\ \ \ \//\ \L\ \
6  *           \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
7  *            \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
8  *                                           /\____/
9  *                                           \_/__/
10  *
11  *      Grabber plugin for managing font objects.
12  *
13  *      By Shawn Hargreaves.
14  *
15  *      GRX font file reader by Mark Wodrich.
16  *
17  *      See readme.txt for copyright information.
18  */
19 
20 
21 #include <stdio.h>
22 #include <string.h>
23 
24 #include "allegro.h"
25 #include "allegro/internal/aintern.h"
26 #include "../datedit.h"
27 
28 
29 
30 /* creates a new font object */
makenew_font(long * size)31 static void* makenew_font(long* size)
32 {
33     FONT *f;
34     FONT_MONO_DATA* mf = 0, * mfread = font->data;
35 
36     f = _AL_MALLOC(sizeof(FONT));
37 
38     f->height = font->height;
39     f->vtable = font->vtable;
40 
41     while(mfread) {
42         int i;
43 
44         if(mf) {
45             mf->next = _AL_MALLOC(sizeof(FONT_MONO_DATA));
46             mf = mf->next;
47         } else f->data = mf = _AL_MALLOC(sizeof(FONT_MONO_DATA));
48 
49         mf->begin = mfread->begin;
50         mf->end = mfread->end;
51         mf->next = 0;
52         mf->glyphs = _AL_MALLOC(sizeof(FONT_GLYPH*) * (mf->end - mf->begin));
53 
54         for(i = mf->begin; i < mf->end; i++) {
55             FONT_GLYPH *gsrc = mfread->glyphs[i - mf->begin], *gdest;
56             int sz = ((gsrc->w + 7) / 8) * gsrc->h;
57 
58             gdest = _AL_MALLOC(sizeof(FONT_GLYPH) + sz);
59             gdest->w = gsrc->w;
60             gdest->h = gsrc->h;
61             memcpy(gdest->dat, gsrc->dat, sz);
62 
63             mf->glyphs[i - mf->begin] = gdest;
64         }
65 
66         mfread = mfread->next;
67     }
68 
69     return f;
70 }
71 
72 
73 
74 /* displays a font in the grabber object view window */
plot_font(AL_CONST DATAFILE * dat,int x,int y)75 static void plot_font(AL_CONST DATAFILE *dat, int x, int y)
76 {
77     FONT* f = dat->dat;
78     int cx = x, bufpos, ch;
79     char buf[8];
80 
81     y += 32;
82 
83     if(is_mono_font(f)) {
84         FONT_MONO_DATA* mf = f->data;
85 
86         while(mf) {
87             for(ch = mf->begin; ch < mf->end; ch++) {
88                 bufpos = usetc(buf, ch);
89                 usetc(buf + bufpos, 0);
90 
91                 if(text_length(f, buf) + cx + 4 > SCREEN_W) {
92                     cx = x;
93                     y += text_height(f) + 4;
94                 }
95 
96                 if(y > SCREEN_H) break;
97 
98                 textout_ex(screen, f, buf, cx, y, gui_fg_color, -1);
99 
100                 cx += text_length(f, buf) + 4;
101             }
102 
103             mf = mf->next;
104         }
105     } else {
106         FONT_COLOR_DATA* cf = f->data;
107 
108         while(cf) {
109             for(ch = cf->begin; ch < cf->end; ch++) {
110                 bufpos = usetc(buf, ch);
111                 usetc(buf + bufpos, 0);
112 
113                 if(text_length(f, buf) + cx + 4 > SCREEN_W) {
114                     cx = x;
115                     y += text_height(f) + 4;
116                 }
117 
118                 if(y > SCREEN_H) break;
119 
120                 textout_ex(screen, f, buf, cx, y, -1, -1);
121 
122                 cx += text_length(f, buf) + 4;
123             }
124 
125             cf = cf->next;
126         }
127     }
128 }
129 
130 
131 /* returns a description string for a font object */
get_font_desc(AL_CONST DATAFILE * dat,char * s)132 static void get_font_desc(AL_CONST DATAFILE *dat, char *s)
133 {
134    FONT *fnt = (FONT *)dat->dat;
135    char *mono = (is_mono_font(fnt)) ? "mono" : "color";
136    int ranges = 0;
137    int glyphs = 0;
138 
139     if(is_mono_font(fnt)) {
140         FONT_MONO_DATA* mf = fnt->data;
141 
142         while(mf) {
143             ranges++;
144             glyphs += mf->end - mf->begin;
145             mf = mf->next;
146         }
147     } else {
148         FONT_COLOR_DATA* cf = fnt->data;
149 
150         while(cf) {
151             ranges++;
152             glyphs += cf->end - cf->begin;
153             cf = cf->next;
154         }
155     }
156 
157    sprintf(s, "%s font, %d range%s, %d glyphs", mono, ranges, (ranges==1) ? "" : "s", glyphs);
158 }
159 
160 
161 
162 /* exports a font into an external file */
export_font(AL_CONST DATAFILE * dat,AL_CONST char * filename)163 static int export_font(AL_CONST DATAFILE* dat, AL_CONST char* filename)
164 {
165     char buf[1024], tmp[1024];
166     PACKFILE *pack;
167     FONT* f = dat->dat;
168 
169     BITMAP *bmp;
170     PALETTE pal;
171 
172     int w = 0, h = 0, max = 0, i;
173 
174     if(stricmp(get_extension(filename), "txt") == 0) {
175         replace_extension(buf, filename, "pcx", sizeof(buf));
176 
177         if(exists(buf)) {
178             i = datedit_ask("%s already exists, overwrite", buf);
179             if(i == 27 || i == 'n' || i == 'N') return TRUE;
180         }
181 
182         pack = pack_fopen(filename, F_WRITE);
183         if(!pack) return FALSE;
184 
185         if(is_mono_font(f)) {
186             FONT_MONO_DATA* mf = f->data;
187             while(mf) {
188                 sprintf(tmp, "%s 0x%04X 0x%04X\n", (mf == f->data) ? get_filename(buf) : "-", mf->begin, mf->end - 1);
189                 pack_fputs(tmp, pack);
190                 mf = mf->next;
191             }
192         } else {
193             FONT_COLOR_DATA* cf = f->data;
194             while(cf) {
195                 sprintf(tmp, "%s 0x%04X 0x%04X\n", (cf == f->data) ? get_filename(buf) : "-", cf->begin, cf->end - 1);
196                 pack_fputs(tmp, pack);
197                 cf = cf->next;
198             }
199         }
200 
201         pack_fclose(pack);
202 
203         filename = buf;
204     } else {
205         int multi = 0;
206 
207         if(is_mono_font(f)) {
208             if( ((FONT_MONO_DATA*)f->data) ->next) multi = 1;
209         } else {
210             if( ((FONT_COLOR_DATA*)f->data)->next) multi = 1;
211         }
212 
213         if(multi) {
214             i = datedit_ask("Really export multi-range font as bitmap rather than .txt");
215             if(i == 27 || i == 'n' || i == 'N') return TRUE;
216         }
217     }
218 
219     if(is_mono_font(f)) {
220         FONT_MONO_DATA* mf = f->data;
221 
222         while(mf) {
223             for(i = mf->begin; i < mf->end; i++) {
224                 FONT_GLYPH* g = mf->glyphs[i - mf->begin];
225 
226                 max++;
227                 if(g->w > w) w = g->w;
228                 if(g->h > h) h = g->h;
229             }
230 
231             mf = mf->next;
232         }
233     } else {
234         FONT_COLOR_DATA* cf = f->data;
235         int i;
236 
237         while(cf) {
238             for(i = cf->begin; i < cf->end; i++) {
239                 BITMAP* g = cf->bitmaps[i - cf->begin];
240 
241                 max++;
242                 if(g->w > w) w = g->w;
243                 if(g->h > h) h = g->h;
244             }
245 
246             cf = cf->next;
247         }
248     }
249 
250     w = (w + 16) & 0xFFF0;
251     h = (h + 16) & 0xFFF0;
252 
253     bmp = create_bitmap_ex(8, 1 + w * 16, 1 + h * ((max + 15) / 16) );
254     clear_to_color(bmp, 255);
255 
256     max = 0;
257 
258     if(is_mono_font(f)) {
259         FONT_MONO_DATA* mf = f->data;
260 
261         while(mf) {
262             for(i = mf->begin; i < mf->end; i++) {
263                 textprintf_ex(bmp, f, 1 + w * (max & 15), 1 + h * (max / 16), 1, 0, "%c", i);
264                 max++;
265             }
266 
267             mf = mf->next;
268         }
269     } else {
270         FONT_COLOR_DATA* cf = f->data;
271 
272         while(cf) {
273             for(i = cf->begin; i < cf->end; i++) {
274                 textprintf_ex(bmp, f, 1 + w * (max & 15), 1 + h * (max / 16), -1, 0, "%c", i);
275                 max++;
276             }
277 
278             cf = cf->next;
279         }
280     }
281 
282     get_palette(pal);
283 
284     save_bitmap(filename, bmp, pal);
285     destroy_bitmap(bmp);
286 
287     return (errno == 0);
288 }
289 
290 
291 
292 /* magic number for GRX format font files */
293 #define FONTMAGIC    0x19590214L
294 
295 
296 
297 /* import routine for the GRX font copyright message */
import_grx_message(AL_CONST char * filename)298 static void import_grx_message(AL_CONST char* filename)
299 {
300     PACKFILE *pack;
301     int w, h, num, i, end, begin;
302 
303     pack = pack_fopen(filename, F_READ);
304     if(!pack) return;
305 
306     if(pack_igetl(pack) != FONTMAGIC) {
307         pack_fclose(pack);
308         return;
309     }
310     pack_igetl(pack);
311 
312     w = pack_igetw(pack);
313     h = pack_igetw(pack);
314 
315     begin = pack_igetw(pack);
316     end = pack_igetw(pack) + 1;
317     num = end - begin;
318 
319     if(pack_igetw(pack) == 0) {
320         for(i = 0; i < 38; i++) pack_getc(pack);
321         for(i = 0; i < num; i++) pack_igetw(pack);
322     } else {
323         for(i = 0; i < 38; i++) pack_getc(pack);
324     }
325 
326     for(i = 0; i < num; i++) {
327         int sz;
328 
329         sz = ((w + 7) / 8) * h;
330         while(sz) {
331             pack_getc(pack);
332             sz--;
333         }
334     }
335 
336     if(!pack_feof(pack)) {
337         char cw_char[1024];
338 
339         strcpy(cw_char, filename);
340         strcpy(get_extension(cw_char), "txt");
341         i = datedit_ask("Save font copyright message into '%s'", cw_char);
342         if(i != 27 && i != 'n' && i != 'N') {
343             PACKFILE* pout = pack_fopen(cw_char, F_WRITE);
344             if(pout) {
345                 while(!pack_feof(pack)) {
346                     i = pack_fread(cw_char, 1024, pack);
347                     pack_fwrite(cw_char, i, pout);
348                 }
349             }
350             pack_fclose(pout);
351         }
352     }
353 
354     pack_fclose(pack);
355 }
356 
357 
358 
359 /* upgrade_to_color, upgrade_to_color_data:
360  *  Helper functions. Upgrades a monochrome font to a color font.
361  */
upgrade_to_color_data(FONT_MONO_DATA * mf)362 static FONT_COLOR_DATA* upgrade_to_color_data(FONT_MONO_DATA* mf)
363 {
364     FONT_COLOR_DATA* cf = _AL_MALLOC(sizeof(FONT_COLOR_DATA));
365     BITMAP** bits = _AL_MALLOC(sizeof(BITMAP*) * (mf->end - mf->begin));
366     int i;
367 
368     cf->begin = mf->begin;
369     cf->end = mf->end;
370     cf->bitmaps = bits;
371     cf->next = 0;
372 
373     for(i = mf->begin; i < mf->end; i++) {
374         FONT_GLYPH* g = mf->glyphs[i - mf->begin];
375         BITMAP* b = create_bitmap_ex(8, g->w, g->h);
376         clear_to_color(b, 0);
377         b->vtable->draw_glyph(b, g, 0, 0, 1, 0);
378 
379         bits[i - mf->begin] = b;
380         free(g);
381     }
382 
383     free(mf->glyphs);
384     free(mf);
385 
386     return cf;
387 }
388 
389 
390 
upgrade_to_color(FONT * f)391 static void upgrade_to_color(FONT* f)
392 {
393     FONT_MONO_DATA* mf = f->data;
394     FONT_COLOR_DATA * cf, *cf_write = 0;
395 
396     if(is_color_font(f)) return;
397     f->vtable = font_vtable_color;
398 
399     while(mf) {
400         FONT_MONO_DATA* mf_next = mf->next;
401 
402         cf = upgrade_to_color_data(mf);
403         if(!cf_write) f->data = cf;
404         else cf_write->next = cf;
405 
406         cf_write = cf;
407         mf = mf_next;
408     }
409 }
410 
411 
412 
413 static DATAFILE *fonts_datafile;
414 
415 /* Get a list of fonts for a font datafile */
datafile_fontname_getter(int index,int * list_size)416 static AL_CONST char *datafile_fontname_getter(int index, int *list_size)
417 {
418    DATAFILE *datf = fonts_datafile;
419    int n;
420 
421    if (index<0) {
422       *list_size = 0;
423       if (datf) {
424          for(n=0; datf[n].type != DAT_END; n++) {
425             if (datf[n].type == DAT_FONT) (*list_size)++;
426          }
427       }
428 
429       return NULL;
430    }
431 
432    if (datf) {
433       for(n=0; datf[n].type != DAT_END && index>-1; n++)
434          if (datf[n].type == DAT_FONT) index--;
435       return get_datafile_property(&(datf[n-1]), DAT_ID('N','A','M','E'));
436    }
437    else {
438       return NULL;
439    }
440 }
441 
442 
443 
444 /* List the fonts available in a datafile */
grab_datafile_font(AL_CONST char * filename)445 static FONT *grab_datafile_font(AL_CONST char *filename)
446 {
447    const char *names[2] = { NULL, NULL };
448    FONT *f = NULL;
449    int c;
450 
451    fonts_datafile = load_datafile(filename);
452 
453    c = datedit_select(datafile_fontname_getter, "Select font:");
454    if (c>=0) {
455       names[0] = datafile_fontname_getter(c, NULL);
456       f = load_font(filename, NULL, (void*)names);
457    }
458 
459    unload_datafile(fonts_datafile);
460    fonts_datafile = NULL;
461 
462    return f;
463 }
464 
465 /* imports a font from an external file (handles various formats) */
grab_font(int type,AL_CONST char * filename,DATAFILE_PROPERTY ** prop,int depth)466 static DATAFILE *grab_font(int type, AL_CONST char *filename, DATAFILE_PROPERTY **prop, int depth)
467 {
468    PACKFILE *f;
469    FONT *font;
470    int id;
471 
472    if (stricmp(get_extension(filename), "dat") == 0) {
473       font = grab_datafile_font(filename);
474    }
475    else {
476       font = load_font(filename, NULL, NULL);
477    }
478 
479    /* Safe copyright message for GRX fonts */
480    if (stricmp(get_extension(filename), "fnt") == 0) {
481       f = pack_fopen(filename, F_READ);
482       if (!f)
483 	 return NULL;
484 
485       id = pack_igetl(f);
486       pack_fclose(f);
487 
488       if (font && id == FONTMAGIC) {
489 	 /* GRX font; safe copyright message? */
490          import_grx_message(filename);
491       }
492    }
493    return datedit_construct(type, font, 0, prop);
494 }
495 
496 
497 
498 /* helper for save_font, below */
save_mono_font(FONT * f,PACKFILE * pack)499 static int save_mono_font(FONT* f, PACKFILE* pack)
500 {
501     FONT_MONO_DATA* mf = f->data;
502     int i = 0;
503 
504    *allegro_errno = 0;
505 
506     /* count number of ranges */
507     while(mf) {
508         i++;
509         mf = mf->next;
510     }
511     pack_mputw(i, pack);
512 
513     mf = f->data;
514 
515     while(mf) {
516 
517         /* mono, begin, end-1 */
518         pack_putc(1, pack);
519         pack_mputl(mf->begin, pack);
520         pack_mputl(mf->end - 1, pack);
521 
522         for(i = mf->begin; i < mf->end; i++) {
523             FONT_GLYPH* g = mf->glyphs[i - mf->begin];
524 
525             pack_mputw(g->w, pack);
526             pack_mputw(g->h, pack);
527 
528 	    pack_fwrite(g->dat, ((g->w + 7) / 8) * g->h, pack);
529         }
530 
531         mf = mf->next;
532 
533     }
534 
535    if (*allegro_errno)
536       return FALSE;
537    else
538       return TRUE;
539 }
540 
541 
542 
543 /* helper for save_font, below */
save_color_font(FONT * f,PACKFILE * pack)544 static int save_color_font(FONT* f, PACKFILE* pack)
545 {
546     FONT_COLOR_DATA* cf = f->data;
547     int i = 0;
548     int depth;
549 
550    *allegro_errno = 0;
551 
552     /* count number of ranges */
553     while(cf) {
554         i++;
555         cf = cf->next;
556     }
557     pack_mputw(i, pack);
558 
559     cf = f->data;
560 
561     while(cf) {
562 
563         /* Get font color depth */
564         depth = bitmap_color_depth(cf->bitmaps[0]);
565 
566         /* Compatibility with older versions: depth=0 means 8 bit */
567         if (depth == 8)
568             depth = 0;
569 
570         /* color, begin, end-1 */
571         pack_putc(depth, pack);
572         pack_mputl(cf->begin, pack);
573         pack_mputl(cf->end - 1, pack);
574 
575         /* Save pixmap data */
576         for(i = cf->begin; i < cf->end; i++) {
577             BITMAP* glyph = cf->bitmaps[i - cf->begin];
578             int x, y, c, r, g, b, a;
579             uint16_t *p16;
580             uint8_t *p24;
581             uint32_t *p32;
582 
583             pack_mputw(glyph->w, pack);
584             pack_mputw(glyph->h, pack);
585 
586             switch (depth) {
587 
588                case 0:
589 	          /* 256 colors */
590 	          for (y=0; y<glyph->h; y++)
591 	             for (x=0; x<glyph->w; x++)
592 	                pack_putc(glyph->line[y][x], pack);
593 	          break;
594 
595                case 15:
596                case 16:
597 	          /* hicolor */
598 	          for (y=0; y<glyph->h; y++) {
599 	             p16 = (uint16_t *)glyph->line[y];
600 
601 	             for (x=0; x<glyph->w; x++) {
602 	                c = p16[x];
603 	                r = getr_depth(depth, c);
604 	                g = getg_depth(depth, c);
605 	                b = getb_depth(depth, c);
606 	                c = ((r<<8)&0xF800) | ((g<<3)&0x7E0) | ((b>>3)&0x1F);
607 	                pack_iputw(c, pack);
608 	             }
609 	          }
610 	          break;
611 
612                case 24:
613 	          /* 24 bit truecolor */
614 	          for (y=0; y<glyph->h; y++) {
615 	             p24 = (unsigned char *)glyph->line[y];
616 
617 	             for (x=0; x<glyph->w; x++) {
618 	                c = READ3BYTES(p24);
619 	                r = getr24(c);
620 	                g = getg24(c);
621 	                b = getb24(c);
622 	                pack_putc(r, pack);
623 	                pack_putc(g, pack);
624 	                pack_putc(b, pack);
625 	                p24 += 3;
626 	             }
627 	          }
628 	          break;
629 
630                case 32:
631 	          /* 32 bit truecolor */
632 	          for (y=0; y<glyph->h; y++) {
633 	             p32 = (uint32_t *)glyph->line[y];
634 
635 	             for (x=0; x<glyph->w; x++) {
636 	                c = p32[x];
637 	                r = getr32(c);
638 	                g = getg32(c);
639 	                b = getb32(c);
640 	                pack_putc(r, pack);
641 	                pack_putc(g, pack);
642 	                pack_putc(b, pack);
643 	             }
644 	          }
645 	          break;
646 
647                case -32:
648 	          /* 32 bit truecolor with alpha channel */
649 	          for (y=0; y<glyph->h; y++) {
650 	             p32 = (uint32_t *)glyph->line[y];
651 
652 	             for (x=0; x<glyph->w; x++) {
653 	                c = p32[x];
654 	                r = getr32(c);
655 	                g = getg32(c);
656 	                b = getb32(c);
657 	                a = geta32(c);
658 	                pack_putc(r, pack);
659 	                pack_putc(g, pack);
660 	                pack_putc(b, pack);
661 	                pack_putc(a, pack);
662 	             }
663 	          }
664 	          break;
665             }
666 
667         }
668 
669         cf = cf->next;
670 
671     }
672 
673    if (*allegro_errno)
674       return FALSE;
675    else
676       return TRUE;
677 }
678 
679 
680 
681 /* saves a font into a datafile */
save_font(DATAFILE * dat,AL_CONST int * fixed_prop,int pack,int pack_kids,int strip,int sort,int verbose,int extra,PACKFILE * f)682 static int save_font(DATAFILE *dat, AL_CONST int *fixed_prop, int pack, int pack_kids, int strip, int sort, int verbose, int extra, PACKFILE *f)
683 {
684     FONT* font = dat->dat;
685 
686     pack_mputw(0, f);
687 
688     if (is_mono_font(font))
689        return save_mono_font(font, f);
690     else
691        return save_color_font(font, f);
692 }
693 
694 
695 
696 /* for the font viewer/editor */
697 static FONT *the_font;
698 
699 static char char_string[8] = "0x0020";
700 
701 static char *range_getter(int index, int *list_size);
702 static int import_proc(int msg, DIALOG *d, int c);
703 static int delete_proc(int msg, DIALOG *d, int c);
704 static int font_view_proc(int msg, DIALOG *d, int c);
705 
706 
707 
708 static DIALOG char_dlg[] =
709 {
710    /* (dialog proc)     (x)   (y)   (w)   (h)   (fg)  (bg)  (key)    (flags)     (d1)           (d2)     (dp)                 (dp2) (dp3) */
711    { d_shadow_box_proc, 0,    0,    225,  73,   0,    0,    0,       0,          0,             0,       NULL,                NULL, NULL  },
712    { d_text_proc,       16,   16,   0,    0,    0,    0,    0,       0,          0,             0,       "Base character:",   NULL, NULL  },
713    { d_edit_proc,       144,  16,   56,   8,    0,    0,    0,       0,          6,             0,       char_string,         NULL, NULL  },
714    { d_button_proc,     72,   44,   81,   17,   0,    0,    13,      D_EXIT,     0,             0,       "OK",                NULL, NULL  },
715    { NULL,              0,    0,    0,    0,    0,    0,    0,       0,          0,             0,       NULL,                NULL, NULL  }
716 };
717 
718 
719 
720 static DIALOG view_font_dlg[] =
721 {
722    /* (dialog proc)     (x)   (y)   (w)   (h)   (fg)  (bg)  (key)    (flags)     (d1)           (d2)     (dp)              (dp2) (dp3) */
723    { d_clear_proc,      0,    0,    0,    0,    0,    0,    0,       0,          0,             0,       NULL,             NULL, NULL  },
724    { font_view_proc,    0,    100,  0,    0,    0,    0,    0,       D_EXIT,     0,             0,       NULL,             NULL, NULL  },
725    { d_list_proc,       0,    0,    161,  100,  0,    0,    0,       D_EXIT,     0,             0,       range_getter,     NULL, NULL  },
726    { import_proc,       180,  8,    113,  17,   0,    0,    'i',     D_EXIT,     0,             0,       "&Import Range",  NULL, NULL  },
727    { delete_proc,       180,  40,   113,  17,   0,    0,    'd',     D_EXIT,     0,             0,       "&Delete Range",  NULL, NULL  },
728    { d_button_proc,     180,  72,   113,  17,   0,    0,    27,      D_EXIT,     0,             0,       "Exit",           NULL, NULL  },
729    { NULL,              0,    0,    0,    0,    0,    0,    0,       0,          0,             0,       NULL,             NULL, NULL  }
730 };
731 
732 
733 #define VIEWER          1
734 #define RANGE_LIST      2
735 
736 
737 
738 /* dialog callback for retrieving information about the font range list */
range_getter(int index,int * list_size)739 static char *range_getter(int index, int *list_size)
740 {
741     static char buf[64];
742     FONT* f = the_font;
743 
744     if(index < 0) {
745         if(!list_size) return 0;
746 
747         *list_size = get_font_ranges(f);
748         if (*list_size < 0)
749            *list_size = 0;
750 
751         return 0;
752     }
753 
754     sprintf(buf, "%04X-%04X, color", get_font_range_begin(f, index), get_font_range_end(f, index));
755 
756     return buf;
757 }
758 
759 
760 
761 /* imports a new font range */
import_proc(int msg,DIALOG * d,int c)762 static int import_proc(int msg, DIALOG *d, int c)
763 {
764    char name[80*6]; /* 80 chars * max UTF8 char width */
765    int ret = d_button_proc(msg, d, c);
766    DATAFILE *dat;
767    FONT *fnt, *f;
768    int base;
769    int i;
770 
771    if (ret & D_CLOSE) {
772       #define EXT_LIST  "bmp;fnt;lbm;pcx;tga"
773 
774       strcpy(name, grabber_import_file);
775       *get_filename(name) = 0;
776 
777       if (file_select_ex("Import range (" EXT_LIST ")", name, EXT_LIST, sizeof(name), 0, 0)) {
778 	 fix_filename_case(name);
779 	 strcpy(grabber_import_file, name);
780 
781 	 grabber_busy_mouse(TRUE);
782 	 dat = grab_font(DAT_FONT, name, NULL, -1);
783 	 grabber_busy_mouse(FALSE);
784 
785 	 if (!dat) {
786 	    datedit_error("Error importing %s", name);
787 	 }
788 	 else {
789 	    int import_begin, import_end;
790 
791 	    fnt = dat->dat;
792 
793 	    centre_dialog(char_dlg);
794 	    set_dialog_color(char_dlg, gui_fg_color, gui_bg_color);
795 	    do_dialog(char_dlg, 2);
796 
797 	    base = strtol(char_string, NULL, 0);
798 
799         if(is_mono_font(fnt)) {
800             FONT_MONO_DATA* mf = fnt->data;
801             import_end = (mf->end += (base - mf->begin));
802             import_begin = mf->begin = base;
803         } else {
804             FONT_COLOR_DATA* cf = fnt->data;
805             import_end = (cf->end += (base - cf->begin));
806             import_begin = cf->begin = base;
807         }
808 
809 	    f = the_font;
810 
811 	    if(is_mono_font(fnt)) {
812 	        FONT_MONO_DATA* mf = f->data;
813 	        while(mf) {
814 	            if(mf->end > import_begin && mf->begin < import_end) {
815                     alert("Warning, data overlaps with an", "existing range. This almost", "certainly isn't what you want", "Silly me", NULL, 13, 0);
816                     break;
817 	            }
818 
819 	            mf = mf->next;
820 	        }
821 	    }
822 
823 	    if(!is_compatible_font(f, fnt)) {
824 	        upgrade_to_color(f);
825 	        upgrade_to_color(fnt);
826 	    }
827 
828 	    f = the_font;
829 	    i = 0;
830 
831         if(is_mono_font(f)) {
832             FONT_MONO_DATA* mf = f->data, * mf2 = fnt->data;
833 
834             if(mf->begin > import_begin) {
835                 mf2->next = mf;
836                 f->data = mf2;
837             } else {
838                 i++;
839                 while(mf->next && mf->next->begin < import_begin) {
840                     mf = mf->next;
841                     i++;
842                 }
843                 mf2->next = mf->next;
844                 mf->next = mf2;
845             }
846         } else {
847             FONT_COLOR_DATA* cf = f->data, * cf2 = fnt->data;
848 
849             if(cf->begin > import_begin) {
850                 cf2->next = cf;
851                 f->data = cf2;
852             } else {
853                 i++;
854                 while(cf->next && cf->next->begin < import_begin) {
855                     cf = cf->next;
856                     i++;
857                 }
858                 cf2->next = cf->next;
859                 cf->next = cf2;
860             }
861         }
862 
863 	    view_font_dlg[RANGE_LIST].d1 = i;
864 
865 	    object_message(view_font_dlg+VIEWER, MSG_START, 0);
866 	    object_message(view_font_dlg+RANGE_LIST, MSG_START, 0);
867 
868 	    grabber_modified(TRUE);
869 	 }
870       }
871 
872       return D_REDRAW;
873    }
874 
875    return ret;
876 }
877 
878 
879 
880 /* deletes a font range */
delete_proc(int msg,DIALOG * d,int c)881 static int delete_proc(int msg, DIALOG *d, int c)
882 {
883    int ret = d_button_proc(msg, d, c);
884    FONT *fnt;
885    int i;
886 
887    if (ret & D_CLOSE) {
888       fnt = the_font;
889 
890         if(is_mono_font(fnt)) {
891 
892             FONT_MONO_DATA* mf = fnt->data, * mf_prev = 0;
893 
894             if(!mf->next) {
895                 alert("Deletion not possible:", "fonts must always have at", "least one character range", "Sorry", NULL, 13, 0);
896                 return D_O_K;
897             }
898 
899             i = view_font_dlg[RANGE_LIST].d1;
900             while(i--) {
901                 mf_prev = mf;
902                 mf = mf->next;
903             }
904 
905             if(mf_prev) mf_prev->next = mf->next;
906             else fnt->data = mf->next;
907 
908             for(i = mf->begin; i < mf->end; i++) free(mf->glyphs[i - mf->begin]);
909             free(mf->glyphs);
910             free(mf);
911 
912         } else {
913 
914             FONT_COLOR_DATA* cf = fnt->data, * cf_prev = 0;
915 
916             if(!cf->next) {
917                 alert("Deletion not possible:", "fonts must always have at", "least one character range", "Sorry", NULL, 13, 0);
918                 return D_O_K;
919             }
920 
921             i = view_font_dlg[RANGE_LIST].d1;
922             while(i--) {
923                 cf_prev = cf;
924                 cf = cf->next;
925             }
926 
927             if(cf_prev) cf_prev->next = cf->next;
928             else fnt->data = cf->next;
929 
930             for(i = cf->begin; i < cf->end; i++) destroy_bitmap(cf->bitmaps[i - cf->begin]);
931             free(cf->bitmaps);
932             free(cf);
933 
934         }
935 
936       object_message(view_font_dlg+VIEWER, MSG_START, 0);
937       object_message(view_font_dlg+RANGE_LIST, MSG_START, 0);
938 
939       grabber_modified(TRUE);
940 
941       return D_REDRAW;
942    }
943 
944    return ret;
945 }
946 
947 
948 
949 /* displays the font contents */
font_view_proc(int msg,DIALOG * d,int c)950 static int font_view_proc(int msg, DIALOG *d, int c)
951 {
952    BITMAP** bits = 0;
953    FONT_GLYPH** gl = 0;
954    FONT *fnt;
955    int x, y, w, h, i;
956    int font_h;
957    int begin, end;
958 
959    switch (msg) {
960 
961       case MSG_START:
962 	 if (!d->dp)
963 	    d->dp = create_bitmap(d->w, d->h);
964 	 d->dp2 = NULL;
965 	 d->d1 = 0;
966 	 d->d2 = 0;
967 	 break;
968 
969       case MSG_END:
970 	 destroy_bitmap(d->dp);
971 	 d->dp = NULL;
972 	 break;
973 
974       case MSG_DRAW:
975 	 clear_to_color(d->dp, gui_mg_color);
976 
977 	 fnt = the_font;
978 	 i = view_font_dlg[RANGE_LIST].d1;
979 
980      if(is_mono_font(fnt)) {
981 
982         FONT_MONO_DATA* mf = fnt->data;
983         while(i--) mf = mf->next;
984 
985         gl = mf->glyphs;
986         begin = mf->begin;
987         end = mf->end;
988 
989      } else {
990 
991         FONT_COLOR_DATA* cf = fnt->data;
992         while(i--) cf = cf->next;
993 
994         bits = cf->bitmaps;
995         begin = cf->begin;
996         end = cf->end;
997 
998      }
999 
1000 	 font_h = text_height(fnt);
1001 	 y = d->d1 + 8;
1002 
1003 	 for (i = begin; i < end; i++) {
1004 	    if (gl) {
1005 	       w = gl[i - begin]->w;
1006 	       h = gl[i - begin]->h;
1007 	    }
1008 	    else {
1009 	        w = bits[i - begin]->w;
1010 	        h = bits[i - begin]->h;
1011 	    }
1012 
1013 	    textprintf_ex(d->dp, font, 32, y+font_h/2-4, gui_fg_color, gui_mg_color, "U+%04X %3dx%-3d %c", i, w, h, i);
1014 	    textprintf_ex(d->dp, fnt, 200, y, (gl ? gui_fg_color : -1), makecol(0xC0, 0xC0, 0xC0), "%c", i);
1015 
1016 	    y += font_h * 3/2;
1017 	 }
1018 
1019 	 if (d->flags & D_GOTFOCUS) {
1020 	    for (i=0; i<d->w; i+=2) {
1021 	       putpixel(d->dp, i,   0,      gui_fg_color);
1022 	       putpixel(d->dp, i+1, 0,      gui_bg_color);
1023 	       putpixel(d->dp, i,   d->h-1, gui_bg_color);
1024 	       putpixel(d->dp, i+1, d->h-1, gui_fg_color);
1025 	    }
1026 	    for (i=1; i<d->h-1; i+=2) {
1027 	       putpixel(d->dp, 0,      i,   gui_bg_color);
1028 	       putpixel(d->dp, 0,      i+1, gui_fg_color);
1029 	       putpixel(d->dp, d->w-1, i,   gui_fg_color);
1030 	       putpixel(d->dp, d->w-1, i+1, gui_bg_color);
1031 	    }
1032 	 }
1033 
1034 	 blit(d->dp, screen, 0, 0, d->x, d->y, d->w, d->h);
1035 
1036 	 d->d2 = y - d->d1;
1037 	 d->dp2 = fnt;
1038 	 break;
1039 
1040       case MSG_WANTFOCUS:
1041 	 return D_WANTFOCUS;
1042 
1043       case MSG_CHAR:
1044 	 switch (c >> 8) {
1045 
1046 	    case KEY_UP:
1047 	       d->d1 += 8;
1048 	       break;
1049 
1050 	    case KEY_DOWN:
1051 	       d->d1 -= 8;
1052 	       break;
1053 
1054 	    case KEY_PGUP:
1055 	       d->d1 += d->h*2/3;
1056 	       break;
1057 
1058 	    case KEY_PGDN:
1059 	       d->d1 -= d->h*2/3;
1060 	       break;
1061 
1062 	    case KEY_HOME:
1063 	       d->d1 = 0;
1064 	       break;
1065 
1066 	    case KEY_END:
1067 	       d->d1 = -d->d2 + d->h;
1068 	       break;
1069 
1070 	    default:
1071 	       return D_O_K;
1072 	 }
1073 
1074 	 if (d->d1 < -d->d2 + d->h)
1075 	    d->d1 = -d->d2 + d->h;
1076 
1077 	 if (d->d1 > 0)
1078 	    d->d1 = 0;
1079 
1080 	 d->flags |= D_DIRTY;
1081 	 return D_USED_CHAR;
1082 
1083       case MSG_CLICK:
1084 	 if (mouse_b & 2)
1085 	    return D_CLOSE;
1086 
1087 	 x = mouse_x;
1088 	 y = mouse_y;
1089 
1090 	 show_mouse(NULL);
1091 
1092 	 while (mouse_b) {
1093 	    poll_mouse();
1094 
1095 	    if (mouse_y != y) {
1096 	       d->d1 += (y - mouse_y);
1097 	       position_mouse(x, y);
1098 
1099 	       if (d->d1 < -d->d2 + d->h)
1100 		  d->d1 = -d->d2 + d->h;
1101 
1102 	       if (d->d1 > 0)
1103 		  d->d1 = 0;
1104 
1105 	       object_message(d, MSG_DRAW, 0);
1106 	    }
1107 	 }
1108 
1109 	 show_mouse(screen);
1110 	 return D_O_K;
1111 
1112       case MSG_KEY:
1113 	 return D_CLOSE;
1114 
1115 	  case MSG_IDLE:
1116 	 if(d->fg != view_font_dlg[RANGE_LIST].d1) {
1117 	    d->fg = view_font_dlg[RANGE_LIST].d1;
1118 	    d->d1 = 0;
1119 	    object_message(d, MSG_DRAW, 0);
1120 	 }
1121    }
1122 
1123    return D_O_K;
1124 }
1125 
1126 
1127 
1128 /* handles double-clicking on a font in the grabber */
view_font(DATAFILE * dat)1129 static int view_font(DATAFILE *dat)
1130 {
1131    show_mouse(NULL);
1132    clear_to_color(screen, gui_mg_color);
1133 
1134    the_font = dat->dat;
1135 
1136    view_font_dlg[RANGE_LIST].d1 = 0;
1137    view_font_dlg[RANGE_LIST].d2 = 0;
1138 
1139    view_font_dlg[VIEWER].w = SCREEN_W;
1140    view_font_dlg[VIEWER].h = SCREEN_H - view_font_dlg[VIEWER].y;
1141 
1142    set_dialog_color(view_font_dlg, gui_fg_color, gui_bg_color);
1143 
1144    view_font_dlg[0].bg = gui_mg_color;
1145 
1146    do_dialog(view_font_dlg, VIEWER);
1147 
1148    dat->dat = the_font;
1149 
1150    show_mouse(screen);
1151    return D_REDRAW;
1152 }
1153 
1154 
1155 
1156 /* plugin interface header */
1157 DATEDIT_OBJECT_INFO datfont_info =
1158 {
1159    DAT_FONT,
1160    "Font",
1161    get_font_desc,
1162    makenew_font,
1163    save_font,
1164    plot_font,
1165    view_font,
1166    NULL
1167 };
1168 
1169 
1170 
1171 DATEDIT_GRABBER_INFO datfont_grabber =
1172 {
1173    DAT_FONT,
1174    "txt;fnt;bmp;lbm;pcx;tga;dat",
1175    "txt;bmp;pcx;tga",
1176    grab_font,
1177    export_font,
1178    NULL
1179 };
1180 
1181