LCOV - code coverage report
Current view: top level - fontforgeexe - fontview.c (source / functions) Hit Total Coverage
Test: FontForge coverage report 2017-08-04 01:21:11+02:00 (commit d35f7e4107a9e1db65cce47c468fcc914cecb8fd) Lines: 125 4787 2.6 %
Date: 2017-08-04 Functions: 16 335 4.8 %

          Line data    Source code
       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             : #include <fontforge-config.h>
      28             : 
      29             : #include "inc/gnetwork.h"
      30             : #include "collabclientui.h"
      31             : #include "collabclientpriv.h"
      32             : 
      33             : #include "autosave.h"
      34             : #include "autotrace.h"
      35             : #include "autowidth.h"
      36             : #include "autowidth2.h"
      37             : #include "bitmapchar.h"
      38             : #include "bvedit.h"
      39             : #include "cvundoes.h"
      40             : #include "dumppfa.h"
      41             : #include "encoding.h"
      42             : #include "fontforgeui.h"
      43             : #include "fvcomposite.h"
      44             : #include "fvfonts.h"
      45             : #include "groups.h"
      46             : #include "mm.h"
      47             : #include "namelist.h"
      48             : #include "nonlineartrans.h"
      49             : #include "psfont.h"
      50             : #include "scripting.h"
      51             : #include "splinefill.h"
      52             : #include "search.h"
      53             : #include "sfd.h"
      54             : #include "splinesaveafm.h"
      55             : #include "splineutil.h"
      56             : #include "splineutil2.h"
      57             : #include "tottfgpos.h"
      58             : #include <gfile.h>
      59             : #include <gio.h>
      60             : #include <gresedit.h>
      61             : #include <ustring.h>
      62             : #include "../fontforge/ffglib.h"
      63             : #include <gkeysym.h>
      64             : #include <utype.h>
      65             : #include <chardata.h>
      66             : #include <gresource.h>
      67             : #include <math.h>
      68             : #include <unistd.h>
      69             : 
      70             : #include "gutils/unicodelibinfo.h"
      71             : #include "sfundo.h"
      72             : 
      73             : #if defined (__MINGW32__)
      74             : #include <windows.h>
      75             : #endif
      76             : 
      77             : #include "xvasprintf.h"
      78             : 
      79             : 
      80             : int OpenCharsInNewWindow = 0;
      81             : char *RecentFiles[RECENT_MAX] = { NULL };
      82             : int save_to_dir = 0;                    /* use sfdir rather than sfd */
      83             : unichar_t *script_menu_names[SCRIPT_MENU_MAX];
      84             : char *script_filenames[SCRIPT_MENU_MAX];
      85             : extern int onlycopydisplayed, copymetadata, copyttfinstr, add_char_to_name_list;
      86             : int home_char='A';
      87             : int compact_font_on_open=0;
      88             : int navigation_mask = 0;                /* Initialized in startui.c */
      89             : 
      90             : static char *fv_fontnames = MONO_UI_FAMILIES;
      91             : extern char* pref_collab_last_server_connected_to;
      92             : extern void python_call_onClosingFunctions();
      93             : 
      94             : #define FV_LAB_HEIGHT   15
      95             : 
      96             : #ifdef BIGICONS
      97             : #define fontview_width 32
      98             : #define fontview_height 32
      99             : static unsigned char fontview_bits[] = {
     100             :    0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0x02, 0x20, 0x80, 0x00,
     101             :    0x82, 0x20, 0x86, 0x08, 0x42, 0x21, 0x8a, 0x14, 0xc2, 0x21, 0x86, 0x04,
     102             :    0x42, 0x21, 0x8a, 0x14, 0x42, 0x21, 0x86, 0x08, 0x02, 0x20, 0x80, 0x00,
     103             :    0xaa, 0xaa, 0xaa, 0xaa, 0x02, 0x20, 0x80, 0x00, 0x82, 0xa0, 0x8f, 0x18,
     104             :    0x82, 0x20, 0x91, 0x24, 0x42, 0x21, 0x91, 0x02, 0x42, 0x21, 0x91, 0x02,
     105             :    0x22, 0x21, 0x8f, 0x02, 0xe2, 0x23, 0x91, 0x02, 0x12, 0x22, 0x91, 0x02,
     106             :    0x3a, 0x27, 0x91, 0x24, 0x02, 0xa0, 0x8f, 0x18, 0x02, 0x20, 0x80, 0x00,
     107             :    0xfe, 0xff, 0xff, 0xff, 0x02, 0x20, 0x80, 0x00, 0x42, 0x20, 0x86, 0x18,
     108             :    0xa2, 0x20, 0x8a, 0x04, 0xa2, 0x20, 0x86, 0x08, 0xa2, 0x20, 0x8a, 0x10,
     109             :    0x42, 0x20, 0x8a, 0x0c, 0x82, 0x20, 0x80, 0x00, 0x02, 0x20, 0x80, 0x00,
     110             :    0xaa, 0xaa, 0xaa, 0xaa, 0x02, 0x20, 0x80, 0x00};
     111             : #else
     112             : #define fontview2_width 16
     113             : #define fontview2_height 16
     114             : static unsigned char fontview2_bits[] = {
     115             :    0x00, 0x07, 0x80, 0x08, 0x40, 0x17, 0x40, 0x15, 0x60, 0x09, 0x10, 0x02,
     116             :    0xa0, 0x01, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0x50, 0x00, 0x52, 0x00,
     117             :    0x55, 0x00, 0x5d, 0x00, 0x22, 0x00, 0x1c, 0x00};
     118             : #endif
     119             : 
     120             : extern int _GScrollBar_Width;
     121             : 
     122             : static int fv_fontsize = 11, fv_fs_init=0;
     123             : static Color fvselcol = 0xffff00, fvselfgcol=0x000000;
     124             : Color view_bgcol;
     125             : static Color fvglyphinfocol = 0xff0000;
     126             : static Color fvemtpyslotfgcol = 0xd08080;
     127             : static Color fvchangedcol = 0x000060;
     128             : static Color fvhintingneededcol = 0x0000ff;
     129             : 
     130             : enum glyphlable { gl_glyph, gl_name, gl_unicode, gl_encoding };
     131             : int default_fv_showhmetrics=false, default_fv_showvmetrics=false,
     132             :         default_fv_glyphlabel = gl_glyph;
     133             : #define METRICS_BASELINE 0x0000c0
     134             : #define METRICS_ORIGIN   0xc00000
     135             : #define METRICS_ADVANCE  0x008000
     136             : FontView *fv_list=NULL;
     137             : 
     138             : static void AskAndMaybeCloseLocalCollabServers( void );
     139             : 
     140             : 
     141        2856 : static void FV_ToggleCharChanged(SplineChar *sc) {
     142             :     int i, j;
     143             :     int pos;
     144             :     FontView *fv;
     145             : 
     146        5712 :     for ( fv = (FontView *) (sc->parent->fv); fv!=NULL; fv=(FontView *) (fv->b.nextsame) ) {
     147        2856 :         if ( fv->b.sf!=sc->parent )               /* Can happen in CID fonts if char's parent is not currently active */
     148           6 :     continue;
     149        2850 :         if ( fv->v==NULL || fv->colcnt==0 )       /* Can happen in scripts */
     150        2850 :     continue;
     151           0 :         for ( pos=0; pos<fv->b.map->enccount; ++pos ) if ( fv->b.map->map[pos]==sc->orig_pos ) {
     152           0 :             i = pos / fv->colcnt;
     153           0 :             j = pos - i*fv->colcnt;
     154           0 :             i -= fv->rowoff;
     155             :  /* Normally we should be checking against fv->rowcnt (rather than <=rowcnt) */
     156             :  /*  but every now and then the WM forces us to use a window size which doesn't */
     157             :  /*  fit our expectations (maximized view) and we must be prepared for half */
     158             :  /*  lines */
     159           0 :             if ( i>=0 && i<=fv->rowcnt ) {
     160             :                 GRect r;
     161           0 :                 r.x = j*fv->cbw+1; r.width = fv->cbw-1;
     162           0 :                 r.y = i*fv->cbh+1; r.height = fv->lab_height-1;
     163           0 :                 GDrawRequestExpose(fv->v,&r,false);
     164             :             }
     165             :         }
     166             :     }
     167        2856 : }
     168             : 
     169        2082 : void FVMarkHintsOutOfDate(SplineChar *sc) {
     170             :     int i, j;
     171             :     int pos;
     172             :     FontView *fv;
     173             : 
     174        2082 :     if ( sc->parent->onlybitmaps || sc->parent->multilayer || sc->parent->strokedfont )
     175        2082 : return;
     176        4164 :     for ( fv = (FontView *) (sc->parent->fv); fv!=NULL; fv=(FontView *) (fv->b.nextsame) ) {
     177        2082 :         if ( fv->b.sf!=sc->parent )               /* Can happen in CID fonts if char's parent is not currently active */
     178           1 :     continue;
     179        2081 :         if ( sc->layers[fv->b.active_layer].order2 )
     180        1215 :     continue;
     181         866 :         if ( fv->v==NULL || fv->colcnt==0 )       /* Can happen in scripts */
     182         866 :     continue;
     183           0 :         for ( pos=0; pos<fv->b.map->enccount; ++pos ) if ( fv->b.map->map[pos]==sc->orig_pos ) {
     184           0 :             i = pos / fv->colcnt;
     185           0 :             j = pos - i*fv->colcnt;
     186           0 :             i -= fv->rowoff;
     187             :  /* Normally we should be checking against fv->rowcnt (rather than <=rowcnt) */
     188             :  /*  but every now and then the WM forces us to use a window size which doesn't */
     189             :  /*  fit our expectations (maximized view) and we must be prepared for half */
     190             :  /*  lines */
     191           0 :             if ( i>=0 && i<=fv->rowcnt ) {
     192             :                 GRect r;
     193           0 :                 r.x = j*fv->cbw+1; r.width = fv->cbw-1;
     194           0 :                 r.y = i*fv->cbh+1; r.height = fv->lab_height-1;
     195           0 :                 GDrawDrawLine(fv->v,r.x,r.y,r.x,r.y+r.height-1,fvhintingneededcol);
     196           0 :                 GDrawDrawLine(fv->v,r.x+1,r.y,r.x+1,r.y+r.height-1,fvhintingneededcol);
     197           0 :                 GDrawDrawLine(fv->v,r.x+r.width-1,r.y,r.x+r.width-1,r.y+r.height-1,fvhintingneededcol);
     198           0 :                 GDrawDrawLine(fv->v,r.x+r.width-2,r.y,r.x+r.width-2,r.y+r.height-1,fvhintingneededcol);
     199             :             }
     200             :         }
     201             :     }
     202             : }
     203             : 
     204           0 : static int FeatureTrans(FontView *fv, int enc) {
     205             :     SplineChar *sc;
     206             :     PST *pst;
     207             :     char *pt;
     208             :     int gid;
     209             : 
     210           0 :     if ( enc<0 || enc>=fv->b.map->enccount || (gid = fv->b.map->map[enc])==-1 )
     211           0 : return( -1 );
     212           0 :     if ( fv->cur_subtable==NULL )
     213           0 : return( gid );
     214             : 
     215           0 :     sc = fv->b.sf->glyphs[gid];
     216           0 :     if ( sc==NULL )
     217           0 : return( -1 );
     218           0 :     for ( pst = sc->possub; pst!=NULL; pst=pst->next ) {
     219           0 :         if (( pst->type == pst_substitution || pst->type == pst_alternate ) &&
     220           0 :                 pst->subtable == fv->cur_subtable )
     221           0 :     break;
     222             :     }
     223           0 :     if ( pst==NULL )
     224           0 : return( -1 );
     225           0 :     pt = strchr(pst->u.subs.variant,' ');
     226           0 :     if ( pt!=NULL )
     227           0 :         *pt = '\0';
     228           0 :     gid = SFFindExistingSlot(fv->b.sf, -1, pst->u.subs.variant );
     229           0 :     if ( pt!=NULL )
     230           0 :         *pt = ' ';
     231           0 : return( gid );
     232             : }
     233             : 
     234           0 : static void FVDrawGlyph(GWindow pixmap, FontView *fv, int index, int forcebg ) {
     235             :     GRect box, old2;
     236             :     int feat_gid;
     237             :     SplineChar *sc;
     238             :     struct _GImage base;
     239             :     GImage gi;
     240             :     GClut clut;
     241             :     int i,j;
     242           0 :     int em = fv->b.sf->ascent+fv->b.sf->descent;
     243           0 :     int yorg = fv->magnify*(fv->show->ascent);
     244             : 
     245           0 :     i = index / fv->colcnt;
     246           0 :     j = index - i*fv->colcnt;
     247           0 :     i -= fv->rowoff;
     248             : 
     249           0 :     if ( index<fv->b.map->enccount && (fv->b.selected[index] || forcebg)) {
     250           0 :         box.x = j*fv->cbw+1; box.width = fv->cbw-1;
     251           0 :         box.y = i*fv->cbh+fv->lab_height+1; box.height = fv->cbw;
     252           0 :         GDrawFillRect(pixmap,&box,fv->b.selected[index] ? fvselcol : view_bgcol );
     253             :     }
     254           0 :     feat_gid = FeatureTrans(fv,index);
     255           0 :     sc = feat_gid!=-1 ? fv->b.sf->glyphs[feat_gid]: NULL;
     256           0 :     if ( !SCWorthOutputting(sc) ) {
     257           0 :         int x = j*fv->cbw+1, xend = x+fv->cbw-2;
     258           0 :         int y = i*fv->cbh+fv->lab_height+1, yend = y+fv->cbw-1;
     259           0 :         GDrawDrawLine(pixmap,x,y,xend,yend,fvemtpyslotfgcol);
     260           0 :         GDrawDrawLine(pixmap,x,yend,xend,y,fvemtpyslotfgcol);
     261             :     }
     262           0 :     if ( sc!=NULL ) {
     263             :         BDFChar *bdfc;
     264             : 
     265           0 :         if ( fv->show!=NULL && fv->show->piecemeal &&
     266           0 :                 feat_gid!=-1 &&
     267           0 :                 (feat_gid>=fv->show->glyphcnt || fv->show->glyphs[feat_gid]==NULL) &&
     268           0 :                 fv->b.sf->glyphs[feat_gid]!=NULL )
     269           0 :             BDFPieceMeal(fv->show,feat_gid);
     270             : 
     271           0 :         if ( fv->show!=NULL && feat_gid!=-1 &&
     272           0 :                 feat_gid < fv->show->glyphcnt &&
     273           0 :                 fv->show->glyphs[feat_gid]==NULL &&
     274           0 :                 SCWorthOutputting(fv->b.sf->glyphs[feat_gid]) ) {
     275             :             /* If we have an outline but no bitmap for this slot */
     276           0 :             box.x = j*fv->cbw+1; box.width = fv->cbw-2;
     277           0 :             box.y = i*fv->cbh+fv->lab_height+2; box.height = box.width+1;
     278           0 :             GDrawDrawRect(pixmap,&box,0xff0000);
     279           0 :             ++box.x; ++box.y; box.width -= 2; box.height -= 2;
     280           0 :             GDrawDrawRect(pixmap,&box,0xff0000);
     281             : /* When reencoding a font we can find times where index>=show->charcnt */
     282           0 :         } else if ( fv->show!=NULL && feat_gid<fv->show->glyphcnt && feat_gid!=-1 &&
     283           0 :                 fv->show->glyphs[feat_gid]!=NULL ) {
     284             :             /* If fontview is set to display an embedded bitmap font (not a temporary font, */
     285             :             /* rasterized specially for this purpose), then we can't use it directly, as bitmap */
     286             :             /* glyphs may contain selections and references. So create a temporary copy of */
     287             :             /* the glyph merging all such elements into a single bitmap */
     288           0 :             bdfc = fv->show->piecemeal ?
     289           0 :                 fv->show->glyphs[feat_gid] : BDFGetMergedChar( fv->show->glyphs[feat_gid] );
     290             : 
     291           0 :             memset(&gi,'\0',sizeof(gi));
     292           0 :             memset(&base,'\0',sizeof(base));
     293           0 :             if ( bdfc->byte_data ) {
     294           0 :                 gi.u.image = &base;
     295           0 :                 base.image_type = it_index;
     296           0 :                 if ( !fv->b.selected[index] )
     297           0 :                     base.clut = fv->show->clut;
     298             :                 else {
     299           0 :                     int bgr=((fvselcol>>16)&0xff), bgg=((fvselcol>>8)&0xff), bgb= (fvselcol&0xff);
     300           0 :                     int fgr=((fvselfgcol>>16)&0xff), fgg=((fvselfgcol>>8)&0xff), fgb= (fvselfgcol&0xff);
     301             :                     int i;
     302           0 :                     memset(&clut,'\0',sizeof(clut));
     303           0 :                     base.clut = &clut;
     304           0 :                     clut.clut_len = fv->show->clut->clut_len;
     305           0 :                     for ( i=0; i<clut.clut_len; ++i ) {
     306           0 :                         clut.clut[i] =
     307           0 :                                 COLOR_CREATE( bgr + (i*(fgr-bgr))/(clut.clut_len-1),
     308             :                                                 bgg + (i*(fgg-bgg))/(clut.clut_len-1),
     309             :                                                 bgb + (i*(fgb-bgb))/(clut.clut_len-1));
     310             :                     }
     311             :                 }
     312           0 :                 GDrawSetDither(NULL, false);    /* on 8 bit displays we don't want any dithering */
     313             :             } else {
     314           0 :                 memset(&clut,'\0',sizeof(clut));
     315           0 :                 gi.u.image = &base;
     316           0 :                 base.image_type = it_mono;
     317           0 :                 base.clut = &clut;
     318           0 :                 clut.clut_len = 2;
     319           0 :                 clut.clut[0] = fv->b.selected[index] ? fvselcol : view_bgcol ;
     320           0 :                 clut.clut[1] = fv->b.selected[index] ? fvselfgcol : 0 ;
     321             :             }
     322           0 :             base.trans = 0;
     323           0 :             base.clut->trans_index = 0;
     324             : 
     325           0 :             base.data = bdfc->bitmap;
     326           0 :             base.bytes_per_line = bdfc->bytes_per_line;
     327           0 :             base.width = bdfc->xmax-bdfc->xmin+1;
     328           0 :             base.height = bdfc->ymax-bdfc->ymin+1;
     329           0 :             box.x = j*fv->cbw; box.width = fv->cbw;
     330           0 :             box.y = i*fv->cbh+fv->lab_height+1; box.height = box.width+1;
     331           0 :             GDrawPushClip(pixmap,&box,&old2);
     332           0 :             if ( !fv->b.sf->onlybitmaps && fv->show!=fv->filled &&
     333           0 :                     sc->layers[fv->b.active_layer].splines==NULL && sc->layers[fv->b.active_layer].refs==NULL &&
     334           0 :                     !sc->widthset &&
     335           0 :                     !(bdfc->xmax<=0 && bdfc->xmin==0 && bdfc->ymax<=0 && bdfc->ymax==0) ) {
     336             :                 /* If we have a bitmap but no outline character... */
     337             :                 GRect b;
     338           0 :                 b.x = box.x+1; b.y = box.y+1; b.width = box.width-2; b.height = box.height-2;
     339           0 :                 GDrawDrawRect(pixmap,&b,0x008000);
     340           0 :                 ++b.x; ++b.y; b.width -= 2; b.height -= 2;
     341           0 :                 GDrawDrawRect(pixmap,&b,0x008000);
     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           0 :             if ( fv->magnify>1 ) {
     347           0 :                 GDrawDrawImageMagnified(pixmap,&gi,NULL,
     348           0 :                         j*fv->cbw+(fv->cbw-1-fv->magnify*base.width)/2,
     349           0 :                         i*fv->cbh+fv->lab_height+1+fv->magnify*(fv->show->ascent-bdfc->ymax),
     350           0 :                         fv->magnify*base.width,fv->magnify*base.height);
     351           0 :             } else if ( (GDrawHasCairo(pixmap)&gc_alpha) && base.image_type==it_index ) {
     352           0 :                 GDrawDrawGlyph(pixmap,&gi,NULL,
     353           0 :                         j*fv->cbw+(fv->cbw-1-base.width)/2,
     354           0 :                         i*fv->cbh+fv->lab_height+1+fv->show->ascent-bdfc->ymax);
     355             :             } else
     356           0 :                 GDrawDrawImage(pixmap,&gi,NULL,
     357           0 :                         j*fv->cbw+(fv->cbw-1-base.width)/2,
     358           0 :                         i*fv->cbh+fv->lab_height+1+fv->show->ascent-bdfc->ymax);
     359           0 :             if ( fv->showhmetrics ) {
     360           0 :                 int x1, x0 = j*fv->cbw+(fv->cbw-1-fv->magnify*base.width)/2- bdfc->xmin*fv->magnify;
     361             :                 /* Draw advance width & horizontal origin */
     362           0 :                 if ( fv->showhmetrics&fvm_origin )
     363           0 :                     GDrawDrawLine(pixmap,x0,i*fv->cbh+fv->lab_height+yorg-3,x0,
     364           0 :                             i*fv->cbh+fv->lab_height+yorg+2,METRICS_ORIGIN);
     365           0 :                 x1 = x0 + fv->magnify*bdfc->width;
     366           0 :                 if ( fv->showhmetrics&fvm_advanceat )
     367           0 :                     GDrawDrawLine(pixmap,x1,i*fv->cbh+fv->lab_height+1,x1,
     368           0 :                             (i+1)*fv->cbh-1,METRICS_ADVANCE);
     369           0 :                 if ( fv->showhmetrics&fvm_advanceto )
     370           0 :                     GDrawDrawLine(pixmap,x0,(i+1)*fv->cbh-2,x1,
     371           0 :                             (i+1)*fv->cbh-2,METRICS_ADVANCE);
     372             :             }
     373           0 :             if ( fv->showvmetrics ) {
     374           0 :                 int x0 = j*fv->cbw+(fv->cbw-1-fv->magnify*base.width)/2- bdfc->xmin*fv->magnify
     375           0 :                         + fv->magnify*fv->show->pixelsize/2;
     376           0 :                 int y0 = i*fv->cbh+fv->lab_height+yorg;
     377           0 :                 int yvw = y0 + fv->magnify*sc->vwidth*fv->show->pixelsize/em;
     378           0 :                 if ( fv->showvmetrics&fvm_baseline )
     379           0 :                     GDrawDrawLine(pixmap,x0,i*fv->cbh+fv->lab_height+1,x0,
     380           0 :                             (i+1)*fv->cbh-1,METRICS_BASELINE);
     381           0 :                 if ( fv->showvmetrics&fvm_advanceat )
     382           0 :                     GDrawDrawLine(pixmap,j*fv->cbw,yvw,(j+1)*fv->cbw,
     383             :                             yvw,METRICS_ADVANCE);
     384           0 :                 if ( fv->showvmetrics&fvm_advanceto )
     385           0 :                     GDrawDrawLine(pixmap,j*fv->cbw+2,y0,j*fv->cbw+2,
     386             :                             yvw,METRICS_ADVANCE);
     387           0 :                 if ( fv->showvmetrics&fvm_origin )
     388           0 :                     GDrawDrawLine(pixmap,x0-3,i*fv->cbh+fv->lab_height+yorg,x0+2,i*fv->cbh+fv->lab_height+yorg,METRICS_ORIGIN);
     389             :             }
     390           0 :             GDrawPopClip(pixmap,&old2);
     391           0 :             if ( !fv->show->piecemeal ) BDFCharFree( bdfc );
     392             :         }
     393             :     }
     394           0 : }
     395             : 
     396           0 : static void FVToggleCharSelected(FontView *fv,int enc) {
     397             :     int i, j;
     398             : 
     399           0 :     if ( fv->v==NULL || fv->colcnt==0 )   /* Can happen in scripts */
     400           0 : return;
     401             : 
     402           0 :     i = enc / fv->colcnt;
     403           0 :     j = enc - i*fv->colcnt;
     404           0 :     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           0 :     if ( i>=0 && i<=fv->rowcnt )
     410           0 :         FVDrawGlyph(fv->v,fv,enc,true);
     411             : }
     412             : 
     413           6 : static void FontViewRefreshAll(SplineFont *sf) {
     414             :     FontView *fv;
     415          12 :     for ( fv = (FontView *) (sf->fv); fv!=NULL; fv = (FontView *) (fv->b.nextsame) )
     416           6 :         if ( fv->v!=NULL )
     417           0 :             GDrawRequestExpose(fv->v,NULL,false);
     418           6 : }
     419             : 
     420           0 : void FVDeselectAll(FontView *fv) {
     421             :     int i;
     422             : 
     423           0 :     for ( i=0; i<fv->b.map->enccount; ++i ) {
     424           0 :         if ( fv->b.selected[i] ) {
     425           0 :             fv->b.selected[i] = false;
     426           0 :             FVToggleCharSelected(fv,i);
     427             :         }
     428             :     }
     429           0 :     fv->sel_index = 0;
     430           0 : }
     431             : 
     432           0 : static void FVInvertSelection(FontView *fv) {
     433             :     int i;
     434             : 
     435           0 :     for ( i=0; i<fv->b.map->enccount; ++i ) {
     436           0 :         fv->b.selected[i] = !fv->b.selected[i];
     437           0 :         FVToggleCharSelected(fv,i);
     438             :     }
     439           0 :     fv->sel_index = 1;
     440           0 : }
     441             : 
     442           0 : static void FVSelectAll(FontView *fv) {
     443             :     int i;
     444             : 
     445           0 :     for ( i=0; i<fv->b.map->enccount; ++i ) {
     446           0 :         if ( !fv->b.selected[i] ) {
     447           0 :             fv->b.selected[i] = true;
     448           0 :             FVToggleCharSelected(fv,i);
     449             :         }
     450             :     }
     451           0 :     fv->sel_index = 1;
     452           0 : }
     453             : 
     454           0 : static void FVReselect(FontView *fv, int newpos) {
     455             :     int i;
     456             : 
     457           0 :     if ( newpos<0 ) newpos = 0;
     458           0 :     else if ( newpos>=fv->b.map->enccount ) newpos = fv->b.map->enccount-1;
     459             : 
     460           0 :     if ( fv->pressed_pos<fv->end_pos ) {
     461           0 :         if ( newpos>fv->end_pos ) {
     462           0 :             for ( i=fv->end_pos+1; i<=newpos; ++i ) if ( !fv->b.selected[i] ) {
     463           0 :                 fv->b.selected[i] = fv->sel_index;
     464           0 :                 FVToggleCharSelected(fv,i);
     465             :             }
     466           0 :         } else if ( newpos<fv->pressed_pos ) {
     467           0 :             for ( i=fv->end_pos; i>fv->pressed_pos; --i ) if ( fv->b.selected[i] ) {
     468           0 :                 fv->b.selected[i] = false;
     469           0 :                 FVToggleCharSelected(fv,i);
     470             :             }
     471           0 :             for ( i=fv->pressed_pos-1; i>=newpos; --i ) if ( !fv->b.selected[i] ) {
     472           0 :                 fv->b.selected[i] = fv->sel_index;
     473           0 :                 FVToggleCharSelected(fv,i);
     474             :             }
     475             :         } else {
     476           0 :             for ( i=fv->end_pos; i>newpos; --i ) if ( fv->b.selected[i] ) {
     477           0 :                 fv->b.selected[i] = false;
     478           0 :                 FVToggleCharSelected(fv,i);
     479             :             }
     480             :         }
     481             :     } else {
     482           0 :         if ( newpos<fv->end_pos ) {
     483           0 :             for ( i=fv->end_pos-1; i>=newpos; --i ) if ( !fv->b.selected[i] ) {
     484           0 :                 fv->b.selected[i] = fv->sel_index;
     485           0 :                 FVToggleCharSelected(fv,i);
     486             :             }
     487           0 :         } else if ( newpos>fv->pressed_pos ) {
     488           0 :             for ( i=fv->end_pos; i<fv->pressed_pos; ++i ) if ( fv->b.selected[i] ) {
     489           0 :                 fv->b.selected[i] = false;
     490           0 :                 FVToggleCharSelected(fv,i);
     491             :             }
     492           0 :             for ( i=fv->pressed_pos+1; i<=newpos; ++i ) if ( !fv->b.selected[i] ) {
     493           0 :                 fv->b.selected[i] = fv->sel_index;
     494           0 :                 FVToggleCharSelected(fv,i);
     495             :             }
     496             :         } else {
     497           0 :             for ( i=fv->end_pos; i<newpos; ++i ) if ( fv->b.selected[i] ) {
     498           0 :                 fv->b.selected[i] = false;
     499           0 :                 FVToggleCharSelected(fv,i);
     500             :             }
     501             :         }
     502             :     }
     503           0 :     fv->end_pos = newpos;
     504           0 :     if ( newpos>=0 && newpos<fv->b.map->enccount && (i = fv->b.map->map[newpos])!=-1 &&
     505           0 :             fv->b.sf->glyphs[i]!=NULL &&
     506           0 :             fv->b.sf->glyphs[i]->unicodeenc>=0 && fv->b.sf->glyphs[i]->unicodeenc<0x10000 )
     507           0 :         GInsCharSetChar(fv->b.sf->glyphs[i]->unicodeenc);
     508           0 : }
     509             : 
     510           0 : static void FVFlattenAllBitmapSelections(FontView *fv) {
     511             :     BDFFont *bdf;
     512             :     int i;
     513             : 
     514           0 :     for ( bdf = fv->b.sf->bitmaps; bdf!=NULL; bdf=bdf->next ) {
     515           0 :         for ( i=0; i<bdf->glyphcnt; ++i )
     516           0 :             if ( bdf->glyphs[i]!=NULL && bdf->glyphs[i]->selection!=NULL )
     517           0 :                 BCFlattenFloat(bdf->glyphs[i]);
     518             :     }
     519           0 : }
     520             : 
     521           0 : static int AskChanged(SplineFont *sf) {
     522             :     int ret;
     523             :     char *buts[4];
     524             :     char *filename, *fontname;
     525             : 
     526           0 :     if ( sf->cidmaster!=NULL )
     527           0 :         sf = sf->cidmaster;
     528             : 
     529           0 :     filename = sf->filename;
     530           0 :     fontname = sf->fontname;
     531             : 
     532           0 :     if ( filename==NULL && sf->origname!=NULL &&
     533           0 :             sf->onlybitmaps && sf->bitmaps!=NULL && sf->bitmaps->next==NULL )
     534           0 :         filename = sf->origname;
     535           0 :     if ( filename==NULL ) filename = "untitled.sfd";
     536           0 :     filename = GFileNameTail(filename);
     537           0 :     buts[0] = _("_Save");
     538           0 :     buts[1] = _("_Don't Save");
     539           0 :     buts[2] = _("_Cancel");
     540           0 :     buts[3] = NULL;
     541           0 :     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           0 : return( ret );
     543             : }
     544             : 
     545           0 : int _FVMenuGenerate(FontView *fv,int family) {
     546           0 :     FVFlattenAllBitmapSelections(fv);
     547           0 : return( SFGenerateFont(fv->b.sf,fv->b.active_layer,family,fv->b.normal==NULL?fv->b.map:fv->b.normal) );
     548             : }
     549             : 
     550           0 : static void FVMenuGenerate(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
     551           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
     552             : 
     553           0 :     _FVMenuGenerate(fv,gf_none);
     554           0 : }
     555             : 
     556           0 : static void FVMenuGenerateFamily(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
     557           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
     558             : 
     559           0 :     _FVMenuGenerate(fv,gf_macfamily);
     560           0 : }
     561             : 
     562           0 : static void FVMenuGenerateTTC(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
     563           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
     564             : 
     565           0 :     _FVMenuGenerate(fv,gf_ttc);
     566           0 : }
     567             : 
     568             : extern int save_to_dir;
     569             : 
     570           0 : static int SaveAs_FormatChange(GGadget *g, GEvent *e) {
     571           0 :     if ( e->type==et_controlevent && e->u.control.subtype == et_radiochanged ) {
     572           0 :         GGadget *fc = GWidgetGetControl(GGadgetGetWindow(g),1000);
     573           0 :         char *oldname = GGadgetGetTitle8(fc);
     574           0 :         int *_s2d = GGadgetGetUserData(g);
     575           0 :         int s2d = GGadgetIsChecked(g);
     576           0 :         char *pt, *newname = malloc(strlen(oldname)+8);
     577           0 :         strcpy(newname,oldname);
     578           0 :         pt = strrchr(newname,'.');
     579           0 :         if ( pt==NULL )
     580           0 :             pt = newname+strlen(newname);
     581           0 :         strcpy(pt,s2d ? ".sfdir" : ".sfd" );
     582           0 :         GGadgetSetTitle8(fc,newname);
     583           0 :         save_to_dir = *_s2d = s2d;
     584           0 :         SavePrefs(true);
     585             :     }
     586           0 : return( true );
     587             : }
     588             : 
     589             : 
     590           0 : static enum fchooserret _FVSaveAsFilterFunc(GGadget *g,struct gdirentry *ent, const unichar_t *dir)
     591             : {
     592           0 :     char* n = u_to_c(ent->name);
     593           0 :     int ew = endswithi( n, "sfd" ) || endswithi( n, "sfdir" );
     594           0 :     if( ew )
     595           0 :         return fc_show;
     596           0 :     if( ent->isdir )
     597           0 :         return fc_show;
     598           0 :     return fc_hide;
     599             : }
     600             : 
     601             : 
     602           0 : int _FVMenuSaveAs(FontView *fv) {
     603             :     char *temp;
     604             :     char *ret;
     605             :     char *filename;
     606             :     int ok;
     607           0 :     int s2d = fv->b.cidmaster!=NULL ? fv->b.cidmaster->save_to_dir :
     608           0 :                 fv->b.sf->mm!=NULL ? fv->b.sf->mm->normal->save_to_dir :
     609           0 :                 fv->b.sf->save_to_dir;
     610             :     GGadgetCreateData gcd;
     611             :     GTextInfo label;
     612             : 
     613           0 :     if ( fv->b.cidmaster!=NULL && fv->b.cidmaster->filename!=NULL )
     614           0 :         temp=def2utf8_copy(fv->b.cidmaster->filename);
     615           0 :     else if ( fv->b.sf->mm!=NULL && fv->b.sf->mm->normal->filename!=NULL )
     616           0 :         temp=def2utf8_copy(fv->b.sf->mm->normal->filename);
     617           0 :     else if ( fv->b.sf->filename!=NULL )
     618           0 :         temp=def2utf8_copy(fv->b.sf->filename);
     619             :     else {
     620           0 :         SplineFont *sf = fv->b.cidmaster?fv->b.cidmaster:
     621           0 :                 fv->b.sf->mm!=NULL?fv->b.sf->mm->normal:fv->b.sf;
     622           0 :         char *fn = sf->defbasefilename ? sf->defbasefilename : sf->fontname;
     623           0 :         temp = malloc((strlen(fn)+10));
     624           0 :         strcpy(temp,fn);
     625           0 :         if ( sf->defbasefilename!=NULL )
     626             :             /* Don't add a default suffix, they've already told us what name to use */;
     627           0 :         else if ( fv->b.cidmaster!=NULL )
     628           0 :             strcat(temp,"CID");
     629           0 :         else if ( sf->mm==NULL )
     630             :             ;
     631           0 :         else if ( sf->mm->apple )
     632           0 :             strcat(temp,"Var");
     633             :         else
     634           0 :             strcat(temp,"MM");
     635           0 :         strcat(temp,save_to_dir ? ".sfdir" : ".sfd");
     636           0 :         s2d = save_to_dir;
     637             :     }
     638             : 
     639           0 :     memset(&gcd,0,sizeof(gcd));
     640           0 :     memset(&label,0,sizeof(label));
     641           0 :     gcd.gd.flags = s2d ? (gg_visible | gg_enabled | gg_cb_on) : (gg_visible | gg_enabled);
     642           0 :     label.text = (unichar_t *) _("Save as _Directory");
     643           0 :     label.text_is_1byte = true;
     644           0 :     label.text_in_resource = true;
     645           0 :     gcd.gd.label = &label;
     646           0 :     gcd.gd.handle_controlevent = SaveAs_FormatChange;
     647           0 :     gcd.data = &s2d;
     648           0 :     gcd.creator = GCheckBoxCreate;
     649             : 
     650           0 :     GFileChooserInputFilenameFuncType FilenameFunc = GFileChooserDefInputFilenameFunc;
     651             : 
     652             : #if defined(__MINGW32__)
     653             :     //
     654             :     // If they are "saving as" but there is no path, lets help
     655             :     // the poor user by starting someplace sane rather than in `pwd`
     656             :     //
     657             :     if( !GFileIsAbsolute(temp) )
     658             :     {
     659             :         char* defaultSaveDir = GFileGetHomeDocumentsDir();
     660             :         printf("save-as:%s\n", temp );
     661             :         char* temp2 = GFileAppendFile( defaultSaveDir, temp, 0 );
     662             :         free(temp);
     663             :         temp = temp2;
     664             :     }
     665             : #endif
     666             : 
     667           0 :     ret = GWidgetSaveAsFileWithGadget8(_("Save as..."),temp,0,NULL,
     668             :                                        _FVSaveAsFilterFunc, FilenameFunc,
     669             :                                        &gcd );
     670           0 :     free(temp);
     671           0 :     if ( ret==NULL )
     672           0 : return( 0 );
     673           0 :     filename = utf82def_copy(ret);
     674           0 :     free(ret);
     675             : 
     676           0 :     if(!(endswithi( filename, ".sfdir") || endswithi( filename, ".sfd")))
     677             :     {
     678             :         // they forgot the extension, so we force the default of .sfd
     679             :         // and alert them to the fact that we have done this and we
     680             :         // are not saving to a OTF, TTF, UFO formatted file
     681             : 
     682           0 :         char* extension = ".sfd";
     683           0 :         char* newpath = copyn( filename, strlen(filename) + strlen(".sfd") + 1 );
     684           0 :         strcat( newpath, ".sfd" );
     685             : 
     686           0 :         char* oldfn = GFileNameTail( filename );
     687           0 :         char* newfn = GFileNameTail( newpath );
     688             :         
     689           0 :         LogError( _("You tried to save with the filename %s but it was saved as %s. "),
     690             :                   oldfn, newfn );
     691           0 :         LogError( _("Please choose File/Generate Fonts to save to other formats."));
     692             : 
     693           0 :         free(filename);
     694           0 :         filename = newpath;
     695             :     }
     696             :     
     697           0 :     FVFlattenAllBitmapSelections(fv);
     698           0 :     fv->b.sf->compression = 0;
     699           0 :     ok = SFDWrite(filename,fv->b.sf,fv->b.map,fv->b.normal,s2d);
     700           0 :     if ( ok ) {
     701           0 :         SplineFont *sf = fv->b.cidmaster?fv->b.cidmaster:fv->b.sf->mm!=NULL?fv->b.sf->mm->normal:fv->b.sf;
     702           0 :         free(sf->filename);
     703           0 :         sf->filename = filename;
     704           0 :         sf->save_to_dir = s2d;
     705           0 :         free(sf->origname);
     706           0 :         sf->origname = copy(filename);
     707           0 :         sf->new = false;
     708           0 :         if ( sf->mm!=NULL ) {
     709             :             int i;
     710           0 :             for ( i=0; i<sf->mm->instance_count; ++i ) {
     711           0 :                 free(sf->mm->instances[i]->filename);
     712           0 :                 sf->mm->instances[i]->filename = filename;
     713           0 :                 free(sf->mm->instances[i]->origname);
     714           0 :                 sf->mm->instances[i]->origname = copy(filename);
     715           0 :                 sf->mm->instances[i]->new = false;
     716             :             }
     717             :         }
     718           0 :         SplineFontSetUnChanged(sf);
     719           0 :         FVSetTitles(fv->b.sf);
     720             :     } else
     721           0 :         free(filename);
     722           0 : return( ok );
     723             : }
     724             : 
     725           0 : static void FVMenuSaveAs(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
     726           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
     727             : 
     728           0 :     _FVMenuSaveAs(fv);
     729           0 : }
     730             : 
     731           0 : static int IsBackupName(char *filename) {
     732             : 
     733           0 :     if ( filename==NULL )
     734           0 : return( false );
     735           0 : return( filename[strlen(filename)-1]=='~' );
     736             : }
     737             : 
     738           0 : int _FVMenuSave(FontView *fv) {
     739           0 :     int ret = 0;
     740           0 :     SplineFont *sf = fv->b.cidmaster?fv->b.cidmaster:
     741           0 :                     fv->b.sf->mm!=NULL?fv->b.sf->mm->normal:
     742             :                             fv->b.sf;
     743             : 
     744           0 :     if ( sf->filename==NULL || IsBackupName(sf->filename))
     745           0 :         ret = _FVMenuSaveAs(fv);
     746             :     else {
     747           0 :         FVFlattenAllBitmapSelections(fv);
     748           0 :         if ( !SFDWriteBak(sf->filename,sf,fv->b.map,fv->b.normal) )
     749           0 :             ff_post_error(_("Save Failed"),_("Save Failed"));
     750             :         else {
     751           0 :             SplineFontSetUnChanged(sf);
     752           0 :             ret = true;
     753             :         }
     754             :     }
     755           0 : return( ret );
     756             : }
     757             : 
     758           0 : static void FVMenuSave(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
     759           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
     760           0 :     _FVMenuSave(fv);
     761           0 : }
     762             : 
     763           0 : void _FVCloseWindows(FontView *fv) {
     764             :     int i, j;
     765             :     BDFFont *bdf;
     766             :     MetricsView *mv, *mnext;
     767           0 :     SplineFont *sf = fv->b.cidmaster?fv->b.cidmaster:fv->b.sf->mm!=NULL?fv->b.sf->mm->normal : fv->b.sf;
     768             : 
     769           0 :     PrintWindowClose();
     770           0 :     if ( fv->b.nextsame==NULL && fv->b.sf->fv==&fv->b && fv->b.sf->kcld!=NULL )
     771           0 :         KCLD_End(fv->b.sf->kcld);
     772           0 :     if ( fv->b.nextsame==NULL && fv->b.sf->fv==&fv->b && fv->b.sf->vkcld!=NULL )
     773           0 :         KCLD_End(fv->b.sf->vkcld);
     774             : 
     775           0 :     for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL ) {
     776             :         CharView *cv, *next;
     777           0 :         for ( cv = (CharView *) (sf->glyphs[i]->views); cv!=NULL; cv = next ) {
     778           0 :             next = (CharView *) (cv->b.next);
     779           0 :             GDrawDestroyWindow(cv->gw);
     780             :         }
     781           0 :         if ( sf->glyphs[i]->charinfo )
     782           0 :             CharInfoDestroy(sf->glyphs[i]->charinfo);
     783             :     }
     784           0 :     if ( sf->mm!=NULL ) {
     785           0 :         MMSet *mm = sf->mm;
     786           0 :         for ( j=0; j<mm->instance_count; ++j ) {
     787           0 :             SplineFont *sf = mm->instances[j];
     788           0 :             for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL ) {
     789             :                 CharView *cv, *next;
     790           0 :                 for ( cv = (CharView *) (sf->glyphs[i]->views); cv!=NULL; cv = next ) {
     791           0 :                     next = (CharView *) (cv->b.next);
     792           0 :                     GDrawDestroyWindow(cv->gw);
     793             :                 }
     794           0 :                 if ( sf->glyphs[i]->charinfo )
     795           0 :                     CharInfoDestroy(sf->glyphs[i]->charinfo);
     796             :             }
     797           0 :             for ( mv=sf->metrics; mv!=NULL; mv = mnext ) {
     798           0 :                 mnext = mv->next;
     799           0 :                 GDrawDestroyWindow(mv->gw);
     800             :             }
     801             :         }
     802           0 :     } else if ( sf->subfontcnt!=0 ) {
     803           0 :         for ( j=0; j<sf->subfontcnt; ++j ) {
     804           0 :             for ( i=0; i<sf->subfonts[j]->glyphcnt; ++i ) if ( sf->subfonts[j]->glyphs[i]!=NULL ) {
     805             :                 CharView *cv, *next;
     806           0 :                 for ( cv = (CharView *) (sf->subfonts[j]->glyphs[i]->views); cv!=NULL; cv = next ) {
     807           0 :                     next = (CharView *) (cv->b.next);
     808           0 :                     GDrawDestroyWindow(cv->gw);
     809           0 :                 if ( sf->subfonts[j]->glyphs[i]->charinfo )
     810           0 :                     CharInfoDestroy(sf->subfonts[j]->glyphs[i]->charinfo);
     811             :                 }
     812             :             }
     813           0 :             for ( mv=sf->subfonts[j]->metrics; mv!=NULL; mv = mnext ) {
     814           0 :                 mnext = mv->next;
     815           0 :                 GDrawDestroyWindow(mv->gw);
     816             :             }
     817             :         }
     818             :     } else {
     819           0 :         for ( mv=sf->metrics; mv!=NULL; mv = mnext ) {
     820           0 :             mnext = mv->next;
     821           0 :             GDrawDestroyWindow(mv->gw);
     822             :         }
     823             :     }
     824           0 :     for ( bdf = sf->bitmaps; bdf!=NULL; bdf=bdf->next ) {
     825           0 :         for ( i=0; i<bdf->glyphcnt; ++i ) if ( bdf->glyphs[i]!=NULL ) {
     826             :             BitmapView *bv, *next;
     827           0 :             for ( bv = bdf->glyphs[i]->views; bv!=NULL; bv = next ) {
     828           0 :                 next = bv->next;
     829           0 :                 GDrawDestroyWindow(bv->gw);
     830             :             }
     831             :         }
     832             :     }
     833           0 :     if ( fv->b.sf->fontinfo!=NULL )
     834           0 :         FontInfoDestroy(fv->b.sf);
     835           0 :     if ( fv->b.sf->valwin!=NULL )
     836           0 :         ValidationDestroy(fv->b.sf);
     837           0 :     SVDetachFV(fv);
     838           0 : }
     839             : 
     840           0 : static int SFAnyChanged(SplineFont *sf) {
     841           0 :     if ( sf->mm!=NULL ) {
     842           0 :         MMSet *mm = sf->mm;
     843             :         int i;
     844           0 :         if ( mm->changed )
     845           0 : return( true );
     846           0 :         for ( i=0; i<mm->instance_count; ++i )
     847           0 :             if ( sf->mm->instances[i]->changed )
     848           0 : return( true );
     849             :         /* Changes to the blended font aren't real (for adobe fonts) */
     850           0 :         if ( mm->apple && mm->normal->changed )
     851           0 : return( true );
     852             : 
     853           0 : return( false );
     854             :     } else
     855           0 : return( sf->changed );
     856             : }
     857             : 
     858           0 : static int _FVMenuClose(FontView *fv) {
     859             :     int i;
     860           0 :     SplineFont *sf = fv->b.cidmaster?fv->b.cidmaster:fv->b.sf;
     861             : 
     862           0 :     if ( !SFCloseAllInstrs(fv->b.sf) )
     863           0 : return( false );
     864             : 
     865           0 :     if ( fv->b.nextsame!=NULL || fv->b.sf->fv!=&fv->b ) {
     866             :         /* There's another view, can close this one with no problems */
     867           0 :     } else if ( SFAnyChanged(sf) ) {
     868           0 :         i = AskChanged(fv->b.sf);
     869           0 :         if ( i==2 )     /* Cancel */
     870           0 : return( false );
     871           0 :         if ( i==0 && !_FVMenuSave(fv))          /* Save */
     872           0 : return(false);
     873             :         else
     874           0 :             SFClearAutoSave(sf);                /* if they didn't save it, remove change record */
     875             :     }
     876           0 :     _FVCloseWindows(fv);
     877           0 :     if ( sf->filename!=NULL )
     878           0 :         RecentFilesRemember(sf->filename);
     879           0 :     else if ( sf->origname!=NULL )
     880           0 :         RecentFilesRemember(sf->origname);
     881           0 :     GDrawDestroyWindow(fv->gw);
     882           0 : return( true );
     883             : }
     884             : 
     885           0 : void MenuNew(GWindow UNUSED(gw), struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
     886           0 :     FontNew();
     887           0 : }
     888             : 
     889           0 : static void FVMenuClose(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
     890           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
     891             : 
     892           0 :     if ( fv->b.container )
     893           0 :         (fv->b.container->funcs->doClose)(fv->b.container);
     894             :     else
     895           0 :         _FVMenuClose(fv);
     896           0 : }
     897             : 
     898           0 : static void FV_ReattachCVs(SplineFont *old,SplineFont *new) {
     899             :     int i, j, pos;
     900             :     CharView *cv, *cvnext;
     901             :     SplineFont *sub;
     902             : 
     903           0 :     for ( i=0; i<old->glyphcnt; ++i ) {
     904           0 :         if ( old->glyphs[i]!=NULL && old->glyphs[i]->views!=NULL ) {
     905           0 :             if ( new->subfontcnt==0 ) {
     906           0 :                 pos = SFFindExistingSlot(new,old->glyphs[i]->unicodeenc,old->glyphs[i]->name);
     907           0 :                 sub = new;
     908             :             } else {
     909           0 :                 pos = -1;
     910           0 :                 for ( j=0; j<new->subfontcnt && pos==-1 ; ++j ) {
     911           0 :                     sub = new->subfonts[j];
     912           0 :                     pos = SFFindExistingSlot(sub,old->glyphs[i]->unicodeenc,old->glyphs[i]->name);
     913             :                 }
     914             :             }
     915           0 :             if ( pos==-1 ) {
     916           0 :                 for ( cv=(CharView *) (old->glyphs[i]->views); cv!=NULL; cv = cvnext ) {
     917           0 :                     cvnext = (CharView *) (cv->b.next);
     918           0 :                     GDrawDestroyWindow(cv->gw);
     919             :                 }
     920             :             } else {
     921           0 :                 for ( cv=(CharView *) (old->glyphs[i]->views); cv!=NULL; cv = cvnext ) {
     922           0 :                     cvnext = (CharView *) (cv->b.next);
     923           0 :                     CVChangeSC(cv,sub->glyphs[pos]);
     924           0 :                     cv->b.layerheads[dm_grid] = &new->grid;
     925             :                 }
     926             :             }
     927           0 :             GDrawProcessPendingEvents(NULL);            /* Don't want to many destroy_notify events clogging up the queue */
     928             :         }
     929             :     }
     930           0 : }
     931             : 
     932           0 : static void FVMenuRevert(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
     933           0 :     FontViewBase *fv = (FontViewBase *) GDrawGetUserData(gw);
     934           0 :     FVRevert(fv);
     935           0 : }
     936             : 
     937           0 : static void FVMenuRevertBackup(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
     938           0 :     FontViewBase *fv = (FontViewBase *) GDrawGetUserData(gw);
     939           0 :     FVRevertBackup(fv);
     940           0 : }
     941             : 
     942           0 : static void FVMenuRevertGlyph(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
     943           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
     944           0 :     FVRevertGlyph((FontViewBase *) fv);
     945           0 : }
     946             : 
     947           0 : static void FVMenuClearSpecialData(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
     948           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
     949           0 :     FVClearSpecialData((FontViewBase *) fv);
     950           0 : }
     951             : 
     952           0 : void MenuPrefs(GWindow UNUSED(base), struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
     953           0 :     DoPrefs();
     954           0 : }
     955             : 
     956           0 : void MenuXRes(GWindow UNUSED(base), struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
     957           0 :     DoXRes();
     958           0 : }
     959             : 
     960           0 : void MenuSaveAll(GWindow UNUSED(base), struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
     961             :     FontView *fv;
     962             : 
     963           0 :     for ( fv = fv_list; fv!=NULL; fv = (FontView *) (fv->b.next) ) {
     964           0 :         if ( SFAnyChanged(fv->b.sf) && !_FVMenuSave(fv))
     965           0 : return;
     966             :     }
     967             : }
     968             : 
     969           0 : static void _MenuExit(void *UNUSED(junk)) {
     970             : 
     971             :     FontView *fv, *next;
     972             : 
     973           0 :     if( collabclient_haveLocalServer() )
     974             :     {
     975           0 :         AskAndMaybeCloseLocalCollabServers();
     976             :     }
     977             : #ifndef _NO_PYTHON
     978           0 :     python_call_onClosingFunctions();
     979             : #endif
     980             : 
     981           0 :     LastFonts_Save();
     982           0 :     for ( fv = fv_list; fv!=NULL; fv = next )
     983             :     {
     984           0 :         next = (FontView *) (fv->b.next);
     985           0 :         if ( !_FVMenuClose(fv))
     986           0 :             return;
     987           0 :         if ( fv->b.nextsame!=NULL || fv->b.sf->fv!=&fv->b )
     988             :         {
     989           0 :             GDrawSync(NULL);
     990           0 :             GDrawProcessPendingEvents(NULL);
     991             :         }
     992             :     }
     993           0 :     GDrawSync(NULL);
     994           0 :     GDrawProcessPendingEvents(NULL);
     995           0 :     exit(0);
     996             : }
     997             : 
     998           0 : static void FVMenuExit(GWindow UNUSED(base), struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
     999           0 :     _MenuExit(NULL);
    1000           0 : }
    1001             : 
    1002           0 : void MenuExit(GWindow UNUSED(base), struct gmenuitem *UNUSED(mi), GEvent *e) {
    1003           0 :     if ( e==NULL )      /* Not from the menu directly, but a shortcut */
    1004           0 :         _MenuExit(NULL);
    1005             :     else
    1006           0 :         DelayEvent(_MenuExit,NULL);
    1007           0 : }
    1008             : 
    1009           0 : char *GetPostScriptFontName(char *dir, int mult) {
    1010             :     unichar_t *ret;
    1011             :     char *u_dir;
    1012             :     char *temp;
    1013             : 
    1014           0 :     u_dir = def2utf8_copy(dir);
    1015           0 :     ret = FVOpenFont(_("Open Font"), u_dir,mult);
    1016           0 :     temp = u2def_copy(ret);
    1017             : 
    1018           0 :     free(ret);
    1019           0 : return( temp );
    1020             : }
    1021             : 
    1022           0 : void MergeKernInfo(SplineFont *sf,EncMap *map) {
    1023             : #ifndef __Mac
    1024             :     static char wild[] = "*.{afm,tfm,ofm,pfm,bin,hqx,dfont,feature,feat,fea}";
    1025             :     static char wild2[] = "*.{afm,amfm,tfm,ofm,pfm,bin,hqx,dfont,feature,feat,fea}";
    1026             : #else
    1027             :     static char wild[] = "*"; /* Mac resource files generally don't have extensions */
    1028             :     static char wild2[] = "*";
    1029             : #endif
    1030           0 :     char *ret = gwwv_open_filename(_("Merge Feature Info"),NULL,
    1031             :             sf->mm!=NULL?wild2:wild,NULL);
    1032             :     char *temp;
    1033             : 
    1034           0 :     if ( ret==NULL )
    1035           0 : return;                         /* Cancelled */
    1036           0 :     temp = utf82def_copy(ret);
    1037             : 
    1038           0 :     if ( !LoadKerningDataFromMetricsFile(sf,temp,map))
    1039           0 :         ff_post_error(_("Load of Kerning Metrics Failed"),_("Failed to load kern data from %s"), temp);
    1040           0 :     free(ret); free(temp);
    1041             : }
    1042             : 
    1043           0 : static void FVMenuMergeKern(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    1044           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    1045           0 :     MergeKernInfo(fv->b.sf,fv->b.map);
    1046           0 : }
    1047             : 
    1048           0 : void _FVMenuOpen(FontView *fv) {
    1049             :     char *temp;
    1050             :     char *eod, *fpt, *file, *full;
    1051             :     FontView *test; int fvcnt, fvtest;
    1052             : 
    1053           0 :     char* OpenDir = NULL, *DefaultDir = NULL, *NewDir = NULL;
    1054             : #if defined(__MINGW32__)
    1055             :     DefaultDir = copy(GFileGetHomeDocumentsDir()); //Default value
    1056             :     if (fv && fv->b.sf && fv->b.sf->filename) {
    1057             :         free(DefaultDir);
    1058             :         DefaultDir = GFileDirNameEx(fv->b.sf->filename, true);
    1059             :     }
    1060             : #endif
    1061             : 
    1062           0 :     for ( fvcnt=0, test=fv_list; test!=NULL; ++fvcnt, test=(FontView *) (test->b.next) );
    1063             :     do {
    1064           0 :         if (NewDir != NULL) {
    1065           0 :             if (OpenDir != DefaultDir) {
    1066           0 :                 free(OpenDir);
    1067             :             }
    1068             :             
    1069           0 :             OpenDir = NewDir;
    1070           0 :             NewDir = NULL;
    1071           0 :         } else if (OpenDir != DefaultDir) {
    1072           0 :             free(OpenDir);
    1073           0 :             OpenDir = DefaultDir;
    1074             :         }
    1075             :         
    1076           0 :         temp = GetPostScriptFontName(OpenDir,true);
    1077           0 :         if ( temp==NULL )
    1078           0 :             return;
    1079             : 
    1080             :         //Make a copy of the folder; may be needed later if opening fails.
    1081           0 :         NewDir = GFileDirName(temp);
    1082           0 :         if (!GFileExists(NewDir)) {
    1083           0 :             free(NewDir);
    1084           0 :             NewDir = NULL;
    1085             :         }
    1086             : 
    1087           0 :         eod = strrchr(temp,'/');
    1088           0 :         if (eod != NULL) {
    1089           0 :             *eod = '\0';
    1090           0 :             file = eod+1;
    1091             :             
    1092           0 :             if (*file) {
    1093             :                 do {
    1094           0 :                     fpt = strstr(file,"; ");
    1095           0 :                     if ( fpt!=NULL ) *fpt = '\0';
    1096           0 :                     full = malloc(strlen(temp)+1+strlen(file)+1);
    1097           0 :                     strcpy(full,temp); strcat(full,"/"); strcat(full,file);
    1098           0 :                     ViewPostScriptFont(full,0);
    1099           0 :                     file = fpt+2;
    1100           0 :                     free(full);
    1101           0 :                 } while ( fpt!=NULL );
    1102             :             }
    1103             :         }
    1104           0 :         free(temp);
    1105           0 :         for ( fvtest=0, test=fv_list; test!=NULL; ++fvtest, test=(FontView *) (test->b.next) );
    1106           0 :     } while ( fvtest==fvcnt );  /* did the load fail for some reason? try again */
    1107             :     
    1108           0 :     free( NewDir );
    1109           0 :     free( OpenDir );
    1110           0 :     if (OpenDir != DefaultDir) {
    1111           0 :         free( DefaultDir );
    1112             :     }
    1113             : }
    1114             : 
    1115           0 : static void FVMenuOpen(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    1116           0 :     FontView *fv = (FontView*) GDrawGetUserData(gw);
    1117           0 :     _FVMenuOpen(fv);
    1118           0 : }
    1119             : 
    1120           0 : static void FVMenuContextualHelp(GWindow UNUSED(base), struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    1121           0 :     help("fontview.html");
    1122           0 : }
    1123             : 
    1124           0 : void MenuHelp(GWindow UNUSED(base), struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    1125           0 :     help("overview.html");
    1126           0 : }
    1127             : 
    1128           0 : void MenuIndex(GWindow UNUSED(base), struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    1129           0 :     help("IndexFS.html");
    1130           0 : }
    1131             : 
    1132           0 : void MenuLicense(GWindow UNUSED(base), struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    1133           0 :     help("license.html");
    1134           0 : }
    1135             : 
    1136           0 : void MenuAbout(GWindow UNUSED(base), struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    1137           0 :     ShowAboutScreen();
    1138           0 : }
    1139             : 
    1140           0 : static void FVMenuImport(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    1141           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    1142           0 :     int empty = fv->b.sf->onlybitmaps && fv->b.sf->bitmaps==NULL;
    1143             :     BDFFont *bdf;
    1144           0 :     FVImport(fv);
    1145           0 :     if ( empty && fv->b.sf->bitmaps!=NULL ) {
    1146           0 :         for ( bdf= fv->b.sf->bitmaps; bdf->next!=NULL; bdf = bdf->next );
    1147           0 :         FVChangeDisplayBitmap((FontViewBase *) fv,bdf);
    1148             :     }
    1149           0 : }
    1150             : 
    1151           0 : static int FVSelCount(FontView *fv) {
    1152           0 :     int i, cnt=0;
    1153             : 
    1154           0 :     for ( i=0; i<fv->b.map->enccount; ++i )
    1155           0 :         if ( fv->b.selected[i] ) ++cnt;
    1156           0 :     if ( cnt>10 ) {
    1157             :         char *buts[3];
    1158           0 :         buts[0] = _("_OK");
    1159           0 :         buts[1] = _("_Cancel");
    1160           0 :         buts[2] = NULL;
    1161           0 :         if ( gwwv_ask(_("Many Windows"),(const char **) buts,0,1,_("This involves opening more than 10 windows.\nIs that really what you want?"))==1 )
    1162           0 : return( false );
    1163             :     }
    1164           0 : return( true );
    1165             : }
    1166             : 
    1167           0 : static void FVMenuOpenOutline(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    1168           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    1169             :     int i;
    1170             :     SplineChar *sc;
    1171             : 
    1172           0 :     if ( !FVSelCount(fv))
    1173           0 : return;
    1174           0 :     if ( fv->b.container!=NULL && fv->b.container->funcs->is_modal )
    1175           0 : return;
    1176             : 
    1177           0 :     for ( i=0; i<fv->b.map->enccount; ++i )
    1178           0 :         if ( fv->b.selected[i] ) {
    1179           0 :             sc = FVMakeChar(fv,i);
    1180           0 :             CharViewCreate(sc,fv,i);
    1181             :         }
    1182             : }
    1183             : 
    1184           0 : static void FVMenuOpenBitmap(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    1185           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    1186             :     int i;
    1187             :     SplineChar *sc;
    1188             : 
    1189           0 :     if ( fv->b.cidmaster==NULL ? (fv->b.sf->bitmaps==NULL) : (fv->b.cidmaster->bitmaps==NULL) )
    1190           0 : return;
    1191           0 :     if ( fv->b.container!=NULL && fv->b.container->funcs->is_modal )
    1192           0 : return;
    1193           0 :     if ( !FVSelCount(fv))
    1194           0 : return;
    1195           0 :     for ( i=0; i<fv->b.map->enccount; ++i )
    1196           0 :         if ( fv->b.selected[i] ) {
    1197           0 :             sc = FVMakeChar(fv,i);
    1198           0 :             if ( sc!=NULL )
    1199           0 :                 BitmapViewCreatePick(i,fv);
    1200             :         }
    1201             : }
    1202             : 
    1203           0 : void _MenuWarnings(GWindow UNUSED(gw), struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    1204           0 :     ShowErrorWindow();
    1205           0 : }
    1206             : 
    1207           0 : static void FVMenuOpenMetrics(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    1208           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    1209           0 :     if ( fv->b.container!=NULL && fv->b.container->funcs->is_modal )
    1210           0 : return;
    1211           0 :     MetricsViewCreate(fv,NULL,fv->filled==fv->show?NULL:fv->show);
    1212             : }
    1213             : 
    1214           0 : static void FVMenuPrint(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    1215           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    1216             : 
    1217           0 :     if ( fv->b.container!=NULL && fv->b.container->funcs->is_modal )
    1218           0 : return;
    1219           0 :     PrintFFDlg(fv,NULL,NULL);
    1220             : }
    1221             : 
    1222             : #if !defined(_NO_FFSCRIPT) || !defined(_NO_PYTHON)
    1223           0 : static void FVMenuExecute(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    1224           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    1225             : 
    1226           0 :     ScriptDlg(fv,NULL);
    1227           0 : }
    1228             : #endif
    1229             : 
    1230           0 : static void FVMenuFontInfo(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    1231           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    1232           0 :     if ( fv->b.container!=NULL && fv->b.container->funcs->is_modal )
    1233           0 : return;
    1234           0 :     FontMenuFontInfo(fv);
    1235             : }
    1236             : 
    1237           0 : static void FVMenuMATHInfo(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    1238           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    1239           0 :     SFMathDlg(fv->b.sf,fv->b.active_layer);
    1240           0 : }
    1241             : 
    1242           0 : static void FVMenuFindProblems(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    1243           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    1244           0 :     FindProblems(fv,NULL,NULL);
    1245           0 : }
    1246             : 
    1247           0 : static void FVMenuValidate(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    1248           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    1249           0 :     SFValidationWindow(fv->b.sf,fv->b.active_layer,ff_none);
    1250           0 : }
    1251             : 
    1252           0 : static void FVMenuSetExtremumBound(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    1253           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    1254             :     char buffer[40], *end, *ret;
    1255             :     int val;
    1256             : 
    1257           0 :     sprintf( buffer, "%d", fv->b.sf->extrema_bound<=0 ?
    1258           0 :             (int) rint((fv->b.sf->ascent+fv->b.sf->descent)/100.0) :
    1259           0 :             fv->b.sf->extrema_bound );
    1260           0 :     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."));
    1261           0 :     if ( ret==NULL )
    1262           0 : return;
    1263           0 :     val = (int) rint(strtod(ret,&end));
    1264           0 :     if ( *end!='\0' )
    1265           0 :         ff_post_error( _("Bad Number"),_("Bad Number") );
    1266             :     else {
    1267           0 :         fv->b.sf->extrema_bound = val;
    1268           0 :         if ( !fv->b.sf->changed ) {
    1269           0 :             fv->b.sf->changed = true;
    1270           0 :             FVSetTitles(fv->b.sf);
    1271             :         }
    1272             :     }
    1273           0 :     free(ret);
    1274             : }
    1275             : 
    1276           0 : static void FVMenuEmbolden(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    1277           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    1278           0 :     EmboldenDlg(fv,NULL);
    1279           0 : }
    1280             : 
    1281           0 : static void FVMenuItalic(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    1282           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    1283           0 :     ItalicDlg(fv,NULL);
    1284           0 : }
    1285             : 
    1286           0 : static void FVMenuSmallCaps(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    1287           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    1288           0 :     GlyphChangeDlg(fv,NULL,gc_smallcaps);
    1289           0 : }
    1290             : 
    1291           0 : static void FVMenuChangeXHeight(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    1292           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    1293           0 :     ChangeXHeightDlg(fv,NULL);
    1294           0 : }
    1295             : 
    1296           0 : static void FVMenuChangeGlyph(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    1297           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    1298           0 :     GlyphChangeDlg(fv,NULL,gc_generic);
    1299           0 : }
    1300             : 
    1301           0 : static void FVMenuSubSup(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    1302           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    1303           0 :     GlyphChangeDlg(fv,NULL,gc_subsuper);
    1304           0 : }
    1305             : 
    1306           0 : static void FVMenuOblique(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    1307           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    1308           0 :     ObliqueDlg(fv,NULL);
    1309           0 : }
    1310             : 
    1311           0 : static void FVMenuCondense(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    1312           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    1313           0 :     CondenseExtendDlg(fv,NULL);
    1314           0 : }
    1315             : 
    1316             : #define MID_24  2001
    1317             : #define MID_36  2002
    1318             : #define MID_48  2004
    1319             : #define MID_72  2014
    1320             : #define MID_96  2015
    1321             : #define MID_128 2018
    1322             : #define MID_AntiAlias   2005
    1323             : #define MID_Next        2006
    1324             : #define MID_Prev        2007
    1325             : #define MID_NextDef     2012
    1326             : #define MID_PrevDef     2013
    1327             : #define MID_ShowHMetrics 2016
    1328             : #define MID_ShowVMetrics 2017
    1329             : #define MID_Ligatures   2020
    1330             : #define MID_KernPairs   2021
    1331             : #define MID_AnchorPairs 2022
    1332             : #define MID_FitToBbox   2023
    1333             : #define MID_DisplaySubs 2024
    1334             : #define MID_32x8        2025
    1335             : #define MID_16x4        2026
    1336             : #define MID_8x2         2027
    1337             : #define MID_BitmapMag   2028
    1338             : #define MID_Layers      2029
    1339             : #define MID_FontInfo    2200
    1340             : #define MID_CharInfo    2201
    1341             : #define MID_Transform   2202
    1342             : #define MID_Stroke      2203
    1343             : #define MID_RmOverlap   2204
    1344             : #define MID_Simplify    2205
    1345             : #define MID_Correct     2206
    1346             : #define MID_BuildAccent 2208
    1347             : #define MID_AvailBitmaps        2210
    1348             : #define MID_RegenBitmaps        2211
    1349             : #define MID_Autotrace   2212
    1350             : #define MID_Round       2213
    1351             : #define MID_MergeFonts  2214
    1352             : #define MID_InterpolateFonts    2215
    1353             : #define MID_FindProblems 2216
    1354             : #define MID_Embolden    2217
    1355             : #define MID_Condense    2218
    1356             : #define MID_ShowDependentRefs   2222
    1357             : #define MID_AddExtrema  2224
    1358             : #define MID_CleanupGlyph        2225
    1359             : #define MID_TilePath    2226
    1360             : #define MID_BuildComposite      2227
    1361             : #define MID_NLTransform 2228
    1362             : #define MID_Intersection        2229
    1363             : #define MID_FindInter   2230
    1364             : #define MID_Styles      2231
    1365             : #define MID_SimplifyMore        2233
    1366             : #define MID_ShowDependentSubs   2234
    1367             : #define MID_DefaultATT  2235
    1368             : #define MID_POV         2236
    1369             : #define MID_BuildDuplicates     2237
    1370             : #define MID_StrikeInfo  2238
    1371             : #define MID_FontCompare 2239
    1372             : #define MID_CanonicalStart      2242
    1373             : #define MID_CanonicalContours   2243
    1374             : #define MID_RemoveBitmaps       2244
    1375             : #define MID_Validate            2245
    1376             : #define MID_MassRename          2246
    1377             : #define MID_Italic              2247
    1378             : #define MID_SmallCaps           2248
    1379             : #define MID_SubSup              2249
    1380             : #define MID_ChangeXHeight       2250
    1381             : #define MID_ChangeGlyph 2251
    1382             : #define MID_SetColor    2252
    1383             : #define MID_SetExtremumBound    2253
    1384             : #define MID_Center      2600
    1385             : #define MID_Thirds      2601
    1386             : #define MID_SetWidth    2602
    1387             : #define MID_SetLBearing 2603
    1388             : #define MID_SetRBearing 2604
    1389             : #define MID_SetVWidth   2605
    1390             : #define MID_RmHKern     2606
    1391             : #define MID_RmVKern     2607
    1392             : #define MID_VKernByClass        2608
    1393             : #define MID_VKernFromH  2609
    1394             : #define MID_SetBearings 2610
    1395             : #define MID_AutoHint    2501
    1396             : #define MID_ClearHints  2502
    1397             : #define MID_ClearWidthMD        2503
    1398             : #define MID_AutoInstr   2504
    1399             : #define MID_EditInstructions    2505
    1400             : #define MID_Editfpgm    2506
    1401             : #define MID_Editprep    2507
    1402             : #define MID_ClearInstrs 2508
    1403             : #define MID_HStemHist   2509
    1404             : #define MID_VStemHist   2510
    1405             : #define MID_BlueValuesHist      2511
    1406             : #define MID_Editcvt     2512
    1407             : #define MID_HintSubsPt  2513
    1408             : #define MID_AutoCounter 2514
    1409             : #define MID_DontAutoHint        2515
    1410             : #define MID_RmInstrTables       2516
    1411             : #define MID_Editmaxp    2517
    1412             : #define MID_Deltas      2518
    1413             : #define MID_OpenBitmap  2700
    1414             : #define MID_OpenOutline 2701
    1415             : #define MID_Revert      2702
    1416             : #define MID_Recent      2703
    1417             : #define MID_Print       2704
    1418             : #define MID_ScriptMenu  2705
    1419             : #define MID_RevertGlyph 2707
    1420             : #define MID_RevertToBackup 2708
    1421             : #define MID_GenerateTTC 2709
    1422             : #define MID_OpenMetrics 2710
    1423             : #define MID_ClearSpecialData 2711
    1424             : #define MID_Cut         2101
    1425             : #define MID_Copy        2102
    1426             : #define MID_Paste       2103
    1427             : #define MID_Clear       2104
    1428             : #define MID_SelAll      2106
    1429             : #define MID_CopyRef     2107
    1430             : #define MID_UnlinkRef   2108
    1431             : #define MID_Undo        2109
    1432             : #define MID_Redo        2110
    1433             : #define MID_CopyWidth   2111
    1434             : #define MID_UndoFontLevel       2112
    1435             : #define MID_AllFonts            2122
    1436             : #define MID_DisplayedFont       2123
    1437             : #define MID_CharName            2124
    1438             : #define MID_RemoveUndoes        2114
    1439             : #define MID_CopyFgToBg  2115
    1440             : #define MID_ClearBackground     2116
    1441             : #define MID_CopyLBearing        2125
    1442             : #define MID_CopyRBearing        2126
    1443             : #define MID_CopyVWidth  2127
    1444             : #define MID_Join        2128
    1445             : #define MID_PasteInto   2129
    1446             : #define MID_SameGlyphAs 2130
    1447             : #define MID_RplRef      2131
    1448             : #define MID_PasteAfter  2132
    1449             : #define MID_TTFInstr    2134
    1450             : #define MID_CopyLookupData      2135
    1451             : #define MID_CopyL2L     2136
    1452             : #define MID_CorrectRefs 2137
    1453             : #define MID_Convert2CID 2800
    1454             : #define MID_Flatten     2801
    1455             : #define MID_InsertFont  2802
    1456             : #define MID_InsertBlank 2803
    1457             : #define MID_CIDFontInfo 2804
    1458             : #define MID_RemoveFromCID 2805
    1459             : #define MID_ConvertByCMap       2806
    1460             : #define MID_FlattenByCMap       2807
    1461             : #define MID_ChangeSupplement    2808
    1462             : #define MID_Reencode            2830
    1463             : #define MID_ForceReencode       2831
    1464             : #define MID_AddUnencoded        2832
    1465             : #define MID_RemoveUnused        2833
    1466             : #define MID_DetachGlyphs        2834
    1467             : #define MID_DetachAndRemoveGlyphs       2835
    1468             : #define MID_LoadEncoding        2836
    1469             : #define MID_MakeFromFont        2837
    1470             : #define MID_RemoveEncoding      2838
    1471             : #define MID_DisplayByGroups     2839
    1472             : #define MID_Compact     2840
    1473             : #define MID_SaveNamelist        2841
    1474             : #define MID_RenameGlyphs        2842
    1475             : #define MID_NameGlyphs          2843
    1476             : #define MID_HideNoGlyphSlots    2844
    1477             : #define MID_CreateMM    2900
    1478             : #define MID_MMInfo      2901
    1479             : #define MID_MMValid     2902
    1480             : #define MID_ChangeMMBlend       2903
    1481             : #define MID_BlendToNew  2904
    1482             : #define MID_ModifyComposition   20902
    1483             : #define MID_BuildSyllables      20903
    1484             : #define MID_CollabStart         22000
    1485             : #define MID_CollabConnect       22001
    1486             : #define MID_CollabDisconnect    22002
    1487             : #define MID_CollabCloseLocalServer  22003
    1488             : #define MID_CollabConnectToExplicitAddress 22004
    1489             : 
    1490             : 
    1491             : #define MID_Warnings    3000
    1492             : 
    1493             : 
    1494             : /* returns -1 if nothing selected, if exactly one char return it, -2 if more than one */
    1495           0 : static int FVAnyCharSelected(FontView *fv) {
    1496           0 :     int i, val=-1;
    1497             : 
    1498           0 :     for ( i=0; i<fv->b.map->enccount; ++i ) {
    1499           0 :         if ( fv->b.selected[i]) {
    1500           0 :             if ( val==-1 )
    1501           0 :                 val = i;
    1502             :             else
    1503           0 : return( -2 );
    1504             :         }
    1505             :     }
    1506           0 : return( val );
    1507             : }
    1508             : 
    1509           0 : static int FVAllSelected(FontView *fv) {
    1510           0 :     int i, any = false;
    1511             :     /* Is everything real selected? */
    1512             : 
    1513           0 :     for ( i=0; i<fv->b.sf->glyphcnt; ++i ) if ( SCWorthOutputting(fv->b.sf->glyphs[i])) {
    1514           0 :         if ( !fv->b.selected[fv->b.map->backmap[i]] )
    1515           0 : return( false );
    1516           0 :         any = true;
    1517             :     }
    1518           0 : return( any );
    1519             : }
    1520             : 
    1521           0 : static void FVMenuCopyFrom(GWindow UNUSED(gw), struct gmenuitem *mi, GEvent *UNUSED(e)) {
    1522             :     /*FontView *fv = (FontView *) GDrawGetUserData(gw);*/
    1523             : 
    1524           0 :     if ( mi->mid==MID_CharName )
    1525           0 :         copymetadata = !copymetadata;
    1526           0 :     else if ( mi->mid==MID_TTFInstr )
    1527           0 :         copyttfinstr = !copyttfinstr;
    1528             :     else
    1529           0 :         onlycopydisplayed = (mi->mid==MID_DisplayedFont);
    1530           0 :     SavePrefs(true);
    1531           0 : }
    1532             : 
    1533           0 : static void FVMenuCopy(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    1534           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    1535           0 :     if ( FVAnyCharSelected(fv)==-1 )
    1536           0 : return;
    1537           0 :     FVCopy((FontViewBase *) fv,ct_fullcopy);
    1538             : }
    1539             : 
    1540           0 : static void FVMenuCopyLookupData(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    1541           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    1542           0 :     if ( FVAnyCharSelected(fv)==-1 )
    1543           0 : return;
    1544           0 :     FVCopy((FontViewBase *) fv,ct_lookups);
    1545             : }
    1546             : 
    1547           0 : static void FVMenuCopyRef(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    1548           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    1549           0 :     if ( FVAnyCharSelected(fv)==-1 )
    1550           0 : return;
    1551           0 :     FVCopy((FontViewBase *) fv,ct_reference);
    1552             : }
    1553             : 
    1554           0 : static void FVMenuCopyWidth(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
    1555           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    1556             : 
    1557           0 :     if ( FVAnyCharSelected(fv)==-1 )
    1558           0 : return;
    1559           0 :     if ( mi->mid==MID_CopyVWidth && !fv->b.sf->hasvmetrics )
    1560           0 : return;
    1561           0 :     FVCopyWidth((FontViewBase *) fv,
    1562           0 :                    mi->mid==MID_CopyWidth?ut_width:
    1563           0 :                    mi->mid==MID_CopyVWidth?ut_vwidth:
    1564           0 :                    mi->mid==MID_CopyLBearing?ut_lbearing:
    1565             :                                          ut_rbearing);
    1566             : }
    1567             : 
    1568           0 : static void FVMenuPaste(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    1569           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    1570           0 :     if ( FVAnyCharSelected(fv)==-1 )
    1571           0 : return;
    1572           0 :     PasteIntoFV((FontViewBase *) fv,false,NULL);
    1573             : }
    1574             : 
    1575           0 : static void FVMenuPasteInto(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    1576           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    1577           0 :     if ( FVAnyCharSelected(fv)==-1 )
    1578           0 : return;
    1579           0 :     PasteIntoFV((FontViewBase *) fv,true,NULL);
    1580             : }
    1581             : 
    1582           0 : static void FVMenuPasteAfter(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    1583           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    1584           0 :     int pos = FVAnyCharSelected(fv);
    1585           0 :     if ( pos<0 )
    1586           0 : return;
    1587           0 :     PasteIntoFV(&fv->b,2,NULL);
    1588             : }
    1589             : 
    1590           0 : static void FVMenuSameGlyphAs(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    1591           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    1592           0 :     FVSameGlyphAs((FontViewBase *) fv);
    1593           0 :     GDrawRequestExpose(fv->v,NULL,false);
    1594           0 : }
    1595             : 
    1596           0 : static void FVMenuCopyFgBg(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    1597           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    1598           0 :     FVCopyFgtoBg( (FontViewBase *) fv );
    1599           0 : }
    1600             : 
    1601           0 : static void FVMenuCopyL2L(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    1602           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    1603           0 :     FVCopyLayerToLayer( fv );
    1604           0 : }
    1605             : 
    1606           0 : static void FVMenuCompareL2L(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    1607           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    1608           0 :     FVCompareLayerToLayer( fv );
    1609           0 : }
    1610             : 
    1611           0 : static void FVMenuClear(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    1612           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    1613           0 :     FVClear( (FontViewBase *) fv );
    1614           0 : }
    1615             : 
    1616           0 : static void FVMenuClearBackground(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    1617           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    1618           0 :     FVClearBackground( (FontViewBase *) fv );
    1619           0 : }
    1620             : 
    1621           0 : static void FVMenuJoin(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    1622           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    1623           0 :     FVJoin( (FontViewBase *) fv );
    1624           0 : }
    1625             : 
    1626           0 : static void FVMenuUnlinkRef(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    1627           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    1628           0 :     FVUnlinkRef( (FontViewBase *) fv );
    1629           0 : }
    1630             : 
    1631           0 : static void FVMenuRemoveUndoes(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    1632           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    1633           0 :     SFRemoveUndoes(fv->b.sf,fv->b.selected,fv->b.map);
    1634           0 : }
    1635             : 
    1636           0 : static void FVMenuUndo(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    1637           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    1638           0 :     FVUndo((FontViewBase *) fv);
    1639           0 : }
    1640             : 
    1641           0 : static void FVMenuRedo(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    1642           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    1643           0 :     FVRedo((FontViewBase *) fv);
    1644           0 : }
    1645             : 
    1646           0 : static void FVMenuUndoFontLevel(GWindow gw,struct gmenuitem *mi,GEvent *e) {
    1647           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    1648           0 :     FontViewBase * fvb = (FontViewBase *) fv;
    1649           0 :     SplineFont *sf = fvb->sf;
    1650             : 
    1651           0 :     if( !sf->undoes )
    1652           0 :         return;
    1653             : 
    1654           0 :     struct sfundoes *undo = sf->undoes;
    1655           0 :     printf("font level undo msg:%s\n", undo->msg );
    1656           0 :     SFUndoPerform( undo, sf );
    1657           0 :     SFUndoRemoveAndFree( sf, undo );
    1658             : }
    1659             : 
    1660           0 : static void FVMenuCut(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    1661           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    1662           0 :     FVCopy(&fv->b,ct_fullcopy);
    1663           0 :     FVClear(&fv->b);
    1664           0 : }
    1665             : 
    1666           0 : static void FVMenuSelectAll(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    1667           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    1668             : 
    1669           0 :     FVSelectAll(fv);
    1670           0 : }
    1671             : 
    1672           0 : static void FVMenuInvertSelection(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    1673           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    1674             : 
    1675           0 :     FVInvertSelection(fv);
    1676           0 : }
    1677             : 
    1678           0 : static void FVMenuDeselectAll(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    1679           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    1680             : 
    1681           0 :     FVDeselectAll(fv);
    1682           0 : }
    1683             : 
    1684             : enum merge_type { mt_set=0, mt_merge=4, mt_or=mt_merge, mt_restrict=8, mt_and=12 };
    1685             :     /* Index array by merge_type(*4) + selection*2 + doit */
    1686             : const uint8 mergefunc[] = {
    1687             : /* mt_set */
    1688             :         0, 1,
    1689             :         0, 1,
    1690             : /* mt_merge */
    1691             :         0, 1,
    1692             :         1, 1,
    1693             : /* mt_restrict */
    1694             :         0, 0,
    1695             :         1, 0,
    1696             : /* mt_and */
    1697             :         0, 0,
    1698             :         0, 1,
    1699             : };
    1700             : 
    1701           0 : static enum merge_type SelMergeType(GEvent *e) {
    1702           0 :     if ( e->type!=et_mouseup )
    1703           0 : return( mt_set );
    1704             : 
    1705           0 : return( ((e->u.mouse.state&ksm_shift)?mt_merge:0) |
    1706           0 :         ((e->u.mouse.state&ksm_control)?mt_restrict:0) );
    1707             : }
    1708             : 
    1709           0 : static char *SubMatch(char *pattern, char *eop, char *name,int ignorecase) {
    1710             :     char ch, *ppt, *npt, *ept, *eon;
    1711             : 
    1712           0 :     while ( pattern<eop && ( ch = *pattern)!='\0' ) {
    1713           0 :         if ( ch=='*' ) {
    1714           0 :             if ( pattern[1]=='\0' )
    1715           0 : return( name+strlen(name));
    1716           0 :             for ( npt=name; ; ++npt ) {
    1717           0 :                 if ( (eon = SubMatch(pattern+1,eop,npt,ignorecase))!= NULL )
    1718           0 : return( eon );
    1719           0 :                 if ( *npt=='\0' )
    1720           0 : return( NULL );
    1721           0 :             }
    1722           0 :         } else if ( ch=='?' ) {
    1723           0 :             if ( *name=='\0' )
    1724           0 : return( NULL );
    1725           0 :             ++name;
    1726           0 :         } else if ( ch=='[' ) {
    1727             :             /* [<char>...] matches the chars
    1728             :              * [<char>-<char>...] matches any char within the range (inclusive)
    1729             :              * the above may be concattenated and the resultant pattern matches
    1730             :              *          anything thing which matches any of them.
    1731             :              * [^<char>...] matches any char which does not match the rest of
    1732             :              *          the pattern
    1733             :              * []...] as a special case a ']' immediately after the '[' matches
    1734             :              *          itself and does not end the pattern
    1735             :              */
    1736           0 :             int found = 0, not=0;
    1737           0 :             ++pattern;
    1738           0 :             if ( pattern[0]=='^' ) { not = 1; ++pattern; }
    1739           0 :             for ( ppt = pattern; (ppt!=pattern || *ppt!=']') && *ppt!='\0' ; ++ppt ) {
    1740           0 :                 ch = *ppt;
    1741           0 :                 if ( ppt[1]=='-' && ppt[2]!=']' && ppt[2]!='\0' ) {
    1742           0 :                     char ch2 = ppt[2];
    1743           0 :                     if ( (*name>=ch && *name<=ch2) ||
    1744           0 :                             (ignorecase && islower(ch) && islower(ch2) &&
    1745           0 :                                     *name>=toupper(ch) && *name<=toupper(ch2)) ||
    1746           0 :                             (ignorecase && isupper(ch) && isupper(ch2) &&
    1747           0 :                                     *name>=tolower(ch) && *name<=tolower(ch2))) {
    1748           0 :                         if ( !not ) {
    1749           0 :                             found = 1;
    1750           0 :             break;
    1751             :                         }
    1752             :                     } else {
    1753           0 :                         if ( not ) {
    1754           0 :                             found = 1;
    1755           0 :             break;
    1756             :                         }
    1757             :                     }
    1758           0 :                     ppt += 2;
    1759           0 :                 } else if ( ch==*name || (ignorecase && tolower(ch)==tolower(*name)) ) {
    1760           0 :                     if ( !not ) {
    1761           0 :                         found = 1;
    1762           0 :             break;
    1763             :                     }
    1764             :                 } else {
    1765           0 :                     if ( not ) {
    1766           0 :                         found = 1;
    1767           0 :             break;
    1768             :                     }
    1769             :                 }
    1770             :             }
    1771           0 :             if ( !found )
    1772           0 : return( NULL );
    1773           0 :             while ( *ppt!=']' && *ppt!='\0' ) ++ppt;
    1774           0 :             pattern = ppt;
    1775           0 :             ++name;
    1776           0 :         } else if ( ch=='{' ) {
    1777             :             /* matches any of a comma separated list of substrings */
    1778           0 :             for ( ppt = pattern+1; *ppt!='\0' ; ppt = ept ) {
    1779           0 :                 for ( ept=ppt; *ept!='}' && *ept!=',' && *ept!='\0'; ++ept );
    1780           0 :                 npt = SubMatch(ppt,ept,name,ignorecase);
    1781           0 :                 if ( npt!=NULL ) {
    1782           0 :                     char *ecurly = ept;
    1783           0 :                     while ( *ecurly!='}' && ecurly<eop && *ecurly!='\0' ) ++ecurly;
    1784           0 :                     if ( (eon=SubMatch(ecurly+1,eop,npt,ignorecase))!=NULL )
    1785           0 : return( eon );
    1786             :                 }
    1787           0 :                 if ( *ept=='}' )
    1788           0 : return( NULL );
    1789           0 :                 if ( *ept==',' ) ++ept;
    1790             :             }
    1791           0 :         } else if ( ch==*name ) {
    1792           0 :             ++name;
    1793           0 :         } else if ( ignorecase && tolower(ch)==tolower(*name)) {
    1794           0 :             ++name;
    1795             :         } else
    1796           0 : return( NULL );
    1797           0 :         ++pattern;
    1798             :     }
    1799           0 : return( name );
    1800             : }
    1801             : 
    1802             : /* Handles *?{}[] wildcards */
    1803           0 : static int WildMatch(char *pattern, char *name,int ignorecase) {
    1804           0 :     char *eop = pattern + strlen(pattern);
    1805             : 
    1806           0 :     if ( pattern==NULL )
    1807           0 : return( true );
    1808             : 
    1809           0 :     name = SubMatch(pattern,eop,name,ignorecase);
    1810           0 :     if ( name==NULL )
    1811           0 : return( false );
    1812           0 :     if ( *name=='\0' )
    1813           0 : return( true );
    1814             : 
    1815           0 : return( false );
    1816             : }
    1817             : 
    1818           0 : static int SS_ScriptChanged(GGadget *g, GEvent *e) {
    1819             : 
    1820           0 :     if ( e->type==et_controlevent && e->u.control.subtype != et_textfocuschanged ) {
    1821           0 :         char *txt = GGadgetGetTitle8(g);
    1822             :         char buf[8];
    1823             :         int i;
    1824             :         extern GTextInfo scripts[];
    1825             : 
    1826           0 :         for ( i=0; scripts[i].text!=NULL; ++i ) {
    1827           0 :             if ( strcmp((char *) scripts[i].text,txt)==0 )
    1828           0 :         break;
    1829             :         }
    1830           0 :         free(txt);
    1831           0 :         if ( scripts[i].text==NULL )
    1832           0 : return( true );
    1833           0 :         buf[0] = ((intpt) scripts[i].userdata)>>24;
    1834           0 :         buf[1] = ((intpt) scripts[i].userdata)>>16;
    1835           0 :         buf[2] = ((intpt) scripts[i].userdata)>>8 ;
    1836           0 :         buf[3] = ((intpt) scripts[i].userdata)    ;
    1837           0 :         buf[4] = 0;
    1838           0 :         GGadgetSetTitle8(g,buf);
    1839             :     }
    1840           0 : return( true );
    1841             : }
    1842             : 
    1843           0 : static int SS_OK(GGadget *g, GEvent *e) {
    1844             : 
    1845           0 :     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
    1846           0 :         int *done = GDrawGetUserData(GGadgetGetWindow(g));
    1847           0 :         *done = 2;
    1848             :     }
    1849           0 : return( true );
    1850             : }
    1851             : 
    1852           0 : static int SS_Cancel(GGadget *g, GEvent *e) {
    1853             : 
    1854           0 :     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
    1855           0 :         int *done = GDrawGetUserData(GGadgetGetWindow(g));
    1856           0 :         *done = true;
    1857             :     }
    1858           0 : return( true );
    1859             : }
    1860             : 
    1861           0 : static int ss_e_h(GWindow gw, GEvent *event) {
    1862           0 :     int *done = GDrawGetUserData(gw);
    1863             : 
    1864           0 :     switch ( event->type ) {
    1865             :       case et_char:
    1866           0 : return( false );
    1867             :       case et_close:
    1868           0 :         *done = true;
    1869           0 :       break;
    1870             :     }
    1871           0 : return( true );
    1872             : }
    1873             : 
    1874           0 : static void FVSelectByScript(FontView *fv,int merge) {
    1875             :     int j, gid;
    1876             :     SplineChar *sc;
    1877           0 :     EncMap *map = fv->b.map;
    1878           0 :     SplineFont *sf = fv->b.sf;
    1879             :     extern GTextInfo scripts[];
    1880             :     GRect pos;
    1881             :     GWindow gw;
    1882             :     GWindowAttrs wattrs;
    1883             :     GGadgetCreateData gcd[10], *hvarray[21][2], *barray[8], boxes[3];
    1884             :     GTextInfo label[10];
    1885             :     int i,k;
    1886           0 :     int done = 0, doit;
    1887             :     char tagbuf[4];
    1888             :     uint32 tag;
    1889             :     const unichar_t *ret;
    1890             :     int lc_k, uc_k, select_k;
    1891           0 :     int only_uc=0, only_lc=0;
    1892             : 
    1893           0 :     LookupUIInit();
    1894             : 
    1895           0 :     memset(&wattrs,0,sizeof(wattrs));
    1896           0 :     memset(&gcd,0,sizeof(gcd));
    1897           0 :     memset(&label,0,sizeof(label));
    1898           0 :     memset(&boxes,0,sizeof(boxes));
    1899             : 
    1900           0 :     wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_undercursor|wam_isdlg|wam_restrict;
    1901           0 :     wattrs.event_masks = ~(1<<et_charup);
    1902           0 :     wattrs.restrict_input_to_me = false;
    1903           0 :     wattrs.is_dlg = 1;
    1904           0 :     wattrs.undercursor = 1;
    1905           0 :     wattrs.cursor = ct_pointer;
    1906           0 :     wattrs.utf8_window_title = _("Select by Script");
    1907           0 :     wattrs.is_dlg = true;
    1908           0 :     pos.x = pos.y = 0;
    1909           0 :     pos.width = 100;
    1910           0 :     pos.height = 100;
    1911           0 :     gw = GDrawCreateTopWindow(NULL,&pos,ss_e_h,&done,&wattrs);
    1912             : 
    1913           0 :     k = i = 0;
    1914             : 
    1915           0 :     gcd[k].gd.flags = gg_visible|gg_enabled ;
    1916           0 :     gcd[k].gd.u.list = scripts;
    1917           0 :     gcd[k].gd.handle_controlevent = SS_ScriptChanged;
    1918           0 :     gcd[k++].creator = GListFieldCreate;
    1919           0 :     hvarray[i][0] = &gcd[k-1]; hvarray[i++][1] = NULL;
    1920             : 
    1921           0 :     label[k].text = (unichar_t *) _("All glyphs");
    1922           0 :     label[k].text_is_1byte = true;
    1923           0 :     gcd[k].gd.label = &label[k];
    1924           0 :     gcd[k].gd.flags = gg_enabled|gg_visible|gg_utf8_popup|gg_cb_on;
    1925           0 :     gcd[k].gd.popup_msg = (unichar_t *) _("Set the selection of the font view to all glyphs in the script.");
    1926           0 :     gcd[k++].creator = GRadioCreate;
    1927           0 :     hvarray[i][0] = &gcd[k-1]; hvarray[i++][1] = NULL;
    1928           0 :     hvarray[i][0] = GCD_HPad10; hvarray[i++][1] = NULL;
    1929             : 
    1930           0 :     uc_k = k;
    1931           0 :     label[k].text = (unichar_t *) _("Only upper case");
    1932           0 :     label[k].text_is_1byte = true;
    1933           0 :     gcd[k].gd.label = &label[k];
    1934           0 :     gcd[k].gd.flags = gg_enabled|gg_visible|gg_utf8_popup;
    1935           0 :     gcd[k].gd.popup_msg = (unichar_t *) _("Set the selection of the font view to any upper case glyphs in the script.");
    1936           0 :     gcd[k++].creator = GRadioCreate;
    1937           0 :     hvarray[i][0] = &gcd[k-1]; hvarray[i++][1] = NULL;
    1938             : 
    1939           0 :     lc_k = k;
    1940           0 :     label[k].text = (unichar_t *) _("Only lower case");
    1941           0 :     label[k].text_is_1byte = true;
    1942           0 :     gcd[k].gd.label = &label[k];
    1943           0 :     gcd[k].gd.flags = gg_enabled|gg_visible|gg_utf8_popup;
    1944           0 :     gcd[k].gd.popup_msg = (unichar_t *) _("Set the selection of the font view to any lower case glyphs in the script.");
    1945           0 :     gcd[k++].creator = GRadioCreate;
    1946           0 :     hvarray[i][0] = &gcd[k-1]; hvarray[i++][1] = NULL;
    1947           0 :     hvarray[i][0] = GCD_HPad10; hvarray[i++][1] = NULL;
    1948             : 
    1949           0 :     select_k = k;
    1950           0 :     label[k].text = (unichar_t *) _("Select Results");
    1951           0 :     label[k].text_is_1byte = true;
    1952           0 :     gcd[k].gd.label = &label[k];
    1953           0 :     gcd[k].gd.flags = gg_enabled|gg_visible|gg_utf8_popup|gg_rad_startnew;
    1954           0 :     gcd[k].gd.popup_msg = (unichar_t *) _("Set the selection of the font view to the glyphs\nwhich match");
    1955           0 :     gcd[k++].creator = GRadioCreate;
    1956           0 :     hvarray[i][0] = &gcd[k-1]; hvarray[i++][1] = NULL;
    1957             : 
    1958           0 :     label[k].text = (unichar_t *) _("Merge Results");
    1959           0 :     label[k].text_is_1byte = true;
    1960           0 :     gcd[k].gd.label = &label[k];
    1961           0 :     gcd[k].gd.flags = gg_enabled|gg_visible|gg_utf8_popup;
    1962           0 :     gcd[k].gd.popup_msg = (unichar_t *) _("Expand the selection of the font view to include\nall the glyphs which match");
    1963           0 :     gcd[k++].creator = GRadioCreate;
    1964           0 :     hvarray[i][0] = &gcd[k-1]; hvarray[i++][1] = NULL;
    1965             : 
    1966           0 :     label[k].text = (unichar_t *) _("Restrict Selection");
    1967           0 :     label[k].text_is_1byte = true;
    1968           0 :     gcd[k].gd.label = &label[k];
    1969           0 :     gcd[k].gd.flags = gg_enabled|gg_visible|gg_utf8_popup;
    1970           0 :     gcd[k].gd.popup_msg = (unichar_t *) _("Remove matching glyphs from the selection." );
    1971           0 :     gcd[k++].creator = GRadioCreate;
    1972           0 :     hvarray[i][0] = &gcd[k-1]; hvarray[i++][1] = NULL;
    1973             : 
    1974           0 :     label[k].text = (unichar_t *) _("Logical And with Selection");
    1975           0 :     label[k].text_is_1byte = true;
    1976           0 :     gcd[k].gd.label = &label[k];
    1977           0 :     gcd[k].gd.flags = gg_enabled|gg_visible|gg_utf8_popup;
    1978           0 :     gcd[k].gd.popup_msg = (unichar_t *) _("Remove glyphs which do not match from the selection." );
    1979           0 :     gcd[k++].creator = GRadioCreate;
    1980           0 :     hvarray[i][0] = &gcd[k-1]; hvarray[i++][1] = NULL;
    1981           0 :     gcd[k-4 + merge/4].gd.flags |= gg_cb_on;
    1982             : 
    1983           0 :     hvarray[i][0] = GCD_Glue; hvarray[i++][1] = NULL;
    1984             : 
    1985           0 :     label[k].text = (unichar_t *) _("_OK");
    1986           0 :     label[k].text_is_1byte = true;
    1987           0 :     label[k].text_in_resource = true;
    1988           0 :     gcd[k].gd.label = &label[k];
    1989           0 :     gcd[k].gd.flags = gg_visible|gg_enabled | gg_but_default;
    1990           0 :     gcd[k].gd.handle_controlevent = SS_OK;
    1991           0 :     gcd[k++].creator = GButtonCreate;
    1992             : 
    1993           0 :     label[k].text = (unichar_t *) _("_Cancel");
    1994           0 :     label[k].text_is_1byte = true;
    1995           0 :     label[k].text_in_resource = true;
    1996           0 :     gcd[k].gd.label = &label[k];
    1997           0 :     gcd[k].gd.flags = gg_visible|gg_enabled | gg_but_cancel;
    1998           0 :     gcd[k].gd.handle_controlevent = SS_Cancel;
    1999           0 :     gcd[k++].creator = GButtonCreate;
    2000             : 
    2001           0 :     barray[0] = barray[2] = barray[3] = barray[4] = barray[6] = GCD_Glue; barray[7] = NULL;
    2002           0 :     barray[1] = &gcd[k-2]; barray[5] = &gcd[k-1];
    2003           0 :     hvarray[i][0] = &boxes[2]; hvarray[i++][1] = NULL;
    2004           0 :     hvarray[i][0] = NULL;
    2005             : 
    2006           0 :     memset(boxes,0,sizeof(boxes));
    2007           0 :     boxes[0].gd.pos.x = boxes[0].gd.pos.y = 2;
    2008           0 :     boxes[0].gd.flags = gg_enabled|gg_visible;
    2009           0 :     boxes[0].gd.u.boxelements = hvarray[0];
    2010           0 :     boxes[0].creator = GHVGroupCreate;
    2011             : 
    2012           0 :     boxes[2].gd.flags = gg_enabled|gg_visible;
    2013           0 :     boxes[2].gd.u.boxelements = barray;
    2014           0 :     boxes[2].creator = GHBoxCreate;
    2015             : 
    2016           0 :     GGadgetsCreate(gw,boxes);
    2017           0 :     GHVBoxSetExpandableCol(boxes[2].ret,gb_expandgluesame);
    2018           0 :     GHVBoxSetExpandableRow(boxes[0].ret,gb_expandglue);
    2019             : 
    2020             : 
    2021           0 :     GHVBoxFitWindow(boxes[0].ret);
    2022             : 
    2023           0 :     GDrawSetVisible(gw,true);
    2024           0 :     ret = NULL;
    2025           0 :     while ( !done ) {
    2026           0 :         GDrawProcessOneEvent(NULL);
    2027           0 :         if ( done==2 ) {
    2028           0 :             ret = _GGadgetGetTitle(gcd[0].ret);
    2029           0 :             if ( *ret=='\0' ) {
    2030           0 :                 ff_post_error(_("No Script"),_("Please specify a script"));
    2031           0 :                 done = 0;
    2032           0 :             } else if ( u_strlen(ret)>4 ) {
    2033           0 :                 ff_post_error(_("Bad Script"),_("Scripts are 4 letter tags"));
    2034           0 :                 done = 0;
    2035             :             }
    2036             :         }
    2037             :     }
    2038           0 :     memset(tagbuf,' ',4);
    2039           0 :     if ( done==2 && ret!=NULL ) {
    2040           0 :         tagbuf[0] = *ret;
    2041           0 :         if ( ret[1]!='\0' ) {
    2042           0 :             tagbuf[1] = ret[1];
    2043           0 :             if ( ret[2]!='\0' ) {
    2044           0 :                 tagbuf[2] = ret[2];
    2045           0 :                 if ( ret[3]!='\0' )
    2046           0 :                     tagbuf[3] = ret[3];
    2047             :             }
    2048             :         }
    2049             :     }
    2050           0 :     merge = GGadgetIsChecked(gcd[select_k+0].ret) ? mt_set :
    2051           0 :             GGadgetIsChecked(gcd[select_k+1].ret) ? mt_merge :
    2052           0 :             GGadgetIsChecked(gcd[select_k+2].ret) ? mt_restrict :
    2053             :                                                     mt_and;
    2054           0 :     only_uc = GGadgetIsChecked(gcd[uc_k+0].ret);
    2055           0 :     only_lc = GGadgetIsChecked(gcd[lc_k+0].ret);
    2056             : 
    2057           0 :     GDrawDestroyWindow(gw);
    2058           0 :     if ( done==1 )
    2059           0 : return;
    2060           0 :     tag = (tagbuf[0]<<24) | (tagbuf[1]<<16) | (tagbuf[2]<<8) | tagbuf[3];
    2061             : 
    2062           0 :     for ( j=0; j<map->enccount; ++j ) if ( (gid=map->map[j])!=-1 && (sc=sf->glyphs[gid])!=NULL ) {
    2063           0 :         doit = ( SCScriptFromUnicode(sc)==tag );
    2064           0 :         if ( doit ) {
    2065           0 :             if ( only_uc && (sc->unicodeenc==-1 || sc->unicodeenc>0xffff ||
    2066           0 :                     !isupper(sc->unicodeenc)) )
    2067           0 :                 doit = false;
    2068           0 :             else if ( only_lc && (sc->unicodeenc==-1 || sc->unicodeenc>0xffff ||
    2069           0 :                     !islower(sc->unicodeenc)) )
    2070           0 :                 doit = false;
    2071             :         }
    2072           0 :         fv->b.selected[j] = mergefunc[ merge + (fv->b.selected[j]?2:0) + doit ];
    2073           0 :     } else if ( merge==mt_set )
    2074           0 :         fv->b.selected[j] = false;
    2075             : 
    2076           0 :     GDrawRequestExpose(fv->v,NULL,false);
    2077             : }
    2078             : 
    2079           0 : static void FVMenuSelectByScript(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *e) {
    2080           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    2081             : 
    2082           0 :     FVSelectByScript(fv,SelMergeType(e));
    2083           0 : }
    2084             : 
    2085           0 : static void FVSelectColor(FontView *fv, uint32 col, int merge) {
    2086             :     int i, doit;
    2087             :     uint32 sccol;
    2088           0 :     SplineChar **glyphs = fv->b.sf->glyphs;
    2089             : 
    2090           0 :     for ( i=0; i<fv->b.map->enccount; ++i ) {
    2091           0 :         int gid = fv->b.map->map[i];
    2092           0 :         sccol =  ( gid==-1 || glyphs[gid]==NULL ) ? COLOR_DEFAULT : glyphs[gid]->color;
    2093           0 :         doit = sccol==col;
    2094           0 :         fv->b.selected[i] = mergefunc[ merge + (fv->b.selected[i]?2:0) + doit ];
    2095             :     }
    2096           0 :     GDrawRequestExpose(fv->v,NULL,false);
    2097           0 : }
    2098             : 
    2099           0 : static void FVMenuSelectColor(GWindow gw, struct gmenuitem *mi, GEvent *e) {
    2100           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    2101           0 :     Color col = (Color) (intpt) (mi->ti.userdata);
    2102           0 :     if ( (intpt) mi->ti.userdata == (intpt) -10 ) {
    2103             :         struct hslrgb retcol, font_cols[6];
    2104           0 :         retcol = GWidgetColor(_("Pick a color"),NULL,SFFontCols(fv->b.sf,font_cols));
    2105           0 :         if ( !retcol.rgb )
    2106           0 : return;
    2107           0 :         col = (((int) rint(255.*retcol.r))<<16 ) |
    2108           0 :                     (((int) rint(255.*retcol.g))<<8 ) |
    2109           0 :                     (((int) rint(255.*retcol.b)) );
    2110             :     }
    2111           0 :     FVSelectColor(fv,col,SelMergeType(e));
    2112             : }
    2113             : 
    2114           0 : static int FVSelectByName(FontView *fv, char *ret, int merge) {
    2115             :     int j, gid, doit;
    2116             :     char *end;
    2117             :     SplineChar *sc;
    2118           0 :     EncMap *map = fv->b.map;
    2119           0 :     SplineFont *sf = fv->b.sf;
    2120             :     struct altuni *alt;
    2121             : 
    2122           0 :     if ( !merge )
    2123           0 :         FVDeselectAll(fv);
    2124           0 :     if (( *ret=='0' && ( ret[1]=='x' || ret[1]=='X' )) ||
    2125           0 :             ((*ret=='u' || *ret=='U') && ret[1]=='+' )) {
    2126           0 :         int uni = (int) strtol(ret+2,&end,16);
    2127           0 :         int vs= -2;
    2128           0 :         if ( *end=='.' ) {
    2129           0 :             ++end;
    2130           0 :             if (( *end=='0' && ( end[1]=='x' || end[1]=='X' )) ||
    2131           0 :                     ((*end=='u' || *end=='U') && end[1]=='+' ))
    2132           0 :                 end += 2;
    2133           0 :             vs = (int) strtoul(end,&end,16);
    2134             :         }
    2135           0 :         if ( *end!='\0' || uni<0 || uni>=0x110000 ) {
    2136           0 :             ff_post_error( _("Bad Number"),_("Bad Number") );
    2137           0 : return( false );
    2138             :         }
    2139           0 :         for ( j=0; j<map->enccount; ++j ) if ( (gid=map->map[j])!=-1 && (sc=sf->glyphs[gid])!=NULL ) {
    2140           0 :             if ( vs==-2 ) {
    2141           0 :                 for ( alt=sc->altuni; alt!=NULL && (alt->unienc!=uni || alt->fid!=0); alt=alt->next );
    2142             :             } else {
    2143           0 :                 for ( alt=sc->altuni; alt!=NULL && (alt->unienc!=uni || alt->vs!=vs || alt->fid!=0); alt=alt->next );
    2144             :             }
    2145           0 :             doit = (sc->unicodeenc == uni && vs<0) || alt!=NULL;
    2146           0 :             fv->b.selected[j] = mergefunc[ merge + (fv->b.selected[j]?2:0) + doit ];
    2147           0 :         } else if ( merge==mt_set )
    2148           0 :             fv->b.selected[j] = false;
    2149             :     } else {
    2150           0 :         for ( j=0; j<map->enccount; ++j ) if ( (gid=map->map[j])!=-1 && (sc=sf->glyphs[gid])!=NULL ) {
    2151           0 :             doit = WildMatch(ret,sc->name,false);
    2152           0 :             fv->b.selected[j] = mergefunc[ merge + (fv->b.selected[j]?2:0) + doit ];
    2153           0 :         } else if ( merge==mt_set )
    2154           0 :             fv->b.selected[j] = false;
    2155             :     }
    2156           0 :     GDrawRequestExpose(fv->v,NULL,false);
    2157           0 :     fv->sel_index = 1;
    2158           0 : return( true );
    2159             : }
    2160             : 
    2161           0 : static void FVMenuSelectByName(GWindow _gw, struct gmenuitem *UNUSED(mi), GEvent *e) {
    2162           0 :     FontView *fv = (FontView *) GDrawGetUserData(_gw);
    2163             :     GRect pos;
    2164             :     GWindow gw;
    2165             :     GWindowAttrs wattrs;
    2166             :     GGadgetCreateData gcd[8], *hvarray[12][2], *barray[8], boxes[3];
    2167             :     GTextInfo label[8];
    2168           0 :     int merge = SelMergeType(e);
    2169           0 :     int done=0,k,i;
    2170             : 
    2171           0 :     memset(&wattrs,0,sizeof(wattrs));
    2172           0 :     memset(&gcd,0,sizeof(gcd));
    2173           0 :     memset(&label,0,sizeof(label));
    2174           0 :     memset(&boxes,0,sizeof(boxes));
    2175             : 
    2176           0 :     wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_undercursor|wam_isdlg|wam_restrict;
    2177           0 :     wattrs.event_masks = ~(1<<et_charup);
    2178           0 :     wattrs.restrict_input_to_me = false;
    2179           0 :     wattrs.undercursor = 1;
    2180           0 :     wattrs.cursor = ct_pointer;
    2181           0 :     wattrs.utf8_window_title = _("Select by Name");
    2182           0 :     wattrs.is_dlg = false;
    2183           0 :     pos.x = pos.y = 0;
    2184           0 :     pos.width = 100;
    2185           0 :     pos.height = 100;
    2186           0 :     gw = GDrawCreateTopWindow(NULL,&pos,ss_e_h,&done,&wattrs);
    2187             : 
    2188           0 :     k = i = 0;
    2189             : 
    2190           0 :     label[k].text = (unichar_t *) _("Enter either a wildcard pattern (to match glyph names)\n or a unicode encoding like \"U+0065\".");
    2191           0 :     label[k].text_is_1byte = true;
    2192           0 :     gcd[k].gd.label = &label[k];
    2193           0 :     gcd[k].gd.flags = gg_visible | gg_enabled | gg_utf8_popup;
    2194           0 :     gcd[k].gd.popup_msg = (unichar_t *) _(
    2195             :         "Unix style wildcarding is accepted:\n"
    2196             :         "Most characters match themselves\n"
    2197             :         "A \"?\" will match any single character\n"
    2198             :         "A \"*\" will match an arbitrary number of characters (including none)\n"
    2199             :         "An \"[abd]\" set of characters within square brackets will match any (single) character\n"
    2200             :         "A \"{scmp,c2sc}\" set of strings within curly brackets will match any string\n"
    2201             :         "So \"a.*\" would match \"a.\" or \"a.sc\" or \"a.swash\"\n"
    2202             :         "While \"a.{scmp,c2sc}\" would match \"a.scmp\" or \"a.c2sc\"\n"
    2203             :         "And \"a.[abd]\" would match \"a.a\" or \"a.b\" or \"a.d\"");
    2204           0 :     gcd[k++].creator = GLabelCreate;
    2205           0 :     hvarray[i][0] = &gcd[k-1]; hvarray[i++][1] = NULL;
    2206             : 
    2207           0 :     gcd[k].gd.flags = gg_visible | gg_enabled | gg_utf8_popup;
    2208           0 :     gcd[k].gd.popup_msg = gcd[k-1].gd.popup_msg;
    2209           0 :     gcd[k++].creator = GTextFieldCreate;
    2210           0 :     hvarray[i][0] = &gcd[k-1]; hvarray[i++][1] = NULL;
    2211             : 
    2212           0 :     label[k].text = (unichar_t *) _("Select Results");
    2213           0 :     label[k].text_is_1byte = true;
    2214           0 :     gcd[k].gd.label = &label[k];
    2215           0 :     gcd[k].gd.flags = gg_enabled|gg_visible|gg_utf8_popup;
    2216           0 :     gcd[k].gd.popup_msg = (unichar_t *) _("Set the selection of the font view to the glyphs\nwhich match");
    2217           0 :     gcd[k++].creator = GRadioCreate;
    2218           0 :     hvarray[i][0] = &gcd[k-1]; hvarray[i++][1] = NULL;
    2219             : 
    2220           0 :     label[k].text = (unichar_t *) _("Merge Results");
    2221           0 :     label[k].text_is_1byte = true;
    2222           0 :     gcd[k].gd.label = &label[k];
    2223           0 :     gcd[k].gd.flags = gg_enabled|gg_visible|gg_utf8_popup;
    2224           0 :     gcd[k].gd.popup_msg = (unichar_t *) _("Expand the selection of the font view to include\nall the glyphs which match");
    2225           0 :     gcd[k++].creator = GRadioCreate;
    2226           0 :     hvarray[i][0] = &gcd[k-1]; hvarray[i++][1] = NULL;
    2227             : 
    2228           0 :     label[k].text = (unichar_t *) _("Restrict Selection");
    2229           0 :     label[k].text_is_1byte = true;
    2230           0 :     gcd[k].gd.label = &label[k];
    2231           0 :     gcd[k].gd.flags = gg_enabled|gg_visible|gg_utf8_popup;
    2232           0 :     gcd[k].gd.popup_msg = (unichar_t *) _("Remove matching glyphs from the selection." );
    2233           0 :     gcd[k++].creator = GRadioCreate;
    2234           0 :     hvarray[i][0] = &gcd[k-1]; hvarray[i++][1] = NULL;
    2235             : 
    2236           0 :     label[k].text = (unichar_t *) _("Logical And with Selection");
    2237           0 :     label[k].text_is_1byte = true;
    2238           0 :     gcd[k].gd.label = &label[k];
    2239           0 :     gcd[k].gd.flags = gg_enabled|gg_visible|gg_utf8_popup;
    2240           0 :     gcd[k].gd.popup_msg = (unichar_t *) _("Remove glyphs which do not match from the selection." );
    2241           0 :     gcd[k++].creator = GRadioCreate;
    2242           0 :     hvarray[i][0] = &gcd[k-1]; hvarray[i++][1] = NULL;
    2243           0 :     gcd[k-4 + merge/4].gd.flags |= gg_cb_on;
    2244             : 
    2245           0 :     hvarray[i][0] = GCD_Glue; hvarray[i++][1] = NULL;
    2246             : 
    2247           0 :     label[k].text = (unichar_t *) _("_OK");
    2248           0 :     label[k].text_is_1byte = true;
    2249           0 :     label[k].text_in_resource = true;
    2250           0 :     gcd[k].gd.label = &label[k];
    2251           0 :     gcd[k].gd.flags = gg_visible|gg_enabled | gg_but_default;
    2252           0 :     gcd[k].gd.handle_controlevent = SS_OK;
    2253           0 :     gcd[k++].creator = GButtonCreate;
    2254             : 
    2255           0 :     label[k].text = (unichar_t *) _("_Cancel");
    2256           0 :     label[k].text_is_1byte = true;
    2257           0 :     label[k].text_in_resource = true;
    2258           0 :     gcd[k].gd.label = &label[k];
    2259           0 :     gcd[k].gd.flags = gg_visible|gg_enabled | gg_but_cancel;
    2260           0 :     gcd[k].gd.handle_controlevent = SS_Cancel;
    2261           0 :     gcd[k++].creator = GButtonCreate;
    2262             : 
    2263           0 :     barray[0] = barray[2] = barray[3] = barray[4] = barray[6] = GCD_Glue; barray[7] = NULL;
    2264           0 :     barray[1] = &gcd[k-2]; barray[5] = &gcd[k-1];
    2265           0 :     hvarray[i][0] = &boxes[2]; hvarray[i++][1] = NULL;
    2266           0 :     hvarray[i][0] = NULL;
    2267             : 
    2268           0 :     memset(boxes,0,sizeof(boxes));
    2269           0 :     boxes[0].gd.pos.x = boxes[0].gd.pos.y = 2;
    2270           0 :     boxes[0].gd.flags = gg_enabled|gg_visible;
    2271           0 :     boxes[0].gd.u.boxelements = hvarray[0];
    2272           0 :     boxes[0].creator = GHVGroupCreate;
    2273             : 
    2274           0 :     boxes[2].gd.flags = gg_enabled|gg_visible;
    2275           0 :     boxes[2].gd.u.boxelements = barray;
    2276           0 :     boxes[2].creator = GHBoxCreate;
    2277             : 
    2278           0 :     GGadgetsCreate(gw,boxes);
    2279           0 :     GHVBoxSetExpandableCol(boxes[2].ret,gb_expandgluesame);
    2280           0 :     GHVBoxSetExpandableRow(boxes[0].ret,gb_expandglue);
    2281             : 
    2282             : 
    2283           0 :     GHVBoxFitWindow(boxes[0].ret);
    2284             : 
    2285           0 :     GDrawSetVisible(gw,true);
    2286           0 :     while ( !done ) {
    2287           0 :         GDrawProcessOneEvent(NULL);
    2288           0 :         if ( done==2 ) {
    2289           0 :             char *str = GGadgetGetTitle8(gcd[1].ret);
    2290           0 :             int merge = GGadgetIsChecked(gcd[2].ret) ? mt_set :
    2291           0 :                         GGadgetIsChecked(gcd[3].ret) ? mt_merge :
    2292           0 :                         GGadgetIsChecked(gcd[4].ret) ? mt_restrict :
    2293             :                                                        mt_and;
    2294           0 :             int ret = FVSelectByName(fv,str,merge);
    2295           0 :             free(str);
    2296           0 :             if ( !ret )
    2297           0 :                 done = 0;
    2298             :         }
    2299             :     }
    2300           0 :     GDrawDestroyWindow(gw);
    2301           0 : }
    2302             : 
    2303           0 : static void FVMenuSelectWorthOutputting(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *e) {
    2304           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    2305             :     int i, gid, doit;
    2306           0 :     EncMap *map = fv->b.map;
    2307           0 :     SplineFont *sf = fv->b.sf;
    2308           0 :     int merge = SelMergeType(e);
    2309             : 
    2310           0 :     for ( i=0; i< map->enccount; ++i ) {
    2311           0 :         doit = ( (gid=map->map[i])!=-1 && sf->glyphs[gid]!=NULL &&
    2312           0 :                 SCWorthOutputting(sf->glyphs[gid]) );
    2313           0 :         fv->b.selected[i] = mergefunc[ merge + (fv->b.selected[i]?2:0) + doit ];
    2314             :     }
    2315           0 :     GDrawRequestExpose(fv->v,NULL,false);
    2316           0 : }
    2317             : 
    2318           0 : static void FVMenuGlyphsRefs(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *e) {
    2319           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    2320             :     int i, gid, doit;
    2321           0 :     EncMap *map = fv->b.map;
    2322           0 :     SplineFont *sf = fv->b.sf;
    2323           0 :     int merge = SelMergeType(e);
    2324           0 :     int layer = fv->b.active_layer;
    2325             : 
    2326           0 :     for ( i=0; i< map->enccount; ++i ) {
    2327           0 :         doit = ( (gid=map->map[i])!=-1 && sf->glyphs[gid]!=NULL &&
    2328           0 :                 sf->glyphs[gid]->layers[layer].refs!=NULL &&
    2329           0 :                 sf->glyphs[gid]->layers[layer].splines==NULL );
    2330           0 :         fv->b.selected[i] = mergefunc[ merge + (fv->b.selected[i]?2:0) + doit ];
    2331             :     }
    2332           0 :     GDrawRequestExpose(fv->v,NULL,false);
    2333           0 : }
    2334             : 
    2335           0 : static void FVMenuGlyphsSplines(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *e) {
    2336           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    2337             :     int i, gid, doit;
    2338           0 :     EncMap *map = fv->b.map;
    2339           0 :     SplineFont *sf = fv->b.sf;
    2340           0 :     int merge = SelMergeType(e);
    2341           0 :     int layer = fv->b.active_layer;
    2342             : 
    2343           0 :     for ( i=0; i< map->enccount; ++i ) {
    2344           0 :         doit = ( (gid=map->map[i])!=-1 && sf->glyphs[gid]!=NULL &&
    2345           0 :                 sf->glyphs[gid]->layers[layer].refs==NULL &&
    2346           0 :                 sf->glyphs[gid]->layers[layer].splines!=NULL );
    2347           0 :         fv->b.selected[i] = mergefunc[ merge + (fv->b.selected[i]?2:0) + doit ];
    2348             :     }
    2349           0 :     GDrawRequestExpose(fv->v,NULL,false);
    2350           0 : }
    2351             : 
    2352           0 : static void FVMenuGlyphsBoth(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *e) {
    2353           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    2354             :     int i, gid, doit;
    2355           0 :     EncMap *map = fv->b.map;
    2356           0 :     SplineFont *sf = fv->b.sf;
    2357           0 :     int merge = SelMergeType(e);
    2358           0 :     int layer = fv->b.active_layer;
    2359             : 
    2360           0 :     for ( i=0; i< map->enccount; ++i ) {
    2361           0 :         doit = ( (gid=map->map[i])!=-1 && sf->glyphs[gid]!=NULL &&
    2362           0 :                 sf->glyphs[gid]->layers[layer].refs!=NULL &&
    2363           0 :                 sf->glyphs[gid]->layers[layer].splines!=NULL );
    2364           0 :         fv->b.selected[i] = mergefunc[ merge + (fv->b.selected[i]?2:0) + doit ];
    2365             :     }
    2366           0 :     GDrawRequestExpose(fv->v,NULL,false);
    2367           0 : }
    2368             : 
    2369           0 : static void FVMenuGlyphsWhite(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *e) {
    2370           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    2371             :     int i, gid, doit;
    2372           0 :     EncMap *map = fv->b.map;
    2373           0 :     SplineFont *sf = fv->b.sf;
    2374           0 :     int merge = SelMergeType(e);
    2375           0 :     int layer = fv->b.active_layer;
    2376             : 
    2377           0 :     for ( i=0; i< map->enccount; ++i ) {
    2378           0 :         doit = ( (gid=map->map[i])!=-1 && sf->glyphs[gid]!=NULL &&
    2379           0 :                 sf->glyphs[gid]->layers[layer].refs==NULL &&
    2380           0 :                 sf->glyphs[gid]->layers[layer].splines==NULL );
    2381           0 :         fv->b.selected[i] = mergefunc[ merge + (fv->b.selected[i]?2:0) + doit ];
    2382             :     }
    2383           0 :     GDrawRequestExpose(fv->v,NULL,false);
    2384           0 : }
    2385             : 
    2386           0 : static void FVMenuSelectChanged(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *e) {
    2387           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    2388             :     int i, gid, doit;
    2389           0 :     EncMap *map = fv->b.map;
    2390           0 :     SplineFont *sf = fv->b.sf;
    2391           0 :     int merge = SelMergeType(e);
    2392             : 
    2393           0 :     for ( i=0; i< map->enccount; ++i ) {
    2394           0 :         doit = ( (gid=map->map[i])!=-1 && sf->glyphs[gid]!=NULL && sf->glyphs[gid]->changed );
    2395           0 :         fv->b.selected[i] = mergefunc[ merge + (fv->b.selected[i]?2:0) + doit ];
    2396             :     }
    2397             : 
    2398           0 :     GDrawRequestExpose(fv->v,NULL,false);
    2399           0 : }
    2400             : 
    2401           0 : static void FVMenuSelectHintingNeeded(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *e) {
    2402           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    2403             :     int i, gid, doit;
    2404           0 :     EncMap *map = fv->b.map;
    2405           0 :     SplineFont *sf = fv->b.sf;
    2406           0 :     int order2 = sf->layers[fv->b.active_layer].order2;
    2407           0 :     int merge = SelMergeType(e);
    2408             : 
    2409           0 :     for ( i=0; i< map->enccount; ++i ) {
    2410           0 :         doit = ( (gid=map->map[i])!=-1 && sf->glyphs[gid]!=NULL &&
    2411           0 :                 ((!order2 && sf->glyphs[gid]->changedsincelasthinted ) ||
    2412           0 :                  ( order2 && sf->glyphs[gid]->layers[fv->b.active_layer].splines!=NULL &&
    2413           0 :                      sf->glyphs[gid]->ttf_instrs_len<=0 ) ||
    2414           0 :                  ( order2 && sf->glyphs[gid]->instructions_out_of_date )) );
    2415           0 :         fv->b.selected[i] = mergefunc[ merge + (fv->b.selected[i]?2:0) + doit ];
    2416             :     }
    2417           0 :     GDrawRequestExpose(fv->v,NULL,false);
    2418           0 : }
    2419             : 
    2420           0 : static void FVMenuSelectAutohintable(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *e) {
    2421           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    2422             :     int i, gid, doit;
    2423           0 :     EncMap *map = fv->b.map;
    2424           0 :     SplineFont *sf = fv->b.sf;
    2425           0 :     int merge = SelMergeType(e);
    2426             : 
    2427           0 :     for ( i=0; i< map->enccount; ++i ) {
    2428           0 :         doit = (gid=map->map[i])!=-1 && sf->glyphs[gid]!=NULL &&
    2429           0 :                 !sf->glyphs[gid]->manualhints;
    2430           0 :         fv->b.selected[i] = mergefunc[ merge + (fv->b.selected[i]?2:0) + doit ];
    2431             :     }
    2432           0 :     GDrawRequestExpose(fv->v,NULL,false);
    2433           0 : }
    2434             : 
    2435           0 : static void FVMenuSelectByPST(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    2436           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    2437             : 
    2438           0 :     FVSelectByPST(fv);
    2439           0 : }
    2440             : 
    2441           0 : static void FVMenuFindRpl(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    2442           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    2443             : 
    2444           0 :     SVCreate(fv);
    2445           0 : }
    2446             : 
    2447           0 : static void FVMenuReplaceWithRef(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    2448           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    2449             : 
    2450           0 :     FVReplaceOutlineWithReference(fv,.001);
    2451           0 : }
    2452             : 
    2453           0 : static void FVMenuCorrectRefs(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    2454           0 :     FontViewBase *fv = (FontViewBase *) GDrawGetUserData(gw);
    2455             : 
    2456           0 :     FVCorrectReferences(fv);
    2457           0 : }
    2458             : 
    2459           0 : static void FVMenuCharInfo(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    2460           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    2461           0 :     int pos = FVAnyCharSelected(fv);
    2462           0 :     if ( pos<0 )
    2463           0 : return;
    2464           0 :     if ( fv->b.cidmaster!=NULL &&
    2465           0 :             (fv->b.map->map[pos]==-1 || fv->b.sf->glyphs[fv->b.map->map[pos]]==NULL ))
    2466           0 : return;
    2467           0 :     SCCharInfo(SFMakeChar(fv->b.sf,fv->b.map,pos),fv->b.active_layer,fv->b.map,pos);
    2468             : }
    2469             : 
    2470           0 : static void FVMenuBDFInfo(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    2471           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    2472           0 :     if ( fv->b.sf->bitmaps==NULL )
    2473           0 : return;
    2474           0 :     if ( fv->show!=fv->filled )
    2475           0 :         SFBdfProperties(fv->b.sf,fv->b.map,fv->show);
    2476             :     else
    2477           0 :         SFBdfProperties(fv->b.sf,fv->b.map,NULL);
    2478             : }
    2479             : 
    2480           0 : static void FVMenuBaseHoriz(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    2481           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    2482           0 :     SplineFont *sf = fv->b.cidmaster == NULL ? fv->b.sf : fv->b.cidmaster;
    2483           0 :     sf->horiz_base = SFBaselines(sf,sf->horiz_base,false);
    2484           0 :     SFBaseSort(sf);
    2485           0 : }
    2486             : 
    2487           0 : static void FVMenuBaseVert(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    2488           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    2489           0 :     SplineFont *sf = fv->b.cidmaster == NULL ? fv->b.sf : fv->b.cidmaster;
    2490           0 :     sf->vert_base = SFBaselines(sf,sf->vert_base,true);
    2491           0 :     SFBaseSort(sf);
    2492           0 : }
    2493             : 
    2494           0 : static void FVMenuJustify(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    2495           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    2496           0 :     SplineFont *sf = fv->b.cidmaster == NULL ? fv->b.sf : fv->b.cidmaster;
    2497           0 :     JustifyDlg(sf);
    2498           0 : }
    2499             : 
    2500           0 : static void FVMenuMassRename(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    2501           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    2502           0 :     FVMassGlyphRename(fv);
    2503           0 : }
    2504             : 
    2505           0 : static void FVSetColor(FontView *fv, uint32 col) {
    2506             :     int i;
    2507             : 
    2508           0 :     for ( i=0; i<fv->b.map->enccount; ++i ) if ( fv->b.selected[i] ) {
    2509           0 :         SplineChar *sc = SFMakeChar(fv->b.sf,fv->b.map,i);
    2510           0 :         sc->color = col;
    2511             :     }
    2512           0 :     GDrawRequestExpose(fv->v,NULL,false);
    2513           0 : }
    2514             : 
    2515           0 : static void FVMenuSetColor(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
    2516           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    2517           0 :     Color col = (Color) (intpt) (mi->ti.userdata);
    2518           0 :     if ( (intpt) mi->ti.userdata == (intpt) -10 ) {
    2519             :         struct hslrgb retcol, font_cols[6];
    2520           0 :         retcol = GWidgetColor(_("Pick a color"),NULL,SFFontCols(fv->b.sf,font_cols));
    2521           0 :         if ( !retcol.rgb )
    2522           0 : return;
    2523           0 :         col = (((int) rint(255.*retcol.r))<<16 ) |
    2524           0 :                     (((int) rint(255.*retcol.g))<<8 ) |
    2525           0 :                     (((int) rint(255.*retcol.b)) );
    2526             :     }
    2527           0 :     FVSetColor(fv,col);
    2528             : }
    2529             : 
    2530           0 : static void FVMenuShowDependentRefs(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    2531           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    2532           0 :     int pos = FVAnyCharSelected(fv);
    2533             :     SplineChar *sc;
    2534             : 
    2535           0 :     if ( pos<0 || fv->b.map->map[pos]==-1 )
    2536           0 : return;
    2537           0 :     sc = fv->b.sf->glyphs[fv->b.map->map[pos]];
    2538           0 :     if ( sc==NULL || sc->dependents==NULL )
    2539           0 : return;
    2540           0 :     SCRefBy(sc);
    2541             : }
    2542             : 
    2543           0 : static void FVMenuShowDependentSubs(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    2544           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    2545           0 :     int pos = FVAnyCharSelected(fv);
    2546             :     SplineChar *sc;
    2547             : 
    2548           0 :     if ( pos<0 || fv->b.map->map[pos]==-1 )
    2549           0 : return;
    2550           0 :     sc = fv->b.sf->glyphs[fv->b.map->map[pos]];
    2551           0 :     if ( sc==NULL )
    2552           0 : return;
    2553           0 :     SCSubBy(sc);
    2554             : }
    2555             : 
    2556           0 : static int getorigin(void *UNUSED(d), BasePoint *base, int index) {
    2557             :     /*FontView *fv = (FontView *) d;*/
    2558             : 
    2559           0 :     base->x = base->y = 0;
    2560           0 :     switch ( index ) {
    2561             :       case 0:           /* Character origin */
    2562             :         /* all done */
    2563           0 :       break;
    2564             :       case 1:           /* Center of selection */
    2565             :         /*CVFindCenter(cv,base,!CVAnySel(cv,NULL,NULL,NULL,NULL));*/
    2566           0 :       break;
    2567             :       default:
    2568           0 : return( false );
    2569             :     }
    2570           0 : return( true );
    2571             : }
    2572             : 
    2573           0 : static void FVDoTransform(FontView *fv) {
    2574           0 :     enum transdlg_flags flags=tdf_enableback|tdf_enablekerns;
    2575           0 :     if ( FVAnyCharSelected(fv)==-1 )
    2576           0 : return;
    2577           0 :     if ( FVAllSelected(fv))
    2578           0 :         flags=tdf_enableback|tdf_enablekerns|tdf_defaultkerns;
    2579           0 :     TransformDlgCreate(fv,FVTransFunc,getorigin,flags,cvt_none);
    2580             : }
    2581             : 
    2582           0 : static void FVMenuTransform(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    2583           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    2584           0 :     FVDoTransform(fv);
    2585           0 : }
    2586             : 
    2587           0 : static void FVMenuPOV(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    2588           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    2589             :     struct pov_data pov_data;
    2590           0 :     if ( FVAnyCharSelected(fv)==-1 || fv->b.sf->onlybitmaps )
    2591           0 : return;
    2592           0 :     if ( PointOfViewDlg(&pov_data,fv->b.sf,false)==-1 )
    2593           0 : return;
    2594           0 :     FVPointOfView((FontViewBase *) fv,&pov_data);
    2595             : }
    2596             : 
    2597           0 : static void FVMenuNLTransform(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    2598           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    2599           0 :     if ( FVAnyCharSelected(fv)==-1 )
    2600           0 : return;
    2601           0 :     NonLinearDlg(fv,NULL);
    2602             : }
    2603             : 
    2604           0 : static void FVMenuBitmaps(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
    2605           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    2606           0 :     BitmapDlg(fv,NULL,mi->mid==MID_RemoveBitmaps?-1:(mi->mid==MID_AvailBitmaps) );
    2607           0 : }
    2608             : 
    2609           0 : static void FVMenuStroke(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    2610           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    2611           0 :     FVStroke(fv);
    2612           0 : }
    2613             : 
    2614             : #  ifdef FONTFORGE_CONFIG_TILEPATH
    2615             : static void FVMenuTilePath(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    2616             :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    2617             :     FVTile(fv);
    2618             : }
    2619             : 
    2620             : static void FVMenuPatternTile(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    2621             :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    2622             :     FVPatternTile(fv);
    2623             : }
    2624             : #endif
    2625             : 
    2626           0 : static void FVMenuOverlap(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
    2627           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    2628             : 
    2629           0 :     if ( fv->b.sf->onlybitmaps )
    2630           0 : return;
    2631             : 
    2632             :     /* We know it's more likely that we'll find a problem in the overlap code */
    2633             :     /*  than anywhere else, so let's save the current state against a crash */
    2634           0 :     DoAutoSaves();
    2635             : 
    2636           0 :     FVOverlap(&fv->b,mi->mid==MID_RmOverlap ? over_remove :
    2637           0 :                  mi->mid==MID_Intersection ? over_intersect :
    2638             :                       over_findinter);
    2639             : }
    2640             : 
    2641           0 : static void FVMenuInline(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    2642           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    2643             : 
    2644           0 :     OutlineDlg(fv,NULL,NULL,true);
    2645           0 : }
    2646             : 
    2647           0 : static void FVMenuOutline(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    2648           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    2649             : 
    2650           0 :     OutlineDlg(fv,NULL,NULL,false);
    2651           0 : }
    2652             : 
    2653           0 : static void FVMenuShadow(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    2654           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    2655             : 
    2656           0 :     ShadowDlg(fv,NULL,NULL,false);
    2657           0 : }
    2658             : 
    2659           0 : static void FVMenuWireframe(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    2660           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    2661             : 
    2662           0 :     ShadowDlg(fv,NULL,NULL,true);
    2663           0 : }
    2664             : 
    2665           0 : static void FVSimplify(FontView *fv,int type) {
    2666             :     static struct simplifyinfo smpls[] = {
    2667             :             { sf_normal, 0, 0, 0, 0, 0, 0 },
    2668             :             { sf_normal,.75,.05,0,-1, 0, 0 },
    2669             :             { sf_normal,.75,.05,0,-1, 0, 0 }};
    2670           0 :     struct simplifyinfo *smpl = &smpls[type+1];
    2671             : 
    2672           0 :     if ( smpl->linelenmax==-1 || (type==0 && !smpl->set_as_default)) {
    2673           0 :         smpl->err = (fv->b.sf->ascent+fv->b.sf->descent)/1000.;
    2674           0 :         smpl->linelenmax = (fv->b.sf->ascent+fv->b.sf->descent)/100.;
    2675             :     }
    2676             : 
    2677           0 :     if ( type==1 ) {
    2678           0 :         if ( !SimplifyDlg(fv->b.sf,smpl))
    2679           0 : return;
    2680           0 :         if ( smpl->set_as_default )
    2681           0 :             smpls[1] = *smpl;
    2682             :     }
    2683           0 :     _FVSimplify((FontViewBase *) fv,smpl);
    2684             : }
    2685             : 
    2686           0 : static void FVMenuSimplify(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    2687           0 :     FVSimplify( (FontView *) GDrawGetUserData(gw),false );
    2688           0 : }
    2689             : 
    2690           0 : static void FVMenuSimplifyMore(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    2691           0 :     FVSimplify( (FontView *) GDrawGetUserData(gw),true );
    2692           0 : }
    2693             : 
    2694           0 : static void FVMenuCleanup(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    2695           0 :     FVSimplify( (FontView *) GDrawGetUserData(gw),-1 );
    2696           0 : }
    2697             : 
    2698           0 : static void FVMenuCanonicalStart(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    2699           0 :     FVCanonicalStart( (FontViewBase *) GDrawGetUserData(gw) );
    2700           0 : }
    2701             : 
    2702           0 : static void FVMenuCanonicalContours(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    2703           0 :     FVCanonicalContours( (FontViewBase *) GDrawGetUserData(gw) );
    2704           0 : }
    2705             : 
    2706           0 : static void FVMenuAddExtrema(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    2707           0 :     FVAddExtrema( (FontViewBase *) GDrawGetUserData(gw) , false);
    2708           0 : }
    2709             : 
    2710           0 : static void FVMenuCorrectDir(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    2711           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    2712           0 :     FVCorrectDir((FontViewBase *) fv);
    2713           0 : }
    2714             : 
    2715           0 : static void FVMenuRound2Int(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    2716           0 :     FVRound2Int( (FontViewBase *) GDrawGetUserData(gw), 1.0 );
    2717           0 : }
    2718             : 
    2719           0 : static void FVMenuRound2Hundredths(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    2720           0 :     FVRound2Int( (FontViewBase *) GDrawGetUserData(gw),100.0 );
    2721           0 : }
    2722             : 
    2723           0 : static void FVMenuCluster(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    2724           0 :     FVCluster( (FontViewBase *) GDrawGetUserData(gw));
    2725           0 : }
    2726             : 
    2727           0 : static void FVMenuAutotrace(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *e) {
    2728           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    2729           0 :     GCursor ct=0;
    2730             : 
    2731           0 :     if ( fv->v!=NULL ) {
    2732           0 :         ct = GDrawGetCursor(fv->v);
    2733           0 :         GDrawSetCursor(fv->v,ct_watch);
    2734           0 :         GDrawSync(NULL);
    2735           0 :         GDrawProcessPendingEvents(NULL);
    2736             :     }
    2737           0 :     FVAutoTrace(&fv->b,e!=NULL && (e->u.mouse.state&ksm_shift));
    2738           0 :     if ( fv->v!=NULL )
    2739           0 :         GDrawSetCursor(fv->v,ct);
    2740           0 : }
    2741             : 
    2742           0 : static void FVMenuBuildAccent(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    2743           0 :     FVBuildAccent( (FontViewBase *) GDrawGetUserData(gw), true );
    2744           0 : }
    2745             : 
    2746           0 : static void FVMenuBuildComposite(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    2747           0 :     FVBuildAccent( (FontViewBase *) GDrawGetUserData(gw), false );
    2748           0 : }
    2749             : 
    2750           0 : static void FVMenuBuildDuplicate(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    2751           0 :     FVBuildDuplicate( (FontViewBase *) GDrawGetUserData(gw));
    2752           0 : }
    2753             : 
    2754             : #ifdef KOREAN
    2755             : static void FVMenuShowGroup(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    2756             :     ShowGroup( ((FontView *) GDrawGetUserData(gw))->sf );
    2757             : }
    2758             : #endif
    2759             : 
    2760             : #if HANYANG
    2761             : static void FVMenuModifyComposition(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    2762             :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    2763             :     if ( fv->b.sf->rules!=NULL )
    2764             :         SFModifyComposition(fv->b.sf);
    2765             : }
    2766             : 
    2767             : static void FVMenuBuildSyllables(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    2768             :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    2769             :     if ( fv->b.sf->rules!=NULL )
    2770             :         SFBuildSyllables(fv->b.sf);
    2771             : }
    2772             : #endif
    2773             : 
    2774           0 : static void FVMenuCompareFonts(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    2775           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    2776           0 :     FontCompareDlg(fv);
    2777           0 : }
    2778             : 
    2779           0 : static void FVMenuMergeFonts(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    2780           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    2781           0 :     FVMergeFonts(fv);
    2782           0 : }
    2783             : 
    2784           0 : static void FVMenuInterpFonts(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    2785           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    2786           0 :     FVInterpolateFonts(fv);
    2787           0 : }
    2788             : 
    2789             : static void FVShowInfo(FontView *fv);
    2790             : 
    2791           0 : void FVChangeChar(FontView *fv,int i) {
    2792             : 
    2793           0 :     if ( i!=-1 ) {
    2794           0 :         FVDeselectAll(fv);
    2795           0 :         fv->b.selected[i] = true;
    2796           0 :         fv->sel_index = 1;
    2797           0 :         fv->end_pos = fv->pressed_pos = i;
    2798           0 :         FVToggleCharSelected(fv,i);
    2799           0 :         FVScrollToChar(fv,i);
    2800           0 :         FVShowInfo(fv);
    2801             :     }
    2802           0 : }
    2803             : 
    2804           0 : void FVScrollToChar(FontView *fv,int i) {
    2805             : 
    2806           0 :     if ( fv->v==NULL || fv->colcnt==0 )   /* Can happen in scripts */
    2807           0 : return;
    2808             : 
    2809           0 :     if ( i!=-1 ) {
    2810           0 :         if ( i/fv->colcnt<fv->rowoff || i/fv->colcnt >= fv->rowoff+fv->rowcnt ) {
    2811           0 :             fv->rowoff = i/fv->colcnt;
    2812           0 :             if ( fv->rowcnt>= 3 )
    2813           0 :                 --fv->rowoff;
    2814           0 :             if ( fv->rowoff+fv->rowcnt>=fv->rowltot )
    2815           0 :                 fv->rowoff = fv->rowltot-fv->rowcnt;
    2816           0 :             if ( fv->rowoff<0 ) fv->rowoff = 0;
    2817           0 :             GScrollBarSetPos(fv->vsb,fv->rowoff);
    2818           0 :             GDrawRequestExpose(fv->v,NULL,false);
    2819             :         }
    2820             :     }
    2821             : }
    2822             : 
    2823           0 : static void FVScrollToGID(FontView *fv,int gid) {
    2824           0 :     FVScrollToChar(fv,fv->b.map->backmap[gid]);
    2825           0 : }
    2826             : 
    2827           0 : static void FV_ChangeGID(FontView *fv,int gid) {
    2828           0 :     FVChangeChar(fv,fv->b.map->backmap[gid]);
    2829           0 : }
    2830             : 
    2831           0 : static void _FVMenuChangeChar(FontView *fv,int mid ) {
    2832           0 :     SplineFont *sf = fv->b.sf;
    2833           0 :     EncMap *map = fv->b.map;
    2834           0 :     int pos = FVAnyCharSelected(fv);
    2835             : 
    2836           0 :     if ( pos>=0 ) {
    2837           0 :         if ( mid==MID_Next )
    2838           0 :             ++pos;
    2839           0 :         else if ( mid==MID_Prev )
    2840           0 :             --pos;
    2841           0 :         else if ( mid==MID_NextDef ) {
    2842           0 :             for ( ++pos; pos<map->enccount &&
    2843           0 :                     (map->map[pos]==-1 || !SCWorthOutputting(sf->glyphs[map->map[pos]]) ||
    2844           0 :                         (fv->show!=fv->filled && fv->show->glyphs[map->map[pos]]==NULL ));
    2845           0 :                     ++pos );
    2846           0 :             if ( pos>=map->enccount ) {
    2847           0 :                 int selpos = FVAnyCharSelected(fv);
    2848           0 :                 char *iconv_name = map->enc->iconv_name ? map->enc->iconv_name :
    2849           0 :                         map->enc->enc_name;
    2850           0 :                 if ( strstr(iconv_name,"2022")!=NULL && selpos<0x2121 )
    2851           0 :                     pos = 0x2121;
    2852           0 :                 else if ( strstr(iconv_name,"EUC")!=NULL && selpos<0xa1a1 )
    2853           0 :                     pos = 0xa1a1;
    2854           0 :                 else if ( map->enc->is_tradchinese ) {
    2855           0 :                     if ( strstrmatch(map->enc->enc_name,"HK")!=NULL &&
    2856             :                             selpos<0x8140 )
    2857           0 :                         pos = 0x8140;
    2858             :                     else
    2859           0 :                         pos = 0xa140;
    2860           0 :                 } else if ( map->enc->is_japanese ) {
    2861           0 :                     if ( strstrmatch(iconv_name,"SJIS")!=NULL ||
    2862           0 :                             (strstrmatch(iconv_name,"JIS")!=NULL && strstrmatch(iconv_name,"SHIFT")!=NULL )) {
    2863           0 :                         if ( selpos<0x8100 )
    2864           0 :                             pos = 0x8100;
    2865           0 :                         else if ( selpos<0xb000 )
    2866           0 :                             pos = 0xb000;
    2867             :                     }
    2868           0 :                 } else if ( map->enc->is_korean ) {
    2869           0 :                     if ( strstrmatch(iconv_name,"JOHAB")!=NULL ) {
    2870           0 :                         if ( selpos<0x8431 )
    2871           0 :                             pos = 0x8431;
    2872             :                     } else {    /* Wansung, EUC-KR */
    2873           0 :                         if ( selpos<0xa1a1 )
    2874           0 :                             pos = 0xa1a1;
    2875             :                     }
    2876           0 :                 } else if ( map->enc->is_simplechinese ) {
    2877           0 :                     if ( strmatch(iconv_name,"EUC-CN")==0 && selpos<0xa1a1 )
    2878           0 :                         pos = 0xa1a1;
    2879             :                 }
    2880           0 :                 if ( pos>=map->enccount )
    2881           0 : return;
    2882             :             }
    2883           0 :         } else if ( mid==MID_PrevDef ) {
    2884           0 :             for ( --pos; pos>=0 &&
    2885           0 :                     (map->map[pos]==-1 || !SCWorthOutputting(sf->glyphs[map->map[pos]]) ||
    2886           0 :                         (fv->show!=fv->filled && fv->show->glyphs[map->map[pos]]==NULL ));
    2887           0 :                     --pos );
    2888           0 :             if ( pos<0 )
    2889           0 : return;
    2890             :         }
    2891             :     }
    2892           0 :     if ( pos<0 ) pos = map->enccount-1;
    2893           0 :     else if ( pos>= map->enccount ) pos = 0;
    2894           0 :     if ( pos>=0 && pos<map->enccount )
    2895           0 :         FVChangeChar(fv,pos);
    2896             : }
    2897             : 
    2898           0 : static void FVMenuChangeChar(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
    2899           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    2900           0 :     _FVMenuChangeChar(fv,mi->mid);
    2901           0 : }
    2902             : 
    2903           0 : static void FVShowSubFont(FontView *fv,SplineFont *new) {
    2904             :     MetricsView *mv, *mvnext;
    2905             :     BDFFont *newbdf;
    2906           0 :     int wascompact = fv->b.normal!=NULL;
    2907             :     extern int use_freetype_to_rasterize_fv;
    2908             : 
    2909           0 :     for ( mv=fv->b.sf->metrics; mv!=NULL; mv = mvnext ) {
    2910             :         /* Don't bother trying to fix up metrics views, just not worth it */
    2911           0 :         mvnext = mv->next;
    2912           0 :         GDrawDestroyWindow(mv->gw);
    2913             :     }
    2914           0 :     if ( wascompact ) {
    2915           0 :         EncMapFree(fv->b.map);
    2916           0 :         if (fv->b.map == fv->b.sf->map) { fv->b.sf->map = fv->b.normal; }
    2917           0 :         fv->b.map = fv->b.normal;
    2918           0 :         fv->b.normal = NULL;
    2919           0 :         fv->b.selected = realloc(fv->b.selected,fv->b.map->enccount);
    2920           0 :         memset(fv->b.selected,0,fv->b.map->enccount);
    2921             :     }
    2922           0 :     CIDSetEncMap((FontViewBase *) fv,new);
    2923           0 :     if ( wascompact ) {
    2924           0 :         fv->b.normal = EncMapCopy(fv->b.map);
    2925           0 :         CompactEncMap(fv->b.map,fv->b.sf);
    2926           0 :         FontViewReformatOne(&fv->b);
    2927           0 :         FVSetTitle(&fv->b);
    2928             :     }
    2929           0 :     newbdf = SplineFontPieceMeal(fv->b.sf,fv->b.active_layer,fv->filled->pixelsize,72,
    2930           0 :             (fv->antialias?pf_antialias:0)|(fv->bbsized?pf_bbsized:0)|
    2931           0 :                 (use_freetype_to_rasterize_fv && !fv->b.sf->strokedfont && !fv->b.sf->multilayer?pf_ft_nohints:0),
    2932             :             NULL);
    2933           0 :     BDFFontFree(fv->filled);
    2934           0 :     if ( fv->filled == fv->show )
    2935           0 :         fv->show = newbdf;
    2936           0 :     fv->filled = newbdf;
    2937           0 :     GDrawRequestExpose(fv->v,NULL,true);
    2938           0 : }
    2939             : 
    2940           0 : static void FVMenuGotoChar(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    2941           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    2942           0 :     int merge_with_selection = false;
    2943           0 :     int pos = GotoChar(fv->b.sf,fv->b.map,&merge_with_selection);
    2944           0 :     if ( fv->b.cidmaster!=NULL && pos!=-1 && !fv->b.map->enc->is_compact ) {
    2945           0 :         SplineFont *cidmaster = fv->b.cidmaster;
    2946           0 :         int k, hadk= cidmaster->subfontcnt;
    2947           0 :         for ( k=0; k<cidmaster->subfontcnt; ++k ) {
    2948           0 :             SplineFont *sf = cidmaster->subfonts[k];
    2949           0 :             if ( pos<sf->glyphcnt && sf->glyphs[pos]!=NULL )
    2950           0 :         break;
    2951           0 :             if ( pos<sf->glyphcnt )
    2952           0 :                 hadk = k;
    2953             :         }
    2954           0 :         if ( k==cidmaster->subfontcnt && pos>=fv->b.sf->glyphcnt )
    2955           0 :             k = hadk;
    2956           0 :         if ( k!=cidmaster->subfontcnt && cidmaster->subfonts[k] != fv->b.sf )
    2957           0 :             FVShowSubFont(fv,cidmaster->subfonts[k]);
    2958           0 :         if ( pos>=fv->b.sf->glyphcnt )
    2959           0 :             pos = -1;
    2960             :     }
    2961           0 :     if ( !merge_with_selection )
    2962           0 :         FVChangeChar(fv,pos);
    2963             :     else {
    2964           0 :         if ( !fv->b.selected[pos] ) {
    2965           0 :             fv->b.selected[pos] = ++fv->sel_index;
    2966           0 :             FVToggleCharSelected(fv,pos);
    2967             :         }
    2968           0 :         fv->end_pos = fv->pressed_pos = pos;
    2969           0 :         FVScrollToChar(fv,pos);
    2970           0 :         FVShowInfo(fv);
    2971             :     }
    2972           0 : }
    2973             : 
    2974           0 : static void FVMenuLigatures(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    2975           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    2976           0 :     SFShowLigatures(fv->b.sf,NULL);
    2977           0 : }
    2978             : 
    2979           0 : static void FVMenuKernPairs(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    2980           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    2981           0 :     SFKernClassTempDecompose(fv->b.sf,false);
    2982           0 :     SFShowKernPairs(fv->b.sf,NULL,NULL,fv->b.active_layer);
    2983           0 :     SFKernCleanup(fv->b.sf,false);
    2984           0 : }
    2985             : 
    2986           0 : static void FVMenuAnchorPairs(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
    2987           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    2988           0 :     SFShowKernPairs(fv->b.sf,NULL,mi->ti.userdata,fv->b.active_layer);
    2989           0 : }
    2990             : 
    2991           0 : static void FVMenuShowAtt(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    2992           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    2993           0 :     ShowAtt(fv->b.sf,fv->b.active_layer);
    2994           0 : }
    2995             : 
    2996           0 : static void FVMenuDisplaySubs(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    2997           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    2998             : 
    2999           0 :     if ( fv->cur_subtable!=0 ) {
    3000           0 :         fv->cur_subtable = NULL;
    3001             :     } else {
    3002           0 :         SplineFont *sf = fv->b.sf;
    3003             :         OTLookup *otf;
    3004             :         struct lookup_subtable *sub;
    3005             :         int cnt, k;
    3006           0 :         char **names = NULL;
    3007           0 :         if ( sf->cidmaster ) sf=sf->cidmaster;
    3008           0 :         for ( k=0; k<2; ++k ) {
    3009           0 :             cnt = 0;
    3010           0 :             for ( otf = sf->gsub_lookups; otf!=NULL; otf=otf->next ) {
    3011           0 :                 if ( otf->lookup_type==gsub_single ) {
    3012           0 :                     for ( sub=otf->subtables; sub!=NULL; sub=sub->next ) {
    3013           0 :                         if ( names )
    3014           0 :                             names[cnt] = sub->subtable_name;
    3015           0 :                         ++cnt;
    3016             :                     }
    3017             :                 }
    3018             :             }
    3019           0 :             if ( cnt==0 )
    3020           0 :         break;
    3021           0 :             if ( names==NULL )
    3022           0 :                 names = malloc((cnt+3) * sizeof(char *));
    3023             :             else {
    3024           0 :                 names[cnt++] = "-";
    3025           0 :                 names[cnt++] = _("New Lookup Subtable...");
    3026           0 :                 names[cnt] = NULL;
    3027             :             }
    3028             :         }
    3029           0 :         sub = NULL;
    3030           0 :         if ( names!=NULL ) {
    3031           0 :             int ret = gwwv_choose(_("Display Substitution..."), (const char **) names, cnt, 0,
    3032           0 :                     _("Pick a substitution to display in the window."));
    3033           0 :             if ( ret!=-1 )
    3034           0 :                 sub = SFFindLookupSubtable(sf,names[ret]);
    3035           0 :             free(names);
    3036           0 :             if ( ret==-1 )
    3037           0 : return;
    3038             :         }
    3039           0 :         if ( sub==NULL )
    3040           0 :             sub = SFNewLookupSubtableOfType(sf,gsub_single,NULL,fv->b.active_layer);
    3041           0 :         if ( sub!=NULL )
    3042           0 :             fv->cur_subtable = sub;
    3043             :     }
    3044           0 :     GDrawRequestExpose(fv->v,NULL,false);
    3045             : }
    3046             : 
    3047           0 : static void FVChangeDisplayFont(FontView *fv,BDFFont *bdf) {
    3048           0 :     int samesize=0;
    3049             :     int rcnt, ccnt;
    3050             :     int oldr, oldc;
    3051           0 :     int first_time = fv->show==NULL;
    3052             : 
    3053           0 :     if ( fv->v==NULL )                       /* Can happen in scripts */
    3054           0 : return;
    3055             : 
    3056           0 :     if ( fv->show!=bdf ) {
    3057           0 :         oldc = fv->cbw*fv->colcnt;
    3058           0 :         oldr = fv->cbh*fv->rowcnt;
    3059             : 
    3060           0 :         fv->show = bdf;
    3061           0 :         fv->b.active_bitmap = bdf==fv->filled ? NULL : bdf;
    3062           0 :         if ( fv->user_requested_magnify!=-1 )
    3063           0 :             fv->magnify=fv->user_requested_magnify;
    3064           0 :         else if ( bdf->pixelsize<20 ) {
    3065           0 :             if ( bdf->pixelsize<=9 )
    3066           0 :                 fv->magnify = 3;
    3067             :             else
    3068           0 :                 fv->magnify = 2;
    3069           0 :             samesize = ( fv->show && fv->cbw == (bdf->pixelsize*fv->magnify)+1 );
    3070             :         } else
    3071           0 :             fv->magnify = 1;
    3072           0 :         if ( !first_time && fv->cbw == fv->magnify*bdf->pixelsize+1 )
    3073           0 :             samesize = true;
    3074           0 :         fv->cbw = (bdf->pixelsize*fv->magnify)+1;
    3075           0 :         fv->cbh = (bdf->pixelsize*fv->magnify)+1+fv->lab_height+1;
    3076           0 :         fv->resize_expected = !samesize;
    3077           0 :         ccnt = fv->b.sf->desired_col_cnt;
    3078           0 :         rcnt = fv->b.sf->desired_row_cnt;
    3079           0 :         if ((( bdf->pixelsize<=fv->b.sf->display_size || bdf->pixelsize<=-fv->b.sf->display_size ) &&
    3080           0 :                  fv->b.sf->top_enc!=-1 /* Not defaulting */ ) ||
    3081           0 :                 bdf->pixelsize<=48 ) {
    3082             :             /* use the desired sizes */
    3083             :         } else {
    3084           0 :             if ( bdf->pixelsize>48 ) {
    3085           0 :                 ccnt = 8;
    3086           0 :                 rcnt = 2;
    3087           0 :             } else if ( bdf->pixelsize>=96 ) {
    3088           0 :                 ccnt = 4;
    3089           0 :                 rcnt = 1;
    3090             :             }
    3091           0 :             if ( !first_time ) {
    3092           0 :                 if ( ccnt < oldc/fv->cbw )
    3093           0 :                     ccnt = oldc/fv->cbw;
    3094           0 :                 if ( rcnt < oldr/fv->cbh )
    3095           0 :                     rcnt = oldr/fv->cbh;
    3096             :             }
    3097             :         }
    3098           0 :         if ( samesize ) {
    3099           0 :             GDrawRequestExpose(fv->v,NULL,false);
    3100           0 :         } else if ( fv->b.container!=NULL && fv->b.container->funcs->doResize!=NULL ) {
    3101           0 :             (fv->b.container->funcs->doResize)(fv->b.container,&fv->b,
    3102           0 :                     ccnt*fv->cbw+1+GDrawPointsToPixels(fv->gw,_GScrollBar_Width),
    3103           0 :                     rcnt*fv->cbh+1+fv->mbh+fv->infoh);
    3104             :         } else {
    3105           0 :             GDrawResize(fv->gw,
    3106           0 :                     ccnt*fv->cbw+1+GDrawPointsToPixels(fv->gw,_GScrollBar_Width),
    3107           0 :                     rcnt*fv->cbh+1+fv->mbh+fv->infoh);
    3108             :         }
    3109             :     }
    3110             : }
    3111             : 
    3112             : struct md_data {
    3113             :     int done;
    3114             :     int ish;
    3115             :     FontView *fv;
    3116             : };
    3117             : 
    3118           0 : static int md_e_h(GWindow gw, GEvent *e) {
    3119           0 :     if ( e->type==et_close ) {
    3120           0 :         struct md_data *d = GDrawGetUserData(gw);
    3121           0 :         d->done = true;
    3122           0 :     } else if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
    3123           0 :         struct md_data *d = GDrawGetUserData(gw);
    3124             :         static int masks[] = { fvm_baseline, fvm_origin, fvm_advanceat, fvm_advanceto, -1 };
    3125             :         int i, metrics;
    3126           0 :         if ( GGadgetGetCid(e->u.control.g)==10 ) {
    3127           0 :             metrics = 0;
    3128           0 :             for ( i=0; masks[i]!=-1 ; ++i )
    3129           0 :                 if ( GGadgetIsChecked(GWidgetGetControl(gw,masks[i])))
    3130           0 :                     metrics |= masks[i];
    3131           0 :             if ( d->ish )
    3132           0 :                 default_fv_showhmetrics = d->fv->showhmetrics = metrics;
    3133             :             else
    3134           0 :                 default_fv_showvmetrics = d->fv->showvmetrics = metrics;
    3135             :         }
    3136           0 :         d->done = true;
    3137           0 :     } else if ( e->type==et_char ) {
    3138           0 : return( false );
    3139             :     }
    3140           0 : return( true );
    3141             : }
    3142             : 
    3143           0 : static void FVMenuShowMetrics(GWindow fvgw,struct gmenuitem *mi, GEvent *UNUSED(e)) {
    3144           0 :     FontView *fv = (FontView *) GDrawGetUserData(fvgw);
    3145             :     GRect pos;
    3146             :     GWindow gw;
    3147             :     GWindowAttrs wattrs;
    3148             :     struct md_data d;
    3149             :     GGadgetCreateData gcd[7];
    3150             :     GTextInfo label[6];
    3151           0 :     int metrics = mi->mid==MID_ShowHMetrics ? fv->showhmetrics : fv->showvmetrics;
    3152             : 
    3153           0 :     d.fv = fv;
    3154           0 :     d.done = 0;
    3155           0 :     d.ish = mi->mid==MID_ShowHMetrics;
    3156             : 
    3157           0 :     memset(&wattrs,0,sizeof(wattrs));
    3158           0 :     wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_undercursor|wam_restrict;
    3159           0 :     wattrs.event_masks = ~(1<<et_charup);
    3160           0 :     wattrs.restrict_input_to_me = 1;
    3161           0 :     wattrs.undercursor = 1;
    3162           0 :     wattrs.cursor = ct_pointer;
    3163           0 :     wattrs.utf8_window_title = d.ish?_("Show H. Metrics"):_("Show V. Metrics");
    3164           0 :     pos.x = pos.y = 0;
    3165           0 :     pos.width =GDrawPointsToPixels(NULL,GGadgetScale(170));
    3166           0 :     pos.height = GDrawPointsToPixels(NULL,130);
    3167           0 :     gw = GDrawCreateTopWindow(NULL,&pos,md_e_h,&d,&wattrs);
    3168             : 
    3169           0 :     memset(&label,0,sizeof(label));
    3170           0 :     memset(&gcd,0,sizeof(gcd));
    3171             : 
    3172           0 :     label[0].text = (unichar_t *) _("Baseline");
    3173           0 :     label[0].text_is_1byte = true;
    3174           0 :     gcd[0].gd.label = &label[0];
    3175           0 :     gcd[0].gd.pos.x = 8; gcd[0].gd.pos.y = 8;
    3176           0 :     gcd[0].gd.flags = gg_enabled|gg_visible|(metrics&fvm_baseline?gg_cb_on:0);
    3177           0 :     gcd[0].gd.cid = fvm_baseline;
    3178           0 :     gcd[0].creator = GCheckBoxCreate;
    3179             : 
    3180           0 :     label[1].text = (unichar_t *) _("Origin");
    3181           0 :     label[1].text_is_1byte = true;
    3182           0 :     gcd[1].gd.label = &label[1];
    3183           0 :     gcd[1].gd.pos.x = 8; gcd[1].gd.pos.y = gcd[0].gd.pos.y+16;
    3184           0 :     gcd[1].gd.flags = gg_enabled|gg_visible|(metrics&fvm_origin?gg_cb_on:0);
    3185           0 :     gcd[1].gd.cid = fvm_origin;
    3186           0 :     gcd[1].creator = GCheckBoxCreate;
    3187             : 
    3188           0 :     label[2].text = (unichar_t *) _("Advance Width as a Line");
    3189           0 :     label[2].text_is_1byte = true;
    3190           0 :     gcd[2].gd.label = &label[2];
    3191           0 :     gcd[2].gd.pos.x = 8; gcd[2].gd.pos.y = gcd[1].gd.pos.y+16;
    3192           0 :     gcd[2].gd.flags = gg_enabled|gg_visible|gg_utf8_popup|(metrics&fvm_advanceat?gg_cb_on:0);
    3193           0 :     gcd[2].gd.cid = fvm_advanceat;
    3194           0 :     gcd[2].gd.popup_msg = (unichar_t *) _("Display the advance width as a line\nperpendicular to the advance direction");
    3195           0 :     gcd[2].creator = GCheckBoxCreate;
    3196             : 
    3197           0 :     label[3].text = (unichar_t *) _("Advance Width as a Bar");
    3198           0 :     label[3].text_is_1byte = true;
    3199           0 :     gcd[3].gd.label = &label[3];
    3200           0 :     gcd[3].gd.pos.x = 8; gcd[3].gd.pos.y = gcd[2].gd.pos.y+16;
    3201           0 :     gcd[3].gd.flags = gg_enabled|gg_visible|gg_utf8_popup|(metrics&fvm_advanceto?gg_cb_on:0);
    3202           0 :     gcd[3].gd.cid = fvm_advanceto;
    3203           0 :     gcd[3].gd.popup_msg = (unichar_t *) _("Display the advance width as a bar under the glyph\nshowing the extent of the advance");
    3204           0 :     gcd[3].creator = GCheckBoxCreate;
    3205             : 
    3206           0 :     label[4].text = (unichar_t *) _("_OK");
    3207           0 :     label[4].text_is_1byte = true;
    3208           0 :     label[4].text_in_resource = true;
    3209           0 :     gcd[4].gd.label = &label[4];
    3210           0 :     gcd[4].gd.pos.x = 20-3; gcd[4].gd.pos.y = GDrawPixelsToPoints(NULL,pos.height)-35-3;
    3211           0 :     gcd[4].gd.pos.width = -1; gcd[4].gd.pos.height = 0;
    3212           0 :     gcd[4].gd.flags = gg_visible | gg_enabled | gg_but_default;
    3213           0 :     gcd[4].gd.cid = 10;
    3214           0 :     gcd[4].creator = GButtonCreate;
    3215             : 
    3216           0 :     label[5].text = (unichar_t *) _("_Cancel");
    3217           0 :     label[5].text_is_1byte = true;
    3218           0 :     label[5].text_in_resource = true;
    3219           0 :     gcd[5].gd.label = &label[5];
    3220           0 :     gcd[5].gd.pos.x = -20; gcd[5].gd.pos.y = gcd[4].gd.pos.y+3;
    3221           0 :     gcd[5].gd.pos.width = -1; gcd[5].gd.pos.height = 0;
    3222           0 :     gcd[5].gd.flags = gg_visible | gg_enabled | gg_but_cancel;
    3223           0 :     gcd[5].creator = GButtonCreate;
    3224             : 
    3225           0 :     GGadgetsCreate(gw,gcd);
    3226             : 
    3227           0 :     GDrawSetVisible(gw,true);
    3228           0 :     while ( !d.done )
    3229           0 :         GDrawProcessOneEvent(NULL);
    3230           0 :     GDrawDestroyWindow(gw);
    3231             : 
    3232           0 :     SavePrefs(true);
    3233           0 :     GDrawRequestExpose(fv->v,NULL,false);
    3234           0 : }
    3235             : 
    3236           0 : static void FV_ChangeDisplayBitmap(FontView *fv,BDFFont *bdf) {
    3237           0 :     FVChangeDisplayFont(fv,bdf);
    3238           0 :     if (fv->show != NULL) {
    3239           0 :         fv->b.sf->display_size = fv->show->pixelsize;
    3240             :     } else {
    3241           0 :         fv->b.sf->display_size = 1;
    3242             :     }
    3243           0 : }
    3244             : 
    3245           0 : static void FVMenuSize(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
    3246           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    3247           0 :     int dspsize = fv->filled->pixelsize;
    3248           0 :     int changedmodifier = false;
    3249             :     extern int use_freetype_to_rasterize_fv;
    3250             : 
    3251           0 :     fv->magnify = 1;
    3252           0 :     fv->user_requested_magnify = -1;
    3253           0 :     if ( mi->mid == MID_24 )
    3254           0 :         default_fv_font_size = dspsize = 24;
    3255           0 :     else if ( mi->mid == MID_36 )
    3256           0 :         default_fv_font_size = dspsize = 36;
    3257           0 :     else if ( mi->mid == MID_48 )
    3258           0 :         default_fv_font_size = dspsize = 48;
    3259           0 :     else if ( mi->mid == MID_72 )
    3260           0 :         default_fv_font_size = dspsize = 72;
    3261           0 :     else if ( mi->mid == MID_96 )
    3262           0 :         default_fv_font_size = dspsize = 96;
    3263           0 :     else if ( mi->mid == MID_128 )
    3264           0 :         default_fv_font_size = dspsize = 128;
    3265           0 :     else if ( mi->mid == MID_FitToBbox ) {
    3266           0 :         default_fv_bbsized = fv->bbsized = !fv->bbsized;
    3267           0 :         fv->b.sf->display_bbsized = fv->bbsized;
    3268           0 :         changedmodifier = true;
    3269             :     } else {
    3270           0 :         default_fv_antialias = fv->antialias = !fv->antialias;
    3271           0 :         fv->b.sf->display_antialias = fv->antialias;
    3272           0 :         changedmodifier = true;
    3273             :     }
    3274             : 
    3275           0 :     SavePrefs(true);
    3276           0 :     if ( fv->filled!=fv->show || fv->filled->pixelsize != dspsize || changedmodifier ) {
    3277             :         BDFFont *new, *old;
    3278           0 :         old = fv->filled;
    3279           0 :         new = SplineFontPieceMeal(fv->b.sf,fv->b.active_layer,dspsize,72,
    3280           0 :             (fv->antialias?pf_antialias:0)|(fv->bbsized?pf_bbsized:0)|
    3281           0 :                 (use_freetype_to_rasterize_fv && !fv->b.sf->strokedfont && !fv->b.sf->multilayer?pf_ft_nohints:0),
    3282             :             NULL);
    3283           0 :         fv->filled = new;
    3284           0 :         FVChangeDisplayFont(fv,new);
    3285           0 :         BDFFontFree(old);
    3286           0 :         fv->b.sf->display_size = -dspsize;
    3287           0 :         if ( fv->b.cidmaster!=NULL ) {
    3288             :             int i;
    3289           0 :             for ( i=0; i<fv->b.cidmaster->subfontcnt; ++i )
    3290           0 :                 fv->b.cidmaster->subfonts[i]->display_size = -dspsize;
    3291             :         }
    3292             :     }
    3293           0 : }
    3294             : 
    3295           0 : void FVSetUIToMatch(FontView *destfv,FontView *srcfv) {
    3296             :     extern int use_freetype_to_rasterize_fv;
    3297             : 
    3298           0 :     if ( destfv->filled==NULL || srcfv->filled==NULL )
    3299           0 : return;
    3300           0 :     if ( destfv->magnify!=srcfv->magnify ||
    3301           0 :             destfv->user_requested_magnify!=srcfv->user_requested_magnify ||
    3302           0 :             destfv->bbsized!=srcfv->bbsized ||
    3303           0 :             destfv->antialias!=srcfv->antialias ||
    3304           0 :             destfv->filled->pixelsize != srcfv->filled->pixelsize ) {
    3305             :         BDFFont *new, *old;
    3306           0 :         destfv->magnify = srcfv->magnify;
    3307           0 :         destfv->user_requested_magnify = srcfv->user_requested_magnify;
    3308           0 :         destfv->bbsized = srcfv->bbsized;
    3309           0 :         destfv->antialias = srcfv->antialias;
    3310           0 :         old = destfv->filled;
    3311           0 :         new = SplineFontPieceMeal(destfv->b.sf,destfv->b.active_layer,srcfv->filled->pixelsize,72,
    3312           0 :             (destfv->antialias?pf_antialias:0)|(destfv->bbsized?pf_bbsized:0)|
    3313           0 :                 (use_freetype_to_rasterize_fv && !destfv->b.sf->strokedfont && !destfv->b.sf->multilayer?pf_ft_nohints:0),
    3314             :             NULL);
    3315           0 :         destfv->filled = new;
    3316           0 :         FVChangeDisplayFont(destfv,new);
    3317           0 :         BDFFontFree(old);
    3318             :     }
    3319             : }
    3320             : 
    3321           0 : static void FV_LayerChanged( FontView *fv ) {
    3322             :     extern int use_freetype_to_rasterize_fv;
    3323             :     BDFFont *new, *old;
    3324             : 
    3325           0 :     fv->magnify = 1;
    3326           0 :     fv->user_requested_magnify = -1;
    3327             : 
    3328           0 :     old = fv->filled;
    3329           0 :     new = SplineFontPieceMeal(fv->b.sf,fv->b.active_layer,fv->filled->pixelsize,72,
    3330           0 :         (fv->antialias?pf_antialias:0)|(fv->bbsized?pf_bbsized:0)|
    3331           0 :             (use_freetype_to_rasterize_fv && !fv->b.sf->strokedfont && !fv->b.sf->multilayer?pf_ft_nohints:0),
    3332             :         NULL);
    3333           0 :     fv->filled = new;
    3334           0 :     FVChangeDisplayFont(fv,new);
    3335           0 :     fv->b.sf->display_size = -fv->filled->pixelsize;
    3336           0 :     BDFFontFree(old);
    3337           0 : }
    3338             : 
    3339           0 : static void FVMenuChangeLayer(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
    3340           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    3341             : 
    3342           0 :     fv->b.active_layer = mi->mid;
    3343           0 :     fv->b.sf->display_layer = mi->mid;
    3344           0 :     FV_LayerChanged(fv);
    3345           0 : }
    3346             : 
    3347           0 : static void FVMenuMagnify(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    3348           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    3349           0 :     int magnify = fv->user_requested_magnify!=-1 ? fv->user_requested_magnify : fv->magnify;
    3350             :     char def[20], *end, *ret;
    3351             :     int val;
    3352           0 :     BDFFont *show = fv->show;
    3353             : 
    3354           0 :     sprintf( def, "%d", magnify );
    3355           0 :     ret = gwwv_ask_string(_("Bitmap Magnification..."),def,_("Please specify a bitmap magnification factor."));
    3356           0 :     if ( ret==NULL )
    3357           0 : return;
    3358           0 :     val = strtol(ret,&end,10);
    3359           0 :     if ( val<1 || val>5 || *end!='\0' )
    3360           0 :         ff_post_error( _("Bad Number"),_("Bad Number") );
    3361             :     else {
    3362           0 :         fv->user_requested_magnify = val;
    3363           0 :         fv->show = fv->filled;
    3364           0 :         fv->b.active_bitmap = NULL;
    3365           0 :         FVChangeDisplayFont(fv,show);
    3366             :     }
    3367           0 :     free(ret);
    3368             : }
    3369             : 
    3370           0 : static void FVMenuWSize(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
    3371           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    3372             :     int h,v;
    3373             :     extern int default_fv_col_count, default_fv_row_count;
    3374             : 
    3375           0 :     if ( mi->mid == MID_32x8 ) {
    3376           0 :         h = 32; v=8;
    3377           0 :     } else if ( mi->mid == MID_16x4 ) {
    3378           0 :         h = 16; v=4;
    3379             :     } else {
    3380           0 :         h = 8; v=2;
    3381             :     }
    3382           0 :     GDrawResize(fv->gw,
    3383           0 :             h*fv->cbw+1+GDrawPointsToPixels(fv->gw,_GScrollBar_Width),
    3384           0 :             v*fv->cbh+1+fv->mbh+fv->infoh);
    3385           0 :     fv->b.sf->desired_col_cnt = default_fv_col_count = h;
    3386           0 :     fv->b.sf->desired_row_cnt = default_fv_row_count = v;
    3387             : 
    3388           0 :     SavePrefs(true);
    3389           0 : }
    3390             : 
    3391           0 : static void FVMenuGlyphLabel(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
    3392           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    3393             : 
    3394           0 :     default_fv_glyphlabel = fv->glyphlabel = mi->mid;
    3395             : 
    3396           0 :     GDrawRequestExpose(fv->v,NULL,false);
    3397             : 
    3398           0 :     SavePrefs(true);
    3399           0 : }
    3400             : 
    3401           0 : static void FVMenuShowBitmap(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
    3402           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    3403           0 :     BDFFont *bdf = mi->ti.userdata;
    3404             : 
    3405           0 :     FV_ChangeDisplayBitmap(fv,bdf);             /* Let's not change any of the others */
    3406           0 : }
    3407             : 
    3408           0 : static void FV_ShowFilled(FontView *fv) {
    3409             : 
    3410           0 :     fv->magnify = 1;
    3411           0 :     fv->user_requested_magnify = 1;
    3412           0 :     if ( fv->show!=fv->filled )
    3413           0 :         FVChangeDisplayFont(fv,fv->filled);
    3414           0 :     fv->b.sf->display_size = -fv->filled->pixelsize;
    3415           0 :     fv->b.active_bitmap = NULL;
    3416           0 : }
    3417             : 
    3418           0 : static void FVMenuCenter(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
    3419           0 :     FontViewBase *fv = (FontViewBase *) GDrawGetUserData(gw);
    3420           0 :     FVMetricsCenter(fv,mi->mid==MID_Center);
    3421           0 : }
    3422             : 
    3423           0 : static void FVMenuSetWidth(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
    3424           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    3425             : 
    3426           0 :     if ( FVAnyCharSelected(fv)==-1 )
    3427           0 : return;
    3428           0 :     if ( mi->mid == MID_SetVWidth && !fv->b.sf->hasvmetrics )
    3429           0 : return;
    3430           0 :     FVSetWidth(fv,mi->mid==MID_SetWidth   ?wt_width:
    3431           0 :                   mi->mid==MID_SetLBearing?wt_lbearing:
    3432           0 :                   mi->mid==MID_SetRBearing?wt_rbearing:
    3433           0 :                   mi->mid==MID_SetBearings?wt_bearings:
    3434             :                   wt_vwidth);
    3435             : }
    3436             : 
    3437           0 : static void FVMenuAutoWidth(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    3438           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    3439             : 
    3440           0 :     FVAutoWidth2(fv);
    3441           0 : }
    3442             : 
    3443           0 : static void FVMenuKernByClasses(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    3444           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    3445             : 
    3446           0 :     ShowKernClasses(fv->b.sf,NULL,fv->b.active_layer,false);
    3447           0 : }
    3448             : 
    3449           0 : static void FVMenuVKernByClasses(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    3450           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    3451             : 
    3452           0 :     ShowKernClasses(fv->b.sf,NULL,fv->b.active_layer,true);
    3453           0 : }
    3454             : 
    3455           0 : static void FVMenuRemoveKern(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    3456           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    3457             : 
    3458           0 :     FVRemoveKerns(&fv->b);
    3459           0 : }
    3460             : 
    3461           0 : static void FVMenuRemoveVKern(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    3462           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    3463             : 
    3464           0 :     FVRemoveVKerns(&fv->b);
    3465           0 : }
    3466             : 
    3467           0 : static void FVMenuKPCloseup(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    3468           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    3469             :     int i;
    3470             : 
    3471           0 :     for ( i=0; i<fv->b.map->enccount; ++i )
    3472           0 :         if ( fv->b.selected[i] )
    3473           0 :     break;
    3474           0 :     KernPairD(fv->b.sf,i==fv->b.map->enccount?NULL:
    3475           0 :                     fv->b.map->map[i]==-1?NULL:
    3476           0 :                     fv->b.sf->glyphs[fv->b.map->map[i]],NULL,fv->b.active_layer,
    3477             :                     false);
    3478           0 : }
    3479             : 
    3480           0 : static void FVMenuVKernFromHKern(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    3481           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    3482             : 
    3483           0 :     FVVKernFromHKern(&fv->b);
    3484           0 : }
    3485             : 
    3486           0 : static void FVMenuAutoHint(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    3487           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    3488           0 :     FVAutoHint( &fv->b );
    3489           0 : }
    3490             : 
    3491           0 : static void FVMenuAutoHintSubs(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    3492           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    3493           0 :     FVAutoHintSubs( &fv->b );
    3494           0 : }
    3495             : 
    3496           0 : static void FVMenuAutoCounter(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    3497           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    3498           0 :     FVAutoCounter( &fv->b );
    3499           0 : }
    3500             : 
    3501           0 : static void FVMenuDontAutoHint(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    3502           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    3503           0 :     FVDontAutoHint( &fv->b );
    3504           0 : }
    3505             : 
    3506           0 : static void FVMenuDeltas(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    3507           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    3508             : 
    3509           0 :     if ( !hasFreeTypeDebugger())
    3510           0 : return;
    3511           0 :     DeltaSuggestionDlg(fv,NULL);
    3512             : }
    3513             : 
    3514           0 : static void FVMenuAutoInstr(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    3515           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    3516           0 :     FVAutoInstr( &fv->b );
    3517           0 : }
    3518             : 
    3519           0 : static void FVMenuEditInstrs(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    3520           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    3521           0 :     int index = FVAnyCharSelected(fv);
    3522             :     SplineChar *sc;
    3523           0 :     if ( index<0 )
    3524           0 : return;
    3525           0 :     sc = SFMakeChar(fv->b.sf,fv->b.map,index);
    3526           0 :     SCEditInstructions(sc);
    3527             : }
    3528             : 
    3529           0 : static void FVMenuEditTable(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
    3530           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    3531           0 :     SFEditTable(fv->b.sf,
    3532           0 :             mi->mid==MID_Editprep?CHR('p','r','e','p'):
    3533           0 :             mi->mid==MID_Editfpgm?CHR('f','p','g','m'):
    3534           0 :             mi->mid==MID_Editmaxp?CHR('m','a','x','p'):
    3535             :                                   CHR('c','v','t',' '));
    3536           0 : }
    3537             : 
    3538           0 : static void FVMenuRmInstrTables(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    3539           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    3540           0 :     TtfTablesFree(fv->b.sf->ttf_tables);
    3541           0 :     fv->b.sf->ttf_tables = NULL;
    3542           0 :     if ( !fv->b.sf->changed ) {
    3543           0 :         fv->b.sf->changed = true;
    3544           0 :         FVSetTitles(fv->b.sf);
    3545             :     }
    3546           0 : }
    3547             : 
    3548           0 : static void FVMenuClearInstrs(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    3549           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    3550           0 :     FVClearInstrs(&fv->b);
    3551           0 : }
    3552             : 
    3553           0 : static void FVMenuClearHints(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    3554           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    3555           0 :     FVClearHints(&fv->b);
    3556           0 : }
    3557             : 
    3558           0 : static void FVMenuHistograms(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
    3559           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    3560           0 :     SFHistogram(fv->b.sf, fv->b.active_layer, NULL,
    3561           0 :                         FVAnyCharSelected(fv)!=-1?fv->b.selected:NULL,
    3562             :                         fv->b.map,
    3563           0 :                         mi->mid==MID_HStemHist ? hist_hstem :
    3564           0 :                         mi->mid==MID_VStemHist ? hist_vstem :
    3565             :                                 hist_blues);
    3566           0 : }
    3567             : 
    3568             : 
    3569          23 : static void FontViewSetTitle(FontView *fv) {
    3570             :     unichar_t *title, *ititle, *temp;
    3571          23 :     char *file=NULL;
    3572             :     char *enc;
    3573             :     int len;
    3574             : 
    3575          23 :     if ( fv->gw==NULL )              /* In scripting */
    3576          46 : return;
    3577             : 
    3578           0 :     const char* collabStateString = "";
    3579           0 :     if( collabclient_inSessionFV( &fv->b )) {
    3580           0 :         printf("collabclient_getState( fv ) %d %d\n",
    3581           0 :                fv->b.collabState, collabclient_getState( &fv->b ));
    3582           0 :         collabStateString = collabclient_stateToString(collabclient_getState( &fv->b ));
    3583             :     }
    3584             : 
    3585           0 :     enc = SFEncodingName(fv->b.sf,fv->b.normal?fv->b.normal:fv->b.map);
    3586           0 :     len = strlen(fv->b.sf->fontname)+1 + strlen(enc)+6;
    3587           0 :     if ( fv->b.normal ) len += strlen(_("Compact"))+1;
    3588           0 :     if ( fv->b.cidmaster!=NULL ) {
    3589           0 :         if ( (file = fv->b.cidmaster->filename)==NULL )
    3590           0 :             file = fv->b.cidmaster->origname;
    3591             :     } else {
    3592           0 :         if ( (file = fv->b.sf->filename)==NULL )
    3593           0 :             file = fv->b.sf->origname;
    3594             :     }
    3595           0 :     len += strlen(collabStateString);
    3596           0 :     if ( file!=NULL )
    3597           0 :         len += 2+strlen(file);
    3598           0 :     title = malloc((len+1)*sizeof(unichar_t));
    3599           0 :     uc_strcpy(title,"");
    3600             : 
    3601           0 :     if(*collabStateString) {
    3602           0 :         uc_strcat(title, collabStateString);
    3603           0 :         uc_strcat(title, " - ");
    3604             :     }
    3605           0 :     uc_strcat(title,fv->b.sf->fontname);
    3606           0 :     if ( fv->b.sf->changed )
    3607           0 :         uc_strcat(title,"*");
    3608           0 :     if ( file!=NULL ) {
    3609           0 :         uc_strcat(title,"  ");
    3610           0 :         temp = def2u_copy(GFileNameTail(file));
    3611           0 :         u_strcat(title,temp);
    3612           0 :         free(temp);
    3613             :     }
    3614           0 :     uc_strcat(title, " (" );
    3615           0 :     if ( fv->b.normal ) { utf82u_strcat(title,_("Compact")); uc_strcat(title," "); }
    3616           0 :     uc_strcat(title,enc);
    3617           0 :     uc_strcat(title, ")" );
    3618           0 :     free(enc);
    3619             : 
    3620           0 :     ititle = uc_copy(fv->b.sf->fontname);
    3621           0 :     GDrawSetWindowTitles(fv->gw,title,ititle);
    3622           0 :     free(title);
    3623           0 :     free(ititle);
    3624             : }
    3625             : 
    3626           0 : void FVTitleUpdate(FontViewBase *fv)
    3627             : {
    3628           0 :     FontViewSetTitle( (FontView*)fv );
    3629           0 : }
    3630             : 
    3631          24 : static void FontViewSetTitles(SplineFont *sf) {
    3632             :     FontView *fv;
    3633             : 
    3634          47 :     for ( fv = (FontView *) (sf->fv); fv!=NULL; fv=(FontView *) (fv->b.nextsame))
    3635          23 :         FontViewSetTitle(fv);
    3636          24 : }
    3637             : 
    3638           0 : static void FVMenuShowSubFont(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
    3639           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    3640           0 :     SplineFont *new = mi->ti.userdata;
    3641           0 :     FVShowSubFont(fv,new);
    3642           0 : }
    3643             : 
    3644           0 : static void FVMenuConvert2CID(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    3645           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    3646           0 :     SplineFont *cidmaster = fv->b.cidmaster;
    3647             :     struct cidmap *cidmap;
    3648             : 
    3649           0 :     if ( cidmaster!=NULL )
    3650           0 : return;
    3651           0 :     SFFindNearTop(fv->b.sf);
    3652           0 :     cidmap = AskUserForCIDMap();
    3653           0 :     if ( cidmap==NULL )
    3654           0 : return;
    3655           0 :     MakeCIDMaster(fv->b.sf,fv->b.map,false,NULL,cidmap);
    3656           0 :     SFRestoreNearTop(fv->b.sf);
    3657             : }
    3658             : 
    3659           0 : static enum fchooserret CMapFilter(GGadget *g,GDirEntry *ent,
    3660             :         const unichar_t *dir) {
    3661           0 :     enum fchooserret ret = GFileChooserDefFilter(g,ent,dir);
    3662             :     char buf2[256];
    3663             :     FILE *file;
    3664             :     static char *cmapflag = "%!PS-Adobe-3.0 Resource-CMap";
    3665             : 
    3666           0 :     if ( ret==fc_show && !ent->isdir ) {
    3667           0 :         int len = 3*(u_strlen(dir)+u_strlen(ent->name)+5);
    3668           0 :         char *filename = malloc(len);
    3669           0 :         u2def_strncpy(filename,dir,len);
    3670           0 :         strcat(filename,"/");
    3671           0 :         u2def_strncpy(buf2,ent->name,sizeof(buf2));
    3672           0 :         strcat(filename,buf2);
    3673           0 :         file = fopen(filename,"r");
    3674           0 :         if ( file==NULL )
    3675           0 :             ret = fc_hide;
    3676             :         else {
    3677           0 :             if ( fgets(buf2,sizeof(buf2),file)==NULL ||
    3678           0 :                     strncmp(buf2,cmapflag,strlen(cmapflag))!=0 )
    3679           0 :                 ret = fc_hide;
    3680           0 :             fclose(file);
    3681             :         }
    3682           0 :         free(filename);
    3683             :     }
    3684           0 : return( ret );
    3685             : }
    3686             : 
    3687           0 : static void FVMenuConvertByCMap(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    3688           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    3689           0 :     SplineFont *cidmaster = fv->b.cidmaster;
    3690             :     char *cmapfilename;
    3691             : 
    3692           0 :     if ( cidmaster!=NULL )
    3693           0 : return;
    3694           0 :     cmapfilename = gwwv_open_filename(_("Find an adobe CMap file..."),NULL,NULL,CMapFilter);
    3695           0 :     if ( cmapfilename==NULL )
    3696           0 : return;
    3697           0 :     MakeCIDMaster(fv->b.sf,fv->b.map,true,cmapfilename,NULL);
    3698           0 :     free(cmapfilename);
    3699             : }
    3700             : 
    3701           0 : static void FVMenuFlatten(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    3702           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    3703           0 :     SplineFont *cidmaster = fv->b.cidmaster;
    3704             : 
    3705           0 :     if ( cidmaster==NULL )
    3706           0 : return;
    3707           0 :     SFFlatten(cidmaster);
    3708             : }
    3709             : 
    3710           0 : static void FVMenuFlattenByCMap(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    3711           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    3712           0 :     SplineFont *cidmaster = fv->b.cidmaster;
    3713             :     char *cmapname;
    3714             : 
    3715           0 :     if ( cidmaster==NULL )
    3716           0 : return;
    3717           0 :     cmapname = gwwv_open_filename(_("Find an adobe CMap file..."),NULL,NULL,CMapFilter);
    3718           0 :     if ( cmapname==NULL )
    3719           0 : return;
    3720           0 :     SFFindNearTop(fv->b.sf);
    3721           0 :     SFFlattenByCMap(cidmaster,cmapname);
    3722           0 :     SFRestoreNearTop(fv->b.sf);
    3723           0 :     free(cmapname);
    3724             : }
    3725             : 
    3726           0 : static void FVMenuInsertFont(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    3727           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    3728           0 :     SplineFont *cidmaster = fv->b.cidmaster;
    3729             :     SplineFont *new;
    3730             :     struct cidmap *map;
    3731             :     char *filename;
    3732             :     extern NameList *force_names_when_opening;
    3733             : 
    3734           0 :     if ( cidmaster==NULL || cidmaster->subfontcnt>=255 )  /* Open type allows 1 byte to specify the fdselect */
    3735           0 : return;
    3736             : 
    3737           0 :     filename = GetPostScriptFontName(NULL,false);
    3738           0 :     if ( filename==NULL )
    3739           0 : return;
    3740           0 :     new = LoadSplineFont(filename,0);
    3741           0 :     free(filename);
    3742           0 :     if ( new==NULL )
    3743           0 : return;
    3744           0 :     if ( new->fv == &fv->b )          /* Already part of us */
    3745           0 : return;
    3746           0 :     if ( new->fv != NULL ) {
    3747           0 :         if ( ((FontView *) (new->fv))->gw!=NULL )
    3748           0 :             GDrawRaise( ((FontView *) (new->fv))->gw);
    3749           0 :         ff_post_error(_("Please close font"),_("Please close %s before inserting it into a CID font"),new->origname);
    3750           0 : return;
    3751             :     }
    3752           0 :     EncMapFree(new->map);
    3753           0 :     if ( force_names_when_opening!=NULL )
    3754           0 :         SFRenameGlyphsToNamelist(new,force_names_when_opening );
    3755             : 
    3756           0 :     map = FindCidMap(cidmaster->cidregistry,cidmaster->ordering,cidmaster->supplement,cidmaster);
    3757           0 :     SFEncodeToMap(new,map);
    3758           0 :     if ( !PSDictHasEntry(new->private,"lenIV"))
    3759           0 :         PSDictChangeEntry(new->private,"lenIV","1");             /* It's 4 by default, in CIDs the convention seems to be 1 */
    3760           0 :     new->display_antialias = fv->b.sf->display_antialias;
    3761           0 :     new->display_bbsized = fv->b.sf->display_bbsized;
    3762           0 :     new->display_size = fv->b.sf->display_size;
    3763           0 :     FVInsertInCID((FontViewBase *) fv,new);
    3764           0 :     CIDMasterAsDes(new);
    3765             : }
    3766             : 
    3767           0 : static void FVMenuInsertBlank(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    3768           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    3769           0 :     SplineFont *cidmaster = fv->b.cidmaster, *sf;
    3770             :     struct cidmap *map;
    3771             : 
    3772           0 :     if ( cidmaster==NULL || cidmaster->subfontcnt>=255 )  /* Open type allows 1 byte to specify the fdselect */
    3773           0 : return;
    3774           0 :     map = FindCidMap(cidmaster->cidregistry,cidmaster->ordering,cidmaster->supplement,cidmaster);
    3775           0 :     sf = SplineFontBlank(MaxCID(map));
    3776           0 :     sf->glyphcnt = sf->glyphmax;
    3777           0 :     sf->cidmaster = cidmaster;
    3778           0 :     sf->display_antialias = fv->b.sf->display_antialias;
    3779           0 :     sf->display_bbsized = fv->b.sf->display_bbsized;
    3780           0 :     sf->display_size = fv->b.sf->display_size;
    3781           0 :     sf->private = calloc(1,sizeof(struct psdict));
    3782           0 :     PSDictChangeEntry(sf->private,"lenIV","1");          /* It's 4 by default, in CIDs the convention seems to be 1 */
    3783           0 :     FVInsertInCID((FontViewBase *) fv,sf);
    3784             : }
    3785             : 
    3786           0 : static void FVMenuRemoveFontFromCID(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    3787           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    3788             :     char *buts[3];
    3789           0 :     SplineFont *cidmaster = fv->b.cidmaster, *sf = fv->b.sf, *replace;
    3790             :     int i;
    3791             :     MetricsView *mv, *mnext;
    3792             :     FontView *fvs;
    3793             : 
    3794           0 :     if ( cidmaster==NULL || cidmaster->subfontcnt<=1 )    /* Can't remove last font */
    3795           0 : return;
    3796           0 :     buts[0] = _("_Remove"); buts[1] = _("_Cancel"); buts[2] = NULL;
    3797           0 :     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"),
    3798             :             sf->fontname,cidmaster->fontname)==1 )
    3799           0 : return;
    3800             : 
    3801           0 :     for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL ) {
    3802             :         CharView *cv, *next;
    3803           0 :         for ( cv = (CharView *) (sf->glyphs[i]->views); cv!=NULL; cv = next ) {
    3804           0 :             next = (CharView *) (cv->b.next);
    3805           0 :             GDrawDestroyWindow(cv->gw);
    3806             :         }
    3807             :     }
    3808           0 :     GDrawProcessPendingEvents(NULL);
    3809           0 :     for ( mv=fv->b.sf->metrics; mv!=NULL; mv = mnext ) {
    3810           0 :         mnext = mv->next;
    3811           0 :         GDrawDestroyWindow(mv->gw);
    3812             :     }
    3813           0 :     GDrawSync(NULL);
    3814           0 :     GDrawProcessPendingEvents(NULL);
    3815             :     /* Just in case... */
    3816           0 :     GDrawSync(NULL);
    3817           0 :     GDrawProcessPendingEvents(NULL);
    3818             : 
    3819           0 :     for ( i=0; i<cidmaster->subfontcnt; ++i )
    3820           0 :         if ( cidmaster->subfonts[i]==sf )
    3821           0 :     break;
    3822           0 :     replace = i==0?cidmaster->subfonts[1]:cidmaster->subfonts[i-1];
    3823           0 :     while ( i<cidmaster->subfontcnt-1 ) {
    3824           0 :         cidmaster->subfonts[i] = cidmaster->subfonts[i+1];
    3825           0 :         ++i;
    3826             :     }
    3827           0 :     --cidmaster->subfontcnt;
    3828             : 
    3829           0 :     for ( fvs=(FontView *) (fv->b.sf->fv); fvs!=NULL; fvs=(FontView *) (fvs->b.nextsame) ) {
    3830           0 :         if ( fvs->b.sf==sf )
    3831           0 :             CIDSetEncMap((FontViewBase *) fvs,replace);
    3832             :     }
    3833           0 :     FontViewReformatAll(fv->b.sf);
    3834           0 :     SplineFontFree(sf);
    3835             : }
    3836             : 
    3837           0 : static void FVMenuCIDFontInfo(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    3838           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    3839           0 :     SplineFont *cidmaster = fv->b.cidmaster;
    3840             : 
    3841           0 :     if ( cidmaster==NULL )
    3842           0 : return;
    3843           0 :     FontInfo(cidmaster,fv->b.active_layer,-1,false);
    3844             : }
    3845             : 
    3846           0 : static void FVMenuChangeSupplement(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    3847           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    3848           0 :     SplineFont *cidmaster = fv->b.cidmaster;
    3849             :     struct cidmap *cidmap;
    3850             :     char buffer[20];
    3851             :     char *ret, *end;
    3852             :     int supple;
    3853             : 
    3854           0 :     if ( cidmaster==NULL )
    3855           0 : return;
    3856           0 :     sprintf(buffer,"%d",cidmaster->supplement);
    3857           0 :     ret = gwwv_ask_string(_("Change Supplement..."),buffer,_("Please specify a new supplement for %.20s-%.20s"),
    3858             :             cidmaster->cidregistry,cidmaster->ordering);
    3859           0 :     if ( ret==NULL )
    3860           0 : return;
    3861           0 :     supple = strtol(ret,&end,10);
    3862           0 :     if ( *end!='\0' || supple<=0 ) {
    3863           0 :         free(ret);
    3864           0 :         ff_post_error( _("Bad Number"),_("Bad Number") );
    3865           0 : return;
    3866             :     }
    3867           0 :     free(ret);
    3868           0 :     if ( supple!=cidmaster->supplement ) {
    3869             :             /* this will make noises if it can't find an appropriate cidmap */
    3870           0 :         cidmap = FindCidMap(cidmaster->cidregistry,cidmaster->ordering,supple,cidmaster);
    3871           0 :         cidmaster->supplement = supple;
    3872           0 :         FontViewSetTitle(fv);
    3873             :     }
    3874             : }
    3875             : 
    3876           0 : static SplineChar *FVFindACharInDisplay(FontView *fv) {
    3877             :     int start, end, enc, gid;
    3878           0 :     EncMap *map = fv->b.map;
    3879           0 :     SplineFont *sf = fv->b.sf;
    3880             :     SplineChar *sc;
    3881             : 
    3882           0 :     start = fv->rowoff*fv->colcnt;
    3883           0 :     end = start + fv->rowcnt*fv->colcnt;
    3884           0 :     for ( enc = start; enc<end && enc<map->enccount; ++enc ) {
    3885           0 :         if ( (gid=map->map[enc])!=-1 && (sc=sf->glyphs[gid])!=NULL )
    3886           0 : return( sc );
    3887             :     }
    3888           0 : return( NULL );
    3889             : }
    3890             : 
    3891           0 : static void FVMenuReencode(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
    3892           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    3893           0 :     Encoding *enc = NULL;
    3894             :     SplineChar *sc;
    3895             : 
    3896           0 :     sc = FVFindACharInDisplay(fv);
    3897           0 :     enc = FindOrMakeEncoding(mi->ti.userdata);
    3898           0 :     if ( enc==NULL ) {
    3899           0 :         IError("Known encoding could not be found");
    3900           0 : return;
    3901             :     }
    3902           0 :     FVReencode((FontViewBase *) fv,enc);
    3903           0 :     if ( sc!=NULL ) {
    3904           0 :         int enc = fv->b.map->backmap[sc->orig_pos];
    3905           0 :         if ( enc!=-1 )
    3906           0 :             FVScrollToChar(fv,enc);
    3907             :     }
    3908             : }
    3909             : 
    3910           0 : static void FVMenuForceEncode(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
    3911           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    3912           0 :     Encoding *enc = NULL;
    3913           0 :     int oldcnt = fv->b.map->enccount;
    3914             : 
    3915           0 :     enc = FindOrMakeEncoding(mi->ti.userdata);
    3916           0 :     if ( enc==NULL ) {
    3917           0 :         IError("Known encoding could not be found");
    3918           0 : return;
    3919             :     }
    3920           0 :     SFForceEncoding(fv->b.sf,fv->b.map,enc);
    3921           0 :     if ( oldcnt < fv->b.map->enccount ) {
    3922           0 :         fv->b.selected = realloc(fv->b.selected,fv->b.map->enccount);
    3923           0 :         memset(fv->b.selected+oldcnt,0,fv->b.map->enccount-oldcnt);
    3924             :     }
    3925           0 :     if ( fv->b.normal!=NULL ) {
    3926           0 :         EncMapFree(fv->b.normal);
    3927           0 :         if (fv->b.normal == fv->b.sf->map) { fv->b.sf->map = NULL; }
    3928           0 :         fv->b.normal = NULL;
    3929             :     }
    3930           0 :     SFReplaceEncodingBDFProps(fv->b.sf,fv->b.map);
    3931           0 :     FontViewSetTitle(fv);
    3932           0 :     FontViewReformatOne(&fv->b);
    3933             : }
    3934             : 
    3935           0 : static void FVMenuDisplayByGroups(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    3936           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    3937             : 
    3938           0 :     DisplayGroups(fv);
    3939           0 : }
    3940             : 
    3941           0 : static void FVMenuDefineGroups(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    3942           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    3943             : 
    3944           0 :     DefineGroups(fv);
    3945           0 : }
    3946             : 
    3947           0 : static void FVMenuMMValid(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    3948           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    3949           0 :     MMSet *mm = fv->b.sf->mm;
    3950             : 
    3951           0 :     if ( mm==NULL )
    3952           0 : return;
    3953           0 :     MMValid(mm,true);
    3954             : }
    3955             : 
    3956           0 : static void FVMenuCreateMM(GWindow UNUSED(gw), struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    3957           0 :     MMWizard(NULL);
    3958           0 : }
    3959             : 
    3960           0 : static void FVMenuMMInfo(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    3961           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    3962           0 :     MMSet *mm = fv->b.sf->mm;
    3963             : 
    3964           0 :     if ( mm==NULL )
    3965           0 : return;
    3966           0 :     MMWizard(mm);
    3967             : }
    3968             : 
    3969           0 : static void FVMenuChangeMMBlend(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    3970           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    3971           0 :     MMSet *mm = fv->b.sf->mm;
    3972             : 
    3973           0 :     if ( mm==NULL || mm->apple )
    3974           0 : return;
    3975           0 :     MMChangeBlend(mm,fv,false);
    3976             : }
    3977             : 
    3978           0 : static void FVMenuBlendToNew(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    3979           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    3980           0 :     MMSet *mm = fv->b.sf->mm;
    3981             : 
    3982           0 :     if ( mm==NULL )
    3983           0 : return;
    3984           0 :     MMChangeBlend(mm,fv,true);
    3985             : }
    3986             : 
    3987           0 : static void cflistcheck(GWindow UNUSED(gw), struct gmenuitem *mi, GEvent *UNUSED(e)) {
    3988             :     /*FontView *fv = (FontView *) GDrawGetUserData(gw);*/
    3989             : 
    3990           0 :     for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
    3991           0 :         switch ( mi->mid ) {
    3992             :           case MID_AllFonts:
    3993           0 :             mi->ti.checked = !onlycopydisplayed;
    3994           0 :           break;
    3995             :           case MID_DisplayedFont:
    3996           0 :             mi->ti.checked = onlycopydisplayed;
    3997           0 :           break;
    3998             :           case MID_CharName:
    3999           0 :             mi->ti.checked = copymetadata;
    4000           0 :           break;
    4001             :           case MID_TTFInstr:
    4002           0 :             mi->ti.checked = copyttfinstr;
    4003           0 :           break;
    4004             :         }
    4005             :     }
    4006           0 : }
    4007             : 
    4008           0 : static void sllistcheck(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    4009           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    4010           0 :     fv = fv;
    4011           0 : }
    4012             : 
    4013           0 : static void htlistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
    4014           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    4015           0 :     int anychars = FVAnyCharSelected(fv);
    4016           0 :     int multilayer = fv->b.sf->multilayer;
    4017             : 
    4018           0 :     for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
    4019           0 :         switch ( mi->mid ) {
    4020             :           case MID_AutoHint:
    4021           0 :             mi->ti.disabled = anychars==-1 || multilayer;
    4022           0 :           break;
    4023             :           case MID_HintSubsPt:
    4024           0 :             mi->ti.disabled = fv->b.sf->layers[fv->b.active_layer].order2 || anychars==-1 || multilayer;
    4025           0 :             if ( fv->b.sf->mm!=NULL && fv->b.sf->mm->apple )
    4026           0 :                 mi->ti.disabled = true;
    4027           0 :           break;
    4028             :           case MID_AutoCounter: case MID_DontAutoHint:
    4029           0 :             mi->ti.disabled = fv->b.sf->layers[fv->b.active_layer].order2 || anychars==-1 || multilayer;
    4030           0 :           break;
    4031             :           case MID_AutoInstr: case MID_EditInstructions: case MID_Deltas:
    4032           0 :             mi->ti.disabled = !fv->b.sf->layers[fv->b.active_layer].order2 || anychars==-1 || multilayer;
    4033           0 :           break;
    4034             :           case MID_RmInstrTables:
    4035           0 :             mi->ti.disabled = fv->b.sf->ttf_tables==NULL;
    4036           0 :           break;
    4037             :           case MID_Editfpgm: case MID_Editprep: case MID_Editcvt: case MID_Editmaxp:
    4038           0 :             mi->ti.disabled = !fv->b.sf->layers[fv->b.active_layer].order2 || multilayer;
    4039           0 :           break;
    4040             :           case MID_ClearHints: case MID_ClearWidthMD: case MID_ClearInstrs:
    4041           0 :             mi->ti.disabled = anychars==-1;
    4042           0 :           break;
    4043             :         }
    4044             :     }
    4045           0 : }
    4046             : 
    4047           0 : static void fllistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
    4048           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    4049           0 :     int anychars = FVAnyCharSelected(fv);
    4050             :     FontView *fvs;
    4051           0 :     int in_modal = (fv->b.container!=NULL && fv->b.container->funcs->is_modal);
    4052             : 
    4053           0 :     for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
    4054           0 :         switch ( mi->mid ) {
    4055             :           case MID_GenerateTTC:
    4056           0 :             for ( fvs=fv_list; fvs!=NULL; fvs=(FontView *) (fvs->b.next) ) {
    4057           0 :                 if ( fvs!=fv )
    4058           0 :             break;
    4059             :             }
    4060           0 :             mi->ti.disabled = fvs==NULL;
    4061           0 :           break;
    4062             :           case MID_Revert:
    4063           0 :             mi->ti.disabled = fv->b.sf->origname==NULL || fv->b.sf->new;
    4064           0 :           break;
    4065             :           case MID_RevertToBackup:
    4066             :             /* We really do want to use filename here and origname above */
    4067           0 :             mi->ti.disabled = true;
    4068           0 :             if ( fv->b.sf->filename!=NULL ) {
    4069           0 :                 if ( fv->b.sf->backedup == bs_dontknow ) {
    4070           0 :                     char *buf = malloc(strlen(fv->b.sf->filename)+20);
    4071           0 :                     strcpy(buf,fv->b.sf->filename);
    4072           0 :                     if ( fv->b.sf->compression!=0 )
    4073           0 :                         strcat(buf,compressors[fv->b.sf->compression-1].ext);
    4074           0 :                     strcat(buf,"~");
    4075           0 :                     if ( access(buf,F_OK)==0 )
    4076           0 :                         fv->b.sf->backedup = bs_backedup;
    4077             :                     else
    4078           0 :                         fv->b.sf->backedup = bs_not;
    4079           0 :                     free(buf);
    4080             :                 }
    4081           0 :                 if ( fv->b.sf->backedup == bs_backedup )
    4082           0 :                     mi->ti.disabled = false;
    4083             :             }
    4084           0 :           break;
    4085             :           case MID_RevertGlyph:
    4086           0 :             mi->ti.disabled = fv->b.sf->origname==NULL || fv->b.sf->sfd_version<2 || anychars==-1 || fv->b.sf->compression!=0;
    4087           0 :           break;
    4088             :           case MID_Recent:
    4089           0 :             mi->ti.disabled = !RecentFilesAny();
    4090           0 :           break;
    4091             :           case MID_ScriptMenu:
    4092           0 :             mi->ti.disabled = script_menu_names[0]==NULL;
    4093           0 :           break;
    4094             :           case MID_Print:
    4095           0 :             mi->ti.disabled = fv->b.sf->onlybitmaps || in_modal;
    4096           0 :           break;
    4097             :         }
    4098             :     }
    4099           0 : }
    4100             : 
    4101           0 : static void edlistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
    4102           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    4103           0 :     int pos = FVAnyCharSelected(fv), i, gid;
    4104           0 :     int not_pasteable = pos==-1 ||
    4105           0 :                     (!CopyContainsSomething() &&
    4106             : #ifndef _NO_LIBPNG
    4107           0 :                     !GDrawSelectionHasType(fv->gw,sn_clipboard,"image/png") &&
    4108             : #endif
    4109           0 :                     !GDrawSelectionHasType(fv->gw,sn_clipboard,"image/svg+xml") &&
    4110           0 :                     !GDrawSelectionHasType(fv->gw,sn_clipboard,"image/svg-xml") &&
    4111           0 :                     !GDrawSelectionHasType(fv->gw,sn_clipboard,"image/svg") &&
    4112           0 :                     !GDrawSelectionHasType(fv->gw,sn_clipboard,"image/bmp") &&
    4113           0 :                     !GDrawSelectionHasType(fv->gw,sn_clipboard,"image/eps") &&
    4114           0 :                     !GDrawSelectionHasType(fv->gw,sn_clipboard,"image/ps"));
    4115           0 :     RefChar *base = CopyContainsRef(fv->b.sf);
    4116           0 :     int base_enc = base!=NULL ? fv->b.map->backmap[base->orig_pos] : -1;
    4117             : 
    4118             : 
    4119           0 :     for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
    4120           0 :         switch ( mi->mid ) {
    4121             :           case MID_Paste: case MID_PasteInto:
    4122           0 :             mi->ti.disabled = not_pasteable;
    4123           0 :           break;
    4124             :           case MID_PasteAfter:
    4125           0 :             mi->ti.disabled = not_pasteable || pos<0;
    4126           0 :           break;
    4127             :           case MID_SameGlyphAs:
    4128           0 :             mi->ti.disabled = not_pasteable || base==NULL || fv->b.cidmaster!=NULL ||
    4129           0 :                     base_enc==-1 ||
    4130           0 :                     fv->b.selected[base_enc];        /* Can't be self-referential */
    4131           0 :           break;
    4132             :           case MID_Join:
    4133             :           case MID_Cut: case MID_Copy: case MID_Clear:
    4134             :           case MID_CopyWidth: case MID_CopyLBearing: case MID_CopyRBearing:
    4135             :           case MID_CopyRef: case MID_UnlinkRef:
    4136             :           case MID_RemoveUndoes: case MID_CopyFgToBg: case MID_CopyL2L:
    4137           0 :             mi->ti.disabled = pos==-1;
    4138           0 :           break;
    4139             :           case MID_RplRef:
    4140             :           case MID_CorrectRefs:
    4141           0 :             mi->ti.disabled = pos==-1 || fv->b.cidmaster!=NULL || fv->b.sf->multilayer;
    4142           0 :           break;
    4143             :           case MID_CopyLookupData:
    4144           0 :             mi->ti.disabled = pos==-1 || (fv->b.sf->gpos_lookups==NULL && fv->b.sf->gsub_lookups==NULL);
    4145           0 :           break;
    4146             :           case MID_CopyVWidth:
    4147           0 :             mi->ti.disabled = pos==-1 || !fv->b.sf->hasvmetrics;
    4148           0 :           break;
    4149             :           case MID_ClearBackground:
    4150           0 :             mi->ti.disabled = true;
    4151           0 :             if ( pos!=-1 && !( onlycopydisplayed && fv->filled!=fv->show )) {
    4152           0 :                 for ( i=0; i<fv->b.map->enccount; ++i )
    4153           0 :                     if ( fv->b.selected[i] && (gid = fv->b.map->map[i])!=-1 &&
    4154           0 :                             fv->b.sf->glyphs[gid]!=NULL )
    4155           0 :                         if ( fv->b.sf->glyphs[gid]->layers[ly_back].images!=NULL ||
    4156           0 :                                 fv->b.sf->glyphs[gid]->layers[ly_back].splines!=NULL ) {
    4157           0 :                             mi->ti.disabled = false;
    4158           0 :                 break;
    4159             :                         }
    4160             :             }
    4161           0 :           break;
    4162             :           case MID_Undo:
    4163           0 :             for ( i=0; i<fv->b.map->enccount; ++i )
    4164           0 :                 if ( fv->b.selected[i] && (gid = fv->b.map->map[i])!=-1 &&
    4165           0 :                         fv->b.sf->glyphs[gid]!=NULL )
    4166           0 :                     if ( fv->b.sf->glyphs[gid]->layers[fv->b.active_layer].undoes!=NULL )
    4167           0 :             break;
    4168           0 :             mi->ti.disabled = i==fv->b.map->enccount;
    4169           0 :           break;
    4170             :           case MID_Redo:
    4171           0 :             for ( i=0; i<fv->b.map->enccount; ++i )
    4172           0 :                 if ( fv->b.selected[i] && (gid = fv->b.map->map[i])!=-1 &&
    4173           0 :                         fv->b.sf->glyphs[gid]!=NULL )
    4174           0 :                     if ( fv->b.sf->glyphs[gid]->layers[fv->b.active_layer].redoes!=NULL )
    4175           0 :             break;
    4176           0 :             mi->ti.disabled = i==fv->b.map->enccount;
    4177           0 :           break;
    4178             :         case MID_UndoFontLevel:
    4179           0 :             mi->ti.disabled = dlist_isempty( (struct dlistnode **)&fv->b.sf->undoes );
    4180           0 :             break;
    4181             :         }
    4182             :     }
    4183           0 : }
    4184             : 
    4185           0 : static void trlistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
    4186           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    4187           0 :     int anychars = FVAnyCharSelected(fv);
    4188             : 
    4189           0 :     for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
    4190           0 :         switch ( mi->mid ) {
    4191             :           case MID_Transform:
    4192           0 :             mi->ti.disabled = anychars==-1;
    4193           0 :           break;
    4194             :           case MID_NLTransform: case MID_POV:
    4195           0 :             mi->ti.disabled = anychars==-1 || fv->b.sf->onlybitmaps;
    4196           0 :           break;
    4197             :         }
    4198             :     }
    4199           0 : }
    4200             : 
    4201           0 : static void validlistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
    4202           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    4203           0 :     int anychars = FVAnyCharSelected(fv);
    4204             : 
    4205           0 :     for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
    4206           0 :         switch ( mi->mid ) {
    4207             :           case MID_FindProblems:
    4208           0 :             mi->ti.disabled = anychars==-1;
    4209           0 :           break;
    4210             :           case MID_Validate:
    4211           0 :             mi->ti.disabled = fv->b.sf->strokedfont || fv->b.sf->multilayer;
    4212           0 :           break;
    4213             :         }
    4214             :     }
    4215           0 : }
    4216             : 
    4217           0 : static void ellistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
    4218           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    4219           0 :     int anychars = FVAnyCharSelected(fv), gid;
    4220             :     int anybuildable, anytraceable;
    4221           0 :     int in_modal = (fv->b.container!=NULL && fv->b.container->funcs->is_modal);
    4222             : 
    4223           0 :     for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
    4224           0 :         switch ( mi->mid ) {
    4225             :           case MID_FontInfo:
    4226           0 :             mi->ti.disabled = in_modal;
    4227           0 :           break;
    4228             :           case MID_CharInfo:
    4229           0 :             mi->ti.disabled = anychars<0 || (gid = fv->b.map->map[anychars])==-1 ||
    4230           0 :                     (fv->b.cidmaster!=NULL && fv->b.sf->glyphs[gid]==NULL) ||
    4231             :                     in_modal;
    4232           0 :           break;
    4233             :           case MID_Transform:
    4234           0 :             mi->ti.disabled = anychars==-1;
    4235             :             /* some Transformations make sense on bitmaps now */
    4236           0 :           break;
    4237             :           case MID_AddExtrema:
    4238           0 :             mi->ti.disabled = anychars==-1 || fv->b.sf->onlybitmaps;
    4239           0 :           break;
    4240             :           case MID_Simplify:
    4241             :           case MID_Stroke: case MID_RmOverlap:
    4242           0 :             mi->ti.disabled = anychars==-1 || fv->b.sf->onlybitmaps;
    4243           0 :           break;
    4244             :           case MID_Styles:
    4245           0 :             mi->ti.disabled = anychars==-1 || fv->b.sf->onlybitmaps;
    4246           0 :           break;
    4247             :           case MID_Round: case MID_Correct:
    4248           0 :             mi->ti.disabled = anychars==-1 || fv->b.sf->onlybitmaps;
    4249           0 :           break;
    4250             : #ifdef FONTFORGE_CONFIG_TILEPATH
    4251             :           case MID_TilePath:
    4252             :             mi->ti.disabled = anychars==-1 || fv->b.sf->onlybitmaps;
    4253             :           break;
    4254             : #endif
    4255             :           case MID_AvailBitmaps:
    4256           0 :             mi->ti.disabled = fv->b.sf->mm!=NULL;
    4257           0 :           break;
    4258             :           case MID_RegenBitmaps: case MID_RemoveBitmaps:
    4259           0 :             mi->ti.disabled = fv->b.sf->bitmaps==NULL || fv->b.sf->onlybitmaps ||
    4260           0 :                     fv->b.sf->mm!=NULL;
    4261           0 :           break;
    4262             :           case MID_BuildAccent:
    4263           0 :             anybuildable = false;
    4264           0 :             if ( anychars!=-1 ) {
    4265             :                 int i;
    4266           0 :                 for ( i=0; i<fv->b.map->enccount; ++i ) if ( fv->b.selected[i] ) {
    4267           0 :                     SplineChar *sc=NULL, dummy;
    4268           0 :                     gid = fv->b.map->map[i];
    4269           0 :                     if ( gid!=-1 )
    4270           0 :                         sc = fv->b.sf->glyphs[gid];
    4271           0 :                     if ( sc==NULL )
    4272           0 :                         sc = SCBuildDummy(&dummy,fv->b.sf,fv->b.map,i);
    4273           0 :                     if ( SFIsSomethingBuildable(fv->b.sf,sc,fv->b.active_layer,false) ||
    4274           0 :                             SFIsDuplicatable(fv->b.sf,sc)) {
    4275           0 :                         anybuildable = true;
    4276           0 :                 break;
    4277             :                     }
    4278             :                 }
    4279             :             }
    4280           0 :             mi->ti.disabled = !anybuildable;
    4281           0 :           break;
    4282             :           case MID_Autotrace:
    4283           0 :             anytraceable = false;
    4284           0 :             if ( FindAutoTraceName()!=NULL && anychars!=-1 ) {
    4285             :                 int i;
    4286           0 :                 for ( i=0; i<fv->b.map->enccount; ++i )
    4287           0 :                     if ( fv->b.selected[i] && (gid = fv->b.map->map[i])!=-1 &&
    4288           0 :                             fv->b.sf->glyphs[gid]!=NULL &&
    4289           0 :                             fv->b.sf->glyphs[gid]->layers[ly_back].images!=NULL ) {
    4290           0 :                         anytraceable = true;
    4291           0 :                 break;
    4292             :                     }
    4293             :             }
    4294           0 :             mi->ti.disabled = !anytraceable;
    4295           0 :           break;
    4296             :           case MID_MergeFonts:
    4297           0 :             mi->ti.disabled = fv->b.sf->bitmaps!=NULL && fv->b.sf->onlybitmaps;
    4298           0 :           break;
    4299             :           case MID_FontCompare:
    4300           0 :             mi->ti.disabled = fv_list->b.next==NULL;
    4301           0 :           break;
    4302             :           case MID_InterpolateFonts:
    4303           0 :             mi->ti.disabled = fv->b.sf->onlybitmaps;
    4304           0 :           break;
    4305             :         }
    4306             :     }
    4307           0 : }
    4308             : 
    4309           0 : static void mtlistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
    4310           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    4311           0 :     int anychars = FVAnyCharSelected(fv);
    4312             : 
    4313           0 :     for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
    4314           0 :         switch ( mi->mid ) {
    4315             :           case MID_Center: case MID_Thirds: case MID_SetWidth:
    4316             :           case MID_SetLBearing: case MID_SetRBearing: case MID_SetBearings:
    4317           0 :             mi->ti.disabled = anychars==-1;
    4318           0 :           break;
    4319             :           case MID_SetVWidth:
    4320           0 :             mi->ti.disabled = anychars==-1 || !fv->b.sf->hasvmetrics;
    4321           0 :           break;
    4322             :           case MID_VKernByClass:
    4323             :           case MID_VKernFromH:
    4324             :           case MID_RmVKern:
    4325           0 :             mi->ti.disabled = !fv->b.sf->hasvmetrics;
    4326           0 :           break;
    4327             :         }
    4328             :     }
    4329           0 : }
    4330             : 
    4331             : #if HANYANG
    4332             : static void hglistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
    4333             :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    4334             : 
    4335             :     for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
    4336             :         if ( mi->mid==MID_BuildSyllables || mi->mid==MID_ModifyComposition )
    4337             :             mi->ti.disabled = fv->b.sf->rules==NULL;
    4338             :     }
    4339             : }
    4340             : 
    4341             : static GMenuItem2 hglist[] = {
    4342             :     { { (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 },
    4343             :     { { (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 },
    4344             :     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, }},
    4345             :     { { (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 },
    4346             :     { NULL }
    4347             : };
    4348             : #endif
    4349             : 
    4350           0 : static void balistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
    4351           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    4352             : 
    4353           0 :     for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
    4354           0 :         if ( mi->mid==MID_BuildAccent || mi->mid==MID_BuildComposite ) {
    4355           0 :             int anybuildable = false;
    4356           0 :             int onlyaccents = mi->mid==MID_BuildAccent;
    4357             :             int i, gid;
    4358           0 :             for ( i=0; i<fv->b.map->enccount; ++i ) if ( fv->b.selected[i] ) {
    4359           0 :                 SplineChar *sc=NULL, dummy;
    4360           0 :                 if ( (gid=fv->b.map->map[i])!=-1 )
    4361           0 :                     sc = fv->b.sf->glyphs[gid];
    4362           0 :                 if ( sc==NULL )
    4363           0 :                     sc = SCBuildDummy(&dummy,fv->b.sf,fv->b.map,i);
    4364           0 :                 if ( SFIsSomethingBuildable(fv->b.sf,sc,fv->b.active_layer,onlyaccents)) {
    4365           0 :                     anybuildable = true;
    4366           0 :             break;
    4367             :                 }
    4368             :             }
    4369           0 :             mi->ti.disabled = !anybuildable;
    4370           0 :         } else if ( mi->mid==MID_BuildDuplicates ) {
    4371           0 :             int anybuildable = false;
    4372             :             int i, gid;
    4373           0 :             for ( i=0; i<fv->b.map->enccount; ++i ) if ( fv->b.selected[i] ) {
    4374           0 :                 SplineChar *sc=NULL, dummy;
    4375           0 :                 if ( (gid=fv->b.map->map[i])!=-1 )
    4376           0 :                     sc = fv->b.sf->glyphs[gid];
    4377           0 :                 if ( sc==NULL )
    4378           0 :                     sc = SCBuildDummy(&dummy,fv->b.sf,fv->b.map,i);
    4379           0 :                 if ( SFIsDuplicatable(fv->b.sf,sc)) {
    4380           0 :                     anybuildable = true;
    4381           0 :             break;
    4382             :                 }
    4383             :             }
    4384           0 :             mi->ti.disabled = !anybuildable;
    4385             :         }
    4386             :     }
    4387           0 : }
    4388             : 
    4389           0 : static void delistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
    4390           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    4391           0 :     int i = FVAnyCharSelected(fv);
    4392           0 :     int gid = i<0 ? -1 : fv->b.map->map[i];
    4393             : 
    4394           0 :     for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
    4395           0 :         switch ( mi->mid ) {
    4396             :           case MID_ShowDependentRefs:
    4397           0 :             mi->ti.disabled = gid<0 || fv->b.sf->glyphs[gid]==NULL ||
    4398           0 :                     fv->b.sf->glyphs[gid]->dependents == NULL;
    4399           0 :           break;
    4400             :           case MID_ShowDependentSubs:
    4401           0 :             mi->ti.disabled = gid<0 || fv->b.sf->glyphs[gid]==NULL ||
    4402           0 :                     !SCUsedBySubs(fv->b.sf->glyphs[gid]);
    4403           0 :           break;
    4404             :         }
    4405             :     }
    4406           0 : }
    4407             : 
    4408           0 : static void infolistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
    4409           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    4410           0 :     int anychars = FVAnyCharSelected(fv);
    4411             : 
    4412           0 :     for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
    4413           0 :         switch ( mi->mid ) {
    4414             :           case MID_StrikeInfo:
    4415           0 :             mi->ti.disabled = fv->b.sf->bitmaps==NULL;
    4416           0 :           break;
    4417             :           case MID_MassRename:
    4418           0 :             mi->ti.disabled = anychars==-1;
    4419           0 :           break;
    4420             :           case MID_SetColor:
    4421           0 :             mi->ti.disabled = anychars==-1;
    4422           0 :           break;
    4423             :         }
    4424             :     }
    4425           0 : }
    4426             : 
    4427             : static GMenuItem2 dummyitem[] = {
    4428             :     { { (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 },
    4429             :     GMENUITEM2_EMPTY
    4430             : };
    4431             : 
    4432             : static GMenuItem2 fllist[] = {
    4433             :     { { (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 },
    4434             : #if HANYANG
    4435             :     { { (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 },
    4436             : #endif
    4437             :     { { (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 },
    4438             :     { { (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 },
    4439             :     { { (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 },
    4440             :     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
    4441             :     { { (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 },
    4442             :     { { (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 },
    4443             :     { { (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 },
    4444             :     { { (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 },
    4445             :     { { (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 },
    4446             :     { { (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 },
    4447             :     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
    4448             :     { { (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 },
    4449             :     { { (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 Kern Info...|No Shortcut"), NULL, NULL, FVMenuMergeKern, 0 },
    4450             :     { { (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 },
    4451             :     { { (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 },
    4452             :     { { (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 },
    4453             :     { { (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 },
    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_("_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 },
    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             : #if !defined(_NO_PYTHON)
    4458             :     { { (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 },
    4459             : #elif !defined(_NO_FFSCRIPT)
    4460             :     { { (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 },
    4461             : #endif
    4462             : #if !defined(_NO_FFSCRIPT)
    4463             :     { { (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 },
    4464             : #endif
    4465             : #if !defined(_NO_FFSCRIPT) || !defined(_NO_PYTHON)
    4466             :     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
    4467             : #endif
    4468             :     { { (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 },
    4469             :     { { (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 },
    4470             :     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
    4471             :     { { (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 */
    4472             :       NULL, NULL, FVMenuExit, 0 },
    4473             :     GMENUITEM2_EMPTY
    4474             : };
    4475             : 
    4476             : static GMenuItem2 cflist[] = {
    4477             :     { { (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 },
    4478             :     { { (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 },
    4479             :     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
    4480             :     { { (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 },
    4481             :     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
    4482             :     { { (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 },
    4483             :     GMENUITEM2_EMPTY
    4484             : };
    4485             : 
    4486             : static GMenuItem2 sclist[] = {
    4487             :     { { (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_("Color Choose|No Shortcut"), NULL, NULL, FVMenuSelectColor, 0 },
    4488             :     { { (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 },
    4489             :     { { 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 },
    4490             :     { { 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 },
    4491             :     { { 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 },
    4492             :     { { 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 },
    4493             :     { { 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 },
    4494             :     { { 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 },
    4495             :     { { 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 },
    4496             :     GMENUITEM2_EMPTY
    4497             : };
    4498             : 
    4499             : static GMenuItem2 sllist[] = {
    4500             :     { { (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 },
    4501             :     { { (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 },
    4502             :     { { (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 },
    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_("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 },
    4505             :     { { (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 },
    4506             :     { { (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 },
    4507             :     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
    4508             :     { { (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 },
    4509             :     { { (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 },
    4510             :     { { (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 },
    4511             :     { { (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 },
    4512             :     { { (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 },
    4513             :     { { (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 },
    4514             :     { { (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 },
    4515             :     { { (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 },
    4516             :     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
    4517             :     { { (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 },
    4518             :     { { (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 },
    4519             :     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
    4520             :     { { (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 },
    4521             :     GMENUITEM2_EMPTY
    4522             : };
    4523             : 
    4524             : static GMenuItem2 edlist[] = {
    4525             :     { { (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 },
    4526             :     { { (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},
    4527             :     { { (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 },
    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_("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 },
    4530             :     { { (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 },
    4531             :     { { (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 },
    4532             :     { { (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 },
    4533             :     { { (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 },
    4534             :     { { (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 },
    4535             :     { { (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 },
    4536             :     { { (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 },
    4537             :     { { (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 },
    4538             :     { { (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 },
    4539             :     { { (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 },
    4540             :     { { (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 },
    4541             :     { { (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 },
    4542             :     { { (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 },
    4543             :     { { (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 },
    4544             :     { { (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 },
    4545             :     { { (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 },
    4546             :     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
    4547             :     { { (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 },
    4548             :     { { (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 },
    4549             :     { { (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 },
    4550             :     { { (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 },
    4551             :     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
    4552             :     { { (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 },
    4553             :     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
    4554             :     { { (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 },
    4555             :     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
    4556             :     { { (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 },
    4557             :     GMENUITEM2_EMPTY
    4558             : };
    4559             : 
    4560             : static GMenuItem2 smlist[] = {
    4561             :     { { (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 },
    4562             :     { { (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 },
    4563             :     { { (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 },
    4564             :     { { (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 },
    4565             :     { { (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 },
    4566             :     GMENUITEM2_EMPTY
    4567             : };
    4568             : 
    4569             : static GMenuItem2 rmlist[] = {
    4570             :     { { (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 },
    4571             :     { { (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 },
    4572             :     { { (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 },
    4573             :     GMENUITEM2_EMPTY
    4574             : };
    4575             : 
    4576             : static GMenuItem2 eflist[] = {
    4577             :     { { (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 },
    4578             :     { { (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 },
    4579             :     { { (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 },
    4580             :     { { (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...|No Shortcut"), NULL, NULL, FVMenuCondense, MID_Condense },
    4581             :     { { (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 XHeight...|No Shortcut"), NULL, NULL, FVMenuChangeXHeight, MID_ChangeXHeight },
    4582             :     { { (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 },
    4583             :     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
    4584             :     { { (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 Caps...|No Shortcut"), NULL, NULL, FVMenuSmallCaps, MID_SmallCaps },
    4585             :     { { (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 },
    4586             :     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
    4587             :     { { (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 },
    4588             :     { { (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 },
    4589             :     { { (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 },
    4590             :     { { (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 },
    4591             :     GMENUITEM2_EMPTY
    4592             : };
    4593             : 
    4594             : static GMenuItem2 balist[] = {
    4595             :     { { (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 },
    4596             :     { { (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 },
    4597             :     { { (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 },
    4598             : #ifdef KOREAN
    4599             :     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
    4600             :     { { (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 },
    4601             : #endif
    4602             :     GMENUITEM2_EMPTY
    4603             : };
    4604             : 
    4605             : static GMenuItem2 delist[] = {
    4606             :     { { (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 },
    4607             :     { { (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 },
    4608             :     GMENUITEM2_EMPTY
    4609             : };
    4610             : 
    4611             : static GMenuItem2 trlist[] = {
    4612             :     { { (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 },
    4613             :     { { (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 },
    4614             :     { { (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 },
    4615             :     GMENUITEM2_EMPTY
    4616             : };
    4617             : 
    4618             : static GMenuItem2 rndlist[] = {
    4619             :     { { (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 },
    4620             :     { { (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 },
    4621             :     { { (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 },
    4622             :     GMENUITEM2_EMPTY
    4623             : };
    4624             : 
    4625             : static GMenuItem2 scollist[] = {
    4626             :     { { (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_("Color Choose|No Shortcut"), NULL, NULL, FVMenuSetColor, 0 },
    4627             :     { { (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 },
    4628             :     { { 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 },
    4629             :     { { 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 },
    4630             :     { { 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 },
    4631             :     { { 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 },
    4632             :     { { 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 },
    4633             :     { { 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 },
    4634             :     { { 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 },
    4635             :     GMENUITEM2_EMPTY
    4636             : };
    4637             : 
    4638             : static GMenuItem2 infolist[] = {
    4639             :     { { (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 },
    4640             :     { { (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 },
    4641             :     { { (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 },
    4642             :     { { (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 },
    4643             :     { { (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 },
    4644             :     { { (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 },
    4645             :     { { (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 },
    4646             :     { { (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 },
    4647             :     GMENUITEM2_EMPTY
    4648             : };
    4649             : 
    4650             : static GMenuItem2 validlist[] = {
    4651             :     { { (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 },
    4652             :     { { (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 },
    4653             :     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
    4654             :     { { (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 },
    4655             :     GMENUITEM2_EMPTY
    4656             : };
    4657             : 
    4658             : static GMenuItem2 ellist[] = {
    4659             :     { { (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 },
    4660             :     { { (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 },
    4661             :     { { (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 },
    4662             :     { { (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 },
    4663             :     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
    4664             :     { { (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 },
    4665             :     { { (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 },
    4666             :     { { (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 },
    4667             :     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
    4668             :     { { (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 },
    4669             :     { { (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 },
    4670             :     { { (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 },
    4671             : #ifdef FONTFORGE_CONFIG_TILEPATH
    4672             :     { { (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 },
    4673             :     { { (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 },
    4674             : #endif
    4675             :     { { (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 },
    4676             :     { { (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 },
    4677             :     { { (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 },
    4678             :     { { (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 },
    4679             :     { { (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 },
    4680             :     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
    4681             :     { { (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 },
    4682             :     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
    4683             :     { { (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 },
    4684             :     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
    4685             :     { { (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 },
    4686             :     { { (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 },
    4687             :     { { (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 },
    4688             :     { { (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 },
    4689             :     GMENUITEM2_EMPTY
    4690             : };
    4691             : 
    4692             : static GMenuItem2 dummyall[] = {
    4693             :     { { (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 },
    4694             :     GMENUITEM2_EMPTY
    4695             : };
    4696             : 
    4697             : /* Builds up a menu containing all the anchor classes */
    4698           0 : static void aplistbuild(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
    4699           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    4700             : 
    4701           0 :     GMenuItemArrayFree(mi->sub);
    4702           0 :     mi->sub = NULL;
    4703             : 
    4704           0 :     _aplistbuild(mi,fv->b.sf,FVMenuAnchorPairs);
    4705           0 : }
    4706             : 
    4707             : static GMenuItem2 cblist[] = {
    4708             :     { { (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 },
    4709             :     { { (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 },
    4710             :     { { (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 },
    4711             :     GMENUITEM2_EMPTY
    4712             : };
    4713             : 
    4714           0 : static void cblistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
    4715           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    4716           0 :     SplineFont *sf = fv->b.sf;
    4717           0 :     int i, anyligs=0, anykerns=0, gid;
    4718             :     PST *pst;
    4719             : 
    4720           0 :     if ( sf->kerns ) anykerns=true;
    4721           0 :     for ( i=0; i<fv->b.map->enccount; ++i ) if ( (gid = fv->b.map->map[i])!=-1 && sf->glyphs[gid]!=NULL ) {
    4722           0 :         for ( pst=sf->glyphs[gid]->possub; pst!=NULL; pst=pst->next ) {
    4723           0 :             if ( pst->type==pst_ligature ) {
    4724           0 :                 anyligs = true;
    4725           0 :                 if ( anykerns )
    4726           0 :     break;
    4727             :             }
    4728             :         }
    4729           0 :         if ( sf->glyphs[gid]->kerns!=NULL ) {
    4730           0 :             anykerns = true;
    4731           0 :             if ( anyligs )
    4732           0 :     break;
    4733             :         }
    4734             :     }
    4735             : 
    4736           0 :     for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
    4737           0 :         switch ( mi->mid ) {
    4738             :           case MID_Ligatures:
    4739           0 :             mi->ti.disabled = !anyligs;
    4740           0 :           break;
    4741             :           case MID_KernPairs:
    4742           0 :             mi->ti.disabled = !anykerns;
    4743           0 :           break;
    4744             :           case MID_AnchorPairs:
    4745           0 :             mi->ti.disabled = sf->anchor==NULL;
    4746           0 :           break;
    4747             :         }
    4748             :     }
    4749           0 : }
    4750             : 
    4751             : 
    4752             : static GMenuItem2 gllist[] = {
    4753             :     { { (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 },
    4754             :     { { (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 },
    4755             :     { { (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 },
    4756             :     { { (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 },
    4757             :     GMENUITEM2_EMPTY
    4758             : };
    4759             : 
    4760           0 : static void gllistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
    4761           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    4762             : 
    4763           0 :     for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
    4764           0 :         mi->ti.checked = fv->glyphlabel == mi->mid;
    4765             :     }
    4766           0 : }
    4767             : 
    4768             : static GMenuItem2 emptymenu[] = {
    4769             :     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0},
    4770             :     GMENUITEM2_EMPTY
    4771             : };
    4772             : 
    4773           0 : static void FVEncodingMenuBuild(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
    4774           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    4775             : 
    4776           0 :     if ( mi->sub!=NULL ) {
    4777           0 :         GMenuItemArrayFree(mi->sub);
    4778           0 :         mi->sub = NULL;
    4779             :     }
    4780           0 :     mi->sub = GetEncodingMenu(FVMenuReencode,fv->b.map->enc);
    4781           0 : }
    4782             : 
    4783           0 : static void FVMenuAddUnencoded(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    4784           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    4785             :     char *ret, *end;
    4786             :     int cnt;
    4787             : 
    4788           0 :     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?"));
    4789           0 :     if ( ret==NULL )
    4790           0 : return;
    4791           0 :     cnt = strtol(ret,&end,10);
    4792           0 :     if ( *end!='\0' || cnt<=0 ) {
    4793           0 :         free(ret);
    4794           0 :         ff_post_error( _("Bad Number"),_("Bad Number") );
    4795           0 : return;
    4796             :     }
    4797           0 :     free(ret);
    4798           0 :     FVAddUnencoded((FontViewBase *) fv, cnt);
    4799             : }
    4800             : 
    4801           0 : static void FVMenuRemoveUnused(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    4802           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    4803           0 :     FVRemoveUnused((FontViewBase *) fv);
    4804           0 : }
    4805             : 
    4806           0 : static void FVMenuCompact(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    4807           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    4808             :     SplineChar *sc;
    4809             : 
    4810           0 :     sc = FVFindACharInDisplay(fv);
    4811           0 :     FVCompact((FontViewBase *) fv);
    4812           0 :     if ( sc!=NULL ) {
    4813           0 :         int enc = fv->b.map->backmap[sc->orig_pos];
    4814           0 :         if ( enc!=-1 )
    4815           0 :             FVScrollToChar(fv,enc);
    4816             :     }
    4817           0 : }
    4818             : 
    4819           0 : static void FVMenuDetachGlyphs(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    4820           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    4821           0 :     FVDetachGlyphs((FontViewBase *) fv);
    4822           0 : }
    4823             : 
    4824           0 : static void FVMenuDetachAndRemoveGlyphs(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    4825           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    4826             :     char *buts[3];
    4827             : 
    4828           0 :     buts[0] = _("_Remove");
    4829           0 :     buts[1] = _("_Cancel");
    4830           0 :     buts[2] = NULL;
    4831             : 
    4832           0 :     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 )
    4833           0 : return;
    4834             : 
    4835           0 :     FVDetachAndRemoveGlyphs((FontViewBase *) fv);
    4836             : }
    4837             : 
    4838           0 : static void FVForceEncodingMenuBuild(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
    4839           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    4840             : 
    4841           0 :     if ( mi->sub!=NULL ) {
    4842           0 :         GMenuItemArrayFree(mi->sub);
    4843           0 :         mi->sub = NULL;
    4844             :     }
    4845           0 :     mi->sub = GetEncodingMenu(FVMenuForceEncode,fv->b.map->enc);
    4846           0 : }
    4847             : 
    4848           0 : static void FVMenuAddEncodingName(GWindow UNUSED(gw), struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    4849             :     char *ret;
    4850             :     Encoding *enc;
    4851             : 
    4852             :     /* Search the iconv database for the named encoding */
    4853           0 :     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."));
    4854           0 :     if ( ret==NULL )
    4855           0 : return;
    4856           0 :     enc = FindOrMakeEncoding(ret);
    4857           0 :     if ( enc==NULL )
    4858           0 :         ff_post_error(_("Invalid Encoding"),_("Invalid Encoding"));
    4859           0 :     free(ret);
    4860             : }
    4861             : 
    4862           0 : static void FVMenuLoadEncoding(GWindow UNUSED(gw), struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    4863           0 :     LoadEncodingFile();
    4864           0 : }
    4865             : 
    4866           0 : static void FVMenuMakeFromFont(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    4867           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    4868           0 :     (void) MakeEncoding(fv->b.sf,fv->b.map);
    4869           0 : }
    4870             : 
    4871           0 : static void FVMenuRemoveEncoding(GWindow UNUSED(gw), struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    4872           0 :     RemoveEncoding();
    4873           0 : }
    4874             : 
    4875           0 : static void FVMenuMakeNamelist(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    4876           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    4877             :     char buffer[1025];
    4878             :     char *filename, *temp;
    4879             :     FILE *file;
    4880             : 
    4881           0 :     snprintf(buffer, sizeof(buffer),"%s/%s.nam", getFontForgeUserDir(Config), fv->b.sf->fontname );
    4882           0 :     temp = def2utf8_copy(buffer);
    4883           0 :     filename = gwwv_save_filename(_("Make Namelist"), temp,"*.nam");
    4884           0 :     free(temp);
    4885           0 :     if ( filename==NULL )
    4886           0 : return;
    4887           0 :     temp = utf82def_copy(filename);
    4888           0 :     file = fopen(temp,"w");
    4889           0 :     free(temp);
    4890           0 :     if ( file==NULL ) {
    4891           0 :         ff_post_error(_("Namelist creation failed"),_("Could not write %s"), filename);
    4892           0 :         free(filename);
    4893           0 : return;
    4894             :     }
    4895           0 :     FVB_MakeNamelist((FontViewBase *) fv, file);
    4896           0 :     fclose(file);
    4897             : }
    4898             : 
    4899           0 : static void FVMenuLoadNamelist(GWindow UNUSED(gw), struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    4900             :     /* Read in a name list and copy it into the prefs dir so that we'll find */
    4901             :     /*  it in the future */
    4902             :     /* Be prepared to update what we've already got if names match */
    4903             :     char buffer[1025];
    4904           0 :     char *ret = gwwv_open_filename(_("Load Namelist"),NULL,
    4905             :             "*.nam",NULL);
    4906             :     char *temp, *pt;
    4907             :     char *buts[3];
    4908             :     FILE *old, *new;
    4909             :     int ch, ans;
    4910             :     NameList *nl;
    4911             : 
    4912           0 :     if ( ret==NULL )
    4913           0 : return;                         /* Cancelled */
    4914           0 :     temp = utf82def_copy(ret);
    4915           0 :     pt = strrchr(temp,'/');
    4916           0 :     if ( pt==NULL )
    4917           0 :         pt = temp;
    4918             :     else
    4919           0 :         ++pt;
    4920           0 :     snprintf(buffer,sizeof(buffer),"%s/%s", getFontForgeUserDir(Config), pt);
    4921           0 :     if ( access(buffer,F_OK)==0 ) {
    4922           0 :         buts[0] = _("_Replace");
    4923           0 :         buts[1] = _("_Cancel");
    4924           0 :         buts[2] = NULL;
    4925           0 :         ans = gwwv_ask( _("Replace"),(const char **) buts,0,1,_("A name list with this name already exists. Replace it?"));
    4926           0 :         if ( ans==1 ) {
    4927           0 :             free(temp);
    4928           0 :             free(ret);
    4929           0 : return;
    4930             :         }
    4931             :     }
    4932             : 
    4933           0 :     old = fopen( temp,"r");
    4934           0 :     if ( old==NULL ) {
    4935           0 :         ff_post_error(_("No such file"),_("Could not read %s"), ret );
    4936           0 :         free(ret); free(temp);
    4937           0 : return;
    4938             :     }
    4939           0 :     if ( (nl = LoadNamelist(temp))==NULL ) {
    4940           0 :         ff_post_error(_("Bad namelist file"),_("Could not parse %s"), ret );
    4941           0 :         free(ret); free(temp);
    4942           0 :         fclose(old);
    4943           0 : return;
    4944             :     }
    4945           0 :     free(ret); free(temp);
    4946           0 :     if ( nl->uses_unicode ) {
    4947           0 :         if ( nl->a_utf8_name!=NULL )
    4948           0 :             ff_post_notice(_("Non-ASCII glyphnames"),_("This namelist contains at least one non-ASCII glyph name, namely: %s"), nl->a_utf8_name );
    4949             :         else
    4950           0 :             ff_post_notice(_("Non-ASCII glyphnames"),_("This namelist is based on a namelist which contains non-ASCII glyph names"));
    4951             :     }
    4952             : 
    4953           0 :     new = fopen( buffer,"w");
    4954           0 :     if ( new==NULL ) {
    4955           0 :         ff_post_error(_("Create failed"),_("Could not write %s"), buffer );
    4956           0 :         fclose(old);
    4957           0 : return;
    4958             :     }
    4959             : 
    4960           0 :     while ( (ch=getc(old))!=EOF )
    4961           0 :         putc(ch,new);
    4962           0 :     fclose(old);
    4963           0 :     fclose(new);
    4964             : }
    4965             : 
    4966           0 : static void FVMenuRenameByNamelist(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    4967           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    4968           0 :     char **namelists = AllNamelistNames();
    4969             :     int i;
    4970             :     int ret;
    4971             :     NameList *nl;
    4972             :     extern int allow_utf8_glyphnames;
    4973             : 
    4974           0 :     for ( i=0; namelists[i]!=NULL; ++i );
    4975           0 :     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"));
    4976           0 :     if ( ret==-1 )
    4977           0 : return;
    4978           0 :     nl = NameListByName(namelists[ret]);
    4979           0 :     if ( nl==NULL ) {
    4980           0 :         IError("Couldn't find namelist");
    4981           0 : return;
    4982           0 :     } else if ( nl!=NULL && nl->uses_unicode && !allow_utf8_glyphnames) {
    4983           0 :         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."));
    4984           0 : return;
    4985             :     }
    4986           0 :     SFRenameGlyphsToNamelist(fv->b.sf,nl);
    4987           0 :     GDrawRequestExpose(fv->v,NULL,false);
    4988             : }
    4989             : 
    4990           0 : static void FVMenuNameGlyphs(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
    4991           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    4992             :     /* Read a file containing a list of names, and add an unencoded glyph for */
    4993             :     /*  each name */
    4994             :     char buffer[33];
    4995           0 :     char *ret = gwwv_open_filename(_("Load glyph names"),NULL, "*",NULL);
    4996             :     char *temp, *pt;
    4997             :     FILE *file;
    4998             :     int ch;
    4999             :     SplineChar *sc;
    5000             :     FontView *fvs;
    5001             : 
    5002           0 :     if ( ret==NULL )
    5003           0 : return;                         /* Cancelled */
    5004           0 :     temp = utf82def_copy(ret);
    5005             : 
    5006           0 :     file = fopen( temp,"r");
    5007           0 :     if ( file==NULL ) {
    5008           0 :         ff_post_error(_("No such file"),_("Could not read %s"), ret );
    5009           0 :         free(ret); free(temp);
    5010           0 : return;
    5011             :     }
    5012           0 :     pt = buffer;
    5013             :     for (;;) {
    5014           0 :         ch = getc(file);
    5015           0 :         if ( ch!=EOF && !isspace(ch)) {
    5016           0 :             if ( pt<buffer+sizeof(buffer)-1 )
    5017           0 :                 *pt++ = ch;
    5018             :         } else {
    5019           0 :             if ( pt!=buffer ) {
    5020           0 :                 *pt = '\0';
    5021           0 :                 sc = NULL;
    5022           0 :                 for ( fvs=(FontView *) (fv->b.sf->fv); fvs!=NULL; fvs=(FontView *) (fvs->b.nextsame) ) {
    5023           0 :                     EncMap *map = fvs->b.map;
    5024           0 :                     if ( map->enccount+1>=map->encmax )
    5025           0 :                         map->map = realloc(map->map,(map->encmax += 20)*sizeof(int));
    5026           0 :                     map->map[map->enccount] = -1;
    5027           0 :                     fvs->b.selected = realloc(fvs->b.selected,(map->enccount+1));
    5028           0 :                     memset(fvs->b.selected+map->enccount,0,1);
    5029           0 :                     ++map->enccount;
    5030           0 :                     if ( sc==NULL ) {
    5031           0 :                         sc = SFMakeChar(fv->b.sf,map,map->enccount-1);
    5032           0 :                         free(sc->name);
    5033           0 :                         sc->name = copy(buffer);
    5034           0 :                         sc->comment = copy(".");   /* Mark as something for sfd file */
    5035             :                     }
    5036           0 :                     map->map[map->enccount-1] = sc->orig_pos;
    5037           0 :                     map->backmap[sc->orig_pos] = map->enccount-1;
    5038             :                 }
    5039           0 :                 pt = buffer;
    5040             :             }
    5041           0 :             if ( ch==EOF )
    5042           0 :     break;
    5043             :         }
    5044           0 :     }
    5045           0 :     fclose(file);
    5046           0 :     free(ret); free(temp);
    5047           0 :     FontViewReformatAll(fv->b.sf);
    5048             : }
    5049             : 
    5050             : static GMenuItem2 enlist[] = {
    5051             :     { { (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 },
    5052             :     { { (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 },
    5053             :     { { (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 },
    5054             :     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
    5055             :     { { (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 },
    5056             :     { { (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 },
    5057             :     { { (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 },
    5058             :     { { (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 },
    5059             :     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
    5060             :     { { (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 },
    5061             :     { { (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 },
    5062             :     { { (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 },
    5063             :     { { (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 },
    5064             :     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
    5065             :     { { (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 },
    5066             :     { { (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 },
    5067             :     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
    5068             :     { { (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 },
    5069             :     { { (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 },
    5070             :     { { (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 },
    5071             :     { { (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 },
    5072             :     GMENUITEM2_EMPTY
    5073             : };
    5074             : 
    5075           0 : static void enlistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
    5076           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    5077             :     int i, gid;
    5078           0 :     SplineFont *sf = fv->b.sf;
    5079           0 :     EncMap *map = fv->b.map;
    5080           0 :     int anyglyphs = false;
    5081             : 
    5082           0 :     for ( i=map->enccount-1; i>=0 ; --i )
    5083           0 :         if ( fv->b.selected[i] && (gid=map->map[i])!=-1 )
    5084           0 :             anyglyphs = true;
    5085             : 
    5086           0 :     for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
    5087           0 :         switch ( mi->mid ) {
    5088             :           case MID_Compact:
    5089           0 :             mi->ti.checked = fv->b.normal!=NULL;
    5090           0 :           break;
    5091             :         case MID_HideNoGlyphSlots:
    5092           0 :             break;
    5093             :           case MID_Reencode: case MID_ForceReencode:
    5094           0 :             mi->ti.disabled = fv->b.cidmaster!=NULL;
    5095           0 :           break;
    5096             :           case MID_DetachGlyphs: case MID_DetachAndRemoveGlyphs:
    5097           0 :             mi->ti.disabled = !anyglyphs;
    5098           0 :           break;
    5099             :           case MID_RemoveUnused:
    5100           0 :             gid = map->enccount>0 ? map->map[map->enccount-1] : -1;
    5101           0 :             mi->ti.disabled = gid!=-1 && SCWorthOutputting(sf->glyphs[gid]);
    5102           0 :           break;
    5103             :           case MID_MakeFromFont:
    5104           0 :             mi->ti.disabled = fv->b.cidmaster!=NULL || map->enccount>1024 || map->enc!=&custom;
    5105           0 :           break;
    5106             :           case MID_RemoveEncoding:
    5107           0 :           break;
    5108             :           case MID_DisplayByGroups:
    5109           0 :             mi->ti.disabled = fv->b.cidmaster!=NULL || group_root==NULL;
    5110           0 :           break;
    5111             :           case MID_NameGlyphs:
    5112           0 :             mi->ti.disabled = fv->b.normal!=NULL || fv->b.cidmaster!=NULL;
    5113           0 :           break;
    5114             :           case MID_RenameGlyphs: case MID_SaveNamelist:
    5115           0 :             mi->ti.disabled = fv->b.cidmaster!=NULL;
    5116           0 :           break;
    5117             :         }
    5118             :     }
    5119           0 : }
    5120             : 
    5121             : static GMenuItem2 lylist[] = {
    5122             :     { { (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 },
    5123             :     GMENUITEM2_EMPTY
    5124             : };
    5125             : 
    5126           0 : static void lylistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
    5127           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    5128           0 :     SplineFont *sf = fv->b.sf;
    5129             :     int ly;
    5130             :     GMenuItem *sub;
    5131             : 
    5132           0 :     sub = calloc(sf->layer_cnt+1,sizeof(GMenuItem));
    5133           0 :     for ( ly=ly_fore; ly<sf->layer_cnt; ++ly ) {
    5134           0 :         sub[ly-1].ti.text = utf82u_copy(sf->layers[ly].name);
    5135           0 :         sub[ly-1].ti.checkable = true;
    5136           0 :         sub[ly-1].ti.checked = ly == fv->b.active_layer;
    5137           0 :         sub[ly-1].invoke = FVMenuChangeLayer;
    5138           0 :         sub[ly-1].mid = ly;
    5139           0 :         sub[ly-1].ti.fg = sub[ly-1].ti.bg = COLOR_DEFAULT;
    5140             :     }
    5141           0 :     GMenuItemArrayFree(mi->sub);
    5142           0 :     mi->sub = sub;
    5143           0 : }
    5144             : 
    5145             : static GMenuItem2 vwlist[] = {
    5146             :     { { (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 },
    5147             :     { { (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 },
    5148             :     { { (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 },
    5149             :     { { (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 },
    5150             :     { { (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 },
    5151             :     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
    5152             :     { { (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 },
    5153             :     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
    5154             :     { { (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 },
    5155             :     { { (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 },
    5156             :     { { (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 },
    5157             :     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
    5158             :     { { (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 },
    5159             :     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
    5160             :     { { (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 },
    5161             :     { { (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 },
    5162             :     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
    5163             :     { { (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 },
    5164             :     { { (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 },
    5165             :     { { (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 },
    5166             :     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
    5167             :     { { (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 },
    5168             :     { { (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 },
    5169             :     { { (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 },
    5170             :     { { (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 },
    5171             :     { { (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 },
    5172             :     { { (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 },
    5173             :     { { (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 },
    5174             :     { { (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 em|No Shortcut"), NULL, NULL, FVMenuSize, MID_FitToBbox },
    5175             :     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
    5176             :     { { (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 },
    5177             :     GMENUITEM2_EMPTY,                   /* Some extra room to show bitmaps */
    5178             :     GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY,
    5179             :     GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY,
    5180             :     GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY,
    5181             :     GMENUITEM2_EMPTY
    5182             : };
    5183             : 
    5184           0 : static void vwlistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
    5185           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    5186           0 :     int anychars = FVAnyCharSelected(fv);
    5187             :     int i, base;
    5188             :     BDFFont *bdf;
    5189             :     char buffer[50];
    5190             :     int pos;
    5191           0 :     SplineFont *sf = fv->b.sf;
    5192           0 :     SplineFont *master = sf->cidmaster ? sf->cidmaster : sf;
    5193           0 :     EncMap *map = fv->b.map;
    5194             :     OTLookup *otl;
    5195             : 
    5196           0 :     for ( i=0; vwlist[i].ti.text==NULL || strcmp((char *) vwlist[i].ti.text, _("Bitmap _Magnification..."))!=0; ++i );
    5197           0 :     base = i+1;
    5198           0 :     for ( i=base; vwlist[i].ti.text!=NULL; ++i ) {
    5199           0 :         free( vwlist[i].ti.text);
    5200           0 :         vwlist[i].ti.text = NULL;
    5201             :     }
    5202             : 
    5203           0 :     vwlist[base-1].ti.disabled = true;
    5204           0 :     if ( master->bitmaps!=NULL ) {
    5205           0 :         for ( bdf = master->bitmaps, i=base;
    5206           0 :                 i<sizeof(vwlist)/sizeof(vwlist[0])-1 && bdf!=NULL;
    5207           0 :                 ++i, bdf = bdf->next ) {
    5208           0 :             if ( BDFDepth(bdf)==1 )
    5209           0 :                 sprintf( buffer, _("%d pixel bitmap"), bdf->pixelsize );
    5210             :             else
    5211           0 :                 sprintf( buffer, _("%d@%d pixel bitmap"),
    5212           0 :                         bdf->pixelsize, BDFDepth(bdf) );
    5213           0 :             vwlist[i].ti.text = (unichar_t *) utf82u_copy(buffer);
    5214           0 :             vwlist[i].ti.checkable = true;
    5215           0 :             vwlist[i].ti.checked = bdf==fv->show;
    5216           0 :             vwlist[i].ti.userdata = bdf;
    5217           0 :             vwlist[i].invoke = FVMenuShowBitmap;
    5218           0 :             vwlist[i].ti.fg = vwlist[i].ti.bg = COLOR_DEFAULT;
    5219           0 :             if ( bdf==fv->show )
    5220           0 :                 vwlist[base-1].ti.disabled = false;
    5221             :         }
    5222             :     }
    5223           0 :     GMenuItemArrayFree(mi->sub);
    5224           0 :     mi->sub = GMenuItem2ArrayCopy(vwlist,NULL);
    5225             : 
    5226           0 :     for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
    5227           0 :         switch ( mi->mid ) {
    5228             :           case MID_Next: case MID_Prev:
    5229           0 :             mi->ti.disabled = anychars<0;
    5230           0 :           break;
    5231             :           case MID_NextDef:
    5232           0 :             pos = anychars+1;
    5233           0 :             if ( anychars<0 ) pos = map->enccount;
    5234           0 :             for ( ; pos<map->enccount &&
    5235           0 :                     (map->map[pos]==-1 || !SCWorthOutputting(sf->glyphs[map->map[pos]]));
    5236           0 :                     ++pos );
    5237           0 :             mi->ti.disabled = pos==map->enccount;
    5238           0 :           break;
    5239             :           case MID_PrevDef:
    5240           0 :             for ( pos = anychars-1; pos>=0 &&
    5241           0 :                     (map->map[pos]==-1 || !SCWorthOutputting(sf->glyphs[map->map[pos]]));
    5242           0 :                     --pos );
    5243           0 :             mi->ti.disabled = pos<0;
    5244           0 :           break;
    5245           0 :           case MID_DisplaySubs: { SplineFont *_sf = sf;
    5246           0 :             mi->ti.checked = fv->cur_subtable!=NULL;
    5247           0 :             if ( _sf->cidmaster ) _sf = _sf->cidmaster;
    5248           0 :             for ( otl=_sf->gsub_lookups; otl!=NULL; otl=otl->next )
    5249           0 :                 if ( otl->lookup_type == gsub_single && otl->subtables!=NULL )
    5250           0 :             break;
    5251           0 :             mi->ti.disabled = otl==NULL;
    5252           0 :           } break;
    5253             :           case MID_ShowHMetrics:
    5254           0 :           break;
    5255             :           case MID_ShowVMetrics:
    5256           0 :             mi->ti.disabled = !sf->hasvmetrics;
    5257           0 :           break;
    5258             :           case MID_32x8:
    5259           0 :             mi->ti.checked = (fv->rowcnt==8 && fv->colcnt==32);
    5260           0 :             mi->ti.disabled = fv->b.container!=NULL;
    5261           0 :           break;
    5262             :           case MID_16x4:
    5263           0 :             mi->ti.checked = (fv->rowcnt==4 && fv->colcnt==16);
    5264           0 :             mi->ti.disabled = fv->b.container!=NULL;
    5265           0 :           break;
    5266             :           case MID_8x2:
    5267           0 :             mi->ti.checked = (fv->rowcnt==2 && fv->colcnt==8);
    5268           0 :             mi->ti.disabled = fv->b.container!=NULL;
    5269           0 :           break;
    5270             :           case MID_24:
    5271           0 :             mi->ti.checked = (fv->show!=NULL && fv->show==fv->filled && fv->show->pixelsize==24);
    5272           0 :             mi->ti.disabled = sf->onlybitmaps && fv->show!=fv->filled;
    5273           0 :           break;
    5274             :           case MID_36:
    5275           0 :             mi->ti.checked = (fv->show!=NULL && fv->show==fv->filled && fv->show->pixelsize==36);
    5276           0 :             mi->ti.disabled = sf->onlybitmaps && fv->show!=fv->filled;
    5277           0 :           break;
    5278             :           case MID_48:
    5279           0 :             mi->ti.checked = (fv->show!=NULL && fv->show==fv->filled && fv->show->pixelsize==48);
    5280           0 :             mi->ti.disabled = sf->onlybitmaps && fv->show!=fv->filled;
    5281           0 :           break;
    5282             :           case MID_72:
    5283           0 :             mi->ti.checked = (fv->show!=NULL && fv->show==fv->filled && fv->show->pixelsize==72);
    5284           0 :             mi->ti.disabled = sf->onlybitmaps && fv->show!=fv->filled;
    5285           0 :           break;
    5286             :           case MID_96:
    5287           0 :             mi->ti.checked = (fv->show!=NULL && fv->show==fv->filled && fv->show->pixelsize==96);
    5288           0 :             mi->ti.disabled = sf->onlybitmaps && fv->show!=fv->filled;
    5289           0 :           break;
    5290             :           case MID_128:
    5291           0 :             mi->ti.checked = (fv->show!=NULL && fv->show==fv->filled && fv->show->pixelsize==128);
    5292           0 :             mi->ti.disabled = sf->onlybitmaps && fv->show!=fv->filled;
    5293           0 :           break;
    5294             :           case MID_AntiAlias:
    5295           0 :             mi->ti.checked = (fv->show!=NULL && fv->show->clut!=NULL);
    5296           0 :             mi->ti.disabled = sf->onlybitmaps && fv->show!=fv->filled;
    5297           0 :           break;
    5298             :           case MID_FitToBbox:
    5299           0 :             mi->ti.checked = (fv->show!=NULL && fv->show->bbsized);
    5300           0 :             mi->ti.disabled = sf->onlybitmaps && fv->show!=fv->filled;
    5301           0 :           break;
    5302             :           case MID_Layers:
    5303           0 :             mi->ti.disabled = sf->layer_cnt<=2 || sf->multilayer;
    5304           0 :           break;
    5305             :         }
    5306             :     }
    5307           0 : }
    5308             : 
    5309             : static GMenuItem2 histlist[] = {
    5310             :     { { (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 },
    5311             :     { { (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 },
    5312             :     { { (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 },
    5313             :     GMENUITEM2_EMPTY
    5314             : };
    5315             : 
    5316             : static GMenuItem2 htlist[] = {
    5317             :     { { (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 },
    5318             :     { { (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 },
    5319             :     { { (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 },
    5320             :     { { (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 },
    5321             :     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
    5322             :     { { (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 },
    5323             :     { { (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 },
    5324             :     { { (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 },
    5325             :     { { (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 },
    5326             :     { { (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 },
    5327             :     { { (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 },
    5328             :     { { (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 },
    5329             :     { { (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 },
    5330             :     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
    5331             :     { { (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 },
    5332             :     { { (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 },
    5333             :     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
    5334             :     { { (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 },
    5335             :     GMENUITEM2_EMPTY
    5336             : };
    5337             : 
    5338             : static GMenuItem2 mtlist[] = {
    5339             :     { { (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 },
    5340             :     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
    5341             :     { { (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 },
    5342             :     { { (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 },
    5343             :     { { (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 },
    5344             :     { { (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 },
    5345             :     { { (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 },
    5346             :     { { (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 },
    5347             :     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
    5348             :     { { (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 },
    5349             :     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
    5350             :     { { (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 },
    5351             :     { { (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 },
    5352             :     { { (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 },
    5353             :     { { (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 },
    5354             :     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
    5355             :     { { (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 },
    5356             :     { { (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 },
    5357             :     { { (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 },
    5358             :     GMENUITEM2_EMPTY
    5359             : };
    5360             : 
    5361             : static GMenuItem2 cdlist[] = {
    5362             :     { { (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 },
    5363             :     { { (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 },
    5364             :     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
    5365             :     { { (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 },
    5366             :     { { (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 },
    5367             :     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
    5368             :     { { (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 },
    5369             :     { { (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 },
    5370             :     { { (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 },
    5371             :     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
    5372             :     { { (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 },
    5373             :     { { (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 },
    5374             :     GMENUITEM2_EMPTY,                           /* Extra room to show sub-font names */
    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, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY,
    5383             :     GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY,
    5384             :     GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY,
    5385             :     GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY,
    5386             :     GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY,
    5387             :     GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY,
    5388             :     GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY,
    5389             :     GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY,
    5390             :     GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY,
    5391             :     GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY,
    5392             :     GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY,
    5393             :     GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY,
    5394             :     GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY,
    5395             :     GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY,
    5396             :     GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY,
    5397             :     GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY,
    5398             :     GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY,
    5399             :     GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY,
    5400             :     GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY,
    5401             :     GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY,
    5402             :     GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY,
    5403             :     GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY,
    5404             :     GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY,
    5405             :     GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY,
    5406             :     GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY,
    5407             :     GMENUITEM2_EMPTY
    5408             : };
    5409             : 
    5410           0 : static void cdlistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
    5411           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    5412             :     int i, base, j;
    5413           0 :     SplineFont *sub, *cidmaster = fv->b.cidmaster;
    5414             : 
    5415           0 :     for ( i=0; cdlist[i].mid!=MID_CIDFontInfo; ++i );
    5416           0 :     base = i+2;
    5417           0 :     for ( i=base; cdlist[i].ti.text!=NULL; ++i ) {
    5418           0 :         free( cdlist[i].ti.text);
    5419           0 :         cdlist[i].ti.text = NULL;
    5420             :     }
    5421             : 
    5422           0 :     cdlist[base-1].ti.fg = cdlist[base-1].ti.bg = COLOR_DEFAULT;
    5423           0 :     if ( cidmaster==NULL ) {
    5424           0 :         cdlist[base-1].ti.line = false;
    5425             :     } else {
    5426           0 :         cdlist[base-1].ti.line = true;
    5427           0 :         for ( j = 0, i=base;
    5428           0 :                 i<sizeof(cdlist)/sizeof(cdlist[0])-1 && j<cidmaster->subfontcnt;
    5429           0 :                 ++i, ++j ) {
    5430           0 :             sub = cidmaster->subfonts[j];
    5431           0 :             cdlist[i].ti.text = uc_copy(sub->fontname);
    5432           0 :             cdlist[i].ti.checkable = true;
    5433           0 :             cdlist[i].ti.checked = sub==fv->b.sf;
    5434           0 :             cdlist[i].ti.userdata = sub;
    5435           0 :             cdlist[i].invoke = FVMenuShowSubFont;
    5436           0 :             cdlist[i].ti.fg = cdlist[i].ti.bg = COLOR_DEFAULT;
    5437             :         }
    5438             :     }
    5439           0 :     GMenuItemArrayFree(mi->sub);
    5440           0 :     mi->sub = GMenuItem2ArrayCopy(cdlist,NULL);
    5441             : 
    5442           0 :     for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
    5443           0 :         switch ( mi->mid ) {
    5444             :           case MID_Convert2CID: case MID_ConvertByCMap:
    5445           0 :             mi->ti.disabled = cidmaster!=NULL || fv->b.sf->mm!=NULL;
    5446           0 :           break;
    5447             :           case MID_InsertFont: case MID_InsertBlank:
    5448             :             /* OpenType allows at most 255 subfonts (PS allows more, but why go to the effort to make safe font check that? */
    5449           0 :             mi->ti.disabled = cidmaster==NULL || cidmaster->subfontcnt>=255;
    5450           0 :           break;
    5451             :           case MID_RemoveFromCID:
    5452           0 :             mi->ti.disabled = cidmaster==NULL || cidmaster->subfontcnt<=1;
    5453           0 :           break;
    5454             :           case MID_Flatten: case MID_FlattenByCMap: case MID_CIDFontInfo:
    5455             :           case MID_ChangeSupplement:
    5456           0 :             mi->ti.disabled = cidmaster==NULL;
    5457           0 :           break;
    5458             :         }
    5459             :     }
    5460           0 : }
    5461             : 
    5462             : static GMenuItem2 mmlist[] = {
    5463             : /* GT: Here (and following) MM means "MultiMaster" */
    5464             :     { { (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 },
    5465             :     { { (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 },
    5466             :     { { (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 },
    5467             :     { { (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 },
    5468             :     { { (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 },
    5469             :     GMENUITEM2_EMPTY,                           /* Extra room to show sub-font names */
    5470             : };
    5471             : 
    5472           0 : static void mmlistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
    5473           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    5474             :     int i, base, j;
    5475           0 :     MMSet *mm = fv->b.sf->mm;
    5476             :     SplineFont *sub;
    5477             :     GMenuItem2 *mml;
    5478             : 
    5479           0 :     for ( i=0; mmlist[i].mid!=MID_ChangeMMBlend; ++i );
    5480           0 :     base = i+2;
    5481           0 :     if ( mm==NULL )
    5482           0 :         mml = mmlist;
    5483             :     else {
    5484           0 :         mml = calloc(base+mm->instance_count+2,sizeof(GMenuItem2));
    5485           0 :         memcpy(mml,mmlist,sizeof(mmlist));
    5486           0 :         mml[base-1].ti.fg = mml[base-1].ti.bg = COLOR_DEFAULT;
    5487           0 :         mml[base-1].ti.line = true;
    5488           0 :         for ( j = 0, i=base; j<mm->instance_count+1; ++i, ++j ) {
    5489           0 :             if ( j==0 )
    5490           0 :                 sub = mm->normal;
    5491             :             else
    5492           0 :                 sub = mm->instances[j-1];
    5493           0 :             mml[i].ti.text = uc_copy(sub->fontname);
    5494           0 :             mml[i].ti.checkable = true;
    5495           0 :             mml[i].ti.checked = sub==fv->b.sf;
    5496           0 :             mml[i].ti.userdata = sub;
    5497           0 :             mml[i].invoke = FVMenuShowSubFont;
    5498           0 :             mml[i].ti.fg = mml[i].ti.bg = COLOR_DEFAULT;
    5499             :         }
    5500             :     }
    5501           0 :     GMenuItemArrayFree(mi->sub);
    5502           0 :     mi->sub = GMenuItem2ArrayCopy(mml,NULL);
    5503           0 :     if ( mml!=mmlist ) {
    5504           0 :         for ( i=base; mml[i].ti.text!=NULL; ++i )
    5505           0 :             free( mml[i].ti.text);
    5506           0 :         free(mml);
    5507             :     }
    5508             : 
    5509           0 :     for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
    5510           0 :         switch ( mi->mid ) {
    5511             :           case MID_CreateMM:
    5512           0 :             mi->ti.disabled = false;
    5513           0 :           break;
    5514             :           case MID_MMInfo: case MID_MMValid: case MID_BlendToNew:
    5515           0 :             mi->ti.disabled = mm==NULL;
    5516           0 :           break;
    5517             :           case MID_ChangeMMBlend:
    5518           0 :             mi->ti.disabled = mm==NULL || mm->apple;
    5519           0 :           break;
    5520             :         }
    5521             :     }
    5522           0 : }
    5523             : 
    5524             : static GMenuItem2 wnmenu[] = {
    5525             :     { { (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 },
    5526             :     { { (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 },
    5527             :     { { (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 },
    5528             :     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
    5529             :     { { (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 },
    5530             :     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
    5531             :     GMENUITEM2_EMPTY
    5532             : };
    5533             : 
    5534           0 : static void FVWindowMenuBuild(GWindow gw, struct gmenuitem *mi, GEvent *e) {
    5535           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    5536           0 :     int anychars = FVAnyCharSelected(fv);
    5537             :     struct gmenuitem *wmi;
    5538           0 :     int in_modal = (fv->b.container!=NULL && fv->b.container->funcs->is_modal);
    5539             : 
    5540           0 :     WindowMenuBuild(gw,mi,e);
    5541           0 :     for ( wmi = mi->sub; wmi->ti.text!=NULL || wmi->ti.line ; ++wmi ) {
    5542           0 :         switch ( wmi->mid ) {
    5543             :           case MID_OpenOutline:
    5544           0 :             wmi->ti.disabled = anychars==-1 || in_modal;
    5545           0 :           break;
    5546             :           case MID_OpenBitmap:
    5547           0 :             wmi->ti.disabled = anychars==-1 || fv->b.sf->bitmaps==NULL || in_modal;
    5548           0 :           break;
    5549             :           case MID_OpenMetrics:
    5550           0 :             wmi->ti.disabled = in_modal;
    5551           0 :           break;
    5552             :           case MID_Warnings:
    5553           0 :             wmi->ti.disabled = ErrorWindowExists();
    5554           0 :           break;
    5555             :         }
    5556             :     }
    5557           0 : }
    5558             : 
    5559             : #ifdef BUILD_COLLAB
    5560             : static void FVMenuCollabStart(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e))
    5561             : {
    5562             :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    5563             : 
    5564             :     printf("connecting to server and sending initial SFD to it...\n");
    5565             : 
    5566             :     int port_default = 5556;
    5567             :     int port = port_default;
    5568             :     char address[IPADDRESS_STRING_LENGTH_T];
    5569             :     if( !getNetworkAddress( address ))
    5570             :     {
    5571             :         snprintf( address, IPADDRESS_STRING_LENGTH_T-1,
    5572             :                   "%s", HostPortPack( "127.0.0.1", port ));
    5573             :     }
    5574             :     else
    5575             :     {
    5576             :         snprintf( address, IPADDRESS_STRING_LENGTH_T-1,
    5577             :                   "%s", HostPortPack( address, port ));
    5578             :     }
    5579             : 
    5580             :     printf("host address:%s\n",address);
    5581             : 
    5582             :     char* res = gwwv_ask_string(
    5583             :         "Starting Collab Server",
    5584             :         address,
    5585             :         "FontForge has determined that your computer can be accessed"
    5586             :         " using the below address. Share that address with other people"
    5587             :         " who you wish to collaborate with...\n\nPress OK to start the collaboration server...");
    5588             : 
    5589             :     if( res )
    5590             :     {
    5591             :         printf("res:%s\n", res );
    5592             :         HostPortUnpack( res, &port, port_default );
    5593             : 
    5594             :         printf("address:%s\n", res );
    5595             :         printf("port:%d\n", port );
    5596             : 
    5597             :         void* cc = collabclient_new( res, port );
    5598             :         fv->b.collabClient = cc;
    5599             :         collabclient_sessionStart( cc, fv );
    5600             :         printf("connecting to server...sent the sfd for session start.\n");
    5601             :         free(res);
    5602             :     }
    5603             : }
    5604             : #endif
    5605             : 
    5606           0 : static int collab_MakeChoicesArray( GHashTable* peers, char** choices, int choices_sz, int localOnly )
    5607             : {
    5608             :     GHashTableIter iter;
    5609             :     gpointer key, value;
    5610           0 :     int lastidx = 0;
    5611           0 :     memset( choices, 0, sizeof(char*) * choices_sz );
    5612             : 
    5613           0 :     int i=0;
    5614           0 :     int maxUserNameLength = 1;
    5615           0 :     g_hash_table_iter_init (&iter, peers);
    5616           0 :     for( i=0; g_hash_table_iter_next (&iter, &key, &value); i++ )
    5617             :     {
    5618           0 :         beacon_announce_t* ba = (beacon_announce_t*)value;
    5619           0 :         maxUserNameLength = imax( maxUserNameLength, strlen(ba->username) );
    5620             :     }
    5621             : 
    5622           0 :     g_hash_table_iter_init (&iter, peers);
    5623           0 :     for( i=0; g_hash_table_iter_next (&iter, &key, &value); i++ )
    5624             :     {
    5625           0 :         beacon_announce_t* ba = (beacon_announce_t*)value;
    5626           0 :         if( localOnly && !collabclient_isAddressLocal( ba->ip ))
    5627           0 :             continue;
    5628             : 
    5629           0 :         printf("user:%s\n", ba->username );
    5630           0 :         printf("mach:%s\n", ba->machinename );
    5631             : 
    5632             :         char buf[101];
    5633           0 :         if( localOnly )
    5634             :         {
    5635           0 :             snprintf( buf, 100, "%s", ba->fontname );
    5636             :         }
    5637             :         else
    5638             :         {
    5639             :             char format[50];
    5640           0 :             sprintf( format, "%s %%%d", "%s", maxUserNameLength );
    5641           0 :             strcat( format, "s %s");
    5642           0 :             snprintf( buf, 100, format, ba->fontname, ba->username, ba->machinename );
    5643             :         }
    5644           0 :         choices[i] = copy( buf );
    5645           0 :         if( i >= choices_sz )
    5646           0 :             break;
    5647           0 :         lastidx++;
    5648             :     }
    5649             : 
    5650           0 :     return lastidx;
    5651             : }
    5652             : 
    5653           0 : static beacon_announce_t* collab_getBeaconFromChoicesArray( GHashTable* peers, int choice, int localOnly )
    5654             : {
    5655             :     GHashTableIter iter;
    5656             :     gpointer key, value;
    5657           0 :     int i=0;
    5658             : 
    5659           0 :     g_hash_table_iter_init (&iter, peers);
    5660           0 :     for( i=0; g_hash_table_iter_next (&iter, &key, &value); i++ )
    5661             :     {
    5662           0 :         beacon_announce_t* ba = (beacon_announce_t*)value;
    5663           0 :         if( localOnly && !collabclient_isAddressLocal( ba->ip ))
    5664           0 :             continue;
    5665           0 :         if( i != choice )
    5666           0 :             continue;
    5667           0 :         return ba;
    5668             :     }
    5669           0 :     return 0;
    5670             : }
    5671             : 
    5672             : 
    5673             : #ifdef BUILD_COLLAB
    5674             : static void FVMenuCollabConnect(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e))
    5675             : {
    5676             :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    5677             : 
    5678             :     printf("connecting to server...\n");
    5679             : 
    5680             :     {
    5681             :         int choices_sz = 100;
    5682             :         char* choices[101];
    5683             :         memset( choices, 0, sizeof(choices));
    5684             : 
    5685             :         collabclient_trimOldBeaconInformation( 0 );
    5686             :         GHashTable* peers = collabclient_getServersFromBeaconInfomration();
    5687             :         int localOnly = 0;
    5688             :         int max = collab_MakeChoicesArray( peers, choices, choices_sz, localOnly );
    5689             :         int choice = gwwv_choose(_("Connect to Collab Server"),(const char **) choices, max,
    5690             :                                  0,_("Select a collab server to connect to..."));
    5691             :         printf("you wanted %d\n", choice );
    5692             :         if( choice <= max )
    5693             :         {
    5694             :             beacon_announce_t* ba = collab_getBeaconFromChoicesArray( peers, choice, localOnly );
    5695             : 
    5696             :             if( ba )
    5697             :             {
    5698             :                 int port = ba->port;
    5699             :                 char address[IPADDRESS_STRING_LENGTH_T];
    5700             :                 strncpy( address, ba->ip, IPADDRESS_STRING_LENGTH_T-1 );
    5701             :                 void* cc = collabclient_new( address, port );
    5702             :                 fv->b.collabClient = cc;
    5703             :                 collabclient_sessionJoin( cc, fv );
    5704             :             }
    5705             :         }
    5706             :     }
    5707             : 
    5708             :     printf("FVMenuCollabConnect(done)\n");
    5709             : }
    5710             : 
    5711             : static void FVMenuCollabConnectToExplicitAddress(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e))
    5712             : {
    5713             :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    5714             : 
    5715             :     printf("********** connecting to server... explicit address... p:%p\n", pref_collab_last_server_connected_to);
    5716             : 
    5717             :     char* default_server = "localhost";
    5718             :     if( pref_collab_last_server_connected_to ) {
    5719             :         default_server = pref_collab_last_server_connected_to;
    5720             :     }
    5721             :     
    5722             :     char* res = gwwv_ask_string(
    5723             :         "Connect to Collab Server",
    5724             :         default_server,
    5725             :         "Please enter the network location of the Collab server you wish to connect to...");
    5726             :     if( res )
    5727             :     {
    5728             :         if( pref_collab_last_server_connected_to ) {
    5729             :             free( pref_collab_last_server_connected_to );
    5730             :         }
    5731             :         pref_collab_last_server_connected_to = copy( res );
    5732             :         SavePrefs(true);
    5733             :         
    5734             :         int port_default = 5556;
    5735             :         int port = port_default;
    5736             :         char address[IPADDRESS_STRING_LENGTH_T];
    5737             :         strncpy( address, res, IPADDRESS_STRING_LENGTH_T-1 );
    5738             :         HostPortUnpack( address, &port, port_default );
    5739             : 
    5740             :         void* cc = collabclient_new( address, port );
    5741             :         fv->b.collabClient = cc;
    5742             :         collabclient_sessionJoin( cc, fv );
    5743             :     }
    5744             : 
    5745             :     printf("FVMenuCollabConnect(done)\n");
    5746             : }
    5747             : 
    5748             : static void FVMenuCollabDisconnect(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e))
    5749             : {
    5750             :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    5751             :     collabclient_sessionDisconnect( &fv->b );
    5752             : }
    5753             : #endif
    5754             : 
    5755           0 : static void AskAndMaybeCloseLocalCollabServers()
    5756             : {
    5757             :     char *buts[3];
    5758           0 :     buts[0] = _("_OK");
    5759           0 :     buts[1] = _("_Cancel");
    5760           0 :     buts[2] = NULL;
    5761             : 
    5762           0 :     int i=0;
    5763           0 :     int choices_sz = 100;
    5764             :     char* choices[101];
    5765           0 :     collabclient_trimOldBeaconInformation( 0 );
    5766           0 :     GHashTable* peers = collabclient_getServersFromBeaconInfomration();
    5767           0 :     if( !peers )
    5768           0 :         return;
    5769             :     
    5770           0 :     int localOnly = 1;
    5771           0 :     int max = collab_MakeChoicesArray( peers, choices, choices_sz, localOnly );
    5772           0 :     if( !max )
    5773           0 :         return;
    5774             : 
    5775             :     char sel[101];
    5776           0 :     memset( sel, 1, max );
    5777           0 :     int choice = gwwv_choose_multiple(_("Close Collab Server(s)"),
    5778             :                                       (const char **) choices, sel, max,
    5779           0 :                                       buts, _("Select which servers you wish to close..."));
    5780             : 
    5781           0 :     int allServersSelected = 1;
    5782           0 :     printf("you wanted %d\n", choice );
    5783           0 :     for( i=0; i < max; i++ )
    5784             :     {
    5785           0 :         printf("sel[%d] is %d\n", i, sel[i] );
    5786           0 :         beacon_announce_t* ba = collab_getBeaconFromChoicesArray( peers, choice, localOnly );
    5787             : 
    5788           0 :         if( sel[i] && ba )
    5789           0 :         {
    5790           0 :             int port = ba->port;
    5791             : 
    5792           0 :             if( sel[i] )
    5793             :             {
    5794           0 :                 FontViewBase* fv = FontViewFind( FontViewFind_byCollabBasePort, (void*)(intptr_t)port );
    5795           0 :                 if( fv )
    5796           0 :                     collabclient_sessionDisconnect( fv );
    5797           0 :                 printf("CLOSING port:%d fv:%p\n", port, fv );
    5798           0 :                 collabclient_closeLocalServer( port );
    5799             :             }
    5800             :         }
    5801             :         else
    5802             :         {
    5803           0 :             allServersSelected = 0;
    5804             :         }
    5805             :     }
    5806             : 
    5807           0 :     printf("allServersSelected:%d\n", allServersSelected );
    5808           0 :     if( allServersSelected )
    5809           0 :         collabclient_closeAllLocalServersForce();
    5810             : }
    5811             : 
    5812           0 : static void FVMenuCollabCloseLocalServer(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e))
    5813             : {
    5814           0 :     AskAndMaybeCloseLocalCollabServers();
    5815           0 : }
    5816             : 
    5817             : 
    5818             : #if defined(__MINGW32__)
    5819             : //
    5820             : // This is an imperfect implemenation of kill() for windows.
    5821             : //
    5822             : static int kill( int pid, int sig )
    5823             : {
    5824             :     HANDLE hHandle;
    5825             :     hHandle = OpenProcess( PROCESS_ALL_ACCESS, 0, pid );
    5826             :     TerminateProcess( hHandle, 0 );
    5827             : }
    5828             : #endif
    5829             : 
    5830             : 
    5831             : 
    5832           0 : static void collablistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e))
    5833             : {
    5834           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    5835             : 
    5836           0 :     for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi )
    5837             :     {
    5838           0 :         switch ( mi->mid )
    5839             :         {
    5840             :         case MID_CollabDisconnect:
    5841             :         {
    5842           0 :             enum collabState_t st = collabclient_getState( &fv->b );
    5843           0 :             mi->ti.disabled = ( st < cs_server );
    5844           0 :             break;
    5845             :         }
    5846             :         case MID_CollabCloseLocalServer:
    5847           0 :             printf("can close local server: %d\n", collabclient_haveLocalServer() );
    5848           0 :             mi->ti.disabled = !collabclient_haveLocalServer();
    5849           0 :             break;
    5850             :         }
    5851             :     }
    5852           0 : }
    5853             : 
    5854             : #ifdef BUILD_COLLAB
    5855             : 
    5856             : static GMenuItem2 collablist[] = {
    5857             :     { { (unichar_t *) N_("_Start Session..."), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'I' }, H_("Start Session...|No Shortcut"), NULL, NULL, FVMenuCollabStart, MID_CollabStart },
    5858             :     { { (unichar_t *) N_("_Connect to Session..."), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'I' }, H_("Connect to Session...|No Shortcut"), NULL, NULL, FVMenuCollabConnect, MID_CollabConnect },
    5859             :     { { (unichar_t *) N_("_Connect to Session (ip:port)..."), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'I' }, H_("Connect to Session (ip:port)...|No Shortcut"), NULL, NULL, FVMenuCollabConnectToExplicitAddress, MID_CollabConnectToExplicitAddress },
    5860             :     { { (unichar_t *) N_("_Disconnect"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'I' }, H_("Disconnect|No Shortcut"), NULL, NULL, FVMenuCollabDisconnect, MID_CollabDisconnect },
    5861             :     GMENUITEM2_LINE,
    5862             :     { { (unichar_t *) N_("Close local server"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'I' }, H_("Close local server|No Shortcut"), NULL, NULL, FVMenuCollabCloseLocalServer, MID_CollabCloseLocalServer },
    5863             : 
    5864             :     GMENUITEM2_EMPTY,                           /* Extra room to show sub-font names */
    5865             : };
    5866             : #endif
    5867             : 
    5868             : GMenuItem2 helplist[] = {
    5869             :     { { (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 },
    5870             :     { { (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 },
    5871             :     { { (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 },
    5872             :     { { (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 },
    5873             :     { { (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 },
    5874             :     GMENUITEM2_EMPTY
    5875             : };
    5876             : 
    5877             : GMenuItem fvpopupmenu[] = {
    5878             :     { { (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 },
    5879             :     GMENUITEM_LINE,
    5880             :     { { (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 },
    5881             :     { { (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 },
    5882             :     { { (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 },
    5883             :     { { (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 },
    5884             :     { { (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 },
    5885             :     { { (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 },
    5886             :     { { (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 },
    5887             :     { { (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 },
    5888             :     { { 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 */
    5889             :     { { (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 },
    5890             :     { { (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 },
    5891             :     { { (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 },
    5892             :     { { (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 },
    5893             :     { { (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 },
    5894             :     { { 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 */
    5895             :     { { (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 },
    5896             :     { { 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 */
    5897             :     { { (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 },
    5898             :     { { (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 },
    5899             :     { { (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 },
    5900             :     GMENUITEM_EMPTY
    5901             : };
    5902             : 
    5903             : static GMenuItem2 mblist[] = {
    5904             :     { { (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 },
    5905             :     { { (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 },
    5906             :     { { (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 },
    5907             : #ifndef _NO_PYTHON
    5908             :     { { (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 },
    5909             : #endif
    5910             : #ifdef NATIVE_CALLBACKS
    5911             :     { { (unichar_t *) N_("Tools_2"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 1, 1, 0, 0, 0, 0, 1, 1, 0, 'l' }, H_("Tools 2|No Shortcut"), NULL, fv_tl2listcheck, NULL, 0 },
    5912             : #endif
    5913             :     { { (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 },
    5914             :     { { (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 },
    5915             :     { { (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 },
    5916             :     { { (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 },
    5917             :     { { (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 },
    5918             : /* GT: Here (and following) MM means "MultiMaster" */
    5919             :     { { (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 },
    5920             :     { { (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 },
    5921             : #ifdef BUILD_COLLAB
    5922             :     { { (unichar_t *) N_("C_ollaborate"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'W' }, H_("Collaborate|No Shortcut"), collablist, collablistcheck, NULL, 0 },
    5923             : #endif
    5924             :     { { (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 },
    5925             :     GMENUITEM2_EMPTY
    5926             : };
    5927             : 
    5928           0 : void FVRefreshChar(FontView *fv,int gid) {
    5929             :     BDFChar *bdfc;
    5930             :     int i, j, enc;
    5931             :     MetricsView *mv;
    5932             : 
    5933             :     /* Can happen in scripts */ /* Can happen if we do an AutoHint when generating a tiny font for freetype context */
    5934           0 :     if ( fv->v==NULL || fv->colcnt==0 || fv->b.sf->glyphs[gid]== NULL )
    5935           0 : return;
    5936           0 :     for ( fv=(FontView *) (fv->b.sf->fv); fv!=NULL; fv = (FontView *) (fv->b.nextsame) ) {
    5937           0 :         if( !fv->colcnt )
    5938           0 :             continue;
    5939             : 
    5940           0 :         for ( mv=fv->b.sf->metrics; mv!=NULL; mv=mv->next )
    5941           0 :             MVRefreshChar(mv,fv->b.sf->glyphs[gid]);
    5942           0 :         if ( fv->show==fv->filled )
    5943           0 :             bdfc = BDFPieceMealCheck(fv->show,gid);
    5944             :         else
    5945           0 :             bdfc = fv->show->glyphs[gid];
    5946           0 :         if ( bdfc==NULL )
    5947           0 :             bdfc = BDFPieceMeal(fv->show,gid);
    5948             :         /* A glyph may be encoded in several places, all need updating */
    5949           0 :         for ( enc = 0; enc<fv->b.map->enccount; ++enc ) if ( fv->b.map->map[enc]==gid ) {
    5950           0 :             i = enc / fv->colcnt;
    5951           0 :             j = enc - i*fv->colcnt;
    5952           0 :             i -= fv->rowoff;
    5953           0 :             if ( i>=0 && i<fv->rowcnt )
    5954           0 :                 FVDrawGlyph(fv->v,fv,enc,true);
    5955             :         }
    5956             :     }
    5957             : }
    5958             : 
    5959        6159 : void FVRegenChar(FontView *fv,SplineChar *sc) {
    5960             :     struct splinecharlist *dlist;
    5961             :     MetricsView *mv;
    5962             : 
    5963        6159 :     if ( fv->v==NULL )                       /* Can happen in scripts */
    5964       12318 : return;
    5965             : 
    5966           0 :     if ( sc->orig_pos<fv->filled->glyphcnt ) {
    5967           0 :         BDFCharFree(fv->filled->glyphs[sc->orig_pos]);
    5968           0 :         fv->filled->glyphs[sc->orig_pos] = NULL;
    5969             :     }
    5970             :     /* FVRefreshChar does NOT do this for us */
    5971           0 :     for ( mv=fv->b.sf->metrics; mv!=NULL; mv=mv->next )
    5972           0 :         MVRegenChar(mv,sc);
    5973             : 
    5974           0 :     FVRefreshChar(fv,sc->orig_pos);
    5975             : #if HANYANG
    5976             :     if ( sc->compositionunit && fv->b.sf->rules!=NULL )
    5977             :         Disp_RefreshChar(fv->b.sf,sc);
    5978             : #endif
    5979             : 
    5980           0 :     for ( dlist=sc->dependents; dlist!=NULL; dlist=dlist->next )
    5981           0 :         FVRegenChar(fv,dlist->sc);
    5982             : }
    5983             : 
    5984           0 : static void AddSubPST(SplineChar *sc,struct lookup_subtable *sub,char *variant) {
    5985             :     PST *pst;
    5986             : 
    5987           0 :     pst = chunkalloc(sizeof(PST));
    5988           0 :     pst->type = pst_substitution;
    5989           0 :     pst->subtable = sub;
    5990           0 :     pst->u.alt.components = copy(variant);
    5991           0 :     pst->next = sc->possub;
    5992           0 :     sc->possub = pst;
    5993           0 : }
    5994             : 
    5995           0 : SplineChar *FVMakeChar(FontView *fv,int enc) {
    5996           0 :     SplineFont *sf = fv->b.sf;
    5997           0 :     SplineChar *base_sc = SFMakeChar(sf,fv->b.map,enc), *feat_sc = NULL;
    5998           0 :     int feat_gid = FeatureTrans(fv,enc);
    5999             : 
    6000           0 :     if ( fv->cur_subtable==NULL )
    6001           0 : return( base_sc );
    6002             : 
    6003           0 :     if ( feat_gid==-1 ) {
    6004           0 :         int uni = -1;
    6005           0 :         FeatureScriptLangList *fl = fv->cur_subtable->lookup->features;
    6006             : 
    6007           0 :         if ( base_sc->unicodeenc>=0x600 && base_sc->unicodeenc<=0x6ff &&
    6008           0 :                 fl!=NULL &&
    6009           0 :                 (fl->featuretag == CHR('i','n','i','t') ||
    6010           0 :                  fl->featuretag == CHR('m','e','d','i') ||
    6011           0 :                  fl->featuretag == CHR('f','i','n','a') ||
    6012           0 :                  fl->featuretag == CHR('i','s','o','l')) ) {
    6013           0 :             uni = fl->featuretag == CHR('i','n','i','t') ? ArabicForms[base_sc->unicodeenc-0x600].initial  :
    6014           0 :                   fl->featuretag == CHR('m','e','d','i') ? ArabicForms[base_sc->unicodeenc-0x600].medial   :
    6015           0 :                   fl->featuretag == CHR('f','i','n','a') ? ArabicForms[base_sc->unicodeenc-0x600].final    :
    6016           0 :                   fl->featuretag == CHR('i','s','o','l') ? ArabicForms[base_sc->unicodeenc-0x600].isolated :
    6017             :                   -1;
    6018           0 :             feat_sc = SFGetChar(sf,uni,NULL);
    6019           0 :             if ( feat_sc!=NULL )
    6020           0 : return( feat_sc );
    6021             :         }
    6022           0 :         feat_sc = SFSplineCharCreate(sf);
    6023           0 :         feat_sc->unicodeenc = uni;
    6024           0 :         if ( uni!=-1 ) {
    6025           0 :             feat_sc->name = malloc(8);
    6026           0 :             feat_sc->unicodeenc = uni;
    6027           0 :             sprintf( feat_sc->name,"uni%04X", uni );
    6028           0 :         } else if ( fv->cur_subtable->suffix!=NULL ) {
    6029           0 :             feat_sc->name = malloc(strlen(base_sc->name)+strlen(fv->cur_subtable->suffix)+2);
    6030           0 :             sprintf( feat_sc->name, "%s.%s", base_sc->name, fv->cur_subtable->suffix );
    6031           0 :         } else if ( fl==NULL ) {
    6032           0 :             feat_sc->name = strconcat(base_sc->name,".unknown");
    6033           0 :         } else if ( fl->ismac ) {
    6034             :             /* mac feature/setting */
    6035           0 :             feat_sc->name = malloc(strlen(base_sc->name)+14);
    6036           0 :             sprintf( feat_sc->name,"%s.m%d_%d", base_sc->name,
    6037           0 :                     (int) (fl->featuretag>>16),
    6038           0 :                     (int) ((fl->featuretag)&0xffff) );
    6039             :         } else {
    6040             :             /* OpenType feature tag */
    6041           0 :             feat_sc->name = malloc(strlen(base_sc->name)+6);
    6042           0 :             sprintf( feat_sc->name,"%s.%c%c%c%c", base_sc->name,
    6043           0 :                     (int) (fl->featuretag>>24),
    6044           0 :                     (int) ((fl->featuretag>>16)&0xff),
    6045           0 :                     (int) ((fl->featuretag>>8)&0xff),
    6046           0 :                     (int) ((fl->featuretag)&0xff) );
    6047             :         }
    6048           0 :         SFAddGlyphAndEncode(sf,feat_sc,fv->b.map,fv->b.map->enccount);
    6049           0 :         AddSubPST(base_sc,fv->cur_subtable,feat_sc->name);
    6050           0 : return( feat_sc );
    6051             :     } else
    6052           0 : return( base_sc );
    6053             : }
    6054             : 
    6055             : /* we style some glyph names differently, see FVExpose() */
    6056             : #define _uni_italic     0x2
    6057             : #define _uni_vertical   (1<<2)
    6058             : #define _uni_fontmax    (2<<2)
    6059             : 
    6060           0 : static GFont *FVCheckFont(FontView *fv,int type) {
    6061             :     FontRequest rq;
    6062             : 
    6063           0 :     if ( fv->fontset[type]==NULL ) {
    6064           0 :         memset(&rq,0,sizeof(rq));
    6065           0 :         rq.utf8_family_name = fv_fontnames;
    6066           0 :         rq.point_size = fv_fontsize;
    6067           0 :         rq.weight = 400;
    6068           0 :         rq.style = 0;
    6069           0 :         if (type&_uni_italic)
    6070           0 :             rq.style |= fs_italic;
    6071           0 :         if (type&_uni_vertical)
    6072           0 :             rq.style |= fs_vertical;
    6073           0 :         fv->fontset[type] = GDrawInstanciateFont(fv->v,&rq);
    6074             :     }
    6075           0 : return( fv->fontset[type] );
    6076             : }
    6077             : 
    6078             : extern unichar_t adobes_pua_alts[0x200][3];
    6079             : 
    6080           0 : static void do_Adobe_Pua(unichar_t *buf,int sob,int uni) {
    6081             :     int i, j;
    6082             : 
    6083           0 :     for ( i=j=0; j<sob-1 && i<3; ++i ) {
    6084           0 :         int ch = adobes_pua_alts[uni-0xf600][i];
    6085           0 :         if ( ch==0 )
    6086           0 :     break;
    6087           0 :         if ( ch>=0xf600 && ch<=0xf7ff && adobes_pua_alts[ch-0xf600]!=0 ) {
    6088           0 :             do_Adobe_Pua(buf+j,sob-j,ch);
    6089           0 :             while ( buf[j]!=0 ) ++j;
    6090             :         } else
    6091           0 :             buf[j++] = ch;
    6092             :     }
    6093           0 :     buf[j] = 0;
    6094           0 : }
    6095             : 
    6096           0 : static void FVExpose(FontView *fv,GWindow pixmap, GEvent *event) {
    6097             :     int i, j, y, width, gid;
    6098             :     int changed;
    6099             :     GRect old, old2, r;
    6100             :     GClut clut;
    6101             :     struct _GImage base;
    6102             :     GImage gi;
    6103             :     SplineChar dummy;
    6104           0 :     int styles, laststyles=0;
    6105             :     Color bg, def_fg;
    6106             :     int fgxor;
    6107             : 
    6108           0 :     def_fg = GDrawGetDefaultForeground(NULL);
    6109           0 :     memset(&gi,'\0',sizeof(gi));
    6110           0 :     memset(&base,'\0',sizeof(base));
    6111           0 :     if ( fv->show->clut!=NULL ) {
    6112           0 :         gi.u.image = &base;
    6113           0 :         base.image_type = it_index;
    6114           0 :         base.clut = fv->show->clut;
    6115           0 :         GDrawSetDither(NULL, false);
    6116           0 :         base.trans = -1;
    6117             :     } else {
    6118           0 :         memset(&clut,'\0',sizeof(clut));
    6119           0 :         gi.u.image = &base;
    6120           0 :         base.image_type = it_mono;
    6121           0 :         base.clut = &clut;
    6122           0 :         clut.clut_len = 2;
    6123           0 :         clut.clut[0] = view_bgcol;
    6124             :     }
    6125             : 
    6126           0 :     GDrawSetFont(pixmap,fv->fontset[0]);
    6127           0 :     GDrawSetLineWidth(pixmap,0);
    6128           0 :     GDrawPushClip(pixmap,&event->u.expose.rect,&old);
    6129           0 :     GDrawFillRect(pixmap,NULL,view_bgcol);
    6130           0 :     for ( i=0; i<=fv->rowcnt; ++i ) {
    6131           0 :         GDrawDrawLine(pixmap,0,i*fv->cbh,fv->width,i*fv->cbh,def_fg);
    6132           0 :         GDrawDrawLine(pixmap,0,i*fv->cbh+fv->lab_height,fv->width,i*fv->cbh+fv->lab_height,0x808080);
    6133             :     }
    6134           0 :     for ( i=0; i<=fv->colcnt; ++i )
    6135           0 :         GDrawDrawLine(pixmap,i*fv->cbw,0,i*fv->cbw,fv->height,def_fg);
    6136           0 :     for ( i=event->u.expose.rect.y/fv->cbh; i<=fv->rowcnt &&
    6137           0 :             (event->u.expose.rect.y+event->u.expose.rect.height+fv->cbh-1)/fv->cbh; ++i ) for ( j=0; j<fv->colcnt; ++j ) {
    6138           0 :         int index = (i+fv->rowoff)*fv->colcnt+j;
    6139             :         SplineChar *sc;
    6140           0 :         styles = 0;
    6141           0 :         if ( index < fv->b.map->enccount && index!=-1 ) {
    6142             :             unichar_t buf[60]; char cbuf[8];
    6143             :             char utf8_buf[8];
    6144           0 :             int use_utf8 = false;
    6145             :             Color fg;
    6146             :             extern const int amspua[];
    6147             :             int uni;
    6148           0 :             struct cidmap *cidmap = NULL;
    6149           0 :             sc = (gid=fv->b.map->map[index])!=-1 ? fv->b.sf->glyphs[gid]: NULL;
    6150             : 
    6151           0 :             if ( fv->b.cidmaster!=NULL )
    6152           0 :                 cidmap = FindCidMap(fv->b.cidmaster->cidregistry,fv->b.cidmaster->ordering,fv->b.cidmaster->supplement,fv->b.cidmaster);
    6153             : 
    6154           0 :             if ( ( fv->b.map->enc==&custom && index<256 ) ||
    6155           0 :                  ( fv->b.map->enc!=&custom && index<fv->b.map->enc->char_cnt ) ||
    6156           0 :                  ( cidmap!=NULL && index<MaxCID(cidmap) ))
    6157           0 :                 fg = def_fg;
    6158             :             else
    6159           0 :                 fg = 0x505050;
    6160           0 :             if ( sc==NULL )
    6161           0 :                 sc = SCBuildDummy(&dummy,fv->b.sf,fv->b.map,index);
    6162           0 :             uni = sc->unicodeenc;
    6163           0 :             buf[0] = buf[1] = 0;
    6164           0 :             if ( fv->b.sf->uni_interp==ui_ams && uni>=0xe000 && uni<=0xf8ff &&
    6165           0 :                     amspua[uni-0xe000]!=0 )
    6166           0 :                 uni = amspua[uni-0xe000];
    6167           0 :             switch ( fv->glyphlabel ) {
    6168             :               case gl_name:
    6169           0 :                 uc_strncpy(buf,sc->name,sizeof(buf)/sizeof(buf[0]));
    6170           0 :               break;
    6171             :               case gl_unicode:
    6172           0 :                 if ( sc->unicodeenc!=-1 ) {
    6173           0 :                     sprintf(cbuf,"%04x",sc->unicodeenc);
    6174           0 :                     uc_strcpy(buf,cbuf);
    6175             :                 } else
    6176           0 :                     uc_strcpy(buf,"?");
    6177           0 :               break;
    6178             :               case gl_encoding:
    6179           0 :                 if ( fv->b.map->enc->only_1byte ||
    6180           0 :                         (fv->b.map->enc->has_1byte && index<256))
    6181           0 :                     sprintf(cbuf,"%02x",index);
    6182             :                 else
    6183           0 :                     sprintf(cbuf,"%04x",index);
    6184           0 :                 uc_strcpy(buf,cbuf);
    6185           0 :               break;
    6186             :               case gl_glyph:
    6187           0 :                 if ( uni==0xad )
    6188           0 :                     buf[0] = '-';
    6189           0 :                 else if ( fv->b.sf->uni_interp==ui_adobe && uni>=0xf600 && uni<=0xf7ff &&
    6190             :                         adobes_pua_alts[uni-0xf600]!=0 ) {
    6191           0 :                     use_utf8 = false;
    6192           0 :                     do_Adobe_Pua(buf,sizeof(buf),uni);
    6193           0 :                 } else if ( uni>=0xe0020 && uni<=0xe007e ) {
    6194           0 :                     buf[0] = uni-0xe0000;       /* A map of Ascii for language names */
    6195             : #if HANYANG
    6196             :                 } else if ( sc->compositionunit ) {
    6197             :                     if ( sc->jamo<19 )
    6198             :                         buf[0] = 0x1100+sc->jamo;
    6199             :                     else if ( sc->jamo<19+21 )
    6200             :                         buf[0] = 0x1161 + sc->jamo-19;
    6201             :                     else        /* Leave a hole for the blank char */
    6202             :                         buf[0] = 0x11a8 + sc->jamo-(19+21+1);
    6203             : #endif
    6204           0 :                 } else if ( uni>0 && uni<unicode4_size ) {
    6205           0 :                     char *pt = utf8_buf;
    6206           0 :                     use_utf8 = true;
    6207           0 :                         *pt = '\0'; // We terminate the string in case the appendage (?) fails.
    6208           0 :                     pt = utf8_idpb(pt,uni,0);
    6209           0 :                     if (pt) *pt = '\0'; else fprintf(stderr, "Invalid Unicode alert.\n");
    6210             :                 } else {
    6211           0 :                     char *pt = strchr(sc->name,'.');
    6212           0 :                     buf[0] = '?';
    6213           0 :                     fg = 0xff0000;
    6214           0 :                     if ( pt!=NULL ) {
    6215           0 :                         int i, n = pt-sc->name;
    6216             :                         char *end;
    6217           0 :                         SplineFont *cm = fv->b.sf->cidmaster;
    6218           0 :                         if ( n==7 && sc->name[0]=='u' && sc->name[1]=='n' && sc->name[2]=='i' &&
    6219           0 :                                 (i=strtol(sc->name+3,&end,16), end-sc->name==7))
    6220           0 :                             buf[0] = i;
    6221           0 :                         else if ( n>=5 && n<=7 && sc->name[0]=='u' &&
    6222           0 :                                 (i=strtol(sc->name+1,&end,16), end-sc->name==n))
    6223           0 :                             buf[0] = i;
    6224           0 :                         else if ( cm!=NULL && (i=CIDFromName(sc->name,cm))!=-1 ) {
    6225             :                             int uni;
    6226           0 :                             uni = CID2Uni(FindCidMap(cm->cidregistry,cm->ordering,cm->supplement,cm),
    6227             :                                     i);
    6228           0 :                             if ( uni!=-1 )
    6229           0 :                                 buf[0] = uni;
    6230             :                         } else {
    6231             :                             int uni;
    6232           0 :                             *pt = '\0';
    6233           0 :                             uni = UniFromName(sc->name,fv->b.sf->uni_interp,fv->b.map->enc);
    6234           0 :                             if ( uni!=-1 )
    6235           0 :                                 buf[0] = uni;
    6236           0 :                             *pt = '.';
    6237             :                         }
    6238           0 :                         if ( strstr(pt,".vert")!=NULL )
    6239           0 :                             styles = _uni_vertical;
    6240           0 :                         if ( buf[0]!='?' ) {
    6241           0 :                             fg = def_fg;
    6242           0 :                             if ( strstr(pt,".italic")!=NULL )
    6243           0 :                                 styles = _uni_italic;
    6244             :                         }
    6245           0 :                     } else if ( strncmp(sc->name,"hwuni",5)==0 ) {
    6246           0 :                         int uni=-1;
    6247           0 :                         sscanf(sc->name,"hwuni%x", (unsigned *) &uni );
    6248           0 :                         if ( uni!=-1 ) buf[0] = uni;
    6249           0 :                     } else if ( strncmp(sc->name,"italicuni",9)==0 ) {
    6250           0 :                         int uni=-1;
    6251           0 :                         sscanf(sc->name,"italicuni%x", (unsigned *) &uni );
    6252           0 :                         if ( uni!=-1 ) { buf[0] = uni; styles=_uni_italic; }
    6253           0 :                         fg = def_fg;
    6254           0 :                     } else if ( strncmp(sc->name,"vertcid_",8)==0 ||
    6255           0 :                             strncmp(sc->name,"vertuni",7)==0 ) {
    6256           0 :                         styles = _uni_vertical;
    6257             :                     }
    6258             :                 }
    6259           0 :               break;
    6260             :             }
    6261           0 :             r.x = j*fv->cbw+1; r.width = fv->cbw-1;
    6262           0 :             r.y = i*fv->cbh+1; r.height = fv->lab_height-1;
    6263           0 :             bg = view_bgcol;
    6264           0 :             fgxor = 0x000000;
    6265           0 :             changed = sc->changed;
    6266           0 :             if ( fv->b.sf->onlybitmaps && gid<fv->show->glyphcnt )
    6267           0 :                 changed = gid==-1 || fv->show->glyphs[gid]==NULL? false : fv->show->glyphs[gid]->changed;
    6268           0 :             if ( changed ||
    6269           0 :                     sc->layers[ly_back].splines!=NULL || sc->layers[ly_back].images!=NULL ||
    6270           0 :                     sc->color!=COLOR_DEFAULT ) {
    6271           0 :                 if ( sc->layers[ly_back].splines!=NULL || sc->layers[ly_back].images!=NULL ||
    6272           0 :                         sc->color!=COLOR_DEFAULT )
    6273           0 :                     bg = sc->color!=COLOR_DEFAULT?sc->color:0x808080;
    6274           0 :                 if ( sc->changed ) {
    6275           0 :                     fgxor = bg ^ fvchangedcol;
    6276           0 :                     bg = fvchangedcol;
    6277             :                 }
    6278           0 :                 GDrawFillRect(pixmap,&r,bg);
    6279             :             }
    6280           0 :             if ( (!fv->b.sf->layers[fv->b.active_layer].order2 && sc->changedsincelasthinted ) ||
    6281           0 :                      ( fv->b.sf->layers[fv->b.active_layer].order2 && sc->layers[fv->b.active_layer].splines!=NULL &&
    6282           0 :                         sc->ttf_instrs_len<=0 ) ||
    6283           0 :                      ( fv->b.sf->layers[fv->b.active_layer].order2 && sc->instructions_out_of_date ) ) {
    6284           0 :                 Color hintcol = fvhintingneededcol;
    6285           0 :                 if ( fv->b.sf->layers[fv->b.active_layer].order2 && sc->instructions_out_of_date && sc->ttf_instrs_len>0 )
    6286           0 :                     hintcol = 0xff0000;
    6287           0 :                 GDrawDrawLine(pixmap,r.x,r.y,r.x,r.y+r.height-1,hintcol);
    6288           0 :                 GDrawDrawLine(pixmap,r.x+1,r.y,r.x+1,r.y+r.height-1,hintcol);
    6289           0 :                 GDrawDrawLine(pixmap,r.x+2,r.y,r.x+2,r.y+r.height-1,hintcol);
    6290           0 :                 GDrawDrawLine(pixmap,r.x+r.width-1,r.y,r.x+r.width-1,r.y+r.height-1,hintcol);
    6291           0 :                 GDrawDrawLine(pixmap,r.x+r.width-2,r.y,r.x+r.width-2,r.y+r.height-1,hintcol);
    6292           0 :                 GDrawDrawLine(pixmap,r.x+r.width-3,r.y,r.x+r.width-3,r.y+r.height-1,hintcol);
    6293             :             }
    6294           0 :             if ( use_utf8 && sc->unicodeenc!=-1 &&
    6295             :                 /* Pango complains if we try to draw non characters */
    6296             :                 /* These two are guaranteed "NOT A UNICODE CHARACTER" in all planes */
    6297           0 :                     ((sc->unicodeenc&0xffff)==0xfffe || (sc->unicodeenc&0xffff)==0xffff ||
    6298           0 :                      (sc->unicodeenc>=0xfdd0 && sc->unicodeenc<=0xfdef) ||  /* noncharacters */
    6299           0 :                      (sc->unicodeenc>=0xfe00 && sc->unicodeenc<=0xfe0f) ||  /* variation selectors */
    6300           0 :                      (sc->unicodeenc>=0xe0110 && sc->unicodeenc<=0xe01ff) ||        /* variation selectors */
    6301             :                 /*  The surrogates in BMP aren't valid either */
    6302           0 :                      (sc->unicodeenc>=0xd800 && sc->unicodeenc<=0xdfff))) { /* surrogates */
    6303           0 :                 GDrawDrawLine(pixmap,r.x,r.y,r.x+r.width-1,r.y+r.height-1,0x000000);
    6304           0 :                 GDrawDrawLine(pixmap,r.x,r.y+r.height-1,r.x+r.width-1,r.y,0x000000);
    6305           0 :             } else if ( use_utf8 ) {
    6306             :                 GTextBounds size;
    6307           0 :                 if ( styles!=laststyles ) GDrawSetFont(pixmap,FVCheckFont(fv,styles));
    6308           0 :                 width = GDrawGetText8Bounds(pixmap,utf8_buf,-1,&size);
    6309           0 :                 if ( size.lbearing==0 && size.rbearing==0 ) {
    6310           0 :                     utf8_buf[0] = 0xe0 | (0xfffd>>12);
    6311           0 :                     utf8_buf[1] = 0x80 | ((0xfffd>>6)&0x3f);
    6312           0 :                     utf8_buf[2] = 0x80 | (0xfffd&0x3f);
    6313           0 :                     utf8_buf[3] = 0;
    6314           0 :                     width = GDrawGetText8Bounds(pixmap,utf8_buf,-1,&size);
    6315             :                 }
    6316           0 :                 width = size.rbearing - size.lbearing+1;
    6317           0 :                 if ( width >= fv->cbw-1 ) {
    6318           0 :                     GDrawPushClip(pixmap,&r,&old2);
    6319           0 :                     width = fv->cbw-1;
    6320             :                 }
    6321           0 :                 if ( sc->unicodeenc<0x80 || sc->unicodeenc>=0xa0 ) {
    6322           0 :                     y = i*fv->cbh+fv->lab_as+1;
    6323             :                     /* move rotated glyph up a bit to center it */
    6324           0 :                     if (styles&_uni_vertical)
    6325           0 :                         y -= fv->lab_as/2;
    6326           0 :                     GDrawDrawText8(pixmap,j*fv->cbw+(fv->cbw-1-width)/2-size.lbearing,y,utf8_buf,-1,fg^fgxor);
    6327             :                 }
    6328           0 :                 if ( width >= fv->cbw-1 )
    6329           0 :                     GDrawPopClip(pixmap,&old2);
    6330           0 :                 laststyles = styles;
    6331             :             } else {
    6332           0 :                 if ( styles!=laststyles ) GDrawSetFont(pixmap,FVCheckFont(fv,styles));
    6333           0 :                 width = GDrawGetTextWidth(pixmap,buf,-1);
    6334           0 :                 if ( width >= fv->cbw-1 ) {
    6335           0 :                     GDrawPushClip(pixmap,&r,&old2);
    6336           0 :                     width = fv->cbw-1;
    6337             :                 }
    6338           0 :                 if ( sc->unicodeenc<0x80 || sc->unicodeenc>=0xa0 ) {
    6339           0 :                     y = i*fv->cbh+fv->lab_as+1;
    6340             :                     /* move rotated glyph up a bit to center it */
    6341           0 :                     if (styles&_uni_vertical)
    6342           0 :                         y -= fv->lab_as/2;
    6343           0 :                     GDrawDrawText(pixmap,j*fv->cbw+(fv->cbw-1-width)/2,y,buf,-1,fg^fgxor);
    6344             :                 }
    6345           0 :                 if ( width >= fv->cbw-1 )
    6346           0 :                     GDrawPopClip(pixmap,&old2);
    6347           0 :                 laststyles = styles;
    6348             :             }
    6349             :         }
    6350           0 :         FVDrawGlyph(pixmap,fv,index,false);
    6351             :     }
    6352           0 :     if ( fv->showhmetrics&fvm_baseline ) {
    6353           0 :         for ( i=0; i<=fv->rowcnt; ++i )
    6354           0 :             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);
    6355             :     }
    6356           0 :     GDrawPopClip(pixmap,&old);
    6357           0 :     GDrawSetDither(NULL, true);
    6358           0 : }
    6359             : 
    6360           0 : void FVDrawInfo(FontView *fv,GWindow pixmap, GEvent *event) {
    6361             :     GRect old, r;
    6362           0 :     Color bg = GDrawGetDefaultBackground(GDrawGetDisplayOfWindow(pixmap));
    6363           0 :     Color fg = fvglyphinfocol;
    6364             :     SplineChar *sc, dummy;
    6365           0 :     SplineFont *sf = fv->b.sf;
    6366           0 :     EncMap *map = fv->b.map;
    6367             :     int gid, uni, localenc;
    6368           0 :     GString *output = g_string_new( "" );
    6369           0 :     gchar *uniname = NULL;
    6370             : 
    6371           0 :     if ( event->u.expose.rect.y+event->u.expose.rect.height<=fv->mbh ) {
    6372           0 :         g_string_free( output, TRUE ); output = NULL;
    6373           0 :         return;
    6374             :     }
    6375             : 
    6376           0 :     GDrawSetFont(pixmap,fv->fontset[0]);
    6377           0 :     GDrawPushClip(pixmap,&event->u.expose.rect,&old);
    6378             : 
    6379           0 :     r.x = 0; r.width = fv->width; r.y = fv->mbh; r.height = fv->infoh;
    6380           0 :     GDrawFillRect(pixmap,&r,bg);
    6381           0 :     if ( fv->end_pos>=map->enccount || fv->pressed_pos>=map->enccount ||
    6382           0 :             fv->end_pos<0 || fv->pressed_pos<0 )
    6383           0 :         fv->end_pos = fv->pressed_pos = -1;       /* Can happen after reencoding */
    6384           0 :     if ( fv->end_pos == -1 ) {
    6385           0 :         g_string_free( output, TRUE ); output = NULL;
    6386           0 :         GDrawPopClip(pixmap,&old);
    6387           0 :         return;
    6388             :     }
    6389             : 
    6390           0 :     localenc = fv->end_pos;
    6391           0 :     if ( map->remap!=NULL ) {
    6392           0 :         struct remap *remap = map->remap;
    6393           0 :         while ( remap->infont!=-1 ) {
    6394           0 :             if ( localenc>=remap->infont && localenc<=remap->infont+(remap->lastenc-remap->firstenc) ) {
    6395           0 :                 localenc += remap->firstenc-remap->infont;
    6396           0 :                 break;
    6397             :             }
    6398           0 :             ++remap;
    6399             :         }
    6400             :     }
    6401           0 :     g_string_printf( output, "%d (0x%x) ", localenc, localenc );
    6402             : 
    6403           0 :     sc = (gid=fv->b.map->map[fv->end_pos])!=-1 ? sf->glyphs[gid] : NULL;
    6404           0 :     if ( fv->b.cidmaster==NULL || fv->b.normal==NULL || sc==NULL )
    6405           0 :         SCBuildDummy(&dummy,sf,fv->b.map,fv->end_pos);
    6406             :     else
    6407           0 :         dummy = *sc;
    6408           0 :     if ( sc==NULL ) sc = &dummy;
    6409           0 :     uni = dummy.unicodeenc!=-1 ? dummy.unicodeenc : sc->unicodeenc;
    6410             : 
    6411             :     /* last resort at guessing unicode code point from partial name */
    6412           0 :     if ( uni == -1 ) {
    6413           0 :         char *pt = strchr( sc->name, '.' );
    6414           0 :         if( pt != NULL ) {
    6415           0 :             gchar *buf = g_strndup( (const gchar *) sc->name, pt - sc->name );
    6416           0 :             uni = UniFromName( (char *) buf, fv->b.sf->uni_interp, map->enc );
    6417           0 :             g_free( buf );
    6418             :         }
    6419             :     }
    6420             : 
    6421           0 :     if ( uni != -1 )
    6422           0 :         g_string_append_printf( output, "U+%04X", uni );
    6423             :     else {
    6424           0 :         output = g_string_append( output, "U+????" );
    6425             :     }
    6426             : 
    6427             :     /* postscript name */
    6428           0 :     g_string_append_printf( output, " \"%s\" ", sc->name );
    6429             : 
    6430             :     /* code point name or range name */
    6431           0 :     if( uni != -1 ) {
    6432           0 :         uniname = (gchar *) unicode_name( uni );
    6433           0 :         if ( uniname == NULL ) {
    6434           0 :             uniname = g_strdup( UnicodeRange( uni ) );
    6435             :         }
    6436             :     }
    6437             : 
    6438           0 :     if ( uniname != NULL ) {
    6439           0 :         output = g_string_append( output, uniname );
    6440           0 :         g_free( uniname );
    6441             :     }
    6442             : 
    6443           0 :     GDrawDrawText8( pixmap, 10, fv->mbh+fv->lab_as, output->str, -1, fg );
    6444           0 :     g_string_free( output, TRUE ); output = NULL;
    6445           0 :     GDrawPopClip( pixmap, &old );
    6446           0 :     return;
    6447             : }
    6448             : 
    6449           0 : static void FVShowInfo(FontView *fv) {
    6450             :     GRect r;
    6451             : 
    6452           0 :     if ( fv->v==NULL )                       /* Can happen in scripts */
    6453           0 : return;
    6454             : 
    6455           0 :     r.x = 0; r.width = fv->width; r.y = fv->mbh; r.height = fv->infoh;
    6456           0 :     GDrawRequestExpose(fv->gw,&r,false);
    6457             : }
    6458             : 
    6459           0 : void FVChar(FontView *fv, GEvent *event) {
    6460             :     int i,pos, cnt, gid;
    6461             :     extern int navigation_mask;
    6462             : 
    6463             : #if MyMemory
    6464             :     if ( event->u.chr.keysym == GK_F2 ) {
    6465             :         fprintf( stderr, "Malloc debug on\n" );
    6466             :         __malloc_debug(5);
    6467             :     } else if ( event->u.chr.keysym == GK_F3 ) {
    6468             :         fprintf( stderr, "Malloc debug off\n" );
    6469             :         __malloc_debug(0);
    6470             :     }
    6471             : #endif
    6472             : 
    6473           0 :     if ( event->u.chr.keysym=='s' &&
    6474           0 :             (event->u.chr.state&ksm_control) &&
    6475           0 :             (event->u.chr.state&ksm_meta) )
    6476           0 :         MenuSaveAll(NULL,NULL,NULL);
    6477           0 :     else if ( event->u.chr.keysym=='q' &&
    6478           0 :             (event->u.chr.state&ksm_control) &&
    6479           0 :             (event->u.chr.state&ksm_meta) )
    6480           0 :         MenuExit(NULL,NULL,NULL);
    6481           0 :     else if ( event->u.chr.keysym=='I' &&
    6482           0 :             (event->u.chr.state&ksm_shift) &&
    6483           0 :             (event->u.chr.state&ksm_meta) )
    6484           0 :         FVMenuCharInfo(fv->gw,NULL,NULL);
    6485           0 :     else if ( (event->u.chr.keysym=='[' || event->u.chr.keysym==']') &&
    6486           0 :             (event->u.chr.state&ksm_control) ) {
    6487           0 :         _FVMenuChangeChar(fv,event->u.chr.keysym=='['?MID_Prev:MID_Next);
    6488           0 :     } else if ( (event->u.chr.keysym=='{' || event->u.chr.keysym=='}') &&
    6489           0 :             (event->u.chr.state&ksm_control) ) {
    6490           0 :         _FVMenuChangeChar(fv,event->u.chr.keysym=='{'?MID_PrevDef:MID_NextDef);
    6491           0 :     } else if ( event->u.chr.keysym=='\\' && (event->u.chr.state&ksm_control) ) {
    6492             :         /* European keyboards need a funky modifier to get \ */
    6493           0 :         FVDoTransform(fv);
    6494             : #if !defined(_NO_FFSCRIPT) || !defined(_NO_PYTHON)
    6495           0 :     } else if ( isdigit(event->u.chr.keysym) && (event->u.chr.state&ksm_control) &&
    6496           0 :             (event->u.chr.state&ksm_meta) ) {
    6497             :         /* The Script menu isn't always up to date, so we might get one of */
    6498             :         /*  the shortcuts here */
    6499           0 :         int index = event->u.chr.keysym-'1';
    6500           0 :         if ( index<0 ) index = 9;
    6501           0 :         if ( script_filenames[index]!=NULL )
    6502           0 :             ExecuteScriptFile((FontViewBase *) fv,NULL,script_filenames[index]);
    6503             : #endif
    6504           0 :     } else if ( event->u.chr.keysym == GK_Left ||
    6505           0 :             event->u.chr.keysym == GK_Tab ||
    6506           0 :             event->u.chr.keysym == GK_BackTab ||
    6507           0 :             event->u.chr.keysym == GK_Up ||
    6508           0 :             event->u.chr.keysym == GK_Right ||
    6509           0 :             event->u.chr.keysym == GK_Down ||
    6510           0 :             event->u.chr.keysym == GK_KP_Left ||
    6511           0 :             event->u.chr.keysym == GK_KP_Up ||
    6512           0 :             event->u.chr.keysym == GK_KP_Right ||
    6513           0 :             event->u.chr.keysym == GK_KP_Down ||
    6514           0 :             event->u.chr.keysym == GK_Home ||
    6515           0 :             event->u.chr.keysym == GK_KP_Home ||
    6516           0 :             event->u.chr.keysym == GK_End ||
    6517           0 :             event->u.chr.keysym == GK_KP_End ||
    6518           0 :             event->u.chr.keysym == GK_Page_Up ||
    6519           0 :             event->u.chr.keysym == GK_KP_Page_Up ||
    6520           0 :             event->u.chr.keysym == GK_Prior ||
    6521           0 :             event->u.chr.keysym == GK_Page_Down ||
    6522           0 :             event->u.chr.keysym == GK_KP_Page_Down ||
    6523           0 :             event->u.chr.keysym == GK_Next ) {
    6524           0 :         int end_pos = fv->end_pos;
    6525             :         /* We move the currently selected char. If there is none, then pick */
    6526             :         /*  something on the screen */
    6527           0 :         if ( end_pos==-1 )
    6528           0 :             end_pos = (fv->rowoff+fv->rowcnt/2)*fv->colcnt;
    6529           0 :         switch ( event->u.chr.keysym ) {
    6530             :           case GK_Tab:
    6531           0 :             pos = end_pos;
    6532             :             do {
    6533           0 :                 if ( event->u.chr.state&ksm_shift )
    6534           0 :                     --pos;
    6535             :                 else
    6536           0 :                     ++pos;
    6537           0 :                 if ( pos>=fv->b.map->enccount ) pos = 0;
    6538           0 :                 else if ( pos<0 ) pos = fv->b.map->enccount-1;
    6539           0 :             } while ( pos!=end_pos &&
    6540           0 :                     ((gid=fv->b.map->map[pos])==-1 || !SCWorthOutputting(fv->b.sf->glyphs[gid])));
    6541           0 :             if ( pos==end_pos ) ++pos;
    6542           0 :             if ( pos>=fv->b.map->enccount ) pos = 0;
    6543           0 :           break;
    6544             : #if GK_Tab!=GK_BackTab
    6545             :           case GK_BackTab:
    6546           0 :             pos = end_pos;
    6547             :             do {
    6548           0 :                 --pos;
    6549           0 :                 if ( pos<0 ) pos = fv->b.map->enccount-1;
    6550           0 :             } while ( pos!=end_pos &&
    6551           0 :                     ((gid=fv->b.map->map[pos])==-1 || !SCWorthOutputting(fv->b.sf->glyphs[gid])));
    6552           0 :             if ( pos==end_pos ) --pos;
    6553           0 :             if ( pos<0 ) pos = 0;
    6554           0 :           break;
    6555             : #endif
    6556             :           case GK_Left: case GK_KP_Left:
    6557           0 :             pos = end_pos-1;
    6558           0 :           break;
    6559             :           case GK_Right: case GK_KP_Right:
    6560           0 :             pos = end_pos+1;
    6561           0 :           break;
    6562             :           case GK_Up: case GK_KP_Up:
    6563           0 :             pos = end_pos-fv->colcnt;
    6564           0 :           break;
    6565             :           case GK_Down: case GK_KP_Down:
    6566           0 :             pos = end_pos+fv->colcnt;
    6567           0 :           break;
    6568             :           case GK_End: case GK_KP_End:
    6569           0 :             pos = fv->b.map->enccount;
    6570           0 :           break;
    6571             :           case GK_Home: case GK_KP_Home:
    6572           0 :             pos = 0;
    6573           0 :             if ( fv->b.sf->top_enc!=-1 && fv->b.sf->top_enc<fv->b.map->enccount )
    6574           0 :                 pos = fv->b.sf->top_enc;
    6575             :             else {
    6576           0 :                 pos = SFFindSlot(fv->b.sf,fv->b.map,home_char,NULL);
    6577           0 :                 if ( pos==-1 ) pos = 0;
    6578             :             }
    6579           0 :           break;
    6580             :           case GK_Page_Up: case GK_KP_Page_Up:
    6581             : #if GK_Prior!=GK_Page_Up
    6582             :           case GK_Prior:
    6583             : #endif
    6584           0 :             pos = (fv->rowoff-fv->rowcnt+1)*fv->colcnt;
    6585           0 :           break;
    6586             :           case GK_Page_Down: case GK_KP_Page_Down:
    6587             : #if GK_Next!=GK_Page_Down
    6588             :           case GK_Next:
    6589             : #endif
    6590           0 :             pos = (fv->rowoff+fv->rowcnt+1)*fv->colcnt;
    6591           0 :           break;
    6592             :         }
    6593           0 :         if ( pos<0 ) pos = 0;
    6594           0 :         if ( pos>=fv->b.map->enccount ) pos = fv->b.map->enccount-1;
    6595           0 :         if ( event->u.chr.state&ksm_shift && event->u.chr.keysym!=GK_Tab && event->u.chr.keysym!=GK_BackTab ) {
    6596           0 :             FVReselect(fv,pos);
    6597             :         } else {
    6598           0 :             FVDeselectAll(fv);
    6599           0 :             fv->b.selected[pos] = true;
    6600           0 :             FVToggleCharSelected(fv,pos);
    6601           0 :             fv->pressed_pos = pos;
    6602           0 :             fv->sel_index = 1;
    6603             :         }
    6604           0 :         fv->end_pos = pos;
    6605           0 :         FVShowInfo(fv);
    6606           0 :         FVScrollToChar(fv,pos);
    6607           0 :     } else if ( event->u.chr.keysym == GK_Help ) {
    6608           0 :         MenuHelp(NULL,NULL,NULL);       /* Menu does F1 */
    6609           0 :     } else if ( event->u.chr.keysym == GK_Escape ) {
    6610           0 :         FVDeselectAll(fv);
    6611           0 :     } else if ( event->u.chr.chars[0]=='\r' || event->u.chr.chars[0]=='\n' ) {
    6612           0 :         if ( fv->b.container!=NULL && fv->b.container->funcs->is_modal )
    6613           0 : return;
    6614           0 :         for ( i=cnt=0; i<fv->b.map->enccount && cnt<10; ++i ) if ( fv->b.selected[i] ) {
    6615           0 :             SplineChar *sc = SFMakeChar(fv->b.sf,fv->b.map,i);
    6616           0 :             if ( fv->show==fv->filled ) {
    6617           0 :                 CharViewCreate(sc,fv,i);
    6618             :             } else {
    6619           0 :                 BDFFont *bdf = fv->show;
    6620           0 :                 BitmapViewCreate(BDFMakeGID(bdf,sc->orig_pos),bdf,fv,i);
    6621             :             }
    6622           0 :             ++cnt;
    6623             :         }
    6624           0 :     } else if ( (event->u.chr.state&((GMenuMask()|navigation_mask)&~(ksm_shift|ksm_capslock)))==navigation_mask &&
    6625           0 :             event->type == et_char &&
    6626           0 :             event->u.chr.keysym!=0 &&
    6627           0 :             (event->u.chr.keysym<GK_Special/* || event->u.chr.keysym>=0x10000*/)) {
    6628           0 :         SplineFont *sf = fv->b.sf;
    6629           0 :         int enc = EncFromUni(event->u.chr.keysym,fv->b.map->enc);
    6630           0 :         if ( enc==-1 ) {
    6631           0 :             for ( i=0; i<sf->glyphcnt; ++i ) {
    6632           0 :                 if ( sf->glyphs[i]!=NULL )
    6633           0 :                     if ( sf->glyphs[i]->unicodeenc==event->u.chr.keysym )
    6634           0 :             break;
    6635             :             }
    6636           0 :             if ( i!=-1 )
    6637           0 :                 enc = fv->b.map->backmap[i];
    6638             :         }
    6639           0 :         if ( enc<fv->b.map->enccount && enc!=-1 )
    6640           0 :             FVChangeChar(fv,enc);
    6641             :     }
    6642             : }
    6643             : 
    6644           0 : static void utf82u_annot_strncat(unichar_t *to, const char *from, int len) {
    6645             :     register unichar_t ch;
    6646             : 
    6647           0 :     to += u_strlen(to);
    6648           0 :     while ( (ch = utf8_ildb(&from)) != '\0' && --len>=0 ) {
    6649           0 :         if ( ch=='\t' ) {
    6650           0 :             *(to++) = ' ';
    6651           0 :             ch = ' ';
    6652             :         }
    6653           0 :         *(to++) = ch;
    6654             :     }
    6655           0 :     *to = 0;
    6656           0 : }
    6657             : 
    6658           0 : void SCPreparePopup(GWindow gw,SplineChar *sc,struct remap *remap, int localenc,
    6659             :         int actualuni) {
    6660             : /* This is for the popup which appears when you hover mouse over a character on main window */
    6661           0 :     int upos=-1;
    6662             :     char *msg, *msg_old;
    6663             : 
    6664             :     /* If a glyph is multiply mapped then the inbuild unicode enc may not be */
    6665             :     /*  the actual one used to access the glyph */
    6666           0 :     if ( remap!=NULL ) {
    6667           0 :         while ( remap->infont!=-1 ) {
    6668           0 :             if ( localenc>=remap->infont && localenc<=remap->infont+(remap->lastenc-remap->firstenc) ) {
    6669           0 :                 localenc += remap->firstenc-remap->infont;
    6670           0 :                 break;
    6671             :             }
    6672           0 :             ++remap;
    6673             :         }
    6674             :     }
    6675             : 
    6676           0 :     if ( actualuni!=-1 )
    6677           0 :         upos = actualuni;
    6678           0 :     else if ( sc->unicodeenc!=-1 )
    6679           0 :         upos = sc->unicodeenc;
    6680             : #if HANYANG
    6681             :     else if ( sc->compositionunit ) {
    6682             :         if ( sc->jamo<19 )
    6683             :             upos = 0x1100+sc->jamo;
    6684             :         else if ( sc->jamo<19+21 )
    6685             :             upos = 0x1161 + sc->jamo-19;
    6686             :         else            /* Leave a hole for the blank char */
    6687             :             upos = 0x11a8 + sc->jamo-(19+21+1);
    6688             :     }
    6689             : #endif
    6690             : 
    6691           0 :     if ( upos == -1 ) {
    6692           0 :         msg = xasprintf( "%u 0x%x U+???? \"%.25s\" ",
    6693             :                 localenc, localenc,
    6694           0 :                 (sc->name == NULL) ? "" : sc->name );
    6695             :     } else {
    6696             :         /* unicode name or range name */
    6697           0 :         char *uniname = unicode_name( upos );
    6698           0 :         if( uniname == NULL ) uniname = strdup( UnicodeRange( upos ) );
    6699           0 :         msg = xasprintf ( "%u 0x%x U+%04X \"%.25s\" %.100s",
    6700             :                 localenc, localenc, upos,
    6701           0 :                 (sc->name == NULL) ? "" : sc->name, uniname );
    6702           0 :         if ( uniname != NULL ) free( uniname ); uniname = NULL;
    6703             : 
    6704             :         /* annotation */
    6705           0 :         char *uniannot = unicode_annot( upos );
    6706           0 :         if( uniannot != NULL ) {
    6707           0 :             msg_old = msg;
    6708           0 :             msg = xasprintf("%s\n%s", msg_old, uniannot);
    6709           0 :             free(msg_old);
    6710           0 :             free( uniannot );
    6711             :         }
    6712             :     }
    6713             : 
    6714             :     /* user comments */
    6715           0 :     if ( sc->comment!=NULL ) {
    6716           0 :         msg_old = msg;
    6717           0 :         msg = xasprintf("%s\n%s", msg_old, sc->comment);
    6718           0 :         free(msg_old);
    6719             :     }
    6720             : 
    6721           0 :     GGadgetPreparePopup8( gw, msg );
    6722           0 :     free(msg);
    6723           0 : }
    6724             : 
    6725           0 : static void noop(void *UNUSED(_fv)) {
    6726           0 : }
    6727             : 
    6728           0 : static void *ddgencharlist(void *_fv,int32 *len) {
    6729             :     int i,j,cnt, gid;
    6730           0 :     FontView *fv = (FontView *) _fv;
    6731           0 :     SplineFont *sf = fv->b.sf;
    6732           0 :     EncMap *map = fv->b.map;
    6733             :     char *data;
    6734             : 
    6735           0 :     for ( i=cnt=0; i<map->enccount; ++i ) if ( fv->b.selected[i] && (gid=map->map[i])!=-1 && sf->glyphs[gid]!=NULL )
    6736           0 :         cnt += strlen(sf->glyphs[gid]->name)+1;
    6737           0 :     data = malloc(cnt+1); data[0] = '\0';
    6738           0 :     for ( cnt=0, j=1 ; j<=fv->sel_index; ++j ) {
    6739           0 :         for ( i=cnt=0; i<map->enccount; ++i )
    6740           0 :             if ( fv->b.selected[i] && (gid=map->map[i])!=-1 && sf->glyphs[gid]!=NULL ) {
    6741           0 :                 strcpy(data+cnt,sf->glyphs[gid]->name);
    6742           0 :                 cnt += strlen(sf->glyphs[gid]->name);
    6743           0 :                 strcpy(data+cnt++," ");
    6744             :             }
    6745             :     }
    6746           0 :     if ( cnt>0 )
    6747           0 :         data[--cnt] = '\0';
    6748           0 :     *len = cnt;
    6749           0 : return( data );
    6750             : }
    6751             : 
    6752           0 : static void FVMouse(FontView *fv, GEvent *event) {
    6753           0 :     int pos = (event->u.mouse.y/fv->cbh + fv->rowoff)*fv->colcnt + event->u.mouse.x/fv->cbw;
    6754             :     int gid;
    6755           0 :     int realpos = pos;
    6756             :     SplineChar *sc, dummy;
    6757           0 :     int dopopup = true;
    6758             : 
    6759           0 :     if ( event->type==et_mousedown )
    6760           0 :         CVPaletteDeactivate();
    6761           0 :     if ( pos<0 ) {
    6762           0 :         pos = 0;
    6763           0 :         dopopup = false;
    6764           0 :     } else if ( pos>=fv->b.map->enccount ) {
    6765           0 :         pos = fv->b.map->enccount-1;
    6766           0 :         if ( pos<0 )         /* No glyph slots in font */
    6767           0 : return;
    6768           0 :         dopopup = false;
    6769             :     }
    6770             : 
    6771           0 :     sc = (gid=fv->b.map->map[pos])!=-1 ? fv->b.sf->glyphs[gid] : NULL;
    6772           0 :     if ( sc==NULL )
    6773           0 :         sc = SCBuildDummy(&dummy,fv->b.sf,fv->b.map,pos);
    6774           0 :     if ( event->type == et_mouseup && event->u.mouse.clicks==2 ) {
    6775           0 :         if ( fv->pressed ) {
    6776           0 :             GDrawCancelTimer(fv->pressed);
    6777           0 :             fv->pressed = NULL;
    6778             :         }
    6779           0 :         if ( fv->b.container!=NULL && fv->b.container->funcs->is_modal )
    6780           0 : return;
    6781           0 :         if ( fv->cur_subtable!=NULL ) {
    6782           0 :             sc = FVMakeChar(fv,pos);
    6783           0 :             pos = fv->b.map->backmap[sc->orig_pos];
    6784             :         }
    6785           0 :         if ( sc==&dummy ) {
    6786           0 :             sc = SFMakeChar(fv->b.sf,fv->b.map,pos);
    6787           0 :             gid = fv->b.map->map[pos];
    6788             :         }
    6789           0 :         if ( fv->show==fv->filled ) {
    6790           0 :             SplineFont *sf = fv->b.sf;
    6791           0 :             gid = -1;
    6792           0 :             if ( !OpenCharsInNewWindow )
    6793           0 :                 for ( gid=sf->glyphcnt-1; gid>=0; --gid )
    6794           0 :                     if ( sf->glyphs[gid]!=NULL && sf->glyphs[gid]->views!=NULL )
    6795           0 :                 break;
    6796           0 :             if ( gid!=-1 ) {
    6797           0 :                 CharView *cv = (CharView *) (sf->glyphs[gid]->views);
    6798           0 :                 printf("calling CVChangeSC() sc:%p %s\n", sc, sc->name );
    6799           0 :                 CVChangeSC(cv,sc);
    6800           0 :                 GDrawSetVisible(cv->gw,true);
    6801           0 :                 GDrawRaise(cv->gw);
    6802             :             } else
    6803           0 :                 CharViewCreate(sc,fv,pos);
    6804             :         } else {
    6805           0 :             BDFFont *bdf = fv->show;
    6806           0 :             BDFChar *bc =BDFMakeGID(bdf,gid);
    6807           0 :             gid = -1;
    6808           0 :             if ( !OpenCharsInNewWindow )
    6809           0 :                 for ( gid=bdf->glyphcnt-1; gid>=0; --gid )
    6810           0 :                     if ( bdf->glyphs[gid]!=NULL && bdf->glyphs[gid]->views!=NULL )
    6811           0 :                 break;
    6812           0 :             if ( gid!=-1 ) {
    6813           0 :                 BitmapView *bv = bdf->glyphs[gid]->views;
    6814           0 :                 BVChangeBC(bv,bc,true);
    6815           0 :                 GDrawSetVisible(bv->gw,true);
    6816           0 :                 GDrawRaise(bv->gw);
    6817             :             } else
    6818           0 :                 BitmapViewCreate(bc,bdf,fv,pos);
    6819             :         }
    6820           0 :     } else if ( event->type == et_mousemove ) {
    6821           0 :         if ( dopopup )
    6822           0 :             SCPreparePopup(fv->v,sc,fv->b.map->remap,pos,sc==&dummy?dummy.unicodeenc: UniFromEnc(pos,fv->b.map->enc));
    6823             :     }
    6824           0 :     if ( event->type == et_mousedown ) {
    6825           0 :         if ( fv->drag_and_drop ) {
    6826           0 :             GDrawSetCursor(fv->v,ct_mypointer);
    6827           0 :             fv->any_dd_events_sent = fv->drag_and_drop = false;
    6828             :         }
    6829           0 :         if ( !(event->u.mouse.state&ksm_shift) && event->u.mouse.clicks<=1 ) {
    6830           0 :             if ( !fv->b.selected[pos] )
    6831           0 :                 FVDeselectAll(fv);
    6832           0 :             else if ( event->u.mouse.button!=3 ) {
    6833           0 :                 fv->drag_and_drop = fv->has_dd_no_cursor = true;
    6834           0 :                 fv->any_dd_events_sent = false;
    6835           0 :                 GDrawSetCursor(fv->v,ct_prohibition);
    6836           0 :                 GDrawGrabSelection(fv->v,sn_drag_and_drop);
    6837           0 :                 GDrawAddSelectionType(fv->v,sn_drag_and_drop,"STRING",fv,0,sizeof(char),
    6838             :                         ddgencharlist,noop);
    6839             :             }
    6840             :         }
    6841           0 :         fv->pressed_pos = fv->end_pos = pos;
    6842           0 :         FVShowInfo(fv);
    6843           0 :         if ( !fv->drag_and_drop ) {
    6844           0 :             if ( !(event->u.mouse.state&ksm_shift))
    6845           0 :                 fv->sel_index = 1;
    6846           0 :             else if ( fv->sel_index<255 )
    6847           0 :                 ++fv->sel_index;
    6848           0 :             if ( fv->pressed!=NULL ) {
    6849           0 :                 GDrawCancelTimer(fv->pressed);
    6850           0 :                 fv->pressed = NULL;
    6851           0 :             } else if ( event->u.mouse.state&ksm_shift ) {
    6852           0 :                 fv->b.selected[pos] = fv->b.selected[pos] ? 0 : fv->sel_index;
    6853           0 :                 FVToggleCharSelected(fv,pos);
    6854           0 :             } else if ( !fv->b.selected[pos] ) {
    6855           0 :                 fv->b.selected[pos] = fv->sel_index;
    6856           0 :                 FVToggleCharSelected(fv,pos);
    6857             :             }
    6858           0 :             if ( event->u.mouse.button==3 )
    6859           0 :                 GMenuCreatePopupMenuWithName(fv->v,event, "Popup", fvpopupmenu);
    6860             :             else
    6861           0 :                 fv->pressed = GDrawRequestTimer(fv->v,200,100,NULL);
    6862             :         }
    6863           0 :     } else if ( fv->drag_and_drop ) {
    6864           0 :         GWindow othergw = GDrawGetPointerWindow(fv->v);
    6865             : 
    6866           0 :         if ( othergw==fv->v || othergw==fv->gw || othergw==NULL ) {
    6867           0 :             if ( !fv->has_dd_no_cursor ) {
    6868           0 :                 fv->has_dd_no_cursor = true;
    6869           0 :                 GDrawSetCursor(fv->v,ct_prohibition);
    6870             :             }
    6871             :         } else {
    6872           0 :             if ( fv->has_dd_no_cursor ) {
    6873           0 :                 fv->has_dd_no_cursor = false;
    6874           0 :                 GDrawSetCursor(fv->v,ct_ddcursor);
    6875             :             }
    6876             :         }
    6877           0 :         if ( event->type==et_mouseup ) {
    6878           0 :             if ( pos!=fv->pressed_pos ) {
    6879           0 :                 GDrawPostDragEvent(fv->v,event,event->type==et_mouseup?et_drop:et_drag);
    6880           0 :                 fv->any_dd_events_sent = true;
    6881             :             }
    6882           0 :             fv->drag_and_drop = fv->has_dd_no_cursor = false;
    6883           0 :             GDrawSetCursor(fv->v,ct_mypointer);
    6884           0 :             if ( !fv->any_dd_events_sent )
    6885           0 :                 FVDeselectAll(fv);
    6886           0 :             fv->any_dd_events_sent = false;
    6887             :         }
    6888           0 :     } else if ( fv->pressed!=NULL ) {
    6889           0 :         int showit = realpos!=fv->end_pos;
    6890           0 :         FVReselect(fv,realpos);
    6891           0 :         if ( showit )
    6892           0 :             FVShowInfo(fv);
    6893           0 :         if ( event->type==et_mouseup ) {
    6894           0 :             GDrawCancelTimer(fv->pressed);
    6895           0 :             fv->pressed = NULL;
    6896             :         }
    6897             :     }
    6898           0 :     if ( event->type==et_mouseup && dopopup )
    6899           0 :         SCPreparePopup(fv->v,sc,fv->b.map->remap,pos,sc==&dummy?dummy.unicodeenc: UniFromEnc(pos,fv->b.map->enc));
    6900           0 :     if ( event->type==et_mouseup )
    6901           0 :         SVAttachFV(fv,2);
    6902             : }
    6903             : 
    6904           0 : static void FVResize(FontView *fv, GEvent *event) {
    6905             :     extern int default_fv_row_count, default_fv_col_count;
    6906             :     GRect pos,screensize;
    6907             :     int topchar;
    6908             : 
    6909           0 :     if ( fv->colcnt!=0 )
    6910           0 :         topchar = fv->rowoff*fv->colcnt;
    6911           0 :     else if ( fv->b.sf->top_enc!=-1 && fv->b.sf->top_enc<fv->b.map->enccount )
    6912           0 :         topchar = fv->b.sf->top_enc;
    6913             :     else {
    6914             :         /* Position on 'A' (or whatever they ask for) if it exists */
    6915           0 :         topchar = SFFindSlot(fv->b.sf,fv->b.map,home_char,NULL);
    6916           0 :         if ( topchar==-1 ) {
    6917           0 :             for ( topchar=0; topchar<fv->b.map->enccount; ++topchar )
    6918           0 :                 if ( fv->b.map->map[topchar]!=-1 && fv->b.sf->glyphs[fv->b.map->map[topchar]]!=NULL )
    6919           0 :             break;
    6920           0 :             if ( topchar==fv->b.map->enccount )
    6921           0 :                 topchar = 0;
    6922             :         }
    6923             :     }
    6924           0 :     if ( !event->u.resize.sized )
    6925             :         /* WM isn't responding to my resize requests, so no point in trying */;
    6926           0 :     else if ( (event->u.resize.size.width-
    6927           0 :                 GDrawPointsToPixels(fv->gw,_GScrollBar_Width)-1)%fv->cbw!=0 ||
    6928           0 :             (event->u.resize.size.height-fv->mbh-fv->infoh-1)%fv->cbh!=0 ) {
    6929           0 :         int cc = (event->u.resize.size.width+fv->cbw/2-
    6930           0 :                 GDrawPointsToPixels(fv->gw,_GScrollBar_Width)-1)/fv->cbw;
    6931           0 :         int rc = (event->u.resize.size.height-fv->mbh-fv->infoh-1)/fv->cbh;
    6932           0 :         if ( cc<=0 ) cc = 1;
    6933           0 :         if ( rc<=0 ) rc = 1;
    6934           0 :         GDrawGetSize(GDrawGetRoot(NULL),&screensize);
    6935           0 :         if ( cc*fv->cbw+GDrawPointsToPixels(fv->gw,_GScrollBar_Width)>screensize.width )
    6936           0 :             --cc;
    6937           0 :         if ( rc*fv->cbh+fv->mbh+fv->infoh+10>screensize.height )
    6938           0 :             --rc;
    6939           0 :         GDrawResize(fv->gw,
    6940           0 :                 cc*fv->cbw+1+GDrawPointsToPixels(fv->gw,_GScrollBar_Width),
    6941           0 :                 rc*fv->cbh+1+fv->mbh+fv->infoh);
    6942             :         /* somehow KDE loses this event of mine so to get even the vague effect */
    6943             :         /*  we can't just return */
    6944             : /*return;*/
    6945             :     }
    6946             : 
    6947           0 :     pos.width = GDrawPointsToPixels(fv->gw,_GScrollBar_Width);
    6948           0 :     pos.height = event->u.resize.size.height-fv->mbh-fv->infoh;
    6949           0 :     pos.x = event->u.resize.size.width-pos.width; pos.y = fv->mbh+fv->infoh;
    6950           0 :     GGadgetResize(fv->vsb,pos.width,pos.height);
    6951           0 :     GGadgetMove(fv->vsb,pos.x,pos.y);
    6952           0 :     pos.width = pos.x; pos.x = 0;
    6953           0 :     GDrawResize(fv->v,pos.width,pos.height);
    6954             : 
    6955           0 :     fv->width = pos.width; fv->height = pos.height;
    6956           0 :     fv->colcnt = (fv->width-1)/fv->cbw;
    6957           0 :     if ( fv->colcnt<1 ) fv->colcnt = 1;
    6958           0 :     fv->rowcnt = (fv->height-1)/fv->cbh;
    6959           0 :     if ( fv->rowcnt<1 ) fv->rowcnt = 1;
    6960           0 :     fv->rowltot = (fv->b.map->enccount+fv->colcnt-1)/fv->colcnt;
    6961             : 
    6962           0 :     GScrollBarSetBounds(fv->vsb,0,fv->rowltot,fv->rowcnt);
    6963           0 :     fv->rowoff = topchar/fv->colcnt;
    6964           0 :     if ( fv->rowoff>=fv->rowltot-fv->rowcnt )
    6965           0 :         fv->rowoff = fv->rowltot-fv->rowcnt;
    6966           0 :     if ( fv->rowoff<0 ) fv->rowoff =0;
    6967           0 :     GScrollBarSetPos(fv->vsb,fv->rowoff);
    6968           0 :     GDrawRequestExpose(fv->gw,NULL,true);
    6969           0 :     GDrawRequestExpose(fv->v,NULL,true);
    6970             : 
    6971           0 :     if ( fv->rowcnt!=fv->b.sf->desired_row_cnt || fv->colcnt!=fv->b.sf->desired_col_cnt ) {
    6972           0 :         default_fv_row_count = fv->rowcnt;
    6973           0 :         default_fv_col_count = fv->colcnt;
    6974           0 :         fv->b.sf->desired_row_cnt = fv->rowcnt;
    6975           0 :         fv->b.sf->desired_col_cnt = fv->colcnt;
    6976           0 :         SavePrefs(true);
    6977             :     }
    6978           0 : }
    6979             : 
    6980           0 : static void FVTimer(FontView *fv, GEvent *event) {
    6981             : 
    6982           0 :     if ( event->u.timer.timer==fv->pressed ) {
    6983             :         GEvent e;
    6984           0 :         GDrawGetPointerPosition(fv->v,&e);
    6985           0 :         if ( e.u.mouse.y<0 || e.u.mouse.y >= fv->height ) {
    6986           0 :             real dy = 0;
    6987           0 :             if ( e.u.mouse.y<0 )
    6988           0 :                 dy = -1;
    6989           0 :             else if ( e.u.mouse.y>=fv->height )
    6990           0 :                 dy = 1;
    6991           0 :             if ( fv->rowoff+dy<0 )
    6992           0 :                 dy = 0;
    6993           0 :             else if ( fv->rowoff+dy+fv->rowcnt > fv->rowltot )
    6994           0 :                 dy = 0;
    6995           0 :             fv->rowoff += dy;
    6996           0 :             if ( dy!=0 ) {
    6997           0 :                 GScrollBarSetPos(fv->vsb,fv->rowoff);
    6998           0 :                 GDrawScroll(fv->v,NULL,0,dy*fv->cbh);
    6999             :             }
    7000             :         }
    7001           0 :     } else if ( event->u.timer.timer==fv->resize ) {
    7002             :         /* It's a delayed resize event (for kde which sends continuous resizes) */
    7003           0 :         fv->resize = NULL;
    7004           0 :         FVResize(fv,(GEvent *) (event->u.timer.userdata));
    7005           0 :     } else if ( event->u.timer.userdata!=NULL ) {
    7006             :         /* It's a delayed function call */
    7007           0 :         void (*func)(FontView *) = (void (*)(FontView *)) (event->u.timer.userdata);
    7008           0 :         func(fv);
    7009             :     }
    7010           0 : }
    7011             : 
    7012           0 : void FVDelay(FontView *fv,void (*func)(FontView *)) {
    7013           0 :     GDrawRequestTimer(fv->v,100,0,(void *) func);
    7014           0 : }
    7015             : 
    7016           0 : static int FVScroll(GGadget *g, GEvent *e) {
    7017           0 :     FontView *fv = GGadgetGetUserData(g);
    7018           0 :     int newpos = fv->rowoff;
    7019           0 :     struct sbevent *sb = &e->u.control.u.sb;
    7020             : 
    7021           0 :     switch( sb->type ) {
    7022             :       case et_sb_top:
    7023           0 :         newpos = 0;
    7024           0 :       break;
    7025             :       case et_sb_uppage:
    7026           0 :         newpos -= fv->rowcnt;
    7027           0 :       break;
    7028             :       case et_sb_up:
    7029           0 :         --newpos;
    7030           0 :       break;
    7031             :       case et_sb_down:
    7032           0 :         ++newpos;
    7033           0 :       break;
    7034             :       case et_sb_downpage:
    7035           0 :         newpos += fv->rowcnt;
    7036           0 :       break;
    7037             :       case et_sb_bottom:
    7038           0 :         newpos = fv->rowltot-fv->rowcnt;
    7039           0 :       break;
    7040             :       case et_sb_thumb:
    7041             :       case et_sb_thumbrelease:
    7042           0 :         newpos = sb->pos;
    7043           0 :       break;
    7044             :     }
    7045           0 :     if ( newpos>fv->rowltot-fv->rowcnt )
    7046           0 :         newpos = fv->rowltot-fv->rowcnt;
    7047           0 :     if ( newpos<0 ) newpos =0;
    7048           0 :     if ( newpos!=fv->rowoff ) {
    7049           0 :         int diff = newpos-fv->rowoff;
    7050           0 :         fv->rowoff = newpos;
    7051           0 :         GScrollBarSetPos(fv->vsb,fv->rowoff);
    7052           0 :         GDrawScroll(fv->v,NULL,0,diff*fv->cbh);
    7053             :     }
    7054           0 : return( true );
    7055             : }
    7056             : 
    7057           0 : static int v_e_h(GWindow gw, GEvent *event) {
    7058           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    7059             : 
    7060           0 :     if (( event->type==et_mouseup || event->type==et_mousedown ) &&
    7061           0 :             (event->u.mouse.button>=4 && event->u.mouse.button<=7) ) {
    7062           0 : return( GGadgetDispatchEvent(fv->vsb,event));
    7063             :     }
    7064             : 
    7065           0 :     GGadgetPopupExternalEvent(event);
    7066           0 :     switch ( event->type ) {
    7067             :       case et_expose:
    7068           0 :         GDrawSetLineWidth(gw,0);
    7069           0 :         FVExpose(fv,gw,event);
    7070           0 :       break;
    7071             :       case et_char:
    7072           0 :         if ( fv->b.container!=NULL )
    7073           0 :             (fv->b.container->funcs->charEvent)(fv->b.container,event);
    7074             :         else
    7075           0 :             FVChar(fv,event);
    7076           0 :       break;
    7077             :       case et_mousemove: case et_mousedown: case et_mouseup:
    7078           0 :         if ( event->type==et_mousedown )
    7079           0 :             GDrawSetGIC(gw,fv->gic,0,20);
    7080           0 :         if ( fv->notactive && event->type==et_mousedown )
    7081           0 :             (fv->b.container->funcs->activateMe)(fv->b.container,&fv->b);
    7082           0 :         FVMouse(fv,event);
    7083           0 :       break;
    7084             :       case et_timer:
    7085           0 :         FVTimer(fv,event);
    7086           0 :       break;
    7087             :       case et_focus:
    7088           0 :           printf("fv.et_focus\n");
    7089           0 :         if ( event->u.focus.gained_focus )
    7090           0 :             GDrawSetGIC(gw,fv->gic,0,20);
    7091           0 :       break;
    7092             :     }
    7093           0 : return( true );
    7094             : }
    7095             : 
    7096           0 : static void FontView_ReformatOne(FontView *fv) {
    7097             :     FontView *fvs;
    7098             : 
    7099           0 :     if ( fv->v==NULL || fv->colcnt==0 )   /* Can happen in scripts */
    7100           0 : return;
    7101             : 
    7102           0 :     GDrawSetCursor(fv->v,ct_watch);
    7103           0 :     fv->rowltot = (fv->b.map->enccount+fv->colcnt-1)/fv->colcnt;
    7104           0 :     GScrollBarSetBounds(fv->vsb,0,fv->rowltot,fv->rowcnt);
    7105           0 :     if ( fv->rowoff>fv->rowltot-fv->rowcnt ) {
    7106           0 :         fv->rowoff = fv->rowltot-fv->rowcnt;
    7107           0 :         if ( fv->rowoff<0 ) fv->rowoff =0;
    7108           0 :         GScrollBarSetPos(fv->vsb,fv->rowoff);
    7109             :     }
    7110           0 :     for ( fvs=(FontView *) (fv->b.sf->fv); fvs!=NULL; fvs=(FontView *) (fvs->b.nextsame) )
    7111           0 :         if ( fvs!=fv && fvs->b.sf==fv->b.sf )
    7112           0 :     break;
    7113           0 :     GDrawRequestExpose(fv->v,NULL,false);
    7114           0 :     GDrawSetCursor(fv->v,ct_pointer);
    7115             : }
    7116             : 
    7117           1 : static void FontView_ReformatAll(SplineFont *sf) {
    7118             :     BDFFont *new, *old, *bdf;
    7119             :     FontView *fv;
    7120             :     MetricsView *mvs;
    7121             :     extern int use_freetype_to_rasterize_fv;
    7122             : 
    7123           1 :     if ( ((FontView *) (sf->fv))->v==NULL || ((FontView *) (sf->fv))->colcnt==0 )                   /* Can happen in scripts */
    7124           2 : return;
    7125             : 
    7126           0 :     for ( fv=(FontView *) (sf->fv); fv!=NULL; fv=(FontView *) (fv->b.nextsame) ) {
    7127           0 :         GDrawSetCursor(fv->v,ct_watch);
    7128           0 :         old = fv->filled;
    7129             :                                 /* In CID fonts fv->b.sf may not be same as sf */
    7130           0 :         new = SplineFontPieceMeal(fv->b.sf,fv->b.active_layer,fv->filled->pixelsize,72,
    7131           0 :                 (fv->antialias?pf_antialias:0)|(fv->bbsized?pf_bbsized:0)|
    7132           0 :                     (use_freetype_to_rasterize_fv && !sf->strokedfont && !sf->multilayer?pf_ft_nohints:0),
    7133             :                 NULL);
    7134           0 :         fv->filled = new;
    7135           0 :         if ( fv->show==old )
    7136           0 :             fv->show = new;
    7137             :         else {
    7138           0 :             for ( bdf=sf->bitmaps; bdf != NULL &&
    7139           0 :                 ( bdf->pixelsize != fv->show->pixelsize || BDFDepth( bdf ) != BDFDepth( fv->show )); bdf=bdf->next );
    7140           0 :             if ( bdf != NULL ) fv->show = bdf;
    7141           0 :             else fv->show = new;
    7142             :         }
    7143           0 :         BDFFontFree(old);
    7144           0 :         fv->rowltot = (fv->b.map->enccount+fv->colcnt-1)/fv->colcnt;
    7145           0 :         GScrollBarSetBounds(fv->vsb,0,fv->rowltot,fv->rowcnt);
    7146           0 :         if ( fv->rowoff>fv->rowltot-fv->rowcnt ) {
    7147           0 :             fv->rowoff = fv->rowltot-fv->rowcnt;
    7148           0 :             if ( fv->rowoff<0 ) fv->rowoff =0;
    7149           0 :             GScrollBarSetPos(fv->vsb,fv->rowoff);
    7150             :         }
    7151           0 :         GDrawRequestExpose(fv->v,NULL,false);
    7152           0 :         GDrawSetCursor(fv->v,ct_pointer);
    7153             :     }
    7154           0 :     for ( mvs=sf->metrics; mvs!=NULL; mvs=mvs->next ) if ( mvs->bdf==NULL ) {
    7155           0 :         BDFFontFree(mvs->show);
    7156           0 :         mvs->show = SplineFontPieceMeal(sf,mvs->layer,mvs->ptsize,mvs->dpi,
    7157           0 :                 mvs->antialias?(pf_antialias|pf_ft_recontext):pf_ft_recontext,NULL);
    7158           0 :         GDrawRequestExpose(mvs->gw,NULL,false);
    7159             :     }
    7160             : }
    7161             : 
    7162          31 : void FontViewRemove(FontView *fv) {
    7163          31 :     if ( fv_list==fv )
    7164          27 :         fv_list = (FontView *) (fv->b.next);
    7165             :     else {
    7166             :         FontView *n;
    7167           4 :         for ( n=fv_list; n->b.next!=&fv->b; n=(FontView *) (n->b.next) );
    7168           4 :         n->b.next = fv->b.next;
    7169             :     }
    7170          31 :     FontViewFree(&fv->b);
    7171          31 : }
    7172             : 
    7173             : /**
    7174             :  * In some cases fontview gets an et_selclear event when using copy
    7175             :  * and paste on the OSX. So this guard lets us quietly ignore that
    7176             :  * event when we have just done command+c or command+x.
    7177             :  */
    7178             : extern int osx_fontview_copy_cut_counter;
    7179             : 
    7180             : static FontView* ActiveFontView = 0;
    7181             : 
    7182           0 : static int fv_e_h(GWindow gw, GEvent *event) {
    7183           0 :     FontView *fv = (FontView *) GDrawGetUserData(gw);
    7184             : 
    7185           0 :     if (( event->type==et_mouseup || event->type==et_mousedown ) &&
    7186           0 :             (event->u.mouse.button>=4 && event->u.mouse.button<=7) ) {
    7187           0 : return( GGadgetDispatchEvent(fv->vsb,event));
    7188             :     }
    7189             : 
    7190           0 :     switch ( event->type ) {
    7191             :       case et_focus:
    7192           0 :           if ( event->u.focus.gained_focus )
    7193             :           {
    7194           0 :               ActiveFontView = fv;
    7195             :           }
    7196             :           else
    7197             :           {
    7198             :           }
    7199           0 :           break;
    7200             :       case et_selclear:
    7201             : #ifdef __Mac
    7202             :           // For some reason command + c and command + x wants
    7203             :           // to send a clear to us, even if that key was pressed
    7204             :           // on a charview.
    7205             :           if( osx_fontview_copy_cut_counter )
    7206             :           {
    7207             :              osx_fontview_copy_cut_counter--;
    7208             :              break;
    7209             :           }
    7210             : //        printf("fontview et_selclear\n");
    7211             : #endif
    7212           0 :         ClipboardClear();
    7213           0 :       break;
    7214             :       case et_expose:
    7215           0 :         GDrawSetLineWidth(gw,0);
    7216           0 :         FVDrawInfo(fv,gw,event);
    7217           0 :       break;
    7218             :       case et_resize:
    7219             :         /* KDE sends a continuous stream of resize events, and gets very */
    7220             :         /*  confused if I start resizing the window myself, try to wait for */
    7221             :         /*  the user to finish before responding to resizes */
    7222           0 :         if ( event->u.resize.sized || fv->resize_expected ) {
    7223           0 :             if ( fv->resize )
    7224           0 :                 GDrawCancelTimer(fv->resize);
    7225           0 :             fv->resize_event = *event;
    7226           0 :             fv->resize = GDrawRequestTimer(fv->v,300,0,(void *) &fv->resize_event);
    7227           0 :             fv->resize_expected = false;
    7228             :         }
    7229           0 :       break;
    7230             :       case et_char:
    7231           0 :         if ( fv->b.container!=NULL )
    7232           0 :             (fv->b.container->funcs->charEvent)(fv->b.container,event);
    7233             :         else
    7234           0 :             FVChar(fv,event);
    7235           0 :       break;
    7236             :       case et_mousedown:
    7237           0 :         GDrawSetGIC(gw,fv->gwgic,0,20);
    7238           0 :         if ( fv->notactive )
    7239           0 :             (fv->b.container->funcs->activateMe)(fv->b.container,&fv->b);
    7240           0 :       break;
    7241             :       case et_close:
    7242           0 :         FVMenuClose(gw,NULL,NULL);
    7243           0 :       break;
    7244             :       case et_create:
    7245           0 :         fv->b.next = (FontViewBase *) fv_list;
    7246           0 :         fv_list = fv;
    7247           0 :       break;
    7248             :       case et_destroy:
    7249           0 :         if ( fv->qg!=NULL )
    7250           0 :             QGRmFontView(fv->qg,fv);
    7251           0 :         FontViewRemove(fv);
    7252           0 :       break;
    7253             :     }
    7254           0 : return( true );
    7255             : }
    7256             : 
    7257           0 : static void FontViewOpenKids(FontView *fv) {
    7258             :     int k, i;
    7259           0 :     SplineFont *sf = fv->b.sf, *_sf;
    7260             : #if defined(__Mac)
    7261             :     int cnt= 0;
    7262             : #endif
    7263             : 
    7264           0 :     if ( sf->cidmaster!=NULL )
    7265           0 :         sf = sf->cidmaster;
    7266             : 
    7267           0 :     k=0;
    7268             :     do {
    7269           0 :         _sf = sf->subfontcnt==0 ? sf : sf->subfonts[k];
    7270           0 :         for ( i=0; i<_sf->glyphcnt; ++i )
    7271           0 :             if ( _sf->glyphs[i]!=NULL && _sf->glyphs[i]->wasopen ) {
    7272           0 :                 _sf->glyphs[i]->wasopen = false;
    7273             : #if defined(__Mac)
    7274             :                 /* If we open a bunch of charviews all at once on the mac, X11*/
    7275             :                 /*  crashes */ /* But opening one seems ok */
    7276             :                 if ( ++cnt==1 )
    7277             : #endif
    7278           0 :                 CharViewCreate(_sf->glyphs[i],fv,-1);
    7279             :             }
    7280           0 :         ++k;
    7281           0 :     } while ( k<sf->subfontcnt );
    7282           0 : }
    7283             : 
    7284          68 : static FontView *__FontViewCreate(SplineFont *sf) {
    7285          68 :     FontView *fv = calloc(1,sizeof(FontView));
    7286             :     int i;
    7287          69 :     int ps = sf->display_size<0 ? -sf->display_size :
    7288           1 :              sf->display_size==0 ? default_fv_font_size : sf->display_size;
    7289             : 
    7290          68 :     if ( ps>200 ) ps = 128;
    7291             : 
    7292             :     /* Filename != NULL if we opened an sfd file. Sfd files know whether */
    7293             :     /*  the font is compact or not and should not depend on a global flag */
    7294             :     /* If a font is new, then compaction will make it vanish completely */
    7295          68 :     if ( sf->fv==NULL && compact_font_on_open && sf->filename==NULL && !sf->new ) {
    7296           0 :         sf->compacted = true;
    7297           0 :         for ( i=0; i<sf->subfontcnt; ++i )
    7298           0 :             sf->subfonts[i]->compacted = true;
    7299             :     }
    7300          68 :     fv->b.nextsame = sf->fv;
    7301          68 :     fv->b.active_layer = sf->display_layer;
    7302          68 :     sf->fv = (FontViewBase *) fv;
    7303          68 :     if ( sf->mm!=NULL ) {
    7304           2 :         sf->mm->normal->fv = (FontViewBase *) fv;
    7305           6 :         for ( i = 0; i<sf->mm->instance_count; ++i )
    7306           4 :             sf->mm->instances[i]->fv = (FontViewBase *) fv;
    7307             :     }
    7308          68 :     if ( sf->subfontcnt==0 ) {
    7309          67 :         fv->b.sf = sf;
    7310          67 :         if ( fv->b.nextsame!=NULL ) {
    7311           0 :             fv->b.map = EncMapCopy(fv->b.nextsame->map);
    7312           0 :             fv->b.normal = fv->b.nextsame->normal==NULL ? NULL : EncMapCopy(fv->b.nextsame->normal);
    7313          67 :         } else if ( sf->compacted ) {
    7314           0 :             fv->b.normal = sf->map;
    7315           0 :             fv->b.map = CompactEncMap(EncMapCopy(sf->map),sf);
    7316           0 :             sf->map = fv->b.map;
    7317             :         } else {
    7318          67 :             fv->b.map = sf->map;
    7319          67 :             fv->b.normal = NULL;
    7320             :         }
    7321             :     } else {
    7322           1 :         fv->b.cidmaster = sf;
    7323           5 :         for ( i=0; i<sf->subfontcnt; ++i )
    7324           4 :             sf->subfonts[i]->fv = (FontViewBase *) fv;
    7325           1 :         for ( i=0; i<sf->subfontcnt; ++i )        /* Search for a subfont that contains more than ".notdef" (most significant in .gai fonts) */
    7326           1 :             if ( sf->subfonts[i]->glyphcnt>1 ) {
    7327           1 :                 fv->b.sf = sf->subfonts[i];
    7328           1 :         break;
    7329             :             }
    7330           1 :         if ( fv->b.sf==NULL )
    7331           0 :             fv->b.sf = sf->subfonts[0];
    7332           1 :         sf = fv->b.sf;
    7333           1 :         if ( fv->b.nextsame==NULL ) { EncMapFree(sf->map); sf->map = NULL; }
    7334           1 :         fv->b.map = EncMap1to1(sf->glyphcnt);
    7335           1 :         if ( fv->b.nextsame==NULL ) { sf->map = fv->b.map; }
    7336           1 :         if ( sf->compacted ) {
    7337           0 :             fv->b.normal = fv->b.map;
    7338           0 :             fv->b.map = CompactEncMap(EncMapCopy(fv->b.map),sf);
    7339           0 :             if ( fv->b.nextsame==NULL ) { sf->map = fv->b.map; }
    7340             :         }
    7341             :     }
    7342          68 :     fv->b.selected = calloc((fv->b.map ? fv->b.map->enccount : 0), sizeof(char));
    7343          68 :     fv->user_requested_magnify = -1;
    7344          68 :     fv->magnify = (ps<=9)? 3 : (ps<20) ? 2 : 1;
    7345          68 :     fv->cbw = (ps*fv->magnify)+1;
    7346          68 :     fv->cbh = (ps*fv->magnify)+1+fv->lab_height+1;
    7347          68 :     fv->antialias = sf->display_antialias;
    7348          68 :     fv->bbsized = sf->display_bbsized;
    7349          68 :     fv->glyphlabel = default_fv_glyphlabel;
    7350             : 
    7351          68 :     fv->end_pos = -1;
    7352             : #ifndef _NO_PYTHON
    7353          68 :     PyFF_InitFontHook((FontViewBase *)fv);
    7354             : #endif
    7355             : 
    7356          68 :     fv->pid_webfontserver = 0;
    7357             : 
    7358          68 : return( fv );
    7359             : }
    7360             : 
    7361             : static int fontview_ready = false;
    7362             : 
    7363           0 : static void FontViewFinish() {
    7364           0 :     if (!fontview_ready) return;
    7365           0 :     mb2FreeGetText(mblist);
    7366           0 :     mbFreeGetText(fvpopupmenu);
    7367             : }
    7368             : 
    7369           0 : void FontViewFinishNonStatic() {
    7370           0 :     FontViewFinish();
    7371           0 : }
    7372             : 
    7373           0 : static void FontViewInit(void) {
    7374             :     // static int done = false; // superseded by fontview_ready.
    7375             : 
    7376           0 :     if ( fontview_ready )
    7377           0 : return;
    7378             : 
    7379           0 :     fontview_ready = true;
    7380             : 
    7381           0 :     mb2DoGetText(mblist);
    7382           0 :     mbDoGetText(fvpopupmenu);
    7383           0 :     atexit(&FontViewFinishNonStatic);
    7384             : }
    7385             : 
    7386             : static struct resed fontview_re[] = {
    7387             :     {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 },
    7388             :     {N_("Empty Slot FG Color"), "EmptySlotFgColor", rt_color, &fvemtpyslotfgcol, N_("Color used to draw the foreground of empty slots"), NULL, { 0 }, 0, 0 },
    7389             :     {N_("Selected BG Color"), "SelectedColor", rt_color, &fvselcol, N_("Color used to draw the background of selected glyphs"), NULL, { 0 }, 0, 0 },
    7390             :     {N_("Selected FG Color"), "SelectedFgColor", rt_color, &fvselfgcol, N_("Color used to draw the foreground of selected glyphs"), NULL, { 0 }, 0, 0 },
    7391             :     {N_("Changed Color"), "ChangedColor", rt_color, &fvchangedcol, N_("Color used to mark a changed glyph"), NULL, { 0 }, 0, 0 },
    7392             :     {N_("Hinting Needed Color"), "HintingNeededColor", rt_color, &fvhintingneededcol, N_("Color used to mark glyphs that need hinting"), NULL, { 0 }, 0, 0 },
    7393             :     {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 },
    7394             :     {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 },
    7395             :     RESED_EMPTY
    7396             : };
    7397             : 
    7398           0 : static void FVCreateInnards(FontView *fv,GRect *pos) {
    7399           0 :     GWindow gw = fv->gw;
    7400             :     GWindowAttrs wattrs;
    7401             :     GGadgetData gd;
    7402             :     FontRequest rq;
    7403             :     BDFFont *bdf;
    7404             :     int as,ds,ld;
    7405             :     extern int use_freetype_to_rasterize_fv;
    7406           0 :     SplineFont *sf = fv->b.sf;
    7407             : 
    7408           0 :     fv->lab_height = FV_LAB_HEIGHT-13+GDrawPointsToPixels(NULL,fv_fontsize);
    7409             : 
    7410           0 :     memset(&gd,0,sizeof(gd));
    7411           0 :     gd.pos.y = pos->y; gd.pos.height = pos->height;
    7412           0 :     gd.pos.width = GDrawPointsToPixels(gw,_GScrollBar_Width);
    7413           0 :     gd.pos.x = pos->width;
    7414           0 :     gd.u.sbinit = NULL;
    7415           0 :     gd.flags = gg_visible|gg_enabled|gg_pos_in_pixels|gg_sb_vert;
    7416           0 :     gd.handle_controlevent = FVScroll;
    7417           0 :     fv->vsb = GScrollBarCreate(gw,&gd,fv);
    7418             : 
    7419             : 
    7420           0 :     memset(&wattrs,0,sizeof(wattrs));
    7421           0 :     wattrs.mask = wam_events|wam_cursor|wam_backcol;
    7422           0 :     wattrs.event_masks = ~(1<<et_charup);
    7423           0 :     wattrs.cursor = ct_pointer;
    7424           0 :     wattrs.background_color = view_bgcol;
    7425           0 :     fv->v = GWidgetCreateSubWindow(gw,pos,v_e_h,fv,&wattrs);
    7426           0 :     GDrawSetVisible(fv->v,true);
    7427           0 :     GDrawSetWindowTypeName(fv->v, "FontView");
    7428             : 
    7429           0 :     fv->gic   = GDrawCreateInputContext(fv->v,gic_root|gic_orlesser);
    7430           0 :     fv->gwgic = GDrawCreateInputContext(fv->gw,gic_root|gic_orlesser);
    7431           0 :     GDrawSetGIC(fv->v,fv->gic,0,20);
    7432           0 :     GDrawSetGIC(fv->gw,fv->gic,0,20);
    7433             : 
    7434           0 :     fv->fontset = calloc(_uni_fontmax,sizeof(GFont *));
    7435           0 :     memset(&rq,0,sizeof(rq));
    7436           0 :     rq.utf8_family_name = fv_fontnames;
    7437           0 :     rq.point_size = fv_fontsize;
    7438           0 :     rq.weight = 400;
    7439           0 :     fv->fontset[0] = GDrawInstanciateFont(gw,&rq);
    7440           0 :     GDrawSetFont(fv->v,fv->fontset[0]);
    7441           0 :     GDrawWindowFontMetrics(fv->v,fv->fontset[0],&as,&ds,&ld);
    7442           0 :     fv->lab_as = as;
    7443           0 :     fv->showhmetrics = default_fv_showhmetrics;
    7444           0 :     fv->showvmetrics = default_fv_showvmetrics && sf->hasvmetrics;
    7445           0 :     bdf = SplineFontPieceMeal(fv->b.sf,fv->b.active_layer,sf->display_size<0?-sf->display_size:default_fv_font_size,72,
    7446           0 :             (fv->antialias?pf_antialias:0)|(fv->bbsized?pf_bbsized:0)|
    7447           0 :                 (use_freetype_to_rasterize_fv && !sf->strokedfont && !sf->multilayer?pf_ft_nohints:0),
    7448             :             NULL);
    7449           0 :     fv->filled = bdf;
    7450           0 :     if ( sf->display_size>0 ) {
    7451           0 :         for ( bdf=sf->bitmaps; bdf!=NULL && bdf->pixelsize!=sf->display_size ;
    7452           0 :                 bdf=bdf->next );
    7453           0 :         if ( bdf==NULL )
    7454           0 :             bdf = fv->filled;
    7455             :     }
    7456           0 :     if ( sf->onlybitmaps && bdf==fv->filled && sf->bitmaps!=NULL )
    7457           0 :         bdf = sf->bitmaps;
    7458           0 :     fv->cbw = -1;
    7459           0 :     FVChangeDisplayFont(fv,bdf);
    7460           0 : }
    7461             : 
    7462           0 : static FontView *FontView_Create(SplineFont *sf, int hide) {
    7463           0 :     FontView *fv = (FontView *) __FontViewCreate(sf);
    7464             :     GRect pos;
    7465             :     GWindow gw;
    7466             :     GWindowAttrs wattrs;
    7467             :     GGadgetData gd;
    7468             :     GRect gsize;
    7469             :     static GWindow icon = NULL;
    7470             :     static int nexty=0;
    7471             :     GRect size;
    7472             : 
    7473           0 :     FontViewInit();
    7474           0 :     if ( icon==NULL ) {
    7475             : #ifdef BIGICONS
    7476             :         icon = GDrawCreateBitmap(NULL,fontview_width,fontview_height,fontview_bits);
    7477             : #else
    7478           0 :         icon = GDrawCreateBitmap(NULL,fontview2_width,fontview2_height,fontview2_bits);
    7479             : #endif
    7480             :     }
    7481             : 
    7482           0 :     GDrawGetSize(GDrawGetRoot(NULL),&size);
    7483             : 
    7484           0 :     memset(&wattrs,0,sizeof(wattrs));
    7485           0 :     wattrs.mask = wam_events|wam_cursor|wam_icon;
    7486           0 :     wattrs.event_masks = ~(1<<et_charup);
    7487           0 :     wattrs.cursor = ct_pointer;
    7488           0 :     wattrs.icon = icon;
    7489           0 :     pos.width = sf->desired_col_cnt*fv->cbw+1;
    7490           0 :     pos.height = sf->desired_row_cnt*fv->cbh+1;
    7491           0 :     pos.x = size.width-pos.width-30; pos.y = nexty;
    7492           0 :     nexty += 2*fv->cbh+50;
    7493           0 :     if ( nexty+pos.height > size.height )
    7494           0 :         nexty = 0;
    7495           0 :     fv->gw = gw = GDrawCreateTopWindow(NULL,&pos,fv_e_h,fv,&wattrs);
    7496           0 :     FontViewSetTitle(fv);
    7497           0 :     GDrawSetWindowTypeName(fv->gw, "FontView");
    7498             : 
    7499           0 :     if ( !fv_fs_init ) {
    7500           0 :         GResEditFind( fontview_re, "FontView.");
    7501           0 :         view_bgcol = GResourceFindColor("View.Background",GDrawGetDefaultBackground(NULL));
    7502           0 :         fv_fs_init = true;
    7503             :     }
    7504             : 
    7505           0 :     memset(&gd,0,sizeof(gd));
    7506           0 :     gd.flags = gg_visible | gg_enabled;
    7507           0 :     helplist[0].invoke = FVMenuContextualHelp;
    7508             : #ifndef _NO_PYTHON
    7509           0 :     if ( fvpy_menu!=NULL )
    7510           0 :         mblist[3].ti.disabled = false;
    7511           0 :     mblist[3].sub = fvpy_menu;
    7512             : #define CALLBACKS_INDEX 4 /* FIXME: There has to be a better way than this. */
    7513             : #else
    7514             : #define CALLBACKS_INDEX 3 /* FIXME: There has to be a better way than this. */
    7515             : #endif          /* _NO_PYTHON */
    7516             : #ifdef NATIVE_CALLBACKS
    7517             :     if ( fv_menu!=NULL )
    7518             :        mblist[CALLBACKS_INDEX].ti.disabled = false;
    7519             :     mblist[CALLBACKS_INDEX].sub = fv_menu;
    7520             : #endif      /* NATIVE_CALLBACKS */
    7521           0 :     gd.u.menu2 = mblist;
    7522           0 :     fv->mb = GMenu2BarCreate( gw, &gd, NULL);
    7523           0 :     GGadgetGetSize(fv->mb,&gsize);
    7524           0 :     fv->mbh = gsize.height;
    7525           0 :     fv->infoh = 1+GDrawPointsToPixels(NULL,fv_fontsize);
    7526             : 
    7527           0 :     pos.x = 0; pos.y = fv->mbh+fv->infoh;
    7528           0 :     FVCreateInnards(fv,&pos);
    7529             : 
    7530           0 :     if ( !hide ) {
    7531           0 :         GDrawSetVisible(gw,true);
    7532           0 :         FontViewOpenKids(fv);
    7533             :     }
    7534           0 : return( fv );
    7535             : }
    7536             : 
    7537          68 : static FontView *FontView_Append(FontView *fv) {
    7538             :     /* Normally fontviews get added to the fv list when their windows are */
    7539             :     /*  created. but we don't create any windows here, so... */
    7540             :     FontView *test;
    7541             : 
    7542          68 :     if ( fv_list==NULL ) fv_list = fv;
    7543             :     else {
    7544          13 :         for ( test = fv_list; test->b.next!=NULL; test=(FontView *) test->b.next );
    7545          13 :         test->b.next = (FontViewBase *) fv;
    7546             :     }
    7547          68 : return( fv );
    7548             : }
    7549             : 
    7550           0 : FontView *FontNew(void) {
    7551           0 : return( FontView_Create(SplineFontNew(),false));
    7552             : }
    7553             : 
    7554          31 : static void FontView_Free(FontView *fv) {
    7555             :     int i;
    7556             :     FontView *prev;
    7557             :     FontView *fvs;
    7558             : 
    7559          31 :     if ( fv->b.sf == NULL )  /* Happens when usurping a font to put it into an MM */
    7560           0 :         BDFFontFree(fv->filled);
    7561          31 :     else if ( fv->b.nextsame==NULL && fv->b.sf->fv==&fv->b ) {
    7562          31 :         EncMapFree(fv->b.map);
    7563          31 :         if (fv->b.sf != NULL && fv->b.map == fv->b.sf->map) { fv->b.sf->map = NULL; }
    7564          31 :         SplineFontFree(fv->b.cidmaster?fv->b.cidmaster:fv->b.sf);
    7565          31 :         BDFFontFree(fv->filled);
    7566             :     } else {
    7567           0 :         EncMapFree(fv->b.map);
    7568           0 :         if (fv->b.sf != NULL && fv->b.map == fv->b.sf->map) { fv->b.sf->map = NULL; }
    7569           0 :         fv->b.map = NULL;
    7570           0 :         for ( fvs=(FontView *) (fv->b.sf->fv), i=0 ; fvs!=NULL; fvs = (FontView *) (fvs->b.nextsame) )
    7571           0 :             if ( fvs->filled==fv->filled ) ++i;
    7572           0 :         if ( i==1 )
    7573           0 :             BDFFontFree(fv->filled);
    7574           0 :         if ( fv->b.sf->fv==&fv->b ) {
    7575           0 :             if ( fv->b.cidmaster==NULL )
    7576           0 :                 fv->b.sf->fv = fv->b.nextsame;
    7577             :             else {
    7578           0 :                 fv->b.cidmaster->fv = fv->b.nextsame;
    7579           0 :                 for ( i=0; i<fv->b.cidmaster->subfontcnt; ++i )
    7580           0 :                     fv->b.cidmaster->subfonts[i]->fv = fv->b.nextsame;
    7581             :             }
    7582             :         } else {
    7583           0 :             for ( prev = (FontView *) (fv->b.sf->fv); prev->b.nextsame!=&fv->b; prev=(FontView *) (prev->b.nextsame) );
    7584           0 :             prev->b.nextsame = fv->b.nextsame;
    7585             :         }
    7586             :     }
    7587             : #ifndef _NO_FFSCRIPT
    7588          31 :     DictionaryFree(fv->b.fontvars);
    7589          31 :     free(fv->b.fontvars);
    7590             : #endif
    7591          31 :     free(fv->b.selected);
    7592          31 :     free(fv->fontset);
    7593             : #ifndef _NO_PYTHON
    7594          31 :     PyFF_FreeFV(&fv->b);
    7595             : #endif
    7596          31 :     free(fv);
    7597          31 : }
    7598             : 
    7599           4 : static int FontViewWinInfo(FontView *fv, int *cc, int *rc) {
    7600           4 :     if ( fv==NULL || fv->colcnt==0 || fv->rowcnt==0 ) {
    7601           4 :         *cc = 16; *rc = 4;
    7602           4 : return( -1 );
    7603             :     }
    7604             : 
    7605           0 :     *cc = fv->colcnt;
    7606           0 :     *rc = fv->rowcnt;
    7607             : 
    7608           0 : return( fv->rowoff*fv->colcnt );
    7609             : }
    7610             : 
    7611             : 
    7612             : 
    7613             : 
    7614             : 
    7615             : 
    7616             : 
    7617             : 
    7618             : 
    7619         145 : static FontViewBase *FVAny(void) { return (FontViewBase *) fv_list; }
    7620             : 
    7621           0 : static int  FontIsActive(SplineFont *sf) {
    7622             :     FontView *fv;
    7623             : 
    7624           0 :     for ( fv=fv_list; fv!=NULL; fv=(FontView *) (fv->b.next) )
    7625           0 :         if ( fv->b.sf == sf )
    7626           0 : return( true );
    7627             : 
    7628           0 : return( false );
    7629             : }
    7630             : 
    7631      202138 : static SplineFont *FontOfFilename(const char *filename) {
    7632             :     char buffer[1025];
    7633             :     FontView *fv;
    7634             : 
    7635      202138 :     GFileGetAbsoluteName((char *) filename,buffer,sizeof(buffer));
    7636      206532 :     for ( fv=fv_list; fv!=NULL ; fv=(FontView *) (fv->b.next) ) {
    7637      206469 :         if ( fv->b.sf->filename!=NULL && strcmp(fv->b.sf->filename,buffer)==0 )
    7638      197698 : return( fv->b.sf );
    7639        8771 :         else if ( fv->b.sf->origname!=NULL && strcmp(fv->b.sf->origname,buffer)==0 )
    7640        4377 : return( fv->b.sf );
    7641             :     }
    7642          63 : return( NULL );
    7643             : }
    7644             : 
    7645           0 : static void FVExtraEncSlots(FontView *fv, int encmax) {
    7646           0 :     if ( fv->colcnt!=0 ) {           /* Ie. scripting vs. UI */
    7647           0 :         fv->rowltot = (encmax+1+fv->colcnt-1)/fv->colcnt;
    7648           0 :         GScrollBarSetBounds(fv->vsb,0,fv->rowltot,fv->rowcnt);
    7649             :     }
    7650           0 : }
    7651             : 
    7652           8 : static void FV_BiggerGlyphCache(FontView *fv, int gidcnt) {
    7653           8 :     if ( fv->filled!=NULL )
    7654           0 :         BDFOrigFixup(fv->filled,gidcnt,fv->b.sf);
    7655           8 : }
    7656             : 
    7657          31 : static void FontView_Close(FontView *fv) {
    7658          31 :     if ( fv->gw!=NULL )
    7659           0 :         GDrawDestroyWindow(fv->gw);
    7660             :     else
    7661          31 :         FontViewRemove(fv);
    7662          31 : }
    7663             : 
    7664             : 
    7665             : struct fv_interface gdraw_fv_interface = {
    7666             :     (FontViewBase *(*)(SplineFont *, int)) FontView_Create,
    7667             :     (FontViewBase *(*)(SplineFont *)) __FontViewCreate,
    7668             :     (void (*)(FontViewBase *)) FontView_Close,
    7669             :     (void (*)(FontViewBase *)) FontView_Free,
    7670             :     (void (*)(FontViewBase *)) FontViewSetTitle,
    7671             :     FontViewSetTitles,
    7672             :     FontViewRefreshAll,
    7673             :     (void (*)(FontViewBase *)) FontView_ReformatOne,
    7674             :     FontView_ReformatAll,
    7675             :     (void (*)(FontViewBase *)) FV_LayerChanged,
    7676             :     FV_ToggleCharChanged,
    7677             :     (int  (*)(FontViewBase *, int *, int *)) FontViewWinInfo,
    7678             :     FontIsActive,
    7679             :     FVAny,
    7680             :     (FontViewBase *(*)(FontViewBase *)) FontView_Append,
    7681             :     FontOfFilename,
    7682             :     (void (*)(FontViewBase *,int)) FVExtraEncSlots,
    7683             :     (void (*)(FontViewBase *,int)) FV_BiggerGlyphCache,
    7684             :     (void (*)(FontViewBase *,BDFFont *)) FV_ChangeDisplayBitmap,
    7685             :     (void (*)(FontViewBase *)) FV_ShowFilled,
    7686             :     FV_ReattachCVs,
    7687             :     (void (*)(FontViewBase *)) FVDeselectAll,
    7688             :     (void (*)(FontViewBase *,int )) FVScrollToGID,
    7689             :     (void (*)(FontViewBase *,int )) FVScrollToChar,
    7690             :     (void (*)(FontViewBase *,int )) FV_ChangeGID,
    7691             :     SF_CloseAllInstrs
    7692             : };
    7693             : 
    7694             : extern GResInfo charview_ri;
    7695             : static struct resed view_re[] = {
    7696             :     {N_("Color|Background"), "Background", rt_color, &view_bgcol, N_("Background color for the drawing area of all views"), NULL, { 0 }, 0, 0 },
    7697             :     RESED_EMPTY
    7698             : };
    7699             : GResInfo view_ri = {
    7700             :     NULL, NULL,NULL, NULL,
    7701             :     NULL,
    7702             :     NULL,
    7703             :     NULL,
    7704             :     view_re,
    7705             :     N_("View"),
    7706             :     N_("This is an abstract class which defines common features of the\nFontView, CharView, BitmapView and MetricsView"),
    7707             :     "View",
    7708             :     "fontforge",
    7709             :     false,
    7710             :     0,
    7711             :     NULL,
    7712             :     GBOX_EMPTY,
    7713             :     NULL,
    7714             :     NULL,
    7715             :     NULL
    7716             : };
    7717             : 
    7718             : GResInfo fontview_ri = {
    7719             :     &charview_ri, NULL,NULL, NULL,
    7720             :     NULL,
    7721             :     NULL,
    7722             :     NULL,
    7723             :     fontview_re,
    7724             :     N_("FontView"),
    7725             :     N_("This is the main fontforge window displaying a font"),
    7726             :     "FontView",
    7727             :     "fontforge",
    7728             :     false,
    7729             :     0,
    7730             :     NULL,
    7731             :     GBOX_EMPTY,
    7732             :     NULL,
    7733             :     NULL,
    7734             :     NULL
    7735             : };
    7736             : 
    7737             : /* ************************************************************************** */
    7738             : /* ***************************** Embedded FontViews ************************* */
    7739             : /* ************************************************************************** */
    7740             : 
    7741           0 : static void FVCopyInnards(FontView *fv,GRect *pos,int infoh,
    7742             :         FontView *fvorig,GWindow dw, int def_layer, struct fvcontainer *kf) {
    7743             : 
    7744           0 :     fv->notactive = true;
    7745           0 :     fv->gw = dw;
    7746           0 :     fv->infoh = infoh;
    7747           0 :     fv->b.container = kf;
    7748           0 :     fv->rowcnt = 4; fv->colcnt = 16;
    7749           0 :     fv->b.active_layer = def_layer;
    7750           0 :     FVCreateInnards(fv,pos);
    7751           0 :     memcpy(fv->b.selected,fvorig->b.selected,fv->b.map->enccount);
    7752           0 :     fv->rowoff = (fvorig->rowoff*fvorig->colcnt)/fv->colcnt;
    7753           0 : }
    7754             : 
    7755           0 : void KFFontViewInits(struct kf_dlg *kf,GGadget *drawable) {
    7756             :     GGadgetData gd;
    7757             :     GRect pos, gsize, sbsize;
    7758           0 :     GWindow dw = GDrawableGetWindow(drawable);
    7759             :     int infoh;
    7760             :     int ps;
    7761           0 :     FontView *fvorig = (FontView *) kf->sf->fv;
    7762             : 
    7763           0 :     FontViewInit();
    7764             : 
    7765           0 :     kf->dw = dw;
    7766             : 
    7767           0 :     memset(&gd,0,sizeof(gd));
    7768           0 :     gd.flags = gg_visible | gg_enabled;
    7769           0 :     helplist[0].invoke = FVMenuContextualHelp;
    7770           0 :     gd.u.menu2 = mblist;
    7771           0 :     kf->mb = GMenu2BarCreate( dw, &gd, NULL);
    7772           0 :     GGadgetGetSize(kf->mb,&gsize);
    7773           0 :     kf->mbh = gsize.height;
    7774           0 :     kf->guts = drawable;
    7775             : 
    7776           0 :     ps = kf->sf->display_size; kf->sf->display_size = -24;
    7777           0 :     kf->first_fv = __FontViewCreate(kf->sf); kf->first_fv->b.container = (struct fvcontainer *) kf;
    7778           0 :     kf->second_fv = __FontViewCreate(kf->sf); kf->second_fv->b.container = (struct fvcontainer *) kf;
    7779             : 
    7780           0 :     kf->infoh = infoh = 1+GDrawPointsToPixels(NULL,fv_fontsize);
    7781           0 :     kf->first_fv->mbh = kf->mbh;
    7782           0 :     pos.x = 0; pos.y = kf->mbh+infoh+kf->fh+4;
    7783           0 :     pos.width = 16*kf->first_fv->cbw+1;
    7784           0 :     pos.height = 4*kf->first_fv->cbh+1;
    7785             : 
    7786           0 :     GDrawSetUserData(dw,kf->first_fv);
    7787           0 :     FVCopyInnards(kf->first_fv,&pos,infoh,fvorig,dw,kf->def_layer,(struct fvcontainer *) kf);
    7788           0 :     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 */
    7789           0 :     kf->second_fv->mbh = kf->mbh;
    7790           0 :     kf->label2_y = pos.y + pos.height+2;
    7791           0 :     pos.y = kf->label2_y + kf->fh + 2;
    7792           0 :     GDrawSetUserData(dw,kf->second_fv);
    7793           0 :     FVCopyInnards(kf->second_fv,&pos,infoh,fvorig,dw,kf->def_layer,(struct fvcontainer *) kf);
    7794             : 
    7795           0 :     kf->sf->display_size = ps;
    7796             : 
    7797           0 :     GGadgetGetSize(kf->second_fv->vsb,&sbsize);
    7798           0 :     gsize.x = gsize.y = 0;
    7799           0 :     gsize.width = pos.width + sbsize.width;
    7800           0 :     gsize.height = pos.y+pos.height;
    7801           0 :     GGadgetSetDesiredSize(drawable,NULL,&gsize);
    7802           0 : }
    7803             : /* ************************************************************************** */
    7804             : /* ************************** Glyph Set from Selection ********************** */
    7805             : /* ************************************************************************** */
    7806             : 
    7807             : struct gsd {
    7808             :     struct fvcontainer base;
    7809             :     FontView *fv;
    7810             :     int done;
    7811             :     int good;
    7812             :     GWindow gw;
    7813             : };
    7814             : 
    7815           0 : static void gs_activateMe(struct fvcontainer *UNUSED(fvc), FontViewBase *UNUSED(fvb)) {
    7816             :     /*struct gsd *gs = (struct gsd *) fvc;*/
    7817           0 : }
    7818             : 
    7819           0 : static void gs_charEvent(struct fvcontainer *fvc,void *event) {
    7820           0 :     struct gsd *gs = (struct gsd *) fvc;
    7821           0 :     FVChar(gs->fv,event);
    7822           0 : }
    7823             : 
    7824           0 : static void gs_doClose(struct fvcontainer *fvc) {
    7825           0 :     struct gsd *gs = (struct gsd *) fvc;
    7826           0 :     gs->done = true;
    7827           0 : }
    7828             : 
    7829             : #define CID_Guts        1000
    7830             : #define CID_TopBox      1001
    7831             : 
    7832           0 : static void gs_doResize(struct fvcontainer *fvc, FontViewBase *UNUSED(fvb),
    7833             :         int width, int height) {
    7834           0 :     struct gsd *gs = (struct gsd *) fvc;
    7835             :     /*FontView *fv = (FontView *) fvb;*/
    7836             :     GRect size;
    7837             : 
    7838           0 :     memset(&size,0,sizeof(size));
    7839           0 :     size.width = width; size.height = height;
    7840           0 :     GGadgetSetDesiredSize(GWidgetGetControl(gs->gw,CID_Guts),
    7841             :             NULL,&size);
    7842           0 :     GHVBoxFitWindow(GWidgetGetControl(gs->gw,CID_TopBox));
    7843           0 : }
    7844             : 
    7845             : static struct fvcontainer_funcs glyphset_funcs = {
    7846             :     fvc_glyphset,
    7847             :     true,                       /* Modal dialog. No charviews, etc. */
    7848             :     gs_activateMe,
    7849             :     gs_charEvent,
    7850             :     gs_doClose,
    7851             :     gs_doResize
    7852             : };
    7853             : 
    7854           0 : static int GS_OK(GGadget *g, GEvent *e) {
    7855             : 
    7856           0 :     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
    7857           0 :         struct gsd *gs = GDrawGetUserData(GGadgetGetWindow(g));
    7858           0 :         gs->done = true;
    7859           0 :         gs->good = true;
    7860             :     }
    7861           0 : return( true );
    7862             : }
    7863             : 
    7864           0 : static int GS_Cancel(GGadget *g, GEvent *e) {
    7865             :     struct gsd *gs;
    7866             : 
    7867           0 :     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
    7868           0 :         gs = GDrawGetUserData(GGadgetGetWindow(g));
    7869           0 :         gs->done = true;
    7870             :     }
    7871           0 : return( true );
    7872             : }
    7873             : 
    7874           0 : static void gs_sizeSet(struct gsd *gs,GWindow dw) {
    7875             :     GRect size, gsize;
    7876             :     int width, height, y;
    7877             :     int cc, rc, topchar;
    7878             :     GRect subsize;
    7879           0 :     FontView *fv = gs->fv;
    7880             : 
    7881           0 :     if ( gs->fv->vsb==NULL )
    7882           0 : return;
    7883             : 
    7884           0 :     GDrawGetSize(dw,&size);
    7885           0 :     GGadgetGetSize(gs->fv->vsb,&gsize);
    7886           0 :     width = size.width - gsize.width;
    7887           0 :     height = size.height - gs->fv->mbh - gs->fv->infoh;
    7888             : 
    7889           0 :     y = gs->fv->mbh + gs->fv->infoh;
    7890             : 
    7891           0 :     topchar = fv->rowoff*fv->colcnt;
    7892           0 :     cc = (width-1) / fv->cbw;
    7893           0 :     if ( cc<1 ) cc=1;
    7894           0 :     rc = (height-1)/ fv->cbh;
    7895           0 :     if ( rc<1 ) rc = 1;
    7896           0 :     subsize.x = 0; subsize.y = 0;
    7897           0 :     subsize.width = cc*fv->cbw + 1;
    7898           0 :     subsize.height = rc*fv->cbh + 1;
    7899           0 :     GDrawResize(fv->v,subsize.width,subsize.height);
    7900           0 :     GDrawMove(fv->v,0,y);
    7901           0 :     GGadgetMove(fv->vsb,subsize.width,y);
    7902           0 :     GGadgetResize(fv->vsb,gsize.width,subsize.height);
    7903             : 
    7904           0 :     fv->colcnt = cc; fv->rowcnt = rc;
    7905           0 :     fv->width = subsize.width; fv->height = subsize.height;
    7906           0 :     fv->rowltot = (fv->b.map->enccount+fv->colcnt-1)/fv->colcnt;
    7907           0 :     GScrollBarSetBounds(fv->vsb,0,fv->rowltot,fv->rowcnt);
    7908           0 :     fv->rowoff = topchar/fv->colcnt;
    7909           0 :     if ( fv->rowoff>=fv->rowltot-fv->rowcnt )
    7910           0 :         fv->rowoff = fv->rowltot-fv->rowcnt;
    7911           0 :     if ( fv->rowoff<0 ) fv->rowoff =0;
    7912           0 :     GScrollBarSetPos(fv->vsb,fv->rowoff);
    7913             : 
    7914           0 :     GDrawRequestExpose(fv->v,NULL,true);
    7915             : }
    7916             : 
    7917           0 : static int gs_sub_e_h(GWindow pixmap, GEvent *event) {
    7918             :     FontView *active_fv;
    7919             :     struct gsd *gs;
    7920             : 
    7921           0 :     if ( event->type==et_destroy )
    7922           0 : return( true );
    7923             : 
    7924           0 :     active_fv = (FontView *) GDrawGetUserData(pixmap);
    7925           0 :     gs = (struct gsd *) (active_fv->b.container);
    7926             : 
    7927           0 :     if (( event->type==et_mouseup || event->type==et_mousedown ) &&
    7928           0 :             (event->u.mouse.button>=4 && event->u.mouse.button<=7) ) {
    7929           0 : return( GGadgetDispatchEvent(active_fv->vsb,event));
    7930             :     }
    7931             : 
    7932             : 
    7933           0 :     switch ( event->type ) {
    7934             :       case et_expose:
    7935           0 :         FVDrawInfo(active_fv,pixmap,event);
    7936           0 :       break;
    7937             :       case et_char:
    7938           0 :         gs_charEvent(&gs->base,event);
    7939           0 :       break;
    7940             :       case et_mousedown:
    7941           0 : return(false);
    7942             :       break;
    7943             :       case et_mouseup: case et_mousemove:
    7944           0 : return(false);
    7945             :       case et_resize:
    7946           0 :         gs_sizeSet(gs,pixmap);
    7947           0 :       break;
    7948             :     }
    7949           0 : return( true );
    7950             : }
    7951             : 
    7952           0 : static int gs_e_h(GWindow gw, GEvent *event) {
    7953           0 :     struct gsd *gs = GDrawGetUserData(gw);
    7954             : 
    7955           0 :     switch ( event->type ) {
    7956             :       case et_close:
    7957           0 :         gs->done = true;
    7958           0 :       break;
    7959             :       case et_char:
    7960           0 :         FVChar(gs->fv,event);
    7961           0 :       break;
    7962             :     }
    7963           0 : return( true );
    7964             : }
    7965             : 
    7966           0 : char *GlyphSetFromSelection(SplineFont *sf,int def_layer,char *current) {
    7967             :     struct gsd gs;
    7968             :     GRect pos;
    7969             :     GWindowAttrs wattrs;
    7970             :     GGadgetCreateData gcd[5], boxes[3];
    7971             :     GGadgetCreateData *varray[21], *buttonarray[8];
    7972             :     GTextInfo label[5];
    7973             :     int i,j,k,guts_row,gid,enc,len;
    7974             :     char *ret, *rpt;
    7975             :     SplineChar *sc;
    7976             :     GGadget *drawable;
    7977             :     GWindow dw;
    7978             :     GGadgetData gd;
    7979             :     GRect gsize, sbsize;
    7980             :     int infoh, mbh;
    7981             :     int ps;
    7982           0 :     FontView *fvorig = (FontView *) sf->fv;
    7983             :     GGadget *mb;
    7984             :     char *start, *pt; int ch;
    7985             : 
    7986           0 :     FontViewInit();
    7987             : 
    7988           0 :     memset(&wattrs,0,sizeof(wattrs));
    7989           0 :     memset(&gcd,0,sizeof(gcd));
    7990           0 :     memset(&boxes,0,sizeof(boxes));
    7991           0 :     memset(&label,0,sizeof(label));
    7992           0 :     memset(&gs,0,sizeof(gs));
    7993             : 
    7994           0 :     gs.base.funcs = &glyphset_funcs;
    7995             : 
    7996           0 :     wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_undercursor|wam_isdlg|wam_restrict;
    7997           0 :     wattrs.event_masks = ~(1<<et_charup);
    7998           0 :     wattrs.restrict_input_to_me = true;
    7999           0 :     wattrs.undercursor = 1;
    8000           0 :     wattrs.cursor = ct_pointer;
    8001           0 :     wattrs.utf8_window_title = _("Glyph Set by Selection") ;
    8002           0 :     wattrs.is_dlg = true;
    8003           0 :     pos.x = pos.y = 0;
    8004           0 :     pos.width = 100;
    8005           0 :     pos.height = 100;
    8006           0 :     gs.gw = GDrawCreateTopWindow(NULL,&pos,gs_e_h,&gs,&wattrs);
    8007             : 
    8008           0 :     i = j = 0;
    8009             : 
    8010           0 :     guts_row = j/2;
    8011           0 :     gcd[i].gd.flags = gg_enabled|gg_visible;
    8012           0 :     gcd[i].gd.cid = CID_Guts;
    8013           0 :     gcd[i].gd.u.drawable_e_h = gs_sub_e_h;
    8014           0 :     gcd[i].creator = GDrawableCreate;
    8015           0 :     varray[j++] = &gcd[i++]; varray[j++] = NULL;
    8016             : 
    8017           0 :     label[i].text = (unichar_t *) _("Select glyphs in the font view above.\nThe selected glyphs become your glyph class.");
    8018           0 :     label[i].text_is_1byte = true;
    8019           0 :     gcd[i].gd.label = &label[i];
    8020           0 :     gcd[i].gd.flags = gg_enabled|gg_visible;
    8021           0 :     gcd[i].creator = GLabelCreate;
    8022           0 :     varray[j++] = &gcd[i++]; varray[j++] = NULL;
    8023             : 
    8024           0 :     gcd[i].gd.flags = gg_visible | gg_enabled | gg_but_default;
    8025           0 :     label[i].text = (unichar_t *) _("_OK");
    8026           0 :     label[i].text_is_1byte = true;
    8027           0 :     label[i].text_in_resource = true;
    8028           0 :     gcd[i].gd.label = &label[i];
    8029           0 :     gcd[i].gd.handle_controlevent = GS_OK;
    8030           0 :     gcd[i++].creator = GButtonCreate;
    8031             : 
    8032           0 :     gcd[i].gd.flags = gg_visible | gg_enabled | gg_but_cancel;
    8033           0 :     label[i].text = (unichar_t *) _("_Cancel");
    8034           0 :     label[i].text_is_1byte = true;
    8035           0 :     label[i].text_in_resource = true;
    8036           0 :     gcd[i].gd.label = &label[i];
    8037           0 :     gcd[i].gd.handle_controlevent = GS_Cancel;
    8038           0 :     gcd[i++].creator = GButtonCreate;
    8039             : 
    8040           0 :     buttonarray[0] = GCD_Glue; buttonarray[1] = &gcd[i-2]; buttonarray[2] = GCD_Glue;
    8041           0 :     buttonarray[3] = GCD_Glue; buttonarray[4] = &gcd[i-1]; buttonarray[5] = GCD_Glue;
    8042           0 :     buttonarray[6] = NULL;
    8043           0 :     boxes[2].gd.flags = gg_enabled|gg_visible;
    8044           0 :     boxes[2].gd.u.boxelements = buttonarray;
    8045           0 :     boxes[2].creator = GHBoxCreate;
    8046           0 :     varray[j++] = &boxes[2]; varray[j++] = NULL; varray[j++] = NULL;
    8047             : 
    8048           0 :     boxes[0].gd.pos.x = boxes[0].gd.pos.y = 2;
    8049           0 :     boxes[0].gd.flags = gg_enabled|gg_visible;
    8050           0 :     boxes[0].gd.u.boxelements = varray;
    8051           0 :     boxes[0].gd.cid = CID_TopBox;
    8052           0 :     boxes[0].creator = GHVGroupCreate;
    8053             : 
    8054           0 :     GGadgetsCreate(gs.gw,boxes);
    8055             : 
    8056           0 :     GHVBoxSetExpandableRow(boxes[0].ret,guts_row);
    8057           0 :     GHVBoxSetExpandableCol(boxes[2].ret,gb_expandgluesame);
    8058             : 
    8059           0 :     drawable = GWidgetGetControl(gs.gw,CID_Guts);
    8060           0 :     dw = GDrawableGetWindow(drawable);
    8061             : 
    8062           0 :     memset(&gd,0,sizeof(gd));
    8063           0 :     gd.flags = gg_visible | gg_enabled;
    8064           0 :     helplist[0].invoke = FVMenuContextualHelp;
    8065           0 :     gd.u.menu2 = mblist;
    8066           0 :     mb = GMenu2BarCreate( dw, &gd, NULL);
    8067           0 :     GGadgetGetSize(mb,&gsize);
    8068           0 :     mbh = gsize.height;
    8069             : 
    8070           0 :     ps = sf->display_size; sf->display_size = -24;
    8071           0 :     gs.fv = __FontViewCreate(sf);
    8072             : 
    8073           0 :     infoh = 1+GDrawPointsToPixels(NULL,fv_fontsize);
    8074           0 :     gs.fv->mbh = mbh;
    8075           0 :     pos.x = 0; pos.y = mbh+infoh;
    8076           0 :     pos.width = 16*gs.fv->cbw+1;
    8077           0 :     pos.height = 4*gs.fv->cbh+1;
    8078             : 
    8079           0 :     GDrawSetUserData(dw,gs.fv);
    8080           0 :     FVCopyInnards(gs.fv,&pos,infoh,fvorig,dw,def_layer,(struct fvcontainer *) &gs);
    8081           0 :     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 */
    8082           0 :     memset(gs.fv->b.selected,0,gs.fv->b.map->enccount);
    8083           0 :     if ( current!=NULL && strcmp(current,_("{Everything Else}"))!=0 ) {
    8084           0 :         int first = true;
    8085           0 :         for ( start = current; *start==' '; ++start );
    8086           0 :         while ( *start ) {
    8087           0 :             for ( pt=start; *pt!='\0' && *pt!=' '; ++pt );
    8088           0 :             ch = *pt; *pt='\0';
    8089           0 :             sc = SFGetChar(sf,-1,start);
    8090           0 :             *pt = ch;
    8091           0 :             if ( sc!=NULL && (enc = gs.fv->b.map->backmap[sc->orig_pos])!=-1 ) {
    8092           0 :                 gs.fv->b.selected[enc] = true;
    8093           0 :                 if ( first ) {
    8094           0 :                     first = false;
    8095           0 :                     gs.fv->rowoff = enc/gs.fv->colcnt;
    8096             :                 }
    8097             :             }
    8098           0 :             start = pt;
    8099           0 :             while ( *start==' ' ) ++start;
    8100             :         }
    8101             :     }
    8102           0 :     sf->display_size = ps;
    8103             : 
    8104           0 :     GGadgetGetSize(gs.fv->vsb,&sbsize);
    8105           0 :     gsize.x = gsize.y = 0;
    8106           0 :     gsize.width = pos.width + sbsize.width;
    8107           0 :     gsize.height = pos.y+pos.height;
    8108           0 :     GGadgetSetDesiredSize(drawable,NULL,&gsize);
    8109             : 
    8110           0 :     GHVBoxFitWindow(boxes[0].ret);
    8111           0 :     GDrawSetVisible(gs.gw,true);
    8112           0 :     while ( !gs.done )
    8113           0 :         GDrawProcessOneEvent(NULL);
    8114             : 
    8115           0 :     ret = rpt = NULL;
    8116           0 :     if ( gs.good ) {
    8117           0 :         for ( k=0; k<2; ++k ) {
    8118           0 :             len = 0;
    8119           0 :             for ( enc=0; enc<gs.fv->b.map->enccount; ++enc ) {
    8120           0 :                 if ( gs.fv->b.selected[enc] &&
    8121           0 :                         (gid=gs.fv->b.map->map[enc])!=-1 &&
    8122           0 :                         (sc = sf->glyphs[gid])!=NULL ) {
    8123           0 :                     char *repr = SCNameUniStr( sc );
    8124           0 :                     if ( ret==NULL )
    8125           0 :                         len += strlen(repr)+2;
    8126             :                     else {
    8127           0 :                         strcpy(rpt,repr);
    8128           0 :                         rpt += strlen( repr );
    8129           0 :                         free(repr);
    8130           0 :                         *rpt++ = ' ';
    8131             :                     }
    8132             :                 }
    8133             :             }
    8134           0 :             if ( k==0 )
    8135           0 :                 ret = rpt = malloc(len+1);
    8136           0 :             else if ( rpt!=ret && rpt[-1]==' ' )
    8137           0 :                 rpt[-1]='\0';
    8138             :             else
    8139           0 :                 *rpt='\0';
    8140             :         }
    8141             :     }
    8142           0 :     FontViewFree(&gs.fv->b);
    8143           0 :     GDrawSetUserData(gs.gw,NULL);
    8144           0 :     GDrawSetUserData(dw,NULL);
    8145           0 :     GDrawDestroyWindow(gs.gw);
    8146           0 : return( ret );
    8147             : }
    8148             : 
    8149             : 
    8150             : /****************************************/
    8151             : /****************************************/
    8152             : /****************************************/
    8153             : 
    8154           0 : int FontViewFind_byXUID( FontViewBase* fv, void* udata )
    8155             : {
    8156           0 :     if( !fv || !fv->sf )
    8157           0 :         return 0;
    8158           0 :     return !strcmp( fv->sf->xuid, (char*)udata );
    8159             : }
    8160             : 
    8161           0 : int FontViewFind_byXUIDConnected( FontViewBase* fv, void* udata )
    8162             : {
    8163           0 :     if( !fv || !fv->sf )
    8164           0 :         return 0;
    8165           0 :     return ( fv->collabState == cs_server || fv->collabState == cs_client )
    8166           0 :         && fv->sf->xuid
    8167           0 :         && !strcmp( fv->sf->xuid, (char*)udata );
    8168             : }
    8169             : 
    8170           0 : int FontViewFind_byCollabPtr( FontViewBase* fv, void* udata )
    8171             : {
    8172           0 :     if( !fv || !fv->sf )
    8173           0 :         return 0;
    8174           0 :     return fv->collabClient == udata;
    8175             : }
    8176             : 
    8177           0 : int FontViewFind_byCollabBasePort( FontViewBase* fv, void* udata )
    8178             : {
    8179           0 :     if( !fv || !fv->sf || !fv->collabClient )
    8180           0 :         return 0;
    8181           0 :     int port = (int)(intptr_t)udata;
    8182           0 :     return port == collabclient_getBasePort( fv->collabClient );
    8183             : }
    8184             : 
    8185           0 : int FontViewFind_bySplineFont( FontViewBase* fv, void* udata )
    8186             : {
    8187           0 :     if( !fv || !fv->sf )
    8188           0 :         return 0;
    8189           0 :     return fv->sf == udata;
    8190             : }
    8191             : 
    8192           0 : static int FontViewFind_ActiveWindow( FontViewBase* fvb, void* udata )
    8193             : {
    8194           0 :     FontView* fv = (FontView*)fvb;
    8195           0 :     return( fv->gw == udata || fv->v == udata );
    8196             : }
    8197             : 
    8198           0 : FontViewBase* FontViewFindActive()
    8199             : {
    8200           0 :     return (FontViewBase*) ActiveFontView;
    8201             :     /* GWindow w = GWindowGetCurrentFocusTopWindow(); */
    8202             :     /* FontViewBase* ret = FontViewFind( FontViewFind_ActiveWindow, w ); */
    8203             :     /* return ret; */
    8204             : }
    8205             : 
    8206             : 
    8207             : 
    8208           0 : FontViewBase* FontViewFind( int (*testFunc)( FontViewBase*, void* udata ), void* udata )
    8209             : {
    8210             :     FontViewBase *fv;
    8211           0 :     printf("FontViewFind(top) fv_list:%p\n", fv_list );
    8212           0 :     for ( fv = (FontViewBase*)fv_list; fv!=NULL; fv=fv->next )
    8213             :     {
    8214           0 :         if( testFunc( fv, udata ))
    8215           0 :             return fv;
    8216             :     }
    8217           0 :     return 0;
    8218             : }
    8219             : 
    8220           0 : FontView* FontViewFindUI( int (*testFunc)( FontViewBase*, void* udata ), void* udata )
    8221             : {
    8222           0 :     return (FontView*)FontViewFind( testFunc, udata );
    8223             : }
    8224             : 
    8225             : 
    8226             : /****************************************/
    8227             : /****************************************/
    8228             : /****************************************/
    8229             : 
    8230             : /* local variables: */
    8231             : /* tab-width: 8     */
    8232             : /* end:             */

Generated by: LCOV version 1.10