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