LCOV - code coverage report
Current view: top level - fontforgeexe - charinfo.c (source / functions) Hit Total Coverage
Test: FontForge coverage report 2017-08-04 01:21:11+02:00 (commit d35f7e4107a9e1db65cce47c468fcc914cecb8fd) Lines: 0 3601 0.0 %
Date: 2017-08-04 Functions: 0 107 0.0 %

          Line data    Source code
       1             : /* -*- coding: utf-8 -*- */
       2             : /* Copyright (C) 2000-2012 by George Williams */
       3             : /*
       4             :  * Redistribution and use in source and binary forms, with or without
       5             :  * modification, are permitted provided that the following conditions are met:
       6             : 
       7             :  * Redistributions of source code must retain the above copyright notice, this
       8             :  * list of conditions and the following disclaimer.
       9             : 
      10             :  * Redistributions in binary form must reproduce the above copyright notice,
      11             :  * this list of conditions and the following disclaimer in the documentation
      12             :  * and/or other materials provided with the distribution.
      13             : 
      14             :  * The name of the author may not be used to endorse or promote products
      15             :  * derived from this software without specific prior written permission.
      16             : 
      17             :  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
      18             :  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
      19             :  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
      20             :  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
      21             :  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
      22             :  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
      23             :  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
      24             :  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
      25             :  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
      26             :  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      27             :  */
      28             : 
      29             : #include "autowidth2.h"
      30             : #include "cvundoes.h"
      31             : #include "fontforgeui.h"
      32             : #include "fvcomposite.h"
      33             : #include "fvfonts.h"
      34             : #include "lookups.h"
      35             : #include "namelist.h"
      36             : #include "splinefill.h"
      37             : #include "splineutil.h"
      38             : #include "tottfgpos.h"
      39             : #include <ustring.h>
      40             : #include <math.h>
      41             : #include <utype.h>
      42             : #include <chardata.h>
      43             : #include "ttf.h"              /* For MAC_DELETED_GLYPH_NAME */
      44             : #include <gkeysym.h>
      45             : #include "gutils/unicodelibinfo.h"
      46             : 
      47             : extern int lookup_hideunused;
      48             : 
      49             : static int last_gi_aspect = 0;
      50             : 
      51             : typedef struct charinfo {
      52             :     CharView *cv;
      53             :     EncMap *map;
      54             :     SplineChar *sc, *cachedsc;
      55             :     int def_layer;
      56             :     SplineChar *oldsc;          /* oldsc->charinfo will point to us. Used to keep track of that pointer */
      57             :     int enc;
      58             :     GWindow gw;
      59             :     int done, first, changed;
      60             :     struct lookup_subtable *old_sub;
      61             :     int r,c;
      62             :     int lc_seen, lc_aspect, vert_aspect;
      63             :     Color last, real_last;
      64             :     struct splinecharlist *changes;
      65             :     int name_change, uni_change;
      66             : } CharInfo;
      67             : 
      68             : #define CI_Width        218
      69             : #define CI_Height       292
      70             : 
      71             : #define CID_UName       1001
      72             : #define CID_UValue      1002
      73             : #define CID_UChar       1003
      74             : #define CID_Cancel      1005
      75             : #define CID_ComponentMsg        1006
      76             : #define CID_Components  1007
      77             : #define CID_Comment     1008
      78             : #define CID_Color       1009
      79             : #define CID_GClass      1010
      80             : #define CID_Tabs        1011
      81             : 
      82             : #define CID_TeX_Height  1012
      83             : #define CID_TeX_Depth   1013
      84             : #define CID_TeX_Italic  1014
      85             : #define CID_HorAccent   1015
      86             : /* Room for one more here, if we need it */
      87             : #define CID_TeX_HeightD 1017
      88             : #define CID_TeX_DepthD  1018
      89             : #define CID_TeX_ItalicD 1019
      90             : #define CID_HorAccentD  1020
      91             : 
      92             : #define CID_ItalicDevTab        1022
      93             : #define CID_AccentDevTab        1023
      94             : 
      95             : #define CID_IsExtended  1024
      96             : #define CID_DefLCCount  1040
      97             : #define CID_LCCount     1041
      98             : #define CID_LCCountLab  1042
      99             : 
     100             : #define CID_UnlinkRmOverlap     1045
     101             : #define CID_AltUni      1046
     102             : 
     103             : /* Offsets for repeated fields. add 100*index (index<=6) */
     104             : #define CID_List        1220
     105             : #define CID_New         1221
     106             : #define CID_Delete      1222
     107             : #define CID_Edit        1223
     108             : 
     109             : #define CID_PST         1111
     110             : #define CID_Tag         1112
     111             : #define CID_Contents    1113
     112             : #define CID_SelectResults       1114
     113             : #define CID_MergeResults        1115
     114             : #define CID_RestrictSelection   1116
     115             : 
     116             : /* Offsets for repeated fields. add 100*index (index<2) */ /* 0=>Vert, 1=>Hor */
     117             : #define CID_VariantList         2000
     118             : #define CID_ExtItalicCor        2001
     119             : #define CID_ExtItalicDev        2002
     120             : #define CID_ExtensionList       2003
     121             : 
     122             : #define CID_IsTileMargin        3001
     123             : #define CID_TileMargin          3002
     124             : #define CID_IsTileBBox          3003
     125             : #define CID_TileBBoxMinX        3004
     126             : #define CID_TileBBoxMinY        3005
     127             : #define CID_TileBBoxMaxX        3006
     128             : #define CID_TileBBoxMaxY        3007
     129             : 
     130             : #define SIM_DX          1
     131             : #define SIM_DY          3
     132             : #define SIM_DX_ADV      5
     133             : #define SIM_DY_ADV      7
     134             : #define PAIR_DX1        2
     135             : #define PAIR_DY1        4
     136             : #define PAIR_DX_ADV1    6
     137             : #define PAIR_DY_ADV1    8
     138             : #define PAIR_DX2        10
     139             : #define PAIR_DY2        12
     140             : #define PAIR_DX_ADV2    14
     141             : #define PAIR_DY_ADV2    16
     142             : 
     143             : static GTextInfo glyphclasses[] = {
     144             :     { (unichar_t *) N_("Automatic"), NULL, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0' },
     145             :     { (unichar_t *) N_("No Class"), NULL, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0' },
     146             :     { (unichar_t *) N_("Base Glyph"), NULL, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0' },
     147             :     { (unichar_t *) N_("Base Lig"), NULL, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0' },
     148             :     { (unichar_t *) N_("Mark"), NULL, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0' },
     149             :     { (unichar_t *) N_("Component"), NULL, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0' },
     150             :     GTEXTINFO_EMPTY
     151             : };
     152             : 
     153             : #define CUSTOM_COLOR    9
     154             : #define COLOR_CHOOSE    (-10)
     155             : static GTextInfo std_colors[] = {
     156             :     { (unichar_t *) N_("Color|Choose..."), NULL, 0, 0, (void *) COLOR_CHOOSE, NULL, 0, 1, 0, 0, 0, 0, 1, 0, 0, '\0' },
     157             :     { (unichar_t *) N_("Color|Default"), &def_image, 0, 0, (void *) COLOR_DEFAULT, NULL, 0, 1, 0, 0, 0, 0, 1, 0, 0, '\0' },
     158             :     { NULL, &white_image, 0, 0, (void *) 0xffffff, NULL, 0, 1, 0, 0, 0, 0, 0, 0, 0, '\0' },
     159             :     { NULL, &red_image, 0, 0, (void *) 0xff0000, NULL, 0, 1, 0, 0, 0, 0, 0, 0, 0, '\0' },
     160             :     { NULL, &green_image, 0, 0, (void *) 0x00ff00, NULL, 0, 1, 0, 0, 0, 0, 0, 0, 0, '\0' },
     161             :     { NULL, &blue_image, 0, 0, (void *) 0x0000ff, NULL, 0, 1, 0, 0, 0, 0, 0, 0, 0, '\0' },
     162             :     { NULL, &yellow_image, 0, 0, (void *) 0xffff00, NULL, 0, 1, 0, 0, 0, 0, 0, 0, 0, '\0' },
     163             :     { NULL, &cyan_image, 0, 0, (void *) 0x00ffff, NULL, 0, 1, 0, 0, 0, 0, 0, 0, 0, '\0' },
     164             :     { NULL, &magenta_image, 0, 0, (void *) 0xff00ff, NULL, 0, 1, 0, 0, 0, 0, 0, 0, 0, '\0' },
     165             :     { NULL, NULL, 0, 0, (void *) 0x000000, NULL, 0, 1, 0, 0, 0, 0, 0, 0, 0, '\0' },
     166             :     GTEXTINFO_EMPTY
     167             : };
     168             : 
     169             : static char *newstrings[] = { N_("New Positioning"), N_("New Pair Position"),
     170             :         N_("New Substitution Variant"),
     171             :         N_("New Alternate List"), N_("New Multiple List"), N_("New Ligature"), NULL };
     172             : 
     173           0 : static unichar_t *CounterMaskLine(SplineChar *sc, HintMask *hm) {
     174           0 :     unichar_t *textmask = NULL;
     175             :     int j,k,len;
     176             :     StemInfo *h;
     177             :     char buffer[100];
     178             : 
     179           0 :     for ( j=0; j<2; ++j ) {
     180           0 :         len = 0;
     181           0 :         for ( h=sc->hstem, k=0; h!=NULL && k<HntMax; h=h->next, ++k ) {
     182           0 :             if ( (*hm)[k>>3]& (0x80>>(k&7)) ) {
     183           0 :                 sprintf( buffer, "H<%g,%g>, ",
     184           0 :                         rint(h->start*100)/100, rint(h->width*100)/100 );
     185           0 :                 if ( textmask!=NULL )
     186           0 :                     uc_strcpy(textmask+len,buffer);
     187           0 :                 len += strlen(buffer);
     188             :             }
     189             :         }
     190           0 :         for ( h=sc->vstem; h!=NULL && k<HntMax; h=h->next, ++k ) {
     191           0 :             if ( (*hm)[k>>3]& (0x80>>(k&7)) ) {
     192           0 :                 sprintf( buffer, "V<%g,%g>, ",
     193           0 :                         rint(h->start*100)/100, rint(h->width*100)/100 );
     194           0 :                 if ( textmask!=NULL )
     195           0 :                     uc_strcpy(textmask+len,buffer);
     196           0 :                 len += strlen(buffer);
     197             :             }
     198             :         }
     199           0 :         if ( textmask==NULL ) {
     200           0 :             textmask = malloc((len+1)*sizeof(unichar_t));
     201           0 :             *textmask = '\0';
     202             :         }
     203             :     }
     204           0 :     if ( len>1 && textmask[len-2]==',' )
     205           0 :         textmask[len-2] = '\0';
     206           0 : return( textmask );
     207             : }
     208             : 
     209             : #define CID_HintMask    2020
     210             : #define HI_Width        200
     211             : #define HI_Height       260
     212             : 
     213             : struct hi_data {
     214             :     int done, ok, empty;
     215             :     GWindow gw;
     216             :     HintMask *cur;
     217             :     SplineChar *sc;
     218             : };
     219             : 
     220           0 : static int HI_Ok(GGadget *g, GEvent *e) {
     221           0 :     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
     222           0 :         struct hi_data *hi = GDrawGetUserData(GGadgetGetWindow(g));
     223             :         int32 i, len;
     224           0 :         GTextInfo **ti = GGadgetGetList(GWidgetGetControl(hi->gw,CID_HintMask),&len);
     225             : 
     226           0 :         for ( i=0; i<len; ++i )
     227           0 :             if ( ti[i]->selected )
     228           0 :         break;
     229             : 
     230           0 :         memset(hi->cur,0,sizeof(HintMask));
     231           0 :         if ( i==len ) {
     232           0 :             hi->empty = true;
     233             :         } else {
     234           0 :             for ( i=0; i<len; ++i )
     235           0 :                 if ( ti[i]->selected )
     236           0 :                     (*hi->cur)[i>>3] |= (0x80>>(i&7));
     237             :         }
     238           0 :         PI_ShowHints(hi->sc,GWidgetGetControl(hi->gw,CID_HintMask),false);
     239             : 
     240           0 :         hi->done = true;
     241           0 :         hi->ok = true;
     242             :     }
     243           0 : return( true );
     244             : }
     245             : 
     246           0 : static void HI_DoCancel(struct hi_data *hi) {
     247           0 :     hi->done = true;
     248           0 :     PI_ShowHints(hi->sc,GWidgetGetControl(hi->gw,CID_HintMask),false);
     249           0 : }
     250             : 
     251           0 : static int HI_HintSel(GGadget *g, GEvent *e) {
     252           0 :     if ( e->type==et_controlevent && e->u.control.subtype == et_listselected ) {
     253           0 :         struct hi_data *hi = GDrawGetUserData(GGadgetGetWindow(g));
     254             : 
     255           0 :         PI_ShowHints(hi->sc,g,true);
     256             :         /* Do I need to check for overlap here? */
     257             :     }
     258           0 : return( true );
     259             : }
     260             : 
     261           0 : static int HI_Cancel(GGadget *g, GEvent *e) {
     262           0 :     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
     263           0 :         HI_DoCancel( GDrawGetUserData(GGadgetGetWindow(g)));
     264             :     }
     265           0 : return( true );
     266             : }
     267             : 
     268           0 : static int hi_e_h(GWindow gw, GEvent *event) {
     269           0 :     if ( event->type==et_close ) {
     270           0 :         HI_DoCancel( GDrawGetUserData(gw));
     271           0 :     } else if ( event->type==et_char ) {
     272           0 :         if ( event->u.chr.keysym == GK_F1 || event->u.chr.keysym == GK_Help ) {
     273           0 :             help("charinfo.html#Counters");
     274           0 : return( true );
     275             :         }
     276           0 : return( false );
     277             :     }
     278           0 : return( true );
     279             : }
     280             : 
     281           0 : static void CI_AskCounters(CharInfo *ci,HintMask *old) {
     282           0 :     HintMask *cur = old != NULL ? old : chunkalloc(sizeof(HintMask));
     283             :     struct hi_data hi;
     284             :     GWindowAttrs wattrs;
     285             :     GGadgetCreateData hgcd[5], *varray[11], *harray[8], boxes[3];
     286             :     GTextInfo hlabel[5];
     287           0 :     GGadget *list = GWidgetGetControl(ci->gw,CID_List+600);
     288             :     int j,k;
     289             :     GRect pos;
     290             : 
     291           0 :     memset(&hi,0,sizeof(hi));
     292           0 :     hi.cur = cur;
     293           0 :     hi.sc = ci->sc;
     294             : 
     295           0 :         memset(&wattrs,0,sizeof(wattrs));
     296           0 :         wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_undercursor|wam_isdlg|wam_restrict;
     297           0 :         wattrs.event_masks = ~(1<<et_charup);
     298           0 :         wattrs.restrict_input_to_me = 1;
     299           0 :         wattrs.undercursor = 1;
     300           0 :         wattrs.cursor = ct_pointer;
     301           0 :         wattrs.utf8_window_title = old==NULL?_("New Counter Mask"):_("Edit Counter Mask");
     302           0 :         wattrs.is_dlg = true;
     303           0 :         pos.width = GGadgetScale(GDrawPointsToPixels(NULL,HI_Width));
     304           0 :         pos.height = GDrawPointsToPixels(NULL,HI_Height);
     305           0 :         hi.gw = GDrawCreateTopWindow(NULL,&pos,hi_e_h,&hi,&wattrs);
     306             : 
     307             : 
     308           0 :         memset(hgcd,0,sizeof(hgcd));
     309           0 :         memset(boxes,0,sizeof(boxes));
     310           0 :         memset(hlabel,0,sizeof(hlabel));
     311             : 
     312           0 :         j=k=0;
     313             : 
     314           0 :         hgcd[j].gd.pos.x = 20-3; hgcd[j].gd.pos.y = HI_Height-31-3;
     315           0 :         hgcd[j].gd.pos.width = -1; hgcd[j].gd.pos.height = 0;
     316           0 :         hgcd[j].gd.flags = gg_visible | gg_enabled;
     317           0 :         hlabel[j].text = (unichar_t *) _("Select hints between which counters are formed");
     318           0 :         hlabel[j].text_is_1byte = true;
     319           0 :         hlabel[j].text_in_resource = true;
     320           0 :         hgcd[j].gd.label = &hlabel[j];
     321           0 :         varray[k++] = &hgcd[j]; varray[k++] = NULL;
     322           0 :         hgcd[j++].creator = GLabelCreate;
     323             : 
     324           0 :         hgcd[j].gd.pos.x = 5; hgcd[j].gd.pos.y = 5;
     325           0 :         hgcd[j].gd.pos.width = HI_Width-10; hgcd[j].gd.pos.height = HI_Height-45;
     326           0 :         hgcd[j].gd.flags = gg_visible | gg_enabled | gg_list_multiplesel;
     327           0 :         hgcd[j].gd.cid = CID_HintMask;
     328           0 :         hgcd[j].gd.u.list = SCHintList(ci->sc,old);
     329           0 :         hgcd[j].gd.handle_controlevent = HI_HintSel;
     330           0 :         varray[k++] = &hgcd[j]; varray[k++] = NULL;
     331           0 :         varray[k++] = GCD_Glue; varray[k++] = NULL;
     332           0 :         hgcd[j++].creator = GListCreate;
     333             : 
     334           0 :         hgcd[j].gd.pos.x = 20-3; hgcd[j].gd.pos.y = HI_Height-31-3;
     335           0 :         hgcd[j].gd.pos.width = -1; hgcd[j].gd.pos.height = 0;
     336           0 :         hgcd[j].gd.flags = gg_visible | gg_enabled | gg_but_default;
     337           0 :         hlabel[j].text = (unichar_t *) _("_OK");
     338           0 :         hlabel[j].text_is_1byte = true;
     339           0 :         hlabel[j].text_in_resource = true;
     340           0 :         hgcd[j].gd.label = &hlabel[j];
     341           0 :         hgcd[j].gd.handle_controlevent = HI_Ok;
     342           0 :         harray[0] = GCD_Glue; harray[1] = &hgcd[j]; harray[2] = GCD_Glue; harray[3] = GCD_Glue;
     343           0 :         hgcd[j++].creator = GButtonCreate;
     344             : 
     345           0 :         hgcd[j].gd.pos.x = -20; hgcd[j].gd.pos.y = HI_Height-31;
     346           0 :         hgcd[j].gd.pos.width = -1; hgcd[j].gd.pos.height = 0;
     347           0 :         hgcd[j].gd.flags = gg_visible | gg_enabled | gg_but_cancel;
     348           0 :         hlabel[j].text = (unichar_t *) _("_Cancel");
     349           0 :         hlabel[j].text_is_1byte = true;
     350           0 :         hlabel[j].text_in_resource = true;
     351           0 :         hgcd[j].gd.label = &hlabel[j];
     352           0 :         hgcd[j].gd.handle_controlevent = HI_Cancel;
     353           0 :         harray[4] = GCD_Glue; harray[5] = &hgcd[j]; harray[6] = GCD_Glue; harray[7] = NULL;
     354           0 :         hgcd[j++].creator = GButtonCreate;
     355             : 
     356           0 :         boxes[2].gd.flags = gg_enabled|gg_visible;
     357           0 :         boxes[2].gd.u.boxelements = harray;
     358           0 :         boxes[2].creator = GHBoxCreate;
     359           0 :         varray[k++] = &boxes[2]; varray[k++] = NULL; 
     360           0 :         varray[k++] = GCD_Glue; varray[k++] = NULL;
     361           0 :         varray[k] = NULL;
     362             : 
     363           0 :         boxes[0].gd.pos.x = boxes[0].gd.pos.y = 2;
     364           0 :         boxes[0].gd.flags = gg_enabled|gg_visible;
     365           0 :         boxes[0].gd.u.boxelements = varray;
     366           0 :         boxes[0].creator = GHVGroupCreate;
     367             : 
     368           0 :         GGadgetsCreate(hi.gw,boxes);
     369           0 :         GHVBoxSetExpandableRow(boxes[0].ret,1);
     370           0 :         GHVBoxSetExpandableCol(boxes[2].ret,gb_expandgluesame);
     371           0 :         GHVBoxFitWindow(boxes[0].ret);
     372           0 :         GTextInfoListFree(hgcd[0].gd.u.list);
     373             : 
     374           0 :         PI_ShowHints(hi.sc,hgcd[0].ret,true);
     375             : 
     376           0 :     GDrawSetVisible(hi.gw,true);
     377           0 :     while ( !hi.done )
     378           0 :         GDrawProcessOneEvent(NULL);
     379           0 :     GDrawDestroyWindow(hi.gw);
     380             : 
     381           0 :     if ( !hi.ok ) {
     382           0 :         if ( old==NULL ) chunkfree(cur,sizeof(HintMask));
     383           0 : return;         /* Cancelled */
     384           0 :     } else if ( old==NULL && hi.empty ) {
     385           0 :         if ( old==NULL ) chunkfree(cur,sizeof(HintMask));
     386           0 : return;         /* Didn't add anything new */
     387           0 :     } else if ( old==NULL ) {
     388           0 :         GListAddStr(list,CounterMaskLine(hi.sc,cur),cur);
     389           0 : return;
     390           0 :     } else if ( !hi.empty ) {
     391           0 :         GListReplaceStr(list,GGadgetGetFirstListSelectedItem(list),
     392             :                 CounterMaskLine(hi.sc,cur),cur);
     393           0 : return;
     394             :     } else {
     395           0 :         GListDelSelected(list);
     396           0 :         chunkfree(cur,sizeof(HintMask));
     397             :     }
     398             : }
     399             : 
     400           0 : static int CI_NewCounter(GGadget *g, GEvent *e) {
     401             :     CharInfo *ci;
     402             : 
     403           0 :     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
     404           0 :         ci = GDrawGetUserData(GGadgetGetWindow(g));
     405           0 :         CI_AskCounters(ci,NULL);
     406             :     }
     407           0 : return( true );
     408             : }
     409             : 
     410           0 : static int CI_EditCounter(GGadget *g, GEvent *e) {
     411             :     GTextInfo *ti;
     412             :     GGadget *list;
     413             :     CharInfo *ci;
     414             : 
     415           0 :     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
     416           0 :         ci = GDrawGetUserData(GGadgetGetWindow(g));
     417           0 :         list = GWidgetGetControl(GGadgetGetWindow(g),CID_List+6*100);
     418           0 :         if ( (ti = GGadgetGetListItemSelected(list))==NULL )
     419           0 : return( true );
     420           0 :         CI_AskCounters(ci,ti->userdata);
     421             :     }
     422           0 : return( true );
     423             : }
     424             : 
     425           0 : static int CI_DeleteCounter(GGadget *g, GEvent *e) {
     426             :     int32 len; int i,j, offset;
     427             :     GTextInfo **old, **new_;
     428             :     GGadget *list;
     429           0 :     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
     430           0 :         offset = GGadgetGetCid(g)-CID_Delete;
     431           0 :         list = GWidgetGetControl(GGadgetGetWindow(g),CID_List+offset);
     432           0 :         old = GGadgetGetList(list,&len);
     433           0 :         new_ = calloc(len+1,sizeof(GTextInfo *));
     434           0 :         for ( i=j=0; i<len; ++i )
     435           0 :             if ( !old[i]->selected ) {
     436           0 :                 new_[j] = (GTextInfo *) malloc(sizeof(GTextInfo));
     437           0 :                 *new_[j] = *old[i];
     438           0 :                 new_[j]->text = u_copy(new_[j]->text);
     439           0 :                 ++j;
     440             :             }
     441           0 :         new_[j] = (GTextInfo *) calloc(1,sizeof(GTextInfo));
     442           0 :         if ( offset==600 ) {
     443           0 :             for ( i=0; i<len; ++i ) if ( old[i]->selected )
     444           0 :                 chunkfree(old[i]->userdata,sizeof(HintMask));
     445             :         }
     446           0 :         GGadgetSetList(list,new_,false);
     447           0 :         GGadgetSetEnabled(GWidgetGetControl(GGadgetGetWindow(g),CID_Delete+offset),false);
     448           0 :         GGadgetSetEnabled(GWidgetGetControl(GGadgetGetWindow(g),CID_Edit+offset),false);
     449             :     }
     450           0 : return( true );
     451             : }
     452             : 
     453           0 : static int CI_CounterSelChanged(GGadget *g, GEvent *e) {
     454           0 :     if ( e->type==et_controlevent && e->u.control.subtype == et_listselected ) {
     455           0 :         CharInfo *ci = GDrawGetUserData(GGadgetGetWindow(g));
     456           0 :         int sel = GGadgetGetFirstListSelectedItem(g);
     457           0 :         int offset = GGadgetGetCid(g)-CID_List;
     458           0 :         GGadgetSetEnabled(GWidgetGetControl(ci->gw,CID_Delete+offset),sel!=-1);
     459           0 :         GGadgetSetEnabled(GWidgetGetControl(ci->gw,CID_Edit+offset),sel!=-1);
     460           0 :     } else if ( e->type==et_controlevent && e->u.control.subtype == et_listdoubleclick ) {
     461           0 :         CharInfo *ci = GDrawGetUserData(GGadgetGetWindow(g));
     462           0 :         int offset = GGadgetGetCid(g)-CID_List;
     463           0 :         e->u.control.subtype = et_buttonactivate;
     464           0 :         e->u.control.g = GWidgetGetControl(ci->gw,CID_Edit+offset);
     465           0 :         CI_EditCounter(e->u.control.g,e);
     466             :     }
     467           0 : return( true );
     468             : }
     469             : 
     470           0 : static int ParseUValue(GWindow gw, int cid, int minusoneok) {
     471           0 :     const unichar_t *ret = _GGadgetGetTitle(GWidgetGetControl(gw,cid));
     472             :     unichar_t *end;
     473             :     int val;
     474             : 
     475           0 :     if (( *ret=='U' || *ret=='u' ) && ret[1]=='+' )
     476           0 :         val = u_strtoul(ret+2,&end,16);
     477           0 :     else if ( *ret=='#' )
     478           0 :         val = u_strtoul(ret+1,&end,16);
     479             :     else
     480           0 :         val = u_strtoul(ret,&end,16);
     481           0 :     if ( val==-1 && minusoneok )
     482           0 : return( -1 );
     483           0 :     if ( *end || val<0 || val>0x10ffff ) {
     484           0 :         GGadgetProtest8( _("Unicode _Value:") );
     485           0 : return( -2 );
     486             :     }
     487           0 : return( val );
     488             : }
     489             : 
     490           0 : static void SetNameFromUnicode(GWindow gw,int cid,int val) {
     491             :     unichar_t *temp;
     492             :     char buf[100];
     493           0 :     CharInfo *ci = GDrawGetUserData(gw);
     494             : 
     495           0 :     temp = utf82u_copy(StdGlyphName(buf,val,ci->sc->parent->uni_interp,ci->sc->parent->for_new_glyphs));
     496           0 :     GGadgetSetTitle(GWidgetGetControl(gw,cid),temp);
     497           0 :     free(temp);
     498           0 : }
     499             : 
     500           0 : void SCInsertPST(SplineChar *sc,PST *new_) {
     501           0 :     new_->next = sc->possub;
     502           0 :     sc->possub = new_;
     503           0 : }
     504             : 
     505           0 : static int CI_NameCheck(const unichar_t *name) {
     506             :     int bad, questionable;
     507             :     extern int allow_utf8_glyphnames;
     508             :     char *buts[3];
     509           0 :     buts[0] = _("_Yes"); buts[1]=_("_No"); buts[2] = NULL;
     510             : 
     511           0 :     if ( uc_strcmp(name,".notdef")==0 )               /* This name is a special case and doesn't follow conventions */
     512           0 : return( true );
     513           0 :     if ( u_strlen(name)>31 ) {
     514           0 :         ff_post_error(_("Bad Name"),_("Glyph names are limited to 31 characters"));
     515           0 : return( false );
     516           0 :     } else if ( *name=='\0' ) {
     517           0 :         ff_post_error(_("Bad Name"),_("Bad Name"));
     518           0 : return( false );
     519           0 :     } else if ( isdigit(*name) || *name=='.' ) {
     520           0 :         ff_post_error(_("Bad Name"),_("A glyph name may not start with a digit nor a full stop (period)"));
     521           0 : return( false );
     522             :     }
     523           0 :     bad = questionable = false;
     524           0 :     while ( *name ) {
     525           0 :         if ( *name<=' ' || (!allow_utf8_glyphnames && *name>=0x7f) ||
     526           0 :                 *name=='(' || *name=='[' || *name=='{' || *name=='<' ||
     527           0 :                 *name==')' || *name==']' || *name=='}' || *name=='>' ||
     528           0 :                 *name=='%' || *name=='/' )
     529           0 :             bad=true;
     530           0 :         else if ( !isalnum(*name) && *name!='.' && *name!='_' )
     531           0 :             questionable = true;
     532           0 :         ++name;
     533             :     }
     534           0 :     if ( bad ) {
     535           0 :         ff_post_error(_("Bad Name"),_("A glyph name must be ASCII, without spaces and may not contain the characters \"([{<>}])/%%\", and should contain only alphanumerics, periods and underscores"));
     536           0 : return( false );
     537           0 :     } else if ( questionable ) {
     538           0 :         if ( gwwv_ask(_("Bad Name"),(const char **) buts,0,1,_("A glyph name should contain only alphanumerics, periods and underscores\nDo you want to use this name in spite of that?"))==1 )
     539           0 : return(false);
     540             :     }
     541           0 : return( true );
     542             : }
     543             : 
     544           0 : static void CI_ParseCounters(CharInfo *ci) {
     545             :     int32 i,len;
     546           0 :     GTextInfo **ti = GGadgetGetList(GWidgetGetControl(ci->gw,CID_List+600),&len);
     547           0 :     SplineChar *sc = ci->cachedsc;
     548             : 
     549           0 :     free(sc->countermasks);
     550             : 
     551           0 :     sc->countermask_cnt = len;
     552           0 :     if ( len==0 )
     553           0 :         sc->countermasks = NULL;
     554             :     else {
     555           0 :         sc->countermasks = malloc(len*sizeof(HintMask));
     556           0 :         for ( i=0; i<len; ++i ) {
     557           0 :             memcpy(sc->countermasks[i],ti[i]->userdata,sizeof(HintMask));
     558           0 :             chunkfree(ti[i]->userdata,sizeof(HintMask));
     559           0 :             ti[i]->userdata = NULL;
     560             :         }
     561             :     }
     562           0 : }
     563             : 
     564           0 : int DeviceTableOK(char *dvstr, int *_low, int *_high) {
     565             :     char *pt, *end;
     566             :     int low, high, pixel, cor;
     567             : 
     568           0 :     low = high = -1;
     569           0 :     if ( dvstr!=NULL ) {
     570           0 :         while ( *dvstr==' ' ) ++dvstr;
     571           0 :         for ( pt=dvstr; *pt; ) {
     572           0 :             pixel = strtol(pt,&end,10);
     573           0 :             if ( pixel<=0 || pt==end)
     574             :         break;
     575           0 :             pt = end;
     576           0 :             if ( *pt==':' ) ++pt;
     577           0 :             cor = strtol(pt,&end,10);
     578           0 :             if ( pt==end || cor<-128 || cor>127 )
     579             :         break;
     580           0 :             pt = end;
     581           0 :             while ( *pt==' ' ) ++pt;
     582           0 :             if ( *pt==',' ) ++pt;
     583           0 :             while ( *pt==' ' ) ++pt;
     584           0 :             if ( low==-1 ) low = high = pixel;
     585           0 :             else if ( pixel<low ) low = pixel;
     586           0 :             else if ( pixel>high ) high = pixel;
     587             :         }
     588           0 :         if ( *pt != '\0' )
     589           0 : return( false );
     590             :     }
     591           0 :     *_low = low; *_high = high;
     592           0 : return( true );
     593             : }
     594             : 
     595           0 : DeviceTable *DeviceTableParse(DeviceTable *dv,char *dvstr) {
     596             :     char *pt, *end;
     597             :     int low, high, pixel, cor;
     598             : 
     599           0 :     DeviceTableOK(dvstr,&low,&high);
     600           0 :     if ( low==-1 ) {
     601           0 :         if ( dv!=NULL ) {
     602           0 :             free(dv->corrections);
     603           0 :             memset(dv,0,sizeof(*dv));
     604             :         }
     605           0 : return( dv );
     606             :     }
     607           0 :     if ( dv==NULL )
     608           0 :         dv = chunkalloc(sizeof(DeviceTable));
     609             :     else
     610           0 :         free(dv->corrections);
     611           0 :     dv->first_pixel_size = low;
     612           0 :     dv->last_pixel_size = high;
     613           0 :     dv->corrections = calloc(high-low+1,1);
     614             : 
     615           0 :     for ( pt=dvstr; *pt; ) {
     616           0 :         pixel = strtol(pt,&end,10);
     617           0 :         if ( pixel<=0 || pt==end)
     618             :     break;
     619           0 :         pt = end;
     620           0 :         if ( *pt==':' ) ++pt;
     621           0 :         cor = strtol(pt,&end,10);
     622           0 :         if ( pt==end || cor<-128 || cor>127 )
     623             :     break;
     624           0 :         pt = end;
     625           0 :         while ( *pt==' ' ) ++pt;
     626           0 :         if ( *pt==',' ) ++pt;
     627           0 :         while ( *pt==' ' ) ++pt;
     628           0 :         dv->corrections[pixel-low] = cor;
     629             :     }
     630           0 : return( dv );
     631             : }
     632             : 
     633           0 : void VRDevTabParse(struct vr *vr,struct matrix_data *md) {
     634             :     ValDevTab temp, *adjust;
     635           0 :     int any = false;
     636             : 
     637           0 :     if ( (adjust = vr->adjust)==NULL ) {
     638           0 :         adjust = &temp;
     639           0 :         memset(&temp,0,sizeof(temp));
     640             :     }
     641           0 :     any |= (DeviceTableParse(&adjust->xadjust,md[0].u.md_str)!=NULL);
     642           0 :     any |= (DeviceTableParse(&adjust->yadjust,md[2].u.md_str)!=NULL);
     643           0 :     any |= (DeviceTableParse(&adjust->xadv,md[4].u.md_str)!=NULL);
     644           0 :     any |= (DeviceTableParse(&adjust->yadv,md[6].u.md_str)!=NULL);
     645           0 :     if ( any && adjust==&temp ) {
     646           0 :         vr->adjust = chunkalloc(sizeof(ValDevTab));
     647           0 :         *vr->adjust = temp;
     648           0 :     } else if ( !any && vr->adjust!=NULL ) {
     649           0 :         ValDevFree(vr->adjust);
     650           0 :         vr->adjust = NULL;
     651             :     }
     652           0 : }
     653             : 
     654           0 : void DevTabToString(char **str,DeviceTable *adjust) {
     655             :     char *pt;
     656             :     int i;
     657             : 
     658           0 :     if ( adjust==NULL || adjust->corrections==NULL ) {
     659           0 :         *str = NULL;
     660           0 : return;
     661             :     }
     662           0 :     *str = pt = malloc(11*(adjust->last_pixel_size-adjust->first_pixel_size+1)+1);
     663           0 :     for ( i=adjust->first_pixel_size; i<=adjust->last_pixel_size; ++i ) {
     664           0 :         if ( adjust->corrections[i-adjust->first_pixel_size]!=0 )
     665           0 :             sprintf( pt, "%d:%d, ", i, adjust->corrections[i-adjust->first_pixel_size]);
     666           0 :         pt += strlen(pt);
     667             :     }
     668           0 :     if ( pt>*str && pt[-2] == ',' )
     669           0 :         pt[-2] = '\0';
     670             : }
     671             :     
     672           0 : void ValDevTabToStrings(struct matrix_data *mds,int first_offset,ValDevTab *adjust) {
     673           0 :     if ( adjust==NULL )
     674           0 : return;
     675           0 :     DevTabToString(&mds[first_offset].u.md_str,&adjust->xadjust);
     676           0 :     DevTabToString(&mds[first_offset+2].u.md_str,&adjust->yadjust);
     677           0 :     DevTabToString(&mds[first_offset+4].u.md_str,&adjust->xadv);
     678           0 :     DevTabToString(&mds[first_offset+6].u.md_str,&adjust->yadv);
     679             : }
     680             : 
     681           0 : void KpMDParse(SplineChar *sc,struct lookup_subtable *sub,
     682             :         struct matrix_data *possub,int rows,int cols,int i) {
     683             :     SplineChar *other;
     684             :     PST *pst;
     685             :     KernPair *kp;
     686             :     int isv, iskpable, offset, newv;
     687             :     char *dvstr;
     688             :     char *pt, *start;
     689             :     int ch;
     690             : 
     691           0 :     for ( start=possub[cols*i+1].u.md_str; ; ) {
     692           0 :         while ( *start==' ' ) ++start;
     693           0 :         if ( *start=='\0' )
     694           0 :     break;
     695           0 :         for ( pt=start; *pt!='\0' && *pt!=' ' && *pt!='('; ++pt );
     696           0 :         ch = *pt; *pt = '\0';
     697           0 :         other = SFGetChar(sc->parent,-1,start);
     698           0 :         for ( pst=sc->possub; pst!=NULL; pst=pst->next ) {
     699           0 :             if ( pst->subtable == sub &&
     700           0 :                     strcmp(start,pst->u.pair.paired)==0 )
     701           0 :         break;
     702             :         }
     703           0 :         kp = NULL;
     704           0 :         if ( pst==NULL && other!=NULL ) {
     705           0 :             for ( isv=0; isv<2; ++isv ) {
     706           0 :                 for ( kp = isv ? sc->vkerns : sc->kerns; kp!=NULL; kp=kp->next )
     707           0 :                     if ( kp->subtable==(void *) possub[cols*i+0].u.md_ival &&
     708           0 :                             kp->sc == other )
     709           0 :                 break;
     710           0 :                 if ( kp!=NULL )
     711           0 :             break;
     712             :             }
     713             :         }
     714           0 :         newv = false;
     715           0 :         if ( other==NULL )
     716           0 :             iskpable = false;
     717           0 :         else if ( sub->vertical_kerning ) {
     718           0 :             newv = true;
     719           0 :             iskpable = possub[cols*i+PAIR_DX1].u.md_ival==0 &&
     720           0 :                         possub[cols*i+PAIR_DY1].u.md_ival==0 &&
     721           0 :                         possub[cols*i+PAIR_DX_ADV1].u.md_ival==0 &&
     722           0 :                         possub[cols*i+PAIR_DX2].u.md_ival==0 &&
     723           0 :                         possub[cols*i+PAIR_DY2].u.md_ival==0 &&
     724           0 :                         possub[cols*i+PAIR_DX_ADV2].u.md_ival==0 &&
     725           0 :                         possub[cols*i+PAIR_DY_ADV2].u.md_ival==0;
     726           0 :             offset = possub[cols*i+PAIR_DY1].u.md_ival;
     727           0 :             iskpable &= (possub[cols*i+PAIR_DX1+1].u.md_str==NULL || *possub[cols*i+PAIR_DX1+1].u.md_str==0 ) &&
     728           0 :                         (possub[cols*i+PAIR_DY1+1].u.md_str==0 || *possub[cols*i+PAIR_DY1+1].u.md_str==0 ) &&
     729           0 :                         (possub[cols*i+PAIR_DX_ADV1+1].u.md_str==0 || *possub[cols*i+PAIR_DX_ADV1+1].u.md_str==0 ) &&
     730           0 :                         (possub[cols*i+PAIR_DX2+1].u.md_str==0 || *possub[cols*i+PAIR_DX2+1].u.md_str==0 ) &&
     731           0 :                         (possub[cols*i+PAIR_DY2+1].u.md_str==0 || *possub[cols*i+PAIR_DY2+1].u.md_str==0 ) &&
     732           0 :                         (possub[cols*i+PAIR_DX_ADV2+1].u.md_str==0 || *possub[cols*i+PAIR_DX_ADV2+1].u.md_str==0 ) &&
     733           0 :                         (possub[cols*i+PAIR_DY_ADV2+1].u.md_str==0 || *possub[cols*i+PAIR_DY_ADV2+1].u.md_str==0 );
     734           0 :             dvstr = possub[cols*i+PAIR_DY1+1].u.md_str;
     735           0 :         } else if ( sub->lookup->lookup_flags & pst_r2l ) {
     736           0 :             iskpable = possub[cols*i+PAIR_DX1].u.md_ival==0 &&
     737           0 :                         possub[cols*i+PAIR_DY1].u.md_ival==0 &&
     738           0 :                         possub[cols*i+PAIR_DX_ADV1].u.md_ival==0 &&
     739           0 :                         possub[cols*i+PAIR_DY_ADV1].u.md_ival==0 &&
     740           0 :                         possub[cols*i+PAIR_DX2].u.md_ival==0 &&
     741           0 :                         possub[cols*i+PAIR_DY2].u.md_ival==0 &&
     742           0 :                         possub[cols*i+PAIR_DY_ADV2].u.md_ival==0;
     743           0 :             offset = possub[cols*i+PAIR_DX_ADV2].u.md_ival;
     744           0 :             iskpable &= (possub[cols*i+PAIR_DX1+1].u.md_str==NULL || *possub[cols*i+PAIR_DX1+1].u.md_str==0 ) &&
     745           0 :                         (possub[cols*i+PAIR_DY1+1].u.md_str==0 || *possub[cols*i+PAIR_DY1+1].u.md_str==0 ) &&
     746           0 :                         (possub[cols*i+PAIR_DX_ADV1+1].u.md_str==0 || *possub[cols*i+PAIR_DX_ADV1+1].u.md_str==0 ) &&
     747           0 :                         (possub[cols*i+PAIR_DY_ADV1+1].u.md_str==0 || *possub[cols*i+PAIR_DY_ADV1+1].u.md_str==0 ) &&
     748           0 :                         (possub[cols*i+PAIR_DX2+1].u.md_str==0 || *possub[cols*i+PAIR_DX2+1].u.md_str==0 ) &&
     749           0 :                         (possub[cols*i+PAIR_DY2+1].u.md_str==0 || *possub[cols*i+PAIR_DY2+1].u.md_str==0 ) &&
     750           0 :                         (possub[cols*i+PAIR_DY_ADV2+1].u.md_str==0 || *possub[cols*i+PAIR_DY_ADV2+1].u.md_str==0 );
     751           0 :             dvstr = possub[cols*i+PAIR_DX_ADV2+1].u.md_str;
     752             :         } else {
     753           0 :             iskpable = possub[cols*i+PAIR_DX1].u.md_ival==0 &&
     754           0 :                         possub[cols*i+PAIR_DY1].u.md_ival==0 &&
     755           0 :                         possub[cols*i+PAIR_DY_ADV1].u.md_ival==0 &&
     756           0 :                         possub[cols*i+PAIR_DX2].u.md_ival==0 &&
     757           0 :                         possub[cols*i+PAIR_DY2].u.md_ival==0 &&
     758           0 :                         possub[cols*i+PAIR_DX_ADV2].u.md_ival==0 &&
     759           0 :                         possub[cols*i+PAIR_DY_ADV2].u.md_ival==0;
     760           0 :             offset = possub[cols*i+PAIR_DX_ADV1].u.md_ival;
     761           0 :             iskpable &= (possub[cols*i+PAIR_DX1+1].u.md_str==NULL || *possub[cols*i+PAIR_DX1+1].u.md_str==0 ) &&
     762           0 :                         (possub[cols*i+PAIR_DY1+1].u.md_str==0 || *possub[cols*i+PAIR_DY1+1].u.md_str==0 ) &&
     763           0 :                         (possub[cols*i+PAIR_DY_ADV1+1].u.md_str==0 || *possub[cols*i+PAIR_DY_ADV1+1].u.md_str==0 ) &&
     764           0 :                         (possub[cols*i+PAIR_DX2+1].u.md_str==0 || *possub[cols*i+PAIR_DX2+1].u.md_str==0 ) &&
     765           0 :                         (possub[cols*i+PAIR_DY2+1].u.md_str==0 || *possub[cols*i+PAIR_DY2+1].u.md_str==0 ) &&
     766           0 :                         (possub[cols*i+PAIR_DX_ADV2+1].u.md_str==0 || *possub[cols*i+PAIR_DX_ADV2+1].u.md_str==0 ) &&
     767           0 :                         (possub[cols*i+PAIR_DY_ADV2+1].u.md_str==0 || *possub[cols*i+PAIR_DY_ADV2+1].u.md_str==0 );
     768           0 :             dvstr = possub[cols*i+PAIR_DX_ADV1+1].u.md_str;
     769             :         }
     770           0 :         if ( iskpable ) {
     771           0 :             if ( kp==NULL ) {
     772             :                 /* If there's a pst, ignore it, it will not get ticked and will*/
     773             :                 /*  be freed later */
     774           0 :                 kp = chunkalloc(sizeof(KernPair));
     775           0 :                 kp->subtable = sub;
     776           0 :                 kp->sc = other;
     777           0 :                 if ( newv ) {
     778           0 :                     kp->next = sc->vkerns;
     779           0 :                     sc->vkerns = kp;
     780             :                 } else {
     781           0 :                     kp->next = sc->kerns;
     782           0 :                     sc->kerns = kp;
     783             :                 }
     784             :             }
     785           0 :             DeviceTableFree(kp->adjust);
     786           0 :             kp->adjust = DeviceTableParse(NULL,dvstr);
     787           0 :             kp->off = offset;
     788           0 :             kp->kcid = true;
     789             :         } else {
     790           0 :             if ( pst == NULL ) {
     791             :                 /* If there's a kp, ignore it, it will not get ticked and will*/
     792             :                 /*  be freed later */
     793           0 :                 pst = chunkalloc(sizeof(PST));
     794           0 :                 pst->type = pst_pair;
     795           0 :                 pst->subtable = sub;
     796           0 :                 pst->next = sc->possub;
     797           0 :                 sc->possub = pst;
     798           0 :                 pst->u.pair.vr = chunkalloc(sizeof(struct vr [2]));
     799           0 :                 pst->u.pair.paired = copy(start);
     800             :             }
     801           0 :             VRDevTabParse(&pst->u.pair.vr[0],&possub[cols*i+PAIR_DX1+1]);
     802           0 :             VRDevTabParse(&pst->u.pair.vr[1],&possub[cols*i+PAIR_DX2]+1);
     803           0 :             pst->u.pair.vr[0].xoff = possub[cols*i+PAIR_DX1].u.md_ival;
     804           0 :             pst->u.pair.vr[0].yoff = possub[cols*i+PAIR_DY1].u.md_ival;
     805           0 :             pst->u.pair.vr[0].h_adv_off = possub[cols*i+PAIR_DX_ADV1].u.md_ival;
     806           0 :             pst->u.pair.vr[0].v_adv_off = possub[cols*i+PAIR_DY_ADV1].u.md_ival;
     807           0 :             pst->u.pair.vr[1].xoff = possub[cols*i+PAIR_DX2].u.md_ival;
     808           0 :             pst->u.pair.vr[1].yoff = possub[cols*i+PAIR_DY2].u.md_ival;
     809           0 :             pst->u.pair.vr[1].h_adv_off = possub[cols*i+PAIR_DX_ADV2].u.md_ival;
     810           0 :             pst->u.pair.vr[1].v_adv_off = possub[cols*i+PAIR_DY_ADV2].u.md_ival;
     811           0 :             pst->ticked = true;
     812             :         }
     813           0 :         *pt = ch;
     814           0 :         if ( ch=='(' ) {
     815           0 :             while ( *pt!=')' && *pt!='\0' ) ++pt;
     816           0 :             if ( *pt==')' ) ++pt;
     817             :         }
     818           0 :         start = pt;
     819           0 :     }
     820           0 : }
     821             : 
     822           0 : static int CI_ProcessPosSubs(CharInfo *ci) {
     823             :     /* Check for duplicate entries in kerning and ligatures. If we find any */
     824             :     /*  complain and return failure */
     825             :     /* Check for various other errors */
     826             :     /* Otherwise process */
     827           0 :     SplineChar *sc = ci->cachedsc, *found;
     828             :     int i,j, rows, cols, isv, pstt, ch;
     829             :     char *pt;
     830             :     struct matrix_data *possub;
     831             :     char *buts[3];
     832             :     KernPair *kp, *kpprev, *kpnext;
     833             :     PST *pst, *pstprev, *pstnext;
     834             : 
     835           0 :     possub = GMatrixEditGet(GWidgetGetControl(ci->gw,CID_List+(pst_ligature-1)*100), &rows );
     836           0 :     cols = GMatrixEditGetColCnt(GWidgetGetControl(ci->gw,CID_List+(pst_ligature-1)*100) );
     837           0 :     for ( i=0; i<rows; ++i ) {
     838           0 :         for ( j=i+1; j<rows; ++j ) {
     839           0 :             if ( possub[cols*i+0].u.md_ival == possub[cols*j+0].u.md_ival &&
     840           0 :                     strcmp(possub[cols*i+1].u.md_str,possub[cols*j+1].u.md_str)==0 ) {
     841           0 :                 ff_post_error( _("Duplicate Ligature"),_("There are two ligature entries with the same components (%.80s) in the same lookup subtable (%.30s)"),
     842           0 :                         possub[cols*j+1].u.md_str,
     843           0 :                         ((struct lookup_subtable *) possub[cols*i+0].u.md_ival)->subtable_name );
     844           0 : return( false );
     845             :             }
     846             :         }
     847             :     }
     848           0 :     possub = GMatrixEditGet(GWidgetGetControl(ci->gw,CID_List+(pst_pair-1)*100), &rows );
     849           0 :     cols = GMatrixEditGetColCnt(GWidgetGetControl(ci->gw,CID_List+(pst_pair-1)*100));
     850           0 :     for ( i=0; i<rows; ++i ) {
     851           0 :         for ( j=i+1; j<rows; ++j ) {
     852           0 :             if ( possub[cols*i+0].u.md_ival == possub[cols*j+0].u.md_ival &&
     853           0 :                     strcmp(possub[cols*i+1].u.md_str,possub[cols*j+1].u.md_str)==0 ) {
     854           0 :                 ff_post_error( _("Duplicate Kern data"),_("There are two kerning entries for the same glyph (%.80s) in the same lookup subtable (%.30s)"),
     855           0 :                         possub[cols*j+1].u.md_str,
     856           0 :                         ((struct lookup_subtable *) possub[cols*i+0].u.md_ival)->subtable_name );
     857           0 : return( false );
     858             :             }
     859             :         }
     860             :     }
     861             : 
     862             :     /* Check for badly specified device tables */
     863           0 :     for ( pstt = pst_position; pstt<=pst_pair; ++pstt ) {
     864           0 :         int startc = pstt==pst_position ? SIM_DX+1 : PAIR_DX1+1;
     865             :         int low, high, c, r;
     866           0 :         possub = GMatrixEditGet(GWidgetGetControl(ci->gw,CID_List+(pstt-1)*100), &rows );
     867           0 :         cols = GMatrixEditGetColCnt(GWidgetGetControl(ci->gw,CID_List+(pstt-1)*100));
     868           0 :         for ( r=0; r<rows; ++r ) {
     869           0 :             for ( c=startc; c<cols; c+=2 ) {
     870           0 :                 if ( !DeviceTableOK(possub[r*cols+c].u.md_str,&low,&high) ) {
     871           0 :                     ff_post_error( _("Bad Device Table Adjustment"),_("A device table adjustment specified for %.80s is invalid"),
     872           0 :                             possub[cols*r+0].u.md_str );
     873           0 : return( true );
     874             :                 }
     875             :             }
     876             :         }
     877             :     }
     878             : 
     879           0 :     for ( pstt = pst_pair; pstt<=pst_ligature; ++pstt ) {
     880           0 :         possub = GMatrixEditGet(GWidgetGetControl(ci->gw,CID_List+(pstt-1)*100), &rows );
     881           0 :         cols = GMatrixEditGetColCnt(GWidgetGetControl(ci->gw,CID_List+(pstt-1)*100));
     882           0 :         for ( i=0; i<rows; ++i ) {
     883           0 :             char *start = possub[cols*i+1].u.md_str;
     884           0 :             while ( *start== ' ' ) ++start;
     885           0 :             if ( *start=='\0' ) {
     886           0 :                 ff_post_error( _("Missing glyph name"),_("You must specify a glyph name for subtable %s"),
     887           0 :                         ((struct lookup_subtable *) possub[cols*i+0].u.md_ival)->subtable_name );
     888           0 : return( false );
     889             :             }
     890           0 :             while ( *start ) {
     891           0 :                 for ( pt=start; *pt!='\0' && *pt!=' ' && *pt!='(' ; ++pt );
     892           0 :                 ch = *pt; *pt='\0';
     893           0 :                 found = SFGetChar(sc->parent,-1,start);
     894           0 :                 if ( found==NULL ) {
     895           0 :                     buts[0] = _("_Yes");
     896           0 :                     buts[1] = _("_Cancel");
     897           0 :                     buts[2] = NULL;
     898           0 :                     if ( gwwv_ask(_("Missing glyph"),(const char **) buts,0,1,_("In lookup subtable %.30s you refer to a glyph named %.80s, which is not in the font yet. Was this intentional?"),
     899           0 :                             ((struct lookup_subtable *) possub[cols*i+0].u.md_ival)->subtable_name,
     900             :                             start)==1 ) {
     901           0 :                         *pt = ch;
     902           0 : return( false );
     903             :                     }
     904           0 :                 } else if ( found==ci->sc && pstt!=pst_pair ) {
     905           0 :                     buts[0] = _("_Yes");
     906           0 :                     buts[1] = _("_Cancel");
     907           0 :                     buts[2] = NULL;
     908           0 :                     if ( gwwv_ask(_("Substitution generates itself"),(const char **) buts,0,1,_("In lookup subtable %.30s you replace a glyph with itself. Was this intentional?"),
     909           0 :                             ((struct lookup_subtable *) possub[cols*i+0].u.md_ival)->subtable_name)==1 ) {
     910           0 :                         *pt = ch;
     911           0 : return( false );
     912             :                     }
     913             :                 }
     914           0 :                 *pt = ch;
     915           0 :                 if ( ch=='(' ) {
     916           0 :                     while ( *pt!=')' && *pt!='\0' ) ++pt;
     917           0 :                     if ( *pt==')' ) ++pt;
     918             :                 }
     919           0 :                 while ( *pt== ' ' ) ++pt;
     920           0 :                 start = pt;
     921             :             }
     922             :         }
     923             :     }
     924             : 
     925             :     /* If we get this far, then we didn't find any errors */
     926           0 :     for ( pst = sc->possub; pst!=NULL; pst=pst->next )
     927           0 :         pst->ticked = pst->type==pst_lcaret;
     928           0 :     for ( isv=0; isv<2; ++isv )
     929           0 :         for ( kp = isv ? sc->vkerns : sc->kerns; kp!=NULL; kp=kp->next )
     930           0 :             kp->kcid = 0;
     931             : 
     932           0 :     for ( pstt=pst_substitution; pstt<=pst_ligature; ++pstt ) {
     933           0 :         possub = GMatrixEditGet(GWidgetGetControl(ci->gw,CID_List+(pstt-1)*100), &rows );
     934           0 :         cols = GMatrixEditGetColCnt(GWidgetGetControl(ci->gw,CID_List+(pstt-1)*100) );
     935           0 :         for ( i=0; i<rows; ++i ) {
     936           0 :             for ( pst=sc->possub; pst!=NULL; pst=pst->next ) {
     937           0 :                 if ( pst->subtable == (void *) possub[cols*i+0].u.md_ival &&
     938           0 :                         !pst->ticked )
     939           0 :             break;
     940             :             }
     941           0 :             if ( pst==NULL ) {
     942           0 :                 pst = chunkalloc(sizeof(PST));
     943           0 :                 pst->type = pstt;
     944           0 :                 pst->subtable = (void *) possub[cols*i+0].u.md_ival;
     945           0 :                 pst->next = sc->possub;
     946           0 :                 sc->possub = pst;
     947             :             } else
     948           0 :                 free( pst->u.subs.variant );
     949           0 :             pst->ticked = true;
     950           0 :             pst->u.subs.variant = GlyphNameListDeUnicode( possub[cols*i+1].u.md_str );
     951           0 :             if ( pstt==pst_ligature )
     952           0 :                 pst->u.lig.lig = sc;
     953             :         }
     954             :     }
     955             : 
     956           0 :     possub = GMatrixEditGet(GWidgetGetControl(ci->gw,CID_List+(pst_position-1)*100), &rows );
     957           0 :     cols = GMatrixEditGetColCnt(GWidgetGetControl(ci->gw,CID_List+(pst_position-1)*100));
     958           0 :     for ( i=0; i<rows; ++i ) {
     959           0 :         for ( pst=sc->possub; pst!=NULL; pst=pst->next ) {
     960           0 :             if ( pst->subtable == (void *) possub[cols*i+0].u.md_ival &&
     961           0 :                     !pst->ticked )
     962           0 :         break;
     963             :         }
     964           0 :         if ( pst==NULL ) {
     965           0 :             pst = chunkalloc(sizeof(PST));
     966           0 :             pst->type = pst_position;
     967           0 :             pst->subtable = (void *) possub[cols*i+0].u.md_ival;
     968           0 :             pst->next = sc->possub;
     969           0 :             sc->possub = pst;
     970             :         }
     971           0 :         VRDevTabParse(&pst->u.pos,&possub[cols*i+SIM_DX+1]);
     972           0 :         pst->u.pos.xoff = possub[cols*i+SIM_DX].u.md_ival;
     973           0 :         pst->u.pos.yoff = possub[cols*i+SIM_DY].u.md_ival;
     974           0 :         pst->u.pos.h_adv_off = possub[cols*i+SIM_DX_ADV].u.md_ival;
     975           0 :         pst->u.pos.v_adv_off = possub[cols*i+SIM_DY_ADV].u.md_ival;
     976           0 :         pst->ticked = true;
     977             :     }
     978             : 
     979           0 :     possub = GMatrixEditGet(GWidgetGetControl(ci->gw,CID_List+(pst_pair-1)*100), &rows );
     980           0 :     cols = GMatrixEditGetColCnt(GWidgetGetControl(ci->gw,CID_List+(pst_pair-1)*100));
     981           0 :     for ( i=0; i<rows; ++i ) {
     982           0 :         struct lookup_subtable *sub = ((struct lookup_subtable *) possub[cols*i+0].u.md_ival);
     983           0 :         KpMDParse(sc,sub,possub,rows,cols,i);
     984             :     }
     985             : 
     986             :     /* Now, free anything that did not get ticked */
     987           0 :     for ( pstprev=NULL, pst = sc->possub; pst!=NULL; pst=pstnext ) {
     988           0 :         pstnext = pst->next;
     989           0 :         if ( pst->ticked )
     990           0 :             pstprev = pst;
     991             :         else {
     992           0 :             if ( pstprev==NULL )
     993           0 :                 sc->possub = pstnext;
     994             :             else
     995           0 :                 pstprev->next = pstnext;
     996           0 :             pst->next = NULL;
     997           0 :             PSTFree(pst);
     998             :         }
     999             :     }
    1000           0 :     for ( isv=0; isv<2; ++isv ) {
    1001           0 :         for ( kpprev=NULL, kp = isv ? sc->vkerns : sc->kerns; kp!=NULL; kp=kpnext ) {
    1002           0 :             kpnext = kp->next;
    1003           0 :             if ( kp->kcid!=0 )
    1004           0 :                 kpprev = kp;
    1005             :             else {
    1006           0 :                 if ( kpprev!=NULL )
    1007           0 :                     kpprev->next = kpnext;
    1008           0 :                 else if ( isv )
    1009           0 :                     sc->vkerns = kpnext;
    1010             :                 else
    1011           0 :                     sc->kerns = kpnext;
    1012           0 :                 kp->next = NULL;
    1013           0 :                 KernPairsFree(kp);
    1014             :             }
    1015             :         }
    1016             :     }
    1017           0 :     for ( isv=0; isv<2; ++isv )
    1018           0 :         for ( kp = isv ? sc->vkerns : sc->kerns; kp!=NULL; kp=kp->next )
    1019           0 :             kp->kcid = 0;
    1020           0 : return( true );
    1021             : }
    1022             : 
    1023           0 : static int gettex(GWindow gw,int cid,char *msg,int *err) {
    1024           0 :     const unichar_t *ret = _GGadgetGetTitle(GWidgetGetControl(gw,cid));
    1025             : 
    1026           0 :     if ( *ret=='\0' )
    1027           0 : return( TEX_UNDEF );
    1028           0 : return( GetInt8(gw,cid,msg,err));
    1029             : }
    1030             : 
    1031           0 : struct glyphvariants *GV_ParseConstruction(struct glyphvariants *gv,
    1032             :         struct matrix_data *stuff, int rows, int cols) {
    1033             :     int i;
    1034             : 
    1035           0 :     if ( gv==NULL )
    1036           0 :         gv = chunkalloc(sizeof(struct glyphvariants));
    1037             : 
    1038           0 :     gv->part_cnt = rows;
    1039           0 :     gv->parts = calloc(rows,sizeof(struct gv_part));
    1040           0 :     for ( i=0; i<rows; ++i ) {
    1041           0 :         gv->parts[i].component = copy(stuff[i*cols+0].u.md_str);
    1042           0 :         gv->parts[i].is_extender = stuff[i*cols+1].u.md_ival;
    1043           0 :         gv->parts[i].startConnectorLength = stuff[i*cols+2].u.md_ival;
    1044           0 :         gv->parts[i].endConnectorLength = stuff[i*cols+3].u.md_ival;
    1045           0 :         gv->parts[i].fullAdvance = stuff[i*cols+4].u.md_ival;
    1046             :     }
    1047           0 : return( gv );
    1048             : }
    1049             : 
    1050           0 : static struct glyphvariants *CI_ParseVariants(struct glyphvariants *gv,
    1051             :         CharInfo *ci, int is_horiz,
    1052             :         char *italic_correction_devtab, int italic_correction,
    1053             :         int only_parts) {
    1054           0 :     char *variants = GGadgetGetTitle8(GWidgetGetControl(ci->gw,CID_VariantList+is_horiz*100));
    1055           0 :     GGadget *construct = GWidgetGetControl(ci->gw,CID_ExtensionList+is_horiz*100);
    1056           0 :     int rows, cols = GMatrixEditGetColCnt(construct);
    1057           0 :     struct matrix_data *stuff = GMatrixEditGet(construct,&rows);
    1058             : 
    1059           0 :     if ( (variants==NULL || variants[0]=='\0' || only_parts) && rows==0 ) {
    1060           0 :         free(variants);
    1061           0 :         GlyphVariantsFree(gv);
    1062           0 : return( NULL );
    1063             :     }
    1064           0 :     if ( gv==NULL )
    1065           0 :         gv = chunkalloc(sizeof(struct glyphvariants));
    1066           0 :     free(gv->variants); gv->variants = NULL;
    1067           0 :     if ( only_parts ) {
    1068           0 :         free(variants); variants = NULL;
    1069           0 :     } else if ( variants!=NULL && *variants!='\0' )
    1070           0 :         gv->variants = variants;
    1071             :     else {
    1072           0 :         gv->variants = NULL;
    1073           0 :         free( variants);
    1074             :     }
    1075           0 :     if ( !only_parts ) {
    1076           0 :         gv->italic_correction = italic_correction;
    1077           0 :         gv->italic_adjusts = DeviceTableParse(gv->italic_adjusts,italic_correction_devtab);
    1078             :     }
    1079           0 :     gv = GV_ParseConstruction(gv,stuff,rows,cols);
    1080           0 : return( gv );
    1081             : }
    1082             : 
    1083           0 : static int CI_ValidateAltUnis(CharInfo *ci) {
    1084           0 :     GGadget *au = GWidgetGetControl(ci->gw,CID_AltUni);
    1085           0 :     int rows, cols = GMatrixEditGetColCnt(au);
    1086           0 :     struct matrix_data *stuff = GMatrixEditGet(au,&rows);
    1087           0 :     int i, asked = false;
    1088             : 
    1089           0 :     for ( i=0; i<rows; ++i ) {
    1090           0 :         int uni = stuff[i*cols+0].u.md_ival, vs = stuff[i*cols+1].u.md_ival;
    1091           0 :         if ( uni<0 || uni>=unicode4_size ||
    1092           0 :                 vs<-1 || vs>=unicode4_size ) {
    1093           0 :             ff_post_error(_("Unicode out of range"), _("Bad unicode value for an alternate unicode / variation selector"));
    1094           0 : return( false );
    1095             :         }
    1096           0 :         if ( (vs>=0x180B && vs<=0x180D) ||        /* Mongolian VS */
    1097           0 :                  (vs>=0xfe00 && vs<=0xfe0f) ||    /* First VS block */
    1098           0 :                  (vs>=0xE0100 && vs<=0xE01EF) ) { /* Second VS block */
    1099             :             /* ok, that's a reasonable value */;
    1100           0 :         } else if ( vs==0 || vs==-1 ) {
    1101             :             /* That's ok too (means no selector, just an alternate encoding) */;
    1102           0 :         } else if ( !asked ) {
    1103             :             char *buts[3];
    1104           0 :             buts[0] = _("_OK"); buts[1] = _("_Cancel"); buts[2]=NULL;
    1105           0 :             if ( gwwv_ask(_("Unexpected Variation Selector"),(const char **) buts,0,1,
    1106           0 :                     _("Variation selectors are normally between\n"
    1107             :                       "   U+180B and U+180D\n"
    1108             :                       "   U+FE00 and U+FE0F\n"
    1109             :                       "   U+E0100 and U+E01EF\n"
    1110             :                       "did you really intend to use U+%04X?"), vs)==1 )
    1111           0 : return( false );
    1112           0 :             asked = true;
    1113             :         }
    1114             :     }
    1115           0 : return( true );
    1116             : }
    1117             : 
    1118           0 : static void CI_ParseAltUnis(CharInfo *ci) {
    1119           0 :     GGadget *au = GWidgetGetControl(ci->gw,CID_AltUni);
    1120           0 :     int rows, cols = GMatrixEditGetColCnt(au);
    1121           0 :     struct matrix_data *stuff = GMatrixEditGet(au,&rows);
    1122             :     int i;
    1123           0 :     struct altuni *altuni, *last = NULL;
    1124           0 :     SplineChar *sc = ci->cachedsc;
    1125           0 :     int deenc = false;
    1126             :     FontView *fvs;
    1127             :     int oldcnt, newcnt;
    1128             : 
    1129           0 :     oldcnt = 0;
    1130           0 :     for ( altuni=sc->altuni ; altuni!=NULL; altuni = altuni->next )
    1131           0 :         if ( altuni->vs==-1 && altuni->fid==0 )
    1132           0 :             ++oldcnt;
    1133             : 
    1134           0 :     newcnt = 0;
    1135           0 :     for ( i=0; i<rows; ++i ) {
    1136           0 :         int uni = stuff[i*cols+0].u.md_ival, vs = stuff[i*cols+1].u.md_ival;
    1137           0 :         if ( vs!=0 )
    1138           0 :     continue;
    1139           0 :         ++newcnt;
    1140           0 :         if ( uni==sc->unicodeenc )
    1141           0 :     continue;
    1142           0 :         for ( altuni=sc->altuni ; altuni!=NULL; altuni = altuni->next )
    1143           0 :             if ( uni==altuni->unienc && altuni->vs==-1 && altuni->fid==0 )
    1144           0 :         break;
    1145           0 :         if ( altuni==NULL ) {
    1146           0 :             deenc = true;
    1147           0 :     break;
    1148             :         }
    1149             :     }
    1150           0 :     if ( oldcnt!=newcnt || deenc ) {
    1151           0 :         for ( fvs=(FontView *) sc->parent->fv; fvs!=NULL; fvs=(FontView *) fvs->b.nextsame ) {
    1152           0 :             fvs->b.map->enc = &custom;
    1153           0 :             FVSetTitle((FontViewBase *) fvs);
    1154             :         }
    1155             :     }
    1156           0 :     AltUniFree(sc->altuni); sc->altuni = NULL;
    1157           0 :     for ( i=0; i<rows; ++i ) {
    1158           0 :         int uni = stuff[i*cols+0].u.md_ival, vs = stuff[i*cols+1].u.md_ival;
    1159           0 :         altuni = chunkalloc(sizeof(struct altuni));
    1160           0 :         altuni->unienc = uni;
    1161           0 :         altuni->vs = vs==0 ? -1 : vs;
    1162           0 :         altuni->fid = 0;
    1163           0 :         if ( last == NULL )
    1164           0 :             sc->altuni = altuni;
    1165             :         else
    1166           0 :             last->next = altuni;
    1167           0 :         last = altuni;
    1168             :     }
    1169           0 : }
    1170             : 
    1171           0 : static KernPair *CI_KPCopy(KernPair *kp) {
    1172           0 :     KernPair *head=NULL, *last=NULL, *newkp;
    1173             : 
    1174           0 :     while ( kp!=NULL ) {
    1175           0 :         newkp = chunkalloc(sizeof(KernPair));
    1176           0 :         *newkp = *kp;
    1177           0 :         newkp->adjust = DeviceTableCopy(kp->adjust);
    1178           0 :         newkp->next = NULL;
    1179           0 :         if ( head==NULL )
    1180           0 :             head = newkp;
    1181             :         else
    1182           0 :             last->next = newkp;
    1183           0 :         last = newkp;
    1184           0 :         kp = kp->next;
    1185             :     }
    1186           0 : return( head );
    1187             : }
    1188             : 
    1189           0 : static PST *CI_PSTCopy(PST *pst) {
    1190           0 :     PST *head=NULL, *last=NULL, *newpst;
    1191             : 
    1192           0 :     while ( pst!=NULL ) {
    1193           0 :         newpst = chunkalloc(sizeof(KernPair));
    1194           0 :         *newpst = *pst;
    1195           0 :         if ( newpst->type==pst_ligature ) {
    1196           0 :             newpst->u.lig.components = copy(pst->u.lig.components);
    1197           0 :         } else if ( newpst->type==pst_pair ) {
    1198           0 :             newpst->u.pair.paired = copy(pst->u.pair.paired);
    1199           0 :             newpst->u.pair.vr = chunkalloc(sizeof( struct vr [2]));
    1200           0 :             memcpy(newpst->u.pair.vr,pst->u.pair.vr,sizeof(struct vr [2]));
    1201           0 :             newpst->u.pair.vr[0].adjust = ValDevTabCopy(pst->u.pair.vr[0].adjust);
    1202           0 :             newpst->u.pair.vr[1].adjust = ValDevTabCopy(pst->u.pair.vr[1].adjust);
    1203           0 :         } else if ( newpst->type==pst_lcaret ) {
    1204           0 :             newpst->u.lcaret.carets = malloc(pst->u.lcaret.cnt*sizeof(uint16));
    1205           0 :             memcpy(newpst->u.lcaret.carets,pst->u.lcaret.carets,pst->u.lcaret.cnt*sizeof(uint16));
    1206           0 :         } else if ( newpst->type==pst_substitution || newpst->type==pst_multiple || newpst->type==pst_alternate )
    1207           0 :             newpst->u.subs.variant = copy(pst->u.subs.variant);
    1208           0 :         newpst->next = NULL;
    1209           0 :         if ( head==NULL )
    1210           0 :             head = newpst;
    1211             :         else
    1212           0 :             last->next = newpst;
    1213           0 :         last = newpst;
    1214           0 :         pst = pst->next;
    1215             :     }
    1216           0 : return( head );
    1217             : }
    1218             : 
    1219           0 : static SplineChar *CI_SCDuplicate(SplineChar *sc) {
    1220             :     SplineChar *newsc;          /* copy everything we care about in this dlg */
    1221             : 
    1222           0 :     newsc = chunkalloc(sizeof(SplineChar));
    1223           0 :     newsc->name = copy(sc->name);
    1224           0 :     newsc->parent = sc->parent;
    1225           0 :     newsc->unicodeenc = sc->unicodeenc;
    1226           0 :     newsc->orig_pos = sc->orig_pos;
    1227           0 :     newsc->comment = copy(sc->comment);
    1228           0 :     newsc->unlink_rm_ovrlp_save_undo = sc->unlink_rm_ovrlp_save_undo;
    1229           0 :     newsc->glyph_class = sc->glyph_class;
    1230           0 :     newsc->color = sc->color;
    1231           0 :     if ( sc->countermask_cnt!=0 ) {
    1232           0 :         newsc->countermask_cnt = sc->countermask_cnt;
    1233           0 :         newsc->countermasks = malloc(sc->countermask_cnt*sizeof(HintMask));
    1234           0 :         memcpy(newsc->countermasks,sc->countermasks,sc->countermask_cnt*sizeof(HintMask));
    1235             :     }
    1236           0 :     newsc->tex_height = sc->tex_height;
    1237           0 :     newsc->tex_depth = sc->tex_depth;
    1238           0 :     newsc->italic_correction = sc->italic_correction;
    1239           0 :     newsc->top_accent_horiz = sc->top_accent_horiz;
    1240           0 :     newsc->is_extended_shape = sc->is_extended_shape;
    1241           0 :     newsc->italic_adjusts = DeviceTableCopy(sc->italic_adjusts);
    1242           0 :     newsc->top_accent_adjusts = DeviceTableCopy(sc->top_accent_adjusts);
    1243           0 :     newsc->horiz_variants = GlyphVariantsCopy(sc->horiz_variants);
    1244           0 :     newsc->vert_variants = GlyphVariantsCopy(sc->vert_variants);
    1245           0 :     newsc->altuni = AltUniCopy(sc->altuni,NULL);
    1246           0 :     newsc->lig_caret_cnt_fixed = sc->lig_caret_cnt_fixed;
    1247           0 :     newsc->possub = CI_PSTCopy(sc->possub);
    1248           0 :     newsc->kerns = CI_KPCopy(sc->kerns);
    1249           0 :     newsc->vkerns = CI_KPCopy(sc->vkerns);
    1250           0 :     newsc->tile_margin = sc->tile_margin;
    1251           0 :     newsc->tile_bounds = sc->tile_bounds;
    1252           0 : return( newsc );
    1253             : }
    1254             : 
    1255           0 : static int CI_CheckMetaData(CharInfo *ci,SplineChar *oldsc,char *name,int unienc, char *comment) {
    1256           0 :     SplineFont *sf = oldsc->parent;
    1257             :     int i;
    1258           0 :     int isnotdef, samename=false, sameuni=false;
    1259             :     struct altuni *alt;
    1260           0 :     SplineChar *newsc = ci->cachedsc;
    1261             :     struct splinecharlist *scl, *baduniscl, *badnamescl;
    1262             :     SplineChar *baduni, *badname;
    1263             : 
    1264           0 :     for ( alt=oldsc->altuni; alt!=NULL && (alt->unienc!=unienc || alt->vs!=-1 || alt->fid!=0); alt=alt->next );
    1265           0 :     if ( unienc==oldsc->unicodeenc || alt!=NULL )
    1266           0 :         sameuni=true;
    1267           0 :     samename = ( oldsc->name!=NULL && strcmp(name,oldsc->name)==0 );
    1268             :     
    1269           0 :     isnotdef = strcmp(name,".notdef")==0;
    1270           0 :     if (( !sameuni && unienc!=-1) || (!samename && !isnotdef) ) {
    1271           0 :         baduniscl = badnamescl = NULL;
    1272           0 :         baduni = badname = NULL;
    1273           0 :         for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL && sf->glyphs[i]!=ci->sc ) {
    1274           0 :             if ( unienc!=-1 && sf->glyphs[i]->unicodeenc==unienc ) {
    1275           0 :                 for ( scl=ci->changes; scl!=NULL && scl->sc->orig_pos!=i; scl = scl->next );
    1276           0 :                 if ( scl==NULL ) {
    1277           0 :                     baduni = sf->glyphs[i];
    1278           0 :                     baduniscl = NULL;
    1279           0 :                 } else if ( scl->sc->unicodeenc==unienc ) {
    1280           0 :                     baduni = scl->sc;
    1281           0 :                     baduniscl = scl;
    1282             :                 }
    1283             :             }
    1284           0 :             if ( !isnotdef && strcmp(name,sf->glyphs[i]->name )==0 ) {
    1285           0 :                 for ( scl=ci->changes; scl!=NULL && scl->sc->orig_pos!=i; scl = scl->next );
    1286           0 :                 if ( scl==NULL ) {
    1287           0 :                     badname = sf->glyphs[i];
    1288           0 :                     badnamescl = NULL;
    1289           0 :                 } else if ( strcmp(scl->sc->name,name)==0 ) {
    1290           0 :                     badname = scl->sc;
    1291           0 :                     badnamescl = scl;
    1292             :                 }
    1293             :             }
    1294             :         }
    1295           0 :         for ( scl=ci->changes; scl!=NULL ; scl = scl->next ) if ( scl->sc!=newsc ) {
    1296           0 :             if ( unienc!=-1 && scl->sc->unicodeenc==unienc ) {
    1297           0 :                 baduni = scl->sc;
    1298           0 :                 baduniscl = scl;
    1299             :             }
    1300           0 :             if ( !isnotdef && strcmp(scl->sc->name,name)==0 ) {
    1301           0 :                 badname = scl->sc;
    1302           0 :                 badnamescl = scl;
    1303             :             }
    1304             :         }
    1305           0 :         if ( baduni!=NULL || badname!=NULL ) {
    1306             :             char *buts[3];
    1307           0 :             buts[0] = _("_Yes"); buts[1]=_("_Cancel"); buts[2] = NULL;
    1308           0 :             if ( badname==baduni ) {
    1309           0 :                 if ( ff_ask(_("Multiple"),(const char **) buts,0,1,_("There is already a glyph with this name and encoding,\nboth must be unique within a font,\ndo you want to swap them?"))==1 )
    1310           0 : return( false );
    1311             :                 /* If we're going to swap, then add the swapee to the list of */
    1312             :                 /*  things that need changing */
    1313           0 :                 if ( baduniscl==NULL ) {
    1314           0 :                     baduni = CI_SCDuplicate(baduni);
    1315           0 :                     baduniscl = chunkalloc(sizeof(struct splinecharlist));
    1316           0 :                     baduniscl->sc = baduni;
    1317           0 :                     baduniscl->next = ci->changes;
    1318           0 :                     ci->changes = baduniscl;
    1319             :                 }
    1320           0 :                 baduni->unicodeenc = oldsc->unicodeenc;
    1321           0 :                 free(baduni->name); baduni->name = copy(oldsc->name);
    1322             :             } else {
    1323           0 :                 if ( baduni!=NULL ) {
    1324           0 :                     if ( ff_ask(_("Multiple"),(const char **) buts,0,1,_("There is already a glyph with this encoding,\nwhich must be unique within a font,\ndo you want to swap the encodings of the two?"))==1 )
    1325           0 : return( false );
    1326           0 :                     if ( baduniscl==NULL ) {
    1327           0 :                         baduni = CI_SCDuplicate(baduni);
    1328           0 :                         baduniscl = chunkalloc(sizeof(struct splinecharlist));
    1329           0 :                         baduniscl->sc = baduni;
    1330           0 :                         baduniscl->next = ci->changes;
    1331           0 :                         ci->changes = baduniscl;
    1332             :                     }
    1333           0 :                     baduni->unicodeenc = oldsc->unicodeenc;
    1334             :                 }
    1335           0 :                 if ( badname!=NULL ) {
    1336           0 :                     if ( ff_ask(_("Multiple"),(const char **) buts,0,1,_("There is already a glyph with this name,\nwhich must be unique within a font,\ndo you want to swap the names of the two?"))==1 )
    1337           0 : return( false );
    1338           0 :                     if ( badnamescl==NULL ) {
    1339           0 :                         badname = CI_SCDuplicate(badname);
    1340           0 :                         badnamescl = chunkalloc(sizeof(struct splinecharlist));
    1341           0 :                         badnamescl->sc = badname;
    1342           0 :                         badnamescl->next = ci->changes;
    1343           0 :                         ci->changes = badnamescl;
    1344             :                     }
    1345           0 :                     free(badname->name); badname->name = copy(oldsc->name);
    1346             :                 }
    1347             :             }
    1348             :         }
    1349             :     }
    1350           0 :     if ( !samename )
    1351           0 :         ci->name_change = true;
    1352           0 :     if ( !sameuni )
    1353           0 :         ci->uni_change = true;
    1354           0 :     free( newsc->name ); free( newsc->comment );
    1355           0 :     newsc->name = copy( name );
    1356           0 :     newsc->unicodeenc = unienc;
    1357           0 :     newsc->comment = copy( comment );
    1358           0 : return( true );
    1359             : }
    1360             : 
    1361           0 : static int _CI_OK(CharInfo *ci) {
    1362             :     int val;
    1363             :     int ret;
    1364             :     char *name, *comment;
    1365             :     const unichar_t *nm;
    1366           0 :     int err = false;
    1367             :     int tex_height, tex_depth, italic, topaccent;
    1368             :     int hic, vic;
    1369           0 :     int lc_cnt=-1;
    1370           0 :     char *italicdevtab=NULL, *accentdevtab=NULL, *hicdt=NULL, *vicdt=NULL;
    1371           0 :     int lig_caret_cnt_fixed=0;
    1372             :     int low,high;
    1373           0 :     real tile_margin=0;
    1374             :     DBounds tileb;
    1375           0 :     SplineChar *oldsc = ci->cachedsc==NULL ? ci->sc : ci->cachedsc;
    1376             : 
    1377           0 :     if ( !CI_ValidateAltUnis(ci))
    1378           0 : return( false );
    1379             : 
    1380           0 :     val = ParseUValue(ci->gw,CID_UValue,true);
    1381           0 :     if ( val==-2 )
    1382           0 : return( false );
    1383           0 :     tex_height = gettex(ci->gw,CID_TeX_Height,_("Height"),&err);
    1384           0 :     tex_depth  = gettex(ci->gw,CID_TeX_Depth ,_("Depth") ,&err);
    1385           0 :     italic     = gettex(ci->gw,CID_TeX_Italic,_("Italic Correction"),&err);
    1386           0 :     topaccent  = gettex(ci->gw,CID_HorAccent,_("Top Accent Horizontal Pos"),&err);
    1387           0 :     if ( err )
    1388           0 : return( false );
    1389           0 :     hic = GetInt8(ci->gw,CID_ExtItalicCor+1*100,_("Horizontal Extension Italic Correction"),&err);
    1390           0 :     vic = GetInt8(ci->gw,CID_ExtItalicCor+0*100,_("Vertical Extension Italic Correction"),&err);
    1391           0 :     if ( err )
    1392           0 : return( false );
    1393             : 
    1394           0 :     memset(&tileb,0,sizeof(tileb));
    1395           0 :     if ( ci->sc->parent->multilayer ) {
    1396           0 :         if ( GGadgetIsChecked(GWidgetGetControl(ci->gw,CID_IsTileMargin)))
    1397           0 :             tile_margin = GetReal8(ci->gw,CID_TileMargin,_("Tile Margin"),&err);
    1398             :         else {
    1399           0 :             tileb.minx = GetReal8(ci->gw,CID_TileBBoxMinX,_("Tile Min X"),&err);
    1400           0 :             tileb.miny = GetReal8(ci->gw,CID_TileBBoxMinY,_("Tile Min Y"),&err);
    1401           0 :             tileb.maxx = GetReal8(ci->gw,CID_TileBBoxMaxX,_("Tile Max X"),&err);
    1402           0 :             tileb.maxy = GetReal8(ci->gw,CID_TileBBoxMaxY,_("Tile Max Y"),&err);
    1403             :         }
    1404           0 :         if ( err )
    1405           0 : return( false );
    1406             :     }
    1407             : 
    1408           0 :     lig_caret_cnt_fixed = !GGadgetIsChecked(GWidgetGetControl(ci->gw,CID_DefLCCount));
    1409           0 :     if ( ci->lc_seen ) {
    1410           0 :         lc_cnt = GetInt8(ci->gw,CID_LCCount,_("Ligature Caret Count"),&err);
    1411           0 :         if ( err )
    1412           0 : return( false );
    1413           0 :         if ( lc_cnt<0 || lc_cnt>100 ) {
    1414           0 :             ff_post_error(_("Bad Lig. Caret Count"),_("Unreasonable ligature caret count"));
    1415           0 : return( false );
    1416             :         }
    1417             :     }
    1418           0 :     nm = _GGadgetGetTitle(GWidgetGetControl(ci->gw,CID_UName));
    1419           0 :     if ( !CI_NameCheck(nm) )
    1420           0 : return( false );
    1421             : 
    1422           0 :     italicdevtab = GGadgetGetTitle8(GWidgetGetControl(ci->gw,CID_ItalicDevTab));
    1423           0 :     accentdevtab = GGadgetGetTitle8(GWidgetGetControl(ci->gw,CID_AccentDevTab));
    1424           0 :     hicdt = GGadgetGetTitle8(GWidgetGetControl(ci->gw,CID_ExtItalicDev+1*100));
    1425           0 :     vicdt = GGadgetGetTitle8(GWidgetGetControl(ci->gw,CID_ExtItalicDev+0*100));
    1426           0 :     if ( !DeviceTableOK(italicdevtab,&low,&high) || !DeviceTableOK(accentdevtab,&low,&high) ||
    1427           0 :             !DeviceTableOK(hicdt,&low,&high) || !DeviceTableOK(vicdt,&low,&high)) {
    1428           0 :         ff_post_error( _("Bad Device Table Adjustment"),_("A device table adjustment specified for the MATH table is invalid") );
    1429           0 :         free( accentdevtab );
    1430           0 :         free( italicdevtab );
    1431           0 :         free(hicdt); free(vicdt);
    1432           0 : return( false );
    1433             :     }
    1434           0 :     if ( ci->cachedsc==NULL ) {
    1435             :         struct splinecharlist *scl;
    1436           0 :         ci->cachedsc = chunkalloc(sizeof(SplineChar));
    1437           0 :         ci->cachedsc->orig_pos = ci->sc->orig_pos;
    1438           0 :         ci->cachedsc->parent = ci->sc->parent;
    1439           0 :         scl = chunkalloc(sizeof(struct splinecharlist));
    1440           0 :         scl->sc = ci->cachedsc;
    1441           0 :         scl->next = ci->changes;
    1442           0 :         ci->changes = scl;
    1443             :     }
    1444             :     /* CI_ProcessPosSubs is the first thing which might change anything real */
    1445           0 :     if ( !CI_ProcessPosSubs(ci)) {
    1446           0 :         free( accentdevtab );
    1447           0 :         free( italicdevtab );
    1448           0 :         free(hicdt); free(vicdt);
    1449           0 : return( false );
    1450             :     }
    1451           0 :     name = u2utf8_copy( nm );
    1452           0 :     comment = GGadgetGetTitle8(GWidgetGetControl(ci->gw,CID_Comment));
    1453           0 :     if ( comment!=NULL && *comment=='\0' ) {
    1454           0 :         free(comment);
    1455           0 :         comment=NULL;
    1456             :     }
    1457           0 :     ret = CI_CheckMetaData(ci,oldsc,name,val,comment);
    1458           0 :     free(name); free(comment);
    1459           0 :     if ( !ret ) {
    1460           0 :         free( accentdevtab );
    1461           0 :         free( italicdevtab );
    1462           0 :         free(hicdt); free(vicdt);
    1463           0 : return( false );
    1464             :     }
    1465           0 :     ci->cachedsc->unlink_rm_ovrlp_save_undo = GGadgetIsChecked(GWidgetGetControl(ci->gw,CID_UnlinkRmOverlap));
    1466           0 :     ci->cachedsc->glyph_class = GGadgetGetFirstListSelectedItem(GWidgetGetControl(ci->gw,CID_GClass));
    1467           0 :     val = GGadgetGetFirstListSelectedItem(GWidgetGetControl(ci->gw,CID_Color));
    1468           0 :     if ( val!=-1 )
    1469           0 :         ci->cachedsc->color = (intpt) (std_colors[val].userdata);
    1470           0 :     CI_ParseCounters(ci);
    1471           0 :     ci->cachedsc->tex_height = tex_height;
    1472           0 :     ci->cachedsc->tex_depth  = tex_depth;
    1473           0 :     ci->cachedsc->italic_correction = italic;
    1474           0 :     ci->cachedsc->top_accent_horiz = topaccent;
    1475           0 :     ci->cachedsc->is_extended_shape = GGadgetIsChecked(GWidgetGetControl(ci->gw,CID_IsExtended));
    1476           0 :     ci->cachedsc->italic_adjusts = DeviceTableParse(ci->cachedsc->italic_adjusts,italicdevtab);
    1477           0 :     ci->cachedsc->top_accent_adjusts = DeviceTableParse(ci->cachedsc->top_accent_adjusts,accentdevtab);
    1478           0 :     ci->cachedsc->horiz_variants = CI_ParseVariants(ci->cachedsc->horiz_variants,ci,1,hicdt,hic,false);
    1479           0 :     ci->cachedsc->vert_variants  = CI_ParseVariants(ci->cachedsc->vert_variants ,ci,0,vicdt,vic,false);
    1480             : 
    1481           0 :     free( accentdevtab );
    1482           0 :     free( italicdevtab );
    1483           0 :     free(hicdt); free(vicdt);
    1484             : 
    1485           0 :     CI_ParseAltUnis(ci);
    1486             : 
    1487           0 :     if ( ci->lc_seen ) {
    1488           0 :         PST *pst, *prev=NULL;
    1489             :         int i;
    1490           0 :         ci->cachedsc->lig_caret_cnt_fixed = lig_caret_cnt_fixed;
    1491           0 :         for ( pst = ci->cachedsc->possub; pst!=NULL && pst->type!=pst_lcaret; pst=pst->next )
    1492           0 :             prev = pst;
    1493           0 :         if ( pst==NULL && lc_cnt==0 )
    1494             :             /* Nothing to do */;
    1495           0 :         else if ( pst!=NULL && lc_cnt==0 ) {
    1496           0 :             if ( prev==NULL )
    1497           0 :                 ci->cachedsc->possub = pst->next;
    1498             :             else
    1499           0 :                 prev->next = pst->next;
    1500           0 :             pst->next = NULL;
    1501           0 :             PSTFree(pst);
    1502             :         } else {
    1503           0 :             if ( pst==NULL ) {
    1504           0 :                 pst = chunkalloc(sizeof(PST));
    1505           0 :                 pst->type = pst_lcaret;
    1506           0 :                 pst->next = ci->sc->possub;
    1507           0 :                 ci->cachedsc->possub = pst;
    1508             :             }
    1509           0 :             if ( lc_cnt>pst->u.lcaret.cnt )
    1510           0 :                 pst->u.lcaret.carets = realloc(pst->u.lcaret.carets,lc_cnt*sizeof(int16));
    1511           0 :             for ( i=pst->u.lcaret.cnt; i<lc_cnt; ++i )
    1512           0 :                 pst->u.lcaret.carets[i] = 0;
    1513           0 :             pst->u.lcaret.cnt = lc_cnt;
    1514             :         }
    1515             :     }
    1516             : 
    1517           0 :     ci->cachedsc->tile_margin = tile_margin;
    1518           0 :     ci->cachedsc->tile_bounds = tileb;
    1519             : 
    1520           0 : return( ret );
    1521             : }
    1522             : 
    1523           0 : static void CI_ApplyAll(CharInfo *ci) {
    1524           0 :     int refresh_fvdi = false;
    1525             :     struct splinecharlist *scl;
    1526             :     SplineChar *cached, *sc;
    1527           0 :     SplineFont *sf = ci->sc->parent;
    1528             :     FontView *fvs;
    1529             : 
    1530           0 :     for ( scl = ci->changes; scl!=NULL; scl=scl->next ) {
    1531           0 :         cached = scl->sc;
    1532           0 :         sc = sf->glyphs[cached->orig_pos];
    1533           0 :         SCPreserveState(sc,2);
    1534           0 :         if ( strcmp(cached->name,sc->name)!=0 || cached->unicodeenc!=sc->unicodeenc )
    1535           0 :             refresh_fvdi = 1;
    1536           0 :         if ( sc->name==NULL || strcmp( sc->name,cached->name )!=0 ) {
    1537           0 :             if ( sc->name!=NULL )
    1538           0 :                 SFGlyphRenameFixup(sf,sc->name,cached->name,false);
    1539           0 :             free(sc->name); sc->name = copy(cached->name);
    1540           0 :             sc->namechanged = true;
    1541           0 :             GlyphHashFree(sf);
    1542             :         }
    1543           0 :         if ( sc->unicodeenc != cached->unicodeenc ) {
    1544             :             struct splinecharlist *scl;
    1545             :             int layer;
    1546             :             RefChar *ref;
    1547             :             struct altuni *alt;
    1548             : 
    1549             :             /* All references need the new unicode value */
    1550           0 :             for ( scl=sc->dependents; scl!=NULL; scl=scl->next ) {
    1551           0 :                 for ( layer=ly_back; layer<scl->sc->layer_cnt; ++layer )
    1552           0 :                     for ( ref = scl->sc->layers[layer].refs; ref!=NULL; ref=ref->next )
    1553           0 :                         if ( ref->sc==sc )
    1554           0 :                             ref->unicode_enc = cached->unicodeenc;
    1555             :             }
    1556             :             /* If the current unicode enc were in the list of alt unis */
    1557             :             /*  the user might have forgotten to remove it. So if s/he did */
    1558             :             /*  forget, swap the altuni value with the old value */
    1559           0 :             for ( alt=cached->altuni; alt!=NULL && (alt->unienc!=cached->unicodeenc || alt->vs!=-1 || alt->fid!=0); alt=alt->next );
    1560           0 :             if ( alt!=NULL )    /* alt->unienc==new value */
    1561           0 :                 alt->unienc = sc->unicodeenc;
    1562           0 :             sc->unicodeenc = cached->unicodeenc;
    1563             :         }
    1564           0 :         free(sc->comment); sc->comment = copy(cached->comment);
    1565           0 :         sc->unlink_rm_ovrlp_save_undo = cached->unlink_rm_ovrlp_save_undo;
    1566           0 :         sc->glyph_class = cached->glyph_class;
    1567           0 :         if ( sc->color != cached->color )
    1568           0 :             refresh_fvdi = true;
    1569           0 :         sc->color = cached->color;
    1570           0 :         free(sc->countermasks);
    1571           0 :         sc->countermask_cnt = cached->countermask_cnt;
    1572           0 :         sc->countermasks = cached->countermasks;
    1573           0 :         cached->countermasks = NULL; cached->countermask_cnt = 0;
    1574           0 :         sc->tex_height = cached->tex_height;
    1575           0 :         sc->tex_depth  = cached->tex_depth;
    1576           0 :         sc->italic_correction = cached->italic_correction;
    1577           0 :         sc->top_accent_horiz = cached->top_accent_horiz;
    1578           0 :         sc->is_extended_shape = cached->is_extended_shape;
    1579           0 :         DeviceTableFree(sc->italic_adjusts);
    1580           0 :         DeviceTableFree(sc->top_accent_adjusts);
    1581           0 :         sc->italic_adjusts = cached->italic_adjusts;
    1582           0 :         sc->top_accent_adjusts = cached->top_accent_adjusts;
    1583           0 :         cached->italic_adjusts = cached->top_accent_adjusts = NULL;
    1584           0 :         GlyphVariantsFree(sc->horiz_variants);
    1585           0 :         GlyphVariantsFree(sc->vert_variants);
    1586           0 :         sc->horiz_variants = cached->horiz_variants;
    1587           0 :         sc->vert_variants = cached->vert_variants;
    1588           0 :         cached->horiz_variants = cached->vert_variants = NULL;
    1589           0 :         AltUniFree(sc->altuni);
    1590           0 :         sc->altuni = cached->altuni;
    1591           0 :         cached->altuni = NULL;
    1592           0 :         sc->lig_caret_cnt_fixed = cached->lig_caret_cnt_fixed;
    1593           0 :         PSTFree(sc->possub);
    1594           0 :         sc->possub = cached->possub;
    1595           0 :         cached->possub = NULL;
    1596           0 :         KernPairsFree(sc->kerns); KernPairsFree(sc->vkerns);
    1597           0 :         sc->kerns = cached->kerns; sc->vkerns = cached->vkerns;
    1598           0 :         cached->kerns = cached->vkerns = NULL;
    1599           0 :         sc->tile_margin = cached->tile_margin;
    1600           0 :         sc->tile_bounds = cached->tile_bounds;
    1601           0 :         if ( !sc->changed ) {
    1602           0 :             sc->changed = true;
    1603           0 :             refresh_fvdi = true;
    1604             :         }
    1605           0 :         SCRefreshTitles(sc);
    1606             :     }
    1607           0 :     if ( ci->name_change || ci->uni_change ) {
    1608           0 :         for ( fvs=(FontView *) sf->fv; fvs!=NULL; fvs=(FontView *) fvs->b.nextsame ) {
    1609             :             /* Postscript encodings are by name, others are by unicode */
    1610             :             /* Hence slight differences in when we update the encoding */
    1611           0 :             if ( (ci->name_change && fvs->b.map->enc->psnames!=NULL ) ||
    1612           0 :                     (ci->uni_change && fvs->b.map->enc->psnames==NULL )) {
    1613           0 :                 fvs->b.map->enc = &custom;
    1614           0 :                 FVSetTitle((FontViewBase *) fvs);
    1615           0 :                 refresh_fvdi = true;
    1616             :             }
    1617             :         }
    1618             :     }
    1619           0 :     if ( refresh_fvdi ) {
    1620           0 :         for ( fvs=(FontView *) sf->fv; fvs!=NULL; fvs=(FontView *) fvs->b.nextsame ) {
    1621           0 :             GDrawRequestExpose(fvs->gw,NULL,false);  /* Redraw info area just in case this char is selected */
    1622           0 :             GDrawRequestExpose(fvs->v,NULL,false);   /* Redraw character area in case this char is on screen */
    1623             :         }
    1624             :     }
    1625           0 :     if ( ci->changes )
    1626           0 :         sf->changed = true;
    1627           0 : }
    1628             : 
    1629           0 : static void CI_Finish(CharInfo *ci) {
    1630             :     struct splinecharlist *scl, *next;
    1631             : 
    1632           0 :     for ( scl=ci->changes; scl!=NULL; scl=next ) {
    1633           0 :         next = scl->next;
    1634           0 :         SplineCharFree(scl->sc);
    1635           0 :         chunkfree(scl,sizeof(*scl));
    1636             :     }
    1637           0 :     GDrawDestroyWindow(ci->gw);
    1638           0 : }
    1639             : 
    1640           0 : static int CI_OK(GGadget *g, GEvent *e) {
    1641           0 :     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
    1642           0 :         CharInfo *ci = GDrawGetUserData(GGadgetGetWindow(g));
    1643           0 :         if ( _CI_OK(ci) ) {
    1644           0 :             CI_ApplyAll(ci);
    1645           0 :             CI_Finish(ci);
    1646             :         }
    1647             :     }
    1648           0 : return( true );
    1649             : }
    1650             : 
    1651           0 : static void CI_BoundsToMargin(CharInfo *ci) {
    1652           0 :     int err=false;
    1653           0 :     real margin = GetCalmReal8(ci->gw,CID_TileMargin,NULL,&err);
    1654             :     DBounds b;
    1655             :     char buffer[40];
    1656             : 
    1657           0 :     if ( err )
    1658           0 : return;
    1659           0 :     SplineCharFindBounds(ci->sc,&b);
    1660           0 :     sprintf( buffer, "%g", (double)(b.minx-margin) );
    1661           0 :     GGadgetSetTitle8(GWidgetGetControl(ci->gw,CID_TileBBoxMinX),buffer);
    1662           0 :     sprintf( buffer, "%g", (double)(b.miny-margin) );
    1663           0 :     GGadgetSetTitle8(GWidgetGetControl(ci->gw,CID_TileBBoxMinY),buffer);
    1664           0 :     sprintf( buffer, "%g", (double)(b.maxx+margin) );
    1665           0 :     GGadgetSetTitle8(GWidgetGetControl(ci->gw,CID_TileBBoxMaxX),buffer);
    1666           0 :     sprintf( buffer, "%g", (double)(b.maxy+margin) );
    1667           0 :     GGadgetSetTitle8(GWidgetGetControl(ci->gw,CID_TileBBoxMaxY),buffer);
    1668             : }
    1669             : 
    1670           0 : static int CI_TileMarginChange(GGadget *g, GEvent *e) {
    1671           0 :     CharInfo *ci = GDrawGetUserData(GGadgetGetWindow(g));
    1672             : 
    1673           0 :     if ( e->type==et_controlevent && e->u.control.subtype == et_textfocuschanged &&
    1674           0 :             e->u.control.u.tf_focus.gained_focus )
    1675           0 :         GGadgetSetChecked(GWidgetGetControl(ci->gw,CID_IsTileMargin),true);
    1676           0 :     else if ( e->type==et_controlevent && e->u.control.subtype == et_textchanged )
    1677           0 :         CI_BoundsToMargin(ci);
    1678           0 : return( true );
    1679             : }
    1680             : 
    1681             : /* Generate default settings for the entries in ligature lookup
    1682             :  * subtables. */
    1683           0 : static char *LigDefaultStr(int uni, char *name, int alt_lig ) {
    1684           0 :     const unichar_t *alt=NULL, *pt;
    1685           0 :     char *components = NULL, *tmp;
    1686             :     int len;
    1687             :     unichar_t hack[30], *upt;
    1688             :     char buffer[80];
    1689             : 
    1690             :     /* If it's not (bmp) unicode we have no info on it */
    1691             :     /*  Unless it looks like one of adobe's special ligature names */
    1692           0 :     if ( uni==-1 || uni>=0x10000 )
    1693             :         /* Nope */;
    1694           0 :     else if ( isdecompositionnormative(uni) &&
    1695           0 :                 unicode_alternates[uni>>8]!=NULL &&
    1696           0 :                 (alt = unicode_alternates[uni>>8][uni&0xff])!=NULL ) {
    1697           0 :         if ( alt[1]=='\0' )
    1698           0 :             alt = NULL;         /* Single replacements aren't ligatures */
    1699           0 :         else if ( iscombining(alt[1]) && ( alt[2]=='\0' || iscombining(alt[2]))) {
    1700           0 :             if ( alt_lig != -10 )       /* alt_lig = 10 => mac unicode decomp */
    1701           0 :                 alt = NULL;             /* Otherwise, don't treat accented letters as ligatures */
    1702           0 :         } else if (! is_LIGATURE_or_VULGAR_FRACTION((uint32)(uni)) &&
    1703           0 :                 uni!=0x152 && uni!=0x153 &&     /* oe ligature should not be standard */
    1704           0 :                 uni!=0x132 && uni!=0x133 &&     /* nor ij */
    1705           0 :                 (uni<0xfb2a || uni>0xfb4f) &&     /* Allow hebrew precomposed chars */
    1706           0 :                 uni!=0x215f &&
    1707           0 :                 !((uni>=0x0958 && uni<=0x095f) || uni==0x929 || uni==0x931 || uni==0x934)) {
    1708           0 :             alt = NULL;
    1709           0 :         } else if ( (tmp=unicode_name(65))==NULL ) { /* test for 'A' to see if library exists */
    1710           0 :             if ( (uni>=0xbc && uni<=0xbe ) ||             /* Latin1 fractions */
    1711           0 :                     (uni>=0x2153 && uni<=0x215e ) ||      /* other fractions */
    1712           0 :                     (uni>=0xfb00 && uni<=0xfb06 ) ||      /* latin ligatures */
    1713           0 :                     (uni>=0xfb13 && uni<=0xfb17 ) ||      /* armenian ligatures */
    1714           0 :                     uni==0xfb17 ||                      /* hebrew ligature */
    1715           0 :                     (uni>=0xfb2a && uni<=0xfb4f ) ||      /* hebrew precomposed chars */
    1716           0 :                     (uni>=0xfbea && uni<=0xfdcf ) ||      /* arabic ligatures */
    1717           0 :                     (uni>=0xfdf0 && uni<=0xfdfb ) ||      /* arabic ligatures */
    1718           0 :                     (uni>=0xfef5 && uni<=0xfefc ))        /* arabic ligatures */
    1719             :                 ;       /* These are good */
    1720             :             else
    1721           0 :                 alt = NULL;
    1722             :         } else
    1723           0 :             free(tmp); /* found 'A' means there is a library, now cleanup */
    1724             :     }
    1725           0 :     if ( alt==NULL ) {
    1726           0 :         if ( name==NULL || alt_lig )
    1727           0 : return( NULL );
    1728             :         else
    1729           0 : return( AdobeLigatureFormat(name));
    1730             :     }
    1731             : 
    1732           0 :     if ( uni==0xfb03 && alt_lig==1 )
    1733           0 :         components = copy("ff i");
    1734           0 :     else if ( uni==0xfb04 && alt_lig==1 )
    1735           0 :         components = copy("ff l");
    1736           0 :     else if ( alt!=NULL ) {
    1737           0 :         if ( alt[1]==0x2044 && (alt[2]==0 || alt[3]==0) && alt_lig==1 ) {
    1738           0 :             u_strcpy(hack,alt);
    1739           0 :             hack[1] = '/';
    1740           0 :             alt = hack;
    1741           0 :         } else if ( alt_lig>0 )
    1742           0 : return( NULL );
    1743             : 
    1744           0 :         if ( isarabisolated(uni) || isarabinitial(uni) || isarabmedial(uni) || isarabfinal(uni) ) {
    1745             :             /* If it is arabic, then convert from the unformed version to the formed */
    1746           0 :             if ( u_strlen(alt)<sizeof(hack)/sizeof(hack[0])-1 ) {
    1747           0 :                 u_strcpy(hack,alt);
    1748           0 :                 for ( upt=hack ; *upt ; ++upt ) {
    1749             :                     /* Make everything medial */
    1750           0 :                     if ( *upt>=0x600 && *upt<=0x6ff )
    1751           0 :                         *upt = ArabicForms[*upt-0x600].medial;
    1752             :                 }
    1753           0 :                 if ( isarabisolated(uni) || isarabfinal(uni) ) {
    1754           0 :                     int len = upt-hack-1;
    1755           0 :                     if ( alt[len]>=0x600 && alt[len]<=0x6ff )
    1756           0 :                         hack[len] = ArabicForms[alt[len]-0x600].final;
    1757             :                 }
    1758           0 :                 if ( isarabisolated(uni) || isarabinitial(uni) ) {
    1759           0 :                     if ( alt[0]>=0x600 && alt[0]<=0x6ff )
    1760           0 :                         hack[0] = ArabicForms[alt[0]-0x600].initial;
    1761             :                 }
    1762           0 :                 alt = hack;
    1763             :             }
    1764             :         }
    1765             : 
    1766           0 :         components=NULL;
    1767             :         while ( 1 ) {
    1768           0 :             len = 0;
    1769           0 :             for ( pt=alt; *pt; ++pt ) {
    1770           0 :                 if ( components==NULL ) {
    1771           0 :                     len += strlen(StdGlyphName(buffer,*pt,ui_none,(NameList *)-1))+1;
    1772             :                 } else {
    1773           0 :                     const char *temp = StdGlyphName(buffer,*pt,ui_none,(NameList *)-1);
    1774           0 :                     strcpy(components+len,temp);
    1775           0 :                     len += strlen( temp );
    1776           0 :                     components[len++] = ' ';
    1777             :                 }
    1778             :             }
    1779           0 :             if ( components!=NULL )
    1780           0 :         break;
    1781           0 :             components = malloc(len+1);
    1782           0 :         }
    1783           0 :         components[len-1] = '\0';
    1784             :     }
    1785           0 : return( components );
    1786             : }
    1787             : 
    1788           0 : char *AdobeLigatureFormat(char *name) {
    1789             :     /* There are two formats for ligs: <glyph-name>_<glyph-name>{...} or */
    1790             :     /*  uni<code><code>{...} (only works for BMP) */
    1791             :     /* I'm not checking to see if all the components are valid */
    1792             :     char *components, *pt, buffer[12];
    1793             :     const char *next;
    1794           0 :     int len = strlen(name), uni;
    1795             : 
    1796           0 :     if ( strncmp(name,"uni",3)==0 && (len-3)%4==0 && len>7 ) {
    1797           0 :         pt = name+3;
    1798           0 :         components = malloc(1); *components = '\0';
    1799           0 :         while ( *pt ) {
    1800           0 :             if ( sscanf(pt,"%4x", (unsigned *) &uni )==0 ) {
    1801           0 :                 free(components); components = NULL;
    1802           0 :         break;
    1803             :             }
    1804           0 :             next = StdGlyphName(buffer,uni,ui_none,(NameList *)-1);
    1805           0 :             components = realloc(components,strlen(components) + strlen(next) + 2);
    1806           0 :             if ( *components!='\0' )
    1807           0 :                 strcat(components," ");
    1808           0 :             strcat(components,next);
    1809           0 :             pt += 4;
    1810             :         }
    1811           0 :         if ( components!=NULL )
    1812           0 : return( components );
    1813             :     }
    1814             : 
    1815           0 :     if ( strchr(name,'_')==NULL )
    1816           0 : return( NULL );
    1817           0 :     pt = components = copy(name);
    1818           0 :     while ( (pt = strchr(pt,'_'))!=NULL )
    1819           0 :         *pt = ' ';
    1820           0 : return( components );
    1821             : }
    1822             : 
    1823           0 : uint32 LigTagFromUnicode(int uni) {
    1824           0 :     int tag = CHR('l','i','g','a');     /* standard */
    1825             : 
    1826           0 :     if (( uni>=0xbc && uni<=0xbe ) || (uni>=0x2153 && uni<=0x215f) )
    1827           0 :         tag = CHR('f','r','a','c');     /* Fraction */
    1828             :     /* hebrew precomposed characters */
    1829           0 :     else if ( uni>=0xfb2a && uni<=0xfb4e )
    1830           0 :         tag = CHR('c','c','m','p');
    1831           0 :     else if ( uni==0xfb4f )
    1832           0 :         tag = CHR('h','l','i','g');
    1833             :     /* armenian */
    1834           0 :     else if ( uni>=0xfb13 && uni<=0xfb17 )
    1835           0 :         tag = CHR('l','i','g','a');
    1836             :     /* devanagari ligatures */
    1837           0 :     else if ( (uni>=0x0958 && uni<=0x095f) || uni==0x931 || uni==0x934 || uni==0x929 )
    1838           0 :         tag = CHR('n','u','k','t');
    1839           0 :     else switch ( uni ) {
    1840             :       case 0xfb05:              /* long-s t */
    1841             :         /* This should be 'liga' for long-s+t and 'hlig' for s+t */
    1842           0 :         tag = CHR('l','i','g','a');
    1843           0 :       break;
    1844             :       case 0x00c6: case 0x00e6:         /* ae, AE */
    1845             :       case 0x0152: case 0x0153:         /* oe, OE */
    1846             :       case 0x0132: case 0x0133:         /* ij, IJ */
    1847             :       case 0xfb06:                      /* s t */
    1848           0 :         tag = CHR('d','l','i','g');
    1849           0 :       break;
    1850             :       case 0xfefb: case 0xfefc: /* Lam & Alef, required ligs */
    1851           0 :         tag = CHR('r','l','i','g');
    1852           0 :       break;
    1853             :     }
    1854           0 : return( tag );
    1855             : }
    1856             : 
    1857           0 : SplineChar *SuffixCheck(SplineChar *sc,char *suffix) {
    1858           0 :     SplineChar *alt = NULL;
    1859           0 :     SplineFont *sf = sc->parent;
    1860             :     char namebuf[200];
    1861             : 
    1862           0 :     if ( *suffix=='.' ) ++suffix;
    1863           0 :     if ( sf->cidmaster!=NULL ) {
    1864           0 :         sprintf( namebuf, "%.20s.%d.%.80s", sf->cidmaster->ordering, sc->orig_pos, suffix );
    1865           0 :         alt = SFGetChar(sf,-1,namebuf);
    1866           0 :         if ( alt==NULL ) {
    1867           0 :             sprintf( namebuf, "cid-%d.%.80s", sc->orig_pos, suffix );
    1868           0 :             alt = SFGetChar(sf,-1,namebuf);
    1869             :         }
    1870             :     }
    1871           0 :     if ( alt==NULL && sc->unicodeenc!=-1 ) {
    1872           0 :         sprintf( namebuf, "uni%04X.%.80s", sc->unicodeenc, suffix );
    1873           0 :         alt = SFGetChar(sf,-1,namebuf);
    1874             :     }
    1875           0 :     if ( alt==NULL ) {
    1876           0 :         sprintf( namebuf, "glyph%d.%.80s", sc->orig_pos, suffix );
    1877           0 :         alt = SFGetChar(sf,-1,namebuf);
    1878             :     }
    1879           0 :     if ( alt==NULL ) {
    1880           0 :         sprintf( namebuf, "%.80s.%.80s", sc->name, suffix );
    1881           0 :         alt = SFGetChar(sf,-1,namebuf);
    1882             :     }
    1883           0 : return( alt );
    1884             : }
    1885             : 
    1886           0 : static SplineChar *SuffixCheckCase(SplineChar *sc,char *suffix, int cvt2lc ) {
    1887           0 :     SplineChar *alt = NULL;
    1888           0 :     SplineFont *sf = sc->parent;
    1889             :     char namebuf[100];
    1890             : 
    1891           0 :     if ( *suffix=='.' ) ++suffix;
    1892           0 :     if ( sf->cidmaster!=NULL )
    1893           0 : return( NULL );
    1894             : 
    1895             :     /* Small cap characters are sometimes named "a.sc" */
    1896             :     /*  and sometimes "A.small" */
    1897             :     /* So if I want a 'smcp' feature I must convert "a" to "A.small" */
    1898             :     /* And if I want a 'c2sc' feature I must convert "A" to "a.sc" */
    1899           0 :     if ( cvt2lc ) {
    1900           0 :         if ( alt==NULL && sc->unicodeenc!=-1 && sc->unicodeenc<0x10000 &&
    1901           0 :                 isupper(sc->unicodeenc)) {
    1902           0 :             sprintf( namebuf, "uni%04X.%s", tolower(sc->unicodeenc), suffix );
    1903           0 :             alt = SFGetChar(sf,-1,namebuf);
    1904             :         }
    1905           0 :         if ( alt==NULL && isupper(*sc->name)) {
    1906           0 :             sprintf( namebuf, "%c%s.%s", tolower(*sc->name), sc->name+1, suffix );
    1907           0 :             alt = SFGetChar(sf,-1,namebuf);
    1908             :         }
    1909             :     } else {
    1910           0 :         if ( alt==NULL && sc->unicodeenc!=-1 && sc->unicodeenc<0x10000 &&
    1911           0 :                 islower(sc->unicodeenc)) {
    1912           0 :             sprintf( namebuf, "uni%04X.%s", toupper(sc->unicodeenc), suffix );
    1913           0 :             alt = SFGetChar(sf,-1,namebuf);
    1914             :         }
    1915           0 :         if ( alt==NULL && islower(*sc->name)) {
    1916           0 :             sprintf( namebuf, "%c%s.%s", toupper(*sc->name), sc->name+1, suffix );
    1917           0 :             alt = SFGetChar(sf,-1,namebuf);
    1918             :         }
    1919             :     }
    1920           0 : return( alt );
    1921             : }
    1922             : 
    1923           0 : void SCLigCaretCheck(SplineChar *sc,int clean) {
    1924           0 :     PST *pst, *carets=NULL, *prev_carets=NULL, *prev;
    1925           0 :     int lig_comp_max=0, lc, i;
    1926             :     char *pt;
    1927             :     /* Check to see if this is a ligature character, and if so, does it have */
    1928             :     /*  a ligature caret structure. If a lig but no lig caret structure then */
    1929             :     /*  create a lig caret struct */
    1930             :     /* This is not entirely sufficient. If we have an old type1 font with afm */
    1931             :     /*  file then there was no way of saying "ffi = f + f + i" instead you    */
    1932             :     /*  said "ffi = ff + i" (only two component ligatures allowed). This means*/
    1933             :     /*  we'd get the wrong number of lcaret positions */
    1934             : 
    1935           0 :     if ( sc->lig_caret_cnt_fixed )
    1936           0 : return;
    1937             : 
    1938           0 :     for ( pst=sc->possub, prev=NULL; pst!=NULL; prev = pst, pst=pst->next ) {
    1939           0 :         if ( pst->type == pst_lcaret ) {
    1940           0 :             if ( carets!=NULL )
    1941           0 :                 IError("Too many ligature caret structures" );
    1942             :             else {
    1943           0 :                 carets = pst;
    1944           0 :                 prev_carets = prev;
    1945             :             }
    1946           0 :         } else if ( pst->type==pst_ligature ) {
    1947           0 :             for ( lc=0, pt=pst->u.lig.components; *pt; ++pt )
    1948           0 :                 if ( *pt==' ' ) ++lc;
    1949           0 :             if ( lc>lig_comp_max )
    1950           0 :                 lig_comp_max = lc;
    1951             :         }
    1952             :     }
    1953           0 :     if ( lig_comp_max == 0 ) {
    1954           0 :         if ( clean && carets!=NULL ) {
    1955           0 :             if ( prev_carets==NULL )
    1956           0 :                 sc->possub = carets->next;
    1957             :             else
    1958           0 :                 prev_carets->next = carets->next;
    1959           0 :             carets->next = NULL;
    1960           0 :             PSTFree(carets);
    1961             :         }
    1962           0 : return;
    1963             :     }
    1964           0 :     if ( carets==NULL ) {
    1965           0 :         carets = chunkalloc(sizeof(PST));
    1966           0 :         carets->type = pst_lcaret;
    1967           0 :         carets->subtable = NULL;             /* Not relevant here */
    1968           0 :         carets->next = sc->possub;
    1969           0 :         sc->possub = carets;
    1970             :     }
    1971           0 :     if ( carets->u.lcaret.cnt>=lig_comp_max ) {
    1972           0 :         carets->u.lcaret.cnt = lig_comp_max;
    1973           0 : return;
    1974             :     }
    1975           0 :     if ( carets->u.lcaret.carets==NULL )
    1976           0 :         carets->u.lcaret.carets = (int16 *) calloc(lig_comp_max,sizeof(int16));
    1977             :     else {
    1978           0 :         carets->u.lcaret.carets = (int16 *) realloc(carets->u.lcaret.carets,lig_comp_max*sizeof(int16));
    1979           0 :         for ( i=carets->u.lcaret.cnt; i<lig_comp_max; ++i )
    1980           0 :             carets->u.lcaret.carets[i] = 0;
    1981             :     }
    1982           0 :     carets->u.lcaret.cnt = lig_comp_max;
    1983             : }
    1984             : 
    1985           0 : static int CI_SName(GGadget *g, GEvent *e) {    /* Set From Name */
    1986           0 :     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
    1987           0 :         CharInfo *ci = GDrawGetUserData(GGadgetGetWindow(g));
    1988           0 :         const unichar_t *ret = _GGadgetGetTitle(GWidgetGetControl(ci->gw,CID_UName));
    1989             :         int i;
    1990             :         char buf[40], *ctemp; unichar_t ubuf[2], *temp;
    1991           0 :         ctemp = u2utf8_copy(ret);
    1992           0 :         i = UniFromName(ctemp,ui_none,&custom);
    1993           0 :         free(ctemp);
    1994           0 :         if ( i==-1 ) {
    1995             :             /* Adobe says names like uni00410042 represent a ligature (A&B) */
    1996             :             /*  (that is "uni" followed by two (or more) 4-digit codes). */
    1997             :             /* But that names outside of BMP should be uXXXX or uXXXXX or uXXXXXX */
    1998           0 :             if ( ret[0]=='u' && ret[1]!='n' && u_strlen(ret)<=1+6 ) {
    1999             :                 unichar_t *end;
    2000           0 :                 i = u_strtol(ret+1,&end,16);
    2001           0 :                 if ( *end )
    2002           0 :                     i = -1;
    2003             :                 else            /* Make sure it is properly capitalized */
    2004           0 :                     SetNameFromUnicode(ci->gw,CID_UName,i);
    2005             :             }
    2006             :         }
    2007             : 
    2008           0 :         sprintf(buf,"U+%04x", i);
    2009           0 :         temp = uc_copy(i==-1?"-1":buf);
    2010           0 :         GGadgetSetTitle(GWidgetGetControl(ci->gw,CID_UValue),temp);
    2011           0 :         free(temp);
    2012             : 
    2013           0 :         ubuf[0] = i;
    2014           0 :         if ( i==-1 || i>0xffff )
    2015           0 :             ubuf[0] = '\0';
    2016           0 :         ubuf[1] = '\0';
    2017           0 :         GGadgetSetTitle(GWidgetGetControl(ci->gw,CID_UChar),ubuf);
    2018             :     }
    2019           0 : return( true );
    2020             : }
    2021             : 
    2022           0 : static int CI_SValue(GGadget *g, GEvent *e) {   /* Set From Value */
    2023           0 :     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
    2024           0 :         CharInfo *ci = GDrawGetUserData(GGadgetGetWindow(g));
    2025             :         unichar_t ubuf[2];
    2026             :         int val;
    2027             : 
    2028           0 :         val = ParseUValue(ci->gw,CID_UValue,false);
    2029           0 :         if ( val<0 )
    2030           0 : return( true );
    2031             : 
    2032           0 :         SetNameFromUnicode(ci->gw,CID_UName,val);
    2033             : 
    2034           0 :         ubuf[0] = val;
    2035           0 :         if ( val==-1 )
    2036           0 :             ubuf[0] = '\0';
    2037           0 :         ubuf[1] = '\0';
    2038           0 :         GGadgetSetTitle(GWidgetGetControl(ci->gw,CID_UChar),ubuf);
    2039             :     }
    2040           0 : return( true );
    2041             : }
    2042             : 
    2043           0 : GTextInfo *TIFromName(const char *name) {
    2044           0 :     GTextInfo *ti = calloc(1,sizeof(GTextInfo));
    2045           0 :     ti->text = utf82u_copy(name);
    2046           0 :     ti->fg = COLOR_DEFAULT;
    2047           0 :     ti->bg = COLOR_DEFAULT;
    2048           0 : return( ti );
    2049             : }
    2050             : 
    2051           0 : static void CI_SetNameList(CharInfo *ci,int val) {
    2052           0 :     GGadget *g = GWidgetGetControl(ci->gw,CID_UName);
    2053             :     int cnt;
    2054             : 
    2055           0 :     if ( GGadgetGetUserData(g)==(void *) (intpt) val )
    2056           0 : return;         /* Didn't change */
    2057             :     {
    2058           0 :         GTextInfo **list = NULL;
    2059           0 :         char **names = AllGlyphNames(val,ci->sc->parent->for_new_glyphs,ci->sc);
    2060             : 
    2061           0 :         for ( cnt=0; names[cnt]!=NULL; ++cnt );
    2062           0 :         list = malloc((cnt+1)*sizeof(GTextInfo*)); 
    2063           0 :         for ( cnt=0; names[cnt]!=NULL; ++cnt ) {
    2064           0 :             list[cnt] = TIFromName(names[cnt]);
    2065           0 :             free(names[cnt]);
    2066             :         }
    2067           0 :         free(names);
    2068           0 :         list[cnt] = TIFromName(NULL);
    2069           0 :         GGadgetSetList(g,list,true);
    2070             :     }
    2071           0 :     GGadgetSetUserData(g,(void *) (intpt) val);
    2072             : }
    2073             : 
    2074           0 : static int CI_UValChanged(GGadget *g, GEvent *e) {
    2075           0 :     if ( e->type==et_controlevent && e->u.control.subtype == et_textchanged ) {
    2076           0 :         CharInfo *ci = GDrawGetUserData(GGadgetGetWindow(g));
    2077           0 :         const unichar_t *ret = _GGadgetGetTitle(GWidgetGetControl(ci->gw,CID_UValue));
    2078             :         unichar_t *end;
    2079             :         int val;
    2080             : 
    2081           0 :         if (( *ret=='U' || *ret=='u' ) && ret[1]=='+' )
    2082           0 :             ret += 2;
    2083           0 :         val = u_strtol(ret,&end,16);
    2084           0 :         if ( *end=='\0' )
    2085           0 :             CI_SetNameList(ci,val);
    2086             :     }
    2087           0 : return( true );
    2088             : }
    2089             : 
    2090           0 : static int CI_CharChanged(GGadget *g, GEvent *e) {
    2091           0 :     if ( e->type==et_controlevent && e->u.control.subtype == et_textchanged ) {
    2092           0 :         CharInfo *ci = GDrawGetUserData(GGadgetGetWindow(g));
    2093           0 :         const unichar_t *ret = _GGadgetGetTitle(GWidgetGetControl(ci->gw,CID_UChar));
    2094           0 :         int val = *ret;
    2095             :         unichar_t *temp, ubuf[2]; char buf[10];
    2096             : 
    2097           0 :         if ( ret[0]=='\0' )
    2098           0 : return( true );
    2099           0 :         else if ( ret[1]!='\0' ) {
    2100           0 :             ff_post_notice(_("Only a single character allowed"),_("Only a single character allowed"));
    2101           0 :             ubuf[0] = ret[0];
    2102           0 :             ubuf[1] = '\0';
    2103           0 :             GGadgetSetTitle(GWidgetGetControl(ci->gw,CID_UChar),ubuf);
    2104           0 : return( true );
    2105             :         }
    2106             : 
    2107           0 :         SetNameFromUnicode(ci->gw,CID_UName,val);
    2108           0 :         CI_SetNameList(ci,val);
    2109             : 
    2110           0 :         sprintf(buf,"U+%04x", val);
    2111           0 :         temp = uc_copy(buf);
    2112           0 :         GGadgetSetTitle(GWidgetGetControl(ci->gw,CID_UValue),temp);
    2113           0 :         free(temp);
    2114             :     }
    2115           0 : return( true );
    2116             : }
    2117             : 
    2118           0 : static int CI_CommentChanged(GGadget *g, GEvent *e) {
    2119           0 :     if ( e->type==et_controlevent && e->u.control.subtype == et_textchanged ) {
    2120           0 :         CharInfo *ci = GDrawGetUserData(GGadgetGetWindow(g));
    2121             :         /* Let's give things with comments a white color. This may not be a good idea */
    2122           0 :         if ( ci->first && ci->sc->color==COLOR_DEFAULT &&
    2123           0 :                 0==GGadgetGetFirstListSelectedItem(GWidgetGetControl(ci->gw,CID_Color)) )
    2124           0 :             GGadgetSelectOneListItem(GWidgetGetControl(ci->gw,CID_Color),1);
    2125           0 :         ci->first = false;
    2126             :     }
    2127           0 : return( true );
    2128             : }
    2129             : 
    2130             : struct devtab_dlg {
    2131             :     int done;
    2132             :     GWindow gw;
    2133             :     GGadget *gme;
    2134             :     DeviceTable devtab;
    2135             : };
    2136             : 
    2137             : static struct col_init devtabci[] = {
    2138             :     { me_int, NULL, NULL, NULL, N_("Pixel Size") },
    2139             :     { me_int, NULL, NULL, NULL, N_("Correction") },
    2140             :     COL_INIT_EMPTY
    2141             : };
    2142             : 
    2143           0 : static void DevTabMatrixInit(struct matrixinit *mi,char *dvstr) {
    2144             :     struct matrix_data *md;
    2145             :     int k, p, cnt;
    2146             :     DeviceTable devtab;
    2147             : 
    2148           0 :     memset(&devtab,0,sizeof(devtab));
    2149           0 :     DeviceTableParse(&devtab,dvstr);
    2150           0 :     cnt = 0;
    2151           0 :     if ( devtab.corrections!=NULL ) {
    2152           0 :         for ( k=devtab.first_pixel_size; k<=devtab.last_pixel_size; ++k )
    2153           0 :             if ( devtab.corrections[k-devtab.first_pixel_size]!=0 )
    2154           0 :                 ++cnt;
    2155             :     }
    2156             : 
    2157           0 :     memset(mi,0,sizeof(*mi));
    2158           0 :     mi->col_cnt = 2;
    2159           0 :     mi->col_init = devtabci;
    2160             : 
    2161           0 :     md = NULL;
    2162           0 :     for ( k=0; k<2; ++k ) {
    2163           0 :         cnt = 0;
    2164           0 :         if ( devtab.corrections==NULL )
    2165             :             /* Do Nothing */;
    2166           0 :         else for ( p=devtab.first_pixel_size; p<=devtab.last_pixel_size; ++p ) {
    2167           0 :             if ( devtab.corrections[p-devtab.first_pixel_size]!=0 ) {
    2168           0 :                 if ( k ) {
    2169           0 :                     md[2*cnt+0].u.md_ival = p;
    2170           0 :                     md[2*cnt+1].u.md_ival = devtab.corrections[p-devtab.first_pixel_size];
    2171             :                 }
    2172           0 :                 ++cnt;
    2173             :             }
    2174             :         }
    2175           0 :         if ( md==NULL )
    2176           0 :             md = calloc(2*(cnt+10),sizeof(struct matrix_data));
    2177             :     }
    2178           0 :     mi->matrix_data = md;
    2179           0 :     mi->initial_row_cnt = cnt;
    2180             : 
    2181           0 :     mi->initrow = NULL;
    2182           0 :     mi->finishedit = NULL;
    2183           0 :     mi->candelete = NULL;
    2184           0 :     mi->popupmenu = NULL;
    2185           0 :     mi->handle_key = NULL;
    2186           0 :     mi->bigedittitle = NULL;
    2187             : 
    2188           0 :     free( devtab.corrections );
    2189           0 : }
    2190             : 
    2191           0 : static int DevTabDlg_OK(GGadget *g, GEvent *e) {
    2192             : 
    2193           0 :     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
    2194           0 :         struct devtab_dlg *dvd = GDrawGetUserData(GGadgetGetWindow(g));
    2195             :         int rows, i, low, high;
    2196           0 :         struct matrix_data *corrections = GMatrixEditGet(dvd->gme, &rows);
    2197             : 
    2198           0 :         low = high = -1;
    2199           0 :         for ( i=0; i<rows; ++i ) {
    2200           0 :             if ( corrections[2*i+1].u.md_ival<-128 || corrections[2*i+1].u.md_ival>127 ) {
    2201           0 :                 ff_post_error(_("Bad correction"),_("The correction on line %d is too big.  It must be between -128 and 127"),
    2202             :                         i+1 );
    2203           0 : return(true);
    2204           0 :             } else if ( corrections[2*i+0].u.md_ival<0 || corrections[2*i+0].u.md_ival>32767 ) {
    2205           0 :                 gwwv_post_error(_("Bad pixel size"),_("The pixel size on line %d is out of bounds."),
    2206             :                         i+1 );
    2207           0 : return(true);
    2208             :             }
    2209           0 :             if ( corrections[2*i+1].u.md_ival!=0 ) {
    2210           0 :                 if ( low==-1 )
    2211           0 :                     low = high = corrections[2*i+0].u.md_ival;
    2212           0 :                 else if ( corrections[2*i+0].u.md_ival<low )
    2213           0 :                     low = corrections[2*i+0].u.md_ival;
    2214           0 :                 else if ( corrections[2*i+0].u.md_ival>high )
    2215           0 :                     high = corrections[2*i+0].u.md_ival;
    2216             :             }
    2217             :         }
    2218           0 :         memset(&dvd->devtab,0,sizeof(DeviceTable));
    2219           0 :         if ( low!=-1 ) {
    2220           0 :             dvd->devtab.first_pixel_size = low;
    2221           0 :             dvd->devtab.last_pixel_size = high;
    2222           0 :             dvd->devtab.corrections = calloc(high-low+1,1);
    2223           0 :             for ( i=0; i<rows; ++i ) {
    2224           0 :                 if ( corrections[2*i+1].u.md_ival!=0 ) {
    2225           0 :                     dvd->devtab.corrections[ corrections[2*i+0].u.md_ival-low ] =
    2226           0 :                             corrections[2*i+1].u.md_ival;
    2227             :                 }
    2228             :             }
    2229             :         }
    2230           0 :         dvd->done = 2;
    2231             :     }
    2232           0 : return( true );
    2233             : }
    2234             : 
    2235           0 : static int DevTabDlg_Cancel(GGadget *g, GEvent *e) {
    2236             : 
    2237           0 :     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
    2238           0 :         struct devtab_dlg *dvd = GDrawGetUserData(GGadgetGetWindow(g));
    2239           0 :         dvd->done = true;
    2240             :     }
    2241           0 : return( true );
    2242             : }
    2243             : 
    2244           0 : static int devtabdlg_e_h(GWindow gw, GEvent *event) {
    2245             : 
    2246           0 :     if ( event->type==et_close ) {
    2247           0 :         struct devtab_dlg *dvd = GDrawGetUserData(gw);
    2248           0 :         dvd->done = true;
    2249           0 :     } else if ( event->type == et_char ) {
    2250           0 : return( false );
    2251             :     }
    2252             : 
    2253           0 : return( true );
    2254             : }
    2255             : 
    2256           0 : char *DevTab_Dlg(GGadget *g, int r, int c) {
    2257           0 :     int rows, k, j, cols = GMatrixEditGetColCnt(g);
    2258           0 :     struct matrix_data *strings = GMatrixEditGet(g, &rows);
    2259           0 :     char *dvstr = strings[cols*r+c].u.md_str;
    2260             :     struct devtab_dlg dvd;
    2261             :     GRect pos;
    2262             :     GWindow gw;
    2263             :     GWindowAttrs wattrs;
    2264             :     GGadgetCreateData gcd[4], boxes[3];
    2265             :     GGadgetCreateData *varray[6], *harray3[8];
    2266             :     GTextInfo label[4];
    2267             :     struct matrixinit mi;
    2268             : 
    2269           0 :     memset(&dvd,0,sizeof(dvd));
    2270             : 
    2271           0 :     memset(&wattrs,0,sizeof(wattrs));
    2272           0 :     wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_undercursor|wam_isdlg|wam_restrict;
    2273           0 :     wattrs.event_masks = ~(1<<et_charup);
    2274           0 :     wattrs.is_dlg = true;
    2275           0 :     wattrs.restrict_input_to_me = 1;
    2276           0 :     wattrs.undercursor = 1;
    2277           0 :     wattrs.cursor = ct_pointer;
    2278           0 :     wattrs.utf8_window_title = _("Device Table Adjustments");
    2279           0 :     pos.x = pos.y = 0;
    2280           0 :     pos.width =GDrawPointsToPixels(NULL,GGadgetScale(268));
    2281           0 :     pos.height = GDrawPointsToPixels(NULL,375);
    2282           0 :     dvd.gw = gw = GDrawCreateTopWindow(NULL,&pos,devtabdlg_e_h,&dvd,&wattrs);
    2283             : 
    2284           0 :     DevTabMatrixInit(&mi,dvstr);
    2285             : 
    2286           0 :     memset(&gcd,0,sizeof(gcd));
    2287           0 :     memset(&boxes,0,sizeof(boxes));
    2288           0 :     memset(&label,0,sizeof(label));
    2289           0 :     k=j=0;
    2290           0 :     gcd[k].gd.pos.x = 10; gcd[k].gd.pos.y = gcd[1].gd.pos.y+14;
    2291           0 :     gcd[k].gd.flags = gg_enabled | gg_visible | gg_utf8_popup;
    2292           0 :     gcd[k].gd.u.matrix = &mi;
    2293           0 :     gcd[k].gd.popup_msg = (unichar_t *) _(
    2294             :         "At small pixel sizes (screen font sizes)\n"
    2295             :         "the rounding errors that occur may be\n"
    2296             :         "extremely ugly. A device table allows\n"
    2297             :         "you to specify adjustments to the rounded\n"
    2298             :         "Every pixel size my have its own adjustment.");
    2299           0 :     gcd[k].creator = GMatrixEditCreate;
    2300           0 :     varray[j++] = &gcd[k++]; varray[j++] = NULL;
    2301             : 
    2302           0 :     gcd[k].gd.pos.x = 30-3; 
    2303           0 :     gcd[k].gd.flags = gg_visible | gg_enabled | gg_but_default;
    2304           0 :     label[k].text = (unichar_t *) _("_OK");
    2305           0 :     label[k].text_is_1byte = true;
    2306           0 :     label[k].text_in_resource = true;
    2307           0 :     gcd[k].gd.label = &label[k];
    2308           0 :     gcd[k].gd.handle_controlevent = DevTabDlg_OK;
    2309           0 :     gcd[k++].creator = GButtonCreate;
    2310             : 
    2311           0 :     gcd[k].gd.pos.x = -30;
    2312           0 :     gcd[k].gd.flags = gg_visible | gg_enabled | gg_but_cancel;
    2313           0 :     label[k].text = (unichar_t *) _("_Cancel");
    2314           0 :     label[k].text_is_1byte = true;
    2315           0 :     label[k].text_in_resource = true;
    2316           0 :     gcd[k].gd.label = &label[k];
    2317           0 :     gcd[k].gd.handle_controlevent = DevTabDlg_Cancel;
    2318           0 :     gcd[k].gd.cid = CID_Cancel;
    2319           0 :     gcd[k++].creator = GButtonCreate;
    2320             : 
    2321           0 :     harray3[0] = harray3[2] = harray3[3] = harray3[4] = harray3[6] = GCD_Glue;
    2322           0 :     harray3[7] = NULL;
    2323           0 :     harray3[1] = &gcd[k-2]; harray3[5] = &gcd[k-1];
    2324             : 
    2325           0 :     boxes[0].gd.flags = gg_enabled|gg_visible;
    2326           0 :     boxes[0].gd.u.boxelements = harray3;
    2327           0 :     boxes[0].creator = GHBoxCreate;
    2328           0 :     varray[j++] = &boxes[0]; varray[j++] = NULL; varray[j] = NULL;
    2329             :     
    2330           0 :     boxes[1].gd.pos.x = boxes[1].gd.pos.y = 2;
    2331           0 :     boxes[1].gd.flags = gg_enabled|gg_visible;
    2332           0 :     boxes[1].gd.u.boxelements = varray;
    2333           0 :     boxes[1].creator = GHVGroupCreate;
    2334             : 
    2335           0 :     GGadgetsCreate(gw,boxes+1);
    2336             : 
    2337           0 :     free( mi.matrix_data );
    2338             : 
    2339           0 :     dvd.gme = gcd[0].ret;
    2340           0 :     GMatrixEditSetNewText(gcd[0].ret,S_("PixelSize|New"));
    2341           0 :     GHVBoxSetExpandableRow(boxes[1].ret,1);
    2342           0 :     GHVBoxSetExpandableCol(boxes[0].ret,gb_expandgluesame);
    2343             : 
    2344           0 :     GHVBoxFitWindow(boxes[1].ret);
    2345             : 
    2346           0 :     GDrawSetVisible(gw,true);
    2347           0 :     while ( !dvd.done )
    2348           0 :         GDrawProcessOneEvent(NULL);
    2349           0 :     GDrawDestroyWindow(gw);
    2350           0 :     if ( dvd.done==2 ) {
    2351             :         char *ret;
    2352           0 :         DevTabToString(&ret,&dvd.devtab);
    2353           0 :         free(dvd.devtab.corrections);
    2354           0 : return( ret );
    2355             :     } else
    2356           0 : return( copy(dvstr));
    2357             : }
    2358             : 
    2359             : static void finishedit(GGadget *g, int r, int c, int wasnew);
    2360             : static void kernfinishedit(GGadget *g, int r, int c, int wasnew);
    2361             : static void kerninit(GGadget *g, int r);
    2362             : static void enable_enum(GGadget *g, GMenuItem *mi, int r, int c);
    2363             : 
    2364             : static struct col_init simplesubsci[] = {
    2365             :     { me_enum , NULL, NULL, enable_enum, N_("Subtable") },
    2366             :     { me_string, NULL, NULL, NULL, N_("Replacement Glyph Name") },
    2367             :     COL_INIT_EMPTY
    2368             : };
    2369             : static struct col_init ligatureci[] = {
    2370             :     { me_enum , NULL, NULL, NULL, N_("Subtable") },   /* There can be multiple ligatures for a glyph */
    2371             :     { me_string, NULL, NULL, NULL, N_("Source Glyph Names") },
    2372             :     COL_INIT_EMPTY
    2373             : };
    2374             : static struct col_init altsubsci[] = {
    2375             :     { me_enum , NULL, NULL, enable_enum, N_("Subtable") },
    2376             :     { me_string, NULL, NULL, NULL, N_("Replacement Glyph Names") },
    2377             :     COL_INIT_EMPTY
    2378             : };
    2379             : static struct col_init multsubsci[] = {
    2380             :     { me_enum , NULL, NULL, enable_enum, N_("Subtable") },
    2381             :     { me_string, NULL, NULL, NULL, N_("Replacement Glyph Names") },
    2382             :     COL_INIT_EMPTY
    2383             : };
    2384             : static struct col_init simpleposci[] = {
    2385             :     { me_enum , NULL, NULL, enable_enum, N_("Subtable") },
    2386             :     { me_int, NULL, NULL, NULL, NU_("∆x") },        /* delta-x */
    2387             : /* GT: "Adjust" here means Device Table based pixel adjustments, an OpenType */
    2388             : /* GT: concept which allows small corrections for small pixel sizes where */
    2389             : /* GT: rounding errors (in kerning for example) may smush too glyphs together */
    2390             : /* GT: or space them too far apart. Generally not a problem for big pixelsizes*/
    2391             :     { me_funcedit, DevTab_Dlg, NULL, NULL, N_("Adjust") },
    2392             :     { me_int, NULL, NULL, NULL, NU_("∆y") },                /* delta-y */
    2393             :     { me_funcedit, DevTab_Dlg, NULL, NULL, N_("Adjust") },
    2394             :     { me_int, NULL, NULL, NULL, NU_("∆x_adv") },    /* delta-x-adv */
    2395             :     { me_funcedit, DevTab_Dlg, NULL, NULL, N_("Adjust") },
    2396             :     { me_int, NULL, NULL, NULL, NU_("∆y_adv") },    /* delta-y-adv */
    2397             :     { me_funcedit, DevTab_Dlg, NULL, NULL, N_("Adjust") },
    2398             :     COL_INIT_EMPTY
    2399             : };
    2400             : static struct col_init pairposci[] = {
    2401             :     { me_enum , NULL, NULL, NULL, N_("Subtable") },   /* There can be multiple kern-pairs for a glyph */
    2402             :     { me_string , DevTab_Dlg, NULL, NULL, N_("Second Glyph Name") },
    2403             :     { me_int, NULL, NULL, NULL, NU_("∆x #1") },             /* delta-x */
    2404             :     { me_funcedit, DevTab_Dlg, NULL, NULL, N_("Adjust") },
    2405             :     { me_int, NULL, NULL, NULL, NU_("∆y #1") },             /* delta-y */
    2406             :     { me_funcedit, DevTab_Dlg, NULL, NULL, N_("Adjust") },
    2407             :     { me_int, NULL, NULL, NULL, NU_("∆x_adv #1") }, /* delta-x-adv */
    2408             :     { me_funcedit, DevTab_Dlg, NULL, NULL, N_("Adjust") },
    2409             :     { me_int, NULL, NULL, NULL, NU_("∆y_adv #1") }, /* delta-y-adv */
    2410             :     { me_funcedit, DevTab_Dlg, NULL, NULL, N_("Adjust") },
    2411             :     { me_int, NULL, NULL, NULL, NU_("∆x #2") },             /* delta-x */
    2412             :     { me_funcedit, DevTab_Dlg, NULL, NULL, N_("Adjust") },
    2413             :     { me_int, NULL, NULL, NULL, NU_("∆y #2") },             /* delta-y */
    2414             :     { me_funcedit, DevTab_Dlg, NULL, NULL, N_("Adjust") },
    2415             :     { me_int, NULL, NULL, NULL, NU_("∆x_adv #2") }, /* delta-x-adv */
    2416             :     { me_funcedit, DevTab_Dlg, NULL, NULL, N_("Adjust") },
    2417             :     { me_int, NULL, NULL, NULL, NU_("∆y_adv #2") }, /* delta-y-adv */
    2418             :     { me_funcedit, DevTab_Dlg, NULL, NULL, N_("Adjust") },
    2419             :     COL_INIT_EMPTY
    2420             : };
    2421             : static int pst2lookuptype[] = { ot_undef, gpos_single, gpos_pair, gsub_single,
    2422             :      gsub_alternate, gsub_multiple, gsub_ligature, 0 };
    2423             : struct matrixinit mi[] = {
    2424             :     { sizeof(simpleposci)/sizeof(struct col_init)-1, simpleposci, 0, NULL, NULL, NULL, finishedit, NULL, NULL, NULL },
    2425             :     { sizeof(pairposci)/sizeof(struct col_init)-1, pairposci, 0, NULL, kerninit, NULL, kernfinishedit, NULL, NULL, NULL },
    2426             :     { sizeof(simplesubsci)/sizeof(struct col_init)-1, simplesubsci, 0, NULL, NULL, NULL, finishedit, NULL, NULL, NULL },
    2427             :     { sizeof(altsubsci)/sizeof(struct col_init)-1, altsubsci, 0, NULL, NULL, NULL, finishedit, NULL, NULL, NULL },
    2428             :     { sizeof(multsubsci)/sizeof(struct col_init)-1, multsubsci, 0, NULL, NULL, NULL, finishedit, NULL, NULL, NULL },
    2429             :     { sizeof(ligatureci)/sizeof(struct col_init)-1, ligatureci, 0, NULL, NULL, NULL, finishedit, NULL, NULL, NULL },
    2430             :     MATRIXINIT_EMPTY
    2431             : };
    2432             : 
    2433           0 : static void enable_enum(GGadget *g, GMenuItem *mi, int r, int c) {
    2434             :     int i,rows,j;
    2435             :     struct matrix_data *possub;
    2436             :     CharInfo *ci;
    2437             :     int sel,cols;
    2438             : 
    2439           0 :     if ( c!=0 )
    2440           0 : return;
    2441           0 :     ci = GDrawGetUserData(GGadgetGetWindow(g));
    2442           0 :     sel = GTabSetGetSel(GWidgetGetControl(ci->gw,CID_Tabs))-2;
    2443           0 :     possub = GMatrixEditGet(g, &rows);
    2444           0 :     cols = GMatrixEditGetColCnt(g);
    2445             : 
    2446           0 :     ci->old_sub = (void *) possub[r*cols+0].u.md_ival;
    2447             : 
    2448           0 :     for ( i=0; mi[i].ti.text!=NULL || mi[i].ti.line; ++i ) {
    2449           0 :         if ( mi[i].ti.line )    /* Lines, and the new entry always enabled */
    2450           0 :             mi[i].ti.disabled = false;
    2451           0 :         else if ( mi[i].ti.userdata == NULL )
    2452             :             /* One of the lookup (rather than subtable) entries. leave disabled */;
    2453           0 :         else if ( mi[i].ti.userdata == (void *) possub[r*cols+0].u.md_ival ) {
    2454           0 :             mi[i].ti.selected = true;           /* Current thing, they can keep on using it */
    2455           0 :             mi[i].ti.disabled = false;
    2456             :         } else {
    2457           0 :             for ( j=0; j<rows; ++j )
    2458           0 :                 if ( mi[i].ti.userdata == (void *) possub[j*cols+0].u.md_ival ) {
    2459           0 :                     mi[i].ti.selected = false;
    2460           0 :                     mi[i].ti.disabled = true;
    2461           0 :             break;
    2462             :                 }
    2463           0 :             if ( j==rows ) {    /* This subtable hasn't been used yet */
    2464           0 :                 mi[i].ti.disabled = false;
    2465             :             }
    2466             :         }
    2467             :     }
    2468             : }
    2469             : 
    2470           0 : void SCSubtableDefaultSubsCheck(SplineChar *sc, struct lookup_subtable *sub,
    2471             :         struct matrix_data *possub, int col_cnt, int r, int layer) {
    2472             :     FeatureScriptLangList *fl;
    2473           0 :     int lookup_type = sub->lookup->lookup_type;
    2474             :     SplineChar *alt;
    2475             :     char buffer[8];
    2476             :     int i;
    2477             :     static uint32 form_tags[] = { CHR('i','n','i','t'), CHR('m','e','d','i'), CHR('f','i','n','a'), CHR('i','s','o','l'), 0 };
    2478             :     real loff, roff;
    2479             : 
    2480           0 :     if ( lookup_type == gsub_single && sub->suffix != NULL ) {
    2481           0 :         alt = SuffixCheck(sc,sub->suffix);
    2482           0 :         if ( alt!=NULL ) {
    2483           0 :             possub[r*col_cnt+1].u.md_str = copy( alt->name );
    2484           0 : return;
    2485             :         }
    2486             :     }
    2487             : 
    2488           0 :     for ( fl = sub->lookup->features; fl!=NULL; fl=fl->next ) {
    2489           0 :         if ( lookup_type == gpos_single ) {
    2490             :             /* These too features are designed to crop off the left and right */
    2491             :             /*  side bearings respectively */
    2492           0 :             if ( fl->featuretag == CHR('l','f','b','d') ) {
    2493           0 :                 GuessOpticalOffset(sc,layer,&loff,&roff,0);
    2494             :                 /* Adjust horixontal positioning and horizontal advance by */
    2495             :                 /*  the left side bearing */
    2496           0 :                 possub[r*col_cnt+SIM_DX].u.md_ival = -loff;
    2497           0 :                 possub[r*col_cnt+SIM_DX_ADV].u.md_ival = -loff;
    2498           0 : return;
    2499           0 :             } else if ( fl->featuretag == CHR('r','t','b','d') ) {
    2500           0 :                 GuessOpticalOffset(sc,layer,&loff,&roff,0);
    2501             :                 /* Adjust horizontal advance by right side bearing */
    2502           0 :                 possub[r*col_cnt+SIM_DX_ADV].u.md_ival = -roff;
    2503           0 : return;
    2504             :             }
    2505           0 :         } else if ( lookup_type == gsub_single ) {
    2506           0 :             alt = NULL;
    2507           0 :             if ( fl->featuretag == CHR('s','m','c','p') ) {
    2508           0 :                 alt = SuffixCheck(sc,"sc");
    2509           0 :                 if ( alt==NULL )
    2510           0 :                     alt = SuffixCheckCase(sc,"small",false);
    2511           0 :             } else if ( fl->featuretag == CHR('c','2','s','c') ) {
    2512           0 :                 alt = SuffixCheck(sc,"small");
    2513           0 :                 if ( alt==NULL )
    2514           0 :                     alt = SuffixCheckCase(sc,"sc",true);
    2515           0 :             } else if ( fl->featuretag == CHR('r','t','l','a') ) {
    2516           0 :                 if ( sc->unicodeenc!=-1 && sc->unicodeenc<0x10000 && tomirror(sc->unicodeenc)!=0 )
    2517           0 :                     alt = SFGetChar(sc->parent,tomirror(sc->unicodeenc),NULL);
    2518           0 :             } else if ( sc->unicodeenc==0x3c3 && fl->featuretag==CHR('f','i','n','a') ) {
    2519             :                 /* Greek final sigma */
    2520           0 :                 alt = SFGetChar(sc->parent,0x3c2,NULL);
    2521             :             }
    2522           0 :             if ( alt==NULL ) {
    2523           0 :                 buffer[0] = fl->featuretag>>24;
    2524           0 :                 buffer[1] = fl->featuretag>>16;
    2525           0 :                 buffer[2] = fl->featuretag>>8;
    2526           0 :                 buffer[3] = fl->featuretag&0xff;
    2527           0 :                 buffer[4] = 0;
    2528           0 :                 alt = SuffixCheck(sc,buffer);
    2529             :             }
    2530           0 :             if ( alt==NULL && sc->unicodeenc>=0x600 && sc->unicodeenc<0x700 ) {
    2531             :                 /* Arabic forms */
    2532           0 :                 for ( i=0; form_tags[i]!=0; ++i ) if ( form_tags[i]==fl->featuretag ) {
    2533           0 :                     if ( (&(ArabicForms[sc->unicodeenc-0x600].initial))[i]!=0 &&
    2534           0 :                             (&(ArabicForms[sc->unicodeenc-0x600].initial))[i]!=sc->unicodeenc &&
    2535           0 :                             (alt = SFGetChar(sc->parent,(&(ArabicForms[sc->unicodeenc-0x600].initial))[i],NULL))!=NULL )
    2536           0 :                 break;
    2537             :                 }
    2538             :             }
    2539           0 :             if ( alt!=NULL ) {
    2540           0 :                 possub[r*col_cnt+1].u.md_str = copy( alt->name );
    2541           0 : return;
    2542             :             }
    2543           0 :         } else if ( lookup_type == gsub_ligature ) {
    2544           0 :             if ( fl->featuretag == LigTagFromUnicode(sc->unicodeenc) ) {
    2545             :                 int alt_index;
    2546           0 :                 for ( alt_index = 0; ; ++alt_index ) {
    2547           0 :                     char *components = LigDefaultStr(sc->unicodeenc,sc->name,alt_index);
    2548           0 :                     if ( components==NULL )
    2549           0 :                 break;
    2550           0 :                     for ( i=0; i<r; ++i ) {
    2551           0 :                         if ( possub[i*col_cnt+0].u.md_ival == (intpt) sub &&
    2552           0 :                                 strcmp(possub[i*col_cnt+1].u.md_str,components)==0 )
    2553           0 :                     break;
    2554             :                     }
    2555           0 :                     if ( i==r ) {
    2556           0 :                         possub[r*col_cnt+1].u.md_str = components;
    2557           0 : return;
    2558             :                     }
    2559           0 :                     free( components );
    2560           0 :                 }
    2561             :             }
    2562             :         }
    2563             :     }
    2564             : }
    2565             : 
    2566           0 : static void finishedit(GGadget *g, int r, int c, int wasnew) {
    2567             :     int rows;
    2568             :     struct matrix_data *possub;
    2569             :     CharInfo *ci;
    2570             :     int sel,cols;
    2571             :     struct lookup_subtable *sub;
    2572             :     struct subtable_data sd;
    2573             :     GTextInfo *ti;
    2574             : 
    2575           0 :     if ( c!=0 )
    2576           0 : return;
    2577           0 :     ci = GDrawGetUserData(GGadgetGetWindow(g));
    2578           0 :     sel = GTabSetGetSel(GWidgetGetControl(ci->gw,CID_Tabs))-2;
    2579           0 :     possub = GMatrixEditGet(g, &rows);
    2580           0 :     cols = GMatrixEditGetColCnt(g);
    2581           0 :     if ( possub[r*cols+0].u.md_ival!=0 ) {
    2582           0 :         if ( wasnew )
    2583           0 :             SCSubtableDefaultSubsCheck(ci->sc,(struct lookup_subtable *) possub[r*cols+0].u.md_ival, possub,
    2584             :                     cols, r, ci->def_layer );
    2585           0 : return;
    2586             :     }
    2587             :     /* They asked to create a new subtable */
    2588             : 
    2589           0 :     memset(&sd,0,sizeof(sd));
    2590           0 :     sd.flags = sdf_dontedit;
    2591           0 :     sub = SFNewLookupSubtableOfType(ci->sc->parent,pst2lookuptype[sel+1],&sd,ci->def_layer);
    2592           0 :     if ( sub!=NULL ) {
    2593           0 :         possub[r*cols+0].u.md_ival = (intpt) sub;
    2594           0 :         ti = SFSubtableListOfType(ci->sc->parent, pst2lookuptype[sel+1], false, false);
    2595           0 :         GMatrixEditSetColumnChoices(g,0,ti);
    2596           0 :         GTextInfoListFree(ti);
    2597           0 :         if ( wasnew && ci->cv!=NULL )
    2598           0 :             SCSubtableDefaultSubsCheck(ci->sc,sub, possub, cols, r, CVLayer((CharViewBase *) (ci->cv)));
    2599           0 :     } else if ( ci->old_sub!=NULL ) {
    2600             :         /* Restore old value */
    2601           0 :         possub[r*cols+0].u.md_ival = (intpt) ci->old_sub;
    2602             :     } else {
    2603           0 :         GMatrixEditDeleteRow(g,r);
    2604             :     }
    2605           0 :     ci->old_sub = NULL;
    2606           0 :     GGadgetRedraw(g);
    2607             : }
    2608             : 
    2609           0 : static void kern_AddKP(void *data,SplineChar *left, SplineChar *right, int off) {
    2610           0 :     int *kp_offset = data;
    2611           0 :     *kp_offset = off;
    2612           0 : }
    2613             : 
    2614           0 : static void kernfinishedit(GGadget *g, int r, int c, int wasnew) {
    2615             :     int rows;
    2616             :     struct matrix_data *possub;
    2617             :     CharInfo *ci;
    2618             :     int cols;
    2619             :     struct lookup_subtable *sub;
    2620             :     SplineChar *lefts[2], *rights[2];
    2621           0 :     int touch, separation, kp_offset=0;
    2622             :     SplineChar *osc;
    2623             : 
    2624           0 :     if ( c==1 ) {
    2625           0 :         ci = GDrawGetUserData(GGadgetGetWindow(g));
    2626           0 :         possub = GMatrixEditGet(g, &rows);
    2627           0 :         cols = GMatrixEditGetColCnt(g);
    2628           0 :         sub = (struct lookup_subtable *) possub[r*cols+0].u.md_ival;
    2629           0 :         if ( possub[r*cols+PAIR_DX_ADV1].u.md_ival==0 &&
    2630           0 :                 possub[r*cols+1].u.md_str!=NULL &&
    2631           0 :                 (osc = SFGetChar(ci->sc->parent,-1,possub[r*cols+1].u.md_str))!=NULL ) {
    2632           0 :             lefts[1] = rights[1] = NULL;
    2633           0 :             if ( sub->lookup->lookup_flags & pst_r2l ) {
    2634           0 :                 lefts[0] = osc;
    2635           0 :                 rights[0] = ci->sc;
    2636             :             } else {
    2637           0 :                 lefts[0] = ci->sc;
    2638           0 :                 rights[0] = osc;
    2639             :             }
    2640           0 :             touch = sub->kerning_by_touch;
    2641           0 :             separation = sub->separation;
    2642           0 :             if ( separation==0 && !touch )
    2643           0 :                 separation = 15*(osc->parent->ascent+osc->parent->descent)/100;
    2644           0 :             AutoKern2(osc->parent,ci->def_layer,lefts,rights,sub,
    2645             :                     separation,0,touch,0,0,     /* Don't bother with minkern or onlyCloser, they asked for this, they get it, whatever it may be */
    2646             :                     kern_AddKP,&kp_offset);
    2647           0 :             possub[r*cols+PAIR_DX_ADV1].u.md_ival=kp_offset;
    2648             :         }
    2649             :     } else
    2650           0 :         finishedit(g,r,c,wasnew);
    2651           0 : }
    2652             : 
    2653           0 : static int SubHasScript(uint32 script,struct lookup_subtable *sub) {
    2654             :     FeatureScriptLangList *f;
    2655             :     struct scriptlanglist *s;
    2656             : 
    2657           0 :     if ( sub==NULL )
    2658           0 : return(false);
    2659           0 :     for ( f = sub->lookup->features; f!=NULL; f=f->next ) {
    2660           0 :         for ( s=f->scripts; s!=NULL; s=s->next ) {
    2661           0 :             if ( s->script == script )
    2662           0 : return( true );
    2663             :         }
    2664             :     }
    2665           0 : return( false );
    2666             : }
    2667             : 
    2668           0 : static void kerninit(GGadget *g, int r) {
    2669           0 :     CharInfo *ci = GDrawGetUserData(GGadgetGetWindow(g));
    2670           0 :     GMenuItem *mi = GMatrixEditGetColumnChoices(g,0);
    2671             :     int i,cols,rows;
    2672             :     struct matrix_data *possub;
    2673             :     uint32 script;
    2674             : 
    2675           0 :     possub = GMatrixEditGet(g, &rows);
    2676           0 :     cols = GMatrixEditGetColCnt(g);
    2677             : 
    2678           0 :     if ( r!=0 )
    2679           0 :         possub[r*cols+0].u.md_ival = possub[(r-1)*cols+0].u.md_ival;
    2680             :     else {
    2681           0 :         script = SCScriptFromUnicode(ci->sc);
    2682           0 :         for ( i=0; mi[i].ti.line || mi[i].ti.text!=NULL; ++i ) {
    2683           0 :             if ( SubHasScript(script,(struct lookup_subtable *) mi[i].ti.userdata ) )
    2684           0 :         break;
    2685             :         }
    2686           0 :         if ( mi[i].ti.line || mi[i].ti.text!=NULL )
    2687           0 :             possub[r*cols+0].u.md_ival = (intpt) mi[i].ti.userdata;
    2688             :     }
    2689           0 : }
    2690             : 
    2691           0 : static void CI_DoHideUnusedSingle(CharInfo *ci) {
    2692           0 :     GGadget *pstk = GWidgetGetControl(ci->gw,CID_List+(pst_position-1)*100);
    2693           0 :     int rows, cols = GMatrixEditGetColCnt(pstk);
    2694           0 :     struct matrix_data *old = GMatrixEditGet(pstk,&rows);
    2695             :     uint8 cols_used[20];
    2696             :     int r, col, tot;
    2697             : 
    2698           0 :     if ( lookup_hideunused ) {
    2699           0 :         memset(cols_used,0,sizeof(cols_used));
    2700           0 :         for ( r=0; r<rows; ++r ) {
    2701           0 :             for ( col=1; col<cols; col+=2 ) {
    2702           0 :                 if ( old[cols*r+col].u.md_ival!=0 )
    2703           0 :                     cols_used[col] = true;
    2704           0 :                 if ( old[cols*r+col+1].u.md_str!=NULL && *old[cols*r+col+1].u.md_str!='\0' )
    2705           0 :                     cols_used[col+1] = true;
    2706             :             }
    2707             :         }
    2708           0 :         for ( col=1, tot=0; col<cols; ++col )
    2709           0 :             tot += cols_used[col];
    2710             :         /* If no columns used (no info yet, all info is to preempt a kernclass and sets to 0) */
    2711             :         /*  then show what we expect to be the default column for this kerning mode*/
    2712           0 :         if ( tot==0 ) {
    2713           0 :             if ( strstr(ci->sc->name,".vert")!=NULL || strstr(ci->sc->name,".vrt2")!=NULL )
    2714           0 :                 cols_used[SIM_DY] = true;
    2715             :             else
    2716           0 :                 cols_used[SIM_DX] = true;
    2717             :         }
    2718           0 :         for ( col=1; col<cols; ++col )
    2719           0 :             GMatrixEditShowColumn(pstk,col,cols_used[col]);
    2720             :     } else {
    2721           0 :         for ( col=1; col<cols; ++col )
    2722           0 :             GMatrixEditShowColumn(pstk,col,true);
    2723             :     }
    2724           0 :     GWidgetToDesiredSize(ci->gw);
    2725             : 
    2726           0 :     GGadgetRedraw(pstk);
    2727           0 : }
    2728             : 
    2729           0 : static void CI_DoHideUnusedPair(CharInfo *ci) {
    2730           0 :     GGadget *pstk = GWidgetGetControl(ci->gw,CID_List+(pst_pair-1)*100);
    2731           0 :     int rows, cols = GMatrixEditGetColCnt(pstk);
    2732           0 :     struct matrix_data *old = GMatrixEditGet(pstk,&rows);
    2733             :     uint8 cols_used[20];
    2734             :     int r, col, tot;
    2735             : 
    2736           0 :     if ( lookup_hideunused ) {
    2737           0 :         memset(cols_used,0,sizeof(cols_used));
    2738           0 :         for ( r=0; r<rows; ++r ) {
    2739           0 :             for ( col=2; col<cols; col+=2 ) {
    2740           0 :                 if ( old[cols*r+col].u.md_ival!=0 )
    2741           0 :                     cols_used[col] = true;
    2742           0 :                 if ( old[cols*r+col+1].u.md_str!=NULL && *old[cols*r+col+1].u.md_str!='\0' )
    2743           0 :                     cols_used[col+1] = true;
    2744             :             }
    2745             :         }
    2746           0 :         for ( col=2, tot=0; col<cols; ++col )
    2747           0 :             tot += cols_used[col];
    2748             :         /* If no columns used (no info yet, all info is to preempt a kernclass and sets to 0) */
    2749             :         /*  then show what we expect to be the default column for this kerning mode*/
    2750           0 :         if ( tot==0 ) {
    2751           0 :             if ( strstr(ci->sc->name,".vert")!=NULL || strstr(ci->sc->name,".vrt2")!=NULL )
    2752           0 :                 cols_used[PAIR_DY_ADV1] = true;
    2753           0 :             else if ( SCRightToLeft(ci->sc))
    2754           0 :                 cols_used[PAIR_DX_ADV2] = true;
    2755             :             else
    2756           0 :                 cols_used[PAIR_DX_ADV1] = true;
    2757             :         }
    2758           0 :         for ( col=2; col<cols; ++col )
    2759           0 :             GMatrixEditShowColumn(pstk,col,cols_used[col]);
    2760             :     } else {
    2761           0 :         for ( col=2; col<cols; ++col )
    2762           0 :             GMatrixEditShowColumn(pstk,col,true);
    2763             :     }
    2764           0 :     GWidgetToDesiredSize(ci->gw);
    2765             : 
    2766           0 :     GGadgetRedraw(pstk);
    2767           0 : }
    2768             : 
    2769           0 : static int CI_HideUnusedPair(GGadget *g, GEvent *e) {
    2770           0 :     if ( e->type==et_controlevent && e->u.control.subtype == et_radiochanged ) {
    2771           0 :         CharInfo *ci = GDrawGetUserData(GGadgetGetWindow(g));
    2772           0 :         lookup_hideunused = GGadgetIsChecked(g);
    2773           0 :         CI_DoHideUnusedPair(ci);
    2774           0 :         GGadgetRedraw(GWidgetGetControl(ci->gw,CID_List+(pst_pair-1)*100));
    2775             :     }
    2776           0 : return( true );
    2777             : }
    2778             : 
    2779           0 : static int CI_HideUnusedSingle(GGadget *g, GEvent *e) {
    2780           0 :     if ( e->type==et_controlevent && e->u.control.subtype == et_radiochanged ) {
    2781           0 :         CharInfo *ci = GDrawGetUserData(GGadgetGetWindow(g));
    2782           0 :         lookup_hideunused = GGadgetIsChecked(g);
    2783           0 :         CI_DoHideUnusedSingle(ci);
    2784           0 :         GGadgetRedraw(GWidgetGetControl(ci->gw,CID_List+(pst_position-1)*100));
    2785             :     }
    2786           0 : return( true );
    2787             : }
    2788             : 
    2789           0 : static void CI_FreeKernedImage(const void *_ci, GImage *img) {
    2790           0 :     GImageDestroy(img);
    2791           0 : }
    2792             : 
    2793             : static const int kern_popup_size = 100;
    2794             : 
    2795           0 : static BDFChar *Rasterize(SplineChar *sc,int def_layer) {
    2796           0 :     void *freetypecontext=NULL;
    2797             :     BDFChar *ret;
    2798             : 
    2799           0 :     freetypecontext = FreeTypeFontContext(sc->parent,sc,sc->parent->fv,def_layer);
    2800           0 :     if ( freetypecontext!=NULL ) {
    2801           0 :         ret = SplineCharFreeTypeRasterize(freetypecontext,sc->orig_pos,kern_popup_size,72,8);
    2802           0 :         FreeTypeFreeContext(freetypecontext);
    2803             :     } else
    2804           0 :         ret = SplineCharAntiAlias(sc,def_layer,kern_popup_size,4);
    2805           0 : return( ret );
    2806             : }
    2807             : 
    2808           0 : static GImage *CI_GetKernedImage(const void *_ci) {
    2809           0 :     CharInfo *ci = (CharInfo *) _ci;
    2810           0 :     GGadget *pstk = GWidgetGetControl(ci->gw,CID_List+(pst_pair-1)*100);
    2811           0 :     int rows, cols = GMatrixEditGetColCnt(pstk);
    2812           0 :     struct matrix_data *old = GMatrixEditGet(pstk,&rows);
    2813           0 :     SplineChar *othersc = SFGetChar(ci->sc->parent,-1, old[cols*ci->r+1].u.md_str);
    2814             :     BDFChar *me, *other;
    2815           0 :     double scale = kern_popup_size/(double) (ci->sc->parent->ascent+ci->sc->parent->descent);
    2816             :     int kern;
    2817             :     int width, height, miny, maxy, minx, maxx;
    2818             :     GImage *img;
    2819             :     struct _GImage *base;
    2820             :     Color fg, bg;
    2821             :     int l,clut_scale;
    2822             :     int x,y, xoffset, yoffset, coff1, coff2;
    2823           0 :     struct lookup_subtable *sub = (struct lookup_subtable *) (old[cols*ci->r+0].u.md_ival);
    2824             : 
    2825           0 :     if ( othersc==NULL )
    2826           0 : return( NULL );
    2827           0 :     me = Rasterize(ci->sc,ci->def_layer);
    2828           0 :     other = Rasterize(othersc,ci->def_layer);
    2829           0 :     if ( sub->vertical_kerning ) {
    2830           0 :         int vwidth = rint(ci->sc->vwidth*scale);
    2831           0 :         kern = rint( old[cols*ci->r+PAIR_DY_ADV1].u.md_ival*scale );
    2832           0 :         miny = me->ymin + rint(old[cols*ci->r+PAIR_DY1].u.md_ival*scale);
    2833           0 :         maxy = me->ymax + rint(old[cols*ci->r+PAIR_DY1].u.md_ival*scale);
    2834           0 :         if ( miny > vwidth + kern + rint(old[cols*ci->r+PAIR_DY2].u.md_ival*scale) + other->ymin )
    2835           0 :             miny = vwidth + kern + rint(old[cols*ci->r+PAIR_DY2].u.md_ival*scale) + other->ymin;
    2836           0 :         if ( maxy < vwidth + kern + rint(old[cols*ci->r+PAIR_DY2].u.md_ival*scale) + other->ymax )
    2837           0 :             maxy = vwidth + kern + rint(old[cols*ci->r+PAIR_DY2].u.md_ival*scale) + other->ymax;
    2838           0 :         height = maxy - miny + 2;
    2839           0 :         minx = me->xmin + rint(old[cols*ci->r+PAIR_DX1].u.md_ival*scale); maxx = me->xmax + rint(old[cols*ci->r+PAIR_DX1].u.md_ival*scale);
    2840           0 :         if ( minx>other->xmin + rint(old[cols*ci->r+PAIR_DX2].u.md_ival*scale) ) minx = other->xmin+ rint(old[cols*ci->r+PAIR_DX2].u.md_ival*scale) ;
    2841           0 :         if ( maxx<other->xmax + rint(old[cols*ci->r+PAIR_DX2].u.md_ival*scale) ) maxx = other->xmax+ rint(old[cols*ci->r+PAIR_DX2].u.md_ival*scale) ;
    2842             : 
    2843           0 :         img = GImageCreate(it_index,maxx-minx+2,height);
    2844           0 :         base = img->u.image;
    2845           0 :         memset(base->data,'\0',base->bytes_per_line*base->height);
    2846             : 
    2847           0 :         yoffset = 1 + maxy - vwidth - kern - rint(old[cols*ci->r+PAIR_DY1].u.md_ival*scale);
    2848           0 :         xoffset = 1 - minx + rint(old[cols*ci->r+PAIR_DX1].u.md_ival*scale);
    2849           0 :         for ( y=me->ymin; y<=me->ymax; ++y ) {
    2850           0 :             for ( x=me->xmin; x<=me->xmax; ++x ) {
    2851           0 :                 base->data[(yoffset-y)*base->bytes_per_line + (x+xoffset)] =
    2852           0 :                         me->bitmap[(me->ymax-y)*me->bytes_per_line + (x-me->xmin)];
    2853             :             }
    2854             :         }
    2855           0 :         yoffset = 1 + maxy - rint(old[cols*ci->r+PAIR_DY2].u.md_ival*scale);
    2856           0 :         xoffset = 1 - minx + rint(old[cols*ci->r+PAIR_DX2].u.md_ival*scale);
    2857           0 :         for ( y=other->ymin; y<=other->ymax; ++y ) {
    2858           0 :             for ( x=other->xmin; x<=other->xmax; ++x ) {
    2859           0 :                 int n = other->bitmap[(other->ymax-y)*other->bytes_per_line + (x-other->xmin)];
    2860           0 :                 if ( n>base->data[(yoffset-y)*base->bytes_per_line + (x+xoffset)] )
    2861           0 :                     base->data[(yoffset-y)*base->bytes_per_line + (x+xoffset)] = n;
    2862             :             }
    2863             :         }
    2864             :     } else {
    2865           0 :         coff1 = coff2 = 0;
    2866           0 :         if ( sub->lookup->lookup_flags & pst_r2l ) {
    2867           0 :             BDFChar *temp = me;
    2868           0 :             me = other;
    2869           0 :             other = temp;
    2870           0 :             coff1 = 8; coff2 = -8;
    2871             :         }
    2872           0 :         kern = rint( old[cols*ci->r+PAIR_DX_ADV1+coff1].u.md_ival*scale );
    2873           0 :         minx = me->xmin + rint(old[cols*ci->r+PAIR_DX1+coff1].u.md_ival*scale);
    2874           0 :         maxx = me->xmax + rint(old[cols*ci->r+PAIR_DX1+coff1].u.md_ival*scale);
    2875           0 :         if ( minx > me->width + kern + rint(old[cols*ci->r+PAIR_DX2+coff2].u.md_ival*scale) + other->xmin )
    2876           0 :             minx = me->width + kern + rint(old[cols*ci->r+PAIR_DX2+coff2].u.md_ival*scale) + other->xmin;
    2877           0 :         if ( maxx < me->width + kern + rint(old[cols*ci->r+PAIR_DX2+coff2].u.md_ival*scale) + other->xmax )
    2878           0 :             maxx = me->width + kern + rint(old[cols*ci->r+PAIR_DX2+coff2].u.md_ival*scale) + other->xmax;
    2879           0 :         width = maxx - minx + 2;
    2880           0 :         miny = me->ymin + rint(old[cols*ci->r+PAIR_DY1+coff1].u.md_ival*scale); maxy = me->ymax + rint(old[cols*ci->r+PAIR_DY1+coff1].u.md_ival*scale);
    2881           0 :         if ( miny>other->ymin + rint(old[cols*ci->r+PAIR_DY2+coff2].u.md_ival*scale) ) miny = other->ymin+ rint(old[cols*ci->r+PAIR_DY2+coff2].u.md_ival*scale) ;
    2882           0 :         if ( maxy<other->ymax + rint(old[cols*ci->r+PAIR_DY2+coff2].u.md_ival*scale) ) maxy = other->ymax+ rint(old[cols*ci->r+PAIR_DY2+coff2].u.md_ival*scale) ;
    2883             : 
    2884           0 :         img = GImageCreate(it_index,width,maxy-miny+2);
    2885           0 :         base = img->u.image;
    2886           0 :         memset(base->data,'\0',base->bytes_per_line*base->height);
    2887             : 
    2888           0 :         xoffset = rint(old[cols*ci->r+PAIR_DX1+coff1].u.md_ival*scale) + 1 - minx;
    2889           0 :         yoffset = 1 + maxy - rint(old[cols*ci->r+PAIR_DY1+coff1].u.md_ival*scale);
    2890           0 :         for ( y=me->ymin; y<=me->ymax; ++y ) {
    2891           0 :             for ( x=me->xmin; x<=me->xmax; ++x ) {
    2892           0 :                 base->data[(yoffset-y)*base->bytes_per_line + (x+xoffset)] =
    2893           0 :                         me->bitmap[(me->ymax-y)*me->bytes_per_line + (x-me->xmin)];
    2894             :             }
    2895             :         }
    2896           0 :         xoffset = 1 - minx + me->width + kern - rint(old[cols*ci->r+PAIR_DX2+coff2].u.md_ival*scale);
    2897           0 :         yoffset = 1 + maxy - rint(old[cols*ci->r+PAIR_DY2+coff2].u.md_ival*scale);
    2898           0 :         for ( y=other->ymin; y<=other->ymax; ++y ) {
    2899           0 :             for ( x=other->xmin; x<=other->xmax; ++x ) {
    2900           0 :                 int n = other->bitmap[(other->ymax-y)*other->bytes_per_line + (x-other->xmin)];
    2901           0 :                 if ( n>base->data[(yoffset-y)*base->bytes_per_line + (x+xoffset)] )
    2902           0 :                     base->data[(yoffset-y)*base->bytes_per_line + (x+xoffset)] = n;
    2903             :             }
    2904             :         }
    2905             :     }
    2906           0 :     memset(base->clut,'\0',sizeof(*base->clut));
    2907           0 :     bg = GDrawGetDefaultBackground(NULL);
    2908           0 :     fg = GDrawGetDefaultForeground(NULL);
    2909           0 :     clut_scale = me->depth == 8 ? 8 : 4;
    2910           0 :     base->clut->clut_len = 1<<clut_scale;
    2911           0 :     for ( l=0; l<(1<<clut_scale); ++l )
    2912           0 :         base->clut->clut[l] =
    2913           0 :             COLOR_CREATE(
    2914             :              COLOR_RED(bg) + (l*(COLOR_RED(fg)-COLOR_RED(bg)))/((1<<clut_scale)-1),
    2915             :              COLOR_GREEN(bg) + (l*(COLOR_GREEN(fg)-COLOR_GREEN(bg)))/((1<<clut_scale)-1),
    2916             :              COLOR_BLUE(bg) + (l*(COLOR_BLUE(fg)-COLOR_BLUE(bg)))/((1<<clut_scale)-1) );
    2917           0 :     BDFCharFree(me);
    2918           0 :     BDFCharFree(other);
    2919           0 : return( img );
    2920             : }
    2921             : 
    2922             : /* Draws an image of a glyph with a vertical bar down the middle. */
    2923             : /*  used to show italic correction position (we also dot in the width line) */
    2924             : /*  and top accent horizontal position for the MATH table */
    2925           0 : GImage *SC_GetLinedImage(SplineChar *sc, int def_layer, int pos, int is_italic_cor) {
    2926             :     BDFChar *me;
    2927           0 :     double scale = kern_popup_size/(double) (sc->parent->ascent+sc->parent->descent);
    2928             :     int miny, maxy, minx, maxx;
    2929             :     GImage *img;
    2930             :     struct _GImage *base;
    2931             :     Color fg, bg;
    2932             :     int l,clut_scale;
    2933             :     int x,y, xoffset, yoffset;
    2934             :     int pixel;
    2935             : 
    2936           0 :     if ( is_italic_cor )
    2937           0 :         pos += sc->width;
    2938           0 :     pos = rint( pos*scale );
    2939           0 :     if ( pos<-100 || pos>100 )
    2940           0 : return( NULL );
    2941           0 :     me = Rasterize(sc,def_layer);
    2942           0 :     if ( pos<me->xmin-10 || pos>me->xmax+30 ) {
    2943           0 :         BDFCharFree(me);
    2944           0 : return( NULL );
    2945             :     }
    2946           0 :     if ( (minx=me->xmin)>0 ) minx = 0;
    2947           0 :     if ( (maxx=me->xmax)<me->width ) maxx = me->width;
    2948           0 :     if ( pos<minx ) minx = pos-2;
    2949           0 :     if ( pos>maxx ) maxx = pos+2;
    2950           0 :     miny = me->ymin - 4;
    2951           0 :     maxy = me->ymax + 4;
    2952             : 
    2953           0 :     pixel = me->depth == 8 ? 0xff : 0xf;
    2954             : 
    2955           0 :     img = GImageCreate(it_index,maxx-minx+2,maxy-miny+2);
    2956           0 :     base = img->u.image;
    2957           0 :     memset(base->data,'\0',base->bytes_per_line*base->height);
    2958             : 
    2959           0 :     xoffset = 1 - minx;
    2960           0 :     yoffset = 1 + maxy;
    2961           0 :     for ( y=me->ymin; y<=me->ymax; ++y ) {
    2962           0 :         for ( x=me->xmin; x<=me->xmax; ++x ) {
    2963           0 :             base->data[(yoffset-y)*base->bytes_per_line + (x+xoffset)] =
    2964           0 :                     me->bitmap[(me->ymax-y)*me->bytes_per_line + (x-me->xmin)];
    2965             :         }
    2966             :     }
    2967           0 :     for ( y=miny; y<=maxy; ++y ) {
    2968           0 :         base->data[(yoffset-y)*base->bytes_per_line + (pos+xoffset)] = pixel;
    2969           0 :         if ( is_italic_cor && (y&1 ))
    2970           0 :             base->data[(yoffset-y)*base->bytes_per_line + (me->width+xoffset)] = pixel;
    2971             :     }
    2972             :     
    2973           0 :     memset(base->clut,'\0',sizeof(*base->clut));
    2974           0 :     bg = GDrawGetDefaultBackground(NULL);
    2975           0 :     fg = GDrawGetDefaultForeground(NULL);
    2976           0 :     clut_scale = me->depth == 8 ? 8 : 4;
    2977           0 :     base->clut->clut_len = 1<<clut_scale;
    2978           0 :     for ( l=0; l<(1<<clut_scale); ++l )
    2979           0 :         base->clut->clut[l] =
    2980           0 :             COLOR_CREATE(
    2981             :              COLOR_RED(bg) + (l*(COLOR_RED(fg)-COLOR_RED(bg)))/((1<<clut_scale)-1),
    2982             :              COLOR_GREEN(bg) + (l*(COLOR_GREEN(fg)-COLOR_GREEN(bg)))/((1<<clut_scale)-1),
    2983             :              COLOR_BLUE(bg) + (l*(COLOR_BLUE(fg)-COLOR_BLUE(bg)))/((1<<clut_scale)-1) );
    2984           0 :     BDFCharFree(me);
    2985           0 : return( img );
    2986             : }
    2987             : 
    2988             : #define ICON_WIDTH 15
    2989             : 
    2990           0 : GImage *GV_GetConstructedImage(SplineChar *sc,int def_layer,struct glyphvariants *gv, int is_horiz) {
    2991           0 :     SplineFont *sf = sc->parent;
    2992             :     BDFChar *me, **others;
    2993           0 :     double scale = kern_popup_size/(double) (sf->ascent+sf->descent);
    2994             :     GImage *img;
    2995             :     struct _GImage *base;
    2996             :     Color fg, bg;
    2997             :     int l,clut_scale;
    2998             :     int x,y;
    2999             :     int i,j;
    3000             : 
    3001           0 :     if ( gv==NULL || gv->part_cnt==0 )
    3002           0 : return( NULL );
    3003           0 :     me = Rasterize(sc,def_layer);
    3004           0 :     others = malloc(gv->part_cnt*sizeof(BDFChar *));
    3005           0 :     for ( i=0; i<gv->part_cnt; ++i ) {
    3006           0 :         SplineChar *othersc = SFGetChar(sf,-1,gv->parts[i].component);
    3007           0 :         if ( othersc==NULL ) {
    3008           0 :             for ( j=0; j<i; ++j )
    3009           0 :                 BDFCharFree(others[j]);
    3010           0 :             free(others);
    3011           0 : return( NULL );
    3012             :         }
    3013           0 :         others[i] = Rasterize(othersc,def_layer);
    3014             :     }
    3015           0 :     if ( is_horiz ) {
    3016             :         int ymin, ymax;
    3017             :         int width, xoff;
    3018             : 
    3019           0 :         for ( i=1; i<gv->part_cnt; ++i ) {        /* Normalize all but first. Makes construction easier */
    3020           0 :             others[i]->xmax -= others[i]->xmin;
    3021           0 :             others[i]->xmin = 0;
    3022             :         }
    3023           0 :         xoff = me->xmin<0 ? -me->xmin : 0;
    3024           0 :         width = xoff + me->width + ICON_WIDTH;
    3025           0 :         ymin = me->ymin; ymax = me->ymax;
    3026           0 :         for ( i=0; i<gv->part_cnt; ++i ) {
    3027             :             int overlap;
    3028           0 :             if ( i==gv->part_cnt-1 )
    3029           0 :                 overlap=0;
    3030             :             else {
    3031           0 :                 overlap = gv->parts[i].endConnectorLength>gv->parts[i+1].startConnectorLength ?
    3032           0 :                         gv->parts[i+1].startConnectorLength :
    3033             :                         gv->parts[i].endConnectorLength;
    3034           0 :                 overlap = rint( scale*overlap );
    3035             :             }
    3036           0 :             width += rint(gv->parts[i].fullAdvance*scale) - overlap + others[i]->xmin/* Only does anything if i==0, then it normalizes the rest to the same baseline */;
    3037           0 :             if ( others[i]->ymin<ymin ) ymin = others[i]->ymin;
    3038           0 :             if ( others[i]->ymax>ymax ) ymax = others[i]->ymax;
    3039             :         }
    3040           0 :         if ( ymax<=ICON_WIDTH ) ymax = ICON_WIDTH;
    3041           0 :         if ( ymin>0 ) ymin = 0;
    3042           0 :         img = GImageCreate(it_index,width+10,ymax-ymin+2);
    3043           0 :         base = img->u.image;
    3044           0 :         memset(base->data,'\0',base->bytes_per_line*base->height);
    3045             : 
    3046           0 :         ++xoff;         /* One pixel margin */
    3047             : 
    3048           0 :         for ( y=me->ymin; y<=me->ymax; ++y ) {
    3049           0 :             for ( x=me->xmin; x<=me->xmax; ++x ) {
    3050           0 :                 base->data[(1+ymax-y)*base->bytes_per_line + (x+xoff)] =
    3051           0 :                         me->bitmap[(me->ymax-y)*me->bytes_per_line + (x-me->xmin)];
    3052             :             }
    3053             :         }
    3054           0 :         xoff += me->width;
    3055             :         {
    3056           0 :             int pixel = me->depth == 8 ? 0xff : 0xf;
    3057           0 :             for ( j = -1; j<2; j+=2 ) {
    3058           0 :                 if ( me->ymax<-me->ymin )
    3059           0 :                     y = (me->ymax+me->ymin)/2;
    3060             :                 else
    3061           0 :                     y = 1+me->ymax/2;
    3062           0 :                 y = ymax-y + j*2;
    3063           0 :                 for ( x=1; x<ICON_WIDTH-5; ++x )
    3064           0 :                     base->data[y*base->bytes_per_line + (x+xoff)] = pixel;
    3065           0 :                 for ( x=ICON_WIDTH-8; x<ICON_WIDTH-1; ++x )
    3066           0 :                     base->data[(y+j*(ICON_WIDTH-4-x))*base->bytes_per_line + (x+xoff)] = pixel;
    3067             :             }
    3068           0 :             xoff += ICON_WIDTH;
    3069             :         }
    3070           0 :         for ( i=0; i<gv->part_cnt; ++i ) {
    3071             :             int overlap;
    3072           0 :             if ( i==gv->part_cnt-1 )
    3073           0 :                 overlap=0;
    3074             :             else {
    3075           0 :                 overlap = gv->parts[i].endConnectorLength>gv->parts[i+1].startConnectorLength ?
    3076           0 :                         gv->parts[i+1].startConnectorLength :
    3077             :                         gv->parts[i].endConnectorLength;
    3078           0 :                 overlap = rint( scale*overlap );
    3079             :             }
    3080           0 :             for ( y=others[i]->ymin; y<=others[i]->ymax; ++y ) {
    3081           0 :                 for ( x=others[i]->xmin; x<=others[i]->xmax; ++x ) {
    3082           0 :                     int n = others[i]->bitmap[(others[i]->ymax-y)*others[i]->bytes_per_line + (x-others[i]->xmin)];
    3083           0 :                     if ( n>base->data[(ymax-y)*base->bytes_per_line + (x+xoff)] )
    3084           0 :                         base->data[(ymax-y)*base->bytes_per_line + (x+xoff)] = n;
    3085             :                 }
    3086             :             }
    3087           0 :             xoff += rint(gv->parts[i].fullAdvance*scale) - overlap + others[i]->xmin/* Only does anything if i==0, then it normalizes the rest to the same baseline */;
    3088             :         }
    3089             :     } else {
    3090             :         int xmin, xmax, ymin, ymax;
    3091             :         int yoff, xoff, width;
    3092             : 
    3093           0 :         for ( i=1; i<gv->part_cnt; ++i ) {        /* Normalize all but first. Makes construction easier */
    3094           0 :             others[i]->ymax -= others[i]->ymin;
    3095           0 :             others[i]->ymin = 0;
    3096             :         }
    3097             : 
    3098           0 :         xoff = me->xmin<0 ? -me->xmin : 0;
    3099           0 :         width = xoff + me->width + ICON_WIDTH;
    3100           0 :         ymin = me->ymin; ymax = me->ymax;
    3101           0 :         xmin = xmax = 0;
    3102           0 :         yoff = 0;
    3103           0 :         for ( i=0; i<gv->part_cnt; ++i ) {
    3104             :             int overlap;
    3105           0 :             if ( i==gv->part_cnt-1 )
    3106           0 :                 overlap=0;
    3107             :             else {
    3108           0 :                 overlap = gv->parts[i].endConnectorLength>gv->parts[i+1].startConnectorLength ?
    3109           0 :                         gv->parts[i+1].startConnectorLength :
    3110             :                         gv->parts[i].endConnectorLength;
    3111           0 :                 overlap = rint( scale*overlap );
    3112             :             }
    3113           0 :             if ( ymin>others[i]->ymin+yoff ) ymin = others[i]->ymin+yoff;
    3114           0 :             if ( ymax<others[i]->ymax+yoff ) ymax = others[i]->ymax+yoff;
    3115           0 :             yoff += rint(gv->parts[i].fullAdvance*scale) - overlap + others[i]->ymin/* Only does anything if i==0, then it normalizes the rest to the same baseline */;
    3116           0 :             if ( others[i]->xmin<xmin ) xmin = others[i]->xmin;
    3117           0 :             if ( others[i]->xmax>xmax ) xmax = others[i]->xmax;
    3118             :         }
    3119           0 :         if ( xmin<-width ) {
    3120           0 :             xoff = -xmin-width;
    3121           0 :             width = -xmin;
    3122             :         }
    3123           0 :         if ( xmax>0 )
    3124           0 :             width += xmax;
    3125           0 :         if ( ymax<=ICON_WIDTH ) ymax = ICON_WIDTH;
    3126           0 :         if ( ymin>0 ) ymin = 0;
    3127           0 :         img = GImageCreate(it_index,width+2,ymax-ymin+2);
    3128           0 :         base = img->u.image;
    3129           0 :         memset(base->data,'\0',base->bytes_per_line*base->height);
    3130             : 
    3131           0 :         ++xoff;         /* One pixel margin */
    3132             : 
    3133           0 :         for ( y=me->ymin; y<=me->ymax; ++y ) {
    3134           0 :             for ( x=me->xmin; x<=me->xmax; ++x ) {
    3135           0 :                 base->data[(1+ymax-y)*base->bytes_per_line + (x+xoff)] =
    3136           0 :                         me->bitmap[(me->ymax-y)*me->bytes_per_line + (x-me->xmin)];
    3137             :             }
    3138             :         }
    3139           0 :         xoff += me->width;
    3140             :         {
    3141           0 :             int pixel = me->depth == 8 ? 0xff : 0xf;
    3142           0 :             for ( j = -1; j<2; j+=2 ) {
    3143           0 :                 if ( me->ymax<-me->ymin )
    3144           0 :                     y = (me->ymax+me->ymin)/2;
    3145             :                 else
    3146           0 :                     y = 1+me->ymax/2;
    3147           0 :                 y = ymax-y + j*2;
    3148           0 :                 for ( x=1; x<ICON_WIDTH-5; ++x )
    3149           0 :                     base->data[y*base->bytes_per_line + (x+xoff)] = pixel;
    3150           0 :                 for ( x=ICON_WIDTH-8; x<ICON_WIDTH-1; ++x )
    3151           0 :                     base->data[(y+j*(ICON_WIDTH-4-x))*base->bytes_per_line + (x+xoff)] = pixel;
    3152             :             }
    3153           0 :             xoff += ICON_WIDTH;
    3154             :         }
    3155           0 :         yoff=0;
    3156           0 :         for ( i=0; i<gv->part_cnt; ++i ) {
    3157             :             int overlap;
    3158           0 :             if ( i==gv->part_cnt-1 )
    3159           0 :                 overlap=0;
    3160             :             else {
    3161           0 :                 overlap = gv->parts[i].endConnectorLength>gv->parts[i+1].startConnectorLength ?
    3162           0 :                         gv->parts[i+1].startConnectorLength :
    3163             :                         gv->parts[i].endConnectorLength;
    3164           0 :                 overlap = rint( scale*overlap );
    3165             :             }
    3166           0 :             for ( y=others[i]->ymin; y<=others[i]->ymax; ++y ) {
    3167           0 :                 for ( x=others[i]->xmin; x<=others[i]->xmax; ++x ) {
    3168           0 :                     int n = others[i]->bitmap[(others[i]->ymax-y)*others[i]->bytes_per_line + (x-others[i]->xmin)];
    3169           0 :                     if ( n>base->data[(ymax-y-yoff)*base->bytes_per_line + (x+xoff)] )
    3170           0 :                         base->data[(ymax-y-yoff)*base->bytes_per_line + (x+xoff)] = n;
    3171             :                 }
    3172             :             }
    3173           0 :             yoff += rint(gv->parts[i].fullAdvance*scale) - overlap + others[i]->ymin/* Only does anything if i==0, then it normalizes the rest to the same baseline */;
    3174             :         }
    3175             :     }
    3176           0 :     for ( i=0; i<gv->part_cnt; ++i )
    3177           0 :         BDFCharFree(others[i]);
    3178           0 :     free(others);
    3179             : 
    3180           0 :     memset(base->clut,'\0',sizeof(*base->clut));
    3181           0 :     bg = GDrawGetDefaultBackground(NULL);
    3182           0 :     fg = GDrawGetDefaultForeground(NULL);
    3183           0 :     clut_scale = me->depth == 8 ? 8 : 4;
    3184           0 :     BDFCharFree(me);
    3185           0 :     base->clut->clut_len = 1<<clut_scale;
    3186           0 :     for ( l=0; l<(1<<clut_scale); ++l )
    3187           0 :         base->clut->clut[l] =
    3188           0 :             COLOR_CREATE(
    3189             :              COLOR_RED(bg) + (l*(COLOR_RED(fg)-COLOR_RED(bg)))/((1<<clut_scale)-1),
    3190             :              COLOR_GREEN(bg) + (l*(COLOR_GREEN(fg)-COLOR_GREEN(bg)))/((1<<clut_scale)-1),
    3191             :              COLOR_BLUE(bg) + (l*(COLOR_BLUE(fg)-COLOR_BLUE(bg)))/((1<<clut_scale)-1) );
    3192           0 : return( img );
    3193             : }
    3194             : 
    3195           0 : static GImage *CI_GetConstructedImage(const void *_ci) {
    3196           0 :     CharInfo *ci = (CharInfo *) _ci;
    3197             :     GImage *ret;
    3198           0 :     int is_horiz = GTabSetGetSel(GWidgetGetControl(ci->gw,CID_Tabs))-ci->vert_aspect;
    3199             :     struct glyphvariants *gv;
    3200             : 
    3201           0 :     gv = CI_ParseVariants(NULL,ci,is_horiz,NULL,0,true);
    3202             : 
    3203           0 :     ret = GV_GetConstructedImage(ci->sc,ci->def_layer,gv,is_horiz);
    3204           0 :     GlyphVariantsFree(gv);
    3205           0 : return( ret );
    3206             : }
    3207             : 
    3208           0 : GImage *NameList_GetImage(SplineFont *sf,SplineChar *sc,int def_layer,
    3209             :         char *namelist, int isliga ) {
    3210             :     BDFChar *me, **extras;
    3211             :     int width, xmin, xmax, ymin, ymax;
    3212             :     GImage *img;
    3213             :     struct _GImage *base;
    3214             :     Color fg, bg;
    3215             :     int l,clut_scale;
    3216             :     int x,y;
    3217             :     SplineChar *other;
    3218             :     int extracnt;
    3219             :     int i,j;
    3220           0 :     char *subs = namelist, *pt, *start;
    3221             :     int ch;
    3222             : 
    3223           0 :     if ( sc==NULL || sf==NULL || namelist==NULL )
    3224           0 : return( NULL );
    3225           0 :     me = Rasterize(sc,def_layer);
    3226           0 :     ymin = me->ymin; ymax = me->ymax;
    3227           0 :     xmin = me->xmin; xmax = me->xmax; width = me->width;
    3228           0 :     extracnt = 0; extras = NULL;
    3229             : 
    3230           0 :     for ( pt=subs; *pt ; ++extracnt ) {
    3231           0 :         while ( *pt!=' ' && *pt!='\0' ) ++pt;
    3232           0 :         if ( *pt==' ' )
    3233           0 :             while ( *pt==' ' ) ++pt;
    3234             :     }
    3235           0 :     extras = malloc(extracnt*sizeof(BDFChar *));
    3236           0 :     extracnt = 0;
    3237           0 :     for ( pt=subs; *pt ; ) {
    3238           0 :         start = pt;
    3239           0 :         while ( *pt!=' ' && *pt!='\0' && *pt!='(' ) ++pt;
    3240           0 :         ch = *pt; *pt = '\0';
    3241           0 :         other = SFGetChar(sf,-1, start);
    3242           0 :         *pt = ch;
    3243           0 :         if ( ch=='(' ) {
    3244           0 :             while ( *pt!=')' && *pt!='\0' ) ++pt;
    3245           0 :             if ( *pt==')' ) ++pt;
    3246             :         }
    3247           0 :         if ( other!=NULL ) {
    3248           0 :             if ( extracnt==0 ) width += ICON_WIDTH;
    3249           0 :             extras[extracnt] = Rasterize(other,def_layer);
    3250           0 :             if ( width+extras[extracnt]->xmin < xmin ) xmin = width+extras[extracnt]->xmin;
    3251           0 :             if ( width+extras[extracnt]->xmax > xmax ) xmax = width+extras[extracnt]->xmax;
    3252           0 :             if ( extras[extracnt]->ymin < ymin ) ymin = extras[extracnt]->ymin;
    3253           0 :             if ( extras[extracnt]->ymax > ymax ) ymax = extras[extracnt]->ymax;
    3254           0 :             width += extras[extracnt++]->width;
    3255             :         }
    3256           0 :         if ( *pt==' ' )
    3257           0 :             while ( *pt==' ' ) ++pt;
    3258             :     }
    3259             : 
    3260           0 :     if ( ymax<=ICON_WIDTH ) ymax = ICON_WIDTH;
    3261           0 :     if ( ymin>0 ) ymin = 0;
    3262           0 :     if ( xmax<xmin ) {
    3263           0 :         for ( i=0; i<extracnt; ++i )
    3264           0 :             BDFCharFree(extras[i]);
    3265           0 :         free(extras);
    3266           0 :         return( NULL );
    3267             :     }
    3268             : 
    3269           0 :     if ( xmin>0 ) xmin = 0;
    3270             : 
    3271           0 :     img = GImageCreate(it_index,xmax - xmin + 2,ymax-ymin+2);
    3272           0 :     base = img->u.image;
    3273           0 :     memset(base->data,'\0',base->bytes_per_line*base->height);
    3274             : 
    3275           0 :     width = -xmin;
    3276           0 :     ++width;
    3277             : 
    3278           0 :     for ( y=me->ymin; y<=me->ymax; ++y ) {
    3279           0 :         for ( x=me->xmin; x<=me->xmax; ++x ) {
    3280           0 :             base->data[(1+ymax-y)*base->bytes_per_line + (x+width)] =
    3281           0 :                     me->bitmap[(me->ymax-y)*me->bytes_per_line + (x-me->xmin)];
    3282             :         }
    3283             :     }
    3284           0 :     width += me->width;
    3285           0 :     if ( extracnt!=0 ) {
    3286           0 :         int pixel = me->depth == 8 ? 0xff : 0xf;
    3287           0 :         if ( !isliga ) {
    3288           0 :             for ( j = -1; j<2; j+=2 ) {
    3289           0 :                 if ( me->ymax<-me->ymin )
    3290           0 :                     y = (me->ymax+me->ymin)/2;
    3291             :                 else
    3292           0 :                     y = 1+me->ymax/2;
    3293           0 :                 y = ymax-y + j*2;
    3294           0 :                 for ( x=1; x<ICON_WIDTH-5; ++x )
    3295           0 :                     base->data[y*base->bytes_per_line + (x+width)] = pixel;
    3296           0 :                 for ( x=ICON_WIDTH-8; x<ICON_WIDTH-1; ++x )
    3297           0 :                     base->data[(y+j*(ICON_WIDTH-4-x))*base->bytes_per_line + (x+width)] = pixel;
    3298             :             }
    3299           0 :         } else if ( isliga>0 ) {
    3300           0 :             for ( j = -1; j<2; j+=2 ) {
    3301           0 :                 y = 1+ymax/2 + j*2;
    3302           0 :                 for ( x=5; x<ICON_WIDTH-1; ++x )
    3303           0 :                     base->data[y*base->bytes_per_line + (x+width)] = pixel;
    3304           0 :                 for ( x=8; x>1 ; --x )
    3305           0 :                     base->data[(y+j*(x-3))*base->bytes_per_line + (x+width)] = pixel;
    3306             :             }
    3307             :         }
    3308           0 :         width += ICON_WIDTH;
    3309           0 :         for ( i=0; i<extracnt; ++i ) {
    3310           0 :             BDFChar *other = extras[i];
    3311           0 :             for ( y=other->ymin; y<=other->ymax; ++y ) {
    3312           0 :                 for ( x=other->xmin; x<=other->xmax; ++x ) {
    3313           0 :                     if ( other->bitmap[(other->ymax-y)*other->bytes_per_line + (x-other->xmin)] != 0 )
    3314           0 :                         base->data[(1+ymax-y)*base->bytes_per_line + (x+width)] =
    3315           0 :                                 other->bitmap[(other->ymax-y)*other->bytes_per_line + (x-other->xmin)];
    3316             :                 }
    3317             :             }
    3318           0 :             width += other->width;
    3319             :         }
    3320             :     }
    3321           0 :     memset(base->clut,'\0',sizeof(*base->clut));
    3322           0 :     bg = GDrawGetDefaultBackground(NULL);
    3323           0 :     fg = GDrawGetDefaultForeground(NULL);
    3324           0 :     clut_scale = me->depth == 8 ? 8 : 4;
    3325           0 :     base->clut->clut_len = 1<<clut_scale;
    3326           0 :     for ( l=0; l<(1<<clut_scale); ++l )
    3327           0 :         base->clut->clut[l] =
    3328           0 :             COLOR_CREATE(
    3329             :              COLOR_RED(bg) + (l*(COLOR_RED(fg)-COLOR_RED(bg)))/((1<<clut_scale)-1),
    3330             :              COLOR_GREEN(bg) + (l*(COLOR_GREEN(fg)-COLOR_GREEN(bg)))/((1<<clut_scale)-1),
    3331             :              COLOR_BLUE(bg) + (l*(COLOR_BLUE(fg)-COLOR_BLUE(bg)))/((1<<clut_scale)-1) );
    3332           0 :      BDFCharFree(me);
    3333           0 :      for ( i=0; i<extracnt; ++i )
    3334           0 :          BDFCharFree(extras[i]);
    3335           0 :      free(extras);
    3336           0 : return( img );
    3337             : }
    3338             : 
    3339           0 : GImage *PST_GetImage(GGadget *pstk,SplineFont *sf,int def_layer,
    3340             :         struct lookup_subtable *sub,int popup_r, SplineChar *sc ) {
    3341           0 :     int rows, cols = GMatrixEditGetColCnt(pstk);
    3342           0 :     struct matrix_data *old = GMatrixEditGet(pstk,&rows);
    3343             : 
    3344           0 :     if ( sc==NULL || sub==NULL )
    3345           0 : return( NULL );
    3346           0 :     if ( sub->lookup->lookup_type<gsub_single || sub->lookup->lookup_type>gsub_ligature )
    3347           0 : return( NULL );
    3348             : 
    3349           0 : return( NameList_GetImage(sf,sc,def_layer,old[cols*popup_r+1].u.md_str,
    3350           0 :         sub->lookup->lookup_type==gsub_ligature));
    3351             : }
    3352             : 
    3353           0 : static GImage *_CI_GetImage(const void *_ci) {
    3354           0 :     CharInfo *ci = (CharInfo *) _ci;
    3355           0 :     int offset = GTabSetGetSel(GWidgetGetControl(ci->gw,CID_Tabs))-2;
    3356           0 :     GGadget *pstk = GWidgetGetControl(ci->gw,CID_List+offset*100);
    3357           0 :     int rows, cols = GMatrixEditGetColCnt(pstk);
    3358           0 :     struct matrix_data *old = GMatrixEditGet(pstk,&rows);
    3359           0 :     struct lookup_subtable *sub = (struct lookup_subtable *) (old[cols*ci->r+0].u.md_ival);
    3360             : 
    3361           0 :     if ( ci->r>=rows )
    3362           0 : return( NULL );
    3363             : 
    3364           0 : return( PST_GetImage(pstk,ci->sc->parent,ci->def_layer,sub,ci->r,ci->sc) );
    3365             : }
    3366             : 
    3367           0 : static void CI_KerningPopupPrepare(GGadget *g, int r, int c) {
    3368           0 :     CharInfo *ci = GDrawGetUserData(GGadgetGetWindow(g));
    3369           0 :     int rows, cols = GMatrixEditGetColCnt(g);
    3370           0 :     struct matrix_data *old = GMatrixEditGet(g,&rows);
    3371             : 
    3372           0 :     if ( c<0 || c>=cols || r<0 || r>=rows || old[cols*r+1].u.md_str==NULL ||
    3373           0 :         SFGetChar(ci->sc->parent,-1, old[cols*r+1].u.md_str)==NULL )
    3374           0 : return;
    3375           0 :     ci->r = r; ci->c = c;
    3376           0 :     GGadgetPreparePopupImage(GGadgetGetWindow(g),NULL,ci,CI_GetKernedImage,CI_FreeKernedImage);
    3377             : }
    3378             : 
    3379           0 : static void CI_SubsPopupPrepare(GGadget *g, int r, int c) {
    3380           0 :     CharInfo *ci = GDrawGetUserData(GGadgetGetWindow(g));
    3381           0 :     int rows, cols = GMatrixEditGetColCnt(g);
    3382             : 
    3383           0 :     (void) GMatrixEditGet(g,&rows);
    3384           0 :     if ( c<0 || c>=cols || r<0 || r>=rows )
    3385           0 : return;
    3386           0 :     ci->r = r; ci->c = c;
    3387           0 :     GGadgetPreparePopupImage(GGadgetGetWindow(g),NULL,ci,_CI_GetImage,CI_FreeKernedImage);
    3388             : }
    3389             : 
    3390           0 : static void CI_ConstructionPopupPrepare(GGadget *g, int r, int c) {
    3391           0 :     CharInfo *ci = GDrawGetUserData(GGadgetGetWindow(g));
    3392             :     int rows/*, cols = GMatrixEditGetColCnt(g)*/;
    3393             : 
    3394           0 :     (void) GMatrixEditGet(g,&rows);
    3395           0 :     if ( rows==0 )
    3396           0 : return;
    3397           0 :     GGadgetPreparePopupImage(GGadgetGetWindow(g),NULL,ci,CI_GetConstructedImage,CI_FreeKernedImage);
    3398             : }
    3399             : 
    3400           0 : static unichar_t **CI_GlyphNameCompletion(GGadget *t,int from_tab) {
    3401           0 :     CharInfo *ci = GDrawGetUserData(GDrawGetParentWindow(GGadgetGetWindow(t)));
    3402           0 :     SplineFont *sf = ci->sc->parent;
    3403             : 
    3404           0 : return( SFGlyphNameCompletion(sf,t,from_tab,false));
    3405             : }
    3406             : 
    3407           0 : static unichar_t **CI_GlyphListCompletion(GGadget *t,int from_tab) {
    3408           0 :     CharInfo *ci = GDrawGetUserData(GDrawGetParentWindow(GGadgetGetWindow(t)));
    3409           0 :     SplineFont *sf = ci->sc->parent;
    3410             : 
    3411           0 : return( SFGlyphNameCompletion(sf,t,from_tab,true));
    3412             : }
    3413             : 
    3414             : 
    3415           0 : static void extpart_finishedit(GGadget *g, int r, int c, int wasnew) {
    3416             :     int rows;
    3417             :     struct matrix_data *possub;
    3418             :     CharInfo *ci;
    3419             :     int is_horiz,cols;
    3420             :     DBounds b;
    3421             :     double full_advance;
    3422             :     SplineChar *sc;
    3423             : 
    3424           0 :     if ( c!=0 )
    3425           0 : return;
    3426           0 :     if ( !wasnew )
    3427           0 : return;
    3428             :     /* If they added a new glyph to the sequence then set some defaults for it. */
    3429             :     /*  only the full advance has any likelyhood of being correct */
    3430           0 :     ci = GDrawGetUserData(GGadgetGetWindow(g));
    3431           0 :     is_horiz = GTabSetGetSel(GWidgetGetControl(ci->gw,CID_Tabs))-ci->vert_aspect;
    3432           0 :     possub = GMatrixEditGet(g, &rows);
    3433           0 :     cols = GMatrixEditGetColCnt(g);
    3434           0 :     if ( possub[r*cols+0].u.md_str==NULL )
    3435           0 : return;
    3436           0 :     sc = SFGetChar(ci->sc->parent,-1,possub[r*cols+0].u.md_str);
    3437           0 :     if ( sc==NULL )
    3438           0 : return;
    3439           0 :     SplineCharFindBounds(sc,&b);
    3440           0 :     if ( is_horiz )
    3441           0 :         full_advance = b.maxx - b.minx;
    3442             :     else
    3443           0 :         full_advance = b.maxy - b.miny;
    3444           0 :     possub[r*cols+2].u.md_ival = possub[r*cols+3].u.md_ival = rint(full_advance/3);
    3445           0 :     possub[r*cols+4].u.md_ival = rint(full_advance);
    3446           0 :     GGadgetRedraw(g);
    3447             : }
    3448             : 
    3449             : static GTextInfo truefalse[] = {
    3450             :     { (unichar_t *) N_("false"), NULL, 0, 0, (void *) 0, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
    3451             :     { (unichar_t *) N_("true"),  NULL, 0, 0, (void *) 1, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
    3452             :     GTEXTINFO_EMPTY
    3453             : };
    3454             : 
    3455             : static struct col_init extensionpart[] = {
    3456             :     { me_string , NULL, NULL, NULL, N_("Glyph") },
    3457             :     { me_enum, NULL, truefalse, NULL, N_("Extender") },
    3458             : /* GT: "Len" is an abreviation for "Length" */
    3459             :     { me_int, NULL, NULL, NULL, N_("StartLen") },
    3460             :     { me_int, NULL, NULL, NULL, N_("EndLen") },
    3461             :     { me_int, NULL, NULL, NULL, N_("FullLen") },
    3462             :     COL_INIT_EMPTY
    3463             : };
    3464             : static struct matrixinit mi_extensionpart =
    3465             :     { sizeof(extensionpart)/sizeof(struct col_init)-1, extensionpart, 0, NULL, NULL, NULL, extpart_finishedit, NULL, NULL, NULL };
    3466             : 
    3467           0 : static int isxheight(int uni) {
    3468           0 :     if ( uni>=0x10000 || !islower(uni))
    3469           0 : return( false );
    3470             : 
    3471           0 :     if ( uni=='a' || uni=='c' || uni=='e' || uni=='i' || uni=='j' ||
    3472           0 :             (uni>='m' && uni<='z') ||
    3473           0 :             uni==0x131 || uni==0x237 || /* Ignore accented letters except the dotlessi/j */
    3474           0 :             (uni>=0x250 && uni<0x253) || uni==0x254 || uni==0x255 ||
    3475           0 :             (uni>=0x258 && uni<0x265) || uni==0x269 || uni==0x26A ||
    3476           0 :             (uni>=0x26f && uni<=0x277) || uni==0x279 ||
    3477           0 :             uni==0x3b1 || uni==0x3b3 || uni==0x3b5 || uni==0x3b7 ||
    3478           0 :             uni==0x3b9 || uni==0x3ba || uni==0x3bc || uni==0x3bd ||
    3479           0 :             (uni>=0x3bf && uni<=0x3c7) || uni==0x3c9 ||
    3480           0 :             (uni>=0x400 && uni<=0x45f))
    3481           0 : return( true );
    3482             : 
    3483           0 : return( false );
    3484             : }
    3485             : 
    3486           0 : static int isbaseline(int uni) {
    3487             :     /* Treat rounded letters as being on the base line */
    3488             :     /* But don't bother including guys that normally are on the baseline */
    3489             : 
    3490           0 :     if ( (uni>='a' && uni<'g') || uni=='h' || uni=='i' ||
    3491           0 :             (uni>='k' && uni<='o') || (uni>='r' && uni<'y') || uni=='z' ||
    3492           0 :             (uni>='A' && uni<='Z' ) ||
    3493           0 :             uni==0x3b0 || uni==0x3b4 || uni==0x3b5 || (uni>=0x3b8 && uni<0x3bb) ||
    3494           0 :             uni==0x3bd || uni==0x3bf || uni==0x3c0 || (uni>=0x3c2 && uni<0x3c6) ||
    3495           0 :             uni==0x3c8 || uni==0x3c7 || uni==0x3c9 ||
    3496           0 :             (uni>=0x391 && uni<0x3aa) ||
    3497           0 :             (uni>=0x400 && uni<0x40f) || (uni>=0x410 && uni<=0x413) ||
    3498           0 :             (uni>=0x415 && uni<0x425) || uni==0x427 || uni==0x428 ||
    3499           0 :             (uni>=0x42a && uni<0x433) || (uni>=0x435 && uni<0x45e) )
    3500           0 : return( true );
    3501             : 
    3502           0 : return( false );
    3503             : }
    3504             : 
    3505           0 : static int TeX_Default(GGadget *g, GEvent *e) {
    3506           0 :     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
    3507           0 :         CharInfo *ci = GDrawGetUserData(GGadgetGetWindow(g));
    3508           0 :         int cid = GGadgetGetCid(g);
    3509             :         DBounds b;
    3510             :         int value;
    3511           0 :         SplineChar *basesc = NULL;
    3512           0 :         SplineFont *sf = ci->sc->parent;
    3513             :         int style;
    3514             :         char buf[12];
    3515             : 
    3516           0 :         basesc = ci->sc;
    3517             :         /* Try to align the top of lowercase (xheight) letters all at the */
    3518             :         /*  same height. Ditto for uppercase & ascender letters */
    3519           0 :         if ( cid==CID_TeX_HeightD && ci->sc->unicodeenc<0x10000 &&
    3520           0 :                 isxheight(ci->sc->unicodeenc) &&
    3521             :                 (basesc = SFGetChar(sf,'x',NULL))!=NULL )
    3522             :             /* Done */;
    3523           0 :         else if ( cid==CID_TeX_HeightD && ci->sc->unicodeenc<0x10000 &&
    3524           0 :                 islower(ci->sc->unicodeenc) &&
    3525             :                 (basesc = SFGetChar(sf,'l',NULL))!=NULL )
    3526             :             /* Done */;
    3527           0 :         else if ( cid==CID_TeX_HeightD && ci->sc->unicodeenc<0x10000 &&
    3528           0 :                 isupper(ci->sc->unicodeenc) &&
    3529             :                 (basesc = SFGetChar(sf,'I',NULL))!=NULL )
    3530             :             /* Done */;
    3531           0 :         else if ( cid==CID_TeX_DepthD && ci->sc->unicodeenc<0x10000 &&
    3532           0 :                 isbaseline(ci->sc->unicodeenc) &&
    3533             :                 (basesc = SFGetChar(sf,'I',NULL))!=NULL )
    3534             :             /* Done */;
    3535             :         else
    3536           0 :             basesc = ci->sc;
    3537             : 
    3538           0 :         SplineCharFindBounds(basesc,&b);
    3539           0 :         style = MacStyleCode(sf,NULL);
    3540             : 
    3541           0 :         if ( cid == CID_TeX_HeightD ) {
    3542           0 :             if ( basesc!=ci->sc && basesc->tex_height!=TEX_UNDEF )
    3543           0 :                 value = basesc->tex_height;
    3544             :             else
    3545           0 :                 value = rint(b.maxy);
    3546           0 :             if ( value<0 ) value = 0;
    3547           0 :         } else if ( cid == CID_TeX_DepthD ) {
    3548           0 :             if ( basesc!=ci->sc && basesc->tex_depth!=TEX_UNDEF )
    3549           0 :                 value = basesc->tex_depth;
    3550             :             else {
    3551           0 :                 value = -rint(b.miny);
    3552           0 :                 if ( value<5 ) value = 0;
    3553             :             }
    3554           0 :         } else if ( cid == CID_HorAccentD ) {
    3555           0 :             double italic_off = (b.maxy-b.miny)*tan(-sf->italicangle);
    3556           0 :             if ( b.maxx-b.minx-italic_off < 0 )
    3557           0 :                 value = rint(b.minx + (b.maxx-b.minx)/2);
    3558             :             else
    3559           0 :                 value = rint(b.minx + italic_off + (b.maxx - b.minx - italic_off)/2);
    3560           0 :         } else if ( (style&sf_italic) || sf->italicangle!=0 ) {
    3561           0 :             value = rint((b.maxx-ci->sc->width) +
    3562           0 :                             (sf->ascent+sf->descent)/16.0);
    3563             :         } else
    3564           0 :             value = 0;
    3565           0 :         sprintf( buf, "%d", value );
    3566           0 :         GGadgetSetTitle8(GWidgetGetControl(ci->gw,cid-5),buf);
    3567             :     }
    3568           0 : return( true );
    3569             : }
    3570             : 
    3571           0 : static int CI_SubSuperPositionings(GGadget *g, GEvent *e) {
    3572           0 :     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
    3573           0 :         CharInfo *ci = GDrawGetUserData(GGadgetGetWindow(g));
    3574           0 :         MathKernDialog(ci->sc,ci->def_layer);
    3575             :     }
    3576           0 : return( true );
    3577             : }
    3578             : 
    3579             : static struct col_init altuniinfo[] = {
    3580             :     { me_uhex , NULL, NULL, NULL, N_("Unicode") },
    3581             :     { me_uhex, NULL, truefalse, NULL, N_("Variation Selector (or 0)") },
    3582             :     COL_INIT_EMPTY
    3583             : };
    3584             : static struct matrixinit mi_altuniinfo =
    3585             :     { sizeof(altuniinfo)/sizeof(struct col_init)-1, altuniinfo, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
    3586             : 
    3587           0 : static void CI_NoteAspect(CharInfo *ci) {
    3588           0 :     int new_aspect = GTabSetGetSel(GWidgetGetControl(ci->gw,CID_Tabs));
    3589             :     PST *pst;
    3590             :     int cnt;
    3591             :     char buf[20];
    3592             : 
    3593           0 :     last_gi_aspect = new_aspect;
    3594           0 :     if ( new_aspect == ci->lc_aspect && (!ci->lc_seen || GGadgetIsChecked(GWidgetGetControl(ci->gw,CID_DefLCCount)))) {
    3595           0 :         ci->lc_seen = true;
    3596           0 :         for ( pst=ci->sc->possub; pst!=NULL && pst->type!=pst_lcaret; pst=pst->next );
    3597           0 :         if ( GGadgetIsChecked(GWidgetGetControl(ci->gw,CID_DefLCCount)) &&
    3598           0 :                 pst==NULL ) {
    3599             :             int rows, cols, i;
    3600             :             struct matrix_data *possub;
    3601             :             /* Normally we look for ligatures in the possub list, but here*/
    3602             :             /*  we will examine the ligature pane itself to get the most */
    3603             :             /*  up to date info */
    3604           0 :             possub = GMatrixEditGet(GWidgetGetControl(ci->gw,CID_List+(pst_ligature-1)*100), &rows );
    3605           0 :             cols = GMatrixEditGetColCnt(GWidgetGetControl(ci->gw,CID_List+(pst_ligature-1)*100) );
    3606           0 :             cnt = 0;
    3607           0 :             for ( i=0; i<rows; ++i ) {
    3608           0 :                 char *pt = possub[cols*i+1].u.md_str;
    3609           0 :                 int comp = 0;
    3610           0 :                 while ( *pt!='\0' ) {
    3611           0 :                     while ( *pt==' ' ) ++pt;
    3612           0 :                     if ( *pt=='\0' )
    3613           0 :                 break;
    3614           0 :                     while ( *pt!=' ' && *pt!='\0' ) ++pt;
    3615           0 :                     ++comp;
    3616             :                 }
    3617           0 :                 if ( comp>cnt ) cnt = comp;
    3618             :             }
    3619           0 :             --cnt;              /* We want one fewer caret than there are components -- carets go BETWEEN components */
    3620           0 :         } else if ( pst!=NULL )
    3621           0 :             cnt = pst->u.lcaret.cnt;
    3622             :         else
    3623           0 :             cnt = 0;
    3624           0 :         if ( cnt<0 ) cnt = 0;
    3625           0 :         sprintf( buf, "%d", cnt );
    3626           0 :         GGadgetSetTitle8(GWidgetGetControl(ci->gw,CID_LCCount),buf);
    3627             :     }
    3628           0 : }
    3629             : 
    3630           0 : static int CI_AspectChange(GGadget *g, GEvent *e) {
    3631           0 :     if ( e->type==et_controlevent && e->u.control.subtype == et_radiochanged ) {
    3632           0 :         CharInfo *ci = GDrawGetUserData(GGadgetGetWindow(g));
    3633           0 :         CI_NoteAspect(ci);
    3634             :     }
    3635           0 : return( true );
    3636             : }
    3637             : 
    3638           0 : static int CI_DefLCChange(GGadget *g, GEvent *e) {
    3639           0 :     if ( e->type==et_controlevent && e->u.control.subtype == et_radiochanged ) {
    3640           0 :         CharInfo *ci = GDrawGetUserData(GGadgetGetWindow(g));
    3641           0 :         int show = !GGadgetIsChecked(g);
    3642           0 :         GGadgetSetEnabled(GWidgetGetControl(ci->gw,CID_LCCount),show);
    3643           0 :         GGadgetSetEnabled(GWidgetGetControl(ci->gw,CID_LCCountLab),show);
    3644             :     }
    3645           0 : return( true );
    3646             : }
    3647             : 
    3648           0 : void GV_ToMD(GGadget *g, struct glyphvariants *gv) {
    3649           0 :     int cols = GMatrixEditGetColCnt(g), j;
    3650             :     struct matrix_data *mds;
    3651           0 :     if ( gv==NULL ) {
    3652           0 :         GMatrixEditSet(g, NULL,0,false);
    3653           0 : return;
    3654             :     }
    3655           0 :     mds = calloc(gv->part_cnt*cols,sizeof(struct matrix_data));
    3656           0 :     for ( j=0; j<gv->part_cnt; ++j ) {
    3657           0 :         mds[j*cols+0].u.md_str = copy(gv->parts[j].component);
    3658           0 :         mds[j*cols+1].u.md_ival = gv->parts[j].is_extender;
    3659           0 :         mds[j*cols+2].u.md_ival = gv->parts[j].startConnectorLength;
    3660           0 :         mds[j*cols+3].u.md_ival = gv->parts[j].endConnectorLength;
    3661           0 :         mds[j*cols+4].u.md_ival = gv->parts[j].fullAdvance;
    3662             :     }
    3663           0 :     GMatrixEditSet(g, mds,gv->part_cnt,false);
    3664             : }
    3665             : 
    3666           0 : static void GA_ToMD(GGadget *g, SplineChar *sc) {
    3667             :     struct altuni *alt;
    3668           0 :     int cols = GMatrixEditGetColCnt(g), cnt;
    3669             :     struct matrix_data *mds;
    3670           0 :     if ( sc->altuni==NULL ) {
    3671           0 :         GMatrixEditSet(g, NULL,0,false);
    3672           0 : return;
    3673             :     }
    3674           0 :     for ( cnt=0, alt=sc->altuni; alt!=NULL; ++cnt, alt=alt->next );
    3675           0 :     mds = calloc(cnt*cols,sizeof(struct matrix_data));
    3676           0 :     for ( cnt=0, alt=sc->altuni; alt!=NULL; ++cnt, alt=alt->next ) {
    3677           0 :         mds[cnt*cols+0].u.md_ival = alt->unienc;
    3678           0 :         mds[cnt*cols+1].u.md_ival = alt->vs==-1? 0 : alt->vs;
    3679             :     }
    3680           0 :     GMatrixEditSet(g, mds,cnt,false);
    3681             : }
    3682             : 
    3683           0 : static void CI_SetColorList(CharInfo *ci,Color color) {
    3684             :     int i;
    3685             :     uint16 junk;
    3686             : 
    3687           0 :     std_colors[CUSTOM_COLOR].image = NULL;
    3688           0 :     for ( i=0; std_colors[i].image!=NULL; ++i ) {
    3689           0 :         if ( std_colors[i].userdata == (void *) (intpt) color )
    3690           0 :     break;
    3691             :     }
    3692           0 :     if ( std_colors[i].image==NULL ) {
    3693           0 :         std_colors[i].image = &customcolor_image;
    3694           0 :         customcolor_image.u.image->clut->clut[1] = color;
    3695           0 :         std_colors[i].userdata = (void *) (intpt) color;
    3696             :     }
    3697           0 :     GGadgetSetList(GWidgetGetControl(ci->gw,CID_Color), GTextInfoArrayFromList(std_colors,&junk), false);
    3698           0 :     GGadgetSelectOneListItem(GWidgetGetControl(ci->gw,CID_Color),i);
    3699           0 :     if ( color!=COLOR_DEFAULT )
    3700           0 :         ci->last = color;
    3701           0 :     ci->real_last = color;
    3702           0 : }
    3703             : 
    3704             : struct colcount { Color color; int cnt; };
    3705           0 : static int colcountorder(const void *op1, const void *op2) {
    3706           0 :     const struct colcount *c1 = op1, *c2 = op2;
    3707             : 
    3708           0 : return( c2->cnt - c1->cnt );              /* Biggest first */
    3709             : }
    3710             : 
    3711           0 : struct hslrgb *SFFontCols(SplineFont *sf,struct hslrgb fontcols[6]) {
    3712             :     int i, gid, cnt;
    3713             :     struct colcount *colcount, stds[7];
    3714             :     SplineChar *sc;
    3715             : 
    3716           0 :     memset(stds,0,sizeof(stds));
    3717           0 :     stds[0].color = 0xffffff;
    3718           0 :     stds[1].color = 0xff0000;
    3719           0 :     stds[2].color = 0x00ff00;
    3720           0 :     stds[3].color = 0x0000ff;
    3721           0 :     stds[4].color = 0xffff00;
    3722           0 :     stds[5].color = 0x00ffff;
    3723           0 :     stds[6].color = 0xff00ff;
    3724           0 :     colcount = calloc(sf->glyphcnt,sizeof(struct colcount));
    3725             : 
    3726           0 :     cnt = 0;
    3727           0 :     for ( gid=0; gid<sf->glyphcnt; ++gid ) if ( (sc= sf->glyphs[gid])!=NULL ) {
    3728           0 :         if ( sc->color==COLOR_DEFAULT )
    3729           0 :     continue;
    3730           0 :         for ( i=0; i<7 && sc->color!=stds[i].color; ++i );
    3731           0 :         if ( i<7 ) {
    3732           0 :             ++stds[i].cnt;
    3733           0 :     continue;
    3734             :         }
    3735           0 :         for ( i=0; i<cnt && sc->color!=colcount[i].color; ++i );
    3736           0 :         if ( i==cnt )
    3737           0 :             colcount[cnt++].color = sc->color;
    3738           0 :         ++colcount[i].cnt;
    3739             :     }
    3740             : 
    3741           0 :     if ( cnt<6 ) {
    3742           0 :         for ( i=0; i<cnt; ++i )
    3743           0 :             ++colcount[i].cnt;
    3744           0 :         for ( i=0; i<7; ++i ) if ( stds[i].cnt!=0 ) {
    3745           0 :             colcount[cnt].color = stds[i].color;
    3746           0 :             colcount[cnt++].cnt = 1;
    3747             :         }
    3748             :     }
    3749           0 :     qsort(colcount,cnt,sizeof(struct colcount),colcountorder);
    3750             : 
    3751           0 :     memset(fontcols,0,6*sizeof(struct hslrgb));
    3752           0 :     for ( i=0; i<6 && i<cnt; ++i ) {
    3753           0 :         fontcols[i].rgb = true;
    3754           0 :         fontcols[i].r = ((colcount[i].color>>16)&0xff)/255.0;
    3755           0 :         fontcols[i].g = ((colcount[i].color>>8 )&0xff)/255.0;
    3756           0 :         fontcols[i].b = ((colcount[i].color    )&0xff)/255.0;
    3757             :     }
    3758           0 :     free(colcount);
    3759           0 :     if ( cnt==0 )
    3760           0 : return( NULL );
    3761             : 
    3762           0 : return(fontcols);
    3763             : }
    3764             :     
    3765           0 : static int CI_PickColor(GGadget *g, GEvent *e) {
    3766           0 :     if ( e->type==et_controlevent && e->u.control.subtype == et_listselected ) {
    3767           0 :         CharInfo *ci = GDrawGetUserData(GGadgetGetWindow(g));
    3768           0 :         GTextInfo *ti = GGadgetGetListItemSelected(g);
    3769           0 :         if ( ti==NULL )
    3770             :             /* Can't happen */;
    3771           0 :         else if ( ti->userdata == (void *) COLOR_CHOOSE ) {
    3772             :             struct hslrgb col, font_cols[6];
    3773           0 :             memset(&col,0,sizeof(col));
    3774           0 :             col.rgb = true;
    3775           0 :             col.r = ((ci->last>>16)&0xff)/255.;
    3776           0 :             col.g = ((ci->last>>8 )&0xff)/255.;
    3777           0 :             col.b = ((ci->last    )&0xff)/255.;
    3778           0 :             col = GWidgetColor(_("Pick a color"),&col,SFFontCols(ci->sc->parent,font_cols));
    3779           0 :             if ( col.rgb ) {
    3780           0 :                 ci->last = (((int) rint(255.*col.r))<<16 ) |
    3781           0 :                             (((int) rint(255.*col.g))<<8 ) |
    3782           0 :                             (((int) rint(255.*col.b)) );
    3783           0 :                 CI_SetColorList(ci,ci->last);
    3784             :             } else /* Cancelled */
    3785           0 :                 CI_SetColorList(ci,ci->real_last);
    3786             :         } else {
    3787           0 :             if ( (intpt) ti->userdata!=COLOR_DEFAULT )
    3788           0 :                 ci->last = (intpt) ti->userdata;
    3789           0 :             ci->real_last = (intpt) ti->userdata;
    3790             :         }
    3791             :     }
    3792           0 : return( true );
    3793             : }
    3794             : 
    3795           0 : static void CIFillup(CharInfo *ci) {
    3796           0 :     SplineChar *sc = ci->cachedsc!=NULL ? ci->cachedsc : ci->sc;
    3797           0 :     SplineFont *sf = sc->parent;
    3798             :     unichar_t *temp;
    3799             :     char buffer[400];
    3800             :     char buf[200];
    3801             :     const unichar_t *bits;
    3802             :     int i,j,gid, isv;
    3803             :     struct matrix_data *mds[pst_max];
    3804             :     int cnts[pst_max];
    3805             :     PST *pst;
    3806             :     KernPair *kp;
    3807             :     unichar_t ubuf[4];
    3808             :     GTextInfo **ti;
    3809             :     char *devtabstr;
    3810             : 
    3811           0 :     sprintf(buf,_("Glyph Info for %.40s"),sc->name);
    3812           0 :     GDrawSetWindowTitles8(ci->gw, buf, _("Glyph Info..."));
    3813             : 
    3814           0 :     if ( ci->oldsc!=NULL && ci->oldsc->charinfo==ci )
    3815           0 :         ci->oldsc->charinfo = NULL;
    3816           0 :     ci->sc->charinfo = ci;
    3817           0 :     ci->oldsc = ci->sc;
    3818             : 
    3819           0 :     GGadgetSetEnabled(GWidgetGetControl(ci->gw,-1), ci->enc>0 &&
    3820           0 :             ((gid=ci->map->map[ci->enc-1])==-1 ||
    3821           0 :              sf->glyphs[gid]==NULL || sf->glyphs[gid]->charinfo==NULL ||
    3822           0 :              gid==sc->orig_pos));
    3823           0 :     GGadgetSetEnabled(GWidgetGetControl(ci->gw,1), ci->enc<ci->map->enccount-1 &&
    3824           0 :             ((gid=ci->map->map[ci->enc+1])==-1 ||
    3825           0 :              sf->glyphs[gid]==NULL || sf->glyphs[gid]->charinfo==NULL ||
    3826           0 :              gid==sc->orig_pos));
    3827             : 
    3828           0 :     temp = utf82u_copy(sc->name);
    3829           0 :     GGadgetSetTitle(GWidgetGetControl(ci->gw,CID_UName),temp);
    3830           0 :     free(temp);
    3831           0 :     CI_SetNameList(ci,sc->unicodeenc);
    3832             : 
    3833           0 :     sprintf(buffer,"U+%04x", sc->unicodeenc);
    3834           0 :     temp = utf82u_copy(sc->unicodeenc==-1?"-1":buffer);
    3835           0 :     GGadgetSetTitle(GWidgetGetControl(ci->gw,CID_UValue),temp);
    3836           0 :     free(temp);
    3837             : 
    3838           0 :     ubuf[0] = sc->unicodeenc;
    3839           0 :     if ( sc->unicodeenc==-1 )
    3840           0 :         ubuf[0] = '\0';
    3841           0 :     ubuf[1] = '\0';
    3842           0 :     GGadgetSetTitle(GWidgetGetControl(ci->gw,CID_UChar),ubuf);
    3843             : 
    3844           0 :     memset(cnts,0,sizeof(cnts));
    3845           0 :     for ( pst = sc->possub; pst!=NULL; pst=pst->next ) if ( pst->type!=pst_lcaret )
    3846           0 :         ++cnts[pst->type];
    3847           0 :     for ( isv=0; isv<2; ++isv ) {
    3848           0 :         for ( kp=isv ? sc->vkerns : sc->kerns; kp!=NULL; kp=kp->next )
    3849           0 :             ++cnts[pst_pair];
    3850             :     }
    3851           0 :     for ( i=pst_null+1; i<pst_max && i<pst_lcaret ; ++i )
    3852           0 :         mds[i] = calloc((cnts[i]+1)*mi[i-1].col_cnt,sizeof(struct matrix_data));
    3853           0 :     memset(cnts,0,sizeof(cnts));
    3854           0 :     for ( pst = sc->possub; pst!=NULL; pst=pst->next ) if ( pst->type!=pst_lcaret ) {
    3855           0 :         j = (cnts[pst->type]++ * mi[pst->type-1].col_cnt);
    3856           0 :         mds[pst->type][j+0].u.md_ival = (intpt) pst->subtable;
    3857           0 :         if ( pst->type==pst_position ) {
    3858           0 :             mds[pst->type][j+SIM_DX].u.md_ival = pst->u.pos.xoff;
    3859           0 :             mds[pst->type][j+SIM_DY].u.md_ival = pst->u.pos.yoff;
    3860           0 :             mds[pst->type][j+SIM_DX_ADV].u.md_ival = pst->u.pos.h_adv_off;
    3861           0 :             mds[pst->type][j+SIM_DY_ADV].u.md_ival = pst->u.pos.v_adv_off;
    3862           0 :             ValDevTabToStrings(mds[pst_position],j+SIM_DX+1,pst->u.pos.adjust);
    3863           0 :         } else if ( pst->type==pst_pair ) {
    3864           0 :             mds[pst->type][j+1].u.md_str = copy(pst->u.pair.paired);
    3865           0 :             mds[pst->type][j+PAIR_DX1].u.md_ival = pst->u.pair.vr[0].xoff;
    3866           0 :             mds[pst->type][j+PAIR_DY1].u.md_ival = pst->u.pair.vr[0].yoff;
    3867           0 :             mds[pst->type][j+PAIR_DX_ADV1].u.md_ival = pst->u.pair.vr[0].h_adv_off;
    3868           0 :             mds[pst->type][j+PAIR_DY_ADV1].u.md_ival = pst->u.pair.vr[0].v_adv_off;
    3869           0 :             mds[pst->type][j+PAIR_DX2].u.md_ival = pst->u.pair.vr[1].xoff;
    3870           0 :             mds[pst->type][j+PAIR_DY2].u.md_ival = pst->u.pair.vr[1].yoff;
    3871           0 :             mds[pst->type][j+PAIR_DX_ADV2].u.md_ival = pst->u.pair.vr[1].h_adv_off;
    3872           0 :             mds[pst->type][j+PAIR_DY_ADV2].u.md_ival = pst->u.pair.vr[1].v_adv_off;
    3873           0 :             ValDevTabToStrings(mds[pst_pair],j+PAIR_DX1+1,pst->u.pair.vr[0].adjust);
    3874           0 :             ValDevTabToStrings(mds[pst_pair],j+PAIR_DX2+1,pst->u.pair.vr[1].adjust);
    3875             :         } else {
    3876           0 :             mds[pst->type][j+1].u.md_str = SFNameList2NameUni(sf,pst->u.subs.variant);
    3877             :         }
    3878             :     }
    3879           0 :     for ( isv=0; isv<2; ++isv ) {
    3880           0 :         for ( kp=isv ? sc->vkerns : sc->kerns; kp!=NULL; kp=kp->next ) {
    3881           0 :             j = (cnts[pst_pair]++ * mi[pst_pair-1].col_cnt);
    3882           0 :             mds[pst_pair][j+0].u.md_ival = (intpt) kp->subtable;
    3883           0 :             mds[pst_pair][j+1].u.md_str = SCNameUniStr(kp->sc);
    3884           0 :             if ( isv ) {
    3885           0 :                 mds[pst_pair][j+PAIR_DY_ADV1].u.md_ival = kp->off;
    3886           0 :                 DevTabToString(&mds[pst_pair][j+PAIR_DY_ADV1+1].u.md_str,kp->adjust);
    3887           0 :             } else if ( kp->subtable->lookup->lookup_flags&pst_r2l ) {
    3888           0 :                 mds[pst_pair][j+PAIR_DX_ADV2].u.md_ival = kp->off;
    3889           0 :                 DevTabToString(&mds[pst_pair][j+PAIR_DX_ADV2+1].u.md_str,kp->adjust);
    3890             :             } else {
    3891           0 :                 mds[pst_pair][j+PAIR_DX_ADV1].u.md_ival = kp->off;
    3892           0 :                 DevTabToString(&mds[pst_pair][j+PAIR_DX_ADV1+1].u.md_str,kp->adjust);
    3893             :             }
    3894             :         }
    3895             :     }
    3896           0 :     for ( i=pst_null+1; i<pst_lcaret /* == pst_max-1 */; ++i ) {
    3897           0 :         GMatrixEditSet(GWidgetGetControl(ci->gw,CID_List+(i-1)*100),
    3898             :                 mds[i],cnts[i],false);
    3899             :     }
    3900             :     /* There's always a pane showing kerning data */
    3901           0 :     CI_DoHideUnusedPair(ci);
    3902           0 :     CI_DoHideUnusedSingle(ci);
    3903             : 
    3904           0 :     bits = SFGetAlternate(sc->parent,sc->unicodeenc,sc,true);
    3905           0 :     GGadgetSetTitle8(GWidgetGetControl(ci->gw,CID_ComponentMsg),
    3906             :         bits==NULL ? _("No components") :
    3907           0 :         hascomposing(sc->parent,sc->unicodeenc,sc) ? _("Accented glyph composed of:") :
    3908             :             _("Glyph composed of:"));
    3909           0 :     if ( bits==NULL ) {
    3910           0 :         ubuf[0] = '\0';
    3911           0 :         GGadgetSetTitle(GWidgetGetControl(ci->gw,CID_Components),ubuf);
    3912             :     } else {
    3913           0 :         unichar_t *temp = malloc(11*u_strlen(bits)*sizeof(unichar_t));
    3914           0 :         unichar_t *upt=temp;
    3915           0 :         while ( *bits!='\0' ) {
    3916           0 :             sprintf(buffer, "U+%04x ", *bits );
    3917           0 :             uc_strcpy(upt,buffer);
    3918           0 :             upt += u_strlen(upt);
    3919           0 :             ++bits;
    3920             :         }
    3921           0 :         upt[-1] = '\0';
    3922           0 :         GGadgetSetTitle(GWidgetGetControl(ci->gw,CID_Components),temp);
    3923           0 :         free(temp);
    3924             :     }
    3925             : 
    3926           0 :     GGadgetSelectOneListItem(GWidgetGetControl(ci->gw,CID_Color),0);
    3927             : 
    3928           0 :     GGadgetSetChecked(GWidgetGetControl(ci->gw,CID_UnlinkRmOverlap),sc->unlink_rm_ovrlp_save_undo);
    3929             : 
    3930           0 :     GGadgetSetTitle8(GWidgetGetControl(ci->gw,CID_Comment),
    3931           0 :             sc->comment?sc->comment:"");
    3932           0 :     GGadgetSelectOneListItem(GWidgetGetControl(ci->gw,CID_GClass),sc->glyph_class);
    3933           0 :     CI_SetColorList(ci,sc->color);
    3934           0 :     ci->first = sc->comment==NULL;
    3935             : 
    3936           0 :     ti = malloc((sc->countermask_cnt+1)*sizeof(GTextInfo *));
    3937           0 :     ti[sc->countermask_cnt] = calloc(1,sizeof(GTextInfo));
    3938           0 :     for ( i=0; i<sc->countermask_cnt; ++i ) {
    3939           0 :         ti[i] = calloc(1,sizeof(GTextInfo));
    3940           0 :         ti[i]->text = CounterMaskLine(sc,&sc->countermasks[i]);
    3941           0 :         ti[i]->fg = ti[i]->bg = COLOR_DEFAULT;
    3942           0 :         ti[i]->userdata = chunkalloc(sizeof(HintMask));
    3943           0 :         memcpy(ti[i]->userdata,sc->countermasks[i],sizeof(HintMask));
    3944             :     }
    3945           0 :     GGadgetSetList(GWidgetGetControl(ci->gw,CID_List+600),ti,false);
    3946             : 
    3947           0 :     if ( sc->tex_height!=TEX_UNDEF )
    3948           0 :         sprintf(buffer,"%d",sc->tex_height);
    3949             :     else
    3950           0 :         buffer[0] = '\0';
    3951           0 :     GGadgetSetTitle8(GWidgetGetControl(ci->gw,CID_TeX_Height),buffer);
    3952             : 
    3953           0 :     if ( sc->tex_depth!=TEX_UNDEF )
    3954           0 :         sprintf(buffer,"%d",sc->tex_depth);
    3955             :     else
    3956           0 :         buffer[0] = '\0';
    3957           0 :     GGadgetSetTitle8(GWidgetGetControl(ci->gw,CID_TeX_Depth),buffer);
    3958             : 
    3959           0 :     if ( sc->italic_correction!=TEX_UNDEF )
    3960           0 :         sprintf(buffer,"%d",sc->italic_correction);
    3961             :     else
    3962           0 :         buffer[0] = '\0';
    3963           0 :     GGadgetSetTitle8(GWidgetGetControl(ci->gw,CID_TeX_Italic),buffer);
    3964           0 :     DevTabToString(&devtabstr,sc->italic_adjusts);
    3965           0 :     GGadgetSetTitle8(GWidgetGetControl(ci->gw,CID_ItalicDevTab),devtabstr==NULL?"":devtabstr);
    3966           0 :     free(devtabstr);
    3967             : 
    3968           0 :     if ( sc->top_accent_horiz!=TEX_UNDEF )
    3969           0 :         sprintf(buffer,"%d",sc->top_accent_horiz);
    3970             :     else
    3971           0 :         buffer[0] = '\0';
    3972           0 :     GGadgetSetTitle8(GWidgetGetControl(ci->gw,CID_HorAccent),buffer);
    3973           0 :     DevTabToString(&devtabstr,sc->top_accent_adjusts);
    3974           0 :     GGadgetSetTitle8(GWidgetGetControl(ci->gw,CID_AccentDevTab),devtabstr==NULL?"":devtabstr);
    3975           0 :     free(devtabstr);
    3976             : 
    3977           0 :     GGadgetSetChecked(GWidgetGetControl(ci->gw,CID_IsExtended),sc->is_extended_shape);
    3978             : 
    3979             :     {
    3980           0 :         GGadget *g = GWidgetGetControl(ci->gw,CID_VariantList+0*100);
    3981           0 :         if ( sc->vert_variants==NULL || sc->vert_variants->variants==NULL )
    3982           0 :             GGadgetSetTitle8(g,"");
    3983             :         else
    3984           0 :             GGadgetSetTitle8(g,sc->vert_variants->variants);
    3985           0 :         sprintf(buffer,"%d",sc->vert_variants!=NULL?sc->vert_variants->italic_correction:0);
    3986           0 :         GGadgetSetTitle8(GWidgetGetControl(ci->gw,CID_ExtItalicCor+0*100),buffer);
    3987           0 :         DevTabToString(&devtabstr,sc->vert_variants!=NULL?
    3988           0 :                 sc->vert_variants->italic_adjusts:
    3989             :                 NULL);
    3990           0 :         GGadgetSetTitle8(GWidgetGetControl(ci->gw,CID_ExtItalicDev+0*100),devtabstr==NULL?"":devtabstr);
    3991           0 :         free(devtabstr);
    3992             : 
    3993           0 :         g = GWidgetGetControl(ci->gw,CID_VariantList+1*100);
    3994           0 :         if ( sc->horiz_variants==NULL || sc->horiz_variants->variants==NULL )
    3995           0 :             GGadgetSetTitle8(g,"");
    3996             :         else
    3997           0 :             GGadgetSetTitle8(g,sc->horiz_variants->variants);
    3998           0 :         sprintf(buffer,"%d",sc->horiz_variants!=NULL?sc->horiz_variants->italic_correction:0);
    3999           0 :         GGadgetSetTitle8(GWidgetGetControl(ci->gw,CID_ExtItalicCor+1*100),buffer);
    4000           0 :         DevTabToString(&devtabstr,sc->horiz_variants!=NULL?
    4001           0 :                 sc->horiz_variants->italic_adjusts:
    4002             :                 NULL);
    4003           0 :         GGadgetSetTitle8(GWidgetGetControl(ci->gw,CID_ExtItalicDev+1*100),devtabstr==NULL?"":devtabstr);
    4004           0 :         free(devtabstr);
    4005             :     }
    4006           0 :     for ( i=0; i<2; ++i ) {
    4007           0 :         struct glyphvariants *gv = i ? sc->horiz_variants : sc->vert_variants ;
    4008           0 :         GGadget *g = GWidgetGetControl(ci->gw,CID_ExtensionList+i*100);
    4009           0 :         GV_ToMD(g, gv);
    4010             :     }
    4011           0 :     GA_ToMD(GWidgetGetControl(ci->gw,CID_AltUni), sc);
    4012             : 
    4013           0 :     if ( ci->sc->parent->multilayer ) {
    4014           0 :         int margined = sc->tile_margin!=0 || (sc->tile_bounds.minx==0 && sc->tile_bounds.maxx==0);
    4015             :         char buffer[40];
    4016             : 
    4017           0 :         GGadgetSetChecked(GWidgetGetControl(ci->gw,CID_IsTileMargin),margined);
    4018           0 :         if ( margined ) {
    4019           0 :             sprintf( buffer, "%g", (double) sc->tile_margin );
    4020           0 :             GGadgetSetTitle8(GWidgetGetControl(ci->gw,CID_TileMargin),buffer);
    4021           0 :             CI_BoundsToMargin(ci);
    4022             :         } else {
    4023           0 :             GGadgetSetTitle8(GWidgetGetControl(ci->gw,CID_TileMargin),"0");
    4024           0 :             sprintf( buffer, "%g", (double) sc->tile_bounds.minx );
    4025           0 :             GGadgetSetTitle8(GWidgetGetControl(ci->gw,CID_TileBBoxMinX),buffer);
    4026           0 :             sprintf( buffer, "%g", (double) sc->tile_bounds.miny );
    4027           0 :             GGadgetSetTitle8(GWidgetGetControl(ci->gw,CID_TileBBoxMinY),buffer);
    4028           0 :             sprintf( buffer, "%g", (double) sc->tile_bounds.maxx );
    4029           0 :             GGadgetSetTitle8(GWidgetGetControl(ci->gw,CID_TileBBoxMaxX),buffer);
    4030           0 :             sprintf( buffer, "%g", (double) sc->tile_bounds.maxy );
    4031           0 :             GGadgetSetTitle8(GWidgetGetControl(ci->gw,CID_TileBBoxMaxY),buffer);
    4032             :         }
    4033             :     }
    4034             : 
    4035           0 :     GGadgetSetChecked(GWidgetGetControl(ci->gw,CID_DefLCCount), !sc->lig_caret_cnt_fixed );
    4036           0 :     GGadgetSetEnabled(GWidgetGetControl(ci->gw,CID_LCCountLab), sc->lig_caret_cnt_fixed );
    4037           0 :     GGadgetSetEnabled(GWidgetGetControl(ci->gw,CID_LCCount), sc->lig_caret_cnt_fixed );
    4038           0 :     ci->lc_seen = false;
    4039           0 :     CI_NoteAspect(ci);
    4040           0 : }
    4041             : 
    4042           0 : static int CI_NextPrev(GGadget *g, GEvent *e) {
    4043           0 :     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
    4044           0 :         CharInfo *ci = GDrawGetUserData(GGadgetGetWindow(g));
    4045           0 :         int enc = ci->enc + GGadgetGetCid(g);        /* cid is 1 for next, -1 for prev */
    4046             :         SplineChar *new_;
    4047             :         struct splinecharlist *scl;
    4048             : 
    4049           0 :         if ( enc<0 || enc>=ci->map->enccount ) {
    4050           0 :             GGadgetSetEnabled(g,false);
    4051           0 : return( true );
    4052             :         }
    4053           0 :         if ( !_CI_OK(ci))
    4054           0 : return( true );
    4055           0 :         new_ = SFMakeChar(ci->sc->parent,ci->map,enc);
    4056           0 :         if ( new_->charinfo!=NULL && new_->charinfo!=ci ) {
    4057           0 :             GGadgetSetEnabled(g,false);
    4058           0 : return( true );
    4059             :         }
    4060           0 :         ci->sc = new_;
    4061           0 :         ci->enc = enc;
    4062           0 :         for ( scl=ci->changes; scl!=NULL && scl->sc->orig_pos!=new_->orig_pos;
    4063           0 :                 scl = scl->next );
    4064           0 :         ci->cachedsc = scl==NULL ? NULL : scl->sc;
    4065           0 :         CIFillup(ci);
    4066             :     }
    4067           0 : return( true );
    4068             : }
    4069             : 
    4070           0 : static void CI_DoCancel(CharInfo *ci) {
    4071             :     int32 i,len;
    4072           0 :     GTextInfo **ti = GGadgetGetList(GWidgetGetControl(ci->gw,CID_List+600),&len);
    4073             : 
    4074           0 :     for ( i=0; i<len; ++i )
    4075           0 :         chunkfree(ti[i]->userdata,sizeof(HintMask));
    4076           0 :     CI_Finish(ci);
    4077           0 : }
    4078             : 
    4079           0 : static int CI_Cancel(GGadget *g, GEvent *e) {
    4080           0 :     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
    4081           0 :         CharInfo *ci = GDrawGetUserData(GGadgetGetWindow(g));
    4082           0 :         CI_DoCancel(ci);
    4083             :     }
    4084           0 : return( true );
    4085             : }
    4086             : 
    4087           0 : static int ci_e_h(GWindow gw, GEvent *event) {
    4088           0 :     if ( event->type==et_close ) {
    4089           0 :         CharInfo *ci = GDrawGetUserData(gw);
    4090           0 :         CI_DoCancel(ci);
    4091           0 :     } else if ( event->type==et_char ) {
    4092           0 :         CharInfo *ci = GDrawGetUserData(gw);
    4093           0 :         if ( event->u.chr.keysym == GK_F1 || event->u.chr.keysym == GK_Help ) {
    4094           0 :             help("charinfo.html");
    4095           0 : return( true );
    4096           0 :         } else if ( GMenuIsCommand(event,H_("Quit|Ctl+Q") )) {
    4097           0 :             MenuExit(NULL,NULL,NULL);
    4098           0 :         } else if ( GMenuIsCommand(event,H_("Close|Ctl+Shft+Q") )) {
    4099           0 :             CI_DoCancel(ci);
    4100             :         }
    4101           0 : return( false );
    4102           0 :     } else if ( event->type == et_destroy ) {
    4103           0 :         CharInfo *ci = GDrawGetUserData(gw);
    4104           0 :         ci->sc->charinfo = NULL;
    4105           0 :         free(ci);
    4106           0 :     } else if ( event->type == et_map ) {
    4107             :         /* Above palettes */
    4108           0 :         GDrawRaise(gw);
    4109             :     }
    4110           0 : return( true );
    4111             : }
    4112             : 
    4113           0 : void SCCharInfo(SplineChar *sc,int deflayer, EncMap *map,int enc) {
    4114             :     CharInfo *ci;
    4115             :     GRect pos;
    4116             :     GWindowAttrs wattrs;
    4117             :     GGadgetCreateData ugcd[14], cgcd[6], psgcd[7][7], cogcd[3], mgcd[9], tgcd[16];
    4118             :     GGadgetCreateData lcgcd[4], vargcd[2][7];
    4119             :     GTextInfo ulabel[14], clabel[6], pslabel[7][6], colabel[3], mlabel[9], tlabel[16];
    4120             :     GTextInfo lclabel[4], varlabel[2][6];
    4121             :     GGadgetCreateData mbox[4], *mvarray[7], *mharray1[7], *mharray2[8];
    4122             :     GGadgetCreateData ubox[3], *uhvarray[29], *uharray[6];
    4123             :     GGadgetCreateData cbox[3], *cvarray[5], *charray[4];
    4124             :     GGadgetCreateData pstbox[7][4], *pstvarray[7][5], *pstharray1[7][8];
    4125             :     GGadgetCreateData cobox[2], *covarray[4];
    4126             :     GGadgetCreateData tbox[3], *thvarray[36], *tbarray[4];
    4127             :     GGadgetCreateData lcbox[2], *lchvarray[4][4];
    4128             :     GGadgetCreateData varbox[2][2], *varhvarray[2][5][4];
    4129             :     GGadgetCreateData tilegcd[16], tilebox[4];
    4130             :     GTextInfo tilelabel[16];
    4131             :     GGadgetCreateData *tlvarray[6], *tlharray[4], *tlhvarray[4][5];
    4132             :     int i;
    4133             :     GTabInfo aspects[17];
    4134             :     static GBox smallbox = { bt_raised, bs_rect, 2, 1, 0, 0, 0, 0, 0, 0, COLOR_DEFAULT, COLOR_DEFAULT, 0, 0, 0, 0, 0, 0, 0 };
    4135             :     static int boxset=0;
    4136             :     FontRequest rq;
    4137             :     static GFont *font=NULL;
    4138             : 
    4139           0 :     CharInfoInit();
    4140             : 
    4141           0 :     if ( sc->charinfo!=NULL ) {
    4142           0 :         GDrawSetVisible(sc->charinfo->gw,true);
    4143           0 :         GDrawRaise(sc->charinfo->gw);
    4144           0 : return;
    4145             :     }
    4146             : 
    4147           0 :     ci = calloc(1,sizeof(CharInfo));
    4148           0 :     ci->sc = sc;
    4149           0 :     ci->def_layer = deflayer;
    4150           0 :     ci->done = false;
    4151           0 :     ci->map = map;
    4152           0 :     ci->last = 0xffffff;
    4153           0 :     if ( enc==-1 )
    4154           0 :         enc = map->backmap[sc->orig_pos];
    4155           0 :     ci->enc = enc;
    4156             : 
    4157           0 :     if ( !boxset ) {
    4158             :         extern GBox _ggadget_Default_Box;
    4159           0 :         GGadgetInit();
    4160           0 :         smallbox = _ggadget_Default_Box;
    4161           0 :         smallbox.padding = 1;
    4162           0 :         boxset = 1;
    4163             :     }
    4164             : 
    4165           0 :         memset(&wattrs,0,sizeof(wattrs));
    4166           0 :         wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_undercursor|wam_isdlg|wam_restrict;
    4167           0 :         wattrs.event_masks = ~(1<<et_charup);
    4168           0 :         wattrs.restrict_input_to_me = false;
    4169           0 :         wattrs.undercursor = 1;
    4170           0 :         wattrs.cursor = ct_pointer;
    4171           0 :         wattrs.utf8_window_title =  _("Glyph Info");
    4172           0 :         wattrs.is_dlg = false;
    4173           0 :         pos.x = pos.y = 0;
    4174           0 :         pos.width = GGadgetScale(GDrawPointsToPixels(NULL,CI_Width+65));
    4175           0 :         pos.height = GDrawPointsToPixels(NULL,CI_Height);
    4176           0 :         ci->gw = GDrawCreateTopWindow(NULL,&pos,ci_e_h,ci,&wattrs);
    4177             : 
    4178           0 :         memset(&ugcd,0,sizeof(ugcd));
    4179           0 :         memset(&ubox,0,sizeof(ubox));
    4180           0 :         memset(&ulabel,0,sizeof(ulabel));
    4181             : 
    4182           0 :         ulabel[0].text = (unichar_t *) _("Gl_yph Name:");
    4183           0 :         ulabel[0].text_is_1byte = true;
    4184           0 :         ulabel[0].text_in_resource = true;
    4185           0 :         ugcd[0].gd.label = &ulabel[0];
    4186           0 :         ugcd[0].gd.pos.x = 5; ugcd[0].gd.pos.y = 5+4; 
    4187           0 :         ugcd[0].gd.flags = gg_enabled|gg_visible;
    4188           0 :         ugcd[0].gd.mnemonic = 'N';
    4189           0 :         ugcd[0].creator = GLabelCreate;
    4190           0 :         uhvarray[0] = &ugcd[0];
    4191             : 
    4192           0 :         ugcd[1].gd.pos.x = 85; ugcd[1].gd.pos.y = 5;
    4193           0 :         ugcd[1].gd.flags = gg_enabled|gg_visible;
    4194           0 :         ugcd[1].gd.mnemonic = 'N';
    4195           0 :         ugcd[1].gd.cid = CID_UName;
    4196           0 :         ugcd[1].creator = GListFieldCreate;
    4197           0 :         ugcd[1].data = (void *) (-2);
    4198           0 :         uhvarray[1] = &ugcd[1]; uhvarray[2] = NULL;
    4199             : 
    4200           0 :         ulabel[2].text = (unichar_t *) _("Unicode _Value:");
    4201           0 :         ulabel[2].text_in_resource = true;
    4202           0 :         ulabel[2].text_is_1byte = true;
    4203           0 :         ugcd[2].gd.label = &ulabel[2];
    4204           0 :         ugcd[2].gd.pos.x = 5; ugcd[2].gd.pos.y = 31+4; 
    4205           0 :         ugcd[2].gd.flags = gg_enabled|gg_visible;
    4206           0 :         ugcd[2].gd.mnemonic = 'V';
    4207           0 :         ugcd[2].creator = GLabelCreate;
    4208           0 :         uhvarray[3] = &ugcd[2];
    4209             : 
    4210           0 :         ugcd[3].gd.pos.x = 85; ugcd[3].gd.pos.y = 31;
    4211           0 :         ugcd[3].gd.flags = gg_enabled|gg_visible;
    4212           0 :         ugcd[3].gd.mnemonic = 'V';
    4213           0 :         ugcd[3].gd.cid = CID_UValue;
    4214           0 :         ugcd[3].gd.handle_controlevent = CI_UValChanged;
    4215           0 :         ugcd[3].creator = GTextFieldCreate;
    4216           0 :         uhvarray[4] = &ugcd[3]; uhvarray[5] = NULL;
    4217             : 
    4218           0 :         ulabel[4].text = (unichar_t *) _("Unicode C_har:");
    4219           0 :         ulabel[4].text_in_resource = true;
    4220           0 :         ulabel[4].text_is_1byte = true;
    4221           0 :         ugcd[4].gd.label = &ulabel[4];
    4222           0 :         ugcd[4].gd.pos.x = 5; ugcd[4].gd.pos.y = 57+4; 
    4223           0 :         ugcd[4].gd.flags = gg_enabled|gg_visible;
    4224           0 :         ugcd[4].gd.mnemonic = 'h';
    4225           0 :         ugcd[4].creator = GLabelCreate;
    4226           0 :         uhvarray[6] = &ugcd[4];
    4227             : 
    4228           0 :         ugcd[5].gd.pos.x = 85; ugcd[5].gd.pos.y = 57;
    4229           0 :         ugcd[5].gd.flags = gg_enabled|gg_visible|gg_text_xim;
    4230           0 :         ugcd[5].gd.mnemonic = 'h';
    4231           0 :         ugcd[5].gd.cid = CID_UChar;
    4232           0 :         ugcd[5].gd.handle_controlevent = CI_CharChanged;
    4233           0 :         ugcd[5].creator = GTextFieldCreate;
    4234           0 :         uhvarray[7] = &ugcd[5]; uhvarray[8] = NULL;
    4235             : 
    4236           0 :         ugcd[6].gd.pos.x = 12; ugcd[6].gd.pos.y = 117;
    4237           0 :         ugcd[6].gd.flags = gg_visible | gg_enabled;
    4238           0 :         ulabel[6].text = (unichar_t *) _("Set From N_ame");
    4239           0 :         ulabel[6].text_is_1byte = true;
    4240           0 :         ulabel[6].text_in_resource = true;
    4241           0 :         ugcd[6].gd.mnemonic = 'a';
    4242           0 :         ugcd[6].gd.label = &ulabel[6];
    4243           0 :         ugcd[6].gd.handle_controlevent = CI_SName;
    4244           0 :         ugcd[6].creator = GButtonCreate;
    4245           0 :         uharray[0] = GCD_Glue; uharray[1] = &ugcd[6];
    4246             : 
    4247           0 :         ugcd[7].gd.pos.x = 107; ugcd[7].gd.pos.y = 117;
    4248           0 :         ugcd[7].gd.flags = gg_visible | gg_enabled;
    4249           0 :         ulabel[7].text = (unichar_t *) _("Set From Val_ue");
    4250           0 :         ulabel[7].text_is_1byte = true;
    4251           0 :         ulabel[7].text_in_resource = true;
    4252           0 :         ugcd[7].gd.mnemonic = 'l';
    4253           0 :         ugcd[7].gd.label = &ulabel[7];
    4254           0 :         ugcd[7].gd.handle_controlevent = CI_SValue;
    4255           0 :         ugcd[7].creator = GButtonCreate;
    4256           0 :         uharray[2] = GCD_Glue; uharray[3] = &ugcd[7]; uharray[4] = GCD_Glue; uharray[5] = NULL;
    4257             : 
    4258           0 :         ubox[2].gd.flags = gg_enabled|gg_visible;
    4259           0 :         ubox[2].gd.u.boxelements = uharray;
    4260           0 :         ubox[2].creator = GHBoxCreate;
    4261           0 :         uhvarray[9] = &ubox[2]; uhvarray[10] = GCD_ColSpan; uhvarray[11] = NULL;
    4262             : 
    4263           0 :         ugcd[8].gd.flags = gg_visible | gg_enabled|gg_utf8_popup;
    4264           0 :         ulabel[8].text = (unichar_t *) _("Alternate Unicode Encodings / Variation Selectors");
    4265           0 :         ulabel[8].text_is_1byte = true;
    4266           0 :         ugcd[8].gd.label = &ulabel[8];
    4267           0 :         ugcd[8].gd.popup_msg = (unichar_t *) _(
    4268             :             "Some glyphs may be used for more than one\n"
    4269             :             "unicode code point -- I don't recommend\n"
    4270             :             "doing this, better to use a reference --\n"
    4271             :             "but it is possible.\n"
    4272             :             "The latin \"A\", the greek \"Alpha\" and the\n"
    4273             :             "cyrillic \"A\" look very much the same.\n\n"
    4274             :             "On the other hand certain Mongolian and CJK\n"
    4275             :             "characters have multiple glyphs depending\n"
    4276             :             "on a unicode Variation Selector.\n\n"
    4277             :             "In the first case use a variation selector\n"
    4278             :             "of 0, in the second use the appropriate\n"
    4279             :             "codepoint.");
    4280           0 :         ugcd[8].creator = GLabelCreate;
    4281           0 :         uhvarray[12] = &ugcd[8]; uhvarray[13] = GCD_ColSpan; uhvarray[14] = NULL;
    4282             : 
    4283           0 :         ugcd[9].gd.flags = gg_enabled|gg_visible|gg_utf8_popup;
    4284           0 :         ugcd[9].gd.u.matrix = &mi_altuniinfo;
    4285           0 :         ugcd[9].gd.cid = CID_AltUni;
    4286           0 :         ugcd[9].gd.popup_msg = ugcd[8].gd.popup_msg;
    4287           0 :         ugcd[9].creator = GMatrixEditCreate;
    4288           0 :         uhvarray[15] = &ugcd[9]; uhvarray[16] = GCD_ColSpan; uhvarray[17] = NULL;
    4289             : 
    4290           0 :         ugcd[10].gd.pos.x = 5; ugcd[10].gd.pos.y = 83+4;
    4291           0 :         ugcd[10].gd.flags = gg_visible | gg_enabled;
    4292           0 :         ulabel[10].text = (unichar_t *) _("OT _Glyph Class:");
    4293           0 :         ulabel[10].text_is_1byte = true;
    4294           0 :         ulabel[10].text_in_resource = true;
    4295           0 :         ugcd[10].gd.label = &ulabel[10];
    4296           0 :         ugcd[10].creator = GLabelCreate;
    4297           0 :         uhvarray[18] = &ugcd[10];
    4298             : 
    4299           0 :         ugcd[11].gd.pos.x = 85; ugcd[11].gd.pos.y = 83;
    4300           0 :         ugcd[11].gd.flags = gg_visible | gg_enabled;
    4301           0 :         ugcd[11].gd.cid = CID_GClass;
    4302           0 :         ugcd[11].gd.u.list = glyphclasses;
    4303           0 :         ugcd[11].creator = GListButtonCreate;
    4304           0 :         uhvarray[19] = &ugcd[11]; uhvarray[20] = NULL;
    4305             : 
    4306           0 :         ugcd[12].gd.flags = gg_visible | gg_enabled | gg_utf8_popup;
    4307           0 :         ulabel[12].text = (unichar_t *) _("Mark for Unlink, Remove Overlap before Generating");
    4308           0 :         ulabel[12].text_is_1byte = true;
    4309           0 :         ulabel[12].text_in_resource = true;
    4310           0 :         ugcd[12].gd.label = &ulabel[12];
    4311           0 :         ugcd[12].gd.cid = CID_UnlinkRmOverlap;
    4312           0 :         ugcd[12].gd.popup_msg = (unichar_t *) _("A few glyphs, like Aring, Ccedilla, Eogonek\nare composed of two overlapping references.\nOften it is desirable to retain the references\n(so that changes made to the base glyph are\nreflected in the composed glyph), but that\nmeans you are stuck with overlapping contours.\nThis flag means that just before generating\nthe font, FontForge will unlink the references\nand run remove overlap on them, while\n retaining the references in the SFD.");
    4313           0 :         ugcd[12].creator = GCheckBoxCreate;
    4314           0 :         uhvarray[21] = &ugcd[12]; uhvarray[22] = GCD_ColSpan; uhvarray[23] = NULL;
    4315           0 :         uhvarray[24] = GCD_Glue; uhvarray[25] = GCD_Glue; uhvarray[26] = NULL;
    4316           0 :         uhvarray[27] = NULL;
    4317             : 
    4318           0 :         ubox[0].gd.flags = gg_enabled|gg_visible;
    4319           0 :         ubox[0].gd.u.boxelements = uhvarray;
    4320           0 :         ubox[0].creator = GHVBoxCreate;
    4321             : 
    4322             : 
    4323           0 :         memset(&cgcd,0,sizeof(cgcd));
    4324           0 :         memset(&cbox,0,sizeof(cbox));
    4325           0 :         memset(&clabel,0,sizeof(clabel));
    4326             : 
    4327           0 :         clabel[0].text = (unichar_t *) _("Comment");
    4328           0 :         clabel[0].text_is_1byte = true;
    4329           0 :         cgcd[0].gd.label = &clabel[0];
    4330           0 :         cgcd[0].gd.pos.x = 5; cgcd[0].gd.pos.y = 5; 
    4331           0 :         cgcd[0].gd.flags = gg_enabled|gg_visible;
    4332           0 :         cgcd[0].creator = GLabelCreate;
    4333           0 :         cvarray[0] = &cgcd[0];
    4334             : 
    4335           0 :         cgcd[1].gd.pos.x = 5; cgcd[1].gd.pos.y = cgcd[0].gd.pos.y+13;
    4336           0 :         cgcd[1].gd.pos.height = 7*12+6;
    4337           0 :         cgcd[1].gd.flags = gg_enabled|gg_visible|gg_textarea_wrap|gg_text_xim;
    4338           0 :         cgcd[1].gd.cid = CID_Comment;
    4339           0 :         cgcd[1].gd.handle_controlevent = CI_CommentChanged;
    4340           0 :         cgcd[1].creator = GTextAreaCreate;
    4341           0 :         cvarray[1] = &cgcd[1]; cvarray[2] = GCD_Glue;
    4342             : 
    4343           0 :         clabel[2].text = (unichar_t *) _("Color:");
    4344           0 :         clabel[2].text_is_1byte = true;
    4345           0 :         cgcd[2].gd.label = &clabel[2];
    4346           0 :         cgcd[2].gd.pos.x = 5; cgcd[2].gd.pos.y = cgcd[1].gd.pos.y+cgcd[1].gd.pos.height+5+6; 
    4347           0 :         cgcd[2].gd.flags = gg_enabled|gg_visible;
    4348           0 :         cgcd[2].creator = GLabelCreate;
    4349           0 :         charray[0] = &cgcd[2];
    4350             : 
    4351           0 :         cgcd[3].gd.pos.x = cgcd[3].gd.pos.x; cgcd[3].gd.pos.y = cgcd[2].gd.pos.y-6;
    4352           0 :         cgcd[3].gd.flags = gg_enabled|gg_visible;
    4353           0 :         cgcd[3].gd.cid = CID_Color;
    4354           0 :         cgcd[3].gd.handle_controlevent = CI_PickColor;
    4355           0 :         std_colors[0].image = GGadgetImageCache("colorwheel.png");
    4356           0 :         cgcd[3].gd.u.list = std_colors;
    4357           0 :         cgcd[3].creator = GListButtonCreate;
    4358           0 :         charray[1] = &cgcd[3]; charray[2] = GCD_Glue; charray[3] = NULL;
    4359             : 
    4360           0 :         cbox[2].gd.flags = gg_enabled|gg_visible;
    4361           0 :         cbox[2].gd.u.boxelements = charray;
    4362           0 :         cbox[2].creator = GHBoxCreate;
    4363           0 :         cvarray[3] = &cbox[2]; cvarray[4] = NULL;
    4364             : 
    4365           0 :         cbox[0].gd.flags = gg_enabled|gg_visible;
    4366           0 :         cbox[0].gd.u.boxelements = cvarray;
    4367           0 :         cbox[0].creator = GVBoxCreate;
    4368             : 
    4369           0 :         memset(&psgcd,0,sizeof(psgcd));
    4370           0 :         memset(&pstbox,0,sizeof(pstbox));
    4371           0 :         memset(&pslabel,0,sizeof(pslabel));
    4372             : 
    4373           0 :         for ( i=0; i<6; ++i ) {
    4374           0 :             psgcd[i][0].gd.pos.x = 5; psgcd[i][0].gd.pos.y = 5;
    4375           0 :             psgcd[i][0].gd.flags = gg_visible | gg_enabled;
    4376           0 :             psgcd[i][0].gd.cid = CID_List+i*100;
    4377           0 :             psgcd[i][0].gd.u.matrix = &mi[i];
    4378           0 :             mi[i].col_init[0].enum_vals = SFSubtableListOfType(sc->parent, pst2lookuptype[i+1], false, false);
    4379           0 :             psgcd[i][0].creator = GMatrixEditCreate;
    4380             :         }
    4381           0 :         for ( i=pst_position; i<=pst_pair; ++i ) {
    4382           0 :             pslabel[i-1][1].text = (unichar_t *) _("_Hide Unused Columns");
    4383           0 :             pslabel[i-1][1].text_is_1byte = true;
    4384           0 :             pslabel[i-1][1].text_in_resource = true;
    4385           0 :             psgcd[i-1][1].gd.label = &pslabel[i-1][1];
    4386           0 :             psgcd[i-1][1].gd.pos.x = 5; psgcd[i-1][1].gd.pos.y = 5+4; 
    4387           0 :             psgcd[i-1][1].gd.flags = lookup_hideunused ? (gg_enabled|gg_visible|gg_cb_on|gg_utf8_popup) : (gg_enabled|gg_visible|gg_utf8_popup);
    4388           0 :             psgcd[i-1][1].gd.popup_msg = (unichar_t *) _("Don't display columns of 0s.\nThe OpenType lookup allows for up to 8 kinds\nof data, but almost all kerning lookups will use just one.\nOmitting the others makes the behavior clearer.");
    4389           0 :             psgcd[i-1][1].gd.handle_controlevent = i==pst_position ? CI_HideUnusedSingle : CI_HideUnusedPair;
    4390           0 :             psgcd[i-1][1].creator = GCheckBoxCreate;
    4391           0 :             pstvarray[i-1][0] = &psgcd[i-1][0];
    4392           0 :             pstvarray[i-1][1] = &psgcd[i-1][1];
    4393           0 :             pstvarray[i-1][2] = NULL;
    4394             : 
    4395           0 :             pstbox[i-1][0].gd.flags = gg_enabled|gg_visible;
    4396           0 :             pstbox[i-1][0].gd.u.boxelements = pstvarray[i-1];
    4397           0 :             pstbox[i-1][0].creator = GVBoxCreate;
    4398             :         }
    4399             : 
    4400           0 :             psgcd[6][0].gd.pos.x = 5; psgcd[6][0].gd.pos.y = 5;
    4401           0 :             psgcd[6][0].gd.flags = gg_visible | gg_enabled;
    4402           0 :             psgcd[6][0].gd.cid = CID_List+6*100;
    4403           0 :             psgcd[6][0].gd.handle_controlevent = CI_CounterSelChanged;
    4404           0 :             psgcd[6][0].gd.box = &smallbox;
    4405           0 :             psgcd[6][0].creator = GListCreate;
    4406           0 :             pstvarray[6][0] = &psgcd[6][0];
    4407             : 
    4408           0 :             psgcd[6][1].gd.pos.x = 10; psgcd[6][1].gd.pos.y = psgcd[6][0].gd.pos.y+psgcd[6][0].gd.pos.height+4;
    4409           0 :             psgcd[6][1].gd.flags = gg_visible | gg_enabled;
    4410           0 :             pslabel[6][1].text = (unichar_t *) S_("CounterHint|_New...");
    4411           0 :             pslabel[6][1].text_is_1byte = true;
    4412           0 :             pslabel[6][1].text_in_resource = true;
    4413           0 :             psgcd[6][1].gd.label = &pslabel[6][1];
    4414           0 :             psgcd[6][1].gd.cid = CID_New+6*100;
    4415           0 :             psgcd[6][1].gd.handle_controlevent = CI_NewCounter;
    4416           0 :             psgcd[6][1].gd.box = &smallbox;
    4417           0 :             psgcd[6][1].creator = GButtonCreate;
    4418           0 :             pstharray1[6][0] = GCD_Glue; pstharray1[6][1] = &psgcd[6][1];
    4419             : 
    4420           0 :             psgcd[6][2].gd.pos.x = 20+GIntGetResource(_NUM_Buttonsize)*100/GIntGetResource(_NUM_ScaleFactor); psgcd[6][2].gd.pos.y = psgcd[6][1].gd.pos.y;
    4421           0 :             psgcd[6][2].gd.flags = gg_visible;
    4422           0 :             pslabel[6][2].text = (unichar_t *) _("_Delete");
    4423           0 :             pslabel[6][2].text_is_1byte = true;
    4424           0 :             pslabel[6][2].text_in_resource = true;
    4425           0 :             psgcd[6][2].gd.label = &pslabel[6][2];
    4426           0 :             psgcd[6][2].gd.cid = CID_Delete+6*100;
    4427           0 :             psgcd[6][2].gd.handle_controlevent = CI_DeleteCounter;
    4428           0 :             psgcd[6][2].gd.box = &smallbox;
    4429           0 :             psgcd[6][2].creator = GButtonCreate;
    4430           0 :             pstharray1[6][2] = GCD_Glue; pstharray1[6][3] = &psgcd[6][2];
    4431             : 
    4432           0 :             psgcd[6][3].gd.pos.x = -10; psgcd[6][3].gd.pos.y = psgcd[6][1].gd.pos.y;
    4433           0 :             psgcd[6][3].gd.flags = gg_visible;
    4434           0 :             pslabel[6][3].text = (unichar_t *) _("_Edit...");
    4435           0 :             pslabel[6][3].text_is_1byte = true;
    4436           0 :             pslabel[6][3].text_in_resource = true;
    4437           0 :             psgcd[6][3].gd.label = &pslabel[6][3];
    4438           0 :             psgcd[6][3].gd.cid = CID_Edit+6*100;
    4439           0 :             psgcd[6][3].gd.handle_controlevent = CI_EditCounter;
    4440           0 :             psgcd[6][3].gd.box = &smallbox;
    4441           0 :             psgcd[6][3].creator = GButtonCreate;
    4442           0 :             pstharray1[6][4] = GCD_Glue; pstharray1[6][5] = &psgcd[6][3]; pstharray1[6][6] = GCD_Glue; pstharray1[6][7] = NULL;
    4443             : 
    4444           0 :             pstbox[6][2].gd.flags = gg_enabled|gg_visible;
    4445           0 :             pstbox[6][2].gd.u.boxelements = pstharray1[6];
    4446           0 :             pstbox[6][2].creator = GHBoxCreate;
    4447           0 :             pstvarray[6][1] = &pstbox[6][2]; pstvarray[6][2] = NULL;
    4448             : 
    4449           0 :             pstbox[6][0].gd.flags = gg_enabled|gg_visible;
    4450           0 :             pstbox[6][0].gd.u.boxelements = pstvarray[6];
    4451           0 :             pstbox[6][0].creator = GVBoxCreate;
    4452           0 :         psgcd[6][4].gd.flags = psgcd[6][5].gd.flags = 0;        /* No copy, paste for hint masks */
    4453             : 
    4454           0 :         memset(&cogcd,0,sizeof(cogcd));
    4455           0 :         memset(&cobox,0,sizeof(cobox));
    4456           0 :         memset(&colabel,0,sizeof(colabel));
    4457             : 
    4458           0 :         colabel[0].text = (unichar_t *) _("Accented glyph composed of:");
    4459           0 :         colabel[0].text_is_1byte = true;
    4460           0 :         cogcd[0].gd.label = &colabel[0];
    4461           0 :         cogcd[0].gd.pos.x = 5; cogcd[0].gd.pos.y = 5; 
    4462           0 :         cogcd[0].gd.flags = gg_enabled|gg_visible|gg_utf8_popup;
    4463           0 :         cogcd[0].gd.cid = CID_ComponentMsg;
    4464           0 :         cogcd[0].creator = GLabelCreate;
    4465             : 
    4466           0 :         cogcd[1].gd.pos.x = 5; cogcd[1].gd.pos.y = cogcd[0].gd.pos.y+12;
    4467           0 :         cogcd[1].gd.flags = gg_enabled|gg_visible|gg_utf8_popup;
    4468           0 :         cogcd[1].gd.cid = CID_Components;
    4469           0 :         cogcd[1].creator = GLabelCreate;
    4470             : 
    4471           0 :         covarray[0] = &cogcd[0]; covarray[1] = &cogcd[1]; covarray[2] = GCD_Glue; covarray[3] = NULL;
    4472           0 :         cobox[0].gd.flags = gg_enabled|gg_visible;
    4473           0 :         cobox[0].gd.u.boxelements = covarray;
    4474           0 :         cobox[0].creator = GVBoxCreate;
    4475             :         
    4476             : 
    4477             : 
    4478           0 :         memset(&tgcd,0,sizeof(tgcd));
    4479           0 :         memset(&tbox,0,sizeof(tbox));
    4480           0 :         memset(&tlabel,0,sizeof(tlabel));
    4481             : 
    4482           0 :         tlabel[0].text = (unichar_t *) _("Height:");
    4483           0 :         tlabel[0].text_is_1byte = true;
    4484           0 :         tgcd[0].gd.label = &tlabel[0];
    4485           0 :         tgcd[0].gd.pos.x = 5; tgcd[0].gd.pos.y = 5+4; 
    4486           0 :         tgcd[0].gd.flags = gg_enabled|gg_visible|gg_utf8_popup;
    4487           0 :         tgcd[0].gd.popup_msg = (unichar_t *) _("The height and depth fields are the metrics fields used\nby TeX, they are corrected for optical distortion.\nSo 'x' and 'o' probably have the same height.");
    4488           0 :         tgcd[0].creator = GLabelCreate;
    4489           0 :         thvarray[0] = &tgcd[0];
    4490             : 
    4491           0 :         tgcd[1].gd.pos.x = 85; tgcd[1].gd.pos.y = 5;
    4492           0 :         tgcd[1].gd.pos.width = 60;
    4493           0 :         tgcd[1].gd.flags = gg_enabled|gg_visible|gg_utf8_popup;
    4494           0 :         tgcd[1].gd.cid = CID_TeX_Height;
    4495           0 :         tgcd[1].creator = GTextFieldCreate;
    4496           0 :         tgcd[1].gd.popup_msg = tgcd[0].gd.popup_msg;
    4497           0 :         thvarray[1] = &tgcd[1];
    4498             : 
    4499           0 :         tlabel[2].text = (unichar_t *) _("Guess");
    4500           0 :         tlabel[2].text_is_1byte = true;
    4501           0 :         tgcd[2].gd.label = &tlabel[2];
    4502           0 :         tgcd[2].gd.flags = gg_enabled|gg_visible|gg_utf8_popup;
    4503           0 :         tgcd[2].gd.cid = CID_TeX_HeightD;
    4504           0 :         tgcd[2].gd.handle_controlevent = TeX_Default;
    4505           0 :         tgcd[2].creator = GButtonCreate;
    4506           0 :         tgcd[2].gd.popup_msg = tgcd[0].gd.popup_msg;
    4507           0 :         thvarray[2] = &tgcd[2]; thvarray[3] = GCD_Glue; thvarray[4] = NULL;
    4508             : 
    4509           0 :         tlabel[3].text = (unichar_t *) _("Depth:");
    4510           0 :         tlabel[3].text_is_1byte = true;
    4511           0 :         tgcd[3].gd.label = &tlabel[3];
    4512           0 :         tgcd[3].gd.pos.x = 5; tgcd[3].gd.pos.y = 31+4; 
    4513           0 :         tgcd[3].gd.flags = gg_enabled|gg_visible|gg_utf8_popup;
    4514           0 :         tgcd[3].gd.popup_msg = tgcd[0].gd.popup_msg;
    4515           0 :         tgcd[3].creator = GLabelCreate;
    4516           0 :         thvarray[5] = &tgcd[3];
    4517             : 
    4518           0 :         tgcd[4].gd.pos.x = 85; tgcd[4].gd.pos.y = 31;
    4519           0 :         tgcd[4].gd.pos.width = 60;
    4520           0 :         tgcd[4].gd.flags = gg_enabled|gg_visible|gg_utf8_popup;
    4521           0 :         tgcd[4].gd.cid = CID_TeX_Depth;
    4522           0 :         tgcd[4].creator = GTextFieldCreate;
    4523           0 :         tgcd[4].gd.popup_msg = tgcd[0].gd.popup_msg;
    4524           0 :         thvarray[6] = &tgcd[4];
    4525             : 
    4526           0 :         tlabel[5].text = (unichar_t *) _("Guess");
    4527           0 :         tlabel[5].text_is_1byte = true;
    4528           0 :         tgcd[5].gd.label = &tlabel[5];
    4529           0 :         tgcd[5].gd.flags = gg_enabled|gg_visible|gg_utf8_popup;
    4530           0 :         tgcd[5].gd.cid = CID_TeX_DepthD;
    4531           0 :         tgcd[5].gd.handle_controlevent = TeX_Default;
    4532           0 :         tgcd[5].creator = GButtonCreate;
    4533           0 :         tgcd[5].gd.popup_msg = tgcd[0].gd.popup_msg;
    4534           0 :         thvarray[7] = &tgcd[5];  thvarray[8] = GCD_Glue; thvarray[9] = NULL;
    4535             : 
    4536           0 :         tlabel[6].text = (unichar_t *) _("Italic Correction:");
    4537           0 :         tlabel[6].text_is_1byte = true;
    4538           0 :         tgcd[6].gd.label = &tlabel[6];
    4539           0 :         tgcd[6].gd.pos.x = 5; tgcd[6].gd.pos.y = 57+4; 
    4540           0 :         tgcd[6].gd.flags = gg_enabled|gg_visible|gg_utf8_popup;
    4541           0 :         tgcd[6].creator = GLabelCreate;
    4542           0 :         tgcd[6].gd.popup_msg = (unichar_t *) _("The Italic correction field is used by both TeX and the MS 'MATH'\ntable. It is used when joining slanted text (italic) to upright.\nIt is the amount of extra white space needed so the slanted text\nwill not run into the upright text.");
    4543           0 :         thvarray[10] = &tgcd[6];
    4544             : 
    4545           0 :         tgcd[7].gd.pos.x = 85; tgcd[7].gd.pos.y = 57;
    4546           0 :         tgcd[7].gd.pos.width = 60;
    4547           0 :         tgcd[7].gd.flags = gg_enabled|gg_visible|gg_utf8_popup;
    4548           0 :         tgcd[7].gd.cid = CID_TeX_Italic;
    4549           0 :         tgcd[7].creator = GTextFieldCreate;
    4550           0 :         tgcd[7].gd.popup_msg = tgcd[6].gd.popup_msg;
    4551           0 :         thvarray[11] = &tgcd[7];
    4552             : 
    4553           0 :         tlabel[8].text = (unichar_t *) _("Guess");
    4554           0 :         tlabel[8].text_is_1byte = true;
    4555           0 :         tgcd[8].gd.label = &tlabel[8];
    4556           0 :         tgcd[8].gd.flags = gg_enabled|gg_visible|gg_utf8_popup;
    4557           0 :         tgcd[8].gd.cid = CID_TeX_ItalicD;
    4558           0 :         tgcd[8].gd.handle_controlevent = TeX_Default;
    4559           0 :         tgcd[8].creator = GButtonCreate;
    4560           0 :         tgcd[8].gd.popup_msg = tgcd[6].gd.popup_msg;
    4561           0 :         thvarray[12] = &tgcd[8];
    4562             : 
    4563           0 :         tgcd[9].gd.flags = gg_enabled|gg_visible|gg_utf8_popup;
    4564           0 :         tgcd[9].gd.cid = CID_ItalicDevTab;
    4565           0 :         tgcd[9].creator = GTextFieldCreate;
    4566           0 :         tgcd[9].gd.popup_msg = (unichar_t *) _("A device table for italic correction.\nExpects a comma separated list of <pixelsize>\":\"<adjustment>\nAs \"9:-1,12:1,13:1\"");
    4567           0 :         thvarray[13] = &tgcd[9]; thvarray[14] = NULL;
    4568             : 
    4569           0 :         tlabel[10].text = (unichar_t *) _("Top Accent Pos:");
    4570           0 :         tlabel[10].text_is_1byte = true;
    4571           0 :         tgcd[10].gd.label = &tlabel[10];
    4572           0 :         tgcd[10].gd.pos.x = 5; tgcd[10].gd.pos.y = 57+4; 
    4573           0 :         tgcd[10].gd.flags = gg_enabled|gg_visible|gg_utf8_popup;
    4574           0 :         tgcd[10].gd.popup_msg = tgcd[9].gd.popup_msg;
    4575           0 :         tgcd[10].creator = GLabelCreate;
    4576           0 :         tgcd[10].gd.popup_msg = (unichar_t *) _("In the MS 'MATH' table this value specifies where (horizontally)\nan accent should be placed above the glyph. Vertical placement\nis handled by other means");
    4577           0 :         thvarray[15] = &tgcd[10];
    4578             : 
    4579           0 :         tgcd[11].gd.pos.x = 85; tgcd[11].gd.pos.y = 57;
    4580           0 :         tgcd[11].gd.pos.width = 60;
    4581           0 :         tgcd[11].gd.flags = gg_enabled|gg_visible|gg_utf8_popup;
    4582           0 :         tgcd[11].gd.cid = CID_HorAccent;
    4583           0 :         tgcd[11].creator = GTextFieldCreate;
    4584           0 :         tgcd[11].gd.popup_msg = tgcd[10].gd.popup_msg;
    4585           0 :         thvarray[16] = &tgcd[11];
    4586             : 
    4587           0 :         tlabel[12].text = (unichar_t *) _("Guess");
    4588           0 :         tlabel[12].text_is_1byte = true;
    4589           0 :         tgcd[12].gd.label = &tlabel[12];
    4590           0 :         tgcd[12].gd.flags = gg_enabled|gg_visible|gg_utf8_popup;
    4591           0 :         tgcd[12].gd.cid = CID_HorAccentD;
    4592           0 :         tgcd[12].gd.handle_controlevent = TeX_Default;
    4593           0 :         tgcd[12].creator = GButtonCreate;
    4594           0 :         tgcd[12].gd.popup_msg = tgcd[10].gd.popup_msg;
    4595           0 :         thvarray[17] = &tgcd[12];
    4596             : 
    4597           0 :         tgcd[13].gd.flags = gg_enabled|gg_visible|gg_utf8_popup;
    4598           0 :         tgcd[13].gd.cid = CID_AccentDevTab;
    4599           0 :         tgcd[13].creator = GTextFieldCreate;
    4600           0 :         tgcd[13].gd.popup_msg = (unichar_t *) _("A device table for horizontal accent positioning.\nExpects a comma separated list of <pixelsize>\":\"<adjustment>\nAs \"9:-1,12:1,13:1\"");
    4601           0 :         thvarray[18] = &tgcd[13]; thvarray[19] = NULL;
    4602             : 
    4603           0 :         tlabel[14].text = (unichar_t *) _("Is Extended Shape");
    4604           0 :         tlabel[14].text_is_1byte = true;
    4605           0 :         tgcd[14].gd.label = &tlabel[14];
    4606           0 :         tgcd[14].gd.pos.x = 5; tgcd[14].gd.pos.y = 57+4; 
    4607           0 :         tgcd[14].gd.flags = gg_enabled|gg_visible|gg_utf8_popup;
    4608           0 :         tgcd[14].gd.cid = CID_IsExtended;
    4609           0 :         tgcd[14].creator = GCheckBoxCreate;
    4610           0 :         tgcd[14].gd.popup_msg = (unichar_t *) _("Is this an extended shape (like a tall parenthesis)?\nExtended shapes need special attention for vertical\nsuperscript placement.");
    4611           0 :         thvarray[20] = &tgcd[14];
    4612           0 :         thvarray[21] = thvarray[22] = GCD_ColSpan; thvarray[23] = GCD_Glue; thvarray[24] = NULL;
    4613             : 
    4614           0 :         tlabel[15].text = (unichar_t *) _("Math Kerning");    /* Graphical */
    4615           0 :         tlabel[15].text_is_1byte = true;
    4616           0 :         tgcd[15].gd.label = &tlabel[15];
    4617           0 :         tgcd[15].gd.flags = gg_enabled|gg_visible|gg_utf8_popup;
    4618           0 :         tgcd[15].gd.handle_controlevent = CI_SubSuperPositionings;
    4619           0 :         tgcd[15].creator = GButtonCreate;
    4620           0 :         tgcd[15].gd.popup_msg = (unichar_t *) _("Brings up a dialog which gives fine control over\nhorizontal positioning of subscripts and superscripts\ndepending on their vertical positioning.");
    4621           0 :         tbarray[0] = GCD_Glue; tbarray[1] = &tgcd[15]; tbarray[2] = GCD_Glue; tbarray[3] = NULL;
    4622             : 
    4623           0 :         tbox[2].gd.flags = gg_enabled|gg_visible;
    4624           0 :         tbox[2].gd.u.boxelements = tbarray;
    4625           0 :         tbox[2].creator = GHBoxCreate;
    4626             : 
    4627           0 :         thvarray[25] = &tbox[2];
    4628           0 :         thvarray[26] = thvarray[27] = thvarray[28] = GCD_ColSpan; thvarray[29] = NULL;
    4629             : 
    4630           0 :         thvarray[30] = thvarray[31] = thvarray[32] = thvarray[33] = GCD_Glue; thvarray[34] = NULL;
    4631           0 :         thvarray[35] = NULL;
    4632             : 
    4633           0 :         tbox[0].gd.flags = gg_enabled|gg_visible;
    4634           0 :         tbox[0].gd.u.boxelements = thvarray;
    4635           0 :         tbox[0].creator = GHVBoxCreate;
    4636             : 
    4637           0 :         memset(&lcgcd,0,sizeof(lcgcd));
    4638           0 :         memset(&lcbox,0,sizeof(lcbox));
    4639           0 :         memset(&lclabel,0,sizeof(lclabel));
    4640             : 
    4641           0 :         lclabel[0].text = (unichar_t *) _("Default Ligature Caret Count");
    4642           0 :         lclabel[0].text_is_1byte = true;
    4643           0 :         lclabel[0].text_in_resource = true;
    4644           0 :         lcgcd[0].gd.cid = CID_DefLCCount;
    4645           0 :         lcgcd[0].gd.label = &lclabel[0];
    4646           0 :         lcgcd[0].gd.flags = gg_enabled|gg_visible|gg_utf8_popup;
    4647           0 :         lcgcd[0].gd.popup_msg = (unichar_t *) _("Ligature caret locations are used by a text editor\nwhen it needs to draw a text edit caret inside a\nligature. This means there should be a caret between\neach ligature component so if there are n components\nthere should be n-1 caret locations.\n  You may adjust the caret locations themselves in the\noutline glyph view (drag them from to origin to the\nappropriate place)." );
    4648           0 :         lcgcd[0].gd.handle_controlevent = CI_DefLCChange;
    4649           0 :         lcgcd[0].creator = GCheckBoxCreate;
    4650           0 :         lchvarray[0][0] = &lcgcd[0];
    4651           0 :         lchvarray[0][1] = lchvarray[0][2] = GCD_Glue; lchvarray[0][3] = NULL;
    4652             : 
    4653           0 :         lclabel[1].text = (unichar_t *) _("Ligature Caret Count:");
    4654           0 :         lclabel[1].text_is_1byte = true;
    4655           0 :         lclabel[1].text_in_resource = true;
    4656           0 :         lcgcd[1].gd.label = &lclabel[1];
    4657           0 :         lcgcd[1].gd.flags = gg_enabled|gg_visible|gg_utf8_popup;
    4658           0 :         lcgcd[1].gd.cid = CID_LCCountLab;
    4659           0 :         lcgcd[1].gd.popup_msg = (unichar_t *) _("Ligature caret locations are used by a text editor\nwhen it needs to draw a text edit caret inside a\nligature. This means there should be a caret between\neach ligature component so if there are n components\nthere should be n-1 caret locations.\n  You may adjust the caret locations themselves in the\noutline glyph view (drag them from to origin to the\nappropriate place)." );
    4660           0 :         lcgcd[1].creator = GLabelCreate;
    4661           0 :         lchvarray[1][0] = &lcgcd[1];
    4662             : 
    4663           0 :         lcgcd[2].gd.pos.width = 50;
    4664           0 :         lcgcd[2].gd.flags = gg_enabled|gg_visible|gg_utf8_popup;
    4665           0 :         lcgcd[2].gd.cid = CID_LCCount;
    4666           0 :         lcgcd[2].gd.popup_msg = (unichar_t *) _("Ligature caret locations are used by a text editor\nwhen it needs to draw a text edit caret inside a\nligature. This means there should be a caret between\neach ligature component so if there are n components\nthere should be n-1 caret locations.\n  You may adjust the caret locations themselves in the\noutline glyph view (drag them from to origin to the\nappropriate place)." );
    4667           0 :         lcgcd[2].creator = GNumericFieldCreate;
    4668           0 :         lchvarray[1][1] = &lcgcd[2]; lchvarray[1][2] = GCD_Glue; lchvarray[1][3] = NULL;
    4669             : 
    4670           0 :         lchvarray[2][0] = lchvarray[2][1] = lchvarray[2][2] = GCD_Glue;
    4671           0 :         lchvarray[2][3] = lchvarray[3][0] = NULL;
    4672             : 
    4673           0 :         lcbox[0].gd.flags = gg_enabled|gg_visible;
    4674           0 :         lcbox[0].gd.u.boxelements = lchvarray[0];
    4675           0 :         lcbox[0].creator = GHVBoxCreate;
    4676             : 
    4677           0 :         memset(&vargcd,0,sizeof(vargcd));
    4678           0 :         memset(&varbox,0,sizeof(varbox));
    4679           0 :         memset(&varlabel,0,sizeof(varlabel));
    4680             : 
    4681           0 :         for ( i=0; i<2; ++i ) {
    4682           0 :             varlabel[i][0].text = (unichar_t *) _("Variant Glyphs:");
    4683           0 :             varlabel[i][0].text_is_1byte = true;
    4684           0 :             vargcd[i][0].gd.label = &varlabel[i][0];
    4685           0 :             vargcd[i][0].gd.pos.x = 5; vargcd[i][0].gd.pos.y = 57+4; 
    4686           0 :             vargcd[i][0].gd.flags = gg_enabled|gg_visible|gg_utf8_popup;
    4687           0 :             vargcd[i][0].creator = GLabelCreate;
    4688           0 :             vargcd[i][0].gd.popup_msg = (unichar_t *) _("A list of the names of pre defined glyphs which represent\nbigger versions of the current glyph.");
    4689           0 :             varhvarray[i][0][0] = &vargcd[i][0];
    4690             : 
    4691           0 :             vargcd[i][1].gd.flags = gg_enabled|gg_visible|gg_utf8_popup;
    4692           0 :             vargcd[i][1].gd.cid = CID_VariantList+i*100;
    4693           0 :             vargcd[i][1].creator = GTextCompletionCreate;
    4694           0 :             vargcd[i][1].gd.popup_msg = vargcd[i][0].gd.popup_msg;
    4695           0 :             varhvarray[i][0][1] = &vargcd[i][1]; varhvarray[i][0][2] = GCD_ColSpan; varhvarray[i][0][3] = NULL;
    4696             : 
    4697           0 :             varlabel[i][2].text = (unichar_t *) _("Glyph Extension Components");
    4698           0 :             varlabel[i][2].text_is_1byte = true;
    4699           0 :             vargcd[i][2].gd.label = &varlabel[i][2];
    4700           0 :             vargcd[i][2].gd.flags = gg_enabled|gg_visible|gg_utf8_popup;
    4701           0 :             vargcd[i][2].creator = GLabelCreate;
    4702           0 :             vargcd[i][2].gd.popup_msg = (unichar_t *) _("A really big version of this glyph may be made up of the\nfollowing component glyphs. They will be stacked either\nhorizontally or vertically. Glyphs marked as Extenders may\nbe removed or repeated (to make shorter or longer versions).\nThe StartLength is the length of the flat section at the\nstart of the glyph which may be overlapped with the previous\nglyph, while the EndLength is the similar region at the end\nof the glyph. The FullLength is the full length of the glyph." );
    4703           0 :             varhvarray[i][1][0] = &vargcd[i][2];
    4704           0 :             varhvarray[i][1][1] = varhvarray[i][1][2] = GCD_ColSpan; varhvarray[i][1][3] = NULL;
    4705             : 
    4706             : /* GT: "Cor" is an abbreviation for correction */
    4707           0 :             varlabel[i][3].text = (unichar_t *) _("Italic Cor:");
    4708           0 :             varlabel[i][3].text_is_1byte = true;
    4709           0 :             vargcd[i][3].gd.label = &varlabel[i][3];
    4710           0 :             vargcd[i][3].gd.flags = gg_enabled|gg_visible|gg_utf8_popup;
    4711           0 :             vargcd[i][3].creator = GLabelCreate;
    4712           0 :             vargcd[i][3].gd.popup_msg = (unichar_t *) _("The italic correction of the composed glyph. Should be independent of glyph size");
    4713           0 :             varhvarray[i][2][0] = &vargcd[i][3];
    4714             : 
    4715           0 :             vargcd[i][4].gd.flags = gg_enabled|gg_visible|gg_utf8_popup;
    4716           0 :             vargcd[i][4].gd.pos.width = 60;
    4717           0 :             vargcd[i][4].gd.cid = CID_ExtItalicCor+i*100;
    4718           0 :             vargcd[i][4].creator = GTextFieldCreate;
    4719           0 :             vargcd[i][4].gd.popup_msg = vargcd[i][3].gd.popup_msg;
    4720           0 :             varhvarray[i][2][1] = &vargcd[i][4];
    4721             : 
    4722           0 :             vargcd[i][5].gd.flags = gg_enabled|gg_visible|gg_utf8_popup;
    4723           0 :             vargcd[i][5].gd.pos.width = 60;
    4724           0 :             vargcd[i][5].gd.cid = CID_ExtItalicDev+i*100;
    4725           0 :             vargcd[i][5].creator = GTextFieldCreate;
    4726           0 :             vargcd[i][5].gd.popup_msg = vargcd[i][3].gd.popup_msg;
    4727           0 :             varhvarray[i][2][2] = &vargcd[i][5];
    4728           0 :             varhvarray[i][2][3] = NULL;
    4729             : 
    4730           0 :             vargcd[i][6].gd.flags = gg_enabled|gg_visible|gg_utf8_popup;
    4731           0 :             vargcd[i][6].gd.u.matrix = &mi_extensionpart;
    4732           0 :             vargcd[i][6].gd.cid = CID_ExtensionList+i*100;
    4733           0 :             vargcd[i][6].creator = GMatrixEditCreate;
    4734           0 :             varhvarray[i][3][0] = &vargcd[i][6];
    4735           0 :             varhvarray[i][3][1] = varhvarray[i][3][2] = GCD_ColSpan; varhvarray[i][3][3] = NULL;
    4736             : 
    4737           0 :             varhvarray[i][4][0] = NULL;
    4738             : 
    4739           0 :             varbox[i][0].gd.flags = gg_enabled|gg_visible;
    4740           0 :             varbox[i][0].gd.u.boxelements = varhvarray[i][0];
    4741           0 :             varbox[i][0].creator = GHVBoxCreate;
    4742             :         }
    4743             : 
    4744           0 :         memset(&tilegcd,0,sizeof(tilegcd));
    4745           0 :         memset(&tilebox,0,sizeof(tilebox));
    4746           0 :         memset(&tilelabel,0,sizeof(tilelabel));
    4747             : 
    4748           0 :         i=0;
    4749           0 :         tilelabel[i].text = (unichar_t *) _(
    4750             :             "If this glyph is used as a pattern to tile\n"
    4751             :             "some other glyph then it is useful to specify\n"
    4752             :             "the amount of whitespace surrounding the tile.\n"
    4753             :             "Either specify a margin to extend the bounding\n"
    4754             :             "box of the contents, or specify the bounds\n"
    4755             :             "explicitly.");
    4756           0 :         tilelabel[i].text_is_1byte = true;
    4757           0 :         tilelabel[i].text_in_resource = true;
    4758           0 :         tilegcd[i].gd.label = &tilelabel[i];
    4759           0 :         tilegcd[i].gd.flags = gg_enabled|gg_visible;
    4760           0 :         tilegcd[i++].creator = GLabelCreate;
    4761           0 :         tlvarray[0] = &tilegcd[i-1];
    4762             : 
    4763           0 :         tilelabel[i].text = (unichar_t *) _("Tile Margin:");
    4764           0 :         tilelabel[i].text_is_1byte = true;
    4765           0 :         tilelabel[i].text_in_resource = true;
    4766           0 :         tilegcd[i].gd.label = &tilelabel[i];
    4767           0 :         tilegcd[i].gd.flags = gg_enabled|gg_visible;
    4768           0 :         tilegcd[i].gd.cid = CID_IsTileMargin;
    4769           0 :         tilegcd[i++].creator = GRadioCreate;
    4770           0 :         tlharray[0] = &tilegcd[i-1];
    4771             : 
    4772           0 :         tilegcd[i].gd.pos.width = 60;
    4773           0 :         tilegcd[i].gd.flags = gg_enabled|gg_visible;
    4774           0 :         tilegcd[i].gd.cid = CID_TileMargin;
    4775           0 :         tilegcd[i].gd.handle_controlevent = CI_TileMarginChange;
    4776           0 :         tilegcd[i++].creator = GTextFieldCreate;
    4777           0 :         tlharray[1] = &tilegcd[i-1]; tlharray[2] = GCD_Glue; tlharray[3] = NULL;
    4778             : 
    4779           0 :         tilebox[2].gd.flags = gg_enabled|gg_visible;
    4780           0 :         tilebox[2].gd.u.boxelements = tlharray;
    4781           0 :         tilebox[2].creator = GHBoxCreate;
    4782           0 :         tlvarray[1] = &tilebox[2];
    4783             : 
    4784           0 :         tilelabel[i].text = (unichar_t *) _("Tile Bounding Box:");
    4785           0 :         tilelabel[i].text_is_1byte = true;
    4786           0 :         tilelabel[i].text_in_resource = true;
    4787           0 :         tilegcd[i].gd.label = &tilelabel[i];
    4788           0 :         tilegcd[i].gd.flags = gg_enabled|gg_visible;
    4789           0 :         tilegcd[i].gd.cid = CID_IsTileBBox;
    4790           0 :         tilegcd[i++].creator = GRadioCreate;
    4791           0 :         tlvarray[2] = &tilegcd[i-1];
    4792             : 
    4793           0 :         tlhvarray[0][0] = GCD_Glue;
    4794             : 
    4795           0 :         tilelabel[i].text = (unichar_t *) _("  X");
    4796           0 :         tilelabel[i].text_is_1byte = true;
    4797           0 :         tilegcd[i].gd.label = &tilelabel[i];
    4798           0 :         tilegcd[i].gd.flags = gg_enabled|gg_visible;
    4799           0 :         tilegcd[i++].creator = GLabelCreate;
    4800           0 :         tlhvarray[0][1] = &tilegcd[i-1];
    4801             : 
    4802           0 :         tilelabel[i].text = (unichar_t *) _("  Y");
    4803           0 :         tilelabel[i].text_is_1byte = true;
    4804           0 :         tilegcd[i].gd.label = &tilelabel[i];
    4805           0 :         tilegcd[i].gd.flags = gg_enabled|gg_visible;
    4806           0 :         tilegcd[i++].creator = GLabelCreate;
    4807           0 :         tlhvarray[0][2] = &tilegcd[i-1]; tlhvarray[0][3] = GCD_Glue; tlhvarray[0][4] = NULL;
    4808             : 
    4809           0 :         tilelabel[i].text = (unichar_t *) _("Min");
    4810           0 :         tilelabel[i].text_is_1byte = true;
    4811           0 :         tilegcd[i].gd.label = &tilelabel[i];
    4812           0 :         tilegcd[i].gd.flags = gg_enabled|gg_visible;
    4813           0 :         tilegcd[i++].creator = GLabelCreate;
    4814           0 :         tlhvarray[1][0] = &tilegcd[i-1];
    4815             : 
    4816           0 :         tilegcd[i].gd.flags = gg_enabled|gg_visible;
    4817           0 :         tilegcd[i].gd.cid = CID_TileBBoxMinX;
    4818           0 :         tilegcd[i++].creator = GTextFieldCreate;
    4819           0 :         tlhvarray[1][1] = &tilegcd[i-1];
    4820             : 
    4821           0 :         tilegcd[i].gd.flags = gg_enabled|gg_visible;
    4822           0 :         tilegcd[i].gd.cid = CID_TileBBoxMinY;
    4823           0 :         tilegcd[i++].creator = GTextFieldCreate;
    4824           0 :         tlhvarray[1][2] = &tilegcd[i-1]; tlhvarray[1][3] = GCD_Glue; tlhvarray[1][4] = NULL;
    4825             : 
    4826           0 :         tilelabel[i].text = (unichar_t *) _("Max");
    4827           0 :         tilelabel[i].text_is_1byte = true;
    4828           0 :         tilegcd[i].gd.label = &tilelabel[i];
    4829           0 :         tilegcd[i].gd.flags = gg_enabled|gg_visible;
    4830           0 :         tilegcd[i++].creator = GLabelCreate;
    4831           0 :         tlhvarray[2][0] = &tilegcd[i-1];
    4832             : 
    4833           0 :         tilegcd[i].gd.flags = gg_enabled|gg_visible;
    4834           0 :         tilegcd[i].gd.cid = CID_TileBBoxMaxX;
    4835           0 :         tilegcd[i++].creator = GTextFieldCreate;
    4836           0 :         tlhvarray[2][1] = &tilegcd[i-1];
    4837             : 
    4838           0 :         tilegcd[i].gd.flags = gg_enabled|gg_visible;
    4839           0 :         tilegcd[i].gd.cid = CID_TileBBoxMaxY;
    4840           0 :         tilegcd[i++].creator = GTextFieldCreate;
    4841           0 :         tlhvarray[2][2] = &tilegcd[i-1]; tlhvarray[2][3] = GCD_Glue; tlhvarray[2][4] = NULL;
    4842           0 :         tlhvarray[3][0] = NULL;
    4843             : 
    4844           0 :         tilebox[3].gd.flags = gg_enabled|gg_visible;
    4845           0 :         tilebox[3].gd.u.boxelements = tlhvarray[0];
    4846           0 :         tilebox[3].creator = GHVBoxCreate;
    4847           0 :         tlvarray[3] = &tilebox[3]; tlvarray[4] = GCD_Glue; tlvarray[5] = NULL;
    4848             : 
    4849           0 :         tilebox[0].gd.flags = gg_enabled|gg_visible;
    4850           0 :         tilebox[0].gd.u.boxelements = tlvarray;
    4851           0 :         tilebox[0].creator = GVBoxCreate;
    4852             : 
    4853           0 :         memset(&mgcd,0,sizeof(mgcd));
    4854           0 :         memset(&mbox,0,sizeof(mbox));
    4855           0 :         memset(&mlabel,0,sizeof(mlabel));
    4856           0 :         memset(&aspects,'\0',sizeof(aspects));
    4857             : 
    4858           0 :         i = 0;
    4859           0 :         aspects[i].text = (unichar_t *) _("Unicode");
    4860           0 :         aspects[i].text_is_1byte = true;
    4861           0 :         aspects[i].selected = true;
    4862           0 :         aspects[i++].gcd = ubox;
    4863             : 
    4864           0 :         aspects[i].text = (unichar_t *) _("Comment");
    4865           0 :         aspects[i].text_is_1byte = true;
    4866           0 :         aspects[i++].gcd = cbox;
    4867             : 
    4868           0 :         aspects[i].text = (unichar_t *) _("Positionings");
    4869           0 :         aspects[i].text_is_1byte = true;
    4870           0 :         aspects[i++].gcd = pstbox[pst_position-1];
    4871             : 
    4872           0 :         aspects[i].text = (unichar_t *) _("Pairwise Pos");
    4873           0 :         aspects[i].text_is_1byte = true;
    4874           0 :         aspects[i++].gcd = pstbox[pst_pair-1];
    4875             : 
    4876           0 :         aspects[i].text = (unichar_t *) _("Substitutions");
    4877           0 :         aspects[i].text_is_1byte = true;
    4878           0 :         aspects[i++].gcd = psgcd[2];
    4879             : 
    4880           0 :         aspects[i].text = (unichar_t *) _("Alt Subs");
    4881           0 :         aspects[i].text_is_1byte = true;
    4882           0 :         aspects[i++].gcd = psgcd[3];
    4883             : 
    4884           0 :         aspects[i].text = (unichar_t *) _("Mult Subs");
    4885           0 :         aspects[i].text_is_1byte = true;
    4886           0 :         aspects[i++].gcd = psgcd[4];
    4887             : 
    4888           0 :         aspects[i].text = (unichar_t *) _("Ligatures");
    4889           0 :         aspects[i].text_is_1byte = true;
    4890           0 :         aspects[i++].gcd = psgcd[5];
    4891             : 
    4892           0 :         aspects[i].text = (unichar_t *) _("Components");
    4893           0 :         aspects[i].text_is_1byte = true;
    4894           0 :         aspects[i].nesting = 1;
    4895           0 :         aspects[i++].gcd = cobox;
    4896             : 
    4897           0 :         ci->lc_aspect = i;
    4898           0 :         aspects[i].text = (unichar_t *) _("Lig. Carets");
    4899           0 :         aspects[i].text_is_1byte = true;
    4900           0 :         aspects[i].nesting = 1;
    4901           0 :         aspects[i++].gcd = lcbox;
    4902             : 
    4903           0 :         aspects[i].text = (unichar_t *) _("Counters");
    4904           0 :         aspects[i].text_is_1byte = true;
    4905           0 :         aspects[i++].gcd = pstbox[6];
    4906             : 
    4907           0 :         aspects[i].text = (unichar_t *) U_("ΤεΧ & Math");      /* TeX */
    4908           0 :         aspects[i].text_is_1byte = true;
    4909           0 :         aspects[i++].gcd = tbox;
    4910             : 
    4911           0 :         ci->vert_aspect = i;
    4912             : /* GT: "Vert." is an abbreviation for Vertical */
    4913           0 :         aspects[i].text = (unichar_t *) U_("Vert. Variants");
    4914           0 :         aspects[i].text_is_1byte = true;
    4915           0 :         aspects[i].nesting = 1;
    4916           0 :         aspects[i++].gcd = varbox[0];
    4917             : 
    4918             : /* GT: "Horiz." is an abbreviation for Horizontal */
    4919           0 :         aspects[i].text = (unichar_t *) U_("Horiz. Variants");
    4920           0 :         aspects[i].text_is_1byte = true;
    4921           0 :         aspects[i].nesting = 1;
    4922           0 :         aspects[i++].gcd = varbox[1];
    4923             : 
    4924           0 :         if ( sc->parent->multilayer ) {
    4925           0 :             aspects[i].text = (unichar_t *) U_("Tile Size");
    4926           0 :             aspects[i].text_is_1byte = true;
    4927           0 :             aspects[i++].gcd = tilebox;
    4928             :         }
    4929             : 
    4930           0 :         if ( last_gi_aspect<i )
    4931           0 :             aspects[last_gi_aspect].selected = true;
    4932             : 
    4933           0 :         mgcd[0].gd.pos.x = 4; mgcd[0].gd.pos.y = 6;
    4934           0 :         mgcd[0].gd.u.tabs = aspects;
    4935           0 :         mgcd[0].gd.flags = gg_visible | gg_enabled | gg_tabset_vert;
    4936           0 :         mgcd[0].gd.cid = CID_Tabs;
    4937           0 :         mgcd[0].gd.handle_controlevent = CI_AspectChange;
    4938           0 :         mgcd[0].creator = GTabSetCreate;
    4939           0 :         mvarray[0] = &mgcd[0]; mvarray[1] = NULL;
    4940             : 
    4941           0 :         mgcd[1].gd.pos.x = 40; mgcd[1].gd.pos.y = mgcd[0].gd.pos.y+mgcd[0].gd.pos.height+3;
    4942           0 :         mgcd[1].gd.flags = gg_visible | gg_enabled ;
    4943           0 :         mlabel[1].text = (unichar_t *) _("< _Prev");
    4944           0 :         mlabel[1].text_is_1byte = true;
    4945           0 :         mlabel[1].text_in_resource = true;
    4946           0 :         mgcd[1].gd.mnemonic = 'P';
    4947           0 :         mgcd[1].gd.label = &mlabel[1];
    4948           0 :         mgcd[1].gd.handle_controlevent = CI_NextPrev;
    4949           0 :         mgcd[1].gd.cid = -1;
    4950           0 :         mharray1[0] = GCD_Glue; mharray1[1] = &mgcd[1]; mharray1[2] = GCD_Glue;
    4951           0 :         mgcd[1].creator = GButtonCreate;
    4952             : 
    4953           0 :         mgcd[2].gd.pos.x = -40; mgcd[2].gd.pos.y = mgcd[1].gd.pos.y;
    4954           0 :         mgcd[2].gd.flags = gg_visible | gg_enabled ;
    4955           0 :         mlabel[2].text = (unichar_t *) _("_Next >");
    4956           0 :         mlabel[2].text_is_1byte = true;
    4957           0 :         mlabel[2].text_in_resource = true;
    4958           0 :         mgcd[2].gd.label = &mlabel[2];
    4959           0 :         mgcd[2].gd.mnemonic = 'N';
    4960           0 :         mgcd[2].gd.handle_controlevent = CI_NextPrev;
    4961           0 :         mgcd[2].gd.cid = 1;
    4962           0 :         mharray1[3] = GCD_Glue; mharray1[4] = &mgcd[2]; mharray1[5] = GCD_Glue; mharray1[6] = NULL;
    4963           0 :         mgcd[2].creator = GButtonCreate;
    4964             : 
    4965           0 :         mbox[2].gd.flags = gg_enabled|gg_visible;
    4966           0 :         mbox[2].gd.u.boxelements = mharray1;
    4967           0 :         mbox[2].creator = GHBoxCreate;
    4968           0 :         mvarray[2] = &mbox[2]; mvarray[3] = NULL;
    4969             : 
    4970           0 :         mgcd[3].gd.pos.x = 25-3; mgcd[3].gd.pos.y = CI_Height-31-3;
    4971           0 :         mgcd[3].gd.flags = gg_visible | gg_enabled | gg_but_default;
    4972           0 :         mlabel[3].text = (unichar_t *) _("_OK");
    4973           0 :         mlabel[3].text_is_1byte = true;
    4974           0 :         mlabel[3].text_in_resource = true;
    4975           0 :         mgcd[3].gd.mnemonic = 'O';
    4976           0 :         mgcd[3].gd.label = &mlabel[3];
    4977           0 :         mgcd[3].gd.handle_controlevent = CI_OK;
    4978           0 :         mharray2[0] = GCD_Glue; mharray2[1] = &mgcd[3]; mharray2[2] = GCD_Glue; mharray2[3] = GCD_Glue;
    4979           0 :         mgcd[3].creator = GButtonCreate;
    4980             : 
    4981           0 :         mgcd[4].gd.pos.x = -25; mgcd[4].gd.pos.y = mgcd[3].gd.pos.y+3;
    4982           0 :         mgcd[4].gd.flags = gg_visible | gg_enabled | gg_but_cancel;
    4983           0 :         mlabel[4].text = (unichar_t *) _("_Cancel");
    4984           0 :         mlabel[4].text_is_1byte = true;
    4985           0 :         mlabel[4].text_in_resource = true;
    4986           0 :         mgcd[4].gd.label = &mlabel[4];
    4987           0 :         mgcd[4].gd.handle_controlevent = CI_Cancel;
    4988           0 :         mgcd[4].gd.cid = CID_Cancel;
    4989           0 :         mharray2[4] = GCD_Glue; mharray2[5] = &mgcd[4]; mharray2[6] = GCD_Glue; mharray2[7] = NULL;
    4990           0 :         mgcd[4].creator = GButtonCreate;
    4991             : 
    4992           0 :         mbox[3].gd.flags = gg_enabled|gg_visible;
    4993           0 :         mbox[3].gd.u.boxelements = mharray2;
    4994           0 :         mbox[3].creator = GHBoxCreate;
    4995           0 :         mvarray[4] = &mbox[3]; mvarray[5] = NULL;
    4996           0 :         mvarray[6] = NULL;
    4997             : 
    4998           0 :         mbox[0].gd.pos.x = mbox[0].gd.pos.y = 2;
    4999           0 :         mbox[0].gd.flags = gg_enabled|gg_visible;
    5000           0 :         mbox[0].gd.u.boxelements = mvarray;
    5001           0 :         mbox[0].creator = GHVGroupCreate;
    5002             : 
    5003           0 :         GGadgetsCreate(ci->gw,mbox);
    5004             : 
    5005           0 :         GHVBoxSetExpandableRow(mbox[0].ret,0);
    5006           0 :         GHVBoxSetExpandableCol(mbox[2].ret,gb_expandgluesame);
    5007           0 :         GHVBoxSetExpandableCol(mbox[3].ret,gb_expandgluesame);
    5008             : 
    5009           0 :         GHVBoxSetExpandableRow(ubox[0].ret,gb_expandglue);
    5010           0 :         GHVBoxSetExpandableCol(ubox[0].ret,1);
    5011           0 :         GHVBoxSetExpandableCol(ubox[2].ret,gb_expandgluesame);
    5012             : 
    5013           0 :         GHVBoxSetExpandableRow(cbox[0].ret,1);
    5014           0 :         GHVBoxSetExpandableCol(cbox[2].ret,gb_expandglue);
    5015             : 
    5016           0 :         for ( i=0; i<6; ++i ) {
    5017           0 :             GGadget *g = GWidgetGetControl(ci->gw,CID_List+i*100);
    5018           0 :             GMatrixEditSetNewText(g, newstrings[i]);
    5019           0 :             if ( i==pst_substitution-1 || i==pst_pair-1 )
    5020           0 :                 GMatrixEditSetColumnCompletion(g,1,CI_GlyphNameCompletion);
    5021           0 :             else if ( i==pst_alternate-1 || i==pst_multiple-1 ||
    5022             :                     i==pst_ligature-1)
    5023           0 :                 GMatrixEditSetColumnCompletion(g,1,CI_GlyphListCompletion);
    5024             :         }
    5025           0 :         GHVBoxSetExpandableRow(pstbox[pst_pair-1][0].ret,0);
    5026           0 :         for ( i=0; i<6; ++i )
    5027           0 :             GMatrixEditSetMouseMoveReporter(psgcd[i][0].ret,CI_SubsPopupPrepare);
    5028           0 :         GMatrixEditSetMouseMoveReporter(psgcd[pst_pair-1][0].ret,CI_KerningPopupPrepare);
    5029           0 :         for ( i=6; i<7; ++i ) {
    5030           0 :             GHVBoxSetExpandableRow(pstbox[i][0].ret,0);
    5031           0 :             GHVBoxSetExpandableCol(pstbox[i][2].ret,gb_expandgluesame);
    5032             :         }
    5033             : 
    5034           0 :         GHVBoxSetExpandableRow(cobox[0].ret,gb_expandglue);
    5035           0 :         GHVBoxSetExpandableRow(tbox[0].ret,gb_expandglue);
    5036           0 :         GHVBoxSetExpandableCol(tbox[0].ret,gb_expandglue);
    5037           0 :         GHVBoxSetPadding(tbox[0].ret,6,4);
    5038           0 :         GHVBoxSetExpandableCol(tbox[2].ret,gb_expandglue);
    5039             : 
    5040           0 :         GHVBoxSetExpandableRow(lcbox[0].ret,gb_expandglue);
    5041           0 :         GHVBoxSetExpandableCol(lcbox[0].ret,gb_expandglue);
    5042             : 
    5043           0 :         GHVBoxSetExpandableRow(varbox[0][0].ret,3);
    5044           0 :         GHVBoxSetExpandableRow(varbox[1][0].ret,3);
    5045             : 
    5046           0 :         if ( sc->parent->multilayer ) {
    5047           0 :             GHVBoxSetExpandableRow(tilebox[0].ret,gb_expandglue);
    5048           0 :             GHVBoxSetExpandableCol(tilebox[2].ret,gb_expandglue);
    5049           0 :             GHVBoxSetExpandableCol(tilebox[3].ret,gb_expandglue);
    5050             :         }
    5051             : 
    5052           0 :         GHVBoxFitWindow(mbox[0].ret);
    5053             : 
    5054           0 :         if ( font==NULL ) {
    5055           0 :             memset(&rq,0,sizeof(rq));
    5056           0 :             rq.utf8_family_name = MONO_UI_FAMILIES;
    5057           0 :             rq.point_size = 12;
    5058           0 :             rq.weight = 400;
    5059           0 :             font = GDrawInstanciateFont(ci->gw,&rq);
    5060           0 :             font = GResourceFindFont("GlyphInfo.Font",font);
    5061             :         }
    5062           0 :         for ( i=0; i<5; ++i )
    5063           0 :             GGadgetSetFont(psgcd[i][0].ret,font);
    5064           0 :         for ( i=0; i<2; ++i ) {
    5065           0 :             GCompletionFieldSetCompletion(vargcd[i][1].ret,CI_GlyphNameCompletion);
    5066           0 :             GCompletionFieldSetCompletionMode(vargcd[i][1].ret,true);
    5067           0 :             GMatrixEditSetColumnCompletion(vargcd[i][6].ret,0,CI_GlyphNameCompletion);
    5068           0 :             GMatrixEditSetMouseMoveReporter(vargcd[i][6].ret,CI_ConstructionPopupPrepare);
    5069             :         }
    5070             : 
    5071           0 :     CIFillup(ci);
    5072             : 
    5073           0 :     GWidgetHidePalettes();
    5074           0 :     GDrawSetVisible(ci->gw,true);
    5075             : }
    5076             : 
    5077           0 : void CharInfoDestroy(CharInfo *ci) {
    5078           0 :     GDrawDestroyWindow(ci->gw);
    5079           0 : }
    5080             : 
    5081             : struct sel_dlg {
    5082             :     int done;
    5083             :     int ok;
    5084             :     FontView *fv;
    5085             : };
    5086             : 
    5087           0 : int FVParseSelectByPST(FontView *fv,struct lookup_subtable *sub,
    5088             :         int search_type) {
    5089             :     int first;
    5090             : 
    5091           0 :     first = FVBParseSelectByPST((FontViewBase *) fv,sub,search_type);
    5092             : 
    5093           0 :     if ( first!=-1 )
    5094           0 :         FVScrollToChar(fv,first);
    5095           0 :     else if ( !no_windowing_ui )
    5096           0 :         ff_post_notice(_("Select By ATT..."),_("No glyphs matched"));
    5097           0 :     if (  !no_windowing_ui )
    5098           0 :         GDrawRequestExpose(fv->v,NULL,false);
    5099           0 : return( true );
    5100             : }
    5101             :     
    5102           0 : static int SelectStuff(struct sel_dlg *sld,GWindow gw) {
    5103           0 :     struct lookup_subtable *sub = GGadgetGetListItemSelected(GWidgetGetControl(gw,CID_PST))->userdata;
    5104           0 :     int search_type = GGadgetIsChecked(GWidgetGetControl(gw,CID_SelectResults)) ? 1 :
    5105           0 :             GGadgetIsChecked(GWidgetGetControl(gw,CID_MergeResults)) ? 2 :
    5106             :                 3;
    5107           0 : return( FVParseSelectByPST(sld->fv, sub, search_type));
    5108             : }
    5109             : 
    5110           0 : static int selpst_e_h(GWindow gw, GEvent *event) {
    5111           0 :     struct sel_dlg *sld = GDrawGetUserData(gw);
    5112             : 
    5113           0 :     if ( event->type==et_close ) {
    5114           0 :         sld->done = true;
    5115           0 :         sld->ok = false;
    5116           0 :     } else if ( event->type==et_char ) {
    5117           0 :         if ( event->u.chr.keysym == GK_F1 || event->u.chr.keysym == GK_Help ) {
    5118           0 :             help("selectbyatt.html");
    5119           0 : return( true );
    5120             :         }
    5121           0 : return( false );
    5122           0 :     } else if ( event->type==et_controlevent && event->u.control.subtype == et_buttonactivate ) {
    5123           0 :         sld->ok = GGadgetGetCid(event->u.control.g);
    5124           0 :         if ( !sld->ok || SelectStuff(sld,gw))
    5125           0 :             sld->done = true;
    5126             :     }
    5127           0 : return( true );
    5128             : }
    5129             : 
    5130           0 : void FVSelectByPST(FontView *fv) {
    5131             :     struct sel_dlg sld;
    5132             :     GWindow gw;
    5133             :     GRect pos;
    5134             :     GWindowAttrs wattrs;
    5135             :     GGadgetCreateData gcd[14];
    5136             :     GTextInfo label[14];
    5137             :     GGadgetCreateData *varray[20], *harray[8];
    5138             :     int i,j,isgpos, cnt;
    5139             :     OTLookup *otl;
    5140             :     struct lookup_subtable *sub;
    5141             :     GTextInfo *ti;
    5142           0 :     SplineFont *sf = fv->b.sf;
    5143             : 
    5144           0 :     if ( sf->cidmaster ) sf = sf->cidmaster;
    5145           0 :     ti = NULL;
    5146           0 :     for ( j=0; j<2; ++j ) {
    5147           0 :         cnt = 0;
    5148           0 :         for ( isgpos=0; isgpos<2; ++isgpos ) {
    5149           0 :             for ( otl = isgpos ? sf->gpos_lookups : sf->gsub_lookups ; otl!=NULL; otl=otl->next ) {
    5150           0 :                 if ( otl->lookup_type== gsub_single ||
    5151           0 :                         otl->lookup_type== gsub_multiple ||
    5152           0 :                         otl->lookup_type== gsub_alternate ||
    5153           0 :                         otl->lookup_type== gsub_ligature ||
    5154           0 :                         otl->lookup_type== gpos_single ||
    5155           0 :                         otl->lookup_type== gpos_pair ||
    5156           0 :                         otl->lookup_type== gpos_cursive ||
    5157           0 :                         otl->lookup_type== gpos_mark2base ||
    5158           0 :                         otl->lookup_type== gpos_mark2ligature ||
    5159           0 :                         otl->lookup_type== gpos_mark2mark )
    5160           0 :                     for ( sub=otl->subtables; sub!=NULL; sub=sub->next )
    5161           0 :                         if ( sub->kc==NULL ) {
    5162           0 :                             if ( ti!=NULL ) {
    5163           0 :                                 ti[cnt].text = (unichar_t *) copy(sub->subtable_name);
    5164           0 :                                 ti[cnt].text_is_1byte = true;
    5165           0 :                                 ti[cnt].userdata = sub;
    5166           0 :                                 ti[cnt].selected = cnt==0;
    5167             :                             }
    5168           0 :                             ++cnt;
    5169             :                         }
    5170             :             }
    5171             :         }
    5172           0 :         if ( cnt==0 ) {
    5173           0 :             ff_post_notice(_("No Lookups"), _("No applicable lookup subtables"));
    5174           0 : return;
    5175             :         }
    5176           0 :         if ( ti==NULL )
    5177           0 :             ti = calloc(cnt+1,sizeof(GTextInfo));
    5178             :     }
    5179             : 
    5180           0 :     CharInfoInit();
    5181             : 
    5182           0 :     memset(&sld,0,sizeof(sld));
    5183           0 :     sld.fv = fv;
    5184           0 :         memset(&wattrs,0,sizeof(wattrs));
    5185           0 :         wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_undercursor|wam_isdlg|wam_restrict;
    5186           0 :         wattrs.event_masks = ~(1<<et_charup);
    5187           0 :         wattrs.restrict_input_to_me = 1;
    5188           0 :         wattrs.undercursor = 1;
    5189           0 :         wattrs.cursor = ct_pointer;
    5190           0 :         wattrs.utf8_window_title =  _("Select By Lookup Subtable");
    5191           0 :         wattrs.is_dlg = true;
    5192           0 :         pos.x = pos.y = 0;
    5193           0 :         pos.width = GGadgetScale(GDrawPointsToPixels(NULL,160));
    5194           0 :         pos.height = GDrawPointsToPixels(NULL,204);
    5195           0 :         gw = GDrawCreateTopWindow(NULL,&pos,selpst_e_h,&sld,&wattrs);
    5196             : 
    5197           0 :         memset(&gcd,0,sizeof(gcd));
    5198           0 :         memset(&label,0,sizeof(label));
    5199             : 
    5200           0 :         i=j=0;
    5201             : 
    5202           0 :         label[i].text = (unichar_t *) _("Select Glyphs in lookup subtable");
    5203           0 :         label[i].text_is_1byte = true;
    5204           0 :         gcd[i].gd.label = &label[i];
    5205           0 :         gcd[i].gd.flags = gg_enabled|gg_visible;
    5206           0 :         gcd[i++].creator = GLabelCreate;
    5207           0 :         varray[j++] = &gcd[i-1]; varray[j++] = NULL;
    5208             : 
    5209           0 :         gcd[i].gd.label = &ti[0];
    5210           0 :         gcd[i].gd.pos.x = 10; gcd[i].gd.pos.y = 5+4;
    5211           0 :         gcd[i].gd.flags = gg_enabled|gg_visible/*|gg_list_exactlyone*/;
    5212           0 :         gcd[i].gd.u.list = ti;
    5213           0 :         gcd[i].gd.cid = CID_PST;
    5214           0 :         gcd[i++].creator = GListButtonCreate;
    5215           0 :         varray[j++] = &gcd[i-1]; varray[j++] = NULL;
    5216           0 :         varray[j++] = GCD_Glue; varray[j++] = NULL;
    5217             : 
    5218           0 :         label[i].text = (unichar_t *) _("Select Results");
    5219           0 :         label[i].text_is_1byte = true;
    5220           0 :         gcd[i].gd.label = &label[i];
    5221           0 :         gcd[i].gd.pos.x = 5; gcd[i].gd.pos.y = gcd[i-1].gd.pos.y+26; 
    5222           0 :         gcd[i].gd.flags = gg_enabled|gg_visible|gg_cb_on|gg_utf8_popup;
    5223           0 :         gcd[i].gd.popup_msg = (unichar_t *) _("Set the selection of the font view to the glyphs\nfound by this search");
    5224           0 :         gcd[i].gd.cid = CID_SelectResults;
    5225           0 :         gcd[i++].creator = GRadioCreate;
    5226           0 :         varray[j++] = &gcd[i-1]; varray[j++] = NULL;
    5227             : 
    5228           0 :         label[i].text = (unichar_t *) _("Merge Results");
    5229           0 :         label[i].text_is_1byte = true;
    5230           0 :         gcd[i].gd.label = &label[i];
    5231           0 :         gcd[i].gd.pos.x = 5; gcd[i].gd.pos.y = gcd[i-1].gd.pos.y+15; 
    5232           0 :         gcd[i].gd.flags = gg_enabled|gg_visible|gg_utf8_popup;
    5233           0 :         gcd[i].gd.popup_msg = (unichar_t *) _("Expand the selection of the font view to include\nall the glyphs found by this search");
    5234           0 :         gcd[i].gd.cid = CID_MergeResults;
    5235           0 :         gcd[i++].creator = GRadioCreate;
    5236           0 :         varray[j++] = &gcd[i-1]; varray[j++] = NULL;
    5237             : 
    5238           0 :         label[i].text = (unichar_t *) _("Restrict Selection");
    5239           0 :         label[i].text_is_1byte = true;
    5240           0 :         gcd[i].gd.label = &label[i];
    5241           0 :         gcd[i].gd.pos.x = 5; gcd[i].gd.pos.y = gcd[i-1].gd.pos.y+15; 
    5242           0 :         gcd[i].gd.flags = gg_enabled|gg_visible|gg_utf8_popup;
    5243           0 :         gcd[i].gd.popup_msg = (unichar_t *) _("Only search the selected glyphs, and unselect\nany characters which do not match this search");
    5244           0 :         gcd[i].gd.cid = CID_RestrictSelection;
    5245           0 :         gcd[i++].creator = GRadioCreate;
    5246           0 :         varray[j++] = &gcd[i-1]; varray[j++] = NULL;
    5247           0 :         varray[j++] = GCD_Glue; varray[j++] = NULL;
    5248             : 
    5249           0 :         gcd[i].gd.pos.x = 15-3; gcd[i].gd.pos.y = gcd[i-1].gd.pos.y+22;
    5250           0 :         gcd[i].gd.flags = gg_visible | gg_enabled | gg_but_default;
    5251           0 :         label[i].text = (unichar_t *) _("_OK");
    5252           0 :         label[i].text_is_1byte = true;
    5253           0 :         label[i].text_in_resource = true;
    5254           0 :         gcd[i].gd.mnemonic = 'O';
    5255           0 :         gcd[i].gd.label = &label[i];
    5256           0 :         gcd[i].gd.cid = true;
    5257           0 :         gcd[i++].creator = GButtonCreate;
    5258           0 :         harray[0] = GCD_Glue; harray[1] = &gcd[i-1]; harray[2] = GCD_Glue;
    5259             : 
    5260           0 :         gcd[i].gd.pos.x = -15; gcd[i].gd.pos.y = gcd[i-1].gd.pos.y+3;
    5261           0 :         gcd[i].gd.flags = gg_visible | gg_enabled | gg_but_cancel;
    5262           0 :         label[i].text = (unichar_t *) _("_Cancel");
    5263           0 :         label[i].text_is_1byte = true;
    5264           0 :         label[i].text_in_resource = true;
    5265           0 :         gcd[i].gd.label = &label[i];
    5266           0 :         gcd[i].gd.mnemonic = 'C';
    5267           0 :         gcd[i].gd.cid = false;
    5268           0 :         gcd[i++].creator = GButtonCreate;
    5269           0 :         harray[3] = GCD_Glue; harray[4] = &gcd[i-1]; harray[5] = GCD_Glue;
    5270           0 :         harray[6] = NULL;
    5271             : 
    5272           0 :         gcd[i].gd.flags = gg_enabled|gg_visible;
    5273           0 :         gcd[i].gd.u.boxelements = harray;
    5274           0 :         gcd[i].creator = GHBoxCreate;
    5275           0 :         varray[j++] = &gcd[i++]; varray[j++] = NULL; varray[j++] = NULL;
    5276             : 
    5277           0 :         gcd[i].gd.pos.x = gcd[i].gd.pos.y = 2;
    5278           0 :         gcd[i].gd.flags = gg_enabled|gg_visible;
    5279           0 :         gcd[i].gd.u.boxelements = varray;
    5280           0 :         gcd[i].creator = GHVGroupCreate;
    5281             : 
    5282           0 :         GGadgetsCreate(gw,gcd+i);
    5283           0 :         GTextInfoListFree(ti);
    5284           0 :         GHVBoxSetExpandableRow(gcd[i].ret,gb_expandglue);
    5285           0 :         GHVBoxSetExpandableCol(gcd[i-1].ret,gb_expandgluesame);
    5286           0 :         GHVBoxFitWindow(gcd[i].ret);
    5287             : 
    5288           0 :     GDrawSetVisible(gw,true);
    5289           0 :     while ( !sld.done )
    5290           0 :         GDrawProcessOneEvent(NULL);
    5291           0 :     if ( sld.ok ) {
    5292             :     }
    5293           0 :     GDrawDestroyWindow(gw);
    5294             : }
    5295             : 
    5296           0 : void CharInfoInit(void) {
    5297             :     static GTextInfo *lists[] = { glyphclasses, std_colors, truefalse, NULL };
    5298             :     static int done = 0;
    5299             :     int i, j;
    5300             :     static char **cnames[] = { newstrings, NULL };
    5301             :     static struct col_init *col_inits[] = { extensionpart, altuniinfo,
    5302             :         devtabci,
    5303             :         simplesubsci, ligatureci, altsubsci, multsubsci, simpleposci,
    5304             :         pairposci, NULL };
    5305             : 
    5306           0 :     if ( done )
    5307           0 : return;
    5308           0 :     done = true;
    5309           0 :     for ( i=0; lists[i]!=NULL; ++i )
    5310           0 :         for ( j=0; lists[i][j].text!=NULL; ++j )
    5311           0 :             lists[i][j].text = (unichar_t *) S_((char *) lists[i][j].text);
    5312           0 :     for ( i=0; cnames[i]!=NULL; ++i )
    5313           0 :         for ( j=0; cnames[i][j]!=NULL; ++j )
    5314           0 :             cnames[i][j] = _(cnames[i][j]);
    5315           0 :     for ( i=0; col_inits[i]!=NULL; ++i )
    5316           0 :         for ( j=0; col_inits[i][j].title!=NULL; ++j )
    5317           0 :             col_inits[i][j].title=_(col_inits[i][j].title);
    5318             : }

Generated by: LCOV version 1.10