1 /* Copyright (C) 2000-2012 by George Williams */
2 /*
3  * Redistribution and use in source and binary forms, with or without
4  * modification, are permitted provided that the following conditions are met:
5 
6  * Redistributions of source code must retain the above copyright notice, this
7  * list of conditions and the following disclaimer.
8 
9  * Redistributions in binary form must reproduce the above copyright notice,
10  * this list of conditions and the following disclaimer in the documentation
11  * and/or other materials provided with the distribution.
12 
13  * The name of the author may not be used to endorse or promote products
14  * derived from this software without specific prior written permission.
15 
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include <fontforge-config.h>
29 
30 #include "autosave.h"
31 #include "autotrace.h"
32 #include "autowidth.h"
33 #include "autowidth2.h"
34 #include "bitmapchar.h"
35 #include "bvedit.h"
36 #include "chardata.h"
37 #include "cvundoes.h"
38 #include "dumppfa.h"
39 #include "encoding.h"
40 #include "ffglib.h"
41 #include "fontforgeui.h"
42 #include "fvcomposite.h"
43 #include "fvfonts.h"
44 #include "gfile.h"
45 #include "gio.h"
46 #include "gkeysym.h"
47 #include "gresedit.h"
48 #include "gresource.h"
49 #include "groups.h"
50 #include "mm.h"
51 #include "namelist.h"
52 #include "nonlineartrans.h"
53 #include "psfont.h"
54 #include "pua.h"
55 #include "scripting.h"
56 #include "search.h"
57 #include "sfd.h"
58 #include "sfundo.h"
59 #include "splinefill.h"
60 #include "splinesaveafm.h"
61 #include "splineutil.h"
62 #include "splineutil2.h"
63 #include "tottfgpos.h"
64 #include "unicodelibinfo.h"
65 #include "ustring.h"
66 #include "utype.h"
67 
68 #include <math.h>
69 #include <unistd.h>
70 
71 #if defined (__MINGW32__)
72 #include <windows.h>
73 #endif
74 
75 int OpenCharsInNewWindow = 0;
76 char *RecentFiles[RECENT_MAX] = { NULL };
77 int save_to_dir = 0;			/* use sfdir rather than sfd */
78 unichar_t *script_menu_names[SCRIPT_MENU_MAX];
79 char *script_filenames[SCRIPT_MENU_MAX];
80 extern int onlycopydisplayed, copymetadata, copyttfinstr, add_char_to_name_list;
81 int home_char='A';
82 int compact_font_on_open=0;
83 int warn_script_unsaved = 0;
84 int navigation_mask = 0;		/* Initialized in startui.c */
85 
86 static char *fv_fontnames = MONO_UI_FAMILIES;
87 extern void python_call_onClosingFunctions();
88 
89 #define	FV_LAB_HEIGHT	15
90 
91 #ifdef BIGICONS
92 #define fontview_width 32
93 #define fontview_height 32
94 static unsigned char fontview_bits[] = {
95    0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0x02, 0x20, 0x80, 0x00,
96    0x82, 0x20, 0x86, 0x08, 0x42, 0x21, 0x8a, 0x14, 0xc2, 0x21, 0x86, 0x04,
97    0x42, 0x21, 0x8a, 0x14, 0x42, 0x21, 0x86, 0x08, 0x02, 0x20, 0x80, 0x00,
98    0xaa, 0xaa, 0xaa, 0xaa, 0x02, 0x20, 0x80, 0x00, 0x82, 0xa0, 0x8f, 0x18,
99    0x82, 0x20, 0x91, 0x24, 0x42, 0x21, 0x91, 0x02, 0x42, 0x21, 0x91, 0x02,
100    0x22, 0x21, 0x8f, 0x02, 0xe2, 0x23, 0x91, 0x02, 0x12, 0x22, 0x91, 0x02,
101    0x3a, 0x27, 0x91, 0x24, 0x02, 0xa0, 0x8f, 0x18, 0x02, 0x20, 0x80, 0x00,
102    0xfe, 0xff, 0xff, 0xff, 0x02, 0x20, 0x80, 0x00, 0x42, 0x20, 0x86, 0x18,
103    0xa2, 0x20, 0x8a, 0x04, 0xa2, 0x20, 0x86, 0x08, 0xa2, 0x20, 0x8a, 0x10,
104    0x42, 0x20, 0x8a, 0x0c, 0x82, 0x20, 0x80, 0x00, 0x02, 0x20, 0x80, 0x00,
105    0xaa, 0xaa, 0xaa, 0xaa, 0x02, 0x20, 0x80, 0x00};
106 #else
107 #define fontview2_width 16
108 #define fontview2_height 16
109 static unsigned char fontview2_bits[] = {
110    0x00, 0x07, 0x80, 0x08, 0x40, 0x17, 0x40, 0x15, 0x60, 0x09, 0x10, 0x02,
111    0xa0, 0x01, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0x50, 0x00, 0x52, 0x00,
112    0x55, 0x00, 0x5d, 0x00, 0x22, 0x00, 0x1c, 0x00};
113 #endif
114 
115 extern int _GScrollBar_Width;
116 
117 static int fv_fontsize = 11, fv_fs_init=0;
118 static Color fvselcol = 0xffff00, fvselfgcol=0x000000;
119 Color view_bgcol;
120 static Color fvglyphinfocol = 0xff0000;
121 static Color fvemtpyslotfgcol = 0xd08080;
122 static Color fvchangedcol = 0x000060;
123 static Color fvhintingneededcol = 0x0000ff;
124 
125 enum glyphlable { gl_glyph, gl_name, gl_unicode, gl_encoding };
126 int default_fv_showhmetrics=false, default_fv_showvmetrics=false,
127 	default_fv_glyphlabel = gl_glyph;
128 #define METRICS_BASELINE 0x0000c0
129 #define METRICS_ORIGIN	 0xc00000
130 #define METRICS_ADVANCE	 0x008000
131 FontView *fv_list=NULL;
132 
133 
FV_ToggleCharChanged(SplineChar * sc)134 static void FV_ToggleCharChanged(SplineChar *sc) {
135     int i, j;
136     int pos;
137     FontView *fv;
138 
139     for ( fv = (FontView *) (sc->parent->fv); fv!=NULL; fv=(FontView *) (fv->b.nextsame) ) {
140 	if ( fv->b.sf!=sc->parent )		/* Can happen in CID fonts if char's parent is not currently active */
141     continue;
142 	if ( fv->v==NULL || fv->colcnt==0 )	/* Can happen in scripts */
143     continue;
144 	for ( pos=0; pos<fv->b.map->enccount; ++pos ) if ( fv->b.map->map[pos]==sc->orig_pos ) {
145 	    i = pos / fv->colcnt;
146 	    j = pos - i*fv->colcnt;
147 	    i -= fv->rowoff;
148  /* Normally we should be checking against fv->rowcnt (rather than <=rowcnt) */
149  /*  but every now and then the WM forces us to use a window size which doesn't */
150  /*  fit our expectations (maximized view) and we must be prepared for half */
151  /*  lines */
152 	    if ( i>=0 && i<=fv->rowcnt ) {
153 		GRect r;
154 		r.x = j*fv->cbw+1; r.width = fv->cbw-1;
155 		r.y = i*fv->cbh+1; r.height = fv->lab_height-1;
156 		GDrawRequestExpose(fv->v,&r,false);
157 	    }
158 	}
159     }
160 }
161 
FVMarkHintsOutOfDate(SplineChar * sc)162 void FVMarkHintsOutOfDate(SplineChar *sc) {
163     int i, j;
164     int pos;
165     FontView *fv;
166 
167     if ( sc->parent->onlybitmaps || sc->parent->multilayer || sc->parent->strokedfont )
168 return;
169     for ( fv = (FontView *) (sc->parent->fv); fv!=NULL; fv=(FontView *) (fv->b.nextsame) ) {
170 	if ( fv->b.sf!=sc->parent )		/* Can happen in CID fonts if char's parent is not currently active */
171     continue;
172 	if ( sc->layers[fv->b.active_layer].order2 )
173     continue;
174 	if ( fv->v==NULL || fv->colcnt==0 )	/* Can happen in scripts */
175     continue;
176 	for ( pos=0; pos<fv->b.map->enccount; ++pos ) if ( fv->b.map->map[pos]==sc->orig_pos ) {
177 	    i = pos / fv->colcnt;
178 	    j = pos - i*fv->colcnt;
179 	    i -= fv->rowoff;
180  /* Normally we should be checking against fv->rowcnt (rather than <=rowcnt) */
181  /*  but every now and then the WM forces us to use a window size which doesn't */
182  /*  fit our expectations (maximized view) and we must be prepared for half */
183  /*  lines */
184 	    if ( i>=0 && i<=fv->rowcnt ) {
185 		GRect r;
186 		r.x = j*fv->cbw+1; r.width = fv->cbw-1;
187 		r.y = i*fv->cbh+1; r.height = fv->lab_height-1;
188 		GDrawDrawLine(fv->v,r.x,r.y,r.x,r.y+r.height-1,fvhintingneededcol);
189 		GDrawDrawLine(fv->v,r.x+1,r.y,r.x+1,r.y+r.height-1,fvhintingneededcol);
190 		GDrawDrawLine(fv->v,r.x+r.width-1,r.y,r.x+r.width-1,r.y+r.height-1,fvhintingneededcol);
191 		GDrawDrawLine(fv->v,r.x+r.width-2,r.y,r.x+r.width-2,r.y+r.height-1,fvhintingneededcol);
192 	    }
193 	}
194     }
195 }
196 
FeatureTrans(FontView * fv,int enc)197 static int FeatureTrans(FontView *fv, int enc) {
198     SplineChar *sc;
199     PST *pst;
200     char *pt;
201     int gid;
202 
203     if ( enc<0 || enc>=fv->b.map->enccount || (gid = fv->b.map->map[enc])==-1 )
204 return( -1 );
205     if ( fv->cur_subtable==NULL )
206 return( gid );
207 
208     sc = fv->b.sf->glyphs[gid];
209     if ( sc==NULL )
210 return( -1 );
211     for ( pst = sc->possub; pst!=NULL; pst=pst->next ) {
212 	if (( pst->type == pst_substitution || pst->type == pst_alternate ) &&
213 		pst->subtable == fv->cur_subtable )
214     break;
215     }
216     if ( pst==NULL )
217 return( -1 );
218     pt = strchr(pst->u.subs.variant,' ');
219     if ( pt!=NULL )
220 	*pt = '\0';
221     gid = SFFindExistingSlot(fv->b.sf, -1, pst->u.subs.variant );
222     if ( pt!=NULL )
223 	*pt = ' ';
224 return( gid );
225 }
226 
FVDrawGlyph(GWindow pixmap,FontView * fv,int index,int forcebg)227 static void FVDrawGlyph(GWindow pixmap, FontView *fv, int index, int forcebg ) {
228     GRect box, old2;
229     int feat_gid;
230     SplineChar *sc;
231     struct _GImage base;
232     GImage gi;
233     GClut clut;
234     int i,j;
235     int em = fv->b.sf->ascent+fv->b.sf->descent;
236     int yorg = fv->magnify*(fv->show->ascent);
237 
238     i = index / fv->colcnt;
239     j = index - i*fv->colcnt;
240     i -= fv->rowoff;
241 
242     if ( index<fv->b.map->enccount && (fv->b.selected[index] || forcebg)) {
243 	box.x = j*fv->cbw+1; box.width = fv->cbw-1;
244 	box.y = i*fv->cbh+fv->lab_height+1; box.height = fv->cbw;
245 	GDrawFillRect(pixmap,&box,fv->b.selected[index] ? fvselcol : view_bgcol );
246     }
247     feat_gid = FeatureTrans(fv,index);
248     sc = feat_gid!=-1 ? fv->b.sf->glyphs[feat_gid]: NULL;
249     if ( !SCWorthOutputting(sc) ) {
250 	int x = j*fv->cbw+1, xend = x+fv->cbw-2;
251 	int y = i*fv->cbh+fv->lab_height+1, yend = y+fv->cbw-1;
252 	GDrawDrawLine(pixmap,x,y,xend,yend,fvemtpyslotfgcol);
253 	GDrawDrawLine(pixmap,x,yend,xend,y,fvemtpyslotfgcol);
254     }
255     if ( sc!=NULL ) {
256 	BDFChar *bdfc;
257 
258 	if ( fv->show!=NULL && fv->show->piecemeal &&
259 		feat_gid!=-1 &&
260 		(feat_gid>=fv->show->glyphcnt || fv->show->glyphs[feat_gid]==NULL) &&
261 		fv->b.sf->glyphs[feat_gid]!=NULL )
262 	    BDFPieceMeal(fv->show,feat_gid);
263 
264 	if ( fv->show!=NULL && feat_gid!=-1 &&
265 		feat_gid < fv->show->glyphcnt &&
266 		fv->show->glyphs[feat_gid]==NULL &&
267 		SCWorthOutputting(fv->b.sf->glyphs[feat_gid]) ) {
268 	    /* If we have an outline but no bitmap for this slot */
269 	    box.x = j*fv->cbw+1; box.width = fv->cbw-2;
270 	    box.y = i*fv->cbh+fv->lab_height+2; box.height = box.width+1;
271 	    GDrawDrawRect(pixmap,&box,0xff0000);
272 	    ++box.x; ++box.y; box.width -= 2; box.height -= 2;
273 	    GDrawDrawRect(pixmap,&box,0xff0000);
274 /* When reencoding a font we can find times where index>=show->charcnt */
275 	} else if ( fv->show!=NULL && feat_gid<fv->show->glyphcnt && feat_gid!=-1 &&
276 		fv->show->glyphs[feat_gid]!=NULL ) {
277 	    /* If fontview is set to display an embedded bitmap font (not a temporary font, */
278 	    /* rasterized specially for this purpose), then we can't use it directly, as bitmap */
279 	    /* glyphs may contain selections and references. So create a temporary copy of */
280 	    /* the glyph merging all such elements into a single bitmap */
281 	    bdfc = fv->show->piecemeal ?
282 		fv->show->glyphs[feat_gid] : BDFGetMergedChar( fv->show->glyphs[feat_gid] );
283 
284 	    memset(&gi,'\0',sizeof(gi));
285 	    memset(&base,'\0',sizeof(base));
286 	    if ( bdfc->byte_data ) {
287 		gi.u.image = &base;
288 		base.image_type = it_index;
289 		if ( !fv->b.selected[index] )
290 		    base.clut = fv->show->clut;
291 		else {
292 		    int bgr=((fvselcol>>16)&0xff), bgg=((fvselcol>>8)&0xff), bgb= (fvselcol&0xff);
293 		    int fgr=((fvselfgcol>>16)&0xff), fgg=((fvselfgcol>>8)&0xff), fgb= (fvselfgcol&0xff);
294 		    int i;
295 		    memset(&clut,'\0',sizeof(clut));
296 		    base.clut = &clut;
297 		    clut.clut_len = fv->show->clut->clut_len;
298 		    for ( i=0; i<clut.clut_len; ++i ) {
299 			clut.clut[i] =
300 				COLOR_CREATE( bgr + (i*(fgr-bgr))/(clut.clut_len-1),
301 						bgg + (i*(fgg-bgg))/(clut.clut_len-1),
302 						bgb + (i*(fgb-bgb))/(clut.clut_len-1));
303 		    }
304 		}
305 		GDrawSetDither(NULL, false);	/* on 8 bit displays we don't want any dithering */
306 	    } else {
307 		memset(&clut,'\0',sizeof(clut));
308 		gi.u.image = &base;
309 		base.image_type = it_mono;
310 		base.clut = &clut;
311 		clut.clut_len = 2;
312 		clut.clut[0] = fv->b.selected[index] ? fvselcol : view_bgcol ;
313 		clut.clut[1] = fv->b.selected[index] ? fvselfgcol : 0 ;
314 	    }
315 	    base.trans = 0;
316 	    base.clut->trans_index = 0;
317 
318 	    base.data = bdfc->bitmap;
319 	    base.bytes_per_line = bdfc->bytes_per_line;
320 	    base.width = bdfc->xmax-bdfc->xmin+1;
321 	    base.height = bdfc->ymax-bdfc->ymin+1;
322 	    box.x = j*fv->cbw; box.width = fv->cbw;
323 	    box.y = i*fv->cbh+fv->lab_height+1; box.height = box.width+1;
324 	    GDrawPushClip(pixmap,&box,&old2);
325 	    if ( !fv->b.sf->onlybitmaps && fv->show!=fv->filled &&
326 		    sc->layers[fv->b.active_layer].splines==NULL && sc->layers[fv->b.active_layer].refs==NULL &&
327 		    !sc->widthset &&
328 		    !(bdfc->xmax<=0 && bdfc->xmin==0 && bdfc->ymax<=0 && bdfc->ymax==0) ) {
329 		/* If we have a bitmap but no outline character... */
330 		GRect b;
331 		b.x = box.x+1; b.y = box.y+1; b.width = box.width-2; b.height = box.height-2;
332 		GDrawDrawRect(pixmap,&b,0x008000);
333 		++b.x; ++b.y; b.width -= 2; b.height -= 2;
334 		GDrawDrawRect(pixmap,&b,0x008000);
335 	    }
336 
337 	    // Keep centering consistent to bdfc->width. If base.width!=bdfc->width,
338 	    // the bitmap has likely been run through BCCompressBitmap. In this
339 	    // case, bdfc->xmin should represent the true offset from the origin
340 	    // to the first used column.
341 	    int xwidth = (bdfc->width != base.width) ? bdfc->width - bdfc->xmin*2 : base.width;
342 
343 	    /* I assume that the bitmap image matches the bounding*/
344 	    /*  box. In some bitmap fonts the bitmap has white space on the*/
345 	    /*  right. This can throw off the centering algorithem */
346 	    if ( fv->magnify>1 ) {
347 		GDrawDrawImageMagnified(pixmap,&gi,NULL,
348 			j*fv->cbw+(fv->cbw-1-fv->magnify*xwidth)/2,
349 			i*fv->cbh+fv->lab_height+1+fv->magnify*(fv->show->ascent-bdfc->ymax),
350 			fv->magnify*base.width,fv->magnify*base.height);
351 	    } else if ( (GDrawHasCairo(pixmap)&gc_alpha) && base.image_type==it_index ) {
352 		GDrawDrawGlyph(pixmap,&gi,NULL,
353 			j*fv->cbw+(fv->cbw-1-xwidth)/2,
354 			i*fv->cbh+fv->lab_height+1+fv->show->ascent-bdfc->ymax);
355 	    } else
356 		GDrawDrawImage(pixmap,&gi,NULL,
357 			j*fv->cbw+(fv->cbw-1-xwidth)/2,
358 			i*fv->cbh+fv->lab_height+1+fv->show->ascent-bdfc->ymax);
359 	    if ( fv->showhmetrics ) {
360 		int x1, x0 = j*fv->cbw+(fv->cbw-1-fv->magnify*xwidth)/2- bdfc->xmin*fv->magnify;
361 		/* Draw advance width & horizontal origin */
362 		if ( fv->showhmetrics&fvm_origin )
363 		    GDrawDrawLine(pixmap,x0,i*fv->cbh+fv->lab_height+yorg-3,x0,
364 			    i*fv->cbh+fv->lab_height+yorg+2,METRICS_ORIGIN);
365 		x1 = x0 + fv->magnify*bdfc->width;
366 		if ( fv->showhmetrics&fvm_advanceat )
367 		    GDrawDrawLine(pixmap,x1,i*fv->cbh+fv->lab_height+1,x1,
368 			    (i+1)*fv->cbh-1,METRICS_ADVANCE);
369 		if ( fv->showhmetrics&fvm_advanceto )
370 		    GDrawDrawLine(pixmap,x0,(i+1)*fv->cbh-2,x1,
371 			    (i+1)*fv->cbh-2,METRICS_ADVANCE);
372 	    }
373 	    if ( fv->showvmetrics ) {
374 		int x0 = j*fv->cbw+(fv->cbw-1-fv->magnify*xwidth)/2- bdfc->xmin*fv->magnify
375 			+ fv->magnify*fv->show->pixelsize/2;
376 		int y0 = i*fv->cbh+fv->lab_height+yorg;
377 		int yvw = y0 + fv->magnify*sc->vwidth*fv->show->pixelsize/em;
378 		if ( fv->showvmetrics&fvm_baseline )
379 		    GDrawDrawLine(pixmap,x0,i*fv->cbh+fv->lab_height+1,x0,
380 			    (i+1)*fv->cbh-1,METRICS_BASELINE);
381 		if ( fv->showvmetrics&fvm_advanceat )
382 		    GDrawDrawLine(pixmap,j*fv->cbw,yvw,(j+1)*fv->cbw,
383 			    yvw,METRICS_ADVANCE);
384 		if ( fv->showvmetrics&fvm_advanceto )
385 		    GDrawDrawLine(pixmap,j*fv->cbw+2,y0,j*fv->cbw+2,
386 			    yvw,METRICS_ADVANCE);
387 		if ( fv->showvmetrics&fvm_origin )
388 		    GDrawDrawLine(pixmap,x0-3,i*fv->cbh+fv->lab_height+yorg,x0+2,i*fv->cbh+fv->lab_height+yorg,METRICS_ORIGIN);
389 	    }
390 	    GDrawPopClip(pixmap,&old2);
391 	    if ( !fv->show->piecemeal ) BDFCharFree( bdfc );
392 	}
393     }
394 }
395 
FVToggleCharSelected(FontView * fv,int enc)396 static void FVToggleCharSelected(FontView *fv,int enc) {
397     int i, j;
398 
399     if ( fv->v==NULL || fv->colcnt==0 )	/* Can happen in scripts */
400 return;
401 
402     i = enc / fv->colcnt;
403     j = enc - i*fv->colcnt;
404     i -= fv->rowoff;
405  /* Normally we should be checking against fv->rowcnt (rather than <=rowcnt) */
406  /*  but every now and then the WM forces us to use a window size which doesn't */
407  /*  fit our expectations (maximized view) and we must be prepared for half */
408  /*  lines */
409     if ( i>=0 && i<=fv->rowcnt )
410 	FVDrawGlyph(fv->v,fv,enc,true);
411 }
412 
FontViewRefreshAll(SplineFont * sf)413 static void FontViewRefreshAll(SplineFont *sf) {
414     FontView *fv;
415     for ( fv = (FontView *) (sf->fv); fv!=NULL; fv = (FontView *) (fv->b.nextsame) )
416 	if ( fv->v!=NULL )
417 	    GDrawRequestExpose(fv->v,NULL,false);
418 }
419 
FVDeselectAll(FontView * fv)420 void FVDeselectAll(FontView *fv) {
421     int i;
422 
423     for ( i=0; i<fv->b.map->enccount; ++i ) {
424 	if ( fv->b.selected[i] ) {
425 	    fv->b.selected[i] = false;
426 	    FVToggleCharSelected(fv,i);
427 	}
428     }
429     fv->sel_index = 0;
430 }
431 
FVInvertSelection(FontView * fv)432 static void FVInvertSelection(FontView *fv) {
433     int i;
434 
435     for ( i=0; i<fv->b.map->enccount; ++i ) {
436 	fv->b.selected[i] = !fv->b.selected[i];
437 	FVToggleCharSelected(fv,i);
438     }
439     fv->sel_index = 1;
440 }
441 
FVSelectAll(FontView * fv)442 static void FVSelectAll(FontView *fv) {
443     int i;
444 
445     for ( i=0; i<fv->b.map->enccount; ++i ) {
446 	if ( !fv->b.selected[i] ) {
447 	    fv->b.selected[i] = true;
448 	    FVToggleCharSelected(fv,i);
449 	}
450     }
451     fv->sel_index = 1;
452 }
453 
FVReselect(FontView * fv,int newpos)454 static void FVReselect(FontView *fv, int newpos) {
455     int i;
456 
457     if ( newpos<0 ) newpos = 0;
458     else if ( newpos>=fv->b.map->enccount ) newpos = fv->b.map->enccount-1;
459 
460     if ( fv->pressed_pos<fv->end_pos ) {
461 	if ( newpos>fv->end_pos ) {
462 	    for ( i=fv->end_pos+1; i<=newpos; ++i ) if ( !fv->b.selected[i] ) {
463 		fv->b.selected[i] = fv->sel_index;
464 		FVToggleCharSelected(fv,i);
465 	    }
466 	} else if ( newpos<fv->pressed_pos ) {
467 	    for ( i=fv->end_pos; i>fv->pressed_pos; --i ) if ( fv->b.selected[i] ) {
468 		fv->b.selected[i] = false;
469 		FVToggleCharSelected(fv,i);
470 	    }
471 	    for ( i=fv->pressed_pos-1; i>=newpos; --i ) if ( !fv->b.selected[i] ) {
472 		fv->b.selected[i] = fv->sel_index;
473 		FVToggleCharSelected(fv,i);
474 	    }
475 	} else {
476 	    for ( i=fv->end_pos; i>newpos; --i ) if ( fv->b.selected[i] ) {
477 		fv->b.selected[i] = false;
478 		FVToggleCharSelected(fv,i);
479 	    }
480 	}
481     } else {
482 	if ( newpos<fv->end_pos ) {
483 	    for ( i=fv->end_pos-1; i>=newpos; --i ) if ( !fv->b.selected[i] ) {
484 		fv->b.selected[i] = fv->sel_index;
485 		FVToggleCharSelected(fv,i);
486 	    }
487 	} else if ( newpos>fv->pressed_pos ) {
488 	    for ( i=fv->end_pos; i<fv->pressed_pos; ++i ) if ( fv->b.selected[i] ) {
489 		fv->b.selected[i] = false;
490 		FVToggleCharSelected(fv,i);
491 	    }
492 	    for ( i=fv->pressed_pos+1; i<=newpos; ++i ) if ( !fv->b.selected[i] ) {
493 		fv->b.selected[i] = fv->sel_index;
494 		FVToggleCharSelected(fv,i);
495 	    }
496 	} else {
497 	    for ( i=fv->end_pos; i<newpos; ++i ) if ( fv->b.selected[i] ) {
498 		fv->b.selected[i] = false;
499 		FVToggleCharSelected(fv,i);
500 	    }
501 	}
502     }
503     fv->end_pos = newpos;
504     if ( newpos>=0 && newpos<fv->b.map->enccount && (i = fv->b.map->map[newpos])!=-1 &&
505 	    fv->b.sf->glyphs[i]!=NULL &&
506 	    fv->b.sf->glyphs[i]->unicodeenc>=0 && fv->b.sf->glyphs[i]->unicodeenc<0x10000 )
507 	GInsCharSetChar(fv->b.sf->glyphs[i]->unicodeenc);
508 }
509 
FVFlattenAllBitmapSelections(FontView * fv)510 static void FVFlattenAllBitmapSelections(FontView *fv) {
511     BDFFont *bdf;
512     int i;
513 
514     for ( bdf = fv->b.sf->bitmaps; bdf!=NULL; bdf=bdf->next ) {
515 	for ( i=0; i<bdf->glyphcnt; ++i )
516 	    if ( bdf->glyphs[i]!=NULL && bdf->glyphs[i]->selection!=NULL )
517 		BCFlattenFloat(bdf->glyphs[i]);
518     }
519 }
520 
AskChanged(SplineFont * sf)521 static int AskChanged(SplineFont *sf) {
522     int ret;
523     char *buts[4];
524     char *filename, *fontname;
525 
526     if ( sf->cidmaster!=NULL )
527 	sf = sf->cidmaster;
528 
529     filename = sf->filename;
530     fontname = sf->fontname;
531 
532     if ( filename==NULL && sf->origname!=NULL &&
533 	    sf->onlybitmaps && sf->bitmaps!=NULL && sf->bitmaps->next==NULL )
534 	filename = sf->origname;
535     if ( filename==NULL ) filename = "untitled.sfd";
536     filename = GFileNameTail(filename);
537     buts[0] = _("_Save");
538     buts[1] = _("_Don't Save");
539     buts[2] = _("_Cancel");
540     buts[3] = NULL;
541     ret = gwwv_ask( _("Font changed"),(const char **) buts,0,2,_("Font %1$.40s in file %2$.40s has been changed.\nDo you want to save it?"),fontname,filename);
542 return( ret );
543 }
544 
AskScriptChanged()545 static int AskScriptChanged() {
546     int ret;
547     char *buts[4];
548 
549     buts[0] = _("_Yes");
550     buts[1] = _("Yes, and don't _remind me again");
551     buts[2] = _("_No");
552     buts[3] = NULL;
553     ret = gwwv_ask( _("Unsaved script"),(const char **) buts,0,2,_("You have an unsaved script in the «Execute Script» dialog. Do you intend to discard it?"));
554     if (ret == 1) {
555         warn_script_unsaved = 0;
556         SavePrefs(true);
557     }
558 return( ret );
559 }
560 
_FVMenuGenerate(FontView * fv,int family)561 int _FVMenuGenerate(FontView *fv,int family) {
562     FVFlattenAllBitmapSelections(fv);
563 return( SFGenerateFont(fv->b.sf,fv->b.active_layer,family,fv->b.normal==NULL?fv->b.map:fv->b.normal) );
564 }
565 
FVMenuGenerate(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))566 static void FVMenuGenerate(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
567     FontView *fv = (FontView *) GDrawGetUserData(gw);
568 
569     _FVMenuGenerate(fv,gf_none);
570 }
571 
FVMenuGenerateFamily(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))572 static void FVMenuGenerateFamily(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
573     FontView *fv = (FontView *) GDrawGetUserData(gw);
574 
575     _FVMenuGenerate(fv,gf_macfamily);
576 }
577 
FVMenuGenerateTTC(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))578 static void FVMenuGenerateTTC(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
579     FontView *fv = (FontView *) GDrawGetUserData(gw);
580 
581     _FVMenuGenerate(fv,gf_ttc);
582 }
583 
584 extern int save_to_dir;
585 
SaveAs_FormatChange(GGadget * g,GEvent * e)586 static int SaveAs_FormatChange(GGadget *g, GEvent *e) {
587     if ( e->type==et_controlevent && e->u.control.subtype == et_radiochanged ) {
588 	GGadget *fc = GWidgetGetControl(GGadgetGetWindow(g),1000);
589 	char *oldname = GGadgetGetTitle8(fc);
590 	int *_s2d = GGadgetGetUserData(g);
591 	int s2d = GGadgetIsChecked(g);
592 	char *pt, *newname = malloc(strlen(oldname)+8);
593 	strcpy(newname,oldname);
594 	pt = strrchr(newname,'.');
595 	if ( pt==NULL )
596 	    pt = newname+strlen(newname);
597 	strcpy(pt,s2d ? ".sfdir" : ".sfd" );
598 	GGadgetSetTitle8(fc,newname);
599 	save_to_dir = *_s2d = s2d;
600 	SavePrefs(true);
601     }
602 return( true );
603 }
604 
605 
_FVSaveAsFilterFunc(GGadget * g,struct gdirentry * ent,const unichar_t * dir)606 static enum fchooserret _FVSaveAsFilterFunc(GGadget *g,struct gdirentry *ent, const unichar_t *dir)
607 {
608     char* n = u_to_c(ent->name);
609     int ew = endswithi( n, "sfd" ) || endswithi( n, "sfdir" );
610     if( ew )
611 	return fc_show;
612     if( ent->isdir )
613 	return fc_show;
614     return fc_hide;
615 }
616 
617 
_FVMenuSaveAs(FontView * fv)618 int _FVMenuSaveAs(FontView *fv) {
619     char *temp;
620     char *ret;
621     char *filename;
622     int ok;
623     int s2d = fv->b.cidmaster!=NULL ? fv->b.cidmaster->save_to_dir :
624 		fv->b.sf->mm!=NULL ? fv->b.sf->mm->normal->save_to_dir :
625 		fv->b.sf->save_to_dir;
626     GGadgetCreateData gcd;
627     GTextInfo label;
628 
629     if ( fv->b.cidmaster!=NULL && fv->b.cidmaster->filename!=NULL )
630 	temp=def2utf8_copy(fv->b.cidmaster->filename);
631     else if ( fv->b.sf->mm!=NULL && fv->b.sf->mm->normal->filename!=NULL )
632 	temp=def2utf8_copy(fv->b.sf->mm->normal->filename);
633     else if ( fv->b.sf->filename!=NULL )
634 	temp=def2utf8_copy(fv->b.sf->filename);
635     else {
636 	SplineFont *sf = fv->b.cidmaster?fv->b.cidmaster:
637 		fv->b.sf->mm!=NULL?fv->b.sf->mm->normal:fv->b.sf;
638 	char *fn = sf->defbasefilename ? sf->defbasefilename : sf->fontname;
639 	temp = malloc((strlen(fn)+10));
640 	strcpy(temp,fn);
641 	if ( sf->defbasefilename!=NULL )
642 	    /* Don't add a default suffix, they've already told us what name to use */;
643 	else if ( fv->b.cidmaster!=NULL )
644 	    strcat(temp,"CID");
645 	else if ( sf->mm==NULL )
646 	    ;
647 	else if ( sf->mm->apple )
648 	    strcat(temp,"Var");
649 	else
650 	    strcat(temp,"MM");
651 	strcat(temp,save_to_dir ? ".sfdir" : ".sfd");
652 	s2d = save_to_dir;
653     }
654 
655     memset(&gcd,0,sizeof(gcd));
656     memset(&label,0,sizeof(label));
657     gcd.gd.flags = s2d ? (gg_visible | gg_enabled | gg_cb_on) : (gg_visible | gg_enabled);
658     label.text = (unichar_t *) _("Save as _Directory");
659     label.text_is_1byte = true;
660     label.text_in_resource = true;
661     gcd.gd.label = &label;
662     gcd.gd.handle_controlevent = SaveAs_FormatChange;
663     gcd.data = &s2d;
664     gcd.creator = GCheckBoxCreate;
665 
666     GFileChooserInputFilenameFuncType FilenameFunc = GFileChooserDefInputFilenameFunc;
667 
668 #if defined(__MINGW32__)
669     //
670     // If they are "saving as" but there is no path, lets help
671     // the poor user by starting someplace sane rather than in `pwd`
672     //
673     if( !GFileIsAbsolute(temp) )
674     {
675     	char* defaultSaveDir = GFileGetHomeDocumentsDir();
676 //	printf("save-as:%s\n", temp );
677     	char* temp2 = GFileAppendFile( defaultSaveDir, temp, 0 );
678     	free(temp);
679     	temp = temp2;
680     }
681 #endif
682 
683     ret = GWidgetSaveAsFileWithGadget8(_("Save as..."),temp,0,NULL,
684 				       _FVSaveAsFilterFunc, FilenameFunc,
685 				       &gcd );
686     free(temp);
687     if ( ret==NULL )
688 return( 0 );
689     filename = utf82def_copy(ret);
690     free(ret);
691 
692     if(!(endswithi( filename, ".sfdir") || endswithi( filename, ".sfd")))
693     {
694 	// they forgot the extension, so we force the default of .sfd
695 	// and alert them to the fact that we have done this and we
696 	// are not saving to a OTF, TTF, UFO formatted file
697 
698 	char* extension = ".sfd";
699 	char* newpath = copyn( filename, strlen(filename) + strlen(".sfd") + 1 );
700 	strcat( newpath, ".sfd" );
701 
702 	char* oldfn = GFileNameTail( filename );
703 	char* newfn = GFileNameTail( newpath );
704 
705 	LogError( _("You tried to save with the filename %s but it was saved as %s. "),
706 		  oldfn, newfn );
707 	LogError( _("Please choose File/Generate Fonts to save to other formats."));
708 
709 	free(filename);
710 	filename = newpath;
711     }
712 
713     FVFlattenAllBitmapSelections(fv);
714     fv->b.sf->compression = 0;
715     ok = SFDWrite(filename,fv->b.sf,fv->b.map,fv->b.normal,s2d);
716     if ( ok ) {
717 	SplineFont *sf = fv->b.cidmaster?fv->b.cidmaster:fv->b.sf->mm!=NULL?fv->b.sf->mm->normal:fv->b.sf;
718 	free(sf->filename);
719 	sf->filename = filename;
720 	sf->save_to_dir = s2d;
721 	free(sf->origname);
722 	sf->origname = copy(filename);
723 	sf->new = false;
724 	if ( sf->mm!=NULL ) {
725 	    int i;
726 	    for ( i=0; i<sf->mm->instance_count; ++i ) {
727 		free(sf->mm->instances[i]->filename);
728 		sf->mm->instances[i]->filename = filename;
729 		free(sf->mm->instances[i]->origname);
730 		sf->mm->instances[i]->origname = copy(filename);
731 		sf->mm->instances[i]->new = false;
732 	    }
733 	}
734 	SplineFontSetUnChanged(sf);
735 	FVSetTitles(fv->b.sf);
736     } else {
737 	ff_post_error(_("Save Failed"),_("Save Failed"));
738 	free(filename);
739     }
740 return( ok );
741 }
742 
FVMenuSaveAs(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))743 static void FVMenuSaveAs(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
744     FontView *fv = (FontView *) GDrawGetUserData(gw);
745 
746     _FVMenuSaveAs(fv);
747 }
748 
IsBackupName(char * filename)749 static int IsBackupName(char *filename) {
750 
751     if ( filename==NULL )
752 return( false );
753 return( filename[strlen(filename)-1]=='~' );
754 }
755 
_FVMenuSave(FontView * fv)756 int _FVMenuSave(FontView *fv) {
757     int ret = 0;
758     SplineFont *sf = fv->b.cidmaster?fv->b.cidmaster:
759 		    fv->b.sf->mm!=NULL?fv->b.sf->mm->normal:
760 			    fv->b.sf;
761 
762     if ( sf->filename==NULL || IsBackupName(sf->filename))
763 	ret = _FVMenuSaveAs(fv);
764     else {
765 	FVFlattenAllBitmapSelections(fv);
766 	if ( !SFDWriteBak(sf->filename,sf,fv->b.map,fv->b.normal) )
767 	    ff_post_error(_("Save Failed"),_("Save Failed"));
768 	else {
769 	    SplineFontSetUnChanged(sf);
770 	    ret = true;
771 	}
772     }
773 return( ret );
774 }
775 
FVMenuSave(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))776 static void FVMenuSave(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
777     FontView *fv = (FontView *) GDrawGetUserData(gw);
778     _FVMenuSave(fv);
779 }
780 
_FVCloseWindows(FontView * fv)781 void _FVCloseWindows(FontView *fv) {
782     int i, j;
783     BDFFont *bdf;
784     MetricsView *mv, *mnext;
785     SplineFont *sf = fv->b.cidmaster?fv->b.cidmaster:fv->b.sf->mm!=NULL?fv->b.sf->mm->normal : fv->b.sf;
786 
787     PrintWindowClose();
788     if ( fv->b.nextsame==NULL && fv->b.sf->fv==&fv->b && fv->b.sf->kcld!=NULL )
789 	KCLD_End(fv->b.sf->kcld);
790     if ( fv->b.nextsame==NULL && fv->b.sf->fv==&fv->b && fv->b.sf->vkcld!=NULL )
791 	KCLD_End(fv->b.sf->vkcld);
792 
793     for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL ) {
794 	CharView *cv, *next;
795 	for ( cv = (CharView *) (sf->glyphs[i]->views); cv!=NULL; cv = next ) {
796 	    next = (CharView *) (cv->b.next);
797 	    GDrawDestroyWindow(cv->gw);
798 	}
799 	if ( sf->glyphs[i]->charinfo )
800 	    CharInfoDestroy(sf->glyphs[i]->charinfo);
801     }
802     if ( sf->mm!=NULL ) {
803 	MMSet *mm = sf->mm;
804 	for ( j=0; j<mm->instance_count; ++j ) {
805 	    SplineFont *sf = mm->instances[j];
806 	    for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL ) {
807 		CharView *cv, *next;
808 		for ( cv = (CharView *) (sf->glyphs[i]->views); cv!=NULL; cv = next ) {
809 		    next = (CharView *) (cv->b.next);
810 		    GDrawDestroyWindow(cv->gw);
811 		}
812 		if ( sf->glyphs[i]->charinfo )
813 		    CharInfoDestroy(sf->glyphs[i]->charinfo);
814 	    }
815 	    for ( mv=sf->metrics; mv!=NULL; mv = mnext ) {
816 		mnext = mv->next;
817 		GDrawDestroyWindow(mv->gw);
818 	    }
819 	}
820     } else if ( sf->subfontcnt!=0 ) {
821 	for ( j=0; j<sf->subfontcnt; ++j ) {
822 	    for ( i=0; i<sf->subfonts[j]->glyphcnt; ++i ) if ( sf->subfonts[j]->glyphs[i]!=NULL ) {
823 		CharView *cv, *next;
824 		for ( cv = (CharView *) (sf->subfonts[j]->glyphs[i]->views); cv!=NULL; cv = next ) {
825 		    next = (CharView *) (cv->b.next);
826 		    GDrawDestroyWindow(cv->gw);
827 		if ( sf->subfonts[j]->glyphs[i]->charinfo )
828 		    CharInfoDestroy(sf->subfonts[j]->glyphs[i]->charinfo);
829 		}
830 	    }
831 	    for ( mv=sf->subfonts[j]->metrics; mv!=NULL; mv = mnext ) {
832 		mnext = mv->next;
833 		GDrawDestroyWindow(mv->gw);
834 	    }
835 	}
836     } else {
837 	for ( mv=sf->metrics; mv!=NULL; mv = mnext ) {
838 	    mnext = mv->next;
839 	    GDrawDestroyWindow(mv->gw);
840 	}
841     }
842     for ( bdf = sf->bitmaps; bdf!=NULL; bdf=bdf->next ) {
843 	for ( i=0; i<bdf->glyphcnt; ++i ) if ( bdf->glyphs[i]!=NULL ) {
844 	    BitmapView *bv, *next;
845 	    for ( bv = bdf->glyphs[i]->views; bv!=NULL; bv = next ) {
846 		next = bv->next;
847 		GDrawDestroyWindow(bv->gw);
848 	    }
849 	}
850     }
851     if ( fv->b.sf->fontinfo!=NULL )
852 	FontInfoDestroy(fv->b.sf);
853     if ( fv->b.sf->valwin!=NULL )
854 	ValidationDestroy(fv->b.sf);
855     SVDetachFV(fv);
856 }
857 
SFAnyChanged(SplineFont * sf)858 static int SFAnyChanged(SplineFont *sf) {
859     if ( sf->mm!=NULL ) {
860 	MMSet *mm = sf->mm;
861 	int i;
862 	if ( mm->changed )
863 return( true );
864 	for ( i=0; i<mm->instance_count; ++i )
865 	    if ( sf->mm->instances[i]->changed )
866 return( true );
867 	/* Changes to the blended font aren't real (for adobe fonts) */
868 	if ( mm->apple && mm->normal->changed )
869 return( true );
870 
871 return( false );
872     } else
873 return( sf->changed );
874 }
875 
_FVMenuClose(FontView * fv)876 static int _FVMenuClose(FontView *fv) {
877     int i;
878     SplineFont *sf = fv->b.cidmaster?fv->b.cidmaster:fv->b.sf;
879 
880     if ( !SFCloseAllInstrs(fv->b.sf) )
881 return( false );
882 
883     if ( fv->b.nextsame!=NULL || fv->b.sf->fv!=&fv->b ) {
884 	/* There's another view, can close this one with no problems */
885     } else if ( warn_script_unsaved && fv->script_unsaved &&
886                 AskScriptChanged()==2 ) {
887         return false;
888     } else if ( SFAnyChanged(sf) ) {
889 	i = AskChanged(fv->b.sf);
890 	if ( i==2 )	/* Cancel */
891 return( false );
892 	if ( i==0 && !_FVMenuSave(fv))		/* Save */
893 return(false);
894 	else
895 	    SFClearAutoSave(sf);		/* if they didn't save it, remove change record */
896     }
897     _FVCloseWindows(fv);
898     if ( sf->filename!=NULL )
899 	RecentFilesRemember(sf->filename);
900     else if ( sf->origname!=NULL )
901 	RecentFilesRemember(sf->origname);
902     GDrawDestroyWindow(fv->gw);
903 return( true );
904 }
905 
MenuNew(GWindow UNUSED (gw),struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))906 void MenuNew(GWindow UNUSED(gw), struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
907     FontNew();
908 }
909 
FVMenuClose(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))910 static void FVMenuClose(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
911     FontView *fv = (FontView *) GDrawGetUserData(gw);
912 
913     if ( fv->b.container )
914 	(fv->b.container->funcs->doClose)(fv->b.container);
915     else
916 	_FVMenuClose(fv);
917 }
918 
FV_ReattachCVs(SplineFont * old,SplineFont * new)919 static void FV_ReattachCVs(SplineFont *old,SplineFont *new) {
920     int i, j, pos;
921     CharView *cv, *cvnext;
922     SplineFont *sub;
923 
924     for ( i=0; i<old->glyphcnt; ++i ) {
925 	if ( old->glyphs[i]!=NULL && old->glyphs[i]->views!=NULL ) {
926 	    if ( new->subfontcnt==0 ) {
927 		pos = SFFindExistingSlot(new,old->glyphs[i]->unicodeenc,old->glyphs[i]->name);
928 		sub = new;
929 	    } else {
930 		pos = -1;
931 		for ( j=0; j<new->subfontcnt && pos==-1 ; ++j ) {
932 		    sub = new->subfonts[j];
933 		    pos = SFFindExistingSlot(sub,old->glyphs[i]->unicodeenc,old->glyphs[i]->name);
934 		}
935 	    }
936 	    if ( pos==-1 ) {
937 		for ( cv=(CharView *) (old->glyphs[i]->views); cv!=NULL; cv = cvnext ) {
938 		    cvnext = (CharView *) (cv->b.next);
939 		    GDrawDestroyWindow(cv->gw);
940 		}
941 	    } else {
942 		for ( cv=(CharView *) (old->glyphs[i]->views); cv!=NULL; cv = cvnext ) {
943 		    cvnext = (CharView *) (cv->b.next);
944 		    CVChangeSC(cv,sub->glyphs[pos]);
945 		    cv->b.layerheads[dm_grid] = &new->grid;
946 		}
947 	    }
948 	    GDrawProcessPendingEvents(NULL);		/* Don't want to many destroy_notify events clogging up the queue */
949 	}
950     }
951 }
952 
FVMenuRevert(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))953 static void FVMenuRevert(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
954     FontViewBase *fv = (FontViewBase *) GDrawGetUserData(gw);
955     FVRevert(fv);
956 }
957 
FVMenuRevertBackup(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))958 static void FVMenuRevertBackup(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
959     FontViewBase *fv = (FontViewBase *) GDrawGetUserData(gw);
960     FVRevertBackup(fv);
961 }
962 
FVMenuRevertGlyph(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))963 static void FVMenuRevertGlyph(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
964     FontView *fv = (FontView *) GDrawGetUserData(gw);
965     FVRevertGlyph((FontViewBase *) fv);
966 }
967 
FVMenuClearSpecialData(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))968 static void FVMenuClearSpecialData(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
969     FontView *fv = (FontView *) GDrawGetUserData(gw);
970     FVClearSpecialData((FontViewBase *) fv);
971 }
972 
MenuPrefs(GWindow UNUSED (base),struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))973 void MenuPrefs(GWindow UNUSED(base), struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
974     DoPrefs();
975 }
976 
MenuXRes(GWindow UNUSED (base),struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))977 void MenuXRes(GWindow UNUSED(base), struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
978     DoXRes();
979 }
980 
MenuSaveAll(GWindow UNUSED (base),struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))981 void MenuSaveAll(GWindow UNUSED(base), struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
982     FontView *fv;
983 
984     for ( fv = fv_list; fv!=NULL; fv = (FontView *) (fv->b.next) ) {
985 	if ( SFAnyChanged(fv->b.sf) && !_FVMenuSave(fv))
986 return;
987     }
988 }
989 
_MenuExit(void * UNUSED (junk))990 static void _MenuExit(void *UNUSED(junk)) {
991 
992     FontView *fv, *next;
993 
994 #ifndef _NO_PYTHON
995     python_call_onClosingFunctions();
996 #endif
997 
998     LastFonts_Save();
999     for ( fv = fv_list; fv!=NULL; fv = next )
1000     {
1001 	next = (FontView *) (fv->b.next);
1002 	if ( !_FVMenuClose(fv))
1003 	    return;
1004 	if ( fv->b.nextsame!=NULL || fv->b.sf->fv!=&fv->b )
1005 	{
1006 	    GDrawSync(NULL);
1007 	    GDrawProcessPendingEvents(NULL);
1008 	}
1009     }
1010     GDrawSync(NULL);
1011     GDrawProcessPendingEvents(NULL);
1012     exit(0);
1013 }
1014 
FVMenuExit(GWindow UNUSED (base),struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))1015 static void FVMenuExit(GWindow UNUSED(base), struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
1016     _MenuExit(NULL);
1017 }
1018 
MenuExit(GWindow UNUSED (base),struct gmenuitem * UNUSED (mi),GEvent * e)1019 void MenuExit(GWindow UNUSED(base), struct gmenuitem *UNUSED(mi), GEvent *e) {
1020     if ( e==NULL )	/* Not from the menu directly, but a shortcut */
1021 	_MenuExit(NULL);
1022     else
1023 	DelayEvent(_MenuExit,NULL);
1024 }
1025 
MergeKernInfo(SplineFont * sf,EncMap * map)1026 void MergeKernInfo(SplineFont *sf,EncMap *map) {
1027 #ifndef __Mac
1028     static char wild[] = "*.{afm,tfm,ofm,pfm,bin,hqx,dfont,feature,feat,fea}";
1029     static char wild2[] = "*.{afm,amfm,tfm,ofm,pfm,bin,hqx,dfont,feature,feat,fea}";
1030 #else
1031     static char wild[] = "*";	/* Mac resource files generally don't have extensions */
1032     static char wild2[] = "*";
1033 #endif
1034     char *ret = gwwv_open_filename(_("Merge Feature Info"),NULL,
1035 	    sf->mm!=NULL?wild2:wild,NULL);
1036     char *temp;
1037 
1038     if ( ret==NULL )
1039 return;				/* Cancelled */
1040     temp = utf82def_copy(ret);
1041 
1042     if ( !LoadKerningDataFromMetricsFile(sf,temp,map))
1043 	ff_post_error(_("Load of Kerning Metrics Failed"),_("Failed to load kern data from %s"), temp);
1044     free(ret); free(temp);
1045 }
1046 
FVMenuMergeKern(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))1047 static void FVMenuMergeKern(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
1048     FontView *fv = (FontView *) GDrawGetUserData(gw);
1049     MergeKernInfo(fv->b.sf,fv->b.map);
1050 }
1051 
_FVMenuOpen(FontView * fv)1052 void _FVMenuOpen(FontView *fv) {
1053     char *temp;
1054     char *eod, *fpt, *file, *full;
1055     FontView *test; int fvcnt, fvtest;
1056 
1057     char* OpenDir = NULL, *DefaultDir = NULL, *NewDir = NULL;
1058 #if defined(__MINGW32__)
1059     DefaultDir = copy(GFileGetHomeDocumentsDir()); //Default value
1060     if (fv && fv->b.sf && fv->b.sf->filename) {
1061         free(DefaultDir);
1062         DefaultDir = GFileDirNameEx(fv->b.sf->filename, true);
1063     }
1064 #endif
1065 
1066     for ( fvcnt=0, test=fv_list; test!=NULL; ++fvcnt, test=(FontView *) (test->b.next) );
1067     do {
1068         if (NewDir != NULL) {
1069             if (OpenDir != DefaultDir) {
1070                 free(OpenDir);
1071             }
1072 
1073             OpenDir = NewDir;
1074             NewDir = NULL;
1075         } else if (OpenDir != DefaultDir) {
1076             free(OpenDir);
1077             OpenDir = DefaultDir;
1078         }
1079 
1080         temp = GetPostScriptFontName(OpenDir,true,fv != NULL);
1081         if ( temp==NULL )
1082             return;
1083 
1084         //Make a copy of the folder; may be needed later if opening fails.
1085         NewDir = GFileDirName(temp);
1086         if (!GFileExists(NewDir)) {
1087             free(NewDir);
1088             NewDir = NULL;
1089         }
1090 
1091         eod = strrchr(temp,'/');
1092         if (eod != NULL) {
1093             *eod = '\0';
1094             file = eod+1;
1095 
1096             if (*file) {
1097                 do {
1098                     fpt = strstr(file,"; ");
1099                     if ( fpt!=NULL ) *fpt = '\0';
1100                     full = malloc(strlen(temp)+1+strlen(file)+1);
1101                     strcpy(full,temp); strcat(full,"/"); strcat(full,file);
1102                     ViewPostScriptFont(full,0);
1103                     file = fpt+2;
1104                     free(full);
1105                 } while ( fpt!=NULL );
1106             }
1107         }
1108         free(temp);
1109         for ( fvtest=0, test=fv_list; test!=NULL; ++fvtest, test=(FontView *) (test->b.next) );
1110     } while ( fvtest==fvcnt );	/* did the load fail for some reason? try again */
1111 
1112     free( NewDir );
1113     free( OpenDir );
1114     if (OpenDir != DefaultDir) {
1115         free( DefaultDir );
1116     }
1117 }
1118 
FVMenuOpen(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))1119 static void FVMenuOpen(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
1120     FontView *fv = (FontView*) GDrawGetUserData(gw);
1121     _FVMenuOpen(fv);
1122 }
1123 
FVMenuContextualHelp(GWindow UNUSED (base),struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))1124 static void FVMenuContextualHelp(GWindow UNUSED(base), struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
1125     help("ui/mainviews/fontview.html", NULL);
1126 }
1127 
MenuHelp(GWindow UNUSED (base),struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))1128 void MenuHelp(GWindow UNUSED(base), struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
1129     help("index.html", NULL);
1130 }
1131 
MenuIndex(GWindow UNUSED (base),struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))1132 void MenuIndex(GWindow UNUSED(base), struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
1133     help("index.html", NULL);
1134 }
1135 
MenuLicense(GWindow UNUSED (base),struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))1136 void MenuLicense(GWindow UNUSED(base), struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
1137     help("https://github.com/fontforge/fontforge/blob/master/LICENSE", NULL);
1138 }
1139 
MenuAbout(GWindow UNUSED (base),struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))1140 void MenuAbout(GWindow UNUSED(base), struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
1141     ShowAboutScreen();
1142 }
1143 
FVMenuImport(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))1144 static void FVMenuImport(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
1145     FontView *fv = (FontView *) GDrawGetUserData(gw);
1146     int empty = fv->b.sf->onlybitmaps && fv->b.sf->bitmaps==NULL;
1147     BDFFont *bdf;
1148     FVImport(fv);
1149     if ( empty && fv->b.sf->bitmaps!=NULL ) {
1150 	for ( bdf= fv->b.sf->bitmaps; bdf->next!=NULL; bdf = bdf->next );
1151 	FVChangeDisplayBitmap((FontViewBase *) fv,bdf);
1152     }
1153 }
1154 
FVSelCount(FontView * fv)1155 static int FVSelCount(FontView *fv) {
1156     int i, cnt=0;
1157 
1158     for ( i=0; i<fv->b.map->enccount; ++i )
1159 	if ( fv->b.selected[i] ) ++cnt;
1160     if ( cnt>10 ) {
1161 	char *buts[3];
1162 	buts[0] = _("_OK");
1163 	buts[1] = _("_Cancel");
1164 	buts[2] = NULL;
1165 	if ( gwwv_ask(_("Many Windows"),(const char **) buts,0,1,_("This involves opening more than 10 windows.\nIs that really what you want?"))==1 )
1166 return( false );
1167     }
1168 return( true );
1169 }
1170 
FVMenuOpenOutline(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))1171 static void FVMenuOpenOutline(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
1172     FontView *fv = (FontView *) GDrawGetUserData(gw);
1173     int i;
1174     SplineChar *sc;
1175 
1176     if ( !FVSelCount(fv))
1177 return;
1178     if ( fv->b.container!=NULL && fv->b.container->funcs->is_modal )
1179 return;
1180 
1181     for ( i=0; i<fv->b.map->enccount; ++i )
1182 	if ( fv->b.selected[i] ) {
1183 	    sc = FVMakeChar(fv,i);
1184 	    CharViewCreate(sc,fv,i);
1185 	}
1186 }
1187 
FVMenuOpenBitmap(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))1188 static void FVMenuOpenBitmap(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
1189     FontView *fv = (FontView *) GDrawGetUserData(gw);
1190     int i;
1191     SplineChar *sc;
1192 
1193     if ( fv->b.cidmaster==NULL ? (fv->b.sf->bitmaps==NULL) : (fv->b.cidmaster->bitmaps==NULL) )
1194 return;
1195     if ( fv->b.container!=NULL && fv->b.container->funcs->is_modal )
1196 return;
1197     if ( !FVSelCount(fv))
1198 return;
1199     for ( i=0; i<fv->b.map->enccount; ++i )
1200 	if ( fv->b.selected[i] ) {
1201 	    sc = FVMakeChar(fv,i);
1202 	    if ( sc!=NULL )
1203 		BitmapViewCreatePick(i,fv);
1204 	}
1205 }
1206 
_MenuWarnings(GWindow UNUSED (gw),struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))1207 void _MenuWarnings(GWindow UNUSED(gw), struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
1208     ShowErrorWindow();
1209 }
1210 
FVMenuOpenMetrics(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))1211 static void FVMenuOpenMetrics(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
1212     FontView *fv = (FontView *) GDrawGetUserData(gw);
1213     if ( fv->b.container!=NULL && fv->b.container->funcs->is_modal )
1214 return;
1215     MetricsViewCreate(fv,NULL,fv->filled==fv->show?NULL:fv->show);
1216 }
1217 
FVMenuPrint(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))1218 static void FVMenuPrint(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
1219     FontView *fv = (FontView *) GDrawGetUserData(gw);
1220 
1221     if ( fv->b.container!=NULL && fv->b.container->funcs->is_modal )
1222 return;
1223     PrintFFDlg(fv,NULL,NULL);
1224 }
1225 
1226 #if !defined(_NO_FFSCRIPT) || !defined(_NO_PYTHON)
FVMenuExecute(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))1227 static void FVMenuExecute(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
1228     FontView *fv = (FontView *) GDrawGetUserData(gw);
1229 
1230     ScriptDlg(fv,NULL);
1231 }
1232 #endif
1233 
FVMenuFontInfo(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))1234 static void FVMenuFontInfo(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
1235     FontView *fv = (FontView *) GDrawGetUserData(gw);
1236     if ( fv->b.container!=NULL && fv->b.container->funcs->is_modal )
1237 return;
1238     FontMenuFontInfo(fv);
1239 }
1240 
FVMenuMATHInfo(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))1241 static void FVMenuMATHInfo(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
1242     FontView *fv = (FontView *) GDrawGetUserData(gw);
1243     SFMathDlg(fv->b.sf,fv->b.active_layer);
1244 }
1245 
FVMenuFindProblems(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))1246 static void FVMenuFindProblems(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
1247     FontView *fv = (FontView *) GDrawGetUserData(gw);
1248     FindProblems(fv,NULL,NULL);
1249 }
1250 
FVMenuValidate(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))1251 static void FVMenuValidate(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
1252     FontView *fv = (FontView *) GDrawGetUserData(gw);
1253     SFValidationWindow(fv->b.sf,fv->b.active_layer,ff_none);
1254 }
1255 
FVMenuSetExtremumBound(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))1256 static void FVMenuSetExtremumBound(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
1257     FontView *fv = (FontView *) GDrawGetUserData(gw);
1258     char buffer[40], *end, *ret;
1259     int val;
1260 
1261     sprintf( buffer, "%d", fv->b.sf->extrema_bound<=0 ?
1262 	    (int) rint((fv->b.sf->ascent+fv->b.sf->descent)/100.0) :
1263 	    fv->b.sf->extrema_bound );
1264     ret = gwwv_ask_string(_("Extremum bound..."),buffer,_("Adobe says that \"big\" splines should not have extrema.\nBut they don't define what big means.\nIf the distance between the spline's end-points is bigger than this value, then the spline is \"big\" to fontforge."));
1265     if ( ret==NULL )
1266 return;
1267     val = (int) rint(strtod(ret,&end));
1268     if ( *end!='\0' )
1269 	ff_post_error( _("Bad Number"),_("Bad Number") );
1270     else {
1271 	fv->b.sf->extrema_bound = val;
1272 	if ( !fv->b.sf->changed ) {
1273 	    fv->b.sf->changed = true;
1274 	    FVSetTitles(fv->b.sf);
1275 	}
1276     }
1277     free(ret);
1278 }
1279 
FVMenuEmbolden(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))1280 static void FVMenuEmbolden(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
1281     FontView *fv = (FontView *) GDrawGetUserData(gw);
1282     EmboldenDlg(fv,NULL);
1283 }
1284 
FVMenuItalic(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))1285 static void FVMenuItalic(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
1286     FontView *fv = (FontView *) GDrawGetUserData(gw);
1287     ItalicDlg(fv,NULL);
1288 }
1289 
FVMenuSmallCaps(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))1290 static void FVMenuSmallCaps(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
1291     FontView *fv = (FontView *) GDrawGetUserData(gw);
1292     GlyphChangeDlg(fv,NULL,gc_smallcaps);
1293 }
1294 
FVMenuChangeXHeight(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))1295 static void FVMenuChangeXHeight(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
1296     FontView *fv = (FontView *) GDrawGetUserData(gw);
1297     ChangeXHeightDlg(fv,NULL);
1298 }
1299 
FVMenuChangeGlyph(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))1300 static void FVMenuChangeGlyph(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
1301     FontView *fv = (FontView *) GDrawGetUserData(gw);
1302     GlyphChangeDlg(fv,NULL,gc_generic);
1303 }
1304 
FVMenuSubSup(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))1305 static void FVMenuSubSup(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
1306     FontView *fv = (FontView *) GDrawGetUserData(gw);
1307     GlyphChangeDlg(fv,NULL,gc_subsuper);
1308 }
1309 
FVMenuOblique(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))1310 static void FVMenuOblique(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
1311     FontView *fv = (FontView *) GDrawGetUserData(gw);
1312     ObliqueDlg(fv,NULL);
1313 }
1314 
FVMenuCondense(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))1315 static void FVMenuCondense(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
1316     FontView *fv = (FontView *) GDrawGetUserData(gw);
1317     CondenseExtendDlg(fv,NULL);
1318 }
1319 
1320 #define MID_24	2001
1321 #define MID_36	2002
1322 #define MID_48	2004
1323 #define MID_72	2014
1324 #define MID_96	2015
1325 #define MID_128	2018
1326 #define MID_AntiAlias	2005
1327 #define MID_Next	2006
1328 #define MID_Prev	2007
1329 #define MID_NextDef	2012
1330 #define MID_PrevDef	2013
1331 #define MID_ShowHMetrics 2016
1332 #define MID_ShowVMetrics 2017
1333 #define MID_Ligatures	2020
1334 #define MID_KernPairs	2021
1335 #define MID_AnchorPairs	2022
1336 #define MID_FitToBbox	2023
1337 #define MID_DisplaySubs	2024
1338 #define MID_32x8	2025
1339 #define MID_16x4	2026
1340 #define MID_8x2		2027
1341 #define MID_BitmapMag	2028
1342 #define MID_Layers	2029
1343 #define MID_FontInfo	2200
1344 #define MID_CharInfo	2201
1345 #define MID_Transform	2202
1346 #define MID_Stroke	2203
1347 #define MID_RmOverlap	2204
1348 #define MID_Simplify	2205
1349 #define MID_Correct	2206
1350 #define MID_BuildAccent	2208
1351 #define MID_AvailBitmaps	2210
1352 #define MID_RegenBitmaps	2211
1353 #define MID_Autotrace	2212
1354 #define MID_Round	2213
1355 #define MID_MergeFonts	2214
1356 #define MID_InterpolateFonts	2215
1357 #define MID_FindProblems 2216
1358 #define MID_Embolden	2217
1359 #define MID_Condense	2218
1360 #define MID_ShowDependentRefs	2222
1361 #define MID_AddExtrema	2224
1362 #define MID_CleanupGlyph	2225
1363 #define MID_TilePath	2226
1364 #define MID_BuildComposite	2227
1365 #define MID_NLTransform	2228
1366 #define MID_Intersection	2229
1367 #define MID_FindInter	2230
1368 #define MID_Styles	2231
1369 #define MID_SimplifyMore	2233
1370 #define MID_ShowDependentSubs	2234
1371 #define MID_DefaultATT	2235
1372 #define MID_POV		2236
1373 #define MID_BuildDuplicates	2237
1374 #define MID_StrikeInfo	2238
1375 #define MID_FontCompare	2239
1376 #define MID_CanonicalStart	2242
1377 #define MID_CanonicalContours	2243
1378 #define MID_RemoveBitmaps	2244
1379 #define MID_Validate		2245
1380 #define MID_MassRename		2246
1381 #define MID_Italic		2247
1382 #define MID_SmallCaps		2248
1383 #define MID_SubSup		2249
1384 #define MID_ChangeXHeight	2250
1385 #define MID_ChangeGlyph	2251
1386 #define MID_SetColor	2252
1387 #define MID_SetExtremumBound	2253
1388 #define MID_Center	2600
1389 #define MID_Thirds	2601
1390 #define MID_SetWidth	2602
1391 #define MID_SetLBearing	2603
1392 #define MID_SetRBearing	2604
1393 #define MID_SetVWidth	2605
1394 #define MID_RmHKern	2606
1395 #define MID_RmVKern	2607
1396 #define MID_VKernByClass	2608
1397 #define MID_VKernFromH	2609
1398 #define MID_SetBearings	2610
1399 #define MID_AutoHint	2501
1400 #define MID_ClearHints	2502
1401 #define MID_ClearWidthMD	2503
1402 #define MID_AutoInstr	2504
1403 #define MID_EditInstructions	2505
1404 #define MID_Editfpgm	2506
1405 #define MID_Editprep	2507
1406 #define MID_ClearInstrs	2508
1407 #define MID_HStemHist	2509
1408 #define MID_VStemHist	2510
1409 #define MID_BlueValuesHist	2511
1410 #define MID_Editcvt	2512
1411 #define MID_HintSubsPt	2513
1412 #define MID_AutoCounter	2514
1413 #define MID_DontAutoHint	2515
1414 #define MID_RmInstrTables	2516
1415 #define MID_Editmaxp	2517
1416 #define MID_Deltas	2518
1417 #define MID_OpenBitmap	2700
1418 #define MID_OpenOutline	2701
1419 #define MID_Revert	2702
1420 #define MID_Recent	2703
1421 #define MID_Print	2704
1422 #define MID_ScriptMenu	2705
1423 #define MID_RevertGlyph	2707
1424 #define MID_RevertToBackup 2708
1425 #define MID_GenerateTTC 2709
1426 #define MID_OpenMetrics	2710
1427 #define MID_ClearSpecialData 2711
1428 #define MID_Cut		2101
1429 #define MID_Copy	2102
1430 #define MID_Paste	2103
1431 #define MID_Clear	2104
1432 #define MID_SelAll	2106
1433 #define MID_CopyRef	2107
1434 #define MID_UnlinkRef	2108
1435 #define MID_Undo	2109
1436 #define MID_Redo	2110
1437 #define MID_CopyWidth	2111
1438 #define MID_UndoFontLevel	2112
1439 #define MID_AllFonts		2122
1440 #define MID_DisplayedFont	2123
1441 #define	MID_CharName		2124
1442 #define MID_RemoveUndoes	2114
1443 #define MID_CopyFgToBg	2115
1444 #define MID_ClearBackground	2116
1445 #define MID_CopyLBearing	2125
1446 #define MID_CopyRBearing	2126
1447 #define MID_CopyVWidth	2127
1448 #define MID_Join	2128
1449 #define MID_PasteInto	2129
1450 #define MID_SameGlyphAs	2130
1451 #define MID_RplRef	2131
1452 #define MID_PasteAfter	2132
1453 #define	MID_TTFInstr	2134
1454 #define	MID_CopyLookupData	2135
1455 #define MID_CopyL2L	2136
1456 #define MID_CorrectRefs	2137
1457 #define MID_Convert2CID	2800
1458 #define MID_Flatten	2801
1459 #define MID_InsertFont	2802
1460 #define MID_InsertBlank	2803
1461 #define MID_CIDFontInfo	2804
1462 #define MID_RemoveFromCID 2805
1463 #define MID_ConvertByCMap	2806
1464 #define MID_FlattenByCMap	2807
1465 #define MID_ChangeSupplement	2808
1466 #define MID_Reencode		2830
1467 #define MID_ForceReencode	2831
1468 #define MID_AddUnencoded	2832
1469 #define MID_RemoveUnused	2833
1470 #define MID_DetachGlyphs	2834
1471 #define MID_DetachAndRemoveGlyphs	2835
1472 #define MID_LoadEncoding	2836
1473 #define MID_MakeFromFont	2837
1474 #define MID_RemoveEncoding	2838
1475 #define MID_DisplayByGroups	2839
1476 #define MID_Compact	2840
1477 #define MID_SaveNamelist	2841
1478 #define MID_RenameGlyphs	2842
1479 #define MID_NameGlyphs		2843
1480 #define MID_HideNoGlyphSlots	2844
1481 #define MID_CreateMM	2900
1482 #define MID_MMInfo	2901
1483 #define MID_MMValid	2902
1484 #define MID_ChangeMMBlend	2903
1485 #define MID_BlendToNew	2904
1486 #define MID_ModifyComposition	20902
1487 #define MID_BuildSyllables	20903
1488 
1489 
1490 #define MID_Warnings	3000
1491 
1492 
1493 /* returns -1 if nothing selected, if exactly one char return it, -2 if more than one */
FVAnyCharSelected(FontView * fv)1494 static int FVAnyCharSelected(FontView *fv) {
1495     int i, val=-1;
1496 
1497     for ( i=0; i<fv->b.map->enccount; ++i ) {
1498 	if ( fv->b.selected[i]) {
1499 	    if ( val==-1 )
1500 		val = i;
1501 	    else
1502 return( -2 );
1503 	}
1504     }
1505 return( val );
1506 }
1507 
FVAllSelected(FontView * fv)1508 static int FVAllSelected(FontView *fv) {
1509     int i, any = false;
1510     /* Is everything real selected? */
1511 
1512     for ( i=0; i<fv->b.sf->glyphcnt; ++i ) if ( SCWorthOutputting(fv->b.sf->glyphs[i])) {
1513 	if ( !fv->b.selected[fv->b.map->backmap[i]] )
1514 return( false );
1515 	any = true;
1516     }
1517 return( any );
1518 }
1519 
FVMenuCopyFrom(GWindow UNUSED (gw),struct gmenuitem * mi,GEvent * UNUSED (e))1520 static void FVMenuCopyFrom(GWindow UNUSED(gw), struct gmenuitem *mi, GEvent *UNUSED(e)) {
1521     /*FontView *fv = (FontView *) GDrawGetUserData(gw);*/
1522 
1523     if ( mi->mid==MID_CharName )
1524 	copymetadata = !copymetadata;
1525     else if ( mi->mid==MID_TTFInstr )
1526 	copyttfinstr = !copyttfinstr;
1527     else
1528 	onlycopydisplayed = (mi->mid==MID_DisplayedFont);
1529     SavePrefs(true);
1530 }
1531 
FVMenuCopy(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))1532 static void FVMenuCopy(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
1533     FontView *fv = (FontView *) GDrawGetUserData(gw);
1534     if ( FVAnyCharSelected(fv)==-1 )
1535 return;
1536     FVCopy((FontViewBase *) fv,ct_fullcopy);
1537 }
1538 
FVMenuCopyLookupData(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))1539 static void FVMenuCopyLookupData(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
1540     FontView *fv = (FontView *) GDrawGetUserData(gw);
1541     if ( FVAnyCharSelected(fv)==-1 )
1542 return;
1543     FVCopy((FontViewBase *) fv,ct_lookups);
1544 }
1545 
FVMenuCopyRef(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))1546 static void FVMenuCopyRef(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
1547     FontView *fv = (FontView *) GDrawGetUserData(gw);
1548     if ( FVAnyCharSelected(fv)==-1 )
1549 return;
1550     FVCopy((FontViewBase *) fv,ct_reference);
1551 }
1552 
FVMenuCopyWidth(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))1553 static void FVMenuCopyWidth(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
1554     FontView *fv = (FontView *) GDrawGetUserData(gw);
1555 
1556     if ( FVAnyCharSelected(fv)==-1 )
1557 return;
1558     if ( mi->mid==MID_CopyVWidth && !fv->b.sf->hasvmetrics )
1559 return;
1560     FVCopyWidth((FontViewBase *) fv,
1561 		   mi->mid==MID_CopyWidth?ut_width:
1562 		   mi->mid==MID_CopyVWidth?ut_vwidth:
1563 		   mi->mid==MID_CopyLBearing?ut_lbearing:
1564 					 ut_rbearing);
1565 }
1566 
FVMenuPaste(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))1567 static void FVMenuPaste(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
1568     FontView *fv = (FontView *) GDrawGetUserData(gw);
1569     if ( FVAnyCharSelected(fv)==-1 )
1570 return;
1571     PasteIntoFV((FontViewBase *) fv,false,NULL);
1572 }
1573 
FVMenuPasteInto(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))1574 static void FVMenuPasteInto(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
1575     FontView *fv = (FontView *) GDrawGetUserData(gw);
1576     if ( FVAnyCharSelected(fv)==-1 )
1577 return;
1578     PasteIntoFV((FontViewBase *) fv,true,NULL);
1579 }
1580 
FVMenuPasteAfter(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))1581 static void FVMenuPasteAfter(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
1582     FontView *fv = (FontView *) GDrawGetUserData(gw);
1583     int pos = FVAnyCharSelected(fv);
1584     if ( pos<0 )
1585 return;
1586     PasteIntoFV(&fv->b,2,NULL);
1587 }
1588 
FVMenuSameGlyphAs(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))1589 static void FVMenuSameGlyphAs(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
1590     FontView *fv = (FontView *) GDrawGetUserData(gw);
1591     FVSameGlyphAs((FontViewBase *) fv);
1592     GDrawRequestExpose(fv->v,NULL,false);
1593 }
1594 
FVMenuCopyFgBg(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))1595 static void FVMenuCopyFgBg(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
1596     FontView *fv = (FontView *) GDrawGetUserData(gw);
1597     FVCopyFgtoBg( (FontViewBase *) fv );
1598 }
1599 
FVMenuCopyL2L(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))1600 static void FVMenuCopyL2L(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
1601     FontView *fv = (FontView *) GDrawGetUserData(gw);
1602     FVCopyLayerToLayer( fv );
1603 }
1604 
FVMenuCompareL2L(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))1605 static void FVMenuCompareL2L(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
1606     FontView *fv = (FontView *) GDrawGetUserData(gw);
1607     FVCompareLayerToLayer( fv );
1608 }
1609 
FVMenuClear(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))1610 static void FVMenuClear(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
1611     FontView *fv = (FontView *) GDrawGetUserData(gw);
1612     FVClear( (FontViewBase *) fv );
1613 }
1614 
FVMenuClearBackground(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))1615 static void FVMenuClearBackground(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
1616     FontView *fv = (FontView *) GDrawGetUserData(gw);
1617     FVClearBackground( (FontViewBase *) fv );
1618 }
1619 
FVMenuJoin(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))1620 static void FVMenuJoin(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
1621     FontView *fv = (FontView *) GDrawGetUserData(gw);
1622     FVJoin( (FontViewBase *) fv );
1623 }
1624 
FVMenuUnlinkRef(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))1625 static void FVMenuUnlinkRef(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
1626     FontView *fv = (FontView *) GDrawGetUserData(gw);
1627     FVUnlinkRef( (FontViewBase *) fv );
1628 }
1629 
FVMenuRemoveUndoes(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))1630 static void FVMenuRemoveUndoes(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
1631     FontView *fv = (FontView *) GDrawGetUserData(gw);
1632     SFRemoveUndoes(fv->b.sf,fv->b.selected,fv->b.map);
1633 }
1634 
FVMenuUndo(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))1635 static void FVMenuUndo(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
1636     FontView *fv = (FontView *) GDrawGetUserData(gw);
1637     FVUndo((FontViewBase *) fv);
1638 }
1639 
FVMenuRedo(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))1640 static void FVMenuRedo(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
1641     FontView *fv = (FontView *) GDrawGetUserData(gw);
1642     FVRedo((FontViewBase *) fv);
1643 }
1644 
FVMenuUndoFontLevel(GWindow gw,struct gmenuitem * mi,GEvent * e)1645 static void FVMenuUndoFontLevel(GWindow gw,struct gmenuitem *mi,GEvent *e) {
1646     FontView *fv = (FontView *) GDrawGetUserData(gw);
1647     FontViewBase * fvb = (FontViewBase *) fv;
1648     SplineFont *sf = fvb->sf;
1649 
1650     if( !sf->undoes )
1651 	return;
1652 
1653     struct sfundoes *undo = sf->undoes;
1654 //    printf("font level undo msg:%s\n", undo->msg );
1655     SFUndoPerform( undo, sf );
1656     SFUndoRemoveAndFree( sf, undo );
1657 }
1658 
FVMenuCut(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))1659 static void FVMenuCut(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
1660     FontView *fv = (FontView *) GDrawGetUserData(gw);
1661     FVCopy(&fv->b,ct_fullcopy);
1662     FVClear(&fv->b);
1663 }
1664 
FVMenuSelectAll(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))1665 static void FVMenuSelectAll(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
1666     FontView *fv = (FontView *) GDrawGetUserData(gw);
1667 
1668     FVSelectAll(fv);
1669 }
1670 
FVMenuInvertSelection(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))1671 static void FVMenuInvertSelection(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
1672     FontView *fv = (FontView *) GDrawGetUserData(gw);
1673 
1674     FVInvertSelection(fv);
1675 }
1676 
FVMenuDeselectAll(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))1677 static void FVMenuDeselectAll(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
1678     FontView *fv = (FontView *) GDrawGetUserData(gw);
1679 
1680     FVDeselectAll(fv);
1681 }
1682 
1683 enum merge_type { mt_set=0, mt_merge=4, mt_or=mt_merge, mt_restrict=8, mt_and=12 };
1684     /* Index array by merge_type(*4) + selection*2 + doit */
1685 const uint8 mergefunc[] = {
1686 /* mt_set */
1687 	0, 1,
1688 	0, 1,
1689 /* mt_merge */
1690 	0, 1,
1691 	1, 1,
1692 /* mt_restrict */
1693 	0, 0,
1694 	1, 0,
1695 /* mt_and */
1696 	0, 0,
1697 	0, 1,
1698 };
1699 
SelMergeType(GEvent * e)1700 static enum merge_type SelMergeType(GEvent *e) {
1701     if ( e->type!=et_mouseup )
1702 return( mt_set );
1703 
1704 return( ((e->u.mouse.state&ksm_shift)?mt_merge:0) |
1705 	((e->u.mouse.state&ksm_control)?mt_restrict:0) );
1706 }
1707 
SubMatch(char * pattern,char * eop,char * name,int ignorecase)1708 static char *SubMatch(char *pattern, char *eop, char *name,int ignorecase) {
1709     char ch, *ppt, *npt, *ept, *eon;
1710 
1711     while ( pattern<eop && ( ch = *pattern)!='\0' ) {
1712 	if ( ch=='*' ) {
1713 	    if ( pattern[1]=='\0' )
1714 return( name+strlen(name));
1715 	    for ( npt=name; ; ++npt ) {
1716 		if ( (eon = SubMatch(pattern+1,eop,npt,ignorecase))!= NULL )
1717 return( eon );
1718 		if ( *npt=='\0' )
1719 return( NULL );
1720 	    }
1721 	} else if ( ch=='?' ) {
1722 	    if ( *name=='\0' )
1723 return( NULL );
1724 	    ++name;
1725 	} else if ( ch=='[' ) {
1726 	    /* [<char>...] matches the chars
1727 	     * [<char>-<char>...] matches any char within the range (inclusive)
1728 	     * the above may be concattenated and the resultant pattern matches
1729 	     *		anything thing which matches any of them.
1730 	     * [^<char>...] matches any char which does not match the rest of
1731 	     *		the pattern
1732 	     * []...] as a special case a ']' immediately after the '[' matches
1733 	     *		itself and does not end the pattern
1734 	     */
1735 	    int found = 0, not=0;
1736 	    ++pattern;
1737 	    if ( pattern[0]=='^' ) { not = 1; ++pattern; }
1738 	    for ( ppt = pattern; (ppt!=pattern || *ppt!=']') && *ppt!='\0' ; ++ppt ) {
1739 		ch = *ppt;
1740 		if ( ppt[1]=='-' && ppt[2]!=']' && ppt[2]!='\0' ) {
1741 		    char ch2 = ppt[2];
1742 		    if ( (*name>=ch && *name<=ch2) ||
1743 			    (ignorecase && islower(ch) && islower(ch2) &&
1744 				    *name>=toupper(ch) && *name<=toupper(ch2)) ||
1745 			    (ignorecase && isupper(ch) && isupper(ch2) &&
1746 				    *name>=tolower(ch) && *name<=tolower(ch2))) {
1747 			if ( !not ) {
1748 			    found = 1;
1749 	    break;
1750 			}
1751 		    } else {
1752 			if ( not ) {
1753 			    found = 1;
1754 	    break;
1755 			}
1756 		    }
1757 		    ppt += 2;
1758 		} else if ( ch==*name || (ignorecase && tolower(ch)==tolower(*name)) ) {
1759 		    if ( !not ) {
1760 			found = 1;
1761 	    break;
1762 		    }
1763 		} else {
1764 		    if ( not ) {
1765 			found = 1;
1766 	    break;
1767 		    }
1768 		}
1769 	    }
1770 	    if ( !found )
1771 return( NULL );
1772 	    while ( *ppt!=']' && *ppt!='\0' ) ++ppt;
1773 	    pattern = ppt;
1774 	    ++name;
1775 	} else if ( ch=='{' ) {
1776 	    /* matches any of a comma separated list of substrings */
1777 	    for ( ppt = pattern+1; *ppt!='\0' ; ppt = ept ) {
1778 		for ( ept=ppt; *ept!='}' && *ept!=',' && *ept!='\0'; ++ept );
1779 		npt = SubMatch(ppt,ept,name,ignorecase);
1780 		if ( npt!=NULL ) {
1781 		    char *ecurly = ept;
1782 		    while ( *ecurly!='}' && ecurly<eop && *ecurly!='\0' ) ++ecurly;
1783 		    if ( (eon=SubMatch(ecurly+1,eop,npt,ignorecase))!=NULL )
1784 return( eon );
1785 		}
1786 		if ( *ept=='}' )
1787 return( NULL );
1788 		if ( *ept==',' ) ++ept;
1789 	    }
1790 	} else if ( ch==*name ) {
1791 	    ++name;
1792 	} else if ( ignorecase && tolower(ch)==tolower(*name)) {
1793 	    ++name;
1794 	} else
1795 return( NULL );
1796 	++pattern;
1797     }
1798 return( name );
1799 }
1800 
1801 /* Handles *?{}[] wildcards */
WildMatch(char * pattern,char * name,int ignorecase)1802 static int WildMatch(char *pattern, char *name,int ignorecase) {
1803     char *eop = pattern + strlen(pattern);
1804 
1805     if ( pattern==NULL )
1806 return( true );
1807 
1808     name = SubMatch(pattern,eop,name,ignorecase);
1809     if ( name==NULL )
1810 return( false );
1811     if ( *name=='\0' )
1812 return( true );
1813 
1814 return( false );
1815 }
1816 
SS_ScriptChanged(GGadget * g,GEvent * e)1817 static int SS_ScriptChanged(GGadget *g, GEvent *e) {
1818 
1819     if ( e->type==et_controlevent && e->u.control.subtype != et_textfocuschanged ) {
1820 	char *txt = GGadgetGetTitle8(g);
1821 	char buf[8];
1822 	int i;
1823 	extern GTextInfo scripts[];
1824 
1825 	for ( i=0; scripts[i].text!=NULL; ++i ) {
1826 	    if ( strcmp((char *) scripts[i].text,txt)==0 )
1827 	break;
1828 	}
1829 	free(txt);
1830 	if ( scripts[i].text==NULL )
1831 return( true );
1832 	buf[0] = ((intpt) scripts[i].userdata)>>24;
1833 	buf[1] = ((intpt) scripts[i].userdata)>>16;
1834 	buf[2] = ((intpt) scripts[i].userdata)>>8 ;
1835 	buf[3] = ((intpt) scripts[i].userdata)    ;
1836 	buf[4] = 0;
1837 	GGadgetSetTitle8(g,buf);
1838     }
1839 return( true );
1840 }
1841 
SS_OK(GGadget * g,GEvent * e)1842 static int SS_OK(GGadget *g, GEvent *e) {
1843 
1844     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
1845 	int *done = GDrawGetUserData(GGadgetGetWindow(g));
1846 	*done = 2;
1847     }
1848 return( true );
1849 }
1850 
SS_Cancel(GGadget * g,GEvent * e)1851 static int SS_Cancel(GGadget *g, GEvent *e) {
1852 
1853     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
1854 	int *done = GDrawGetUserData(GGadgetGetWindow(g));
1855 	*done = true;
1856     }
1857 return( true );
1858 }
1859 
ss_e_h(GWindow gw,GEvent * event)1860 static int ss_e_h(GWindow gw, GEvent *event) {
1861     int *done = GDrawGetUserData(gw);
1862 
1863     switch ( event->type ) {
1864       case et_char:
1865 return( false );
1866       case et_close:
1867 	*done = true;
1868       break;
1869     }
1870 return( true );
1871 }
1872 
FVSelectByScript(FontView * fv,int merge)1873 static void FVSelectByScript(FontView *fv,int merge) {
1874     int j, gid;
1875     SplineChar *sc;
1876     EncMap *map = fv->b.map;
1877     SplineFont *sf = fv->b.sf;
1878     extern GTextInfo scripts[];
1879     GRect pos;
1880     GWindow gw;
1881     GWindowAttrs wattrs;
1882     GGadgetCreateData gcd[10], *hvarray[21][2], *barray[8], boxes[3];
1883     GTextInfo label[10];
1884     int i,k;
1885     int done = 0, doit;
1886     char tagbuf[4];
1887     uint32 tag;
1888     const unichar_t *ret;
1889     int lc_k, uc_k, select_k;
1890     int only_uc=0, only_lc=0;
1891 
1892     LookupUIInit();
1893 
1894     memset(&wattrs,0,sizeof(wattrs));
1895     memset(&gcd,0,sizeof(gcd));
1896     memset(&label,0,sizeof(label));
1897     memset(&boxes,0,sizeof(boxes));
1898 
1899     wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_undercursor|wam_isdlg|wam_restrict;
1900     wattrs.event_masks = ~(1<<et_charup);
1901     wattrs.restrict_input_to_me = false;
1902     wattrs.is_dlg = 1;
1903     wattrs.undercursor = 1;
1904     wattrs.cursor = ct_pointer;
1905     wattrs.utf8_window_title = _("Select by Script");
1906     wattrs.is_dlg = true;
1907     pos.x = pos.y = 0;
1908     pos.width = 100;
1909     pos.height = 100;
1910     gw = GDrawCreateTopWindow(NULL,&pos,ss_e_h,&done,&wattrs);
1911 
1912     k = i = 0;
1913 
1914     gcd[k].gd.flags = gg_visible|gg_enabled ;
1915     gcd[k].gd.u.list = scripts;
1916     gcd[k].gd.handle_controlevent = SS_ScriptChanged;
1917     gcd[k++].creator = GListFieldCreate;
1918     hvarray[i][0] = &gcd[k-1]; hvarray[i++][1] = NULL;
1919 
1920     label[k].text = (unichar_t *) _("All glyphs");
1921     label[k].text_is_1byte = true;
1922     gcd[k].gd.label = &label[k];
1923     gcd[k].gd.flags = gg_enabled|gg_visible|gg_cb_on;
1924     gcd[k].gd.popup_msg = _("Set the selection of the font view to all glyphs in the script.");
1925     gcd[k++].creator = GRadioCreate;
1926     hvarray[i][0] = &gcd[k-1]; hvarray[i++][1] = NULL;
1927     hvarray[i][0] = GCD_HPad10; hvarray[i++][1] = NULL;
1928 
1929     uc_k = k;
1930     label[k].text = (unichar_t *) _("Only upper case");
1931     label[k].text_is_1byte = true;
1932     gcd[k].gd.label = &label[k];
1933     gcd[k].gd.flags = gg_enabled|gg_visible;
1934     gcd[k].gd.popup_msg = _("Set the selection of the font view to any upper case glyphs in the script.");
1935     gcd[k++].creator = GRadioCreate;
1936     hvarray[i][0] = &gcd[k-1]; hvarray[i++][1] = NULL;
1937 
1938     lc_k = k;
1939     label[k].text = (unichar_t *) _("Only lower case");
1940     label[k].text_is_1byte = true;
1941     gcd[k].gd.label = &label[k];
1942     gcd[k].gd.flags = gg_enabled|gg_visible;
1943     gcd[k].gd.popup_msg = _("Set the selection of the font view to any lower case glyphs in the script.");
1944     gcd[k++].creator = GRadioCreate;
1945     hvarray[i][0] = &gcd[k-1]; hvarray[i++][1] = NULL;
1946     hvarray[i][0] = GCD_HPad10; hvarray[i++][1] = NULL;
1947 
1948     select_k = k;
1949     label[k].text = (unichar_t *) _("Select Results");
1950     label[k].text_is_1byte = true;
1951     gcd[k].gd.label = &label[k];
1952     gcd[k].gd.flags = gg_enabled|gg_visible|gg_rad_startnew;
1953     gcd[k].gd.popup_msg = _("Set the selection of the font view to the glyphs\nwhich match");
1954     gcd[k++].creator = GRadioCreate;
1955     hvarray[i][0] = &gcd[k-1]; hvarray[i++][1] = NULL;
1956 
1957     label[k].text = (unichar_t *) _("Merge Results");
1958     label[k].text_is_1byte = true;
1959     gcd[k].gd.label = &label[k];
1960     gcd[k].gd.flags = gg_enabled|gg_visible;
1961     gcd[k].gd.popup_msg = _("Expand the selection of the font view to include\nall the glyphs which match");
1962     gcd[k++].creator = GRadioCreate;
1963     hvarray[i][0] = &gcd[k-1]; hvarray[i++][1] = NULL;
1964 
1965     label[k].text = (unichar_t *) _("Restrict Selection");
1966     label[k].text_is_1byte = true;
1967     gcd[k].gd.label = &label[k];
1968     gcd[k].gd.flags = gg_enabled|gg_visible;
1969     gcd[k].gd.popup_msg = _("Remove matching glyphs from the selection." );
1970     gcd[k++].creator = GRadioCreate;
1971     hvarray[i][0] = &gcd[k-1]; hvarray[i++][1] = NULL;
1972 
1973     label[k].text = (unichar_t *) _("Logical And with Selection");
1974     label[k].text_is_1byte = true;
1975     gcd[k].gd.label = &label[k];
1976     gcd[k].gd.flags = gg_enabled|gg_visible;
1977     gcd[k].gd.popup_msg = _("Remove glyphs which do not match from the selection." );
1978     gcd[k++].creator = GRadioCreate;
1979     hvarray[i][0] = &gcd[k-1]; hvarray[i++][1] = NULL;
1980     gcd[k-4 + merge/4].gd.flags |= gg_cb_on;
1981 
1982     hvarray[i][0] = GCD_Glue; hvarray[i++][1] = NULL;
1983 
1984     label[k].text = (unichar_t *) _("_OK");
1985     label[k].text_is_1byte = true;
1986     label[k].text_in_resource = true;
1987     gcd[k].gd.label = &label[k];
1988     gcd[k].gd.flags = gg_visible|gg_enabled | gg_but_default;
1989     gcd[k].gd.handle_controlevent = SS_OK;
1990     gcd[k++].creator = GButtonCreate;
1991 
1992     label[k].text = (unichar_t *) _("_Cancel");
1993     label[k].text_is_1byte = true;
1994     label[k].text_in_resource = true;
1995     gcd[k].gd.label = &label[k];
1996     gcd[k].gd.flags = gg_visible|gg_enabled | gg_but_cancel;
1997     gcd[k].gd.handle_controlevent = SS_Cancel;
1998     gcd[k++].creator = GButtonCreate;
1999 
2000     barray[0] = barray[2] = barray[3] = barray[4] = barray[6] = GCD_Glue; barray[7] = NULL;
2001     barray[1] = &gcd[k-2]; barray[5] = &gcd[k-1];
2002     hvarray[i][0] = &boxes[2]; hvarray[i++][1] = NULL;
2003     hvarray[i][0] = NULL;
2004 
2005     memset(boxes,0,sizeof(boxes));
2006     boxes[0].gd.pos.x = boxes[0].gd.pos.y = 2;
2007     boxes[0].gd.flags = gg_enabled|gg_visible;
2008     boxes[0].gd.u.boxelements = hvarray[0];
2009     boxes[0].creator = GHVGroupCreate;
2010 
2011     boxes[2].gd.flags = gg_enabled|gg_visible;
2012     boxes[2].gd.u.boxelements = barray;
2013     boxes[2].creator = GHBoxCreate;
2014 
2015     GGadgetsCreate(gw,boxes);
2016     GHVBoxSetExpandableCol(boxes[2].ret,gb_expandgluesame);
2017     GHVBoxSetExpandableRow(boxes[0].ret,gb_expandglue);
2018 
2019 
2020     GHVBoxFitWindow(boxes[0].ret);
2021 
2022     GDrawSetVisible(gw,true);
2023     ret = NULL;
2024     while ( !done ) {
2025 	GDrawProcessOneEvent(NULL);
2026 	if ( done==2 ) {
2027 	    ret = _GGadgetGetTitle(gcd[0].ret);
2028 	    if ( *ret=='\0' ) {
2029 		ff_post_error(_("No Script"),_("Please specify a script"));
2030 		done = 0;
2031 	    } else if ( u_strlen(ret)>4 ) {
2032 		ff_post_error(_("Bad Script"),_("Scripts are 4 letter tags"));
2033 		done = 0;
2034 	    }
2035 	}
2036     }
2037     memset(tagbuf,' ',4);
2038     if ( done==2 && ret!=NULL ) {
2039 	tagbuf[0] = *ret;
2040 	if ( ret[1]!='\0' ) {
2041 	    tagbuf[1] = ret[1];
2042 	    if ( ret[2]!='\0' ) {
2043 		tagbuf[2] = ret[2];
2044 		if ( ret[3]!='\0' )
2045 		    tagbuf[3] = ret[3];
2046 	    }
2047 	}
2048     }
2049     merge = GGadgetIsChecked(gcd[select_k+0].ret) ? mt_set :
2050 	    GGadgetIsChecked(gcd[select_k+1].ret) ? mt_merge :
2051 	    GGadgetIsChecked(gcd[select_k+2].ret) ? mt_restrict :
2052 						    mt_and;
2053     only_uc = GGadgetIsChecked(gcd[uc_k+0].ret);
2054     only_lc = GGadgetIsChecked(gcd[lc_k+0].ret);
2055 
2056     GDrawDestroyWindow(gw);
2057     if ( done==1 )
2058 return;
2059     tag = (tagbuf[0]<<24) | (tagbuf[1]<<16) | (tagbuf[2]<<8) | tagbuf[3];
2060 
2061     for ( j=0; j<map->enccount; ++j ) if ( (gid=map->map[j])!=-1 && (sc=sf->glyphs[gid])!=NULL ) {
2062 	doit = ( SCScriptFromUnicode(sc)==tag );
2063 	if ( doit ) {
2064 	    if ( only_uc && (sc->unicodeenc==-1 || sc->unicodeenc>0xffff ||
2065 		    !isupper(sc->unicodeenc)) )
2066 		doit = false;
2067 	    else if ( only_lc && (sc->unicodeenc==-1 || sc->unicodeenc>0xffff ||
2068 		    !islower(sc->unicodeenc)) )
2069 		doit = false;
2070 	}
2071 	fv->b.selected[j] = mergefunc[ merge + (fv->b.selected[j]?2:0) + doit ];
2072     } else if ( merge==mt_set )
2073 	fv->b.selected[j] = false;
2074 
2075     GDrawRequestExpose(fv->v,NULL,false);
2076 }
2077 
FVMenuSelectByScript(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * e)2078 static void FVMenuSelectByScript(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *e) {
2079     FontView *fv = (FontView *) GDrawGetUserData(gw);
2080 
2081     FVSelectByScript(fv,SelMergeType(e));
2082 }
2083 
FVSelectColor(FontView * fv,uint32 col,int merge)2084 static void FVSelectColor(FontView *fv, uint32 col, int merge) {
2085     int i, doit;
2086     uint32 sccol;
2087     SplineChar **glyphs = fv->b.sf->glyphs;
2088 
2089     for ( i=0; i<fv->b.map->enccount; ++i ) {
2090 	int gid = fv->b.map->map[i];
2091 	sccol =  ( gid==-1 || glyphs[gid]==NULL ) ? COLOR_DEFAULT : glyphs[gid]->color;
2092 	doit = sccol==col;
2093 	fv->b.selected[i] = mergefunc[ merge + (fv->b.selected[i]?2:0) + doit ];
2094     }
2095     GDrawRequestExpose(fv->v,NULL,false);
2096 }
2097 
FVMenuSelectColor(GWindow gw,struct gmenuitem * mi,GEvent * e)2098 static void FVMenuSelectColor(GWindow gw, struct gmenuitem *mi, GEvent *e) {
2099     FontView *fv = (FontView *) GDrawGetUserData(gw);
2100     Color col = (Color) (intpt) (mi->ti.userdata);
2101     if ( (intpt) mi->ti.userdata == (intpt) -10 ) {
2102 	struct hslrgb retcol, font_cols[6];
2103 	retcol = GWidgetColor(_("Pick a color"),NULL,SFFontCols(fv->b.sf,font_cols));
2104 	if ( !retcol.rgb )
2105 return;
2106 	col = (((int) rint(255.*retcol.r))<<16 ) |
2107 		    (((int) rint(255.*retcol.g))<<8 ) |
2108 		    (((int) rint(255.*retcol.b)) );
2109     }
2110     FVSelectColor(fv,col,SelMergeType(e));
2111 }
2112 
FVSelectByName(FontView * fv,char * ret,int merge)2113 static int FVSelectByName(FontView *fv, char *ret, int merge) {
2114     int j, gid, doit;
2115     char *end;
2116     SplineChar *sc;
2117     EncMap *map = fv->b.map;
2118     SplineFont *sf = fv->b.sf;
2119     struct altuni *alt;
2120 
2121     if ( !merge )
2122 	FVDeselectAll(fv);
2123     if (( *ret=='0' && ( ret[1]=='x' || ret[1]=='X' )) ||
2124 	    ((*ret=='u' || *ret=='U') && ret[1]=='+' )) {
2125 	int uni = (int) strtol(ret+2,&end,16);
2126 	int vs= -2;
2127 	if ( *end=='.' ) {
2128 	    ++end;
2129 	    if (( *end=='0' && ( end[1]=='x' || end[1]=='X' )) ||
2130 		    ((*end=='u' || *end=='U') && end[1]=='+' ))
2131 		end += 2;
2132 	    vs = (int) strtoul(end,&end,16);
2133 	}
2134 	if ( *end!='\0' || uni<0 || uni>=0x110000 ) {
2135 	    ff_post_error( _("Bad Number"),_("Bad Number") );
2136 return( false );
2137 	}
2138 	for ( j=0; j<map->enccount; ++j ) if ( (gid=map->map[j])!=-1 && (sc=sf->glyphs[gid])!=NULL ) {
2139 	    if ( vs==-2 ) {
2140 		for ( alt=sc->altuni; alt!=NULL && (alt->unienc!=uni || alt->fid!=0); alt=alt->next );
2141 	    } else {
2142 		for ( alt=sc->altuni; alt!=NULL && (alt->unienc!=uni || alt->vs!=vs || alt->fid!=0); alt=alt->next );
2143 	    }
2144 	    doit = (sc->unicodeenc == uni && vs<0) || alt!=NULL;
2145 	    fv->b.selected[j] = mergefunc[ merge + (fv->b.selected[j]?2:0) + doit ];
2146 	} else if ( merge==mt_set )
2147 	    fv->b.selected[j] = false;
2148     } else {
2149 	for ( j=0; j<map->enccount; ++j ) if ( (gid=map->map[j])!=-1 && (sc=sf->glyphs[gid])!=NULL ) {
2150 	    doit = WildMatch(ret,sc->name,false);
2151 	    fv->b.selected[j] = mergefunc[ merge + (fv->b.selected[j]?2:0) + doit ];
2152 	} else if ( merge==mt_set )
2153 	    fv->b.selected[j] = false;
2154     }
2155     GDrawRequestExpose(fv->v,NULL,false);
2156     fv->sel_index = 1;
2157 return( true );
2158 }
2159 
FVMenuSelectByName(GWindow _gw,struct gmenuitem * UNUSED (mi),GEvent * e)2160 static void FVMenuSelectByName(GWindow _gw, struct gmenuitem *UNUSED(mi), GEvent *e) {
2161     FontView *fv = (FontView *) GDrawGetUserData(_gw);
2162     GRect pos;
2163     GWindow gw;
2164     GWindowAttrs wattrs;
2165     GGadgetCreateData gcd[8], *hvarray[12][2], *barray[8], boxes[3];
2166     GTextInfo label[8];
2167     int merge = SelMergeType(e);
2168     int done=0,k,i;
2169 
2170     memset(&wattrs,0,sizeof(wattrs));
2171     memset(&gcd,0,sizeof(gcd));
2172     memset(&label,0,sizeof(label));
2173     memset(&boxes,0,sizeof(boxes));
2174 
2175     wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_undercursor|wam_isdlg|wam_restrict;
2176     wattrs.event_masks = ~(1<<et_charup);
2177     wattrs.restrict_input_to_me = false;
2178     wattrs.undercursor = 1;
2179     wattrs.cursor = ct_pointer;
2180     wattrs.utf8_window_title = _("Select by Name");
2181     wattrs.is_dlg = false;
2182     pos.x = pos.y = 0;
2183     pos.width = 100;
2184     pos.height = 100;
2185     gw = GDrawCreateTopWindow(NULL,&pos,ss_e_h,&done,&wattrs);
2186 
2187     k = i = 0;
2188 
2189     label[k].text = (unichar_t *) _("Enter either a wildcard pattern (to match glyph names)\n or a unicode encoding like \"U+0065\".");
2190     label[k].text_is_1byte = true;
2191     gcd[k].gd.label = &label[k];
2192     gcd[k].gd.flags = gg_visible | gg_enabled;
2193     gcd[k].gd.popup_msg = _(
2194 	"Unix style wildcarding is accepted:\n"
2195 	"Most characters match themselves\n"
2196 	"A \"?\" will match any single character\n"
2197 	"A \"*\" will match an arbitrary number of characters (including none)\n"
2198 	"An \"[abd]\" set of characters within square brackets will match any (single) character\n"
2199 	"A \"{scmp,c2sc}\" set of strings within curly brackets will match any string\n"
2200 	"So \"a.*\" would match \"a.\" or \"a.sc\" or \"a.swash\"\n"
2201 	"While \"a.{scmp,c2sc}\" would match \"a.scmp\" or \"a.c2sc\"\n"
2202 	"And \"a.[abd]\" would match \"a.a\" or \"a.b\" or \"a.d\"");
2203     gcd[k++].creator = GLabelCreate;
2204     hvarray[i][0] = &gcd[k-1]; hvarray[i++][1] = NULL;
2205 
2206     gcd[k].gd.flags = gg_visible | gg_enabled;
2207     gcd[k].gd.popup_msg = gcd[k-1].gd.popup_msg;
2208     gcd[k++].creator = GTextFieldCreate;
2209     hvarray[i][0] = &gcd[k-1]; hvarray[i++][1] = NULL;
2210 
2211     label[k].text = (unichar_t *) _("Select Results");
2212     label[k].text_is_1byte = true;
2213     gcd[k].gd.label = &label[k];
2214     gcd[k].gd.flags = gg_enabled|gg_visible;
2215     gcd[k].gd.popup_msg = _("Set the selection of the font view to the glyphs\nwhich match");
2216     gcd[k++].creator = GRadioCreate;
2217     hvarray[i][0] = &gcd[k-1]; hvarray[i++][1] = NULL;
2218 
2219     label[k].text = (unichar_t *) _("Merge Results");
2220     label[k].text_is_1byte = true;
2221     gcd[k].gd.label = &label[k];
2222     gcd[k].gd.flags = gg_enabled|gg_visible;
2223     gcd[k].gd.popup_msg = _("Expand the selection of the font view to include\nall the glyphs which match");
2224     gcd[k++].creator = GRadioCreate;
2225     hvarray[i][0] = &gcd[k-1]; hvarray[i++][1] = NULL;
2226 
2227     label[k].text = (unichar_t *) _("Restrict Selection");
2228     label[k].text_is_1byte = true;
2229     gcd[k].gd.label = &label[k];
2230     gcd[k].gd.flags = gg_enabled|gg_visible;
2231     gcd[k].gd.popup_msg = _("Remove matching glyphs from the selection." );
2232     gcd[k++].creator = GRadioCreate;
2233     hvarray[i][0] = &gcd[k-1]; hvarray[i++][1] = NULL;
2234 
2235     label[k].text = (unichar_t *) _("Logical And with Selection");
2236     label[k].text_is_1byte = true;
2237     gcd[k].gd.label = &label[k];
2238     gcd[k].gd.flags = gg_enabled|gg_visible;
2239     gcd[k].gd.popup_msg = _("Remove glyphs which do not match from the selection." );
2240     gcd[k++].creator = GRadioCreate;
2241     hvarray[i][0] = &gcd[k-1]; hvarray[i++][1] = NULL;
2242     gcd[k-4 + merge/4].gd.flags |= gg_cb_on;
2243 
2244     hvarray[i][0] = GCD_Glue; hvarray[i++][1] = NULL;
2245 
2246     label[k].text = (unichar_t *) _("_OK");
2247     label[k].text_is_1byte = true;
2248     label[k].text_in_resource = true;
2249     gcd[k].gd.label = &label[k];
2250     gcd[k].gd.flags = gg_visible|gg_enabled | gg_but_default;
2251     gcd[k].gd.handle_controlevent = SS_OK;
2252     gcd[k++].creator = GButtonCreate;
2253 
2254     label[k].text = (unichar_t *) _("_Cancel");
2255     label[k].text_is_1byte = true;
2256     label[k].text_in_resource = true;
2257     gcd[k].gd.label = &label[k];
2258     gcd[k].gd.flags = gg_visible|gg_enabled | gg_but_cancel;
2259     gcd[k].gd.handle_controlevent = SS_Cancel;
2260     gcd[k++].creator = GButtonCreate;
2261 
2262     barray[0] = barray[2] = barray[3] = barray[4] = barray[6] = GCD_Glue; barray[7] = NULL;
2263     barray[1] = &gcd[k-2]; barray[5] = &gcd[k-1];
2264     hvarray[i][0] = &boxes[2]; hvarray[i++][1] = NULL;
2265     hvarray[i][0] = NULL;
2266 
2267     memset(boxes,0,sizeof(boxes));
2268     boxes[0].gd.pos.x = boxes[0].gd.pos.y = 2;
2269     boxes[0].gd.flags = gg_enabled|gg_visible;
2270     boxes[0].gd.u.boxelements = hvarray[0];
2271     boxes[0].creator = GHVGroupCreate;
2272 
2273     boxes[2].gd.flags = gg_enabled|gg_visible;
2274     boxes[2].gd.u.boxelements = barray;
2275     boxes[2].creator = GHBoxCreate;
2276 
2277     GGadgetsCreate(gw,boxes);
2278     GHVBoxSetExpandableCol(boxes[2].ret,gb_expandgluesame);
2279     GHVBoxSetExpandableRow(boxes[0].ret,gb_expandglue);
2280 
2281 
2282     GHVBoxFitWindow(boxes[0].ret);
2283 
2284     GDrawSetVisible(gw,true);
2285     while ( !done ) {
2286 	GDrawProcessOneEvent(NULL);
2287 	if ( done==2 ) {
2288 	    char *str = GGadgetGetTitle8(gcd[1].ret);
2289 	    int merge = GGadgetIsChecked(gcd[2].ret) ? mt_set :
2290 			GGadgetIsChecked(gcd[3].ret) ? mt_merge :
2291 			GGadgetIsChecked(gcd[4].ret) ? mt_restrict :
2292 						       mt_and;
2293 	    int ret = FVSelectByName(fv,str,merge);
2294 	    free(str);
2295 	    if ( !ret )
2296 		done = 0;
2297 	}
2298     }
2299     GDrawDestroyWindow(gw);
2300 }
2301 
FVMenuSelectWorthOutputting(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * e)2302 static void FVMenuSelectWorthOutputting(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *e) {
2303     FontView *fv = (FontView *) GDrawGetUserData(gw);
2304     int i, gid, doit;
2305     EncMap *map = fv->b.map;
2306     SplineFont *sf = fv->b.sf;
2307     int merge = SelMergeType(e);
2308 
2309     for ( i=0; i< map->enccount; ++i ) {
2310 	doit = ( (gid=map->map[i])!=-1 && sf->glyphs[gid]!=NULL &&
2311 		SCWorthOutputting(sf->glyphs[gid]) );
2312 	fv->b.selected[i] = mergefunc[ merge + (fv->b.selected[i]?2:0) + doit ];
2313     }
2314     GDrawRequestExpose(fv->v,NULL,false);
2315 }
2316 
FVMenuGlyphsRefs(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * e)2317 static void FVMenuGlyphsRefs(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *e) {
2318     FontView *fv = (FontView *) GDrawGetUserData(gw);
2319     int i, gid, doit;
2320     EncMap *map = fv->b.map;
2321     SplineFont *sf = fv->b.sf;
2322     int merge = SelMergeType(e);
2323     int layer = fv->b.active_layer;
2324 
2325     for ( i=0; i< map->enccount; ++i ) {
2326 	doit = ( (gid=map->map[i])!=-1 && sf->glyphs[gid]!=NULL &&
2327 		sf->glyphs[gid]->layers[layer].refs!=NULL &&
2328 		sf->glyphs[gid]->layers[layer].splines==NULL );
2329 	fv->b.selected[i] = mergefunc[ merge + (fv->b.selected[i]?2:0) + doit ];
2330     }
2331     GDrawRequestExpose(fv->v,NULL,false);
2332 }
2333 
FVMenuGlyphsSplines(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * e)2334 static void FVMenuGlyphsSplines(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *e) {
2335     FontView *fv = (FontView *) GDrawGetUserData(gw);
2336     int i, gid, doit;
2337     EncMap *map = fv->b.map;
2338     SplineFont *sf = fv->b.sf;
2339     int merge = SelMergeType(e);
2340     int layer = fv->b.active_layer;
2341 
2342     for ( i=0; i< map->enccount; ++i ) {
2343 	doit = ( (gid=map->map[i])!=-1 && sf->glyphs[gid]!=NULL &&
2344 		sf->glyphs[gid]->layers[layer].refs==NULL &&
2345 		sf->glyphs[gid]->layers[layer].splines!=NULL );
2346 	fv->b.selected[i] = mergefunc[ merge + (fv->b.selected[i]?2:0) + doit ];
2347     }
2348     GDrawRequestExpose(fv->v,NULL,false);
2349 }
2350 
FVMenuGlyphsBoth(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * e)2351 static void FVMenuGlyphsBoth(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *e) {
2352     FontView *fv = (FontView *) GDrawGetUserData(gw);
2353     int i, gid, doit;
2354     EncMap *map = fv->b.map;
2355     SplineFont *sf = fv->b.sf;
2356     int merge = SelMergeType(e);
2357     int layer = fv->b.active_layer;
2358 
2359     for ( i=0; i< map->enccount; ++i ) {
2360 	doit = ( (gid=map->map[i])!=-1 && sf->glyphs[gid]!=NULL &&
2361 		sf->glyphs[gid]->layers[layer].refs!=NULL &&
2362 		sf->glyphs[gid]->layers[layer].splines!=NULL );
2363 	fv->b.selected[i] = mergefunc[ merge + (fv->b.selected[i]?2:0) + doit ];
2364     }
2365     GDrawRequestExpose(fv->v,NULL,false);
2366 }
2367 
FVMenuGlyphsWhite(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * e)2368 static void FVMenuGlyphsWhite(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *e) {
2369     FontView *fv = (FontView *) GDrawGetUserData(gw);
2370     int i, gid, doit;
2371     EncMap *map = fv->b.map;
2372     SplineFont *sf = fv->b.sf;
2373     int merge = SelMergeType(e);
2374     int layer = fv->b.active_layer;
2375 
2376     for ( i=0; i< map->enccount; ++i ) {
2377 	doit = ( (gid=map->map[i])!=-1 && sf->glyphs[gid]!=NULL &&
2378 		sf->glyphs[gid]->layers[layer].refs==NULL &&
2379 		sf->glyphs[gid]->layers[layer].splines==NULL );
2380 	fv->b.selected[i] = mergefunc[ merge + (fv->b.selected[i]?2:0) + doit ];
2381     }
2382     GDrawRequestExpose(fv->v,NULL,false);
2383 }
2384 
FVMenuSelectChanged(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * e)2385 static void FVMenuSelectChanged(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *e) {
2386     FontView *fv = (FontView *) GDrawGetUserData(gw);
2387     int i, gid, doit;
2388     EncMap *map = fv->b.map;
2389     SplineFont *sf = fv->b.sf;
2390     int merge = SelMergeType(e);
2391 
2392     for ( i=0; i< map->enccount; ++i ) {
2393 	doit = ( (gid=map->map[i])!=-1 && sf->glyphs[gid]!=NULL && sf->glyphs[gid]->changed );
2394 	fv->b.selected[i] = mergefunc[ merge + (fv->b.selected[i]?2:0) + doit ];
2395     }
2396 
2397     GDrawRequestExpose(fv->v,NULL,false);
2398 }
2399 
FVMenuSelectHintingNeeded(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * e)2400 static void FVMenuSelectHintingNeeded(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *e) {
2401     FontView *fv = (FontView *) GDrawGetUserData(gw);
2402     int i, gid, doit;
2403     EncMap *map = fv->b.map;
2404     SplineFont *sf = fv->b.sf;
2405     int order2 = sf->layers[fv->b.active_layer].order2;
2406     int merge = SelMergeType(e);
2407 
2408     for ( i=0; i< map->enccount; ++i ) {
2409 	doit = ( (gid=map->map[i])!=-1 && sf->glyphs[gid]!=NULL &&
2410 		((!order2 && sf->glyphs[gid]->changedsincelasthinted ) ||
2411 		 ( order2 && sf->glyphs[gid]->layers[fv->b.active_layer].splines!=NULL &&
2412 		     sf->glyphs[gid]->ttf_instrs_len<=0 ) ||
2413 		 ( order2 && sf->glyphs[gid]->instructions_out_of_date )) );
2414 	fv->b.selected[i] = mergefunc[ merge + (fv->b.selected[i]?2:0) + doit ];
2415     }
2416     GDrawRequestExpose(fv->v,NULL,false);
2417 }
2418 
FVMenuSelectAutohintable(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * e)2419 static void FVMenuSelectAutohintable(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *e) {
2420     FontView *fv = (FontView *) GDrawGetUserData(gw);
2421     int i, gid, doit;
2422     EncMap *map = fv->b.map;
2423     SplineFont *sf = fv->b.sf;
2424     int merge = SelMergeType(e);
2425 
2426     for ( i=0; i< map->enccount; ++i ) {
2427 	doit = (gid=map->map[i])!=-1 && sf->glyphs[gid]!=NULL &&
2428 		!sf->glyphs[gid]->manualhints;
2429 	fv->b.selected[i] = mergefunc[ merge + (fv->b.selected[i]?2:0) + doit ];
2430     }
2431     GDrawRequestExpose(fv->v,NULL,false);
2432 }
2433 
FVMenuSelectByPST(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))2434 static void FVMenuSelectByPST(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2435     FontView *fv = (FontView *) GDrawGetUserData(gw);
2436 
2437     FVSelectByPST(fv);
2438 }
2439 
FVMenuFindRpl(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))2440 static void FVMenuFindRpl(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2441     FontView *fv = (FontView *) GDrawGetUserData(gw);
2442 
2443     SVCreate(fv);
2444 }
2445 
FVMenuReplaceWithRef(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))2446 static void FVMenuReplaceWithRef(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2447     FontView *fv = (FontView *) GDrawGetUserData(gw);
2448 
2449     FVReplaceOutlineWithReference(fv,.001);
2450 }
2451 
FVMenuCorrectRefs(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))2452 static void FVMenuCorrectRefs(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2453     FontViewBase *fv = (FontViewBase *) GDrawGetUserData(gw);
2454 
2455     FVCorrectReferences(fv);
2456 }
2457 
FVMenuCharInfo(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))2458 static void FVMenuCharInfo(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2459     FontView *fv = (FontView *) GDrawGetUserData(gw);
2460     int pos = FVAnyCharSelected(fv);
2461     if ( pos<0 )
2462 return;
2463     if ( fv->b.cidmaster!=NULL &&
2464 	    (fv->b.map->map[pos]==-1 || fv->b.sf->glyphs[fv->b.map->map[pos]]==NULL ))
2465 return;
2466     SCCharInfo(SFMakeChar(fv->b.sf,fv->b.map,pos),fv->b.active_layer,fv->b.map,pos);
2467 }
2468 
FVMenuBDFInfo(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))2469 static void FVMenuBDFInfo(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2470     FontView *fv = (FontView *) GDrawGetUserData(gw);
2471     if ( fv->b.sf->bitmaps==NULL )
2472 return;
2473     if ( fv->show!=fv->filled )
2474 	SFBdfProperties(fv->b.sf,fv->b.map,fv->show);
2475     else
2476 	SFBdfProperties(fv->b.sf,fv->b.map,NULL);
2477 }
2478 
FVMenuBaseHoriz(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))2479 static void FVMenuBaseHoriz(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2480     FontView *fv = (FontView *) GDrawGetUserData(gw);
2481     SplineFont *sf = fv->b.cidmaster == NULL ? fv->b.sf : fv->b.cidmaster;
2482     sf->horiz_base = SFBaselines(sf,sf->horiz_base,false);
2483     SFBaseSort(sf);
2484 }
2485 
FVMenuBaseVert(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))2486 static void FVMenuBaseVert(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2487     FontView *fv = (FontView *) GDrawGetUserData(gw);
2488     SplineFont *sf = fv->b.cidmaster == NULL ? fv->b.sf : fv->b.cidmaster;
2489     sf->vert_base = SFBaselines(sf,sf->vert_base,true);
2490     SFBaseSort(sf);
2491 }
2492 
FVMenuJustify(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))2493 static void FVMenuJustify(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2494     FontView *fv = (FontView *) GDrawGetUserData(gw);
2495     SplineFont *sf = fv->b.cidmaster == NULL ? fv->b.sf : fv->b.cidmaster;
2496     JustifyDlg(sf);
2497 }
2498 
FVMenuMassRename(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))2499 static void FVMenuMassRename(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2500     FontView *fv = (FontView *) GDrawGetUserData(gw);
2501     FVMassGlyphRename(fv);
2502 }
2503 
FVSetColor(FontView * fv,uint32 col)2504 static void FVSetColor(FontView *fv, uint32 col) {
2505     int i;
2506 
2507     for ( i=0; i<fv->b.map->enccount; ++i ) if ( fv->b.selected[i] ) {
2508 	SplineChar *sc = SFMakeChar(fv->b.sf,fv->b.map,i);
2509 	sc->color = col;
2510     }
2511     GDrawRequestExpose(fv->v,NULL,false);
2512 }
2513 
FVMenuSetColor(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))2514 static void FVMenuSetColor(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
2515     FontView *fv = (FontView *) GDrawGetUserData(gw);
2516     Color col = (Color) (intpt) (mi->ti.userdata);
2517     if ( (intpt) mi->ti.userdata == (intpt) -10 ) {
2518 	struct hslrgb retcol, font_cols[6];
2519 	retcol = GWidgetColor(_("Pick a color"),NULL,SFFontCols(fv->b.sf,font_cols));
2520 	if ( !retcol.rgb )
2521 return;
2522 	col = (((int) rint(255.*retcol.r))<<16 ) |
2523 		    (((int) rint(255.*retcol.g))<<8 ) |
2524 		    (((int) rint(255.*retcol.b)) );
2525     }
2526     FVSetColor(fv,col);
2527 }
2528 
FVMenuShowDependentRefs(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))2529 static void FVMenuShowDependentRefs(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2530     FontView *fv = (FontView *) GDrawGetUserData(gw);
2531     int pos = FVAnyCharSelected(fv);
2532     SplineChar *sc;
2533 
2534     if ( pos<0 || fv->b.map->map[pos]==-1 )
2535 return;
2536     sc = fv->b.sf->glyphs[fv->b.map->map[pos]];
2537     if ( sc==NULL || sc->dependents==NULL )
2538 return;
2539     SCRefBy(sc);
2540 }
2541 
FVMenuShowDependentSubs(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))2542 static void FVMenuShowDependentSubs(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2543     FontView *fv = (FontView *) GDrawGetUserData(gw);
2544     int pos = FVAnyCharSelected(fv);
2545     SplineChar *sc;
2546 
2547     if ( pos<0 || fv->b.map->map[pos]==-1 )
2548 return;
2549     sc = fv->b.sf->glyphs[fv->b.map->map[pos]];
2550     if ( sc==NULL )
2551 return;
2552     SCSubBy(sc);
2553 }
2554 
getorigin(void * UNUSED (d),BasePoint * base,int index)2555 static int getorigin(void *UNUSED(d), BasePoint *base, int index) {
2556     /*FontView *fv = (FontView *) d;*/
2557 
2558     base->x = base->y = 0;
2559     switch ( index ) {
2560       case 0:		/* Character origin */
2561 	/* all done */
2562       break;
2563       case 1:		/* Center of selection */
2564 	/*CVFindCenter(cv,base,!CVAnySel(cv,NULL,NULL,NULL,NULL));*/
2565       break;
2566       default:
2567 return( false );
2568     }
2569 return( true );
2570 }
2571 
FVDoTransform(FontView * fv)2572 static void FVDoTransform(FontView *fv) {
2573     enum transdlg_flags flags=tdf_enableback|tdf_enablekerns;
2574     if ( FVAnyCharSelected(fv)==-1 )
2575 return;
2576     if ( FVAllSelected(fv))
2577 	flags=tdf_enableback|tdf_enablekerns|tdf_defaultkerns;
2578     TransformDlgCreate(fv,FVTransFunc,getorigin,flags,cvt_none);
2579 }
2580 
FVMenuTransform(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))2581 static void FVMenuTransform(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2582     FontView *fv = (FontView *) GDrawGetUserData(gw);
2583     FVDoTransform(fv);
2584 }
2585 
FVMenuPOV(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))2586 static void FVMenuPOV(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2587     FontView *fv = (FontView *) GDrawGetUserData(gw);
2588     struct pov_data pov_data;
2589     if ( FVAnyCharSelected(fv)==-1 || fv->b.sf->onlybitmaps )
2590 return;
2591     if ( PointOfViewDlg(&pov_data,fv->b.sf,false)==-1 )
2592 return;
2593     FVPointOfView((FontViewBase *) fv,&pov_data);
2594 }
2595 
FVMenuNLTransform(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))2596 static void FVMenuNLTransform(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2597     FontView *fv = (FontView *) GDrawGetUserData(gw);
2598     if ( FVAnyCharSelected(fv)==-1 )
2599 return;
2600     NonLinearDlg(fv,NULL);
2601 }
2602 
FVMenuBitmaps(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))2603 static void FVMenuBitmaps(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
2604     FontView *fv = (FontView *) GDrawGetUserData(gw);
2605     BitmapDlg(fv,NULL,mi->mid==MID_RemoveBitmaps?-1:(mi->mid==MID_AvailBitmaps) );
2606 }
2607 
FVMenuStroke(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))2608 static void FVMenuStroke(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2609     FontView *fv = (FontView *) GDrawGetUserData(gw);
2610     FVStroke(fv);
2611 }
2612 
2613 #  ifdef FONTFORGE_CONFIG_TILEPATH
FVMenuTilePath(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))2614 static void FVMenuTilePath(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2615     FontView *fv = (FontView *) GDrawGetUserData(gw);
2616     FVTile(fv);
2617 }
2618 
FVMenuPatternTile(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))2619 static void FVMenuPatternTile(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2620     FontView *fv = (FontView *) GDrawGetUserData(gw);
2621     FVPatternTile(fv);
2622 }
2623 #endif
2624 
FVMenuOverlap(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))2625 static void FVMenuOverlap(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
2626     FontView *fv = (FontView *) GDrawGetUserData(gw);
2627 
2628     if ( fv->b.sf->onlybitmaps )
2629 return;
2630 
2631     /* We know it's more likely that we'll find a problem in the overlap code */
2632     /*  than anywhere else, so let's save the current state against a crash */
2633     DoAutoSaves();
2634 
2635     FVOverlap(&fv->b,mi->mid==MID_RmOverlap ? over_remove :
2636 		 mi->mid==MID_Intersection ? over_intersect :
2637 		      over_findinter);
2638 }
2639 
FVMenuInline(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))2640 static void FVMenuInline(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2641     FontView *fv = (FontView *) GDrawGetUserData(gw);
2642 
2643     OutlineDlg(fv,NULL,NULL,true);
2644 }
2645 
FVMenuOutline(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))2646 static void FVMenuOutline(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2647     FontView *fv = (FontView *) GDrawGetUserData(gw);
2648 
2649     OutlineDlg(fv,NULL,NULL,false);
2650 }
2651 
FVMenuShadow(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))2652 static void FVMenuShadow(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2653     FontView *fv = (FontView *) GDrawGetUserData(gw);
2654 
2655     ShadowDlg(fv,NULL,NULL,false);
2656 }
2657 
FVMenuWireframe(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))2658 static void FVMenuWireframe(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2659     FontView *fv = (FontView *) GDrawGetUserData(gw);
2660 
2661     ShadowDlg(fv,NULL,NULL,true);
2662 }
2663 
FVSimplify(FontView * fv,int type)2664 static void FVSimplify(FontView *fv,int type) {
2665     static struct simplifyinfo smpls[] = {
2666 	    { sf_normal, 0, 0, 0, 0, 0, 0 },
2667 	    { sf_normal,.75,.05,0,-1, 0, 0 },
2668 	    { sf_normal,.75,.05,0,-1, 0, 0 }};
2669     struct simplifyinfo *smpl = &smpls[type+1];
2670 
2671     if ( smpl->linelenmax==-1 || (type==0 && !smpl->set_as_default)) {
2672 	smpl->err = (fv->b.sf->ascent+fv->b.sf->descent)/1000.;
2673 	smpl->linelenmax = (fv->b.sf->ascent+fv->b.sf->descent)/100.;
2674     }
2675 
2676     if ( type==1 ) {
2677 	if ( !SimplifyDlg(fv->b.sf,smpl))
2678 return;
2679 	if ( smpl->set_as_default )
2680 	    smpls[1] = *smpl;
2681     }
2682     _FVSimplify((FontViewBase *) fv,smpl);
2683 }
2684 
FVMenuSimplify(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))2685 static void FVMenuSimplify(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2686     FVSimplify( (FontView *) GDrawGetUserData(gw),false );
2687 }
2688 
FVMenuSimplifyMore(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))2689 static void FVMenuSimplifyMore(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2690     FVSimplify( (FontView *) GDrawGetUserData(gw),true );
2691 }
2692 
FVMenuCleanup(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))2693 static void FVMenuCleanup(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2694     FVSimplify( (FontView *) GDrawGetUserData(gw),-1 );
2695 }
2696 
FVMenuCanonicalStart(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))2697 static void FVMenuCanonicalStart(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2698     FVCanonicalStart( (FontViewBase *) GDrawGetUserData(gw) );
2699 }
2700 
FVMenuCanonicalContours(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))2701 static void FVMenuCanonicalContours(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2702     FVCanonicalContours( (FontViewBase *) GDrawGetUserData(gw) );
2703 }
2704 
FVMenuAddExtrema(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))2705 static void FVMenuAddExtrema(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2706     FVAddExtrema( (FontViewBase *) GDrawGetUserData(gw) , false);
2707 }
2708 
FVMenuCorrectDir(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))2709 static void FVMenuCorrectDir(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2710     FontView *fv = (FontView *) GDrawGetUserData(gw);
2711     FVCorrectDir((FontViewBase *) fv);
2712 }
2713 
FVMenuRound2Int(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))2714 static void FVMenuRound2Int(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2715     FVRound2Int( (FontViewBase *) GDrawGetUserData(gw), 1.0 );
2716 }
2717 
FVMenuRound2Hundredths(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))2718 static void FVMenuRound2Hundredths(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2719     FVRound2Int( (FontViewBase *) GDrawGetUserData(gw),100.0 );
2720 }
2721 
FVMenuCluster(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))2722 static void FVMenuCluster(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2723     FVCluster( (FontViewBase *) GDrawGetUserData(gw));
2724 }
2725 
FVMenuAutotrace(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * e)2726 static void FVMenuAutotrace(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *e) {
2727     FontView *fv = (FontView *) GDrawGetUserData(gw);
2728     GCursor ct=0;
2729 
2730     if ( fv->v!=NULL ) {
2731 	ct = GDrawGetCursor(fv->v);
2732 	GDrawSetCursor(fv->v,ct_watch);
2733 	GDrawSync(NULL);
2734 	GDrawProcessPendingEvents(NULL);
2735     }
2736     FVAutoTrace(&fv->b,e!=NULL && (e->u.mouse.state&ksm_shift));
2737     if ( fv->v!=NULL )
2738 	GDrawSetCursor(fv->v,ct);
2739 }
2740 
FVMenuBuildAccent(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))2741 static void FVMenuBuildAccent(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2742     FVBuildAccent( (FontViewBase *) GDrawGetUserData(gw), true );
2743 }
2744 
FVMenuBuildComposite(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))2745 static void FVMenuBuildComposite(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2746     FVBuildAccent( (FontViewBase *) GDrawGetUserData(gw), false );
2747 }
2748 
FVMenuBuildDuplicate(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))2749 static void FVMenuBuildDuplicate(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2750     FVBuildDuplicate( (FontViewBase *) GDrawGetUserData(gw));
2751 }
2752 
2753 #ifdef KOREAN
FVMenuShowGroup(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))2754 static void FVMenuShowGroup(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2755     ShowGroup( ((FontView *) GDrawGetUserData(gw))->sf );
2756 }
2757 #endif
2758 
2759 #if HANYANG
FVMenuModifyComposition(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))2760 static void FVMenuModifyComposition(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2761     FontView *fv = (FontView *) GDrawGetUserData(gw);
2762     if ( fv->b.sf->rules!=NULL )
2763 	SFModifyComposition(fv->b.sf);
2764 }
2765 
FVMenuBuildSyllables(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))2766 static void FVMenuBuildSyllables(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2767     FontView *fv = (FontView *) GDrawGetUserData(gw);
2768     if ( fv->b.sf->rules!=NULL )
2769 	SFBuildSyllables(fv->b.sf);
2770 }
2771 #endif
2772 
FVMenuCompareFonts(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))2773 static void FVMenuCompareFonts(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2774     FontView *fv = (FontView *) GDrawGetUserData(gw);
2775     FontCompareDlg(fv);
2776 }
2777 
FVMenuMergeFonts(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))2778 static void FVMenuMergeFonts(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2779     FontView *fv = (FontView *) GDrawGetUserData(gw);
2780     FVMergeFonts(fv);
2781 }
2782 
FVMenuInterpFonts(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))2783 static void FVMenuInterpFonts(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2784     FontView *fv = (FontView *) GDrawGetUserData(gw);
2785     FVInterpolateFonts(fv);
2786 }
2787 
2788 static void FVShowInfo(FontView *fv);
2789 
FVChangeChar(FontView * fv,int i)2790 void FVChangeChar(FontView *fv,int i) {
2791 
2792     if ( i!=-1 ) {
2793 	FVDeselectAll(fv);
2794 	fv->b.selected[i] = true;
2795 	fv->sel_index = 1;
2796 	fv->end_pos = fv->pressed_pos = i;
2797 	FVToggleCharSelected(fv,i);
2798 	FVScrollToChar(fv,i);
2799 	FVShowInfo(fv);
2800     }
2801 }
2802 
FVScrollToChar(FontView * fv,int i)2803 void FVScrollToChar(FontView *fv,int i) {
2804 
2805     if ( fv->v==NULL || fv->colcnt==0 )	/* Can happen in scripts */
2806 return;
2807 
2808     if ( i!=-1 ) {
2809 	if ( i/fv->colcnt<fv->rowoff || i/fv->colcnt >= fv->rowoff+fv->rowcnt ) {
2810 	    fv->rowoff = i/fv->colcnt;
2811 	    if ( fv->rowcnt>= 3 )
2812 		--fv->rowoff;
2813 	    if ( fv->rowoff+fv->rowcnt>=fv->rowltot )
2814 		fv->rowoff = fv->rowltot-fv->rowcnt;
2815 	    if ( fv->rowoff<0 ) fv->rowoff = 0;
2816 	    GScrollBarSetPos(fv->vsb,fv->rowoff);
2817 	    GDrawRequestExpose(fv->v,NULL,false);
2818 	}
2819     }
2820 }
2821 
FVScrollToGID(FontView * fv,int gid)2822 static void FVScrollToGID(FontView *fv,int gid) {
2823     FVScrollToChar(fv,fv->b.map->backmap[gid]);
2824 }
2825 
FV_ChangeGID(FontView * fv,int gid)2826 static void FV_ChangeGID(FontView *fv,int gid) {
2827     FVChangeChar(fv,fv->b.map->backmap[gid]);
2828 }
2829 
_FVMenuChangeChar(FontView * fv,int mid)2830 static void _FVMenuChangeChar(FontView *fv,int mid ) {
2831     SplineFont *sf = fv->b.sf;
2832     EncMap *map = fv->b.map;
2833     int pos = FVAnyCharSelected(fv);
2834 
2835     if ( pos>=0 ) {
2836 	if ( mid==MID_Next )
2837 	    ++pos;
2838 	else if ( mid==MID_Prev )
2839 	    --pos;
2840 	else if ( mid==MID_NextDef ) {
2841 	    for ( ++pos; pos<map->enccount &&
2842 		    (map->map[pos]==-1 || !SCWorthOutputting(sf->glyphs[map->map[pos]]) ||
2843 			(fv->show!=fv->filled && fv->show->glyphs[map->map[pos]]==NULL ));
2844 		    ++pos );
2845 	    if ( pos>=map->enccount ) {
2846 		int selpos = FVAnyCharSelected(fv);
2847 		char *iconv_name = map->enc->iconv_name ? map->enc->iconv_name :
2848 			map->enc->enc_name;
2849 		if ( strstr(iconv_name,"2022")!=NULL && selpos<0x2121 )
2850 		    pos = 0x2121;
2851 		else if ( strstr(iconv_name,"EUC")!=NULL && selpos<0xa1a1 )
2852 		    pos = 0xa1a1;
2853 		else if ( map->enc->is_tradchinese ) {
2854 		    if ( strstrmatch(map->enc->enc_name,"HK")!=NULL &&
2855 			    selpos<0x8140 )
2856 			pos = 0x8140;
2857 		    else
2858 			pos = 0xa140;
2859 		} else if ( map->enc->is_japanese ) {
2860 		    if ( strstrmatch(iconv_name,"SJIS")!=NULL ||
2861 			    (strstrmatch(iconv_name,"JIS")!=NULL && strstrmatch(iconv_name,"SHIFT")!=NULL )) {
2862 			if ( selpos<0x8100 )
2863 			    pos = 0x8100;
2864 			else if ( selpos<0xb000 )
2865 			    pos = 0xb000;
2866 		    }
2867 		} else if ( map->enc->is_korean ) {
2868 		    if ( strstrmatch(iconv_name,"JOHAB")!=NULL ) {
2869 			if ( selpos<0x8431 )
2870 			    pos = 0x8431;
2871 		    } else {	/* Wansung, EUC-KR */
2872 			if ( selpos<0xa1a1 )
2873 			    pos = 0xa1a1;
2874 		    }
2875 		} else if ( map->enc->is_simplechinese ) {
2876 		    if ( strmatch(iconv_name,"EUC-CN")==0 && selpos<0xa1a1 )
2877 			pos = 0xa1a1;
2878 		}
2879 		if ( pos>=map->enccount )
2880 return;
2881 	    }
2882 	} else if ( mid==MID_PrevDef ) {
2883 	    for ( --pos; pos>=0 &&
2884 		    (map->map[pos]==-1 || !SCWorthOutputting(sf->glyphs[map->map[pos]]) ||
2885 			(fv->show!=fv->filled && fv->show->glyphs[map->map[pos]]==NULL ));
2886 		    --pos );
2887 	    if ( pos<0 )
2888 return;
2889 	}
2890     }
2891     if ( pos<0 ) pos = map->enccount-1;
2892     else if ( pos>= map->enccount ) pos = 0;
2893     if ( pos>=0 && pos<map->enccount )
2894 	FVChangeChar(fv,pos);
2895 }
2896 
FVMenuChangeChar(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))2897 static void FVMenuChangeChar(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
2898     FontView *fv = (FontView *) GDrawGetUserData(gw);
2899     _FVMenuChangeChar(fv,mi->mid);
2900 }
2901 
FVShowSubFont(FontView * fv,SplineFont * new)2902 static void FVShowSubFont(FontView *fv,SplineFont *new) {
2903     MetricsView *mv, *mvnext;
2904     BDFFont *newbdf;
2905     int wascompact = fv->b.normal!=NULL;
2906     extern int use_freetype_to_rasterize_fv;
2907 
2908     for ( mv=fv->b.sf->metrics; mv!=NULL; mv = mvnext ) {
2909 	/* Don't bother trying to fix up metrics views, just not worth it */
2910 	mvnext = mv->next;
2911 	GDrawDestroyWindow(mv->gw);
2912     }
2913     if ( wascompact ) {
2914 	EncMapFree(fv->b.map);
2915 	if (fv->b.map == fv->b.sf->map) { fv->b.sf->map = fv->b.normal; }
2916 	fv->b.map = fv->b.normal;
2917 	fv->b.normal = NULL;
2918 	fv->b.selected = realloc(fv->b.selected,fv->b.map->enccount);
2919 	memset(fv->b.selected,0,fv->b.map->enccount);
2920     }
2921     CIDSetEncMap((FontViewBase *) fv,new);
2922     if ( wascompact ) {
2923 	fv->b.normal = EncMapCopy(fv->b.map);
2924 	CompactEncMap(fv->b.map,fv->b.sf);
2925 	FontViewReformatOne(&fv->b);
2926 	FVSetTitle(&fv->b);
2927     }
2928     newbdf = SplineFontPieceMeal(fv->b.sf,fv->b.active_layer,fv->filled->pixelsize,72,
2929 	    (fv->antialias?pf_antialias:0)|(fv->bbsized?pf_bbsized:0)|
2930 		(use_freetype_to_rasterize_fv && !fv->b.sf->strokedfont && !fv->b.sf->multilayer?pf_ft_nohints:0),
2931 	    NULL);
2932     BDFFontFree(fv->filled);
2933     if ( fv->filled == fv->show )
2934 	fv->show = newbdf;
2935     fv->filled = newbdf;
2936     GDrawRequestExpose(fv->v,NULL,true);
2937 }
2938 
FVMenuGotoChar(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))2939 static void FVMenuGotoChar(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2940     FontView *fv = (FontView *) GDrawGetUserData(gw);
2941     int merge_with_selection = false;
2942     int pos = GotoChar(fv->b.sf,fv->b.map,&merge_with_selection);
2943     if ( fv->b.cidmaster!=NULL && pos!=-1 && !fv->b.map->enc->is_compact ) {
2944 	SplineFont *cidmaster = fv->b.cidmaster;
2945 	int k, hadk= cidmaster->subfontcnt;
2946 	for ( k=0; k<cidmaster->subfontcnt; ++k ) {
2947 	    SplineFont *sf = cidmaster->subfonts[k];
2948 	    if ( pos<sf->glyphcnt && sf->glyphs[pos]!=NULL )
2949 	break;
2950 	    if ( pos<sf->glyphcnt )
2951 		hadk = k;
2952 	}
2953 	if ( k==cidmaster->subfontcnt && pos>=fv->b.sf->glyphcnt )
2954 	    k = hadk;
2955 	if ( k!=cidmaster->subfontcnt && cidmaster->subfonts[k] != fv->b.sf )
2956 	    FVShowSubFont(fv,cidmaster->subfonts[k]);
2957 	if ( pos>=fv->b.sf->glyphcnt )
2958 	    pos = -1;
2959     }
2960     if ( !merge_with_selection )
2961 	FVChangeChar(fv,pos);
2962     else {
2963 	if ( !fv->b.selected[pos] ) {
2964 	    fv->b.selected[pos] = ++fv->sel_index;
2965 	    FVToggleCharSelected(fv,pos);
2966 	}
2967 	fv->end_pos = fv->pressed_pos = pos;
2968 	FVScrollToChar(fv,pos);
2969 	FVShowInfo(fv);
2970     }
2971 }
2972 
FVMenuLigatures(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))2973 static void FVMenuLigatures(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2974     FontView *fv = (FontView *) GDrawGetUserData(gw);
2975     SFShowLigatures(fv->b.sf,NULL);
2976 }
2977 
FVMenuKernPairs(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))2978 static void FVMenuKernPairs(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2979     FontView *fv = (FontView *) GDrawGetUserData(gw);
2980     SFKernClassTempDecompose(fv->b.sf,false);
2981     SFShowKernPairs(fv->b.sf,NULL,NULL,fv->b.active_layer);
2982     SFKernCleanup(fv->b.sf,false);
2983 }
2984 
FVMenuAnchorPairs(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))2985 static void FVMenuAnchorPairs(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
2986     FontView *fv = (FontView *) GDrawGetUserData(gw);
2987     SFShowKernPairs(fv->b.sf,NULL,mi->ti.userdata,fv->b.active_layer);
2988 }
2989 
FVMenuShowAtt(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))2990 static void FVMenuShowAtt(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2991     FontView *fv = (FontView *) GDrawGetUserData(gw);
2992     ShowAtt(fv->b.sf,fv->b.active_layer);
2993 }
2994 
FVMenuDisplaySubs(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))2995 static void FVMenuDisplaySubs(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2996     FontView *fv = (FontView *) GDrawGetUserData(gw);
2997 
2998     if ( fv->cur_subtable!=0 ) {
2999 	fv->cur_subtable = NULL;
3000     } else {
3001 	SplineFont *sf = fv->b.sf;
3002 	OTLookup *otf;
3003 	struct lookup_subtable *sub;
3004 	int cnt, k;
3005 	char **names = NULL;
3006 	if ( sf->cidmaster ) sf=sf->cidmaster;
3007 	for ( k=0; k<2; ++k ) {
3008 	    cnt = 0;
3009 	    for ( otf = sf->gsub_lookups; otf!=NULL; otf=otf->next ) {
3010 		if ( otf->lookup_type==gsub_single ) {
3011 		    for ( sub=otf->subtables; sub!=NULL; sub=sub->next ) {
3012 			if ( names )
3013 			    names[cnt] = sub->subtable_name;
3014 			++cnt;
3015 		    }
3016 		}
3017 	    }
3018 	    if ( cnt==0 )
3019 	break;
3020 	    if ( names==NULL )
3021 		names = malloc((cnt+3) * sizeof(char *));
3022 	    else {
3023 		names[cnt++] = "-";
3024 		names[cnt++] = _("New Lookup Subtable...");
3025 		names[cnt] = NULL;
3026 	    }
3027 	}
3028 	sub = NULL;
3029 	if ( names!=NULL ) {
3030 	    int ret = gwwv_choose(_("Display Substitution..."), (const char **) names, cnt, 0,
3031 		    _("Pick a substitution to display in the window."));
3032 	    if ( ret!=-1 )
3033 		sub = SFFindLookupSubtable(sf,names[ret]);
3034 	    free(names);
3035 	    if ( ret==-1 )
3036 return;
3037 	}
3038 	if ( sub==NULL )
3039 	    sub = SFNewLookupSubtableOfType(sf,gsub_single,NULL,fv->b.active_layer);
3040 	if ( sub!=NULL )
3041 	    fv->cur_subtable = sub;
3042     }
3043     GDrawRequestExpose(fv->v,NULL,false);
3044 }
3045 
FVChangeDisplayFont(FontView * fv,BDFFont * bdf)3046 static void FVChangeDisplayFont(FontView *fv,BDFFont *bdf) {
3047     int samesize=0;
3048     int rcnt, ccnt;
3049     int oldr, oldc;
3050     int first_time = fv->show==NULL;
3051 
3052     if ( fv->v==NULL )			/* Can happen in scripts */
3053 return;
3054 
3055     if ( fv->show!=bdf ) {
3056 	oldc = fv->cbw*fv->colcnt;
3057 	oldr = fv->cbh*fv->rowcnt;
3058 
3059 	fv->show = bdf;
3060 	fv->b.active_bitmap = bdf==fv->filled ? NULL : bdf;
3061 	if ( fv->user_requested_magnify!=-1 )
3062 	    fv->magnify=fv->user_requested_magnify;
3063 	else if ( bdf->pixelsize<20 ) {
3064 	    if ( bdf->pixelsize<=9 )
3065 		fv->magnify = 3;
3066 	    else
3067 		fv->magnify = 2;
3068 	    samesize = ( fv->show && fv->cbw == (bdf->pixelsize*fv->magnify)+1 );
3069 	} else
3070 	    fv->magnify = 1;
3071 	if ( !first_time && fv->cbw == fv->magnify*bdf->pixelsize+1 )
3072 	    samesize = true;
3073 	fv->cbw = (bdf->pixelsize*fv->magnify)+1;
3074 	fv->cbh = (bdf->pixelsize*fv->magnify)+1+fv->lab_height+1;
3075 	fv->resize_expected = !samesize;
3076 	ccnt = fv->b.sf->desired_col_cnt;
3077 	rcnt = fv->b.sf->desired_row_cnt;
3078 	if ((( bdf->pixelsize<=fv->b.sf->display_size || bdf->pixelsize<=-fv->b.sf->display_size ) &&
3079 		 fv->b.sf->top_enc!=-1 /* Not defaulting */ ) ||
3080 		bdf->pixelsize<=48 ) {
3081 	    /* use the desired sizes */
3082 	} else {
3083 	    if ( bdf->pixelsize>48 ) {
3084 		ccnt = 8;
3085 		rcnt = 2;
3086 	    } else if ( bdf->pixelsize>=96 ) {
3087 		ccnt = 4;
3088 		rcnt = 1;
3089 	    }
3090 	    if ( !first_time ) {
3091 		if ( ccnt < oldc/fv->cbw )
3092 		    ccnt = oldc/fv->cbw;
3093 		if ( rcnt < oldr/fv->cbh )
3094 		    rcnt = oldr/fv->cbh;
3095 	    }
3096 	}
3097 	if ( samesize ) {
3098 	    GDrawRequestExpose(fv->v,NULL,false);
3099 	} else if ( fv->b.container!=NULL && fv->b.container->funcs->doResize!=NULL ) {
3100 	    (fv->b.container->funcs->doResize)(fv->b.container,&fv->b,
3101 		    ccnt*fv->cbw+1+GDrawPointsToPixels(fv->gw,_GScrollBar_Width),
3102 		    rcnt*fv->cbh+1+fv->mbh+fv->infoh);
3103 	} else {
3104 	    GDrawResize(fv->gw,
3105 		    ccnt*fv->cbw+1+GDrawPointsToPixels(fv->gw,_GScrollBar_Width),
3106 		    rcnt*fv->cbh+1+fv->mbh+fv->infoh);
3107 	}
3108     }
3109 }
3110 
3111 struct md_data {
3112     int done;
3113     int ish;
3114     FontView *fv;
3115 };
3116 
md_e_h(GWindow gw,GEvent * e)3117 static int md_e_h(GWindow gw, GEvent *e) {
3118     if ( e->type==et_close ) {
3119 	struct md_data *d = GDrawGetUserData(gw);
3120 	d->done = true;
3121     } else if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
3122 	struct md_data *d = GDrawGetUserData(gw);
3123 	static int masks[] = { fvm_baseline, fvm_origin, fvm_advanceat, fvm_advanceto, -1 };
3124 	int i, metrics;
3125 	if ( GGadgetGetCid(e->u.control.g)==10 ) {
3126 	    metrics = 0;
3127 	    for ( i=0; masks[i]!=-1 ; ++i )
3128 		if ( GGadgetIsChecked(GWidgetGetControl(gw,masks[i])))
3129 		    metrics |= masks[i];
3130 	    if ( d->ish )
3131 		default_fv_showhmetrics = d->fv->showhmetrics = metrics;
3132 	    else
3133 		default_fv_showvmetrics = d->fv->showvmetrics = metrics;
3134 	}
3135 	d->done = true;
3136     } else if ( e->type==et_char ) {
3137 return( false );
3138     }
3139 return( true );
3140 }
3141 
FVMenuShowMetrics(GWindow fvgw,struct gmenuitem * mi,GEvent * UNUSED (e))3142 static void FVMenuShowMetrics(GWindow fvgw,struct gmenuitem *mi, GEvent *UNUSED(e)) {
3143     FontView *fv = (FontView *) GDrawGetUserData(fvgw);
3144     GRect pos;
3145     GWindow gw;
3146     GWindowAttrs wattrs;
3147     struct md_data d;
3148     GGadgetCreateData gcd[7];
3149     GTextInfo label[6];
3150     int metrics = mi->mid==MID_ShowHMetrics ? fv->showhmetrics : fv->showvmetrics;
3151 
3152     d.fv = fv;
3153     d.done = 0;
3154     d.ish = mi->mid==MID_ShowHMetrics;
3155 
3156     memset(&wattrs,0,sizeof(wattrs));
3157     wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_undercursor|wam_restrict;
3158     wattrs.event_masks = ~(1<<et_charup);
3159     wattrs.restrict_input_to_me = 1;
3160     wattrs.undercursor = 1;
3161     wattrs.cursor = ct_pointer;
3162     wattrs.utf8_window_title = d.ish?_("Show H. Metrics"):_("Show V. Metrics");
3163     pos.x = pos.y = 0;
3164     pos.width =GDrawPointsToPixels(NULL,GGadgetScale(170));
3165     pos.height = GDrawPointsToPixels(NULL,130);
3166     gw = GDrawCreateTopWindow(NULL,&pos,md_e_h,&d,&wattrs);
3167 
3168     memset(&label,0,sizeof(label));
3169     memset(&gcd,0,sizeof(gcd));
3170 
3171     label[0].text = (unichar_t *) _("Baseline");
3172     label[0].text_is_1byte = true;
3173     gcd[0].gd.label = &label[0];
3174     gcd[0].gd.pos.x = 8; gcd[0].gd.pos.y = 8;
3175     gcd[0].gd.flags = gg_enabled|gg_visible|(metrics&fvm_baseline?gg_cb_on:0);
3176     gcd[0].gd.cid = fvm_baseline;
3177     gcd[0].creator = GCheckBoxCreate;
3178 
3179     label[1].text = (unichar_t *) _("Origin");
3180     label[1].text_is_1byte = true;
3181     gcd[1].gd.label = &label[1];
3182     gcd[1].gd.pos.x = 8; gcd[1].gd.pos.y = gcd[0].gd.pos.y+16;
3183     gcd[1].gd.flags = gg_enabled|gg_visible|(metrics&fvm_origin?gg_cb_on:0);
3184     gcd[1].gd.cid = fvm_origin;
3185     gcd[1].creator = GCheckBoxCreate;
3186 
3187     label[2].text = (unichar_t *) _("Advance Width as a Line");
3188     label[2].text_is_1byte = true;
3189     gcd[2].gd.label = &label[2];
3190     gcd[2].gd.pos.x = 8; gcd[2].gd.pos.y = gcd[1].gd.pos.y+16;
3191     gcd[2].gd.flags = gg_enabled|gg_visible|(metrics&fvm_advanceat?gg_cb_on:0);
3192     gcd[2].gd.cid = fvm_advanceat;
3193     gcd[2].gd.popup_msg = _("Display the advance width as a line\nperpendicular to the advance direction");
3194     gcd[2].creator = GCheckBoxCreate;
3195 
3196     label[3].text = (unichar_t *) _("Advance Width as a Bar");
3197     label[3].text_is_1byte = true;
3198     gcd[3].gd.label = &label[3];
3199     gcd[3].gd.pos.x = 8; gcd[3].gd.pos.y = gcd[2].gd.pos.y+16;
3200     gcd[3].gd.flags = gg_enabled|gg_visible|(metrics&fvm_advanceto?gg_cb_on:0);
3201     gcd[3].gd.cid = fvm_advanceto;
3202     gcd[3].gd.popup_msg = _("Display the advance width as a bar under the glyph\nshowing the extent of the advance");
3203     gcd[3].creator = GCheckBoxCreate;
3204 
3205     label[4].text = (unichar_t *) _("_OK");
3206     label[4].text_is_1byte = true;
3207     label[4].text_in_resource = true;
3208     gcd[4].gd.label = &label[4];
3209     gcd[4].gd.pos.x = 20-3; gcd[4].gd.pos.y = GDrawPixelsToPoints(NULL,pos.height)-35-3;
3210     gcd[4].gd.pos.width = -1; gcd[4].gd.pos.height = 0;
3211     gcd[4].gd.flags = gg_visible | gg_enabled | gg_but_default;
3212     gcd[4].gd.cid = 10;
3213     gcd[4].creator = GButtonCreate;
3214 
3215     label[5].text = (unichar_t *) _("_Cancel");
3216     label[5].text_is_1byte = true;
3217     label[5].text_in_resource = true;
3218     gcd[5].gd.label = &label[5];
3219     gcd[5].gd.pos.x = -20; gcd[5].gd.pos.y = gcd[4].gd.pos.y+3;
3220     gcd[5].gd.pos.width = -1; gcd[5].gd.pos.height = 0;
3221     gcd[5].gd.flags = gg_visible | gg_enabled | gg_but_cancel;
3222     gcd[5].creator = GButtonCreate;
3223 
3224     GGadgetsCreate(gw,gcd);
3225 
3226     GDrawSetVisible(gw,true);
3227     while ( !d.done )
3228 	GDrawProcessOneEvent(NULL);
3229     GDrawDestroyWindow(gw);
3230 
3231     SavePrefs(true);
3232     GDrawRequestExpose(fv->v,NULL,false);
3233 }
3234 
FV_ChangeDisplayBitmap(FontView * fv,BDFFont * bdf)3235 static void FV_ChangeDisplayBitmap(FontView *fv,BDFFont *bdf) {
3236     FVChangeDisplayFont(fv,bdf);
3237     if (fv->show != NULL) {
3238         fv->b.sf->display_size = fv->show->pixelsize;
3239     } else {
3240         fv->b.sf->display_size = 1;
3241     }
3242 }
3243 
FVMenuSize(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))3244 static void FVMenuSize(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
3245     FontView *fv = (FontView *) GDrawGetUserData(gw);
3246     int dspsize = fv->filled->pixelsize;
3247     int changedmodifier = false;
3248     extern int use_freetype_to_rasterize_fv;
3249 
3250     fv->magnify = 1;
3251     fv->user_requested_magnify = -1;
3252     if ( mi->mid == MID_24 )
3253 	default_fv_font_size = dspsize = 24;
3254     else if ( mi->mid == MID_36 )
3255 	default_fv_font_size = dspsize = 36;
3256     else if ( mi->mid == MID_48 )
3257 	default_fv_font_size = dspsize = 48;
3258     else if ( mi->mid == MID_72 )
3259 	default_fv_font_size = dspsize = 72;
3260     else if ( mi->mid == MID_96 )
3261 	default_fv_font_size = dspsize = 96;
3262     else if ( mi->mid == MID_128 )
3263 	default_fv_font_size = dspsize = 128;
3264     else if ( mi->mid == MID_FitToBbox ) {
3265 	default_fv_bbsized = fv->bbsized = !fv->bbsized;
3266 	fv->b.sf->display_bbsized = fv->bbsized;
3267 	changedmodifier = true;
3268     } else {
3269 	default_fv_antialias = fv->antialias = !fv->antialias;
3270 	fv->b.sf->display_antialias = fv->antialias;
3271 	changedmodifier = true;
3272     }
3273 
3274     SavePrefs(true);
3275     if ( fv->filled!=fv->show || fv->filled->pixelsize != dspsize || changedmodifier ) {
3276 	BDFFont *new, *old;
3277 	old = fv->filled;
3278 	new = SplineFontPieceMeal(fv->b.sf,fv->b.active_layer,dspsize,72,
3279 	    (fv->antialias?pf_antialias:0)|(fv->bbsized?pf_bbsized:0)|
3280 		(use_freetype_to_rasterize_fv && !fv->b.sf->strokedfont && !fv->b.sf->multilayer?pf_ft_nohints:0),
3281 	    NULL);
3282 	fv->filled = new;
3283 	FVChangeDisplayFont(fv,new);
3284 	BDFFontFree(old);
3285 	fv->b.sf->display_size = -dspsize;
3286 	if ( fv->b.cidmaster!=NULL ) {
3287 	    int i;
3288 	    for ( i=0; i<fv->b.cidmaster->subfontcnt; ++i )
3289 		fv->b.cidmaster->subfonts[i]->display_size = -dspsize;
3290 	}
3291     }
3292 }
3293 
FVSetUIToMatch(FontView * destfv,FontView * srcfv)3294 void FVSetUIToMatch(FontView *destfv,FontView *srcfv) {
3295     extern int use_freetype_to_rasterize_fv;
3296 
3297     if ( destfv->filled==NULL || srcfv->filled==NULL )
3298 return;
3299     if ( destfv->magnify!=srcfv->magnify ||
3300 	    destfv->user_requested_magnify!=srcfv->user_requested_magnify ||
3301 	    destfv->bbsized!=srcfv->bbsized ||
3302 	    destfv->antialias!=srcfv->antialias ||
3303 	    destfv->filled->pixelsize != srcfv->filled->pixelsize ) {
3304 	BDFFont *new, *old;
3305 	destfv->magnify = srcfv->magnify;
3306 	destfv->user_requested_magnify = srcfv->user_requested_magnify;
3307 	destfv->bbsized = srcfv->bbsized;
3308 	destfv->antialias = srcfv->antialias;
3309 	old = destfv->filled;
3310 	new = SplineFontPieceMeal(destfv->b.sf,destfv->b.active_layer,srcfv->filled->pixelsize,72,
3311 	    (destfv->antialias?pf_antialias:0)|(destfv->bbsized?pf_bbsized:0)|
3312 		(use_freetype_to_rasterize_fv && !destfv->b.sf->strokedfont && !destfv->b.sf->multilayer?pf_ft_nohints:0),
3313 	    NULL);
3314 	destfv->filled = new;
3315 	FVChangeDisplayFont(destfv,new);
3316 	BDFFontFree(old);
3317     }
3318 }
3319 
FV_LayerChanged(FontView * fv)3320 static void FV_LayerChanged( FontView *fv ) {
3321     extern int use_freetype_to_rasterize_fv;
3322     BDFFont *new, *old;
3323 
3324     fv->magnify = 1;
3325     fv->user_requested_magnify = -1;
3326 
3327     old = fv->filled;
3328     new = SplineFontPieceMeal(fv->b.sf,fv->b.active_layer,fv->filled->pixelsize,72,
3329 	(fv->antialias?pf_antialias:0)|(fv->bbsized?pf_bbsized:0)|
3330 	    (use_freetype_to_rasterize_fv && !fv->b.sf->strokedfont && !fv->b.sf->multilayer?pf_ft_nohints:0),
3331 	NULL);
3332     fv->filled = new;
3333     FVChangeDisplayFont(fv,new);
3334     fv->b.sf->display_size = -fv->filled->pixelsize;
3335     BDFFontFree(old);
3336 }
3337 
FVMenuChangeLayer(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))3338 static void FVMenuChangeLayer(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
3339     FontView *fv = (FontView *) GDrawGetUserData(gw);
3340 
3341     fv->b.active_layer = mi->mid;
3342     fv->b.sf->display_layer = mi->mid;
3343     FV_LayerChanged(fv);
3344 }
3345 
FVMenuMagnify(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))3346 static void FVMenuMagnify(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
3347     FontView *fv = (FontView *) GDrawGetUserData(gw);
3348     int magnify = fv->user_requested_magnify!=-1 ? fv->user_requested_magnify : fv->magnify;
3349     char def[20], *end, *ret;
3350     int val;
3351     BDFFont *show = fv->show;
3352 
3353     sprintf( def, "%d", magnify );
3354     ret = gwwv_ask_string(_("Bitmap Magnification..."),def,_("Please specify a bitmap magnification factor."));
3355     if ( ret==NULL )
3356 return;
3357     val = strtol(ret,&end,10);
3358     if ( val<1 || val>5 || *end!='\0' )
3359 	ff_post_error( _("Bad Number"),_("Bad Number") );
3360     else {
3361 	fv->user_requested_magnify = val;
3362 	fv->show = fv->filled;
3363 	fv->b.active_bitmap = NULL;
3364 	FVChangeDisplayFont(fv,show);
3365     }
3366     free(ret);
3367 }
3368 
FVMenuWSize(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))3369 static void FVMenuWSize(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
3370     FontView *fv = (FontView *) GDrawGetUserData(gw);
3371     int h,v;
3372     extern int default_fv_col_count, default_fv_row_count;
3373 
3374     if ( mi->mid == MID_32x8 ) {
3375 	h = 32; v=8;
3376     } else if ( mi->mid == MID_16x4 ) {
3377 	h = 16; v=4;
3378     } else {
3379 	h = 8; v=2;
3380     }
3381     GDrawResize(fv->gw,
3382 	    h*fv->cbw+1+GDrawPointsToPixels(fv->gw,_GScrollBar_Width),
3383 	    v*fv->cbh+1+fv->mbh+fv->infoh);
3384     fv->b.sf->desired_col_cnt = default_fv_col_count = h;
3385     fv->b.sf->desired_row_cnt = default_fv_row_count = v;
3386 
3387     SavePrefs(true);
3388 }
3389 
FVMenuGlyphLabel(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))3390 static void FVMenuGlyphLabel(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
3391     FontView *fv = (FontView *) GDrawGetUserData(gw);
3392 
3393     default_fv_glyphlabel = fv->glyphlabel = mi->mid;
3394 
3395     GDrawRequestExpose(fv->v,NULL,false);
3396 
3397     SavePrefs(true);
3398 }
3399 
FVMenuShowBitmap(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))3400 static void FVMenuShowBitmap(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
3401     FontView *fv = (FontView *) GDrawGetUserData(gw);
3402     BDFFont *bdf = mi->ti.userdata;
3403 
3404     FV_ChangeDisplayBitmap(fv,bdf);		/* Let's not change any of the others */
3405 }
3406 
FV_ShowFilled(FontView * fv)3407 static void FV_ShowFilled(FontView *fv) {
3408 
3409     fv->magnify = 1;
3410     fv->user_requested_magnify = 1;
3411     if ( fv->show!=fv->filled )
3412 	FVChangeDisplayFont(fv,fv->filled);
3413     fv->b.sf->display_size = -fv->filled->pixelsize;
3414     fv->b.active_bitmap = NULL;
3415 }
3416 
FVMenuCenter(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))3417 static void FVMenuCenter(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
3418     FontViewBase *fv = (FontViewBase *) GDrawGetUserData(gw);
3419     FVMetricsCenter(fv,mi->mid==MID_Center);
3420 }
3421 
FVMenuSetWidth(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))3422 static void FVMenuSetWidth(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
3423     FontView *fv = (FontView *) GDrawGetUserData(gw);
3424 
3425     if ( FVAnyCharSelected(fv)==-1 )
3426 return;
3427     if ( mi->mid == MID_SetVWidth && !fv->b.sf->hasvmetrics )
3428 return;
3429     FVSetWidth(fv,mi->mid==MID_SetWidth   ?wt_width:
3430 		  mi->mid==MID_SetLBearing?wt_lbearing:
3431 		  mi->mid==MID_SetRBearing?wt_rbearing:
3432 		  mi->mid==MID_SetBearings?wt_bearings:
3433 		  wt_vwidth);
3434 }
3435 
FVMenuAutoWidth(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))3436 static void FVMenuAutoWidth(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
3437     FontView *fv = (FontView *) GDrawGetUserData(gw);
3438 
3439     FVAutoWidth2(fv);
3440 }
3441 
FVMenuKernByClasses(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))3442 static void FVMenuKernByClasses(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
3443     FontView *fv = (FontView *) GDrawGetUserData(gw);
3444 
3445     ShowKernClasses(fv->b.sf,NULL,fv->b.active_layer,false);
3446 }
3447 
FVMenuVKernByClasses(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))3448 static void FVMenuVKernByClasses(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
3449     FontView *fv = (FontView *) GDrawGetUserData(gw);
3450 
3451     ShowKernClasses(fv->b.sf,NULL,fv->b.active_layer,true);
3452 }
3453 
FVMenuRemoveKern(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))3454 static void FVMenuRemoveKern(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
3455     FontView *fv = (FontView *) GDrawGetUserData(gw);
3456 
3457     FVRemoveKerns(&fv->b);
3458 }
3459 
FVMenuRemoveVKern(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))3460 static void FVMenuRemoveVKern(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
3461     FontView *fv = (FontView *) GDrawGetUserData(gw);
3462 
3463     FVRemoveVKerns(&fv->b);
3464 }
3465 
FVMenuKPCloseup(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))3466 static void FVMenuKPCloseup(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
3467     FontView *fv = (FontView *) GDrawGetUserData(gw);
3468     int i;
3469 
3470     for ( i=0; i<fv->b.map->enccount; ++i )
3471 	if ( fv->b.selected[i] )
3472     break;
3473     KernPairD(fv->b.sf,i==fv->b.map->enccount?NULL:
3474 		    fv->b.map->map[i]==-1?NULL:
3475 		    fv->b.sf->glyphs[fv->b.map->map[i]],NULL,fv->b.active_layer,
3476 		    false);
3477 }
3478 
FVMenuVKernFromHKern(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))3479 static void FVMenuVKernFromHKern(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
3480     FontView *fv = (FontView *) GDrawGetUserData(gw);
3481 
3482     FVVKernFromHKern(&fv->b);
3483 }
3484 
FVMenuAutoHint(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))3485 static void FVMenuAutoHint(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
3486     FontView *fv = (FontView *) GDrawGetUserData(gw);
3487     FVAutoHint( &fv->b );
3488 }
3489 
FVMenuAutoHintSubs(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))3490 static void FVMenuAutoHintSubs(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
3491     FontView *fv = (FontView *) GDrawGetUserData(gw);
3492     FVAutoHintSubs( &fv->b );
3493 }
3494 
FVMenuAutoCounter(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))3495 static void FVMenuAutoCounter(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
3496     FontView *fv = (FontView *) GDrawGetUserData(gw);
3497     FVAutoCounter( &fv->b );
3498 }
3499 
FVMenuDontAutoHint(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))3500 static void FVMenuDontAutoHint(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
3501     FontView *fv = (FontView *) GDrawGetUserData(gw);
3502     FVDontAutoHint( &fv->b );
3503 }
3504 
FVMenuDeltas(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))3505 static void FVMenuDeltas(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
3506     FontView *fv = (FontView *) GDrawGetUserData(gw);
3507 
3508     if ( !hasFreeTypeDebugger())
3509 return;
3510     DeltaSuggestionDlg(fv,NULL);
3511 }
3512 
FVMenuAutoInstr(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))3513 static void FVMenuAutoInstr(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
3514     FontView *fv = (FontView *) GDrawGetUserData(gw);
3515     FVAutoInstr( &fv->b );
3516 }
3517 
FVMenuEditInstrs(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))3518 static void FVMenuEditInstrs(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
3519     FontView *fv = (FontView *) GDrawGetUserData(gw);
3520     int index = FVAnyCharSelected(fv);
3521     SplineChar *sc;
3522     if ( index<0 )
3523 return;
3524     sc = SFMakeChar(fv->b.sf,fv->b.map,index);
3525     SCEditInstructions(sc);
3526 }
3527 
FVMenuEditTable(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))3528 static void FVMenuEditTable(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
3529     FontView *fv = (FontView *) GDrawGetUserData(gw);
3530     SFEditTable(fv->b.sf,
3531 	    mi->mid==MID_Editprep?CHR('p','r','e','p'):
3532 	    mi->mid==MID_Editfpgm?CHR('f','p','g','m'):
3533 	    mi->mid==MID_Editmaxp?CHR('m','a','x','p'):
3534 				  CHR('c','v','t',' '));
3535 }
3536 
FVMenuRmInstrTables(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))3537 static void FVMenuRmInstrTables(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
3538     FontView *fv = (FontView *) GDrawGetUserData(gw);
3539     TtfTablesFree(fv->b.sf->ttf_tables);
3540     fv->b.sf->ttf_tables = NULL;
3541     if ( !fv->b.sf->changed ) {
3542 	fv->b.sf->changed = true;
3543 	FVSetTitles(fv->b.sf);
3544     }
3545 }
3546 
FVMenuClearInstrs(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))3547 static void FVMenuClearInstrs(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
3548     FontView *fv = (FontView *) GDrawGetUserData(gw);
3549     FVClearInstrs(&fv->b);
3550 }
3551 
FVMenuClearHints(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))3552 static void FVMenuClearHints(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
3553     FontView *fv = (FontView *) GDrawGetUserData(gw);
3554     FVClearHints(&fv->b);
3555 }
3556 
FVMenuHistograms(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))3557 static void FVMenuHistograms(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
3558     FontView *fv = (FontView *) GDrawGetUserData(gw);
3559     SFHistogram(fv->b.sf, fv->b.active_layer, NULL,
3560 			FVAnyCharSelected(fv)!=-1?fv->b.selected:NULL,
3561 			fv->b.map,
3562 			mi->mid==MID_HStemHist ? hist_hstem :
3563 			mi->mid==MID_VStemHist ? hist_vstem :
3564 				hist_blues);
3565 }
3566 
3567 
FontViewSetTitle(FontView * fv)3568 static void FontViewSetTitle(FontView *fv) {
3569     unichar_t *title, *ititle, *temp;
3570     char *file=NULL;
3571     char *enc;
3572     int len;
3573 
3574     if ( fv->gw==NULL )		/* In scripting */
3575 return;
3576 
3577     enc = SFEncodingName(fv->b.sf,fv->b.normal?fv->b.normal:fv->b.map);
3578     len = strlen(fv->b.sf->fontname)+1 + strlen(enc)+6;
3579     if ( fv->b.normal ) len += strlen(_("Compact"))+1;
3580     if ( fv->b.cidmaster!=NULL ) {
3581 	if ( (file = fv->b.cidmaster->filename)==NULL )
3582 	    file = fv->b.cidmaster->origname;
3583     } else {
3584 	if ( (file = fv->b.sf->filename)==NULL )
3585 	    file = fv->b.sf->origname;
3586     }
3587     if ( file!=NULL )
3588 	len += 2+strlen(file);
3589     title = malloc((len+1)*sizeof(unichar_t));
3590     uc_strcpy(title,"");
3591     uc_strcat(title,fv->b.sf->fontname);
3592     if ( fv->b.sf->changed )
3593 	uc_strcat(title,"*");
3594     if ( file!=NULL ) {
3595 	uc_strcat(title,"  ");
3596 	temp = def2u_copy(GFileNameTail(file));
3597 	u_strcat(title,temp);
3598 	free(temp);
3599     }
3600     uc_strcat(title, " (" );
3601     if ( fv->b.normal ) { utf82u_strcat(title,_("Compact")); uc_strcat(title," "); }
3602     uc_strcat(title,enc);
3603     uc_strcat(title, ")" );
3604     free(enc);
3605 
3606     ititle = uc_copy(fv->b.sf->fontname);
3607     GDrawSetWindowTitles(fv->gw,title,ititle);
3608     free(title);
3609     free(ititle);
3610 }
3611 
FVTitleUpdate(FontViewBase * fv)3612 void FVTitleUpdate(FontViewBase *fv)
3613 {
3614     FontViewSetTitle( (FontView*)fv );
3615 }
3616 
FontViewSetTitles(SplineFont * sf)3617 static void FontViewSetTitles(SplineFont *sf) {
3618     FontView *fv;
3619 
3620     for ( fv = (FontView *) (sf->fv); fv!=NULL; fv=(FontView *) (fv->b.nextsame))
3621 	FontViewSetTitle(fv);
3622 }
3623 
FVMenuShowSubFont(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))3624 static void FVMenuShowSubFont(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
3625     FontView *fv = (FontView *) GDrawGetUserData(gw);
3626     SplineFont *new = mi->ti.userdata;
3627     FVShowSubFont(fv,new);
3628 }
3629 
FVMenuConvert2CID(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))3630 static void FVMenuConvert2CID(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
3631     FontView *fv = (FontView *) GDrawGetUserData(gw);
3632     SplineFont *cidmaster = fv->b.cidmaster;
3633     struct cidmap *cidmap;
3634 
3635     if ( cidmaster!=NULL )
3636 return;
3637     SFFindNearTop(fv->b.sf);
3638     cidmap = AskUserForCIDMap();
3639     if ( cidmap==NULL )
3640 return;
3641     MakeCIDMaster(fv->b.sf,fv->b.map,false,NULL,cidmap);
3642     SFRestoreNearTop(fv->b.sf);
3643 }
3644 
CMapFilter(GGadget * g,GDirEntry * ent,const unichar_t * dir)3645 static enum fchooserret CMapFilter(GGadget *g,GDirEntry *ent,
3646 	const unichar_t *dir) {
3647     enum fchooserret ret = GFileChooserDefFilter(g,ent,dir);
3648     char buf2[256];
3649     FILE *file;
3650     static char *cmapflag = "%!PS-Adobe-3.0 Resource-CMap";
3651 
3652     if ( ret==fc_show && !ent->isdir ) {
3653 	int len = 3*(u_strlen(dir)+u_strlen(ent->name)+5);
3654 	char *filename = malloc(len);
3655 	u2def_strncpy(filename,dir,len);
3656 	strcat(filename,"/");
3657 	u2def_strncpy(buf2,ent->name,sizeof(buf2));
3658 	strcat(filename,buf2);
3659 	file = fopen(filename,"r");
3660 	if ( file==NULL )
3661 	    ret = fc_hide;
3662 	else {
3663 	    if ( fgets(buf2,sizeof(buf2),file)==NULL ||
3664 		    strncmp(buf2,cmapflag,strlen(cmapflag))!=0 )
3665 		ret = fc_hide;
3666 	    fclose(file);
3667 	}
3668 	free(filename);
3669     }
3670 return( ret );
3671 }
3672 
FVMenuConvertByCMap(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))3673 static void FVMenuConvertByCMap(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
3674     FontView *fv = (FontView *) GDrawGetUserData(gw);
3675     SplineFont *cidmaster = fv->b.cidmaster;
3676     char *cmapfilename;
3677 
3678     if ( cidmaster!=NULL )
3679 return;
3680     cmapfilename = gwwv_open_filename(_("Find an adobe CMap file..."),NULL,NULL,CMapFilter);
3681     if ( cmapfilename==NULL )
3682 return;
3683     MakeCIDMaster(fv->b.sf,fv->b.map,true,cmapfilename,NULL);
3684     free(cmapfilename);
3685 }
3686 
FVMenuFlatten(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))3687 static void FVMenuFlatten(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
3688     FontView *fv = (FontView *) GDrawGetUserData(gw);
3689     SplineFont *cidmaster = fv->b.cidmaster;
3690 
3691     if ( cidmaster==NULL )
3692 return;
3693     SFFlatten(&cidmaster);
3694 }
3695 
FVMenuFlattenByCMap(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))3696 static void FVMenuFlattenByCMap(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
3697     FontView *fv = (FontView *) GDrawGetUserData(gw);
3698     SplineFont *cidmaster = fv->b.cidmaster;
3699     char *cmapname;
3700 
3701     if ( cidmaster==NULL )
3702 return;
3703     cmapname = gwwv_open_filename(_("Find an adobe CMap file..."),NULL,NULL,CMapFilter);
3704     if ( cmapname==NULL )
3705 return;
3706     SFFindNearTop(fv->b.sf);
3707     SFFlattenByCMap(&cidmaster,cmapname);
3708     SFRestoreNearTop(fv->b.sf);
3709     free(cmapname);
3710 }
3711 
FVMenuInsertFont(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))3712 static void FVMenuInsertFont(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
3713     FontView *fv = (FontView *) GDrawGetUserData(gw);
3714     SplineFont *cidmaster = fv->b.cidmaster;
3715     SplineFont *new;
3716     struct cidmap *map;
3717     char *filename;
3718     extern NameList *force_names_when_opening;
3719 
3720     if ( cidmaster==NULL || cidmaster->subfontcnt>=255 )	/* Open type allows 1 byte to specify the fdselect */
3721 return;
3722 
3723     filename = GetPostScriptFontName(NULL,false,true);
3724     if ( filename==NULL )
3725 return;
3726     new = LoadSplineFont(filename,0);
3727     free(filename);
3728     if ( new==NULL )
3729 return;
3730     if ( new->fv == &fv->b )		/* Already part of us */
3731 return;
3732     if ( new->fv != NULL ) {
3733 	if ( ((FontView *) (new->fv))->gw!=NULL )
3734 	    GDrawRaise( ((FontView *) (new->fv))->gw);
3735 	ff_post_error(_("Please close font"),_("Please close %s before inserting it into a CID font"),new->origname);
3736 return;
3737     }
3738     EncMapFree(new->map);
3739     if ( force_names_when_opening!=NULL )
3740 	SFRenameGlyphsToNamelist(new,force_names_when_opening );
3741 
3742     map = FindCidMap(cidmaster->cidregistry,cidmaster->ordering,cidmaster->supplement,cidmaster);
3743     SFEncodeToMap(new,map);
3744     if ( !PSDictHasEntry(new->private,"lenIV"))
3745 	PSDictChangeEntry(new->private,"lenIV","1");		/* It's 4 by default, in CIDs the convention seems to be 1 */
3746     new->display_antialias = fv->b.sf->display_antialias;
3747     new->display_bbsized = fv->b.sf->display_bbsized;
3748     new->display_size = fv->b.sf->display_size;
3749     FVInsertInCID((FontViewBase *) fv,new);
3750     CIDMasterAsDes(new);
3751 }
3752 
FVMenuInsertBlank(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))3753 static void FVMenuInsertBlank(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
3754     FontView *fv = (FontView *) GDrawGetUserData(gw);
3755     SplineFont *cidmaster = fv->b.cidmaster, *sf;
3756     struct cidmap *map;
3757 
3758     if ( cidmaster==NULL || cidmaster->subfontcnt>=255 )	/* Open type allows 1 byte to specify the fdselect */
3759 return;
3760     map = FindCidMap(cidmaster->cidregistry,cidmaster->ordering,cidmaster->supplement,cidmaster);
3761     sf = SplineFontBlank(MaxCID(map));
3762     sf->glyphcnt = sf->glyphmax;
3763     sf->cidmaster = cidmaster;
3764     sf->display_antialias = fv->b.sf->display_antialias;
3765     sf->display_bbsized = fv->b.sf->display_bbsized;
3766     sf->display_size = fv->b.sf->display_size;
3767     sf->private = calloc(1,sizeof(struct psdict));
3768     PSDictChangeEntry(sf->private,"lenIV","1");		/* It's 4 by default, in CIDs the convention seems to be 1 */
3769     FVInsertInCID((FontViewBase *) fv,sf);
3770 }
3771 
FVMenuRemoveFontFromCID(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))3772 static void FVMenuRemoveFontFromCID(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
3773     FontView *fv = (FontView *) GDrawGetUserData(gw);
3774     char *buts[3];
3775     SplineFont *cidmaster = fv->b.cidmaster, *sf = fv->b.sf, *replace;
3776     int i;
3777     MetricsView *mv, *mnext;
3778     FontView *fvs;
3779 
3780     if ( cidmaster==NULL || cidmaster->subfontcnt<=1 )	/* Can't remove last font */
3781 return;
3782     buts[0] = _("_Remove"); buts[1] = _("_Cancel"); buts[2] = NULL;
3783     if ( gwwv_ask(_("_Remove Font"),(const char **) buts,0,1,_("Are you sure you wish to remove sub-font %1$.40s from the CID font %2$.40s"),
3784 	    sf->fontname,cidmaster->fontname)==1 )
3785 return;
3786 
3787     for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL ) {
3788 	CharView *cv, *next;
3789 	for ( cv = (CharView *) (sf->glyphs[i]->views); cv!=NULL; cv = next ) {
3790 	    next = (CharView *) (cv->b.next);
3791 	    GDrawDestroyWindow(cv->gw);
3792 	}
3793     }
3794     GDrawProcessPendingEvents(NULL);
3795     for ( mv=fv->b.sf->metrics; mv!=NULL; mv = mnext ) {
3796 	mnext = mv->next;
3797 	GDrawDestroyWindow(mv->gw);
3798     }
3799     GDrawSync(NULL);
3800     GDrawProcessPendingEvents(NULL);
3801     /* Just in case... */
3802     GDrawSync(NULL);
3803     GDrawProcessPendingEvents(NULL);
3804 
3805     for ( i=0; i<cidmaster->subfontcnt; ++i )
3806 	if ( cidmaster->subfonts[i]==sf )
3807     break;
3808     replace = i==0?cidmaster->subfonts[1]:cidmaster->subfonts[i-1];
3809     while ( i<cidmaster->subfontcnt-1 ) {
3810 	cidmaster->subfonts[i] = cidmaster->subfonts[i+1];
3811 	++i;
3812     }
3813     --cidmaster->subfontcnt;
3814 
3815     for ( fvs=(FontView *) (fv->b.sf->fv); fvs!=NULL; fvs=(FontView *) (fvs->b.nextsame) ) {
3816 	if ( fvs->b.sf==sf )
3817 	    CIDSetEncMap((FontViewBase *) fvs,replace);
3818     }
3819     FontViewReformatAll(fv->b.sf);
3820     SplineFontFree(sf);
3821 }
3822 
FVMenuCIDFontInfo(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))3823 static void FVMenuCIDFontInfo(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
3824     FontView *fv = (FontView *) GDrawGetUserData(gw);
3825     SplineFont *cidmaster = fv->b.cidmaster;
3826 
3827     if ( cidmaster==NULL )
3828 return;
3829     FontInfo(cidmaster,fv->b.active_layer,-1,false);
3830 }
3831 
FVMenuChangeSupplement(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))3832 static void FVMenuChangeSupplement(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
3833     FontView *fv = (FontView *) GDrawGetUserData(gw);
3834     SplineFont *cidmaster = fv->b.cidmaster;
3835     struct cidmap *cidmap;
3836     char buffer[20];
3837     char *ret, *end;
3838     int supple;
3839 
3840     if ( cidmaster==NULL )
3841 return;
3842     sprintf(buffer,"%d",cidmaster->supplement);
3843     ret = gwwv_ask_string(_("Change Supplement..."),buffer,_("Please specify a new supplement for %.20s-%.20s"),
3844 	    cidmaster->cidregistry,cidmaster->ordering);
3845     if ( ret==NULL )
3846 return;
3847     supple = strtol(ret,&end,10);
3848     if ( *end!='\0' || supple<=0 ) {
3849 	free(ret);
3850 	ff_post_error( _("Bad Number"),_("Bad Number") );
3851 return;
3852     }
3853     free(ret);
3854     if ( supple!=cidmaster->supplement ) {
3855 	    /* this will make noises if it can't find an appropriate cidmap */
3856 	cidmap = FindCidMap(cidmaster->cidregistry,cidmaster->ordering,supple,cidmaster);
3857 	cidmaster->supplement = supple;
3858 	FontViewSetTitle(fv);
3859     }
3860 }
3861 
FVFindACharInDisplay(FontView * fv)3862 static SplineChar *FVFindACharInDisplay(FontView *fv) {
3863     int start, end, enc, gid;
3864     EncMap *map = fv->b.map;
3865     SplineFont *sf = fv->b.sf;
3866     SplineChar *sc;
3867 
3868     start = fv->rowoff*fv->colcnt;
3869     end = start + fv->rowcnt*fv->colcnt;
3870     for ( enc = start; enc<end && enc<map->enccount; ++enc ) {
3871 	if ( (gid=map->map[enc])!=-1 && (sc=sf->glyphs[gid])!=NULL )
3872 return( sc );
3873     }
3874 return( NULL );
3875 }
3876 
FVMenuReencode(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))3877 static void FVMenuReencode(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
3878     FontView *fv = (FontView *) GDrawGetUserData(gw);
3879     Encoding *enc = NULL;
3880     SplineChar *sc;
3881 
3882     sc = FVFindACharInDisplay(fv);
3883     enc = FindOrMakeEncoding(mi->ti.userdata);
3884     if ( enc==NULL ) {
3885 	IError("Known encoding could not be found");
3886 return;
3887     }
3888     FVReencode((FontViewBase *) fv,enc);
3889     if ( sc!=NULL ) {
3890 	int enc = fv->b.map->backmap[sc->orig_pos];
3891 	if ( enc!=-1 )
3892 	    FVScrollToChar(fv,enc);
3893     }
3894 }
3895 
FVMenuForceEncode(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))3896 static void FVMenuForceEncode(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
3897     FontView *fv = (FontView *) GDrawGetUserData(gw);
3898     Encoding *enc = NULL;
3899     int oldcnt = fv->b.map->enccount;
3900 
3901     enc = FindOrMakeEncoding(mi->ti.userdata);
3902     if ( enc==NULL ) {
3903 	IError("Known encoding could not be found");
3904 return;
3905     }
3906     SFForceEncoding(fv->b.sf,fv->b.map,enc);
3907     if ( oldcnt < fv->b.map->enccount ) {
3908 	fv->b.selected = realloc(fv->b.selected,fv->b.map->enccount);
3909 	memset(fv->b.selected+oldcnt,0,fv->b.map->enccount-oldcnt);
3910     }
3911     if ( fv->b.normal!=NULL ) {
3912 	EncMapFree(fv->b.normal);
3913 	if (fv->b.normal == fv->b.sf->map) { fv->b.sf->map = NULL; }
3914 	fv->b.normal = NULL;
3915     }
3916     SFReplaceEncodingBDFProps(fv->b.sf,fv->b.map);
3917     FontViewSetTitle(fv);
3918     FontViewReformatOne(&fv->b);
3919 }
3920 
FVMenuDisplayByGroups(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))3921 static void FVMenuDisplayByGroups(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
3922     FontView *fv = (FontView *) GDrawGetUserData(gw);
3923 
3924     DisplayGroups(fv);
3925 }
3926 
FVMenuDefineGroups(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))3927 static void FVMenuDefineGroups(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
3928     FontView *fv = (FontView *) GDrawGetUserData(gw);
3929 
3930     DefineGroups(fv);
3931 }
3932 
FVMenuMMValid(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))3933 static void FVMenuMMValid(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
3934     FontView *fv = (FontView *) GDrawGetUserData(gw);
3935     MMSet *mm = fv->b.sf->mm;
3936 
3937     if ( mm==NULL )
3938 return;
3939     MMValid(mm,true);
3940 }
3941 
FVMenuCreateMM(GWindow UNUSED (gw),struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))3942 static void FVMenuCreateMM(GWindow UNUSED(gw), struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
3943     MMWizard(NULL);
3944 }
3945 
FVMenuMMInfo(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))3946 static void FVMenuMMInfo(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
3947     FontView *fv = (FontView *) GDrawGetUserData(gw);
3948     MMSet *mm = fv->b.sf->mm;
3949 
3950     if ( mm==NULL )
3951 return;
3952     MMWizard(mm);
3953 }
3954 
FVMenuChangeMMBlend(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))3955 static void FVMenuChangeMMBlend(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
3956     FontView *fv = (FontView *) GDrawGetUserData(gw);
3957     MMSet *mm = fv->b.sf->mm;
3958 
3959     if ( mm==NULL || mm->apple )
3960 return;
3961     MMChangeBlend(mm,fv,false);
3962 }
3963 
FVMenuBlendToNew(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))3964 static void FVMenuBlendToNew(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
3965     FontView *fv = (FontView *) GDrawGetUserData(gw);
3966     MMSet *mm = fv->b.sf->mm;
3967 
3968     if ( mm==NULL )
3969 return;
3970     MMChangeBlend(mm,fv,true);
3971 }
3972 
cflistcheck(GWindow UNUSED (gw),struct gmenuitem * mi,GEvent * UNUSED (e))3973 static void cflistcheck(GWindow UNUSED(gw), struct gmenuitem *mi, GEvent *UNUSED(e)) {
3974     /*FontView *fv = (FontView *) GDrawGetUserData(gw);*/
3975 
3976     for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
3977 	switch ( mi->mid ) {
3978 	  case MID_AllFonts:
3979 	    mi->ti.checked = !onlycopydisplayed;
3980 	  break;
3981 	  case MID_DisplayedFont:
3982 	    mi->ti.checked = onlycopydisplayed;
3983 	  break;
3984 	  case MID_CharName:
3985 	    mi->ti.checked = copymetadata;
3986 	  break;
3987 	  case MID_TTFInstr:
3988 	    mi->ti.checked = copyttfinstr;
3989 	  break;
3990 	}
3991     }
3992 }
3993 
sllistcheck(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))3994 static void sllistcheck(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
3995     FontView *fv = (FontView *) GDrawGetUserData(gw);
3996     fv = fv;
3997 }
3998 
htlistcheck(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))3999 static void htlistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
4000     FontView *fv = (FontView *) GDrawGetUserData(gw);
4001     int anychars = FVAnyCharSelected(fv);
4002     int multilayer = fv->b.sf->multilayer;
4003 
4004     for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
4005 	switch ( mi->mid ) {
4006 	  case MID_AutoHint:
4007 	    mi->ti.disabled = anychars==-1 || multilayer;
4008 	  break;
4009 	  case MID_HintSubsPt:
4010 	    mi->ti.disabled = fv->b.sf->layers[fv->b.active_layer].order2 || anychars==-1 || multilayer;
4011 	    if ( fv->b.sf->mm!=NULL && fv->b.sf->mm->apple )
4012 		mi->ti.disabled = true;
4013 	  break;
4014 	  case MID_AutoCounter: case MID_DontAutoHint:
4015 	    mi->ti.disabled = fv->b.sf->layers[fv->b.active_layer].order2 || anychars==-1 || multilayer;
4016 	  break;
4017 	  case MID_AutoInstr: case MID_EditInstructions: case MID_Deltas:
4018 	    mi->ti.disabled = !fv->b.sf->layers[fv->b.active_layer].order2 || anychars==-1 || multilayer;
4019 	  break;
4020 	  case MID_RmInstrTables:
4021 	    mi->ti.disabled = fv->b.sf->ttf_tables==NULL;
4022 	  break;
4023 	  case MID_Editfpgm: case MID_Editprep: case MID_Editcvt: case MID_Editmaxp:
4024 	    mi->ti.disabled = !fv->b.sf->layers[fv->b.active_layer].order2 || multilayer;
4025 	  break;
4026 	  case MID_ClearHints: case MID_ClearWidthMD: case MID_ClearInstrs:
4027 	    mi->ti.disabled = anychars==-1;
4028 	  break;
4029 	}
4030     }
4031 }
4032 
fllistcheck(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))4033 static void fllistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
4034     FontView *fv = (FontView *) GDrawGetUserData(gw);
4035     int anychars = FVAnyCharSelected(fv);
4036     FontView *fvs;
4037     int in_modal = (fv->b.container!=NULL && fv->b.container->funcs->is_modal);
4038 
4039     for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
4040 	switch ( mi->mid ) {
4041 	  case MID_GenerateTTC:
4042 	    for ( fvs=fv_list; fvs!=NULL; fvs=(FontView *) (fvs->b.next) ) {
4043 		if ( fvs!=fv )
4044 	    break;
4045 	    }
4046 	    mi->ti.disabled = fvs==NULL;
4047 	  break;
4048 	  case MID_Revert:
4049 	    mi->ti.disabled = fv->b.sf->origname==NULL || fv->b.sf->new;
4050 	  break;
4051 	  case MID_RevertToBackup:
4052 	    /* We really do want to use filename here and origname above */
4053 	    mi->ti.disabled = true;
4054 	    if ( fv->b.sf->filename!=NULL ) {
4055 		if ( fv->b.sf->backedup == bs_dontknow ) {
4056 		    char *buf = malloc(strlen(fv->b.sf->filename)+20);
4057 		    strcpy(buf,fv->b.sf->filename);
4058 		    if ( fv->b.sf->compression!=0 )
4059 			strcat(buf,compressors[fv->b.sf->compression-1].ext);
4060 		    strcat(buf,"~");
4061 		    if ( access(buf,F_OK)==0 )
4062 			fv->b.sf->backedup = bs_backedup;
4063 		    else
4064 			fv->b.sf->backedup = bs_not;
4065 		    free(buf);
4066 		}
4067 		if ( fv->b.sf->backedup == bs_backedup )
4068 		    mi->ti.disabled = false;
4069 	    }
4070 	  break;
4071 	  case MID_RevertGlyph:
4072 	    mi->ti.disabled = fv->b.sf->origname==NULL || fv->b.sf->sfd_version<2 || anychars==-1 || fv->b.sf->compression!=0;
4073 	  break;
4074 	  case MID_Recent:
4075 	    mi->ti.disabled = !RecentFilesAny();
4076 	  break;
4077 	  case MID_ScriptMenu:
4078 	    mi->ti.disabled = script_menu_names[0]==NULL;
4079 	  break;
4080 	  case MID_Print:
4081 	    mi->ti.disabled = fv->b.sf->onlybitmaps || in_modal;
4082 	  break;
4083 	}
4084     }
4085 }
4086 
edlistcheck(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))4087 static void edlistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
4088     FontView *fv = (FontView *) GDrawGetUserData(gw);
4089     int pos = FVAnyCharSelected(fv), i, gid;
4090     int not_pasteable = pos==-1 ||
4091 		    (!CopyContainsSomething() && !SCClipboardHasPasteableContents());
4092     RefChar *base = CopyContainsRef(fv->b.sf);
4093     int base_enc = base!=NULL ? fv->b.map->backmap[base->orig_pos] : -1;
4094 
4095 
4096     for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
4097 	switch ( mi->mid ) {
4098 	  case MID_Paste: case MID_PasteInto:
4099 	    mi->ti.disabled = not_pasteable;
4100 	  break;
4101 	  case MID_PasteAfter:
4102 	    mi->ti.disabled = not_pasteable || pos<0;
4103 	  break;
4104 	  case MID_SameGlyphAs:
4105 	    mi->ti.disabled = not_pasteable || base==NULL || fv->b.cidmaster!=NULL ||
4106 		    base_enc==-1 ||
4107 		    fv->b.selected[base_enc];	/* Can't be self-referential */
4108 	  break;
4109 	  case MID_Join:
4110 	  case MID_Cut: case MID_Copy: case MID_Clear:
4111 	  case MID_CopyWidth: case MID_CopyLBearing: case MID_CopyRBearing:
4112 	  case MID_CopyRef: case MID_UnlinkRef:
4113 	  case MID_RemoveUndoes: case MID_CopyFgToBg: case MID_CopyL2L:
4114 	    mi->ti.disabled = pos==-1;
4115 	  break;
4116 	  case MID_RplRef:
4117 	  case MID_CorrectRefs:
4118 	    mi->ti.disabled = pos==-1 || fv->b.cidmaster!=NULL || fv->b.sf->multilayer;
4119 	  break;
4120 	  case MID_CopyLookupData:
4121 	    mi->ti.disabled = pos==-1 || (fv->b.sf->gpos_lookups==NULL && fv->b.sf->gsub_lookups==NULL);
4122 	  break;
4123 	  case MID_CopyVWidth:
4124 	    mi->ti.disabled = pos==-1 || !fv->b.sf->hasvmetrics;
4125 	  break;
4126 	  case MID_ClearBackground:
4127 	    mi->ti.disabled = true;
4128 	    if ( pos!=-1 && !( onlycopydisplayed && fv->filled!=fv->show )) {
4129 		for ( i=0; i<fv->b.map->enccount; ++i )
4130 		    if ( fv->b.selected[i] && (gid = fv->b.map->map[i])!=-1 &&
4131 			    fv->b.sf->glyphs[gid]!=NULL )
4132 			if ( fv->b.sf->glyphs[gid]->layers[ly_back].images!=NULL ||
4133 				fv->b.sf->glyphs[gid]->layers[ly_back].splines!=NULL ) {
4134 			    mi->ti.disabled = false;
4135 		break;
4136 			}
4137 	    }
4138 	  break;
4139 	  case MID_Undo:
4140 	    for ( i=0; i<fv->b.map->enccount; ++i )
4141 		if ( fv->b.selected[i] && (gid = fv->b.map->map[i])!=-1 &&
4142 			fv->b.sf->glyphs[gid]!=NULL )
4143 		    if ( fv->b.sf->glyphs[gid]->layers[fv->b.active_layer].undoes!=NULL )
4144 	    break;
4145 	    mi->ti.disabled = i==fv->b.map->enccount;
4146 	  break;
4147 	  case MID_Redo:
4148 	    for ( i=0; i<fv->b.map->enccount; ++i )
4149 		if ( fv->b.selected[i] && (gid = fv->b.map->map[i])!=-1 &&
4150 			fv->b.sf->glyphs[gid]!=NULL )
4151 		    if ( fv->b.sf->glyphs[gid]->layers[fv->b.active_layer].redoes!=NULL )
4152 	    break;
4153 	    mi->ti.disabled = i==fv->b.map->enccount;
4154 	  break;
4155 	case MID_UndoFontLevel:
4156 	    mi->ti.disabled = dlist_isempty( (struct dlistnode **)&fv->b.sf->undoes );
4157 	    break;
4158 	}
4159     }
4160 }
4161 
trlistcheck(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))4162 static void trlistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
4163     FontView *fv = (FontView *) GDrawGetUserData(gw);
4164     int anychars = FVAnyCharSelected(fv);
4165 
4166     for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
4167 	switch ( mi->mid ) {
4168 	  case MID_Transform:
4169 	    mi->ti.disabled = anychars==-1;
4170 	  break;
4171 	  case MID_NLTransform: case MID_POV:
4172 	    mi->ti.disabled = anychars==-1 || fv->b.sf->onlybitmaps;
4173 	  break;
4174 	}
4175     }
4176 }
4177 
validlistcheck(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))4178 static void validlistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
4179     FontView *fv = (FontView *) GDrawGetUserData(gw);
4180     int anychars = FVAnyCharSelected(fv);
4181 
4182     for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
4183 	switch ( mi->mid ) {
4184 	  case MID_FindProblems:
4185 	    mi->ti.disabled = anychars==-1;
4186 	  break;
4187 	  case MID_Validate:
4188 	    mi->ti.disabled = fv->b.sf->strokedfont || fv->b.sf->multilayer;
4189 	  break;
4190         }
4191     }
4192 }
4193 
ellistcheck(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))4194 static void ellistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
4195     FontView *fv = (FontView *) GDrawGetUserData(gw);
4196     int anychars = FVAnyCharSelected(fv), gid;
4197     int anybuildable, anytraceable;
4198     int in_modal = (fv->b.container!=NULL && fv->b.container->funcs->is_modal);
4199 
4200     for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
4201 	switch ( mi->mid ) {
4202 	  case MID_FontInfo:
4203 	    mi->ti.disabled = in_modal;
4204 	  break;
4205 	  case MID_CharInfo:
4206 	    mi->ti.disabled = anychars<0 || in_modal;
4207 	  break;
4208 	  case MID_Transform:
4209 	    mi->ti.disabled = anychars==-1;
4210 	    /* some Transformations make sense on bitmaps now */
4211 	  break;
4212 	  case MID_AddExtrema:
4213 	    mi->ti.disabled = anychars==-1 || fv->b.sf->onlybitmaps;
4214 	  break;
4215 	  case MID_Simplify:
4216 	  case MID_Stroke: case MID_RmOverlap:
4217 	    mi->ti.disabled = anychars==-1 || fv->b.sf->onlybitmaps;
4218 	  break;
4219 	  case MID_Styles:
4220 	    mi->ti.disabled = anychars==-1 || fv->b.sf->onlybitmaps;
4221 	  break;
4222 	  case MID_Round: case MID_Correct:
4223 	    mi->ti.disabled = anychars==-1 || fv->b.sf->onlybitmaps;
4224 	  break;
4225 #ifdef FONTFORGE_CONFIG_TILEPATH
4226 	  case MID_TilePath:
4227 	    mi->ti.disabled = anychars==-1 || fv->b.sf->onlybitmaps;
4228 	  break;
4229 #endif
4230 	  case MID_AvailBitmaps:
4231 	    mi->ti.disabled = fv->b.sf->mm!=NULL;
4232 	  break;
4233 	  case MID_RegenBitmaps: case MID_RemoveBitmaps:
4234 	    mi->ti.disabled = fv->b.sf->bitmaps==NULL || fv->b.sf->onlybitmaps ||
4235 		    fv->b.sf->mm!=NULL;
4236 	  break;
4237 	  case MID_BuildAccent:
4238 	    anybuildable = false;
4239 	    if ( anychars!=-1 ) {
4240 		int i;
4241 		for ( i=0; i<fv->b.map->enccount; ++i ) if ( fv->b.selected[i] ) {
4242 		    SplineChar *sc=NULL, dummy;
4243 		    gid = fv->b.map->map[i];
4244 		    if ( gid!=-1 )
4245 			sc = fv->b.sf->glyphs[gid];
4246 		    if ( sc==NULL )
4247 			sc = SCBuildDummy(&dummy,fv->b.sf,fv->b.map,i);
4248 		    if ( SFIsSomethingBuildable(fv->b.sf,sc,fv->b.active_layer,false) ||
4249 			    SFIsDuplicatable(fv->b.sf,sc)) {
4250 			anybuildable = true;
4251 		break;
4252 		    }
4253 		}
4254 	    }
4255 	    mi->ti.disabled = !anybuildable;
4256 	  break;
4257 	  case MID_Autotrace:
4258 	    anytraceable = false;
4259 	    if ( FindAutoTraceName()!=NULL && anychars!=-1 ) {
4260 		int i;
4261 		for ( i=0; i<fv->b.map->enccount; ++i )
4262 		    if ( fv->b.selected[i] && (gid = fv->b.map->map[i])!=-1 &&
4263 			    fv->b.sf->glyphs[gid]!=NULL &&
4264 			    fv->b.sf->glyphs[gid]->layers[ly_back].images!=NULL ) {
4265 			anytraceable = true;
4266 		break;
4267 		    }
4268 	    }
4269 	    mi->ti.disabled = !anytraceable;
4270 	  break;
4271 	  case MID_MergeFonts:
4272 	    mi->ti.disabled = fv->b.sf->bitmaps!=NULL && fv->b.sf->onlybitmaps;
4273 	  break;
4274 	  case MID_FontCompare:
4275 	    mi->ti.disabled = fv_list->b.next==NULL;
4276 	  break;
4277 	  case MID_InterpolateFonts:
4278 	    mi->ti.disabled = fv->b.sf->onlybitmaps;
4279 	  break;
4280 	}
4281     }
4282 }
4283 
mtlistcheck(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))4284 static void mtlistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
4285     FontView *fv = (FontView *) GDrawGetUserData(gw);
4286     int anychars = FVAnyCharSelected(fv);
4287 
4288     for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
4289 	switch ( mi->mid ) {
4290 	  case MID_Center: case MID_Thirds: case MID_SetWidth:
4291 	  case MID_SetLBearing: case MID_SetRBearing: case MID_SetBearings:
4292 	    mi->ti.disabled = anychars==-1;
4293 	  break;
4294 	  case MID_SetVWidth:
4295 	    mi->ti.disabled = anychars==-1 || !fv->b.sf->hasvmetrics;
4296 	  break;
4297 	  case MID_VKernByClass:
4298 	  case MID_VKernFromH:
4299 	  case MID_RmVKern:
4300 	    mi->ti.disabled = !fv->b.sf->hasvmetrics;
4301 	  break;
4302 	}
4303     }
4304 }
4305 
4306 #if HANYANG
hglistcheck(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))4307 static void hglistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
4308     FontView *fv = (FontView *) GDrawGetUserData(gw);
4309 
4310     for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
4311         if ( mi->mid==MID_BuildSyllables || mi->mid==MID_ModifyComposition )
4312 	    mi->ti.disabled = fv->b.sf->rules==NULL;
4313     }
4314 }
4315 
4316 static GMenuItem2 hglist[] = {
4317     { { (unichar_t *) N_("_New Composition..."), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'N' }, H_("New Composition...|No Shortcut"), NULL, NULL, MenuNewComposition },
4318     { { (unichar_t *) N_("_Modify Composition..."), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'M' }, H_("Modify Composition...|No Shortcut"), NULL, NULL, FVMenuModifyComposition, MID_ModifyComposition },
4319     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, }},
4320     { { (unichar_t *) N_("_Build Syllables"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'B' }, H_("Build Syllables|No Shortcut"), NULL, NULL, FVMenuBuildSyllables, MID_BuildSyllables },
4321     { NULL }
4322 };
4323 #endif
4324 
balistcheck(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))4325 static void balistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
4326     FontView *fv = (FontView *) GDrawGetUserData(gw);
4327 
4328     for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
4329         if ( mi->mid==MID_BuildAccent || mi->mid==MID_BuildComposite ) {
4330 	    int anybuildable = false;
4331 	    int onlyaccents = mi->mid==MID_BuildAccent;
4332 	    int i, gid;
4333 	    for ( i=0; i<fv->b.map->enccount; ++i ) if ( fv->b.selected[i] ) {
4334 		SplineChar *sc=NULL, dummy;
4335 		if ( (gid=fv->b.map->map[i])!=-1 )
4336 		    sc = fv->b.sf->glyphs[gid];
4337 		if ( sc==NULL )
4338 		    sc = SCBuildDummy(&dummy,fv->b.sf,fv->b.map,i);
4339 		if ( SFIsSomethingBuildable(fv->b.sf,sc,fv->b.active_layer,onlyaccents)) {
4340 		    anybuildable = true;
4341 	    break;
4342 		}
4343 	    }
4344 	    mi->ti.disabled = !anybuildable;
4345         } else if ( mi->mid==MID_BuildDuplicates ) {
4346 	    int anybuildable = false;
4347 	    int i, gid;
4348 	    for ( i=0; i<fv->b.map->enccount; ++i ) if ( fv->b.selected[i] ) {
4349 		SplineChar *sc=NULL, dummy;
4350 		if ( (gid=fv->b.map->map[i])!=-1 )
4351 		    sc = fv->b.sf->glyphs[gid];
4352 		if ( sc==NULL )
4353 		    sc = SCBuildDummy(&dummy,fv->b.sf,fv->b.map,i);
4354 		if ( SFIsDuplicatable(fv->b.sf,sc)) {
4355 		    anybuildable = true;
4356 	    break;
4357 		}
4358 	    }
4359 	    mi->ti.disabled = !anybuildable;
4360 	}
4361     }
4362 }
4363 
delistcheck(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))4364 static void delistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
4365     FontView *fv = (FontView *) GDrawGetUserData(gw);
4366     int i = FVAnyCharSelected(fv);
4367     int gid = i<0 ? -1 : fv->b.map->map[i];
4368 
4369     for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
4370 	switch ( mi->mid ) {
4371 	  case MID_ShowDependentRefs:
4372 	    mi->ti.disabled = gid<0 || fv->b.sf->glyphs[gid]==NULL ||
4373 		    fv->b.sf->glyphs[gid]->dependents == NULL;
4374 	  break;
4375 	  case MID_ShowDependentSubs:
4376 	    mi->ti.disabled = gid<0 || fv->b.sf->glyphs[gid]==NULL ||
4377 		    !SCUsedBySubs(fv->b.sf->glyphs[gid]);
4378 	  break;
4379 	}
4380     }
4381 }
4382 
infolistcheck(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))4383 static void infolistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
4384     FontView *fv = (FontView *) GDrawGetUserData(gw);
4385     int anychars = FVAnyCharSelected(fv);
4386 
4387     for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
4388 	switch ( mi->mid ) {
4389 	  case MID_StrikeInfo:
4390 	    mi->ti.disabled = fv->b.sf->bitmaps==NULL;
4391 	  break;
4392 	  case MID_MassRename:
4393 	    mi->ti.disabled = anychars==-1;
4394 	  break;
4395 	  case MID_SetColor:
4396 	    mi->ti.disabled = anychars==-1;
4397 	  break;
4398 	}
4399     }
4400 }
4401 
4402 static GMenuItem2 dummyitem[] = {
4403     { { (unichar_t *) N_("Font|_New"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'N' }, NULL, NULL, NULL, NULL, 0 },
4404     GMENUITEM2_EMPTY
4405 };
4406 
4407 static GMenuItem2 fllist[] = {
4408     { { (unichar_t *) N_("Font|_New"), (GImage *) "filenew.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'N' }, H_("New|No Shortcut"), NULL, NULL, MenuNew, 0 },
4409 #if HANYANG
4410     { { (unichar_t *) N_("_Hangul"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'H' }, H_("Hangul|No Shortcut"), hglist, hglistcheck, NULL, 0 },
4411 #endif
4412     { { (unichar_t *) N_("_Open"), (GImage *) "fileopen.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'O' }, H_("Open|No Shortcut"), NULL, NULL, FVMenuOpen, 0 },
4413     { { (unichar_t *) N_("Recen_t"), (GImage *) "filerecent.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 't' }, H_("Recent|No Shortcut"), dummyitem, MenuRecentBuild, NULL, MID_Recent },
4414     { { (unichar_t *) N_("_Close"), (GImage *) "fileclose.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'C' }, H_("Close|No Shortcut"), NULL, NULL, FVMenuClose, 0 },
4415     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
4416     { { (unichar_t *) N_("_Save"), (GImage *) "filesave.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'S' }, H_("Save|No Shortcut"), NULL, NULL, FVMenuSave, 0 },
4417     { { (unichar_t *) N_("S_ave as..."), (GImage *) "filesaveas.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'a' }, H_("Save as...|No Shortcut"), NULL, NULL, FVMenuSaveAs, 0 },
4418     { { (unichar_t *) N_("Save A_ll"), (GImage *) "filesaveall.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'l' }, H_("Save All|No Shortcut"), NULL, NULL, MenuSaveAll, 0 },
4419     { { (unichar_t *) N_("_Generate Fonts..."), (GImage *) "filegenerate.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'G' }, H_("Generate Fonts...|No Shortcut"), NULL, NULL, FVMenuGenerate, 0 },
4420     { { (unichar_t *) N_("Generate Mac _Family..."), (GImage *) "filegeneratefamily.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'F' }, H_("Generate Mac Family...|No Shortcut"), NULL, NULL, FVMenuGenerateFamily, 0 },
4421     { { (unichar_t *) N_("Generate TTC..."), (GImage *) "filegeneratefamily.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'F' }, H_("Generate TTC...|No Shortcut"), NULL, NULL, FVMenuGenerateTTC, MID_GenerateTTC },
4422     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
4423     { { (unichar_t *) N_("_Import..."), (GImage *) "fileimport.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'I' }, H_("Import...|No Shortcut"), NULL, NULL, FVMenuImport, 0 },
4424     { { (unichar_t *) N_("_Merge Feature Info..."), (GImage *) "filemergefeature.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'M' }, H_("Merge Feature Info...|No Shortcut"), NULL, NULL, FVMenuMergeKern, 0 },
4425     { { (unichar_t *) N_("_Revert File"), (GImage *) "filerevert.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'R' }, H_("Revert File|No Shortcut"), NULL, NULL, FVMenuRevert, MID_Revert },
4426     { { (unichar_t *) N_("Revert To _Backup"), (GImage *) "filerevertbackup.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'R' }, H_("Revert To Backup|No Shortcut"), NULL, NULL, FVMenuRevertBackup, MID_RevertToBackup },
4427     { { (unichar_t *) N_("Revert Gl_yph"), (GImage *) "filerevertglyph.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'R' }, H_("Revert Glyph|No Shortcut"), NULL, NULL, FVMenuRevertGlyph, MID_RevertGlyph },
4428     { { (unichar_t *) N_("Clear Special Data"), (GImage *) "menuempty.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'R' }, H_("Clear Special Data|No Shortcut"), NULL, NULL, FVMenuClearSpecialData, MID_ClearSpecialData },
4429     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
4430     { { (unichar_t *) N_("_Print..."), (GImage *) "fileprint.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'P' }, H_("Print...|No Shortcut"), NULL, NULL, FVMenuPrint, MID_Print },
4431     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
4432 #if !defined(_NO_PYTHON)
4433     { { (unichar_t *) N_("E_xecute Script..."), (GImage *) "python.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'x' }, H_("Execute Script...|No Shortcut"), NULL, NULL, FVMenuExecute, 0 },
4434 #elif !defined(_NO_FFSCRIPT)
4435     { { (unichar_t *) N_("E_xecute Script..."), (GImage *) "menuempty.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'x' }, H_("Execute Script...|No Shortcut"), NULL, NULL, FVMenuExecute, 0 },
4436 #endif
4437 #if !defined(_NO_FFSCRIPT)
4438     { { (unichar_t *) N_("Script Menu"), (GImage *) "fileexecute.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'r' }, H_("Script Menu|No Shortcut"), dummyitem, MenuScriptsBuild, NULL, MID_ScriptMenu },
4439 #endif
4440 #if !defined(_NO_FFSCRIPT) || !defined(_NO_PYTHON)
4441     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
4442 #endif
4443     { { (unichar_t *) N_("Pr_eferences..."), (GImage *) "fileprefs.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'e' }, H_("Preferences...|No Shortcut"), NULL, NULL, MenuPrefs, 0 },
4444     { { (unichar_t *) N_("_X Resource Editor..."), (GImage *) "menuempty.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'e' }, H_("X Resource Editor...|No Shortcut"), NULL, NULL, MenuXRes, 0 },
4445     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
4446     { { (unichar_t *) N_("_Quit"), (GImage *) "filequit.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'Q' }, H_("Quit|Ctl+Q"), /* WARNING: THIS BINDING TO PROPERLY INITIALIZE KEYBOARD INPUT */
4447       NULL, NULL, FVMenuExit, 0 },
4448     GMENUITEM2_EMPTY
4449 };
4450 
4451 static GMenuItem2 cflist[] = {
4452     { { (unichar_t *) N_("_All Fonts"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'A' }, H_("All Fonts|No Shortcut"), NULL, NULL, FVMenuCopyFrom, MID_AllFonts },
4453     { { (unichar_t *) N_("_Displayed Font"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'D' }, H_("Displayed Font|No Shortcut"), NULL, NULL, FVMenuCopyFrom, MID_DisplayedFont },
4454     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
4455     { { (unichar_t *) N_("Glyph _Metadata"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'N' }, H_("Glyph Metadata|No Shortcut"), NULL, NULL, FVMenuCopyFrom, MID_CharName },
4456     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
4457     { { (unichar_t *) N_("_TrueType Instructions"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'N' }, H_("TrueType Instructions|No Shortcut"), NULL, NULL, FVMenuCopyFrom, MID_TTFInstr },
4458     GMENUITEM2_EMPTY
4459 };
4460 
4461 static GMenuItem2 sclist[] = {
4462     { { (unichar_t *) N_("Color|Choose..."), (GImage *)"colorwheel.png", COLOR_DEFAULT, COLOR_DEFAULT, (void *) -10, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, '\0' }, H_("Choose...|No Shortcut"), NULL, NULL, FVMenuSelectColor, 0 },
4463     { { (unichar_t *)  N_("Color|Default"), &def_image, COLOR_DEFAULT, COLOR_DEFAULT, (void *) COLOR_DEFAULT, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, '\0' }, H_("Default|No Shortcut"), NULL, NULL, FVMenuSelectColor, 0 },
4464     { { NULL, &white_image, COLOR_DEFAULT, COLOR_DEFAULT, (void *) 0xffffff, NULL, 0, 1, 0, 0, 0, 0, 0, 0, 0, '\0' }, NULL, NULL, NULL, FVMenuSelectColor, 0 },
4465     { { NULL, &red_image, COLOR_DEFAULT, COLOR_DEFAULT, (void *) 0xff0000, NULL, 0, 1, 0, 0, 0, 0, 0, 0, 0, '\0' }, NULL, NULL, NULL, FVMenuSelectColor, 0 },
4466     { { NULL, &green_image, COLOR_DEFAULT, COLOR_DEFAULT, (void *) 0x00ff00, NULL, 0, 1, 0, 0, 0, 0, 0, 0, 0, '\0' }, NULL, NULL, NULL, FVMenuSelectColor, 0 },
4467     { { NULL, &blue_image, COLOR_DEFAULT, COLOR_DEFAULT, (void *) 0x0000ff, NULL, 0, 1, 0, 0, 0, 0, 0, 0, 0, '\0' }, NULL, NULL, NULL, FVMenuSelectColor, 0 },
4468     { { NULL, &yellow_image, COLOR_DEFAULT, COLOR_DEFAULT, (void *) 0xffff00, NULL, 0, 1, 0, 0, 0, 0, 0, 0, 0, '\0' }, NULL, NULL, NULL, FVMenuSelectColor, 0 },
4469     { { NULL, &cyan_image, COLOR_DEFAULT, COLOR_DEFAULT, (void *) 0x00ffff, NULL, 0, 1, 0, 0, 0, 0, 0, 0, 0, '\0' }, NULL, NULL, NULL, FVMenuSelectColor, 0 },
4470     { { NULL, &magenta_image, COLOR_DEFAULT, COLOR_DEFAULT, (void *) 0xff00ff, NULL, 0, 1, 0, 0, 0, 0, 0, 0, 0, '\0' }, NULL, NULL, NULL, FVMenuSelectColor, 0 },
4471     GMENUITEM2_EMPTY
4472 };
4473 
4474 static GMenuItem2 sllist[] = {
4475     { { (unichar_t *) N_("Select _All"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'A' }, H_("Select All|No Shortcut"), NULL, NULL, FVMenuSelectAll, 0 },
4476     { { (unichar_t *) N_("_Invert Selection"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'I' }, H_("Invert Selection|No Shortcut"), NULL, NULL, FVMenuInvertSelection, 0 },
4477     { { (unichar_t *) N_("_Deselect All"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'o' }, H_("Deselect All|Escape"), NULL, NULL, FVMenuDeselectAll, 0 },
4478     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
4479     { { (unichar_t *) N_("Select by _Color"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, '\0' }, H_("Select by Color|No Shortcut"), sclist, NULL, NULL, 0 },
4480     { { (unichar_t *) N_("Select by _Wildcard..."), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, '\0' }, H_("Select by Wildcard...|No Shortcut"), NULL, NULL, FVMenuSelectByName, 0 },
4481     { { (unichar_t *) N_("Select by _Script..."), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, '\0' }, H_("Select by Script...|No Shortcut"), NULL, NULL, FVMenuSelectByScript, 0 },
4482     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
4483     { { (unichar_t *) N_("_Glyphs Worth Outputting"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, '\0' }, H_("Glyphs Worth Outputting|No Shortcut"), NULL,NULL, FVMenuSelectWorthOutputting, 0 },
4484     { { (unichar_t *) N_("Glyphs with only _References"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, '\0' }, H_("Glyphs with only References|No Shortcut"), NULL,NULL, FVMenuGlyphsRefs, 0 },
4485     { { (unichar_t *) N_("Glyphs with only S_plines"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, '\0' }, H_("Glyphs with only Splines|No Shortcut"), NULL,NULL, FVMenuGlyphsSplines, 0 },
4486     { { (unichar_t *) N_("Glyphs with both"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, '\0' }, H_("Glyphs with both|No Shortcut"), NULL,NULL, FVMenuGlyphsBoth, 0 },
4487     { { (unichar_t *) N_("W_hitespace Glyphs"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, '\0' }, H_("Whitespace Glyphs|No Shortcut"), NULL,NULL, FVMenuGlyphsWhite, 0 },
4488     { { (unichar_t *) N_("_Changed Glyphs"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, '\0' }, H_("Changed Glyphs|No Shortcut"), NULL,NULL, FVMenuSelectChanged, 0 },
4489     { { (unichar_t *) N_("_Hinting Needed"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, '\0' }, H_("Hinting Needed|No Shortcut"), NULL,NULL, FVMenuSelectHintingNeeded, 0 },
4490     { { (unichar_t *) N_("Autohinta_ble"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, '\0' }, H_("Autohintable|No Shortcut"), NULL,NULL, FVMenuSelectAutohintable, 0 },
4491     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
4492     { { (unichar_t *) N_("Hold [Shift] key to merge"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 1, 1, 0, 0, 0, 0, 1, 1, 0, '\0' }, NULL, NULL, NULL, NULL, 0 },
4493     { { (unichar_t *) N_("Hold [Control] key to restrict"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 1, 1, 0, 0, 0, 0, 1, 1, 0, '\0' }, NULL, NULL, NULL, NULL, 0 },
4494     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
4495     { { (unichar_t *) N_("Selec_t By Lookup Subtable..."), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'T' }, H_("Select By Lookup Subtable...|No Shortcut"), NULL, NULL, FVMenuSelectByPST, 0 },
4496     GMENUITEM2_EMPTY
4497 };
4498 
4499 static GMenuItem2 edlist[] = {
4500     { { (unichar_t *) N_("_Undo"), (GImage *) "editundo.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'U' }, H_("Undo|No Shortcut"), NULL, NULL, FVMenuUndo, MID_Undo },
4501     { { (unichar_t *) N_("_Redo"), (GImage *) "editredo.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'R' }, H_("Redo|No Shortcut"), NULL, NULL, FVMenuRedo, MID_Redo},
4502     { { (unichar_t *) N_("Undo Fontlevel"), (GImage *) "editundo.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'U' }, H_("Undo Fontlevel|No Shortcut"), NULL, NULL, FVMenuUndoFontLevel, MID_UndoFontLevel },
4503     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
4504     { { (unichar_t *) N_("Cu_t"), (GImage *) "editcut.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 't' }, H_("Cut|No Shortcut"), NULL, NULL, FVMenuCut, MID_Cut },
4505     { { (unichar_t *) N_("_Copy"), (GImage *) "editcopy.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'C' }, H_("Copy|No Shortcut"), NULL, NULL, FVMenuCopy, MID_Copy },
4506     { { (unichar_t *) N_("C_opy Reference"), (GImage *) "editcopyref.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'o' }, H_("Copy Reference|No Shortcut"), NULL, NULL, FVMenuCopyRef, MID_CopyRef },
4507     { { (unichar_t *) N_("Copy _Lookup Data"), (GImage *) "editcopylookupdata.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'o' }, H_("Copy Lookup Data|No Shortcut"), NULL, NULL, FVMenuCopyLookupData, MID_CopyLookupData },
4508     { { (unichar_t *) N_("Copy _Width"), (GImage *) "editcopywidth.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'W' }, H_("Copy Width|No Shortcut"), NULL, NULL, FVMenuCopyWidth, MID_CopyWidth },
4509     { { (unichar_t *) N_("Copy _VWidth"), (GImage *) "editcopyvwidth.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'V' }, H_("Copy VWidth|No Shortcut"), NULL, NULL, FVMenuCopyWidth, MID_CopyVWidth },
4510     { { (unichar_t *) N_("Co_py LBearing"), (GImage *) "editcopylbearing.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'p' }, H_("Copy LBearing|No Shortcut"), NULL, NULL, FVMenuCopyWidth, MID_CopyLBearing },
4511     { { (unichar_t *) N_("Copy RBearin_g"), (GImage *) "editcopyrbearing.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'g' }, H_("Copy RBearing|No Shortcut"), NULL, NULL, FVMenuCopyWidth, MID_CopyRBearing },
4512     { { (unichar_t *) N_("_Paste"), (GImage *) "editpaste.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'P' }, H_("Paste|No Shortcut"), NULL, NULL, FVMenuPaste, MID_Paste },
4513     { { (unichar_t *) N_("Paste Into"), (GImage *) "editpasteinto.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, '\0' }, H_("Paste Into|No Shortcut"), NULL, NULL, FVMenuPasteInto, MID_PasteInto },
4514     { { (unichar_t *) N_("Paste After"), (GImage *) "editpasteafter.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, '\0' }, H_("Paste After|No Shortcut"), NULL, NULL, FVMenuPasteAfter, MID_PasteAfter },
4515     { { (unichar_t *) N_("Sa_me Glyph As"), (GImage *) "editsameas.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'm' }, H_("Same Glyph As|No Shortcut"), NULL, NULL, FVMenuSameGlyphAs, MID_SameGlyphAs },
4516     { { (unichar_t *) N_("C_lear"), (GImage *) "editclear.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'l' }, H_("Clear|No Shortcut"), NULL, NULL, FVMenuClear, MID_Clear },
4517     { { (unichar_t *) N_("Clear _Background"), (GImage *) "editclearback.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'B' }, H_("Clear Background|No Shortcut"), NULL, NULL, FVMenuClearBackground, MID_ClearBackground },
4518     { { (unichar_t *) N_("Copy _Fg To Bg"), (GImage *) "editcopyfg2bg.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'F' }, H_("Copy Fg To Bg|No Shortcut"), NULL, NULL, FVMenuCopyFgBg, MID_CopyFgToBg },
4519     { { (unichar_t *) N_("Copy Layer To Layer"), (GImage *) "editcopylayer2layer.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'F' }, H_("Copy Layer To Layer|No Shortcut"), NULL, NULL, FVMenuCopyL2L, MID_CopyL2L },
4520     { { (unichar_t *) N_("_Join"), (GImage *) "editjoin.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'J' }, H_("Join|No Shortcut"), NULL, NULL, FVMenuJoin, MID_Join },
4521     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
4522     { { (unichar_t *) N_("_Select"), (GImage *) "editselect.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'S' }, H_("Select|No Shortcut"), sllist, sllistcheck, NULL, 0 },
4523     { { (unichar_t *) N_("F_ind / Replace..."), (GImage *) "editfind.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'i' }, H_("Find / Replace...|No Shortcut"), NULL, NULL, FVMenuFindRpl, 0 },
4524     { { (unichar_t *) N_("Replace with Reference"), (GImage *) "editrplref.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'i' }, H_("Replace with Reference|No Shortcut"), NULL, NULL, FVMenuReplaceWithRef, MID_RplRef },
4525     { { (unichar_t *) N_("Correct References"), (GImage *) "menuempty.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'i' }, H_("Correct References|No Shortcut"), NULL, NULL, FVMenuCorrectRefs, MID_CorrectRefs },
4526     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
4527     { { (unichar_t *) N_("U_nlink Reference"), (GImage *) "editunlink.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'U' }, H_("Unlink Reference|No Shortcut"), NULL, NULL, FVMenuUnlinkRef, MID_UnlinkRef },
4528     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
4529     { { (unichar_t *) N_("Copy _From"), (GImage *) "menuempty.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'F' }, H_("Copy From|No Shortcut"), cflist, cflistcheck, NULL, 0 },
4530     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
4531     { { (unichar_t *) N_("Remo_ve Undoes"), (GImage *) "editrmundoes.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'e' }, H_("Remove Undoes|No Shortcut"), NULL, NULL, FVMenuRemoveUndoes, MID_RemoveUndoes },
4532     GMENUITEM2_EMPTY
4533 };
4534 
4535 static GMenuItem2 smlist[] = {
4536     { { (unichar_t *) N_("_Simplify"), (GImage *) "elementsimplify.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'S' }, H_("Simplify|No Shortcut"), NULL, NULL, FVMenuSimplify, MID_Simplify },
4537     { { (unichar_t *) N_("Simplify More..."), (GImage *) "menuempty.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'M' }, H_("Simplify More...|No Shortcut"), NULL, NULL, FVMenuSimplifyMore, MID_SimplifyMore },
4538     { { (unichar_t *) N_("Clea_nup Glyph"), (GImage *) "menuempty.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'n' }, H_("Cleanup Glyph|No Shortcut"), NULL, NULL, FVMenuCleanup, MID_CleanupGlyph },
4539     { { (unichar_t *) N_("Canonical Start _Point"), (GImage *) "menuempty.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'n' }, H_("Canonical Start Point|No Shortcut"), NULL, NULL, FVMenuCanonicalStart, MID_CanonicalStart },
4540     { { (unichar_t *) N_("Canonical _Contours"), (GImage *) "menuempty.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'n' }, H_("Canonical Contours|No Shortcut"), NULL, NULL, FVMenuCanonicalContours, MID_CanonicalContours },
4541     GMENUITEM2_EMPTY
4542 };
4543 
4544 static GMenuItem2 rmlist[] = {
4545     { { (unichar_t *) N_("_Remove Overlap"), (GImage *) "overlaprm.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, true, 0, 0, 0, 0, 1, 1, 0, 'O' }, H_("Remove Overlap|No Shortcut"), NULL, NULL, FVMenuOverlap, MID_RmOverlap },
4546     { { (unichar_t *) N_("_Intersect"), (GImage *) "overlapintersection.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, true, 0, 0, 0, 0, 1, 1, 0, 'I' }, H_("Intersect|No Shortcut"), NULL, NULL, FVMenuOverlap, MID_Intersection },
4547     { { (unichar_t *) N_("_Find Intersections"), (GImage *) "overlapfindinter.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, true, 0, 0, 0, 0, 1, 1, 0, 'O' }, H_("Find Intersections|No Shortcut"), NULL, NULL, FVMenuOverlap, MID_FindInter },
4548     GMENUITEM2_EMPTY
4549 };
4550 
4551 static GMenuItem2 eflist[] = {
4552     { { (unichar_t *) N_("Change _Weight..."), (GImage *) "styleschangeweight.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, true, 0, 0, 0, 0, 1, 1, 0, '\0' }, H_("Change Weight...|No Shortcut"), NULL, NULL, FVMenuEmbolden, MID_Embolden },
4553     { { (unichar_t *) N_("_Italic..."), (GImage *) "stylesitalic.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, true, 0, 0, 0, 0, 1, 1, 0, '\0' }, H_("Italic...|No Shortcut"), NULL, NULL, FVMenuItalic, MID_Italic },
4554     { { (unichar_t *) N_("Obli_que..."), (GImage *) "stylesoblique.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, true, 0, 0, 0, 0, 1, 1, 0, '\0' }, H_("Oblique...|No Shortcut"), NULL, NULL, FVMenuOblique, 0 },
4555     { { (unichar_t *) N_("_Condense/Extend..."), (GImage *) "stylesextendcondense.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, true, 0, 0, 0, 0, 1, 1, 0, '\0' }, H_("Condense/Extend...|No Shortcut"), NULL, NULL, FVMenuCondense, MID_Condense },
4556     { { (unichar_t *) N_("Change _X-Height..."), (GImage *) "styleschangexheight.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, true, 0, 0, 0, 0, 1, 1, 0, '\0' }, H_("Change X-Height...|No Shortcut"), NULL, NULL, FVMenuChangeXHeight, MID_ChangeXHeight },
4557     { { (unichar_t *) N_("Change _Glyph..."), (GImage *) "menuempty.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, true, 0, 0, 0, 0, 1, 1, 0, '\0' }, H_("Change Glyph...|No Shortcut"), NULL, NULL, FVMenuChangeGlyph, MID_ChangeGlyph },
4558     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
4559     { { (unichar_t *) N_("Add _Small Capitals..."), (GImage *) "stylessmallcaps.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, true, 0, 0, 0, 0, 1, 1, 0, '\0' }, H_("Add Small Capitals...|No Shortcut"), NULL, NULL, FVMenuSmallCaps, MID_SmallCaps },
4560     { { (unichar_t *) N_("Add Subscripts/Superscripts..."), (GImage *) "stylessubsuper.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, true, 0, 0, 0, 0, 1, 1, 0, '\0' }, H_("Add Subscripts/Superscripts...|No Shortcut"), NULL, NULL, FVMenuSubSup, MID_SubSup },
4561     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
4562     { { (unichar_t *) N_("In_line..."), (GImage *) "stylesinline.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, true, 0, 0, 0, 0, 1, 1, 0, '\0' }, H_("Inline...|No Shortcut"), NULL, NULL, FVMenuInline, 0 },
4563     { { (unichar_t *) N_("_Outline..."), (GImage *) "stylesoutline.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, true, 0, 0, 0, 0, 1, 1, 0, '\0' }, H_("Outline...|No Shortcut"), NULL, NULL, FVMenuOutline, 0 },
4564     { { (unichar_t *) N_("S_hadow..."), (GImage *) "stylesshadow.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, true, 0, 0, 0, 0, 1, 1, 0, '\0' }, H_("Shadow...|No Shortcut"), NULL, NULL, FVMenuShadow, 0 },
4565     { { (unichar_t *) N_("_Wireframe..."), (GImage *) "styleswireframe.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, true, 0, 0, 0, 0, 1, 1, 0, '\0' }, H_("Wireframe...|No Shortcut"), NULL, NULL, FVMenuWireframe, 0 },
4566     GMENUITEM2_EMPTY
4567 };
4568 
4569 static GMenuItem2 balist[] = {
4570     { { (unichar_t *) N_("_Build Accented Glyph"), (GImage *) "elementbuildaccent.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'B' }, H_("Build Accented Glyph|No Shortcut"), NULL, NULL, FVMenuBuildAccent, MID_BuildAccent },
4571     { { (unichar_t *) N_("Build _Composite Glyph"), (GImage *) "elementbuildcomposite.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'B' }, H_("Build Composite Glyph|No Shortcut"), NULL, NULL, FVMenuBuildComposite, MID_BuildComposite },
4572     { { (unichar_t *) N_("Buil_d Duplicate Glyph"), (GImage *) "menuempty.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'B' }, H_("Build Duplicate Glyph|No Shortcut"), NULL, NULL, FVMenuBuildDuplicate, MID_BuildDuplicates },
4573 #ifdef KOREAN
4574     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
4575     { { (unichar_t *) _STR_ShowGrp, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'B' }, NULL, NULL, NULL, FVMenuShowGroup },
4576 #endif
4577     GMENUITEM2_EMPTY
4578 };
4579 
4580 static GMenuItem2 delist[] = {
4581     { { (unichar_t *) N_("_References..."), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'u' }, H_("References...|No Shortcut"), NULL, NULL, FVMenuShowDependentRefs, MID_ShowDependentRefs },
4582     { { (unichar_t *) N_("_Substitutions..."), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'B' }, H_("Substitutions...|No Shortcut"), NULL, NULL, FVMenuShowDependentSubs, MID_ShowDependentSubs },
4583     GMENUITEM2_EMPTY
4584 };
4585 
4586 static GMenuItem2 trlist[] = {
4587     { { (unichar_t *) N_("_Transform..."), (GImage *) "elementtransform.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'T' }, H_("Transform...|No Shortcut"), NULL, NULL, FVMenuTransform, MID_Transform },
4588     { { (unichar_t *) N_("_Point of View Projection..."), (GImage *) "menuempty.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'T' }, H_("Point of View Projection...|No Shortcut"), NULL, NULL, FVMenuPOV, MID_POV },
4589     { { (unichar_t *) N_("_Non Linear Transform..."), (GImage *) "menuempty.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'T' }, H_("Non Linear Transform...|No Shortcut"), NULL, NULL, FVMenuNLTransform, MID_NLTransform },
4590     GMENUITEM2_EMPTY
4591 };
4592 
4593 static GMenuItem2 rndlist[] = {
4594     { { (unichar_t *) N_("To _Int"), (GImage *) "elementround.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'I' }, H_("To Int|No Shortcut"), NULL, NULL, FVMenuRound2Int, MID_Round },
4595     { { (unichar_t *) N_("To _Hundredths"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'I' }, H_("To Hundredths|No Shortcut"), NULL, NULL, FVMenuRound2Hundredths, 0 },
4596     { { (unichar_t *) N_("_Cluster"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'I' }, H_("Cluster|No Shortcut"), NULL, NULL, FVMenuCluster, 0 },
4597     GMENUITEM2_EMPTY
4598 };
4599 
4600 static GMenuItem2 scollist[] = {
4601     { { (unichar_t *) N_("Color|Choose..."), (GImage *)"colorwheel.png", COLOR_DEFAULT, COLOR_DEFAULT, (void *) -10, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, '\0' }, H_("Choose...|No Shortcut"), NULL, NULL, FVMenuSetColor, 0 },
4602     { { (unichar_t *)  N_("Color|Default"), &def_image, COLOR_DEFAULT, COLOR_DEFAULT, (void *) COLOR_DEFAULT, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, '\0' }, H_("Default|No Shortcut"), NULL, NULL, FVMenuSetColor, 0 },
4603     { { NULL, &white_image, COLOR_DEFAULT, COLOR_DEFAULT, (void *) 0xffffff, NULL, 0, 1, 0, 0, 0, 0, 0, 0, 0, '\0' }, NULL, NULL, NULL, FVMenuSetColor, 0 },
4604     { { NULL, &red_image, COLOR_DEFAULT, COLOR_DEFAULT, (void *) 0xff0000, NULL, 0, 1, 0, 0, 0, 0, 0, 0, 0, '\0' }, NULL, NULL, NULL, FVMenuSetColor, 0 },
4605     { { NULL, &green_image, COLOR_DEFAULT, COLOR_DEFAULT, (void *) 0x00ff00, NULL, 0, 1, 0, 0, 0, 0, 0, 0, 0, '\0' }, NULL, NULL, NULL, FVMenuSetColor, 0 },
4606     { { NULL, &blue_image, COLOR_DEFAULT, COLOR_DEFAULT, (void *) 0x0000ff, NULL, 0, 1, 0, 0, 0, 0, 0, 0, 0, '\0' }, NULL, NULL, NULL, FVMenuSetColor, 0 },
4607     { { NULL, &yellow_image, COLOR_DEFAULT, COLOR_DEFAULT, (void *) 0xffff00, NULL, 0, 1, 0, 0, 0, 0, 0, 0, 0, '\0' }, NULL, NULL, NULL, FVMenuSetColor, 0 },
4608     { { NULL, &cyan_image, COLOR_DEFAULT, COLOR_DEFAULT, (void *) 0x00ffff, NULL, 0, 1, 0, 0, 0, 0, 0, 0, 0, '\0' }, NULL, NULL, NULL, FVMenuSetColor, 0 },
4609     { { NULL, &magenta_image, COLOR_DEFAULT, COLOR_DEFAULT, (void *) 0xff00ff, NULL, 0, 1, 0, 0, 0, 0, 0, 0, 0, '\0' }, NULL, NULL, NULL, FVMenuSetColor, 0 },
4610     GMENUITEM2_EMPTY
4611 };
4612 
4613 static GMenuItem2 infolist[] = {
4614     { { (unichar_t *) N_("_MATH Info..."), (GImage *) "elementmathinfo.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, '\0' }, H_("MATH Info...|No Shortcut"), NULL, NULL, FVMenuMATHInfo, 0 },
4615     { { (unichar_t *) N_("_BDF Info..."), (GImage *) "elementbdfinfo.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, '\0' }, H_("BDF Info...|No Shortcut"), NULL, NULL, FVMenuBDFInfo, MID_StrikeInfo },
4616     { { (unichar_t *) N_("_Horizontal Baselines..."), (GImage *) "elementhbaselines.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, '\0' }, H_("Horizontal Baselines...|No Shortcut"), NULL, NULL, FVMenuBaseHoriz, 0 },
4617     { { (unichar_t *) N_("_Vertical Baselines..."), (GImage *) "elementvbaselines.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, '\0' }, H_("Vertical Baselines...|No Shortcut"), NULL, NULL, FVMenuBaseVert, 0 },
4618     { { (unichar_t *) N_("_Justification..."), (GImage *) "menuempty.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, '\0' }, H_("Justification...|No Shortcut"), NULL, NULL, FVMenuJustify, 0 },
4619     { { (unichar_t *) N_("Show _Dependent"), (GImage *) "elementshowdep.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, '\0' }, H_("Show Dependent|No Shortcut"), delist, delistcheck, NULL, 0 },
4620     { { (unichar_t *) N_("Mass Glyph _Rename..."), (GImage *) "elementrenameglyph.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, '\0' }, H_("Mass Glyph Rename...|No Shortcut"), NULL, NULL, FVMenuMassRename, MID_MassRename },
4621     { { (unichar_t *) N_("Set _Color"), (GImage *) "menuempty.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, '\0' }, H_("Set Color|No Shortcut"), scollist, NULL, NULL, MID_SetColor },
4622     GMENUITEM2_EMPTY
4623 };
4624 
4625 static GMenuItem2 validlist[] = {
4626     { { (unichar_t *) N_("Find Pr_oblems..."), (GImage *) "elementfindprobs.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'o' }, H_("Find Problems...|No Shortcut"), NULL, NULL, FVMenuFindProblems, MID_FindProblems },
4627     { { (unichar_t *) N_("_Validate..."), (GImage *) "elementvalidate.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'o' }, H_("Validate...|No Shortcut"), NULL, NULL, FVMenuValidate, MID_Validate },
4628     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
4629     { { (unichar_t *) N_("Set E_xtremum Bound..."), (GImage *) "menuempty.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'o' }, H_("Set Extremum Bound...|No Shortcut"), NULL, NULL, FVMenuSetExtremumBound, MID_SetExtremumBound },
4630     GMENUITEM2_EMPTY
4631 };
4632 
4633 static GMenuItem2 ellist[] = {
4634     { { (unichar_t *) N_("_Font Info..."), (GImage *) "elementfontinfo.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'F' }, H_("Font Info...|No Shortcut"), NULL, NULL, FVMenuFontInfo, MID_FontInfo },
4635     { { (unichar_t *) N_("_Glyph Info..."), (GImage *) "elementglyphinfo.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'I' }, H_("Glyph Info...|No Shortcut"), NULL, NULL, FVMenuCharInfo, MID_CharInfo },
4636     { { (unichar_t *) N_("Other Info"), (GImage *) "elementotherinfo.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'I' }, H_("Other Info|No Shortcut"), infolist, infolistcheck, NULL, 0 },
4637     { { (unichar_t *) N_("_Validation"), (GImage *) "elementvalidate.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'I' }, H_("Validation|No Shortcut"), validlist, validlistcheck, NULL, 0 },
4638     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
4639     { { (unichar_t *) N_("Bitm_ap Strikes Available..."), (GImage *) "elementbitmapsavail.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'A' }, H_("Bitmap Strikes Available...|No Shortcut"), NULL, NULL, FVMenuBitmaps, MID_AvailBitmaps },
4640     { { (unichar_t *) N_("Regenerate _Bitmap Glyphs..."), (GImage *) "elementregenbitmaps.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'B' }, H_("Regenerate Bitmap Glyphs...|No Shortcut"), NULL, NULL, FVMenuBitmaps, MID_RegenBitmaps },
4641     { { (unichar_t *) N_("Remove Bitmap Glyphs..."), (GImage *) "elementremovebitmaps.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, '\0' }, H_("Remove Bitmap Glyphs...|No Shortcut"), NULL, NULL, FVMenuBitmaps, MID_RemoveBitmaps },
4642     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
4643     { { (unichar_t *) N_("St_yle"), (GImage *) "elementstyles.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'S' }, H_("Style|No Shortcut"), eflist, NULL, NULL, MID_Styles },
4644     { { (unichar_t *) N_("_Transformations"), (GImage *) "elementtransform.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'T' }, H_("Transformations|No Shortcut"), trlist, trlistcheck, NULL, MID_Transform },
4645     { { (unichar_t *) N_("_Expand Stroke..."), (GImage *) "elementexpandstroke.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'E' }, H_("Expand Stroke...|No Shortcut"), NULL, NULL, FVMenuStroke, MID_Stroke },
4646 #ifdef FONTFORGE_CONFIG_TILEPATH
4647     { { (unichar_t *) N_("Tile _Path..."), (GImage *) "elementtilepath.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'P' }, H_("Tile Path...|No Shortcut"), NULL, NULL, FVMenuTilePath, MID_TilePath },
4648     { { (unichar_t *) N_("Tile Pattern..."), (GImage *) "elementtilepattern.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, '\0' }, H_("Tile Pattern...|No Shortcut"), NULL, NULL, FVMenuPatternTile, 0 },
4649 #endif
4650     { { (unichar_t *) N_("O_verlap"), (GImage *) "overlaprm.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'O' }, H_("Overlap|No Shortcut"), rmlist, NULL, NULL, MID_RmOverlap },
4651     { { (unichar_t *) N_("_Simplify"), (GImage *) "elementsimplify.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'S' }, H_("Simplify|No Shortcut"), smlist, NULL, NULL, MID_Simplify },
4652     { { (unichar_t *) N_("Add E_xtrema"), (GImage *) "elementaddextrema.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'x' }, H_("Add Extrema|No Shortcut"), NULL, NULL, FVMenuAddExtrema, MID_AddExtrema },
4653     { { (unichar_t *) N_("Roun_d"), (GImage *) "elementround.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'I' }, H_("Round|No Shortcut"), rndlist, NULL, NULL, MID_Round },
4654     { { (unichar_t *) N_("Autot_race"), (GImage *) "elementautotrace.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'r' }, H_("Autotrace|No Shortcut"), NULL, NULL, FVMenuAutotrace, MID_Autotrace },
4655     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
4656     { { (unichar_t *) N_("_Correct Direction"), (GImage *) "elementcorrectdir.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'D' }, H_("Correct Direction|No Shortcut"), NULL, NULL, FVMenuCorrectDir, MID_Correct },
4657     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
4658     { { (unichar_t *) N_("B_uild"), (GImage *) "elementbuildaccent.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'B' }, H_("Build|No Shortcut"), balist, balistcheck, NULL, MID_BuildAccent },
4659     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
4660     { { (unichar_t *) N_("_Merge Fonts..."), (GImage *) "elementmergefonts.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'M' }, H_("Merge Fonts...|No Shortcut"), NULL, NULL, FVMenuMergeFonts, MID_MergeFonts },
4661     { { (unichar_t *) N_("Interpo_late Fonts..."), (GImage *) "elementinterpolatefonts.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'p' }, H_("Interpolate Fonts...|No Shortcut"), NULL, NULL, FVMenuInterpFonts, MID_InterpolateFonts },
4662     { { (unichar_t *) N_("Compare Fonts..."), (GImage *) "elementcomparefonts.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'p' }, H_("Compare Fonts...|No Shortcut"), NULL, NULL, FVMenuCompareFonts, MID_FontCompare },
4663     { { (unichar_t *) N_("Compare Layers..."), (GImage *) "elementcomparelayers.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'p' }, H_("Compare Layers...|No Shortcut"), NULL, NULL, FVMenuCompareL2L, 0 },
4664     GMENUITEM2_EMPTY
4665 };
4666 
4667 static GMenuItem2 dummyall[] = {
4668     { { (unichar_t *) N_("All"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 1, 0, 0, 0, 0, 0, 1, 1, 0, 'K' }, H_("All|No Shortcut"), NULL, NULL, NULL, 0 },
4669     GMENUITEM2_EMPTY
4670 };
4671 
4672 /* Builds up a menu containing all the anchor classes */
aplistbuild(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))4673 static void aplistbuild(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
4674     FontView *fv = (FontView *) GDrawGetUserData(gw);
4675 
4676     GMenuItemArrayFree(mi->sub);
4677     mi->sub = NULL;
4678 
4679     _aplistbuild(mi,fv->b.sf,FVMenuAnchorPairs);
4680 }
4681 
4682 static GMenuItem2 cblist[] = {
4683     { { (unichar_t *) N_("_Kern Pairs"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'K' }, H_("Kern Pairs|No Shortcut"), NULL, NULL, FVMenuKernPairs, MID_KernPairs },
4684     { { (unichar_t *) N_("_Anchored Pairs"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'K' }, H_("Anchored Pairs|No Shortcut"), dummyall, aplistbuild, NULL, MID_AnchorPairs },
4685     { { (unichar_t *) N_("_Ligatures"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'L' }, H_("Ligatures|No Shortcut"), NULL, NULL, FVMenuLigatures, MID_Ligatures },
4686     GMENUITEM2_EMPTY
4687 };
4688 
cblistcheck(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))4689 static void cblistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
4690     FontView *fv = (FontView *) GDrawGetUserData(gw);
4691     SplineFont *sf = fv->b.sf;
4692     int i, anyligs=0, anykerns=0, gid;
4693     PST *pst;
4694 
4695     if ( sf->kerns ) anykerns=true;
4696     for ( i=0; i<fv->b.map->enccount; ++i ) if ( (gid = fv->b.map->map[i])!=-1 && sf->glyphs[gid]!=NULL ) {
4697 	for ( pst=sf->glyphs[gid]->possub; pst!=NULL; pst=pst->next ) {
4698 	    if ( pst->type==pst_ligature ) {
4699 		anyligs = true;
4700 		if ( anykerns )
4701     break;
4702 	    }
4703 	}
4704 	if ( sf->glyphs[gid]->kerns!=NULL ) {
4705 	    anykerns = true;
4706 	    if ( anyligs )
4707     break;
4708 	}
4709     }
4710 
4711     for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
4712 	switch ( mi->mid ) {
4713 	  case MID_Ligatures:
4714 	    mi->ti.disabled = !anyligs;
4715 	  break;
4716 	  case MID_KernPairs:
4717 	    mi->ti.disabled = !anykerns;
4718 	  break;
4719 	  case MID_AnchorPairs:
4720 	    mi->ti.disabled = sf->anchor==NULL;
4721 	  break;
4722 	}
4723     }
4724 }
4725 
4726 
4727 static GMenuItem2 gllist[] = {
4728     { { (unichar_t *) N_("_Glyph Image"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'K' }, H_("Glyph Image|No Shortcut"), NULL, NULL, FVMenuGlyphLabel, gl_glyph },
4729     { { (unichar_t *) N_("_Name"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'K' }, H_("Name|No Shortcut"), NULL, NULL, FVMenuGlyphLabel, gl_name },
4730     { { (unichar_t *) N_("_Unicode"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'L' }, H_("Unicode|No Shortcut"), NULL, NULL, FVMenuGlyphLabel, gl_unicode },
4731     { { (unichar_t *) N_("_Encoding Hex"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'L' }, H_("Encoding Hex|No Shortcut"), NULL, NULL, FVMenuGlyphLabel, gl_encoding },
4732     GMENUITEM2_EMPTY
4733 };
4734 
gllistcheck(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))4735 static void gllistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
4736     FontView *fv = (FontView *) GDrawGetUserData(gw);
4737 
4738     for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
4739 	mi->ti.checked = fv->glyphlabel == mi->mid;
4740     }
4741 }
4742 
4743 static GMenuItem2 emptymenu[] = {
4744     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0},
4745     GMENUITEM2_EMPTY
4746 };
4747 
FVEncodingMenuBuild(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))4748 static void FVEncodingMenuBuild(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
4749     FontView *fv = (FontView *) GDrawGetUserData(gw);
4750 
4751     if ( mi->sub!=NULL ) {
4752 	GMenuItemArrayFree(mi->sub);
4753 	mi->sub = NULL;
4754     }
4755     mi->sub = GetEncodingMenu(FVMenuReencode,fv->b.map->enc);
4756 }
4757 
FVMenuAddUnencoded(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))4758 static void FVMenuAddUnencoded(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
4759     FontView *fv = (FontView *) GDrawGetUserData(gw);
4760     char *ret, *end;
4761     int cnt;
4762 
4763     ret = gwwv_ask_string(_("Add Encoding Slots..."),"1",fv->b.cidmaster?_("How many CID slots do you wish to add?"):_("How many unencoded glyph slots do you wish to add?"));
4764     if ( ret==NULL )
4765 return;
4766     cnt = strtol(ret,&end,10);
4767     if ( *end!='\0' || cnt<=0 ) {
4768 	free(ret);
4769 	ff_post_error( _("Bad Number"),_("Bad Number") );
4770 return;
4771     }
4772     free(ret);
4773     FVAddUnencoded((FontViewBase *) fv, cnt);
4774 }
4775 
FVMenuRemoveUnused(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))4776 static void FVMenuRemoveUnused(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
4777     FontView *fv = (FontView *) GDrawGetUserData(gw);
4778     FVRemoveUnused((FontViewBase *) fv);
4779 }
4780 
FVMenuCompact(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))4781 static void FVMenuCompact(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
4782     FontView *fv = (FontView *) GDrawGetUserData(gw);
4783     SplineChar *sc;
4784 
4785     sc = FVFindACharInDisplay(fv);
4786     FVCompact((FontViewBase *) fv);
4787     if ( sc!=NULL ) {
4788 	int enc = fv->b.map->backmap[sc->orig_pos];
4789 	if ( enc!=-1 )
4790 	    FVScrollToChar(fv,enc);
4791     }
4792 }
4793 
FVMenuDetachGlyphs(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))4794 static void FVMenuDetachGlyphs(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
4795     FontView *fv = (FontView *) GDrawGetUserData(gw);
4796     FVDetachGlyphs((FontViewBase *) fv);
4797 }
4798 
FVMenuDetachAndRemoveGlyphs(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))4799 static void FVMenuDetachAndRemoveGlyphs(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
4800     FontView *fv = (FontView *) GDrawGetUserData(gw);
4801     char *buts[3];
4802 
4803     buts[0] = _("_Remove");
4804     buts[1] = _("_Cancel");
4805     buts[2] = NULL;
4806 
4807     if ( gwwv_ask(_("Detach & Remove Glyphs"),(const char **) buts,0,1,_("Are you sure you wish to remove these glyphs? This operation cannot be undone."))==1 )
4808 return;
4809 
4810     FVDetachAndRemoveGlyphs((FontViewBase *) fv);
4811 }
4812 
FVForceEncodingMenuBuild(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))4813 static void FVForceEncodingMenuBuild(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
4814     FontView *fv = (FontView *) GDrawGetUserData(gw);
4815 
4816     if ( mi->sub!=NULL ) {
4817 	GMenuItemArrayFree(mi->sub);
4818 	mi->sub = NULL;
4819     }
4820     mi->sub = GetEncodingMenu(FVMenuForceEncode,fv->b.map->enc);
4821 }
4822 
FVMenuAddEncodingName(GWindow UNUSED (gw),struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))4823 static void FVMenuAddEncodingName(GWindow UNUSED(gw), struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
4824     char *ret;
4825     Encoding *enc;
4826 
4827     /* Search the iconv database for the named encoding */
4828     ret = gwwv_ask_string(_("Add Encoding Name..."),NULL,_("Please provide the name of an encoding in the iconv database which you want in the menu."));
4829     if ( ret==NULL )
4830 return;
4831     enc = FindOrMakeEncoding(ret);
4832     if ( enc==NULL )
4833 	ff_post_error(_("Invalid Encoding"),_("Invalid Encoding"));
4834     free(ret);
4835 }
4836 
FVMenuLoadEncoding(GWindow UNUSED (gw),struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))4837 static void FVMenuLoadEncoding(GWindow UNUSED(gw), struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
4838     LoadEncodingFile();
4839 }
4840 
FVMenuMakeFromFont(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))4841 static void FVMenuMakeFromFont(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
4842     FontView *fv = (FontView *) GDrawGetUserData(gw);
4843     (void) MakeEncoding(fv->b.sf,fv->b.map);
4844 }
4845 
FVMenuRemoveEncoding(GWindow UNUSED (gw),struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))4846 static void FVMenuRemoveEncoding(GWindow UNUSED(gw), struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
4847     RemoveEncoding();
4848 }
4849 
FVMenuMakeNamelist(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))4850 static void FVMenuMakeNamelist(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
4851     FontView *fv = (FontView *) GDrawGetUserData(gw);
4852     char buffer[1025];
4853     char *filename, *temp;
4854     FILE *file;
4855 
4856     snprintf(buffer, sizeof(buffer),"%s/%s.nam", getFontForgeUserDir(Config), fv->b.sf->fontname );
4857     temp = def2utf8_copy(buffer);
4858     filename = gwwv_save_filename(_("Make Namelist"), temp,"*.nam");
4859     free(temp);
4860     if ( filename==NULL )
4861 return;
4862     temp = utf82def_copy(filename);
4863     file = fopen(temp,"w");
4864     free(temp);
4865     if ( file==NULL ) {
4866 	ff_post_error(_("Namelist creation failed"),_("Could not write %s"), filename);
4867 	free(filename);
4868 return;
4869     }
4870     FVB_MakeNamelist((FontViewBase *) fv, file);
4871     fclose(file);
4872 }
4873 
FVMenuLoadNamelist(GWindow UNUSED (gw),struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))4874 static void FVMenuLoadNamelist(GWindow UNUSED(gw), struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
4875     /* Read in a name list and copy it into the prefs dir so that we'll find */
4876     /*  it in the future */
4877     /* Be prepared to update what we've already got if names match */
4878     char buffer[1025];
4879     char *ret = gwwv_open_filename(_("Load Namelist"),NULL,
4880 	    "*.nam",NULL);
4881     char *temp, *pt;
4882     char *buts[3];
4883     FILE *old, *new;
4884     int ch, ans;
4885     NameList *nl;
4886 
4887     if ( ret==NULL )
4888 return;				/* Cancelled */
4889     temp = utf82def_copy(ret);
4890     pt = strrchr(temp,'/');
4891     if ( pt==NULL )
4892 	pt = temp;
4893     else
4894 	++pt;
4895     snprintf(buffer,sizeof(buffer),"%s/%s", getFontForgeUserDir(Config), pt);
4896     if ( access(buffer,F_OK)==0 ) {
4897 	buts[0] = _("_Replace");
4898 	buts[1] = _("_Cancel");
4899 	buts[2] = NULL;
4900 	ans = gwwv_ask( _("Replace"),(const char **) buts,0,1,_("A name list with this name already exists. Replace it?"));
4901 	if ( ans==1 ) {
4902 	    free(temp);
4903 	    free(ret);
4904 return;
4905 	}
4906     }
4907 
4908     old = fopen( temp,"r");
4909     if ( old==NULL ) {
4910 	ff_post_error(_("No such file"),_("Could not read %s"), ret );
4911 	free(ret); free(temp);
4912 return;
4913     }
4914     if ( (nl = LoadNamelist(temp))==NULL ) {
4915 	ff_post_error(_("Bad namelist file"),_("Could not parse %s"), ret );
4916 	free(ret); free(temp);
4917         fclose(old);
4918 return;
4919     }
4920     free(ret); free(temp);
4921     if ( nl->uses_unicode ) {
4922 	if ( nl->a_utf8_name!=NULL )
4923 	    ff_post_notice(_("Non-ASCII glyphnames"),_("This namelist contains at least one non-ASCII glyph name, namely: %s"), nl->a_utf8_name );
4924 	else
4925 	    ff_post_notice(_("Non-ASCII glyphnames"),_("This namelist is based on a namelist which contains non-ASCII glyph names"));
4926     }
4927 
4928     new = fopen( buffer,"w");
4929     if ( new==NULL ) {
4930 	ff_post_error(_("Create failed"),_("Could not write %s"), buffer );
4931         fclose(old);
4932 return;
4933     }
4934 
4935     while ( (ch=getc(old))!=EOF )
4936 	putc(ch,new);
4937     fclose(old);
4938     fclose(new);
4939 }
4940 
FVMenuRenameByNamelist(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))4941 static void FVMenuRenameByNamelist(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
4942     FontView *fv = (FontView *) GDrawGetUserData(gw);
4943     char **namelists = AllNamelistNames();
4944     int i;
4945     int ret;
4946     NameList *nl;
4947     extern int allow_utf8_glyphnames;
4948 
4949     for ( i=0; namelists[i]!=NULL; ++i );
4950     ret = gwwv_choose(_("Rename by NameList"),(const char **) namelists,i,0,_("Rename the glyphs in this font to the names found in the selected namelist"));
4951     if ( ret==-1 )
4952 return;
4953     nl = NameListByName(namelists[ret]);
4954     if ( nl==NULL ) {
4955 	IError("Couldn't find namelist");
4956 return;
4957     } else if ( nl!=NULL && nl->uses_unicode && !allow_utf8_glyphnames) {
4958 	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."));
4959 return;
4960     }
4961     SFRenameGlyphsToNamelist(fv->b.sf,nl);
4962     GDrawRequestExpose(fv->v,NULL,false);
4963 }
4964 
FVMenuNameGlyphs(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))4965 static void FVMenuNameGlyphs(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
4966     FontView *fv = (FontView *) GDrawGetUserData(gw);
4967     /* Read a file containing a list of names, and add an unencoded glyph for */
4968     /*  each name */
4969     char buffer[33];
4970     char *ret = gwwv_open_filename(_("Load glyph names"),NULL, "*",NULL);
4971     char *temp, *pt;
4972     FILE *file;
4973     int ch;
4974     SplineChar *sc;
4975     FontView *fvs;
4976 
4977     if ( ret==NULL )
4978 return;				/* Cancelled */
4979     temp = utf82def_copy(ret);
4980 
4981     file = fopen( temp,"r");
4982     if ( file==NULL ) {
4983 	ff_post_error(_("No such file"),_("Could not read %s"), ret );
4984 	free(ret); free(temp);
4985 return;
4986     }
4987     pt = buffer;
4988     for (;;) {
4989 	ch = getc(file);
4990 	if ( ch!=EOF && !isspace(ch)) {
4991 	    if ( pt<buffer+sizeof(buffer)-1 )
4992 		*pt++ = ch;
4993 	} else {
4994 	    if ( pt!=buffer ) {
4995 		*pt = '\0';
4996 		sc = NULL;
4997 		for ( fvs=(FontView *) (fv->b.sf->fv); fvs!=NULL; fvs=(FontView *) (fvs->b.nextsame) ) {
4998 		    EncMap *map = fvs->b.map;
4999 		    if ( map->enccount+1>=map->encmax )
5000 			map->map = realloc(map->map,(map->encmax += 20)*sizeof(int));
5001 		    map->map[map->enccount] = -1;
5002 		    fvs->b.selected = realloc(fvs->b.selected,(map->enccount+1));
5003 		    memset(fvs->b.selected+map->enccount,0,1);
5004 		    ++map->enccount;
5005 		    if ( sc==NULL ) {
5006 			sc = SFMakeChar(fv->b.sf,map,map->enccount-1);
5007 			free(sc->name);
5008 			sc->name = copy(buffer);
5009 			sc->comment = copy(".");	/* Mark as something for sfd file */
5010 		    }
5011 		    map->map[map->enccount-1] = sc->orig_pos;
5012 		    map->backmap[sc->orig_pos] = map->enccount-1;
5013 		}
5014 		pt = buffer;
5015 	    }
5016 	    if ( ch==EOF )
5017     break;
5018 	}
5019     }
5020     fclose(file);
5021     free(ret); free(temp);
5022     FontViewReformatAll(fv->b.sf);
5023 }
5024 
5025 static GMenuItem2 enlist[] = {
5026     { { (unichar_t *) N_("_Reencode"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'E' }, H_("Reencode|No Shortcut"), emptymenu, FVEncodingMenuBuild, NULL, MID_Reencode },
5027     { { (unichar_t *) N_("_Compact"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'C' }, H_("Compact|No Shortcut"), NULL, NULL, FVMenuCompact, MID_Compact },
5028     { { (unichar_t *) N_("_Force Encoding"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'C' }, H_("Force Encoding|No Shortcut"), emptymenu, FVForceEncodingMenuBuild, NULL, MID_ForceReencode },
5029     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
5030     { { (unichar_t *) N_("_Add Encoding Slots..."), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'C' }, H_("Add Encoding Slots...|No Shortcut"), NULL, NULL, FVMenuAddUnencoded, MID_AddUnencoded },
5031     { { (unichar_t *) N_("Remove _Unused Slots"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'C' }, H_("Remove Unused Slots|No Shortcut"), NULL, NULL, FVMenuRemoveUnused, MID_RemoveUnused },
5032     { { (unichar_t *) N_("_Detach Glyphs"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'C' }, H_("Detach Glyphs|No Shortcut"), NULL, NULL, FVMenuDetachGlyphs, MID_DetachGlyphs },
5033     { { (unichar_t *) N_("Detach & Remo_ve Glyphs..."), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'C' }, H_("Detach & Remove Glyphs...|No Shortcut"), NULL, NULL, FVMenuDetachAndRemoveGlyphs, MID_DetachAndRemoveGlyphs },
5034     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
5035     { { (unichar_t *) N_("Add E_ncoding Name..."), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'C' }, H_("Add Encoding Name...|No Shortcut"), NULL, NULL, FVMenuAddEncodingName, 0 },
5036     { { (unichar_t *) N_("_Load Encoding..."), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'C' }, H_("Load Encoding...|No Shortcut"), NULL, NULL, FVMenuLoadEncoding, MID_LoadEncoding },
5037     { { (unichar_t *) N_("Ma_ke From Font..."), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'C' }, H_("Make From Font...|No Shortcut"), NULL, NULL, FVMenuMakeFromFont, MID_MakeFromFont },
5038     { { (unichar_t *) N_("Remove En_coding..."), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'C' }, H_("Remove Encoding...|No Shortcut"), NULL, NULL, FVMenuRemoveEncoding, MID_RemoveEncoding },
5039     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
5040     { { (unichar_t *) N_("Display By _Groups..."), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'C' }, H_("Display By Groups...|No Shortcut"), NULL, NULL, FVMenuDisplayByGroups, MID_DisplayByGroups },
5041     { { (unichar_t *) N_("D_efine Groups..."), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'C' }, H_("Define Groups...|No Shortcut"), NULL, NULL, FVMenuDefineGroups, 0 },
5042     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
5043     { { (unichar_t *) N_("_Save Namelist of Font..."), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'C' }, H_("Save Namelist of Font...|No Shortcut"), NULL, NULL, FVMenuMakeNamelist, MID_SaveNamelist },
5044     { { (unichar_t *) N_("L_oad Namelist..."), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'C' }, H_("Load Namelist...|No Shortcut"), NULL, NULL, FVMenuLoadNamelist, 0 },
5045     { { (unichar_t *) N_("Rename Gl_yphs..."), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'C' }, H_("Rename Glyphs...|No Shortcut"), NULL, NULL, FVMenuRenameByNamelist, MID_RenameGlyphs },
5046     { { (unichar_t *) N_("Cre_ate Named Glyphs..."), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'C' }, H_("Create Named Glyphs...|No Shortcut"), NULL, NULL, FVMenuNameGlyphs, MID_NameGlyphs },
5047     GMENUITEM2_EMPTY
5048 };
5049 
enlistcheck(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))5050 static void enlistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
5051     FontView *fv = (FontView *) GDrawGetUserData(gw);
5052     int i, gid;
5053     SplineFont *sf = fv->b.sf;
5054     EncMap *map = fv->b.map;
5055     int anyglyphs = false;
5056 
5057     for ( i=map->enccount-1; i>=0 ; --i )
5058 	if ( fv->b.selected[i] && (gid=map->map[i])!=-1 )
5059 	    anyglyphs = true;
5060 
5061     for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
5062 	switch ( mi->mid ) {
5063 	  case MID_Compact:
5064 	    mi->ti.checked = fv->b.normal!=NULL;
5065 	  break;
5066 	case MID_HideNoGlyphSlots:
5067 	    break;
5068 	  case MID_Reencode: case MID_ForceReencode:
5069 	    mi->ti.disabled = fv->b.cidmaster!=NULL;
5070 	  break;
5071 	  case MID_DetachGlyphs: case MID_DetachAndRemoveGlyphs:
5072 	    mi->ti.disabled = !anyglyphs;
5073 	  break;
5074 	  case MID_RemoveUnused:
5075 	    gid = map->enccount>0 ? map->map[map->enccount-1] : -1;
5076 	    mi->ti.disabled = gid!=-1 && SCWorthOutputting(sf->glyphs[gid]);
5077 	  break;
5078 	  case MID_MakeFromFont:
5079 	    mi->ti.disabled = fv->b.cidmaster!=NULL || map->enccount>1024 || map->enc!=&custom;
5080 	  break;
5081 	  case MID_RemoveEncoding:
5082 	  break;
5083 	  case MID_DisplayByGroups:
5084 	    mi->ti.disabled = fv->b.cidmaster!=NULL || group_root==NULL;
5085 	  break;
5086 	  case MID_NameGlyphs:
5087 	    mi->ti.disabled = fv->b.normal!=NULL || fv->b.cidmaster!=NULL;
5088 	  break;
5089 	  case MID_RenameGlyphs: case MID_SaveNamelist:
5090 	    mi->ti.disabled = fv->b.cidmaster!=NULL;
5091 	  break;
5092 	}
5093     }
5094 }
5095 
5096 static GMenuItem2 lylist[] = {
5097     { { (unichar_t *) N_("Layer|Foreground"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 1, 0, 1, 1, 0, 0, 1, 1, 0, '\0' }, NULL, NULL, NULL, FVMenuChangeLayer, ly_fore },
5098     GMENUITEM2_EMPTY
5099 };
5100 
lylistcheck(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))5101 static void lylistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
5102     FontView *fv = (FontView *) GDrawGetUserData(gw);
5103     SplineFont *sf = fv->b.sf;
5104     int ly;
5105     GMenuItem *sub;
5106 
5107     sub = calloc(sf->layer_cnt+1,sizeof(GMenuItem));
5108     for ( ly=ly_fore; ly<sf->layer_cnt; ++ly ) {
5109 	sub[ly-1].ti.text = utf82u_copy(sf->layers[ly].name);
5110 	sub[ly-1].ti.checkable = true;
5111 	sub[ly-1].ti.checked = ly == fv->b.active_layer;
5112 	sub[ly-1].invoke = FVMenuChangeLayer;
5113 	sub[ly-1].mid = ly;
5114 	sub[ly-1].ti.fg = sub[ly-1].ti.bg = COLOR_DEFAULT;
5115     }
5116     GMenuItemArrayFree(mi->sub);
5117     mi->sub = sub;
5118 }
5119 
5120 static GMenuItem2 vwlist[] = {
5121     { { (unichar_t *) N_("_Next Glyph"), (GImage *) "viewnext.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'N' }, H_("Next Glyph|No Shortcut"), NULL, NULL, FVMenuChangeChar, MID_Next },
5122     { { (unichar_t *) N_("_Prev Glyph"), (GImage *) "viewprev.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'P' }, H_("Prev Glyph|No Shortcut"), NULL, NULL, FVMenuChangeChar, MID_Prev },
5123     { { (unichar_t *) N_("Next _Defined Glyph"), (GImage *) "viewnextdef.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'D' }, H_("Next Defined Glyph|No Shortcut"), NULL, NULL, FVMenuChangeChar, MID_NextDef },
5124     { { (unichar_t *) N_("Prev Defined Gl_yph"), (GImage *) "viewprevdef.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'a' }, H_("Prev Defined Glyph|No Shortcut"), NULL, NULL, FVMenuChangeChar, MID_PrevDef },
5125     { { (unichar_t *) N_("_Goto"), (GImage *) "viewgoto.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'G' }, H_("Goto|No Shortcut"), NULL, NULL, FVMenuGotoChar, 0 },
5126     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
5127     { { (unichar_t *) N_("_Layers"), (GImage *) "viewlayers.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, '\0' }, H_("Layers|No Shortcut"), lylist, lylistcheck, NULL, 0 },
5128     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
5129     { { (unichar_t *) N_("_Show ATT"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'S' }, H_("Show ATT|No Shortcut"), NULL, NULL, FVMenuShowAtt, 0 },
5130     { { (unichar_t *) N_("Display S_ubstitutions..."), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'u' }, H_("Display Substitutions...|No Shortcut"), NULL, NULL, FVMenuDisplaySubs, MID_DisplaySubs },
5131     { { (unichar_t *) N_("Com_binations"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'b' }, H_("Combinations|No Shortcut"), cblist, cblistcheck, NULL, 0 },
5132     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
5133     { { (unichar_t *) N_("Label Gl_yph By"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'b' }, H_("Label Glyph By|No Shortcut"), gllist, gllistcheck, NULL, 0 },
5134     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
5135     { { (unichar_t *) N_("S_how H. Metrics..."), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'H' }, H_("Show H. Metrics...|No Shortcut"), NULL, NULL, FVMenuShowMetrics, MID_ShowHMetrics },
5136     { { (unichar_t *) N_("Show _V. Metrics..."), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'V' }, H_("Show V. Metrics...|No Shortcut"), NULL, NULL, FVMenuShowMetrics, MID_ShowVMetrics },
5137     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
5138     { { (unichar_t *) N_("32x8 cell window"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, '2' }, H_("32x8 cell window|No Shortcut"), NULL, NULL, FVMenuWSize, MID_32x8 },
5139     { { (unichar_t *) N_("_16x4 cell window"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, '3' }, H_("16x4 cell window|No Shortcut"), NULL, NULL, FVMenuWSize, MID_16x4 },
5140     { { (unichar_t *) N_("_8x2  cell window"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, '3' }, H_("8x2  cell window|No Shortcut"), NULL, NULL, FVMenuWSize, MID_8x2 },
5141     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
5142     { { (unichar_t *) N_("_24 pixel outline"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, '2' }, H_("24 pixel outline|No Shortcut"), NULL, NULL, FVMenuSize, MID_24 },
5143     { { (unichar_t *) N_("_36 pixel outline"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, '3' }, H_("36 pixel outline|No Shortcut"), NULL, NULL, FVMenuSize, MID_36 },
5144     { { (unichar_t *) N_("_48 pixel outline"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, '4' }, H_("48 pixel outline|No Shortcut"), NULL, NULL, FVMenuSize, MID_48 },
5145     { { (unichar_t *) N_("_72 pixel outline"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, '4' }, H_("72 pixel outline|No Shortcut"), NULL, NULL, FVMenuSize, MID_72 },
5146     { { (unichar_t *) N_("_96 pixel outline"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, '4' }, H_("96 pixel outline|No Shortcut"), NULL, NULL, FVMenuSize, MID_96 },
5147     { { (unichar_t *) N_("_128 pixel outline"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, '4' }, H_("128 pixel outline|No Shortcut"), NULL, NULL, FVMenuSize, MID_128 },
5148     { { (unichar_t *) N_("_Anti Alias"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'A' }, H_("Anti Alias|No Shortcut"), NULL, NULL, FVMenuSize, MID_AntiAlias },
5149     { { (unichar_t *) N_("_Fit to font bounding box"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'F' }, H_("Fit to font bounding box|No Shortcut"), NULL, NULL, FVMenuSize, MID_FitToBbox },
5150     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
5151     { { (unichar_t *) N_("Bitmap _Magnification..."), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'F' }, H_("Bitmap Magnification...|No Shortcut"), NULL, NULL, FVMenuMagnify, MID_BitmapMag },
5152     GMENUITEM2_EMPTY,			/* Some extra room to show bitmaps */
5153     GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY,
5154     GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY,
5155     GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY,
5156     GMENUITEM2_EMPTY
5157 };
5158 
vwlistcheck(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))5159 static void vwlistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
5160     FontView *fv = (FontView *) GDrawGetUserData(gw);
5161     int anychars = FVAnyCharSelected(fv);
5162     int i, base;
5163     BDFFont *bdf;
5164     char buffer[50];
5165     int pos;
5166     SplineFont *sf = fv->b.sf;
5167     SplineFont *master = sf->cidmaster ? sf->cidmaster : sf;
5168     EncMap *map = fv->b.map;
5169     OTLookup *otl;
5170 
5171     for ( i=0; vwlist[i].ti.text==NULL || strcmp((char *) vwlist[i].ti.text, _("Bitmap _Magnification..."))!=0; ++i );
5172     base = i+1;
5173     for ( i=base; vwlist[i].ti.text!=NULL; ++i ) {
5174 	free( vwlist[i].ti.text);
5175 	vwlist[i].ti.text = NULL;
5176     }
5177 
5178     vwlist[base-1].ti.disabled = true;
5179     if ( master->bitmaps!=NULL ) {
5180 	for ( bdf = master->bitmaps, i=base;
5181 		i<sizeof(vwlist)/sizeof(vwlist[0])-1 && bdf!=NULL;
5182 		++i, bdf = bdf->next ) {
5183 	    if ( BDFDepth(bdf)==1 )
5184 		sprintf( buffer, _("%d pixel bitmap"), bdf->pixelsize );
5185 	    else
5186 		sprintf( buffer, _("%d@%d pixel bitmap"),
5187 			bdf->pixelsize, BDFDepth(bdf) );
5188 	    vwlist[i].ti.text = (unichar_t *) utf82u_copy(buffer);
5189 	    vwlist[i].ti.checkable = true;
5190 	    vwlist[i].ti.checked = bdf==fv->show;
5191 	    vwlist[i].ti.userdata = bdf;
5192 	    vwlist[i].invoke = FVMenuShowBitmap;
5193 	    vwlist[i].ti.fg = vwlist[i].ti.bg = COLOR_DEFAULT;
5194 	    if ( bdf==fv->show )
5195 		vwlist[base-1].ti.disabled = false;
5196 	}
5197     }
5198     GMenuItemArrayFree(mi->sub);
5199     mi->sub = GMenuItem2ArrayCopy(vwlist,NULL);
5200 
5201     for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
5202 	switch ( mi->mid ) {
5203 	  case MID_Next: case MID_Prev:
5204 	    mi->ti.disabled = anychars<0;
5205 	  break;
5206 	  case MID_NextDef:
5207 	    pos = anychars+1;
5208 	    if ( anychars<0 ) pos = map->enccount;
5209 	    for ( ; pos<map->enccount &&
5210 		    (map->map[pos]==-1 || !SCWorthOutputting(sf->glyphs[map->map[pos]]));
5211 		    ++pos );
5212 	    mi->ti.disabled = pos==map->enccount;
5213 	  break;
5214 	  case MID_PrevDef:
5215 	    for ( pos = anychars-1; pos>=0 &&
5216 		    (map->map[pos]==-1 || !SCWorthOutputting(sf->glyphs[map->map[pos]]));
5217 		    --pos );
5218 	    mi->ti.disabled = pos<0;
5219 	  break;
5220 	  case MID_DisplaySubs: { SplineFont *_sf = sf;
5221 	    mi->ti.checked = fv->cur_subtable!=NULL;
5222 	    if ( _sf->cidmaster ) _sf = _sf->cidmaster;
5223 	    for ( otl=_sf->gsub_lookups; otl!=NULL; otl=otl->next )
5224 		if ( otl->lookup_type == gsub_single && otl->subtables!=NULL )
5225 	    break;
5226 	    mi->ti.disabled = otl==NULL;
5227 	  } break;
5228 	  case MID_ShowHMetrics:
5229 	  break;
5230 	  case MID_ShowVMetrics:
5231 	    mi->ti.disabled = !sf->hasvmetrics;
5232 	  break;
5233 	  case MID_32x8:
5234 	    mi->ti.checked = (fv->rowcnt==8 && fv->colcnt==32);
5235 	    mi->ti.disabled = fv->b.container!=NULL;
5236 	  break;
5237 	  case MID_16x4:
5238 	    mi->ti.checked = (fv->rowcnt==4 && fv->colcnt==16);
5239 	    mi->ti.disabled = fv->b.container!=NULL;
5240 	  break;
5241 	  case MID_8x2:
5242 	    mi->ti.checked = (fv->rowcnt==2 && fv->colcnt==8);
5243 	    mi->ti.disabled = fv->b.container!=NULL;
5244 	  break;
5245 	  case MID_24:
5246 	    mi->ti.checked = (fv->show!=NULL && fv->show==fv->filled && fv->show->pixelsize==24);
5247 	    mi->ti.disabled = sf->onlybitmaps && fv->show!=fv->filled;
5248 	  break;
5249 	  case MID_36:
5250 	    mi->ti.checked = (fv->show!=NULL && fv->show==fv->filled && fv->show->pixelsize==36);
5251 	    mi->ti.disabled = sf->onlybitmaps && fv->show!=fv->filled;
5252 	  break;
5253 	  case MID_48:
5254 	    mi->ti.checked = (fv->show!=NULL && fv->show==fv->filled && fv->show->pixelsize==48);
5255 	    mi->ti.disabled = sf->onlybitmaps && fv->show!=fv->filled;
5256 	  break;
5257 	  case MID_72:
5258 	    mi->ti.checked = (fv->show!=NULL && fv->show==fv->filled && fv->show->pixelsize==72);
5259 	    mi->ti.disabled = sf->onlybitmaps && fv->show!=fv->filled;
5260 	  break;
5261 	  case MID_96:
5262 	    mi->ti.checked = (fv->show!=NULL && fv->show==fv->filled && fv->show->pixelsize==96);
5263 	    mi->ti.disabled = sf->onlybitmaps && fv->show!=fv->filled;
5264 	  break;
5265 	  case MID_128:
5266 	    mi->ti.checked = (fv->show!=NULL && fv->show==fv->filled && fv->show->pixelsize==128);
5267 	    mi->ti.disabled = sf->onlybitmaps && fv->show!=fv->filled;
5268 	  break;
5269 	  case MID_AntiAlias:
5270 	    mi->ti.checked = (fv->show!=NULL && fv->show->clut!=NULL);
5271 	    mi->ti.disabled = sf->onlybitmaps && fv->show!=fv->filled;
5272 	  break;
5273 	  case MID_FitToBbox:
5274 	    mi->ti.checked = (fv->show!=NULL && fv->show->bbsized);
5275 	    mi->ti.disabled = sf->onlybitmaps && fv->show!=fv->filled;
5276 	  break;
5277 	  case MID_Layers:
5278 	    mi->ti.disabled = sf->layer_cnt<=2 || sf->multilayer;
5279 	  break;
5280 	}
5281     }
5282 }
5283 
5284 static GMenuItem2 histlist[] = {
5285     { { (unichar_t *) N_("_HStem"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'H' }, H_("HStem|No Shortcut"), NULL, NULL, FVMenuHistograms, MID_HStemHist },
5286     { { (unichar_t *) N_("_VStem"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'V' }, H_("VStem|No Shortcut"), NULL, NULL, FVMenuHistograms, MID_VStemHist },
5287     { { (unichar_t *) N_("BlueValues"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'B' }, H_("BlueValues|No Shortcut"), NULL, NULL, FVMenuHistograms, MID_BlueValuesHist },
5288     GMENUITEM2_EMPTY
5289 };
5290 
5291 static GMenuItem2 htlist[] = {
5292     { { (unichar_t *) N_("Auto_Hint"), (GImage *) "hintsautohint.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'H' }, H_("AutoHint|No Shortcut"), NULL, NULL, FVMenuAutoHint, MID_AutoHint },
5293     { { (unichar_t *) N_("Hint _Substitution Pts"), (GImage *) "menuempty.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'H' }, H_("Hint Substitution Pts|No Shortcut"), NULL, NULL, FVMenuAutoHintSubs, MID_HintSubsPt },
5294     { { (unichar_t *) N_("Auto _Counter Hint"), (GImage *) "menuempty.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'H' }, H_("Auto Counter Hint|No Shortcut"), NULL, NULL, FVMenuAutoCounter, MID_AutoCounter },
5295     { { (unichar_t *) N_("_Don't AutoHint"), (GImage *) "hintsdontautohint.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'H' }, H_("Don't AutoHint|No Shortcut"), NULL, NULL, FVMenuDontAutoHint, MID_DontAutoHint },
5296     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
5297     { { (unichar_t *) N_("Auto_Instr"), (GImage *) "menuempty.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'T' }, H_("AutoInstr|No Shortcut"), NULL, NULL, FVMenuAutoInstr, MID_AutoInstr },
5298     { { (unichar_t *) N_("_Edit Instructions..."), (GImage *) "menuempty.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'l' }, H_("Edit Instructions...|No Shortcut"), NULL, NULL, FVMenuEditInstrs, MID_EditInstructions },
5299     { { (unichar_t *) N_("Edit 'fpgm'..."), (GImage *) "menuempty.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, '\0' }, H_("Edit 'fpgm'...|No Shortcut"), NULL, NULL, FVMenuEditTable, MID_Editfpgm },
5300     { { (unichar_t *) N_("Edit 'prep'..."), (GImage *) "menuempty.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, '\0' }, H_("Edit 'prep'...|No Shortcut"), NULL, NULL, FVMenuEditTable, MID_Editprep },
5301     { { (unichar_t *) N_("Edit 'maxp'..."), (GImage *) "menuempty.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, '\0' }, H_("Edit 'maxp'...|No Shortcut"), NULL, NULL, FVMenuEditTable, MID_Editmaxp },
5302     { { (unichar_t *) N_("Edit 'cvt '..."), (GImage *) "menuempty.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, '\0' }, H_("Edit 'cvt '...|No Shortcut"), NULL, NULL, FVMenuEditTable, MID_Editcvt },
5303     { { (unichar_t *) N_("Remove Instr Tables"), (GImage *) "menuempty.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, '\0' }, H_("Remove Instr Tables|No Shortcut"), NULL, NULL, FVMenuRmInstrTables, MID_RmInstrTables },
5304     { { (unichar_t *) N_("S_uggest Deltas..."), (GImage *) "menuempty.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'l' }, H_("Suggest Deltas...|No Shortcut"), NULL, NULL, FVMenuDeltas, MID_Deltas },
5305     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
5306     { { (unichar_t *) N_("_Clear Hints"), (GImage *) "hintsclearvstems.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'C' }, H_("Clear Hints|No Shortcut"), NULL, NULL, FVMenuClearHints, MID_ClearHints },
5307     { { (unichar_t *) N_("Clear Instructions"), (GImage *) "menuempty.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'C' }, H_("Clear Instructions|No Shortcut"), NULL, NULL, FVMenuClearInstrs, MID_ClearInstrs },
5308     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
5309     { { (unichar_t *) N_("Histograms"), (GImage *) "menuempty.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, '\0' }, H_("Histograms|No Shortcut"), histlist, NULL, NULL, 0 },
5310     GMENUITEM2_EMPTY
5311 };
5312 
5313 static GMenuItem2 mtlist[] = {
5314     { { (unichar_t *) N_("New _Metrics Window"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'M' }, H_("New Metrics Window|No Shortcut"), NULL, NULL, FVMenuOpenMetrics, MID_OpenMetrics },
5315     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
5316     { { (unichar_t *) N_("_Center in Width"), (GImage *) "metricscenter.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'C' }, H_("Center in Width|No Shortcut"), NULL, NULL, FVMenuCenter, MID_Center },
5317     { { (unichar_t *) N_("_Thirds in Width"), (GImage *) "menuempty.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'T' }, H_("Thirds in Width|No Shortcut"), NULL, NULL, FVMenuCenter, MID_Thirds },
5318     { { (unichar_t *) N_("Set _Width..."), (GImage *) "metricssetwidth.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'W' }, H_("Set Width...|No Shortcut"), NULL, NULL, FVMenuSetWidth, MID_SetWidth },
5319     { { (unichar_t *) N_("Set _LBearing..."), (GImage *) "metricssetlbearing.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'L' }, H_("Set LBearing...|No Shortcut"), NULL, NULL, FVMenuSetWidth, MID_SetLBearing },
5320     { { (unichar_t *) N_("Set _RBearing..."), (GImage *) "metricssetrbearing.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'R' }, H_("Set RBearing...|No Shortcut"), NULL, NULL, FVMenuSetWidth, MID_SetRBearing },
5321     { { (unichar_t *) N_("Set Both Bearings..."), (GImage *) "menuempty.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'R' }, H_("Set Both Bearings...|No Shortcut"), NULL, NULL, FVMenuSetWidth, MID_SetBearings },
5322     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
5323     { { (unichar_t *) N_("Set _Vertical Advance..."), (GImage *) "metricssetvwidth.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'V' }, H_("Set Vertical Advance...|No Shortcut"), NULL, NULL, FVMenuSetWidth, MID_SetVWidth },
5324     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
5325     { { (unichar_t *) N_("_Auto Width..."), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'A' }, H_("Auto Width...|No Shortcut"), NULL, NULL, FVMenuAutoWidth, 0 },
5326     { { (unichar_t *) N_("Ker_n By Classes..."), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'K' }, H_("Kern By Classes...|No Shortcut"), NULL, NULL, FVMenuKernByClasses, 0 },
5327     { { (unichar_t *) N_("Remove All Kern _Pairs"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'P' }, H_("Remove All Kern Pairs|No Shortcut"), NULL, NULL, FVMenuRemoveKern, MID_RmHKern },
5328     { { (unichar_t *) N_("Kern Pair Closeup..."), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'P' }, H_("Kern Pair Closeup...|No Shortcut"), NULL, NULL, FVMenuKPCloseup, 0 },
5329     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
5330     { { (unichar_t *) N_("VKern By Classes..."), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'K' }, H_("VKern By Classes...|No Shortcut"), NULL, NULL, FVMenuVKernByClasses, MID_VKernByClass },
5331     { { (unichar_t *) N_("VKern From HKern"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'P' }, H_("VKern From HKern|No Shortcut"), NULL, NULL, FVMenuVKernFromHKern, MID_VKernFromH },
5332     { { (unichar_t *) N_("Remove All VKern Pairs"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'P' }, H_("Remove All VKern Pairs|No Shortcut"), NULL, NULL, FVMenuRemoveVKern, MID_RmVKern },
5333     GMENUITEM2_EMPTY
5334 };
5335 
5336 static GMenuItem2 cdlist[] = {
5337     { { (unichar_t *) N_("_Convert to CID"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'C' }, H_("Convert to CID|No Shortcut"), NULL, NULL, FVMenuConvert2CID, MID_Convert2CID },
5338     { { (unichar_t *) N_("Convert By C_Map"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'C' }, H_("Convert By CMap|No Shortcut"), NULL, NULL, FVMenuConvertByCMap, MID_ConvertByCMap },
5339     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
5340     { { (unichar_t *) N_("_Flatten"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'F' }, H_("Flatten|No Shortcut"), NULL, NULL, FVMenuFlatten, MID_Flatten },
5341     { { (unichar_t *) N_("Fl_attenByCMap"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'F' }, H_("FlattenByCMap|No Shortcut"), NULL, NULL, FVMenuFlattenByCMap, MID_FlattenByCMap },
5342     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
5343     { { (unichar_t *) N_("Insert F_ont..."), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'o' }, H_("Insert Font...|No Shortcut"), NULL, NULL, FVMenuInsertFont, MID_InsertFont },
5344     { { (unichar_t *) N_("Insert _Blank"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'B' }, H_("Insert Blank|No Shortcut"), NULL, NULL, FVMenuInsertBlank, MID_InsertBlank },
5345     { { (unichar_t *) N_("_Remove Font"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'R' }, H_("Remove Font|No Shortcut"), NULL, NULL, FVMenuRemoveFontFromCID, MID_RemoveFromCID },
5346     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
5347     { { (unichar_t *) N_("_Change Supplement..."), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'I' }, H_("Change Supplement...|No Shortcut"), NULL, NULL, FVMenuChangeSupplement, MID_ChangeSupplement },
5348     { { (unichar_t *) N_("C_ID Font Info..."), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'I' }, H_("CID Font Info...|No Shortcut"), NULL, NULL, FVMenuCIDFontInfo, MID_CIDFontInfo },
5349     GMENUITEM2_EMPTY,				/* Extra room to show sub-font names */
5350     GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY,
5351     GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY,
5352     GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY,
5353     GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY,
5354     GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY,
5355     GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY,
5356     GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY,
5357     GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY,
5358     GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY,
5359     GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY,
5360     GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY,
5361     GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY,
5362     GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY,
5363     GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY,
5364     GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY,
5365     GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY,
5366     GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY,
5367     GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY,
5368     GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY,
5369     GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY,
5370     GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY,
5371     GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY,
5372     GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY,
5373     GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY,
5374     GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY,
5375     GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY,
5376     GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY,
5377     GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY,
5378     GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY,
5379     GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY,
5380     GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY,
5381     GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY,
5382     GMENUITEM2_EMPTY
5383 };
5384 
cdlistcheck(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))5385 static void cdlistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
5386     FontView *fv = (FontView *) GDrawGetUserData(gw);
5387     int i, base, j;
5388     SplineFont *sub, *cidmaster = fv->b.cidmaster;
5389 
5390     for ( i=0; cdlist[i].mid!=MID_CIDFontInfo; ++i );
5391     base = i+2;
5392     for ( i=base; cdlist[i].ti.text!=NULL; ++i ) {
5393 	free( cdlist[i].ti.text);
5394 	cdlist[i].ti.text = NULL;
5395     }
5396 
5397     cdlist[base-1].ti.fg = cdlist[base-1].ti.bg = COLOR_DEFAULT;
5398     if ( cidmaster==NULL ) {
5399 	cdlist[base-1].ti.line = false;
5400     } else {
5401 	cdlist[base-1].ti.line = true;
5402 	for ( j = 0, i=base;
5403 		i<sizeof(cdlist)/sizeof(cdlist[0])-1 && j<cidmaster->subfontcnt;
5404 		++i, ++j ) {
5405 	    sub = cidmaster->subfonts[j];
5406 	    cdlist[i].ti.text = uc_copy(sub->fontname);
5407 	    cdlist[i].ti.checkable = true;
5408 	    cdlist[i].ti.checked = sub==fv->b.sf;
5409 	    cdlist[i].ti.userdata = sub;
5410 	    cdlist[i].invoke = FVMenuShowSubFont;
5411 	    cdlist[i].ti.fg = cdlist[i].ti.bg = COLOR_DEFAULT;
5412 	}
5413     }
5414     GMenuItemArrayFree(mi->sub);
5415     mi->sub = GMenuItem2ArrayCopy(cdlist,NULL);
5416 
5417     for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
5418 	switch ( mi->mid ) {
5419 	  case MID_Convert2CID: case MID_ConvertByCMap:
5420 	    mi->ti.disabled = cidmaster!=NULL || fv->b.sf->mm!=NULL;
5421 	  break;
5422 	  case MID_InsertFont: case MID_InsertBlank:
5423 	    /* OpenType allows at most 255 subfonts (PS allows more, but why go to the effort to make safe font check that? */
5424 	    mi->ti.disabled = cidmaster==NULL || cidmaster->subfontcnt>=255;
5425 	  break;
5426 	  case MID_RemoveFromCID:
5427 	    mi->ti.disabled = cidmaster==NULL || cidmaster->subfontcnt<=1;
5428 	  break;
5429 	  case MID_Flatten: case MID_FlattenByCMap: case MID_CIDFontInfo:
5430 	  case MID_ChangeSupplement:
5431 	    mi->ti.disabled = cidmaster==NULL;
5432 	  break;
5433 	}
5434     }
5435 }
5436 
5437 static GMenuItem2 mmlist[] = {
5438 /* GT: Here (and following) MM means "MultiMaster" */
5439     { { (unichar_t *) N_("_Create MM..."), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'I' }, H_("Create MM...|No Shortcut"), NULL, NULL, FVMenuCreateMM, MID_CreateMM },
5440     { { (unichar_t *) N_("MM _Validity Check"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'I' }, H_("MM Validity Check|No Shortcut"), NULL, NULL, FVMenuMMValid, MID_MMValid },
5441     { { (unichar_t *) N_("MM _Info..."), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'I' }, H_("MM Info...|No Shortcut"), NULL, NULL, FVMenuMMInfo, MID_MMInfo },
5442     { { (unichar_t *) N_("_Blend to New Font..."), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'I' }, H_("Blend to New Font...|No Shortcut"), NULL, NULL, FVMenuBlendToNew, MID_BlendToNew },
5443     { { (unichar_t *) N_("MM Change Default _Weights..."), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'I' }, H_("MM Change Default Weights...|No Shortcut"), NULL, NULL, FVMenuChangeMMBlend, MID_ChangeMMBlend },
5444     GMENUITEM2_EMPTY,				/* Extra room to show sub-font names */
5445 };
5446 
mmlistcheck(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))5447 static void mmlistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
5448     FontView *fv = (FontView *) GDrawGetUserData(gw);
5449     int i, base, j;
5450     MMSet *mm = fv->b.sf->mm;
5451     SplineFont *sub;
5452     GMenuItem2 *mml;
5453 
5454     for ( i=0; mmlist[i].mid!=MID_ChangeMMBlend; ++i );
5455     base = i+2;
5456     if ( mm==NULL )
5457 	mml = mmlist;
5458     else {
5459 	mml = calloc(base+mm->instance_count+2,sizeof(GMenuItem2));
5460 	memcpy(mml,mmlist,sizeof(mmlist));
5461 	mml[base-1].ti.fg = mml[base-1].ti.bg = COLOR_DEFAULT;
5462 	mml[base-1].ti.line = true;
5463 	for ( j = 0, i=base; j<mm->instance_count+1; ++i, ++j ) {
5464 	    if ( j==0 )
5465 		sub = mm->normal;
5466 	    else
5467 		sub = mm->instances[j-1];
5468 	    mml[i].ti.text = uc_copy(sub->fontname);
5469 	    mml[i].ti.checkable = true;
5470 	    mml[i].ti.checked = sub==fv->b.sf;
5471 	    mml[i].ti.userdata = sub;
5472 	    mml[i].invoke = FVMenuShowSubFont;
5473 	    mml[i].ti.fg = mml[i].ti.bg = COLOR_DEFAULT;
5474 	}
5475     }
5476     GMenuItemArrayFree(mi->sub);
5477     mi->sub = GMenuItem2ArrayCopy(mml,NULL);
5478     if ( mml!=mmlist ) {
5479 	for ( i=base; mml[i].ti.text!=NULL; ++i )
5480 	    free( mml[i].ti.text);
5481 	free(mml);
5482     }
5483 
5484     for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
5485 	switch ( mi->mid ) {
5486 	  case MID_CreateMM:
5487 	    mi->ti.disabled = false;
5488 	  break;
5489 	  case MID_MMInfo: case MID_MMValid: case MID_BlendToNew:
5490 	    mi->ti.disabled = mm==NULL;
5491 	  break;
5492 	  case MID_ChangeMMBlend:
5493 	    mi->ti.disabled = mm==NULL || mm->apple;
5494 	  break;
5495 	}
5496     }
5497 }
5498 
5499 static GMenuItem2 wnmenu[] = {
5500     { { (unichar_t *) N_("New O_utline Window"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'u' }, H_("New Outline Window|No Shortcut"), NULL, NULL, FVMenuOpenOutline, MID_OpenOutline },
5501     { { (unichar_t *) N_("New _Bitmap Window"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'B' }, H_("New Bitmap Window|No Shortcut"), NULL, NULL, FVMenuOpenBitmap, MID_OpenBitmap },
5502     { { (unichar_t *) N_("New _Metrics Window"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'M' }, H_("New Metrics Window|No Shortcut"), NULL, NULL, FVMenuOpenMetrics, MID_OpenMetrics },
5503     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
5504     { { (unichar_t *) N_("Warnings"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'M' }, H_("Warnings|No Shortcut"), NULL, NULL, _MenuWarnings, MID_Warnings },
5505     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
5506     GMENUITEM2_EMPTY
5507 };
5508 
FVWindowMenuBuild(GWindow gw,struct gmenuitem * mi,GEvent * e)5509 static void FVWindowMenuBuild(GWindow gw, struct gmenuitem *mi, GEvent *e) {
5510     FontView *fv = (FontView *) GDrawGetUserData(gw);
5511     int anychars = FVAnyCharSelected(fv);
5512     struct gmenuitem *wmi;
5513     int in_modal = (fv->b.container!=NULL && fv->b.container->funcs->is_modal);
5514 
5515     WindowMenuBuild(gw,mi,e);
5516     for ( wmi = mi->sub; wmi->ti.text!=NULL || wmi->ti.line ; ++wmi ) {
5517 	switch ( wmi->mid ) {
5518 	  case MID_OpenOutline:
5519 	    wmi->ti.disabled = anychars==-1 || in_modal;
5520 	  break;
5521 	  case MID_OpenBitmap:
5522 	    wmi->ti.disabled = anychars==-1 || fv->b.sf->bitmaps==NULL || in_modal;
5523 	  break;
5524 	  case MID_OpenMetrics:
5525 	    wmi->ti.disabled = in_modal;
5526 	  break;
5527 	  case MID_Warnings:
5528 	    wmi->ti.disabled = ErrorWindowExists();
5529 	  break;
5530 	}
5531     }
5532 }
5533 
5534 GMenuItem2 helplist[] = {
5535     { { (unichar_t *) N_("_Help"), (GImage *) "helphelp.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'H' }, H_("Help|F1"), NULL, NULL, FVMenuContextualHelp, 0 },
5536     { { (unichar_t *) N_("_Overview"), (GImage *) "menuempty.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'I' }, H_("Overview|Shft+F1"), NULL, NULL, MenuHelp, 0 },
5537     { { (unichar_t *) N_("_Index"), (GImage *) "helpindex.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'I' }, H_("Index|No Shortcut"), NULL, NULL, MenuIndex, 0 },
5538     { { (unichar_t *) N_("_About..."), (GImage *) "helpabout.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'A' }, H_("About...|No Shortcut"), NULL, NULL, MenuAbout, 0 },
5539     { { (unichar_t *) N_("_License..."), (GImage *) "menuempty.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'A' }, H_("License...|No Shortcut"), NULL, NULL, MenuLicense, 0 },
5540     GMENUITEM2_EMPTY
5541 };
5542 
5543 GMenuItem fvpopupmenu[] = {
5544     { { (unichar_t *) N_("New O_utline Window"), 0, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'u' }, '\0', ksm_control, NULL, NULL, FVMenuOpenOutline, MID_OpenOutline },
5545     GMENUITEM_LINE,
5546     { { (unichar_t *) N_("Cu_t"), (GImage *) "editcut.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 't' }, '\0', ksm_control, NULL, NULL, FVMenuCut, MID_Cut },
5547     { { (unichar_t *) N_("_Copy"), (GImage *) "editcopy.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'C' }, '\0', ksm_control, NULL, NULL, FVMenuCopy, MID_Copy },
5548     { { (unichar_t *) N_("C_opy Reference"), (GImage *) "editcopyref.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'o' }, '\0', ksm_control, NULL, NULL, FVMenuCopyRef, MID_CopyRef },
5549     { { (unichar_t *) N_("Copy _Width"), (GImage *) "editcopywidth.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'W' }, '\0', ksm_control, NULL, NULL, FVMenuCopyWidth, MID_CopyWidth },
5550     { { (unichar_t *) N_("_Paste"), (GImage *) "editpaste.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'P' }, '\0', ksm_control, NULL, NULL, FVMenuPaste, MID_Paste },
5551     { { (unichar_t *) N_("C_lear"), (GImage *) "editclear.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'l' }, 0, 0, NULL, NULL, FVMenuClear, MID_Clear },
5552     { { (unichar_t *) N_("Copy _Fg To Bg"), (GImage *) "editcopyfg2bg.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'F' }, '\0', ksm_control|ksm_shift, NULL, NULL, FVMenuCopyFgBg, MID_CopyFgToBg },
5553     { { (unichar_t *) N_("U_nlink Reference"), (GImage *) "editunlink.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'U' }, '\0', ksm_control, NULL, NULL, FVMenuUnlinkRef, MID_UnlinkRef },
5554     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, '\0', 0, NULL, NULL, NULL, 0 }, /* line */
5555     { { (unichar_t *) N_("Glyph _Info..."), (GImage *) "elementglyphinfo.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'I' }, '\0', ksm_control, NULL, NULL, FVMenuCharInfo, MID_CharInfo },
5556     { { (unichar_t *) N_("_Transform..."), (GImage *) "elementtransform.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'T' }, '\0', ksm_control, NULL, NULL, FVMenuTransform, MID_Transform },
5557     { { (unichar_t *) N_("_Expand Stroke..."), (GImage *) "elementexpandstroke.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'E' }, '\0', ksm_control|ksm_shift, NULL, NULL, FVMenuStroke, MID_Stroke },
5558     { { (unichar_t *) N_("To _Int"), (GImage *) "elementround.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'I' }, '\0', ksm_control|ksm_shift, NULL, NULL, FVMenuRound2Int, MID_Round },
5559     { { (unichar_t *) N_("_Correct Direction"), (GImage *) "elementcorrectdir.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'D' }, '\0', ksm_control|ksm_shift, NULL, NULL, FVMenuCorrectDir, MID_Correct },
5560     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, '\0', 0, NULL, NULL, NULL, 0 }, /* line */
5561     { { (unichar_t *) N_("Auto_Hint"), (GImage *) "hintsautohint.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'H' }, '\0', ksm_control|ksm_shift, NULL, NULL, FVMenuAutoHint, MID_AutoHint },
5562     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, '\0', 0, NULL, NULL, NULL, 0 }, /* line */
5563     { { (unichar_t *) N_("_Center in Width"), (GImage *) "metricscenter.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'C' }, '\0', ksm_control, NULL, NULL, FVMenuCenter, MID_Center },
5564     { { (unichar_t *) N_("Set _Width..."), (GImage *) "metricssetwidth.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'W' }, '\0', ksm_control|ksm_shift, NULL, NULL, FVMenuSetWidth, MID_SetWidth },
5565     { { (unichar_t *) N_("Set _Vertical Advance..."), (GImage *) "metricssetvwidth.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'V' }, '\0', ksm_control|ksm_shift, NULL, NULL, FVMenuSetWidth, MID_SetVWidth },
5566     GMENUITEM_EMPTY
5567 };
5568 
5569 static GMenuItem2 mblist[] = {
5570     { { (unichar_t *) N_("_File"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'F' }, H_("File|No Shortcut"), fllist, fllistcheck, NULL, 0 },
5571     { { (unichar_t *) N_("_Edit"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'E' }, H_("Edit|No Shortcut"), edlist, edlistcheck, NULL, 0 },
5572     { { (unichar_t *) N_("E_lement"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'l' }, H_("Element|No Shortcut"), ellist, ellistcheck, NULL, 0 },
5573 #ifndef _NO_PYTHON
5574     { { (unichar_t *) N_("_Tools"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 1, 1, 0, 0, 0, 0, 1, 1, 0, 'l' }, H_("Tools|No Shortcut"), NULL, fvpy_tllistcheck, NULL, 0 },
5575 #endif
5576 #ifdef NATIVE_CALLBACKS
5577     { { (unichar_t *) N_("Tools_2"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 1, 1, 0, 0, 0, 0, 1, 1, 0, 'l' }, H_("Tools2|No Shortcut"), NULL, fv_tl2listcheck, NULL, 0 },
5578 #endif
5579     { { (unichar_t *) N_("H_ints"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'i' }, H_("Hints|No Shortcut"), htlist, htlistcheck, NULL, 0 },
5580     { { (unichar_t *) N_("E_ncoding"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'V' }, H_("Encoding|No Shortcut"), enlist, enlistcheck, NULL, 0 },
5581     { { (unichar_t *) N_("_View"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'V' }, H_("View|No Shortcut"), vwlist, vwlistcheck, NULL, 0 },
5582     { { (unichar_t *) N_("_Metrics"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'M' }, H_("Metrics|No Shortcut"), mtlist, mtlistcheck, NULL, 0 },
5583     { { (unichar_t *) N_("_CID"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'C' }, H_("CID|No Shortcut"), cdlist, cdlistcheck, NULL, 0 },
5584 /* GT: Here (and following) MM means "MultiMaster" */
5585     { { (unichar_t *) N_("MM"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, '\0' }, H_("MM|No Shortcut"), mmlist, mmlistcheck, NULL, 0 },
5586     { { (unichar_t *) N_("_Window"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'W' }, H_("Window|No Shortcut"), wnmenu, FVWindowMenuBuild, NULL, 0 },
5587     { { (unichar_t *) N_("_Help"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'H' }, H_("Help|No Shortcut"), helplist, NULL, NULL, 0 },
5588     GMENUITEM2_EMPTY
5589 };
5590 
FVRefreshChar(FontView * fv,int gid)5591 void FVRefreshChar(FontView *fv,int gid) {
5592     BDFChar *bdfc;
5593     int i, j, enc;
5594     MetricsView *mv;
5595 
5596     /* Can happen in scripts */ /* Can happen if we do an AutoHint when generating a tiny font for freetype context */
5597     if ( fv->v==NULL || fv->colcnt==0 || fv->b.sf->glyphs[gid]== NULL )
5598 return;
5599     for ( fv=(FontView *) (fv->b.sf->fv); fv!=NULL; fv = (FontView *) (fv->b.nextsame) ) {
5600 	if( !fv->colcnt )
5601 	    continue;
5602 
5603 	for ( mv=fv->b.sf->metrics; mv!=NULL; mv=mv->next )
5604 	    MVRefreshChar(mv,fv->b.sf->glyphs[gid]);
5605 	if ( fv->show==fv->filled )
5606 	    bdfc = BDFPieceMealCheck(fv->show,gid);
5607 	else
5608 	    bdfc = fv->show->glyphs[gid];
5609 	if ( bdfc==NULL )
5610 	    bdfc = BDFPieceMeal(fv->show,gid);
5611 	/* A glyph may be encoded in several places, all need updating */
5612 	for ( enc = 0; enc<fv->b.map->enccount; ++enc ) if ( fv->b.map->map[enc]==gid ) {
5613 	    i = enc / fv->colcnt;
5614 	    j = enc - i*fv->colcnt;
5615 	    i -= fv->rowoff;
5616 	    if ( i>=0 && i<fv->rowcnt )
5617 		FVDrawGlyph(fv->v,fv,enc,true);
5618 	}
5619     }
5620 }
5621 
FVRegenChar(FontView * fv,SplineChar * sc)5622 void FVRegenChar(FontView *fv,SplineChar *sc) {
5623     struct splinecharlist *dlist;
5624     MetricsView *mv;
5625 
5626     if ( fv->v==NULL )			/* Can happen in scripts */
5627 return;
5628 
5629     if ( sc->orig_pos<fv->filled->glyphcnt ) {
5630 	BDFCharFree(fv->filled->glyphs[sc->orig_pos]);
5631 	fv->filled->glyphs[sc->orig_pos] = NULL;
5632     }
5633     /* FVRefreshChar does NOT do this for us */
5634     for ( mv=fv->b.sf->metrics; mv!=NULL; mv=mv->next )
5635 	MVRegenChar(mv,sc);
5636 
5637     FVRefreshChar(fv,sc->orig_pos);
5638 #if HANYANG
5639     if ( sc->compositionunit && fv->b.sf->rules!=NULL )
5640 	Disp_RefreshChar(fv->b.sf,sc);
5641 #endif
5642 
5643     for ( dlist=sc->dependents; dlist!=NULL; dlist=dlist->next )
5644 	FVRegenChar(fv,dlist->sc);
5645 }
5646 
AddSubPST(SplineChar * sc,struct lookup_subtable * sub,char * variant)5647 static void AddSubPST(SplineChar *sc,struct lookup_subtable *sub,char *variant) {
5648     PST *pst;
5649 
5650     pst = chunkalloc(sizeof(PST));
5651     pst->type = pst_substitution;
5652     pst->subtable = sub;
5653     pst->u.alt.components = copy(variant);
5654     pst->next = sc->possub;
5655     sc->possub = pst;
5656 }
5657 
FVMakeChar(FontView * fv,int enc)5658 SplineChar *FVMakeChar(FontView *fv,int enc) {
5659     SplineFont *sf = fv->b.sf;
5660     SplineChar *base_sc = SFMakeChar(sf,fv->b.map,enc), *feat_sc = NULL;
5661     int feat_gid = FeatureTrans(fv,enc);
5662 
5663     if ( fv->cur_subtable==NULL )
5664 return( base_sc );
5665 
5666     if ( feat_gid==-1 ) {
5667 	int uni = -1;
5668 	FeatureScriptLangList *fl = fv->cur_subtable->lookup->features;
5669 
5670 	if ( base_sc->unicodeenc>=0x600 && base_sc->unicodeenc<=0x6ff &&
5671 		fl!=NULL &&
5672 		(fl->featuretag == CHR('i','n','i','t') ||
5673 		 fl->featuretag == CHR('m','e','d','i') ||
5674 		 fl->featuretag == CHR('f','i','n','a') ||
5675 		 fl->featuretag == CHR('i','s','o','l')) ) {
5676 	    uni = fl->featuretag == CHR('i','n','i','t') ? ArabicForms[base_sc->unicodeenc-0x600].initial  :
5677 		  fl->featuretag == CHR('m','e','d','i') ? ArabicForms[base_sc->unicodeenc-0x600].medial   :
5678 		  fl->featuretag == CHR('f','i','n','a') ? ArabicForms[base_sc->unicodeenc-0x600].final    :
5679 		  fl->featuretag == CHR('i','s','o','l') ? ArabicForms[base_sc->unicodeenc-0x600].isolated :
5680 		  -1;
5681 	    feat_sc = SFGetChar(sf,uni,NULL);
5682 	    if ( feat_sc!=NULL )
5683 return( feat_sc );
5684 	}
5685 	feat_sc = SFSplineCharCreate(sf);
5686 	feat_sc->unicodeenc = uni;
5687 	if ( uni!=-1 ) {
5688 	    feat_sc->name = malloc(8);
5689 	    feat_sc->unicodeenc = uni;
5690 	    sprintf( feat_sc->name,"uni%04X", uni );
5691 	} else if ( fv->cur_subtable->suffix!=NULL ) {
5692 	    feat_sc->name = malloc(strlen(base_sc->name)+strlen(fv->cur_subtable->suffix)+2);
5693 	    sprintf( feat_sc->name, "%s.%s", base_sc->name, fv->cur_subtable->suffix );
5694 	} else if ( fl==NULL ) {
5695 	    feat_sc->name = strconcat(base_sc->name,".unknown");
5696 	} else if ( fl->ismac ) {
5697 	    /* mac feature/setting */
5698 	    feat_sc->name = malloc(strlen(base_sc->name)+14);
5699 	    sprintf( feat_sc->name,"%s.m%d_%d", base_sc->name,
5700 		    (int) (fl->featuretag>>16),
5701 		    (int) ((fl->featuretag)&0xffff) );
5702 	} else {
5703 	    /* OpenType feature tag */
5704 	    feat_sc->name = malloc(strlen(base_sc->name)+6);
5705 	    sprintf( feat_sc->name,"%s.%c%c%c%c", base_sc->name,
5706 		    (int) (fl->featuretag>>24),
5707 		    (int) ((fl->featuretag>>16)&0xff),
5708 		    (int) ((fl->featuretag>>8)&0xff),
5709 		    (int) ((fl->featuretag)&0xff) );
5710 	}
5711 	SFAddGlyphAndEncode(sf,feat_sc,fv->b.map,fv->b.map->enccount);
5712 	AddSubPST(base_sc,fv->cur_subtable,feat_sc->name);
5713 return( feat_sc );
5714     } else
5715 return( base_sc );
5716 }
5717 
5718 /* we style some glyph names differently, see FVExpose() */
5719 #define _uni_italic	0x2
5720 #define _uni_vertical	(1<<2)
5721 #define _uni_fontmax	(2<<2)
5722 
FVCheckFont(FontView * fv,int type)5723 static GFont *FVCheckFont(FontView *fv,int type) {
5724     FontRequest rq;
5725 
5726     if ( fv->fontset[type]==NULL ) {
5727 	memset(&rq,0,sizeof(rq));
5728 	rq.utf8_family_name = fv_fontnames;
5729 	rq.point_size = fv_fontsize;
5730 	rq.weight = 400;
5731 	rq.style = 0;
5732 	if (type&_uni_italic)
5733 	    rq.style |= fs_italic;
5734 	if (type&_uni_vertical)
5735 	    rq.style |= fs_vertical;
5736 	fv->fontset[type] = GDrawInstanciateFont(fv->v,&rq);
5737     }
5738 return( fv->fontset[type] );
5739 }
5740 
5741 extern unichar_t adobes_pua_alts[0x200][3];
5742 
do_Adobe_Pua(unichar_t * buf,int sob,int uni)5743 static void do_Adobe_Pua(unichar_t *buf,int sob,int uni) {
5744     int i, j;
5745 
5746     for ( i=j=0; j<sob-1 && i<3; ++i ) {
5747 	int ch = adobes_pua_alts[uni-0xf600][i];
5748 	if ( ch==0 )
5749     break;
5750 	if ( ch>=0xf600 && ch<=0xf7ff && adobes_pua_alts[ch-0xf600]!=0 ) {
5751 	    do_Adobe_Pua(buf+j,sob-j,ch);
5752 	    while ( buf[j]!=0 ) ++j;
5753 	} else
5754 	    buf[j++] = ch;
5755     }
5756     buf[j] = 0;
5757 }
5758 
FVExpose(FontView * fv,GWindow pixmap,GEvent * event)5759 static void FVExpose(FontView *fv,GWindow pixmap, GEvent *event) {
5760     int i, j, y, width, gid;
5761     int changed;
5762     GRect old, old2, r;
5763     GClut clut;
5764     struct _GImage base;
5765     GImage gi;
5766     SplineChar dummy;
5767     int styles, laststyles=0;
5768     Color bg, def_fg;
5769     int fgxor;
5770 
5771     def_fg = GDrawGetDefaultForeground(NULL);
5772     memset(&gi,'\0',sizeof(gi));
5773     memset(&base,'\0',sizeof(base));
5774     if ( fv->show->clut!=NULL ) {
5775 	gi.u.image = &base;
5776 	base.image_type = it_index;
5777 	base.clut = fv->show->clut;
5778 	GDrawSetDither(NULL, false);
5779 	base.trans = -1;
5780     } else {
5781 	memset(&clut,'\0',sizeof(clut));
5782 	gi.u.image = &base;
5783 	base.image_type = it_mono;
5784 	base.clut = &clut;
5785 	clut.clut_len = 2;
5786 	clut.clut[0] = view_bgcol;
5787     }
5788 
5789     GDrawSetFont(pixmap,fv->fontset[0]);
5790     GDrawSetLineWidth(pixmap,0);
5791     GDrawPushClip(pixmap,&event->u.expose.rect,&old);
5792     GDrawFillRect(pixmap,NULL,view_bgcol);
5793     for ( i=0; i<=fv->rowcnt; ++i ) {
5794 	GDrawDrawLine(pixmap,0,i*fv->cbh,fv->width,i*fv->cbh,def_fg);
5795 	GDrawDrawLine(pixmap,0,i*fv->cbh+fv->lab_height,fv->width,i*fv->cbh+fv->lab_height,0x808080);
5796     }
5797     for ( i=0; i<=fv->colcnt; ++i )
5798 	GDrawDrawLine(pixmap,i*fv->cbw,0,i*fv->cbw,fv->height,def_fg);
5799     for ( i=event->u.expose.rect.y/fv->cbh; i<=fv->rowcnt &&
5800 	    (event->u.expose.rect.y+event->u.expose.rect.height+fv->cbh-1)/fv->cbh; ++i ) for ( j=0; j<fv->colcnt; ++j ) {
5801 	int index = (i+fv->rowoff)*fv->colcnt+j;
5802 	SplineChar *sc;
5803 	styles = 0;
5804 	if ( index < fv->b.map->enccount && index!=-1 ) {
5805 	    unichar_t buf[60]; char cbuf[8];
5806 	    char utf8_buf[8];
5807 	    int use_utf8 = false;
5808 	    Color fg;
5809 	    int uni;
5810 	    struct cidmap *cidmap = NULL;
5811 	    sc = (gid=fv->b.map->map[index])!=-1 ? fv->b.sf->glyphs[gid]: NULL;
5812 
5813 	    if ( fv->b.cidmaster!=NULL )
5814 		cidmap = FindCidMap(fv->b.cidmaster->cidregistry,fv->b.cidmaster->ordering,fv->b.cidmaster->supplement,fv->b.cidmaster);
5815 
5816 	    if ( ( fv->b.map->enc==&custom && index<256 ) ||
5817 		 ( fv->b.map->enc!=&custom && index<fv->b.map->enc->char_cnt ) ||
5818 		 ( cidmap!=NULL && index<MaxCID(cidmap) ))
5819 		fg = def_fg;
5820 	    else
5821 		fg = 0x505050;
5822 	    if ( sc==NULL )
5823 		sc = SCBuildDummy(&dummy,fv->b.sf,fv->b.map,index);
5824 	    uni = sc->unicodeenc;
5825 	    buf[0] = buf[1] = 0;
5826 	    if ( fv->b.sf->uni_interp==ui_ams && uni>=0xe000 && uni<=0xf8ff &&
5827 		    amspua[uni-0xe000]!=0 )
5828 		uni = amspua[uni-0xe000];
5829 	    switch ( fv->glyphlabel ) {
5830 	      case gl_name:
5831 		uc_strncpy(buf,sc->name,sizeof(buf)/sizeof(buf[0]));
5832 	      break;
5833 	      case gl_unicode:
5834 		if ( sc->unicodeenc!=-1 ) {
5835 		    sprintf(cbuf,"%04x",sc->unicodeenc);
5836 		    uc_strcpy(buf,cbuf);
5837 		} else
5838 		    uc_strcpy(buf,"?");
5839 	      break;
5840 	      case gl_encoding:
5841 		if ( fv->b.map->enc->only_1byte ||
5842 			(fv->b.map->enc->has_1byte && index<256))
5843 		    sprintf(cbuf,"%02x",index);
5844 		else
5845 		    sprintf(cbuf,"%04x",index);
5846 		uc_strcpy(buf,cbuf);
5847 	      break;
5848 	      case gl_glyph:
5849 		if ( uni==0xad )
5850 		    buf[0] = '-';
5851 		else if ( fv->b.sf->uni_interp==ui_adobe && uni>=0xf600 && uni<=0xf7ff &&
5852 			adobes_pua_alts[uni-0xf600]!=0 ) {
5853 		    use_utf8 = false;
5854 		    do_Adobe_Pua(buf,sizeof(buf),uni);
5855 		} else if ( uni>=0xe0020 && uni<=0xe007e ) {
5856 		    buf[0] = uni-0xe0000;	/* A map of Ascii for language names */
5857 #if HANYANG
5858 		} else if ( sc->compositionunit ) {
5859 		    if ( sc->jamo<19 )
5860 			buf[0] = 0x1100+sc->jamo;
5861 		    else if ( sc->jamo<19+21 )
5862 			buf[0] = 0x1161 + sc->jamo-19;
5863 		    else	/* Leave a hole for the blank char */
5864 			buf[0] = 0x11a8 + sc->jamo-(19+21+1);
5865 #endif
5866 		} else if ( uni>0 && uni<unicode4_size ) {
5867 		    char *pt = utf8_buf;
5868 		    use_utf8 = true;
5869 			*pt = '\0'; // We terminate the string in case the appendage (?) fails.
5870 		    pt = utf8_idpb(pt,uni,0);
5871 		    if (pt) *pt = '\0';
5872                     else if (uni<0xd800 || uni>0xdfff)
5873                         TRACE("Invalid Unicode alert.\n");
5874 		} else {
5875 		    char *pt = strchr(sc->name,'.');
5876 		    buf[0] = '?';
5877 		    fg = 0xff0000;
5878 		    if ( pt!=NULL ) {
5879 			int i, n = pt-sc->name;
5880 			char *end;
5881 			SplineFont *cm = fv->b.sf->cidmaster;
5882 			if ( n==7 && sc->name[0]=='u' && sc->name[1]=='n' && sc->name[2]=='i' &&
5883 				(i=strtol(sc->name+3,&end,16), end-sc->name==7))
5884 			    buf[0] = i;
5885 			else if ( n>=5 && n<=7 && sc->name[0]=='u' &&
5886 				(i=strtol(sc->name+1,&end,16), end-sc->name==n))
5887 			    buf[0] = i;
5888 			else if ( cm!=NULL && (i=CIDFromName(sc->name,cm))!=-1 ) {
5889 			    int uni;
5890 			    uni = CID2Uni(FindCidMap(cm->cidregistry,cm->ordering,cm->supplement,cm),
5891 				    i);
5892 			    if ( uni!=-1 )
5893 				buf[0] = uni;
5894 			} else {
5895 			    int uni;
5896 			    *pt = '\0';
5897 			    uni = UniFromName(sc->name,fv->b.sf->uni_interp,fv->b.map->enc);
5898 			    if ( uni!=-1 )
5899 				buf[0] = uni;
5900 			    *pt = '.';
5901 			}
5902 			if ( strstr(pt,".vert")!=NULL )
5903 			    styles = _uni_vertical;
5904 			if ( buf[0]!='?' ) {
5905 			    fg = def_fg;
5906 			    if ( strstr(pt,".italic")!=NULL )
5907 				styles = _uni_italic;
5908 			}
5909 		    } else if ( strncmp(sc->name,"hwuni",5)==0 ) {
5910 			int uni=-1;
5911 			sscanf(sc->name,"hwuni%x", (unsigned *) &uni );
5912 			if ( uni!=-1 ) buf[0] = uni;
5913 		    } else if ( strncmp(sc->name,"italicuni",9)==0 ) {
5914 			int uni=-1;
5915 			sscanf(sc->name,"italicuni%x", (unsigned *) &uni );
5916 			if ( uni!=-1 ) { buf[0] = uni; styles=_uni_italic; }
5917 			fg = def_fg;
5918 		    } else if ( strncmp(sc->name,"vertcid_",8)==0 ||
5919 			    strncmp(sc->name,"vertuni",7)==0 ) {
5920 			styles = _uni_vertical;
5921 		    }
5922 		}
5923 	      break;
5924 	    }
5925 	    r.x = j*fv->cbw+1; r.width = fv->cbw-1;
5926 	    r.y = i*fv->cbh+1; r.height = fv->lab_height-1;
5927 	    bg = view_bgcol;
5928 	    fgxor = 0x000000;
5929 	    changed = sc->changed;
5930 	    if ( fv->b.sf->onlybitmaps && gid<fv->show->glyphcnt )
5931 		changed = gid==-1 || fv->show->glyphs[gid]==NULL? false : fv->show->glyphs[gid]->changed;
5932 	    if ( changed ||
5933 		    sc->layers[ly_back].splines!=NULL || sc->layers[ly_back].images!=NULL ||
5934 		    sc->color!=COLOR_DEFAULT ) {
5935 		if ( sc->layers[ly_back].splines!=NULL || sc->layers[ly_back].images!=NULL ||
5936 			sc->color!=COLOR_DEFAULT )
5937 		    bg = sc->color!=COLOR_DEFAULT?sc->color:0x808080;
5938 		if ( sc->changed ) {
5939 		    fgxor = bg ^ fvchangedcol;
5940 		    bg = fvchangedcol;
5941 		}
5942 		GDrawFillRect(pixmap,&r,bg);
5943 	    }
5944 	    if ( (!fv->b.sf->layers[fv->b.active_layer].order2 && sc->changedsincelasthinted ) ||
5945 		     ( fv->b.sf->layers[fv->b.active_layer].order2 && sc->layers[fv->b.active_layer].splines!=NULL &&
5946 			sc->ttf_instrs_len<=0 ) ||
5947 		     ( fv->b.sf->layers[fv->b.active_layer].order2 && sc->instructions_out_of_date ) ) {
5948 		Color hintcol = fvhintingneededcol;
5949 		if ( fv->b.sf->layers[fv->b.active_layer].order2 && sc->instructions_out_of_date && sc->ttf_instrs_len>0 )
5950 		    hintcol = 0xff0000;
5951 		GDrawDrawLine(pixmap,r.x,r.y,r.x,r.y+r.height-1,hintcol);
5952 		GDrawDrawLine(pixmap,r.x+1,r.y,r.x+1,r.y+r.height-1,hintcol);
5953 		GDrawDrawLine(pixmap,r.x+2,r.y,r.x+2,r.y+r.height-1,hintcol);
5954 		GDrawDrawLine(pixmap,r.x+r.width-1,r.y,r.x+r.width-1,r.y+r.height-1,hintcol);
5955 		GDrawDrawLine(pixmap,r.x+r.width-2,r.y,r.x+r.width-2,r.y+r.height-1,hintcol);
5956 		GDrawDrawLine(pixmap,r.x+r.width-3,r.y,r.x+r.width-3,r.y+r.height-1,hintcol);
5957 	    }
5958 	    if ( use_utf8 && sc->unicodeenc!=-1 &&
5959 		/* Pango complains if we try to draw non characters */
5960 		/* These two are guaranteed "NOT A UNICODE CHARACTER" in all planes */
5961 		    ((sc->unicodeenc&0xffff)==0xfffe || (sc->unicodeenc&0xffff)==0xffff ||
5962 		     (sc->unicodeenc>=0xfdd0 && sc->unicodeenc<=0xfdef) ||	/* noncharacters */
5963 		     (sc->unicodeenc>=0xfe00 && sc->unicodeenc<=0xfe0f) ||	/* variation selectors */
5964 		     (sc->unicodeenc>=0xe0110 && sc->unicodeenc<=0xe01ff) ||	/* variation selectors */
5965 		/*  The surrogates in BMP aren't valid either */
5966 		     (sc->unicodeenc>=0xd800 && sc->unicodeenc<=0xdfff))) {	/* surrogates */
5967 		GDrawDrawLine(pixmap,r.x,r.y,r.x+r.width-1,r.y+r.height-1,0x000000);
5968 		GDrawDrawLine(pixmap,r.x,r.y+r.height-1,r.x+r.width-1,r.y,0x000000);
5969 	    } else if ( use_utf8 ) {
5970 		GTextBounds size;
5971 		if ( styles!=laststyles ) GDrawSetFont(pixmap,FVCheckFont(fv,styles));
5972 		width = GDrawGetText8Bounds(pixmap,utf8_buf,-1,&size);
5973 		if ( size.lbearing==0 && size.rbearing==0 ) {
5974 		    utf8_buf[0] = 0xe0 | (0xfffd>>12);
5975 		    utf8_buf[1] = 0x80 | ((0xfffd>>6)&0x3f);
5976 		    utf8_buf[2] = 0x80 | (0xfffd&0x3f);
5977 		    utf8_buf[3] = 0;
5978 		    width = GDrawGetText8Bounds(pixmap,utf8_buf,-1,&size);
5979 		}
5980 		width = size.rbearing - size.lbearing+1;
5981 		if ( width >= fv->cbw-1 ) {
5982 		    GDrawPushClip(pixmap,&r,&old2);
5983 		    width = fv->cbw-1;
5984 		}
5985 		if ( sc->unicodeenc<0x80 || sc->unicodeenc>=0xa0 ) {
5986 		    y = i*fv->cbh+fv->lab_as+1;
5987 		    /* move rotated glyph up a bit to center it */
5988 		    if (styles&_uni_vertical)
5989 			y -= fv->lab_as/2;
5990 		    GDrawDrawText8(pixmap,j*fv->cbw+(fv->cbw-1-width)/2-size.lbearing,y,utf8_buf,-1,fg^fgxor);
5991 		}
5992 		if ( width >= fv->cbw-1 )
5993 		    GDrawPopClip(pixmap,&old2);
5994 		laststyles = styles;
5995 	    } else {
5996 		if ( styles!=laststyles ) GDrawSetFont(pixmap,FVCheckFont(fv,styles));
5997 		width = GDrawGetTextWidth(pixmap,buf,-1);
5998 		if ( width >= fv->cbw-1 ) {
5999 		    GDrawPushClip(pixmap,&r,&old2);
6000 		    width = fv->cbw-1;
6001 		}
6002 		if ( sc->unicodeenc<0x80 || sc->unicodeenc>=0xa0 ) {
6003 		    y = i*fv->cbh+fv->lab_as+1;
6004 		    /* move rotated glyph up a bit to center it */
6005 		    if (styles&_uni_vertical)
6006 			y -= fv->lab_as/2;
6007 		    GDrawDrawText(pixmap,j*fv->cbw+(fv->cbw-1-width)/2,y,buf,-1,fg^fgxor);
6008 		}
6009 		if ( width >= fv->cbw-1 )
6010 		    GDrawPopClip(pixmap,&old2);
6011 		laststyles = styles;
6012 	    }
6013 	}
6014 	FVDrawGlyph(pixmap,fv,index,false);
6015     }
6016     if ( fv->showhmetrics&fvm_baseline ) {
6017 	for ( i=0; i<=fv->rowcnt; ++i )
6018 	    GDrawDrawLine(pixmap,0,i*fv->cbh+fv->lab_height+fv->magnify*fv->show->ascent+1,fv->width,i*fv->cbh+fv->lab_height+fv->magnify*fv->show->ascent+1,METRICS_BASELINE);
6019     }
6020     GDrawPopClip(pixmap,&old);
6021     GDrawSetDither(NULL, true);
6022 }
6023 
FVDrawInfo(FontView * fv,GWindow pixmap,GEvent * event)6024 void FVDrawInfo(FontView *fv,GWindow pixmap, GEvent *event) {
6025     GRect old, r;
6026     Color bg = GDrawGetDefaultBackground(GDrawGetDisplayOfWindow(pixmap));
6027     Color fg = fvglyphinfocol;
6028     SplineChar *sc, dummy;
6029     SplineFont *sf = fv->b.sf;
6030     EncMap *map = fv->b.map;
6031     int gid, uni, localenc;
6032     GString *output = g_string_new( "" );
6033     gchar *uniname = NULL;
6034 
6035     if ( event->u.expose.rect.y+event->u.expose.rect.height<=fv->mbh ) {
6036         g_string_free( output, TRUE ); output = NULL;
6037 	return;
6038     }
6039 
6040     GDrawSetFont(pixmap,fv->fontset[0]);
6041     GDrawPushClip(pixmap,&event->u.expose.rect,&old);
6042 
6043     r.x = 0; r.width = fv->width; r.y = fv->mbh; r.height = fv->infoh;
6044     GDrawFillRect(pixmap,&r,bg);
6045     if ( fv->end_pos>=map->enccount || fv->pressed_pos>=map->enccount ||
6046 	    fv->end_pos<0 || fv->pressed_pos<0 )
6047 	fv->end_pos = fv->pressed_pos = -1;	/* Can happen after reencoding */
6048     if ( fv->end_pos == -1 ) {
6049         g_string_free( output, TRUE ); output = NULL;
6050 	GDrawPopClip(pixmap,&old);
6051 	return;
6052     }
6053 
6054     localenc = fv->end_pos;
6055     if ( map->remap!=NULL ) {
6056 	struct remap *remap = map->remap;
6057 	while ( remap->infont!=-1 ) {
6058 	    if ( localenc>=remap->infont && localenc<=remap->infont+(remap->lastenc-remap->firstenc) ) {
6059 		localenc += remap->firstenc-remap->infont;
6060 		break;
6061 	    }
6062 	    ++remap;
6063 	}
6064     }
6065     g_string_printf( output, "%d (0x%x) ", localenc, localenc );
6066 
6067     sc = (gid=fv->b.map->map[fv->end_pos])!=-1 ? sf->glyphs[gid] : NULL;
6068     if ( fv->b.cidmaster==NULL || fv->b.normal==NULL || sc==NULL )
6069 	SCBuildDummy(&dummy,sf,fv->b.map,fv->end_pos);
6070     else
6071 	dummy = *sc;
6072     if ( sc==NULL ) sc = &dummy;
6073     uni = dummy.unicodeenc!=-1 ? dummy.unicodeenc : sc->unicodeenc;
6074 
6075     /* last resort at guessing unicode code point from partial name */
6076     if ( uni == -1 ) {
6077 	char *pt = strchr( sc->name, '.' );
6078 	if( pt != NULL ) {
6079 	    gchar *buf = g_strndup( (const gchar *) sc->name, pt - sc->name );
6080 	    uni = UniFromName( (char *) buf, fv->b.sf->uni_interp, map->enc );
6081 	    g_free( buf );
6082 	}
6083     }
6084 
6085     if ( uni != -1 )
6086 	g_string_append_printf( output, "U+%04X", uni );
6087     else {
6088 	output = g_string_append( output, "U+????" );
6089     }
6090 
6091     /* postscript name */
6092     g_string_append_printf( output, " \"%s\" ", sc->name );
6093 
6094     /* code point name or range name */
6095     if( uni != -1 ) {
6096 	uniname = (gchar *) unicode_name( uni );
6097 	if ( uniname == NULL ) {
6098 	    uniname = g_strdup( UnicodeRange( uni ) );
6099 	}
6100     }
6101 
6102     if ( uniname != NULL ) {
6103 	output = g_string_append( output, uniname );
6104 	g_free( uniname );
6105     }
6106 
6107     GDrawDrawText8( pixmap, 10, fv->mbh+fv->lab_as, output->str, -1, fg );
6108     g_string_free( output, TRUE ); output = NULL;
6109     GDrawPopClip( pixmap, &old );
6110     return;
6111 }
6112 
FVShowInfo(FontView * fv)6113 static void FVShowInfo(FontView *fv) {
6114     GRect r;
6115 
6116     if ( fv->v==NULL )			/* Can happen in scripts */
6117 return;
6118 
6119     r.x = 0; r.width = fv->width; r.y = fv->mbh; r.height = fv->infoh;
6120     GDrawRequestExpose(fv->gw,&r,false);
6121 }
6122 
FVChar(FontView * fv,GEvent * event)6123 void FVChar(FontView *fv, GEvent *event) {
6124     int i,pos, cnt, gid;
6125     extern int navigation_mask;
6126 
6127 #if MyMemory
6128     if ( event->u.chr.keysym == GK_F2 ) {
6129 	fprintf( stderr, "Malloc debug on\n" );
6130 	__malloc_debug(5);
6131     } else if ( event->u.chr.keysym == GK_F3 ) {
6132 	fprintf( stderr, "Malloc debug off\n" );
6133 	__malloc_debug(0);
6134     }
6135 #endif
6136 
6137     if ( event->u.chr.keysym=='s' &&
6138 	    (event->u.chr.state&ksm_control) &&
6139 	    (event->u.chr.state&ksm_meta) )
6140 	MenuSaveAll(NULL,NULL,NULL);
6141     else if ( event->u.chr.keysym=='q' &&
6142 	    (event->u.chr.state&ksm_control) &&
6143 	    (event->u.chr.state&ksm_meta) )
6144 	MenuExit(NULL,NULL,NULL);
6145     else if ( event->u.chr.keysym=='I' &&
6146 	    (event->u.chr.state&ksm_shift) &&
6147 	    (event->u.chr.state&ksm_meta) )
6148 	FVMenuCharInfo(fv->gw,NULL,NULL);
6149     else if ( (event->u.chr.keysym=='[' || event->u.chr.keysym==']') &&
6150 	    (event->u.chr.state&ksm_control) ) {
6151 	_FVMenuChangeChar(fv,event->u.chr.keysym=='['?MID_Prev:MID_Next);
6152     } else if ( (event->u.chr.keysym=='{' || event->u.chr.keysym=='}') &&
6153 	    (event->u.chr.state&ksm_control) ) {
6154 	_FVMenuChangeChar(fv,event->u.chr.keysym=='{'?MID_PrevDef:MID_NextDef);
6155     } else if ( event->u.chr.keysym=='\\' && (event->u.chr.state&ksm_control) ) {
6156 	/* European keyboards need a funky modifier to get \ */
6157 	FVDoTransform(fv);
6158 #if !defined(_NO_FFSCRIPT) || !defined(_NO_PYTHON)
6159     } else if ( isdigit(event->u.chr.keysym) && (event->u.chr.state&ksm_control) &&
6160 	    (event->u.chr.state&ksm_meta) ) {
6161 	/* The Script menu isn't always up to date, so we might get one of */
6162 	/*  the shortcuts here */
6163 	int index = event->u.chr.keysym-'1';
6164 	if ( index<0 ) index = 9;
6165 	if ( script_filenames[index]!=NULL )
6166 	    ExecuteScriptFile((FontViewBase *) fv,NULL,script_filenames[index]);
6167 #endif
6168     } else if ( event->u.chr.keysym == GK_Left ||
6169 	    event->u.chr.keysym == GK_Tab ||
6170 	    event->u.chr.keysym == GK_BackTab ||
6171 	    event->u.chr.keysym == GK_Up ||
6172 	    event->u.chr.keysym == GK_Right ||
6173 	    event->u.chr.keysym == GK_Down ||
6174 	    event->u.chr.keysym == GK_KP_Left ||
6175 	    event->u.chr.keysym == GK_KP_Up ||
6176 	    event->u.chr.keysym == GK_KP_Right ||
6177 	    event->u.chr.keysym == GK_KP_Down ||
6178 	    event->u.chr.keysym == GK_Home ||
6179 	    event->u.chr.keysym == GK_KP_Home ||
6180 	    event->u.chr.keysym == GK_End ||
6181 	    event->u.chr.keysym == GK_KP_End ||
6182 	    event->u.chr.keysym == GK_Page_Up ||
6183 	    event->u.chr.keysym == GK_KP_Page_Up ||
6184 	    event->u.chr.keysym == GK_Prior ||
6185 	    event->u.chr.keysym == GK_Page_Down ||
6186 	    event->u.chr.keysym == GK_KP_Page_Down ||
6187 	    event->u.chr.keysym == GK_Next ) {
6188 	int end_pos = fv->end_pos;
6189 	/* We move the currently selected char. If there is none, then pick */
6190 	/*  something on the screen */
6191 	if ( end_pos==-1 )
6192 	    end_pos = (fv->rowoff+fv->rowcnt/2)*fv->colcnt;
6193 	switch ( event->u.chr.keysym ) {
6194 	  case GK_Tab:
6195 	    pos = end_pos;
6196 	    do {
6197 		if ( event->u.chr.state&ksm_shift )
6198 		    --pos;
6199 		else
6200 		    ++pos;
6201 		if ( pos>=fv->b.map->enccount ) pos = 0;
6202 		else if ( pos<0 ) pos = fv->b.map->enccount-1;
6203 	    } while ( pos!=end_pos &&
6204 		    ((gid=fv->b.map->map[pos])==-1 || !SCWorthOutputting(fv->b.sf->glyphs[gid])));
6205 	    if ( pos==end_pos ) ++pos;
6206 	    if ( pos>=fv->b.map->enccount ) pos = 0;
6207 	  break;
6208 #if GK_Tab!=GK_BackTab
6209 	  case GK_BackTab:
6210 	    pos = end_pos;
6211 	    do {
6212 		--pos;
6213 		if ( pos<0 ) pos = fv->b.map->enccount-1;
6214 	    } while ( pos!=end_pos &&
6215 		    ((gid=fv->b.map->map[pos])==-1 || !SCWorthOutputting(fv->b.sf->glyphs[gid])));
6216 	    if ( pos==end_pos ) --pos;
6217 	    if ( pos<0 ) pos = 0;
6218 	  break;
6219 #endif
6220 	  case GK_Left: case GK_KP_Left:
6221 	    pos = end_pos-1;
6222 	  break;
6223 	  case GK_Right: case GK_KP_Right:
6224 	    pos = end_pos+1;
6225 	  break;
6226 	  case GK_Up: case GK_KP_Up:
6227 	    pos = end_pos-fv->colcnt;
6228 	  break;
6229 	  case GK_Down: case GK_KP_Down:
6230 	    pos = end_pos+fv->colcnt;
6231 	  break;
6232 	  case GK_End: case GK_KP_End:
6233 	    pos = fv->b.map->enccount;
6234 	  break;
6235 	  case GK_Home: case GK_KP_Home:
6236 	    pos = 0;
6237 	    if ( fv->b.sf->top_enc!=-1 && fv->b.sf->top_enc<fv->b.map->enccount )
6238 		pos = fv->b.sf->top_enc;
6239 	    else {
6240 		pos = SFFindSlot(fv->b.sf,fv->b.map,home_char,NULL);
6241 		if ( pos==-1 ) pos = 0;
6242 	    }
6243 	  break;
6244 	  case GK_Page_Up: case GK_KP_Page_Up:
6245 #if GK_Prior!=GK_Page_Up
6246 	  case GK_Prior:
6247 #endif
6248 	    pos = (fv->rowoff-fv->rowcnt+1)*fv->colcnt;
6249 	  break;
6250 	  case GK_Page_Down: case GK_KP_Page_Down:
6251 #if GK_Next!=GK_Page_Down
6252 	  case GK_Next:
6253 #endif
6254 	    pos = (fv->rowoff+fv->rowcnt+1)*fv->colcnt;
6255 	  break;
6256 	}
6257 	if ( pos<0 ) pos = 0;
6258 	if ( pos>=fv->b.map->enccount ) pos = fv->b.map->enccount-1;
6259 	if ( event->u.chr.state&ksm_shift && event->u.chr.keysym!=GK_Tab && event->u.chr.keysym!=GK_BackTab ) {
6260 	    FVReselect(fv,pos);
6261 	} else {
6262 	    FVDeselectAll(fv);
6263 	    fv->b.selected[pos] = true;
6264 	    FVToggleCharSelected(fv,pos);
6265 	    fv->pressed_pos = pos;
6266 	    fv->sel_index = 1;
6267 	}
6268 	fv->end_pos = pos;
6269 	FVShowInfo(fv);
6270 	FVScrollToChar(fv,pos);
6271     } else if ( event->u.chr.keysym == GK_Help ) {
6272 	MenuHelp(NULL,NULL,NULL);	/* Menu does F1 */
6273     } else if ( event->u.chr.keysym == GK_Escape ) {
6274 	FVDeselectAll(fv);
6275     } else if ( event->u.chr.chars[0]=='\r' || event->u.chr.chars[0]=='\n' ) {
6276 	if ( fv->b.container!=NULL && fv->b.container->funcs->is_modal )
6277 return;
6278 	for ( i=cnt=0; i<fv->b.map->enccount && cnt<10; ++i ) if ( fv->b.selected[i] ) {
6279 	    SplineChar *sc = SFMakeChar(fv->b.sf,fv->b.map,i);
6280 	    if ( fv->show==fv->filled ) {
6281 		CharViewCreate(sc,fv,i);
6282 	    } else {
6283 		BDFFont *bdf = fv->show;
6284 		BitmapViewCreate(BDFMakeGID(bdf,sc->orig_pos),bdf,fv,i);
6285 	    }
6286 	    ++cnt;
6287 	}
6288     } else if ( (event->u.chr.state&((GMenuMask()|navigation_mask)&~(ksm_shift|ksm_capslock)))==navigation_mask &&
6289 	    event->type == et_char &&
6290 	    event->u.chr.keysym!=0 &&
6291 	    (event->u.chr.keysym<GK_Special/* || event->u.chr.keysym>=0x10000*/)) {
6292 	SplineFont *sf = fv->b.sf;
6293 	int enc = EncFromUni(event->u.chr.keysym,fv->b.map->enc);
6294 	if ( enc==-1 ) {
6295 	    for ( i=0; i<sf->glyphcnt; ++i ) {
6296 		if ( sf->glyphs[i]!=NULL )
6297 		    if ( sf->glyphs[i]->unicodeenc==event->u.chr.keysym )
6298 	    break;
6299 	    }
6300 	    if ( i<sf->glyphcnt )
6301 		enc = fv->b.map->backmap[i];
6302 	}
6303 	if ( enc<fv->b.map->enccount && enc!=-1 )
6304 	    FVChangeChar(fv,enc);
6305     }
6306 }
6307 
utf82u_annot_strncat(unichar_t * to,const char * from,int len)6308 static void utf82u_annot_strncat(unichar_t *to, const char *from, int len) {
6309     register unichar_t ch;
6310 
6311     to += u_strlen(to);
6312     while ( (ch = utf8_ildb(&from)) != '\0' && --len>=0 ) {
6313 	if ( ch=='\t' ) {
6314 	    *(to++) = ' ';
6315 	    ch = ' ';
6316 	}
6317 	*(to++) = ch;
6318     }
6319     *to = 0;
6320 }
6321 
SCPreparePopup(GWindow gw,SplineChar * sc,struct remap * remap,int localenc,int actualuni)6322 void SCPreparePopup(GWindow gw,SplineChar *sc,struct remap *remap, int localenc,
6323 	int actualuni) {
6324 /* This is for the popup which appears when you hover mouse over a character on main window */
6325     int upos=-1;
6326     char *msg, *msg_old;
6327 
6328     /* If a glyph is multiply mapped then the inbuild unicode enc may not be */
6329     /*  the actual one used to access the glyph */
6330     if ( remap!=NULL ) {
6331 	while ( remap->infont!=-1 ) {
6332 	    if ( localenc>=remap->infont && localenc<=remap->infont+(remap->lastenc-remap->firstenc) ) {
6333 		localenc += remap->firstenc-remap->infont;
6334                 break;
6335 	    }
6336 	    ++remap;
6337 	}
6338     }
6339 
6340     if ( actualuni!=-1 )
6341 	upos = actualuni;
6342     else if ( sc->unicodeenc!=-1 )
6343 	upos = sc->unicodeenc;
6344 #if HANYANG
6345     else if ( sc->compositionunit ) {
6346 	if ( sc->jamo<19 )
6347 	    upos = 0x1100+sc->jamo;
6348 	else if ( sc->jamo<19+21 )
6349 	    upos = 0x1161 + sc->jamo-19;
6350 	else		/* Leave a hole for the blank char */
6351 	    upos = 0x11a8 + sc->jamo-(19+21+1);
6352     }
6353 #endif
6354 
6355     if ( upos == -1 ) {
6356 	msg = smprintf( "%u 0x%x U+???? \"%.25s\" ",
6357 		localenc, localenc,
6358 		(sc->name == NULL) ? "" : sc->name );
6359     } else {
6360 	/* unicode name or range name */
6361 	char *uniname = unicode_name( upos );
6362 	if( uniname == NULL ) uniname = strdup( UnicodeRange( upos ) );
6363 	msg = smprintf ( "%u 0x%x U+%04X \"%.25s\" %.100s",
6364 		localenc, localenc, upos,
6365 		(sc->name == NULL) ? "" : sc->name, uniname );
6366 	if ( uniname != NULL ) free( uniname ); uniname = NULL;
6367 
6368 	/* annotation */
6369         char *uniannot = unicode_annot( upos );
6370         if( uniannot != NULL ) {
6371             msg_old = msg;
6372             msg = smprintf("%s\n%s", msg_old, uniannot);
6373             free(msg_old);
6374             free( uniannot );
6375         }
6376     }
6377 
6378     /* user comments */
6379     if ( sc->comment!=NULL ) {
6380         msg_old = msg;
6381         msg = smprintf("%s\n%s", msg_old, sc->comment);
6382         free(msg_old);
6383     }
6384 
6385     GGadgetPreparePopup8( gw, msg );
6386     free(msg);
6387 }
6388 
noop(void * UNUSED (_fv))6389 static void noop(void *UNUSED(_fv)) {
6390 }
6391 
ddgencharlist(void * _fv,int32 * len)6392 static void *ddgencharlist(void *_fv,int32 *len) {
6393     int i,j,cnt, gid;
6394     FontView *fv = (FontView *) _fv;
6395     SplineFont *sf = fv->b.sf;
6396     EncMap *map = fv->b.map;
6397     char *data;
6398 
6399     for ( i=cnt=0; i<map->enccount; ++i ) if ( fv->b.selected[i] && (gid=map->map[i])!=-1 && sf->glyphs[gid]!=NULL )
6400 	cnt += strlen(sf->glyphs[gid]->name)+1;
6401     data = malloc(cnt+1); data[0] = '\0';
6402     for ( cnt=0, j=1 ; j<=fv->sel_index; ++j ) {
6403 	for ( i=cnt=0; i<map->enccount; ++i )
6404 	    if ( fv->b.selected[i] && (gid=map->map[i])!=-1 && sf->glyphs[gid]!=NULL ) {
6405 		strcpy(data+cnt,sf->glyphs[gid]->name);
6406 		cnt += strlen(sf->glyphs[gid]->name);
6407 		strcpy(data+cnt++," ");
6408 	    }
6409     }
6410     if ( cnt>0 )
6411 	data[--cnt] = '\0';
6412     *len = cnt;
6413 return( data );
6414 }
6415 
FVMouse(FontView * fv,GEvent * event)6416 static void FVMouse(FontView *fv, GEvent *event) {
6417     int pos = (event->u.mouse.y/fv->cbh + fv->rowoff)*fv->colcnt + event->u.mouse.x/fv->cbw;
6418     int gid;
6419     int realpos = pos;
6420     SplineChar *sc, dummy;
6421     int dopopup = true;
6422 
6423     if ( event->type==et_mousedown )
6424 	CVPaletteDeactivate();
6425     if ( pos<0 ) {
6426 	pos = 0;
6427 	dopopup = false;
6428     } else if ( pos>=fv->b.map->enccount ) {
6429 	pos = fv->b.map->enccount-1;
6430 	if ( pos<0 )		/* No glyph slots in font */
6431 return;
6432 	dopopup = false;
6433     }
6434 
6435     sc = (gid=fv->b.map->map[pos])!=-1 ? fv->b.sf->glyphs[gid] : NULL;
6436     if ( sc==NULL )
6437 	sc = SCBuildDummy(&dummy,fv->b.sf,fv->b.map,pos);
6438     if ( event->type == et_mouseup && event->u.mouse.clicks==2 ) {
6439 	if ( fv->pressed ) {
6440 	    GDrawCancelTimer(fv->pressed);
6441 	    fv->pressed = NULL;
6442 	}
6443 	if ( fv->b.container!=NULL && fv->b.container->funcs->is_modal )
6444 return;
6445 	if ( fv->cur_subtable!=NULL ) {
6446 	    sc = FVMakeChar(fv,pos);
6447 	    pos = fv->b.map->backmap[sc->orig_pos];
6448 	}
6449 	if ( sc==&dummy ) {
6450 	    sc = SFMakeChar(fv->b.sf,fv->b.map,pos);
6451 	    gid = fv->b.map->map[pos];
6452 	}
6453 	if ( fv->show==fv->filled ) {
6454 	    SplineFont *sf = fv->b.sf;
6455 	    gid = -1;
6456 	    if ( !OpenCharsInNewWindow )
6457 		for ( gid=sf->glyphcnt-1; gid>=0; --gid )
6458 		    if ( sf->glyphs[gid]!=NULL && sf->glyphs[gid]->views!=NULL )
6459 		break;
6460 	    if ( gid!=-1 ) {
6461 		CharView *cv = (CharView *) (sf->glyphs[gid]->views);
6462 //		printf("calling CVChangeSC() sc:%p %s\n", sc, sc->name );
6463 		CVChangeSC(cv,sc);
6464 		GDrawSetVisible(cv->gw,true);
6465 		GDrawRaise(cv->gw);
6466 	    } else
6467 		CharViewCreate(sc,fv,pos);
6468 	} else {
6469 	    BDFFont *bdf = fv->show;
6470 	    BDFChar *bc =BDFMakeGID(bdf,gid);
6471 	    gid = -1;
6472 	    if ( !OpenCharsInNewWindow )
6473 		for ( gid=bdf->glyphcnt-1; gid>=0; --gid )
6474 		    if ( bdf->glyphs[gid]!=NULL && bdf->glyphs[gid]->views!=NULL )
6475 		break;
6476 	    if ( gid!=-1 ) {
6477 		BitmapView *bv = bdf->glyphs[gid]->views;
6478 		BVChangeBC(bv,bc,true);
6479 		GDrawSetVisible(bv->gw,true);
6480 		GDrawRaise(bv->gw);
6481 	    } else
6482 		BitmapViewCreate(bc,bdf,fv,pos);
6483 	}
6484     } else if ( event->type == et_mousemove ) {
6485 	if ( dopopup )
6486 	    SCPreparePopup(fv->v,sc,fv->b.map->remap,pos,sc==&dummy?dummy.unicodeenc: UniFromEnc(pos,fv->b.map->enc));
6487     }
6488     if ( event->type == et_mousedown ) {
6489 	if ( fv->drag_and_drop ) {
6490 	    GDrawSetCursor(fv->v,ct_mypointer);
6491 	    fv->any_dd_events_sent = fv->drag_and_drop = false;
6492 	}
6493 	if ( !(event->u.mouse.state&ksm_shift) && event->u.mouse.clicks<=1 ) {
6494 	    if ( !fv->b.selected[pos] )
6495 		FVDeselectAll(fv);
6496 	    else if ( event->u.mouse.button!=3 ) {
6497 		fv->drag_and_drop = fv->has_dd_no_cursor = true;
6498 		fv->any_dd_events_sent = false;
6499 		GDrawSetCursor(fv->v,ct_prohibition);
6500 		GDrawGrabSelection(fv->v,sn_drag_and_drop);
6501 		GDrawAddSelectionType(fv->v,sn_drag_and_drop,"STRING",fv,0,sizeof(char),
6502 			ddgencharlist,noop);
6503 	    }
6504 	}
6505 	fv->pressed_pos = fv->end_pos = pos;
6506 	FVShowInfo(fv);
6507 	if ( !fv->drag_and_drop ) {
6508 	    if ( !(event->u.mouse.state&ksm_shift))
6509 		fv->sel_index = 1;
6510 	    else if ( fv->sel_index<255 )
6511 		++fv->sel_index;
6512 	    if ( fv->pressed!=NULL ) {
6513 		GDrawCancelTimer(fv->pressed);
6514 		fv->pressed = NULL;
6515 	    } else if ( event->u.mouse.state&ksm_shift ) {
6516 		fv->b.selected[pos] = fv->b.selected[pos] ? 0 : fv->sel_index;
6517 		FVToggleCharSelected(fv,pos);
6518 	    } else if ( !fv->b.selected[pos] ) {
6519 		fv->b.selected[pos] = fv->sel_index;
6520 		FVToggleCharSelected(fv,pos);
6521 	    }
6522 	    if ( event->u.mouse.button==3 )
6523 		GMenuCreatePopupMenuWithName(fv->v,event, "Popup", fvpopupmenu);
6524 	    else
6525 		fv->pressed = GDrawRequestTimer(fv->v,200,100,NULL);
6526 	}
6527     } else if ( fv->drag_and_drop ) {
6528 	GWindow othergw = GDrawGetPointerWindow(fv->v);
6529 
6530 	if ( othergw==fv->v || othergw==fv->gw || othergw==NULL ) {
6531 	    if ( !fv->has_dd_no_cursor ) {
6532 		fv->has_dd_no_cursor = true;
6533 		GDrawSetCursor(fv->v,ct_prohibition);
6534 	    }
6535 	} else {
6536 	    if ( fv->has_dd_no_cursor ) {
6537 		fv->has_dd_no_cursor = false;
6538 		GDrawSetCursor(fv->v,ct_ddcursor);
6539 	    }
6540 	}
6541 	if ( event->type==et_mouseup ) {
6542 	    if ( pos!=fv->pressed_pos ) {
6543 		GDrawPostDragEvent(fv->v,event,event->type==et_mouseup?et_drop:et_drag);
6544 		fv->any_dd_events_sent = true;
6545 	    }
6546 	    fv->drag_and_drop = fv->has_dd_no_cursor = false;
6547 	    GDrawSetCursor(fv->v,ct_mypointer);
6548 	    if ( !fv->any_dd_events_sent )
6549 		FVDeselectAll(fv);
6550 	    fv->any_dd_events_sent = false;
6551 	}
6552     } else if ( fv->pressed!=NULL ) {
6553 	int showit = realpos!=fv->end_pos;
6554 	FVReselect(fv,realpos);
6555 	if ( showit )
6556 	    FVShowInfo(fv);
6557 	if ( event->type==et_mouseup ) {
6558 	    GDrawCancelTimer(fv->pressed);
6559 	    fv->pressed = NULL;
6560 	}
6561     }
6562     if ( event->type==et_mouseup && dopopup )
6563 	SCPreparePopup(fv->v,sc,fv->b.map->remap,pos,sc==&dummy?dummy.unicodeenc: UniFromEnc(pos,fv->b.map->enc));
6564     if ( event->type==et_mouseup )
6565 	SVAttachFV(fv,2);
6566 }
6567 
FVResize(FontView * fv,GEvent * event)6568 static void FVResize(FontView *fv, GEvent *event) {
6569     extern int default_fv_row_count, default_fv_col_count;
6570     GRect pos,screensize;
6571     int topchar;
6572 
6573     if ( fv->colcnt!=0 )
6574 	topchar = fv->rowoff*fv->colcnt;
6575     else if ( fv->b.sf->top_enc!=-1 && fv->b.sf->top_enc<fv->b.map->enccount )
6576 	topchar = fv->b.sf->top_enc;
6577     else {
6578 	/* Position on 'A' (or whatever they ask for) if it exists */
6579 	topchar = SFFindSlot(fv->b.sf,fv->b.map,home_char,NULL);
6580 	if ( topchar==-1 ) {
6581 	    for ( topchar=0; topchar<fv->b.map->enccount; ++topchar )
6582 		if ( fv->b.map->map[topchar]!=-1 && fv->b.sf->glyphs[fv->b.map->map[topchar]]!=NULL )
6583 	    break;
6584 	    if ( topchar==fv->b.map->enccount )
6585 		topchar = 0;
6586 	}
6587     }
6588     if ( !event->u.resize.sized )
6589 	/* WM isn't responding to my resize requests, so no point in trying */;
6590     else if ( (event->u.resize.size.width-
6591 		GDrawPointsToPixels(fv->gw,_GScrollBar_Width)-1)%fv->cbw!=0 ||
6592 	    (event->u.resize.size.height-fv->mbh-fv->infoh-1)%fv->cbh!=0 ) {
6593 	int cc = (event->u.resize.size.width+fv->cbw/2-
6594 		GDrawPointsToPixels(fv->gw,_GScrollBar_Width)-1)/fv->cbw;
6595 	int rc = (event->u.resize.size.height-fv->mbh-fv->infoh-1)/fv->cbh;
6596 	if ( cc<=0 ) cc = 1;
6597 	if ( rc<=0 ) rc = 1;
6598 	GDrawGetSize(GDrawGetRoot(NULL),&screensize);
6599 	if ( cc*fv->cbw+GDrawPointsToPixels(fv->gw,_GScrollBar_Width)>screensize.width )
6600 	    --cc;
6601 	if ( rc*fv->cbh+fv->mbh+fv->infoh+10>screensize.height )
6602 	    --rc;
6603 	GDrawResize(fv->gw,
6604 		cc*fv->cbw+1+GDrawPointsToPixels(fv->gw,_GScrollBar_Width),
6605 		rc*fv->cbh+1+fv->mbh+fv->infoh);
6606 	/* somehow KDE loses this event of mine so to get even the vague effect */
6607 	/*  we can't just return */
6608 /*return;*/
6609     }
6610 
6611     pos.width = GDrawPointsToPixels(fv->gw,_GScrollBar_Width);
6612     pos.height = event->u.resize.size.height-fv->mbh-fv->infoh;
6613     pos.x = event->u.resize.size.width-pos.width; pos.y = fv->mbh+fv->infoh;
6614     GGadgetResize(fv->vsb,pos.width,pos.height);
6615     GGadgetMove(fv->vsb,pos.x,pos.y);
6616     pos.width = pos.x; pos.x = 0;
6617     GDrawResize(fv->v,pos.width,pos.height);
6618 
6619     fv->width = pos.width; fv->height = pos.height;
6620     fv->colcnt = (fv->width-1)/fv->cbw;
6621     if ( fv->colcnt<1 ) fv->colcnt = 1;
6622     fv->rowcnt = (fv->height-1)/fv->cbh;
6623     if ( fv->rowcnt<1 ) fv->rowcnt = 1;
6624     fv->rowltot = (fv->b.map->enccount+fv->colcnt-1)/fv->colcnt;
6625 
6626     GScrollBarSetBounds(fv->vsb,0,fv->rowltot,fv->rowcnt);
6627     fv->rowoff = topchar/fv->colcnt;
6628     if ( fv->rowoff>=fv->rowltot-fv->rowcnt )
6629         fv->rowoff = fv->rowltot-fv->rowcnt;
6630     if ( fv->rowoff<0 ) fv->rowoff =0;
6631     GScrollBarSetPos(fv->vsb,fv->rowoff);
6632     GDrawRequestExpose(fv->gw,NULL,true);
6633     GDrawRequestExpose(fv->v,NULL,true);
6634 
6635     if ( fv->rowcnt!=fv->b.sf->desired_row_cnt || fv->colcnt!=fv->b.sf->desired_col_cnt ) {
6636 	default_fv_row_count = fv->rowcnt;
6637 	default_fv_col_count = fv->colcnt;
6638 	fv->b.sf->desired_row_cnt = fv->rowcnt;
6639 	fv->b.sf->desired_col_cnt = fv->colcnt;
6640 	SavePrefs(true);
6641     }
6642 }
6643 
FVTimer(FontView * fv,GEvent * event)6644 static void FVTimer(FontView *fv, GEvent *event) {
6645 
6646     if ( event->u.timer.timer==fv->pressed ) {
6647 	GEvent e;
6648 	GDrawGetPointerPosition(fv->v,&e);
6649 	if ( e.u.mouse.y<0 || e.u.mouse.y >= fv->height ) {
6650 	    real dy = 0;
6651 	    if ( e.u.mouse.y<0 )
6652 		dy = -1;
6653 	    else if ( e.u.mouse.y>=fv->height )
6654 		dy = 1;
6655 	    if ( fv->rowoff+dy<0 )
6656 		dy = 0;
6657 	    else if ( fv->rowoff+dy+fv->rowcnt > fv->rowltot )
6658 		dy = 0;
6659 	    fv->rowoff += dy;
6660 	    if ( dy!=0 ) {
6661 		GScrollBarSetPos(fv->vsb,fv->rowoff);
6662 		GDrawScroll(fv->v,NULL,0,dy*fv->cbh);
6663 	    }
6664 	}
6665     } else if ( event->u.timer.timer==fv->resize ) {
6666 	/* It's a delayed resize event (for kde which sends continuous resizes) */
6667 	fv->resize = NULL;
6668 	FVResize(fv,(GEvent *) (event->u.timer.userdata));
6669     } else if ( event->u.timer.userdata!=NULL ) {
6670 	/* It's a delayed function call */
6671 	void (*func)(FontView *) = (void (*)(FontView *)) (event->u.timer.userdata);
6672 	func(fv);
6673     }
6674 }
6675 
FVDelay(FontView * fv,void (* func)(FontView *))6676 void FVDelay(FontView *fv,void (*func)(FontView *)) {
6677     GDrawRequestTimer(fv->v,100,0,(void *) func);
6678 }
6679 
FVScroll(GGadget * g,GEvent * e)6680 static int FVScroll(GGadget *g, GEvent *e) {
6681     FontView *fv = GGadgetGetUserData(g);
6682     int newpos = fv->rowoff;
6683     struct sbevent *sb = &e->u.control.u.sb;
6684 
6685     switch( sb->type ) {
6686       case et_sb_top:
6687         newpos = 0;
6688       break;
6689       case et_sb_uppage:
6690         newpos -= fv->rowcnt;
6691       break;
6692       case et_sb_up:
6693         --newpos;
6694       break;
6695       case et_sb_down:
6696         ++newpos;
6697       break;
6698       case et_sb_downpage:
6699         newpos += fv->rowcnt;
6700       break;
6701       case et_sb_bottom:
6702         newpos = fv->rowltot-fv->rowcnt;
6703       break;
6704       case et_sb_thumb:
6705       case et_sb_thumbrelease:
6706         newpos = sb->pos;
6707       break;
6708     }
6709     if ( newpos>fv->rowltot-fv->rowcnt )
6710         newpos = fv->rowltot-fv->rowcnt;
6711     if ( newpos<0 ) newpos =0;
6712     if ( newpos!=fv->rowoff ) {
6713 	int diff = newpos-fv->rowoff;
6714 	fv->rowoff = newpos;
6715 	GScrollBarSetPos(fv->vsb,fv->rowoff);
6716 	GDrawScroll(fv->v,NULL,0,diff*fv->cbh);
6717     }
6718 return( true );
6719 }
6720 
v_e_h(GWindow gw,GEvent * event)6721 static int v_e_h(GWindow gw, GEvent *event) {
6722     FontView *fv = (FontView *) GDrawGetUserData(gw);
6723 
6724     if (( event->type==et_mouseup || event->type==et_mousedown ) &&
6725 	    (event->u.mouse.button>=4 && event->u.mouse.button<=7) ) {
6726 return( GGadgetDispatchEvent(fv->vsb,event));
6727     }
6728 
6729     GGadgetPopupExternalEvent(event);
6730     switch ( event->type ) {
6731       case et_expose:
6732 	GDrawSetLineWidth(gw,0);
6733 	FVExpose(fv,gw,event);
6734       break;
6735       case et_char:
6736 	if ( fv->b.container!=NULL )
6737 	    (fv->b.container->funcs->charEvent)(fv->b.container,event);
6738 	else
6739 	    FVChar(fv,event);
6740       break;
6741       case et_mousemove: case et_mousedown: case et_mouseup:
6742 	if ( event->type==et_mousedown )
6743 	    GDrawSetGIC(gw,fv->gic,0,20);
6744 	if ( fv->notactive && event->type==et_mousedown )
6745 	    (fv->b.container->funcs->activateMe)(fv->b.container,&fv->b);
6746 	FVMouse(fv,event);
6747       break;
6748       case et_timer:
6749 	FVTimer(fv,event);
6750       break;
6751       case et_focus:
6752 //	  printf("fv.et_focus\n");
6753 	if ( event->u.focus.gained_focus )
6754 	    GDrawSetGIC(gw,fv->gic,0,20);
6755       break;
6756     }
6757 return( true );
6758 }
6759 
FontView_ReformatOne(FontView * fv)6760 static void FontView_ReformatOne(FontView *fv) {
6761     FontView *fvs;
6762 
6763     if ( fv->v==NULL || fv->colcnt==0 )	/* Can happen in scripts */
6764 return;
6765 
6766     GDrawSetCursor(fv->v,ct_watch);
6767     fv->rowltot = (fv->b.map->enccount+fv->colcnt-1)/fv->colcnt;
6768     GScrollBarSetBounds(fv->vsb,0,fv->rowltot,fv->rowcnt);
6769     if ( fv->rowoff>fv->rowltot-fv->rowcnt ) {
6770         fv->rowoff = fv->rowltot-fv->rowcnt;
6771 	if ( fv->rowoff<0 ) fv->rowoff =0;
6772 	GScrollBarSetPos(fv->vsb,fv->rowoff);
6773     }
6774     for ( fvs=(FontView *) (fv->b.sf->fv); fvs!=NULL; fvs=(FontView *) (fvs->b.nextsame) )
6775 	if ( fvs!=fv && fvs->b.sf==fv->b.sf )
6776     break;
6777     GDrawRequestExpose(fv->v,NULL,false);
6778     GDrawSetCursor(fv->v,ct_pointer);
6779 }
6780 
FontView_ReformatAll(SplineFont * sf)6781 static void FontView_ReformatAll(SplineFont *sf) {
6782     BDFFont *new, *old, *bdf;
6783     FontView *fv;
6784     MetricsView *mvs;
6785     extern int use_freetype_to_rasterize_fv;
6786 
6787     if ( sf->fv==NULL || ((FontView *) (sf->fv))->v==NULL )			/* Can happen in scripts */
6788 return;
6789 
6790     for ( fv=(FontView *) (sf->fv); fv!=NULL; fv=(FontView *) (fv->b.nextsame) ) {
6791 	GDrawSetCursor(fv->v,ct_watch);
6792 	old = fv->filled;
6793 				/* In CID fonts fv->b.sf may not be same as sf */
6794 	new = SplineFontPieceMeal(fv->b.sf,fv->b.active_layer,fv->filled->pixelsize,72,
6795 		(fv->antialias?pf_antialias:0)|(fv->bbsized?pf_bbsized:0)|
6796 		    (use_freetype_to_rasterize_fv && !sf->strokedfont && !sf->multilayer?pf_ft_nohints:0),
6797 		NULL);
6798 	fv->filled = new;
6799 	if ( fv->show==old )
6800 	    fv->show = new;
6801 	else {
6802 	    for ( bdf=sf->bitmaps; bdf != NULL &&
6803 		( bdf->pixelsize != fv->show->pixelsize || BDFDepth( bdf ) != BDFDepth( fv->show )); bdf=bdf->next );
6804 	    if ( bdf != NULL ) fv->show = bdf;
6805 	    else fv->show = new;
6806 	}
6807 	BDFFontFree(old);
6808 	if ( ((FontView *) (sf->fv))->colcnt!=0 ) {
6809 	    fv->rowltot = (fv->b.map->enccount+fv->colcnt-1)/fv->colcnt;
6810 	    GScrollBarSetBounds(fv->vsb,0,fv->rowltot,fv->rowcnt);
6811 	    if ( fv->rowoff>fv->rowltot-fv->rowcnt ) {
6812 		    fv->rowoff = fv->rowltot-fv->rowcnt;
6813 		    if ( fv->rowoff<0 ) fv->rowoff =0;
6814 		    GScrollBarSetPos(fv->vsb,fv->rowoff);
6815 	    }
6816 	    GDrawRequestExpose(fv->v,NULL,false);
6817 	}
6818 	GDrawSetCursor(fv->v,ct_pointer);
6819     }
6820     for ( mvs=sf->metrics; mvs!=NULL; mvs=mvs->next ) if ( mvs->bdf==NULL ) {
6821 	BDFFontFree(mvs->show);
6822 	mvs->show = SplineFontPieceMeal(sf,mvs->layer,mvs->ptsize,mvs->dpi,
6823 		mvs->antialias?(pf_antialias|pf_ft_recontext):pf_ft_recontext,NULL);
6824 	GDrawRequestExpose(mvs->gw,NULL,false);
6825     }
6826 }
6827 
FontViewRemove(FontView * fv)6828 void FontViewRemove(FontView *fv) {
6829     if ( fv_list==fv )
6830 	fv_list = (FontView *) (fv->b.next);
6831     else {
6832 	FontView *n;
6833 	for ( n=fv_list; n->b.next!=&fv->b; n=(FontView *) (n->b.next) );
6834 	n->b.next = fv->b.next;
6835     }
6836     FontViewFree(&fv->b);
6837 }
6838 
6839 /**
6840  * In some cases fontview gets an et_selclear event when using copy
6841  * and paste on the OSX. So this guard lets us quietly ignore that
6842  * event when we have just done command+c or command+x.
6843  */
6844 extern int osx_fontview_copy_cut_counter;
6845 
6846 static FontView* ActiveFontView = 0;
6847 
fv_e_h(GWindow gw,GEvent * event)6848 static int fv_e_h(GWindow gw, GEvent *event) {
6849     FontView *fv = (FontView *) GDrawGetUserData(gw);
6850 
6851     if (( event->type==et_mouseup || event->type==et_mousedown ) &&
6852 	    (event->u.mouse.button>=4 && event->u.mouse.button<=7) ) {
6853 return( GGadgetDispatchEvent(fv->vsb,event));
6854     }
6855 
6856     switch ( event->type ) {
6857       case et_focus:
6858 	  if ( event->u.focus.gained_focus )
6859 	  {
6860 	      ActiveFontView = fv;
6861 	  }
6862 	  else
6863 	  {
6864 	  }
6865 	  break;
6866       case et_selclear:
6867 #ifdef __Mac
6868 	  // For some reason command + c and command + x wants
6869 	  // to send a clear to us, even if that key was pressed
6870 	  // on a charview.
6871 	  if( osx_fontview_copy_cut_counter )
6872 	  {
6873 	     osx_fontview_copy_cut_counter--;
6874 	     break;
6875           }
6876 //	  printf("fontview et_selclear\n");
6877 #endif
6878 	ClipboardClear();
6879       break;
6880       case et_expose:
6881 	GDrawSetLineWidth(gw,0);
6882 	FVDrawInfo(fv,gw,event);
6883       break;
6884       case et_resize:
6885 	/* KDE sends a continuous stream of resize events, and gets very */
6886 	/*  confused if I start resizing the window myself, try to wait for */
6887 	/*  the user to finish before responding to resizes */
6888 	if ( event->u.resize.sized || fv->resize_expected ) {
6889 	    if ( fv->resize )
6890 		GDrawCancelTimer(fv->resize);
6891 	    fv->resize_event = *event;
6892 	    fv->resize = GDrawRequestTimer(fv->v,300,0,(void *) &fv->resize_event);
6893 	    fv->resize_expected = false;
6894 	}
6895       break;
6896       case et_char:
6897 	if ( fv->b.container!=NULL )
6898 	    (fv->b.container->funcs->charEvent)(fv->b.container,event);
6899 	else
6900 	    FVChar(fv,event);
6901       break;
6902       case et_mousedown:
6903 	GDrawSetGIC(gw,fv->gwgic,0,20);
6904 	if ( fv->notactive )
6905 	    (fv->b.container->funcs->activateMe)(fv->b.container,&fv->b);
6906       break;
6907       case et_close:
6908 	FVMenuClose(gw,NULL,NULL);
6909       break;
6910       case et_create:
6911 	fv->b.next = (FontViewBase *) fv_list;
6912 	fv_list = fv;
6913       break;
6914       case et_destroy:
6915 	if ( fv->qg!=NULL )
6916 	    QGRmFontView(fv->qg,fv);
6917 	FontViewRemove(fv);
6918       break;
6919     }
6920 return( true );
6921 }
6922 
FontViewOpenKids(FontView * fv)6923 static void FontViewOpenKids(FontView *fv) {
6924     int k, i;
6925     SplineFont *sf = fv->b.sf, *_sf;
6926 #if defined(__Mac)
6927     int cnt= 0;
6928 #endif
6929 
6930     if ( sf->cidmaster!=NULL )
6931 	sf = sf->cidmaster;
6932 
6933     k=0;
6934     do {
6935 	_sf = sf->subfontcnt==0 ? sf : sf->subfonts[k];
6936 	for ( i=0; i<_sf->glyphcnt; ++i )
6937 	    if ( _sf->glyphs[i]!=NULL && _sf->glyphs[i]->wasopen ) {
6938 		_sf->glyphs[i]->wasopen = false;
6939 #if defined(__Mac)
6940 		/* If we open a bunch of charviews all at once on the mac, X11*/
6941 		/*  crashes */ /* But opening one seems ok */
6942 		if ( ++cnt==1 )
6943 #endif
6944 		CharViewCreate(_sf->glyphs[i],fv,-1);
6945 	    }
6946 	++k;
6947     } while ( k<sf->subfontcnt );
6948 }
6949 
__FontViewCreate(SplineFont * sf)6950 static FontView *__FontViewCreate(SplineFont *sf) {
6951     FontView *fv = calloc(1,sizeof(FontView));
6952     int i;
6953     int ps = sf->display_size<0 ? -sf->display_size :
6954 	     sf->display_size==0 ? default_fv_font_size : sf->display_size;
6955 
6956     if ( ps>200 ) ps = 128;
6957 
6958     /* Filename != NULL if we opened an sfd file. Sfd files know whether */
6959     /*  the font is compact or not and should not depend on a global flag */
6960     /* If a font is new, then compaction will make it vanish completely */
6961     if ( sf->fv==NULL && compact_font_on_open && sf->filename==NULL && !sf->new ) {
6962 	sf->compacted = true;
6963 	for ( i=0; i<sf->subfontcnt; ++i )
6964 	    sf->subfonts[i]->compacted = true;
6965     }
6966     fv->b.nextsame = sf->fv;
6967     fv->b.active_layer = sf->display_layer;
6968     sf->fv = (FontViewBase *) fv;
6969     if ( sf->mm!=NULL ) {
6970 	sf->mm->normal->fv = (FontViewBase *) fv;
6971 	for ( i = 0; i<sf->mm->instance_count; ++i )
6972 	    sf->mm->instances[i]->fv = (FontViewBase *) fv;
6973     }
6974     if ( sf->subfontcnt==0 ) {
6975 	fv->b.sf = sf;
6976 	if ( fv->b.nextsame!=NULL ) {
6977 	    fv->b.map = EncMapCopy(fv->b.nextsame->map);
6978 	    fv->b.normal = fv->b.nextsame->normal==NULL ? NULL : EncMapCopy(fv->b.nextsame->normal);
6979 	} else if ( sf->compacted ) {
6980 	    fv->b.normal = sf->map;
6981 	    fv->b.map = CompactEncMap(EncMapCopy(sf->map),sf);
6982 	    sf->map = fv->b.map;
6983 	} else {
6984 	    fv->b.map = sf->map;
6985 	    fv->b.normal = NULL;
6986 	}
6987     } else {
6988 	fv->b.cidmaster = sf;
6989 	for ( i=0; i<sf->subfontcnt; ++i )
6990 	    sf->subfonts[i]->fv = (FontViewBase *) fv;
6991 	for ( i=0; i<sf->subfontcnt; ++i )	/* Search for a subfont that contains more than ".notdef" (most significant in .gai fonts) */
6992 	    if ( sf->subfonts[i]->glyphcnt>1 ) {
6993 		fv->b.sf = sf->subfonts[i];
6994 	break;
6995 	    }
6996 	if ( fv->b.sf==NULL )
6997 	    fv->b.sf = sf->subfonts[0];
6998 	sf = fv->b.sf;
6999 	if ( fv->b.nextsame==NULL ) { EncMapFree(sf->map); sf->map = NULL; }
7000 	fv->b.map = EncMap1to1(sf->glyphcnt);
7001 	if ( fv->b.nextsame==NULL ) { sf->map = fv->b.map; }
7002 	if ( sf->compacted ) {
7003 	    fv->b.normal = fv->b.map;
7004 	    fv->b.map = CompactEncMap(EncMapCopy(fv->b.map),sf);
7005 	    if ( fv->b.nextsame==NULL ) { sf->map = fv->b.map; }
7006 	}
7007     }
7008     fv->b.selected = calloc((fv->b.map ? fv->b.map->enccount : 0), sizeof(uint8));
7009     fv->user_requested_magnify = -1;
7010     fv->magnify = (ps<=9)? 3 : (ps<20) ? 2 : 1;
7011     fv->cbw = (ps*fv->magnify)+1;
7012     fv->cbh = (ps*fv->magnify)+1+fv->lab_height+1;
7013     fv->antialias = sf->display_antialias;
7014     fv->bbsized = sf->display_bbsized;
7015     fv->glyphlabel = default_fv_glyphlabel;
7016 
7017     fv->end_pos = -1;
7018 #ifndef _NO_PYTHON
7019     PyFF_InitFontHook((FontViewBase *)fv);
7020 #endif
7021 
7022     fv->pid_webfontserver = 0;
7023 
7024 return( fv );
7025 }
7026 
7027 static int fontview_ready = false;
7028 
FontViewFinish()7029 static void FontViewFinish() {
7030     if (!fontview_ready) return;
7031     mb2FreeGetText(mblist);
7032     mbFreeGetText(fvpopupmenu);
7033 }
7034 
FontViewFinishNonStatic()7035 void FontViewFinishNonStatic() {
7036     FontViewFinish();
7037 }
7038 
FontViewInit(void)7039 static void FontViewInit(void) {
7040     // static int done = false; // superseded by fontview_ready.
7041 
7042     if ( fontview_ready )
7043 return;
7044 
7045     fontview_ready = true;
7046 
7047     mb2DoGetText(mblist);
7048     mbDoGetText(fvpopupmenu);
7049     atexit(&FontViewFinishNonStatic);
7050 }
7051 
7052 static struct resed fontview_re[] = {
7053     {N_("Glyph Info Color"), "GlyphInfoColor", rt_color, &fvglyphinfocol, N_("Color of the font used to display glyph information in the fontview"), NULL, { 0 }, 0, 0 },
7054     {N_("Empty Slot FG Color"), "EmptySlotFgColor", rt_color, &fvemtpyslotfgcol, N_("Color used to draw the foreground of empty slots"), NULL, { 0 }, 0, 0 },
7055     {N_("Selected BG Color"), "SelectedColor", rt_color, &fvselcol, N_("Color used to draw the background of selected glyphs"), NULL, { 0 }, 0, 0 },
7056     {N_("Selected FG Color"), "SelectedFgColor", rt_color, &fvselfgcol, N_("Color used to draw the foreground of selected glyphs"), NULL, { 0 }, 0, 0 },
7057     {N_("Changed Color"), "ChangedColor", rt_color, &fvchangedcol, N_("Color used to mark a changed glyph"), NULL, { 0 }, 0, 0 },
7058     {N_("Hinting Needed Color"), "HintingNeededColor", rt_color, &fvhintingneededcol, N_("Color used to mark glyphs that need hinting"), NULL, { 0 }, 0, 0 },
7059     {N_("Font Size"), "FontSize", rt_int, &fv_fontsize, N_("Size (in points) of the font used to display information and glyph labels in the fontview"), NULL, { 0 }, 0, 0 },
7060     {N_("Font Family"), "FontFamily", rt_stringlong, &fv_fontnames, N_("A comma separated list of font family names used to display small example images of glyphs over the user designed glyphs"), NULL, { 0 }, 0, 0 },
7061     RESED_EMPTY
7062 };
7063 
FVCreateInnards(FontView * fv,GRect * pos)7064 static void FVCreateInnards(FontView *fv,GRect *pos) {
7065     GWindow gw = fv->gw;
7066     GWindowAttrs wattrs;
7067     GGadgetData gd;
7068     FontRequest rq;
7069     BDFFont *bdf;
7070     int as,ds,ld;
7071     extern int use_freetype_to_rasterize_fv;
7072     SplineFont *sf = fv->b.sf;
7073 
7074     fv->lab_height = FV_LAB_HEIGHT-13+GDrawPointsToPixels(NULL,fv_fontsize);
7075 
7076     memset(&gd,0,sizeof(gd));
7077     gd.pos.y = pos->y; gd.pos.height = pos->height;
7078     gd.pos.width = GDrawPointsToPixels(gw,_GScrollBar_Width);
7079     gd.pos.x = pos->width;
7080     gd.u.sbinit = NULL;
7081     gd.flags = gg_visible|gg_enabled|gg_pos_in_pixels|gg_sb_vert;
7082     gd.handle_controlevent = FVScroll;
7083     fv->vsb = GScrollBarCreate(gw,&gd,fv);
7084 
7085 
7086     memset(&wattrs,0,sizeof(wattrs));
7087     wattrs.mask = wam_events|wam_cursor|wam_backcol;
7088     wattrs.event_masks = ~(1<<et_charup);
7089     wattrs.cursor = ct_pointer;
7090     wattrs.background_color = view_bgcol;
7091     fv->v = GWidgetCreateSubWindow(gw,pos,v_e_h,fv,&wattrs);
7092     GDrawSetVisible(fv->v,true);
7093     GDrawSetWindowTypeName(fv->v, "FontView");
7094 
7095     fv->gic   = GDrawCreateInputContext(fv->v,gic_root|gic_orlesser);
7096     fv->gwgic = GDrawCreateInputContext(fv->gw,gic_root|gic_orlesser);
7097     GDrawSetGIC(fv->v,fv->gic,0,20);
7098     GDrawSetGIC(fv->gw,fv->gic,0,20);
7099 
7100     fv->fontset = calloc(_uni_fontmax,sizeof(GFont *));
7101     memset(&rq,0,sizeof(rq));
7102     rq.utf8_family_name = fv_fontnames;
7103     rq.point_size = fv_fontsize;
7104     rq.weight = 400;
7105     fv->fontset[0] = GDrawInstanciateFont(gw,&rq);
7106     GDrawSetFont(fv->v,fv->fontset[0]);
7107     GDrawWindowFontMetrics(fv->v,fv->fontset[0],&as,&ds,&ld);
7108     fv->lab_as = as;
7109     fv->showhmetrics = default_fv_showhmetrics;
7110     fv->showvmetrics = default_fv_showvmetrics && sf->hasvmetrics;
7111     bdf = SplineFontPieceMeal(fv->b.sf,fv->b.active_layer,sf->display_size<0?-sf->display_size:default_fv_font_size,72,
7112 	    (fv->antialias?pf_antialias:0)|(fv->bbsized?pf_bbsized:0)|
7113 		(use_freetype_to_rasterize_fv && !sf->strokedfont && !sf->multilayer?pf_ft_nohints:0),
7114 	    NULL);
7115     fv->filled = bdf;
7116     if ( sf->display_size>0 ) {
7117 	for ( bdf=sf->bitmaps; bdf!=NULL && bdf->pixelsize!=sf->display_size ;
7118 		bdf=bdf->next );
7119 	if ( bdf==NULL )
7120 	    bdf = fv->filled;
7121     }
7122     if ( sf->onlybitmaps && bdf==fv->filled && sf->bitmaps!=NULL )
7123 	bdf = sf->bitmaps;
7124     fv->cbw = -1;
7125     FVChangeDisplayFont(fv,bdf);
7126 }
7127 
FontView_Create(SplineFont * sf,int hide)7128 static FontView *FontView_Create(SplineFont *sf, int hide) {
7129     FontView *fv = (FontView *) __FontViewCreate(sf);
7130     GRect pos;
7131     GWindow gw;
7132     GWindowAttrs wattrs;
7133     GGadgetData gd;
7134     GRect gsize;
7135     static GWindow icon = NULL;
7136     static int nexty=0;
7137     GRect size;
7138 
7139     FontViewInit();
7140     if ( icon==NULL ) {
7141 #ifdef BIGICONS
7142 	icon = GDrawCreateBitmap(NULL,fontview_width,fontview_height,fontview_bits);
7143 #else
7144 	icon = GDrawCreateBitmap(NULL,fontview2_width,fontview2_height,fontview2_bits);
7145 #endif
7146     }
7147 
7148     GDrawGetSize(GDrawGetRoot(NULL),&size);
7149 
7150     memset(&wattrs,0,sizeof(wattrs));
7151     wattrs.mask = wam_events|wam_cursor|wam_icon;
7152     wattrs.event_masks = ~(1<<et_charup);
7153     wattrs.cursor = ct_pointer;
7154     wattrs.icon = icon;
7155     pos.width = sf->desired_col_cnt*fv->cbw+1;
7156     pos.height = sf->desired_row_cnt*fv->cbh+1;
7157     pos.x = size.width-pos.width-30; pos.y = nexty;
7158     nexty += 2*fv->cbh+50;
7159     if ( nexty+pos.height > size.height )
7160 	nexty = 0;
7161     fv->gw = gw = GDrawCreateTopWindow(NULL,&pos,fv_e_h,fv,&wattrs);
7162     FontViewSetTitle(fv);
7163     GDrawSetWindowTypeName(fv->gw, "FontView");
7164 
7165     if ( !fv_fs_init ) {
7166 	GResEditFind( fontview_re, "FontView.");
7167 	view_bgcol = GResourceFindColor("View.Background",GDrawGetDefaultBackground(NULL));
7168 	fv_fs_init = true;
7169     }
7170 
7171     memset(&gd,0,sizeof(gd));
7172     gd.flags = gg_visible | gg_enabled;
7173     helplist[0].invoke = FVMenuContextualHelp;
7174 #ifndef _NO_PYTHON
7175     if ( fvpy_menu!=NULL )
7176 	mblist[3].ti.disabled = false;
7177     mblist[3].sub = fvpy_menu;
7178 #define CALLBACKS_INDEX 4 /* FIXME: There has to be a better way than this. */
7179 #else
7180 #define CALLBACKS_INDEX 3 /* FIXME: There has to be a better way than this. */
7181 #endif		/* _NO_PYTHON */
7182 #ifdef NATIVE_CALLBACKS
7183     if ( fv_menu!=NULL )
7184        mblist[CALLBACKS_INDEX].ti.disabled = false;
7185     mblist[CALLBACKS_INDEX].sub = fv_menu;
7186 #endif      /* NATIVE_CALLBACKS */
7187     gd.u.menu2 = mblist;
7188     fv->mb = GMenu2BarCreate( gw, &gd, NULL);
7189     GGadgetGetSize(fv->mb,&gsize);
7190     fv->mbh = gsize.height;
7191     fv->infoh = 1+GDrawPointsToPixels(NULL,fv_fontsize);
7192 
7193     pos.x = 0; pos.y = fv->mbh+fv->infoh;
7194     FVCreateInnards(fv,&pos);
7195 
7196     if ( !hide ) {
7197 	GDrawSetVisible(gw,true);
7198 	FontViewOpenKids(fv);
7199     }
7200 return( fv );
7201 }
7202 
FontView_Append(FontView * fv)7203 static FontView *FontView_Append(FontView *fv) {
7204     /* Normally fontviews get added to the fv list when their windows are */
7205     /*  created. but we don't create any windows here, so... */
7206     FontView *test;
7207 
7208     if ( fv_list==NULL ) fv_list = fv;
7209     else {
7210 	for ( test = fv_list; test->b.next!=NULL; test=(FontView *) test->b.next );
7211 	test->b.next = (FontViewBase *) fv;
7212     }
7213 return( fv );
7214 }
7215 
FontNew(void)7216 FontView *FontNew(void) {
7217 return( FontView_Create(SplineFontNew(),false));
7218 }
7219 
FontView_Free(FontView * fv)7220 static void FontView_Free(FontView *fv) {
7221     int i;
7222     FontView *prev;
7223     FontView *fvs;
7224 
7225     if ( fv->b.sf == NULL )	/* Happens when usurping a font to put it into an MM */
7226 	BDFFontFree(fv->filled);
7227     else if ( fv->b.nextsame==NULL && fv->b.sf->fv==&fv->b ) {
7228 	EncMapFree(fv->b.map);
7229 	if (fv->b.sf != NULL && fv->b.map == fv->b.sf->map) { fv->b.sf->map = NULL; }
7230 	SplineFontFree(fv->b.cidmaster?fv->b.cidmaster:fv->b.sf);
7231 	BDFFontFree(fv->filled);
7232     } else {
7233 	EncMapFree(fv->b.map);
7234 	if (fv->b.sf != NULL && fv->b.map == fv->b.sf->map) { fv->b.sf->map = NULL; }
7235 	fv->b.map = NULL;
7236 	for ( fvs=(FontView *) (fv->b.sf->fv), i=0 ; fvs!=NULL; fvs = (FontView *) (fvs->b.nextsame) )
7237 	    if ( fvs->filled==fv->filled ) ++i;
7238 	if ( i==1 )
7239 	    BDFFontFree(fv->filled);
7240 	if ( fv->b.sf->fv==&fv->b ) {
7241 	    if ( fv->b.cidmaster==NULL )
7242 		fv->b.sf->fv = fv->b.nextsame;
7243 	    else {
7244 		fv->b.cidmaster->fv = fv->b.nextsame;
7245 		for ( i=0; i<fv->b.cidmaster->subfontcnt; ++i )
7246 		    fv->b.cidmaster->subfonts[i]->fv = fv->b.nextsame;
7247 	    }
7248 	} else {
7249 	    for ( prev = (FontView *) (fv->b.sf->fv); prev->b.nextsame!=&fv->b; prev=(FontView *) (prev->b.nextsame) );
7250 	    prev->b.nextsame = fv->b.nextsame;
7251 	}
7252     }
7253 #ifndef _NO_FFSCRIPT
7254     DictionaryFree(fv->b.fontvars);
7255     free(fv->b.fontvars);
7256 #endif
7257     free(fv->b.selected);
7258     free(fv->fontset);
7259 #ifndef _NO_PYTHON
7260     PyFF_FreeFV(&fv->b);
7261 #endif
7262     free(fv);
7263 }
7264 
FontViewWinInfo(FontView * fv,int * cc,int * rc)7265 static int FontViewWinInfo(FontView *fv, int *cc, int *rc) {
7266     if ( fv==NULL || fv->colcnt==0 || fv->rowcnt==0 ) {
7267 	*cc = 16; *rc = 4;
7268 return( -1 );
7269     }
7270 
7271     *cc = fv->colcnt;
7272     *rc = fv->rowcnt;
7273 
7274 return( fv->rowoff*fv->colcnt );
7275 }
7276 
7277 
7278 
7279 
7280 
7281 
7282 
7283 
7284 
FVAny(void)7285 static FontViewBase *FVAny(void) { return (FontViewBase *) fv_list; }
7286 
FontIsActive(SplineFont * sf)7287 static int  FontIsActive(SplineFont *sf) {
7288     FontView *fv;
7289 
7290     for ( fv=fv_list; fv!=NULL; fv=(FontView *) (fv->b.next) )
7291 	if ( fv->b.sf == sf )
7292 return( true );
7293 
7294 return( false );
7295 }
7296 
FontOfFilename(const char * filename)7297 static SplineFont *FontOfFilename(const char *filename) {
7298     char buffer[1025];
7299     FontView *fv;
7300 
7301     GFileGetAbsoluteName((char *) filename,buffer,sizeof(buffer));
7302     for ( fv=fv_list; fv!=NULL ; fv=(FontView *) (fv->b.next) ) {
7303 	if ( fv->b.sf->filename!=NULL && strcmp(fv->b.sf->filename,buffer)==0 )
7304 return( fv->b.sf );
7305 	else if ( fv->b.sf->origname!=NULL && strcmp(fv->b.sf->origname,buffer)==0 )
7306 return( fv->b.sf );
7307     }
7308 return( NULL );
7309 }
7310 
FVExtraEncSlots(FontView * fv,int encmax)7311 static void FVExtraEncSlots(FontView *fv, int encmax) {
7312     if ( fv->colcnt!=0 ) {		/* Ie. scripting vs. UI */
7313 	fv->rowltot = (encmax+1+fv->colcnt-1)/fv->colcnt;
7314 	GScrollBarSetBounds(fv->vsb,0,fv->rowltot,fv->rowcnt);
7315     }
7316 }
7317 
FV_BiggerGlyphCache(FontView * fv,int gidcnt)7318 static void FV_BiggerGlyphCache(FontView *fv, int gidcnt) {
7319     if ( fv->filled!=NULL )
7320 	BDFOrigFixup(fv->filled,gidcnt,fv->b.sf);
7321 }
7322 
FontView_Close(FontView * fv)7323 static void FontView_Close(FontView *fv) {
7324     if ( fv->gw!=NULL )
7325 	GDrawDestroyWindow(fv->gw);
7326     else
7327 	FontViewRemove(fv);
7328 }
7329 
7330 
7331 struct fv_interface gdraw_fv_interface = {
7332     (FontViewBase *(*)(SplineFont *, int)) FontView_Create,
7333     (FontViewBase *(*)(SplineFont *)) __FontViewCreate,
7334     (void (*)(FontViewBase *)) FontView_Close,
7335     (void (*)(FontViewBase *)) FontView_Free,
7336     (void (*)(FontViewBase *)) FontViewSetTitle,
7337     FontViewSetTitles,
7338     FontViewRefreshAll,
7339     (void (*)(FontViewBase *)) FontView_ReformatOne,
7340     FontView_ReformatAll,
7341     (void (*)(FontViewBase *)) FV_LayerChanged,
7342     FV_ToggleCharChanged,
7343     (int  (*)(FontViewBase *, int *, int *)) FontViewWinInfo,
7344     FontIsActive,
7345     FVAny,
7346     (FontViewBase *(*)(FontViewBase *)) FontView_Append,
7347     FontOfFilename,
7348     (void (*)(FontViewBase *,int)) FVExtraEncSlots,
7349     (void (*)(FontViewBase *,int)) FV_BiggerGlyphCache,
7350     (void (*)(FontViewBase *,BDFFont *)) FV_ChangeDisplayBitmap,
7351     (void (*)(FontViewBase *)) FV_ShowFilled,
7352     FV_ReattachCVs,
7353     (void (*)(FontViewBase *)) FVDeselectAll,
7354     (void (*)(FontViewBase *,int )) FVScrollToGID,
7355     (void (*)(FontViewBase *,int )) FVScrollToChar,
7356     (void (*)(FontViewBase *,int )) FV_ChangeGID,
7357     SF_CloseAllInstrs
7358 };
7359 
7360 extern GResInfo charview_ri;
7361 static struct resed view_re[] = {
7362     {N_("Color|Background"), "Background", rt_color, &view_bgcol, N_("Background color for the drawing area of all views"), NULL, { 0 }, 0, 0 },
7363     RESED_EMPTY
7364 };
7365 GResInfo view_ri = {
7366     NULL, NULL,NULL, NULL,
7367     NULL,
7368     NULL,
7369     NULL,
7370     view_re,
7371     N_("View"),
7372     N_("This is an abstract class which defines common features of the\nFontView, CharView, BitmapView and MetricsView"),
7373     "View",
7374     "fontforge",
7375     false,
7376     0,
7377     NULL,
7378     GBOX_EMPTY,
7379     NULL,
7380     NULL,
7381     NULL
7382 };
7383 
7384 GResInfo fontview_ri = {
7385     &charview_ri, NULL,NULL, NULL,
7386     NULL,
7387     NULL,
7388     NULL,
7389     fontview_re,
7390     N_("FontView"),
7391     N_("This is the main fontforge window displaying a font"),
7392     "FontView",
7393     "fontforge",
7394     false,
7395     0,
7396     NULL,
7397     GBOX_EMPTY,
7398     NULL,
7399     NULL,
7400     NULL
7401 };
7402 
7403 /* ************************************************************************** */
7404 /* ***************************** Embedded FontViews ************************* */
7405 /* ************************************************************************** */
7406 
FVCopyInnards(FontView * fv,GRect * pos,int infoh,FontView * fvorig,GWindow dw,int def_layer,struct fvcontainer * kf)7407 static void FVCopyInnards(FontView *fv,GRect *pos,int infoh,
7408 	FontView *fvorig,GWindow dw, int def_layer, struct fvcontainer *kf) {
7409 
7410     fv->notactive = true;
7411     fv->gw = dw;
7412     fv->infoh = infoh;
7413     fv->b.container = kf;
7414     fv->rowcnt = 4; fv->colcnt = 16;
7415     fv->b.active_layer = def_layer;
7416     FVCreateInnards(fv,pos);
7417     memcpy(fv->b.selected,fvorig->b.selected,fv->b.map->enccount);
7418     fv->rowoff = (fvorig->rowoff*fvorig->colcnt)/fv->colcnt;
7419 }
7420 
KFFontViewInits(struct kf_dlg * kf,GGadget * drawable)7421 void KFFontViewInits(struct kf_dlg *kf,GGadget *drawable) {
7422     GGadgetData gd;
7423     GRect pos, gsize, sbsize;
7424     GWindow dw = GDrawableGetWindow(drawable);
7425     int infoh;
7426     int ps;
7427     FontView *fvorig = (FontView *) kf->sf->fv;
7428 
7429     FontViewInit();
7430 
7431     kf->dw = dw;
7432 
7433     memset(&gd,0,sizeof(gd));
7434     gd.flags = gg_visible | gg_enabled;
7435     helplist[0].invoke = FVMenuContextualHelp;
7436     gd.u.menu2 = mblist;
7437     kf->mb = GMenu2BarCreate( dw, &gd, NULL);
7438     GGadgetGetSize(kf->mb,&gsize);
7439     kf->mbh = gsize.height;
7440     kf->guts = drawable;
7441 
7442     ps = kf->sf->display_size; kf->sf->display_size = -24;
7443     kf->first_fv = __FontViewCreate(kf->sf); kf->first_fv->b.container = (struct fvcontainer *) kf;
7444     kf->second_fv = __FontViewCreate(kf->sf); kf->second_fv->b.container = (struct fvcontainer *) kf;
7445 
7446     kf->infoh = infoh = 1+GDrawPointsToPixels(NULL,fv_fontsize);
7447     kf->first_fv->mbh = kf->mbh;
7448     pos.x = 0; pos.y = kf->mbh+infoh+kf->fh+4;
7449     pos.width = 16*kf->first_fv->cbw+1;
7450     pos.height = 4*kf->first_fv->cbh+1;
7451 
7452     GDrawSetUserData(dw,kf->first_fv);
7453     FVCopyInnards(kf->first_fv,&pos,infoh,fvorig,dw,kf->def_layer,(struct fvcontainer *) kf);
7454     pos.height = 4*kf->first_fv->cbh+1;		/* We don't know the real fv->cbh until after creating the innards. The size of the last window is probably wrong, we'll fix later */
7455     kf->second_fv->mbh = kf->mbh;
7456     kf->label2_y = pos.y + pos.height+2;
7457     pos.y = kf->label2_y + kf->fh + 2;
7458     GDrawSetUserData(dw,kf->second_fv);
7459     FVCopyInnards(kf->second_fv,&pos,infoh,fvorig,dw,kf->def_layer,(struct fvcontainer *) kf);
7460 
7461     kf->sf->display_size = ps;
7462 
7463     GGadgetGetSize(kf->second_fv->vsb,&sbsize);
7464     gsize.x = gsize.y = 0;
7465     gsize.width = pos.width + sbsize.width;
7466     gsize.height = pos.y+pos.height;
7467     GGadgetSetDesiredSize(drawable,NULL,&gsize);
7468 }
7469 /* ************************************************************************** */
7470 /* ************************** Glyph Set from Selection ********************** */
7471 /* ************************************************************************** */
7472 
7473 struct gsd {
7474     struct fvcontainer base;
7475     FontView *fv;
7476     int done;
7477     int good;
7478     GWindow gw;
7479 };
7480 
gs_activateMe(struct fvcontainer * UNUSED (fvc),FontViewBase * UNUSED (fvb))7481 static void gs_activateMe(struct fvcontainer *UNUSED(fvc), FontViewBase *UNUSED(fvb)) {
7482     /*struct gsd *gs = (struct gsd *) fvc;*/
7483 }
7484 
gs_charEvent(struct fvcontainer * fvc,void * event)7485 static void gs_charEvent(struct fvcontainer *fvc,void *event) {
7486     struct gsd *gs = (struct gsd *) fvc;
7487     FVChar(gs->fv,event);
7488 }
7489 
gs_doClose(struct fvcontainer * fvc)7490 static void gs_doClose(struct fvcontainer *fvc) {
7491     struct gsd *gs = (struct gsd *) fvc;
7492     gs->done = true;
7493 }
7494 
7495 #define CID_Guts	1000
7496 #define CID_TopBox	1001
7497 
gs_doResize(struct fvcontainer * fvc,FontViewBase * UNUSED (fvb),int width,int height)7498 static void gs_doResize(struct fvcontainer *fvc, FontViewBase *UNUSED(fvb),
7499 	int width, int height) {
7500     struct gsd *gs = (struct gsd *) fvc;
7501     /*FontView *fv = (FontView *) fvb;*/
7502     GRect size;
7503 
7504     memset(&size,0,sizeof(size));
7505     size.width = width; size.height = height;
7506     GGadgetSetDesiredSize(GWidgetGetControl(gs->gw,CID_Guts),
7507 	    NULL,&size);
7508     GHVBoxFitWindow(GWidgetGetControl(gs->gw,CID_TopBox));
7509 }
7510 
7511 static struct fvcontainer_funcs glyphset_funcs = {
7512     fvc_glyphset,
7513     true,			/* Modal dialog. No charviews, etc. */
7514     gs_activateMe,
7515     gs_charEvent,
7516     gs_doClose,
7517     gs_doResize
7518 };
7519 
GS_OK(GGadget * g,GEvent * e)7520 static int GS_OK(GGadget *g, GEvent *e) {
7521 
7522     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
7523 	struct gsd *gs = GDrawGetUserData(GGadgetGetWindow(g));
7524 	gs->done = true;
7525 	gs->good = true;
7526     }
7527 return( true );
7528 }
7529 
GS_Cancel(GGadget * g,GEvent * e)7530 static int GS_Cancel(GGadget *g, GEvent *e) {
7531     struct gsd *gs;
7532 
7533     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
7534 	gs = GDrawGetUserData(GGadgetGetWindow(g));
7535 	gs->done = true;
7536     }
7537 return( true );
7538 }
7539 
gs_sizeSet(struct gsd * gs,GWindow dw)7540 static void gs_sizeSet(struct gsd *gs,GWindow dw) {
7541     GRect size, gsize;
7542     int width, height, y;
7543     int cc, rc, topchar;
7544     GRect subsize;
7545     FontView *fv = gs->fv;
7546 
7547     if ( gs->fv->vsb==NULL )
7548 return;
7549 
7550     GDrawGetSize(dw,&size);
7551     GGadgetGetSize(gs->fv->vsb,&gsize);
7552     width = size.width - gsize.width;
7553     height = size.height - gs->fv->mbh - gs->fv->infoh;
7554 
7555     y = gs->fv->mbh + gs->fv->infoh;
7556 
7557     topchar = fv->rowoff*fv->colcnt;
7558     cc = (width-1) / fv->cbw;
7559     if ( cc<1 ) cc=1;
7560     rc = (height-1)/ fv->cbh;
7561     if ( rc<1 ) rc = 1;
7562     subsize.x = 0; subsize.y = 0;
7563     subsize.width = cc*fv->cbw + 1;
7564     subsize.height = rc*fv->cbh + 1;
7565     GDrawResize(fv->v,subsize.width,subsize.height);
7566     GDrawMove(fv->v,0,y);
7567     GGadgetMove(fv->vsb,subsize.width,y);
7568     GGadgetResize(fv->vsb,gsize.width,subsize.height);
7569 
7570     fv->colcnt = cc; fv->rowcnt = rc;
7571     fv->width = subsize.width; fv->height = subsize.height;
7572     fv->rowltot = (fv->b.map->enccount+fv->colcnt-1)/fv->colcnt;
7573     GScrollBarSetBounds(fv->vsb,0,fv->rowltot,fv->rowcnt);
7574     fv->rowoff = topchar/fv->colcnt;
7575     if ( fv->rowoff>=fv->rowltot-fv->rowcnt )
7576         fv->rowoff = fv->rowltot-fv->rowcnt;
7577     if ( fv->rowoff<0 ) fv->rowoff =0;
7578     GScrollBarSetPos(fv->vsb,fv->rowoff);
7579 
7580     GDrawRequestExpose(fv->v,NULL,true);
7581 }
7582 
gs_sub_e_h(GWindow pixmap,GEvent * event)7583 static int gs_sub_e_h(GWindow pixmap, GEvent *event) {
7584     FontView *active_fv;
7585     struct gsd *gs;
7586 
7587     if ( event->type==et_destroy )
7588 return( true );
7589 
7590     active_fv = (FontView *) GDrawGetUserData(pixmap);
7591     gs = (struct gsd *) (active_fv->b.container);
7592 
7593     if (( event->type==et_mouseup || event->type==et_mousedown ) &&
7594 	    (event->u.mouse.button>=4 && event->u.mouse.button<=7) ) {
7595 return( GGadgetDispatchEvent(active_fv->vsb,event));
7596     }
7597 
7598 
7599     switch ( event->type ) {
7600       case et_expose:
7601 	FVDrawInfo(active_fv,pixmap,event);
7602       break;
7603       case et_char:
7604 	gs_charEvent(&gs->base,event);
7605       break;
7606       case et_mousedown:
7607 return(false);
7608       break;
7609       case et_mouseup: case et_mousemove:
7610 return(false);
7611       case et_resize:
7612         gs_sizeSet(gs,pixmap);
7613       break;
7614     }
7615 return( true );
7616 }
7617 
gs_e_h(GWindow gw,GEvent * event)7618 static int gs_e_h(GWindow gw, GEvent *event) {
7619     struct gsd *gs = GDrawGetUserData(gw);
7620 
7621     switch ( event->type ) {
7622       case et_close:
7623 	gs->done = true;
7624       break;
7625       case et_char:
7626 	FVChar(gs->fv,event);
7627       break;
7628     }
7629 return( true );
7630 }
7631 
GlyphSetFromSelection(SplineFont * sf,int def_layer,char * current)7632 char *GlyphSetFromSelection(SplineFont *sf,int def_layer,char *current) {
7633     struct gsd gs;
7634     GRect pos;
7635     GWindowAttrs wattrs;
7636     GGadgetCreateData gcd[5], boxes[3];
7637     GGadgetCreateData *varray[21], *buttonarray[8];
7638     GTextInfo label[5];
7639     int i,j,k,guts_row,gid,enc,len;
7640     char *ret, *rpt;
7641     SplineChar *sc;
7642     GGadget *drawable;
7643     GWindow dw;
7644     GGadgetData gd;
7645     GRect gsize, sbsize;
7646     int infoh, mbh;
7647     int ps;
7648     FontView *fvorig = (FontView *) sf->fv;
7649     GGadget *mb;
7650     char *start, *pt; int ch;
7651 
7652     FontViewInit();
7653 
7654     memset(&wattrs,0,sizeof(wattrs));
7655     memset(&gcd,0,sizeof(gcd));
7656     memset(&boxes,0,sizeof(boxes));
7657     memset(&label,0,sizeof(label));
7658     memset(&gs,0,sizeof(gs));
7659 
7660     gs.base.funcs = &glyphset_funcs;
7661 
7662     wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_undercursor|wam_isdlg|wam_restrict;
7663     wattrs.event_masks = ~(1<<et_charup);
7664     wattrs.restrict_input_to_me = true;
7665     wattrs.undercursor = 1;
7666     wattrs.cursor = ct_pointer;
7667     wattrs.utf8_window_title = _("Glyph Set by Selection") ;
7668     wattrs.is_dlg = true;
7669     pos.x = pos.y = 0;
7670     pos.width = 100;
7671     pos.height = 100;
7672     gs.gw = GDrawCreateTopWindow(NULL,&pos,gs_e_h,&gs,&wattrs);
7673 
7674     i = j = 0;
7675 
7676     guts_row = j/2;
7677     gcd[i].gd.flags = gg_enabled|gg_visible;
7678     gcd[i].gd.cid = CID_Guts;
7679     gcd[i].gd.u.drawable_e_h = gs_sub_e_h;
7680     gcd[i].creator = GDrawableCreate;
7681     varray[j++] = &gcd[i++]; varray[j++] = NULL;
7682 
7683     label[i].text = (unichar_t *) _("Select glyphs in the font view above.\nThe selected glyphs become your glyph class.");
7684     label[i].text_is_1byte = true;
7685     gcd[i].gd.label = &label[i];
7686     gcd[i].gd.flags = gg_enabled|gg_visible;
7687     gcd[i].creator = GLabelCreate;
7688     varray[j++] = &gcd[i++]; varray[j++] = NULL;
7689 
7690     gcd[i].gd.flags = gg_visible | gg_enabled | gg_but_default;
7691     label[i].text = (unichar_t *) _("_OK");
7692     label[i].text_is_1byte = true;
7693     label[i].text_in_resource = true;
7694     gcd[i].gd.label = &label[i];
7695     gcd[i].gd.handle_controlevent = GS_OK;
7696     gcd[i++].creator = GButtonCreate;
7697 
7698     gcd[i].gd.flags = gg_visible | gg_enabled | gg_but_cancel;
7699     label[i].text = (unichar_t *) _("_Cancel");
7700     label[i].text_is_1byte = true;
7701     label[i].text_in_resource = true;
7702     gcd[i].gd.label = &label[i];
7703     gcd[i].gd.handle_controlevent = GS_Cancel;
7704     gcd[i++].creator = GButtonCreate;
7705 
7706     buttonarray[0] = GCD_Glue; buttonarray[1] = &gcd[i-2]; buttonarray[2] = GCD_Glue;
7707     buttonarray[3] = GCD_Glue; buttonarray[4] = &gcd[i-1]; buttonarray[5] = GCD_Glue;
7708     buttonarray[6] = NULL;
7709     boxes[2].gd.flags = gg_enabled|gg_visible;
7710     boxes[2].gd.u.boxelements = buttonarray;
7711     boxes[2].creator = GHBoxCreate;
7712     varray[j++] = &boxes[2]; varray[j++] = NULL; varray[j++] = NULL;
7713 
7714     boxes[0].gd.pos.x = boxes[0].gd.pos.y = 2;
7715     boxes[0].gd.flags = gg_enabled|gg_visible;
7716     boxes[0].gd.u.boxelements = varray;
7717     boxes[0].gd.cid = CID_TopBox;
7718     boxes[0].creator = GHVGroupCreate;
7719 
7720     GGadgetsCreate(gs.gw,boxes);
7721 
7722     GHVBoxSetExpandableRow(boxes[0].ret,guts_row);
7723     GHVBoxSetExpandableCol(boxes[2].ret,gb_expandgluesame);
7724 
7725     drawable = GWidgetGetControl(gs.gw,CID_Guts);
7726     dw = GDrawableGetWindow(drawable);
7727 
7728     memset(&gd,0,sizeof(gd));
7729     gd.flags = gg_visible | gg_enabled;
7730     helplist[0].invoke = FVMenuContextualHelp;
7731     gd.u.menu2 = mblist;
7732     mb = GMenu2BarCreate( dw, &gd, NULL);
7733     GGadgetGetSize(mb,&gsize);
7734     mbh = gsize.height;
7735 
7736     ps = sf->display_size; sf->display_size = -24;
7737     gs.fv = __FontViewCreate(sf);
7738 
7739     infoh = 1+GDrawPointsToPixels(NULL,fv_fontsize);
7740     gs.fv->mbh = mbh;
7741     pos.x = 0; pos.y = mbh+infoh;
7742     pos.width = 16*gs.fv->cbw+1;
7743     pos.height = 4*gs.fv->cbh+1;
7744 
7745     GDrawSetUserData(dw,gs.fv);
7746     FVCopyInnards(gs.fv,&pos,infoh,fvorig,dw,def_layer,(struct fvcontainer *) &gs);
7747     pos.height = 4*gs.fv->cbh+1;	/* We don't know the real fv->cbh until after creating the innards. The size of the last window is probably wrong, we'll fix later */
7748     memset(gs.fv->b.selected,0,gs.fv->b.map->enccount);
7749     if ( current!=NULL && strcmp(current,_("{Everything Else}"))!=0 ) {
7750 	int first = true;
7751 	for ( start = current; *start==' '; ++start );
7752 	while ( *start ) {
7753 	    for ( pt=start; *pt!='\0' && *pt!=' '; ++pt );
7754 	    ch = *pt; *pt='\0';
7755 	    sc = SFGetChar(sf,-1,start);
7756 	    *pt = ch;
7757 	    if ( sc!=NULL && (enc = gs.fv->b.map->backmap[sc->orig_pos])!=-1 ) {
7758 		gs.fv->b.selected[enc] = true;
7759 		if ( first ) {
7760 		    first = false;
7761 		    gs.fv->rowoff = enc/gs.fv->colcnt;
7762 		}
7763 	    }
7764 	    start = pt;
7765 	    while ( *start==' ' ) ++start;
7766 	}
7767     }
7768     sf->display_size = ps;
7769 
7770     GGadgetGetSize(gs.fv->vsb,&sbsize);
7771     gsize.x = gsize.y = 0;
7772     gsize.width = pos.width + sbsize.width;
7773     gsize.height = pos.y+pos.height;
7774     GGadgetSetDesiredSize(drawable,NULL,&gsize);
7775 
7776     GHVBoxFitWindow(boxes[0].ret);
7777     GDrawSetVisible(gs.gw,true);
7778     while ( !gs.done )
7779 	GDrawProcessOneEvent(NULL);
7780 
7781     ret = rpt = NULL;
7782     if ( gs.good ) {
7783 	for ( k=0; k<2; ++k ) {
7784 	    len = 0;
7785 	    for ( enc=0; enc<gs.fv->b.map->enccount; ++enc ) {
7786 		if ( gs.fv->b.selected[enc] &&
7787 			(gid=gs.fv->b.map->map[enc])!=-1 &&
7788 			(sc = sf->glyphs[gid])!=NULL ) {
7789 		    char *repr = SCNameUniStr( sc );
7790 		    if ( ret==NULL )
7791 			len += strlen(repr)+2;
7792 		    else {
7793 			strcpy(rpt,repr);
7794 			rpt += strlen( repr );
7795 			free(repr);
7796 			*rpt++ = ' ';
7797 		    }
7798 		}
7799 	    }
7800 	    if ( k==0 )
7801 		ret = rpt = malloc(len+1);
7802 	    else if ( rpt!=ret && rpt[-1]==' ' )
7803 		rpt[-1]='\0';
7804 	    else
7805 		*rpt='\0';
7806 	}
7807     }
7808     FontViewFree(&gs.fv->b);
7809     GDrawSetUserData(gs.gw,NULL);
7810     GDrawSetUserData(dw,NULL);
7811     GDrawDestroyWindow(gs.gw);
7812 return( ret );
7813 }
7814 
7815 /* local variables: */
7816 /* tab-width: 8     */
7817 /* end:             */
7818