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

          Line data    Source code
       1             : /* Copyright (C) 2003-2012 by George Williams */
       2             : /*
       3             :  * Redistribution and use in source and binary forms, with or without
       4             :  * modification, are permitted provided that the following conditions are met:
       5             : 
       6             :  * Redistributions of source code must retain the above copyright notice, this
       7             :  * list of conditions and the following disclaimer.
       8             : 
       9             :  * Redistributions in binary form must reproduce the above copyright notice,
      10             :  * this list of conditions and the following disclaimer in the documentation
      11             :  * and/or other materials provided with the distribution.
      12             : 
      13             :  * The name of the author may not be used to endorse or promote products
      14             :  * derived from this software without specific prior written permission.
      15             : 
      16             :  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
      17             :  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
      18             :  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
      19             :  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
      20             :  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
      21             :  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
      22             :  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
      23             :  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
      24             :  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
      25             :  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      26             :  */
      27             : #include "asmfpst.h"
      28             : #include "fontforgeui.h"
      29             : #include "lookups.h"
      30             : #include "splineutil.h"
      31             : #include <chardata.h>
      32             : #include <utype.h>
      33             : #include <ustring.h>
      34             : #include <gkeysym.h>
      35             : 
      36             : /* Currently uses class numbers rather than names!!!!!! */
      37             : 
      38             : /* ************************************************************************** */
      39             : /* ************************ Context/Chaining Dialog ************************* */
      40             : /* ************************************************************************** */
      41             : enum activewindow { aw_formats, aw_coverage, aw_grules, aw_glyphs,
      42             :                     aw_classrules, aw_classnumber,
      43             :                     aw_coverage_simple, aw_glyphs_simple, aw_classes_simple };
      44             : struct contextchaindlg {
      45             :     struct gfi_data *gfi;
      46             :     SplineFont *sf;
      47             :     FPST *fpst;
      48             :     unichar_t *newname;
      49             :     int isnew;
      50             :     GWindow gw;
      51             :     GWindow formats, coverage, grules, glyphs, classrules, classnumber;
      52             :     GWindow coverage_simple, glyphs_simple, classes_simple;
      53             :     enum activewindow aw;
      54             : /* Wizard panes:
      55             :   formats         -- gives user a choice between by glyph/class/coverage table
      56             : Simple version:
      57             :   glyphs_simple   -- user picked glyph format, shows a matrix edit of glyph lists
      58             :                      and lookups.
      59             :   classes_simple  -- user picked class format. shows a matrix edit of class lists
      60             :                      with lookups. Also the three sets of classes_simple.
      61             :   coverage_simple -- user picked coverage table format. shows a matrix edit with
      62             :                      a bunch of coverage tables and lookups/replacements.
      63             :                      [coverage_simple format only accepts 1 rule]
      64             : Complex version:
      65             :   grules     -- user picked glyph format, shows a list of glyph lists and with
      66             :                   lookups. Editing a glyph list takes us to the glyphs pane
      67             :   classrules -- user picked class format. shows a list of class lists with
      68             :                   lookups. Also a tabbed widget showing the three sets of
      69             :                   classes.
      70             :   coverage   -- user picked coverage table format. shows a tabbed widget with
      71             :                   three lists of coverage tables. (for match also shows a
      72             :                   set of sequence #/lookup pairs.
      73             :                   [There is no coveragerules pane because coverage format
      74             :                    only accepts 1 rule]
      75             :   glyphs     -- from grules, user asked for a new rule. Shows tabbed widget
      76             :                   with three lists of glyphs (for match, also shows a set of
      77             :                   sequence #/lookups
      78             :   classnumber - from class rules, tabbed pane describing one class based rule
      79             : */
      80             :     int row_being_edited;
      81             :     int subheightdiff, canceldrop;
      82             :     int done;
      83             :     int layer;
      84             : };
      85             : 
      86             : #define CID_OK          100
      87             : #define CID_Cancel      101
      88             : #define CID_Next        102
      89             : #define CID_Prev        103
      90             : #define CID_SubSize     104
      91             : 
      92             : #define CID_ByGlyph     200
      93             : #define CID_ByClass     201
      94             : #define CID_ByCoverage  202
      95             : 
      96             : #define CID_Simple      205
      97             : #define CID_Complex     206
      98             : 
      99             : /* There are more CIDs used in this file than those listed here */
     100             : /* The CIDs given here are for glyph lists (aw_glyphs & aw_grules) */
     101             : /*  similar controls refering to coverage tables have 100 added to them */
     102             : /* The CIDs here are also for the "match" aspect of the tabsets */
     103             : /*  those in backtrack get 20 added, those in lookahead get 40 */
     104             : #define CID_GList       305
     105             : 
     106             : #define CID_MatchType   1003
     107             : #define CID_Set         1004
     108             : #define CID_Select      1005
     109             : #define CID_GlyphList   1006
     110             : #define CID_Set2        1007
     111             : #define CID_Select2     1008
     112             : #define CID_RplList     1009
     113             : #define CID_LookupList  1010
     114             : #define CID_LNew        1011
     115             : #define CID_LEdit       1012
     116             : #define CID_LDelete     1013
     117             : #define CID_LUp         1014
     118             : #define CID_LDown       1015
     119             : 
     120             : #define CID_ClassNumbers        2000
     121             : #define CID_ClassList           2001
     122             : #define CID_ClassType           2002
     123             : #define CID_SameAsClasses       2003
     124             : 
     125             : /* And for the simple dlg... */
     126             : 
     127             : #define CID_GList_Simple        4000
     128             : #define CID_GNewSection         4001
     129             : #define CID_GAddLookup          4002
     130             : 
     131             : #define CID_CList_Simple        (CID_GList_Simple+100)
     132             : #define CID_CNewSection         (CID_GNewSection+100)
     133             : #define CID_CAddLookup          (CID_GAddLookup+100)
     134             : 
     135             : #define CID_MatchClasses        (CID_GList_Simple+300+0*20)
     136             : #define CID_BackClasses         (CID_MatchClasses+1*20)
     137             : #define CID_ForeClasses         (CID_MatchClasses+2*20)
     138             : #define CID_SameAsClasses_S     (CID_MatchClasses+1)            /* Not actually used itself */
     139             : #define CID_BackClassesSameAs_S (CID_SameAsClasses_S+1*20)
     140             : #define CID_ForeClassesSameAs_S (CID_SameAsClasses_S+2*20)
     141             : 
     142             : #define CID_ClassMatchType      4500
     143             : 
     144             : #define CID_Covers              4600
     145             : 
     146           0 : char *cu_copybetween(const unichar_t *start, const unichar_t *end) {
     147           0 :     char *ret = malloc(end-start+1);
     148           0 :     cu_strncpy(ret,start,end-start);
     149           0 :     ret[end-start] = '\0';
     150           0 : return( ret );
     151             : }
     152             : 
     153           0 : static char *reversenames(char *str) {
     154             :     char *ret;
     155             :     char *rpt, *pt, *start, *spt;
     156             : 
     157           0 :     if ( str==NULL )
     158           0 : return( NULL );
     159             : 
     160           0 :     rpt = ret = malloc(strlen(str)+1);
     161           0 :     *ret = '\0';
     162           0 :     for ( pt=str+strlen(str); pt>str; pt=start ) {
     163           0 :         for ( start = pt-1; start>=str && *start!=' '; --start );
     164           0 :         for ( spt=start+1; spt<pt; )
     165           0 :             *rpt++ = *spt++;
     166           0 :         *rpt++ = ' ';
     167             :     }
     168           0 :     if ( rpt>ret )
     169           0 :         rpt[-1] = '\0';
     170           0 : return( ret );
     171             : }
     172             : 
     173           0 : static char *rpl(const char *src, const char *find, const char *rpl) {
     174             :     const char *pt, *start;
     175             :     char *ret, *rpt;
     176           0 :     int found_cnt=0;
     177           0 :     int flen = strlen(find);
     178             : 
     179           0 :     for ( pt=src; *pt; ) {
     180           0 :         while ( isspace(*pt)) ++pt;
     181           0 :         if ( *pt=='\0' )
     182           0 :     break;
     183           0 :         for ( start=pt; !isspace(*pt) && *pt!='\0'; ++pt );
     184           0 :         if ( pt-start==flen && strncmp(find,start,flen)==0 )
     185           0 :             ++found_cnt;
     186             :     }
     187           0 :     if ( found_cnt==0 )
     188           0 : return( copy(src));
     189             : 
     190           0 :     rpt = ret = malloc(strlen(src)+found_cnt*(strlen(rpl)-flen)+1);
     191           0 :     for ( pt=src; *pt; ) {
     192           0 :         while ( isspace(*pt))
     193           0 :             *rpt++ = *pt++;
     194           0 :         if ( *pt=='\0' )
     195           0 :     break;
     196           0 :         for ( start=pt; !isspace(*pt) && *pt!='\0'; ++pt );
     197           0 :         if ( pt-start==flen && strncmp(find,start,flen)==0 ) {
     198           0 :             strcpy(rpt,rpl);
     199           0 :             rpt += strlen(rpt);
     200             :         } else {
     201           0 :             strncpy(rpt,start,pt-start);
     202           0 :             rpt += (pt-start);
     203             :         }
     204             :     }
     205           0 :     *rpt = '\0';
     206           0 : return( ret );
     207             : }
     208             : 
     209           0 : static char *classnumbers(int cnt,uint16 *classes, struct matrix_data *classnames, int rows, int cols) {
     210             :     char buf[20];
     211             :     int i, len;
     212             :     char *pt, *ret;
     213             : 
     214           0 :     len = 0;
     215           0 :     for ( i=0; i<cnt; ++i ) {
     216           0 :         if ( classnames[cols*classes[i]+0].u.md_str==NULL ) {
     217           0 :             sprintf( buf, "%d ", classes[i]);
     218           0 :             len += strlen(buf);
     219             :         } else {
     220           0 :             len += strlen(classnames[cols*classes[i]+0].u.md_str)+1;
     221             :         }
     222             :     }
     223           0 :     ret = pt = malloc(len+3);
     224           0 :     *pt = '\0';         /* In case it is empty */
     225             : 
     226           0 :     for ( i=0; i<cnt; ++i ) {
     227           0 :         if ( classnames[cols*classes[i]+0].u.md_str==NULL ) {
     228           0 :             sprintf( pt, "%d ", classes[i]);
     229           0 :             pt += strlen(pt);
     230             :         } else {
     231           0 :             strcpy(pt, classnames[cols*classes[i]+0].u.md_str);
     232           0 :             pt += strlen(pt);
     233           0 :             *pt++ = ' ';
     234             :         }
     235             :     }
     236           0 :     if ( pt>ret && pt[-1]==' ' )
     237           0 :         pt[-1] = '\0';
     238           0 : return( ret );
     239             : }
     240             : 
     241           0 : static char *rclassnumbers(int cnt,uint16 *classes, struct matrix_data *classnames, int rows, int cols) {
     242             :     char buf[20];
     243             :     int i, len;
     244             :     char *pt, *ret;
     245             : 
     246           0 :     len = 0;
     247           0 :     for ( i=0; i<cnt; ++i ) {
     248           0 :         if ( classnames[cols*classes[i]+0].u.md_str==NULL ) {
     249           0 :             sprintf( buf, "%d ", classes[i]);
     250           0 :             len += strlen(buf);
     251             :         } else {
     252           0 :             len += strlen(classnames[cols*classes[i]+0].u.md_str)+1;
     253             :         }
     254             :     }
     255           0 :     ret = pt = malloc(len+3);
     256           0 :     *pt = '\0';
     257           0 :     for ( i=cnt-1; i>=0; --i ) {
     258           0 :         if ( classnames[cols*classes[i]+0].u.md_str==NULL ) {
     259           0 :             sprintf( pt, "%d ", classes[i]);
     260           0 :             pt += strlen(pt);
     261             :         } else {
     262           0 :             strcpy(pt, classnames[cols*classes[i]+0].u.md_str);
     263           0 :             pt += strlen(pt);
     264           0 :             *pt++ = ' ';
     265             :         }
     266             :     }
     267           0 :     if ( pt>ret && pt[-1]==' ' )
     268           0 :         pt[-1] = '\0';
     269           0 : return( ret );
     270             : }
     271             : 
     272           0 : static int CCD_GlyphNameCnt(const char *pt) {
     273           0 :     int cnt = 0;
     274             : 
     275           0 :     while ( *pt ) {
     276           0 :         while ( isspace( *pt )) ++pt;
     277           0 :         if ( *pt=='\0' )
     278           0 : return( cnt );
     279           0 :         ++cnt;
     280           0 :         while ( !isspace(*pt) && *pt!='\0' ) ++pt;
     281             :     }
     282           0 : return( cnt );
     283             : }
     284             : 
     285           0 : static int seqlookuplen(struct fpst_rule *r) {
     286           0 :     int i, len=0;
     287             :     char buf[20];
     288             : 
     289           0 :     len += 4;           /* for the arrow, takes 3 bytes in utf8 */
     290           0 :     for ( i=0; i<r->lookup_cnt; ++i ) {
     291           0 :         sprintf( buf," %d \"\",", r->lookups[i].seq );
     292           0 :         len += strlen(buf) + strlen( r->lookups[i].lookup->lookup_name );
     293             :     }
     294           0 : return( len );
     295             : }
     296             : 
     297           0 : static char *addseqlookups(char *pt, struct fpst_rule *r) {
     298             :     int i;
     299             : 
     300           0 :     pt = utf8_idpb(pt, 0x21d2,0);
     301           0 :     for ( i=0; i<r->lookup_cnt; ++i ) {
     302           0 :         sprintf( pt," %d <%s>,", r->lookups[i].seq, r->lookups[i].lookup->lookup_name);
     303           0 :         pt += strlen(pt);
     304             :     }
     305           0 :     if ( pt[-1]==',' ) --pt;
     306           0 :     *pt = '\0';
     307           0 : return( pt );
     308             : }
     309             : 
     310           0 : static void parseseqlookups(SplineFont *sf, const char *solooks, struct fpst_rule *r) {
     311             :     int cnt;
     312             :     const char *pt;
     313             : 
     314           0 :     for ( pt = solooks, cnt=0; *pt!='\0'; ) {
     315           0 :         ++cnt;
     316           0 :         while ( *pt!='<' && *pt!='\0' ) ++pt;
     317           0 :         if ( *pt=='<' ) {
     318           0 :             ++pt;
     319           0 :             while ( *pt!='>' && *pt!='\0' ) ++pt;
     320           0 :             if ( *pt=='>' ) ++pt;
     321             :         }
     322           0 :         if ( *pt==',' ) ++pt;
     323             :     }
     324           0 :     r->lookup_cnt = cnt;
     325           0 :     r->lookups = calloc(cnt,sizeof(struct seqlookup));
     326           0 :     cnt = 0;
     327           0 :     pt = solooks;
     328             :     for (;;) {
     329             :         char *end;
     330           0 :         r->lookups[cnt].seq = strtol(pt,&end,10);
     331           0 :         for ( pt = end+1; isspace( *pt ); ++pt );
     332           0 :         if ( *pt=='<' ) {
     333             :             const char *eoname; char *temp;
     334           0 :             ++pt;
     335           0 :             for ( eoname = pt; *eoname!='\0' && *eoname!='>'; ++eoname );
     336           0 :             temp = copyn(pt,eoname-pt);
     337           0 :             r->lookups[cnt].lookup = SFFindLookup(sf,temp);
     338           0 :             if ( r->lookups[cnt].lookup==NULL )
     339           0 :                 IError("No lookup in parseseqlookups");
     340           0 :             free(temp);
     341           0 :             pt = eoname;
     342           0 :             if ( *pt=='>' ) ++pt;
     343             :         } else
     344           0 :             IError("No lookup in parseseqlookups");
     345           0 :         ++cnt;
     346           0 :         if ( *pt!=',' )
     347           0 :     break;
     348           0 :         ++pt;
     349           0 :     }
     350           0 : }
     351             : 
     352           0 : static char *gruleitem(struct fpst_rule *r) {
     353             :     char *ret, *pt;
     354             :     int len;
     355             : 
     356           0 :     len = (r->u.glyph.back==NULL ? 0 : strlen(r->u.glyph.back)) +
     357           0 :             strlen(r->u.glyph.names) +
     358           0 :             (r->u.glyph.fore==0 ? 0 : strlen(r->u.glyph.fore)) +
     359           0 :             seqlookuplen(r);
     360             : 
     361           0 :     ret = pt = malloc(len+8);
     362           0 :     if ( r->u.glyph.back!=NULL && *r->u.glyph.back!='\0' ) {
     363           0 :         char *temp = reversenames(r->u.glyph.back);
     364           0 :         strcpy(pt,temp);
     365           0 :         pt += strlen(temp);
     366           0 :         free(temp);
     367           0 :         *pt++ = ' ';
     368             :     }
     369           0 :     *pt++ = '|';
     370           0 :     *pt++ = ' ';
     371           0 :     strcpy(pt,r->u.glyph.names);
     372           0 :     pt += strlen(r->u.glyph.names);
     373           0 :     *pt++ = ' ';
     374           0 :     *pt++ = '|';
     375           0 :     *pt++ = ' ';
     376           0 :     if ( r->u.glyph.fore!=NULL  && *r->u.glyph.fore!='\0' ) {
     377           0 :         strcpy(pt,r->u.glyph.fore);
     378           0 :         pt += strlen(r->u.glyph.fore);
     379           0 :         *pt++ = ' ';
     380             :     }
     381           0 :     pt = addseqlookups(pt, r);
     382           0 : return( ret );
     383             : }
     384             : 
     385           0 : static void gruleitem2rule(SplineFont *sf, const char *ruletext,struct fpst_rule *r) {
     386             :     const char *pt, *pt2;
     387             :     char *temp, *freeme;
     388             :     int ch;
     389             : 
     390           0 :     if ( ruletext==NULL )
     391           0 : return;
     392           0 :     for ( pt=ruletext; *pt!='\0' && *pt!='|'; ++pt );
     393           0 :     if ( *pt=='\0' )
     394           0 : return;
     395           0 :     if ( pt>ruletext ) {
     396           0 :         temp = GlyphNameListDeUnicode(freeme = copyn(ruletext,pt-1-ruletext));
     397           0 :         r->u.glyph.back = reversenames(temp);
     398           0 :         free(temp); free(freeme);
     399             :     }
     400           0 :     ruletext = pt+2;
     401           0 :     for ( pt=ruletext; *pt!='\0' && *pt!='|'; ++pt );
     402           0 :     if ( *pt=='\0' )
     403           0 : return;
     404           0 :     r->u.glyph.names = GlyphNameListDeUnicode(freeme = copyn(ruletext,pt-1-ruletext));
     405           0 :     free(freeme);
     406           0 :     ruletext = pt+2;
     407           0 :     for ( pt2=ruletext; (ch=utf8_ildb((const char **) &pt2))!='\0' && ch!=0x21d2; );
     408           0 :     if ( ch=='\0' )
     409           0 : return;
     410           0 :     if ( pt2!=ruletext ) {
     411           0 :         r->u.glyph.fore = GlyphNameListDeUnicode(freeme = copyn(ruletext,pt2-3-ruletext));
     412           0 :         free(freeme);
     413             :     }
     414           0 :     parseseqlookups(sf,pt2+2,r);
     415             : }
     416             : 
     417           0 : static char *classruleitem(struct fpst_rule *r,struct matrix_data **classes, int clen[3], int cols) {
     418             :     char *ret, *pt;
     419             :     int len, i, k;
     420             :     char buf[20];
     421             : 
     422           0 :     len = 0;
     423           0 :     for ( i=0; i<3; ++i ) {
     424           0 :         for ( k=0; k<(&r->u.class.ncnt)[i]; ++k ) {
     425           0 :             int c = (&r->u.class.nclasses)[i][k];
     426           0 :             if ( classes[i][cols*c+0].u.md_str!=NULL && *classes[i][cols*c+0].u.md_str!='\0' )
     427           0 :                 len += strlen(classes[i][cols*c+0].u.md_str)+1;
     428             :             else {
     429           0 :                 sprintf( buf, "%d ", c);
     430           0 :                 len += strlen(buf);
     431             :             }
     432             :         }
     433             :     }
     434             : 
     435           0 :     ret = pt = malloc((len+8+seqlookuplen(r)) * sizeof(unichar_t));
     436           0 :     for ( k=r->u.class.bcnt-1; k>=0; --k ) {
     437           0 :         int c = r->u.class.bclasses[k];
     438           0 :         if ( classes[1][cols*c+0].u.md_str!=NULL && *classes[1][cols*c+0].u.md_str!='\0' ) {
     439           0 :             strcpy(pt,classes[1][cols*c+0].u.md_str);
     440           0 :             pt += strlen( pt );
     441           0 :             *pt++ = ' ';
     442             :         } else {
     443           0 :             sprintf( pt, "%d ", c);
     444           0 :             pt += strlen(pt);
     445             :         }
     446             :     }
     447           0 :     *pt++ = '|';
     448           0 :     for ( k=0; k<r->u.class.ncnt; ++k ) {
     449           0 :         int c = r->u.class.nclasses[k];
     450           0 :         if ( classes[0][cols*c+0].u.md_str!=NULL && *classes[0][cols*c+0].u.md_str!='\0' ) {
     451           0 :             strcpy(pt,classes[0][cols*c+0].u.md_str);
     452           0 :             pt += strlen( pt );
     453           0 :             *pt++ = ' ';
     454             :         } else {
     455           0 :             sprintf( pt, "%d ", c);
     456           0 :             pt += strlen(pt);
     457             :         }
     458             :     }
     459           0 :     if ( pt[-1]==' ' ) --pt;
     460           0 :     *pt++ = '|';
     461           0 :     for ( k=0; k<r->u.class.fcnt; ++k ) {
     462           0 :         int c = r->u.class.fclasses[k];
     463           0 :         if ( classes[2][cols*c+0].u.md_str!=NULL && *classes[2][cols*c+0].u.md_str!='\0' ) {
     464           0 :             strcpy(pt,classes[2][cols*c+0].u.md_str);
     465           0 :             pt += strlen( pt );
     466           0 :             *pt++ = ' ';
     467             :         } else {
     468           0 :             sprintf( pt, "%d ", c);
     469           0 :             pt += strlen(pt);
     470             :         }
     471             :     }
     472             : 
     473           0 :     *pt++ = ' ';
     474           0 :     pt = addseqlookups(pt, r);
     475           0 : return( ret );
     476             : }
     477             : 
     478           0 : static void classruleitem2rule(SplineFont *sf,const char *ruletext,struct fpst_rule *r,
     479             :         struct matrix_data **classes, int clen[3], int cols) {
     480             :     const char *pt, *start, *nstart; char *end;
     481             :     int len, i, ch, k;
     482             : 
     483           0 :     memset(r,0,sizeof(*r));
     484             : 
     485           0 :     len = 0; i=1;
     486           0 :     for ( pt=ruletext; *pt; ) {
     487           0 :         ch = utf8_ildb((const char **) &pt);
     488           0 :         while ( ch!='|' && ch!=0x21d2 && ch!='\0' ) {
     489           0 :             while ( isspace(ch))
     490           0 :                 ch = utf8_ildb((const char **) &pt);
     491           0 :             if ( ch=='|' || ch== 0x21d2 || ch=='\0' )
     492             :         break;
     493           0 :             ++len;
     494           0 :             while ( !isspace(ch) && ch!='|' && ch!=0x21d2 && ch!='\0' )
     495           0 :                 ch = utf8_ildb((const char **) &pt);
     496             :         }
     497           0 :         (&r->u.class.ncnt)[i] = len;
     498           0 :         (&r->u.class.nclasses)[i] = malloc(len*sizeof(uint16));
     499           0 :         len = 0;
     500           0 :         if ( ch=='\0' || ch==0x21d2 )
     501             :     break;
     502           0 :         if ( ch=='|' ) {
     503           0 :             if ( i==1 ) i=0;
     504           0 :             else if ( i==0 ) i=2;
     505             :         }
     506             :     }
     507           0 :     len = 0; i=1;
     508           0 :     for ( pt=ruletext; *pt; ) {
     509           0 :         start = pt;
     510           0 :         ch = utf8_ildb((const char **) &pt);
     511           0 :         while ( ch!='|' && ch!=0x21d2 && ch!='\0' ) {
     512           0 :             while ( isspace(ch)) {
     513           0 :                 start = pt;
     514           0 :                 ch = utf8_ildb((const char **) &pt);
     515             :             }
     516           0 :             if ( ch=='|' || ch== 0x21d2 || ch=='\0' )
     517             :         break;
     518           0 :             nstart = start;
     519           0 :             while ( !isspace(ch) && ch!='|' && ch!=0x21d2 && ch!='\0' ) {
     520           0 :                 nstart = pt;
     521           0 :                 ch = utf8_ildb((const char **) &pt);
     522             :             }
     523           0 :             (&r->u.class.nclasses)[i][len] = strtol(start,&end,10);
     524           0 :             if ( end<nstart ) {              /* Not a number, must be a class name */
     525           0 :                 for ( k=0; k<clen[i]; ++k ) {
     526           0 :                     if ( classes[i][cols*k+0].u.md_str==NULL )
     527           0 :                 continue;
     528           0 :                     if ( strlen(classes[i][cols*k+0].u.md_str)==nstart-start &&
     529           0 :                             strncmp(classes[i][cols*k+0].u.md_str,start,nstart-start)==0 ) {
     530           0 :                         (&r->u.class.nclasses)[i][len] = k;
     531           0 :                 break;
     532             :                     }
     533             :                 }
     534             :             }
     535           0 :             start = nstart;
     536           0 :             ++len;
     537             :         }
     538           0 :         len = 0;
     539           0 :         if ( ch=='\0' || ch==0x21d2 )
     540             :     break;
     541           0 :         if ( ch=='|' ) {
     542           0 :             if ( i==1 ) i=0;
     543           0 :             else if ( i==0 ) i=2;
     544             :         }
     545             :     }
     546             :     /* reverse the backtrack */
     547           0 :     for ( i=0; i<r->u.class.bcnt/2; ++i ) {
     548           0 :         int temp = r->u.class.bclasses[i];
     549           0 :         r->u.class.bclasses[i] = r->u.class.bclasses[r->u.class.bcnt-1-i];
     550           0 :         r->u.class.bclasses[r->u.class.bcnt-1-i] = temp;
     551             :     }
     552             : 
     553           0 :     if ( ch=='\0' || *pt=='\0' )
     554           0 : return;
     555           0 :     parseseqlookups(sf,pt,r);
     556             : }
     557             : 
     558           0 : static void CCD_ParseLookupList(SplineFont *sf, struct fpst_rule *r,GGadget *list) {
     559             :     int len, i;
     560           0 :     struct matrix_data *classes = GMatrixEditGet(list,&len);
     561             : 
     562           0 :     r->lookup_cnt = len;
     563           0 :     r->lookups = malloc(len*sizeof(struct seqlookup));
     564           0 :     for ( i=0; i<len; ++i ) {
     565           0 :         r->lookups[i].seq = classes[2*i+1].u.md_ival;
     566           0 :         r->lookups[i].lookup = (OTLookup *) classes[2*i+0].u.md_ival;
     567             :     }
     568           0 : }
     569             : 
     570           0 : static void CCD_EnableNextPrev(struct contextchaindlg *ccd) {
     571             :     /* Cancel is always enabled, Not so for OK or Next or Prev */
     572           0 :     switch ( ccd->aw ) {
     573             :       case aw_formats:
     574           0 :         GGadgetSetEnabled(GWidgetGetControl(ccd->gw,CID_Prev),false);
     575           0 :         GGadgetSetEnabled(GWidgetGetControl(ccd->gw,CID_Next),true);
     576           0 :         GGadgetSetEnabled(GWidgetGetControl(ccd->gw,CID_OK),false);
     577           0 :       break;
     578             :       case aw_glyphs:
     579             :       case aw_classnumber:
     580           0 :         GGadgetSetEnabled(GWidgetGetControl(ccd->gw,CID_Prev),true);
     581           0 :         GGadgetSetEnabled(GWidgetGetControl(ccd->gw,CID_Next),true);
     582           0 :         GGadgetSetEnabled(GWidgetGetControl(ccd->gw,CID_OK),false);
     583           0 :       break;
     584             :       case aw_coverage:
     585             :       case aw_grules:
     586             :       case aw_classrules:
     587           0 :         GGadgetSetEnabled(GWidgetGetControl(ccd->gw,CID_Prev),ccd->fpst->format!=pst_reversecoverage);
     588           0 :         GGadgetSetEnabled(GWidgetGetControl(ccd->gw,CID_Next),false);
     589           0 :         GGadgetSetEnabled(GWidgetGetControl(ccd->gw,CID_OK),true);
     590           0 :       break;
     591             :       case aw_glyphs_simple:
     592             :       case aw_classes_simple:
     593             :       case aw_coverage_simple:
     594           0 :         GGadgetSetEnabled(GWidgetGetControl(ccd->gw,CID_Prev),ccd->fpst->type!=pst_reversesub);
     595           0 :         GGadgetSetEnabled(GWidgetGetControl(ccd->gw,CID_Next),false);
     596           0 :         GGadgetSetEnabled(GWidgetGetControl(ccd->gw,CID_OK),true);
     597           0 :       break;
     598             :       default:
     599           0 :         IError("Can't get here");
     600           0 :       break;
     601             :     }
     602           0 : }
     603             : 
     604           0 : static int CCD_ReasonableClassNum(const unichar_t *umatch,GGadget *list,
     605             :         struct fpst_rule *r, int which ) {
     606             :     int cols, len;
     607             :     struct matrix_data *classes;
     608           0 :     char *match = u2utf8_copy(umatch);
     609             :     char *pt, *start, *end;
     610             :     int doit;
     611             :     int any,val;
     612             : 
     613           0 :     cols = GMatrixEditGetColCnt(list);
     614           0 :     classes = GMatrixEditGet(list,&len);
     615             : 
     616           0 :     for ( doit = 0; doit<2; ++doit ) {
     617           0 :         any = 0;
     618           0 :         for ( pt=match;; ) {
     619           0 :             while ( *pt==' ' ) ++pt;
     620           0 :             if ( *pt=='\0' )
     621           0 :         break;
     622           0 :             for ( start=pt; *pt!=' ' && *pt!='\0'; ++pt );
     623           0 :             val = strtol(start,&end,10);
     624           0 :             if ( *end!='\0' ) {
     625           0 :                 for ( val=len-1; val>=0; --val )
     626           0 :                     if ( classes[cols*val+0].u.md_str!=NULL &&
     627           0 :                             strlen(classes[cols*val+0].u.md_str)==pt-start &&
     628           0 :                             strncasecmp(start,classes[cols*val+0].u.md_str,pt-start)==0 )
     629           0 :                 break;
     630             :             }
     631           0 :             if ( val<0 || val>=len ) {
     632           0 :                 ff_post_error(_("Bad Class"),_("%.*s is not a valid class name (or number)"), pt-start, start);
     633           0 : return( false );
     634             :             }
     635           0 :             if ( doit )
     636           0 :                 (&r->u.class.nclasses)[which][any] = val;
     637           0 :             ++any;
     638           0 :         }
     639           0 :         if ( !doit ) {
     640           0 :             (&r->u.class.ncnt)[which] = any;
     641           0 :             (&r->u.class.nclasses)[which] = malloc(any*sizeof(uint16));
     642             :         }
     643             :     }
     644           0 : return( true );
     645             : }
     646             : 
     647           0 : static int ClassNamePrep(struct contextchaindlg *ccd,struct matrix_data **classes,int clen[3]) {
     648             :     int i;
     649             : 
     650           0 :     for ( i=0; i<3; ++i ) {
     651           0 :         if ( i==0 || !GGadgetIsChecked(GWidgetGetControl(ccd->gw,CID_SameAsClasses+i*20)) )
     652           0 :             classes[i] = GMatrixEditGet(GWidgetGetControl(ccd->gw,CID_GList+300+i*20),&clen[i]);
     653             :         else
     654           0 :             classes[i] = GMatrixEditGet(GWidgetGetControl(ccd->gw,CID_GList+300),&clen[i]);
     655             :     }
     656           0 : return( GMatrixEditGetColCnt(GWidgetGetControl(ccd->gw,CID_GList+300+0*20)) );
     657             : }
     658             : 
     659           0 : static void CCD_FinishRule(struct contextchaindlg *ccd) {
     660             :     struct fpst_rule dummy;
     661             :     GGadget *list;
     662             :     int i,tot;
     663             :     char *buts[3];
     664           0 :     buts[0] = _("_Yes"); buts[1] = _("_No"); buts[2] = NULL;
     665             :     struct matrix_data *md;
     666             :     int len;
     667             :     int clen[3], ccols;
     668             :     struct matrix_data *classes[3];
     669             : 
     670           0 :     if ( ccd->aw==aw_classnumber ) {
     671             :         char *ret;
     672           0 :         memset(&dummy,0,sizeof(dummy));
     673           0 :         CCD_ParseLookupList(ccd->sf,&dummy,GWidgetGetControl(ccd->gw,CID_LookupList+500));
     674           0 :         if ( dummy.lookup_cnt==0 ) {
     675           0 :             int ans = gwwv_ask(_("No Sequence/Lookups"),
     676             :                     (const char **) buts,0,1,
     677           0 :                     _("There are no entries in the Sequence/Lookup List, was this intentional?"));
     678           0 :             if ( ans==1 )
     679           0 : return;
     680             :         }
     681           0 :         ccols = ClassNamePrep(ccd,classes,clen);
     682           0 :         if ( !CCD_ReasonableClassNum(
     683           0 :                 _GGadgetGetTitle(GWidgetGetControl(ccd->gw,CID_ClassNumbers)),
     684           0 :                     GWidgetGetControl(ccd->gw,CID_ClassList),
     685           0 :                     &dummy,0) ||
     686           0 :              !CCD_ReasonableClassNum(
     687           0 :                 _GGadgetGetTitle(GWidgetGetControl(ccd->gw,CID_ClassNumbers+20)),
     688           0 :                     GWidgetGetControl(ccd->gw,CID_ClassList+20),
     689           0 :                     &dummy,1) ||
     690           0 :              !CCD_ReasonableClassNum(
     691           0 :                 _GGadgetGetTitle(GWidgetGetControl(ccd->gw,CID_ClassNumbers+40)),
     692           0 :                     GWidgetGetControl(ccd->gw,CID_ClassList+40),
     693             :                     &dummy,2)) {
     694           0 :             FPSTRuleContentsFree(&dummy,pst_class);
     695           0 : return;
     696             :         }
     697             :         /* reverse the backtrack */
     698           0 :         for ( i=0; i<dummy.u.class.bcnt/2; ++i ) {
     699           0 :             int temp = dummy.u.class.bclasses[i];
     700           0 :             dummy.u.class.bclasses[i] = dummy.u.class.bclasses[dummy.u.class.bcnt-1-i];
     701           0 :             dummy.u.class.bclasses[dummy.u.class.bcnt-1-i] = temp;
     702             :         }
     703           0 :         for ( i=0; i<dummy.lookup_cnt; ++i ) {
     704           0 :             if ( dummy.lookups[i].seq >= dummy.u.class.ncnt ) {
     705           0 :                 ff_post_error(_("Bad Sequence/Lookup List"),_("Sequence number out of bounds, must be less than %d (number of classes in list above)"), dummy.u.class.ncnt );
     706           0 : return;
     707             :             }
     708             :         }
     709           0 :         ret = classruleitem(&dummy,classes,clen,ccols);
     710           0 :         FPSTRuleContentsFree(&dummy,pst_class);
     711           0 :         list = GWidgetGetControl(ccd->gw,CID_GList+200);
     712           0 :         md = GMatrixEditGet(list,&len);
     713           0 :         free(md[ccd->row_being_edited].u.md_str);
     714           0 :         md[ccd->row_being_edited].u.md_str = ret;
     715           0 :         GMatrixEditSet(list,md,len,false);
     716           0 :         ccd->aw = aw_classrules;
     717           0 :         GDrawSetVisible(ccd->classnumber,false);
     718           0 :         GDrawSetVisible(ccd->classrules,true);
     719           0 :     } else if ( ccd->aw==aw_glyphs ) {                       /* It's from glyph list */
     720             :         char *ret, *temp, *freeme;
     721             : 
     722           0 :         memset(&dummy,0,sizeof(dummy));
     723           0 :         CCD_ParseLookupList(ccd->sf,&dummy,GWidgetGetControl(ccd->gw,CID_LookupList));
     724           0 :         if ( dummy.lookup_cnt==0 ) {
     725           0 :             int ans = gwwv_ask(_("No Sequence/Lookups"),
     726             :                     (const char **) buts,0,1,
     727           0 :                     _("There are no entries in the Sequence/Lookup List, was this intentional?"));
     728           0 :             if ( ans==1 )
     729           0 : return;
     730             :         }
     731           0 :         temp = GGadgetGetTitle8(GWidgetGetControl(ccd->gw,CID_GlyphList));
     732           0 :         dummy.u.glyph.names = GlyphNameListDeUnicode(temp);
     733           0 :         free(temp);
     734           0 :         tot = CCD_GlyphNameCnt( temp = GGadgetGetTitle8(GWidgetGetControl(ccd->gw,CID_GlyphList)));
     735           0 :         free(temp);
     736           0 :         for ( i=0; i<dummy.lookup_cnt; ++i ) {
     737           0 :             if ( dummy.lookups[i].seq >= tot ) {
     738           0 :                 ff_post_error(_("Bad Sequence/Lookup List"),_("Sequence number out of bounds, must be less than %d (number of glyphs, classes or coverage tables)"),  tot );
     739           0 : return;
     740             :             }
     741             :         }
     742           0 :         temp = GGadgetGetTitle8(GWidgetGetControl(ccd->gw,CID_GlyphList+20));
     743           0 :         freeme = GlyphNameListDeUnicode(temp);
     744           0 :         dummy.u.glyph.back = reversenames(freeme);
     745           0 :         free(temp); free(freeme);
     746           0 :         temp = GGadgetGetTitle8(GWidgetGetControl(ccd->gw,CID_GlyphList+40));
     747           0 :         dummy.u.glyph.fore = GlyphNameListDeUnicode(temp);
     748           0 :         free(temp);
     749           0 :         ret = gruleitem(&dummy);
     750           0 :         FPSTRuleContentsFree(&dummy,pst_glyphs);
     751           0 :         list = GWidgetGetControl(ccd->gw,CID_GList+0);
     752           0 :         md = GMatrixEditGet(list,&len);
     753           0 :         free(md[ccd->row_being_edited].u.md_str);
     754           0 :         md[ccd->row_being_edited].u.md_str = ret;
     755           0 :         GMatrixEditSet(list,md,len,false);
     756           0 :         ccd->aw = aw_grules;
     757           0 :         GDrawSetVisible(ccd->glyphs,false);
     758           0 :         GDrawSetVisible(ccd->grules,true);
     759             :     } else {
     760           0 :         IError("Bad format in CCD_FinishRule");
     761             :     }
     762             : }
     763             : 
     764           0 : static int isEverythingElse(char *text) {
     765             :     /* GT: The string "{Everything Else}" is used in the context of a list */
     766             :     /* GT: of classes (a set of kerning classes) where class 0 designates the */
     767             :     /* GT: default class containing all glyphs not specified in the other classes */
     768           0 :     int ret = strcmp(text,_("{Everything Else}"));
     769           0 : return( ret==0 );
     770             : }
     771             : 
     772           0 : static char *CCD_PickGlyphsForClass(GGadget *g,int r, int c) {
     773           0 :     struct contextchaindlg *ccd = GDrawGetUserData(GGadgetGetWindow(g));
     774           0 :     int rows, cols = GMatrixEditGetColCnt(g);
     775           0 :     struct matrix_data *classes = _GMatrixEditGet(g,&rows);
     776           0 :     char *new = GlyphSetFromSelection(ccd->sf,ccd->layer,classes[r*cols+c].u.md_str);
     777           0 : return( new );
     778             : }
     779             : 
     780           0 : static void _CCD_FromSelection(struct contextchaindlg *ccd,int cid ) {
     781           0 :     char *curval = GGadgetGetTitle8(GWidgetGetControl(ccd->gw,cid));
     782           0 :     char *new = GlyphSetFromSelection(ccd->sf,ccd->layer,curval);
     783             : 
     784           0 :     free(curval);
     785           0 :     if ( new==NULL )
     786           0 : return;
     787           0 :     GGadgetSetTitle8(GWidgetGetControl(ccd->gw,cid),new);
     788           0 :     free(new);
     789             : }
     790             : 
     791           0 : static int CCD_FromSelection(GGadget *g, GEvent *e) {
     792           0 :     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
     793           0 :         struct contextchaindlg *ccd = GDrawGetUserData(GGadgetGetWindow(g));
     794           0 :         int cid = (intpt) GGadgetGetUserData(g);
     795             : 
     796           0 :         _CCD_FromSelection(ccd,cid);
     797             :     }
     798           0 : return( true );
     799             : }
     800             : 
     801           0 : static struct matrix_data *MD2MD(struct matrix_data *md,int len) {
     802           0 :     struct matrix_data *newmd = calloc(2*len,sizeof(struct matrix_data));
     803             :     int i;
     804             : 
     805           0 :     for ( i=0; i<len; ++i ) {
     806           0 :         newmd[2*i+0].u.md_str = copy(md[3*i+0].u.md_str);
     807           0 :         newmd[2*i+1].u.md_str = copy(md[3*i+1].u.md_str);
     808             :     }
     809           0 : return( newmd );
     810             : }
     811             : 
     812           0 : static void CCD_NewGlyphRule(GGadget *glyphrules,int r,int c) {
     813           0 :     struct contextchaindlg *ccd = GDrawGetUserData(GGadgetGetWindow(glyphrules));
     814             :     int rows;
     815           0 :     struct matrix_data *rulelist = GMatrixEditGet(glyphrules,&rows);
     816             :     struct fpst_rule dummy;
     817           0 :     GGadget *lookuplist = GWidgetGetControl(ccd->glyphs,CID_LookupList+0);
     818             :     struct matrix_data *md;
     819             :     char *temp2;
     820             :     int j;
     821             : 
     822           0 :     memset(&dummy,0,sizeof(dummy));
     823           0 :     gruleitem2rule(ccd->sf,rulelist[r].u.md_str,&dummy);
     824           0 :     GGadgetSetTitle8(GWidgetGetControl(ccd->gw,CID_GlyphList),dummy.u.glyph.names==NULL?"":dummy.u.glyph.names);
     825           0 :     GGadgetSetTitle8(GWidgetGetControl(ccd->gw,CID_GlyphList+20),(temp2 = reversenames(dummy.u.glyph.back))==NULL ? "" : temp2);
     826           0 :     free(temp2);
     827           0 :     GGadgetSetTitle8(GWidgetGetControl(ccd->gw,CID_GlyphList+40),dummy.u.glyph.fore!=NULL?dummy.u.glyph.fore:"");
     828             : 
     829           0 :     md = calloc(2*dummy.lookup_cnt,sizeof(struct matrix_data));
     830           0 :     for ( j=0; j<dummy.lookup_cnt; ++j ) {
     831           0 :         md[2*j+0].u.md_ival = (intpt) (void *) dummy.lookups[j].lookup;
     832           0 :         md[2*j+1].u.md_ival = (intpt) dummy.lookups[j].seq;
     833             :     }
     834           0 :     GMatrixEditSet(lookuplist,md,dummy.lookup_cnt,false);
     835           0 :     ccd->aw = aw_glyphs;
     836           0 :     ccd->row_being_edited = r;
     837           0 :     GDrawSetVisible(ccd->grules,false);
     838           0 :     GDrawSetVisible(ccd->glyphs,true);
     839           0 :     CCD_EnableNextPrev(ccd);
     840           0 : }
     841             : 
     842           0 : static char *_CCD_NewGlyphRule(GGadget *glyphrules,int r,int c) {
     843             :     int rows;
     844           0 :     struct matrix_data *rulelist = GMatrixEditGet(glyphrules,&rows);
     845           0 :     CCD_NewGlyphRule(glyphrules,r,c);
     846           0 : return( copy( rulelist[r].u.md_str ) );         /* We change the display to get the new value, but we must return something... */
     847             : }
     848             : 
     849           0 : static void CCD_NewClassRule(GGadget *classrules,int r,int c) {
     850           0 :     struct contextchaindlg *ccd = GDrawGetUserData(GGadgetGetWindow(classrules));
     851             :     int rows;
     852           0 :     struct matrix_data *rulelist = GMatrixEditGet(classrules,&rows);
     853             :     struct fpst_rule dummy;
     854           0 :     GGadget *lookuplist = GWidgetGetControl(ccd->classnumber,CID_LookupList+500);
     855             :     struct matrix_data *md, *classes[3];
     856             :     int len, clen[3], ccols;
     857             :     int i,j;
     858             :     char *temp;
     859             : 
     860           0 :     ccols = ClassNamePrep(ccd,classes,clen);
     861           0 :     memset(&dummy,0,sizeof(dummy));
     862           0 :     classruleitem2rule(ccd->sf,rulelist[r].u.md_str,&dummy,classes,clen,ccols);
     863           0 :     GGadgetSetTitle8(GWidgetGetControl(ccd->gw,CID_ClassNumbers),
     864           0 :             (temp=classnumbers(dummy.u.class.ncnt,dummy.u.class.nclasses,classes[0],clen[0],ccols)));
     865           0 :     free(temp);
     866           0 :     GGadgetSetTitle8(GWidgetGetControl(ccd->gw,CID_ClassNumbers+20),
     867           0 :             (temp=rclassnumbers(dummy.u.class.bcnt,dummy.u.class.bclasses,classes[1],clen[1],ccols)));
     868           0 :     free(temp);
     869           0 :     GGadgetSetTitle8(GWidgetGetControl(ccd->gw,CID_ClassNumbers+40),
     870           0 :             (temp=classnumbers(dummy.u.class.fcnt,dummy.u.class.fclasses,classes[2],clen[2],ccols)));
     871           0 :     free(temp);
     872             : 
     873           0 :     md = calloc(2*dummy.lookup_cnt,sizeof(struct matrix_data));
     874           0 :     for ( j=0; j<dummy.lookup_cnt; ++j ) {
     875           0 :         md[2*j+0].u.md_ival = (intpt) (void *) dummy.lookups[j].lookup;
     876           0 :         md[2*j+1].u.md_ival = (intpt) dummy.lookups[j].seq;
     877             :     }
     878           0 :     GMatrixEditSet(lookuplist,md,dummy.lookup_cnt,false);
     879           0 :     FPSTRuleContentsFree(&dummy,pst_class);
     880           0 :     GWidgetIndicateFocusGadget(GWidgetGetControl(ccd->gw,CID_ClassNumbers));
     881           0 :     for ( i=0; i<3; ++i ) {
     882           0 :         if ( i!=0 && GGadgetIsChecked(GWidgetGetControl(ccd->gw,CID_SameAsClasses+i*20)) )
     883           0 :             md = GMatrixEditGet(GWidgetGetControl(ccd->gw,CID_GList+300),&len);
     884             :         else
     885           0 :             md = GMatrixEditGet(GWidgetGetControl(ccd->gw,CID_GList+300+i*20),&len);
     886           0 :         GMatrixEditSet(GWidgetGetControl(ccd->gw,CID_ClassList+i*20),MD2MD(md,len),len,false);
     887             :     }
     888           0 :     ccd->aw = aw_classnumber;
     889           0 :     ccd->row_being_edited = r;
     890           0 :     GDrawSetVisible(ccd->classrules,false);
     891           0 :     GDrawSetVisible(ccd->classnumber,true);
     892           0 :     CCD_EnableNextPrev(ccd);
     893           0 : }
     894             : 
     895           0 : static char *_CCD_NewClassRule(GGadget *classrules,int r,int c) {
     896             :     int rows;
     897           0 :     struct matrix_data *rulelist = GMatrixEditGet(classrules,&rows);
     898           0 :     CCD_NewClassRule(classrules,r,c);
     899           0 : return( copy( rulelist[r].u.md_str ) );         /* We change the display to get the new value, but we must return something... */
     900             : }
     901             : 
     902           0 : static int CCD_SameAsClasses(GGadget *g, GEvent *e) {
     903           0 :     int ison = GGadgetIsChecked(g);
     904           0 :     int cid = GGadgetGetCid(g);
     905           0 :     struct contextchaindlg *ccd = GDrawGetUserData(GGadgetGetWindow(g));
     906             : 
     907           0 :     if ( cid < CID_SameAsClasses_S ) {
     908           0 :         int off = cid-CID_SameAsClasses;
     909           0 :         GGadgetSetEnabled(GWidgetGetControl(ccd->gw,CID_GList+300+off),!ison);
     910           0 : return( true );
     911             :     } else {
     912           0 :         int off = cid-CID_SameAsClasses_S;
     913           0 :         GGadgetSetEnabled(GWidgetGetControl(ccd->gw,CID_CList_Simple+off),!ison);
     914           0 : return( true );
     915             :     }
     916             : }
     917             : 
     918           0 : static void CCD_ClassSelected(GGadget *g, int r, int c) {
     919           0 :     struct contextchaindlg *ccd = GDrawGetUserData(GGadgetGetWindow(g));
     920           0 :     int off = GGadgetGetCid(g)-CID_ClassList;
     921           0 :     int rows, cols = GMatrixEditGetColCnt(g);
     922           0 :     struct matrix_data *classes = GMatrixEditGet(g,&rows);
     923           0 :     GGadget *tf = GWidgetGetControl(ccd->gw,CID_ClassNumbers+off);
     924             :     char buf[20];
     925             :     unichar_t ubuf[80];
     926             : 
     927           0 :     if ( r<0 || r>=rows )
     928           0 : return;
     929           0 :     if ( classes[cols*r+0].u.md_str == NULL || classes[cols*r+0].u.md_str[0]=='\0' ) {
     930           0 :         sprintf( buf, " %d ", r );
     931           0 :         uc_strcpy(ubuf,buf);
     932             :     } else {
     933           0 :         ubuf[0]=' ';
     934           0 :         utf82u_strncpy(ubuf+1,classes[cols*r+0].u.md_str,sizeof(ubuf)/sizeof(ubuf[0])-2 );
     935           0 :         ubuf[sizeof(ubuf)/sizeof(ubuf[0])-2] = '\0';
     936           0 :         uc_strcat(ubuf," ");
     937             :     }
     938           0 :     GTextFieldReplace(tf,ubuf);
     939           0 : return;
     940             : }
     941             : 
     942           0 : static void CCD_Close(struct contextchaindlg *ccd) {
     943           0 :     if ( ccd->isnew )
     944           0 :         GFI_FinishContextNew(ccd->gfi,ccd->fpst,false);
     945           0 :     ccd->done = true;
     946           0 : }
     947             : 
     948           0 : static char **CCD_ParseCoverageList(struct contextchaindlg *ccd,int cid,int *cnt) {
     949             :     int i;
     950             :     int _cnt;
     951           0 :     struct matrix_data *covers = GMatrixEditGet(GWidgetGetControl(ccd->gw,cid),&_cnt);
     952             :     char **ret;
     953             : 
     954           0 :     *cnt = _cnt;
     955           0 :     if ( _cnt==0 )
     956           0 : return( NULL );
     957           0 :     ret = malloc(*cnt*sizeof(char *));
     958           0 :     for ( i=0; i<_cnt; ++i )
     959           0 :         ret[i] = GlyphNameListDeUnicode(covers[i].u.md_str);
     960           0 : return( ret );
     961             : }
     962             : 
     963           0 : static void CoverageReverse(char **bcovers,int bcnt) {
     964             :     int i;
     965             :     char *temp;
     966             : 
     967           0 :     for ( i=0; i<bcnt/2; ++i ) {
     968           0 :         temp = bcovers[i];
     969           0 :         bcovers[i] = bcovers[bcnt-i-1];
     970           0 :         bcovers[bcnt-i-1] = temp;
     971             :     }
     972           0 : }
     973             : 
     974           0 : static void _CCD_Ok(struct contextchaindlg *ccd) {
     975           0 :     FPST *fpst = ccd->fpst, *dummyfpst;
     976             :     int len, i, k, had_class0, clen[3], ccols;
     977             :     struct matrix_data *old, *classes[3], *classes_simple;
     978             :     struct fpst_rule dummy;
     979             :     char *msg;
     980             :     int ans, cnt, cols, first, last, forward_start;
     981             :     int iswarning;
     982             :     char *temp;
     983             :     int has[3];
     984             :     char *buts[3];
     985             : 
     986           0 :     buts[0] = _("_Yes"); buts[1] = _("_No"); buts[2] = NULL;
     987             : 
     988           0 :     switch ( ccd->aw ) {
     989             :       case aw_grules: {
     990           0 :         old = GMatrixEditGet(GWidgetGetControl(ccd->gw,CID_GList),&len);
     991           0 :         if ( len==0 ) {
     992           0 :             ff_post_error(_("Missing rules"),_(" There must be at least one contextual rule"));
     993           0 : return;
     994             :         }
     995           0 :         FPSTRulesFree(fpst->rules,fpst->format,fpst->rule_cnt);
     996           0 :         fpst->format = pst_glyphs;
     997           0 :         fpst->rule_cnt = len;
     998           0 :         fpst->rules = calloc(len,sizeof(struct fpst_rule));
     999           0 :         for ( i=0; i<len; ++i )
    1000           0 :             gruleitem2rule(ccd->sf,old[i].u.md_str,&fpst->rules[i]);
    1001           0 :       } break;
    1002             :       case aw_classrules: {
    1003           0 :         old = GMatrixEditGet(GWidgetGetControl(ccd->gw,CID_GList+200),&len);
    1004           0 :         if ( len==0 ) {
    1005           0 :             ff_post_error(_("Missing rules"),_(" There must be at least one contextual rule"));
    1006           0 : return;
    1007             :         }
    1008           0 :         FPSTRulesFree(fpst->rules,fpst->format,fpst->rule_cnt);
    1009           0 :         fpst->format = pst_class;
    1010           0 :         fpst->rule_cnt = len;
    1011           0 :         fpst->rules = calloc(len,sizeof(struct fpst_rule));
    1012           0 :         fpst->nccnt = fpst->bccnt = fpst->fccnt = 0;
    1013           0 :         fpst->nclass = fpst->bclass = fpst->fclass = NULL;
    1014           0 :         has[1] = has[2] = false; has[0] = true;
    1015           0 :         ccols = ClassNamePrep(ccd,classes,clen);
    1016           0 :         for ( i=0; i<len; ++i ) {
    1017           0 :             classruleitem2rule(ccd->sf,old[i].u.md_str,&fpst->rules[i],classes,clen,ccols);
    1018           0 :             if ( fpst->rules[i].u.class.bcnt!=0 ) has[1] = true;
    1019           0 :             if ( fpst->rules[i].u.class.fcnt!=0 ) has[2] = true;
    1020             :         }
    1021           0 :         for ( i=0; i<3; ++i ) {
    1022           0 :             if ( i!=0 && !has[i] )
    1023           0 :         continue;
    1024           0 :             (&fpst->nccnt)[i] = clen[i];
    1025           0 :             (&fpst->nclass)[i] = malloc(clen[i]*sizeof(char*));
    1026           0 :             (&fpst->nclass)[i][0] = NULL;
    1027           0 :             had_class0 = i==0 && !isEverythingElse(classes[i][0].u.md_str);
    1028           0 :             for ( k=had_class0 ? 0 : 1 ; k<clen[i]; ++k )
    1029           0 :                 (&fpst->nclass)[i][k] = GlyphNameListDeUnicode(classes[i][ccols*k+1].u.md_str);
    1030           0 :             for ( k=0; k<clen[i]; ++k )
    1031           0 :                 (&fpst->nclassnames)[i][k] = copy(classes[i][ccols*k+0].u.md_str);
    1032             :         }
    1033           0 :       } break;
    1034             :       case aw_coverage:
    1035           0 :         old = GMatrixEditGet(GWidgetGetControl(ccd->gw,CID_GList+100),&len);
    1036           0 :         if ( len==0 ) {
    1037           0 :             ff_post_error(_("Bad Coverage Table"),_("There must be at least one match coverage table"));
    1038           0 : return;
    1039             :         }
    1040           0 :         if ( fpst->format==pst_reversecoverage ) {
    1041           0 :             if ( len!=1 ) {
    1042           0 :                 ff_post_error(_("Bad Coverage Table"),_("In a Reverse Chaining Substitution there must be exactly one coverage table to match"));
    1043           0 : return;
    1044             :             }
    1045           0 :             if ( CCD_GlyphNameCnt(old[0].u.md_str)!=CCD_GlyphNameCnt(
    1046           0 :                     temp=GGadgetGetTitle8(GWidgetGetControl(ccd->gw,CID_RplList+100))) ) {
    1047           0 :                 free(temp);
    1048           0 :                 ff_post_error(_("Replacement mismatch"),_("In a Reverse Chaining Substitution there must be exactly as many replacements as there are glyph names in the match coverage table"));
    1049           0 : return;
    1050             :             }
    1051           0 :             dummy.u.rcoverage.replacements = GlyphNameListDeUnicode(temp);
    1052           0 :             free(temp);
    1053             :         } else {
    1054           0 :             CCD_ParseLookupList(ccd->sf,&dummy,GWidgetGetControl(ccd->gw,CID_LookupList+100));
    1055           0 :             if ( dummy.lookup_cnt==0 ) {
    1056           0 :                 int ans = gwwv_ask(_("No Sequence/Lookups"),
    1057             :                         (const char **) buts,0,1,
    1058           0 :                         _("There are no entries in the Sequence/Lookup List, was this intentional?"));
    1059           0 :                 if ( ans==1 )
    1060           0 : return;
    1061             :             }
    1062             :         }
    1063           0 :         FPSTRulesFree(fpst->rules,fpst->format,fpst->rule_cnt);
    1064           0 :         fpst->format = fpst->type==pst_reversesub ? pst_reversecoverage : pst_coverage;
    1065           0 :         fpst->rule_cnt = 1;
    1066           0 :         fpst->rules = calloc(1,sizeof(struct fpst_rule));
    1067           0 :         fpst->rules[0].u.coverage.ncovers = CCD_ParseCoverageList(ccd,CID_GList+100,&fpst->rules[0].u.coverage.ncnt);
    1068           0 :         fpst->rules[0].u.coverage.bcovers = CCD_ParseCoverageList(ccd,CID_GList+100+20,&fpst->rules[0].u.coverage.bcnt);
    1069           0 :         CoverageReverse(fpst->rules[0].u.coverage.bcovers,fpst->rules[0].u.coverage.bcnt);
    1070           0 :         fpst->rules[0].u.coverage.fcovers = CCD_ParseCoverageList(ccd,CID_GList+100+40,&fpst->rules[0].u.coverage.fcnt);
    1071           0 :         if ( fpst->format==pst_reversecoverage )
    1072           0 :             fpst->rules[0].u.rcoverage.replacements = dummy.u.rcoverage.replacements;
    1073             :         else {
    1074           0 :             fpst->rules[0].lookup_cnt = dummy.lookup_cnt;
    1075           0 :             fpst->rules[0].lookups = dummy.lookups;
    1076           0 :             for ( i=0; i<dummy.lookup_cnt; ++i ) {
    1077           0 :                 if ( dummy.lookups[i].seq >= fpst->rules[0].u.coverage.ncnt ) {
    1078           0 :                     ff_post_error(_("Bad Sequence/Lookup List"),
    1079           0 :                             _("Sequence number out of bounds, must be less than %d (number of classes in list above)"),
    1080           0 :                             fpst->rules[0].u.coverage.ncnt );
    1081           0 : return;
    1082             :                 }
    1083             :             }
    1084             :         }
    1085           0 :       break;
    1086             :       case aw_classes_simple:
    1087             :       case aw_glyphs_simple: {
    1088           0 :         old = GMatrixEditGet(GWidgetGetControl(ccd->gw,ccd->aw==aw_glyphs_simple?CID_GList_Simple:CID_CList_Simple),&len);
    1089           0 :         if ( len==0 ) {
    1090           0 :             ff_post_error(_("Missing rules"),_(" There must be at least one contextual rule"));
    1091           0 : return;
    1092             :         }
    1093           0 :         dummyfpst = chunkalloc(sizeof(FPST));
    1094           0 :         *dummyfpst = *fpst;
    1095           0 :         dummyfpst->format = pst_glyphs;
    1096           0 :         if ( ccd->aw==aw_classes_simple ) {
    1097           0 :             dummyfpst->format = pst_class;
    1098           0 :             for ( i=0; i<3; ++i ) { int clen;
    1099           0 :                 if ( i==0 || !GGadgetIsChecked(GWidgetGetControl(ccd->gw,CID_SameAsClasses_S+i*20)) )
    1100           0 :                     classes_simple = GMatrixEditGet(GWidgetGetControl(ccd->gw,CID_MatchClasses+i*20),&clen);
    1101             :                 else    /* If SameAs the reparse the match classes_simple */
    1102           0 :                     classes_simple = GMatrixEditGet(GWidgetGetControl(ccd->gw,CID_MatchClasses),&clen);
    1103           0 :                 (&dummyfpst->nccnt)[i] = clen;
    1104           0 :                 if ( clen!=0 ) {
    1105           0 :                     (&dummyfpst->nclass)[i] = malloc(clen*sizeof(char*));
    1106           0 :                     (&dummyfpst->nclassnames)[i] = malloc(clen*sizeof(char*));
    1107           0 :                     (&dummyfpst->nclass)[i][0] = NULL;
    1108           0 :                     (&dummyfpst->nclassnames)[i][0] = NULL;
    1109           0 :                     had_class0 = i==0 && !isEverythingElse(classes_simple[3*0+1].u.md_str);
    1110           0 :                     if ( !had_class0 )
    1111           0 :                         (&dummyfpst->nclassnames)[i][0] = copy(classes_simple[3*0+0].u.md_str);
    1112           0 :                     for ( k=had_class0 ? 0 : 1 ; k<clen; ++k ) {
    1113           0 :                         (&dummyfpst->nclassnames)[i][k] = copy(classes_simple[3*k+0].u.md_str);
    1114           0 :                         (&dummyfpst->nclass)[i][k] = GlyphNameListDeUnicode(classes_simple[3*k+1].u.md_str);
    1115             :                     }
    1116             :                 }
    1117             :             }
    1118             :         } else {
    1119           0 :             dummyfpst->nccnt = dummyfpst->bccnt = dummyfpst->fccnt = 0;
    1120           0 :             dummyfpst->nclass = dummyfpst->bclass = dummyfpst->fclass = NULL;
    1121           0 :             dummyfpst->nclassnames = dummyfpst->bclassnames = dummyfpst->fclassnames = NULL;
    1122             :         }
    1123           0 :         dummyfpst->rule_cnt = len;
    1124           0 :         dummyfpst->rules = calloc(len,sizeof(struct fpst_rule));
    1125           0 :         for ( i=0; i<len; ++i ) {
    1126           0 :             char *temp = old[i].u.md_str;
    1127           0 :             if ( ccd->aw==aw_glyphs_simple )
    1128           0 :                 temp = GlyphNameListDeUnicode(temp);
    1129           0 :             msg = FPSTRule_From_Str(ccd->sf,dummyfpst,&dummyfpst->rules[i],temp,&iswarning);
    1130           0 :             if ( temp!=old[i].u.md_str )
    1131           0 :                 free(temp);
    1132           0 :             if ( msg!=NULL ) {
    1133           0 :                 if ( !iswarning ) {
    1134           0 :                     ff_post_error(_("Bad rule"), "%s", msg );
    1135           0 :                     free(msg);
    1136           0 :                     FPSTClassesFree(dummyfpst);
    1137           0 :                     FPSTRulesFree(dummyfpst->rules,dummyfpst->format,dummyfpst->rule_cnt);
    1138           0 :                     chunkfree(dummyfpst,sizeof(FPST));
    1139           0 : return;
    1140             :                 } else {
    1141           0 :                     ans = gwwv_ask(_("Warning"),
    1142             :                             (const char **) buts,0,1,
    1143           0 :                             _("%s\nProceed anyway?"), msg);
    1144           0 :                     free(msg);
    1145           0 :                     if ( ans==1 ) {
    1146           0 :                         FPSTClassesFree(dummyfpst);
    1147           0 :                         FPSTRulesFree(dummyfpst->rules,dummyfpst->format,dummyfpst->rule_cnt);
    1148           0 :                         chunkfree(dummyfpst,sizeof(FPST));
    1149           0 : return;
    1150             :                     }
    1151             :                 }
    1152             :             }
    1153             :         }
    1154           0 :         FPSTRulesFree(fpst->rules,fpst->format,fpst->rule_cnt);
    1155           0 :         fpst->format = dummyfpst->format;
    1156           0 :         fpst->rule_cnt = dummyfpst->rule_cnt;
    1157           0 :         fpst->rules = dummyfpst->rules;
    1158           0 :         if ( fpst->format==pst_class ) {
    1159           0 :             FPSTClassesFree(fpst);
    1160           0 :             fpst->nccnt = dummyfpst->nccnt; fpst->bccnt = dummyfpst->bccnt; fpst->fccnt = dummyfpst->fccnt;
    1161           0 :             fpst->nclass = dummyfpst->nclass; fpst->bclass = dummyfpst->bclass; fpst->fclass = dummyfpst->fclass;
    1162           0 :             fpst->nclassnames = dummyfpst->nclassnames; fpst->bclassnames = dummyfpst->bclassnames; fpst->fclassnames = dummyfpst->fclassnames;
    1163             :         }
    1164           0 :         chunkfree(dummyfpst,sizeof(FPST));
    1165           0 :       } break;
    1166             :       case aw_coverage_simple:
    1167           0 :         old = GMatrixEditGet(GWidgetGetControl(ccd->gw,CID_Covers),&len);
    1168           0 :         cols = GMatrixEditGetColCnt(GWidgetGetControl(ccd->gw,CID_Covers));
    1169           0 :         if ( len==0 ) {
    1170           0 :             ff_post_error(_("Bad Coverage Table"),_("There must be at least one match coverage table"));
    1171           0 : return;
    1172             :         }
    1173           0 :         memset(&dummy,0,sizeof(dummy));
    1174           0 :         if ( fpst->format==pst_reversecoverage ) {
    1175           0 :             first = last = -1;
    1176           0 :             for ( i=0; i<len; ++i ) {
    1177           0 :                 if ( old[cols*i+1].u.md_str!=NULL && *old[cols*i+1].u.md_str!='\0' ) {
    1178           0 :                     if ( first==-1 )
    1179           0 :                         first = last = i;
    1180             :                     else {
    1181           0 :                         ff_post_error(_("Bad Coverage Table"),_("In a Reverse Chaining Substitution there must be exactly one coverage table with replacements"));
    1182           0 : return;
    1183             :                     }
    1184             :                 }
    1185             :             }
    1186           0 :             if ( first==-1 ) {
    1187           0 :                 ff_post_error(_("Bad Coverage Table"),_("In a Reverse Chaining Substitution there must be exactly one coverage table with replacements"));
    1188           0 : return;
    1189             :             }
    1190           0 :             if ( GlyphNameCnt(old[cols*first+0].u.md_str)!=GlyphNameCnt(old[cols*first+1].u.md_str) ) {
    1191           0 :                 ff_post_error(_("Replacement mismatch"),_("In a Reverse Chaining Substitution there must be exactly as many replacements as there are glyph names in the match coverage table"));
    1192           0 : return;
    1193             :             }
    1194           0 :             forward_start = last+1;
    1195             :         } else {
    1196           0 :             first = last = forward_start = -1;
    1197           0 :             if ( fpst->type == pst_contextpos || fpst->type == pst_contextsub ) {
    1198           0 :                 first = 0;
    1199           0 :                 forward_start = len;
    1200             :                 /* No check here to see if any lookups invoked. It's only a warning */
    1201             :                 /*  Do we need to add it???? */
    1202             :             } else {
    1203           0 :                 for ( i=0; i<len; ++i ) {
    1204           0 :                     if ( old[cols*i+2].u.md_ival ) {
    1205           0 :                         if ( first==-1 )
    1206           0 :                             first = last = i;
    1207           0 :                         else if ( forward_start==-1 ) {
    1208           0 :                             if ( old[cols*i+1].u.md_addr!=NULL ) {
    1209           0 :                                 ff_post_error(_("Bad Sections"),_("The sections specified do not make sense. All lookups must lie in the middle section."));
    1210           0 : return;
    1211             :                             }
    1212           0 :                             forward_start = i;
    1213             :                         } else {
    1214           0 :                             ff_post_error(_("Bad Sections"),_("The sections specified do not make sense. All lookups must lie in the middle section."));
    1215           0 : return;
    1216             :                         }
    1217           0 :                     } else if ( old[cols*i+1].u.md_addr!=NULL ) {
    1218           0 :                         if ( first==-1 )
    1219           0 :                             first = last = i;
    1220           0 :                         else if ( forward_start!=-1 ) {
    1221           0 :                             ff_post_error(_("Bad Sections"),_("The sections specified do not make sense. All lookups must lie in the middle section."));
    1222           0 : return;
    1223             :                         }
    1224             :                     }
    1225             :                 }
    1226           0 :                 if ( forward_start==-1 && last!=-1 )
    1227           0 :                     forward_start = last+1;
    1228           0 :                 if ( first==-1 ) {
    1229           0 :                     ans = gwwv_ask(_("Warning"),
    1230             :                             (const char **) buts,0,1,
    1231           0 :                             _("This rule activates no lookups.\nProceed anyway?"));
    1232           0 :                     if ( ans==1 )
    1233           0 : return;
    1234           0 :                     first = 0;
    1235           0 :                     forward_start = len;
    1236             :                 }
    1237             :             }
    1238           0 :             for ( i=first, cnt=0; i<forward_start; ++i )
    1239           0 :                 if ( old[cols*i+1].u.md_addr!=NULL )
    1240           0 :                     ++cnt;
    1241           0 :             dummy.lookup_cnt = cnt;
    1242           0 :             if ( cnt!=0 ) {
    1243           0 :                 dummy.lookups = calloc(cnt,sizeof(struct seqlookup));
    1244           0 :                 for ( i=first, cnt=0; i<forward_start; ++i ) {
    1245           0 :                     if ( old[cols*i+1].u.md_addr!=NULL ) {
    1246           0 :                         dummy.lookups[cnt].lookup = old[cols*i+1].u.md_addr;
    1247           0 :                         dummy.lookups[cnt].seq = i-first;
    1248           0 :                         ++cnt;
    1249             :                     }
    1250             :                 }
    1251             :             }
    1252             :         }
    1253           0 :         dummy.u.coverage.bcnt = first;
    1254           0 :         dummy.u.coverage.ncnt = forward_start-first;
    1255           0 :         dummy.u.coverage.fcnt = len-forward_start;
    1256           0 :         dummy.u.coverage.ncovers = malloc(dummy.u.coverage.ncnt*sizeof(char *));
    1257           0 :         if ( dummy.u.coverage.bcnt!=0 )
    1258           0 :             dummy.u.coverage.bcovers = malloc(dummy.u.coverage.bcnt*sizeof(char *));
    1259           0 :         if ( dummy.u.coverage.fcnt!=0 )
    1260           0 :             dummy.u.coverage.fcovers = malloc(dummy.u.coverage.fcnt*sizeof(char *));
    1261           0 :         for ( i=0; i<first; ++i )
    1262           0 :             dummy.u.coverage.bcovers[first-1-i] = GlyphNameListDeUnicode( old[cols*i+0].u.md_str );
    1263           0 :         for ( i=0; i<dummy.u.coverage.ncnt; ++i )
    1264           0 :             dummy.u.coverage.ncovers[i] = GlyphNameListDeUnicode( old[cols*(first+i)+0].u.md_str );
    1265           0 :         for ( i=forward_start; i<len; ++i )
    1266           0 :             dummy.u.coverage.fcovers[i-forward_start] = GlyphNameListDeUnicode( old[cols*i+0].u.md_str );
    1267           0 :         FPSTClassesFree(fpst);
    1268           0 :         FPSTRulesFree(fpst->rules,fpst->format,fpst->rule_cnt);
    1269           0 :         fpst->format = fpst->type==pst_reversesub ? pst_reversecoverage : pst_coverage;
    1270           0 :         fpst->rule_cnt = 1;
    1271           0 :         fpst->rules = calloc(1,sizeof(struct fpst_rule));
    1272           0 :         fpst->rules[0] = dummy;
    1273           0 :       break;
    1274             :       default:
    1275           0 :         IError("The OK button should not be enabled here");
    1276           0 : return;
    1277             :     }
    1278           0 :     if ( ccd->isnew )
    1279           0 :         GFI_FinishContextNew(ccd->gfi,ccd->fpst,true);
    1280           0 :     ccd->done = true;
    1281             : }
    1282             : 
    1283           0 : static int CCD_OK(GGadget *g, GEvent *e) {
    1284           0 :     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
    1285           0 :         struct contextchaindlg *ccd = GDrawGetUserData(GGadgetGetWindow(g));
    1286           0 :         _CCD_Ok(ccd);
    1287             :     }
    1288           0 : return( true );
    1289             : }
    1290             : 
    1291           0 : static int CCD_Cancel(GGadget *g, GEvent *e) {
    1292           0 :     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
    1293           0 :         struct contextchaindlg *ccd = GDrawGetUserData(GGadgetGetWindow(g));
    1294           0 :         CCD_Close(ccd);
    1295             :     }
    1296           0 : return( true );
    1297             : }
    1298             : 
    1299           0 : static int CCD_Next(GGadget *g, GEvent *e) {
    1300           0 :     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
    1301           0 :         struct contextchaindlg *ccd = GDrawGetUserData(GGadgetGetWindow(g));
    1302           0 :         switch ( ccd->aw ) {
    1303             :           case aw_formats:
    1304           0 :             GDrawSetVisible(ccd->formats,false);
    1305           0 :             if ( GGadgetIsChecked(GWidgetGetControl(ccd->gw,CID_Simple)) ) {
    1306           0 :                 if ( GGadgetIsChecked(GWidgetGetControl(ccd->gw,CID_ByGlyph)) ) {
    1307           0 :                     ccd->aw = aw_glyphs_simple;
    1308           0 :                     GDrawSetVisible(ccd->glyphs_simple,true);
    1309           0 :                 } else if ( GGadgetIsChecked(GWidgetGetControl(ccd->gw,CID_ByClass)) ) {
    1310           0 :                     ccd->aw = aw_classes_simple;
    1311           0 :                     GDrawSetVisible(ccd->classes_simple,true);
    1312             :                 } else {
    1313           0 :                     ccd->aw = aw_coverage_simple;
    1314           0 :                     GDrawSetVisible(ccd->coverage_simple,true);
    1315             :                 }
    1316             :             } else {
    1317           0 :                 if ( GGadgetIsChecked(GWidgetGetControl(ccd->gw,CID_ByGlyph)) ) {
    1318           0 :                     ccd->aw = aw_grules;
    1319           0 :                     GDrawSetVisible(ccd->grules,true);
    1320           0 :                 } else if ( GGadgetIsChecked(GWidgetGetControl(ccd->gw,CID_ByClass)) ) {
    1321           0 :                     ccd->aw = aw_classrules;
    1322           0 :                     GDrawSetVisible(ccd->classrules,true);
    1323             :                 } else {
    1324           0 :                     ccd->aw = aw_coverage;
    1325           0 :                     GDrawSetVisible(ccd->coverage,true);
    1326             :                 }
    1327             :             }
    1328           0 :           break;
    1329             :           case aw_glyphs:
    1330             :           case aw_classnumber:
    1331           0 :             CCD_FinishRule(ccd);
    1332           0 :           break;
    1333             :           default:
    1334           0 :             IError("The next button should not be enabled here");
    1335           0 :           break;
    1336             :         }
    1337           0 :         CCD_EnableNextPrev(ccd);
    1338             :     }
    1339           0 : return( true );
    1340             : }
    1341             : 
    1342           0 : static int CCD_Prev(GGadget *g, GEvent *e) {
    1343           0 :     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
    1344           0 :         struct contextchaindlg *ccd = GDrawGetUserData(GGadgetGetWindow(g));
    1345           0 :         switch ( ccd->aw ) {
    1346             :           case aw_formats:
    1347           0 :             CCD_Cancel(g,e);
    1348           0 :           break;
    1349             :           case aw_glyphs:
    1350           0 :             ccd->aw = aw_grules;
    1351           0 :             GDrawSetVisible(ccd->glyphs,false);
    1352           0 :             GDrawSetVisible(ccd->grules,true);
    1353           0 :           break;
    1354             :           case aw_classnumber:
    1355           0 :             ccd->aw = aw_classrules;
    1356           0 :             GDrawSetVisible(ccd->classnumber,false);
    1357           0 :             GDrawSetVisible(ccd->classrules,true);
    1358           0 :           break;
    1359             :           case aw_coverage:
    1360             :           case aw_classrules:
    1361             :           case aw_grules:
    1362           0 :             ccd->aw = aw_formats;
    1363           0 :             GDrawSetVisible(ccd->coverage,false);
    1364           0 :             GDrawSetVisible(ccd->classrules,false);
    1365           0 :             GDrawSetVisible(ccd->grules,false);
    1366           0 :             GDrawSetVisible(ccd->formats,true);
    1367           0 :           break;
    1368             :           case aw_coverage_simple:
    1369             :           case aw_classes_simple:
    1370             :           case aw_glyphs_simple:
    1371           0 :             ccd->aw = aw_formats;
    1372           0 :             GDrawSetVisible(ccd->coverage_simple,false);
    1373           0 :             GDrawSetVisible(ccd->classes_simple,false);
    1374           0 :             GDrawSetVisible(ccd->glyphs_simple,false);
    1375           0 :             GDrawSetVisible(ccd->formats,true);
    1376           0 :           break;
    1377             :           default:
    1378           0 :             IError("Can't get here");
    1379           0 :           break;
    1380             :         }
    1381           0 :         CCD_EnableNextPrev(ccd);
    1382             :     }
    1383           0 : return( true );
    1384             : }
    1385             : 
    1386           0 : static void CCD_SimulateDefaultButton( struct contextchaindlg *ccd ) {
    1387             :     GEvent ev;
    1388             : 
    1389             :     /* figure out what the default action should be */
    1390           0 :     memset(&ev,0,sizeof(ev));
    1391           0 :     ev.type = et_controlevent;
    1392           0 :     ev.u.control.subtype = et_buttonactivate;
    1393           0 :     if ( ccd->aw==aw_formats || ccd->aw == aw_glyphs ) {
    1394           0 :         ev.u.control.g = GWidgetGetControl(ccd->gw,CID_Next);
    1395           0 :         CCD_Next(ev.u.control.g,&ev);
    1396             : /* For the glyph list and the coverage list, the [Next] button is disabled */
    1397             : /* I think [OK] is probably inappropriate, so let's do either [New] or [Edit] */
    1398             : /*  (which are what [Next] would logically do) depending on which of the two */
    1399             : /*  is more appropriate */
    1400             : /*      ev.u.control.g = GWidgetGetControl(ccd->gw,CID_OK); */
    1401             : /*      CCD_OK(ev.u.control.g,&ev);                     */
    1402             :     } else {
    1403             :     }
    1404           0 : }
    1405             : 
    1406           0 : static int CCD_NewSection(GGadget *g, GEvent *e) {
    1407           0 :     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
    1408           0 :         int off = GGadgetGetCid(g)-CID_GNewSection;
    1409           0 :         GGadget *gme = GWidgetGetControl(GGadgetGetWindow(g),CID_GList_Simple+off);
    1410           0 :         GGadget *tf = _GMatrixEditGetActiveTextField(gme);
    1411             :         static const unichar_t section_mark[] = { ' ', '|', ' ', '\0' };
    1412             : 
    1413           0 :         if ( tf!=NULL )
    1414           0 :             GTextFieldReplace(tf,section_mark);
    1415             :     }
    1416           0 : return( true );
    1417             : }
    1418             : 
    1419           0 : static int CCD_AddLookup(GGadget *g, GEvent *e) {
    1420           0 :     if ( e->type==et_controlevent && e->u.control.subtype == et_listselected ) {
    1421           0 :         int off = GGadgetGetCid(g)-CID_GAddLookup;
    1422           0 :         GGadget *gme = GWidgetGetControl(GGadgetGetWindow(g),CID_GList_Simple+off);
    1423           0 :         GGadget *tf = _GMatrixEditGetActiveTextField(gme);
    1424           0 :         GTextInfo *lookup_ti = GGadgetGetListItemSelected(g);
    1425             :         OTLookup *otl;
    1426             : 
    1427           0 :         if ( tf!=NULL && lookup_ti!=NULL && lookup_ti->userdata!=NULL) {
    1428             :             char *space;
    1429             :             unichar_t *temp;
    1430           0 :             otl = lookup_ti->userdata;
    1431           0 :             space = malloc(strlen(otl->lookup_name)+8);
    1432           0 :             sprintf( space, " @<%s> ", otl->lookup_name );
    1433           0 :             temp = utf82u_copy(space);
    1434           0 :             GTextFieldReplace(tf,temp);
    1435           0 :             free(space);
    1436           0 :             free(temp);
    1437             :         }
    1438           0 :         GGadgetSelectOneListItem(g,0);
    1439             :     }
    1440           0 : return( true );
    1441             : }
    1442             : 
    1443           0 : static int subccd_e_h(GWindow gw, GEvent *event) {
    1444           0 :     if ( event->type==et_char ) {
    1445           0 :         if ( event->u.chr.keysym == GK_F1 || event->u.chr.keysym == GK_Help ) {
    1446           0 :             help("contextchain.html");
    1447           0 : return( true );
    1448           0 :         } else if ( GMenuIsCommand(event,H_("Quit|Ctl+Q") )) {
    1449           0 :             MenuExit(NULL,NULL,NULL);
    1450           0 : return( true );
    1451           0 :         } else if ( GMenuIsCommand(event,H_("Close|Ctl+Shft+Q") )) {
    1452           0 :                 CCD_Close(GDrawGetUserData(gw));
    1453           0 : return( true );
    1454           0 :         } else if ( event->u.chr.chars[0]=='\r' ) {
    1455           0 :             CCD_SimulateDefaultButton( (struct contextchaindlg *) GDrawGetUserData(gw));
    1456           0 : return( true );
    1457             :         }
    1458           0 : return( false );
    1459             :     }
    1460           0 : return( true );
    1461             : }
    1462             : 
    1463           0 : static int ccd_e_h(GWindow gw, GEvent *event) {
    1464           0 :     if ( event->type==et_close ) {
    1465           0 :         struct contextchaindlg *ccd = GDrawGetUserData(gw);
    1466           0 :         CCD_Close(ccd);
    1467           0 :     } else if ( event->type==et_destroy ) {
    1468           0 :         struct contextchaindlg *ccd = GDrawGetUserData(gw);
    1469           0 :         chunkfree(ccd,sizeof(struct contextchaindlg));
    1470           0 :     } else if ( event->type==et_char ) {
    1471           0 :         if ( event->u.chr.keysym == GK_F1 || event->u.chr.keysym == GK_Help ) {
    1472           0 :             help("contextchain.html");
    1473           0 : return( true );
    1474           0 :         } else if ( GMenuIsCommand(event,H_("Quit|Ctl+Q") )) {
    1475           0 :             MenuExit(NULL,NULL,NULL);
    1476           0 : return( true );
    1477           0 :         } else if ( GMenuIsCommand(event,H_("Close|Ctl+Shft+Q") )) {
    1478           0 :             CCD_Close(GDrawGetUserData(gw));
    1479           0 : return( true );
    1480           0 :         } else if ( event->u.chr.chars[0]=='\r' ) {
    1481           0 :             CCD_SimulateDefaultButton( (struct contextchaindlg *) GDrawGetUserData(gw));
    1482           0 : return( true );
    1483             :         }
    1484           0 : return( false );
    1485           0 :     } else if ( event->type==et_resize ) {
    1486             :         /* int blen = GDrawPointsToPixels(NULL,GIntGetResource(_NUM_Buttonsize)),*/
    1487             :         GRect wsize;
    1488           0 :         struct contextchaindlg *ccd = GDrawGetUserData(gw);
    1489             : 
    1490           0 :         GGadgetGetSize(GWidgetGetControl(ccd->gw,CID_SubSize),&wsize);
    1491             : 
    1492           0 :         GDrawResize(ccd->formats,wsize.width,wsize.height);
    1493           0 :         GDrawResize(ccd->coverage,wsize.width,wsize.height);
    1494           0 :         GDrawResize(ccd->grules,wsize.width,wsize.height);
    1495           0 :         GDrawResize(ccd->glyphs,wsize.width,wsize.height);
    1496           0 :         GDrawResize(ccd->classrules,wsize.width,wsize.height);
    1497           0 :         GDrawResize(ccd->classnumber,wsize.width,wsize.height);
    1498           0 :         GDrawResize(ccd->coverage_simple,wsize.width,wsize.height);
    1499           0 :         GDrawResize(ccd->glyphs_simple,wsize.width,wsize.height);
    1500           0 :         GDrawResize(ccd->classes_simple,wsize.width,wsize.height);
    1501             : 
    1502           0 :         GDrawRequestExpose(ccd->gw,NULL,false);
    1503           0 :         GDrawRequestExpose(ccd->aw==aw_formats ? ccd->formats :
    1504           0 :                             ccd->aw==aw_coverage ? ccd->coverage :
    1505           0 :                             ccd->aw==aw_grules ? ccd->grules :
    1506           0 :                             ccd->aw==aw_glyphs ? ccd->glyphs :
    1507           0 :                             ccd->aw==aw_classrules ? ccd->classrules :
    1508           0 :                             ccd->aw==aw_classnumber ? ccd->classnumber :
    1509           0 :                             ccd->aw==aw_coverage_simple ? ccd->coverage_simple :
    1510           0 :                             ccd->aw==aw_classes_simple ? ccd->classes_simple :
    1511             :                                         ccd->glyphs_simple, NULL,false);
    1512             :     }
    1513           0 : return( true );
    1514             : }
    1515             : 
    1516             : #define CCD_WIDTH       340
    1517             : #define CCD_HEIGHT      340
    1518             : 
    1519           0 : static unichar_t **CCD_GlyphListCompletion(GGadget *t,int from_tab) {
    1520           0 :     struct contextchaindlg *ccd = GDrawGetUserData(GDrawGetParentWindow(GGadgetGetWindow(t)));
    1521           0 :     SplineFont *sf = ccd->sf;
    1522             : 
    1523           0 : return( SFGlyphNameCompletion(sf,t,from_tab,true));
    1524             : }
    1525             : 
    1526           0 : static unichar_t **CCD_ClassListCompletion(GGadget *t,int from_tab) {
    1527           0 :     struct contextchaindlg *ccd = GDrawGetUserData(GDrawGetParentWindow(GGadgetGetWindow(t)));
    1528             :     unichar_t *pt, *spt, *basept, *wild; unichar_t **ret;
    1529             :     int i, cnt, doit, match_len;
    1530             :     int do_wildcards;
    1531             :     int section;
    1532             :     int namecnt;
    1533             :     int cid;
    1534             :     struct matrix_data *classnames;
    1535             : 
    1536           0 :     section = 0;
    1537             : 
    1538           0 :     pt = spt = basept = (unichar_t *) _GGadgetGetTitle(t);
    1539           0 :     if ( pt==NULL || *pt=='\0' )
    1540           0 : return( NULL );
    1541             : 
    1542           0 :     if ( ccd->fpst->type==pst_contextsub || ccd->fpst->type==pst_contextpos )
    1543           0 :         section=1;
    1544             :     else {
    1545           0 :         for ( pt=basept; *pt ; ++pt )
    1546           0 :             if ( *pt=='|' )
    1547           0 :                 ++section;
    1548           0 :         if ( section>2 )
    1549           0 :             section=2;
    1550             :     }
    1551           0 :     if ( section==0 && !GGadgetIsChecked(GWidgetGetControl(ccd->gw,CID_BackClassesSameAs_S)) )
    1552           0 :         cid = CID_BackClasses;
    1553           0 :     else if ( section==2 && !GGadgetIsChecked(GWidgetGetControl(ccd->gw,CID_ForeClassesSameAs_S)) )
    1554           0 :         cid = CID_ForeClasses;
    1555             :     else
    1556           0 :         cid = CID_MatchClasses;
    1557           0 :     classnames = GMatrixEditGet(GWidgetGetControl(ccd->gw,cid),&namecnt);
    1558           0 :     if ( namecnt==0 )           /* No classes_simple specified yet, can't help */
    1559           0 : return( NULL );
    1560             : 
    1561           0 :     if (( spt = u_strrchr(spt,' '))== NULL )
    1562           0 :         spt = basept;
    1563             :     else {
    1564           0 :         pt = ++spt;
    1565           0 :         if ( *pt=='\0' )
    1566           0 : return( NULL );
    1567             :     }
    1568           0 :     while ( *pt && *pt!='*' && *pt!='?' && *pt!='[' && *pt!='{' )
    1569           0 :         ++pt;
    1570           0 :     do_wildcards = *pt!='\0';
    1571             : 
    1572           0 :     if ( do_wildcards && !from_tab )
    1573           0 : return( NULL );
    1574             : 
    1575           0 :     wild = NULL;
    1576           0 :     if ( do_wildcards ) {
    1577           0 :         pt = spt;
    1578           0 :         wild = malloc((u_strlen(spt)+2)*sizeof(unichar_t));
    1579           0 :         u_strcpy(wild,pt);
    1580           0 :         uc_strcat(wild,"*");
    1581             :     }
    1582             : 
    1583           0 :     match_len = u_strlen(spt);
    1584           0 :     ret = NULL;
    1585           0 :     for ( doit=0; doit<2; ++doit ) {
    1586           0 :         cnt=0;
    1587           0 :         for ( i=0; i<namecnt; ++i ) if ( classnames[3*i+0].u.md_str!=NULL ) {
    1588             :             int matched;
    1589           0 :             char *str = classnames[3*i+0].u.md_str;
    1590           0 :             if ( do_wildcards ) {
    1591           0 :                 unichar_t *temp = utf82u_copy(str);
    1592           0 :                 matched = GGadgetWildMatch((unichar_t *) wild,temp,false);
    1593           0 :                 free(temp);
    1594             :             } else
    1595           0 :                 matched = uc_strncmp(spt,str,match_len)==0;
    1596           0 :             if ( matched ) {
    1597           0 :                 if ( doit ) {
    1598           0 :                     if ( spt==basept ) {
    1599           0 :                         ret[cnt] = utf82u_copy(str);
    1600             :                     } else {
    1601           0 :                         unichar_t *temp = malloc((spt-basept+strlen(str)+4)*sizeof(unichar_t));
    1602             :                         int len;
    1603           0 :                         u_strncpy(temp,basept,spt-basept);
    1604           0 :                         utf82u_strcpy(temp+(spt-basept),str);
    1605           0 :                         len = u_strlen(temp);
    1606           0 :                         ret[cnt] = temp;
    1607             :                     }
    1608             :                 }
    1609           0 :                 ++cnt;
    1610             :             }
    1611             :         }
    1612           0 :         if ( doit )
    1613           0 :             ret[cnt] = NULL;
    1614           0 :         else if ( cnt==0 )
    1615           0 :     break;
    1616             :         else
    1617           0 :             ret = malloc((cnt+1)*sizeof(unichar_t *));
    1618             :     }
    1619           0 :     free(wild);
    1620           0 : return( ret );
    1621             : }
    1622             : 
    1623           0 : static void CCD_FinishCoverageEdit(GGadget *g,int r, int c, int wasnew) {
    1624           0 :     struct contextchaindlg *ccd = GDrawGetUserData(GGadgetGetWindow(g));
    1625             : 
    1626           0 :     ME_SetCheckUnique(g, r, c, ccd->sf);
    1627           0 : }
    1628             : 
    1629           0 : static void CCD_FinishCoverageSimpleEdit(GGadget *g,int r, int c, int wasnew) {
    1630           0 :     struct contextchaindlg *ccd = GDrawGetUserData(GGadgetGetWindow(g));
    1631           0 :     int cols = GMatrixEditGetColCnt(g);
    1632             :     int first, last, i;
    1633             :     int rows;
    1634           0 :     struct matrix_data *covers = _GMatrixEditGet(g,&rows);
    1635             : 
    1636             : 
    1637           0 :     if ( c==0 )
    1638           0 :         ME_SetCheckUnique(g, r, c, ccd->sf);
    1639           0 :     else if ( c==1 && cols==2 ) {       /* The replacement list in a reverse coverage_simple */
    1640           0 :         ME_ListCheck(g, r, c, ccd->sf);
    1641           0 :     } else if ( c==1 && cols==4 ) {     /* The lookup in a coverage_simple line (not reverse coverage_simple) */
    1642           0 :         if ( covers[cols*r+c].u.md_addr== (void *) (intpt) -1 ) {
    1643             :             /* They asked to remove the lookup that was there */
    1644           0 :             covers[cols*r+c].u.md_addr = NULL;
    1645           0 :         } else if ( covers[cols*r+c].u.md_addr==NULL ) {
    1646             :             /* The selected the "Add Lookup" item which should be a no-op */
    1647             :             /*  but actually sets the thing to 0 */
    1648           0 :             covers[cols*r+c].u.md_addr = covers[cols*r+3].u.md_addr;
    1649             :         }
    1650             :         /* Save the new value somewhere safe */
    1651           0 :         covers[cols*r+3].u.md_addr = covers[cols*r+c].u.md_addr;
    1652           0 :         first = last = -1;
    1653           0 :         for ( i=0; i<rows; ++i ) {
    1654           0 :             if ( covers[cols*i+c].u.md_addr!=NULL ) {
    1655           0 :                 if ( first==-1 )
    1656           0 :                     first = i;
    1657           0 :                 last = i;
    1658             :             }
    1659             :         }
    1660           0 :         if ( first!=-1 ) {
    1661             :             /* there may not be a section break between first and last */
    1662           0 :             for ( i=first; i<=last; ++i )
    1663           0 :                 covers[cols*i+2].u.md_ival = false;
    1664           0 :             for ( i=0; i<first; ++i )
    1665           0 :                 if ( covers[cols*i+2].u.md_ival )
    1666           0 :             break;
    1667           0 :             if ( i==first )
    1668           0 :                 covers[cols*first+2].u.md_ival = true;
    1669           0 :             for ( i=rows-1; i>last; --i )
    1670           0 :                 if ( covers[cols*i+2].u.md_ival )
    1671           0 :             break;
    1672           0 :             if ( i<=last && last+1<rows )
    1673           0 :                 covers[cols*(last+1)+2].u.md_ival = true;
    1674             :         }
    1675           0 :         GGadgetRedraw(g);
    1676           0 :     } else if ( c==2 ) {
    1677           0 :         first = last = -1;
    1678           0 :         for ( i=0; i<rows; ++i ) {
    1679           0 :             if ( covers[cols*i+1].u.md_addr!=NULL ) {
    1680           0 :                 if ( first==-1 )
    1681           0 :                     first = i;
    1682           0 :                 last = i;
    1683             :             }
    1684             :         }
    1685           0 :         if ( covers[cols*i+2].u.md_ival ) {
    1686           0 :             if ( r<=first ) {
    1687           0 :                 for ( i=0; i<=first; ++i ) if ( i!=r )
    1688           0 :                     covers[cols*i+2].u.md_ival = false;
    1689           0 :             } else if ( r<=last ) {
    1690           0 :                 covers[cols*i+2].u.md_ival = false;
    1691           0 :                 GDrawBeep(NULL);
    1692             :             } else {
    1693           0 :                 for ( i=last+1; i<=rows; ++i ) if ( i!=r )
    1694           0 :                     covers[cols*i+2].u.md_ival = false;
    1695             :             }
    1696             :         } else {
    1697           0 :             for ( i=first; i>=0; --i )
    1698           0 :                 if ( covers[cols*i+2].u.md_ival )
    1699           0 :             break;
    1700           0 :             if ( i==0 )
    1701           0 :                 covers[cols*0+2].u.md_ival = true;
    1702             :         }
    1703           0 :         GGadgetRedraw(g);
    1704             :     }
    1705           0 : }
    1706             : 
    1707           0 : static int WhichSections(struct contextchaindlg *ccd, GGadget *g) {
    1708           0 :     int off = GGadgetGetCid(g)-CID_MatchClasses;
    1709           0 :     int sections = 0;
    1710             : 
    1711           0 :     if ( ccd->fpst->type==pst_contextpos || ccd->fpst->type==pst_contextsub )
    1712           0 :         sections = 0x7;         /* All sections */
    1713           0 :     else if ( off==0 ) {
    1714           0 :         sections = 0x2;         /* Match */
    1715           0 :         if ( GGadgetIsChecked(GWidgetGetControl(ccd->classes_simple,CID_SameAsClasses_S+20)))
    1716           0 :             sections |= 0x1;
    1717           0 :         if ( GGadgetIsChecked(GWidgetGetControl(ccd->classes_simple,CID_SameAsClasses_S+40)))
    1718           0 :             sections |= 0x4;
    1719           0 :     } else if ( off==20 )
    1720           0 :         sections = 0x1;         /* Backtracking */
    1721             :     else
    1722           0 :         sections = 0x4;         /* Foreward */
    1723           0 : return( sections );
    1724             : }
    1725             : 
    1726           0 : static void RenameClass(struct contextchaindlg *ccd,char *old,char *new,int sections) {
    1727             :     /* A class has been renamed. We should fix up all class rules that use */
    1728             :     /*  the old name to use the new one. The name may only be valid in one */
    1729             :     /*  section of the rule (backtrack, match, or forward), or in all, or */
    1730             :     /*  in match and one of the other two */
    1731             :     int rows, i;
    1732           0 :     GGadget *gclassrules = GWidgetGetControl(ccd->classes_simple,CID_CList_Simple);
    1733           0 :     struct matrix_data *classrules = GMatrixEditGet(gclassrules,&rows);
    1734           0 :     int cols = GMatrixEditGetColCnt(gclassrules);
    1735           0 :     char *end_back=NULL, *end_match=NULL, *pt, *last_name, *temp;
    1736             :     int ch;
    1737             : 
    1738           0 :     if ( sections==0x7 ) {
    1739             :         /* name change applies through out rule, no need to search for sections */
    1740           0 :         for ( i=0; i<rows; ++i ) {
    1741           0 :             char *oldrule = classrules[cols*i+0].u.md_str;
    1742           0 :             char *newrule = rpl(oldrule,old,new);
    1743           0 :             free(oldrule);
    1744           0 :             classrules[cols*i+0].u.md_str = newrule;
    1745             :         }
    1746             :     } else {
    1747           0 :         for ( i=0; i<rows; ++i ) {
    1748           0 :             char *oldrule = classrules[cols*i+0].u.md_str;
    1749             :             char *newrule;
    1750           0 :             for ( pt=last_name=oldrule; *pt; ) {
    1751           0 :                 while ( isspace(*pt)) ++pt;
    1752           0 :                 if ( *pt=='|' ) {
    1753           0 :                     if ( end_back == NULL )
    1754           0 :                         end_back = pt;
    1755           0 :                     else if ( end_match==NULL )
    1756           0 :                         end_match = pt;
    1757           0 :                 } else if ( end_back==NULL && ( *pt=='<' || *pt=='@' )) {
    1758           0 :                     end_back = last_name;
    1759             :                 } else
    1760           0 :                     last_name = pt;
    1761           0 :                 if ( *pt=='<' || *pt=='@' ) {
    1762           0 :                     while ( *pt!='>' && *pt!='\0' ) ++pt;
    1763           0 :                     if ( *pt=='>' ) ++pt;
    1764             :                 } else {
    1765           0 :                     while ( !isspace( *pt ) && *pt!='\0' )
    1766           0 :                         ++pt;
    1767             :                 }
    1768             :             }
    1769           0 :             if ( (sections==0x3 && end_match==NULL) ||
    1770           0 :                     (sections==0x6 && end_back==NULL) ||
    1771           0 :                     (sections==0x2 && end_match==NULL && end_back==NULL)) {
    1772           0 :                 newrule = rpl(oldrule,old,new);
    1773           0 :             } else if ( sections==0x3 ) {
    1774           0 :                 ch = *end_match; *end_match='\0';
    1775           0 :                 temp = rpl(oldrule,old,new);
    1776           0 :                 *end_match = ch;
    1777           0 :                 newrule = strconcat(temp,end_match);
    1778           0 :                 free(temp);
    1779           0 :             } else if ( sections==0x6 ) {
    1780           0 :                 temp = rpl(end_back,old,new);
    1781           0 :                 ch = *end_back; *end_back = '\0';
    1782           0 :                 newrule = strconcat(oldrule,temp);
    1783           0 :                 *end_back = ch;
    1784           0 :                 free(temp);
    1785           0 :             } else if ( sections==0x1 ) {
    1786           0 :                 if ( end_back==NULL )
    1787           0 :                     newrule=NULL;
    1788             :                 else {
    1789           0 :                     ch = *end_back; *end_back = '\0';
    1790           0 :                     temp = rpl(oldrule,old,new);
    1791           0 :                     *end_back = ch;
    1792           0 :                     newrule = strconcat(temp,end_back);
    1793           0 :                     free(temp);
    1794             :                 }
    1795           0 :             } else if ( sections==0x2 ) {
    1796           0 :                 if ( end_match==NULL ) {
    1797           0 :                     temp = rpl(end_back,old,new);       /* end_back is not NULL, checked above */
    1798           0 :                     ch = *end_back; *end_back = '\0';
    1799           0 :                     newrule = strconcat(oldrule,temp);
    1800           0 :                     *end_back = ch;
    1801           0 :                     free(temp);
    1802           0 :                 } else if ( end_back==NULL ) {
    1803           0 :                     ch = *end_match; *end_match = '\0';
    1804           0 :                     temp = rpl(oldrule,old,new);
    1805           0 :                     *end_match = ch;
    1806           0 :                     newrule = strconcat(temp,end_match);
    1807           0 :                     free(temp);
    1808             :                 } else {
    1809           0 :                     ch = *end_match; *end_match = '\0';
    1810           0 :                     temp = rpl(end_back,old,new);
    1811           0 :                     *end_match = ch;
    1812           0 :                     ch = *end_back; *end_back = '\0';
    1813           0 :                     newrule = strconcat3(oldrule,temp,end_match);
    1814           0 :                     *end_back = ch;
    1815           0 :                     free(temp);
    1816             :                 }
    1817           0 :             } else if ( sections==0x4 ) {
    1818           0 :                 if ( end_match==NULL )
    1819           0 :                     newrule=NULL;
    1820             :                 else {
    1821           0 :                     temp = rpl(end_match,old,new);
    1822           0 :                     ch = *end_match; *end_match = '\0';
    1823           0 :                     newrule = strconcat(oldrule,temp);
    1824           0 :                     *end_match = ch;
    1825           0 :                     free(temp);
    1826             :                 }
    1827             :             } else
    1828           0 :                 newrule = NULL;
    1829           0 :             if ( newrule!=NULL ) {
    1830           0 :                 free(oldrule);
    1831           0 :                 classrules[cols*i+0].u.md_str = newrule;
    1832             :             }
    1833             :         }
    1834             :     }
    1835           0 :     GGadgetRedraw(gclassrules);
    1836           0 : }
    1837             : 
    1838           0 : static void CCD_FinishClassEdit(GGadget *g,int r, int c, int wasnew) {
    1839           0 :     struct contextchaindlg *ccd = GDrawGetUserData(GGadgetGetWindow(g));
    1840             : 
    1841           0 :     if ( c==1 )
    1842           0 :         ME_ClassCheckUnique(g, r, c, ccd->sf);
    1843           0 :     else if ( c==0 ) {
    1844             :         int rows, i;
    1845           0 :         struct matrix_data *classes_simple = _GMatrixEditGet(g,&rows);
    1846             :         char buffer[40], *end, *pt;
    1847             : 
    1848           0 :         if ( strchr(classes_simple[3*r+0].u.md_str,' ')!=NULL ) {
    1849           0 :             for ( pt=classes_simple[3*r+0].u.md_str; *pt; ++pt) {
    1850           0 :                 if ( isspace(*pt))
    1851           0 :                     *pt = '_';
    1852             :             }
    1853           0 :             GGadgetRedraw(g);
    1854           0 :             ff_post_error(_("Bad class name"),_("No spaces allowed in class names."));
    1855             :         }
    1856           0 :         i = strtol(classes_simple[3*r+0].u.md_str,&end,10);
    1857           0 :         if ( *end=='\0' && i!=r ) {
    1858           0 :             sprintf( buffer,"%d",r );
    1859           0 :             free( classes_simple[3*r+0].u.md_str );
    1860           0 :             classes_simple[3*r+0].u.md_str = copy(buffer);
    1861           0 :             GGadgetRedraw(g);
    1862           0 :             ff_post_error(_("Bad class name"),_("If a class name is a number, it must be the index of the class in the array of classes_simple."));
    1863             :         }
    1864           0 :         for ( i=0; i<rows; ++i ) if ( i!=r ) {
    1865           0 :             if ( strcmp(classes_simple[3*i+0].u.md_str,classes_simple[3*r+0].u.md_str) == 0 ) {
    1866           0 :                 sprintf( buffer,"%d",r );
    1867           0 :                 free( classes_simple[3*r+0].u.md_str );
    1868           0 :                 classes_simple[3*r+0].u.md_str = copy(buffer);
    1869           0 :                 GGadgetRedraw(g);
    1870           0 :                 ff_post_error(_("Bad class name"),_("The class name, %s, is already in use."), classes_simple[3*i+0].u.md_str);
    1871             :             }
    1872             :         }
    1873           0 :         if ( strcmp(classes_simple[3*r+0].u.md_str,classes_simple[3*r+2].u.md_str)!=0 ) {
    1874           0 :             RenameClass(ccd,classes_simple[3*r+2].u.md_str,classes_simple[3*r+0].u.md_str,WhichSections(ccd,g));
    1875           0 :             free(classes_simple[3*r+2].u.md_str);
    1876           0 :             classes_simple[3*r+2].u.md_str = copy(classes_simple[3*r+0].u.md_str);
    1877             :         }
    1878             :     }
    1879           0 : }
    1880             : 
    1881           0 : static void CCD_ClassGoing(GGadget *g,int r) {
    1882             :     /* We are about to delete this row in the class dlg, so fix up all numeric */
    1883             :     /*  classes_simple after it */
    1884           0 :     struct contextchaindlg *ccd = GDrawGetUserData(GGadgetGetWindow(g));
    1885           0 :     int sections = WhichSections(ccd,g);
    1886             :     int rows, i;
    1887           0 :     struct matrix_data *classes_simple = _GMatrixEditGet(g,&rows);
    1888             :     char buffer[20], *end;
    1889             : 
    1890           0 :     for ( i=r+1; i<rows; ++i ) {
    1891           0 :         strtol(classes_simple[3*i+0].u.md_str,&end,10);
    1892           0 :         if ( *end=='\0' ) {
    1893           0 :             sprintf(buffer,"%d",i-1);
    1894           0 :             free(classes_simple[3*i+0].u.md_str);
    1895           0 :             classes_simple[3*i+0].u.md_str = copy(buffer);
    1896           0 :             RenameClass(ccd,classes_simple[3*i+2].u.md_str,buffer,sections);
    1897           0 :             free(classes_simple[3*i+2].u.md_str);
    1898           0 :             classes_simple[3*i+2].u.md_str = copy(buffer);
    1899             :         }
    1900             :     }
    1901           0 : }
    1902             : 
    1903           0 : static void CCD_InitClassRow(GGadget *g,int r) {
    1904             :     char buffer[20];
    1905             :     int rows;
    1906           0 :     struct matrix_data *classes_simple = _GMatrixEditGet(g,&rows);
    1907             : 
    1908           0 :     sprintf( buffer, "%d", r );
    1909           0 :     classes_simple[3*r+0].u.md_str = copy(buffer);
    1910           0 : }
    1911             : 
    1912           0 : static int CCD_EnableDeleteClass(GGadget *g,int whichclass) {
    1913           0 : return( whichclass>0 );
    1914             : }
    1915             : 
    1916           0 : static enum gme_updown CCD_EnableUpDown(GGadget *g,int r) {
    1917             :     int rows;
    1918           0 :     enum gme_updown ret = 0;
    1919             : 
    1920           0 :     (void) GMatrixEditGet(g,&rows);
    1921           0 :     if ( r>=2 )
    1922           0 :         ret = ud_up_enabled;
    1923           0 :     if ( r>=1 && r<rows-1 )
    1924           0 :         ret |= ud_down_enabled;
    1925           0 : return( ret );
    1926             : }
    1927             : 
    1928             : static GTextInfo section[] = {
    1929             :     { (unichar_t *) N_("Section|Continue"), NULL, 0, 0, (void *) 0, NULL, 0, 0, 0, 0, 1, 0, 1, 0, 0, '\0'},
    1930             :     { (unichar_t *) N_("Section|Start"), NULL, 0, 0, (void *) 1, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
    1931             :     GTEXTINFO_EMPTY
    1932             : };
    1933             : static struct col_init class_ci[] = {
    1934             :     { me_string, NULL, NULL, NULL, N_("Class|Name") },
    1935             :     { me_funcedit, CCD_PickGlyphsForClass, NULL, NULL, N_("Glyphs in the class") },
    1936             :     { me_string, NULL, NULL, NULL, "Old Name (hidden)" },
    1937             :     };
    1938             : static struct col_init classlist_ci[] = {
    1939             :     { me_string, NULL, NULL, NULL, N_("Class|Name") },
    1940             :     { me_string, NULL, NULL, NULL, N_("Glyphs in the class") },
    1941             :     };
    1942             : static struct col_init coverage_ci[] = {
    1943             :     { me_funcedit, CCD_PickGlyphsForClass, NULL, NULL, N_("Glyphs in the coverage tables") },
    1944             :     };
    1945             : static struct col_init seqlookup_ci[] = {
    1946             :     { me_enum, NULL, NULL, NULL, N_("Apply lookup") },
    1947             :     { me_int, NULL, NULL, NULL, N_("at position") },
    1948             :     };
    1949             : static struct col_init glyphrules_ci[] = {
    1950             :     { me_onlyfuncedit, _CCD_NewGlyphRule, NULL, NULL, N_("Matching rules based on a list of glyphs") },
    1951             :     };
    1952             : static struct col_init classrules_ci[] = {
    1953             :     { me_onlyfuncedit, _CCD_NewClassRule, NULL, NULL, N_("Matching rules based on a list of classes") },
    1954             :     };
    1955             : static struct col_init coveragesimple_ci[] = {
    1956             :     { me_funcedit, CCD_PickGlyphsForClass, NULL, NULL, N_("Glyphs in the coverage tables") },
    1957             :     { me_enum, NULL, NULL, NULL, N_("Apply lookup") },
    1958             :     { me_enum, NULL, section, NULL, N_("Section")},
    1959             :     { me_addr, NULL, section, NULL, "Old lookup, internal use only"},
    1960             :     };
    1961             : static struct col_init rcoveragesimple_ci[] = {
    1962             :     { me_funcedit, CCD_PickGlyphsForClass, NULL, NULL, N_("Glyphs in the coverage tables") },
    1963             :     { me_funcedit, CCD_PickGlyphsForClass, NULL, NULL, N_("Replacement glyphs") },
    1964             :     };
    1965             : static struct col_init glyph_ci[] = {
    1966             :     { me_string, NULL, NULL, NULL, N_("Matching rules based on a list of glyphs") },
    1967             :     };
    1968             : static struct col_init classsimple_ci[] = {
    1969             :     { me_string, NULL, NULL, NULL, N_("Matching rules based on a list of classes") },
    1970             :     };
    1971             : 
    1972             : /* The "simple" dialog has several problems:
    1973             :   1. The order in which lookups are to be applied is lost, they will be
    1974             :       applied in sequence order
    1975             :   2. In coverage_simple classes_simple only one lookup may be applied for any given
    1976             :       coverage_simple set.
    1977             :   Adobe's feature files have these restrictions and more, so my hope is that
    1978             :    they will not matter.
    1979             :   If they do matter, then we fall back on the old, more complex (I think more
    1980             :    complex anyway) format.
    1981             : */
    1982           0 : static int CanBeSimple(FPST *fpst) {
    1983             :     int i, s, last_seq;
    1984           0 :     for ( i=0; i<fpst->rule_cnt; ++i ) {
    1985           0 :         struct fpst_rule *r = &fpst->rules[i];
    1986             : 
    1987           0 :         last_seq = -1;
    1988           0 :         for ( s=0; s<r->lookup_cnt; ++s ) {
    1989           0 :             if ( last_seq>r->lookups[s].seq )
    1990           0 : return( false );
    1991           0 :             else if ( last_seq==r->lookups[s].seq &&
    1992           0 :                     (fpst->format==pst_coverage || fpst->format==pst_reversecoverage))
    1993           0 : return( false );
    1994           0 :             last_seq = r->lookups[s].seq;
    1995             :         }
    1996             :     }
    1997           0 : return( true );
    1998             : }
    1999             : 
    2000           0 : void ContextChainEdit(SplineFont *sf,FPST *fpst,
    2001             :         struct gfi_data *gfi, unichar_t *newname,int layer) {
    2002             :     struct contextchaindlg *ccd;
    2003             :     int i,j,k;
    2004             :     static char *titles[2][5] = {
    2005             :         { N_("Edit Contextual Position"), N_("Edit Contextual Substitution"),
    2006             :             N_("Edit Chaining Position"), N_("Edit Chaining Substitution"),
    2007             :             N_("Edit Reverse Chaining Substitution"),
    2008             :         },
    2009             :         { N_("New Contextual Position"), N_("New Contextual Substitution"),
    2010             :             N_("New Chaining Position"), N_("New Chaining Substitution"),
    2011             :             N_("New Reverse Chaining Substitution")
    2012             :         }};
    2013             :     GRect pos, subpos;
    2014             :     GWindow gw;
    2015             :     GWindowAttrs wattrs;
    2016             :     GTabInfo faspects[5];
    2017             :     GGadgetCreateData glgcd[8], fgcd[3], ggcd[3][14], cgcd[3][18],
    2018             :         clgcd[10], subboxes[3][5], topbox[3], classbox[2], extrabuttonsgcd[3];
    2019             :     GTextInfo gllabel[8], flabel[3], glabel[3][14], clabel[3][18],
    2020             :         cllabel[10], extrabuttonslab[3];
    2021             :     GGadgetCreateData bgcd[6], rgcd[15], boxes[4], *barray[10], *hvarray[7][2];
    2022             :     GGadgetCreateData *subvarray[3][10], *subvarray2[4], *subvarray3[4], *topvarray[8],
    2023             :             *classv[4], *subvarray4[4], *barray2[6];
    2024             :     GTextInfo blabel[5], rlabel[15];
    2025           0 :     struct fpst_rule *r=NULL;
    2026             :     FPST *tempfpst;
    2027             :     struct matrixinit coverage_mi[3], class_mi[3], classlist_mi[3],
    2028             :         gl_seqlookup_mi, cl_seqlookup_mi,
    2029             :         co_seqlookup_mi, classrules_mi, glyphrules_mi,
    2030             :         coveragesimple_mi, classsimple_mi, glyphs_mi;
    2031             :     static int inited=false;
    2032           0 :     int isgpos = ( fpst->type==pst_contextpos || fpst->type==pst_chainpos );
    2033             :     struct matrix_data *md;
    2034             :     GTextInfo *lookup_list, *addlookup_list, *addrmlookup_list;
    2035           0 :     int use_simple = CanBeSimple(fpst);
    2036             :     struct matrix_data *_classes[3]; int clen[3];
    2037             : 
    2038           0 :     lookup_list = SFLookupArrayFromType(sf,isgpos?gpos_start:gsub_start);
    2039           0 :     for ( i=0; lookup_list[i].text!=NULL; ++i ) {
    2040           0 :         if (fpst!=NULL && lookup_list[i].userdata == fpst->subtable->lookup )
    2041           0 :             lookup_list[i].disabled = true;
    2042           0 :         lookup_list[i].selected = false;
    2043             :     }
    2044           0 :     addlookup_list = calloc(i+3,sizeof(GTextInfo));
    2045           0 :     memcpy(addlookup_list+1,lookup_list,(i+1)*sizeof(GTextInfo));
    2046           0 :     addrmlookup_list = calloc(i+3,sizeof(GTextInfo));
    2047           0 :     memcpy(addrmlookup_list+2,lookup_list,(i+1)*sizeof(GTextInfo));
    2048           0 :     addlookup_list[0].text = (unichar_t *) S_("Add Lookup");
    2049           0 :     addlookup_list[0].text_is_1byte = true;
    2050           0 :     addlookup_list[0].selected = true;
    2051           0 :     addrmlookup_list[0].text = (unichar_t *) S_("Add Lookup");
    2052           0 :     addrmlookup_list[0].text_is_1byte = true;
    2053           0 :     addrmlookup_list[0].selected = true;
    2054           0 :     addrmlookup_list[1].text = (unichar_t *) S_("Remove Lookup");
    2055           0 :     addrmlookup_list[1].text_is_1byte = true;
    2056           0 :     addrmlookup_list[1].selected = false;
    2057           0 :     addrmlookup_list[1].userdata = (void *) (intpt) -1;
    2058           0 :     coveragesimple_ci[1].enum_vals = addrmlookup_list;
    2059           0 :     seqlookup_ci[0].enum_vals = lookup_list;
    2060             : 
    2061           0 :     if ( !inited ) {
    2062           0 :         inited = true;
    2063           0 :         section[0].text = (unichar_t *) S_( (char *) section[0].text);
    2064           0 :         section[1].text = (unichar_t *) S_( (char *) section[1].text);
    2065           0 :         classlist_ci[0].title = class_ci[0].title = S_(class_ci[0].title);
    2066           0 :         classlist_ci[1].title = class_ci[1].title = S_(class_ci[1].title);
    2067           0 :         coverage_ci[0].title = S_(coverage_ci[0].title);
    2068           0 :         seqlookup_ci[0].title = S_(seqlookup_ci[0].title);
    2069           0 :         seqlookup_ci[1].title = S_(seqlookup_ci[1].title);
    2070           0 :         glyphrules_ci[0].title = S_(glyphrules_ci[0].title);
    2071           0 :         classrules_ci[0].title = S_(classrules_ci[0].title);
    2072           0 :         coveragesimple_ci[0].title = S_(coveragesimple_ci[0].title);
    2073           0 :         coveragesimple_ci[1].title = S_(coveragesimple_ci[1].title);
    2074           0 :         coveragesimple_ci[2].title = S_(coveragesimple_ci[2].title);
    2075           0 :         rcoveragesimple_ci[0].title = S_(rcoveragesimple_ci[0].title);
    2076           0 :         rcoveragesimple_ci[1].title = S_(rcoveragesimple_ci[1].title);
    2077           0 :         glyph_ci[0].title = S_(glyph_ci[0].title);
    2078             :     }
    2079             : 
    2080           0 :     ccd = chunkalloc(sizeof(struct contextchaindlg));
    2081           0 :     ccd->gfi = gfi;
    2082           0 :     ccd->sf = sf;
    2083           0 :     ccd->fpst = fpst;
    2084           0 :     ccd->newname = newname;
    2085           0 :     ccd->isnew = newname!=NULL;
    2086           0 :     ccd->layer = layer;
    2087             : 
    2088           0 :     memset(&wattrs,0,sizeof(wattrs));
    2089           0 :     wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_undercursor|wam_isdlg|wam_restrict;
    2090           0 :     wattrs.event_masks = ~(1<<et_charup);
    2091           0 :     wattrs.is_dlg = true;
    2092           0 :     wattrs.restrict_input_to_me = false;
    2093           0 :     wattrs.undercursor = 1;
    2094           0 :     wattrs.cursor = ct_pointer;
    2095           0 :     wattrs.utf8_window_title = _(titles[ccd->isnew][fpst->type-pst_contextpos]);
    2096           0 :     pos.x = pos.y = 0;
    2097           0 :     pos.width =GDrawPointsToPixels(NULL,GGadgetScale(CCD_WIDTH));
    2098           0 :     pos.height = GDrawPointsToPixels(NULL,CCD_HEIGHT);
    2099           0 :     ccd->gw = gw = GDrawCreateTopWindow(NULL,&pos,ccd_e_h,ccd,&wattrs);
    2100             : 
    2101           0 :     subpos = pos;
    2102           0 :     subpos.y = subpos.x = 4;
    2103           0 :     subpos.width -= 8;
    2104           0 :     ccd->subheightdiff = GDrawPointsToPixels(NULL,44)-8;
    2105           0 :     subpos.height -= ccd->subheightdiff;
    2106             : 
    2107             : 
    2108           0 :     memset(&blabel,0,sizeof(blabel));
    2109           0 :     memset(&bgcd,0,sizeof(bgcd));
    2110           0 :     memset(&boxes,0,sizeof(boxes));
    2111             : 
    2112           0 :     ccd->canceldrop = GDrawPointsToPixels(NULL,30);
    2113           0 :     bgcd[0].gd.pos = subpos;
    2114           0 :     bgcd[0].gd.flags = gg_visible | gg_enabled | gg_pos_in_pixels;
    2115           0 :     bgcd[0].gd.cid = CID_SubSize;
    2116           0 :     bgcd[0].creator = GSpacerCreate;
    2117           0 :     hvarray[0][0] = &bgcd[0]; hvarray[0][1] = NULL;
    2118             : 
    2119           0 :     bgcd[1].gd.flags = gg_visible | gg_enabled;
    2120           0 :     blabel[1].text = (unichar_t *) _("_OK");
    2121           0 :     blabel[1].text_is_1byte = true;
    2122           0 :     blabel[1].text_in_resource = true;
    2123           0 :     bgcd[1].gd.label = &blabel[1];
    2124           0 :     bgcd[1].gd.cid = CID_OK;
    2125           0 :     bgcd[1].gd.handle_controlevent = CCD_OK;
    2126           0 :     bgcd[1].creator = GButtonCreate;
    2127           0 :     barray[0] = GCD_Glue; barray[1] = &bgcd[1];
    2128             : 
    2129           0 :     bgcd[2].gd.flags = gg_visible;
    2130           0 :     blabel[2].text = (unichar_t *) _("< _Prev");
    2131           0 :     blabel[2].text_is_1byte = true;
    2132           0 :     blabel[2].text_in_resource = true;
    2133           0 :     bgcd[2].gd.label = &blabel[2];
    2134           0 :     bgcd[2].gd.handle_controlevent = CCD_Prev;
    2135           0 :     bgcd[2].gd.cid = CID_Prev;
    2136           0 :     bgcd[2].creator = GButtonCreate;
    2137           0 :     barray[2] = GCD_Glue; barray[3] = &bgcd[2];
    2138             : 
    2139           0 :     bgcd[3].gd.flags = gg_visible;
    2140           0 :     blabel[3].text = (unichar_t *) _("_Next >");
    2141           0 :     blabel[3].text_is_1byte = true;
    2142           0 :     blabel[3].text_in_resource = true;
    2143           0 :     bgcd[3].gd.label = &blabel[3];
    2144           0 :     bgcd[3].gd.handle_controlevent = CCD_Next;
    2145           0 :     bgcd[3].gd.cid = CID_Next;
    2146           0 :     bgcd[3].creator = GButtonCreate;
    2147           0 :     barray[4] = GCD_Glue; barray[5] = &bgcd[3];
    2148             : 
    2149           0 :     bgcd[4].gd.flags = gg_visible | gg_enabled | gg_but_cancel;
    2150           0 :     blabel[4].text = (unichar_t *) _("_Cancel");
    2151           0 :     blabel[4].text_is_1byte = true;
    2152           0 :     blabel[4].text_in_resource = true;
    2153           0 :     bgcd[4].gd.label = &blabel[4];
    2154           0 :     bgcd[4].gd.handle_controlevent = CCD_Cancel;
    2155           0 :     bgcd[4].gd.cid = CID_Cancel;
    2156           0 :     bgcd[4].creator = GButtonCreate;
    2157           0 :     barray[6] = GCD_Glue; barray[7] = &bgcd[4]; barray[8] = GCD_Glue; barray[9] = NULL;
    2158             : 
    2159           0 :     boxes[2].gd.flags = gg_enabled | gg_visible;
    2160           0 :     boxes[2].gd.u.boxelements = barray;
    2161           0 :     boxes[2].creator = GHBoxCreate;
    2162           0 :     hvarray[1][0] = &boxes[2]; hvarray[1][1] = hvarray[2][0] = NULL;
    2163             : 
    2164           0 :     boxes[0].gd.pos.x = boxes[0].gd.pos.y = 2;
    2165           0 :     boxes[0].gd.flags = gg_enabled | gg_visible;
    2166           0 :     boxes[0].gd.u.boxelements = hvarray[0];
    2167           0 :     boxes[0].creator = GHVGroupCreate;
    2168             : 
    2169           0 :     if ( fpst->type == pst_reversesub ) {
    2170           0 :         bgcd[2].gd.flags = bgcd[3].gd.flags = gg_visible;
    2171           0 :         ccd->aw = use_simple ? aw_coverage_simple : aw_coverage;
    2172           0 :     } else if ( ccd->isnew || fpst->rule_cnt==0) {
    2173           0 :         fpst->format = pst_class;
    2174           0 :         bgcd[1].gd.flags = gg_visible;
    2175           0 :         bgcd[3].gd.flags = gg_visible | gg_enabled;
    2176           0 :         ccd->aw = aw_formats;
    2177           0 :     } else if ( fpst->format==pst_coverage ) {
    2178           0 :         bgcd[2].gd.flags = gg_visible | gg_enabled;
    2179           0 :         bgcd[3].gd.flags = gg_visible;
    2180           0 :         ccd->aw = use_simple ? aw_coverage_simple : aw_coverage;
    2181             :             /* different buttens are enabled from those of reversesub above */
    2182           0 :     } else if ( fpst->format==pst_class ) {
    2183           0 :         bgcd[2].gd.flags = gg_visible | gg_enabled;
    2184           0 :         bgcd[3].gd.flags = gg_visible;
    2185           0 :         ccd->aw = use_simple ? aw_classes_simple : aw_classrules;
    2186             :     } else {
    2187           0 :         bgcd[2].gd.flags = gg_visible | gg_enabled;
    2188           0 :         bgcd[3].gd.flags = gg_visible;
    2189           0 :         ccd->aw = use_simple ? aw_glyphs_simple : aw_grules;
    2190             :     }
    2191             : 
    2192           0 :     GGadgetsCreate(gw,boxes);
    2193           0 :     GHVBoxSetExpandableRow(boxes[0].ret,0);
    2194           0 :     GHVBoxSetExpandableCol(boxes[2].ret,gb_expandgluesame);
    2195             :     /*GHVBoxFitWindow(boxes[0].ret);*/
    2196             : 
    2197           0 :     wattrs.mask = wam_events;
    2198           0 :     ccd->formats = GWidgetCreateSubWindow(ccd->gw,&subpos,subccd_e_h,ccd,&wattrs);
    2199           0 :     memset(&rlabel,0,sizeof(rlabel));
    2200           0 :     memset(&rgcd,0,sizeof(rgcd));
    2201           0 :     memset(boxes,0,sizeof(boxes));
    2202             : 
    2203           0 :     i = 0;
    2204           0 :     rgcd[i].gd.pos.x = 5; rgcd[i].gd.pos.y = 5+i*13;
    2205           0 :     rgcd[i].gd.flags = gg_visible | gg_enabled;
    2206           0 :     rlabel[i].text = (unichar_t *) _(
    2207             :             "OpenType Contextual or Chaining subtables may be in one\n"
    2208             :             " of three formats. The context may be specified either\n"
    2209             :             " as a string of specific glyphs, a string of glyph classes\n"
    2210             :             " or a string of coverage tables\n"
    2211             :             "In the first format you must specify a string of glyph-names\n"
    2212             :             " In the second format you must specify a string of class names\n"
    2213             :             " In the third format you must specify a string each element\n"
    2214             :             "  of which may contain several glyph-names\n"
    2215             :             "For chaining subtables you may also specify backtrack and\n"
    2216             :             " lookahead lists.");
    2217           0 :     rlabel[i].text_is_1byte = true;
    2218           0 :     rgcd[i].gd.label = &rlabel[i];
    2219           0 :     rgcd[i++].creator = GLabelCreate;
    2220           0 :     hvarray[0][0] = &rgcd[i-1]; hvarray[0][1] = NULL;
    2221             : 
    2222           0 :     rgcd[i].gd.flags = gg_visible | gg_enabled | (fpst->format==pst_glyphs ? gg_cb_on : 0 );
    2223           0 :     rlabel[i].text = (unichar_t *) _("By Glyphs");
    2224           0 :     rlabel[i].text_is_1byte = true;
    2225           0 :     rgcd[i].gd.label = &rlabel[i];
    2226           0 :     rgcd[i].gd.cid = CID_ByGlyph;
    2227           0 :     rgcd[i++].creator = GRadioCreate;
    2228           0 :     barray[0] = GCD_HPad10; barray[1] = &rgcd[i-1];
    2229             : 
    2230           0 :     rgcd[i].gd.pos.x = rgcd[i-1].gd.pos.x; rgcd[i].gd.pos.y = rgcd[i-1].gd.pos.y+16;
    2231           0 :     rgcd[i].gd.flags = gg_visible | gg_enabled | (fpst->format==pst_class ? gg_cb_on : 0 );
    2232           0 :     rlabel[i].text = (unichar_t *) _("By Classes");
    2233           0 :     rlabel[i].text_is_1byte = true;
    2234           0 :     rgcd[i].gd.label = &rlabel[i];
    2235           0 :     rgcd[i].gd.cid = CID_ByClass;
    2236           0 :     rgcd[i++].creator = GRadioCreate;
    2237           0 :     barray[2] = &rgcd[i-1];
    2238             : 
    2239           0 :     rgcd[i].gd.pos.x = rgcd[i-1].gd.pos.x; rgcd[i].gd.pos.y = rgcd[i-1].gd.pos.y+16;
    2240           0 :     rgcd[i].gd.flags = gg_visible | gg_enabled | (fpst->format!=pst_glyphs && fpst->format!=pst_class ? gg_cb_on : 0 );
    2241           0 :     rlabel[i].text = (unichar_t *) _("By Coverage");
    2242           0 :     rlabel[i].text_is_1byte = true;
    2243           0 :     rgcd[i].gd.label = &rlabel[i];
    2244           0 :     rgcd[i].gd.cid = CID_ByCoverage;
    2245           0 :     rgcd[i++].creator = GRadioCreate;
    2246           0 :     barray[3] = &rgcd[i-1]; barray[4] = GCD_Glue; barray[5] = NULL;
    2247             : 
    2248           0 :     boxes[2].gd.flags = gg_enabled|gg_visible;
    2249           0 :     boxes[2].gd.u.boxelements = barray;
    2250           0 :     boxes[2].creator = GHBoxCreate;
    2251           0 :     hvarray[1][0] = &boxes[2]; hvarray[1][1] = NULL;
    2252             : 
    2253           0 :     rgcd[i].gd.flags = gg_visible | gg_enabled;
    2254           0 :     rlabel[i].text = (unichar_t *) _(
    2255             :             "This dialog has two formats. A simpler one which\n"
    2256             :             " hides some of the complexities of these rules,\n"
    2257             :             " or a more complex form which gives you full control.");
    2258           0 :     rlabel[i].text_is_1byte = true;
    2259           0 :     rgcd[i].gd.label = &rlabel[i];
    2260           0 :     rgcd[i++].creator = GLabelCreate;
    2261           0 :     hvarray[2][0] = GCD_HPad10; hvarray[2][1] = NULL;
    2262           0 :     hvarray[3][0] = &rgcd[i-1]; hvarray[3][1] = NULL;
    2263             : 
    2264           0 :     rgcd[i].gd.pos.x = 5; rgcd[i].gd.pos.y = 5+i*13;
    2265           0 :     rgcd[i].gd.flags = gg_visible | gg_enabled;
    2266           0 :     rlabel[i].text = (unichar_t *) _( "Dialog Type:");
    2267           0 :     rlabel[i].text_is_1byte = true;
    2268           0 :     rgcd[i].gd.label = &rlabel[i];
    2269           0 :     rgcd[i++].creator = GLabelCreate;
    2270           0 :     barray2[0] = GCD_HPad10; barray2[1] = &rgcd[i-1];
    2271             : 
    2272           0 :     rgcd[i].gd.pos.x = rgcd[i-1].gd.pos.x; rgcd[i].gd.pos.y = rgcd[i-1].gd.pos.y+16;
    2273           0 :     rgcd[i].gd.flags = gg_visible | gg_enabled | (use_simple ? gg_cb_on : 0 );
    2274           0 :     rlabel[i].text = (unichar_t *) _("Simple");
    2275           0 :     rlabel[i].text_is_1byte = true;
    2276           0 :     rgcd[i].gd.label = &rlabel[i];
    2277           0 :     rgcd[i].gd.cid = CID_Simple;
    2278           0 :     rgcd[i++].creator = GRadioCreate;
    2279           0 :     barray2[2] = &rgcd[i-1];
    2280             : 
    2281           0 :     rgcd[i].gd.pos.x = rgcd[i-1].gd.pos.x; rgcd[i].gd.pos.y = rgcd[i-1].gd.pos.y+16;
    2282           0 :     rgcd[i].gd.flags = gg_visible | gg_enabled | (!use_simple ? gg_cb_on : 0 );
    2283           0 :     rlabel[i].text = (unichar_t *) _("Complex");
    2284           0 :     rlabel[i].text_is_1byte = true;
    2285           0 :     rgcd[i].gd.label = &rlabel[i];
    2286           0 :     rgcd[i].gd.cid = CID_Complex;
    2287           0 :     rgcd[i++].creator = GRadioCreate;
    2288           0 :     barray2[3] = &rgcd[i-1]; barray2[4] = GCD_Glue; barray2[5] = NULL;
    2289             : 
    2290           0 :     boxes[3].gd.flags = gg_enabled|gg_visible;
    2291           0 :     boxes[3].gd.u.boxelements = barray2;
    2292           0 :     boxes[3].creator = GHBoxCreate;
    2293           0 :     hvarray[4][0] = &boxes[3]; hvarray[4][1] = NULL;
    2294           0 :     hvarray[5][0] = GCD_Glue; hvarray[5][1] = NULL; hvarray[6][0] = NULL;
    2295             : 
    2296           0 :     boxes[0].gd.pos.x = boxes[0].gd.pos.y = 2;
    2297           0 :     boxes[0].gd.flags = gg_enabled|gg_visible;
    2298           0 :     boxes[0].gd.u.boxelements = hvarray[0];
    2299           0 :     boxes[0].creator = GHVGroupCreate;
    2300             : 
    2301           0 :     GGadgetsCreate(ccd->formats,boxes);
    2302           0 :     GHVBoxSetExpandableRow(boxes[0].ret,gb_expandglue);
    2303           0 :     GHVBoxSetExpandableCol(boxes[2].ret,gb_expandgluesame);
    2304           0 :     GHVBoxSetExpandableCol(boxes[3].ret,gb_expandglue);
    2305             : 
    2306             :         /* Pane showing all rules from a glyph format, simple format */
    2307           0 :     ccd->grules = GWidgetCreateSubWindow(ccd->gw,&subpos,subccd_e_h,ccd,&wattrs);
    2308           0 :     memset(&gllabel,0,sizeof(gllabel));
    2309           0 :     memset(&glgcd,0,sizeof(glgcd));
    2310             : 
    2311           0 :     k = 0;
    2312           0 :     memset(&glyphrules_mi,0,sizeof(glyphrules_mi));
    2313           0 :     glyphrules_mi.col_cnt = 1;
    2314           0 :     glyphrules_mi.col_init = glyphrules_ci;
    2315           0 :     if ( fpst->format==pst_glyphs && fpst->rule_cnt>0 ) {
    2316           0 :         glyphrules_mi.initial_row_cnt = fpst->rule_cnt;
    2317           0 :         md = calloc(fpst->rule_cnt,sizeof(struct matrix_data));
    2318           0 :         for ( j=0; j<fpst->rule_cnt; ++j ) {
    2319           0 :             md[j+0].u.md_str = gruleitem(&fpst->rules[j]);
    2320             :         }
    2321           0 :         glyphrules_mi.matrix_data = md;
    2322             :     } else {
    2323           0 :         glyphrules_mi.initial_row_cnt = 0;
    2324           0 :         glyphrules_mi.matrix_data = NULL;
    2325             :     }
    2326           0 :     glgcd[k].gd.flags = gg_visible | gg_enabled;
    2327           0 :     glgcd[k].gd.cid = CID_GList+0;
    2328           0 :     glgcd[k].gd.u.matrix = &glyphrules_mi;
    2329           0 :     glgcd[k++].creator = GMatrixEditCreate;
    2330             :     /* No need for a box, this widget fills the pane */
    2331             : 
    2332           0 :     GGadgetsCreate(ccd->grules,glgcd);
    2333           0 :     GMatrixEditSetUpDownVisible(GWidgetGetControl(ccd->grules,CID_GList+0),
    2334             :             true);
    2335           0 :     GMatrixEditSetOtherButtonEnable(GWidgetGetControl(ccd->grules,CID_GList+0),CCD_NewGlyphRule);
    2336             : 
    2337           0 :     ccd->glyphs_simple = GWidgetCreateSubWindow(ccd->gw,&subpos,subccd_e_h,ccd,&wattrs);
    2338           0 :     memset(&gllabel,0,sizeof(gllabel));
    2339           0 :     memset(&glgcd,0,sizeof(glgcd));
    2340             : 
    2341           0 :     k = 0;
    2342           0 :     memset(&glyphs_mi,0,sizeof(glyphs_mi));
    2343           0 :     glyphs_mi.col_cnt = 1;
    2344           0 :     glyphs_mi.col_init = glyph_ci;
    2345           0 :     if ( fpst->format==pst_glyphs && fpst->rule_cnt>0 ) {
    2346           0 :         glyphs_mi.initial_row_cnt = fpst->rule_cnt;
    2347           0 :         md = calloc(fpst->rule_cnt,sizeof(struct matrix_data));
    2348           0 :         for ( j=0; j<fpst->rule_cnt; ++j ) {
    2349           0 :             md[j+0].u.md_str = FPSTRule_To_Str(sf,fpst,&fpst->rules[j]);;
    2350             :         }
    2351           0 :         glyphs_mi.matrix_data = md;
    2352             :     } else {
    2353           0 :         glyphs_mi.initial_row_cnt = 0;
    2354           0 :         glyphs_mi.matrix_data = NULL;
    2355             :     }
    2356           0 :     glgcd[k].gd.flags = gg_visible | gg_enabled;
    2357           0 :     glgcd[k].gd.cid = CID_GList_Simple;
    2358           0 :     glgcd[k].gd.u.matrix = &glyphs_mi;
    2359           0 :     glgcd[k++].creator = GMatrixEditCreate;
    2360             :     /* No need for a box, this widget fills the pane */
    2361             : 
    2362           0 :     GGadgetsCreate(ccd->glyphs_simple,glgcd);
    2363           0 :     GMatrixEditSetUpDownVisible(GWidgetGetControl(ccd->glyphs_simple,CID_GList_Simple),
    2364             :             true);
    2365           0 :     GMatrixEditSetColumnCompletion(GWidgetGetControl(ccd->glyphs_simple,CID_GList_Simple),0,
    2366             :             CCD_GlyphListCompletion);
    2367             : 
    2368           0 :     memset(&extrabuttonslab,0,sizeof(extrabuttonslab));
    2369           0 :     memset(&extrabuttonsgcd,0,sizeof(extrabuttonsgcd));
    2370             : 
    2371           0 :     i=0;
    2372           0 :     if ( fpst->type==pst_chainpos || fpst->type==pst_chainsub ) {
    2373           0 :         extrabuttonsgcd[i].gd.flags = gg_visible | gg_enabled;
    2374           0 :         extrabuttonslab[i].text = (unichar_t *) _("New Section");
    2375           0 :         extrabuttonslab[i].text_is_1byte = true;
    2376           0 :         extrabuttonsgcd[i].gd.label = &extrabuttonslab[i];
    2377           0 :         extrabuttonsgcd[i].gd.cid = CID_GNewSection;
    2378           0 :         extrabuttonsgcd[i].gd.handle_controlevent = CCD_NewSection;
    2379           0 :         extrabuttonsgcd[i++].creator = GButtonCreate;
    2380             :     }
    2381           0 :     extrabuttonsgcd[i].gd.flags = gg_visible | gg_enabled;
    2382           0 :     extrabuttonslab[i].text = (unichar_t *) _("Add Lookup");
    2383           0 :     extrabuttonslab[i].text_is_1byte = true;
    2384           0 :     extrabuttonsgcd[i].gd.u.list = addlookup_list;
    2385           0 :     extrabuttonsgcd[i].gd.label = &extrabuttonslab[i];
    2386             :     {
    2387             :         extern FontInstance *_ggadget_default_font;
    2388           0 :         GDrawSetFont(ccd->glyphs_simple,_ggadget_default_font);
    2389             :     }
    2390           0 :     extrabuttonsgcd[i].gd.pos.width = GDrawPixelsToPoints(ccd->glyphs_simple,
    2391           0 :             GDrawGetText8Width(ccd->glyphs_simple,(char *)extrabuttonslab[i].text,-1))+50;
    2392           0 :     extrabuttonsgcd[i].gd.cid = CID_GAddLookup;
    2393           0 :     extrabuttonsgcd[i].gd.handle_controlevent = CCD_AddLookup;
    2394           0 :     extrabuttonsgcd[i++].creator = GListButtonCreate;
    2395           0 :     GMatrixEditAddButtons(GWidgetGetControl(ccd->glyphs_simple,CID_GList_Simple),extrabuttonsgcd);
    2396             : 
    2397             :         /* Pane showing a single rule from a glyph format (not classes or coverage tables) */
    2398           0 :     ccd->glyphs = GWidgetCreateSubWindow(ccd->gw,&subpos,subccd_e_h,ccd,&wattrs);
    2399           0 :     memset(&ggcd,0,sizeof(ggcd));
    2400           0 :     memset(&fgcd,0,sizeof(fgcd));
    2401           0 :     memset(&glabel,0,sizeof(glabel));
    2402           0 :     memset(&flabel,0,sizeof(flabel));
    2403           0 :     memset(&faspects,0,sizeof(faspects));
    2404           0 :     memset(&subboxes,0,sizeof(subboxes));
    2405           0 :     memset(&topbox,0,sizeof(topbox));
    2406           0 :     for ( i=0; i<3; ++i ) {  /* Match, background foreground tabs */
    2407           0 :         k=0;
    2408           0 :         glabel[i][k].text = (unichar_t *) _("Set From Selection");
    2409           0 :         glabel[i][k].text_is_1byte = true;
    2410           0 :         ggcd[i][k].gd.label = &glabel[i][k];
    2411           0 :         ggcd[i][k].gd.popup_msg = (unichar_t *) _("Set this glyph list from a selection.");
    2412           0 :         ggcd[i][k].gd.flags = gg_visible | gg_enabled | gg_utf8_popup;
    2413           0 :         ggcd[i][k].gd.handle_controlevent = CCD_FromSelection;
    2414           0 :         ggcd[i][k].data=(void *)((intpt)CID_GlyphList+(0*100+i*20));
    2415           0 :         ggcd[i][k++].creator = GButtonCreate;
    2416           0 :         subvarray[i][0] = &ggcd[i][k-1];
    2417             : 
    2418           0 :         ggcd[i][k].gd.flags = gg_visible | gg_enabled | gg_textarea_wrap;
    2419           0 :         ggcd[i][k].gd.cid = CID_GlyphList+(0*100+i*20);
    2420           0 :         ggcd[i][k].gd.u.completion = CCD_GlyphListCompletion;
    2421           0 :         ggcd[i][k++].creator = GTextCompletionCreate;
    2422           0 :         subvarray[i][1] = &ggcd[i][k-1];
    2423             : 
    2424           0 :         if ( i==0 ) {
    2425           0 :             glabel[i][k].text = (unichar_t *) _("An ordered list of lookups and positions");
    2426           0 :             glabel[i][k].text_is_1byte = true;
    2427           0 :             ggcd[i][k].gd.label = &glabel[i][k];
    2428           0 :             ggcd[i][k].gd.flags = gg_visible | gg_enabled;
    2429           0 :             ggcd[i][k++].creator = GLabelCreate;
    2430           0 :             subvarray[i][2] = &ggcd[i][k-1];
    2431             : 
    2432           0 :             memset(&gl_seqlookup_mi,0,sizeof(gl_seqlookup_mi));
    2433           0 :             gl_seqlookup_mi.col_cnt = 2;
    2434           0 :             gl_seqlookup_mi.col_init = seqlookup_ci;
    2435           0 :             gl_seqlookup_mi.matrix_data = NULL;
    2436           0 :             gl_seqlookup_mi.initial_row_cnt = 0;
    2437             : 
    2438           0 :             ggcd[i][k].gd.flags = gg_visible | gg_enabled;
    2439           0 :             ggcd[i][k].gd.cid = CID_LookupList+0;
    2440           0 :             ggcd[i][k].gd.u.matrix = &gl_seqlookup_mi;
    2441           0 :             ggcd[i][k++].creator = GMatrixEditCreate;
    2442           0 :             subvarray[i][3] = &ggcd[i][k-1];
    2443             :         } else
    2444           0 :             subvarray[i][2] = subvarray[i][3] = GCD_Glue;
    2445           0 :         subvarray[i][4] = NULL;
    2446             : 
    2447           0 :         subboxes[i][0].gd.flags = gg_enabled|gg_visible;
    2448           0 :         subboxes[i][0].gd.u.boxelements = subvarray[i];
    2449           0 :         subboxes[i][0].creator = GVBoxCreate;
    2450             :     }
    2451             : 
    2452           0 :     j = 0;
    2453             : 
    2454           0 :     faspects[j].text = (unichar_t *) _("Match");
    2455           0 :     faspects[j].text_is_1byte = true;
    2456           0 :     faspects[j].selected = true;
    2457           0 :     faspects[j].gcd = subboxes[j]; ++j;
    2458             : 
    2459           0 :     faspects[j].text = (unichar_t *) _("Backtrack");
    2460           0 :     faspects[j].text_is_1byte = true;
    2461           0 :     faspects[j].disabled = fpst->type==pst_contextpos || fpst->type==pst_contextsub;
    2462           0 :     faspects[j].gcd = subboxes[j]; ++j;
    2463             : 
    2464           0 :     faspects[j].text = (unichar_t *) _("Lookahead");
    2465           0 :     faspects[j].text_is_1byte = true;
    2466           0 :     faspects[j].disabled = fpst->type==pst_contextpos || fpst->type==pst_contextsub;
    2467           0 :     faspects[j].gcd = subboxes[j]; ++j;
    2468             : 
    2469           0 :     flabel[0].text = (unichar_t *) _("A list of glyphs:");
    2470           0 :     flabel[0].text_is_1byte = true;
    2471           0 :     fgcd[0].gd.label = &flabel[0];
    2472           0 :     fgcd[0].gd.flags = gg_visible | gg_enabled;
    2473           0 :     fgcd[0].creator = GLabelCreate;
    2474           0 :     topvarray[0] = &fgcd[0];
    2475             : 
    2476           0 :     fgcd[1].gd.u.tabs = faspects;
    2477           0 :     fgcd[1].gd.flags = gg_visible | gg_enabled;
    2478           0 :     fgcd[1].gd.cid = CID_MatchType;
    2479           0 :     fgcd[1].creator = GTabSetCreate;
    2480           0 :     topvarray[1] = &fgcd[1];
    2481           0 :     topvarray[2] = NULL;
    2482           0 :     topbox[0].gd.flags = gg_enabled|gg_visible;
    2483           0 :     topbox[0].gd.u.boxelements = topvarray;
    2484           0 :     topbox[0].creator = GVBoxCreate;
    2485           0 :     GGadgetsCreate(ccd->glyphs,topbox);
    2486             : 
    2487           0 :     GMatrixEditSetUpDownVisible(GWidgetGetControl(ccd->glyphs,CID_LookupList+0),
    2488             :             true);
    2489           0 :     GHVBoxSetExpandableRow(topbox[0].ret,1);
    2490           0 :     GHVBoxSetExpandableRow(subboxes[0][0].ret,3);
    2491           0 :     GHVBoxSetExpandableRow(subboxes[1][0].ret,gb_expandglue);
    2492           0 :     GHVBoxSetExpandableRow(subboxes[2][0].ret,gb_expandglue);
    2493             : 
    2494             :         /* Pane showing the single rule in a coverage table (complex) */
    2495           0 :     ccd->coverage = GWidgetCreateSubWindow(ccd->gw,&subpos,subccd_e_h,ccd,&wattrs);
    2496           0 :     memset(&clabel,0,sizeof(clabel));
    2497           0 :     memset(&cgcd,0,sizeof(cgcd));
    2498           0 :     memset(&subboxes,0,sizeof(subboxes));
    2499           0 :     memset(&topbox,0,sizeof(topbox));
    2500             : 
    2501           0 :     for ( i=0; i<3; ++i ) {
    2502           0 :         k = 0;
    2503           0 :         memset(&coverage_mi[i],0,sizeof(coverage_mi[i]));
    2504           0 :         coverage_mi[i].col_cnt = 1;
    2505           0 :         coverage_mi[i].col_init = coverage_ci;
    2506           0 :         if (( fpst->format==pst_coverage || fpst->format==pst_reversecoverage )
    2507           0 :                 && fpst->rules!=NULL ) {
    2508           0 :             int cnt = (&fpst->rules[0].u.coverage.ncnt)[i];
    2509           0 :             char **names = (&fpst->rules[0].u.coverage.ncovers)[i];
    2510           0 :             coverage_mi[i].initial_row_cnt = cnt;
    2511           0 :             md = calloc(cnt,sizeof(struct matrix_data));
    2512           0 :             for ( j=0; j<cnt; ++j ) {
    2513           0 :                 md[j].u.md_str = SFNameList2NameUni(sf,names[j]);
    2514             :             }
    2515           0 :             coverage_mi[i].matrix_data = md;
    2516             :         } else {
    2517           0 :             coverage_mi[i].initial_row_cnt = 0;
    2518           0 :             coverage_mi[i].matrix_data = NULL;
    2519             :         }
    2520           0 :         coverage_mi[i].finishedit = CCD_FinishCoverageEdit;
    2521           0 :         cgcd[i][k].gd.flags = gg_visible | gg_enabled;
    2522           0 :         cgcd[i][k].gd.cid = CID_GList+100+i*20;
    2523           0 :         cgcd[i][k].gd.u.matrix = &coverage_mi[i];
    2524           0 :         cgcd[i][k++].creator = GMatrixEditCreate;
    2525             : 
    2526           0 :         faspects[i].gcd = &cgcd[i][k-1];
    2527             : 
    2528           0 :         if ( i==0 ) {
    2529           0 :             if ( ccd->fpst->type!=pst_reversesub ) {
    2530           0 :                 clabel[i][k].text = (unichar_t *) _("An ordered list of lookups and positions");
    2531           0 :                 clabel[i][k].text_is_1byte = true;
    2532           0 :                 cgcd[i][k].gd.label = &clabel[i][k];
    2533           0 :                 cgcd[i][k].gd.flags = gg_visible | gg_enabled;
    2534           0 :                 cgcd[i][k++].creator = GLabelCreate;
    2535           0 :                 subvarray2[0] = &cgcd[i][k-1];
    2536             : 
    2537           0 :                 memset(&co_seqlookup_mi,0,sizeof(co_seqlookup_mi));
    2538           0 :                 co_seqlookup_mi.col_cnt = 2;
    2539           0 :                 co_seqlookup_mi.col_init = seqlookup_ci;
    2540           0 :                 if ( fpst->format==pst_coverage ) {
    2541           0 :                     r = &fpst->rules[0];
    2542           0 :                     co_seqlookup_mi.initial_row_cnt = r->lookup_cnt;
    2543           0 :                     md = calloc(2*r->lookup_cnt,sizeof(struct matrix_data));
    2544           0 :                     for ( j=0; j<r->lookup_cnt; ++j ) {
    2545           0 :                         md[2*j+0].u.md_ival = (intpt) (void *) r->lookups[j].lookup;
    2546           0 :                         md[2*j+1].u.md_ival = (intpt) r->lookups[j].seq;
    2547             :                     }
    2548           0 :                     co_seqlookup_mi.matrix_data = md;
    2549             :                 } else {
    2550           0 :                     co_seqlookup_mi.initial_row_cnt = 0;
    2551           0 :                     co_seqlookup_mi.matrix_data = NULL;
    2552             :                 }
    2553           0 :                 cgcd[i][k].gd.flags = gg_visible | gg_enabled;
    2554           0 :                 cgcd[i][k].gd.cid = CID_LookupList+100+(i*20);
    2555           0 :                 cgcd[i][k].gd.u.matrix = &co_seqlookup_mi;
    2556           0 :                 cgcd[i][k++].creator = GMatrixEditCreate;
    2557           0 :                 subvarray2[1] = &cgcd[i][k-1];
    2558           0 :                 subvarray2[2] = NULL;
    2559             : 
    2560           0 :                 subboxes[i][1].gd.flags = gg_enabled|gg_visible;
    2561           0 :                 subboxes[i][1].gd.u.boxelements = subvarray2;
    2562           0 :                 subboxes[i][1].creator = GVBoxCreate;
    2563             : 
    2564           0 :                 subvarray3[0] = &cgcd[i][0];
    2565           0 :                 subvarray3[1] = &subboxes[i][1];
    2566           0 :                 subvarray3[2] = NULL;
    2567             : 
    2568           0 :                 subboxes[i][2].gd.flags = gg_enabled|gg_visible;
    2569           0 :                 subboxes[i][2].gd.u.boxelements = subvarray3;
    2570           0 :                 subboxes[i][2].creator = GVBoxCreate;
    2571           0 :                 faspects[i].gcd = subboxes[i]+2;
    2572             :             } else {
    2573           0 :                 r = NULL;
    2574           0 :                 if ( fpst->rule_cnt==1 ) r = &fpst->rules[0];
    2575             : 
    2576           0 :                 clabel[i][k].text = (unichar_t *) _("Replacements");
    2577           0 :                 clabel[i][k].text_is_1byte = true;
    2578           0 :                 cgcd[i][k].gd.label = &clabel[i][k];
    2579           0 :                 cgcd[i][k].gd.flags = gg_visible | gg_enabled;
    2580           0 :                 cgcd[i][k++].creator = GLabelCreate;
    2581           0 :                 subvarray2[0] = &cgcd[i][k-1];
    2582             : 
    2583           0 :                 clabel[i][k].text = (unichar_t *) _("Set From Selection");
    2584           0 :                 clabel[i][k].text_is_1byte = true;
    2585           0 :                 cgcd[i][k].gd.label = &clabel[i][k];
    2586           0 :                 cgcd[i][k].gd.popup_msg = (unichar_t *) _("Set this glyph list from a selection.");
    2587           0 :                 cgcd[i][k].gd.flags = gg_visible | gg_enabled | gg_utf8_popup;
    2588           0 :                 cgcd[i][k].gd.handle_controlevent = CCD_FromSelection;
    2589           0 :                 cgcd[i][k].data = (void *) (intpt) (CID_RplList+100);
    2590           0 :                 cgcd[i][k++].creator = GButtonCreate;
    2591           0 :                 subvarray2[1] = &cgcd[i][k-1];
    2592           0 :                 subvarray2[2] = GCD_Glue;
    2593           0 :                 subvarray2[3] = NULL;
    2594             : 
    2595           0 :                 subboxes[i][1].gd.flags = gg_enabled|gg_visible;
    2596           0 :                 subboxes[i][1].gd.u.boxelements = subvarray2;
    2597           0 :                 subboxes[i][1].creator = GHBoxCreate;
    2598           0 :                 subvarray3[0] = &subboxes[i][1];
    2599             : 
    2600           0 :                 if ( r!=NULL && r->u.rcoverage.replacements!=NULL ) {
    2601           0 :                     clabel[i][k].text = (unichar_t *) SFNameList2NameUni(sf,r->u.rcoverage.replacements);
    2602           0 :                     clabel[i][k].text_is_1byte = true;
    2603           0 :                     cgcd[i][k].gd.label = &clabel[i][k];
    2604             :                 }
    2605           0 :                 cgcd[i][k].gd.flags = gg_visible | gg_enabled;
    2606           0 :                 cgcd[i][k].gd.cid = CID_RplList+100;
    2607           0 :                 cgcd[i][k].gd.u.completion = CCD_GlyphListCompletion;
    2608           0 :                 cgcd[i][k++].creator = GTextCompletionCreate;
    2609           0 :                 subvarray3[1] = &cgcd[i][k-1];
    2610           0 :                 subvarray3[2] = GCD_Glue;
    2611           0 :                 subvarray3[3] = NULL;
    2612             : 
    2613           0 :                 subboxes[i][2].gd.flags = gg_enabled|gg_visible;
    2614           0 :                 subboxes[i][2].gd.u.boxelements = subvarray3;
    2615           0 :                 subboxes[i][2].creator = GVBoxCreate;
    2616             : 
    2617           0 :                 subvarray4[0] = &cgcd[i][0];
    2618           0 :                 subvarray4[1] = &subboxes[i][2];
    2619           0 :                 subvarray4[2] = NULL;
    2620             : 
    2621           0 :                 subboxes[i][3].gd.flags = gg_enabled|gg_visible;
    2622           0 :                 subboxes[i][3].gd.u.boxelements = subvarray4;
    2623           0 :                 subboxes[i][3].creator = GVBoxCreate;
    2624           0 :                 faspects[i].gcd = subboxes[i]+3;
    2625             :             }
    2626             :         }
    2627             :     }
    2628             : 
    2629           0 :     flabel[0].text = (unichar_t *) _("A coverage table:");
    2630           0 :     flabel[0].text_is_1byte = true;
    2631           0 :     fgcd[0].gd.label = &flabel[0];
    2632           0 :     fgcd[0].gd.flags = gg_visible | gg_enabled;
    2633           0 :     fgcd[0].creator = GLabelCreate;
    2634           0 :     topvarray[0] = &fgcd[0];
    2635             : 
    2636           0 :     fgcd[1].gd.u.tabs = faspects;
    2637           0 :     fgcd[1].gd.flags = gg_visible | gg_enabled;
    2638           0 :     fgcd[1].gd.cid = CID_MatchType+100;
    2639           0 :     fgcd[1].creator = GTabSetCreate;
    2640           0 :     topvarray[1] = &fgcd[1];
    2641           0 :     topvarray[2] = NULL;
    2642           0 :     topbox[0].gd.flags = gg_enabled|gg_visible;
    2643           0 :     topbox[0].gd.u.boxelements = topvarray;
    2644           0 :     topbox[0].creator = GVBoxCreate;
    2645           0 :     GGadgetsCreate(ccd->coverage,topbox);
    2646           0 :     for ( i=0; i<3; ++i ) {
    2647           0 :         GMatrixEditSetUpDownVisible(GWidgetGetControl(ccd->coverage,CID_GList+100+i*20),
    2648             :                 true);
    2649           0 :         GMatrixEditSetColumnCompletion(GWidgetGetControl(ccd->coverage,CID_GList+100+i*20),0,
    2650             :                 CCD_GlyphListCompletion);
    2651             :     }
    2652           0 :     if ( ccd->fpst->type!=pst_reversesub ) {
    2653           0 :         GMatrixEditSetUpDownVisible(GWidgetGetControl(ccd->coverage,CID_LookupList+100+0),
    2654             :                 true);
    2655           0 :         GHVBoxSetExpandableRow(subboxes[0][1].ret,1);
    2656             :     } else {
    2657           0 :         GHVBoxSetExpandableCol(subboxes[0][1].ret,gb_expandglue);
    2658           0 :         GHVBoxSetExpandableRow(subboxes[0][2].ret,gb_expandglue);
    2659             :     }
    2660           0 :     GHVBoxSetExpandableRow(topbox[0].ret,1);
    2661             : 
    2662             :         /* Pane showing the single rule in a coverage table (simple) */
    2663           0 :     ccd->coverage_simple = GWidgetCreateSubWindow(ccd->gw,&subpos,subccd_e_h,ccd,&wattrs);
    2664           0 :     memset(&clabel,0,sizeof(clabel));
    2665           0 :     memset(&cgcd,0,sizeof(cgcd));
    2666           0 :     memset(&subboxes,0,sizeof(subboxes));
    2667           0 :     memset(&flabel,0,sizeof(flabel));
    2668           0 :     memset(&fgcd,0,sizeof(fgcd));
    2669           0 :     memset(&topbox,0,sizeof(topbox));
    2670             : 
    2671           0 :     memset(&coveragesimple_mi,0,sizeof(coveragesimple_mi));
    2672           0 :     coveragesimple_mi.col_cnt = 4;
    2673           0 :     coveragesimple_mi.col_init = coveragesimple_ci;
    2674           0 :     if ( fpst->format==pst_reversecoverage ) {
    2675           0 :         coveragesimple_mi.col_cnt = 2;
    2676           0 :         coveragesimple_mi.col_init = rcoveragesimple_ci;
    2677             :     }
    2678           0 :     if (( fpst->format==pst_coverage || fpst->format==pst_reversecoverage )
    2679           0 :             && fpst->rules!=NULL ) {
    2680           0 :         int cnt = fpst->rules[0].u.coverage.ncnt+fpst->rules[0].u.coverage.bcnt+fpst->rules[0].u.coverage.fcnt;
    2681           0 :         coveragesimple_mi.initial_row_cnt = cnt;
    2682           0 :         md = calloc(cnt*coveragesimple_mi.col_cnt,sizeof(struct matrix_data));
    2683           0 :         for ( i=0,j=fpst->rules[0].u.coverage.bcnt-1; j>=0; --j, ++i )
    2684           0 :             md[i*coveragesimple_mi.col_cnt].u.md_str = SFNameList2NameUni(sf,fpst->rules[0].u.coverage.bcovers[j]);
    2685           0 :         for ( j=0; j<fpst->rules[0].u.coverage.ncnt; ++j, ++i ) {
    2686           0 :             md[coveragesimple_mi.col_cnt*i+0].u.md_str = SFNameList2NameUni(sf,fpst->rules[0].u.coverage.ncovers[j]);
    2687           0 :             if ( fpst->format==pst_reversecoverage )
    2688           0 :                 md[i*2+1].u.md_str = SFNameList2NameUni(sf,fpst->rules[0].u.rcoverage.replacements);
    2689             :             else {
    2690           0 :                 md[4*i+2].u.md_ival = j==0;
    2691           0 :                 for ( k=0; k<fpst->rules[0].lookup_cnt; ++k ) {
    2692           0 :                     if ( fpst->rules[0].lookups[k].seq==j ) {
    2693           0 :                         md[4*i+1].u.md_addr = md[4*i+3].u.md_addr = fpst->rules[0].lookups[k].lookup;
    2694           0 :                 break;
    2695             :                     }
    2696             :                 }
    2697             :             }
    2698             :         }
    2699           0 :         for ( j=0; j<fpst->rules[0].u.coverage.fcnt; ++j, ++i ) {
    2700           0 :             md[coveragesimple_mi.col_cnt*i].u.md_str = SFNameList2NameUni(sf,fpst->rules[0].u.coverage.fcovers[j]);
    2701           0 :             if ( fpst->format==pst_coverage )
    2702           0 :                 md[4*i+2].u.md_ival = j==0;
    2703             :         }
    2704           0 :         coveragesimple_mi.matrix_data = md;
    2705             :     } else {
    2706           0 :         coveragesimple_mi.initial_row_cnt = 0;
    2707           0 :         coveragesimple_mi.matrix_data = NULL;
    2708             :     }
    2709           0 :     coveragesimple_mi.finishedit = CCD_FinishCoverageSimpleEdit;
    2710             : 
    2711           0 :     flabel[0].text = (unichar_t *) _("A list of coverage tables:");
    2712           0 :     flabel[0].text_is_1byte = true;
    2713           0 :     fgcd[0].gd.label = &flabel[0];
    2714           0 :     fgcd[0].gd.flags = gg_visible | gg_enabled;
    2715           0 :     fgcd[0].creator = GLabelCreate;
    2716           0 :     topvarray[0] = &fgcd[0];
    2717             : 
    2718           0 :     fgcd[1].gd.flags = gg_visible | gg_enabled;
    2719           0 :     fgcd[1].gd.cid = CID_Covers;
    2720           0 :     fgcd[1].gd.u.matrix = &coveragesimple_mi;
    2721           0 :     fgcd[1].creator = GMatrixEditCreate;
    2722           0 :     topvarray[1] = &fgcd[1];
    2723           0 :     topvarray[2] = NULL;
    2724           0 :     topbox[0].gd.flags = gg_enabled|gg_visible;
    2725           0 :     topbox[0].gd.u.boxelements = topvarray;
    2726           0 :     topbox[0].creator = GVBoxCreate;
    2727           0 :     GGadgetsCreate(ccd->coverage_simple,topbox);
    2728           0 :     GMatrixEditSetUpDownVisible(GWidgetGetControl(ccd->coverage_simple,CID_Covers),
    2729             :             true);
    2730           0 :     GMatrixEditSetColumnCompletion(GWidgetGetControl(ccd->coverage_simple,CID_Covers),0,
    2731             :             CCD_GlyphListCompletion);
    2732           0 :     if ( fpst->type==pst_reversesub ) {
    2733           0 :         GMatrixEditSetColumnCompletion(GWidgetGetControl(ccd->coverage_simple,CID_Covers),1,
    2734             :                 CCD_GlyphListCompletion);
    2735             :     }
    2736           0 :     GHVBoxSetExpandableRow(topbox[0].ret,1);
    2737           0 :     if ( fpst->type == pst_contextpos || fpst->type == pst_contextsub )
    2738           0 :         GMatrixEditShowColumn(GWidgetGetControl(ccd->coverage_simple,CID_Covers),2,false);
    2739           0 :     if ( fpst->format!=pst_reversecoverage )
    2740           0 :         GMatrixEditShowColumn(GWidgetGetControl(ccd->coverage_simple,CID_Covers),3,false);
    2741             : 
    2742             : 
    2743             :         /* This pane displays a set of class rules, and below the three sets of classes for those rules */
    2744           0 :     ccd->classrules = GWidgetCreateSubWindow(ccd->gw,&subpos,subccd_e_h,ccd,&wattrs);
    2745           0 :     memset(&cllabel,0,sizeof(cllabel));
    2746           0 :     memset(&clgcd,0,sizeof(clgcd));
    2747           0 :     memset(&clabel,0,sizeof(clabel));
    2748           0 :     memset(&cgcd,0,sizeof(cgcd));
    2749           0 :     memset(&subboxes,0,sizeof(subboxes));
    2750           0 :     memset(&topbox,0,sizeof(topbox));
    2751           0 :     memset(&classbox,0,sizeof(classbox));
    2752             : 
    2753           0 :     tempfpst = fpst;
    2754           0 :     if ( fpst->format==pst_glyphs && fpst->rule_cnt>0 )
    2755           0 :         tempfpst = FPSTGlyphToClass(fpst);
    2756             : 
    2757           0 :     k=0;
    2758             : 
    2759           0 :     memset(&classrules_mi,0,sizeof(classrules_mi));
    2760           0 :     classrules_mi.col_cnt = 1;
    2761           0 :     classrules_mi.col_init = classrules_ci;
    2762             :     /* Further inits happen after we've set up the classnames */
    2763           0 :     clgcd[k].gd.flags = gg_visible | gg_enabled;
    2764           0 :     clgcd[k].gd.cid = CID_GList+200;
    2765           0 :     clgcd[k].gd.u.matrix = &classrules_mi;
    2766           0 :     clgcd[k++].creator = GMatrixEditCreate;
    2767           0 :     classv[k-1] = &clgcd[k-1];
    2768             : 
    2769           0 :     clgcd[k].gd.pos.width = CCD_WIDTH-23;
    2770           0 :     clgcd[k].gd.flags = gg_visible | gg_enabled;
    2771           0 :     clgcd[k++].creator = GLineCreate;
    2772           0 :     classv[k-1] = &clgcd[k-1];
    2773           0 :     classv[k] = NULL;
    2774             : 
    2775           0 :     classbox[0].gd.flags = gg_enabled|gg_visible;
    2776           0 :     classbox[0].gd.u.boxelements = classv;
    2777           0 :     classbox[0].creator = GVBoxCreate;
    2778           0 :     topvarray[0] = &classbox[0];
    2779             : 
    2780           0 :     for ( i=0; i<3; ++i ) {
    2781           0 :         int l=0, cc, j, sameas=0;
    2782             : 
    2783           0 :         if ( i!=0 ) {
    2784           0 :             if ( (&tempfpst->nccnt)[i] == tempfpst->nccnt ) {
    2785           0 :                 sameas = gg_cb_on;
    2786           0 :                 for ( j=1; j<(&tempfpst->nccnt)[i]; ++j ) {
    2787           0 :                     if ( strcmp((&tempfpst->nclass)[i][j],tempfpst->nclass[j])!=0 ) {
    2788           0 :                         sameas = 0;
    2789           0 :                 break;
    2790             :                     }
    2791             :                 }
    2792             :             }
    2793           0 :             clabel[i][l].text = (unichar_t *) _("Same as Match Classes");
    2794           0 :             clabel[i][l].text_is_1byte = true;
    2795           0 :             cgcd[i][l].gd.label = &clabel[i][l];
    2796           0 :             cgcd[i][l].gd.handle_controlevent = CCD_SameAsClasses;
    2797           0 :             cgcd[i][l].gd.flags = gg_visible | gg_enabled | sameas;
    2798           0 :             cgcd[i][l].gd.cid = CID_SameAsClasses + i*20;
    2799           0 :             cgcd[i][l++].creator = GCheckBoxCreate;
    2800           0 :             subvarray[i][l-1] = &cgcd[i][l-1];
    2801             :         }
    2802             : 
    2803           0 :         memset(&class_mi[i],0,sizeof(class_mi[0]));
    2804           0 :         class_mi[i].col_cnt = 3;
    2805           0 :         class_mi[i].col_init = class_ci;
    2806             :         {
    2807             :             char **classes, **classnames;
    2808           0 :             if ( tempfpst->format==pst_class ) {
    2809           0 :                 classes = (&tempfpst->nclass)[i];
    2810           0 :                 classnames = (&tempfpst->nclassnames)[i];
    2811             :             } else {
    2812           0 :                 classes = NULL;
    2813           0 :                 classnames = NULL;
    2814             :             }
    2815           0 :             if ( classes==NULL )
    2816             :                 /* Make sure the class 0 is always present */
    2817           0 :                 cc=1;
    2818             :             else
    2819           0 :                 cc = (&tempfpst->nccnt)[i];
    2820           0 :             class_mi[i].initial_row_cnt = cc;
    2821           0 :             md = calloc(3*cc+3,sizeof(struct matrix_data));
    2822           0 :             md[0+0].u.md_str = copy(classnames==NULL || cc==0 || classnames[0]==NULL?S_("Glyphs|All_Others"):classnames[0]);
    2823           0 :             md[3*0+1].u.md_str = copy(_("{Everything Else}"));
    2824           0 :             md[3*0+1].frozen = true;
    2825           0 :             md[0+2].u.md_str = copy(md[0+0].u.md_str);
    2826           0 :             for ( j=1; j<cc; ++j ) {
    2827           0 :                 if ( classnames==NULL || classnames[j]==NULL ) {
    2828             :                     char buffer[12];
    2829           0 :                     sprintf( buffer,"%d",j );
    2830           0 :                     md[3*j+0].u.md_str = copy(buffer);
    2831             :                 } else
    2832           0 :                     md[3*j+0].u.md_str = copy(classnames[j]);
    2833           0 :                 md[3*j+1].u.md_str = SFNameList2NameUni(sf,classes[j]);
    2834           0 :                 md[3*j+2].u.md_str = copy(md[3*j+0].u.md_str);
    2835             :             }
    2836           0 :             class_mi[i].matrix_data = md;
    2837             : 
    2838           0 :             clen[i] = cc;
    2839           0 :             _classes[i] = md;
    2840             :         }
    2841           0 :         class_mi[i].initrow = CCD_InitClassRow;
    2842           0 :         class_mi[i].finishedit = CCD_FinishClassEdit;
    2843           0 :         class_mi[i].candelete = CCD_EnableDeleteClass;
    2844             : 
    2845           0 :         if ( sameas )
    2846           0 :             cgcd[i][l].gd.flags = gg_visible;
    2847             :         else
    2848           0 :             cgcd[i][l].gd.flags = gg_visible | gg_enabled;
    2849           0 :         cgcd[i][l].gd.cid = CID_GList+300+i*20;
    2850           0 :         cgcd[i][l].gd.u.matrix = &class_mi[i];
    2851           0 :         cgcd[i][l++].creator = GMatrixEditCreate;
    2852           0 :         subvarray[i][l-1] = &cgcd[i][l-1];
    2853           0 :         subvarray[i][l] = NULL;
    2854             : 
    2855           0 :         subboxes[i][0].gd.flags = gg_enabled|gg_visible;
    2856           0 :         subboxes[i][0].gd.u.boxelements = subvarray[i];
    2857           0 :         subboxes[i][0].creator = GVBoxCreate;
    2858             : 
    2859           0 :         faspects[i].gcd = subboxes[i];
    2860             :     }
    2861           0 :     j=0;
    2862           0 :     faspects[j++].text = (unichar_t *) _("Match Classes");
    2863           0 :     faspects[j++].text = (unichar_t *) _("Back Classes");
    2864           0 :     faspects[j++].text = (unichar_t *) _("Ahead Classes");
    2865             : 
    2866             :     /* Finish initializing the list of class rules */
    2867           0 :     if ( tempfpst->format==pst_class && tempfpst->rule_cnt>0 ) {
    2868           0 :         classrules_mi.initial_row_cnt = tempfpst->rule_cnt;
    2869           0 :         md = calloc(tempfpst->rule_cnt,sizeof(struct matrix_data));
    2870           0 :         for ( j=0; j<tempfpst->rule_cnt; ++j ) {
    2871           0 :             md[j+0].u.md_str = classruleitem(&tempfpst->rules[j],_classes,clen,3);
    2872             :         }
    2873           0 :         classrules_mi.matrix_data = md;
    2874             :     } else {
    2875           0 :         classrules_mi.initial_row_cnt = 0;
    2876           0 :         classrules_mi.matrix_data = NULL;
    2877             :     }
    2878             : 
    2879           0 :     clgcd[k].gd.u.tabs = faspects;
    2880           0 :     clgcd[k].gd.flags = gg_visible | gg_enabled;
    2881           0 :     clgcd[k].gd.cid = CID_MatchType+300;
    2882           0 :     clgcd[k].creator = GTabSetCreate;
    2883           0 :     topvarray[1] = &clgcd[k]; topvarray[2] = NULL;
    2884           0 :     topbox[0].gd.flags = gg_enabled|gg_visible;
    2885           0 :     topbox[0].gd.u.boxelements = topvarray;
    2886           0 :     topbox[0].creator = GVBoxCreate;
    2887           0 :     GGadgetsCreate(ccd->classrules,topbox);
    2888             : 
    2889             :     /* Top box should give it's size equally to its two components */
    2890           0 :     GHVBoxSetExpandableRow(classbox[0].ret,0);
    2891           0 :     GHVBoxSetExpandableRow(subboxes[0][0].ret,0);
    2892           0 :     GHVBoxSetExpandableRow(subboxes[1][0].ret,1);
    2893           0 :     GHVBoxSetExpandableRow(subboxes[2][0].ret,1);
    2894           0 :     GMatrixEditSetColumnCompletion(GWidgetGetControl(ccd->classrules,CID_GList+300+0*20),0,CCD_GlyphListCompletion);
    2895           0 :     GMatrixEditSetColumnCompletion(GWidgetGetControl(ccd->classrules,CID_GList+300+1*20),0,CCD_GlyphListCompletion);
    2896           0 :     GMatrixEditSetColumnCompletion(GWidgetGetControl(ccd->classrules,CID_GList+300+2*20),0,CCD_GlyphListCompletion);
    2897           0 :     GMatrixEditSetUpDownVisible(GWidgetGetControl(ccd->classrules,CID_GList+200), true);
    2898           0 :     GMatrixEditSetOtherButtonEnable(GWidgetGetControl(ccd->classrules,CID_GList+200),CCD_NewClassRule);
    2899           0 :     for ( i=0; i<3; ++i ) {
    2900           0 :         GGadget *list = GWidgetGetControl(ccd->classrules,CID_GList+300+i*20);
    2901           0 :         GMatrixEditShowColumn(list,2,false);
    2902           0 :         GMatrixEditSetUpDownVisible(list, true);
    2903           0 :         GMatrixEditSetCanUpDown(list, CCD_EnableUpDown);
    2904             :     }
    2905             : 
    2906             :         /* This pane displays a set of class rules, and below the three sets of classes_simple for those rules */
    2907           0 :     ccd->classes_simple = GWidgetCreateSubWindow(ccd->gw,&subpos,subccd_e_h,ccd,&wattrs);
    2908           0 :     memset(&cllabel,0,sizeof(cllabel));
    2909           0 :     memset(&clgcd,0,sizeof(clgcd));
    2910           0 :     memset(&clabel,0,sizeof(clabel));
    2911           0 :     memset(&cgcd,0,sizeof(cgcd));
    2912           0 :     memset(&subboxes,0,sizeof(subboxes));
    2913           0 :     memset(&topbox,0,sizeof(topbox));
    2914           0 :     memset(&classbox,0,sizeof(classbox));
    2915           0 :     memset(&faspects,0,sizeof(faspects));
    2916             : 
    2917           0 :     tempfpst = fpst;
    2918           0 :     if ( fpst->format==pst_glyphs && fpst->rule_cnt>0 )
    2919           0 :         tempfpst = FPSTGlyphToClass(fpst);
    2920             : 
    2921           0 :     k=0;
    2922             : 
    2923           0 :     memset(&classsimple_mi,0,sizeof(classsimple_mi));
    2924           0 :     classsimple_mi.col_cnt = 1;
    2925           0 :     classsimple_mi.col_init = classsimple_ci;
    2926           0 :     if ( tempfpst->format==pst_class && tempfpst->rule_cnt>0 ) {
    2927           0 :         classsimple_mi.initial_row_cnt = tempfpst->rule_cnt;
    2928           0 :         md = calloc(tempfpst->rule_cnt,sizeof(struct matrix_data));
    2929           0 :         for ( j=0; j<tempfpst->rule_cnt; ++j ) {
    2930           0 :             md[j+0].u.md_str = FPSTRule_To_Str(sf,tempfpst,&tempfpst->rules[j]);;
    2931             :         }
    2932           0 :         classsimple_mi.matrix_data = md;
    2933             :     } else {
    2934           0 :         classsimple_mi.initial_row_cnt = 0;
    2935           0 :         classsimple_mi.matrix_data = NULL;
    2936             :     }
    2937           0 :     clgcd[k].gd.flags = gg_visible | gg_enabled;
    2938           0 :     clgcd[k].gd.cid = CID_CList_Simple;
    2939           0 :     clgcd[k].gd.u.matrix = &classsimple_mi;
    2940           0 :     clgcd[k++].creator = GMatrixEditCreate;
    2941           0 :     classv[k-1] = &clgcd[k-1];
    2942             : 
    2943           0 :     clgcd[k].gd.pos.width = CCD_WIDTH-23;
    2944           0 :     clgcd[k].gd.flags = gg_visible | gg_enabled;
    2945           0 :     clgcd[k++].creator = GLineCreate;
    2946           0 :     classv[k-1] = &clgcd[k-1];
    2947           0 :     classv[k] = NULL;
    2948             : 
    2949           0 :     classbox[0].gd.flags = gg_enabled|gg_visible;
    2950           0 :     classbox[0].gd.u.boxelements = classv;
    2951           0 :     classbox[0].creator = GVBoxCreate;
    2952           0 :     topvarray[0] = &classbox[0];
    2953             : 
    2954           0 :     for ( i=0; i<3; ++i ) {
    2955           0 :         int l=0, cc, j, sameas=0;
    2956             : 
    2957           0 :         if ( i!=0 ) {
    2958           0 :             if ( (&tempfpst->nccnt)[i] == tempfpst->nccnt ) {
    2959           0 :                 sameas = gg_cb_on;
    2960           0 :                 for ( j=1; j<(&tempfpst->nccnt)[i]; ++j ) {
    2961           0 :                     if ( strcmp((&tempfpst->nclass)[i][j],tempfpst->nclass[j])!=0 ) {
    2962           0 :                         sameas = 0;
    2963           0 :                 break;
    2964             :                     }
    2965             :                 }
    2966             :             }
    2967           0 :             clabel[i][l].text = (unichar_t *) _("Same as Match Classes");
    2968           0 :             clabel[i][l].text_is_1byte = true;
    2969           0 :             cgcd[i][l].gd.label = &clabel[i][l];
    2970           0 :             cgcd[i][l].gd.handle_controlevent = CCD_SameAsClasses;
    2971           0 :             cgcd[i][l].gd.flags = gg_visible | gg_enabled | sameas;
    2972           0 :             cgcd[i][l].gd.cid = CID_SameAsClasses_S + i*20;
    2973           0 :             cgcd[i][l++].creator = GCheckBoxCreate;
    2974           0 :             subvarray[i][l-1] = &cgcd[i][l-1];
    2975             :         }
    2976             : 
    2977           0 :         memset(&class_mi[i],0,sizeof(class_mi[0]));
    2978           0 :         class_mi[i].col_cnt = 3;
    2979           0 :         class_mi[i].col_init = class_ci;
    2980             :         {
    2981             :             char **classes, **classnames;
    2982           0 :             if ( tempfpst->format==pst_class ) {
    2983           0 :                 classes = (&tempfpst->nclass)[i];
    2984           0 :                 classnames = (&tempfpst->nclassnames)[i];
    2985             :             } else {
    2986           0 :                 classes = NULL;
    2987           0 :                 classnames = NULL;
    2988             :             }
    2989           0 :             if ( classes==NULL )
    2990             :                 /* Make sure the class 0 is always present */
    2991           0 :                 cc=1;
    2992             :             else
    2993           0 :                 cc = (&tempfpst->nccnt)[i];
    2994           0 :             class_mi[i].initial_row_cnt = cc;
    2995           0 :             md = calloc(3*cc+3,sizeof(struct matrix_data));
    2996             : /* GT: This is the default class name for the class containing any glyphs_simple */
    2997             : /* GT: which aren't specified in other classes_simple. The class name may NOT */
    2998             : /* GT: contain spaces. Use an underscore or something similar instead */
    2999           0 :             md[0+0].u.md_str = copy(classnames==NULL || cc==0 || classnames[0]==NULL?S_("Glyphs|All_Others"):classnames[0]);
    3000           0 :             md[0+1].u.md_str = copy(_("{Everything Else}"));
    3001           0 :             md[0+1].frozen = true;
    3002           0 :             md[0+2].u.md_str = copy(md[0+0].u.md_str);
    3003           0 :             for ( j=1; j<cc; ++j ) {
    3004           0 :                 if ( classnames==NULL || classnames[j]==NULL ) {
    3005             :                     char buffer[12];
    3006           0 :                     sprintf( buffer,"%d",j );
    3007           0 :                     md[3*j+0].u.md_str = copy(buffer);
    3008             :                 } else
    3009           0 :                     md[3*j+0].u.md_str = copy(classnames[j]);
    3010           0 :                 md[3*j+1].u.md_str = SFNameList2NameUni(sf,classes[j]);
    3011           0 :                 md[3*j+2].u.md_str = copy(md[3*j+0].u.md_str);
    3012             :             }
    3013           0 :             class_mi[i].matrix_data = md;
    3014             :         }
    3015           0 :         class_mi[i].initrow = CCD_InitClassRow;
    3016           0 :         class_mi[i].finishedit = CCD_FinishClassEdit;
    3017           0 :         class_mi[i].candelete = CCD_EnableDeleteClass;
    3018             : 
    3019           0 :         if ( sameas )
    3020           0 :             cgcd[i][l].gd.flags = gg_visible;
    3021             :         else
    3022           0 :             cgcd[i][l].gd.flags = gg_visible | gg_enabled;
    3023           0 :         cgcd[i][l].gd.cid = CID_MatchClasses+i*20;
    3024           0 :         cgcd[i][l].gd.u.matrix = &class_mi[i];
    3025           0 :         cgcd[i][l++].creator = GMatrixEditCreate;
    3026           0 :         subvarray[i][l-1] = &cgcd[i][l-1];
    3027           0 :         subvarray[i][l] = NULL;
    3028             : 
    3029           0 :         subboxes[i][0].gd.flags = gg_enabled|gg_visible;
    3030           0 :         subboxes[i][0].gd.u.boxelements = subvarray[i];
    3031           0 :         subboxes[i][0].creator = GVBoxCreate;
    3032             : 
    3033           0 :         faspects[i].gcd = subboxes[i];
    3034           0 :         faspects[i].text_is_1byte = true;
    3035             :     }
    3036           0 :     j=0;
    3037           0 :     faspects[j++].text = (unichar_t *) _("Match Classes");
    3038           0 :     faspects[j++].text = (unichar_t *) _("Back Classes");
    3039           0 :     faspects[j++].text = (unichar_t *) _("Ahead Classes");
    3040           0 :     if ( fpst->type == pst_contextpos || fpst->type == pst_contextsub )
    3041           0 :         faspects[1].disabled = faspects[2].disabled = true;
    3042             : 
    3043           0 :     clgcd[k].gd.u.tabs = faspects;
    3044           0 :     clgcd[k].gd.flags = gg_visible | gg_enabled;
    3045           0 :     clgcd[k].gd.cid = CID_ClassMatchType;
    3046           0 :     clgcd[k].creator = GTabSetCreate;
    3047           0 :     topvarray[1] = &clgcd[k]; topvarray[2] = NULL;
    3048           0 :     topbox[0].gd.flags = gg_enabled|gg_visible;
    3049           0 :     topbox[0].gd.u.boxelements = topvarray;
    3050           0 :     topbox[0].creator = GVBoxCreate;
    3051           0 :     GGadgetsCreate(ccd->classes_simple,topbox);
    3052             : 
    3053             :     /* Top box should give it's size equally to its two components */
    3054           0 :     GHVBoxSetExpandableRow(classbox[0].ret,0);
    3055           0 :     GHVBoxSetExpandableRow(subboxes[0][0].ret,0);
    3056           0 :     GHVBoxSetExpandableRow(subboxes[1][0].ret,1);
    3057           0 :     GHVBoxSetExpandableRow(subboxes[2][0].ret,1);
    3058           0 :     GMatrixEditSetColumnCompletion(GWidgetGetControl(ccd->classes_simple,CID_MatchClasses),1,CCD_GlyphListCompletion);
    3059           0 :     GMatrixEditSetColumnCompletion(GWidgetGetControl(ccd->classes_simple,CID_BackClasses),1,CCD_GlyphListCompletion);
    3060           0 :     GMatrixEditSetColumnCompletion(GWidgetGetControl(ccd->classes_simple,CID_ForeClasses),1,CCD_GlyphListCompletion);
    3061           0 :     GMatrixEditSetColumnCompletion(GWidgetGetControl(ccd->classes_simple,CID_CList_Simple),0,
    3062             :             CCD_ClassListCompletion);
    3063           0 :     if ( fpst->type==pst_chainpos || fpst->type==pst_chainsub ) {
    3064           0 :         extrabuttonsgcd[0].gd.cid = CID_CNewSection;
    3065           0 :         extrabuttonsgcd[1].gd.cid = CID_CAddLookup;
    3066             :     } else
    3067           0 :         extrabuttonsgcd[0].gd.cid = CID_CAddLookup;
    3068           0 :     GMatrixEditSetUpDownVisible(GWidgetGetControl(ccd->classes_simple,CID_CList_Simple), true);
    3069           0 :     GMatrixEditAddButtons(GWidgetGetControl(ccd->classes_simple,CID_CList_Simple),extrabuttonsgcd);
    3070           0 :     for ( i=0; i<3; ++i ) {
    3071           0 :         GGadget *list = GWidgetGetControl(ccd->classes_simple,CID_MatchClasses+i*20);
    3072           0 :         GMatrixEditShowColumn(list,2,false);
    3073           0 :         GMatrixEditSetUpDownVisible(list, true);
    3074           0 :         GMatrixEditSetCanUpDown(list, CCD_EnableUpDown);
    3075           0 :         GMatrixEditSetBeforeDelete(list,CCD_ClassGoing);
    3076             :     }
    3077           0 :     if ( tempfpst!=fpst )
    3078           0 :         FPSTFree(tempfpst);
    3079             : 
    3080             :         /* This pane displays a tabbed set describing one rule in class format */
    3081           0 :     ccd->classnumber = GWidgetCreateSubWindow(ccd->gw,&subpos,subccd_e_h,ccd,&wattrs);
    3082           0 :     memset(&clabel,0,sizeof(clabel));
    3083           0 :     memset(&cgcd,0,sizeof(cgcd));
    3084           0 :     memset(&cllabel,0,sizeof(cllabel));
    3085           0 :     memset(&clgcd,0,sizeof(clgcd));
    3086             : 
    3087           0 :     for ( i=0; i<3; ++i ) {
    3088           0 :         k=0;
    3089             : 
    3090           0 :         clabel[i][k].text = (unichar_t *) _("List of class names");
    3091           0 :         clabel[i][k].text_is_1byte = true;
    3092           0 :         cgcd[i][k].gd.label = &clabel[i][k];
    3093           0 :         cgcd[i][k].gd.flags = gg_visible | gg_enabled;
    3094           0 :         cgcd[i][k++].creator = GLabelCreate;
    3095           0 :         subvarray[i][k-1] = &cgcd[i][k-1];
    3096             : 
    3097           0 :         cgcd[i][k].gd.flags = gg_visible | gg_enabled | gg_textarea_wrap;
    3098           0 :         cgcd[i][k].gd.cid = CID_ClassNumbers+i*20;
    3099           0 :         cgcd[i][k++].creator = GTextAreaCreate;
    3100           0 :         subvarray[i][k-1] = &cgcd[i][k-1];
    3101             : 
    3102           0 :         clabel[i][k].text = (unichar_t *) _("Classes");
    3103           0 :         clabel[i][k].text_is_1byte = true;
    3104           0 :         cgcd[i][k].gd.label = &clabel[i][k];
    3105           0 :         cgcd[i][k].gd.flags = gg_visible | gg_enabled;
    3106           0 :         cgcd[i][k++].creator = GLabelCreate;
    3107           0 :         subvarray[i][k-1] = &cgcd[i][k-1];
    3108             : 
    3109           0 :         memset(&classlist_mi[i],0,sizeof(classlist_mi[0]));
    3110           0 :         classlist_mi[i].col_cnt = 2;
    3111           0 :         classlist_mi[i].col_init = classlist_ci;
    3112             : 
    3113           0 :         cgcd[i][k].gd.flags = gg_visible | gg_enabled | gg_textarea_wrap;
    3114           0 :         cgcd[i][k].gd.cid = CID_ClassList+i*20;
    3115           0 :         cgcd[i][k].gd.u.matrix = &classlist_mi[i];
    3116           0 :         cgcd[i][k++].creator = GMatrixEditCreate;
    3117           0 :         subvarray[i][k-1] = &cgcd[i][k-1];
    3118           0 :         subvarray[i][k] = NULL;
    3119             : 
    3120           0 :         subboxes[i][0].gd.flags = gg_enabled|gg_visible;
    3121           0 :         subboxes[i][0].gd.u.boxelements = subvarray[i];
    3122           0 :         subboxes[i][0].creator = GVBoxCreate;
    3123             : 
    3124           0 :         faspects[i].gcd = subboxes[i];
    3125             : 
    3126           0 :         if ( i==0 ) {
    3127           0 :             clabel[i][k].text = (unichar_t *) _("An ordered list of lookups and positions");
    3128           0 :             clabel[i][k].text_is_1byte = true;
    3129           0 :             ggcd[i][k].gd.label = &clabel[i][k];
    3130           0 :             ggcd[i][k].gd.flags = gg_visible | gg_enabled;
    3131           0 :             ggcd[i][k++].creator = GLabelCreate;
    3132           0 :             subvarray2[0] = &ggcd[i][k-1];
    3133             : 
    3134           0 :             memset(&cl_seqlookup_mi,0,sizeof(cl_seqlookup_mi));
    3135           0 :             cl_seqlookup_mi.col_cnt = 2;
    3136           0 :             cl_seqlookup_mi.col_init = seqlookup_ci;
    3137           0 :             cl_seqlookup_mi.matrix_data = NULL;
    3138           0 :             cl_seqlookup_mi.initial_row_cnt = 0;
    3139             : 
    3140           0 :             ggcd[i][k].gd.flags = gg_visible | gg_enabled;
    3141           0 :             ggcd[i][k].gd.cid = CID_LookupList+500;
    3142           0 :             ggcd[i][k].gd.u.matrix = &cl_seqlookup_mi;
    3143           0 :             ggcd[i][k++].creator = GMatrixEditCreate;
    3144           0 :             subvarray2[1] = &ggcd[i][k-1];
    3145           0 :             subvarray2[2] = NULL;
    3146             : 
    3147           0 :             subboxes[i][1].gd.flags = gg_enabled|gg_visible;
    3148           0 :             subboxes[i][1].gd.u.boxelements = subvarray2;
    3149           0 :             subboxes[i][1].creator = GVBoxCreate;
    3150             : 
    3151           0 :             subvarray3[0] = &subboxes[i][0];
    3152           0 :             subvarray3[1] = &subboxes[i][1];
    3153           0 :             subvarray3[2] = NULL;
    3154             : 
    3155           0 :             subboxes[i][2].gd.flags = gg_enabled|gg_visible;
    3156           0 :             subboxes[i][2].gd.u.boxelements = subvarray3;
    3157           0 :             subboxes[i][2].creator = GVBoxCreate;
    3158           0 :             faspects[i].gcd = subboxes[i]+2;
    3159             :         }
    3160             :     }
    3161             : 
    3162           0 :     j=0;
    3163           0 :     faspects[j++].text = (unichar_t *) _("Match");
    3164           0 :     faspects[j++].text = (unichar_t *) _("Backtrack");
    3165           0 :     faspects[j++].text = (unichar_t *) _("Lookahead");
    3166             : 
    3167           0 :     k=0;
    3168           0 :     clgcd[k].gd.u.tabs = faspects;
    3169           0 :     clgcd[k].gd.flags = gg_visible | gg_enabled;
    3170           0 :     clgcd[k].gd.cid = CID_ClassType;
    3171           0 :     clgcd[k].creator = GTabSetCreate;
    3172           0 :     GGadgetsCreate(ccd->classnumber,clgcd);
    3173           0 :     GHVBoxSetExpandableRow(subboxes[0][0].ret,3);
    3174           0 :     GHVBoxSetExpandableRow(subboxes[1][0].ret,3);
    3175           0 :     GHVBoxSetExpandableRow(subboxes[2][0].ret,3);
    3176           0 :     GHVBoxSetExpandableRow(subboxes[0][1].ret,1);
    3177             : 
    3178           0 :     GMatrixEditSetEditable(GWidgetGetControl(ccd->classnumber,CID_ClassList+0*20),false);
    3179           0 :     GMatrixEditSetEditable(GWidgetGetControl(ccd->classnumber,CID_ClassList+1*20),false);
    3180           0 :     GMatrixEditSetEditable(GWidgetGetControl(ccd->classnumber,CID_ClassList+2*20),false);
    3181           0 :     GMatrixEditSetOtherButtonEnable(GWidgetGetControl(ccd->classnumber,CID_ClassList+0*20),CCD_ClassSelected);
    3182           0 :     GMatrixEditSetOtherButtonEnable(GWidgetGetControl(ccd->classnumber,CID_ClassList+1*20),CCD_ClassSelected);
    3183           0 :     GMatrixEditSetOtherButtonEnable(GWidgetGetControl(ccd->classnumber,CID_ClassList+2*20),CCD_ClassSelected);
    3184             : 
    3185             : 
    3186           0 :     if ( ccd->aw == aw_formats )
    3187           0 :         GDrawSetVisible(ccd->formats,true);
    3188           0 :     else if ( use_simple ) {
    3189           0 :         if ( ccd->aw == aw_glyphs_simple )
    3190           0 :             GDrawSetVisible(ccd->glyphs_simple,true);
    3191           0 :         else if ( ccd->aw == aw_classes_simple )
    3192           0 :             GDrawSetVisible(ccd->classes_simple,true);
    3193             :         else {
    3194           0 :             GDrawSetVisible(ccd->coverage_simple,true);
    3195           0 :             GDrawResize(ccd->gw,
    3196           0 :                     fpst->format==pst_reversecoverage?3*pos.width/2:2*pos.width,
    3197             :                     pos.height);
    3198             :         }
    3199             :     } else {
    3200           0 :         if ( ccd->aw == aw_grules )
    3201           0 :             GDrawSetVisible(ccd->grules,true);
    3202           0 :         else if ( ccd->aw == aw_classrules )
    3203           0 :             GDrawSetVisible(ccd->classrules,true);
    3204             :         else
    3205           0 :             GDrawSetVisible(ccd->coverage,true);
    3206             :     }
    3207             : 
    3208           0 :     GDrawSetVisible(gw,true);
    3209           0 :     while ( !ccd->done )
    3210           0 :         GDrawProcessOneEvent(NULL);
    3211           0 :     GDrawDestroyWindow(ccd->gw);
    3212             : 
    3213           0 :     GTextInfoListFree(lookup_list);
    3214           0 :     seqlookup_ci[1].enum_vals = NULL;
    3215             : 
    3216             :     /* ccd is freed by the event handler when we get a et_destroy event */
    3217             : 
    3218           0 : return;
    3219             : }

Generated by: LCOV version 1.10