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