1 /* -*- coding: utf-8 -*- */
2 /* Copyright (C) 2000-2012 by George Williams */
3 /*
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6 
7  * Redistributions of source code must retain the above copyright notice, this
8  * list of conditions and the following disclaimer.
9 
10  * Redistributions in binary form must reproduce the above copyright notice,
11  * this list of conditions and the following disclaimer in the documentation
12  * and/or other materials provided with the distribution.
13 
14  * The name of the author may not be used to endorse or promote products
15  * derived from this software without specific prior written permission.
16 
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
18  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
20  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
23  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
25  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
26  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include <fontforge-config.h>
30 
31 #include "fontforgeui.h"
32 #include "namelist.h"
33 #include "scripting.h"
34 
35 #include "gdraw.h"
36 #include "ggadget.h"
37 #include "gwidget.h"
38 #include "ustring.h"
39 
40 #include <stdlib.h>
41 #include <string.h>
42 
43 extern NameList *force_names_when_opening;
44 int default_font_filter_index=0;
45 struct openfilefilters *user_font_filters = NULL;
46 
47 #ifdef FONTFORGE_CAN_USE_WOFF2
48 /* GGadgetWildMatch is buggy... it must be woff2 then woff */
49 #  define WOFF_EXT ",woff2,woff"
50 #else
51 #  define WOFF_EXT ",woff"
52 #endif
53 
54 struct openfilefilters def_font_filters[] = {
55     {
56         N_("All Fonts"),
57         /* any these files... */
58         "*.{"
59 	   "pfa,"
60 	   "pfb,"
61 	   "pt3,"
62 	   "t42,"
63 	   "sfd,"
64 	   "ufo,"
65 	   "ttf,"
66 	   "bdf,"
67 	   "otf,"
68 	   "otb,"
69 	   "cff,"
70 	   "cef,"
71 	   "gai,"
72 	   "svg,"
73 	   "ufo,"
74 	   "pf3,"
75 	   "ttc,"
76 	   "gsf,"
77 	   "cid,"
78 	   "bin,"
79 	   "hqx,"
80 	   "dfont,"
81 	   "mf,"
82 	   "ik,"
83 	   "fon,"
84 	   "fnt,"
85 	   "pcf,"
86 	   "pmf,"
87 	   "[0-9]*pk,"
88 /* I used to say "*gf" but that also matched xgf (xgridfit) files -- which ff can't open */
89 	   "[0-9]*gf,"
90 	   "pdb"
91 	   WOFF_EXT
92         "}"
93         /* With any of these methods of compression */
94 	"{.gz,.Z,.bz2,.lzma,}"
95     },
96     {
97 	N_("Outline Fonts"),
98 	"*.{"
99 	   "pfa,"
100 	   "pfb,"
101 	   "pt3,"
102 	   "t42,"
103 	   "sfd,"
104 	   "ufo,"
105 	   "ttf,"
106 	   "otf,"
107 	   "cff,"
108 	   "cef,"
109 	   "gai,"
110 	   "svg,"
111 	   "ufo,"
112 	   "pf3,"
113 	   "ttc,"
114 	   "gsf,"
115 	   "cid,"
116 	   "bin,"
117 	   "hqx,"
118 	   "dfont,"
119 	   "mf,"
120 	   "ik"
121 	   WOFF_EXT
122 	"}"
123 	"{.gz,.Z,.bz2,.lzma,}"
124     },
125     {
126 	N_("Bitmap Fonts"),
127 	"*.{"
128 	   "bdf,"
129 	   "otb,"
130 	   "bin,"
131 	   "hqx,"
132 	   "fon,"
133 	   "fnt,"
134 	   "pcf,"
135 	   "pmf,"
136 	   "*pk,"
137 	   "*gf,"
138 	   "pdb"
139 	"}"
140 	"{.gz,.Z,.bz2,.lzma,}"
141     },
142     { NU_("ΤεΧ Bitmap Fonts"), "*{pk,gf}" },
143     { N_("PostScript"), "*.{pfa,pfb,t42,otf,cef,cff,gai,pf3,pt3,gsf,cid}{.gz,.Z,.bz,.bz2,.lzma,}" },
144     { N_("TrueType"), "*.{ttf,t42,ttc}{.gz,.Z,.bz,.bz2,.lzma,}" },
145     { N_("OpenType"), "*.{ttf,otf" WOFF_EXT "}{.gz,.Z,.bz,.bz2,.lzma,}" },
146     { N_("Type1"), "*.{pfa,pfb,gsf,cid}{.gz,.Z,.bz2,.lzma,}" },
147     { N_("Type2"), "*.{otf,cef,cff,gai}{.gz,.Z,.bz2,.lzma,}" },
148     { N_("Type3"), "*.{pf3,pt3}{.gz,.Z,.bz2,.lzma,}" },
149     { N_("SVG"), "*.svg{.gz,.Z,.bz2,.lzma,}" },
150     { N_("Unified Font Object"), "*.ufo" },
151     { N_("FontForge's SFD"), "*.sfd{.gz,.Z,.bz2,.lzma,}" },
152     { N_("Backup SFD"), "*.sfd~" },
153     { N_("Extract from PDF"), "*.pdf{.gz,.Z,.bz2,.lzma,}" },
154     { "-", NULL },
155     { N_("Archives"), "*.{zip,tgz,tbz,tbz2,tar.gz,tar.bz,tar.bz2,tar}" },
156     { N_("All Files"), "*" },
157     { NULL, NULL }
158 };
159 
StandardFilters(void)160 static GTextInfo **StandardFilters(void) {
161     int k, cnt, i;
162     GTextInfo **ti;
163 
164     /* Make two passes thru outer loop. The first pass determines the
165      * interim count of how many entries will be generated and then
166      * allocates an array with 3 entries more than that. The second
167      * pass ( if(k) ) accumulates the data values, then adds a trailer,
168      * to return in the GTextInfo** structure 'ti'.
169      */
170     for ( k=0; k<2; ++k ) {
171 	cnt = 0;
172 	for ( i=0; def_font_filters[i].name!=NULL; ++i ) {
173 	    if ( k ) {
174 		ti[cnt] = calloc(1,sizeof(GTextInfo));
175 		ti[cnt]->userdata = def_font_filters[i].filter;
176 		ti[cnt]->fg = ti[cnt]->bg = COLOR_DEFAULT;
177 		if ( *(char *) def_font_filters[i].name == '-' )
178 		    ti[cnt]->line = true;
179 		else
180 		    ti[cnt]->text = utf82u_copy(_(def_font_filters[i].name));
181 	    }
182 	    ++cnt;
183 	}
184 	if ( user_font_filters!=NULL ) {
185 	    if ( k ) {
186 		ti[cnt] = calloc(1,sizeof(GTextInfo));
187 		ti[cnt]->fg = ti[cnt]->bg = COLOR_DEFAULT;
188 		/* Don't translate this name */
189 		ti[cnt]->line = true;
190 	    }
191 	    ++cnt;
192 	    for ( i=0; user_font_filters[i].name!=NULL; ++i ) {
193 		if ( k ) {
194 		    ti[cnt] = calloc(1,sizeof(GTextInfo));
195 		    ti[cnt]->userdata = user_font_filters[i].filter;
196 		    ti[cnt]->fg = ti[cnt]->bg = COLOR_DEFAULT;
197 		    /* Don't translate this name */
198 		    if ( *(char *) user_font_filters[i].name == '-' )
199 			ti[cnt]->line = true;
200 		    else
201 			ti[cnt]->text = utf82u_copy(user_font_filters[i].name);
202 		}
203 		++cnt;
204 	    }
205 	}
206 	if ( k ) {
207 	    ti[cnt] = calloc(1,sizeof(GTextInfo));
208 	    ti[cnt]->fg = ti[cnt]->bg = COLOR_DEFAULT;
209 	    ti[cnt++]->line = true;
210 	    ti[cnt] = calloc(1,sizeof(GTextInfo));
211 	    ti[cnt]->userdata = (void *) -1;
212 	    ti[cnt]->fg = ti[cnt]->bg = COLOR_DEFAULT;
213 	    ti[cnt++]->text = utf82u_copy(_("Edit Filter List"));
214 	    ti[cnt] = calloc(1,sizeof(GTextInfo));
215 	} else
216 	    ti = malloc((cnt+3)*sizeof(GTextInfo *));
217     }
218     ti[default_font_filter_index]->selected = true;
219 return( ti );
220 }
221 
222 struct filter_d {
223     int done;
224     GGadget *gme;
225 };
226 
Filter_Cancel(GGadget * g,GEvent * e)227 static int Filter_Cancel(GGadget *g, GEvent *e) {
228     GWindow gw;
229     struct filter_d *d;
230 
231     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
232 	gw = GGadgetGetWindow(g);
233 	d = GDrawGetUserData(gw);
234 	d->done = true;
235     }
236 return( true );
237 }
238 
Filter_OK(GGadget * g,GEvent * e)239 static int Filter_OK(GGadget *g, GEvent *e) {
240     struct filter_d *d;
241     struct matrix_data *md;
242     int rows,i,cnt;
243 
244     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
245 	if ( user_font_filters!=NULL ) {
246 	    for ( i=0; user_font_filters[i].name!=NULL; ++i ) {
247 		free(user_font_filters[i].name);
248 		free(user_font_filters[i].filter);
249 	    }
250 	    free(user_font_filters);
251 	    user_font_filters = NULL;
252 	}
253 	d = GDrawGetUserData(GGadgetGetWindow(g));
254 	md = GMatrixEditGet(d->gme,&rows);
255 	for ( i=cnt=0; i<rows; ++i )
256 	    if ( !md[2*i].frozen )
257 		++cnt;
258 	if ( cnt!=0 ) {
259 	    user_font_filters = malloc((cnt+1)*sizeof(struct openfilefilters));
260 	    for ( i=cnt=0; i<rows; ++i ) if ( !md[2*i].frozen ) {
261 		user_font_filters[cnt].name = copy(md[2*i].u.md_str);
262 		user_font_filters[cnt].filter = copy(md[2*i+1].u.md_str);
263 		++cnt;
264 	    }
265 	    user_font_filters[cnt].name = user_font_filters[cnt].filter = NULL;
266 	}
267 	SavePrefs(true);
268 	d->done = true;
269     }
270 return( true );
271 }
272 
filter_e_h(GWindow gw,GEvent * event)273 static int filter_e_h(GWindow gw, GEvent *event) {
274     if ( event->type==et_close ) {
275 	struct filter_d *d = GDrawGetUserData(gw);
276 	d->done = true;
277     } else if ( event->type == et_char ) {
278 return( false );
279     }
280 return( true );
281 }
282 
filter_candelete(GGadget * g,int r)283 static int filter_candelete(GGadget *g, int r) {
284     struct matrix_data *md;
285     int rows;
286 
287     md = GMatrixEditGet(g,&rows);
288     if ( r>=rows )
289 return( false );
290 
291 return( !md[2*r].frozen );
292 }
293 
FilterDlg(void)294 static void FilterDlg(void) {
295     static struct col_init cols[] = {
296 	{ me_string, NULL, NULL, NULL, N_("Name") },
297 	{ me_string, NULL, NULL, NULL, N_("Filter") }
298     };
299     static int inited = false;
300     static struct matrixinit mi = {
301 	2, cols,
302 	0, NULL,
303 	NULL,
304 	filter_candelete,
305 	NULL,
306 	NULL,
307 	NULL,
308 	NULL
309     };
310     struct matrix_data *md;
311     int k, cnt, i, ptwidth;
312     GGadgetCreateData gcd[3], boxes[3], *varray[7], *harray[7];
313     GTextInfo label[3];
314     GRect pos;
315     GWindow gw;
316     GWindowAttrs wattrs;
317     struct filter_d d;
318 
319     if ( !inited ) {
320 	inited = true;
321 	cols[0].title = _(cols[0].title);
322 	cols[1].title = _(cols[1].title);
323     }
324 
325     for ( k=0; k<2; ++k ) {
326 	cnt = 0;
327 	for ( i=0; def_font_filters[i].name!=NULL; ++i ) {
328 	    if ( *(char *) def_font_filters[i].name != '-' ) {
329 		if ( k ) {
330 		    md[2*cnt].u.md_str = copy(_(def_font_filters[i].name));
331 		    md[2*cnt].frozen = true;
332 		    md[2*cnt+1].u.md_str = copy(def_font_filters[i].filter);
333 		    md[2*cnt+1].frozen = true;
334 		}
335 		++cnt;
336 	    }
337 	}
338 	if ( user_font_filters!=NULL ) {
339 	    for ( i=0; user_font_filters[i].name!=NULL; ++i ) {
340 		if ( *(char *) user_font_filters[i].name != '-' ) {
341 		    if ( k ) {
342 			md[2*cnt].u.md_str = copy(user_font_filters[i].name);
343 			md[2*cnt].frozen = false;
344 			md[2*cnt+1].u.md_str = copy(user_font_filters[i].filter);
345 			md[2*cnt+1].frozen = false;
346 		    }
347 		    ++cnt;
348 		}
349 	    }
350 	}
351 	if ( !k )
352 	    md = calloc(2*cnt,sizeof(struct matrix_data));
353     }
354     mi.initial_row_cnt = cnt;
355     mi.matrix_data = md;
356 
357 
358     memset(&d,'\0',sizeof(d));
359 
360     memset(&wattrs,0,sizeof(wattrs));
361     wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_undercursor|wam_restrict|wam_isdlg;
362     wattrs.event_masks = ~(1<<et_charup);
363     wattrs.restrict_input_to_me = 1;
364     wattrs.is_dlg = true;
365     wattrs.undercursor = 1;
366     wattrs.cursor = ct_pointer;
367     wattrs.utf8_window_title = _("Edit Font Filters");
368     pos.x = pos.y = 0;
369     ptwidth = 2*GIntGetResource(_NUM_Buttonsize)+GGadgetScale(60);
370     pos.width =GDrawPointsToPixels(NULL,ptwidth);
371     pos.height = GDrawPointsToPixels(NULL,90);
372     gw = GDrawCreateTopWindow(NULL,&pos,filter_e_h,&d,&wattrs);
373 
374 
375     memset(&label,0,sizeof(label));
376     memset(&gcd,0,sizeof(gcd));
377     memset(&boxes,0,sizeof(boxes));
378 
379     gcd[0].gd.pos.x = 10; gcd[0].gd.pos.y = 6;
380     gcd[0].gd.pos.width = 300; gcd[0].gd.pos.height = 200;
381     gcd[0].gd.flags = gg_visible | gg_enabled;
382     gcd[0].creator = GMatrixEditCreate;
383     gcd[0].gd.u.matrix = &mi;
384     varray[0] = &gcd[0]; varray[1] = NULL;
385 
386     gcd[1].gd.pos.x = 20-3; gcd[1].gd.pos.y = 90-35-3;
387     gcd[1].gd.pos.width = -1; gcd[1].gd.pos.height = 0;
388     gcd[1].gd.flags = gg_visible | gg_enabled | gg_but_default;
389     label[1].text = (unichar_t *) _("_OK");
390     label[1].text_is_1byte = true;
391     label[1].text_in_resource = true;
392     gcd[1].gd.label = &label[1];
393     gcd[1].gd.handle_controlevent = Filter_OK;
394     gcd[1].creator = GButtonCreate;
395     harray[0] = GCD_Glue; harray[1] = &gcd[1]; harray[2] = GCD_Glue;
396 
397     gcd[2].gd.pos.x = -20; gcd[2].gd.pos.y = 90-35;
398     gcd[2].gd.pos.width = -1; gcd[2].gd.pos.height = 0;
399     gcd[2].gd.flags = gg_visible | gg_enabled | gg_but_cancel;
400     label[2].text = (unichar_t *) _("_Cancel");
401     label[2].text_is_1byte = true;
402     label[2].text_in_resource = true;
403     gcd[2].gd.label = &label[2];
404     gcd[2].gd.handle_controlevent = Filter_Cancel;
405     gcd[2].creator = GButtonCreate;
406     harray[3] = GCD_Glue; harray[4] = &gcd[2]; harray[5] = GCD_Glue;
407     harray[6] = NULL;
408     varray[2] = &boxes[2]; varray[3] = NULL;
409     varray[4] = NULL;
410 
411     boxes[0].gd.pos.x = boxes[0].gd.pos.y = 2;
412     boxes[0].gd.flags = gg_enabled|gg_visible;
413     boxes[0].gd.u.boxelements = varray;
414     boxes[0].creator = GHVGroupCreate;
415 
416     boxes[2].gd.flags = gg_enabled|gg_visible;
417     boxes[2].gd.u.boxelements = harray;
418     boxes[2].creator = GHBoxCreate;
419 
420 
421     GGadgetsCreate(gw,boxes);
422     GHVBoxSetExpandableRow(boxes[0].ret,0);
423     GHVBoxSetExpandableCol(boxes[2].ret,gb_expandgluesame);
424     GHVBoxFitWindow(boxes[0].ret);
425     GMatrixEditSetNewText(gcd[0].ret,S_("Filter|New"));
426     d.gme = gcd[0].ret;
427 
428     GDrawSetVisible(gw,true);
429     while ( !d.done )
430 	GDrawProcessOneEvent(NULL);
431     GDrawDestroyWindow(gw);
432 
433     for ( i=0; i<cnt; ++i ) {
434 	free(md[2*i].u.md_str);
435 	free(md[2*i+1].u.md_str);
436     }
437     free(md);
438 }
439 
440 struct gfc_data {
441     int done;
442     unichar_t *ret;
443     GGadget *gfc;
444     GGadget *rename;
445     int filename_popup_pos;
446     unichar_t *lastpopupfontname;
447 };
448 
GFD_Ok(GGadget * g,GEvent * e)449 static int GFD_Ok(GGadget *g, GEvent *e) {
450     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
451 	struct gfc_data *d = GDrawGetUserData(GGadgetGetWindow(g));
452 	GGadget *tf;
453 	GFileChooserGetChildren(d->gfc,NULL,NULL,&tf);
454 	if ( *_GGadgetGetTitle(tf)!='\0' ) {
455 	    extern int allow_utf8_glyphnames;
456 	    GTextInfo *ti = GGadgetGetListItemSelected(d->rename);
457 	    char *nlname = u2utf8_copy(ti->text);
458 	    force_names_when_opening = NameListByName(nlname);
459 	    free(nlname);
460 	    if ( force_names_when_opening!=NULL && force_names_when_opening->uses_unicode &&
461 		    !allow_utf8_glyphnames) {
462 		ff_post_error(_("Namelist contains non-ASCII names"),_("Glyph names should be limited to characters in the ASCII character set, but there are names in this namelist which use characters outside that range."));
463 return(true);
464 	    }
465 	    d->done = true;
466 	    d->ret = GGadgetGetTitle(d->gfc);
467 
468 	    // Trim trailing '/' if its there and put that string back as
469 	    // the d->gfc string.
470 	    int tmplen = u_strlen( d->ret );
471 	    if( tmplen > 0 ) {
472 		if( d->ret[ tmplen-1 ] == '/' ) {
473 		    unichar_t* tmp = u_copy( d->ret );
474 		    tmp[ tmplen-1 ] = '\0';
475 		    GGadgetSetTitle(d->gfc, tmp);
476 		    free(tmp);
477 		    d->ret = GGadgetGetTitle(d->gfc);
478 		}
479 	    }
480 	}
481     }
482 return( true );
483 }
484 
GFD_New(GGadget * g,GEvent * e)485 static int GFD_New(GGadget *g, GEvent *e) {
486     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
487 	struct gfc_data *d = GDrawGetUserData(GGadgetGetWindow(g));
488 	d->done = true;
489 	GDrawSetVisible(GGadgetGetWindow(g),false);
490 	FontNew();
491     }
492 return( true );
493 }
494 
GFD_Cancel(GGadget * g,GEvent * e)495 static int GFD_Cancel(GGadget *g, GEvent *e) {
496     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
497 	struct gfc_data *d = GDrawGetUserData(GGadgetGetWindow(g));
498 	d->done = true;
499     }
500 return( true );
501 }
502 
GFD_FilterSelected(GGadget * g,GEvent * e)503 static int GFD_FilterSelected(GGadget *g, GEvent *e) {
504     if ( e->type==et_controlevent && e->u.control.subtype == et_listselected ) {
505 	struct gfc_data *d = GDrawGetUserData(GGadgetGetWindow(g));
506 	GTextInfo *ti = GGadgetGetListItemSelected(g);
507 	if ( ti->userdata==NULL )
508 	    /* They selected a line. Dull */;
509 	else if ( ti->userdata == (void *) -1 ) {
510 	    FilterDlg();
511 	    GGadgetSetList(g,StandardFilters(),true);
512 	} else {
513 	    unichar_t *temp = utf82u_copy(ti->userdata);
514 	    GFileChooserSetFilterText(d->gfc,temp);
515 	    free(temp);
516 	    temp = GFileChooserGetDir(d->gfc);
517 	    GFileChooserSetDir(d->gfc,temp);
518 	    free(temp);
519 	    default_font_filter_index = GGadgetGetFirstListSelectedItem(g);
520 	    SavePrefs(true);
521 	}
522     }
523 return( true );
524 }
525 
WithinList(struct gfc_data * d,GEvent * event)526 static int WithinList(struct gfc_data *d,GEvent *event) {
527     GRect size;
528     GGadget *list;
529     int32 pos;
530     unichar_t *ufile;
531     char *file, **fontnames;
532     int cnt, len;
533     unichar_t *msg;
534 
535     if ( event->type!=et_mousemove )
536 return( false );
537 
538     GFileChooserGetChildren(d->gfc,NULL, &list, NULL);
539     if ( list==NULL )
540 return( false );
541     if ( !GGadgetWithin(list,event->u.mouse.x,event->u.mouse.y) )
542         return( false );
543     pos = GListIndexFromY(list,event->u.mouse.y);
544     if ( pos == d->filename_popup_pos )
545 return( pos!=-1 );
546     if ( pos==-1 || GFileChooserPosIsDir(d->gfc,pos)) {
547 	d->filename_popup_pos = -1;
548 return( pos!=-1 );
549     }
550     ufile = GFileChooserFileNameOfPos(d->gfc,pos);
551     if ( ufile==NULL )
552 return( true );
553     file = u2def_copy(ufile);
554     free(ufile);
555 
556     fontnames = GetFontNames(file, 0);
557     if ( fontnames==NULL || fontnames[0]==NULL )
558 	msg = uc_copy( "???" );
559     else {
560 	len = 0;
561 	for ( cnt=0; fontnames[cnt]!=NULL; ++cnt )
562 	    len += strlen(fontnames[cnt])+1;
563 	msg = malloc((len+2)*sizeof(unichar_t));
564 	len = 0;
565 	for ( cnt=0; fontnames[cnt]!=NULL; ++cnt ) {
566 	    uc_strcpy(msg+len,fontnames[cnt]);
567 	    len += strlen(fontnames[cnt]);
568 	    msg[len++] = '\n';
569 	}
570 	msg[len-1] = '\0';
571     }
572     GGadgetPreparePopup(GGadgetGetWindow(d->gfc),msg);
573     if ( fontnames!=NULL ) {
574         for ( cnt=0; fontnames[cnt]!=NULL; ++cnt ) {
575             free(fontnames[cnt]);
576         }
577         free(fontnames);
578     }
579     free(file);
580     free(d->lastpopupfontname);
581     d->lastpopupfontname = msg;
582 return( true );
583 }
584 
e_h(GWindow gw,GEvent * event)585 static int e_h(GWindow gw, GEvent *event) {
586     if ( event->type==et_close ) {
587 	struct gfc_data *d = GDrawGetUserData(gw);
588 	d->done = true;
589     } else if ( event->type == et_map ) {
590 	/* Above palettes */
591 	GDrawRaise(gw);
592     } else if ( event->type == et_char ) {
593 return( false );
594     } else if ( event->type == et_mousemove ||
595 	    (event->type==et_mousedown && event->u.mouse.button==3 )) {
596 	struct gfc_data *d = GDrawGetUserData(gw);
597 	if ( !WithinList(d,event) )
598 	    GFileChooserPopupCheck(d->gfc,event);
599     } else if (( event->type==et_mouseup || event->type==et_mousedown ) &&
600 	    (event->u.mouse.button>=4 && event->u.mouse.button<=7) ) {
601 	struct gfc_data *d = GDrawGetUserData(gw);
602 return( GGadgetDispatchEvent((GGadget *) (d->gfc),event));
603     } else if ( event->type == et_resize ) {
604 	GRect r, size;
605 	struct gfc_data *d = GDrawGetUserData(gw);
606 	if ( d->gfc!=NULL ) {
607 	    GDrawGetSize(gw,&size);
608 	    GGadgetGetSize(d->gfc,&r);
609 	    GGadgetResize(d->gfc,size.width-2*r.x,r.height);
610 	}
611     }
612 return( event->type!=et_char );
613 }
614 
FVOpenFont(char * title,const char * defaultfile,bool mult,bool modal)615 static unichar_t *FVOpenFont(char *title, const char *defaultfile, bool mult, bool modal) {
616     GRect pos;
617     int i, filter, renamei;
618     GWindow gw;
619     GWindowAttrs wattrs;
620     GGadgetCreateData gcd[11], boxes[5], *varray[9], *harray1[7], *harray2[4], *harray3[9];
621     GTextInfo label[10];
622     struct gfc_data d;
623     int bs = GIntGetResource(_NUM_Buttonsize), bsbigger, totwid, spacing;
624     GGadget *tf;
625     unichar_t *temp;
626     char **nlnames;
627     GTextInfo *namelistnames, **filts;
628     int cnt;
629 
630     memset(&d,'\0',sizeof(d));
631 
632     memset(&wattrs,0,sizeof(wattrs));
633     if (modal) {
634         wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_undercursor|wam_isdlg|wam_restrict;
635         wattrs.restrict_input_to_me = 1;
636         wattrs.is_dlg = true;
637         wattrs.undercursor = 1;
638     } else {
639         wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle;
640     }
641     wattrs.event_masks = ~(1<<et_charup);
642     wattrs.cursor = ct_pointer;
643     wattrs.utf8_window_title = title;
644 
645     pos.x = pos.y = 0;
646 
647     totwid = GGadgetScale(295);
648     bsbigger = 4*bs+4*14>totwid; totwid = bsbigger?4*bs+4*12:totwid;
649     spacing = (totwid-4*bs-2*12)/3;
650 
651     pos.width = GDrawPointsToPixels(NULL,totwid);
652     pos.height = GDrawPointsToPixels(NULL,247);
653     gw = GDrawCreateTopWindow(NULL,&pos,e_h,&d,&wattrs);
654 
655     memset(&label,0,sizeof(label));
656     memset(&gcd,0,sizeof(gcd));
657     memset(&boxes,0,sizeof(boxes));
658     i=0;
659     gcd[i].gd.pos.x = 12; gcd[i].gd.pos.y = 6; gcd[i].gd.pos.width = totwid*100/GIntGetResource(_NUM_ScaleFactor)-24; gcd[i].gd.pos.height = 180;
660     gcd[i].gd.flags = gg_visible | gg_enabled;
661     if ( RecentFiles[0]!=NULL )
662 	gcd[i].gd.flags = gg_visible | gg_enabled | gg_file_pulldown;
663     if ( mult )
664 	gcd[i].gd.flags |= gg_file_multiple;
665     varray[0] = &gcd[i]; varray[1] = NULL;
666     gcd[i++].creator = GFileChooserCreate;
667 
668     label[i].text = (unichar_t *) _("Filter:");
669     label[i].text_is_1byte = true;
670     gcd[i].gd.label = &label[i];
671     gcd[i].gd.pos.x = 8; gcd[i].gd.pos.y = 188+6;
672     gcd[i].gd.flags = gg_visible | gg_enabled;
673     gcd[i].gd.popup_msg = _("Display files of this type" );
674     harray1[0] = GCD_Glue; harray1[1] = &gcd[i];
675     gcd[i++].creator = GLabelCreate;
676 
677     gcd[i].gd.pos.x = 0; gcd[i].gd.pos.y = gcd[i-1].gd.pos.y-6;
678     gcd[i].gd.flags = gg_visible | gg_enabled;
679     gcd[i].gd.popup_msg = _("Display files of this type");
680     gcd[i].gd.handle_controlevent = GFD_FilterSelected;
681     harray1[2] = &gcd[i]; harray1[3] = GCD_Glue; harray1[4] = GCD_Glue; harray1[5] = GCD_Glue; harray1[6] = NULL;
682     gcd[i++].creator = GListButtonCreate;
683 
684     boxes[2].gd.flags = gg_visible | gg_enabled;
685     boxes[2].gd.u.boxelements = harray1;
686     boxes[2].creator = GHBoxCreate;
687     varray[2] = &boxes[2]; varray[3] = NULL;
688 
689     label[i].text = (unichar_t *) _("Force glyph names to:");
690     label[i].text_is_1byte = true;
691     gcd[i].gd.label = &label[i];
692     gcd[i].gd.pos.x = 8; gcd[i].gd.pos.y = 188+6;
693     gcd[i].gd.flags = gg_visible | gg_enabled;
694     gcd[i].gd.popup_msg = _("In the saved font, force all glyph names to match those in the specified namelist");
695     harray2[0] = &gcd[i];
696     gcd[i++].creator = GLabelCreate;
697 
698     renamei = i;
699     gcd[i].gd.pos.x = 0; gcd[i].gd.pos.y = gcd[i-1].gd.pos.y-6;
700     gcd[i].gd.flags = gg_visible | gg_enabled;
701     gcd[i].gd.popup_msg = _("In the saved font, force all glyph names to match those in the specified namelist");
702     gcd[i].creator = GListButtonCreate;
703     nlnames = AllNamelistNames();
704     for ( cnt=0; nlnames[cnt]!=NULL; ++cnt);
705     namelistnames = calloc(cnt+3,sizeof(GTextInfo));
706     namelistnames[0].text = (unichar_t *) _("No Rename");
707     namelistnames[0].text_is_1byte = true;
708     if ( force_names_when_opening==NULL ) {
709 	namelistnames[0].selected = true;
710 	gcd[i].gd.label = &namelistnames[0];
711     }
712     namelistnames[1].line = true;
713     for ( cnt=0; nlnames[cnt]!=NULL; ++cnt) {
714 	namelistnames[cnt+2].text = (unichar_t *) nlnames[cnt];
715 	namelistnames[cnt+2].text_is_1byte = true;
716 	if ( force_names_when_opening!=NULL &&
717 		strcmp(_(force_names_when_opening->title),nlnames[cnt])==0 ) {
718 	    namelistnames[cnt+2].selected = true;
719 	    gcd[i].gd.label = &namelistnames[cnt+2];
720 	}
721     }
722     harray2[1] = &gcd[i]; harray2[2] = GCD_Glue; harray2[3] = NULL;
723     gcd[i++].gd.u.list = namelistnames;
724 
725     boxes[3].gd.flags = gg_visible | gg_enabled;
726     boxes[3].gd.u.boxelements = harray2;
727     boxes[3].creator = GHBoxCreate;
728     varray[4] = &boxes[3]; varray[5] = NULL;
729 
730     gcd[i].gd.pos.x = 12; gcd[i].gd.pos.y = 216-3;
731     gcd[i].gd.pos.width = -1;
732     gcd[i].gd.flags = gg_visible | gg_enabled | gg_but_default;
733     label[i].text = (unichar_t *) _("_OK");
734     label[i].text_is_1byte = true;
735     label[i].text_in_resource = true;
736     gcd[i].gd.mnemonic = 'O';
737     gcd[i].gd.label = &label[i];
738     gcd[i].gd.handle_controlevent = GFD_Ok;
739     harray3[0] = GCD_Glue; harray3[1] = &gcd[i];
740     gcd[i++].creator = GButtonCreate;
741 
742     gcd[i].gd.pos.x = -(spacing+bs)*100/GIntGetResource(_NUM_ScaleFactor)-12; gcd[i].gd.pos.y = gcd[i-1].gd.pos.y+3;
743     gcd[i].gd.pos.width = -1;
744     gcd[i].gd.flags = gg_visible | gg_enabled;
745     label[i].text = (unichar_t *) S_("Font|_New");
746     label[i].text_is_1byte = true;
747     label[i].text_in_resource = true;
748     gcd[i].gd.mnemonic = 'N';
749     gcd[i].gd.label = &label[i];
750     gcd[i].gd.handle_controlevent = GFD_New;
751     harray3[2] = GCD_Glue; harray3[3] = &gcd[i];
752     gcd[i++].creator = GButtonCreate;
753 
754     filter = i;
755     gcd[i].gd.pos.x = (spacing+bs)*100/GIntGetResource(_NUM_ScaleFactor)+12; gcd[i].gd.pos.y = gcd[i-1].gd.pos.y;
756     gcd[i].gd.pos.width = -1;
757     gcd[i].gd.flags = /* gg_visible |*/ gg_enabled;
758     label[i].text = (unichar_t *) _("_Filter");
759     label[i].text_is_1byte = true;
760     label[i].text_in_resource = true;
761     gcd[i].gd.mnemonic = 'F';
762     gcd[i].gd.label = &label[i];
763     gcd[i].gd.handle_controlevent = GFileChooserFilterEh;
764     harray3[4] = &gcd[i];
765     gcd[i++].creator = GButtonCreate;
766 
767     gcd[i].gd.pos.x = -12; gcd[i].gd.pos.y = gcd[i-1].gd.pos.y;
768     gcd[i].gd.pos.width = -1;
769     gcd[i].gd.flags = gg_visible | gg_enabled | gg_but_cancel;
770     label[i].text = (unichar_t *) _("_Cancel");
771     label[i].text_is_1byte = true;
772     label[i].text_in_resource = true;
773     gcd[i].gd.label = &label[i];
774     gcd[i].gd.mnemonic = 'C';
775     gcd[i].gd.handle_controlevent = GFD_Cancel;
776     harray3[5] = GCD_Glue; harray3[6] = &gcd[i]; harray3[7] = GCD_Glue; harray3[8] = NULL;
777     gcd[i++].creator = GButtonCreate;
778 
779     boxes[4].gd.flags = gg_visible | gg_enabled;
780     boxes[4].gd.u.boxelements = harray3;
781     boxes[4].creator = GHBoxCreate;
782     varray[6] = &boxes[4]; varray[7] = NULL;
783     varray[8] = NULL;
784 
785     boxes[0].gd.pos.x = boxes[0].gd.pos.y = 2;
786     boxes[0].gd.flags = gg_visible | gg_enabled;
787     boxes[0].gd.u.boxelements = varray;
788     boxes[0].creator = GHVGroupCreate;
789 
790     gcd[i].gd.pos.x = 2; gcd[i].gd.pos.y = 2;
791     gcd[i].gd.pos.width = pos.width-4; gcd[i].gd.pos.height = pos.height-4;
792     gcd[i].gd.flags = gg_enabled | gg_visible | gg_pos_in_pixels;
793     gcd[i++].creator = GGroupCreate;
794 
795     GGadgetsCreate(gw,boxes);
796 
797     d.gfc = gcd[0].ret;
798     d.rename = gcd[renamei].ret;
799 
800     filts = StandardFilters();
801     GGadgetSetList(harray1[2]->ret,filts,true);
802     GHVBoxSetExpandableRow(boxes[0].ret,0);
803     GHVBoxSetExpandableCol(boxes[2].ret,gb_expandglue);
804     GHVBoxSetExpandableCol(boxes[3].ret,gb_expandglue);
805     GHVBoxSetExpandableCol(boxes[4].ret,gb_expandgluesame);
806     GHVBoxFitWindow(boxes[0].ret);
807     free(namelistnames);
808     GGadgetSetUserData(gcd[filter].ret,gcd[0].ret);
809 
810     GFileChooserConnectButtons(gcd[0].ret,harray3[1]->ret,gcd[filter].ret);
811     temp = utf82u_copy(filts[default_font_filter_index]->userdata);
812     GFileChooserSetFilterText(gcd[0].ret,temp);
813     free(temp);
814     GFileChooserGetChildren(gcd[0].ret,NULL, NULL, &tf);
815     if ( RecentFiles[0]!=NULL ) {
816 	GGadgetSetList(tf,GTextInfoFromChars(RecentFiles,RECENT_MAX),false);
817     }
818     GGadgetSetTitle8(gcd[0].ret,defaultfile);
819 
820     GWidgetHidePalettes();
821     GDrawSetVisible(gw,true);
822     while ( !d.done )
823 	GDrawProcessOneEvent(NULL);
824     GDrawDestroyWindow(gw);
825     GDrawProcessPendingEvents(NULL);		/* Give the window a chance to vanish... */
826     GDrawSync(NULL);
827     GDrawProcessPendingEvents(NULL);		/* Give the window a chance to vanish... */
828     free( d.lastpopupfontname );
829     GTextInfoArrayFree(filts);
830     for ( cnt=0; nlnames[cnt]!=NULL; ++cnt) {
831 	free(nlnames[cnt]);
832     }
833     free(nlnames);
834 return(d.ret);
835 }
836 
GetPostScriptFontName(char * dir,bool mult,bool modal)837 char *GetPostScriptFontName(char *dir, bool mult, bool modal) {
838     unichar_t *ret;
839     char *u_dir;
840     char *temp;
841 
842     u_dir = def2utf8_copy(dir);
843     ret = FVOpenFont(_("Open Font"), u_dir, mult, modal);
844     temp = u2def_copy(ret);
845 
846     free(ret);
847 return( temp );
848 }
849 
850