LCOV - code coverage report
Current view: top level - fontforgeexe - kernclass.c (source / functions) Hit Total Coverage
Test: FontForge coverage report 2017-08-04 01:21:11+02:00 (commit d35f7e4107a9e1db65cce47c468fcc914cecb8fd) Lines: 0 2392 0.0 %
Date: 2017-08-04 Functions: 0 81 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 "autowidth2.h"
      28             : #include "fontforgeui.h"
      29             : #include "fvfonts.h"
      30             : #include "lookups.h"
      31             : #include "splinefill.h"
      32             : #include "splineutil.h"
      33             : #include "tottfgpos.h"
      34             : #include <gkeysym.h>
      35             : #include <string.h>
      36             : #include <ustring.h>
      37             : #include <utype.h>
      38             : #include <math.h>
      39             : 
      40             : extern GBox _ggadget_Default_Box;
      41             : #define ACTIVE_BORDER   (_ggadget_Default_Box.active_border)
      42             : #define MAIN_FOREGROUND (_ggadget_Default_Box.main_foreground)
      43             : 
      44             : typedef struct kernclassdlg {
      45             :     struct kernclasslistdlg *kcld;
      46             :     KernClass *orig;
      47             :     struct lookup_subtable *subtable;
      48             :     int first_cnt, second_cnt;
      49             :     char **firsts_names;
      50             :     char **seconds_names;
      51             :     int *firsts_flags;
      52             :     int *seconds_flags;
      53             :     int16 *offsets;
      54             :     int *offsets_flags;
      55             :     DeviceTable *adjusts;
      56             :     DeviceTable active_adjust;          /* The one that is currently active */
      57             :     DeviceTable orig_adjust;            /* Initial value for this the active adjust */
      58             :     GWindow gw, subw;
      59             :     GFont *font;
      60             :     int fh, as;
      61             :     int kernh, kernw;           /* Width of the box containing the kerning val */
      62             :     int xstart, ystart;         /* This is where the headers start */
      63             :     int xstart2, ystart2;       /* This is where the data start */
      64             :     int width, height, fullwidth, subwidth;
      65             :     int canceldrop, sbdrop;
      66             :     int offleft, offtop;
      67             :     GGadget *hsb, *vsb;
      68             :     int isedit, off;
      69             :     int st_pos, old_pos;
      70             :     BDFChar *fsc, *ssc;
      71             :     int pixelsize;
      72             :     int magfactor;
      73             :     int downpos, down, within, orig_kern;
      74             :     SplineFont *sf;
      75             :     int layer;
      76             :     int isv;
      77             :     int first_class_new, r2l, index;
      78             :     int orig_kern_offset;
      79             : /* For the kern pair dlg */
      80             :     int done;
      81             :     SplineChar *sc1, *sc2;
      82             :     int iskernpair;
      83             :     SplineChar *scf, *scs;
      84             :     struct kernclassdlg *next;
      85             : 
      86             : } KernClassDlg;
      87             : 
      88             : typedef struct kernclasslistdlg {
      89             :     SplineFont *sf;
      90             :     int layer;
      91             :     GWindow gw;
      92             :     int isv;
      93             : } KernClassListDlg;
      94             : 
      95             : #define KCL_Width       200
      96             : #define KCL_Height      173
      97             : #define KC_Width        400
      98             : #define KC_Height       424
      99             : #define KC_CANCELDROP   33
     100             : 
     101             : #define CID_Subtable    1001
     102             : 
     103             : #define CID_List        1040            /* List of kern class subtables */
     104             : #define CID_New         1041
     105             : #define CID_Delete      1042
     106             : #define CID_Edit        1043
     107             : 
     108             : #define CID_ClassList   1007            /* And 1107 for second char */
     109             : #define CID_ClassLabel  1011
     110             : #define CID_ClassSelect 1014
     111             : 
     112             : #define CID_OK          1015
     113             : #define CID_Cancel      1016
     114             : 
     115             : #define CID_First       1030
     116             : #define CID_Second      1031
     117             : #define CID_KernOffset  1032
     118             : #define CID_Prev2       1033
     119             : #define CID_Next2       1034
     120             : #define CID_DisplaySize 1036
     121             : #define CID_Correction  1037
     122             : #define CID_FreeType    1038
     123             : #define CID_Magnifications      1039
     124             : #define CID_ClearDevice 1040
     125             : #define CID_Display     1041
     126             : 
     127             : #define CID_Separation  2008
     128             : #define CID_MinKern     2009
     129             : #define CID_Touched     2010
     130             : #define CID_OnlyCloser  2011
     131             : #define CID_Autokern    2012
     132             : 
     133             : #define CID_SizeLabel   3000
     134             : #define CID_MagLabel    3001
     135             : #define CID_OffsetLabel 3002
     136             : #define CID_CorrectLabel        3003
     137             : #define CID_Revert      3004
     138             : #define CID_TopBox      3005
     139             : #define CID_ShowHideKern        3006
     140             : 
     141             : extern int _GScrollBar_Width;
     142             : int show_kerning_pane_in_class = true;
     143             : 
     144             : static GTextInfo magnifications[] = {
     145             :     { (unichar_t *) "100%", NULL, 0, 0, NULL, NULL, 0, 0, 0, 0, 1, 0, 1, 0, 0, '\0'},
     146             :     { (unichar_t *) "200%", NULL, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
     147             :     { (unichar_t *) "300%", NULL, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
     148             :     { (unichar_t *) "400%", NULL, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
     149             :     GTEXTINFO_EMPTY
     150             : };
     151             : 
     152             : static int  KCD_SBReset(KernClassDlg *);
     153             : static void KCD_HShow(KernClassDlg *, int pos);
     154             : static void KCD_VShow(KernClassDlg *, int pos);
     155             : 
     156           0 : static GTextInfo **KCLookupSubtableArray(SplineFont *sf,int isv) {
     157             :     int cnt;
     158           0 :     KernClass *kc, *head = isv ? sf->vkerns : sf->kerns;
     159             :     GTextInfo **ti;
     160             : 
     161           0 :     if ( sf->cidmaster!=NULL ) sf=sf->cidmaster;
     162           0 :     else if ( sf->mm!=NULL ) sf = sf->mm->normal;
     163             : 
     164           0 :     for ( kc=head, cnt=0; kc!=NULL; kc=kc->next, ++cnt );
     165           0 :     ti = calloc(cnt+1,sizeof(GTextInfo*));
     166           0 :     for ( kc=head, cnt=0; kc!=NULL; kc=kc->next, ++cnt ) {
     167           0 :         ti[cnt] = calloc(1,sizeof(GTextInfo));
     168           0 :         ti[cnt]->fg = ti[cnt]->bg = COLOR_DEFAULT;
     169           0 :         ti[cnt]->text = utf82u_copy(kc->subtable->subtable_name);
     170             :     }
     171           0 :     ti[cnt] = calloc(1,sizeof(GTextInfo));
     172           0 : return( ti );
     173             : }
     174             : 
     175           0 : static GTextInfo *KCLookupSubtableList(SplineFont *sf,int isv) {
     176             :     int cnt;
     177           0 :     KernClass *kc, *head = isv ? sf->vkerns : sf->kerns;
     178             :     GTextInfo *ti;
     179             : 
     180           0 :     if ( sf->cidmaster!=NULL ) sf=sf->cidmaster;
     181           0 :     else if ( sf->mm!=NULL ) sf = sf->mm->normal;
     182             : 
     183           0 :     for ( kc=head, cnt=0; kc!=NULL; kc=kc->next, ++cnt );
     184           0 :     ti = calloc(cnt+1,sizeof(GTextInfo));
     185           0 :     for ( kc=head, cnt=0; kc!=NULL; kc=kc->next, ++cnt )
     186           0 :         ti[cnt].text = utf82u_copy(kc->subtable->subtable_name);
     187           0 : return( ti );
     188             : }
     189             : 
     190           0 : static int isEverythingElse(char *text) {
     191             :     /* GT: The string "{Everything Else}" is used in the context of a list */
     192             :     /* GT: of classes (a set of kerning classes) where class 0 designates the */
     193             :     /* GT: default class containing all glyphs not specified in the other classes */
     194           0 :     int ret = strcmp(text,_("{Everything Else}") );
     195           0 : return( ret==0 );
     196             : }
     197             : 
     198           0 : static void KCD_AddOffset(void *data,int left_index,int right_index, int kern) {
     199           0 :     KernClassDlg *kcd = data;
     200             : 
     201           0 :     if ( kcd->first_class_new && !kcd->r2l ) {
     202           0 :         left_index = kcd->index;
     203           0 :         kcd->offsets[left_index*kcd->second_cnt+right_index] = kern;
     204           0 :     } else if ( kcd->first_class_new ) {
     205           0 :         right_index = kcd->index;
     206           0 :         kcd->offsets[right_index*kcd->second_cnt+left_index] = kern;
     207           0 :     } else if ( !kcd->r2l ) {
     208           0 :         right_index = kcd->index;
     209           0 :         kcd->offsets[left_index*kcd->second_cnt+right_index] = kern;
     210             :     } else {
     211           0 :         left_index = kcd->index;
     212           0 :         kcd->offsets[right_index*kcd->second_cnt+left_index] = kern;
     213             :     }
     214           0 : }
     215             : 
     216           0 : static void KCD_AddOffsetAsIs(void *data,int left_index,int right_index, int kern) {
     217           0 :     KernClassDlg *kcd = data;
     218             : 
     219           0 :     if ( !kcd->r2l ) {
     220           0 :         kcd->offsets[left_index*kcd->second_cnt+right_index] = kern;
     221             :     } else {
     222           0 :         kcd->offsets[right_index*kcd->second_cnt+left_index] = kern;
     223             :     }
     224           0 : }
     225             : 
     226           0 : static void KCD_AutoKernAClass(KernClassDlg *kcd,int index,int is_first) {
     227             :     char *space[1], **lefts, **rights, **others;
     228             :     int lcnt, rcnt; int ocnt, acnt;
     229             :     // CID_ClassList is a constant. It presumably provides a base for identifying the two list controls in the KernAClass dialogue, and we assign by which is active, not by which is the first list.
     230             :     // Empirical testing suggests that index indexes a unified collection of unique characters spread across the two list views. The empirical testing seems to reflect an incorrect calling sequence, as it turns out.
     231             :     // This function expects things to be indexed separately according to the items in the two visible lists.
     232           0 :     GGadget *activelist = GWidgetGetControl( kcd->gw, CID_ClassList+(is_first?0:100));
     233           0 :     GGadget *otherlist = GWidgetGetControl( kcd->gw, CID_ClassList+(is_first?100:0));
     234             :     // Each of these returns a GGadget. We then make the assumption that each gadget is nested in a GMatrixEdit and retrieve the GMatrixEdit object.
     235           0 :     struct matrix_data *otherdata = GMatrixEditGet(otherlist,&ocnt);
     236           0 :     struct matrix_data *activedata = GMatrixEditGet(activelist,&acnt);
     237           0 :     int err, touch=0, separation=0, minkern=0, onlyCloser;
     238             :     int r2l, i;
     239             : 
     240           0 :     if ( kcd->isv )
     241           0 : return;
     242           0 :     if( acnt <= index )
     243           0 :         return;
     244             : 
     245           0 :     err = false;
     246           0 :     touch = GGadgetIsChecked(GWidgetGetControl(kcd->gw,CID_Touched));
     247           0 :     separation = GetInt8(kcd->gw,CID_Separation,_("Separation"),&err);
     248           0 :     minkern = GetInt8(kcd->gw,CID_MinKern,_("Min Kern"),&err);
     249           0 :     onlyCloser = GGadgetIsChecked(GWidgetGetControl(kcd->gw,CID_OnlyCloser));
     250           0 :     if ( err )
     251           0 : return;
     252             : 
     253             :     // We next strdup from activedata[index].u.md_str, which causes a segmentation fault sometimes.
     254           0 :     space[0] = copy(activedata[index].u.md_str);
     255             :     // space keeps just the specified item from activelist. others stores the items from the opposite list.
     256           0 :     others = malloc((ocnt+1)*sizeof(char *));
     257           0 :     for ( i=0; i<ocnt; ++i ) {
     258           0 :         if ( i==0 && isEverythingElse(otherdata[0].u.md_str))
     259           0 :             others[i] = copy("");
     260             :         else
     261           0 :             others[i] = copy(otherdata[i].u.md_str);
     262             :     }
     263           0 :     kcd->first_class_new = is_first;
     264           0 :     kcd->r2l = r2l = (kcd->subtable->lookup->lookup_flags & pst_r2l)?1:0;
     265           0 :     kcd->index = index;
     266             : 
     267           0 :     if ( (is_first && !r2l) || (!is_first && r2l) ) {
     268           0 :         lefts = space; lcnt = 1;
     269           0 :         rights = others; rcnt = ocnt;
     270             :     } else {
     271           0 :         lefts = others; lcnt = ocnt;
     272           0 :         rights = space; rcnt=1;
     273             :     }
     274           0 :     AutoKern2NewClass(kcd->sf,kcd->layer, lefts, rights, lcnt, rcnt,
     275             :             KCD_AddOffset, kcd, separation, minkern, touch, onlyCloser, 0);
     276           0 :     for ( i=0; i<ocnt; ++i )
     277           0 :         free(others[i]);
     278           0 :     free(others);
     279           0 :     free(space[0]);
     280             : }
     281             : 
     282           0 : static void KCD_AutoKernAll(KernClassDlg *kcd) {
     283             :     char **lefts, **rights, **firsts, **seconds;
     284             :     int lcnt, rcnt; int fcnt, scnt;
     285           0 :     GGadget *firstlist = GWidgetGetControl( kcd->gw, CID_ClassList+0);
     286           0 :     GGadget *secondlist = GWidgetGetControl( kcd->gw, CID_ClassList+100);
     287           0 :     struct matrix_data *seconddata = GMatrixEditGet(secondlist,&scnt);
     288           0 :     struct matrix_data *firstdata = GMatrixEditGet(firstlist,&fcnt);
     289           0 :     int err, touch=0, separation=0, minkern=0, onlyCloser;
     290             :     int r2l, i;
     291             : 
     292           0 :     if ( kcd->isv )
     293           0 : return;
     294             : 
     295           0 :     err = false;
     296           0 :     touch = GGadgetIsChecked(GWidgetGetControl(kcd->gw,CID_Touched));
     297           0 :     separation = GetInt8(kcd->gw,CID_Separation,_("Separation"),&err);
     298           0 :     minkern = GetInt8(kcd->gw,CID_MinKern,_("Min Kern"),&err);
     299           0 :     onlyCloser = GGadgetIsChecked(GWidgetGetControl(kcd->gw,CID_OnlyCloser));
     300           0 :     if ( err )
     301           0 : return;
     302             : 
     303           0 :     firsts = malloc((fcnt+1)*sizeof(char *));
     304           0 :     for ( i=0; i<fcnt; ++i ) {
     305           0 :         if ( i==0 && isEverythingElse(firstdata[0].u.md_str))
     306           0 :             firsts[i] = copy("");
     307             :         else
     308           0 :             firsts[i] = copy(firstdata[i].u.md_str);
     309             :     }
     310           0 :     seconds = malloc((scnt+1)*sizeof(char *));
     311           0 :     for ( i=0; i<scnt; ++i ) {
     312           0 :         if ( i==0 && isEverythingElse(seconddata[0].u.md_str))
     313           0 :             seconds[i] = copy("");
     314             :         else
     315           0 :             seconds[i] = copy(seconddata[i].u.md_str);
     316             :     }
     317           0 :     kcd->r2l = r2l = (kcd->subtable->lookup->lookup_flags & pst_r2l)?1:0;
     318             : 
     319           0 :     if ( !r2l ) {
     320           0 :         lefts = firsts; lcnt = fcnt;
     321           0 :         rights = seconds; rcnt = scnt;
     322             :     } else {
     323           0 :         lefts = seconds; lcnt = scnt;
     324           0 :         rights = firsts; rcnt=fcnt;
     325             :     }
     326           0 :     AutoKern2NewClass(kcd->sf,kcd->layer, lefts, rights, lcnt, rcnt,
     327             :             KCD_AddOffsetAsIs, kcd, separation, minkern, touch, onlyCloser, 0);
     328           0 :     for ( i=0; i<fcnt; ++i )
     329           0 :         free(firsts[i]);
     330           0 :     free(firsts);
     331           0 :     for ( i=0; i<scnt; ++i )
     332           0 :         free(seconds[i]);
     333           0 :     free(seconds);
     334             : }
     335             : 
     336             : /* ************************************************************************** */
     337             : /* ************************** Kern Class Display **************************** */
     338             : /* ************************************************************************** */
     339             : 
     340           0 : static void KPD_DoCancel(KernClassDlg *kcd) {
     341           0 :     BDFCharFree(kcd->fsc); BDFCharFree(kcd->ssc);
     342           0 :     kcd->fsc = kcd->ssc = NULL;
     343           0 :     free(kcd->active_adjust.corrections); kcd->active_adjust.corrections = NULL;
     344           0 :     free(kcd->orig_adjust.corrections); kcd->orig_adjust.corrections = NULL;
     345           0 :     kcd->done = true;
     346           0 : }
     347             : 
     348           0 : static int KPD_Cancel(GGadget *g, GEvent *e) {
     349           0 :     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
     350           0 :         KernClassDlg *kcd = GDrawGetUserData(GGadgetGetWindow(g));
     351           0 :         KPD_DoCancel(kcd);
     352             :     }
     353           0 : return( true );
     354             : }
     355             : 
     356             : static int KPD_FinishKP(KernClassDlg *);
     357             : 
     358           0 : static int KPD_OK(GGadget *g, GEvent *e) {
     359           0 :     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
     360           0 :         KernClassDlg *kcd = GDrawGetUserData(GGadgetGetWindow(g));
     361           0 :         if ( !KPD_FinishKP(kcd))
     362           0 : return( true );
     363           0 :         BDFCharFree(kcd->fsc); BDFCharFree(kcd->ssc);
     364           0 :         kcd->fsc = kcd->ssc = NULL;
     365           0 :         free(kcd->active_adjust.corrections); kcd->active_adjust.corrections = NULL;
     366           0 :         free(kcd->orig_adjust.corrections); kcd->orig_adjust.corrections = NULL;
     367           0 :         kcd->done = true;
     368             :     }
     369           0 : return( true );
     370             : }
     371             : 
     372           0 : static void KCD_Finalize(KernClassDlg *kcd) {
     373           0 :     const unichar_t *ret = _GGadgetGetTitle(GWidgetGetControl(kcd->gw,CID_KernOffset));
     374             :     unichar_t *end;
     375           0 :     int val = u_strtol(ret,&end,10);
     376             : 
     377           0 :     if ( kcd->old_pos==-1 )
     378           0 : return;
     379             : 
     380           0 :     if ( val<-32768 || val>32767 || *end!='\0' ) {
     381           0 :         ff_post_error( _("Bad Number"), _("Bad Number") );
     382           0 : return;
     383             :     }
     384           0 :     kcd->offsets[kcd->old_pos] = val;
     385           0 :     free(kcd->adjusts[kcd->old_pos].corrections);
     386           0 :     kcd->adjusts[kcd->old_pos] = kcd->active_adjust;
     387           0 :     kcd->active_adjust.corrections = NULL;
     388             : 
     389           0 :     BDFCharFree(kcd->fsc); BDFCharFree(kcd->ssc);
     390           0 :     kcd->fsc = kcd->ssc = NULL;
     391           0 :     GDrawRequestExpose(kcd->gw,NULL,false);
     392           0 :     kcd->old_pos = -1;
     393             : }
     394             : 
     395           0 : void KCD_DrawGlyph(GWindow pixmap,int x,int baseline,BDFChar *bdfc,int mag) {
     396             :     struct _GImage base;
     397             :     GImage gi;
     398             :     GClut clut;
     399             : 
     400           0 :     memset(&gi,'\0',sizeof(gi));
     401           0 :     memset(&base,'\0',sizeof(base));
     402           0 :     memset(&clut,'\0',sizeof(clut));
     403           0 :     gi.u.image = &base;
     404           0 :     base.clut = &clut;
     405           0 :     if ( !bdfc->byte_data ) {
     406           0 :         base.image_type = it_mono;
     407           0 :         clut.clut_len = 2;
     408           0 :         clut.clut[0] = GDrawGetDefaultBackground(NULL);
     409           0 :         clut.clut[1] = 0x000000;
     410             :     } else {
     411             :         int scale, l;
     412             :         Color fg, bg;
     413           0 :         scale = bdfc->depth == 8 ? 8 : 4;
     414           0 :         base.image_type = it_index;
     415           0 :         clut.clut_len = 1<<scale;
     416           0 :         bg = GDrawGetDefaultBackground(NULL);
     417           0 :         fg = GDrawGetDefaultForeground(NULL);
     418           0 :         for ( l=0; l<(1<<scale); ++l )
     419           0 :             clut.clut[l] =
     420           0 :                 COLOR_CREATE(
     421             :                  COLOR_RED(bg) + (l*(COLOR_RED(fg)-COLOR_RED(bg)))/((1<<scale)-1),
     422             :                  COLOR_GREEN(bg) + (l*(COLOR_GREEN(fg)-COLOR_GREEN(bg)))/((1<<scale)-1),
     423             :                  COLOR_BLUE(bg) + (l*(COLOR_BLUE(fg)-COLOR_BLUE(bg)))/((1<<scale)-1) );
     424             :     }
     425           0 :     base.data = bdfc->bitmap;
     426           0 :     base.bytes_per_line = bdfc->bytes_per_line;
     427           0 :     base.width = bdfc->xmax-bdfc->xmin+1;
     428           0 :     base.height = bdfc->ymax-bdfc->ymin+1;
     429           0 :     x += mag*bdfc->xmin;
     430           0 :     if ( mag==1 )
     431           0 :         GDrawDrawImage(pixmap,&gi,NULL,x,baseline-bdfc->ymax);
     432             :     else
     433           0 :         GDrawDrawImageMagnified(pixmap, &gi, NULL,
     434           0 :                 x,baseline-mag*bdfc->ymax,
     435           0 :                 base.width*mag,base.height*mag);
     436           0 : }
     437             : 
     438           0 : static int KCD_RightToLeft(KernClassDlg *kcd) {
     439           0 :     if ( kcd->subtable!=NULL )
     440           0 : return( kcd->subtable->lookup->lookup_flags&pst_r2l );
     441             : 
     442           0 :     if ( kcd->scf!=NULL ) {
     443           0 :         uint32 script = SCScriptFromUnicode(kcd->scf);
     444           0 :         if ( script!=DEFAULT_SCRIPT )
     445           0 : return( ScriptIsRightToLeft( script ));
     446             :     }
     447           0 :     if ( kcd->scs!=NULL ) {
     448           0 :         uint32 script = SCScriptFromUnicode(kcd->scs);
     449           0 :         if ( script!=DEFAULT_SCRIPT )
     450           0 : return( ScriptIsRightToLeft( script ));
     451             :     }
     452           0 : return( false );
     453             : }
     454             : 
     455           0 : static void KCD_KernMouse(KernClassDlg *kcd,GEvent *event) {
     456             :     int x, y, width;
     457             :     char buf[20];
     458             :     unichar_t ubuf[20];
     459             :     int kern, pkern;
     460             :     double scale;
     461             : //    printf("KCD_KernMouse()\n");
     462             : 
     463           0 :     scale = kcd->pixelsize/(double) (kcd->sf->ascent+kcd->sf->descent);
     464           0 :     kern = u_strtol(_GGadgetGetTitle(GWidgetGetControl(kcd->gw,CID_KernOffset)),NULL,10);
     465           0 :     pkern = kcd->magfactor*rint( kern*scale );       /* rounding can't include magnification */
     466             : 
     467           0 :     if ( !kcd->isv ) {
     468             :         /* Horizontal */
     469           0 :         width = kcd->magfactor*((kcd->fsc!=NULL?kcd->fsc->width:0)+(kcd->ssc!=NULL?kcd->ssc->width:0))+pkern;
     470           0 :         x = (kcd->subwidth - width)/2;
     471             : 
     472           0 :         if ( KCD_RightToLeft(kcd) ) {
     473           0 :             if ( kcd->ssc!=NULL )
     474           0 :                 width -= kcd->magfactor*kcd->ssc->width;
     475             :         } else {
     476           0 :             if ( kcd->fsc!=NULL ) {
     477           0 :                 x += kcd->magfactor*kcd->fsc->width + pkern;
     478           0 :                 width -= kcd->magfactor*kcd->fsc->width + pkern;
     479             :             }
     480             :         }
     481             : 
     482           0 :         if ( event->u.mouse.y>2*kcd->pixelsize*kcd->magfactor ||
     483           0 :                 event->u.mouse.x<x || event->u.mouse.x>x+width ) {
     484           0 :             if ( event->type == et_mousedown )
     485           0 : return;
     486           0 :             if ( kcd->within ) {
     487           0 :                 GDrawSetCursor(kcd->subw,ct_pointer);
     488           0 :                 if ( kcd->down && kcd->orig_kern!=kern ) {
     489           0 :                     sprintf(buf, "%d", kcd->orig_kern);
     490           0 :                     uc_strcpy(ubuf,buf);
     491           0 :                     GGadgetSetTitle(GWidgetGetControl(kcd->gw,CID_KernOffset),ubuf);
     492           0 :                     GDrawRequestExpose(kcd->subw,NULL,false);
     493             :                 }
     494           0 :                 kcd->within = false;
     495             :             }
     496           0 :             if ( event->type==et_mouseup )
     497           0 :                 kcd->down = false;
     498           0 : return;
     499             :         }
     500             : 
     501           0 :         if ( !kcd->within ) {
     502           0 :             GDrawSetCursor(kcd->subw,ct_leftright);
     503           0 :             kcd->within = true;
     504             :         }
     505           0 :         if ( event->type == et_mousedown ) {
     506           0 :             kcd->orig_kern = kern;
     507           0 :             kcd->down = true;
     508           0 :             kcd->downpos = event->u.mouse.x;
     509           0 :         } else if ( kcd->down ) {
     510             :             /* I multiply by 2 here because I center the glyphs, so the kerning */
     511             :             /*  changes in both directions */
     512           0 :             int nkern = kcd->orig_kern + rint(2*(event->u.mouse.x-kcd->downpos)/scale/kcd->magfactor);
     513           0 :             if ( kern!=nkern ) {
     514           0 :                 sprintf(buf, "%d", nkern);
     515           0 :                 uc_strcpy(ubuf,buf);
     516           0 :                 GGadgetSetTitle(GWidgetGetControl(kcd->gw,CID_KernOffset),ubuf);
     517           0 :                 GDrawRequestExpose(kcd->subw,NULL,false);
     518             :             }
     519           0 :             if ( event->type==et_mouseup ) {
     520           0 :                 kcd->down = false;
     521           0 :                 if ( nkern!=kcd->orig_kern && kcd->active_adjust.corrections!=NULL ) {
     522           0 :                     free(kcd->active_adjust.corrections);
     523           0 :                     kcd->active_adjust.corrections = NULL;
     524           0 :                     ubuf[0] = '0'; ubuf[1] = '\0';
     525           0 :                     GGadgetSetTitle(GWidgetGetControl(kcd->gw,CID_Correction),ubuf);
     526           0 :                     GDrawRequestExpose(kcd->subw,NULL,false);
     527             :                 }
     528             :             }
     529             :         }
     530             :     } else {
     531             :         /* Vertical */
     532           0 :         y = kcd->pixelsize/3;
     533           0 :         width = (kcd->ssc!=NULL ? kcd->magfactor*rint(kcd->ssc->sc->vwidth * scale) : 0);
     534           0 :         if ( kcd->fsc!=NULL )
     535           0 :             y += kcd->magfactor*rint(kcd->fsc->sc->vwidth * scale) + pkern;
     536           0 :         x = (kcd->subwidth/2 - kcd->pixelsize/2)*kcd->magfactor;
     537             : 
     538           0 :         if ( event->u.mouse.y<y || event->u.mouse.y>y+width ||
     539           0 :                 event->u.mouse.x<x || event->u.mouse.x>x+kcd->pixelsize ) {
     540           0 :             if ( event->type == et_mousedown )
     541           0 : return;
     542           0 :             if ( kcd->within ) {
     543           0 :                 GDrawSetCursor(kcd->subw,ct_pointer);
     544           0 :                 if ( kcd->down && kcd->orig_kern!=kern ) {
     545           0 :                     sprintf(buf, "%d", kcd->orig_kern);
     546           0 :                     uc_strcpy(ubuf,buf);
     547           0 :                     GGadgetSetTitle(GWidgetGetControl(kcd->gw,CID_KernOffset),ubuf);
     548           0 :                     GDrawRequestExpose(kcd->subw,NULL,false);
     549             :                 }
     550           0 :                 kcd->within = false;
     551             :             }
     552           0 :             if ( event->type==et_mouseup )
     553           0 :                 kcd->down = false;
     554           0 : return;
     555             :         }
     556             : 
     557           0 :         if ( !kcd->within ) {
     558           0 :             GDrawSetCursor(kcd->subw,ct_updown);
     559           0 :             kcd->within = true;
     560             :         }
     561           0 :         if ( event->type == et_mousedown ) {
     562           0 :             kcd->orig_kern = kern;
     563           0 :             kcd->down = true;
     564           0 :             kcd->downpos = event->u.mouse.y;
     565           0 :         } else if ( kcd->down ) {
     566           0 :             int nkern = kcd->orig_kern + rint((event->u.mouse.y-kcd->downpos)/scale)/kcd->magfactor;
     567           0 :             if ( kern!=nkern ) {
     568           0 :                 sprintf(buf, "%d", nkern);
     569           0 :                 uc_strcpy(ubuf,buf);
     570           0 :                 GGadgetSetTitle(GWidgetGetControl(kcd->gw,CID_KernOffset),ubuf);
     571           0 :                 GDrawRequestExpose(kcd->subw,NULL,false);
     572             :             }
     573           0 :             if ( event->type==et_mouseup ) {
     574           0 :                 kcd->down = false;
     575           0 :                 if ( nkern!=kcd->orig_kern && kcd->active_adjust.corrections!=NULL ) {
     576           0 :                     free(kcd->active_adjust.corrections);
     577           0 :                     kcd->active_adjust.corrections = NULL;
     578           0 :                     ubuf[0] = '0'; ubuf[1] = '\0';
     579           0 :                     GGadgetSetTitle(GWidgetGetControl(kcd->gw,CID_Correction),ubuf);
     580           0 :                     GDrawRequestExpose(kcd->subw,NULL,false);
     581             :                 }
     582             :             }
     583             :         }
     584             :     }
     585             : }
     586             : 
     587           0 : static void KCD_KernExpose(KernClassDlg *kcd,GWindow pixmap,GEvent *event) {
     588             :     int x, y;
     589           0 :     SplineFont *sf = kcd->sf;
     590           0 :     int em = sf->ascent+sf->descent;
     591           0 :     int as = kcd->magfactor*rint(sf->ascent*kcd->pixelsize/(double) em);
     592           0 :     const unichar_t *ret = _GGadgetGetTitle(GWidgetGetControl(kcd->gw,CID_KernOffset));
     593           0 :     int kern = u_strtol(ret,NULL,10);
     594             :     int baseline, xbaseline;
     595             : 
     596             : //    printf("KCD_KernExpose() ssc:%p fsc:%p\n", kcd->ssc, kcd->fsc );
     597             : 
     598           0 :     kern = kcd->magfactor*rint(kern*kcd->pixelsize/(double) em);
     599             : 
     600             :     { int correction;
     601             :         unichar_t *end;
     602             : 
     603           0 :         ret = _GGadgetGetTitle(GWidgetGetControl(kcd->gw,CID_Correction));
     604           0 :         correction = u_strtol(ret,&end,10);
     605           0 :         while ( *end==' ' ) ++end;
     606           0 :         if ( *end=='\0' && correction>=-128 && correction<=127 )
     607           0 :             kern += correction*kcd->magfactor;
     608             :     }
     609             : 
     610           0 :     if ( !kcd->isv ) {
     611           0 :         x = (kcd->subwidth-( kcd->magfactor*(kcd->fsc!=NULL?kcd->fsc->width:0)+
     612           0 :                 kcd->magfactor*(kcd->ssc!=NULL?kcd->ssc->width:0)+
     613             :                 kern))/2;
     614           0 :         baseline = 0 + as + kcd->magfactor*kcd->pixelsize/2;
     615           0 :         if ( KCD_RightToLeft(kcd) ) {
     616           0 :             if ( kcd->ssc!=NULL ) {
     617           0 :                 KCD_DrawGlyph(pixmap,x,baseline,kcd->ssc,kcd->magfactor);
     618           0 :                 x += kcd->magfactor*kcd->ssc->width + kern;
     619             :             }
     620           0 :             if ( kcd->fsc!=NULL )
     621           0 :                 KCD_DrawGlyph(pixmap,x,baseline,kcd->fsc,kcd->magfactor);
     622             :         } else {
     623           0 :             if ( kcd->fsc!=NULL ) {
     624           0 :                 KCD_DrawGlyph(pixmap,x,baseline,kcd->fsc,kcd->magfactor);
     625           0 :                 x += kcd->fsc->width*kcd->magfactor + kern;
     626             :             }
     627           0 :             if ( kcd->ssc!=NULL )
     628           0 :                 KCD_DrawGlyph(pixmap,x,baseline,kcd->ssc,kcd->magfactor);
     629             :         }
     630             :     } else {
     631             :         /* I don't support top to bottom vertical */
     632           0 :         y = kcd->magfactor*kcd->pixelsize/3 + as;
     633           0 :         xbaseline = kcd->subwidth/2;
     634           0 :         if ( kcd->fsc!=NULL ) {
     635           0 :             KCD_DrawGlyph(pixmap,xbaseline-kcd->magfactor*kcd->pixelsize/2,y,kcd->fsc,kcd->magfactor);
     636           0 :             y += kcd->magfactor*rint(kcd->fsc->sc->vwidth * kcd->pixelsize/(double) em) + kern;
     637             :         }
     638           0 :         if ( kcd->ssc!=NULL )
     639           0 :             KCD_DrawGlyph(pixmap,xbaseline-kcd->magfactor*kcd->pixelsize/2,y,kcd->ssc,kcd->magfactor);
     640             :     }
     641           0 : }
     642             : 
     643           0 : static int KCD_KernOffChanged(GGadget *g, GEvent *e) {
     644           0 :     KernClassDlg *kcd = GDrawGetUserData(GGadgetGetWindow(g));
     645           0 :     if ( e->type==et_controlevent && e->u.control.subtype == et_textchanged )
     646           0 :         GDrawRequestExpose(kcd->subw,NULL,false);
     647           0 : return( true );
     648             : }
     649             : 
     650           0 : static void KCD_UpdateGlyphFromName(KernClassDlg *kcd,int which,char* glyphname)
     651             : {
     652           0 :     BDFChar **scpos = which==0 ? &kcd->fsc : &kcd->ssc;
     653           0 :     SplineChar **possc = which==0 ? &kcd->scf : &kcd->scs;
     654             :     SplineChar *sc;
     655           0 :     void *freetypecontext=NULL;
     656           0 :     printf("KCD_UpdateGlyphFromName() which:%d iskp:%d\n", which, kcd->iskernpair);
     657             : 
     658           0 :     char* localglyphname = copy( glyphname );
     659           0 :     char* p = 0;
     660           0 :     if((p = strstr( localglyphname, " " )))
     661           0 :         *p = '\0';
     662             : 
     663           0 :     BDFCharFree(*scpos);
     664           0 :     *scpos = NULL;
     665             : 
     666           0 :     *possc = sc = SFGetChar( kcd->sf, -1, localglyphname);
     667           0 :     free( localglyphname );
     668             : 
     669           0 :     if ( sc==NULL )
     670           0 :         return;
     671             : 
     672           0 :     if ( GGadgetIsChecked(GWidgetGetControl(kcd->gw,CID_FreeType)) )
     673           0 :         freetypecontext = FreeTypeFontContext(sc->parent,sc,sc->parent->fv,kcd->layer);
     674           0 :     if ( freetypecontext )
     675             :     {
     676           0 :         *scpos = SplineCharFreeTypeRasterize(freetypecontext,sc->orig_pos,kcd->pixelsize,72,8);
     677           0 :         FreeTypeFreeContext(freetypecontext);
     678             :     }
     679             :     else
     680             :     {
     681           0 :         *scpos = SplineCharAntiAlias(sc,kcd->layer,kcd->pixelsize,4);
     682             :     }
     683             : 
     684           0 :     printf("KCD_UpdateGlyph() scpos:%p\n", *scpos );
     685             : }
     686             : 
     687           0 : static void KCD_UpdateGlyph(KernClassDlg *kcd,int which) {
     688           0 :     BDFChar **scpos = which==0 ? &kcd->fsc : &kcd->ssc;
     689           0 :     SplineChar **possc = which==0 ? &kcd->scf : &kcd->scs;
     690             :     SplineChar *sc;
     691             :     char *temp;
     692           0 :     void *freetypecontext=NULL;
     693             : //    printf("KCD_UpdateGlyph() which:%d iskp:%d\n", which, kcd->iskernpair);
     694             : 
     695           0 :     BDFCharFree(*scpos);
     696           0 :     *scpos = NULL;
     697           0 :     if ( kcd->iskernpair )
     698             :     {
     699           0 :         temp = cu_copy(_GGadgetGetTitle(GWidgetGetControl(kcd->gw,
     700             :                 which==0 ? CID_First : CID_Second )));
     701             :     }
     702             :     else
     703             :     {
     704           0 :         GTextInfo *sel = GGadgetGetListItemSelected(GWidgetGetControl(kcd->gw,
     705             :                 which==0 ? CID_First : CID_Second ));
     706           0 :         if ( sel==NULL )
     707             :         {
     708             : //          printf("KCD_UpdateGlyph() which:%d no selection...returning\n", which );
     709           0 :             return;
     710             :         }
     711             :         else
     712             :         {
     713           0 :             temp = cu_copy(sel->text);
     714             :         }
     715             : 
     716             : //      printf("KCD_UpdateGlyph() temp:%s\n", temp );
     717             :     }
     718             : 
     719           0 :     *possc = sc = SFGetChar(kcd->sf,-1,temp);
     720           0 :     free(temp);
     721           0 :     if ( sc==NULL )
     722           0 :         return;
     723           0 :     if ( GGadgetIsChecked(GWidgetGetControl(kcd->gw,CID_FreeType)) )
     724           0 :         freetypecontext = FreeTypeFontContext(sc->parent,sc,sc->parent->fv,kcd->layer);
     725           0 :     if ( freetypecontext )
     726             :     {
     727           0 :         *scpos = SplineCharFreeTypeRasterize(freetypecontext,sc->orig_pos,kcd->pixelsize,72,8);
     728           0 :         FreeTypeFreeContext(freetypecontext);
     729             :     }
     730             :     else
     731             :     {
     732           0 :         *scpos = SplineCharAntiAlias(sc,kcd->layer,kcd->pixelsize,4);
     733             :     }
     734             : 
     735             : //    printf("KCD_UpdateGlyph() scpos:%p\n", *scpos );
     736             : }
     737             : 
     738           0 : static void _KCD_DisplaySizeChanged(KernClassDlg *kcd) {
     739           0 :     const unichar_t *ret = _GGadgetGetTitle(GWidgetGetControl(kcd->gw,CID_DisplaySize));
     740             :     unichar_t *end;
     741           0 :     int pixelsize = u_strtol(ret,&end,10);
     742             : 
     743           0 :     while ( *end==' ' ) ++end;
     744           0 :     if ( pixelsize>4 && pixelsize<400 && *end=='\0' ) {
     745             :         unichar_t ubuf[20]; char buffer[20];
     746           0 :         ubuf[0] = '0'; ubuf[1] = '\0';
     747           0 :         if ( kcd->active_adjust.corrections!=NULL &&
     748           0 :                 pixelsize>=kcd->active_adjust.first_pixel_size &&
     749           0 :                 pixelsize<=kcd->active_adjust.last_pixel_size ) {
     750           0 :             sprintf( buffer, "%d", kcd->active_adjust.corrections[
     751           0 :                     pixelsize-kcd->active_adjust.first_pixel_size]);
     752           0 :             uc_strcpy(ubuf,buffer);
     753             :         }
     754           0 :         GGadgetSetTitle(GWidgetGetControl(kcd->gw,CID_Correction),ubuf);
     755           0 :         kcd->pixelsize = pixelsize;
     756           0 :         KCD_UpdateGlyph(kcd,0);
     757           0 :         KCD_UpdateGlyph(kcd,1);
     758           0 :         GDrawRequestExpose(kcd->subw,NULL,false);
     759             :     }
     760           0 : }
     761             : 
     762           0 : static int KCD_DisplaySizeChanged(GGadget *g, GEvent *e) {
     763           0 :     KernClassDlg *kcd = GDrawGetUserData(GGadgetGetWindow(g));
     764           0 :     if ( e->type==et_controlevent && e->u.control.subtype == et_textchanged ) {
     765           0 :         _KCD_DisplaySizeChanged(kcd);
     766             :     }
     767           0 : return( true );
     768             : }
     769             : 
     770           0 : static int KCD_MagnificationChanged(GGadget *g, GEvent *e) {
     771           0 :     KernClassDlg *kcd = GDrawGetUserData(GGadgetGetWindow(g));
     772           0 :     if ( e->type==et_controlevent && e->u.control.subtype == et_listselected ) {
     773           0 :         int mag = GGadgetGetFirstListSelectedItem(GWidgetGetControl(kcd->gw,CID_Magnifications));
     774             : 
     775           0 :         if ( mag!=-1 && mag!=kcd->magfactor-1 ) {
     776           0 :             kcd->magfactor = mag+1;
     777           0 :             GDrawRequestExpose(kcd->subw,NULL,false);
     778             :         }
     779             :     }
     780           0 : return( true );
     781             : }
     782             : 
     783           0 : static int KCB_FreeTypeChanged(GGadget *g, GEvent *e) {
     784           0 :     KernClassDlg *kcd = GDrawGetUserData(GGadgetGetWindow(g));
     785           0 :     if ( e->type==et_controlevent && e->u.control.subtype == et_radiochanged ) {
     786           0 :         KCD_UpdateGlyph(kcd,0);
     787           0 :         KCD_UpdateGlyph(kcd,1);
     788           0 :         GDrawRequestExpose(kcd->subw,NULL,false);
     789             :     }
     790           0 : return( true );
     791             : }
     792             : 
     793           0 : static int KCD_CorrectionChanged(GGadget *g, GEvent *e) {
     794           0 :     KernClassDlg *kcd = GDrawGetUserData(GGadgetGetWindow(g));
     795           0 :     if ( e->type==et_controlevent && e->u.control.subtype == et_textchanged ) {
     796           0 :         const unichar_t *ret = _GGadgetGetTitle(GWidgetGetControl(kcd->gw,CID_Correction));
     797             :         unichar_t *end;
     798           0 :         int correction = u_strtol(ret,&end,10);
     799             : 
     800           0 :         while ( *end==' ' ) ++end;
     801           0 :         if ( *end!='\0' )
     802           0 : return( true );
     803           0 :         if ( correction<-128 || correction>127 ) {
     804           0 :             ff_post_error(_("Value out of range"),_("Value out of range"));
     805           0 : return( true );
     806             :         }
     807             : 
     808           0 :         DeviceTableSet(&kcd->active_adjust,kcd->pixelsize,correction);
     809           0 :         GDrawRequestExpose(kcd->subw,NULL,false);
     810           0 :         GGadgetSetEnabled(GWidgetGetControl(kcd->gw,CID_ClearDevice),
     811           0 :                 kcd->active_adjust.corrections!=NULL);
     812             :     }
     813           0 : return( true );
     814             : }
     815             : 
     816           0 : static int KCD_ClearDevice(GGadget *g, GEvent *e) {
     817           0 :     KernClassDlg *kcd = GDrawGetUserData(GGadgetGetWindow(g));
     818           0 :     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
     819           0 :         free(kcd->active_adjust.corrections);
     820           0 :         kcd->active_adjust.corrections = NULL;
     821           0 :         kcd->active_adjust.first_pixel_size = kcd->active_adjust.last_pixel_size = 0;
     822           0 :         GGadgetSetTitle8(GWidgetGetControl(kcd->gw,CID_Correction),"0");
     823           0 :         GGadgetSetEnabled(g,false);
     824             :     }
     825           0 : return( true );
     826             : }
     827             : 
     828           0 : static int KCD_RevertKerning(GGadget *g, GEvent *e) {
     829           0 :     KernClassDlg *kcd = GDrawGetUserData(GGadgetGetWindow(g));
     830           0 :     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
     831             :         char buf[20];
     832           0 :         sprintf( buf, "%d", kcd->orig_kern_offset );
     833           0 :         GGadgetSetTitle8(GWidgetGetControl(kcd->gw,CID_KernOffset),buf);
     834           0 :         free(kcd->active_adjust.corrections);
     835           0 :         kcd->active_adjust = kcd->orig_adjust;
     836           0 :         if ( kcd->orig_adjust.corrections!=NULL ) {
     837           0 :             int len = kcd->orig_adjust.last_pixel_size-kcd->orig_adjust.first_pixel_size+1;
     838           0 :             kcd->active_adjust = kcd->orig_adjust;
     839           0 :             kcd->active_adjust.corrections = malloc(len);
     840           0 :             memcpy(kcd->active_adjust.corrections,kcd->orig_adjust.corrections,len);
     841             :         }
     842           0 :         _KCD_DisplaySizeChanged(kcd);
     843             :     }
     844           0 : return( true );
     845             : }
     846             : 
     847           0 : static void KPD_RestoreGlyphs(KernClassDlg *kcd) {
     848           0 :     if ( kcd->scf!=NULL )
     849           0 :         GGadgetSetTitle8(GWidgetGetControl(kcd->gw,CID_First),kcd->scf->name);
     850           0 :     if ( kcd->scs!=NULL )
     851           0 :         GGadgetSetTitle8(GWidgetGetControl(kcd->gw,CID_Second),kcd->scs->name);
     852           0 : }
     853             : 
     854           0 : static int KPD_FinishKP(KernClassDlg *kcd) {
     855             :     KernPair *kp;
     856           0 :     const unichar_t *ret = _GGadgetGetTitle(GWidgetGetControl(kcd->gw,CID_KernOffset));
     857           0 :     int offset = u_strtol(ret,NULL,10);
     858             : 
     859           0 :     if ( kcd->scf!=NULL && kcd->scs!=NULL ) {
     860           0 :         for ( kp = kcd->isv?kcd->scf->vkerns:kcd->scf->kerns; kp!=NULL && kp->sc!=kcd->scs; kp=kp->next );
     861           0 :         if ( kp==NULL && offset==0 && kcd->active_adjust.corrections==NULL )
     862           0 : return(true);
     863           0 :         if ( kcd->subtable==NULL ) {
     864           0 :             ff_post_error(_("No lookup selected"),_("You must select a lookup subtable to contain this kerning pair" ));
     865           0 : return(false);
     866             :         }
     867           0 :         if ( kp==NULL ) {
     868           0 :             kp = chunkalloc(sizeof(KernPair));
     869           0 :             kp->next = kcd->isv?kcd->scf->vkerns:kcd->scf->kerns;
     870           0 :             kp->sc = kcd->scs;
     871           0 :             if ( kcd->isv )
     872           0 :                 kcd->scf->vkerns = kp;
     873             :             else
     874           0 :                 kcd->scf->kerns = kp;
     875             :         }
     876           0 :         kp->subtable = kcd->subtable;
     877           0 :         kp->off = offset;
     878           0 :         if ( kp->adjust!=NULL && kcd->active_adjust.corrections!=NULL ) {
     879           0 :             free(kp->adjust->corrections);
     880           0 :             *kp->adjust = kcd->active_adjust;
     881           0 :         } else if ( kcd->active_adjust.corrections!=NULL ) {
     882           0 :             kp->adjust = chunkalloc(sizeof(DeviceTable));
     883           0 :             *kp->adjust = kcd->active_adjust;
     884           0 :         } else if ( kp->adjust!=NULL ) {
     885           0 :             DeviceTableFree(kp->adjust);
     886           0 :             kp->adjust = NULL;
     887             :         }
     888           0 :         memset(&kcd->active_adjust,0,sizeof(DeviceTable));
     889             :     }
     890           0 : return( true );
     891             : }
     892             : 
     893           0 : static void KCD_SetDevTab(KernClassDlg *kcd) {
     894             :     unichar_t ubuf[20];
     895             : 
     896           0 :     ubuf[0] = '0'; ubuf[1] = '\0';
     897           0 :     GGadgetClearList(GWidgetGetControl(kcd->gw,CID_DisplaySize));
     898           0 :     if ( kcd->active_adjust.corrections!=NULL ) {
     899             :         int i;
     900           0 :         int len = kcd->active_adjust.last_pixel_size - kcd->active_adjust.first_pixel_size +1;
     901             :         char buffer[20];
     902           0 :         GTextInfo **ti = malloc((len+1)*sizeof(GTextInfo *));
     903           0 :         for ( i=0; i<len; ++i ) {
     904           0 :             ti[i] = calloc(1,sizeof(GTextInfo));
     905           0 :             sprintf( buffer, "%d", i+kcd->active_adjust.first_pixel_size);
     906           0 :             ti[i]->text = uc_copy(buffer);
     907           0 :             ti[i]->fg = ti[i]->bg = COLOR_DEFAULT;
     908             :         }
     909           0 :         ti[i] = calloc(1,sizeof(GTextInfo));
     910           0 :         GGadgetSetList(GWidgetGetControl(kcd->gw,CID_DisplaySize),ti,false);
     911           0 :         if ( kcd->pixelsize>=kcd->active_adjust.first_pixel_size &&
     912           0 :                 kcd->pixelsize<=kcd->active_adjust.last_pixel_size ) {
     913           0 :             sprintf( buffer, "%d", kcd->active_adjust.corrections[
     914           0 :                     kcd->pixelsize-kcd->active_adjust.first_pixel_size]);
     915           0 :             uc_strcpy(ubuf,buffer);
     916             :         }
     917             :     }
     918           0 :     GGadgetSetTitle(GWidgetGetControl(kcd->gw,CID_Correction),ubuf);
     919           0 :     GGadgetSetEnabled(GWidgetGetControl(kcd->gw,CID_ClearDevice),
     920           0 :             kcd->active_adjust.corrections!=NULL);
     921           0 : }
     922             : 
     923           0 : static void KP_SelectSubtable(KernClassDlg *kcd,struct lookup_subtable *sub) {
     924             :     int32 len;
     925           0 :     GTextInfo **ti = GGadgetGetList(GWidgetGetControl(kcd->gw,CID_Subtable),&len);
     926           0 :     int i, new_pos = -1;
     927             : 
     928           0 :     for ( i=0; i<len; ++i ) if ( !ti[i]->line ) {
     929           0 :         if ( ti[i]->userdata == sub )
     930           0 :     break;
     931           0 :         else if ( ti[i]->userdata == NULL )
     932           0 :             new_pos = i;
     933             :     }
     934           0 :     if ( i==len )
     935           0 :         i = new_pos;
     936           0 :     if ( i!=-1 )
     937           0 :         GGadgetSelectOneListItem(GWidgetGetControl(kcd->gw,CID_Subtable),i);
     938           0 :     if ( sub!=NULL )
     939           0 :         kcd->subtable = sub;
     940           0 : }
     941             : 
     942           0 : static int KP_Subtable(GGadget *g, GEvent *e) {
     943           0 :     KernClassDlg *kcd = GDrawGetUserData(GGadgetGetWindow(g));
     944             :     GTextInfo *ti;
     945             :     struct lookup_subtable *sub;
     946             :     struct subtable_data sd;
     947             : 
     948           0 :     if ( e->type==et_controlevent && e->u.control.subtype == et_listselected ) {
     949           0 :         ti = GGadgetGetListItemSelected(g);
     950           0 :         if ( ti!=NULL ) {
     951           0 :             if ( ti->userdata!=NULL )
     952           0 :                 kcd->subtable = ti->userdata;
     953             :             else {
     954           0 :                 memset(&sd,0,sizeof(sd));
     955           0 :                 sd.flags = (kcd->isv ? sdf_verticalkern : sdf_horizontalkern ) |
     956             :                         sdf_kernpair;
     957           0 :                 sub = SFNewLookupSubtableOfType(kcd->sf,gpos_pair,&sd,kcd->layer);
     958           0 :                 if ( sub!=NULL ) {
     959           0 :                     kcd->subtable = sub;
     960           0 :                     GGadgetSetList(g,SFSubtablesOfType(kcd->sf,gpos_pair,false,false),false);
     961             :                 }
     962           0 :                 KP_SelectSubtable(kcd,kcd->subtable);
     963             :             }
     964             :         }
     965             :     }
     966           0 : return( true );
     967             : }
     968             : 
     969           0 : static void KPD_PairSearch(KernClassDlg *kcd) {
     970           0 :     int offset = 0;
     971           0 :     KernPair *kp=NULL;
     972             :     char buf[20];
     973             :     unichar_t ubuf[20];
     974             : 
     975           0 :     free(kcd->active_adjust.corrections); kcd->active_adjust.corrections = NULL;
     976           0 :     if ( kcd->scf!=NULL && kcd->scs!=NULL ) {
     977           0 :         for ( kp = kcd->isv?kcd->scf->vkerns:kcd->scf->kerns; kp!=NULL && kp->sc!=kcd->scs; kp=kp->next );
     978           0 :         if ( kp!=NULL ) {
     979           0 :             offset = kp->off;
     980           0 :             kcd->orig_kern_offset = offset;
     981           0 :             KP_SelectSubtable(kcd,kp->subtable);
     982           0 :             if ( kp->adjust!=NULL ) {
     983           0 :                 int len = kp->adjust->last_pixel_size-kp->adjust->first_pixel_size+1;
     984           0 :                 kcd->active_adjust = *kp->adjust;
     985           0 :                 kcd->active_adjust.corrections = malloc(len);
     986           0 :                 memcpy(kcd->active_adjust.corrections,kp->adjust->corrections,len);
     987           0 :                 kcd->orig_adjust = *kp->adjust;
     988           0 :                 kcd->orig_adjust.corrections = malloc(len);
     989           0 :                 memcpy(kcd->orig_adjust.corrections,kp->adjust->corrections,len);
     990             :             }
     991             :         }
     992             :     }
     993           0 :     if ( kp==NULL && kcd->scf!=NULL ) {
     994             :         int32 len;
     995           0 :         GTextInfo **ti = GGadgetGetList(GWidgetGetControl(kcd->gw,CID_Subtable),&len);
     996           0 :         uint32 script = SCScriptFromUnicode(kcd->scf);
     997             :         int i;
     998           0 :         struct lookup_subtable *sub = NULL;
     999             : 
    1000           0 :         for ( i=0; i<len; ++i ) {
    1001           0 :             struct lookup_subtable *test = ti[i]->userdata;
    1002           0 :             if ( test!=NULL && ScriptInFeatureScriptList(script,test->lookup->features)) {
    1003           0 :                 sub = test;
    1004           0 :         break;
    1005             :             }
    1006             :         }
    1007           0 :         KP_SelectSubtable(kcd,sub);
    1008             :     }
    1009             : 
    1010           0 :     sprintf(buf, "%d", offset);
    1011           0 :     uc_strcpy(ubuf,buf);
    1012           0 :     GGadgetSetTitle(GWidgetGetControl(kcd->gw,CID_KernOffset),ubuf);
    1013           0 :     KCD_SetDevTab(kcd);
    1014           0 : }
    1015             : 
    1016           0 : static void KPD_BuildKernList(KernClassDlg *kcd) {
    1017             :     int len;
    1018             :     KernPair *kp;
    1019             :     GTextInfo **ti;
    1020             : 
    1021           0 :     len = 0;
    1022           0 :     if ( kcd->scf!=NULL )
    1023           0 :         for ( kp=kcd->isv?kcd->scf->vkerns:kcd->scf->kerns, len=0; kp!=NULL; kp=kp->next )
    1024           0 :             ++len;
    1025           0 :     ti = calloc(len+1,sizeof(GTextInfo*));
    1026           0 :     if ( kcd->scf!=NULL )
    1027           0 :         for ( kp=kcd->isv?kcd->scf->vkerns:kcd->scf->kerns, len=0; kp!=NULL; kp=kp->next, ++len ) {
    1028           0 :             ti[len] = calloc(1,sizeof(GTextInfo));
    1029           0 :             ti[len]->fg = ti[len]->bg = COLOR_DEFAULT;
    1030           0 :             ti[len]->text = uc_copy(kp->sc->name);
    1031             :         }
    1032           0 :     ti[len] = calloc(1,sizeof(GTextInfo));
    1033           0 :     GGadgetSetList(GWidgetGetControl(kcd->gw,CID_Second),ti,false);
    1034           0 : }
    1035             : 
    1036           0 : static int KCD_GlyphSelected(GGadget *g, GEvent *e) {
    1037           0 :     KernClassDlg *kcd = GDrawGetUserData(GGadgetGetWindow(g));
    1038           0 :     int which = GGadgetGetCid(g)==CID_Second;
    1039           0 :     if ( e->type==et_controlevent && e->u.control.subtype == et_listselected ) {
    1040           0 :         KCD_UpdateGlyph(kcd,which);
    1041           0 :         GDrawRequestExpose(kcd->subw,NULL,false);
    1042           0 :     } else if ( e->type==et_controlevent && e->u.control.subtype == et_textchanged ) {
    1043           0 :         if ( !KPD_FinishKP(kcd)) {
    1044           0 :             KPD_RestoreGlyphs(kcd);
    1045           0 : return( true );
    1046             :         }
    1047           0 :         KCD_UpdateGlyph(kcd,which);
    1048           0 :         if ( which==0 )
    1049           0 :             KPD_BuildKernList(kcd);
    1050           0 :         KPD_PairSearch(kcd);
    1051           0 :         GDrawRequestExpose(kcd->subw,NULL,false);
    1052             :     }
    1053           0 : return( true );
    1054             : }
    1055             : 
    1056           0 : static GTextInfo **TiNamesFromClass(GGadget *list,int class_index) {
    1057             :     /* Return a list containing all the names in this class */
    1058             :     char *pt, *end;
    1059             :     GTextInfo **ti;
    1060             :     int cnt;
    1061           0 :     struct matrix_data *classes = GMatrixEditGet(list,&cnt);
    1062           0 :     char *class_str = classes[class_index].u.md_str;
    1063             :     int i, k;
    1064             : 
    1065           0 :     if ( class_str==NULL || isEverythingElse(class_str) ) {
    1066           0 :         i=0;
    1067           0 :         ti = malloc((i+1)*sizeof(GTextInfo*));
    1068             :     } else {
    1069           0 :         for ( k=0 ; k<2; ++k ) {
    1070           0 :             for ( i=0, pt=class_str; *pt; ) {
    1071           0 :                 while ( *pt==' ' ) ++pt;
    1072           0 :                 if ( *pt=='\0' )
    1073           0 :             break;
    1074           0 :                 for ( end = pt; *end!='\0' && *end!=' '; ++end );
    1075           0 :                 if ( k==1 ) {
    1076           0 :                     ti[i] = calloc(1,sizeof(GTextInfo));
    1077           0 :                     ti[i]->text = utf82u_copyn(pt,end-pt);
    1078           0 :                     ti[i]->bg = ti[i]->fg = COLOR_DEFAULT;
    1079             :                 }
    1080           0 :                 ++i;
    1081           0 :                 pt = end;
    1082             :             }
    1083           0 :             if ( k==0 )
    1084           0 :                 ti = malloc((i+1)*sizeof(GTextInfo*));
    1085             :         }
    1086             :     }
    1087           0 :     if ( i>0 )
    1088           0 :         ti[0]->selected = true;
    1089           0 :     ti[i] = calloc(1,sizeof(GTextInfo));
    1090           0 : return( ti );
    1091             : }
    1092             : 
    1093           0 : static void KCD_EditOffset(KernClassDlg *kcd, int first, int second) {
    1094             :     char buf[12];
    1095             :     unichar_t ubuf[12];
    1096             :     GTextInfo **ti;
    1097             :     static unichar_t nullstr[] = { 0 };
    1098             : 
    1099           0 :     KCD_Finalize(kcd);
    1100           0 :     if ( GMatrixEditGetActiveRow(GWidgetGetControl(kcd->gw,CID_ClassList))!=first )
    1101           0 :         GMatrixEditActivateRowCol(GWidgetGetControl(kcd->gw,CID_ClassList),first,-1);
    1102           0 :     if ( GMatrixEditGetActiveRow(GWidgetGetControl(kcd->gw,CID_ClassList+100))!=second )
    1103           0 :         GMatrixEditActivateRowCol(GWidgetGetControl(kcd->gw,CID_ClassList+100),second,-1);
    1104           0 :     if ( second==0 )
    1105           0 :         ff_post_notice(_("Class 0"),_("The kerning values for class 0 (\"Everything Else\") should always be 0"));
    1106           0 :     if ( first!=-1 && second!=-1 && first < kcd->first_cnt && second < kcd->second_cnt ) {
    1107           0 :         kcd->st_pos = first*kcd->second_cnt+second;
    1108           0 :         kcd->old_pos = kcd->st_pos;
    1109           0 :         GGadgetSetList(GWidgetGetControl(kcd->gw,CID_First),
    1110           0 :                 ti = TiNamesFromClass(GWidgetGetControl(kcd->gw,CID_ClassList),first),false);
    1111           0 :         GGadgetSetTitle(GWidgetGetControl(kcd->gw,CID_First),
    1112           0 :                 ti==NULL || ti[0]->text==NULL ? nullstr: ti[0]->text);
    1113           0 :         GGadgetSetList(GWidgetGetControl(kcd->gw,CID_Second),
    1114           0 :                 ti = TiNamesFromClass(GWidgetGetControl(kcd->gw,CID_ClassList+100),second),false);
    1115           0 :         GGadgetSetTitle(GWidgetGetControl(kcd->gw,CID_Second),
    1116           0 :                 ti==NULL || ti[0]->text==NULL ? nullstr: ti[0]->text);
    1117           0 :         KCD_UpdateGlyph(kcd,0);
    1118           0 :         KCD_UpdateGlyph(kcd,1);
    1119             : 
    1120           0 :         kcd->orig_kern_offset = kcd->offsets[kcd->st_pos];
    1121           0 :         sprintf( buf, "%d", kcd->offsets[kcd->st_pos]);
    1122           0 :         uc_strcpy(ubuf,buf);
    1123           0 :         GGadgetSetTitle(GWidgetGetControl(kcd->gw,CID_KernOffset),ubuf);
    1124             : 
    1125           0 :         kcd->active_adjust = kcd->adjusts[kcd->st_pos];
    1126           0 :         kcd->orig_adjust = kcd->adjusts[kcd->st_pos];
    1127           0 :         if ( kcd->active_adjust.corrections!=NULL ) {
    1128           0 :             int len = kcd->active_adjust.last_pixel_size - kcd->active_adjust.first_pixel_size +1;
    1129           0 :             kcd->active_adjust.corrections = malloc(len);
    1130           0 :             memcpy(kcd->active_adjust.corrections,kcd->adjusts[kcd->st_pos].corrections,len);
    1131           0 :             kcd->orig_adjust.corrections = malloc(len);
    1132           0 :             memcpy(kcd->orig_adjust.corrections,kcd->adjusts[kcd->st_pos].corrections,len);
    1133             :         }
    1134           0 :         KCD_SetDevTab(kcd);
    1135             :     }
    1136           0 :     GDrawRequestExpose(kcd->subw,NULL,false);
    1137           0 :     GDrawRequestExpose(kcd->gw,NULL,false);
    1138           0 : }
    1139             : 
    1140             : /* ************************************************************************** */
    1141             : /* *************************** Kern Class Dialog **************************** */
    1142             : /* ************************************************************************** */
    1143             : 
    1144           0 : static void KC_DoResize(KernClassDlg *kcd) {
    1145             :     GRect wsize, csize;
    1146             : 
    1147           0 :     GDrawGetSize(kcd->gw,&wsize);
    1148             : 
    1149           0 :     kcd->fullwidth = wsize.width;
    1150           0 :     kcd->width = wsize.width-kcd->xstart2-5;
    1151           0 :     kcd->height = wsize.height-kcd->ystart2;
    1152           0 :     if ( kcd->hsb!=NULL ) {
    1153           0 :         GGadgetGetSize(kcd->hsb,&csize);
    1154           0 :         kcd->width = csize.width;
    1155           0 :         kcd->xstart2 = csize.x;
    1156           0 :         GGadgetGetSize(kcd->vsb,&csize);
    1157           0 :         kcd->ystart2 = csize.y;
    1158           0 :         kcd->height = csize.height;
    1159           0 :         kcd->xstart = kcd->xstart2-kcd->kernw;
    1160           0 :         kcd->ystart = kcd->ystart2-kcd->fh-1;
    1161           0 :         KCD_SBReset(kcd);
    1162             :     }
    1163           0 :     GDrawRequestExpose(kcd->gw,NULL,false);
    1164           0 : }
    1165             : 
    1166           0 : static int KC_ShowHideKernPane(GGadget *g, GEvent *e) {
    1167             :     static int cidlist[] = { CID_First, CID_Second, CID_FreeType, CID_SizeLabel,
    1168             :             CID_DisplaySize, CID_MagLabel,CID_Magnifications, CID_OffsetLabel,
    1169             :             CID_KernOffset,
    1170             :             CID_CorrectLabel, CID_Correction, CID_Revert, CID_ClearDevice,
    1171             :             CID_Display, 0 };
    1172           0 :     if ( e==NULL ||
    1173           0 :             (e->type==et_controlevent && e->u.control.subtype == et_radiochanged) ) {
    1174           0 :         KernClassDlg *kcd = GDrawGetUserData(GGadgetGetWindow(g));
    1175             :         int i;
    1176             : 
    1177           0 :         show_kerning_pane_in_class = GGadgetIsChecked(g);
    1178             : 
    1179           0 :         for ( i=0; cidlist[i]!=0; ++i )
    1180           0 :             GGadgetSetVisible(GWidgetGetControl(kcd->gw,cidlist[i]),show_kerning_pane_in_class);
    1181           0 :         GHVBoxReflow(GWidgetGetControl(kcd->gw,CID_TopBox));
    1182           0 :         KC_DoResize(kcd);
    1183           0 :         if ( e!=NULL )
    1184           0 :             SavePrefs(true);
    1185             :     }
    1186           0 : return( true );
    1187             : }
    1188             : 
    1189           0 : static int KC_OK(GGadget *g, GEvent *e) {
    1190             :     SplineFont *sf;
    1191             : 
    1192           0 :     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
    1193           0 :         KernClassDlg *kcd = GDrawGetUserData(GGadgetGetWindow(g));
    1194             :         KernClass *kc;
    1195             :         int i;
    1196             :         int len;
    1197             :         struct matrix_data *classes;
    1198           0 :         int err, touch=0, separation=0, minkern=0, onlyCloser, autokern;
    1199             : 
    1200           0 :         sf = kcd->sf;
    1201           0 :         if ( sf->cidmaster!=NULL ) sf = sf->cidmaster;
    1202           0 :         else if ( sf->mm!=NULL ) sf = sf->mm->normal;
    1203             : 
    1204           0 :         err = false;
    1205           0 :         touch = GGadgetIsChecked(GWidgetGetControl(kcd->gw,CID_Touched));
    1206           0 :         separation = GetInt8(kcd->gw,CID_Separation,_("Separation"),&err);
    1207           0 :         minkern = GetInt8(kcd->gw,CID_MinKern,_("Min Kern"),&err);
    1208           0 :         onlyCloser = GGadgetIsChecked(GWidgetGetControl(kcd->gw,CID_OnlyCloser));
    1209           0 :         autokern = GGadgetIsChecked(GWidgetGetControl(kcd->gw,CID_Autokern));
    1210           0 :         if ( err )
    1211           0 : return( true );
    1212           0 :         KCD_Finalize(kcd);
    1213             : 
    1214           0 :         kc = kcd->orig;
    1215           0 :         for ( i=1; i<kc->first_cnt; ++i )
    1216           0 :             free( kc->firsts[i]);
    1217           0 :         for ( i=1; i<kc->second_cnt; ++i )
    1218           0 :             free( kc->seconds[i]);
    1219           0 :         free(kc->firsts);
    1220           0 :         free(kc->seconds);
    1221           0 :         free(kc->offsets);
    1222           0 :         free(kc->adjusts);
    1223             : 
    1224             :         // Group kerning.
    1225           0 :         if (kc->firsts_names)
    1226           0 :           for ( i=1; i<kc->first_cnt; ++i )
    1227           0 :             if (kc->firsts_names[i]) free(kc->firsts_names[i]);
    1228           0 :         if (kc->seconds_names)
    1229           0 :           for ( i=1; i<kc->second_cnt; ++i )
    1230           0 :             if (kc->seconds_names[i]) free(kc->seconds_names[i]);
    1231           0 :         if (kc->firsts_flags) free(kc->firsts_flags);
    1232           0 :         if (kc->seconds_flags) free(kc->seconds_flags);
    1233           0 :         if (kc->offsets_flags) free(kc->offsets_flags);
    1234           0 :         if (kc->firsts_names) free(kc->firsts_names);
    1235           0 :         if (kc->seconds_names) free(kc->seconds_names);
    1236             : 
    1237           0 :         kc->subtable->separation = separation;
    1238           0 :         kc->subtable->minkern = minkern;
    1239           0 :         kc->subtable->kerning_by_touch = touch;
    1240           0 :         kc->subtable->onlyCloser = onlyCloser;
    1241           0 :         kc->subtable->dontautokern = !autokern;
    1242             : 
    1243           0 :         kc->first_cnt = kcd->first_cnt;
    1244           0 :         kc->second_cnt = kcd->second_cnt;
    1245           0 :         kc->firsts = malloc(kc->first_cnt*sizeof(char *));
    1246           0 :         kc->seconds = malloc(kc->second_cnt*sizeof(char *));
    1247           0 :         kc->firsts[0] = kc->seconds[0] = NULL;
    1248           0 :         classes = GMatrixEditGet(GWidgetGetControl(kcd->gw,CID_ClassList),&len);
    1249           0 :         if ( !isEverythingElse(classes[0].u.md_str) )
    1250           0 :             kc->firsts[0] = GlyphNameListDeUnicode(classes[0].u.md_str);
    1251           0 :         for ( i=1; i<kc->first_cnt; ++i )
    1252           0 :             kc->firsts[i] = GlyphNameListDeUnicode(classes[i].u.md_str);
    1253           0 :         classes = GMatrixEditGet(GWidgetGetControl(kcd->gw,CID_ClassList+100),&len);
    1254           0 :         for ( i=1; i<kc->second_cnt; ++i )
    1255           0 :             kc->seconds[i] = GlyphNameListDeUnicode(classes[i].u.md_str);
    1256           0 :         kc->offsets = kcd->offsets;
    1257           0 :         kc->adjusts = kcd->adjusts;
    1258             : 
    1259             :         // Group kerning.
    1260           0 :         kc->firsts_flags = kcd->firsts_flags;
    1261           0 :         kc->seconds_flags = kcd->seconds_flags;
    1262           0 :         kc->offsets_flags = kcd->offsets_flags;
    1263           0 :         kc->firsts_names = kcd->firsts_names;
    1264           0 :         kc->seconds_names = kcd->seconds_names;
    1265             : 
    1266           0 :         kcd->sf->changed = true;
    1267           0 :         sf->changed = true;
    1268             : 
    1269           0 :         GDrawDestroyWindow(kcd->gw);
    1270             :     }
    1271           0 : return( true );
    1272             : }
    1273             : 
    1274           0 : static void KC_DoCancel(KernClassDlg *kcd) {
    1275           0 :     if ( kcd->iskernpair )
    1276           0 :         KPD_DoCancel(kcd);
    1277             :     else {
    1278           0 :         free(kcd->offsets);
    1279             :         { int i;
    1280           0 :             for ( i=0; i<kcd->first_cnt*kcd->second_cnt; ++i )
    1281           0 :                 free(kcd->adjusts[i].corrections);
    1282             :         }
    1283           0 :         free(kcd->adjusts);
    1284             : 
    1285             :         // Group kerning.
    1286           0 :         if (kcd->firsts_names) {
    1287             :           int i;
    1288           0 :           for ( i=1; i<kcd->first_cnt; ++i )
    1289           0 :             if (kcd->firsts_names[i]) free(kcd->firsts_names[i]);
    1290             :         }
    1291           0 :         if (kcd->seconds_names) {
    1292             :           int i;
    1293           0 :           for ( i=1; i<kcd->second_cnt; ++i )
    1294           0 :             if (kcd->seconds_names[i]) free(kcd->seconds_names[i]);
    1295             :         }
    1296           0 :         if (kcd->firsts_flags) free(kcd->firsts_flags);
    1297           0 :         if (kcd->seconds_flags) free(kcd->seconds_flags);
    1298           0 :         if (kcd->offsets_flags) free(kcd->offsets_flags);
    1299           0 :         if (kcd->firsts_names) free(kcd->firsts_names);
    1300           0 :         if (kcd->seconds_names) free(kcd->seconds_names);
    1301             : 
    1302           0 :         GDrawDestroyWindow(kcd->gw);
    1303             :     }
    1304           0 : }
    1305             : 
    1306           0 : static int KC_Cancel(GGadget *g, GEvent *e) {
    1307             :     KernClassDlg *kcd;
    1308             : 
    1309           0 :     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
    1310           0 :         kcd = GDrawGetUserData(GGadgetGetWindow(g));
    1311             : 
    1312           0 :         KC_DoCancel(kcd);
    1313             :     }
    1314           0 : return( true );
    1315             : }
    1316             : 
    1317           0 : static int KCD_TextSelect(GGadget *g, GEvent *e) {
    1318           0 :     if ( e->type==et_controlevent && e->u.control.subtype == et_textchanged ) {
    1319           0 :         KernClassDlg *kcd = GDrawGetUserData(GGadgetGetWindow(g));
    1320           0 :         int off = GGadgetGetCid(g)-CID_ClassSelect;
    1321           0 :         const unichar_t *uname = _GGadgetGetTitle(g), *upt;
    1322           0 :         GGadget *list = GWidgetGetControl(kcd->gw,CID_ClassList+off);
    1323             :         int rows;
    1324           0 :         struct matrix_data *classes = GMatrixEditGet(list,&rows);
    1325             :         int nlen;
    1326             :         char *start, *pt, *name;
    1327             :         int i;
    1328             : 
    1329             :         /* length of initial text contents up until blank, '(' or end-of-string */
    1330           0 :         for ( upt=uname; *upt!='\0' && *upt!='(' && *upt!=' '; ++upt );
    1331           0 :         name = u2utf8_copyn(uname,upt-uname);
    1332             :         /* if string empty or invalid for any reason, quit processing text */
    1333           0 :         if ( name==NULL )
    1334           0 :             return( false );
    1335           0 :         nlen = strlen(name);
    1336             : 
    1337           0 :         for ( i=0; i<rows; ++i ) {
    1338           0 :             for ( start = classes[i].u.md_str; start!=NULL && *start!='\0'; ) {
    1339           0 :                 while ( *start==' ' ) ++start;
    1340           0 :                 for ( pt=start; *pt!='\0' && *pt!=' ' && *pt!='('; ++pt );
    1341           0 :                 if ( pt-start == nlen && strncmp(name,start,nlen)==0 ) {
    1342           0 :                     GMatrixEditScrollToRowCol(list,i,0);
    1343           0 :                     GMatrixEditActivateRowCol(list,i,0);
    1344           0 :                     if ( off==0 )
    1345           0 :                         KCD_VShow(kcd,i);
    1346             :                     else
    1347           0 :                         KCD_HShow(kcd,i);
    1348           0 :                     return( true );
    1349             :                 }
    1350           0 :                 if ( *pt=='(' ) {
    1351           0 :                     while ( *pt!=')' && *pt!='\0' ) ++pt;
    1352           0 :                     if ( *pt==')' ) ++pt;
    1353             :                 }
    1354           0 :                 start = pt;
    1355             :             }
    1356             :         }
    1357             : 
    1358             :         /* Otherwise deselect everything */
    1359           0 :         if ( nlen!=0 )
    1360           0 :             GMatrixEditActivateRowCol(list,-1,-1);
    1361             :     }
    1362           0 : return( true );
    1363             : }
    1364             : 
    1365             : #define MID_Clear               1000
    1366             : #define MID_ClearAll            1001
    1367             : #define MID_ClearDevTab         1002
    1368             : #define MID_ClearAllDevTab      1003
    1369             : #define MID_AutoKernRow         1004
    1370             : #define MID_AutoKernCol         1005
    1371             : #define MID_AutoKernAll         1006
    1372             : 
    1373           0 : static void kernmenu_dispatch(GWindow gw, GMenuItem *mi, GEvent *e) {
    1374           0 :     KernClassDlg *kcd = GDrawGetUserData(gw);
    1375             :     int i;
    1376             : 
    1377           0 :     switch ( mi->mid ) {
    1378             :       case MID_AutoKernRow:
    1379           0 :         KCD_AutoKernAClass(kcd,kcd->st_pos/kcd->second_cnt,true);
    1380           0 :       break;
    1381             :       case MID_AutoKernCol:
    1382           0 :         KCD_AutoKernAClass(kcd,kcd->st_pos%kcd->second_cnt,false);
    1383           0 :       break;
    1384             :       case MID_AutoKernAll:
    1385           0 :         KCD_AutoKernAll(kcd);
    1386           0 :       break;
    1387             :       case MID_Clear:
    1388           0 :         kcd->offsets[kcd->st_pos] = 0;
    1389           0 :       break;
    1390             :       case MID_ClearAll:
    1391           0 :         for ( i=0; i<kcd->first_cnt*kcd->second_cnt; ++i )
    1392           0 :             kcd->offsets[i] = 0;
    1393           0 :         if (kcd->offsets_flags != NULL)
    1394           0 :           for ( i=0; i<kcd->first_cnt*kcd->second_cnt; ++i )
    1395           0 :             kcd->offsets_flags[i] = 0;
    1396           0 :       break;
    1397             :       case MID_ClearDevTab: {
    1398           0 :         DeviceTable *devtab = &kcd->adjusts[kcd->st_pos];
    1399           0 :         free(devtab->corrections);
    1400           0 :         devtab->corrections = NULL;
    1401           0 :         devtab->first_pixel_size = devtab->last_pixel_size = 0;
    1402           0 :       } break;
    1403             :       case MID_ClearAllDevTab:
    1404           0 :         for ( i=0; i<kcd->first_cnt*kcd->second_cnt; ++i ) {
    1405           0 :             DeviceTable *devtab = &kcd->adjusts[i];
    1406           0 :             free(devtab->corrections);
    1407           0 :             devtab->corrections = NULL;
    1408           0 :             devtab->first_pixel_size = devtab->last_pixel_size = 0;
    1409             :         }
    1410           0 :       break;
    1411             :     }
    1412           0 :     kcd->st_pos = -1;
    1413           0 :     GDrawRequestExpose(kcd->gw,NULL,false);
    1414           0 : }
    1415             : 
    1416             : static GMenuItem kernpopupmenu[] = {
    1417             :     { { (unichar_t *) N_("AutoKern Row"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 0, 0, 0, 0, 0, 1, 1, 0, 't' }, '\0', ksm_control, NULL, NULL, kernmenu_dispatch, MID_AutoKernRow },
    1418             :     { { (unichar_t *) N_("AutoKern Column"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 0, 0, 0, 0, 0, 1, 1, 0, 't' }, '\0', ksm_control, NULL, NULL, kernmenu_dispatch, MID_AutoKernCol },
    1419             :     { { (unichar_t *) N_("AutoKern All"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 0, 0, 0, 0, 0, 1, 1, 0, 't' }, '\0', ksm_control, NULL, NULL, kernmenu_dispatch, MID_AutoKernAll },
    1420             :     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, '\0', 0, NULL, NULL, NULL, 0 }, /* line */
    1421             : #define Menu_VKern_Offset 4             /* No autokerning for vertical kerning */
    1422             :     { { (unichar_t *) N_("Clear"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 0, 0, 0, 0, 0, 1, 1, 0, 't' }, '\0', ksm_control, NULL, NULL, kernmenu_dispatch, MID_Clear },
    1423             :     { { (unichar_t *) N_("Clear All"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 0, 0, 0, 0, 0, 1, 1, 0, 'C' }, '\0', ksm_control, NULL, NULL, kernmenu_dispatch, MID_ClearAll },
    1424             :     { { (unichar_t *) N_("Clear Device Table"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 0, 0, 0, 0, 0, 1, 1, 0, 'o' }, '\0', ksm_control, NULL, NULL, kernmenu_dispatch, MID_ClearDevTab },
    1425             :     { { (unichar_t *) N_("Clear All Device Tables"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 0, 0, 0, 0, 0, 1, 1, 0, 'o' }, '\0', ksm_control, NULL, NULL, kernmenu_dispatch, MID_ClearAllDevTab },
    1426             :     GMENUITEM_EMPTY
    1427             : };
    1428             : 
    1429           0 : static void KCD_PopupMenu(KernClassDlg *kcd,GEvent *event,int pos) {
    1430           0 :     kcd->st_pos = pos;
    1431           0 :     if ( kcd->isv )
    1432           0 :         GMenuCreatePopupMenu(event->w,event, kernpopupmenu+Menu_VKern_Offset);
    1433             :     else
    1434           0 :         GMenuCreatePopupMenu(event->w,event, kernpopupmenu);
    1435           0 : }
    1436             : 
    1437           0 : static void KCD_Mouse(KernClassDlg *kcd,GEvent *event) {
    1438             :     static char space[200];
    1439             :     int len;
    1440             :     struct matrix_data *classes;
    1441           0 :     int pos = ((event->u.mouse.y-kcd->ystart2)/kcd->kernh + kcd->offtop) * kcd->second_cnt +
    1442           0 :             (event->u.mouse.x-kcd->xstart2)/kcd->kernw + kcd->offleft;
    1443             : 
    1444           0 :     GGadgetEndPopup();
    1445             : //    printf("KCD_Mouse()\n");
    1446             : 
    1447           0 :     if (( event->type==et_mouseup || event->type==et_mousedown ) &&
    1448           0 :             (event->u.mouse.button>=4 && event->u.mouse.button<=7) ) {
    1449           0 :         GGadgetDispatchEvent(kcd->vsb,event);
    1450           0 : return;
    1451             :     }
    1452             : 
    1453           0 :     if ( event->u.mouse.x<kcd->xstart || event->u.mouse.x>kcd->xstart2+kcd->fullwidth ||
    1454           0 :             event->u.mouse.y<kcd->ystart || event->u.mouse.y>kcd->ystart2+kcd->height )
    1455           0 : return;
    1456             : 
    1457           0 :     if ( event->type==et_mousemove ) {
    1458           0 :         int c = (event->u.mouse.x - kcd->xstart2)/kcd->kernw + kcd->offleft;
    1459           0 :         int s = (event->u.mouse.y - kcd->ystart2)/kcd->kernh + kcd->offtop;
    1460             :         char *str;
    1461             :         //space[0] = '\0';
    1462           0 :         memset(space,'\0',sizeof(space));
    1463           0 :         if ( event->u.mouse.y>=kcd->ystart2 && s<kcd->first_cnt ) {
    1464           0 :             sprintf( space, _("First Class %d\n"), s );
    1465           0 :             classes = GMatrixEditGet(GWidgetGetControl(kcd->gw,CID_ClassList),&len);
    1466           0 :             str = classes[s].u.md_str!=NULL ? classes[s].u.md_str :
    1467           0 :                     s==0 ? _("{Everything Else}") : "";
    1468           0 :             len = strlen(space);
    1469           0 :             strncpy(space+len,str,sizeof(space)/2-2 - len);
    1470           0 :             space[sizeof(space)/2-2] = '\0';
    1471           0 :             utf8_truncatevalid(space+len);
    1472           0 :             strcat(space+strlen(space),"\n");
    1473             :         }
    1474           0 :         if ( event->u.mouse.x>=kcd->xstart2 && c<kcd->second_cnt ) {
    1475           0 :             len = strlen(space);
    1476           0 :             sprintf( space+len, _("Second Class %d\n"), c );
    1477           0 :             classes = GMatrixEditGet(GWidgetGetControl(kcd->gw,CID_ClassList+100),&len);
    1478           0 :             str = classes[c].u.md_str!=NULL ? classes[c].u.md_str :
    1479           0 :                     c==0 ? _("{Everything Else}") : "";
    1480           0 :             len = strlen(space);
    1481           0 :             strncpy(space+len,str,sizeof(space)-1 - len);
    1482           0 :             space[sizeof(space)-1] = '\0';
    1483           0 :             utf8_truncatevalid(space+len);
    1484             :         }
    1485           0 :         if ( space[0]=='\0' )
    1486           0 : return;
    1487           0 :         if ( space[strlen(space)-1]=='\n' )
    1488           0 :             space[strlen(space)-1]='\0';
    1489           0 :         GGadgetPreparePopup8(kcd->gw,space);
    1490           0 :     } else if ( event->u.mouse.x<kcd->xstart2 || event->u.mouse.y<kcd->ystart2 )
    1491           0 : return;
    1492           0 :     else if ( event->type==et_mousedown && event->u.mouse.button==3 )
    1493           0 :         KCD_PopupMenu(kcd,event,pos);
    1494           0 :     else if ( event->type==et_mousedown )
    1495           0 :         kcd->st_pos = pos;
    1496           0 :     else if ( event->type==et_mouseup ) {
    1497             : //      printf("KCD_Mouse(up)\n");
    1498           0 :         if ( pos==kcd->st_pos )
    1499           0 :             KCD_EditOffset(kcd, pos/kcd->second_cnt, pos%kcd->second_cnt);
    1500             :     }
    1501             : }
    1502             : 
    1503           0 : static int KCD_NameClass(SplineFont *sf,char *buf,int blen,char *class_str) {
    1504             :     char *start, *pt, *bpt;
    1505             :     int i, ch;
    1506             :     SplineChar *sc;
    1507             : 
    1508           0 :     if ( class_str==NULL ) {
    1509           0 :         utf8_idpb(buf,0x2205,0);        /* Empty set glyph */
    1510           0 : return( true );
    1511             :     }
    1512           0 :     if ( isEverythingElse(class_str)) {
    1513             :  /* GT: Short form of {Everything Else}, might use universal? U+2200 */
    1514           0 :         strcpy(buf,_("{All}") );
    1515           0 : return( true );
    1516             :     }
    1517           0 :     for ( start=class_str; *start==' '; ++start );
    1518           0 :     bpt = buf;
    1519           0 :     for ( i=0; i<2; ++i ) {
    1520           0 :         for ( pt=start; *pt!='(' && *pt!=' ' && *pt!='\0'; ++pt );
    1521           0 :         if ( *pt=='(' && (pt[2]==')' || pt[3]==')' || pt[4]==')' || pt[5]==')')) {
    1522           0 :             ++pt;
    1523           0 :             while ( *pt!=')' )
    1524           0 :                 *bpt++ = *pt++;
    1525           0 :             ++pt;
    1526           0 :         } else if ( isalpha(*(unsigned char *) start) && pt-start==1 && *pt!='(' ) {
    1527           0 :             *bpt++ = *start;
    1528             :         } else
    1529             :     break;
    1530           0 :         for ( ; *pt==' '; ++pt );
    1531           0 :         start = pt;
    1532           0 :         if ( *start=='\0' ) {
    1533           0 :             *bpt = '\0';
    1534           0 : return( false );
    1535             :         }
    1536           0 :         *bpt++ = ' ';
    1537             :     }
    1538           0 :     if ( i!=0 ) {
    1539             :         /* We parsed at least one glyph, and there's more stuff */
    1540           0 :         bpt[-1] = '.'; *bpt++ = '.'; *bpt++ = '.';
    1541           0 :         *bpt = '\0';
    1542           0 : return( false );
    1543             :     }
    1544             : 
    1545           0 :     ch = *pt; *pt='\0';
    1546           0 :     sc = SFGetChar(sf,-1,start);
    1547           0 :     if ( sc==NULL ) {
    1548           0 :         snprintf( buf, blen, "!%s", start );
    1549           0 :         *pt = ch;
    1550           0 : return( true );
    1551           0 :     } else if ( sc->unicodeenc==-1 || isprivateuse(sc->unicodeenc)
    1552           0 :                || issurrogate(sc->unicodeenc))       /* Pango complains that privateuse code points are "Invalid UTF8 strings" */
    1553           0 :         snprintf( buf, blen, "%s", start );
    1554             :     else {
    1555           0 :         char *bpt = utf8_idpb(buf,sc->unicodeenc,0);
    1556           0 :         *bpt = '\0';
    1557             :     }
    1558           0 :     *pt = ch;
    1559           0 : return( false );
    1560             : }
    1561             : 
    1562           0 : static void KCD_Expose(KernClassDlg *kcd,GWindow pixmap,GEvent *event) {
    1563           0 :     GRect *area = &event->u.expose.rect;
    1564             :     GRect rect, select,r;
    1565             :     GRect clip,old1,old2,old3;
    1566             :     int len, i, j, x, y;
    1567             :     char buf[100];
    1568             :     int fcnt, scnt;
    1569           0 :     GGadget *first = GWidgetGetControl(kcd->gw,CID_ClassList);
    1570           0 :     GGadget *second = GWidgetGetControl(kcd->gw,CID_ClassList+100);
    1571           0 :     struct matrix_data *fclasses = GMatrixEditGet(first,&fcnt);
    1572           0 :     struct matrix_data *sclasses = GMatrixEditGet(second,&scnt);
    1573           0 :     int factive = GMatrixEditGetActiveRow(first);
    1574           0 :     int sactive = GMatrixEditGetActiveRow(second);
    1575             : 
    1576           0 :     if ( area->y+area->height<kcd->ystart )
    1577           0 : return;
    1578           0 :     if ( area->y>kcd->ystart2+kcd->height )
    1579           0 : return;
    1580             : 
    1581           0 :     GDrawPushClip(pixmap,area,&old1);
    1582           0 :     GDrawSetFont(pixmap,kcd->font);
    1583           0 :     GDrawSetLineWidth(pixmap,0);
    1584           0 :     rect.x = kcd->xstart; rect.y = kcd->ystart;
    1585           0 :     rect.width = kcd->width+(kcd->xstart2-kcd->xstart);
    1586           0 :     rect.height = kcd->height+(kcd->ystart2-kcd->ystart);
    1587           0 :     clip = rect;
    1588           0 :     GDrawPushClip(pixmap,&clip,&old2);
    1589             : 
    1590             :     /* In the offsets list, show which classes are selected above in the class*/
    1591             :     /*  lists */
    1592           0 :     for ( i=0 ; kcd->offtop+i<=kcd->first_cnt && (i-1)*kcd->kernh<kcd->height; ++i ) {
    1593           0 :         if ( i+kcd->offtop<fcnt && i+kcd->offtop==factive ) {
    1594           0 :             select.x = kcd->xstart+1; select.y = kcd->ystart2+i*kcd->kernh+1;
    1595           0 :             select.width = rect.width-1; select.height = kcd->kernh-1;
    1596           0 :             GDrawFillRect(pixmap,&select,ACTIVE_BORDER);
    1597             :         }
    1598             :     }
    1599           0 :     for ( i=0 ; kcd->offleft+i<=kcd->second_cnt && (i-1)*kcd->kernw<kcd->fullwidth; ++i ) {
    1600           0 :         if ( i+kcd->offleft<scnt && i+kcd->offleft==sactive ) {
    1601           0 :             select.x = kcd->xstart2+i*kcd->kernw+1; select.y = kcd->ystart+1;
    1602           0 :             select.width = kcd->kernw-1; select.height = rect.height-1;
    1603           0 :             GDrawFillRect(pixmap,&select,ACTIVE_BORDER);
    1604             :         }
    1605             :     }
    1606             : 
    1607           0 :     for ( i=0 ; kcd->offtop+i<=kcd->first_cnt && (i-1)*kcd->kernh<kcd->height; ++i ) {
    1608           0 :         GDrawDrawLine(pixmap,kcd->xstart,kcd->ystart2+i*kcd->kernh,kcd->xstart+rect.width,kcd->ystart2+i*kcd->kernh,
    1609             :                     0x808080);
    1610           0 :         if ( i+kcd->offtop<kcd->first_cnt ) {
    1611           0 :             int err = KCD_NameClass(kcd->sf,buf,sizeof(buf),fclasses[i+kcd->offtop].u.md_str);
    1612           0 :             int fg = err ? 0xff0000 : 0x006080;
    1613           0 :             len = GDrawGetText8Width(pixmap,buf,-1);
    1614           0 :             if ( len<=kcd->kernw )
    1615           0 :                 GDrawDrawText8(pixmap,kcd->xstart+(kcd->kernw-len)/2,kcd->ystart2+i*kcd->kernh+kcd->as+1,
    1616             :                         buf,-1,fg);
    1617             :             else {
    1618           0 :                 r.x = kcd->xstart; r.width = kcd->kernw;
    1619           0 :                 r.y = kcd->ystart2+i*kcd->kernh-1; r.height = kcd->kernh+1;
    1620           0 :                 GDrawPushClip(pixmap,&r,&old3);
    1621           0 :                 GDrawDrawText8(pixmap,r.x,r.y+kcd->as+1,
    1622             :                         buf,-1,fg);
    1623           0 :                 GDrawPopClip(pixmap,&old3);
    1624             :             }
    1625             :         }
    1626             :     }
    1627           0 :     for ( i=0 ; kcd->offleft+i<=scnt && (i-1)*kcd->kernw<kcd->fullwidth; ++i ) {
    1628           0 :         GDrawDrawLine(pixmap,kcd->xstart2+i*kcd->kernw,kcd->ystart,kcd->xstart2+i*kcd->kernw,kcd->ystart+rect.height,
    1629             :                 0x808080);
    1630           0 :         if ( i+kcd->offleft<kcd->second_cnt ) {
    1631           0 :             int err = KCD_NameClass(kcd->sf,buf,sizeof(buf),sclasses[i+kcd->offleft].u.md_str);
    1632           0 :             int fg = err ? 0xff0000 : 0x006080;
    1633           0 :             len = GDrawGetText8Width(pixmap,buf,-1);
    1634           0 :             if ( len<=kcd->kernw )
    1635           0 :                 GDrawDrawText8(pixmap,kcd->xstart2+i*kcd->kernw+(kcd->kernw-len)/2,kcd->ystart+kcd->as+1,
    1636             :                     buf,-1,fg);
    1637             :             else {
    1638           0 :                 r.x = kcd->xstart2+i*kcd->kernw; r.width = kcd->kernw;
    1639           0 :                 r.y = kcd->ystart-1; r.height = kcd->kernh+1;
    1640           0 :                 GDrawPushClip(pixmap,&r,&old3);
    1641           0 :                 GDrawDrawText8(pixmap,r.x,r.y+kcd->as+1,
    1642             :                         buf,-1,fg);
    1643           0 :                 GDrawPopClip(pixmap,&old3);
    1644             :             }
    1645             :         }
    1646             :     }
    1647             : 
    1648           0 :     for ( i=0 ; kcd->offtop+i<kcd->first_cnt && (i-1)*kcd->kernh<kcd->height; ++i ) {
    1649           0 :         y = kcd->ystart2+i*kcd->kernh;
    1650           0 :         if ( y>area->y+area->height )
    1651           0 :     break;
    1652           0 :         if ( y+kcd->kernh<area->y )
    1653           0 :     continue;
    1654           0 :         for ( j=0 ; kcd->offleft+j<kcd->second_cnt && (j-1)*kcd->kernw<kcd->fullwidth; ++j ) {
    1655           0 :             x = kcd->xstart2+j*kcd->kernw;
    1656           0 :             if ( x>area->x+area->width )
    1657           0 :         break;
    1658           0 :             if ( x+kcd->kernw<area->x )
    1659           0 :         continue;
    1660             : 
    1661           0 :             sprintf( buf, "%d", kcd->offsets[(i+kcd->offtop)*kcd->second_cnt+j+kcd->offleft] );
    1662           0 :             len = GDrawGetText8Width(pixmap,buf,-1);
    1663           0 :             GDrawDrawText8(pixmap,x+kcd->kernw-3-len,y+kcd->as+1,
    1664             :                 buf,-1,MAIN_FOREGROUND);
    1665             :         }
    1666             :     }
    1667             : 
    1668           0 :     GDrawDrawLine(pixmap,kcd->xstart,kcd->ystart2,kcd->xstart+rect.width,kcd->ystart2,
    1669             :             0x000000);
    1670           0 :     GDrawDrawLine(pixmap,kcd->xstart2,kcd->ystart,kcd->xstart2,kcd->ystart+rect.height,
    1671             :             0x000000);
    1672           0 :     GDrawPopClip(pixmap,&old2);
    1673           0 :     GDrawPopClip(pixmap,&old1);
    1674           0 :     --rect.y; ++rect.height;            /* Makes accented letters show better */
    1675           0 :     GDrawDrawRect(pixmap,&rect,0x000000);
    1676           0 :     rect.y += rect.height;
    1677           0 :     rect.x += rect.width;
    1678           0 :     LogoExpose(pixmap,event,&rect,dm_fore);
    1679             : }
    1680             : 
    1681           0 : static int KCD_SBReset(KernClassDlg *kcd) {
    1682           0 :     int oldtop = kcd->offtop, oldleft = kcd->offleft;
    1683             : 
    1684           0 :     if ( kcd->height>=kcd->kernh )
    1685           0 :         GScrollBarSetBounds(kcd->vsb,0,kcd->first_cnt, kcd->height/kcd->kernh);
    1686           0 :     if ( kcd->width>=kcd->kernw )
    1687           0 :         GScrollBarSetBounds(kcd->hsb,0,kcd->second_cnt, kcd->width/kcd->kernw);
    1688           0 :     if ( kcd->offtop + (kcd->height/kcd->kernh) >= kcd->first_cnt )
    1689           0 :         kcd->offtop = kcd->first_cnt - (kcd->height/kcd->kernh);
    1690           0 :     if ( kcd->offtop < 0 ) kcd->offtop = 0;
    1691           0 :     if ( kcd->offleft + (kcd->width/kcd->kernw) >= kcd->second_cnt )
    1692           0 :         kcd->offleft = kcd->second_cnt - (kcd->width/kcd->kernw);
    1693           0 :     if ( kcd->offleft < 0 ) kcd->offleft = 0;
    1694           0 :     GScrollBarSetPos(kcd->vsb,kcd->offtop);
    1695           0 :     GScrollBarSetPos(kcd->hsb,kcd->offleft);
    1696             : 
    1697           0 : return( oldtop!=kcd->offtop || oldleft!=kcd->offleft );
    1698             : }
    1699             : 
    1700           0 : static void KCD_HShow(KernClassDlg *kcd, int pos) {
    1701           0 :     if ( pos>=0 && pos<kcd->second_cnt ) {
    1702           0 :         --pos;  /* One line of context */
    1703           0 :         if ( pos + (kcd->width/kcd->kernw) >= kcd->second_cnt )
    1704           0 :             pos = kcd->second_cnt - (kcd->width/kcd->kernw);
    1705           0 :         if ( pos < 0 ) pos = 0;
    1706           0 :         kcd->offleft = pos;
    1707           0 :         GScrollBarSetPos(kcd->hsb,pos);
    1708             :     }
    1709           0 :     GDrawRequestExpose(kcd->gw,NULL,false);
    1710           0 : }
    1711             : 
    1712           0 : static void KCD_HScroll(KernClassDlg *kcd,struct sbevent *sb) {
    1713           0 :     int newpos = kcd->offleft;
    1714             :     GRect rect;
    1715             : 
    1716           0 :     switch( sb->type ) {
    1717             :       case et_sb_top:
    1718           0 :         newpos = 0;
    1719           0 :       break;
    1720             :       case et_sb_uppage:
    1721           0 :         if ( kcd->width/kcd->kernw == 1 )
    1722           0 :             --newpos;
    1723             :         else
    1724           0 :             newpos -= kcd->width/kcd->kernw - 1;
    1725           0 :       break;
    1726             :       case et_sb_up:
    1727           0 :         --newpos;
    1728           0 :       break;
    1729             :       case et_sb_down:
    1730           0 :         ++newpos;
    1731           0 :       break;
    1732             :       case et_sb_downpage:
    1733           0 :         if ( kcd->width/kcd->kernw == 1 )
    1734           0 :             ++newpos;
    1735             :         else
    1736           0 :             newpos += kcd->width/kcd->kernw - 1;
    1737           0 :       break;
    1738             :       case et_sb_bottom:
    1739           0 :         newpos = kcd->second_cnt - (kcd->width/kcd->kernw);
    1740           0 :       break;
    1741             :       case et_sb_thumb:
    1742             :       case et_sb_thumbrelease:
    1743           0 :         newpos = sb->pos;
    1744           0 :       break;
    1745             :     }
    1746           0 :     if ( newpos + (kcd->width/kcd->kernw) >= kcd->second_cnt )
    1747           0 :         newpos = kcd->second_cnt - (kcd->width/kcd->kernw);
    1748           0 :     if ( newpos < 0 ) newpos = 0;
    1749           0 :     if ( newpos!=kcd->offleft ) {
    1750           0 :         int diff = newpos-kcd->offleft;
    1751           0 :         kcd->offleft = newpos;
    1752           0 :         GScrollBarSetPos(kcd->hsb,newpos);
    1753           0 :         rect.x = kcd->xstart2+1; rect.y = kcd->ystart;
    1754           0 :         rect.width = kcd->width-1;
    1755           0 :         rect.height = kcd->height+(kcd->ystart2-kcd->ystart);
    1756           0 :         GDrawScroll(kcd->gw,&rect,-diff*kcd->kernw,0);
    1757             :     }
    1758           0 : }
    1759             : 
    1760           0 : static void KCD_VShow(KernClassDlg *kcd, int pos) {
    1761           0 :     if ( pos>=0 && pos<kcd->first_cnt ) {
    1762           0 :         --pos;  /* One line of context */
    1763           0 :         if ( pos + (kcd->height/kcd->kernh) >= kcd->first_cnt )
    1764           0 :             pos = kcd->first_cnt - (kcd->height/kcd->kernh);
    1765           0 :         if ( pos < 0 ) pos = 0;
    1766           0 :         kcd->offtop = pos;
    1767           0 :         GScrollBarSetPos(kcd->vsb,pos);
    1768             :     }
    1769           0 :     GDrawRequestExpose(kcd->gw,NULL,false);
    1770           0 : }
    1771             : 
    1772           0 : static void KCD_VScroll(KernClassDlg *kcd,struct sbevent *sb) {
    1773           0 :     int newpos = kcd->offtop;
    1774             :     GRect rect;
    1775             : 
    1776           0 :     switch( sb->type ) {
    1777             :       case et_sb_top:
    1778           0 :         newpos = 0;
    1779           0 :       break;
    1780             :       case et_sb_uppage:
    1781           0 :         if ( kcd->height/kcd->kernh == 1 )
    1782           0 :             --newpos;
    1783             :         else
    1784           0 :             newpos -= kcd->height/kcd->kernh - 1;
    1785           0 :       break;
    1786             :       case et_sb_up:
    1787           0 :         --newpos;
    1788           0 :       break;
    1789             :       case et_sb_down:
    1790           0 :         ++newpos;
    1791           0 :       break;
    1792             :       case et_sb_downpage:
    1793           0 :         if ( kcd->height/kcd->kernh == 1 )
    1794           0 :             ++newpos;
    1795             :         else
    1796           0 :             newpos += kcd->height/kcd->kernh - 1;
    1797           0 :       break;
    1798             :       case et_sb_bottom:
    1799           0 :         newpos = kcd->first_cnt - (kcd->height/kcd->kernh);
    1800           0 :       break;
    1801             :       case et_sb_thumb:
    1802             :       case et_sb_thumbrelease:
    1803           0 :         newpos = sb->pos;
    1804           0 :       break;
    1805             :     }
    1806           0 :     if ( newpos + (kcd->height/kcd->kernh) >= kcd->first_cnt )
    1807           0 :         newpos = kcd->first_cnt - (kcd->height/kcd->kernh);
    1808           0 :     if ( newpos < 0 ) newpos = 0;
    1809           0 :     if ( newpos!=kcd->offtop ) {
    1810           0 :         int diff = newpos-kcd->offtop;
    1811           0 :         kcd->offtop = newpos;
    1812           0 :         GScrollBarSetPos(kcd->vsb,newpos);
    1813           0 :         rect.x = kcd->xstart; rect.y = kcd->ystart2+1;
    1814           0 :         rect.width = kcd->width+(kcd->xstart2-kcd->xstart);
    1815           0 :         rect.height = kcd->height-1;
    1816           0 :         GDrawScroll(kcd->gw,&rect,0,diff*kcd->kernh);
    1817             :     }
    1818           0 : }
    1819             : 
    1820           0 : static int kcd_sub_e_h(GWindow gw, GEvent *event) {
    1821           0 :     KernClassDlg *kcd = GDrawGetUserData(gw);
    1822           0 :     switch ( event->type ) {
    1823             :       case et_expose:
    1824           0 :         KCD_KernExpose(kcd,gw,event);
    1825           0 :       break;
    1826             :       case et_mouseup: case et_mousedown: case et_mousemove:
    1827           0 :         KCD_KernMouse(kcd,event);
    1828           0 :       break;
    1829             :       case et_char:
    1830           0 : return( false );
    1831             :       case et_resize:
    1832           0 :         kcd->subwidth = event->u.resize.size.width;
    1833           0 :         GDrawRequestExpose(gw,NULL,false);
    1834           0 :       break;
    1835             :     }
    1836           0 : return( true );
    1837             : }
    1838             : 
    1839           0 : static int kcd_e_h(GWindow gw, GEvent *event) {
    1840           0 :     KernClassDlg *kcd = GDrawGetUserData(gw);
    1841             : 
    1842           0 :     switch ( event->type ) {
    1843             :       case et_close:
    1844           0 :         KC_DoCancel(kcd);
    1845           0 :       break;
    1846             :       case et_char:
    1847           0 :         if ( event->u.chr.keysym == GK_F1 || event->u.chr.keysym == GK_Help ) {
    1848           0 :             help(kcd->iskernpair ?  "metricsview.html#kernpair":
    1849             :                                     "metricsview.html#kernclass");
    1850           0 : return( true );
    1851             :         }
    1852           0 : return( false );
    1853             :       break;
    1854             :       case et_destroy:
    1855           0 :         if ( kcd!=NULL ) {
    1856           0 :             SplineFont *sf = kcd->sf;
    1857           0 :             KernClassListDlg *kcld = kcd->isv ? sf->vkcld : sf->kcld;
    1858             :             KernClassDlg *prev, *test;
    1859           0 :             for ( prev=NULL, test=sf->kcd; test!=NULL && test!=kcd; prev=test, test=test->next );
    1860           0 :             if ( test==kcd ) {
    1861           0 :                 if ( prev==NULL )
    1862           0 :                     sf->kcd = test->next;
    1863             :                 else
    1864           0 :                     prev->next = test->next;
    1865             :             }
    1866           0 :             if ( kcld!=NULL ) {
    1867           0 :                 GGadgetSetList(GWidgetGetControl(kcld->gw,CID_List),
    1868             :                         KCLookupSubtableArray(sf,kcd->isv),false);
    1869             :             }
    1870           0 :             free(kcd);
    1871             :         }
    1872           0 :       break;
    1873             :       case et_mouseup: case et_mousemove: case et_mousedown:
    1874           0 :         if ( !kcd->iskernpair )
    1875           0 :             KCD_Mouse(kcd,event);
    1876           0 :       break;
    1877             :       case et_expose:
    1878           0 :         if ( !kcd->iskernpair )
    1879           0 :             KCD_Expose(kcd,gw,event);
    1880           0 :       break;
    1881             :       case et_resize:
    1882           0 :         KC_DoResize(kcd);
    1883           0 :       break;
    1884             :       case et_controlevent:
    1885           0 :         switch( event->u.control.subtype ) {
    1886             :           case et_scrollbarchange:
    1887           0 :             if ( event->u.control.g == kcd->hsb )
    1888           0 :                 KCD_HScroll(kcd,&event->u.control.u.sb);
    1889             :             else
    1890           0 :                 KCD_VScroll(kcd,&event->u.control.u.sb);
    1891           0 :           break;
    1892             :         }
    1893           0 :       break;
    1894             :     }
    1895           0 : return( true );
    1896             : }
    1897             : 
    1898           0 : void ME_ListCheck(GGadget *g,int r, int c, SplineFont *sf) {
    1899             :     /* Gadget g is a matrix edit and the column "c" contains a list of glyph */
    1900             :     /*  lists. Glyphs may appear multiple times in the list, but glyph names */
    1901             :     /*  should be in the font. */
    1902             :     /* the entry at r,c has just changed. Check to validate the above */
    1903           0 :     int rows, cols = GMatrixEditGetColCnt(g);
    1904           0 :     struct matrix_data *classes = _GMatrixEditGet(g,&rows);
    1905             :     char *start1, *pt1, *eow1;
    1906             :     int ch1, off;
    1907           0 :     int changed = false;
    1908             : 
    1909             :     /* Remove any leading spaces */
    1910           0 :     for ( start1=classes[r*cols+c].u.md_str; *start1==' '; ++start1 );
    1911           0 :     if ( start1!=classes[r*cols+c].u.md_str ) {
    1912           0 :         off = start1-classes[r*cols+c].u.md_str;
    1913           0 :         for ( pt1=start1; *pt1; ++pt1 )
    1914           0 :             pt1[-off] = *pt1;
    1915           0 :         pt1[-off] = '\0';
    1916           0 :         changed = true;
    1917           0 :         pt1 -= off;
    1918           0 :         start1 -= off;
    1919             :     } else
    1920           0 :         pt1 = start1+strlen(start1);
    1921           0 :     while ( pt1>start1 && pt1[-1]==' ' ) --pt1;
    1922           0 :     *pt1 = '\0';
    1923             : 
    1924             :     /* Check for duplicate names in this class */
    1925             :     /*  also check for glyph names which aren't in the font */
    1926           0 :     while ( *start1!='\0' ) {
    1927           0 :         for ( pt1=start1; *pt1!=' ' && *pt1!='(' && *pt1!='{' && *pt1!='\0' ; ++pt1 );
    1928             :         /* Preserve the {Everything Else} string from splitting */
    1929           0 :         if ( *pt1=='{' ) {
    1930           0 :             while ( *pt1!='\0' && *pt1!='}' ) ++pt1;
    1931           0 :             if ( *pt1=='}' ) ++pt1;
    1932             :         }
    1933           0 :         eow1 = pt1;
    1934           0 :         if ( *eow1=='(' ) {
    1935           0 :             while ( *eow1!='\0' && *eow1!=')' ) ++eow1;
    1936           0 :             if ( *eow1==')' ) ++eow1;
    1937             :         }
    1938           0 :         while ( *eow1==' ' ) ++eow1;
    1939           0 :         ch1 = *pt1; *pt1='\0';
    1940           0 :         if ( sf!=NULL && !isEverythingElse( start1 )) {
    1941           0 :             SplineChar *sc = SFGetChar(sf,-1,start1);
    1942           0 :             if ( sc==NULL )
    1943           0 :                 ff_post_notice(_("Missing glyph"),_("The font does not contain a glyph named %s."), start1 );
    1944             :         }
    1945           0 :         if ( *eow1=='\0' ) {
    1946           0 :             *pt1 = ch1;
    1947           0 :     break;
    1948             :         }
    1949           0 :         *pt1 = ch1;
    1950           0 :         start1 = eow1;
    1951             :     }
    1952           0 :     if ( changed ) {
    1953             :         /* Remove trailing spaces too */
    1954           0 :         start1=classes[r*cols+c].u.md_str;
    1955           0 :         pt1 = start1+strlen(start1);
    1956           0 :         while ( pt1>start1 && pt1[-1]==' ' )
    1957           0 :             --pt1;
    1958           0 :         *pt1 = '\0';
    1959           0 :         GGadgetRedraw(g);
    1960             :     }
    1961           0 : }
    1962             : 
    1963           0 : void ME_SetCheckUnique(GGadget *g,int r, int c, SplineFont *sf) {
    1964             :     /* Gadget g is a matrix edit and the column "c" contains a list of glyph */
    1965             :     /*  sets. No glyph may appear twice in a set, and glyph names */
    1966             :     /*  should be in the font. */
    1967             :     /* the entry at r,c has just changed. Check to validate the above */
    1968           0 :     int rows, cols = GMatrixEditGetColCnt(g);
    1969           0 :     struct matrix_data *classes = _GMatrixEditGet(g,&rows);
    1970             :     char *start1, *start2, *pt1, *pt2, *eow1, *eow2;
    1971             :     int ch1, ch2, off;
    1972           0 :     int changed = false;
    1973             : 
    1974             :     /* Remove any leading spaces */
    1975           0 :     for ( start1=classes[r*cols+c].u.md_str; *start1==' '; ++start1 );
    1976           0 :     if ( start1!=classes[r*cols+c].u.md_str ) {
    1977           0 :         off = start1-classes[r*cols+c].u.md_str;
    1978           0 :         for ( pt1=start1; *pt1; ++pt1 )
    1979           0 :             pt1[-off] = *pt1;
    1980           0 :         pt1[-off] = '\0';
    1981           0 :         changed = true;
    1982           0 :         pt1 -= off;
    1983           0 :         start1 -= off;
    1984             :     } else
    1985           0 :         pt1 = start1+strlen(start1);
    1986           0 :     while ( pt1>start1 && pt1[-1]==' ' ) --pt1;
    1987           0 :     *pt1 = '\0';
    1988             : 
    1989             :     /* Check for duplicate names in this class */
    1990             :     /*  also check for glyph names which aren't in the font */
    1991           0 :     while ( *start1!='\0' ) {
    1992           0 :         for ( pt1=start1; *pt1!=' ' && *pt1!='(' && *pt1!='{' && *pt1!='\0' ; ++pt1 );
    1993             :         /* Preserve the {Everything Else} string from splitting */
    1994           0 :         if ( *pt1=='{' ) {
    1995           0 :             while ( *pt1!='\0' && *pt1!='}' ) ++pt1;
    1996           0 :             if ( *pt1=='}' ) ++pt1;
    1997             :         }
    1998           0 :         eow1 = pt1;
    1999           0 :         if ( *eow1=='(' ) {
    2000           0 :             while ( *eow1!='\0' && *eow1!=')' ) ++eow1;
    2001           0 :             if ( *eow1==')' ) ++eow1;
    2002             :         }
    2003           0 :         while ( *eow1==' ' ) ++eow1;
    2004           0 :         ch1 = *pt1; *pt1='\0';
    2005           0 :         if ( sf!=NULL && !isEverythingElse( start1 )) {
    2006           0 :             SplineChar *sc = SFGetChar(sf,-1,start1);
    2007           0 :             if ( sc==NULL )
    2008           0 :                 ff_post_notice(_("Missing glyph"),_("The font does not contain a glyph named %s."), start1 );
    2009             :         }
    2010           0 :         if ( *eow1=='\0' ) {
    2011           0 :             *pt1 = ch1;
    2012           0 :     break;
    2013             :         }
    2014           0 :         for ( start2 = eow1; *start2!='\0'; ) {
    2015           0 :             for ( pt2=start2; *pt2!=' ' && *pt2!='(' && *pt2!='\0' ; ++pt2 );
    2016           0 :             eow2 = pt2;
    2017           0 :             if ( *eow2=='(' ) {
    2018           0 :                 while ( *eow2!='\0' && *eow2!=')' ) ++eow2;
    2019           0 :                 if ( *eow2==')' ) ++eow2;
    2020             :             }
    2021           0 :             while ( *eow2==' ' ) ++eow2;
    2022           0 :             ch2 = *pt2; *pt2='\0';
    2023           0 :             if ( strcmp(start1,start2)==0 ) {
    2024           0 :                 off = eow2-start2;
    2025           0 :                 if ( *eow2=='\0' && start2>classes[r*cols+c].u.md_str &&
    2026           0 :                         start2[-1]==' ' )
    2027           0 :                     ++off;
    2028           0 :                 for ( pt2=eow2; *pt2; ++pt2 )
    2029           0 :                     pt2[-off] = *pt2;
    2030           0 :                 pt2[-off] = '\0';
    2031           0 :                 changed = true;
    2032             :             } else {
    2033           0 :                 start2 = eow2;
    2034           0 :                 *pt2 = ch2;
    2035             :             }
    2036             :         }
    2037           0 :         *pt1 = ch1;
    2038           0 :         start1 = eow1;
    2039             :     }
    2040           0 :     if ( changed ) {
    2041           0 :         GGadgetRedraw(g);
    2042             :         /* Remove trailing spaces too */
    2043           0 :         start1=classes[r*cols+c].u.md_str;
    2044           0 :         pt1 = start1+strlen(start1);
    2045           0 :         while ( pt1>start1 && pt1[-1]==' ' )
    2046           0 :             --pt1;
    2047           0 :         *pt1 = '\0';
    2048             :     }
    2049           0 : }
    2050             : 
    2051           0 : void ME_ClassCheckUnique(GGadget *g,int r, int c, SplineFont *sf) {
    2052             :     /* Gadget g is a matrix edit and column "c" contains a list of glyph */
    2053             :     /*  classes. No glyph may appear in more than one class. */
    2054             :     /*  Also all checks in the above routine should be done. */
    2055             :     /* the entry at r,c has just changed. Check to validate the above */
    2056           0 :     int rows, cols = GMatrixEditGetColCnt(g);
    2057           0 :     struct matrix_data *classes = _GMatrixEditGet(g,&rows);
    2058             :     char *start1, *start2, *pt1, *pt2, *eow1, *eow2;
    2059             :     int ch1, ch2, testr, off;
    2060           0 :     int changed = false;
    2061             :     char *buts[3];
    2062             : 
    2063           0 :     ME_SetCheckUnique(g,r,c,sf);
    2064             : 
    2065           0 :     buts[0] = _("_From this class"); buts[1] = _("From the _other class"); buts[2]=NULL;
    2066             :     /* Now check for duplicates in other rows */
    2067           0 :     for ( start1=classes[r*cols+c].u.md_str; *start1!='\0'; ) {
    2068           0 :         for ( pt1=start1; *pt1!=' ' && *pt1!='(' && *pt1!='\0' ; ++pt1 );
    2069           0 :         eow1 = pt1;
    2070           0 :         if ( *eow1=='(' ) {
    2071           0 :             while ( *eow1!='\0' && *eow1!=')' ) ++eow1;
    2072           0 :             if ( *eow1==')' ) ++eow1;
    2073             :         }
    2074           0 :         while ( *eow1==' ' ) ++eow1;
    2075           0 :         ch1 = *pt1; *pt1='\0';
    2076             : 
    2077           0 :         for ( testr=0; testr<rows; ++testr ) if ( testr!=r ) {
    2078           0 :             for ( start2 = classes[testr*cols+c].u.md_str; *start2!='\0'; ) {
    2079           0 :                 for ( pt2=start2; *pt2!=' ' && *pt2!='(' && *pt2!='\0' ; ++pt2 );
    2080           0 :                 eow2 = pt2;
    2081           0 :                 if ( *eow2=='(' ) {
    2082           0 :                     while ( *eow2!='\0' && *eow2!=')' ) ++eow2;
    2083           0 :                     if ( *eow2==')' ) ++eow2;
    2084             :                 }
    2085           0 :                 while ( *eow2==' ' ) ++eow2;
    2086           0 :                 ch2 = *pt2; *pt2='\0';
    2087           0 :                 if ( strcmp(start1,start2)==0 ) {
    2088           0 :                     *pt2 = ch2;
    2089           0 :                     if ( gwwv_ask(_("Glyph in two classes"),(const char **) buts,0,1,
    2090           0 :                             _("The glyph named %s also occurs in the class on row %d which begins with %.20s...\nYou must remove it from one of them."),
    2091           0 :                             start1, testr, classes[testr*cols+c].u.md_str )==0 ) {
    2092           0 :                         off = eow1-start1;
    2093           0 :                         for ( pt1=eow1; *pt1; ++pt1 )
    2094           0 :                             pt1[-off] = *pt1;
    2095           0 :                         pt1[-off] = '\0';
    2096           0 :                         changed = true;
    2097           0 :       goto end_of_outer_loop;
    2098             :                     } else {
    2099           0 :                         off = eow2-start2;
    2100           0 :                         for ( pt2=eow2; *pt2; ++pt2 )
    2101           0 :                             pt2[-off] = *pt2;
    2102           0 :                         pt2[-off] = '\0';
    2103           0 :                         changed = true;
    2104             :                     }
    2105             :                 } else {
    2106           0 :                     start2 = eow2;
    2107           0 :                     *pt2 = ch2;
    2108             :                 }
    2109             :             }
    2110             :         }
    2111           0 :         *pt1 = ch1;
    2112           0 :         start1 = eow1;
    2113             :       end_of_outer_loop:;
    2114             :     }
    2115           0 :     if ( changed )
    2116           0 :         GGadgetRedraw(g);
    2117           0 : }
    2118             : 
    2119           0 : static void KCD_FinishEdit(GGadget *g,int r, int c, int wasnew) {
    2120             :     // This function expands the cross-mapping structures and then calls KCD_AutoKernAClass in order to populate them.
    2121           0 :     KernClassDlg *kcd = GDrawGetUserData(GGadgetGetWindow(g));
    2122             :     // CID_ClassList is a macro denoting the identification number for the widget for the first character list.
    2123             :     // If the CID differs, then we assume that we are using the second list.
    2124           0 :     int is_first = GGadgetGetCid(g) == CID_ClassList;
    2125             :     int i, autokern;
    2126             : 
    2127             : //    printf("KCD_FinishEdit()\n");
    2128           0 :     ME_ClassCheckUnique(g, r, c, kcd->sf);
    2129             : 
    2130           0 :     if ( wasnew ) {
    2131           0 :         autokern = GGadgetIsChecked(GWidgetGetControl(kcd->gw,CID_Autokern));
    2132           0 :         if ( is_first ) {
    2133             :             // offsets and adjusts are mappings between the characters in the first and second lists.
    2134           0 :             kcd->offsets = realloc(kcd->offsets,(kcd->first_cnt+1)*kcd->second_cnt*sizeof(int16));
    2135           0 :             memset(kcd->offsets+kcd->first_cnt*kcd->second_cnt,
    2136           0 :                     0, kcd->second_cnt*sizeof(int16));
    2137             :             // adjusts are resolution-specific.
    2138           0 :             kcd->adjusts = realloc(kcd->adjusts,(kcd->first_cnt+1)*kcd->second_cnt*sizeof(DeviceTable));
    2139           0 :             memset(kcd->adjusts+kcd->first_cnt*kcd->second_cnt,
    2140           0 :                     0, kcd->second_cnt*sizeof(DeviceTable));
    2141             :             // Group kerning.
    2142           0 :             if (kcd->firsts_names) {
    2143           0 :               kcd->firsts_names = realloc(kcd->firsts_names,(kcd->first_cnt+1)*sizeof(char*));
    2144           0 :               memset(kcd->firsts_names+kcd->first_cnt, 0, sizeof(char*));
    2145             :             }
    2146           0 :             if (kcd->firsts_flags) {
    2147           0 :               kcd->firsts_flags = realloc(kcd->firsts_flags,(kcd->first_cnt+1)*sizeof(int));
    2148           0 :               memset(kcd->firsts_flags+kcd->first_cnt, 0, sizeof(int));
    2149             :             }
    2150           0 :             if (kcd->offsets_flags) {
    2151           0 :               kcd->offsets_flags = realloc(kcd->offsets_flags,(kcd->first_cnt+1)*kcd->second_cnt*sizeof(int));
    2152           0 :               memset(kcd->offsets_flags+kcd->first_cnt*kcd->second_cnt,
    2153           0 :                     0, kcd->second_cnt*sizeof(int));
    2154             :             }
    2155           0 :             ++kcd->first_cnt;
    2156           0 :             if ( autokern )
    2157           0 :                 KCD_AutoKernAClass(kcd,kcd->first_cnt-1,true);
    2158             :         } else {
    2159             :             // The procedure for expanding offsets varies here, adding a column, since it is necessary to leave a space on each row for the new column.
    2160             :             {
    2161           0 :             int16 *new = malloc(kcd->first_cnt*(kcd->second_cnt+1)*sizeof(int16));
    2162           0 :                 for ( i=0; i<kcd->first_cnt; ++i ) {
    2163           0 :                     memcpy(new+i*(kcd->second_cnt+1),kcd->offsets+i*kcd->second_cnt,
    2164           0 :                             kcd->second_cnt*sizeof(int16));
    2165           0 :                     new[i*(kcd->second_cnt+1)+kcd->second_cnt] = 0;
    2166             :                 }
    2167           0 :                 free( kcd->offsets );
    2168           0 :                 kcd->offsets = new;
    2169             :             }
    2170             :             
    2171             :             {
    2172           0 :                 DeviceTable *new = malloc(kcd->first_cnt*(kcd->second_cnt+1)*sizeof(DeviceTable));
    2173           0 :                 for ( i=0; i<kcd->first_cnt; ++i ) {
    2174           0 :                     memcpy(new+i*(kcd->second_cnt+1),kcd->adjusts+i*kcd->second_cnt,
    2175           0 :                             kcd->second_cnt*sizeof(DeviceTable));
    2176           0 :                     memset(&new[i*(kcd->second_cnt+1)+kcd->second_cnt],0,sizeof(DeviceTable));
    2177             :                 }
    2178           0 :                 free( kcd->adjusts );
    2179           0 :                 kcd->adjusts = new;
    2180             :             }
    2181             : 
    2182             :             // Group kerning.
    2183           0 :             if (kcd->seconds_names) {
    2184           0 :               kcd->seconds_names = realloc(kcd->seconds_names,(kcd->second_cnt+1)*sizeof(char*));
    2185           0 :               memset(kcd->seconds_names+kcd->second_cnt, 0, sizeof(char*));
    2186             :             }
    2187           0 :             if (kcd->seconds_flags) {
    2188           0 :               kcd->seconds_flags = realloc(kcd->seconds_flags,(kcd->second_cnt+1)*sizeof(int));
    2189           0 :               memset(kcd->seconds_flags+kcd->second_cnt, 0, sizeof(int));
    2190             :             }
    2191           0 :             if (kcd->offsets_flags) {
    2192           0 :               int *new = malloc(kcd->first_cnt*(kcd->second_cnt+1)*sizeof(int));
    2193           0 :                 for ( i=0; i<kcd->first_cnt; ++i ) {
    2194           0 :                     memcpy(new+i*(kcd->second_cnt+1),kcd->offsets_flags+i*kcd->second_cnt,
    2195           0 :                             kcd->second_cnt*sizeof(int));
    2196           0 :                     new[i*(kcd->second_cnt+1)+kcd->second_cnt] = 0;
    2197             :                 }
    2198           0 :                 free( kcd->offsets_flags );
    2199           0 :                 kcd->offsets_flags = new;
    2200             :             }
    2201             : 
    2202           0 :             ++kcd->second_cnt;
    2203           0 :             if ( autokern )
    2204           0 :                 KCD_AutoKernAClass(kcd,kcd->second_cnt-1,false);
    2205             :         }
    2206           0 :         KCD_SBReset(kcd);
    2207           0 :         GDrawRequestExpose(kcd->gw,NULL,false);
    2208             :     }
    2209           0 : }
    2210             : 
    2211           0 : static int whichToWidgetID( int which )
    2212             : {
    2213           0 :     return which==0 ? CID_First : CID_Second;
    2214             : }
    2215             : 
    2216             : 
    2217           0 : static char *KCD_PickGlyphsForClass(GGadget *g,int r, int c) {
    2218           0 :     KernClassDlg *kcd = GDrawGetUserData(GGadgetGetWindow(g));
    2219           0 :     int rows, cols = GMatrixEditGetColCnt(g);
    2220           0 :     struct matrix_data *classes = _GMatrixEditGet(g,&rows);
    2221             : 
    2222           0 :     int which    = GWidgetGetControl(kcd->gw,CID_ClassList+100) == g;
    2223           0 :     int widgetid = whichToWidgetID( which );
    2224           0 :     char *new = GlyphSetFromSelection(kcd->sf,kcd->layer,classes[r*cols+c].u.md_str);
    2225           0 :     if (new == NULL) new = copy("");
    2226           0 :     if (new != NULL) {
    2227           0 :       GGadgetSetTitle8(GWidgetGetControl(kcd->gw,widgetid),new );
    2228           0 :       KCD_UpdateGlyphFromName(kcd,which,new);
    2229             :     }
    2230           0 :     char *other = GGadgetGetTitle8(GWidgetGetControl(kcd->gw,whichToWidgetID( !which )));
    2231           0 :     if( other )
    2232             :     {
    2233           0 :         KCD_UpdateGlyphFromName(kcd,!which,other);
    2234             :     }
    2235             : 
    2236           0 :     GDrawRequestExpose(kcd->subw,NULL,false);
    2237             : 
    2238           0 : return( new );
    2239             : }
    2240             : 
    2241           0 : static enum gme_updown KCD_EnableUpDown(GGadget *g,int r) {
    2242             :     int rows;
    2243           0 :     enum gme_updown ret = 0;
    2244             : 
    2245           0 :     (void) GMatrixEditGet(g,&rows);
    2246           0 :     if ( r>=2 )
    2247           0 :         ret = ud_up_enabled;
    2248           0 :     if ( r>=1 && r<rows-1 )
    2249           0 :         ret |= ud_down_enabled;
    2250           0 : return( ret );
    2251             : }
    2252             : 
    2253           0 : static void KCD_RowMotion(GGadget *g,int oldr, int newr) {
    2254           0 :     KernClassDlg *kcd = GDrawGetUserData(GGadgetGetWindow(g));
    2255           0 :     int is_first = GGadgetGetCid(g) == CID_ClassList;
    2256             :     int i;
    2257             :     DeviceTable tempdt;
    2258             : 
    2259           0 :     if ( is_first ) {
    2260           0 :         for ( i=0; i<kcd->second_cnt; ++i ) {
    2261           0 :             int16 off = kcd->offsets[oldr*kcd->second_cnt + i];
    2262           0 :             kcd->offsets[oldr*kcd->second_cnt + i] = kcd->offsets[newr*kcd->second_cnt + i];
    2263           0 :             kcd->offsets[newr*kcd->second_cnt + i] = off;
    2264           0 :             tempdt = kcd->adjusts[oldr*kcd->second_cnt + i];
    2265           0 :             kcd->adjusts[oldr*kcd->second_cnt + i] = kcd->adjusts[newr*kcd->second_cnt + i];
    2266           0 :             kcd->adjusts[newr*kcd->second_cnt + i] = tempdt;
    2267             :             // Group kerning.
    2268           0 :             if (kcd->offsets_flags) {
    2269           0 :               int offflag = kcd->offsets_flags[oldr*kcd->second_cnt + i];
    2270           0 :               kcd->offsets_flags[oldr*kcd->second_cnt + i] = kcd->offsets_flags[newr*kcd->second_cnt + i];
    2271           0 :               kcd->offsets_flags[newr*kcd->second_cnt + i] = off;
    2272             :             }
    2273             :         }
    2274             :         // Group kerning.
    2275           0 :         if (kcd->firsts_names) {
    2276           0 :             char *name = kcd->firsts_names[oldr];
    2277           0 :             kcd->firsts_names[oldr] = kcd->firsts_names[newr];
    2278           0 :             kcd->firsts_names[newr] = name;
    2279             :         }
    2280           0 :         if (kcd->firsts_flags) {
    2281           0 :             int flags = kcd->firsts_flags[oldr];
    2282           0 :             kcd->firsts_flags[oldr] = kcd->firsts_flags[newr];
    2283           0 :             kcd->firsts_flags[newr] = flags;
    2284             :         }
    2285             :     } else {
    2286           0 :         for ( i=0; i<kcd->first_cnt; ++i ) {
    2287           0 :             int16 off = kcd->offsets[i*kcd->second_cnt + oldr];
    2288           0 :             kcd->offsets[i*kcd->second_cnt + oldr] = kcd->offsets[i*kcd->second_cnt + newr];
    2289           0 :             kcd->offsets[i*kcd->second_cnt + newr] = off;
    2290           0 :             tempdt = kcd->adjusts[i*kcd->second_cnt + oldr];
    2291           0 :             kcd->adjusts[i*kcd->second_cnt + oldr] = kcd->adjusts[i*kcd->second_cnt + newr];
    2292           0 :             kcd->adjusts[i*kcd->second_cnt + newr] = tempdt;
    2293             :             // Group kerning.
    2294           0 :             if (kcd->offsets_flags) {
    2295           0 :               int offflag = kcd->offsets_flags[i*kcd->second_cnt + oldr];
    2296           0 :               kcd->offsets_flags[i*kcd->second_cnt + oldr] = kcd->offsets_flags[i*kcd->second_cnt + newr];
    2297           0 :               kcd->offsets_flags[i*kcd->second_cnt + newr] = off;
    2298             :             }
    2299             :         }
    2300             :         // Group kerning.
    2301           0 :         if (kcd->seconds_names) {
    2302           0 :             char *name = kcd->seconds_names[oldr];
    2303           0 :             kcd->seconds_names[oldr] = kcd->seconds_names[newr];
    2304           0 :             kcd->seconds_names[newr] = name;
    2305             :         }
    2306           0 :         if (kcd->seconds_flags) {
    2307           0 :             int flags = kcd->seconds_flags[oldr];
    2308           0 :             kcd->seconds_flags[oldr] = kcd->seconds_flags[newr];
    2309           0 :             kcd->seconds_flags[newr] = flags;
    2310             :         }
    2311             :     }
    2312           0 :     GDrawRequestExpose(kcd->gw,NULL,false);
    2313           0 : }
    2314             : 
    2315           0 : static int KCD_EnableDeleteClass(GGadget *g,int whichclass) {
    2316           0 : return( whichclass>0 );
    2317             : }
    2318             : 
    2319           0 : static void KCD_DeleteClass(GGadget *g,int whichclass) {
    2320           0 :     KernClassDlg *kcd = GDrawGetUserData(GGadgetGetWindow(g));
    2321             :     int rows;
    2322           0 :     int is_first = GGadgetGetCid(g) == CID_ClassList;
    2323             :     int i,j;
    2324             : 
    2325           0 :     (void) GMatrixEditGet(g,&rows);
    2326           0 :     if ( is_first ) {
    2327           0 :         for ( i=0; i<kcd->second_cnt; ++i ) {
    2328           0 :             free(kcd->adjusts[whichclass*kcd->second_cnt+i].corrections);
    2329           0 :             kcd->adjusts[whichclass*kcd->second_cnt+i].corrections = NULL;
    2330             :         }
    2331           0 :         for ( i=whichclass+1; i<rows; ++i ) {
    2332           0 :             memmove(kcd->offsets+(i-1)*kcd->second_cnt,
    2333           0 :                     kcd->offsets+i*kcd->second_cnt,
    2334           0 :                     kcd->second_cnt*sizeof(int16));
    2335           0 :             memmove(kcd->adjusts+(i-1)*kcd->second_cnt,
    2336           0 :                     kcd->adjusts+i*kcd->second_cnt,
    2337           0 :                     kcd->second_cnt*sizeof(DeviceTable));
    2338             :             // Group kerning.
    2339           0 :             if (kcd->offsets_flags != NULL) {
    2340           0 :               memmove(kcd->offsets_flags+(i-1)*kcd->second_cnt,
    2341           0 :                     kcd->offsets_flags+i*kcd->second_cnt,
    2342           0 :                     kcd->second_cnt*sizeof(int));
    2343             :             }
    2344             :         }
    2345             :         // Group kerning.
    2346           0 :         kcd->offsets = realloc(kcd->offsets, (kcd->first_cnt-1)*kcd->second_cnt*sizeof(int16));
    2347           0 :         kcd->adjusts = realloc(kcd->adjusts, (kcd->first_cnt-1)*kcd->second_cnt*sizeof(DeviceTable));
    2348           0 :         kcd->offsets_flags = realloc(kcd->offsets_flags, (kcd->first_cnt-1)*kcd->second_cnt*sizeof(int));
    2349           0 :         if (kcd->firsts_names) {
    2350           0 :           memmove(kcd->firsts_names+whichclass, kcd->firsts_names+whichclass + 1, (kcd->first_cnt - whichclass - 1) * sizeof(char*));
    2351           0 :           kcd->firsts_names = realloc(kcd->firsts_names, (kcd->first_cnt - 1) * sizeof(char*));
    2352             :         }
    2353           0 :         if (kcd->firsts_flags) {
    2354           0 :           memmove(kcd->firsts_flags+whichclass, kcd->firsts_flags+whichclass + 1, (kcd->first_cnt - whichclass - 1) * sizeof(int));
    2355           0 :           kcd->firsts_flags = realloc(kcd->firsts_flags, (kcd->first_cnt - 1) * sizeof(int));
    2356             :         }
    2357             : 
    2358           0 :         -- kcd->first_cnt;
    2359             :     } else {
    2360           0 :         int16 *newoffs = malloc(kcd->first_cnt*(kcd->second_cnt-1)*sizeof(int16));
    2361           0 :         DeviceTable *newadj = malloc(kcd->first_cnt*(kcd->second_cnt-1)*sizeof(DeviceTable));
    2362           0 :         int *newoffflags = NULL;
    2363           0 :         if (kcd->offsets_flags != NULL) newoffflags = malloc(kcd->first_cnt*(kcd->second_cnt-1)*sizeof(int));
    2364           0 :         for ( i=0; i<kcd->first_cnt; ++i ) {
    2365           0 :             free(kcd->adjusts[i*kcd->second_cnt+whichclass].corrections);
    2366           0 :             kcd->adjusts[i*kcd->second_cnt+whichclass].corrections = NULL;
    2367             :         }
    2368           0 :         for ( i=0; i<rows; ++i ) if ( i!=whichclass ) {
    2369           0 :             int newi = i>whichclass ? i-1 : i;
    2370           0 :             for ( j=0; j<kcd->first_cnt; ++j ) {
    2371           0 :                 newoffs[j*(kcd->second_cnt-1)+newi] =
    2372           0 :                         kcd->offsets[j*kcd->second_cnt+i];
    2373           0 :                 newadj[j*(kcd->second_cnt-1)+newi] =
    2374           0 :                         kcd->adjusts[j*kcd->second_cnt+i];
    2375             :                 // Group kerning.
    2376           0 :                 if (newoffflags != NULL)
    2377           0 :                   newoffflags[j*(kcd->second_cnt-1)+newi] =
    2378           0 :                         kcd->offsets_flags[j*kcd->second_cnt+i];
    2379             :             }
    2380             :         }
    2381             :         // Group kerning.
    2382           0 :         if (kcd->seconds_names) {
    2383           0 :           memmove(kcd->seconds_names+whichclass, kcd->seconds_names+whichclass + 1, (kcd->second_cnt - whichclass - 1) * sizeof(char*));
    2384           0 :           kcd->seconds_names = realloc(kcd->seconds_names, (kcd->second_cnt - 1) * sizeof(char*));
    2385             :         }
    2386           0 :         if (kcd->seconds_flags) {
    2387           0 :           memmove(kcd->seconds_flags+whichclass, kcd->seconds_flags+whichclass + 1, (kcd->second_cnt - whichclass - 1) * sizeof(int));
    2388           0 :           kcd->seconds_flags = realloc(kcd->seconds_flags, (kcd->second_cnt - 1) * sizeof(int));
    2389             :         }
    2390             : 
    2391           0 :         -- kcd->second_cnt;
    2392           0 :         free(kcd->offsets);
    2393           0 :         kcd->offsets = newoffs;
    2394           0 :         free(kcd->adjusts);
    2395           0 :         kcd->adjusts = newadj;
    2396             :         // Group kerning.
    2397           0 :         if (kcd->offsets_flags != NULL) free(kcd->offsets_flags);
    2398           0 :         kcd->offsets_flags = newoffflags;
    2399             :     }
    2400           0 : }
    2401             : 
    2402           0 : static void KCD_ClassSelectionChanged(GGadget *g,int whichclass, int c) {
    2403           0 :     KernClassDlg *kcd = GDrawGetUserData(GGadgetGetWindow(g));
    2404           0 :     int is_first = GGadgetGetCid(g) == CID_ClassList;
    2405             :     int first, second;
    2406             : 
    2407           0 :     if ( is_first )
    2408           0 :         KCD_VShow(kcd,whichclass);
    2409             :     else
    2410           0 :         KCD_HShow(kcd,whichclass);
    2411           0 :     first = GMatrixEditGetActiveRow(GWidgetGetControl(kcd->gw,CID_ClassList));
    2412           0 :     second = GMatrixEditGetActiveRow(GWidgetGetControl(kcd->gw,CID_ClassList+100));
    2413           0 :     if ( first!=-1 && second!=-1 )
    2414           0 :         KCD_EditOffset(kcd, first, second);
    2415           0 : }
    2416             : 
    2417           0 : static unichar_t **KCD_GlyphListCompletion(GGadget *t,int from_tab) {
    2418           0 :     KernClassDlg *kcd = GDrawGetUserData(GDrawGetParentWindow(GGadgetGetWindow(t)));
    2419           0 :     SplineFont *sf = kcd->sf;
    2420             : 
    2421           0 : return( SFGlyphNameCompletion(sf,t,from_tab,true));
    2422             : }
    2423             : 
    2424           0 : static unichar_t **KCD_GlyphCompletion(GGadget *t,int from_tab) {
    2425           0 :     KernClassDlg *kcd = GDrawGetUserData(GGadgetGetWindow(t));
    2426           0 :     SplineFont *sf = kcd->sf;
    2427             : 
    2428           0 : return( SFGlyphNameCompletion(sf,t,from_tab,false));
    2429             : }
    2430             : 
    2431             : static struct col_init class_ci[] = {
    2432             :     { me_funcedit, KCD_PickGlyphsForClass, NULL, NULL, N_("Glyphs in the classes") },
    2433             :     };
    2434           0 : static int AddClassList(GGadgetCreateData *gcd, GTextInfo *label, int k, int off,
    2435             :         struct matrixinit *mi, GGadgetCreateData **harray, GGadgetCreateData **varray,
    2436             :         SplineFont *sf, char **classes, int cnt) {
    2437             :     static char *empty[] = { NULL };
    2438             :     static int initted = false;
    2439             :     struct matrix_data *md;
    2440             :     int i;
    2441             : 
    2442           0 :     if ( !initted ) {
    2443           0 :         class_ci[0].title = S_(class_ci[0].title);
    2444           0 :         initted = true;
    2445             :     }
    2446             : 
    2447           0 :     label[k].text = (unichar_t *) (off==0?_("First Char"):_("Second Char"));
    2448           0 :     label[k].text_is_1byte = true;
    2449           0 :     gcd[k].gd.label = &label[k];
    2450           0 :     gcd[k].gd.flags = gg_visible | gg_enabled;
    2451           0 :     gcd[k].gd.cid = CID_ClassLabel+off;
    2452           0 :     gcd[k++].creator = GLabelCreate;
    2453           0 :     varray[0] = &gcd[k-1];
    2454             : 
    2455           0 :     memset(mi,0,sizeof(*mi));
    2456           0 :     mi->col_cnt = 1;
    2457           0 :     mi->col_init = class_ci;
    2458             : 
    2459           0 :     if ( cnt==0 ) {
    2460           0 :         cnt=1;
    2461           0 :         classes = empty;
    2462             :     }
    2463           0 :     md = calloc(cnt+10,sizeof(struct matrix_data));
    2464           0 :     for ( i=0; i<cnt; ++i ) {
    2465           0 :         if ( i==0 && classes[i]==NULL ) {
    2466           0 :             md[i+0].u.md_str = copy( _("{Everything Else}") );
    2467           0 :             if ( off!=0 ) md[i+0].frozen = true;
    2468             :         } else
    2469           0 :             md[i+0].u.md_str = SFNameList2NameUni(sf,classes[i]);
    2470             :     }
    2471           0 :     mi->matrix_data = md;
    2472           0 :     mi->initial_row_cnt = cnt;
    2473           0 :     mi->finishedit = KCD_FinishEdit;
    2474           0 :     mi->candelete = KCD_EnableDeleteClass;
    2475             : 
    2476           0 :     gcd[k].gd.flags = gg_enabled | gg_visible;
    2477           0 :     gcd[k].gd.cid = CID_ClassList+off;
    2478           0 :     gcd[k].gd.u.matrix = mi;
    2479           0 :     gcd[k++].creator = GMatrixEditCreate;
    2480           0 :     varray[1] = &gcd[k-1];
    2481             : 
    2482             : /* GT: Select the class containing the glyph named in the following text field */
    2483           0 :     label[k].text = (unichar_t *) _("Select Class Containing:");
    2484           0 :     label[k].text_is_1byte = true;
    2485           0 :     label[k].text_in_resource = true;
    2486           0 :     gcd[k].gd.label = &label[k];
    2487           0 :     gcd[k].gd.pos.x = gcd[k-3].gd.pos.x+5; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y+26+4;
    2488           0 :     gcd[k].gd.flags = gg_visible | gg_enabled | gg_utf8_popup;
    2489           0 :     gcd[k].gd.popup_msg = (unichar_t *) _("Select the class containing the named glyph");
    2490           0 :     gcd[k++].creator = GLabelCreate;
    2491           0 :     harray[0] = &gcd[k-1];
    2492             : 
    2493           0 :     gcd[k].gd.pos.x = gcd[k-1].gd.pos.x+100; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y-4;
    2494           0 :     gcd[k].gd.pos.width = 80;
    2495           0 :     gcd[k].gd.flags = gg_visible | gg_enabled | gg_utf8_popup;
    2496           0 :     gcd[k].gd.popup_msg = (unichar_t *) _("Select the class containing the named glyph");
    2497           0 :     gcd[k].gd.handle_controlevent = KCD_TextSelect;
    2498           0 :     gcd[k].gd.cid = CID_ClassSelect+off;
    2499           0 :     gcd[k].gd.u.completion = KCD_GlyphCompletion;
    2500           0 :     gcd[k++].creator = GTextCompletionCreate;
    2501           0 :     harray[1] = &gcd[k-1]; harray[2] = NULL;
    2502             : 
    2503           0 :     gcd[k].gd.flags = gg_enabled|gg_visible;
    2504           0 :     gcd[k].gd.u.boxelements = harray;
    2505           0 :     gcd[k++].creator = GHBoxCreate;
    2506           0 :     varray[2] = &gcd[k-1]; varray[3] = NULL;
    2507             : 
    2508           0 :     gcd[k].gd.flags = gg_enabled|gg_visible;
    2509           0 :     gcd[k].gd.u.boxelements = varray;
    2510           0 :     gcd[k++].creator = GVBoxCreate;
    2511             : 
    2512           0 : return( k );
    2513             : }
    2514             : 
    2515           0 : static void FillShowKerningWindow(KernClassDlg *kcd, GGadgetCreateData *left,
    2516             :         SplineFont *sf, GGadgetCreateData *topbox) {
    2517             :     GGadgetCreateData gcd[31], hbox, flagbox, hvbox, buttonbox, mainbox[2];
    2518             :     GGadgetCreateData *harray[10], *hvarray[20], *flagarray[4], *buttonarray[9], *varray[12];
    2519             :     GGadgetCreateData *bigharray[6];
    2520             :     GTextInfo label[31];
    2521             :     int k,j;
    2522             :     char buffer[20];
    2523             :     int drawable_row;
    2524             : 
    2525           0 :     kcd->pixelsize = 150;
    2526           0 :     kcd->magfactor = 1;
    2527             : 
    2528           0 :     memset(gcd,0,sizeof(gcd));
    2529           0 :     memset(label,0,sizeof(label));
    2530           0 :     memset(&hbox,0,sizeof(hbox));
    2531           0 :     memset(&flagbox,0,sizeof(flagbox));
    2532           0 :     memset(&hvbox,0,sizeof(hvbox));
    2533           0 :     memset(&buttonbox,0,sizeof(buttonbox));
    2534           0 :     memset(&mainbox,0,sizeof(mainbox));
    2535           0 :     if ( topbox!=NULL )
    2536           0 :         memset(topbox,0,2*sizeof(*topbox));
    2537           0 :     k = j = 0;
    2538             : 
    2539           0 :     gcd[k].gd.pos.x = 5; gcd[k].gd.pos.y = 5;
    2540           0 :     gcd[k].gd.pos.width = 110;
    2541           0 :     gcd[k].gd.flags = gg_visible | gg_enabled;
    2542           0 :     gcd[k].gd.handle_controlevent = KCD_GlyphSelected;
    2543           0 :     gcd[k].gd.cid = CID_First;
    2544           0 :     gcd[k++].creator = left!=NULL ? GListButtonCreate : GTextFieldCreate;
    2545           0 :     harray[0] = &gcd[k-1];
    2546             : 
    2547           0 :     gcd[k].gd.pos.x = 130; gcd[k].gd.pos.y = 5;
    2548           0 :     gcd[k].gd.pos.width = 110;
    2549           0 :     gcd[k].gd.flags = gg_visible | gg_enabled;
    2550           0 :     if ( left==NULL ) gcd[k].gd.flags |= gg_list_alphabetic;
    2551           0 :     gcd[k].gd.handle_controlevent = KCD_GlyphSelected;
    2552           0 :     gcd[k].gd.cid = CID_Second;
    2553           0 :     gcd[k++].creator = left!=NULL ? GListButtonCreate : GListFieldCreate;
    2554           0 :     harray[1] = &gcd[k-1];
    2555             : 
    2556           0 :     label[k].text = (unichar_t *) _("Use FreeType");
    2557           0 :     label[k].text_is_1byte = true;
    2558           0 :     gcd[k].gd.label = &label[k];
    2559           0 :     gcd[k].gd.pos.x = 260; gcd[k].gd.pos.y = 7;
    2560           0 :     if ( !hasFreeType() )
    2561           0 :         gcd[k].gd.flags = gg_visible;
    2562             :     else
    2563           0 :         gcd[k].gd.flags = gg_enabled|gg_visible|gg_cb_on;
    2564           0 :     gcd[k].gd.cid = CID_FreeType;
    2565           0 :     gcd[k].gd.handle_controlevent = KCB_FreeTypeChanged;
    2566           0 :     gcd[k++].creator = GCheckBoxCreate;
    2567           0 :     harray[2] = GCD_Glue; harray[3] = &gcd[k-1];
    2568           0 :     harray[4] = GCD_Glue; harray[5] = GCD_Glue;
    2569           0 :     harray[6] = GCD_Glue; harray[7] = GCD_Glue; harray[8] = NULL;
    2570             : 
    2571           0 :     hbox.gd.flags = gg_enabled|gg_visible;
    2572           0 :     hbox.gd.u.boxelements = harray;
    2573           0 :     hbox.creator = GHBoxCreate;
    2574           0 :     varray[j++] = &hbox; varray[j++] = NULL;
    2575             : 
    2576           0 :     label[k].text = (unichar_t *) _("Display Size:");
    2577           0 :     label[k].text_is_1byte = true;
    2578           0 :     gcd[k].gd.label = &label[k];
    2579           0 :     gcd[k].gd.flags = gg_visible|gg_enabled ;
    2580           0 :     gcd[k].gd.cid = CID_SizeLabel;
    2581           0 :     gcd[k++].creator = GLabelCreate;
    2582           0 :     hvarray[0] = &gcd[k-1];
    2583             : 
    2584           0 :     sprintf( buffer, "%d", kcd->pixelsize );
    2585           0 :     label[k].text = (unichar_t *) buffer;
    2586           0 :     label[k].text_is_1byte = true;
    2587           0 :     gcd[k].gd.label = &label[k];
    2588           0 :     gcd[k].gd.pos.width = 80;
    2589           0 :     gcd[k].gd.flags = gg_visible|gg_enabled ;
    2590           0 :     gcd[k].gd.cid = CID_DisplaySize;
    2591           0 :     gcd[k].gd.handle_controlevent = KCD_DisplaySizeChanged;
    2592           0 :     gcd[k++].creator = GListFieldCreate;
    2593           0 :     hvarray[1] = &gcd[k-1];
    2594             : 
    2595           0 :     label[k].text = (unichar_t *) _("Magnification:");
    2596           0 :     label[k].text_is_1byte = true;
    2597           0 :     gcd[k].gd.label = &label[k];
    2598           0 :     gcd[k].gd.flags = gg_visible|gg_enabled ;
    2599           0 :     gcd[k].gd.cid = CID_MagLabel;
    2600           0 :     gcd[k++].creator = GLabelCreate;
    2601           0 :     hvarray[2] = &gcd[k-1];
    2602             : 
    2603           0 :     gcd[k].gd.flags = gg_visible|gg_enabled ;
    2604           0 :     gcd[k].gd.cid = CID_Magnifications;
    2605           0 :     gcd[k].gd.pos.width = 60;
    2606           0 :     gcd[k].gd.u.list = magnifications;
    2607           0 :     gcd[k].gd.handle_controlevent = KCD_MagnificationChanged;
    2608           0 :     gcd[k++].creator = GListButtonCreate;
    2609           0 :     hvarray[3] = &gcd[k-1]; hvarray[4] = GCD_Glue; hvarray[5] = NULL;
    2610             : 
    2611           0 :     label[k].text = (unichar_t *) _("Kern Offset:");
    2612           0 :     label[k].text_is_1byte = true;
    2613           0 :     gcd[k].gd.label = &label[k];
    2614           0 :     gcd[k].gd.flags = gg_visible|gg_enabled ;
    2615           0 :     gcd[k].gd.cid = CID_OffsetLabel;
    2616           0 :     gcd[k++].creator = GLabelCreate;
    2617           0 :     hvarray[6] = &gcd[k-1];
    2618             : 
    2619           0 :     gcd[k].gd.pos.x = 90; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y-4;
    2620           0 :     gcd[k].gd.pos.width = 60;
    2621           0 :     gcd[k].gd.flags = gg_visible|gg_enabled ;
    2622           0 :     gcd[k].gd.cid = CID_KernOffset;
    2623           0 :     gcd[k].gd.handle_controlevent = KCD_KernOffChanged;
    2624           0 :     gcd[k++].creator = GTextFieldCreate;
    2625           0 :     hvarray[7] = &gcd[k-1];
    2626             : 
    2627           0 :     label[k].text = (unichar_t *) _("Device Table Correction:\n  (at display size)");
    2628           0 :     label[k].text_is_1byte = true;
    2629           0 :     gcd[k].gd.label = &label[k];
    2630           0 :     gcd[k].gd.flags = gg_visible|gg_enabled ;
    2631           0 :     gcd[k].gd.cid = CID_CorrectLabel;
    2632           0 :     gcd[k++].creator = GLabelCreate;
    2633           0 :     hvarray[8] = &gcd[k-1];
    2634             : 
    2635           0 :     label[k].text = (unichar_t *) "0";
    2636           0 :     label[k].text_is_1byte = true;
    2637           0 :     gcd[k].gd.label = &label[k];
    2638           0 :     gcd[k].gd.pos.width = 60;
    2639           0 :     gcd[k].gd.flags = gg_visible|gg_enabled ;
    2640           0 :     gcd[k].gd.cid = CID_Correction;
    2641           0 :     gcd[k].gd.handle_controlevent = KCD_CorrectionChanged;
    2642           0 :     gcd[k++].creator = GTextFieldCreate;
    2643           0 :     hvarray[9] = &gcd[k-1]; hvarray[10]=NULL;
    2644             : 
    2645           0 :     label[k].text = (unichar_t *) _("Revert Kerning");
    2646           0 :     label[k].text_is_1byte = true;
    2647           0 :     gcd[k].gd.label = &label[k];
    2648           0 :     gcd[k].gd.flags = gg_visible|gg_enabled|gg_utf8_popup ;
    2649           0 :     gcd[k].gd.popup_msg = (unichar_t *) _("Resets the kerning offset and device table corrections to what they were originally");
    2650           0 :     gcd[k].gd.handle_controlevent = KCD_RevertKerning;
    2651           0 :     gcd[k].gd.cid = CID_Revert;
    2652           0 :     gcd[k++].creator = GButtonCreate;
    2653           0 :     hvarray[11] = &gcd[k-1]; hvarray[12] = GCD_ColSpan;
    2654             : 
    2655           0 :     label[k].text = (unichar_t *) _("Clear Device Table");
    2656           0 :     label[k].text_is_1byte = true;
    2657           0 :     gcd[k].gd.label = &label[k];
    2658           0 :     gcd[k].gd.flags = gg_visible|gg_enabled|gg_utf8_popup ;
    2659           0 :     gcd[k].gd.popup_msg = (unichar_t *) _("Clear all device table corrections associated with this combination");
    2660           0 :     gcd[k].gd.cid = CID_ClearDevice;
    2661           0 :     gcd[k].gd.handle_controlevent = KCD_ClearDevice;
    2662           0 :     gcd[k++].creator = GButtonCreate;
    2663           0 :     hvarray[13] = &gcd[k-1]; hvarray[14] = GCD_ColSpan; hvarray[15] = NULL;
    2664           0 :     hvarray[16] = NULL;
    2665             : 
    2666           0 :     hvbox.gd.flags = gg_enabled|gg_visible;
    2667           0 :     hvbox.gd.u.boxelements = hvarray;
    2668           0 :     hvbox.creator = GHVBoxCreate;
    2669           0 :     varray[j++] = &hvbox; varray[j++] = NULL;
    2670             : 
    2671           0 :     gcd[k].gd.flags = gg_visible|gg_enabled ;
    2672           0 :     gcd[k].gd.pos.width = gcd[k].gd.pos.height = 100;
    2673           0 :     gcd[k].gd.cid = CID_Display;
    2674           0 :     gcd[k].gd.u.drawable_e_h = kcd_sub_e_h;
    2675           0 :     gcd[k].data = kcd;
    2676           0 :     gcd[k++].creator = GDrawableCreate;
    2677           0 :     drawable_row = j/2;
    2678           0 :     varray[j++] = &gcd[k-1]; varray[j++] = NULL;
    2679             : 
    2680           0 :     if ( left==NULL ) {
    2681           0 :         gcd[k].gd.pos.x = 5; gcd[k].gd.pos.y = -40;
    2682           0 :         gcd[k].gd.flags = gg_enabled ;
    2683           0 :         label[k].text = (unichar_t *) _("Lookup subtable:");
    2684           0 :         label[k].text_is_1byte = true;
    2685           0 :         gcd[k].gd.label = &label[k];
    2686           0 :         gcd[k++].creator = GLabelCreate;
    2687           0 :         flagarray[0] = &gcd[k-1];
    2688             : 
    2689           0 :         gcd[k].gd.flags = gg_enabled|gg_visible;
    2690           0 :         gcd[k].gd.cid = CID_Subtable;
    2691           0 :         gcd[k].gd.handle_controlevent = KP_Subtable;
    2692           0 :         gcd[k++].creator = GListButtonCreate;
    2693           0 :         flagarray[1] = &gcd[k-1]; flagarray[2] = GCD_Glue; flagarray[3] = NULL;
    2694             : 
    2695           0 :         flagbox.gd.flags = gg_enabled|gg_visible;
    2696           0 :         flagbox.gd.u.boxelements = flagarray;
    2697           0 :         flagbox.creator = GHBoxCreate;
    2698           0 :         varray[j++] = &flagbox; varray[j++] = NULL;
    2699             : 
    2700           0 :         label[k].text = (unichar_t *) _("_OK");
    2701           0 :         label[k].text_is_1byte = true;
    2702           0 :         label[k].text_in_resource = true;
    2703           0 :         gcd[k].gd.label = &label[k];
    2704           0 :         gcd[k].gd.pos.x = 30; gcd[k].gd.pos.y = KC_Height-KC_CANCELDROP;
    2705           0 :         gcd[k].gd.pos.width = -1;
    2706           0 :         gcd[k].gd.flags = gg_visible|gg_enabled;
    2707           0 :         if ( left==NULL ) gcd[k].gd.flags |= gg_but_default;
    2708           0 :         gcd[k].gd.handle_controlevent = KPD_OK;
    2709           0 :         gcd[k].gd.cid = CID_Prev2;
    2710           0 :         gcd[k++].creator = GButtonCreate;
    2711             : 
    2712           0 :         label[k].text = (unichar_t *) _("_Cancel");
    2713           0 :         label[k].text_is_1byte = true;
    2714           0 :         label[k].text_in_resource = true;
    2715           0 :         gcd[k].gd.label = &label[k];
    2716           0 :         gcd[k].gd.pos.x = -30+3; gcd[k].gd.pos.y = KC_Height-KC_CANCELDROP;
    2717           0 :         gcd[k].gd.pos.width = -1;
    2718           0 :         gcd[k].gd.flags = gg_visible|gg_enabled ;
    2719           0 :         if ( left==NULL ) gcd[k].gd.flags |= gg_but_cancel;
    2720           0 :         gcd[k].gd.handle_controlevent = KPD_Cancel;
    2721           0 :         gcd[k].gd.cid = CID_Next2;
    2722           0 :         gcd[k++].creator = GButtonCreate;
    2723             : 
    2724           0 :         buttonarray[0] = GCD_Glue; buttonarray[1] = &gcd[k-2]; buttonarray[2] = GCD_Glue;
    2725           0 :         buttonarray[3] = GCD_Glue; buttonarray[4] = &gcd[k-1]; buttonarray[5] = GCD_Glue;
    2726           0 :         buttonarray[6] = NULL;
    2727           0 :         buttonbox.gd.flags = gg_enabled|gg_visible;
    2728           0 :         buttonbox.gd.u.boxelements = buttonarray;
    2729           0 :         buttonbox.creator = GHBoxCreate;
    2730           0 :         varray[j++] = &buttonbox; varray[j++] = NULL; varray[j++] = NULL;
    2731             : 
    2732           0 :         mainbox[0].gd.pos.x = mainbox[0].gd.pos.y = 2;
    2733           0 :         mainbox[0].gd.flags = gg_enabled|gg_visible;
    2734           0 :         mainbox[0].gd.u.boxelements = varray;
    2735           0 :         mainbox[0].creator = GHVGroupCreate;
    2736             : 
    2737           0 :         GGadgetsCreate(kcd->gw,mainbox);
    2738           0 :         GHVBoxSetExpandableCol(buttonbox.ret,gb_expandgluesame);
    2739             :     } else {
    2740           0 :         varray[j++] = NULL;
    2741           0 :         mainbox[0].gd.flags = gg_enabled|gg_visible;
    2742           0 :         mainbox[0].gd.u.boxelements = varray;
    2743           0 :         mainbox[0].creator = GHVBoxCreate;
    2744             : 
    2745           0 :         bigharray[0] = left;
    2746           0 :         bigharray[1] = mainbox;
    2747           0 :         bigharray[2] = bigharray[3] = NULL;
    2748             : 
    2749           0 :         topbox[0].gd.pos.x = mainbox[0].gd.pos.y = 2;
    2750           0 :         topbox[0].gd.flags = gg_enabled|gg_visible;
    2751           0 :         topbox[0].gd.u.boxelements = bigharray;
    2752           0 :         topbox[0].gd.cid = CID_TopBox;
    2753           0 :         topbox[0].creator = GHVGroupCreate;
    2754             : 
    2755           0 :         GGadgetsCreate(kcd->gw,topbox);
    2756           0 :         GHVBoxSetExpandableCol(topbox[0].ret,0);
    2757             :     }
    2758             : 
    2759           0 :     GHVBoxSetExpandableRow(mainbox[0].ret,drawable_row);
    2760           0 :     GHVBoxSetExpandableCol(hbox.ret,gb_expandglue);
    2761             :     /*GHVBoxSetExpandableCol(hvbox.ret,gb_expandglue);*/
    2762           0 :     if ( left==NULL ) {
    2763           0 :         GHVBoxSetExpandableCol(flagbox.ret,gb_expandglue);
    2764           0 :         GGadgetSetList(flagarray[1]->ret,SFSubtablesOfType(sf,gpos_pair,false,false),false);
    2765             :     }
    2766           0 :     kcd->subw = GDrawableGetWindow(GWidgetGetControl(kcd->gw,CID_Display));
    2767           0 : }
    2768             : 
    2769           0 : void KernClassD(KernClass *kc, SplineFont *sf, int layer, int isv) {
    2770             :     GRect pos;
    2771             :     GWindowAttrs wattrs;
    2772             :     GGadgetCreateData gcd[54], sepbox, classbox, hvbox, buttonbox, mainbox[2], topbox[2], titbox, hbox;
    2773             :     GGadgetCreateData *harray1[17], *harray2[17], *varray1[5], *varray2[5];
    2774             :     GGadgetCreateData *hvarray[13], *buttonarray[8], *varray[19], *h4array[8], *harrayclasses[6], *titlist[4], *h5array[3];
    2775             :     GTextInfo label[54];
    2776             :     KernClassDlg *kcd;
    2777             :     int i, j, kc_width, vi;
    2778             :     int as, ds, ld, sbsize;
    2779             :     FontRequest rq;
    2780             :     static unichar_t kernw[] = { '-', '1', '2', '3', '4', '5', 0 };
    2781             :     GWindow gw;
    2782             :     char titlebuf[300];
    2783             :     static GFont *font;
    2784             :     char sepbuf[40], mkbuf[40];
    2785             :     struct matrixinit firstmi, secondmi;
    2786             : 
    2787           0 :     for ( kcd = sf->kcd; kcd!=NULL && kcd->orig!=kc; kcd = kcd->next );
    2788           0 :     if ( kcd!=NULL ) {
    2789           0 :         GDrawSetVisible(kcd->gw,true);
    2790           0 :         GDrawRaise(kcd->gw);
    2791           0 : return;
    2792             :     }
    2793           0 :     kcd = calloc(1,sizeof(KernClassDlg));
    2794           0 :     kcd->orig = kc;
    2795           0 :     kcd->subtable = kc->subtable;
    2796           0 :     kcd->sf = sf;
    2797           0 :     kcd->layer = layer;
    2798           0 :     kcd->isv = isv;
    2799           0 :     kcd->old_pos = -1;
    2800           0 :     kcd->next = sf->kcd;
    2801           0 :     sf->kcd = kcd;
    2802             : 
    2803           0 :     kcd->first_cnt = kc->first_cnt;
    2804           0 :     kcd->second_cnt = kc->second_cnt;
    2805           0 :     kcd->offsets = malloc(kc->first_cnt*kc->second_cnt*sizeof(int16));
    2806           0 :     memcpy(kcd->offsets,kc->offsets,kc->first_cnt*kc->second_cnt*sizeof(int16));
    2807           0 :     kcd->adjusts = malloc(kc->first_cnt*kc->second_cnt*sizeof(DeviceTable));
    2808           0 :     memcpy(kcd->adjusts,kc->adjusts,kc->first_cnt*kc->second_cnt*sizeof(DeviceTable));
    2809           0 :     for ( i=0; i<kcd->first_cnt*kcd->second_cnt; ++i ) {
    2810           0 :         if ( kcd->adjusts[i].corrections!=NULL ) {
    2811           0 :             int len = kcd->adjusts[i].last_pixel_size-kcd->adjusts[i].first_pixel_size+1;
    2812           0 :             kcd->adjusts[i].corrections = malloc(len);
    2813           0 :             memcpy(kcd->adjusts[i].corrections,kc->adjusts[i].corrections,len);
    2814             :         }
    2815             :     }
    2816             : 
    2817             :     // Group kerning.
    2818           0 :     if (kc->firsts_names) {
    2819           0 :       kcd->firsts_names = malloc(kc->first_cnt*sizeof(char*));
    2820             :       int namepos;
    2821           0 :       for (namepos = 0; namepos < kc->first_cnt; namepos ++)
    2822           0 :         kcd->firsts_names[namepos] = copy(kc->firsts_names[namepos]);
    2823             :     }
    2824           0 :     if (kc->seconds_names) {
    2825           0 :       kcd->seconds_names = malloc(kc->second_cnt*sizeof(char*));
    2826             :       int namepos;
    2827           0 :       for (namepos = 0; namepos < kc->second_cnt; namepos ++)
    2828           0 :         kcd->seconds_names[namepos] = copy(kc->seconds_names[namepos]);
    2829             :     }
    2830           0 :     if (kc->firsts_flags) {
    2831           0 :       kcd->firsts_flags = malloc(kc->first_cnt*sizeof(int));
    2832           0 :       memcpy(kcd->firsts_flags,kc->firsts_flags,kc->first_cnt*sizeof(int));
    2833             :     }
    2834           0 :     if (kc->seconds_flags) {
    2835           0 :       kcd->seconds_flags = malloc(kc->second_cnt*sizeof(int));
    2836           0 :       memcpy(kcd->seconds_flags,kc->seconds_flags,kc->second_cnt*sizeof(int));
    2837             :     }
    2838           0 :     if (kcd->offsets_flags) {
    2839           0 :       kcd->offsets_flags = malloc(kc->first_cnt*kc->second_cnt*sizeof(int));
    2840           0 :       memcpy(kcd->offsets_flags,kc->offsets_flags,kc->first_cnt*kc->second_cnt*sizeof(int));
    2841             :     }
    2842             : 
    2843           0 :     memset(&wattrs,0,sizeof(wattrs));
    2844           0 :     memset(&gcd,0,sizeof(gcd));
    2845           0 :     memset(&classbox,0,sizeof(classbox));
    2846           0 :     memset(&hbox,0,sizeof(hbox));
    2847           0 :     memset(&hvbox,0,sizeof(hvbox));
    2848           0 :     memset(&buttonbox,0,sizeof(buttonbox));
    2849           0 :     memset(&mainbox,0,sizeof(mainbox));
    2850           0 :     memset(&titbox,0,sizeof(titbox));
    2851           0 :     memset(&label,0,sizeof(label));
    2852             : 
    2853           0 :     wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_undercursor|wam_isdlg|wam_restrict;
    2854           0 :     wattrs.event_masks = ~(1<<et_charup);
    2855           0 :     wattrs.restrict_input_to_me = true;
    2856           0 :     wattrs.undercursor = 1;
    2857           0 :     wattrs.cursor = ct_pointer;
    2858             : /* GT: The %s is the name of the lookup subtable containing this kerning class */
    2859           0 :     snprintf( titlebuf, sizeof(titlebuf), _("Kerning by Classes: %s"), kc->subtable->subtable_name );
    2860           0 :     wattrs.utf8_window_title =  titlebuf ;
    2861           0 :     wattrs.is_dlg = false;
    2862           0 :     pos.x = pos.y = 0;
    2863           0 :     pos.width = GGadgetScale(GDrawPointsToPixels(NULL,KC_Width));
    2864           0 :     pos.height = GDrawPointsToPixels(NULL,KC_Height);
    2865           0 :     kcd->gw = gw = GDrawCreateTopWindow(NULL,&pos,kcd_e_h,kcd,&wattrs);
    2866             : 
    2867           0 :     kc_width = GDrawPixelsToPoints(NULL,pos.width*100/GGadgetScale(100));
    2868             : 
    2869           0 :     if ( font==NULL ) {
    2870           0 :         memset(&rq,'\0',sizeof(rq));
    2871           0 :         rq.point_size = 12;
    2872           0 :         rq.weight = 400;
    2873           0 :         rq.utf8_family_name = MONO_UI_FAMILIES;
    2874           0 :         font = GDrawInstanciateFont(gw,&rq);
    2875           0 :         font = GResourceFindFont("KernClass.Font",font);
    2876             :     }
    2877           0 :     kcd->font = font;
    2878           0 :     GDrawWindowFontMetrics(gw,kcd->font,&as,&ds,&ld);
    2879           0 :     kcd->fh = as+ds; kcd->as = as;
    2880           0 :     GDrawSetFont(gw,kcd->font);
    2881             : 
    2882           0 :     kcd->kernh = kcd->fh+3;
    2883           0 :     kcd->kernw = GDrawGetTextWidth(gw,kernw,-1)+3;
    2884             : 
    2885           0 :     if ( kc->subtable->separation==0 && !kc->subtable->kerning_by_touch ) {
    2886           0 :         kc->subtable->separation = sf->width_separation;
    2887           0 :         if ( sf->width_separation==0 )
    2888           0 :             kc->subtable->separation = 15*(sf->ascent+sf->descent)/100;
    2889           0 :         kc->subtable->minkern = 0;
    2890             :     }
    2891             : 
    2892           0 :     i = j = 0;
    2893           0 :     snprintf( titlebuf, sizeof(titlebuf), _("Lookup Subtable: %s"), kc->subtable->subtable_name );
    2894           0 :     gcd[i].gd.pos.x = 5; gcd[i].gd.pos.y = 5;
    2895           0 :     gcd[i].gd.flags = gg_visible | gg_enabled;
    2896           0 :     label[i].text = (unichar_t *) titlebuf;
    2897           0 :     label[i].text_is_1byte = true;
    2898           0 :     gcd[i].gd.label = &label[i];
    2899           0 :     gcd[i++].creator = GLabelCreate;
    2900           0 :     titlist[0] = &gcd[i-1]; titlist[1] = GCD_Glue;
    2901             : 
    2902             : 
    2903           0 :     gcd[i].gd.flags = show_kerning_pane_in_class ? (gg_visible | gg_enabled | gg_cb_on) : (gg_visible | gg_enabled);
    2904           0 :     label[i].text = (unichar_t *) _("Show Kerning");
    2905           0 :     label[i].text_is_1byte = true;
    2906           0 :     gcd[i].gd.label = &label[i];
    2907           0 :     gcd[i].gd.handle_controlevent = KC_ShowHideKernPane;
    2908           0 :     gcd[i].gd.cid = CID_ShowHideKern;
    2909           0 :     gcd[i++].creator = GCheckBoxCreate;
    2910           0 :     titlist[2] = &gcd[i-1]; titlist[3] = NULL;
    2911             : 
    2912           0 :     memset(&titbox,0,sizeof(titbox));
    2913           0 :     titbox.gd.flags = gg_enabled|gg_visible;
    2914           0 :     titbox.gd.u.boxelements = titlist;
    2915           0 :     titbox.creator = GHBoxCreate;
    2916             : 
    2917           0 :     varray[j++] = &titbox; varray[j++] = NULL;
    2918             : 
    2919           0 :         label[i].text = (unichar_t *) _("_Default Separation:");
    2920           0 :         label[i].text_is_1byte = true;
    2921           0 :         label[i].text_in_resource = true;
    2922           0 :         gcd[i].gd.label = &label[i];
    2923           0 :         gcd[i].gd.pos.x = 5; gcd[i].gd.pos.y = 5+4;
    2924           0 :         gcd[i].gd.flags = gg_enabled|gg_visible|gg_utf8_popup;
    2925           0 :         gcd[i].gd.popup_msg = (unichar_t *) _(
    2926             :             "Add entries to the lookup trying to make the optical\n"
    2927             :             "separation between all pairs of glyphs equal to this\n"
    2928             :             "value." );
    2929           0 :         gcd[i].creator = GLabelCreate;
    2930           0 :         h4array[0] = &gcd[i++];
    2931             : 
    2932           0 :         sprintf( sepbuf, "%d", kc->subtable->separation );
    2933           0 :         label[i].text = (unichar_t *) sepbuf;
    2934           0 :         label[i].text_is_1byte = true;
    2935           0 :         label[i].text_in_resource = true;
    2936           0 :         gcd[i].gd.label = &label[i];
    2937           0 :         gcd[i].gd.pos.width = 50;
    2938           0 :         gcd[i].gd.flags = gg_enabled|gg_visible|gg_utf8_popup;
    2939           0 :         gcd[i].gd.popup_msg = gcd[i-1].gd.popup_msg;
    2940           0 :         gcd[i].gd.cid = CID_Separation;
    2941           0 :         gcd[i].creator = GTextFieldCreate;
    2942           0 :         h4array[1] = &gcd[i++]; h4array[2] = GCD_Glue;
    2943             : 
    2944           0 :         label[i].text = (unichar_t *) _("_Min Kern:");
    2945           0 :         label[i].text_is_1byte = true;
    2946           0 :         label[i].text_in_resource = true;
    2947           0 :         gcd[i].gd.label = &label[i];
    2948           0 :         gcd[i].gd.pos.x = 5; gcd[i].gd.pos.y = 5+4;
    2949           0 :         gcd[i].gd.flags = gg_enabled|gg_visible|gg_utf8_popup;
    2950           0 :         gcd[i].gd.popup_msg = (unichar_t *) _(
    2951             :             "Any computed kerning change whose absolute value is less\n"
    2952             :             "that this will be ignored.\n" );
    2953           0 :         gcd[i].creator = GLabelCreate;
    2954           0 :         h4array[3] = &gcd[i++];
    2955             : 
    2956           0 :         sprintf( mkbuf, "%d", kc->subtable->minkern );
    2957           0 :         label[i].text = (unichar_t *) mkbuf;
    2958           0 :         label[i].text_is_1byte = true;
    2959           0 :         label[i].text_in_resource = true;
    2960           0 :         gcd[i].gd.label = &label[i];
    2961           0 :         gcd[i].gd.pos.width = 50;
    2962           0 :         gcd[i].gd.flags = gg_enabled|gg_visible|gg_utf8_popup;
    2963           0 :         gcd[i].gd.popup_msg = gcd[i-1].gd.popup_msg;
    2964           0 :         gcd[i].gd.cid = CID_MinKern;
    2965           0 :         gcd[i].creator = GTextFieldCreate;
    2966           0 :         h4array[4] = &gcd[i++];
    2967             : 
    2968           0 :         label[i].text = (unichar_t *) _("_Touching");
    2969           0 :         label[i].text_is_1byte = true;
    2970           0 :         label[i].text_in_resource = true;
    2971           0 :         gcd[i].gd.label = &label[i];
    2972           0 :         gcd[i].gd.pos.x = 5; gcd[i].gd.pos.y = 5+4;
    2973           0 :         gcd[i].gd.flags = gg_enabled|gg_visible|gg_utf8_popup;
    2974           0 :         if ( kc->subtable->kerning_by_touch )
    2975           0 :             gcd[i].gd.flags = gg_enabled|gg_visible|gg_utf8_popup|gg_cb_on;
    2976           0 :         gcd[i].gd.popup_msg = (unichar_t *) _(
    2977             :             "Normally kerning is based on achieving a constant (optical)\n"
    2978             :             "separation between glyphs, but occasionally it is desirable\n"
    2979             :             "to have a kerning table where the kerning is based on the\n"
    2980             :             "closest approach between two glyphs (So if the desired separ-\n"
    2981             :             "ation is 0 then the glyphs will actually be touching.");
    2982           0 :         gcd[i].gd.cid = CID_Touched;
    2983           0 :         gcd[i].creator = GCheckBoxCreate;
    2984           0 :         h4array[5] = &gcd[i++];
    2985             : 
    2986           0 :         h4array[6] = GCD_Glue; h4array[7] = NULL;
    2987             : 
    2988           0 :         memset(&sepbox,0,sizeof(sepbox));
    2989           0 :         sepbox.gd.flags = gg_enabled|gg_visible;
    2990           0 :         sepbox.gd.u.boxelements = h4array;
    2991           0 :         sepbox.creator = GHBoxCreate;
    2992           0 :         varray[j++] = &sepbox; varray[j++] = NULL;
    2993             : 
    2994           0 :         label[i].text = (unichar_t *) _("Only kern glyphs closer");
    2995           0 :         label[i].text_is_1byte = true;
    2996           0 :         label[i].text_in_resource = true;
    2997           0 :         gcd[i].gd.label = &label[i];
    2998           0 :         gcd[i].gd.flags = gg_enabled|gg_visible|gg_utf8_popup;
    2999           0 :         if ( kc->subtable->onlyCloser )
    3000           0 :             gcd[i].gd.flags = gg_enabled|gg_visible|gg_utf8_popup|gg_cb_on;
    3001           0 :         gcd[i].gd.popup_msg = (unichar_t *) _(
    3002             :             "When doing autokerning, only move glyphs closer together,\n"
    3003             :             "so the kerning offset will be negative.");
    3004           0 :         gcd[i].gd.cid = CID_OnlyCloser;
    3005           0 :         gcd[i].creator = GCheckBoxCreate;
    3006           0 :         h5array[0] = &gcd[i++];
    3007             : 
    3008           0 :         label[i].text = (unichar_t *) _("Autokern new entries");
    3009           0 :         label[i].text_is_1byte = true;
    3010           0 :         label[i].text_in_resource = true;
    3011           0 :         gcd[i].gd.label = &label[i];
    3012           0 :         gcd[i].gd.flags = gg_enabled|gg_visible|gg_utf8_popup;
    3013           0 :         if ( !kc->subtable->dontautokern )
    3014           0 :             gcd[i].gd.flags = gg_enabled|gg_visible|gg_utf8_popup|gg_cb_on;
    3015           0 :         gcd[i].gd.popup_msg = (unichar_t *) _(
    3016             :             "When adding a new class provide default kerning values\n"
    3017             :             "Between it and every class with which it interacts.");
    3018           0 :         gcd[i].gd.cid = CID_Autokern;
    3019           0 :         gcd[i].creator = GCheckBoxCreate;
    3020           0 :         h5array[1] = &gcd[i++]; h5array[2] = NULL;
    3021             : 
    3022           0 :         memset(&hbox,0,sizeof(hbox));
    3023           0 :         hbox.gd.flags = gg_enabled|gg_visible;
    3024           0 :         hbox.gd.u.boxelements = h5array;
    3025           0 :         hbox.creator = GHBoxCreate;
    3026             : 
    3027           0 :         varray[j++] = &hbox; varray[j++] = NULL;
    3028             : 
    3029           0 :     gcd[i].gd.pos.x = 10; gcd[i].gd.pos.y = GDrawPointsToPixels(gw,gcd[i-1].gd.pos.y+17);
    3030           0 :     gcd[i].gd.pos.width = pos.width-20;
    3031           0 :     gcd[i].gd.flags = gg_visible | gg_enabled | gg_pos_in_pixels;
    3032           0 :     gcd[i++].creator = GLineCreate;
    3033           0 :     varray[j++] = &gcd[i-1]; varray[j++] = NULL;
    3034             : 
    3035           0 :     i = AddClassList(gcd,label,i,0,&firstmi,harray1,varray1,
    3036             :             sf,kc->firsts,kc->first_cnt);
    3037           0 :     harrayclasses[0] = &gcd[i-1];
    3038           0 :     i = AddClassList(gcd,label,i,100,&secondmi,harray2,varray2,
    3039             :             sf,kc->seconds,kc->second_cnt);
    3040           0 :     harrayclasses[2] = &gcd[i-1]; harrayclasses[3] = NULL;
    3041             : 
    3042           0 :     gcd[i].gd.pos.height = 20;
    3043           0 :     gcd[i].gd.flags = gg_visible | gg_enabled | gg_line_vert;
    3044           0 :     gcd[i++].creator = GLineCreate;
    3045           0 :     harrayclasses[1] = &gcd[i-1];
    3046             : 
    3047           0 :     classbox.gd.flags = gg_enabled|gg_visible;
    3048           0 :     classbox.gd.u.boxelements = harrayclasses;
    3049           0 :     classbox.creator = GHBoxCreate;
    3050           0 :     varray[j++] = &classbox; varray[j++] = NULL;
    3051             : 
    3052           0 :     gcd[i].gd.pos.x = 10; gcd[i].gd.pos.y = GDrawPointsToPixels(gw,gcd[i-1].gd.pos.y+27);
    3053           0 :     gcd[i].gd.pos.width = pos.width-20;
    3054           0 :     gcd[i].gd.flags = gg_visible | gg_enabled | gg_pos_in_pixels;
    3055           0 :     gcd[i++].creator = GLineCreate;
    3056           0 :     varray[j++] = &gcd[i-1]; varray[j++] = NULL;
    3057             : 
    3058           0 :     kcd->canceldrop = GDrawPointsToPixels(gw,KC_CANCELDROP);
    3059           0 :     kcd->sbdrop = kcd->canceldrop+GDrawPointsToPixels(gw,7);
    3060           0 :     gcd[i].gd.pos.width = kcd->kernw;
    3061           0 :     gcd[i].gd.pos.height = kcd->kernh;
    3062           0 :     gcd[i].gd.flags = gg_visible|gg_enabled|gg_pos_in_pixels;
    3063           0 :     gcd[i++].creator = GSpacerCreate;
    3064           0 :     hvarray[0] = &gcd[i-1]; hvarray[1] = GCD_Glue; hvarray[2] = GCD_Glue; hvarray[3] = NULL;
    3065             : 
    3066           0 :     gcd[i].gd.pos.width = kcd->kernw;
    3067           0 :     gcd[i].gd.pos.height = 4*kcd->kernh;
    3068           0 :     gcd[i].gd.flags = gg_visible|gg_enabled|gg_pos_in_pixels;
    3069           0 :     gcd[i++].creator = GSpacerCreate;
    3070             : 
    3071           0 :     vi = i;
    3072           0 :     gcd[i].gd.pos.width = sbsize = GDrawPointsToPixels(gw,_GScrollBar_Width);
    3073           0 :     gcd[i].gd.pos.x = pos.width-sbsize;
    3074           0 :     gcd[i].gd.pos.y = gcd[i-1].gd.pos.y+8;
    3075           0 :     gcd[i].gd.pos.height = pos.height-gcd[i].gd.pos.y-sbsize-kcd->sbdrop;
    3076           0 :     gcd[i].gd.flags = gg_visible|gg_enabled|gg_pos_in_pixels|gg_sb_vert;
    3077           0 :     gcd[i++].creator = GScrollBarCreate;
    3078           0 :     hvarray[4] = &gcd[i-2]; hvarray[5] = GCD_Glue; hvarray[6] = &gcd[i-1]; hvarray[7] = NULL;
    3079             : 
    3080           0 :     gcd[i].gd.pos.height = sbsize;
    3081           0 :     gcd[i].gd.pos.y = pos.height-sbsize-8;
    3082           0 :     gcd[i].gd.pos.x = 4;
    3083           0 :     gcd[i].gd.pos.width = pos.width-sbsize;
    3084           0 :     gcd[i].gd.flags = gg_visible|gg_enabled|gg_pos_in_pixels;
    3085           0 :     gcd[i++].creator = GScrollBarCreate;
    3086           0 :     hvarray[8] = GCD_Glue; hvarray[9] = &gcd[i-1]; hvarray[10] = GCD_Glue; hvarray[11] = NULL;
    3087           0 :     hvarray[12] = NULL;
    3088           0 :     kcd->width = gcd[i-1].gd.pos.width;
    3089           0 :     kcd->xstart = 5;
    3090             : 
    3091           0 :     hvbox.gd.flags = gg_enabled|gg_visible;
    3092           0 :     hvbox.gd.u.boxelements = hvarray;
    3093           0 :     hvbox.creator = GHVBoxCreate;
    3094           0 :     varray[j++] = &hvbox; varray[j++] = NULL;
    3095             : 
    3096           0 :     gcd[i].gd.pos.x = 10; gcd[i].gd.pos.y = gcd[i-1].gd.pos.y+24+3;
    3097           0 :     gcd[i].gd.pos.width = -1;
    3098           0 :     gcd[i].gd.flags = gg_visible | gg_enabled | gg_but_default;
    3099           0 :     label[i].text = (unichar_t *) _("_OK");
    3100           0 :     label[i].text_is_1byte = true;
    3101           0 :     label[i].text_in_resource = true;
    3102           0 :     gcd[i].gd.label = &label[i];
    3103           0 :     gcd[i].gd.handle_controlevent = KC_OK;
    3104           0 :     gcd[i].gd.cid = CID_OK;
    3105           0 :     gcd[i++].creator = GButtonCreate;
    3106             : 
    3107           0 :     gcd[i].gd.pos.x = -10; gcd[i].gd.pos.y = gcd[i-1].gd.pos.y+3;
    3108           0 :     gcd[i].gd.pos.width = -1;
    3109           0 :     gcd[i].gd.flags = gg_visible | gg_enabled | gg_but_cancel;
    3110           0 :     label[i].text = (unichar_t *) _("_Cancel");
    3111           0 :     label[i].text_is_1byte = true;
    3112           0 :     label[i].text_in_resource = true;
    3113           0 :     gcd[i].gd.label = &label[i];
    3114           0 :     gcd[i].gd.handle_controlevent = KC_Cancel;
    3115           0 :     gcd[i].gd.cid = CID_Cancel;
    3116           0 :     gcd[i++].creator = GButtonCreate;
    3117             : 
    3118           0 :     buttonarray[0] = GCD_Glue; buttonarray[1] = &gcd[i-2]; buttonarray[2] = GCD_Glue;
    3119           0 :     buttonarray[3] = GCD_Glue; buttonarray[4] = &gcd[i-1]; buttonarray[5] = GCD_Glue;
    3120           0 :     buttonarray[6] = NULL;
    3121           0 :     buttonbox.gd.flags = gg_enabled|gg_visible;
    3122           0 :     buttonbox.gd.u.boxelements = buttonarray;
    3123           0 :     buttonbox.creator = GHBoxCreate;
    3124           0 :     varray[j++] = &buttonbox; varray[j++] = NULL; varray[j++] = NULL;
    3125             : 
    3126           0 :     mainbox[0].gd.pos.x = mainbox[0].gd.pos.y = 2;
    3127           0 :     mainbox[0].gd.flags = gg_enabled|gg_visible;
    3128           0 :     mainbox[0].gd.u.boxelements = varray;
    3129           0 :     mainbox[0].creator = GHVGroupCreate;
    3130             : 
    3131           0 :     FillShowKerningWindow(kcd, mainbox, kcd->sf, topbox);
    3132           0 :     kcd->vsb = gcd[vi].ret;
    3133           0 :     kcd->hsb = gcd[vi+1].ret;
    3134             : 
    3135           0 :     GHVBoxSetExpandableRow(mainbox[0].ret,6);
    3136             : 
    3137           0 :     GHVBoxSetExpandableCol(titbox.ret,gb_expandglue);
    3138             : 
    3139           0 :     GHVBoxSetExpandableCol(buttonbox.ret,gb_expandgluesame);
    3140           0 :     GHVBoxSetExpandableCol(sepbox.ret,gb_expandglue);
    3141             : 
    3142           0 :     GHVBoxSetPadding(hvbox.ret,0,0);
    3143           0 :     GHVBoxSetExpandableRow(hvbox.ret,1);
    3144           0 :     GHVBoxSetExpandableCol(hvbox.ret,1);
    3145             : 
    3146           0 :     for ( i=0; i<2; ++i ) {
    3147           0 :         GGadgetCreateData *box = harrayclasses[2*i], **boxarray = box->gd.u.boxelements;
    3148           0 :         GHVBoxSetExpandableRow(box->ret,1);
    3149           0 :         GHVBoxSetExpandableCol(boxarray[2]->ret,1);
    3150             :     }
    3151             : 
    3152           0 :     for ( i=0; i<2; ++i ) {
    3153           0 :         GGadget *list = GWidgetGetControl(kcd->gw,CID_ClassList+i*100);
    3154             :         GRect size;
    3155           0 :         memset(&size,0,sizeof(size));
    3156           0 :         size.width = (kc_width-20)/2; size.height = 6;
    3157           0 :         GGadgetSetDesiredSize(list,NULL,&size);
    3158           0 :         GMatrixEditSetUpDownVisible(list, true);
    3159           0 :         GMatrixEditSetCanUpDown(list, KCD_EnableUpDown);
    3160           0 :         GMatrixEditSetRowMotionCallback(list, KCD_RowMotion);
    3161           0 :         GMatrixEditSetBeforeDelete(list, KCD_DeleteClass);
    3162             :     /* When the selection changes */
    3163           0 :         GMatrixEditSetOtherButtonEnable(list, KCD_ClassSelectionChanged);
    3164           0 :         GMatrixEditSetColumnCompletion(list,0,KCD_GlyphListCompletion);
    3165             :     }
    3166             : 
    3167           0 :     KC_ShowHideKernPane(GWidgetGetControl(gw,CID_ShowHideKern),NULL);
    3168           0 :     GHVBoxFitWindow(topbox[0].ret);
    3169           0 :     GDrawSetVisible(kcd->gw,true);
    3170             : }
    3171             : 
    3172           0 : static int KCL_New(GGadget *g, GEvent *e) {
    3173             :     KernClassListDlg *kcld;
    3174             :     struct subtable_data sd;
    3175             : 
    3176           0 :     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
    3177           0 :         kcld = GDrawGetUserData(GGadgetGetWindow(g));
    3178           0 :         memset(&sd,0,sizeof(sd));
    3179           0 :         sd.flags = (kcld->isv ? sdf_verticalkern : sdf_horizontalkern ) |
    3180             :                 sdf_kernclass;
    3181           0 :         SFNewLookupSubtableOfType(kcld->sf,gpos_pair,&sd,kcld->layer);
    3182             :     }
    3183           0 : return( true );
    3184             : }
    3185             : 
    3186           0 : static int KCL_Delete(GGadget *g, GEvent *e) {
    3187             :     int32 len; int i,j;
    3188             :     GTextInfo **old, **new;
    3189             :     GGadget *list;
    3190             :     KernClassListDlg *kcld;
    3191             :     KernClassDlg *kcd;
    3192             :     KernClass *p, *kc, *n;
    3193             : 
    3194           0 :     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
    3195           0 :         kcld = GDrawGetUserData(GGadgetGetWindow(g));
    3196           0 :         list = GWidgetGetControl(kcld->gw,CID_List);
    3197           0 :         old = GGadgetGetList(list,&len);
    3198           0 :         new = calloc(len+1,sizeof(GTextInfo *));
    3199           0 :         p = NULL; kc = kcld->isv ? kcld->sf->vkerns : kcld->sf->kerns;
    3200           0 :         for ( i=j=0; i<len; ++i, kc = n ) {
    3201           0 :             n = kc->next;
    3202           0 :             if ( !old[i]->selected ) {
    3203           0 :                 new[j] = malloc(sizeof(GTextInfo));
    3204           0 :                 *new[j] = *old[i];
    3205           0 :                 new[j]->text = u_copy(new[j]->text);
    3206           0 :                 ++j;
    3207           0 :                 p = kc;
    3208             :             } else {
    3209           0 :                 if ( p!=NULL )
    3210           0 :                     p->next = n;
    3211           0 :                 else if ( kcld->isv )
    3212           0 :                     kcld->sf->vkerns = n;
    3213             :                 else
    3214           0 :                     kcld->sf->kerns = n;
    3215           0 :                 kc->next = NULL;
    3216           0 :                 for ( kcd=kcld->sf->kcd; kcd!=NULL && kcd->orig!=kc; kcd=kcd->next );
    3217           0 :                 if ( kcd!=NULL )
    3218           0 :                     KC_DoCancel(kcd);
    3219           0 :                 KernClassListFree(kc);
    3220             :             }
    3221             :         }
    3222           0 :         new[j] = calloc(1,sizeof(GTextInfo));
    3223           0 :         GGadgetSetList(list,new,false);
    3224           0 :         GGadgetSetEnabled(GWidgetGetControl(GGadgetGetWindow(g),CID_Delete),false);
    3225           0 :         GGadgetSetEnabled(GWidgetGetControl(GGadgetGetWindow(g),CID_Edit),false);
    3226             :     }
    3227           0 : return( true );
    3228             : }
    3229             : 
    3230           0 : static int KCL_Edit(GGadget *g, GEvent *e) {
    3231             :     int sel, i;
    3232             :     KernClassListDlg *kcld;
    3233             :     KernClass *kc;
    3234             : 
    3235           0 :     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
    3236           0 :         kcld = GDrawGetUserData(GGadgetGetWindow(g));
    3237           0 :         sel = GGadgetGetFirstListSelectedItem(GWidgetGetControl(GGadgetGetWindow(g),CID_List));
    3238           0 :         if ( sel==-1 )
    3239           0 : return( true );
    3240           0 :         for ( kc=kcld->isv?kcld->sf->vkerns:kcld->sf->kerns, i=0; i<sel; kc=kc->next, ++i );
    3241           0 :         KernClassD(kc,kcld->sf,kcld->layer,kcld->isv);
    3242             :     }
    3243           0 : return( true );
    3244             : }
    3245             : 
    3246           0 : static int KCL_Done(GGadget *g, GEvent *e) {
    3247             :     KernClassListDlg *kcld;
    3248             : 
    3249           0 :     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
    3250           0 :         kcld = GDrawGetUserData(GGadgetGetWindow(g));
    3251             :         //
    3252             :         // Update any metrics views for the splinefont.
    3253             :         //
    3254           0 :         if( kcld && kcld->sf )
    3255             :         {
    3256           0 :             SplineFont *sf = kcld->sf;
    3257             : 
    3258           0 :             MVReFeatureAll( sf );
    3259           0 :             MVReKernAll( sf );
    3260             : 
    3261             :             /* KernClass* kc = sf->kerns; */
    3262             :             /* int i = 0; */
    3263             :             /* for( ; kc; kc = kc->next ) */
    3264             :             /*  i++; */
    3265             :             /* printf("kern count:%d\n", i ); */
    3266             : 
    3267             :             MetricsView *mv;
    3268           0 :             for ( mv=sf->metrics; mv!=NULL; mv=mv->next )
    3269           0 :                 MVSelectFirstKerningTable( mv );
    3270             : 
    3271             :         }
    3272           0 :         GDrawDestroyWindow(kcld->gw);
    3273             :     }
    3274           0 : return( true );
    3275             : }
    3276             : 
    3277           0 : static int KCL_SelChanged(GGadget *g, GEvent *e) {
    3278           0 :     if ( e->type==et_controlevent && e->u.control.subtype == et_listselected ) {
    3279           0 :         KernClassListDlg *kcld = GDrawGetUserData(GGadgetGetWindow(g));
    3280           0 :         int sel = GGadgetGetFirstListSelectedItem(g);
    3281           0 :         GGadgetSetEnabled(GWidgetGetControl(kcld->gw,CID_Delete),sel!=-1);
    3282           0 :         GGadgetSetEnabled(GWidgetGetControl(kcld->gw,CID_Edit),sel!=-1);
    3283           0 :     } else if ( e->type==et_controlevent && e->u.control.subtype == et_listdoubleclick ) {
    3284           0 :         KernClassListDlg *kcld = GDrawGetUserData(GGadgetGetWindow(g));
    3285           0 :         e->u.control.subtype = et_buttonactivate;
    3286           0 :         e->u.control.g = GWidgetGetControl(kcld->gw,CID_Edit);
    3287           0 :         KCL_Edit(e->u.control.g,e);
    3288             :     }
    3289           0 : return( true );
    3290             : }
    3291             : 
    3292           0 : static int kcl_e_h(GWindow gw, GEvent *event) {
    3293           0 :     if ( event->type==et_close ) {
    3294           0 :         KernClassListDlg *kcld = GDrawGetUserData(gw);
    3295           0 :         GDrawDestroyWindow(kcld->gw);
    3296           0 :     } else if ( event->type==et_char ) {
    3297           0 :         if ( event->u.chr.keysym == GK_F1 || event->u.chr.keysym == GK_Help ) {
    3298           0 :             help("metricsview.html#kernclass");
    3299           0 : return( true );
    3300             :         }
    3301           0 : return( false );
    3302           0 :     } else if ( event->type == et_destroy ) {
    3303           0 :         KernClassListDlg *kcld = GDrawGetUserData(gw);
    3304           0 :         if ( kcld->isv )
    3305           0 :             kcld->sf->vkcld = NULL;
    3306             :         else
    3307           0 :             kcld->sf->kcld = NULL;
    3308           0 :         free(kcld);
    3309             :     }
    3310           0 : return( true );
    3311             : }
    3312             : 
    3313           0 : void ShowKernClasses(SplineFont *sf,MetricsView *mv,int layer,int isv) {
    3314             :     KernClassListDlg *kcld;
    3315             :     GRect pos;
    3316             :     GWindowAttrs wattrs;
    3317             :     GGadgetCreateData gcd[7], boxes[4], *varray[10], *harray[9], *harray2[5];
    3318             :     GTextInfo label[7];
    3319           0 :     int kcl_width = KCL_Width, temp;
    3320             : 
    3321           0 :     if ( sf->kcld && !isv ) {
    3322           0 :         GDrawSetVisible(sf->kcld->gw,true);
    3323           0 :         GDrawRaise(sf->kcld->gw);
    3324           0 : return;
    3325           0 :     } else if ( sf->vkcld && isv ) {
    3326           0 :         GDrawSetVisible(sf->vkcld->gw,true);
    3327           0 :         GDrawRaise(sf->vkcld->gw);
    3328           0 : return;
    3329             :     }
    3330             : 
    3331           0 :     kcld = calloc(1,sizeof(KernClassListDlg));
    3332           0 :     kcld->sf = sf;
    3333           0 :     kcld->layer = layer;
    3334           0 :     kcld->isv = isv;
    3335           0 :     if ( isv )
    3336           0 :         sf->vkcld = kcld;
    3337             :     else
    3338           0 :         sf->kcld = kcld;
    3339             : 
    3340           0 :     memset(&wattrs,0,sizeof(wattrs));
    3341           0 :     memset(&gcd,0,sizeof(gcd));
    3342           0 :     memset(&label,0,sizeof(label));
    3343           0 :     memset(boxes,0,sizeof(boxes));
    3344             : 
    3345           0 :     wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_undercursor|wam_isdlg|wam_restrict;
    3346           0 :     wattrs.event_masks = ~(1<<et_charup);
    3347           0 :     wattrs.restrict_input_to_me = false;
    3348           0 :     wattrs.undercursor = 1;
    3349           0 :     wattrs.cursor = ct_pointer;
    3350           0 :     wattrs.utf8_window_title =  isv?_("VKern By Classes"):_("Kern By Classes");
    3351           0 :     wattrs.is_dlg = false;
    3352           0 :     pos.x = pos.y = 0;
    3353             :     // temp = 40 + 300*GIntGetResource(_NUM_Buttonsize)/GGadgetScale(100); // The _NUM_Buttonsize value is obsolete.
    3354           0 :     temp = 40 + 300*114/GGadgetScale(100);
    3355           0 :     if ( kcl_width<temp ) kcl_width = temp;
    3356           0 :     pos.width = GGadgetScale(GDrawPointsToPixels(NULL,kcl_width));
    3357           0 :     pos.height = GDrawPointsToPixels(NULL,KCL_Height);
    3358           0 :     kcld->gw = GDrawCreateTopWindow(NULL,&pos,kcl_e_h,kcld,&wattrs);
    3359             : 
    3360           0 :     gcd[0].gd.pos.x = 5; gcd[0].gd.pos.y = 5;
    3361           0 :     gcd[0].gd.pos.width = kcl_width-10; gcd[0].gd.pos.height = 7*12+10;
    3362           0 :     gcd[0].gd.flags = gg_visible | gg_enabled | gg_list_multiplesel;
    3363           0 :     gcd[0].gd.cid = CID_List;
    3364           0 :     gcd[0].gd.u.list = KCLookupSubtableList(sf,isv);
    3365           0 :     gcd[0].gd.handle_controlevent = KCL_SelChanged;
    3366           0 :     gcd[0].creator = GListCreate;
    3367           0 :     varray[0] = &gcd[0]; varray[1] = NULL;
    3368             : 
    3369           0 :     gcd[1].gd.pos.x = 10; gcd[1].gd.pos.y = gcd[0].gd.pos.y+gcd[0].gd.pos.height+4;
    3370           0 :     gcd[1].gd.flags = gg_visible | gg_enabled;
    3371           0 :     label[1].text = (unichar_t *) S_("KernClass|_New Lookup...");
    3372           0 :     label[1].text_is_1byte = true;
    3373           0 :     label[1].text_in_resource = true;
    3374           0 :     gcd[1].gd.label = &label[1];
    3375           0 :     gcd[1].gd.cid = CID_New;
    3376           0 :     gcd[1].gd.handle_controlevent = KCL_New;
    3377           0 :     gcd[1].creator = GButtonCreate;
    3378           0 :     harray[0] = GCD_Glue; harray[1] = &gcd[1];
    3379             : 
    3380           0 :     gcd[2].gd.pos.x = 20+GIntGetResource(_NUM_Buttonsize)*100/GIntGetResource(_NUM_ScaleFactor); gcd[2].gd.pos.y = gcd[1].gd.pos.y;
    3381           0 :     gcd[2].gd.flags = gg_visible;
    3382           0 :     label[2].text = (unichar_t *) _("_Delete");
    3383           0 :     label[2].text_is_1byte = true;
    3384           0 :     label[2].text_in_resource = true;
    3385           0 :     gcd[2].gd.label = &label[2];
    3386           0 :     gcd[2].gd.cid = CID_Delete;
    3387           0 :     gcd[2].gd.handle_controlevent = KCL_Delete;
    3388           0 :     gcd[2].creator = GButtonCreate;
    3389           0 :     harray[2] = GCD_Glue; harray[3] = &gcd[2];
    3390             : 
    3391           0 :     gcd[3].gd.pos.x = -10; gcd[3].gd.pos.y = gcd[1].gd.pos.y;
    3392           0 :     gcd[3].gd.pos.width = -1;
    3393           0 :     gcd[3].gd.flags = gg_visible;
    3394           0 :     label[3].text = (unichar_t *) _("_Edit...");
    3395           0 :     label[3].text_is_1byte = true;
    3396           0 :     label[3].text_in_resource = true;
    3397           0 :     gcd[3].gd.label = &label[3];
    3398           0 :     gcd[3].gd.cid = CID_Edit;
    3399           0 :     gcd[3].gd.handle_controlevent = KCL_Edit;
    3400           0 :     gcd[3].creator = GButtonCreate;
    3401           0 :     harray[4] = GCD_Glue; harray[5] = &gcd[3]; harray[6] = GCD_Glue; harray[7] = NULL;
    3402             : 
    3403           0 :     boxes[0].gd.flags = gg_enabled|gg_visible;
    3404           0 :     boxes[0].gd.u.boxelements = harray;
    3405           0 :     boxes[0].creator = GHBoxCreate;
    3406           0 :     varray[2] = &boxes[0]; varray[3] = NULL;
    3407             : 
    3408           0 :     gcd[4].gd.pos.x = 10; gcd[4].gd.pos.y = gcd[1].gd.pos.y+28;
    3409           0 :     gcd[4].gd.pos.width = kcl_width-20;
    3410           0 :     gcd[4].gd.flags = gg_visible;
    3411           0 :     gcd[4].creator = GLineCreate;
    3412           0 :     varray[4] = &gcd[4]; varray[5] = NULL;
    3413             : 
    3414           0 :     gcd[5].gd.pos.x = (kcl_width-GIntGetResource(_NUM_Buttonsize))/2; gcd[5].gd.pos.y = gcd[4].gd.pos.y+7;
    3415           0 :     gcd[5].gd.flags = gg_visible|gg_enabled|gg_but_default|gg_but_cancel;
    3416           0 :     label[5].text = (unichar_t *) _("_Done");
    3417           0 :     label[5].text_is_1byte = true;
    3418           0 :     label[5].text_in_resource = true;
    3419           0 :     gcd[5].gd.label = &label[5];
    3420           0 :     gcd[5].gd.handle_controlevent = KCL_Done;
    3421           0 :     gcd[5].creator = GButtonCreate;
    3422           0 :     harray2[0] = GCD_Glue; harray2[1] = &gcd[5]; harray2[2] = GCD_Glue; harray2[3] = NULL;
    3423             : 
    3424           0 :     boxes[1].gd.flags = gg_enabled|gg_visible;
    3425           0 :     boxes[1].gd.u.boxelements = harray2;
    3426           0 :     boxes[1].creator = GHBoxCreate;
    3427           0 :     varray[6] = &boxes[1]; varray[7] = NULL; varray[8] = NULL;
    3428             : 
    3429           0 :     boxes[2].gd.pos.x = boxes[0].gd.pos.y = 2;
    3430           0 :     boxes[2].gd.flags = gg_enabled|gg_visible;
    3431           0 :     boxes[2].gd.u.boxelements = varray;
    3432           0 :     boxes[2].creator = GHVGroupCreate;
    3433             : 
    3434           0 :     GGadgetsCreate(kcld->gw,&boxes[2]);
    3435           0 :     GHVBoxSetExpandableRow(boxes[2].ret,0);
    3436           0 :     GHVBoxSetExpandableCol(boxes[0].ret,gb_expandgluesame);
    3437           0 :     GHVBoxSetExpandableCol(boxes[1].ret,gb_expandgluesame);
    3438           0 :     GDrawSetVisible(kcld->gw,true);
    3439             : }
    3440             : 
    3441           0 : void KCLD_End(KernClassListDlg *kcld) {
    3442             :     KernClassDlg *kcd, *kcdnext;
    3443           0 :     for ( kcd= kcld->sf->kcd; kcd!=NULL; kcd=kcdnext ) {
    3444           0 :         kcdnext = kcd->next;
    3445           0 :         KC_DoCancel(kcd);
    3446             :     }
    3447           0 :     if ( kcld==NULL )
    3448           0 : return;
    3449           0 :     GDrawDestroyWindow(kcld->gw);
    3450             : }
    3451             : 
    3452           0 : void KCLD_MvDetach(KernClassListDlg *kcld,MetricsView *mv) {
    3453           0 :     if ( kcld==NULL )
    3454           0 : return;
    3455             : }
    3456             : 
    3457             : /* ************************************************************************** */
    3458             : /* *************************** Kern Pair Dialog  **************************** */
    3459             : /* ************************************************************************** */
    3460             : 
    3461           0 : void KernPairD(SplineFont *sf,SplineChar *sc1,SplineChar *sc2,int layer,int isv) {
    3462             :     GRect pos;
    3463             :     GWindowAttrs wattrs;
    3464             :     KernClassDlg kcd;
    3465             :     GWindow gw;
    3466             :     int gid;
    3467             : 
    3468           0 :     if ( sc1==NULL ) {
    3469           0 :         FontView *fv = (FontView *) sf->fv;
    3470           0 :         int start = fv->rowoff*fv->colcnt, end = start+fv->rowcnt*fv->colcnt;
    3471             :         int i;
    3472           0 :         for ( i=start; i<end && i<fv->b.map->enccount; ++i )
    3473           0 :             if ( (gid=fv->b.map->map[i])!=-1 && sf->glyphs[gid]!=NULL &&
    3474           0 :                     (isv ? sf->glyphs[gid]->vkerns : sf->glyphs[gid]->kerns)!=NULL )
    3475           0 :         break;
    3476           0 :         if ( i==end || i==fv->b.map->enccount ) {
    3477           0 :             for ( i=0; i<fv->b.map->enccount; ++i )
    3478           0 :                 if ( (gid=fv->b.map->map[i])!=-1 && sf->glyphs[gid]!=NULL &&
    3479           0 :                         (isv ? sf->glyphs[gid]->vkerns : sf->glyphs[gid]->kerns)!=NULL )
    3480           0 :             break;
    3481             :         }
    3482           0 :         if ( i==fv->b.map->enccount ) {
    3483           0 :             for ( i=start; i<end && i<fv->b.map->enccount; ++i )
    3484           0 :                 if ( (gid=fv->b.map->map[i])!=-1 && sf->glyphs[gid]!=NULL )
    3485           0 :             break;
    3486           0 :             if ( i==end || i==fv->b.map->enccount ) {
    3487           0 :                 for ( i=0; i<fv->b.map->enccount; ++i )
    3488           0 :                     if ( (gid=fv->b.map->map[i])!=-1 && sf->glyphs[gid]!=NULL )
    3489           0 :                 break;
    3490             :             }
    3491             :         }
    3492           0 :         if ( i!=fv->b.map->enccount )
    3493           0 :             sc1 = sf->glyphs[gid];
    3494             :     }
    3495           0 :     if ( sc2==NULL && sc1!=NULL && (isv ? sc1->vkerns : sc1->kerns)!=NULL )
    3496           0 :         sc2 = (isv ? sc1->vkerns : sc1->kerns)->sc;
    3497             : 
    3498           0 :     memset(&kcd,0,sizeof(kcd));
    3499           0 :     kcd.sf = sf;
    3500           0 :     kcd.layer = layer;
    3501           0 :     kcd.scf = sc1;
    3502           0 :     kcd.scs = sc2;
    3503           0 :     kcd.isv = isv;
    3504           0 :     kcd.iskernpair = true;
    3505             : 
    3506           0 :     memset(&wattrs,0,sizeof(wattrs));
    3507             : 
    3508           0 :     wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_undercursor|wam_isdlg|wam_restrict;
    3509           0 :     wattrs.event_masks = ~(1<<et_charup);
    3510           0 :     wattrs.restrict_input_to_me = true;
    3511           0 :     wattrs.undercursor = 1;
    3512           0 :     wattrs.cursor = ct_pointer;
    3513           0 :     wattrs.utf8_window_title = _("Kern Pair Closeup");
    3514           0 :     wattrs.is_dlg = true;
    3515           0 :     pos.x = pos.y = 0;
    3516           0 :     pos.width = GGadgetScale(GDrawPointsToPixels(NULL,KC_Width));
    3517           0 :     pos.height = GDrawPointsToPixels(NULL,KC_Height);
    3518           0 :     kcd.gw = gw = GDrawCreateTopWindow(NULL,&pos,kcd_e_h,&kcd,&wattrs);
    3519           0 :     kcd.canceldrop = GDrawPointsToPixels(gw,KC_CANCELDROP);
    3520             : 
    3521             : 
    3522           0 :     FillShowKerningWindow(&kcd, NULL, kcd.sf, NULL);
    3523             : 
    3524           0 :     if ( sc1!=NULL ) {
    3525             :         unichar_t *utemp;
    3526           0 :         GGadgetSetTitle(GWidgetGetControl(kcd.gw,CID_First),(utemp=uc_copy(sc1->name)));
    3527           0 :         free(utemp);
    3528           0 :         KPD_BuildKernList(&kcd);
    3529           0 :         KCD_UpdateGlyph(&kcd,0);
    3530             :     }
    3531           0 :     if ( sc2!=NULL ) {
    3532             :         unichar_t *utemp;
    3533           0 :         GGadgetSetTitle(GWidgetGetControl(kcd.gw,CID_Second),(utemp=uc_copy(sc2->name)));
    3534           0 :         free(utemp);
    3535           0 :         KCD_UpdateGlyph(&kcd,1);
    3536           0 :         KPD_PairSearch(&kcd);
    3537             :     }
    3538             : 
    3539           0 :     GDrawSetVisible(kcd.gw,true);
    3540           0 :     while ( !kcd.done )
    3541           0 :         GDrawProcessOneEvent(NULL);
    3542           0 :     GDrawSetUserData(kcd.gw,NULL);
    3543           0 :     GDrawDestroyWindow(kcd.gw);
    3544           0 : }
    3545             : 
    3546             : /* ************************************************************************** */
    3547             : /* *******************************   kerning   ****************************** */
    3548             : /* ************************************************************************** */
    3549             : 
    3550           0 : KernClass *SFFindKernClass(SplineFont *sf,SplineChar *first,SplineChar *last,
    3551             :         int *index,int allow_zero) {
    3552           0 :     int i,f,l,pcnt = 2;
    3553             :     KernClass *kc;
    3554             : 
    3555             :     /* At the first pass we check only combinations between defined classes. */
    3556             :     /* while at the second pass class 0 is also accepted. If zero kerning values are */
    3557             :     /* allowed, then we may need two more passes (again, first checking only defined */
    3558             :     /* classes, and then also class 0, but this time accepting also zero offsets) */
    3559           0 :     if (allow_zero) pcnt *= 2;
    3560           0 :     for ( i=0; i<=pcnt; ++i ) {
    3561           0 :         for ( kc=sf->kerns; kc!=NULL; kc=kc->next ) {
    3562           0 :             uint8 kspecd = kc->firsts[0] != NULL;
    3563           0 :             f = KCFindName(first->name,kc->firsts ,kc->first_cnt ,i % 2);
    3564           0 :             l = KCFindName(last->name ,kc->seconds,kc->second_cnt,i % 2);
    3565           0 :             if ( f!=-1 && l!=-1 && ( kspecd || f!=0 || l!=0 )  ) {
    3566           0 :                 if ( i > 1 || kc->offsets[f*kc->second_cnt+l]!=0 ) {
    3567           0 :                     *index = f*kc->second_cnt+l;
    3568           0 : return( kc );
    3569             :                 }
    3570             :             }
    3571             :         }
    3572             :     }
    3573           0 : return( NULL );
    3574             : }
    3575             : 
    3576           0 : KernClass *SFFindVKernClass(SplineFont *sf,SplineChar *first,SplineChar *last,
    3577             :         int *index,int allow_zero) {
    3578           0 :     int i,f,l,pcnt = 2;
    3579             :     KernClass *kc;
    3580             : 
    3581           0 :     if (allow_zero) pcnt *= 2;
    3582           0 :     for ( i=0; i<=pcnt; ++i ) {
    3583           0 :         for ( kc=sf->vkerns; kc!=NULL; kc=kc->next ) {
    3584           0 :             uint8 kspecd = kc->firsts[0] != NULL;
    3585           0 :             f = KCFindName(first->name,kc->firsts ,kc->first_cnt ,i % 2);
    3586           0 :             l = KCFindName(last->name ,kc->seconds,kc->second_cnt,i % 2);
    3587           0 :             if ( f!=-1 && l!=-1 && ( kspecd || f!=0 || l!=0 ) ) {
    3588           0 :                 if ( i > 1 || kc->offsets[f*kc->second_cnt+l]!=0 ) {
    3589           0 :                     *index = f*kc->second_cnt+l;
    3590           0 : return( kc );
    3591             :                 }
    3592             :             }
    3593             :         }
    3594             :     }
    3595           0 : return( NULL );
    3596             : }

Generated by: LCOV version 1.10