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