1 /* Copyright (C) 2007-2012 by George Williams */
2 /*
3  * Redistribution and use in source and binary forms, with or without
4  * modification, are permitted provided that the following conditions are met:
5 
6  * Redistributions of source code must retain the above copyright notice, this
7  * list of conditions and the following disclaimer.
8 
9  * Redistributions in binary form must reproduce the above copyright notice,
10  * this list of conditions and the following disclaimer in the documentation
11  * and/or other materials provided with the distribution.
12 
13  * The name of the author may not be used to endorse or promote products
14  * derived from this software without specific prior written permission.
15 
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include <fontforge-config.h>
29 
30 #include "fontforgeui.h"
31 #include "fvfonts.h"
32 #include "gkeysym.h"
33 #include "mathconstants.h"
34 #include "splineutil.h"
35 #include "ustring.h"
36 #include "utype.h"
37 
38 #include <math.h>
39 #include <stddef.h>
40 
41 extern struct math_constants_descriptor math_constants_descriptor[];
42 
43 static char *aspectnames[] = {
44     N_("Constants"),
45     N_("Sub/Superscript"),
46     N_("Limits"),
47     N_("Stacks"),
48     N_("Fractions"),
49     N_("Over/Underbars"),
50     N_("Radicals"),
51     N_("Connectors"),
52     NULL
53 };
54 
55 static char *GlyphConstruction_Dlg(GGadget *g, int r, int c);
56 static char *MKChange_Dlg(GGadget *g, int r, int c);
57 static void extpart_finishedit(GGadget *g, int r, int c, int wasnew);
58 static void italic_finishedit(GGadget *g, int r, int c, int wasnew);
59 static void topaccent_finishedit(GGadget *g, int r, int c, int wasnew);
60 static void mathkern_initrow(GGadget *g, int r);
61 
62 static GTextInfo truefalse[] = {
63     { (unichar_t *) N_("false"), NULL, 0, 0, (void *) 0, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0' },
64     { (unichar_t *) N_("true"),  NULL, 0, 0, (void *) 1, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0' },
65     GTEXTINFO_EMPTY
66 };
67 
68 static struct col_init exten_shape_ci[] = {
69     { me_string, NULL, NULL, NULL, N_("Glyph") },
70     { me_enum, NULL, truefalse, NULL, N_("Is Extended Shape") },
71     COL_INIT_EMPTY
72 };
73 
74 static struct col_init italic_cor_ci[] = {
75     { me_string, NULL, NULL, NULL, N_("Glyph") },
76     { me_int, NULL, NULL, NULL, N_("Italic Correction") },
77     { me_funcedit, DevTab_Dlg, NULL, NULL, N_("Adjust") },
78     COL_INIT_EMPTY
79 };
80 
81 static struct col_init top_accent_ci[] = {
82     { me_string, NULL, NULL, NULL, N_("Glyph") },
83     { me_int, NULL, NULL, NULL, N_("Top Accent Horiz. Pos") },
84     { me_funcedit, DevTab_Dlg, NULL, NULL, N_("Adjust") },
85     COL_INIT_EMPTY
86 };
87 
88 static struct col_init glyph_variants_ci[] = {
89     { me_string, NULL, NULL, NULL, N_("Glyph") },
90     { me_string, NULL, NULL, NULL, N_("Pre-Built Larger Variants") },
91     COL_INIT_EMPTY
92 };
93 
94 static struct col_init glyph_construction_ci[] = {
95     { me_string, NULL, NULL, NULL, N_("Glyph") },
96 /* GT: Italic correction */
97     { me_int, NULL, NULL, NULL, N_("I.C.") },
98     { me_funcedit, DevTab_Dlg, NULL, NULL, N_("Adjust") },
99     { me_funcedit, GlyphConstruction_Dlg, NULL, NULL, N_("Parts List") },
100     COL_INIT_EMPTY
101 };
102 
103 static struct col_init math_kern_ci[] = {
104     { me_string, NULL, NULL, NULL, N_("Glyph") },
105     { me_button, MKChange_Dlg, NULL, NULL, N_("Height/Kern Data") },
106     COL_INIT_EMPTY
107 };
108 
109 struct matrixinit mis[] = {
110     { sizeof(exten_shape_ci)/sizeof(struct col_init)-1, exten_shape_ci, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
111     { sizeof(italic_cor_ci)/sizeof(struct col_init)-1, italic_cor_ci, 0, NULL, NULL, NULL, italic_finishedit, NULL, NULL, NULL },
112     { sizeof(top_accent_ci)/sizeof(struct col_init)-1, top_accent_ci, 0, NULL, NULL, NULL, topaccent_finishedit, NULL, NULL, NULL },
113     { sizeof(math_kern_ci)/sizeof(struct col_init)-1, math_kern_ci, 0, NULL, mathkern_initrow, NULL, NULL, NULL, NULL, NULL },
114     { sizeof(glyph_variants_ci)/sizeof(struct col_init)-1, glyph_variants_ci, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
115     { sizeof(glyph_construction_ci)/sizeof(struct col_init)-1, glyph_construction_ci, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
116     { sizeof(glyph_variants_ci)/sizeof(struct col_init)-1, glyph_variants_ci, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
117     { sizeof(glyph_construction_ci)/sizeof(struct col_init)-1, glyph_construction_ci, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
118     MATRIXINIT_EMPTY
119 };
120 
121 static struct col_init extensionpart[] = {
122     { me_string , NULL, NULL, NULL, N_("Glyph") },
123     { me_enum, NULL, truefalse, NULL, N_("Extender") },
124 /* GT: "Len" is an abreviation for "Length" */
125     { me_int, NULL, NULL, NULL, N_("StartLen") },
126     { me_int, NULL, NULL, NULL, N_("EndLen") },
127     { me_int, NULL, NULL, NULL, N_("FullLen") },
128     COL_INIT_EMPTY
129 };
130 static struct matrixinit mi_extensionpart =
131     { sizeof(extensionpart)/sizeof(struct col_init)-1, extensionpart, 0, NULL, NULL, NULL, extpart_finishedit, NULL, NULL, NULL };
132 
133 static struct col_init mathkern[] = {
134     { me_int , NULL, NULL, NULL, N_("Height") },
135     { me_int, NULL, NULL, NULL, N_("Kern") },
136     { me_funcedit, DevTab_Dlg, NULL, NULL, N_("Height Adjusts") },
137     { me_funcedit, DevTab_Dlg, NULL, NULL, N_("Kern Adjusts") },
138     COL_INIT_EMPTY
139 };
140 static struct matrixinit mi_mathkern =
141     { sizeof(mathkern)/sizeof(struct col_init)-1, mathkern, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
142 
143 
144 #define CID_Exten	1000
145 #define CID_Italic	1001
146 #define CID_TopAccent	1002
147 #define CID_MathKern	1003
148 #define CID_VGlyphVar	1004
149 #define CID_VGlyphConst	1005
150 #define CID_HGlyphVar	1006
151 #define CID_HGlyphConst	1007
152 
153 static char *gi_aspectnames[] = {
154     N_("Exten Shapes"),
155     N_("Italic Correction"),
156     N_("Top Accent"),
157     N_("Math Kern"),
158     N_("Vert. Variants"),
159     N_("Vert. Construction"),
160     N_("Hor. Variants"),
161     N_("Hor. Construction"),
162     NULL
163 };
164 
165 static char *cornernames[] = {
166     N_("Top Right"),
167     N_("Top Left"),
168     N_("Bottom Right"),
169     N_("Bottom Left"),
170     NULL
171 };
172 
MathInit(void)173 void MathInit(void) {
174     int i, j;
175     static int inited = false;
176     static struct col_init *ci[] = { exten_shape_ci, italic_cor_ci,
177 	    top_accent_ci, glyph_variants_ci, glyph_construction_ci,
178 	    extensionpart, math_kern_ci, mathkern, NULL };
179     static GTextInfo *tis[] = { truefalse, NULL };
180     static char **chars[] = { aspectnames, gi_aspectnames, cornernames, NULL };
181 
182     if ( inited )
183 return;
184 
185     for ( j=0; chars[j]!=NULL; ++j )
186 	for ( i=0; chars[j][i]!=NULL; ++i )
187 	    chars[j][i] = _(chars[j][i]);
188     for ( i=0; math_constants_descriptor[i].ui_name!=NULL; ++i ) {
189 	math_constants_descriptor[i].ui_name=_(math_constants_descriptor[i].ui_name);
190 	if ( math_constants_descriptor[i].message != NULL )
191 	    math_constants_descriptor[i].message=_(math_constants_descriptor[i].message);
192     }
193 
194     for ( j=0; tis[j]!=NULL; ++j )
195 	for ( i=0; tis[j][i].text!=NULL; ++i )
196 	    tis[j][i].text = (unichar_t *) _((char *) tis[j][i].text);
197     for ( j=0; ci[j]!=NULL; ++j )
198 	for ( i=0; ci[j][i].title!=NULL; ++i )
199 	    ci[j][i].title = _(ci[j][i].title);
200 
201     inited = true;
202 }
203 
GV_StringCheck(SplineFont * sf,char * str)204 static int GV_StringCheck(SplineFont *sf,char *str) {
205     char *start, *pt;
206     int scnt, pcnt, ch;
207     SplineChar *sc;
208 
209     pcnt = 0;
210     for ( start = str ; ; ) {
211 	while ( *start==' ' ) ++start;
212 	if ( *start=='\0' )
213 return( pcnt );
214 	for ( pt=start; *pt!=':' && *pt!=' ' && *pt!='\0' ; ++pt );
215 	ch = *pt;
216 	if ( ch==' ' || ch=='\0' )
217 return( -1 );
218 	if ( sf!=NULL ) {
219 	    *pt = '\0';
220 	    sc = SFGetChar(sf,-1,start);
221 	    *pt = ch;
222 	    if ( sc==NULL )
223 return( -1 );
224 	}
225 	scnt = 0;
226 	while ( *pt!=' ' && *pt!='\0' ) {
227 	    if ( *pt==':' ) ++scnt;
228 	    else if ( !isdigit( *pt ))
229 return( -1 );
230 	    ++pt;
231 	}
232 	if ( scnt!=4 )
233 return( -1 );
234 	++pcnt;
235 	start = pt;
236     }
237 }
238 
GV_FromString(struct glyphvariants * gv,char * str)239 static struct glyphvariants *GV_FromString(struct glyphvariants *gv,char *str) {
240     int pcnt = GV_StringCheck(NULL,str);
241     char *start, *pt;
242     int ch, temp;
243 
244     if ( pcnt<=0 )
245 return( gv );
246     if ( gv==NULL )
247 	gv = chunkalloc(sizeof(struct glyphvariants));
248     gv->part_cnt = pcnt;
249     gv->parts = calloc(pcnt,sizeof(struct gv_part));
250     pcnt = 0;
251     for ( start = str ; ; ) {
252 	while ( *start==' ' ) ++start;
253 	if ( *start=='\0' )
254 return( gv );
255 	for ( pt=start; *pt!=':' ; ++pt );
256 	ch = *pt; *pt = '\0';
257 	gv->parts[pcnt].component = copy(start);
258 	*pt = ch;
259 	sscanf(pt,":%d:%hd:%hd:%hd", &temp,
260 		&gv->parts[pcnt].startConnectorLength,
261 		&gv->parts[pcnt].endConnectorLength,
262 		&gv->parts[pcnt].fullAdvance);
263 	gv->parts[pcnt].is_extender = temp;
264 	while ( *pt!=' ' && *pt!='\0' ) ++pt;
265 	++pcnt;
266 	start = pt;
267     }
268 }
269 
GV_ToString(struct glyphvariants * gv)270 static char *GV_ToString(struct glyphvariants *gv) {
271     int i, len;
272     char buffer[80], *str;
273 
274     if ( gv==NULL || gv->part_cnt==0 )
275 return( NULL );
276     for ( i=len=0; i<gv->part_cnt; ++i ) {
277 	len += strlen(gv->parts[i].component);
278 	sprintf( buffer, ":%d:%d:%d:%d ", gv->parts[i].is_extender,
279 		gv->parts[i].startConnectorLength,
280 		gv->parts[i].endConnectorLength,
281 		gv->parts[i].fullAdvance);
282 	len += strlen( buffer );
283     }
284     str = malloc(len+1);
285     for ( i=len=0; i<gv->part_cnt; ++i ) {
286 	strcpy(str+len,gv->parts[i].component);
287 	len += strlen(gv->parts[i].component);
288 	sprintf( buffer, ":%d:%d:%d:%d ", gv->parts[i].is_extender,
289 		gv->parts[i].startConnectorLength,
290 		gv->parts[i].endConnectorLength,
291 		gv->parts[i].fullAdvance);
292 	strcpy(str+len,buffer);
293 	len += strlen( buffer );
294     }
295     if ( len!=0 )
296 	str[len-1] = '\0';
297     else
298 	*str = '\0';
299 return( str );
300 }
301 
SF_NameListCheck(SplineFont * sf,char * list)302 static int SF_NameListCheck(SplineFont *sf,char *list) {
303     char *start, *pt;
304     int ch;
305     SplineChar *sc;
306 
307     if ( list==NULL )
308 return( true );
309 
310     for ( start = list ; ; ) {
311 	while ( *start== ' ' ) ++start;
312 	if ( *start=='\0' )
313 return( true );
314 	for ( pt=start ; *pt!=' ' && *pt!='\0' && *pt!='('; ++pt );
315 	ch = *pt; *pt = '\0';
316 	sc = SFGetChar(sf,-1,start);
317 	*pt = ch;
318 	if ( ch=='(' ) {
319 	    while ( *pt!=')' && *pt!='\0' ) ++pt;
320 	    if ( *pt==')' ) ++pt;
321 	}
322 	start = pt;
323 	if ( sc==NULL )
324 return( false );
325     }
326 }
327 
328 typedef struct mathdlg {
329     GWindow gw;
330     SplineFont *sf;
331     int def_layer;
332     struct MATH *math;
333     uint8 done;
334     uint8 ok;
335     uint16 popup_r;
336     GGadget *popup_g;
337     /* Used by glyphconstruction_dlg */
338     SplineChar *sc;
339     int is_horiz;
340 } MathDlg;
341 
MATH_GlyphNameCompletion(GGadget * t,int from_tab)342 static unichar_t **MATH_GlyphNameCompletion(GGadget *t,int from_tab) {
343     MathDlg *math = GDrawGetUserData(GDrawGetParentWindow(GGadgetGetWindow(t)));
344     SplineFont *sf = math->sf;
345 
346 return( SFGlyphNameCompletion(sf,t,from_tab,false));
347 }
348 
MATH_GlyphListCompletion(GGadget * t,int from_tab)349 static unichar_t **MATH_GlyphListCompletion(GGadget *t,int from_tab) {
350     MathDlg *math = GDrawGetUserData(GDrawGetParentWindow(GGadgetGetWindow(t)));
351     SplineFont *sf = math->sf;
352 
353 return( SFGlyphNameCompletion(sf,t,from_tab,true));
354 }
355 
MATH_Init(MathDlg * math)356 static void MATH_Init(MathDlg *math) {
357     int i, cnt, ccnt, ta, h;
358     char buffer[20];
359     GGadget *g;
360     struct matrix_data *mds;
361     SplineFont *sf = math->sf;
362     SplineChar *sc;
363     int cols;
364     char *change = _("Change");
365 
366     for ( i=0; math_constants_descriptor[i].ui_name!=NULL; ++i ) {
367 	GGadget *tf = GWidgetGetControl(math->gw,2*i+1);
368 	int16 *pos = (int16 *) (((char *) (math->math)) + math_constants_descriptor[i].offset );
369 
370 	sprintf( buffer, "%d", *pos );
371 	GGadgetSetTitle8(tf,buffer);
372 	if ( math_constants_descriptor[i].devtab_offset >= 0 ) {
373 	    GGadget *tf2 = GWidgetGetControl(math->gw,2*i+2);
374 	    DeviceTable **devtab = (DeviceTable **) (((char *) (math->math)) + math_constants_descriptor[i].devtab_offset );
375 	    char *str;
376 
377 	    DevTabToString(&str,*devtab);
378 	    if ( str!=NULL )
379 		GGadgetSetTitle8(tf2,str);
380 	    free(str);
381 	}
382     }
383 
384     /* Extension Shapes */
385     for ( i=cnt=0; i<sf->glyphcnt; ++i ) if ( (sc=sf->glyphs[i])!=NULL )
386 	if ( sc->is_extended_shape )
387 	    ++cnt;
388     mds = calloc(cnt*2,sizeof(struct matrix_data));
389     for ( i=cnt=0; i<sf->glyphcnt; ++i ) if ( (sc=sf->glyphs[i])!=NULL )
390 	if ( sc->is_extended_shape ) {
391 	    mds[2*cnt+0].u.md_str = copy(sc->name);
392 	    mds[2*cnt+1].u.md_ival = true;
393 	    ++cnt;
394 	}
395     GMatrixEditSet(GWidgetGetControl(math->gw,CID_Exten), mds,cnt,false);
396 
397     /* Italic Correction && Top Angle Horizontal Position */
398     for ( ta=0; ta<2; ++ta ) {
399 	g = GWidgetGetControl(math->gw,ta?CID_TopAccent:CID_Italic );
400 	cols = GMatrixEditGetColCnt(g);
401 	for ( i=cnt=0; i<sf->glyphcnt; ++i ) if ( (sc=sf->glyphs[i])!=NULL ) {
402 	    if ( (ta==0 && sc->italic_correction!=TEX_UNDEF ) ||
403 		    (ta==1 && sc->top_accent_horiz!=TEX_UNDEF))
404 		++cnt;
405 	}
406 	mds = calloc(cnt*cols,sizeof(struct matrix_data));
407 	for ( i=cnt=0; i<sf->glyphcnt; ++i ) if ( (sc=sf->glyphs[i])!=NULL ) {
408 	    if ( ta==0 && sc->italic_correction!=TEX_UNDEF ) {
409 		mds[cols*cnt+0].u.md_str = copy(sc->name);
410 		mds[cols*cnt+1].u.md_ival = sc->italic_correction;
411 		DevTabToString(&mds[cols*cnt+2].u.md_str,sc->italic_adjusts);
412 		++cnt;
413 	    } else if ( ta==1 &&sc->top_accent_horiz!=TEX_UNDEF ) {
414 		mds[cols*cnt+0].u.md_str = copy(sc->name);
415 		mds[cols*cnt+1].u.md_ival = sc->top_accent_horiz;
416 		DevTabToString(&mds[cols*cnt+2].u.md_str,sc->top_accent_adjusts);
417 		++cnt;
418 	    }
419 	}
420 	GMatrixEditSet(g, mds,cnt,false);
421     }
422 
423     /* Math Kern */
424     g = GWidgetGetControl(math->gw,CID_MathKern);
425     cols = GMatrixEditGetColCnt(g);
426     for ( i=cnt=0; i<sf->glyphcnt; ++i ) if ( (sc=sf->glyphs[i])!=NULL )
427 	if ( sc->mathkern!=NULL )
428 	    ++cnt;
429     mds = calloc(cnt*cols,sizeof(struct matrix_data));
430     for ( i=cnt=0; i<sf->glyphcnt; ++i ) if ( (sc=sf->glyphs[i])!=NULL )
431 	if ( sc->mathkern!=NULL ) {
432 	    mds[cols*cnt+0].u.md_str = copy(sc->name);
433 	    mds[cols*cnt+1].u.md_str = copy(change);
434 	    ++cnt;
435 	}
436     GMatrixEditSet(g, mds,cnt,false);
437 
438     /* Horizontal/Vertical Glyph Variants */
439     for ( h=0; h<2; ++h ) {
440 	g = GWidgetGetControl(math->gw,CID_VGlyphVar+2*h);
441 	cols = GMatrixEditGetColCnt(g);
442 	for ( i=cnt=ccnt=0; i<sf->glyphcnt; ++i ) if ( (sc=sf->glyphs[i])!=NULL ) {
443 	    struct glyphvariants *gv = h ? sc->horiz_variants : sc->vert_variants;
444 	    if ( gv!=NULL && gv->variants!=NULL )
445 		++cnt;
446 	    if ( gv!=NULL && gv->part_cnt!=0 )
447 		++ccnt;
448 	}
449 	mds = calloc(cnt*cols,sizeof(struct matrix_data));
450 	for ( i=cnt=0; i<sf->glyphcnt; ++i ) if ( (sc=sf->glyphs[i])!=NULL ) {
451 	    struct glyphvariants *gv = h ? sc->horiz_variants : sc->vert_variants;
452 	    if ( gv!=NULL && gv->variants!=NULL ) {
453 		mds[cols*cnt+0].u.md_str = SCNameUniStr(sc);
454 		mds[cols*cnt+1].u.md_str = SFNameList2NameUni(sf,gv->variants);
455 		++cnt;
456 	    }
457 	}
458 	GMatrixEditSet(g, mds,cnt,false);
459 
460 	/* Glyph Construction */
461 	g = GWidgetGetControl(math->gw,CID_VGlyphConst+2*h);
462 	cols = GMatrixEditGetColCnt(g);
463 	mds = calloc(ccnt*cols,sizeof(struct matrix_data));
464 	for ( i=cnt=0; i<sf->glyphcnt; ++i ) if ( (sc=sf->glyphs[i])!=NULL ) {
465 	    struct glyphvariants *gv = h ? sc->horiz_variants : sc->vert_variants;
466 	    if ( gv!=NULL && gv->part_cnt!=0 ) {
467 		mds[cols*cnt+0].u.md_str = copy(sc->name);
468 		mds[cols*cnt+1].u.md_ival = gv->italic_correction;
469 		DevTabToString(&mds[cols*cnt+2].u.md_str,gv->italic_adjusts);
470 		mds[cols*cnt+cols-1].u.md_str = GV_ToString(gv);
471 		++cnt;
472 	    }
473 	}
474 	GMatrixEditSet(g, mds,cnt,false);
475     }
476 }
477 
MATH_FreeImage(const void * _math,GImage * img)478 static void MATH_FreeImage(const void *_math, GImage *img) {
479     GImageDestroy(img);
480 }
481 
_MATHVar_GetImage(const void * _math)482 static GImage *_MATHVar_GetImage(const void *_math) {
483     MathDlg *math = (MathDlg *) _math;
484     GGadget *varlist = math->popup_g;
485     int rows, cols = GMatrixEditGetColCnt(varlist);
486     struct matrix_data *old = GMatrixEditGet(varlist,&rows);
487     SplineChar *sc = SFGetChar(math->sf,-1, old[cols*math->popup_r].u.md_str);
488     static OTLookup dummyl = OTLOOKUP_EMPTY;
489     static struct lookup_subtable dummys = LOOKUP_SUBTABLE_EMPTY;
490 
491     dummyl.lookup_type = gsub_multiple;
492     dummys.lookup = &dummyl;
493 return( PST_GetImage(varlist,math->sf,math->def_layer,&dummys,math->popup_r,sc) );
494 }
495 
MATHVar_PopupPrepare(GGadget * g,int r,int c)496 static void MATHVar_PopupPrepare(GGadget *g, int r, int c) {
497     MathDlg *math = GDrawGetUserData(GGadgetGetWindow(g));
498     int rows, cols = GMatrixEditGetColCnt(g);
499     struct matrix_data *old = GMatrixEditGet(g,&rows);
500 
501     if ( c<0 || c>=cols || r<0 || r>=rows || old[cols*r].u.md_str==NULL ||
502 	SFGetChar(math->sf,-1, old[cols*r+0].u.md_str)==NULL )
503 return;
504     math->popup_r = r;
505     math->popup_g = g;
506     GGadgetPreparePopupImage(GGadgetGetWindow(g),NULL,math,_MATHVar_GetImage,MATH_FreeImage);
507 }
508 
_MATHConst_GetImage(const void * _math)509 static GImage *_MATHConst_GetImage(const void *_math) {
510     MathDlg *math = (MathDlg *) _math;
511     GGadget *varlist = math->popup_g;
512     int rows, cols = GMatrixEditGetColCnt(varlist);
513     struct matrix_data *old = GMatrixEditGet(varlist,&rows);
514     SplineChar *sc = SFGetChar(math->sf,-1, old[cols*math->popup_r].u.md_str);
515     struct glyphvariants *gv = GV_FromString(NULL,old[cols*math->popup_r+cols-1].u.md_str);
516     GImage *ret;
517 
518     ret = GV_GetConstructedImage(sc,math->def_layer,gv,GGadgetGetCid(varlist)==CID_HGlyphConst);
519     GlyphVariantsFree(gv);
520 return( ret );
521 }
522 
MATHConst_PopupPrepare(GGadget * g,int r,int c)523 static void MATHConst_PopupPrepare(GGadget *g, int r, int c) {
524     MathDlg *math = GDrawGetUserData(GGadgetGetWindow(g));
525     int rows, cols = GMatrixEditGetColCnt(g);
526     struct matrix_data *old = GMatrixEditGet(g,&rows);
527 
528     if ( c<0 || c>=cols || r<0 || r>=rows || old[cols*r].u.md_str==NULL ||
529 	SFGetChar(math->sf,-1, old[cols*r+0].u.md_str)==NULL )
530 return;
531     math->popup_r = r;
532     math->popup_g = g;
533     GGadgetPreparePopupImage(GGadgetGetWindow(g),NULL,math,_MATHConst_GetImage,MATH_FreeImage);
534 }
535 
_MATHLine_GetImage(const void * _math)536 static GImage *_MATHLine_GetImage(const void *_math) {
537     MathDlg *math = (MathDlg *) _math;
538     GGadget *varlist = math->popup_g;
539     int rows, cols = GMatrixEditGetColCnt(varlist);
540     struct matrix_data *old = GMatrixEditGet(varlist,&rows);
541     SplineChar *sc = SFGetChar(math->sf,-1, old[cols*math->popup_r].u.md_str);
542 
543 return( SC_GetLinedImage(sc,math->def_layer,old[cols*math->popup_r+1].u.md_ival,GGadgetGetCid(varlist)==CID_Italic));
544 }
545 
MATHLine_PopupPrepare(GGadget * g,int r,int c)546 static void MATHLine_PopupPrepare(GGadget *g, int r, int c) {
547     MathDlg *math = GDrawGetUserData(GGadgetGetWindow(g));
548     int rows, cols = GMatrixEditGetColCnt(g);
549     struct matrix_data *old = GMatrixEditGet(g,&rows);
550 
551     if ( c<0 || c>=cols || r<0 || r>=rows || old[cols*r].u.md_str==NULL ||
552 	SFGetChar(math->sf,-1, old[cols*r+0].u.md_str)==NULL )
553 return;
554     math->popup_r = r;
555     math->popup_g = g;
556     GGadgetPreparePopupImage(GGadgetGetWindow(g),NULL,math,_MATHLine_GetImage,MATH_FreeImage);
557 }
558 
_GVC_GetImage(const void * _math)559 static GImage *_GVC_GetImage(const void *_math) {
560     MathDlg *math = (MathDlg *) _math;
561     GGadget *varlist = math->popup_g;
562     int rows, cols = GMatrixEditGetColCnt(varlist);
563     struct matrix_data *old = GMatrixEditGet(varlist,&rows);
564     GImage *ret;
565     struct glyphvariants *gv;
566 
567     gv = GV_ParseConstruction(NULL,old,rows,cols);
568     ret = GV_GetConstructedImage(math->sc,math->def_layer,gv,math->is_horiz);
569     GlyphVariantsFree(gv);
570 return( ret );
571 }
572 
italic_finishedit(GGadget * g,int r,int c,int wasnew)573 static void italic_finishedit(GGadget *g, int r, int c, int wasnew) {
574     int rows;
575     struct matrix_data *stuff;
576     MathDlg *math;
577     int cols;
578     DBounds b;
579     SplineChar *sc;
580 
581     if ( c!=0 )
582 return;
583     if ( !wasnew )
584 return;
585     /* If they added a new glyph to the sequence then set some defaults for it. */
586     /*  only the full advance has any likelyhood of being correct */
587     math = GDrawGetUserData(GGadgetGetWindow(g));
588     stuff = GMatrixEditGet(g, &rows);
589     cols = GMatrixEditGetColCnt(g);
590     if ( stuff[r*cols+0].u.md_str==NULL )
591 return;
592     sc = SFGetChar(math->sf,-1,stuff[r*cols+0].u.md_str);
593     if ( sc==NULL )
594 return;
595     SplineCharFindBounds(sc,&b);
596     if ( b.maxx>sc->width ) {
597 	stuff[r*cols+1].u.md_ival = rint((b.maxx-sc->width) +
598 			(math->sf->ascent+math->sf->descent)/16.0);
599 	GGadgetRedraw(g);
600     }
601 }
602 
topaccent_finishedit(GGadget * g,int r,int c,int wasnew)603 static void topaccent_finishedit(GGadget *g, int r, int c, int wasnew) {
604     int rows;
605     struct matrix_data *stuff;
606     MathDlg *math;
607     int cols;
608     DBounds b;
609     SplineChar *sc;
610     double italic_off;
611 
612     if ( c!=0 )
613 return;
614     if ( !wasnew )
615 return;
616     /* If they added a new glyph to the sequence then set some defaults for it. */
617     /*  only the full advance has any likelyhood of being correct */
618     math = GDrawGetUserData(GGadgetGetWindow(g));
619     stuff = GMatrixEditGet(g, &rows);
620     cols = GMatrixEditGetColCnt(g);
621     if ( stuff[r*cols+0].u.md_str==NULL )
622 return;
623     sc = SFGetChar(math->sf,-1,stuff[r*cols+0].u.md_str);
624     if ( sc==NULL )
625 return;
626     SplineCharFindBounds(sc,&b);
627     italic_off = (b.maxy-b.miny)*tan(-math->sf->italicangle);
628     if ( b.maxx-b.minx-italic_off < 0 )
629 	stuff[r*cols+1].u.md_ival = rint(b.minx + (b.maxx-b.minx)/2);
630     else
631 	stuff[r*cols+1].u.md_ival = rint(b.minx + italic_off + (b.maxx - b.minx - italic_off)/2);
632     GGadgetRedraw(g);
633 }
634 
mathkern_initrow(GGadget * g,int r)635 static void mathkern_initrow(GGadget *g, int r) {
636     int rows;
637     struct matrix_data *stuff;
638     int cols;
639 
640     cols = GMatrixEditGetColCnt(g);
641     stuff = GMatrixEditGet(g, &rows);
642     stuff[r*cols+1].u.md_str = copy(_("Change"));
643 };
644 
extpart_finishedit(GGadget * g,int r,int c,int wasnew)645 static void extpart_finishedit(GGadget *g, int r, int c, int wasnew) {
646     int rows;
647     struct matrix_data *stuff;
648     MathDlg *math;
649     int cols;
650     DBounds b;
651     double full_advance;
652     SplineChar *sc;
653 
654     if ( c!=0 )
655 return;
656     if ( !wasnew )
657 return;
658     /* If they added a new glyph to the sequence then set some defaults for it. */
659     /*  only the full advance has any likelyhood of being correct */
660     math = GDrawGetUserData(GGadgetGetWindow(g));
661     stuff = GMatrixEditGet(g, &rows);
662     cols = GMatrixEditGetColCnt(g);
663     if ( stuff[r*cols+0].u.md_str==NULL )
664 return;
665     sc = SFGetChar(math->sf,-1,stuff[r*cols+0].u.md_str);
666     if ( sc==NULL )
667 return;
668     SplineCharFindBounds(sc,&b);
669     if ( math->is_horiz )
670 	full_advance = b.maxx - b.minx;
671     else
672 	full_advance = b.maxy - b.miny;
673     stuff[r*cols+2].u.md_ival = stuff[r*cols+3].u.md_ival = rint(full_advance/3);
674     stuff[r*cols+4].u.md_ival = rint(full_advance);
675     GGadgetRedraw(g);
676 }
677 
GVC_PopupPrepare(GGadget * g,int r,int c)678 static void GVC_PopupPrepare(GGadget *g, int r, int c) {
679     MathDlg *math = GDrawGetUserData(GGadgetGetWindow(g));
680 
681     math->popup_g = g;
682     if ( math->sc==NULL )
683 return;
684     GGadgetPreparePopupImage(GGadgetGetWindow(g),NULL,math,_GVC_GetImage,MATH_FreeImage);
685 }
686 
GVC_OK(GGadget * g,GEvent * e)687 static int GVC_OK(GGadget *g, GEvent *e) {
688     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
689 	MathDlg *math = GDrawGetUserData(GGadgetGetWindow(g));
690 	math->done = true;
691 	math->ok = true;
692     }
693 return( true );
694 }
695 
MATH_Cancel(GGadget * g,GEvent * e)696 static int MATH_Cancel(GGadget *g, GEvent *e) {
697     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
698 	MathDlg *math = GDrawGetUserData(GGadgetGetWindow(g));
699 	math->done = true;
700     }
701 return( true );
702 }
703 
gc_e_h(GWindow gw,GEvent * event)704 static int gc_e_h(GWindow gw, GEvent *event) {
705     MathDlg *math = GDrawGetUserData(gw);
706 
707     if ( event->type==et_close ) {
708 	math->done = true;
709     } else if ( event->type==et_char ) {
710 	if ( event->u.chr.keysym == GK_F1 || event->u.chr.keysym == GK_Help ) {
711 	    help("ui/dialogs/math.html", "#math-glyphconstruction");
712 return( true );
713 	} else if ( GMenuIsCommand(event,H_("Quit|Ctl+Q") )) {
714 	    MenuExit(NULL,NULL,NULL);
715 	} else if ( GMenuIsCommand(event,H_("Close|Ctl+Shft+Q") )) {
716 	    math->done = true;
717 	}
718 return( false );
719     }
720 return( true );
721 }
722 
GlyphConstruction_Dlg(GGadget * g,int r,int c)723 static char *GlyphConstruction_Dlg(GGadget *g, int r, int c) {
724     MathDlg *math = GDrawGetUserData(GGadgetGetWindow(g));
725     MathDlg md;
726     GRect pos;
727     GWindow gw;
728     GWindowAttrs wattrs;
729     int rows, cols = GMatrixEditGetColCnt(g);
730     struct matrix_data *old = GMatrixEditGet(g,&rows);
731     GGadgetCreateData *harray[7], mgcd[4], *varray[6], mboxes[3];
732     GTextInfo mlabel[3];
733     struct glyphvariants *gv;
734     char *ret;
735 
736     memset(&md,0,sizeof(md));
737     md.sf = math->sf;
738     md.is_horiz = GGadgetGetCid(g)==CID_HGlyphConst;
739     md.sc = SFGetChar(md.sf,-1,old[r*cols+0].u.md_str);
740 
741     memset(&wattrs,0,sizeof(wattrs));
742     wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_undercursor|wam_restrict|wam_isdlg;
743     wattrs.event_masks = ~(1<<et_charup);
744     wattrs.restrict_input_to_me = 1;
745     wattrs.is_dlg = 1;
746     wattrs.undercursor = 1;
747     wattrs.cursor = ct_pointer;
748     wattrs.utf8_window_title = _("Glyph Construction");
749     pos.x = pos.y = 0;
750     pos.width = 100;
751     pos.height = 100;
752     md.gw = gw = GDrawCreateTopWindow(NULL,&pos,gc_e_h,&md,&wattrs);
753 
754     memset(mgcd,0,sizeof(mgcd));
755     memset(mlabel,0,sizeof(mlabel));
756     memset(mboxes,0,sizeof(mboxes));
757 
758     mgcd[0].gd.flags = gg_visible | gg_enabled;
759     mgcd[0].gd.u.matrix = &mi_extensionpart;
760     mgcd[0].gd.cid = CID_VGlyphConst;
761     mgcd[0].creator = GMatrixEditCreate;
762 
763     mgcd[1].gd.flags = gg_visible | gg_enabled | gg_but_default;
764     mlabel[1].text = (unichar_t *) _("_OK");
765     mlabel[1].text_is_1byte = true;
766     mlabel[1].text_in_resource = true;
767     mgcd[1].gd.label = &mlabel[1];
768     mgcd[1].gd.handle_controlevent = GVC_OK;
769     mgcd[1].creator = GButtonCreate;
770 
771     mgcd[2].gd.flags = gg_visible | gg_enabled | gg_but_cancel;
772     mlabel[2].text = (unichar_t *) _("_Cancel");
773     mlabel[2].text_is_1byte = true;
774     mlabel[2].text_in_resource = true;
775     mgcd[2].gd.label = &mlabel[2];
776     mgcd[2].gd.handle_controlevent = MATH_Cancel;
777     mgcd[2].creator = GButtonCreate;
778 
779     harray[0] = GCD_Glue; harray[1] = &mgcd[1]; harray[2] = GCD_Glue;
780     harray[3] = GCD_Glue; harray[4] = &mgcd[2]; harray[5] = GCD_Glue;
781     harray[6] = NULL;
782 
783     mboxes[2].gd.flags = gg_enabled|gg_visible;
784     mboxes[2].gd.u.boxelements = harray;
785     mboxes[2].creator = GHBoxCreate;
786 
787     varray[0] = &mgcd[0]; varray[1] = NULL;
788     varray[2] = &mboxes[2]; varray[3] = NULL;
789     varray[4] = NULL;
790 
791     mboxes[0].gd.pos.x = mboxes[0].gd.pos.y = 2;
792     mboxes[0].gd.flags = gg_enabled|gg_visible;
793     mboxes[0].gd.u.boxelements = varray;
794     mboxes[0].creator = GHVGroupCreate;
795 
796     GGadgetsCreate(gw,mboxes);
797     GHVBoxSetExpandableRow(mboxes[0].ret,0);
798     GHVBoxSetExpandableCol(mboxes[2].ret,gb_expandgluesame);
799     GMatrixEditSetColumnCompletion(mgcd[0].ret,0,MATH_GlyphNameCompletion);
800     GMatrixEditSetMouseMoveReporter(mgcd[0].ret,GVC_PopupPrepare);
801 
802     /* If it's unparseable, this will give 'em nothing */
803     gv = GV_FromString(NULL,old[r*cols+cols-1].u.md_str);
804     GV_ToMD(mgcd[0].ret,gv);
805     GlyphVariantsFree(gv);
806 
807     GHVBoxFitWindow(mboxes[0].ret);
808 
809     GDrawSetVisible(md.gw,true);
810 
811     while ( !md.done )
812 	GDrawProcessOneEvent(NULL);
813 
814     if ( md.ok ) {
815 	int rs, cs = GMatrixEditGetColCnt(mgcd[0].ret);
816 	struct matrix_data *stuff = GMatrixEditGet(mgcd[0].ret,&rs);
817 	gv = GV_ParseConstruction(NULL,stuff,rs,cs);
818 	ret = GV_ToString(gv);
819 	GlyphVariantsFree(gv);
820     } else
821 	ret = copy( old[r*cols+cols-1].u.md_str );
822     GDrawDestroyWindow(md.gw);
823 return( ret );
824 }
825 
MKChange_Dlg(GGadget * g,int r,int c)826 static char *MKChange_Dlg(GGadget *g, int r, int c) {
827     MathDlg *math = GDrawGetUserData(GGadgetGetWindow(g));
828     int rows, cols = GMatrixEditGetColCnt(g);
829     struct matrix_data *old = GMatrixEditGet(g,&rows);
830     SplineChar *sc;
831 
832     if ( old[r*cols+0].u.md_str==NULL )
833 return( NULL );
834     sc = SFGetChar(math->sf,-1,old[r*cols+0].u.md_str);
835     if ( sc==NULL )
836 return( NULL );
837 
838     MathKernDialog(sc,math->def_layer);
839 return( NULL );
840 }
841 
MATH_OK(GGadget * g,GEvent * e)842 static int MATH_OK(GGadget *g, GEvent *e) {
843     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
844 	MathDlg *math = GDrawGetUserData(GGadgetGetWindow(g));
845 	int err=false;
846 	int cid,i;
847 	int high,low;
848 	SplineFont *sf = math->sf;
849 	SplineChar *sc;
850 
851 	/* Two passes. First checks that everything is parsable */
852 	for ( i=0; math_constants_descriptor[i].ui_name!=NULL; ++i ) {
853 	    GetInt8(math->gw,2*i+1,math_constants_descriptor[i].ui_name,&err);
854 	    if ( err )
855 return( true );
856 	    if ( math_constants_descriptor[i].devtab_offset >= 0 ) {
857 		GGadget *tf2 = GWidgetGetControl(math->gw,2*i+2);
858 		char *str = GGadgetGetTitle8(tf2);
859 		if ( !DeviceTableOK(str,&low,&high)) {
860 		    ff_post_error(_("Bad device table"), _("Bad device table for %s"),
861 			    math_constants_descriptor[i].ui_name);
862 		    free(str);
863 return( true );
864 		}
865 		free(str);
866 	    }
867 	}
868 	/* Now check that the various glyph lists are parseable */
869 	for ( cid=CID_Exten; cid<=CID_HGlyphConst; ++cid ) {
870 	    GGadget *g = GWidgetGetControl(math->gw,cid);
871 	    int rows, cols = GMatrixEditGetColCnt(g);
872 	    struct matrix_data *old = GMatrixEditGet(g,&rows);
873 	    for ( i=0; i<rows; ++i ) {
874 		if ( SFGetChar(sf,-1,old[i*cols+0].u.md_str)==NULL ) {
875 		    ff_post_error(_("Missing Glyph"), _("There is no glyph named %s (used in %s)"),
876 			    old[i*cols+0].u.md_str, gi_aspectnames[cid-CID_Exten]);
877 return( true );
878 		}
879 		if ( cid==CID_Italic || cid==CID_TopAccent ||
880 			cid == CID_VGlyphConst || cid == CID_HGlyphConst ) {
881 		    if ( !DeviceTableOK(old[i*cols+2].u.md_str,&low,&high)) {
882 			ff_post_error(_("Bad device table"), _("Bad device table for glyph %s in %s"),
883 				old[i*cols+0].u.md_str, gi_aspectnames[cid-CID_Exten]);
884 return( true );
885 		    }
886 		}
887 		if ( cid == CID_VGlyphConst || cid == CID_HGlyphConst ) {
888 		    if ( GV_StringCheck(sf,old[i*cols+cols-1].u.md_str)==-1 ) {
889 			ff_post_error(_("Bad Parts List"), _("Bad parts list for glyph %s in %s"),
890 				old[i*cols+0].u.md_str, gi_aspectnames[cid-CID_Exten]);
891 return( true );
892 		    }
893 		}
894 		if ( cid == CID_VGlyphVar || cid == CID_HGlyphVar ) {
895 		    if ( !SF_NameListCheck(sf,old[i*cols+1].u.md_str)) {
896 			ff_post_error(_("Bad Variants List"), _("Bad Variants list for glyph %s in %s"),
897 				old[i*cols+0].u.md_str, gi_aspectnames[cid-CID_Exten]);
898 return( true );
899 		    }
900 		}
901 	    }
902 	}
903 
904 	/*********************************************/
905 	/* Ok, if we got this far it should be legal */
906 	/*********************************************/
907 	for ( i=0; math_constants_descriptor[i].ui_name!=NULL; ++i ) {
908 	    int16 *pos = (int16 *) (((char *) (math->math)) + math_constants_descriptor[i].offset );
909 	    *pos = GetInt8(math->gw,2*i+1,math_constants_descriptor[i].ui_name,&err);
910 
911 	    if ( math_constants_descriptor[i].devtab_offset >= 0 ) {
912 		GGadget *tf2 = GWidgetGetControl(math->gw,2*i+2);
913 		char *str = GGadgetGetTitle8(tf2);
914 		DeviceTable **devtab = (DeviceTable **) (((char *) (math->math)) + math_constants_descriptor[i].devtab_offset );
915 
916 		*devtab = DeviceTableParse(*devtab,str);
917 		free(str);
918 	    }
919 	}
920 	sf->MATH = math->math;
921 
922 	/* As for the per-glyph stuff... Well the only way I can insure that */
923 	/* things which have been removed in the dlg are removed in the font */
924 	/* is to clear everything now, and start from a blank slate when I   */
925 	/* parse stuff. (Except for math kerning which I don't support here) */
926 	for ( i=0; i<sf->glyphcnt; ++i ) if ( (sc=sf->glyphs[i])!=NULL ) {
927 	    sc->is_extended_shape = false;
928 	    sc->italic_correction = TEX_UNDEF;
929 	    sc->top_accent_horiz  = TEX_UNDEF;
930 	    DeviceTableFree(sc->italic_adjusts);
931 	    DeviceTableFree(sc->top_accent_adjusts);
932 	    sc->italic_adjusts = sc->top_accent_adjusts = NULL;
933 	    GlyphVariantsFree(sc->vert_variants);
934 	    GlyphVariantsFree(sc->horiz_variants);
935 	    sc->vert_variants = sc->horiz_variants = NULL;
936 	    /* MathKernFree(sc->mathkern); sc->mathkern = NULL; */
937 	}
938 	/* Then process each table to set whatever it sets */
939 	for ( cid=CID_Exten; cid<=CID_HGlyphConst; ++cid ) {
940 	    GGadget *g = GWidgetGetControl(math->gw,cid);
941 	    int rows, cols = GMatrixEditGetColCnt(g);
942 	    struct matrix_data *old = GMatrixEditGet(g,&rows);
943 	    for ( i=0; i<rows; ++i ) {
944 		sc = SFGetChar(sf,-1,old[i*cols+0].u.md_str);
945 		if ( cid==CID_Exten )
946 		    sc->is_extended_shape = old[i*cols+1].u.md_ival;
947 		else if ( cid==CID_Italic ) {
948 		    sc->italic_correction = old[i*cols+1].u.md_ival;
949 		    sc->italic_adjusts = DeviceTableParse(NULL,old[i*cols+2].u.md_str);
950 		} else if ( cid==CID_TopAccent ) {
951 		    sc->top_accent_horiz = old[i*cols+1].u.md_ival;
952 		    sc->top_accent_adjusts = DeviceTableParse(NULL,old[i*cols+2].u.md_str);
953 		} else if ( cid==CID_VGlyphVar || cid==CID_HGlyphVar ) {
954 		    struct glyphvariants **gvp = cid == CID_VGlyphVar ?
955 			    &sc->vert_variants : &sc->horiz_variants;
956 		    char *str = old[i*cols+1].u.md_str;
957 		    if ( str!=NULL ) while ( *str==' ' ) ++str;
958 		    if ( str!=NULL && *str!='\0' ) {
959 			*gvp = chunkalloc(sizeof(struct glyphvariants));
960 			(*gvp)->variants = GlyphNameListDeUnicode( str );
961 		    }
962 		} else if ( cid==CID_VGlyphConst || cid==CID_HGlyphConst ) {
963 		    struct glyphvariants **gvp = cid == CID_VGlyphConst ?
964 			    &sc->vert_variants : &sc->horiz_variants;
965 		    *gvp = GV_FromString(*gvp,old[cols*i+cols-1].u.md_str);
966 		    if ( *gvp!=NULL && (*gvp)->part_cnt!=0 ) {
967 			(*gvp)->italic_correction = old[i*cols+1].u.md_ival;
968 			(*gvp)->italic_adjusts = DeviceTableParse(NULL,old[i*cols+2].u.md_str);
969 		    }
970 		}
971 	    }
972 	}
973 
974 	/* Done! */
975 
976 	math->done = true;
977 	math->ok = true;
978     }
979 return( true );
980 }
981 
math_e_h(GWindow gw,GEvent * event)982 static int math_e_h(GWindow gw, GEvent *event) {
983     MathDlg *math = GDrawGetUserData(gw);
984 
985     if ( event->type==et_close ) {
986 	math->done = true;
987     } else if ( event->type==et_char ) {
988 	if ( event->u.chr.keysym == GK_F1 || event->u.chr.keysym == GK_Help ) {
989 	    help("ui/dialogs/math.html", NULL);
990 return( true );
991 	} else if ( GMenuIsCommand(event,H_("Quit|Ctl+Q") )) {
992 	    MenuExit(NULL,NULL,NULL);
993 	} else if ( GMenuIsCommand(event,H_("Close|Ctl+Shft+Q") )) {
994 	    math->done = true;
995 	}
996 return( false );
997     }
998 return( true );
999 }
1000 
1001 #define MAX_PAGE	9
1002 #define MAX_ROW		12
1003 
SFMathDlg(SplineFont * sf,int def_layer)1004 void SFMathDlg(SplineFont *sf,int def_layer) {
1005     MathDlg md;
1006     int i, j, page, row, h;
1007     GGadget *g;
1008     GRect pos;
1009     GWindow gw;
1010     GWindowAttrs wattrs;
1011     GGadgetCreateData gcd[MAX_PAGE][MAX_ROW][3], boxes[MAX_PAGE][2],
1012 	    *hvarray[MAX_PAGE][MAX_ROW+1][4], *harray[7], mgcd[4],
1013 	    *varray[6], mboxes[3], gi[8][2];
1014     GTextInfo label[MAX_PAGE][MAX_ROW], mlabel[3];
1015     GTabInfo aspects[MAX_PAGE+8+1];
1016 
1017     MathInit();
1018 
1019     memset(&md,0,sizeof(md));
1020     if ( sf->cidmaster ) sf = sf->cidmaster;
1021     md.sf = sf;
1022     md.def_layer = def_layer;
1023     md.math = sf->MATH;
1024     if ( md.math==NULL )
1025 	md.math = MathTableNew(sf);
1026 
1027     memset(&wattrs,0,sizeof(wattrs));
1028     wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_undercursor|wam_restrict|wam_isdlg;
1029     wattrs.event_masks = ~(1<<et_charup);
1030     wattrs.restrict_input_to_me = 1;
1031     wattrs.is_dlg = 1;
1032     wattrs.undercursor = 1;
1033     wattrs.cursor = ct_pointer;
1034     wattrs.utf8_window_title = _("MATH table");
1035     pos.x = pos.y = 0;
1036     pos.width = 100;
1037     pos.height = 100;
1038     md.gw = gw = GDrawCreateTopWindow(NULL,&pos,math_e_h,&md,&wattrs);
1039 
1040     memset(gcd,0,sizeof(gcd));
1041     memset(label,0,sizeof(label));
1042     memset(boxes,0,sizeof(boxes));
1043     memset(aspects,0,sizeof(aspects));
1044     memset(gi,0,sizeof(gi));
1045 
1046     page = row = 0;
1047     for ( i=0; math_constants_descriptor[i].ui_name!=NULL; ++i ) {
1048 	if ( math_constants_descriptor[i].new_page ) {
1049 	    hvarray[page][row][0] = hvarray[page][row][1] = hvarray[page][row][2] = GCD_Glue;
1050 	    hvarray[page][row][3] = NULL;
1051 	    hvarray[page][row+1][0] = NULL;
1052 	    ++page;
1053 	    if ( page>=MAX_PAGE ) {
1054 		IError( "Too many pages" );
1055 return;
1056 	    }
1057 	    row = 0;
1058 	}
1059 
1060 	label[page][row].text = (unichar_t *) math_constants_descriptor[i].ui_name;
1061 	label[page][row].text_is_1byte = true;
1062 	label[page][row].text_in_resource = true;
1063 	gcd[page][row][0].gd.label = &label[page][row];
1064 	gcd[page][row][0].gd.flags = gg_visible | gg_enabled;
1065 	gcd[page][row][0].gd.popup_msg = math_constants_descriptor[i].message;
1066 	gcd[page][row][0].creator = GLabelCreate;
1067 	hvarray[page][row][0] = &gcd[page][row][0];
1068 
1069 	gcd[page][row][1].gd.flags = gg_visible | gg_enabled;
1070 	gcd[page][row][1].gd.pos.width = 50;
1071 	gcd[page][row][1].gd.cid = 2*i+1;
1072 	gcd[page][row][1].gd.popup_msg = math_constants_descriptor[i].message;
1073 	gcd[page][row][1].creator = GTextFieldCreate;
1074 	hvarray[page][row][1] = &gcd[page][row][1];
1075 
1076 	if ( math_constants_descriptor[i].devtab_offset>=0 ) {
1077 	    gcd[page][row][2].gd.flags = gg_visible | gg_enabled;
1078 	    gcd[page][row][2].gd.cid = 2*i+2;
1079 	    gcd[page][row][2].gd.popup_msg = math_constants_descriptor[i].message;
1080 	    gcd[page][row][2].creator = GTextFieldCreate;
1081 	    hvarray[page][row][2] = &gcd[page][row][2];
1082 	} else
1083 	    hvarray[page][row][2] = GCD_Glue;
1084 	hvarray[page][row][3] = NULL;
1085 
1086 	if ( ++row>=MAX_ROW ) {
1087 	    IError( "Too many rows" );
1088 return;
1089 	}
1090     }
1091     hvarray[page][row][0] = hvarray[page][row][1] = hvarray[page][row][2] = GCD_Glue;
1092     hvarray[page][row][3] = NULL;
1093     hvarray[page][row+1][0] = NULL;
1094 
1095     for ( i=0; aspectnames[i]!=NULL; ++i ) {
1096 	boxes[i][0].gd.flags = gg_enabled|gg_visible;
1097 	boxes[i][0].gd.u.boxelements = hvarray[i][0];
1098 	boxes[i][0].creator = GHVBoxCreate;
1099 
1100 	aspects[i].text = (unichar_t *) aspectnames[i];
1101 	aspects[i].text_is_1byte = true;
1102 	aspects[i].nesting = i!=0;
1103 	aspects[i].gcd = boxes[i];
1104     }
1105     if ( i!=page+1 ) {	/* Page never gets its final increment */
1106 	IError( "Page miscount %d in descriptor table, but only %d names.", page+1, i );
1107 return;
1108     }
1109 
1110     for ( j=0; mis[j].col_cnt!=0; ++j ) {
1111 	gi[j][0].gd.flags = gg_enabled|gg_visible;
1112 	gi[j][0].gd.u.matrix = &mis[j];
1113 	gi[j][0].gd.cid = CID_Exten+j;
1114 	gi[j][0].creator = GMatrixEditCreate;
1115 
1116 	aspects[i+j].text = (unichar_t *) gi_aspectnames[j];
1117 	aspects[i+j].text_is_1byte = true;
1118 	aspects[i+j].gcd = gi[j];
1119     }
1120 
1121     memset(mgcd,0,sizeof(mgcd));
1122     memset(mlabel,0,sizeof(mlabel));
1123     memset(mboxes,0,sizeof(mboxes));
1124 
1125     mgcd[0].gd.u.tabs = aspects;
1126     mgcd[0].gd.flags = gg_visible | gg_enabled | gg_tabset_vert;
1127     /*mgcd[0].gd.cid = CID_Tabs;*/
1128     mgcd[0].creator = GTabSetCreate;
1129 
1130     mgcd[1].gd.flags = gg_visible | gg_enabled | gg_but_default;
1131     mlabel[1].text = (unichar_t *) _("_OK");
1132     mlabel[1].text_is_1byte = true;
1133     mlabel[1].text_in_resource = true;
1134     mgcd[1].gd.label = &mlabel[1];
1135     mgcd[1].gd.handle_controlevent = MATH_OK;
1136     mgcd[1].creator = GButtonCreate;
1137 
1138     mgcd[2].gd.flags = gg_visible | gg_enabled | gg_but_cancel;
1139     mlabel[2].text = (unichar_t *) _("_Cancel");
1140     mlabel[2].text_is_1byte = true;
1141     mlabel[2].text_in_resource = true;
1142     mgcd[2].gd.label = &mlabel[2];
1143     mgcd[2].gd.handle_controlevent = MATH_Cancel;
1144     mgcd[2].creator = GButtonCreate;
1145 
1146     harray[0] = GCD_Glue; harray[1] = &mgcd[1]; harray[2] = GCD_Glue;
1147     harray[3] = GCD_Glue; harray[4] = &mgcd[2]; harray[5] = GCD_Glue;
1148     harray[6] = NULL;
1149 
1150     mboxes[2].gd.flags = gg_enabled|gg_visible;
1151     mboxes[2].gd.u.boxelements = harray;
1152     mboxes[2].creator = GHBoxCreate;
1153 
1154     varray[0] = &mgcd[0]; varray[1] = NULL;
1155     varray[2] = &mboxes[2]; varray[3] = NULL;
1156     varray[4] = NULL;
1157 
1158     mboxes[0].gd.pos.x = mboxes[0].gd.pos.y = 2;
1159     mboxes[0].gd.flags = gg_enabled|gg_visible;
1160     mboxes[0].gd.u.boxelements = varray;
1161     mboxes[0].creator = GHVGroupCreate;
1162 
1163     GGadgetsCreate(gw,mboxes);
1164     GHVBoxSetExpandableRow(mboxes[0].ret,0);
1165     GHVBoxSetExpandableCol(mboxes[2].ret,gb_expandgluesame);
1166     for ( i=0; aspectnames[i]!=NULL; ++i ) {
1167 	GHVBoxSetExpandableCol(boxes[i][0].ret,2);
1168 	GHVBoxSetExpandableRow(boxes[i][0].ret,gb_expandglue);
1169     }
1170     for ( j=0; mis[j].col_cnt!=0; ++j )
1171 	GMatrixEditSetColumnCompletion(gi[j][0].ret,0,MATH_GlyphNameCompletion);
1172     for ( h=0; h<2; ++h ) {
1173 	g = GWidgetGetControl(md.gw,CID_VGlyphVar+2*h);
1174 	GMatrixEditSetColumnCompletion(g,1,MATH_GlyphListCompletion);
1175 	GMatrixEditSetMouseMoveReporter(g,MATHVar_PopupPrepare);
1176 	g = GWidgetGetControl(md.gw,CID_VGlyphConst+2*h);
1177 	GMatrixEditSetMouseMoveReporter(g,MATHConst_PopupPrepare);
1178     }
1179     GMatrixEditSetMouseMoveReporter(GWidgetGetControl(md.gw,CID_Italic),MATHLine_PopupPrepare);
1180     GMatrixEditSetMouseMoveReporter(GWidgetGetControl(md.gw,CID_TopAccent),MATHLine_PopupPrepare);
1181     MATH_Init(&md);
1182     GHVBoxFitWindow(mboxes[0].ret);
1183 
1184     GDrawSetVisible(md.gw,true);
1185 
1186     while ( !md.done )
1187 	GDrawProcessOneEvent(NULL);
1188     if ( sf->MATH==NULL && !md.ok )
1189 	MATHFree(md.math);
1190 
1191     GDrawDestroyWindow(md.gw);
1192 }
1193 
1194 /* ************************************************************************** */
1195 /* ****************************** Math Kern Dlg ***************************** */
1196 /* ************************************************************************** */
1197 
1198 #define CID_TopBox	1000
1199 #define CID_Glyph	1001
1200 #define CID_Tabs	1002
1201 #define CID_Corners	1003
1202 #define CID_TopRight	1004
1203 #define CID_TopLeft	1005
1204 #define CID_BottomRight	1006
1205 #define CID_BottomLeft	1007
1206 
MKD_SetGlyphList(MathKernDlg * mkd,SplineChar * sc)1207 static void MKD_SetGlyphList(MathKernDlg *mkd, SplineChar *sc) {
1208     SplineFont *sf = sc->parent;
1209     int k,cnt, gid;
1210     GTextInfo **tis = NULL;
1211     SplineChar *test;
1212 
1213     for ( k=0; k<2; ++k ) {
1214 	cnt = 0;
1215 	for ( gid=0; gid<sf->glyphcnt; ++gid ) if ( (test=sf->glyphs[gid])!=NULL ) {
1216 	    if ( test==sc || test->mathkern!=NULL ) {
1217 		if ( k ) {
1218 		    tis[cnt] = calloc(1,sizeof(GTextInfo));
1219 		    tis[cnt]->text = utf82u_copy(test->name);
1220 		    tis[cnt]->userdata = test;
1221 		    tis[cnt]->selected = test==sc;
1222 		    tis[cnt]->fg = tis[cnt]->bg = COLOR_DEFAULT;
1223 		}
1224 		++cnt;
1225 	    }
1226 	}
1227 	if ( !k )
1228 	    tis = malloc((cnt+1)*sizeof(GTextInfo *));
1229 	else
1230 	    tis[cnt] = calloc(1,sizeof(GTextInfo));
1231     }
1232     GGadgetSetList(GWidgetGetControl(mkd->gw,CID_Glyph),tis,false);
1233 }
1234 
MKDSubResize(MathKernDlg * mkd,GEvent * event)1235 static void MKDSubResize(MathKernDlg *mkd, GEvent *event) {
1236     int width, height;
1237     int i;
1238     GRect r;
1239 
1240     if ( !event->u.resize.sized )
1241 return;
1242 
1243     width = (event->u.resize.size.width-4*mkd->mid_space)/4;
1244     height = (event->u.resize.size.height-mkd->cv_y-8);
1245     if ( width<70 || height<80 ) {
1246 	if ( width<70 ) width = 70;
1247 	width = 4*(width+mkd->mid_space);
1248 	if ( height<80 ) height = 80;
1249 	height += mkd->cv_y+mkd->button_height+8;
1250 	GDrawGetSize(mkd->gw,&r);
1251 	width += r.width-event->u.resize.size.width;
1252 	height += r.height-event->u.resize.size.height;
1253 	GDrawResize(mkd->gw,width,height);
1254 return;
1255     }
1256     if ( width!=mkd->cv_width || height!=mkd->cv_height ) {
1257 	mkd->cv_width = width; mkd->cv_height = height;
1258 	for ( i=0; i<4; ++i ) {
1259 	    CharView *cv = (&mkd->cv_topright)+i;
1260 	    GDrawResize(cv->gw,width,height);
1261 	    if ( i!=0 )
1262 		GDrawMove(cv->gw,10+i*(mkd->cv_width+mkd->mid_space),mkd->cv_y);
1263 	}
1264     }
1265 
1266     GDrawSync(NULL);
1267     GDrawProcessPendingEvents(NULL);
1268     GDrawRequestExpose(mkd->cvparent_w,NULL,false);
1269 }
1270 
MKDTopResize(MathKernDlg * mkd,GEvent * event)1271 static void MKDTopResize(MathKernDlg *mkd, GEvent *event) {
1272 
1273     if ( !event->u.resize.sized )
1274 return;
1275 
1276     GGadgetMove(GWidgetGetControl(mkd->gw,CID_TopBox),4,4);
1277     GGadgetResize(GWidgetGetControl(mkd->gw,CID_TopBox),
1278 	    event->u.resize.size.width-8,
1279 	    event->u.resize.size.height-12);
1280 }
1281 
1282 
MKDDraw(MathKernDlg * mkd,GWindow pixmap,GEvent * event)1283 static void MKDDraw(MathKernDlg *mkd, GWindow pixmap, GEvent *event) {
1284     GRect r;
1285     int i;
1286 
1287     GDrawSetLineWidth(pixmap,0);
1288     for ( i=0; i<4; ++i ) {
1289 	CharView *cv = (&mkd->cv_topright)+i;
1290 
1291 	r.x = 10+i*(mkd->cv_width+mkd->mid_space)-1; r.y=mkd->cv_y-1;
1292 	r.width = mkd->cv_width+1; r.height = mkd->cv_height+1;
1293 	GDrawDrawRect(pixmap,&r,0);
1294 
1295 	GDrawSetFont(pixmap,cv->inactive ? mkd->plain : mkd->bold);
1296 	GDrawDrawText8(pixmap,r.x,5+mkd->as,cornernames[i],-1,0);
1297     }
1298 }
1299 
MKDMakeActive(MathKernDlg * mkd,CharView * cv)1300 void MKDMakeActive(MathKernDlg *mkd,CharView *cv) {
1301     GRect r;
1302     int i;
1303 
1304     if ( mkd==NULL )
1305 return;
1306     for ( i=0; i<4; ++i )
1307 	(&mkd->cv_topright)[i].inactive = true;
1308     cv->inactive = false;
1309     GDrawSetUserData(mkd->gw,cv);
1310     GDrawSetUserData(mkd->cvparent_w,cv);
1311     for ( i=0; i<4; ++i )
1312 	GDrawRequestExpose((&mkd->cv_topright)[i].v,NULL,false);
1313     GDrawGetSize(mkd->gw,&r);
1314     r.x = 0;
1315     r.y = 0;
1316     r.height = mkd->fh+10;
1317     GDrawRequestExpose(mkd->cvparent_w,&r,false);
1318 }
1319 
MKDChar(MathKernDlg * mkd,GEvent * event)1320 static void MKDChar(MathKernDlg *mkd, GEvent *event) {
1321     int i;
1322     for ( i=0; i<4; ++i )
1323 	if ( !(&mkd->cv_topright)[i].inactive )
1324     break;
1325 
1326     if ( event->u.chr.keysym==GK_Tab || event->u.chr.keysym==GK_BackTab ) {
1327 	if ( event->u.chr.keysym==GK_Tab ) ++i; else --i;
1328 	if ( i<0 ) i=3; else if ( i>3 ) i = 0;
1329 	MKDMakeActive(mkd,(&mkd->cv_topright)+i);
1330     } else
1331 	CVChar((&mkd->cv_topright)+i,event);
1332 }
1333 
MKD_DoClose(struct cvcontainer * cvc)1334 void MKD_DoClose(struct cvcontainer *cvc) {
1335     MathKernDlg *mkd = (MathKernDlg *) cvc;
1336     int i;
1337 
1338     for ( i=0; i<4; ++i ) {
1339 	SplineChar *msc = &(&mkd->sc_topright)[i];
1340 	SplinePointListsFree(msc->layers[0].splines);
1341 	SplinePointListsFree(msc->layers[1].splines);
1342 	free( msc->layers );
1343     }
1344 
1345     mkd->done = true;
1346 }
1347 
mkd_sub_e_h(GWindow gw,GEvent * event)1348 static int mkd_sub_e_h(GWindow gw, GEvent *event) {
1349     MathKernDlg *mkd = (MathKernDlg *) ((CharViewBase *) GDrawGetUserData(gw))->container;
1350 
1351     switch ( event->type ) {
1352       case et_expose:
1353 	MKDDraw(mkd,gw,event);
1354       break;
1355       case et_resize:
1356 	if ( event->u.resize.sized )
1357 	    MKDSubResize(mkd,event);
1358       break;
1359       case et_char:
1360 	MKDChar(mkd,event);
1361       break;
1362     }
1363 return( true );
1364 }
1365 
mkd_e_h(GWindow gw,GEvent * event)1366 static int mkd_e_h(GWindow gw, GEvent *event) {
1367     MathKernDlg *mkd = (MathKernDlg *) ((CharViewBase *) GDrawGetUserData(gw))->container;
1368     int i;
1369 
1370     switch ( event->type ) {
1371       case et_char:
1372 	MKDChar(mkd,event);
1373       break;
1374       case et_resize:
1375 	if ( event->u.resize.sized )
1376 	    MKDTopResize(mkd,event);
1377       break;
1378       case et_close:
1379 	MKD_DoClose((struct cvcontainer *) mkd);
1380       break;
1381       case et_create:
1382       break;
1383       case et_map:
1384 	for ( i=0; i<4; ++i ) {
1385 	    CharView *cv = (&mkd->cv_topright)+i;
1386 	    if ( !cv->inactive ) {
1387 		if ( event->u.map.is_visible )
1388 		    CVPaletteActivate(cv);
1389 		else
1390 		    CVPalettesHideIfMine(cv);
1391 	break;
1392 	    }
1393 	}
1394 	/* mkd->isvisible = event->u.map.is_visible; */
1395       break;
1396     }
1397 return( true );
1398 }
1399 
MKDFillup(MathKernDlg * mkd,SplineChar * sc)1400 static void MKDFillup(MathKernDlg *mkd, SplineChar *sc) {
1401     int i, j, rows;
1402     SplineSet *last, *cur;
1403     RefChar *ref;
1404     GTextInfo **list;
1405 
1406     if ( mkd->last_aspect==0 ) {
1407 	for ( i=0; i<4; ++i ) {
1408 	    SplineChar *msc = &(&mkd->sc_topright)[i];
1409 	    struct mathkernvertex *mkv = sc->mathkern==NULL ? NULL : &(&sc->mathkern->top_right)[i];
1410 	    msc->width = sc->width;
1411 	    msc->italic_correction = sc->italic_correction;
1412 	    msc->top_accent_horiz = sc->top_accent_horiz;
1413 	    last = NULL;
1414 	    SplinePointListsFree(msc->layers[0].splines);
1415 	    SplinePointListsFree(msc->layers[1].splines);
1416 	    msc->layers[0].splines = msc->layers[1].splines = NULL;
1417 
1418 	    /* copy the character itself into the background */
1419 	    last = msc->layers[0].splines = SplinePointListCopy(sc->layers[ly_fore].splines);
1420 	    if ( last!=NULL )
1421 		while ( last->next!=NULL ) last = last->next;
1422 	    for ( ref=sc->layers[ly_fore].refs; ref!=NULL; ref=ref->next ) {
1423 		if ( last==NULL )
1424 		    cur = SplinePointListCopy(ref->layers[0].splines);
1425 		if ( last==NULL )
1426 		    msc->layers[0].splines = cur;
1427 		else
1428 		    last->next = cur;
1429 		if ( cur!=NULL )
1430 		    for ( last=cur; last->next==NULL; last = last->next );
1431 	    }
1432 	    /* Now copy the dots from the mathkern vertex structure */
1433 	    last = NULL;
1434 	    if ( mkv!=NULL ) {
1435 		for ( j=0; j<mkv->cnt; ++j ) {
1436 		    cur = chunkalloc(sizeof(SplineSet));
1437 		    cur->first = cur->last = SplinePointCreate(mkv->mkd[j].kern +
1438 			    ((i&1)?0:sc->width) +
1439 			    ((i&2)?0:sc->italic_correction==TEX_UNDEF?0:sc->italic_correction),
1440 			mkv->mkd[j].height );
1441 		    cur->first->pointtype = pt_corner;
1442 		    if ( last==NULL )
1443 			msc->layers[ly_fore].splines = cur;
1444 		    else
1445 			last->next = cur;
1446 		    last = cur;
1447 		}
1448 	    }
1449 	}
1450     } else {
1451 	for ( i=0; i<4; ++i ) {
1452 	    struct mathkernvertex *mkv = sc->mathkern==NULL ? NULL : &(&sc->mathkern->top_right)[i];
1453 	    GGadget *list = GWidgetGetControl(mkd->gw,CID_TopRight+i);
1454 	    int cols = GMatrixEditGetColCnt(list);
1455 	    struct matrix_data *md;
1456 
1457 	    if ( mkv!=NULL ) {
1458 		md = calloc(mkv->cnt*cols,sizeof(struct matrix_data));
1459 		for ( j=0; j<mkv->cnt; ++j ) {
1460 		    md[j*cols+0].u.md_ival = mkv->mkd[j].height;
1461 		    md[j*cols+1].u.md_ival = mkv->mkd[j].kern;
1462 		    DevTabToString(&md[j*cols+2].u.md_str,mkv->mkd[j].height_adjusts);
1463 		    DevTabToString(&md[j*cols+3].u.md_str,mkv->mkd[j].kern_adjusts);
1464 		}
1465 		GMatrixEditSet(list, md,mkv->cnt,false);
1466 	    } else
1467 		GMatrixEditSet(list, NULL,0,false);
1468 	}
1469     }
1470     mkd->cursc = sc;
1471 
1472     list = GGadgetGetList(GWidgetGetControl(mkd->gw,CID_Glyph),&rows);
1473     for ( i=rows-1; i>=0; --i )
1474 	if ( list[i]->userdata==sc )
1475     break;
1476     if ( i>=0 )
1477 	GGadgetSelectOneListItem(GWidgetGetControl(mkd->gw,CID_Glyph),i);
1478 }
1479 
MKDFillupRefresh(MathKernDlg * mkd,SplineChar * sc)1480 static void MKDFillupRefresh(MathKernDlg *mkd, SplineChar *sc) {
1481     int i;
1482 
1483     MKDFillup(mkd, sc);
1484     if ( mkd->last_aspect==0 ) {
1485 	for ( i=0; i<4; ++i ) {
1486 	    CharView *cv = &mkd->cv_topright + i;
1487 	    GDrawRequestExpose(cv->gw,NULL,false);
1488 	    GDrawRequestExpose(cv->v,NULL,false);
1489 	}
1490     }
1491 }
1492 
bp_order_height(const void * bpp1,const void * bpp2)1493 static int bp_order_height(const void *bpp1, const void *bpp2) {
1494     const BasePoint *bp1 = *(const BasePoint **) bpp1;
1495     const BasePoint *bp2 = *(const BasePoint **) bpp2;
1496     if ( bp1->y > bp2->y )
1497 return( 1 );
1498     else if ( bp1->y < bp2->y )
1499 return( -1 );
1500 
1501 return( 0 );
1502 }
1503 
mkd_order_height(const void * _mkd1,const void * _mkd2)1504 static int mkd_order_height(const void *_mkd1, const void *_mkd2) {
1505     const struct mathkerndata *mkd1 = (const struct mathkerndata *) _mkd1;
1506     const struct mathkerndata *mkd2 = (const struct mathkerndata *) _mkd2;
1507     if ( mkd1->height > mkd2->height )
1508 return( 1 );
1509     else if ( mkd1->height < mkd2->height )
1510 return( -1 );
1511 
1512 return( 0 );
1513 }
1514 
MKD_Parse(MathKernDlg * mkd)1515 static int MKD_Parse(MathKernDlg *mkd) {
1516     int i, cnt, j, k;
1517     SplineSet *ss;
1518     SplinePoint *sp;
1519     BasePoint **bases;
1520     int allzeroes = true;
1521 
1522     if ( mkd->cursc->mathkern==NULL )
1523 	mkd->cursc->mathkern = chunkalloc(sizeof(struct mathkern));
1524 
1525     if ( mkd->last_aspect==0 ) {		/* Graphical view is current */
1526 	for ( i=0; i<4; ++i ) {
1527 	    SplineChar *msc = &(&mkd->sc_topright)[i];
1528 	    struct mathkernvertex *mkv = &(&mkd->cursc->mathkern->top_right)[i];
1529 
1530 	    for ( k=0; k<2; ++k ) {
1531 		cnt = 0;
1532 		for ( ss = msc->layers[ly_fore].splines; ss!=NULL; ss=ss->next ) {
1533 		    for ( sp=ss->first ; ; ) {
1534 			if ( k )
1535 			    bases[cnt] = &sp->me;
1536 			++cnt;
1537 			if ( sp->next == NULL )
1538 		    break;
1539 			sp = sp->next->to;
1540 			if ( sp == ss->first )
1541 		    break;
1542 		    }
1543 		}
1544 		if ( !k )
1545 		    bases = malloc(cnt*sizeof(BasePoint *));
1546 	    }
1547 	    qsort(bases,cnt,sizeof(BasePoint *),bp_order_height);
1548 	    if ( cnt>mkv->cnt ) {
1549 		mkv->mkd = realloc(mkv->mkd,cnt*sizeof(struct mathkerndata));
1550 		memset(mkv->mkd+mkv->cnt,0,(cnt-mkv->cnt)*sizeof(struct mathkerndata));
1551 	    }
1552 	    for ( j=0; j<cnt; ++j ) {
1553 		bases[j]->x = rint(bases[j]->x);
1554 		if ( !(i&1) ) bases[j]->x -= mkd->cursc->width;
1555 		if ( !(i&2) ) bases[j]->x -= mkd->cursc->italic_correction==TEX_UNDEF?0:mkd->cursc->italic_correction;
1556 		bases[j]->y = rint(bases[j]->y);
1557 		/* If we have a previous entry with this height retain the height dv */
1558 		/* If we have a previous entry with this height and width retain the width dv too */
1559 		for ( k=j; k<mkv->cnt; ++k )
1560 		    if ( bases[j]->y == mkv->mkd[k].height )
1561 		break;
1562 		if ( k!=j ) {
1563 		    DeviceTableFree(mkv->mkd[j].height_adjusts);
1564 		    DeviceTableFree(mkv->mkd[j].kern_adjusts);
1565 		    mkv->mkd[j].height_adjusts = mkv->mkd[j].kern_adjusts = NULL;
1566 		}
1567 		if ( k<mkv->cnt ) {
1568 		    mkv->mkd[j].height_adjusts = mkv->mkd[k].height_adjusts;
1569 		    if ( bases[j]->x == mkv->mkd[k].kern )
1570 			mkv->mkd[j].kern_adjusts = mkv->mkd[k].kern_adjusts;
1571 		    else {
1572 			DeviceTableFree(mkv->mkd[k].kern_adjusts);
1573 			mkv->mkd[k].kern_adjusts = NULL;
1574 		    }
1575 		    if ( j!=k )
1576 			mkv->mkd[k].height_adjusts = mkv->mkd[k].kern_adjusts = NULL;
1577 		}
1578 		mkv->mkd[j].height = bases[j]->y;
1579 		mkv->mkd[j].kern   = bases[j]->x;
1580 	    }
1581 	    for ( ; j<mkv->cnt; ++j ) {
1582 		DeviceTableFree(mkv->mkd[j].height_adjusts);
1583 		DeviceTableFree(mkv->mkd[j].kern_adjusts);
1584 		mkv->mkd[j].height_adjusts = mkv->mkd[j].kern_adjusts = NULL;
1585 	    }
1586 	    mkv->cnt = cnt;
1587 	    free(bases);
1588 	    if ( cnt!=0 )
1589 		allzeroes = false;
1590 	}
1591     } else {
1592 	int low, high;
1593 	/* Parse the textual info */
1594 	for ( i=0; i<4; ++i ) {
1595 	    GGadget *list = GWidgetGetControl(mkd->gw,CID_TopRight+i);
1596 	    int rows, cols = GMatrixEditGetColCnt(list);
1597 	    struct matrix_data *old = GMatrixEditGet(list,&rows);
1598 
1599 	    for ( j=0; j<rows; ++j ) {
1600 		if ( !DeviceTableOK(old[j*cols+2].u.md_str,&low,&high) ||
1601 			!DeviceTableOK(old[j*cols+3].u.md_str,&low,&high)) {
1602 		    ff_post_error(_("Bad device table"), _("Bad device table for in row %d of %s"),
1603 			    j, cornernames[i]);
1604 return( false );
1605 		}
1606 	    }
1607 	}
1608 	for ( i=0; i<4; ++i ) {
1609 	    struct mathkernvertex *mkv = &(&mkd->cursc->mathkern->top_right)[i];
1610 	    GGadget *list = GWidgetGetControl(mkd->gw,CID_TopRight+i);
1611 	    int rows, cols = GMatrixEditGetColCnt(list);
1612 	    struct matrix_data *old = GMatrixEditGet(list,&rows);
1613 
1614 	    for ( j=0; j<mkv->cnt; ++j ) {
1615 		DeviceTableFree(mkv->mkd[j].height_adjusts);
1616 		DeviceTableFree(mkv->mkd[j].kern_adjusts);
1617 		mkv->mkd[j].height_adjusts = mkv->mkd[j].kern_adjusts = NULL;
1618 	    }
1619 	    if ( rows>mkv->cnt ) {
1620 		mkv->mkd = realloc(mkv->mkd,rows*sizeof(struct mathkerndata));
1621 		memset(mkv->mkd+mkv->cnt,0,(rows-mkv->cnt)*sizeof(struct mathkerndata));
1622 	    }
1623 	    for ( j=0; j<rows; ++j ) {
1624 		mkv->mkd[j].height = old[j*cols+0].u.md_ival;
1625 		mkv->mkd[j].kern   = old[j*cols+1].u.md_ival;
1626 		mkv->mkd[j].height_adjusts = DeviceTableParse(NULL,old[j*cols+2].u.md_str);
1627 		mkv->mkd[j].kern_adjusts   = DeviceTableParse(NULL,old[j*cols+3].u.md_str);
1628 	    }
1629 	    qsort(mkv->mkd,rows,sizeof(struct mathkerndata),mkd_order_height);
1630 	    mkv->cnt = rows;
1631 	    if ( rows!=0 )
1632 		allzeroes=false;
1633 	}
1634     }
1635     if ( allzeroes ) {
1636 	MathKernFree(mkd->cursc->mathkern);
1637 	mkd->cursc->mathkern = NULL;
1638     }
1639     /* The only potential error is two entries with the same height, and I don't */
1640     /*  check for that */
1641 return( true );
1642 }
1643 
MKD_AspectChange(GGadget * g,GEvent * e)1644 static int MKD_AspectChange(GGadget *g, GEvent *e) {
1645     if ( e==NULL || (e->type==et_controlevent && e->u.control.subtype == et_radiochanged )) {
1646 	MathKernDlg *mkd = (MathKernDlg *) (((CharViewBase *) GDrawGetUserData(GGadgetGetWindow(g)))->container);
1647 	int new_aspect = GTabSetGetSel(g);
1648 
1649 	if ( new_aspect == mkd->last_aspect )
1650 return( true );
1651 
1652 	GGadgetSetEnabled(mkd->mb,new_aspect==0);
1653 
1654 	if ( new_aspect==0 ) {
1655 	    /* We are moving from textual to graphical. Parse text, clear old */
1656 	    /*  points, set new points */
1657 	} else {
1658 	    /* We are moving from graphical to textual. */
1659 	    if ( !mkd->saved_mathkern ) {
1660 		mkd->orig_mathkern = MathKernCopy(mkd->cursc->mathkern);
1661 		mkd->saved_mathkern = true;
1662 	    }
1663 	}
1664 	MKD_Parse(mkd);
1665 	mkd->last_aspect = new_aspect;
1666 	MKDFillup(mkd,mkd->cursc);
1667     }
1668 return( true );
1669 }
1670 
MathKernD_GlyphChanged(GGadget * g,GEvent * e)1671 static int MathKernD_GlyphChanged(GGadget *g, GEvent *e) {
1672     MathKernDlg *mkd = (MathKernDlg *) (((CharViewBase *) GDrawGetUserData(GGadgetGetWindow(g)))->container);
1673     if ( e->type==et_controlevent && e->u.control.subtype == et_listselected ) {
1674 	GTextInfo *sel = GGadgetGetListItemSelected(g);
1675 
1676 	if ( sel!=NULL && MKD_Parse(mkd)) {
1677 	    SplineChar *sc = sel->userdata;
1678 	    MKDFillupRefresh(mkd, sc);
1679 	}
1680     }
1681 return( true );
1682 }
1683 
MathKernD_Cancel(GGadget * g,GEvent * e)1684 static int MathKernD_Cancel(GGadget *g, GEvent *e) {
1685     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
1686 	MathKernDlg *mkd = (MathKernDlg *) (((CharViewBase *) GDrawGetUserData(GGadgetGetWindow(g)))->container);
1687 	if ( mkd->saved_mathkern ) {
1688 	    MathKernFree(mkd->cursc->mathkern);
1689 	    mkd->cursc->mathkern = mkd->orig_mathkern;
1690 	}
1691 	MKD_DoClose(((CharViewBase *) GDrawGetUserData(GGadgetGetWindow(g)))->container);
1692     }
1693 return( true );
1694 }
1695 
MathKernD_OK(GGadget * g,GEvent * e)1696 static int MathKernD_OK(GGadget *g, GEvent *e) {
1697     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
1698 	MathKernDlg *mkd = (MathKernDlg *) (((CharViewBase *) GDrawGetUserData(GGadgetGetWindow(g)))->container);
1699 	if ( MKD_Parse(mkd) ) {
1700 	    MathKernFree(mkd->orig_mathkern);
1701 	    mkd->orig_mathkern = NULL;
1702 	    mkd->saved_mathkern = false;
1703 	    MKD_DoClose( (struct cvcontainer *) mkd );
1704 	}
1705     }
1706 return( true );
1707 }
1708 
MKD_Can_Navigate(struct cvcontainer * cvc,enum nav_type type)1709 static int MKD_Can_Navigate(struct cvcontainer *cvc, enum nav_type type) {
1710 return( true );
1711 }
1712 
MKD_Can_Open(struct cvcontainer * cvc)1713 static int MKD_Can_Open(struct cvcontainer *cvc) {
1714 return( false );
1715 }
1716 
MKD_Do_Navigate(struct cvcontainer * cvc,enum nav_type type)1717 static void MKD_Do_Navigate(struct cvcontainer *cvc, enum nav_type type) {
1718     MathKernDlg *mkd = ( MathKernDlg * ) cvc;
1719     SplineChar *sc = NULL;
1720     int pos;
1721     GGadget *list = GWidgetGetControl(mkd->gw,CID_Glyph);
1722     int32 rows;
1723     GTextInfo **tis;
1724 
1725     if ( !MKD_Parse(mkd))
1726 return;
1727     MathKernFree(mkd->orig_mathkern);
1728     mkd->orig_mathkern = NULL;
1729     mkd->saved_mathkern = false;
1730 
1731     if ( type == nt_goto ) {
1732 	SplineFont *sf = mkd->cursc->parent;
1733 	int enc = GotoChar(sf,sf->fv->map,NULL);
1734 	if ( enc==-1 || sf->fv->map->map[enc]==-1 || (sc = sf->glyphs[ sf->fv->map->map[enc] ])==NULL )
1735 return;
1736 	if ( sc->mathkern==NULL )
1737 	    MKD_SetGlyphList(mkd,sc);
1738     } else if ( type == nt_next || type == nt_nextdef ) {
1739 	tis = GGadgetGetList(list,&rows);
1740 	for ( pos=rows-1; pos>=0; --pos )
1741 	    if ( tis[pos]->selected )
1742 	break;
1743 	++pos;
1744 	if ( pos==rows )
1745 return;
1746 	sc = tis[pos]->userdata;
1747     } else {
1748 	tis = GGadgetGetList(list,&rows);
1749 	for ( pos=rows-1; pos>=0; --pos )
1750 	    if ( tis[pos]->selected )
1751 	break;
1752 	if ( pos<=0 )
1753 return;
1754 	--pos;
1755 	sc = tis[pos]->userdata;
1756     }
1757     MKDFillupRefresh(mkd,sc);
1758 }
1759 
SF_Of_MKD(struct cvcontainer * foo)1760 static SplineFont *SF_Of_MKD(struct cvcontainer *foo) {
1761 return( NULL );
1762 }
1763 
1764 struct cvcontainer_funcs mathkern_funcs = {
1765     cvc_mathkern,
1766     (void (*) (struct cvcontainer *cvc,CharViewBase *cv)) MKDMakeActive,
1767     (void (*) (struct cvcontainer *cvc,void *)) MKDChar,
1768     MKD_Can_Navigate,
1769     MKD_Do_Navigate,
1770     MKD_Can_Open,
1771     MKD_DoClose,
1772     SF_Of_MKD
1773 };
1774 
MKDInit(MathKernDlg * mkd,SplineChar * sc)1775 static void MKDInit(MathKernDlg *mkd,SplineChar *sc) {
1776     int i;
1777 
1778     memset(mkd,0,sizeof(*mkd));
1779     mkd->base.funcs = &mathkern_funcs;
1780 
1781     for ( i=0; i<4; ++i ) {
1782 	SplineChar *msc = &(&mkd->sc_topright)[i];
1783 	CharView *mcv = &(&mkd->cv_topright)[i];
1784 	msc->orig_pos = i;
1785 	msc->unicodeenc = -1;
1786 	msc->name = i==0 ? _("TopRight") :
1787 		    i==1 ? _("TopLeft")  :
1788 		    i==2 ? _("BottomRight"):
1789 			    _("BottomLeft");
1790 	msc->parent = &mkd->dummy_sf;
1791 	msc->layer_cnt = 2;
1792 	msc->layers = calloc(2,sizeof(Layer));
1793 	LayerDefault(&msc->layers[0]);
1794 	LayerDefault(&msc->layers[1]);
1795 	mkd->chars[i] = msc;
1796 
1797 	mcv->b.sc = msc;
1798 	mcv->b.layerheads[dm_fore] = &msc->layers[ly_fore];
1799 	mcv->b.layerheads[dm_back] = &msc->layers[ly_back];
1800 	mcv->b.layerheads[dm_grid] = &mkd->dummy_sf.grid;
1801 	mcv->b.drawmode = dm_fore;
1802 	mcv->b.container = (struct cvcontainer *) mkd;
1803 	mcv->inactive = i!=0;
1804     }
1805     mkd->dummy_sf.glyphs = mkd->chars;
1806     mkd->dummy_sf.glyphcnt = mkd->dummy_sf.glyphmax = 4;
1807     mkd->dummy_sf.pfminfo.fstype = -1;
1808     mkd->dummy_sf.pfminfo.stylemap = -1;
1809     mkd->dummy_sf.fontname = mkd->dummy_sf.fullname = mkd->dummy_sf.familyname = "dummy";
1810     mkd->dummy_sf.weight = "Medium";
1811     mkd->dummy_sf.origname = "dummy";
1812     mkd->dummy_sf.ascent = sc->parent->ascent;
1813     mkd->dummy_sf.descent = sc->parent->descent;
1814     mkd->dummy_sf.layers = mkd->layerinfo;
1815     mkd->dummy_sf.layer_cnt = 2;
1816     mkd->layerinfo[ly_back].order2 = sc->layers[ly_back].order2;
1817     mkd->layerinfo[ly_back].name = _("Back");
1818     mkd->layerinfo[ly_fore].order2 = sc->layers[ly_fore].order2;
1819     mkd->layerinfo[ly_fore].name = _("Fore");
1820     mkd->dummy_sf.grid.order2 = sc->layers[ly_back].order2;
1821     mkd->dummy_sf.anchor = NULL;
1822 
1823     mkd->dummy_sf.fv = (FontViewBase *) &mkd->dummy_fv;
1824     mkd->dummy_fv.b.active_layer = ly_fore;
1825     mkd->dummy_fv.b.sf = &mkd->dummy_sf;
1826     mkd->dummy_fv.b.selected = mkd->sel;
1827     mkd->dummy_fv.cbw = mkd->dummy_fv.cbh = default_fv_font_size+1;
1828     mkd->dummy_fv.magnify = 1;
1829 
1830     mkd->dummy_fv.b.map = &mkd->dummy_map;
1831     mkd->dummy_map.map = mkd->map;
1832     mkd->dummy_map.backmap = mkd->backmap;
1833     mkd->dummy_map.enccount = mkd->dummy_map.encmax = mkd->dummy_map.backmax = 4;
1834     mkd->dummy_map.enc = &custom;
1835 }
1836 
MathKernDialog(SplineChar * sc,int def_layer)1837 void MathKernDialog(SplineChar *sc,int def_layer) {
1838     MathKernDlg mkd;
1839     GRect pos;
1840     GWindow gw;
1841     GWindowAttrs wattrs;
1842     GGadgetCreateData gcd[6], boxes[4], *harray[8], *varray[5], *garray[5];
1843     GGadgetCreateData cgcd[4][2], tabsetgcd[2];
1844     GTextInfo label[6];
1845     GTabInfo aspects[3], corners[5];
1846     FontRequest rq;
1847     int as, ds, ld;
1848     int i,k;
1849     static GFont *mathfont = NULL, *mathbold=NULL;
1850 
1851     MathInit();
1852     MKDInit( &mkd, sc );
1853     mkd.def_layer = def_layer;
1854 
1855     memset(&wattrs,0,sizeof(wattrs));
1856     wattrs.mask = wam_events|wam_cursor|wam_isdlg|wam_restrict|wam_undercursor|wam_utf8_wtitle;
1857     wattrs.is_dlg = true;
1858     wattrs.restrict_input_to_me = 1;
1859     wattrs.undercursor = 1;
1860     wattrs.event_masks = -1;
1861     wattrs.cursor = ct_pointer;
1862     wattrs.utf8_window_title = _("Math Kerning");
1863     pos.width = 600;
1864     pos.height = 400;
1865     mkd.gw = gw = GDrawCreateTopWindow(NULL,&pos,mkd_e_h,&mkd.cv_topright,&wattrs);
1866 
1867     if ( mathfont==NULL ) {
1868 	memset(&rq,0,sizeof(rq));
1869 	rq.utf8_family_name = SANS_UI_FAMILIES;
1870 	rq.point_size = 12;
1871 	rq.weight = 400;
1872 	mathfont = GDrawInstanciateFont(NULL,&rq);
1873 	mathfont = GResourceFindFont("Math.Font",mathfont);
1874 
1875 	GDrawDecomposeFont(mathfont, &rq);
1876 	rq.weight = 700;
1877 	mathbold = GDrawInstanciateFont(NULL,&rq);
1878 	mathbold = GResourceFindFont("Math.BoldFont",mathbold);
1879     }
1880     mkd.plain = mathfont;
1881     mkd.bold = mathbold;
1882     GDrawWindowFontMetrics(mkd.gw,mkd.plain,&as,&ds,&ld);
1883     mkd.fh = as+ds; mkd.as = as;
1884 
1885     memset(&label,0,sizeof(label));
1886     memset(&gcd,0,sizeof(gcd));
1887     memset(&boxes,0,sizeof(boxes));
1888     memset(&aspects,'\0',sizeof(aspects));
1889     memset(&corners,'\0',sizeof(corners));
1890     memset(&cgcd,0,sizeof(cgcd));
1891     memset(&tabsetgcd,0,sizeof(tabsetgcd));
1892 
1893     for ( k=0; k<4; ++k ) {
1894 	cgcd[k][0].gd.flags = gg_visible | gg_enabled;
1895 	cgcd[k][0].gd.u.matrix = &mi_mathkern;
1896 	cgcd[k][0].gd.cid = CID_TopRight+k;
1897 	cgcd[k][0].creator = GMatrixEditCreate;
1898 
1899 	corners[k].text = (unichar_t *) cornernames[k];
1900 	corners[k].text_is_1byte = true;
1901 	corners[k].gcd = cgcd[k];
1902     }
1903 
1904     tabsetgcd[0].gd.flags = gg_visible|gg_enabled|gg_tabset_vert ;
1905     tabsetgcd[0].gd.u.tabs = corners;
1906     tabsetgcd[0].gd.cid = CID_Corners;
1907     /*tabsetgcd[0].gd.handle_controlevent = MKD_AspectChange;*/
1908     tabsetgcd[0].creator = GTabSetCreate;
1909 
1910     k = 0;
1911     gcd[k].gd.flags = gg_visible|gg_enabled ;
1912     gcd[k].gd.pos.height = 18; gcd[k].gd.pos.width = 20;
1913     gcd[k++].creator = GSpacerCreate;
1914 
1915     aspects[0].text = (unichar_t *) _("Graphical");
1916     aspects[0].text_is_1byte = true;
1917     aspects[0].gcd = NULL;
1918 
1919     aspects[1].text = (unichar_t *) _("Textual");
1920     aspects[1].text_is_1byte = true;
1921     aspects[1].gcd = tabsetgcd;
1922 
1923     gcd[k].gd.flags = gg_visible|gg_enabled ;
1924     gcd[k].gd.u.tabs = aspects;
1925     gcd[k].gd.cid = CID_Tabs;
1926     gcd[k].gd.handle_controlevent = MKD_AspectChange;
1927     gcd[k++].creator = GTabSetCreate;
1928 
1929     gcd[k].gd.flags = gg_visible|gg_enabled ;
1930     gcd[k].gd.cid = CID_Glyph;
1931     gcd[k].gd.handle_controlevent = MathKernD_GlyphChanged;
1932     gcd[k++].creator = GListButtonCreate;
1933 
1934     label[k].text = (unichar_t *) _("_OK");
1935     label[k].text_is_1byte = true;
1936     label[k].text_in_resource = true;
1937     gcd[k].gd.label = &label[k];
1938     gcd[k].gd.flags = gg_enabled|gg_visible|gg_but_default;
1939     gcd[k].gd.handle_controlevent = MathKernD_OK;
1940     gcd[k++].creator = GButtonCreate;
1941 
1942     label[k].text = (unichar_t *) _("_Done");
1943     label[k].text_is_1byte = true;
1944     label[k].text_in_resource = true;
1945     gcd[k].gd.label = &label[k];
1946     gcd[k].gd.flags = gg_enabled|gg_visible|gg_but_cancel;
1947     gcd[k].gd.handle_controlevent = MathKernD_Cancel;
1948     gcd[k++].creator = GButtonCreate;
1949 
1950     harray[0] = GCD_Glue; harray[1] = &gcd[k-2]; harray[2] = GCD_Glue;
1951     harray[3] = GCD_Glue; harray[4] = &gcd[k-1]; harray[5] = GCD_Glue;
1952     harray[6] = NULL;
1953 
1954     boxes[2].gd.flags = gg_enabled|gg_visible;
1955     boxes[2].gd.u.boxelements = harray;
1956     boxes[2].creator = GHBoxCreate;
1957 
1958     garray[0] = &gcd[k-3]; garray[1] = GCD_Glue; garray[2] = NULL;
1959     boxes[3].gd.flags = gg_enabled|gg_visible;
1960     boxes[3].gd.u.boxelements = garray;
1961     boxes[3].creator = GHBoxCreate;
1962 
1963     varray[0] = &gcd[0];
1964     varray[1] = &gcd[1];
1965     varray[2] = &boxes[3];
1966     varray[3] = &boxes[2];
1967     varray[4] = NULL;
1968 
1969     boxes[0].gd.flags = gg_enabled|gg_visible;
1970     boxes[0].gd.u.boxelements = varray;
1971     boxes[0].gd.cid = CID_TopBox;
1972     boxes[0].creator = GVBoxCreate;
1973 
1974     GGadgetsCreate(gw,boxes);
1975 
1976     mkd.cvparent_w = GTabSetGetSubwindow(gcd[1].ret,0);
1977     GDrawSetEH(mkd.cvparent_w,mkd_sub_e_h);
1978     MKDCharViewInits(&mkd);
1979 
1980     MKD_SetGlyphList(&mkd, sc);
1981     MKDFillup( &mkd, sc );
1982 
1983     GHVBoxSetExpandableRow(boxes[0].ret,1);
1984     GHVBoxSetExpandableCol(boxes[2].ret,gb_expandgluesame);
1985     GHVBoxSetExpandableCol(boxes[3].ret,gb_expandglue);
1986     GGadgetResize(boxes[0].ret,pos.width,pos.height);
1987 
1988     mkd.button_height = GDrawPointsToPixels(gw,60);
1989     GDrawResize(gw,1000,400);		/* Force a resize event */
1990 
1991     GDrawSetVisible(mkd.gw,true);
1992 
1993     while ( !mkd.done )
1994 	GDrawProcessOneEvent(NULL);
1995 
1996     for ( i=0; i<4; ++i ) {
1997 	CharView *cv = &mkd.cv_topright + i;
1998 	if ( cv->backimgs!=NULL ) {
1999 	    GDrawDestroyWindow(cv->backimgs);
2000 	    cv->backimgs = NULL;
2001 	}
2002 	CVPalettesHideIfMine(cv);
2003     }
2004     GDrawDestroyWindow(mkd.gw);
2005 }
2006