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

          Line data    Source code
       1             : /* -*- coding: utf-8 -*- */
       2             : /* Copyright (C) 2000-2012 by George Williams */
       3             : /*
       4             :  * Redistribution and use in source and binary forms, with or without
       5             :  * modification, are permitted provided that the following conditions are met:
       6             : 
       7             :  * Redistributions of source code must retain the above copyright notice, this
       8             :  * list of conditions and the following disclaimer.
       9             : 
      10             :  * Redistributions in binary form must reproduce the above copyright notice,
      11             :  * this list of conditions and the following disclaimer in the documentation
      12             :  * and/or other materials provided with the distribution.
      13             : 
      14             :  * The name of the author may not be used to endorse or promote products
      15             :  * derived from this software without specific prior written permission.
      16             : 
      17             :  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
      18             :  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
      19             :  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
      20             :  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
      21             :  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
      22             :  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
      23             :  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
      24             :  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
      25             :  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
      26             :  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      27             :  */
      28             : #include "fontforgeui.h"
      29             : #include "fvcomposite.h"
      30             : #include "fvfonts.h"
      31             : #include "lookups.h"
      32             : #include "psfont.h"
      33             : #include "splinefill.h"
      34             : #include "splineutil.h"
      35             : #include "tottfgpos.h"
      36             : #include <ustring.h>
      37             : #include <gkeysym.h>
      38             : #include <utype.h>
      39             : #include <unistd.h>
      40             : 
      41             : 
      42             : GTextInfo sizes[] = {
      43             :     { (unichar_t *) "24", NULL, 0, 0, (void *) 24, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
      44             :     { (unichar_t *) "36", NULL, 0, 0, (void *) 36, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
      45             :     { (unichar_t *) "48", NULL, 0, 0, (void *) 48, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
      46             :     { (unichar_t *) "72", NULL, 0, 0, (void *) 72, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
      47             :     { (unichar_t *) "96", NULL, 0, 0, (void *) 96, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
      48             :     { (unichar_t *) "200", NULL, 0, 0, (void *) 200, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
      49             :     GTEXTINFO_EMPTY
      50             : };
      51             : enum sortby { sb_first, sb_second, sb_kern };
      52             : GTextInfo sortby[] = {
      53             :     { (unichar_t *) N_("First Char"), NULL, 0, 0, (void *) sb_first, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
      54             :     { (unichar_t *) N_("Second Char"), NULL, 0, 0, (void *) sb_second, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
      55             :     { (unichar_t *) N_("Kern Size"), NULL, 0, 0, (void *) sb_kern, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
      56             :     GTEXTINFO_EMPTY
      57             : };
      58             : 
      59           0 : void SFShowLigatures(SplineFont *sf,SplineChar *searchfor) {
      60             :     int i, cnt;
      61           0 :     char **choices=NULL;
      62           0 :     int *where=NULL;
      63             :     SplineChar *sc, *sc2;
      64             :     char *pt, *line;
      65             :     char *start, *end, ch;
      66             :     PST *pst;
      67             : 
      68             :     while ( 1 ) {
      69           0 :         for ( i=cnt=0; i<sf->glyphcnt; ++i ) {
      70           0 :             if ( (sc=sf->glyphs[i])!=NULL && SCDrawsSomething(sc) ) {
      71           0 :                 for ( pst=sc->possub; pst!=NULL; pst=pst->next )
      72           0 :                         if ( pst->type==pst_ligature &&
      73           0 :                                 (searchfor==NULL || PSTContains(pst->u.lig.components,searchfor->name))) {
      74           0 :                     if ( choices!=NULL ) {
      75           0 :                         line = pt = malloc((strlen(sc->name)+13+3*strlen(pst->u.lig.components)));
      76           0 :                         strcpy(pt,sc->name);
      77           0 :                         pt += strlen(pt);
      78           0 :                         if ( sc->unicodeenc!=-1 && sc->unicodeenc<0x10000 ) {
      79           0 :                             *pt++='(';
      80           0 :                             pt = utf8_idpb(pt,sc->unicodeenc,0);
      81           0 :                             *pt++=')';
      82             :                         }
      83             :                         /* *pt++ = 0x21d0;*/ /* left arrow */
      84           0 :                         strcpy(pt," ⇐ "); pt += strlen(pt);
      85           0 :                         for ( start= pst->u.lig.components; ; start=end ) {
      86           0 :                             while ( *start==' ' ) ++start;
      87           0 :                             if ( *start=='\0' )
      88           0 :                         break;
      89           0 :                             for ( end=start+1; *end!='\0' && *end!=' '; ++end );
      90           0 :                             ch = *end;
      91           0 :                             *end = '\0';
      92           0 :                             strcpy( pt,start );
      93           0 :                             pt += strlen(pt);
      94           0 :                             sc2 = SFGetChar(sf,-1,start);
      95           0 :                             *end = ch;
      96           0 :                             if ( sc2!=NULL && sc2->unicodeenc!=-1 && sc2->unicodeenc<0x10000 ) {
      97           0 :                                 *pt++='(';
      98           0 :                                 *pt++ = sc2->unicodeenc;
      99           0 :                                 *pt++=')';
     100             :                             }
     101           0 :                             *pt++ = ' ';
     102           0 :                         }
     103           0 :                         pt[-1] = '\0';
     104           0 :                         choices[cnt] = line;
     105           0 :                         where[cnt] = i;
     106             :                     }
     107           0 :                     ++cnt;
     108             :                 }
     109             :             }
     110             :         }
     111           0 :         if ( choices!=NULL )
     112           0 :     break;
     113           0 :         choices = malloc((cnt+2)*sizeof(unichar_t *));
     114           0 :         where = malloc((cnt+1)*sizeof(int));
     115           0 :         if ( cnt==0 ) {
     116           0 :             choices[0] = copy("<No Ligatures>");
     117           0 :             where[0] = -1;
     118           0 :             choices[1] = NULL;
     119           0 :     break;
     120             :         }
     121           0 :     }
     122           0 :     choices[cnt] = NULL;
     123           0 :     i = gwwv_choose(_("Ligatures"),(const char **) choices,cnt,0,_("Select a ligature to view"));
     124           0 :     if ( i!=-1 && where[i]!=-1 )
     125           0 :         CharViewCreate(sf->glyphs[where[i]],(FontView *) sf->fv,-1);
     126           0 :     free(where);
     127           0 :     for ( i=0; i<cnt; ++i )
     128           0 :         free(choices[i]);
     129           0 :     free(choices);
     130           0 : }
     131             : 
     132             : struct kerns {
     133             :     SplineChar *first;
     134             :     SplineChar *second;
     135             :     int newoff, newyoff;
     136             :     unsigned int r2l: 1;
     137             :     KernPair *kp;
     138             :     AnchorClass *ac;
     139             : };
     140             : 
     141             : typedef struct kpdata {
     142             :     GWindow gw,v;
     143             :     int vwidth;
     144             :     SplineFont *sf;
     145             :     SplineChar *sc;             /* If set then restrict to kerns of this char */
     146             :                                 /*  in either position */
     147             :     AnchorClass *ac;            /* If set then don't do kerns, but look for */
     148             :                                 /*  anchor combos with this class. If -1 */
     149             :                                 /*  then all anchor combos with any class */
     150             :     struct kerns *kerns;        /* All the kerns we care about */
     151             :     int layer;
     152             :     int kcnt, firstcnt;
     153             :     BDFFont *bdf;
     154             :     int header_height;
     155             :     int sb_width;
     156             :     GFont *font;
     157             :     int fh, as;
     158             :     int uh, wh, off_top, selected, last_index, vpad;
     159             :     int pressed_x, old_val;
     160             :     unsigned int done:1;
     161             :     unsigned int first:1;
     162             :     unsigned int pressed:1;
     163             :     unsigned int movecursor:1;
     164             : } KPData;
     165             : 
     166             : #define CID_Size        1001
     167             : #define CID_SortBy      1002
     168             : #define CID_ScrollBar   1003
     169             : #define CID_OK          1004
     170             : #define CID_Cancel      1005
     171             : 
     172           0 : static int firstcmpr(const void *_k1, const void *_k2) {
     173           0 :     const struct kerns *k1 = _k1, *k2 = _k2;
     174             : 
     175           0 :     if ( k1->first==k2->first )           /* If same first char, use second char as tie breaker */
     176           0 : return( k1->second->unicodeenc-k2->second->unicodeenc );
     177             : 
     178           0 : return( k1->first->unicodeenc-k2->first->unicodeenc );
     179             : }
     180             : 
     181           0 : static int secondcmpr(const void *_k1, const void *_k2) {
     182           0 :     const struct kerns *k1 = _k1, *k2 = _k2;
     183             : 
     184           0 :     if ( k1->second==k2->second )         /* If same second char, use first char as tie breaker */
     185           0 : return( k1->first->unicodeenc-k2->first->unicodeenc );
     186             : 
     187           0 : return( k1->second->unicodeenc-k2->second->unicodeenc );
     188             : }
     189             : 
     190           0 : static int offcmpr(const void *_k1, const void *_k2) {
     191           0 :     const struct kerns *k1 = _k1, *k2 = _k2;
     192             :     int off1, off2;
     193             : 
     194           0 :     if ( (off1=k1->newoff)<0 ) off1 = -off1;
     195           0 :     if ( (off2=k2->newoff)<0 ) off2 = -off2;
     196             : 
     197           0 :     if ( off1!=off2 )           /* If same offset, use first char as tie breaker */
     198           0 : return( off1-off2 );
     199             : 
     200           0 :     if ( k1->first!=k2->first )           /* If same first char, use second char as tie breaker */
     201           0 : return( k1->first->unicodeenc-k2->first->unicodeenc );
     202             : 
     203           0 : return( k1->second->unicodeenc-k2->second->unicodeenc );
     204             : }
     205             : 
     206           0 : static void KPSortEm(KPData *kpd,enum sortby sort_func) {
     207             :     int oldenc;
     208             : 
     209           0 :     if ( sort_func==sb_first || sort_func==sb_second ) {
     210           0 :         if ( kpd->sc!=NULL ) {
     211           0 :             oldenc = kpd->sc->unicodeenc;
     212           0 :             kpd->sc->unicodeenc = -1;
     213             :         }
     214           0 :         qsort(kpd->kerns,kpd->kcnt,sizeof(struct kerns),
     215             :                 sort_func==sb_first ? firstcmpr : secondcmpr );
     216           0 :         if ( kpd->sc!=NULL )
     217           0 :             kpd->sc->unicodeenc = oldenc;
     218             :     } else
     219           0 :         qsort(kpd->kerns,kpd->kcnt,sizeof(struct kerns), offcmpr );
     220             : 
     221           0 :     if ( sort_func==sb_first ) {
     222           0 :         int cnt=1, i;
     223           0 :         for ( i=1; i<kpd->kcnt; ++i ) {
     224           0 :             if ( kpd->kerns[i].first!=kpd->kerns[i-1].first )
     225           0 :                 ++cnt;
     226             :         }
     227           0 :         kpd->firstcnt = cnt;
     228             :     }
     229           0 : }
     230             : 
     231           0 : static void CheckLeftRight(struct kerns *k) {
     232             :     /* flag any hebrew/arabic entries */
     233             : 
     234             :     /* Figure that there won't be any mixed orientation kerns (no latin "A" with hebrew "Alef" kern) */
     235             :     /*  but there might be some hebrew/arabic ligatures or something that */
     236             :     /*  we don't recognize as right-to-left (ie. not in unicode) */
     237           0 :     if ( SCRightToLeft(k->first) || SCRightToLeft(k->second) )
     238           0 :         k->r2l = true;
     239             :     else 
     240           0 :         k->r2l = false;
     241           0 : }
     242             : 
     243           0 : static void KPBuildKernList(KPData *kpd) {
     244             :     int i, cnt;
     245             :     KernPair *kp;
     246             : 
     247           0 :     if ( kpd->sc!=NULL ) {
     248             :         while ( 1 ) {
     249           0 :             for ( cnt=0, kp=kpd->sc->kerns; kp!=NULL; kp=kp->next ) {
     250           0 :                 if ( kpd->kerns!=NULL ) {
     251           0 :                     kpd->kerns[cnt].first = kpd->sc;
     252           0 :                     kpd->kerns[cnt].second = kp->sc;
     253           0 :                     kpd->kerns[cnt].newoff = kp->off;
     254           0 :                     kpd->kerns[cnt].newyoff = 0;
     255           0 :                     kpd->kerns[cnt].kp = kp;
     256           0 :                     kpd->kerns[cnt].ac = NULL;
     257           0 :                     CheckLeftRight(&kpd->kerns[cnt]);
     258             :                 }
     259           0 :                 ++cnt;
     260             :             }
     261           0 :             for ( i=0; i<kpd->sf->glyphcnt; ++i ) if ( kpd->sf->glyphs[i]!=NULL ) {
     262           0 :                 for ( kp = kpd->sf->glyphs[i]->kerns; kp!=NULL; kp=kp->next ) {
     263           0 :                     if ( kp->sc == kpd->sc ) {
     264           0 :                         if ( kpd->kerns!=NULL ) {
     265           0 :                             kpd->kerns[cnt].first = kpd->sf->glyphs[i];
     266           0 :                             kpd->kerns[cnt].second = kp->sc;
     267           0 :                             kpd->kerns[cnt].newoff = kp->off;
     268           0 :                             kpd->kerns[cnt].newyoff = 0;
     269           0 :                             kpd->kerns[cnt].kp = kp;
     270           0 :                             kpd->kerns[cnt].ac = NULL;
     271           0 :                             CheckLeftRight(&kpd->kerns[cnt]);
     272             :                         }
     273           0 :                         ++cnt;
     274           0 :                 break;
     275             :                     }
     276             :                 }
     277             :             }
     278           0 :             if ( kpd->kerns!=NULL )
     279           0 :         break;
     280           0 :             if ( cnt==0 )
     281           0 : return;
     282           0 :             kpd->kerns = calloc(cnt+1, sizeof(struct kerns));
     283           0 :             kpd->kcnt = cnt;
     284           0 :         }
     285             :     } else {
     286             :         while ( 1 ) {
     287           0 :             for ( cnt=i=0; i<kpd->sf->glyphcnt; ++i ) if ( kpd->sf->glyphs[i]!=NULL ) {
     288           0 :                 for ( kp = kpd->sf->glyphs[i]->kerns; kp!=NULL; kp=kp->next ) {
     289           0 :                     if ( kpd->kerns!=NULL ) {
     290           0 :                         kpd->kerns[cnt].first = kpd->sf->glyphs[i];
     291           0 :                         kpd->kerns[cnt].second = kp->sc;
     292           0 :                         kpd->kerns[cnt].newoff = kp->off;
     293           0 :                         kpd->kerns[cnt].newyoff = 0;
     294           0 :                         kpd->kerns[cnt].kp = kp;
     295           0 :                         kpd->kerns[cnt].ac = NULL;
     296           0 :                         CheckLeftRight(&kpd->kerns[cnt]);
     297             :                     }
     298           0 :                     ++cnt;
     299             :                 }
     300             :             }
     301           0 :             if ( kpd->kerns!=NULL )
     302           0 :         break;
     303           0 :             if ( cnt==0 )
     304           0 : return;
     305           0 :             kpd->kerns = calloc(cnt+1, sizeof(struct kerns));
     306           0 :             kpd->kcnt = cnt;
     307           0 :         }
     308             :     }
     309           0 :     KPSortEm(kpd,sb_first);
     310             : }
     311             : 
     312           0 : static void AnchorRefigure(KPData *kpd) {
     313             :     AnchorPoint *ap1, *ap2;
     314             :     DBounds bb;
     315             :     int i;
     316             : 
     317           0 :     for ( i=0; i<kpd->kcnt; ++i ) {
     318           0 :         struct kerns *k= &kpd->kerns[i];
     319           0 :         for ( ap1=k->first->anchor; ap1!=NULL && ap1->anchor!=k->ac; ap1=ap1->next );
     320           0 :         for ( ap2=k->second->anchor; ap2!=NULL && ap2->anchor!=k->ac; ap2=ap2->next );
     321           0 :         if ( ap1!=NULL && ap2!=NULL ) {
     322           0 :             if ( k->r2l ) {
     323           0 :                 SplineCharQuickBounds(k->second,&bb);
     324           0 :                 k->newoff = k->second->width-ap1->me.x + ap2->me.x;
     325             :             } else
     326           0 :                 k->newoff = -k->first->width+ap1->me.x-ap2->me.x;
     327           0 :             k->newyoff = ap1->me.y-ap2->me.y;
     328             :         }
     329             :     }
     330           0 : }
     331             : 
     332           0 : static void KPBuildAnchorList(KPData *kpd) {
     333             :     int i, j, cnt;
     334             :     AnchorClass *ac;
     335             :     AnchorPoint *ap1, *ap2, *temp;
     336           0 :     SplineFont *sf = kpd->sf;
     337             :     DBounds bb;
     338             : 
     339           0 :     if ( kpd->sc!=NULL ) {
     340             :         while ( 1 ) {
     341           0 :             cnt = 0;
     342           0 :             for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL ) {
     343           0 :                 if ( (ac = AnchorClassMatch(kpd->sc,sf->glyphs[i],kpd->ac,&ap1,&ap2)) ||
     344           0 :                         (ac = AnchorClassMatch(sf->glyphs[i],kpd->sc,kpd->ac,&ap1,&ap2)) ) {
     345           0 :                     if ( kpd->kerns!=NULL ) {
     346           0 :                         struct kerns *k = &kpd->kerns[cnt];
     347           0 :                         switch ( ap1->type ) {
     348             :                           case at_cexit: case at_basechar: case at_baselig: case at_basemark:
     349           0 :                             k->first = kpd->sc;
     350           0 :                             k->second = sf->glyphs[i];
     351           0 :                           break;
     352             :                           case at_centry: case at_mark:
     353           0 :                             k->first = sf->glyphs[i];
     354           0 :                             k->second = kpd->sc;
     355           0 :                             temp = ap1; ap1=ap2; ap2=temp;
     356           0 :                           break;
     357             :                         }
     358           0 :                         CheckLeftRight(k);
     359           0 :                         if ( k->r2l ) {
     360           0 :                             SplineCharQuickBounds(k->second,&bb);
     361           0 :                             k->newoff = k->second->width-ap1->me.x + ap2->me.x;
     362             :                         } else
     363           0 :                             k->newoff = -k->first->width+ap1->me.x-ap2->me.x;
     364           0 :                         k->newyoff = ap1->me.y-ap2->me.y;
     365           0 :                         k->ac = ac;
     366           0 :                         k->kp = NULL;
     367             :                     }
     368           0 :                     ++cnt;
     369             :                 }
     370             :             }
     371           0 :             if ( kpd->kerns!=NULL )
     372           0 :         break;
     373           0 :             if ( cnt==0 )
     374           0 : return;
     375           0 :             kpd->kerns = malloc((cnt+1)*sizeof(struct kerns));
     376           0 :             kpd->kcnt = cnt;
     377           0 :         }
     378             :     } else {
     379             :         while ( 1 ) {
     380           0 :             cnt = 0;
     381           0 :             for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL && sf->glyphs[i]->anchor ) {
     382           0 :                 if ( kpd->ac!=(AnchorClass *) -1 ) {
     383           0 :                     for ( temp = sf->glyphs[i]->anchor; temp!=NULL && temp->anchor!=kpd->ac; temp=temp->next );
     384           0 :                     if ( temp==NULL )
     385           0 :             continue;
     386             :                 }
     387           0 :                 for ( j=0; j<sf->glyphcnt; ++j ) if ( sf->glyphs[j]!=NULL ) {
     388           0 :                     if ( (ac = AnchorClassMatch(sf->glyphs[i],sf->glyphs[j],kpd->ac,&ap1,&ap2)) ) {
     389           0 :                         if ( kpd->kerns!=NULL ) {
     390           0 :                             struct kerns *k = &kpd->kerns[cnt];
     391           0 :                             k->first = sf->glyphs[i];
     392           0 :                             k->second = sf->glyphs[j];
     393           0 :                             CheckLeftRight(k);
     394           0 :                             if ( k->r2l ) {
     395           0 :                                 SplineCharQuickBounds(k->second,&bb);
     396           0 :                                 k->newoff = k->second->width-ap1->me.x + ap2->me.x;
     397             :                             } else
     398           0 :                                 k->newoff = -k->first->width+ap1->me.x-ap2->me.x;
     399           0 :                             k->newyoff = ap1->me.y-ap2->me.y;
     400           0 :                             k->ac = ac;
     401           0 :                             k->kp = NULL;
     402             :                         }
     403           0 :                         ++cnt;
     404             :                     }
     405             :                 }
     406             :             }
     407           0 :             if ( kpd->kerns!=NULL )
     408           0 :         break;
     409           0 :             if ( cnt==0 )
     410           0 : return;
     411           0 :             kpd->kerns = malloc((cnt+1)*sizeof(struct kerns));
     412           0 :             kpd->kcnt = cnt;
     413           0 :         }
     414             :     }
     415           0 :     KPSortEm(kpd,sb_first);
     416           0 :     AnchorRefigure(kpd);
     417             : }
     418             : 
     419           0 : static void KPScrollTo(KPData *kpd, unichar_t uch, enum sortby sort) {
     420             :     int i;
     421             : 
     422           0 :     if ( sort==sb_first ) {
     423           0 :         for ( i=0; i<kpd->kcnt && kpd->kerns[i].first->unicodeenc<uch; ++i );
     424             :     } else {
     425           0 :         for ( i=0; i<kpd->kcnt && kpd->kerns[i].second->unicodeenc<uch; ++i );
     426             :     }
     427           0 :     if ( kpd->wh<=2 )
     428             :         /* As is */;
     429           0 :     else if ( kpd->wh<5 )
     430           0 :         --i;
     431             :     else
     432           0 :         i -= kpd->wh/5;
     433             : 
     434           0 :     if ( i>kpd->kcnt-kpd->wh )
     435           0 :         i = kpd->kcnt-kpd->wh;
     436           0 :     if ( i<0 )
     437           0 :         i = 0;
     438           0 :     if ( i!=kpd->off_top ) {
     439           0 :         int off = i-kpd->off_top;
     440           0 :         kpd->off_top = i;
     441           0 :         GScrollBarSetPos(GWidgetGetControl(kpd->gw,CID_ScrollBar),kpd->off_top);
     442           0 :         GDrawScroll(kpd->v,NULL,0,off*kpd->uh);
     443             :     }
     444           0 : }
     445             : 
     446           0 : static void BaseFillFromBDFC(struct _GImage *base,BDFChar *bdfc) {
     447           0 :     base->data = bdfc->bitmap;
     448           0 :     base->bytes_per_line = bdfc->bytes_per_line;
     449           0 :     base->width = bdfc->xmax-bdfc->xmin+1;
     450           0 :     base->height = bdfc->ymax-bdfc->ymin+1;
     451           0 : }
     452             : 
     453           0 : static void KP_ExposeKerns(KPData *kpd,GWindow pixmap,GRect *rect) {
     454             :     GRect old, subclip, subold, sel;
     455             :     struct _GImage base;
     456             :     GImage gi;
     457             :     int index1, index2;
     458             :     BDFChar *bdfc1, *bdfc2;
     459           0 :     int i, as, x, em = kpd->sf->ascent+kpd->sf->descent, yoff;
     460             :     int first, last;
     461             :     struct kerns *kern;
     462             :     char buffer[140];
     463             : 
     464           0 :     first = rect->y/kpd->uh;
     465           0 :     last = (rect->y+rect->height+kpd->uh-1)/kpd->uh;
     466             : 
     467           0 :     for ( i=first; i<=last && i+kpd->off_top<kpd->kcnt; ++i ) {
     468           0 :         kern = &kpd->kerns[i+kpd->off_top];
     469           0 :         index1 = kern->first->orig_pos;
     470           0 :         if ( kpd->bdf->glyphs[index1]==NULL )
     471           0 :             BDFPieceMeal(kpd->bdf,index1);
     472           0 :         index2 = kern->second->orig_pos;
     473           0 :         if ( kpd->bdf->glyphs[index2]==NULL )
     474           0 :             BDFPieceMeal(kpd->bdf,index2);
     475             :     }
     476             : 
     477           0 :     as = kpd->vpad + kpd->sf->ascent * kpd->bdf->pixelsize / em;
     478             : 
     479           0 :     memset(&gi,'\0',sizeof(gi));
     480           0 :     memset(&base,'\0',sizeof(base));
     481           0 :     gi.u.image = &base;
     482           0 :     base.image_type = it_index;
     483           0 :     base.clut = kpd->bdf->clut;
     484           0 :     GDrawSetDither(NULL, false);
     485             : 
     486           0 :     GDrawPushClip(pixmap,rect,&old);
     487           0 :     GDrawSetFont(pixmap,kpd->font);
     488           0 :     GDrawSetLineWidth(pixmap,0);
     489           0 :     GDrawFillRect(pixmap,rect,GDrawGetDefaultBackground(NULL));
     490           0 :     subclip = *rect;
     491           0 :     for ( i=first; i<=last && i+kpd->off_top<kpd->kcnt; ++i ) {
     492           0 :         subclip.y = i*kpd->uh; subclip.height = kpd->uh;
     493           0 :         GDrawPushClip(pixmap,&subclip,&subold);
     494             : 
     495           0 :         kern = &kpd->kerns[i+kpd->off_top];
     496           0 :         index1 = kern->first->orig_pos;
     497           0 :         index2 = kern->second->orig_pos;
     498           0 :         bdfc1 = kpd->bdf->glyphs[index1];
     499           0 :         bdfc2 = kpd->bdf->glyphs[index2];
     500             : 
     501           0 :         BaseFillFromBDFC(&base,bdfc1);
     502           0 :         base.trans = base.clut->trans_index = -1;
     503             :         /* the peculiar behavior concerning xmin/xmax is because the bitmaps */
     504             :         /*  don't contain the side-bearings, we have to add that spacing manually */
     505           0 :         if ( !kern->r2l ) {
     506           0 :             GDrawDrawImage(pixmap,&gi,NULL, 10,subclip.y+as-bdfc1->ymax);
     507           0 :             x = 10 + (bdfc1->width-bdfc1->xmin) + bdfc2->xmin +
     508           0 :                     (kern->newoff*kpd->bdf->pixelsize/em);
     509             :         } else {
     510           0 :             x = kpd->vwidth-10-(bdfc1->xmax-bdfc1->xmin);
     511           0 :             GDrawDrawImage(pixmap,&gi,NULL, x,subclip.y+as-bdfc1->ymax);
     512           0 :             x -= bdfc1->xmin + (bdfc2->width-bdfc2->xmin) +
     513           0 :                     (kern->newoff*kpd->bdf->pixelsize/em);
     514             :         }
     515           0 :         BaseFillFromBDFC(&base,bdfc2);
     516             : #ifndef _BrokenBitmapImages
     517           0 :         base.trans = base.clut->trans_index = 0;
     518             : #endif
     519           0 :         yoff = (kern->newyoff*kpd->bdf->pixelsize/em);
     520           0 :         GDrawDrawImage(pixmap,&gi,NULL, x,subclip.y+as-bdfc2->ymax-yoff);
     521           0 :         GDrawDrawLine(pixmap,0,subclip.y+kpd->uh-1,
     522           0 :                 subclip.x+subclip.width,subclip.y+kpd->uh-1,0x000000);
     523           0 :         if ( kern->kp!=NULL )
     524           0 :             sprintf( buffer, "%d ", kern->newoff);
     525             :         else
     526           0 :             sprintf( buffer, "%d,%d ", kern->newoff, kern->newyoff );
     527           0 :         if ( kern->ac!=NULL )
     528           0 :             strncat(buffer,kern->ac->name,sizeof(buffer)-strlen(buffer)-1);
     529           0 :         GDrawDrawText8(pixmap,15,subclip.y+kpd->uh-kpd->fh+kpd->as,buffer,-1,
     530           0 :                 kern->kp!=NULL && kern->newoff!=kern->kp->off ? 0xff0000 : 0x000000 );
     531           0 :         if ( i+kpd->off_top==kpd->selected ) {
     532           0 :             sel.x = 0; sel.width = kpd->vwidth-1;
     533           0 :             sel.y = subclip.y; sel.height = kpd->uh-2;
     534           0 :             GDrawDrawRect(pixmap,&sel,0x000000);
     535             :         }
     536           0 :         GDrawPopClip(pixmap,&subold);
     537             :     }
     538             : #ifndef _BrokenBitmapImages
     539           0 :     base.clut->trans_index = -1;
     540             : #endif
     541           0 :     GDrawPopClip(pixmap,&old);
     542           0 :     GDrawSetDither(NULL, true);
     543           0 : }
     544             : 
     545           0 : static void KP_RefreshSel(KPData *kpd,int index) {
     546           0 :     Color col = index==kpd->selected ? 0x000000 : GDrawGetDefaultBackground(NULL);
     547             :     GRect sel;
     548             : 
     549           0 :     if ( index==-1 )
     550           0 : return;
     551           0 :     sel.x = 0; sel.width = kpd->vwidth-1;
     552           0 :     sel.y = (index-kpd->off_top)*kpd->uh; sel.height = kpd->uh-2;
     553           0 :     GDrawSetLineWidth(kpd->v,0);
     554           0 :     GDrawDrawRect(kpd->v,&sel,col);
     555             : }
     556             : 
     557           0 : static void KP_RefreshKP(KPData *kpd,int index) {
     558             :     GRect sel;
     559             : 
     560           0 :     if ( index<kpd->off_top || index>kpd->off_top+kpd->wh )
     561           0 : return;
     562           0 :     sel.x = 0; sel.width = kpd->vwidth;
     563           0 :     sel.y = (index-kpd->off_top)*kpd->uh; sel.height = kpd->uh;
     564           0 :     GDrawRequestExpose(kpd->v,&sel,false);
     565             : }
     566             : 
     567           0 : static void KP_KernClassAlter(KPData *kpd,int index) {
     568           0 :     KernPair *kp = kpd->kerns[index].kp;
     569             :     int kc_pos, kc_pos2;
     570           0 :     KernClass *kc = SFFindKernClass(kpd->sf,kpd->kerns[index].first,kpd->kerns[index].second,
     571             :             &kc_pos,false);
     572             :     int i;
     573             : 
     574           0 :     if ( kc==NULL )
     575           0 : return;
     576             : 
     577           0 :     for ( i=0; i<kpd->kcnt; ++i ) if ( i!=index &&
     578           0 :             kpd->kerns[i].kp->kcid==kp->kcid &&
     579           0 :             kpd->kerns[i].kp->off==kp->off ) {
     580           0 :         if ( SFFindKernClass(kpd->sf,kpd->kerns[i].first,kpd->kerns[i].second,
     581           0 :                 &kc_pos2,false)==kc && kc_pos==kc_pos2 ) {
     582           0 :             kpd->kerns[i].newoff = kpd->kerns[index].newoff;
     583           0 :             KP_RefreshKP(kpd,i);
     584             :         }
     585             :     }
     586             : }
     587             : 
     588           0 : static BDFChar *KP_Inside(KPData *kpd, GEvent *e) {
     589             :     struct kerns *kern;
     590             :     int index1, index2, i;
     591           0 :     int baseline, x, em = kpd->sf->ascent+kpd->sf->descent;
     592             :     BDFChar *bdfc1, *bdfc2;
     593             : 
     594           0 :     i = e->u.mouse.y/kpd->uh + kpd->off_top;
     595           0 :     if ( i>=kpd->kcnt )
     596           0 : return( NULL );
     597             : 
     598           0 :     kern = &kpd->kerns[i];
     599           0 :     index1 = kern->first->orig_pos;
     600           0 :     index2 = kern->second->orig_pos;
     601           0 :     bdfc1 = kpd->bdf->glyphs[index1];
     602           0 :     bdfc2 = kpd->bdf->glyphs[index2];
     603           0 :     if ( bdfc1 ==NULL || bdfc2==NULL )
     604           0 : return( NULL );
     605           0 :     if ( !kern->r2l )
     606           0 :         x = 10 + (bdfc1->width-bdfc1->xmin) + bdfc2->xmin +
     607           0 :                 (kpd->kerns[i].newoff*kpd->bdf->pixelsize/em);
     608             :     else
     609           0 :         x = kpd->vwidth-10- (bdfc1->xmax-bdfc1->xmin) - bdfc1->xmin -
     610           0 :                 (bdfc2->width-bdfc2->xmin) -
     611           0 :                 (kern->newoff*kpd->bdf->pixelsize/em);
     612           0 :     if ( e->u.mouse.x < x || e->u.mouse.x>= x+bdfc2->xmax-bdfc2->xmin )
     613           0 : return( NULL );
     614             : 
     615           0 :     baseline = (i-kpd->off_top)*kpd->uh + kpd->sf->ascent * kpd->bdf->pixelsize / em + kpd->vpad;
     616           0 :     if ( e->u.mouse.y < baseline-bdfc2->ymax || e->u.mouse.y >= baseline-bdfc2->ymin )
     617           0 : return( NULL );
     618             : 
     619           0 : return( bdfc2 );
     620             : }
     621             : 
     622           0 : static void KP_SetCursor(KPData *kpd, int ismove ) {
     623             : 
     624           0 :     if ( kpd->movecursor!=ismove ) {
     625           0 :         GDrawSetCursor(kpd->v,ismove ? ct_leftright : ct_mypointer );
     626           0 :         kpd->movecursor = ismove;
     627             :     }
     628           0 : }
     629             : 
     630           0 : static BDFChar *KP_Cursor(KPData *kpd, GEvent *e) {
     631           0 :     if ( kpd->ac==NULL ) {
     632           0 :         BDFChar *bdfc2 = KP_Inside(kpd,e);
     633             : 
     634           0 :         KP_SetCursor(kpd,bdfc2!=NULL );
     635           0 : return( bdfc2 );
     636             :     }
     637           0 : return( NULL );
     638             : }
     639             : 
     640           0 : static void KP_ScrollTo(KPData *kpd,int where) {
     641             :     /* Make sure the line "where" is visible */
     642             : 
     643           0 :     if ( where<kpd->off_top || where>=kpd->off_top+kpd->wh ) {
     644           0 :         where -= kpd->wh/4;
     645           0 :         if ( where>kpd->kcnt-kpd->wh )
     646           0 :             where = kpd->kcnt-kpd->wh;
     647           0 :         if ( where<0 ) where = 0;
     648           0 :         kpd->off_top = where;
     649           0 :         GScrollBarSetPos(GWidgetGetControl(kpd->gw,CID_ScrollBar),where);
     650           0 :         GDrawRequestExpose(kpd->v,NULL,false);
     651             :     }
     652           0 : }
     653             : 
     654           0 : static void KPRemove(KPData *kpd) {
     655           0 :     if ( kpd->selected!=-1 ) {
     656           0 :         kpd->kerns[kpd->selected].newoff = 0;
     657           0 :         GDrawRequestExpose(kpd->v,NULL,false);
     658             :     }
     659           0 : }
     660             : 
     661           0 : static void KP_Commands(KPData *kpd, GEvent *e) {
     662             :     int old_sel, amount;
     663             : 
     664           0 :     switch( e->u.chr.keysym ) {
     665             :       case '\177':
     666           0 :         KPRemove(kpd);
     667           0 :       break;
     668             :       case 'z': case 'Z':
     669           0 :         if ( e->u.chr.state&ksm_control ) {
     670           0 :             if ( kpd->last_index!=-1 ) {
     671           0 :                 kpd->kerns[kpd->last_index].newoff = kpd->old_val;
     672           0 :                 KP_RefreshKP(kpd,kpd->last_index);
     673           0 :                 if ( kpd->kerns[kpd->last_index].kp->kcid!=0 )
     674           0 :                     KP_KernClassAlter(kpd,kpd->last_index);
     675           0 :                 kpd->last_index = -1;
     676             :             }
     677           0 :         } else if ( e->u.chr.state&ksm_meta ) {
     678           0 :             if ( kpd->selected!=-1 ) {
     679           0 :                 kpd->kerns[kpd->selected].newoff = kpd->kerns[kpd->selected].kp->off;
     680           0 :                 KP_RefreshKP(kpd,kpd->selected);
     681           0 :                 if ( kpd->kerns[kpd->selected].kp->kcid!=0 )
     682           0 :                     KP_KernClassAlter(kpd,kpd->selected);
     683           0 :                 kpd->last_index = -1;
     684             :             }
     685             :         }
     686           0 :       break;
     687             :       case GK_Up: case GK_KP_Up:
     688           0 :         old_sel = kpd->selected;
     689           0 :         if ( kpd->selected<=0 )
     690           0 :             kpd->selected = kpd->kcnt-1;
     691             :         else
     692           0 :             --kpd->selected;
     693           0 :         KP_RefreshSel(kpd,old_sel);
     694           0 :         KP_RefreshSel(kpd,kpd->selected);
     695           0 :         KP_ScrollTo(kpd,kpd->selected);
     696           0 :       break;
     697             :       case GK_Down: case GK_KP_Down:
     698           0 :         old_sel = kpd->selected;
     699           0 :         if ( kpd->selected==-1 || kpd->selected==kpd->kcnt-1 )
     700           0 :             kpd->selected = 0;
     701             :         else
     702           0 :             ++kpd->selected;
     703           0 :         KP_RefreshSel(kpd,old_sel);
     704           0 :         KP_RefreshSel(kpd,kpd->selected);
     705           0 :         KP_ScrollTo(kpd,kpd->selected);
     706           0 :       break;
     707             :       case GK_Left: case GK_KP_Left: case GK_Right: case GK_KP_Right:
     708           0 :         amount = e->u.chr.keysym==GK_Left || e->u.chr.keysym==GK_KP_Left? -1 : 1;
     709           0 :         if ( e->u.chr.state&(ksm_shift|ksm_control|ksm_meta) ) amount *= 10;
     710           0 :         if ( kpd->selected!=-1 ) {
     711           0 :             KP_ScrollTo(kpd,kpd->selected);
     712           0 :             kpd->last_index = kpd->selected;
     713           0 :             kpd->old_val = kpd->kerns[kpd->selected].newoff;
     714           0 :             kpd->kerns[kpd->selected].newoff += amount;
     715           0 :             KP_RefreshKP(kpd,kpd->selected);
     716           0 :             if ( kpd->kerns[kpd->selected].kp->kcid!=0 )
     717           0 :                 KP_KernClassAlter(kpd,kpd->selected);
     718             :         }
     719           0 :       break;
     720             :     }
     721           0 : }
     722             : 
     723           0 : static void KPV_Resize(KPData *kpd) {
     724             :     GRect size;
     725             :     GGadget *sb;
     726             : 
     727           0 :     GDrawGetSize(kpd->v,&size);
     728           0 :     kpd->wh = size.height/kpd->uh;
     729             : 
     730           0 :     sb = GWidgetGetControl(kpd->gw,CID_ScrollBar);
     731           0 :     GScrollBarSetBounds(sb,0,kpd->kcnt,kpd->wh);
     732           0 :     if ( kpd->off_top>kpd->kcnt-kpd->wh )
     733           0 :         kpd->off_top = kpd->kcnt-kpd->wh;
     734           0 :     if ( kpd->off_top<0 )
     735           0 :         kpd->off_top = 0;
     736           0 :     GScrollBarSetPos(sb,kpd->off_top);
     737           0 :     kpd->vwidth = size.width;
     738           0 :     GDrawRequestExpose(kpd->v,NULL,false);
     739           0 :     GDrawRequestExpose(kpd->gw,NULL,false);
     740           0 : }
     741             : 
     742           0 : static void KP_Resize(KPData *kpd) {
     743             : 
     744           0 :     kpd->uh = (4*kpd->bdf->pixelsize/3)+kpd->fh+6;
     745           0 :     kpd->vpad = kpd->bdf->pixelsize/5 + 3;
     746           0 : }
     747             : 
     748           0 : static int KP_ChangeSize(GGadget *g, GEvent *e) {
     749           0 :     if ( e->type==et_controlevent && e->u.control.subtype == et_listselected ) {
     750           0 :         KPData *kpd = GDrawGetUserData(GGadgetGetWindow(g));
     751           0 :         int newsize = (intpt) (GGadgetGetListItemSelected(g)->userdata);
     752             :         BDFFont *temp;
     753           0 :         if ( newsize==kpd->bdf->pixelsize )
     754           0 : return( true );
     755           0 :         temp = SplineFontPieceMeal(kpd->sf,kpd->layer,newsize,72,true,NULL);
     756           0 :         BDFFontFree(kpd->bdf);
     757           0 :         kpd->bdf = temp;
     758           0 :         KP_Resize(kpd);
     759           0 :         KPV_Resize(kpd);
     760             :     }
     761           0 : return( true );
     762             : }
     763             : 
     764           0 : static int KP_ChangeSort(GGadget *g, GEvent *e) {
     765           0 :     if ( e->type==et_controlevent && e->u.control.subtype == et_listselected ) {
     766           0 :         KPData *kpd = GDrawGetUserData(GGadgetGetWindow(g));
     767           0 :         KernPair *old = kpd->selected==-1 ? NULL : kpd->kerns[kpd->selected].kp;
     768             :         int i;
     769             : 
     770           0 :         KPSortEm(kpd,GGadgetGetFirstListSelectedItem(g));
     771           0 :         for ( i=0 ; i<kpd->kcnt; ++i )
     772           0 :             if ( kpd->kerns[i].kp==old ) {
     773           0 :                 kpd->selected = i;
     774           0 :                 KP_ScrollTo(kpd,i);
     775           0 :         break;
     776             :             }
     777           0 :         GDrawRequestExpose(kpd->v,NULL,false);
     778             :     }
     779           0 : return( true );
     780             : }
     781             : 
     782           0 : static int KP_Scrolled(GGadget *g, GEvent *e) {
     783           0 :     if ( e->type==et_controlevent && e->u.control.subtype == et_scrollbarchange ) {
     784           0 :         KPData *kpd = GDrawGetUserData(GGadgetGetWindow(g));
     785           0 :         int newpos = kpd->off_top;
     786             : 
     787           0 :         switch( e->u.control.u.sb.type ) {
     788             :           case et_sb_top:
     789           0 :             newpos = 0;
     790           0 :           break;
     791             :           case et_sb_halfup:
     792             :           case et_sb_uppage:
     793           0 :             newpos -= kpd->wh==1?1:kpd->wh-1;
     794           0 :           break;
     795             :           case et_sb_up:
     796           0 :             newpos -= 1;
     797           0 :           break;
     798             :           case et_sb_halfdown:
     799             :           case et_sb_down:
     800           0 :             newpos += 1;
     801           0 :           break;
     802             :           case et_sb_downpage:
     803           0 :             newpos += kpd->wh==1?1:kpd->wh-1;
     804           0 :           break;
     805             :           case et_sb_bottom:
     806           0 :             newpos = kpd->kcnt-kpd->wh;
     807           0 :           break;
     808             :           case et_sb_thumb:
     809             :           case et_sb_thumbrelease:
     810           0 :             newpos = e->u.control.u.sb.pos;
     811           0 :           break;
     812             :         }
     813           0 :         if ( newpos>kpd->kcnt-kpd->wh )
     814           0 :             newpos = kpd->kcnt-kpd->wh;
     815           0 :         if ( newpos<0 )
     816           0 :             newpos = 0;
     817           0 :         if ( newpos!=kpd->off_top ) {
     818           0 :             int off = newpos-kpd->off_top;
     819           0 :             kpd->off_top = newpos;
     820           0 :             GScrollBarSetPos(g,kpd->off_top);
     821           0 :             GDrawScroll(kpd->v,NULL,0,off*kpd->uh);
     822             :         }
     823             :     }
     824           0 : return( true );
     825             : }
     826             : 
     827           0 : static int KP_OK(GGadget *g, GEvent *e) {
     828           0 :     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
     829           0 :         KPData *kpd = GDrawGetUserData(GGadgetGetWindow(g));
     830             :         int i;
     831             :         FontView *fv; MetricsView *mv;
     832             : 
     833           0 :         for ( i=0; i<kpd->kcnt; ++i ) if ( kpd->kerns[i].kp!=NULL )
     834           0 :             if ( kpd->kerns[i].newoff != kpd->kerns[i].kp->off ) {
     835           0 :                 kpd->kerns[i].kp->off = kpd->kerns[i].newoff;
     836           0 :                 kpd->sf->changed = true;
     837           0 :                 for ( fv=(FontView *) kpd->sf->fv; fv!=NULL; fv = (FontView *) (fv->b.nextsame) ) {
     838           0 :                     for ( mv=fv->b.sf->metrics; mv!=NULL; mv=mv->next )
     839           0 :                         MVRefreshChar(mv,kpd->kerns[i].first);
     840             :                 }
     841             :             }
     842           0 :         kpd->done = true;
     843             :     }
     844           0 : return( true );
     845             : }
     846             : 
     847           0 : static int KP_Cancel(GGadget *g, GEvent *e) {
     848           0 :     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
     849           0 :         KPData *kpd = GDrawGetUserData(GGadgetGetWindow(g));
     850           0 :         kpd->done = true;
     851             :     }
     852           0 : return( true );
     853             : }
     854             : 
     855           0 : static void KPMenuRemove(GWindow gw,struct gmenuitem *mi,GEvent *e) {
     856           0 :     KPData *kpd = GDrawGetUserData(gw);
     857           0 :     KPRemove(kpd);
     858           0 : }
     859             : 
     860           0 : static void KPKPCloseup(KPData *kpd) {
     861           0 :     if ( kpd->selected!=-1 ) {
     862           0 :         struct kerns *k = &kpd->kerns[kpd->selected];
     863           0 :         int oldoff = k->kp->off;
     864           0 :         k->kp->off = k->newoff;
     865           0 :         KernPairD(k->first->parent,k->first,k->second,kpd->layer,false);
     866           0 :         k->newoff = k->kp->off;
     867           0 :         k->kp->off = oldoff;
     868           0 :         GDrawRequestExpose(kpd->v,NULL,false);
     869           0 :         kpd->selected = -1;
     870             :     }
     871           0 : }
     872             : 
     873           0 : static void KPAC(KPData *kpd, int base) {
     874           0 :     if ( kpd->selected!=-1 ) {
     875           0 :         struct kerns *k = &kpd->kerns[kpd->selected];
     876           0 :         SplineChar *sc = base ? k->first : k->second;
     877             :         AnchorPoint *ap;
     878           0 :         for ( ap=sc->anchor; ap!=NULL && ap->anchor!=k->ac; ap=ap->next );
     879           0 :         if ( ap!=NULL ) {
     880             :             /* There is currently no way to modify anchors in this dlg */
     881             :             /* so the anchor will be right. On the other hand we might */
     882             :             /* need to reinit all other combinations which use this point */
     883           0 :             AnchorControl(sc,ap,kpd->layer);
     884           0 :             AnchorRefigure(kpd);
     885           0 :             GDrawRequestExpose(kpd->v,NULL,false);
     886             :         }
     887             :     }
     888           0 : }
     889             : 
     890           0 : static void KPMenuKPCloseup(GWindow gw,struct gmenuitem *mi,GEvent *e) {
     891           0 :     KPData *kpd = GDrawGetUserData(gw);
     892           0 :     KPKPCloseup(kpd);
     893           0 : }
     894             : 
     895           0 : static void KPMenuACB(GWindow gw,struct gmenuitem *mi,GEvent *e) {
     896           0 :     KPData *kpd = GDrawGetUserData(gw);
     897           0 :     KPAC(kpd,true);
     898           0 : }
     899             : 
     900           0 : static void KPMenuACM(GWindow gw,struct gmenuitem *mi,GEvent *e) {
     901           0 :     KPData *kpd = GDrawGetUserData(gw);
     902           0 :     KPAC(kpd,false);
     903           0 : }
     904             : 
     905             : static GMenuItem kernmenu[] = {
     906             :     { { (unichar_t *) N_("C_lear"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, 'N' }, '\177', 0, NULL, NULL, KPMenuRemove, 0 },
     907             :     { { (unichar_t *) N_("Kern Pair Closeup"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, 'N' }, '\0', 0, NULL, NULL, KPMenuKPCloseup, 0 },
     908             :     GMENUITEM_EMPTY
     909             : };
     910             : 
     911             : static GMenuItem acmenu[] = {
     912             :     { { (unichar_t *) N_("Anchor Control for Base"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, 'N' }, '\0', 0, NULL, NULL, KPMenuACB, 0 },
     913             :     { { (unichar_t *) N_("Anchor Control for Mark"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, 'N' }, '\0', 0, NULL, NULL, KPMenuACM, 0 },
     914             :     GMENUITEM_EMPTY
     915             : };
     916             : 
     917             : static unichar_t upopupbuf[100];
     918             : 
     919           0 : static int kpdv_e_h(GWindow gw, GEvent *event) {
     920           0 :     KPData *kpd = GDrawGetUserData(gw);
     921             :     int index, old_sel, temp;
     922             :     char buffer[100];
     923             :     static int done=false;
     924             : 
     925           0 :     switch ( event->type ) {
     926             :       case et_expose:
     927           0 :         KP_ExposeKerns(kpd,gw,&event->u.expose.rect);
     928           0 :       break;
     929             :       case et_char:
     930           0 :         if ( event->u.chr.keysym == GK_F1 || event->u.chr.keysym == GK_Help ) {
     931           0 :             help("kernpairs.html");
     932           0 : return( true );
     933             :         }
     934           0 :         KP_Commands(kpd,event);
     935           0 :       break;
     936             :       case et_mousedown:
     937           0 :         GGadgetEndPopup();
     938           0 :         kpd->pressed = true;
     939           0 :         index = kpd->off_top + event->u.mouse.y/kpd->uh;
     940           0 :         if ( index>=kpd->kcnt )
     941           0 :             index = -1;
     942           0 :         if ( index!=kpd->selected ) {
     943           0 :             old_sel = kpd->selected;
     944           0 :             kpd->selected = index;
     945           0 :             KP_RefreshSel(kpd,old_sel);
     946           0 :             KP_RefreshSel(kpd,index);
     947             :         }
     948           0 :         if ( event->u.mouse.button==3 && index>=0 ) {
     949           0 :             if ( !done ) {
     950             :                 int i;
     951           0 :                 for ( i=0; kernmenu[i].ti.text!=NULL || kernmenu[i].ti.line; ++i )
     952           0 :                     if ( kernmenu[i].ti.text!=NULL )
     953           0 :                         kernmenu[i].ti.text = (unichar_t *) _((char *) kernmenu[i].ti.text);
     954           0 :                 for ( i=0; acmenu[i].ti.text!=NULL || acmenu[i].ti.line; ++i )
     955           0 :                     if ( acmenu[i].ti.text!=NULL )
     956           0 :                         acmenu[i].ti.text = (unichar_t *) _((char *) acmenu[i].ti.text);
     957           0 :                 done = true;
     958             :             }
     959           0 :             if ( kpd->ac==NULL )
     960           0 :                 GMenuCreatePopupMenu(gw,event, kernmenu);
     961             :             else
     962           0 :                 GMenuCreatePopupMenu(gw,event, acmenu);
     963           0 :         } else if ( KP_Cursor(kpd,event)!=NULL ) {
     964           0 :             kpd->pressed_x = event->u.mouse.x;
     965           0 :             kpd->old_val = kpd->kerns[index].newoff;
     966             :         } else
     967           0 :             kpd->pressed_x = -1;
     968           0 :       break;
     969             :       case et_mouseup:
     970           0 :         if ( kpd->pressed_x!=-1 )
     971           0 :             kpd->last_index = kpd->selected;
     972             :         else
     973           0 :             kpd->last_index = -1;
     974           0 :         if ( kpd->selected>=0 && event->u.mouse.clicks>1 ) {
     975           0 :             if ( kpd->ac==NULL )
     976           0 :                 KPKPCloseup(kpd);
     977             :             else
     978           0 :                 KPAC(kpd,true);
     979           0 : return( true );
     980             :         }
     981             :       /* Fall through... */
     982             :       case et_mousemove:
     983           0 :         GGadgetEndPopup();
     984           0 :         index = kpd->off_top + event->u.mouse.y/kpd->uh;
     985           0 :         if ( !kpd->pressed && index<kpd->kcnt ) {
     986           0 :             sprintf( buffer, "%.20s %d U+%04x",
     987           0 :                     kpd->kerns[index].first->name,
     988           0 :                     kpd->kerns[index].first->orig_pos,
     989           0 :                     kpd->kerns[index].first->unicodeenc );
     990           0 :             if ( kpd->kerns[index].first->unicodeenc==-1 )
     991           0 :                 strcpy(buffer+strlen(buffer)-4, "????");
     992           0 :             sprintf( buffer+strlen(buffer), " + %.20s %d U+%04x",
     993           0 :                     kpd->kerns[index].second->name,
     994           0 :                     kpd->kerns[index].second->orig_pos,
     995           0 :                     kpd->kerns[index].second->unicodeenc );
     996           0 :             if ( kpd->kerns[index].second->unicodeenc==-1 )
     997           0 :                 strcpy(buffer+strlen(buffer)-4, "????");
     998           0 :             uc_strcpy(upopupbuf,buffer);
     999           0 :             GGadgetPreparePopup(gw,upopupbuf);
    1000           0 :             KP_Cursor(kpd,event);
    1001           0 :         } else if ( kpd->pressed && kpd->pressed_x!=-1 ) {
    1002           0 :             if ( kpd->ac!=NULL ) {
    1003             :                 /* Nothing to be done. That's what I find so wonderful. Happy Days */
    1004           0 :             } else if ( index==kpd->selected ) {
    1005           0 :                 KP_SetCursor(kpd,true);
    1006           0 :                 temp = kpd->old_val + (event->u.mouse.x-kpd->pressed_x)*(kpd->sf->ascent+kpd->sf->descent)/kpd->bdf->pixelsize;
    1007           0 :                 if ( temp!=kpd->kerns[index].newoff ) {
    1008           0 :                     kpd->kerns[index].newoff = temp;
    1009           0 :                     KP_RefreshKP(kpd,index);
    1010             :                 }
    1011             :             } else {
    1012           0 :                 if ( kpd->movecursor ) {
    1013           0 :                     kpd->kerns[kpd->selected].newoff = kpd->old_val;
    1014           0 :                     KP_SetCursor(kpd,false);
    1015           0 :                     KP_RefreshKP(kpd,kpd->selected);
    1016             :                 }
    1017             :             }
    1018           0 :             if ( kpd->ac==NULL && kpd->kerns[index].kp->kcid!=0 && event->type==et_mouseup )
    1019           0 :                 KP_KernClassAlter(kpd,index);
    1020             :         }
    1021           0 :         if ( event->type==et_mouseup )
    1022           0 :             kpd->pressed = false;
    1023           0 :       break;
    1024             :       case et_resize:
    1025           0 :         KPV_Resize(kpd);
    1026           0 :       break;
    1027             :     }
    1028           0 : return( true );
    1029             : }
    1030             : 
    1031           0 : static void kpdpopup(KPData *kpd) {
    1032             :     char buffer[100];
    1033             : 
    1034           0 :     if ( kpd->ac==NULL ) {
    1035           0 :         sprintf( buffer, "total kern pairs=%d\nchars starting kerns=%d",
    1036             :                 kpd->kcnt, kpd->firstcnt );
    1037             :     } else {
    1038           0 :         sprintf( buffer, "total anchored pairs=%d\nbase char cnt=%d",
    1039             :                 kpd->kcnt, kpd->firstcnt );
    1040             :     }
    1041           0 :     uc_strcpy(upopupbuf,buffer);
    1042           0 :     GGadgetPreparePopup(kpd->gw,upopupbuf);
    1043           0 : }
    1044             : 
    1045           0 : static int kpd_e_h(GWindow gw, GEvent *event) {
    1046           0 :     if ( event->type==et_close ) {
    1047           0 :         KPData *kpd = GDrawGetUserData(gw);
    1048           0 :         kpd->done = true;
    1049           0 :     } else if ( event->type == et_mousemove ) {
    1050           0 :         kpdpopup(GDrawGetUserData(gw));
    1051           0 :     } else if ( event->type == et_expose ) {
    1052           0 :         KPData *kpd = GDrawGetUserData(gw);
    1053             :         GRect size, sbsize;
    1054           0 :         GDrawGetSize(kpd->v,&size);
    1055           0 :         GGadgetGetSize(GWidgetGetControl(kpd->gw,CID_ScrollBar),&sbsize);
    1056           0 :         GDrawSetLineWidth(gw,0);
    1057           0 :         GDrawDrawLine(gw,size.x,size.y-1,sbsize.x+sbsize.width-1,size.y-1,0x000000);
    1058           0 :         GDrawDrawLine(gw,size.x,size.y+size.height,sbsize.x+sbsize.width-1,size.y+size.height,0x000000);
    1059           0 :         GDrawDrawLine(gw,size.x-1,size.y-1,size.x-1,size.y+size.height,0x000000);
    1060           0 :     } else if ( event->type == et_char ) {
    1061           0 :         if ( event->u.chr.keysym == GK_F1 || event->u.chr.keysym == GK_Help ) {
    1062           0 :             help("kernpairs.html");
    1063           0 : return( true );
    1064             :         }
    1065           0 :         if ( event->u.chr.chars[0]!='\0' && event->u.chr.chars[1]=='\0' ) {
    1066           0 :             enum sortby sort = GGadgetGetFirstListSelectedItem(GWidgetGetControl(gw,CID_SortBy));
    1067           0 :             KPData *kpd = GDrawGetUserData(gw);
    1068           0 :             if ( sort!=sb_kern ) {
    1069           0 :                 KPScrollTo(kpd,event->u.chr.chars[0],sort);
    1070           0 : return( true );
    1071             :             } else
    1072           0 :                 GDrawBeep(NULL);
    1073             :         }
    1074           0 : return( false );
    1075           0 :     } else if ( event->type == et_resize && event->u.resize.sized ) {
    1076           0 :         KP_Resize((KPData *) GDrawGetUserData(gw) );
    1077             :     }
    1078           0 : return( true );
    1079             : }
    1080             : 
    1081           0 : void SFShowKernPairs(SplineFont *sf,SplineChar *sc,AnchorClass *ac,int layer) {
    1082             :     KPData kpd;
    1083             :     GRect pos;
    1084             :     GWindow gw;
    1085             :     GWindowAttrs wattrs;
    1086             :     GGadgetCreateData gcd[9], boxes[6], *hvarray[3][3], *harray[3], *barray[10], *varray[5];
    1087             :     GTextInfo label[9];
    1088             :     FontRequest rq;
    1089             :     int as, ds, ld,i;
    1090             :     static int done=false;
    1091             :     static GFont *font=NULL;
    1092             : 
    1093           0 :     memset(&kpd,0,sizeof(kpd));
    1094           0 :     kpd.sf = sf;
    1095           0 :     kpd.sc = sc;
    1096           0 :     kpd.ac = ac;
    1097           0 :     kpd.layer = layer;
    1098           0 :     kpd.first = true;
    1099           0 :     kpd.last_index = kpd.selected = -1;
    1100           0 :     if ( ac==NULL )
    1101           0 :         KPBuildKernList(&kpd);
    1102             :     else
    1103           0 :         KPBuildAnchorList(&kpd);
    1104           0 :     if ( kpd.kcnt==0 )
    1105           0 : return;
    1106             : 
    1107           0 :     memset(&wattrs,0,sizeof(wattrs));
    1108           0 :     wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_undercursor|wam_isdlg|wam_restrict;
    1109           0 :     wattrs.event_masks = ~(1<<et_charup);
    1110           0 :     wattrs.restrict_input_to_me = 1;
    1111           0 :     wattrs.undercursor = 1;
    1112           0 :     wattrs.cursor = ct_pointer;
    1113           0 :     wattrs.utf8_window_title = ac==NULL?_("Kern Pairs"):_("Anchored Pairs");
    1114           0 :     wattrs.is_dlg = true;
    1115           0 :     pos.x = pos.y = 0;
    1116           0 :     pos.width = GGadgetScale(200);
    1117           0 :     pos.height = GDrawPointsToPixels(NULL,500);
    1118           0 :     kpd.gw = gw = GDrawCreateTopWindow(NULL,&pos,kpd_e_h,&kpd,&wattrs);
    1119             : 
    1120           0 :     memset(&label,0,sizeof(label));
    1121           0 :     memset(&gcd,0,sizeof(gcd));
    1122           0 :     memset(&boxes,0,sizeof(boxes));
    1123             : 
    1124           0 :     label[0].text = (unichar_t *) _("_Size:");
    1125           0 :     label[0].text_is_1byte = true;
    1126           0 :     label[0].text_in_resource = true;
    1127           0 :     gcd[0].gd.label = &label[0];
    1128           0 :     gcd[0].gd.pos.x = 5; gcd[0].gd.pos.y = 5+6;
    1129           0 :     gcd[0].gd.flags = gg_enabled|gg_visible;
    1130           0 :     gcd[0].creator = GLabelCreate;
    1131           0 :     hvarray[0][0] = &gcd[0];
    1132             : 
    1133           0 :     gcd[1].gd.label = &sizes[1];  gcd[1].gd.label->selected = true;
    1134           0 :     gcd[1].gd.pos.x = 50; gcd[1].gd.pos.y = 5;
    1135           0 :     gcd[1].gd.flags = gg_enabled|gg_visible;
    1136           0 :     gcd[1].gd.cid = CID_Size;
    1137           0 :     gcd[1].gd.u.list = sizes;
    1138           0 :     gcd[1].gd.handle_controlevent = KP_ChangeSize;
    1139           0 :     gcd[1].creator = GListButtonCreate;
    1140           0 :     hvarray[0][1] = &gcd[1]; hvarray[0][2] = NULL;
    1141             : 
    1142           0 :     label[2].text = (unichar_t *) _("Sort By:");
    1143           0 :     label[2].text_is_1byte = true;
    1144           0 :     gcd[2].gd.label = &label[2];
    1145           0 :     gcd[2].gd.pos.x = gcd[0].gd.pos.x; gcd[2].gd.pos.y = gcd[0].gd.pos.y+25;
    1146           0 :     gcd[2].gd.flags = gg_enabled|gg_visible;
    1147           0 :     gcd[2].creator = GLabelCreate;
    1148           0 :     hvarray[1][0] = &gcd[2];
    1149             : 
    1150           0 :     if ( !done ) {
    1151           0 :         done = true;
    1152           0 :         for ( i=0; sortby[i].text!=NULL; ++i )
    1153           0 :             sortby[i].text = (unichar_t *) _((char *) sortby[i].text);
    1154             :     }
    1155             : 
    1156           0 :     gcd[3].gd.label = &sortby[0]; gcd[3].gd.label->selected = true;
    1157           0 :     gcd[3].gd.pos.x = 50; gcd[3].gd.pos.y = gcd[1].gd.pos.y+25;
    1158           0 :     gcd[3].gd.flags = gg_enabled|gg_visible;
    1159           0 :     gcd[3].gd.cid = CID_SortBy;
    1160           0 :     gcd[3].gd.u.list = sortby;
    1161           0 :     gcd[3].gd.handle_controlevent = KP_ChangeSort;
    1162           0 :     gcd[3].creator = GListButtonCreate;
    1163           0 :     hvarray[1][1] = &gcd[3]; hvarray[1][2] = NULL; hvarray[2][0] = NULL;
    1164             : 
    1165           0 :     boxes[2].gd.flags = gg_enabled|gg_visible;
    1166           0 :     boxes[2].gd.u.boxelements = hvarray[0];
    1167           0 :     boxes[2].creator = GHVBoxCreate;
    1168           0 :     varray[0] = &boxes[2];
    1169             : 
    1170           0 :     gcd[4].gd.pos.width = 40;
    1171           0 :     gcd[4].gd.pos.height = 250;
    1172           0 :     gcd[4].gd.flags = gg_visible | gg_enabled;
    1173           0 :     gcd[4].gd.u.drawable_e_h = kpdv_e_h;
    1174           0 :     gcd[4].creator = GDrawableCreate;
    1175             : 
    1176           0 :     gcd[5].gd.flags = gg_enabled|gg_visible|gg_sb_vert;
    1177           0 :     gcd[5].gd.cid = CID_ScrollBar;
    1178           0 :     gcd[5].gd.handle_controlevent = KP_Scrolled;
    1179           0 :     gcd[5].creator = GScrollBarCreate;
    1180           0 :     harray[0] = &gcd[4]; harray[1] = &gcd[5]; harray[2] = NULL;
    1181             : 
    1182           0 :     boxes[3].gd.flags = gg_enabled|gg_visible;
    1183           0 :     boxes[3].gd.u.boxelements = harray;
    1184           0 :     boxes[3].creator = GHBoxCreate;
    1185           0 :     varray[1] = &boxes[3];
    1186             : 
    1187           0 :     gcd[6].gd.pos.x = 20-3; gcd[6].gd.pos.y = 17+37;
    1188           0 :     gcd[6].gd.pos.width = -1; gcd[6].gd.pos.height = 0;
    1189           0 :     gcd[6].gd.flags = gg_visible | gg_enabled | gg_but_default;
    1190           0 :     label[6].text = (unichar_t *) _("_OK");
    1191           0 :     label[6].text_is_1byte = true;
    1192           0 :     label[6].text_in_resource = true;
    1193           0 :     gcd[6].gd.label = &label[6];
    1194           0 :     gcd[6].gd.cid = CID_OK;
    1195           0 :     gcd[6].gd.handle_controlevent = KP_OK;
    1196           0 :     gcd[6].creator = GButtonCreate;
    1197             : 
    1198           0 :     gcd[7].gd.pos.x = -20; gcd[7].gd.pos.y = gcd[6].gd.pos.y+3;
    1199           0 :     gcd[7].gd.pos.width = -1; gcd[7].gd.pos.height = 0;
    1200           0 :     gcd[7].gd.flags = gg_visible | gg_enabled | gg_but_cancel;
    1201           0 :     label[7].text = (unichar_t *) _("_Cancel");
    1202           0 :     label[7].text_is_1byte = true;
    1203           0 :     label[7].text_in_resource = true;
    1204           0 :     gcd[7].gd.label = &label[7];
    1205           0 :     gcd[7].gd.cid = CID_Cancel;
    1206           0 :     gcd[7].gd.handle_controlevent = KP_Cancel;
    1207           0 :     gcd[7].creator = GButtonCreate;
    1208           0 :     barray[0] = GCD_Glue; barray[1] = &gcd[6]; barray[2] = GCD_Glue;
    1209           0 :     barray[3] = GCD_Glue; barray[4] = &gcd[7]; barray[5] = GCD_Glue; barray[6] = NULL;
    1210             : 
    1211           0 :     boxes[4].gd.flags = gg_enabled|gg_visible;
    1212           0 :     boxes[4].gd.u.boxelements = barray;
    1213           0 :     boxes[4].creator = GHBoxCreate;
    1214           0 :     varray[2] = &boxes[4];
    1215           0 :     varray[3] = NULL;
    1216             : 
    1217           0 :     boxes[0].gd.flags = gg_enabled|gg_visible;
    1218           0 :     boxes[0].gd.u.boxelements = varray;
    1219           0 :     boxes[0].creator = GVBoxCreate;
    1220             : 
    1221             : 
    1222           0 :     GGadgetsCreate(gw,boxes);
    1223             : 
    1224           0 :     GHVBoxSetExpandableRow(boxes[0].ret,1);
    1225           0 :     GHVBoxSetExpandableCol(boxes[3].ret,0);
    1226           0 :     GHVBoxSetExpandableCol(boxes[4].ret,gb_expandgluesame);
    1227           0 :     GHVBoxSetPadding(boxes[0].ret,0,2);
    1228           0 :     GHVBoxSetPadding(boxes[3].ret,0,0);
    1229           0 :     kpd.v = GDrawableGetWindow(gcd[4].ret);;
    1230             : 
    1231           0 :     GGadgetGetSize(gcd[4].ret,&pos);
    1232           0 :     kpd.sb_width = pos.width;
    1233           0 :     GGadgetGetSize(gcd[3].ret,&pos);
    1234           0 :     kpd.header_height = pos.y+pos.height+4;
    1235             : 
    1236           0 :     kpd.bdf = SplineFontPieceMeal(kpd.sf,kpd.layer,(intpt) (gcd[1].gd.label->userdata),72,true,NULL);
    1237             : 
    1238           0 :     if ( font==NULL ) {
    1239           0 :         memset(&rq,'\0',sizeof(rq));
    1240           0 :         rq.utf8_family_name = SANS_UI_FAMILIES;
    1241           0 :         rq.point_size = -12;
    1242           0 :         rq.weight = 400;
    1243           0 :         font = GDrawInstanciateFont(gw,&rq);
    1244           0 :         font = GResourceFindFont("Combinations.Font",font);
    1245             :     }
    1246           0 :     kpd.font = font;
    1247           0 :     GDrawWindowFontMetrics(gw,kpd.font,&as,&ds,&ld);
    1248           0 :     kpd.fh = as+ds; kpd.as = as;
    1249             : 
    1250           0 :     kpd.uh = (4*kpd.bdf->pixelsize/3)+kpd.fh+6;
    1251           0 :     kpd.vpad = kpd.bdf->pixelsize/5 + 3;
    1252             : 
    1253           0 :     GHVBoxFitWindow(boxes[0].ret);
    1254             : 
    1255           0 :     GDrawSetVisible(kpd.v,true);
    1256           0 :     GDrawSetVisible(kpd.gw,true);
    1257           0 :     while ( !kpd.done )
    1258           0 :         GDrawProcessOneEvent(NULL);
    1259           0 :     free( kpd.kerns );
    1260           0 :     GDrawDestroyWindow(gw);
    1261             : }

Generated by: LCOV version 1.10