1 /* -*- coding: utf-8 -*- */
2 /* Copyright (C) 2007-2012 by George Williams */
3 /*
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6 
7  * Redistributions of source code must retain the above copyright notice, this
8  * list of conditions and the following disclaimer.
9 
10  * Redistributions in binary form must reproduce the above copyright notice,
11  * this list of conditions and the following disclaimer in the documentation
12  * and/or other materials provided with the distribution.
13 
14  * The name of the author may not be used to endorse or promote products
15  * derived from this software without specific prior written permission.
16 
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
18  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
20  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
23  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
25  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
26  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include <fontforge-config.h>
30 
31 #include "autohint.h"
32 #include "cvundoes.h"
33 #include "dumppfa.h"
34 #include "fontforgeui.h"
35 #include "gkeysym.h"
36 #include "scstyles.h"
37 #include "ustring.h"
38 #include "utype.h"
39 
40 #include <math.h>
41 
42 /* Code for various stylistic changes embolden/thin, condense/extend, oblique */
43 
44 
45 /* ************************************************************************** */
46 /* ***************************** Condense/Extend **************************** */
47 /* ************************************************************************** */
48 
CVCondenseExtend(CharView * cv,struct counterinfo * ci)49 static void CVCondenseExtend(CharView *cv,struct counterinfo *ci) {
50     SplineChar *sc = cv->b.sc;
51 
52     if ( cv->b.drawmode == dm_grid )
53 return;
54 
55     SCCondenseExtend(ci, sc, CVLayer((CharViewBase *) cv),true);
56 
57     free( ci->zones[0]);
58     free( ci->zones[1]);
59 }
60 
61 typedef struct styledlg {
62     int done;
63     GWindow gw;
64     CharView *cv;
65     FontView *fv;
66     SplineFont *sf;
67     int layer;
68     struct smallcaps *small;
69     enum glyphchange_type gc;
70     bigreal scale;
71 } StyleDlg;
72 
73 #define CID_C_Factor	1001
74 #define CID_C_Add	1002
75 #define CID_SB_Factor	1003
76 #define CID_SB_Add	1004
77 #define CID_CorrectItalic	1005
78 
79 static struct counterinfo last_ci = {
80     90, 0, 90, 0, true,
81     /* initializers below are dummy... will be set later */
82     BLUEDATA_EMPTY, 0, NULL, 0, DBOUNDS_EMPTY, 0.0, 0.0, 0.0, 0,
83     { 0, 0 }, /* cnts */
84     { 0, 0 }, /* maxes */
85     { NULL, NULL } /* zones */
86 };
87 
CondenseExtend_OK(GGadget * g,GEvent * e)88 static int CondenseExtend_OK(GGadget *g, GEvent *e) {
89     struct counterinfo ci;
90     int err = false;
91 
92     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
93 	GWindow ew = GGadgetGetWindow(g);
94 	StyleDlg *ed = GDrawGetUserData(ew);
95 	memset(&ci,0,sizeof(ci));
96 	err = false;
97 	ci.c_factor  = GetReal8(ew,CID_C_Factor,_("Counter Expansion Factor"),&err);
98 	ci.c_add     = GetReal8(ew,CID_C_Add,_("Counter Addition"),&err);
99 	ci.sb_factor = GetReal8(ew,CID_SB_Factor,_("Side Bearing Expansion Factor"),&err);
100 	ci.sb_add    = GetReal8(ew,CID_SB_Add,_("Side Bearing Addition"),&err);
101 	ci.correct_italic= GGadgetIsChecked( GWidgetGetControl(ew,CID_CorrectItalic));
102 	if ( err )
103 return( true );
104 
105 	last_ci = ci;
106 
107 	CI_Init(&ci,ed->sf);
108 	if ( ed->fv!=NULL )
109 	    FVCondenseExtend((FontViewBase *) ed->fv, &ci);
110 	else
111 	    CVCondenseExtend(ed->cv, &ci);
112 	ed->done = true;
113     }
114 return( true );
115 }
116 
CondenseExtend_Cancel(GGadget * g,GEvent * e)117 static int CondenseExtend_Cancel(GGadget *g, GEvent *e) {
118     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
119 	StyleDlg *ed = GDrawGetUserData(GGadgetGetWindow(g));
120 	ed->done = true;
121     }
122 return( true );
123 }
124 
style_e_h(GWindow gw,GEvent * event)125 static int style_e_h(GWindow gw, GEvent *event) {
126     if ( event->type==et_close ) {
127 	StyleDlg *ed = GDrawGetUserData(gw);
128 	ed->done = true;
129     } else if ( event->type == et_char ) {
130 	if ( event->u.chr.keysym == GK_F1 || event->u.chr.keysym == GK_Help ) {
131 	    help("ui/dialogs/Styles.html", NULL);
132 return( true );
133 	}
134 return( false );
135     }
136 return( true );
137 }
138 
CondenseExtendDlg(FontView * fv,CharView * cv)139 void CondenseExtendDlg(FontView *fv, CharView *cv) {
140     StyleDlg ed;
141     SplineFont *sf = fv!=NULL ? fv->b.sf : cv->b.sc->parent;
142     GRect pos;
143     GWindow gw;
144     GWindowAttrs wattrs;
145     GGadgetCreateData gcd[15], boxes[6], *barray[8], *hvarray[31];
146     GTextInfo label[15];
147     int k;
148     char c_factor[40], c_add[40], sb_factor[40], sb_add[40];
149 
150     memset(&ed,0,sizeof(ed));
151     ed.fv = fv;
152     ed.cv = cv;
153     ed.sf = sf;
154 
155     memset(&wattrs,0,sizeof(wattrs));
156     wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_undercursor|wam_isdlg|wam_restrict;
157     wattrs.event_masks = ~(1<<et_charup);
158     wattrs.restrict_input_to_me = 1;
159     wattrs.undercursor = 1;
160     wattrs.cursor = ct_pointer;
161     wattrs.utf8_window_title = _("Condense/Extend");
162     wattrs.is_dlg = true;
163     pos.x = pos.y = 0;
164     pos.width = 100;
165     pos.height = 100;
166     ed.gw = gw = GDrawCreateTopWindow(NULL,&pos,style_e_h,&ed,&wattrs);
167 
168 
169     k=0;
170 
171     memset(gcd,0,sizeof(gcd));
172     memset(boxes,0,sizeof(boxes));
173     memset(label,0,sizeof(label));
174 
175     hvarray[0] = GCD_Glue;
176 
177     label[k].text = (unichar_t *) _("Scale By");
178     label[k].text_is_1byte = true;
179     label[k].text_in_resource = true;
180     gcd[k].gd.label = &label[k];
181     gcd[k].gd.flags = gg_enabled | gg_visible;
182     gcd[k++].creator = GLabelCreate;
183     hvarray[1] = &gcd[k-1];
184     hvarray[2] = GCD_Glue;
185 
186     label[k].text = (unichar_t *) _("Add");
187     label[k].text_is_1byte = true;
188     label[k].text_in_resource = true;
189     gcd[k].gd.label = &label[k];
190     gcd[k].gd.flags = gg_enabled | gg_visible;
191     gcd[k++].creator = GLabelCreate;
192     hvarray[3] = &gcd[k-1];
193     hvarray[4] = NULL;
194 
195     label[k].text = (unichar_t *) _("Counters:");
196     label[k].text_is_1byte = true;
197     label[k].text_in_resource = true;
198     gcd[k].gd.label = &label[k];
199     gcd[k].gd.flags = gg_enabled | gg_visible;
200     gcd[k++].creator = GLabelCreate;
201     hvarray[5] = &gcd[k-1];
202 
203     sprintf( c_factor, "%g", last_ci.c_factor );
204     label[k].text = (unichar_t *) c_factor;
205     label[k].text_is_1byte = true;
206     gcd[k].gd.label = &label[k];
207     gcd[k].gd.pos.width = 60;
208     gcd[k].gd.flags = gg_enabled | gg_visible;
209     gcd[k].gd.cid = CID_C_Factor;
210     gcd[k++].creator = GNumericFieldCreate;
211     hvarray[6] = &gcd[k-1];
212 
213     label[k].text = (unichar_t *) " % + ";
214     label[k].text_is_1byte = true;
215     label[k].text_in_resource = true;
216     gcd[k].gd.label = &label[k];
217     gcd[k].gd.flags = gg_enabled | gg_visible;
218     gcd[k++].creator = GLabelCreate;
219     hvarray[7] = &gcd[k-1];
220 
221     sprintf( c_add, "%g", last_ci.c_add );
222     label[k].text = (unichar_t *) c_add;
223     label[k].text_is_1byte = true;
224     gcd[k].gd.label = &label[k];
225     gcd[k].gd.pos.width = 60;
226     gcd[k].gd.flags = gg_enabled | gg_visible;
227     gcd[k].gd.cid = CID_C_Add;
228     gcd[k++].creator = GNumericFieldCreate;
229     hvarray[8] = &gcd[k-1];
230     hvarray[9] = NULL;
231 
232     label[k].text = (unichar_t *) _("Side Bearings:");
233     label[k].text_is_1byte = true;
234     label[k].text_in_resource = true;
235     gcd[k].gd.label = &label[k];
236     gcd[k].gd.flags = gg_enabled | gg_visible;
237     gcd[k++].creator = GLabelCreate;
238     hvarray[10] = &gcd[k-1];
239 
240     sprintf( sb_factor, "%g", last_ci.sb_factor );
241     label[k].text = (unichar_t *) sb_factor;
242     label[k].text_is_1byte = true;
243     gcd[k].gd.label = &label[k];
244     gcd[k].gd.pos.width = 60;
245     gcd[k].gd.flags = gg_enabled | gg_visible;
246     gcd[k].gd.cid = CID_SB_Factor;
247     gcd[k++].creator = GNumericFieldCreate;
248     hvarray[11] = &gcd[k-1];
249 
250     label[k].text = (unichar_t *) " % + ";
251     label[k].text_is_1byte = true;
252     label[k].text_in_resource = true;
253     gcd[k].gd.label = &label[k];
254     gcd[k].gd.flags = gg_enabled | gg_visible;
255     gcd[k++].creator = GLabelCreate;
256     hvarray[12] = &gcd[k-1];
257 
258     sprintf( sb_add, "%g", last_ci.sb_add );
259     label[k].text = (unichar_t *) sb_add;
260     label[k].text_is_1byte = true;
261     gcd[k].gd.label = &label[k];
262     gcd[k].gd.pos.width = 60;
263     gcd[k].gd.flags = gg_enabled | gg_visible;
264     gcd[k].gd.cid = CID_SB_Add;
265     gcd[k++].creator = GNumericFieldCreate;
266     hvarray[13] = &gcd[k-1];
267     hvarray[14] = NULL;
268 
269     label[k].text = (unichar_t *) _("Correct for Italic Angle");
270     label[k].text_is_1byte = true;
271     label[k].text_in_resource = true;
272     gcd[k].gd.label = &label[k];
273     gcd[k].gd.flags = gg_enabled | gg_visible| (last_ci.correct_italic?gg_cb_on:0);
274     gcd[k].gd.cid = CID_CorrectItalic;
275     gcd[k].gd.popup_msg = _("When FontForge detects that an expanded stroke will self-intersect,\nthen setting this option will cause it to try to make things nice\nby removing the intersections");
276     gcd[k++].creator = GCheckBoxCreate;
277     hvarray[15] = &gcd[k-1];
278     hvarray[16] = hvarray[17] = hvarray[18] = GCD_ColSpan; hvarray[19] = NULL;
279     if ( sf->italicangle==0 )
280 	gcd[k-1].gd.flags = ~gg_enabled;
281 
282     hvarray[20] = hvarray[21] = hvarray[22] = hvarray[23] = GCD_ColSpan; hvarray[24] = NULL;
283 
284     gcd[k].gd.pos.x = 30-3; gcd[k].gd.pos.y = 5;
285     gcd[k].gd.pos.width = -1;
286     gcd[k].gd.flags = gg_visible | gg_enabled | gg_but_default;
287     label[k].text = (unichar_t *) _("_OK");
288     label[k].text_is_1byte = true;
289     label[k].text_in_resource = true;
290     gcd[k].gd.label = &label[k];
291     gcd[k].gd.handle_controlevent = CondenseExtend_OK;
292     gcd[k++].creator = GButtonCreate;
293     barray[0] = GCD_Glue; barray[1] = &gcd[k-1]; barray[2] = GCD_Glue;
294 
295     gcd[k].gd.pos.x = -30; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y+3;
296     gcd[k].gd.pos.width = -1;
297     gcd[k].gd.flags = gg_visible | gg_enabled | gg_but_cancel;
298     label[k].text = (unichar_t *) _("_Cancel");
299     label[k].text_is_1byte = true;
300     label[k].text_in_resource = true;
301     gcd[k].gd.label = &label[k];
302     gcd[k].gd.handle_controlevent = CondenseExtend_Cancel;
303     gcd[k].creator = GButtonCreate;
304     barray[3] = GCD_Glue; barray[4] = &gcd[k]; barray[5] = GCD_Glue;
305     barray[6] = NULL;
306 
307     boxes[3].gd.flags = gg_enabled|gg_visible;
308     boxes[3].gd.u.boxelements = barray;
309     boxes[3].creator = GHBoxCreate;
310     hvarray[25] = &boxes[3];
311     hvarray[26] = hvarray[27] = hvarray[28] = GCD_ColSpan; hvarray[29] = NULL;
312     hvarray[30] = NULL;
313 
314     boxes[0].gd.pos.x = boxes[0].gd.pos.y = 2;
315     boxes[0].gd.flags = gg_enabled|gg_visible;
316     boxes[0].gd.u.boxelements = hvarray;
317     boxes[0].creator = GHVGroupCreate;
318 
319     GGadgetsCreate(gw,boxes);
320     GHVBoxSetExpandableRow(boxes[0].ret,gb_expandglue);
321     GHVBoxSetExpandableCol(boxes[3].ret,gb_expandgluesame);
322     GHVBoxFitWindow(boxes[0].ret);
323     GDrawSetVisible(gw,true);
324 
325     while ( !ed.done )
326 	GDrawProcessOneEvent(NULL);
327     GDrawDestroyWindow(gw);
328 }
329 
330 /* ************************************************************************** */
331 /* ************************* Generic Change Dialog ************************** */
332 /* ************************************************************************** */
333 
334 #undef CID_Letter_Ext
335 #undef CID_Symbol_Ext
336 #undef CID_Symbols_Too
337 
338 #undef CID_HScale
339 #undef CID_VScale
340 
341 #define CID_Feature		1001
342 #define CID_Extension		1002
343 #define CID_StemsUniform	1003
344 #define CID_Stems_H_V		1004
345 #define CID_Stems_by_Width	1005
346 #define CID_StemThreshold	1006
347 #define CID_StemHeight		1007
348 #define CID_StemHeightLabel	1008
349 #define CID_StemWidth		1009
350 #define CID_StemWidthLabel	1010
351 #define CID_StemHeightAdd	1011
352 #define CID_StemWidthAdd	1012
353 #define CID_DStemOn		1013
354 
355 #define CID_Counter_SameAdvance	1020
356 #define CID_Counter_PropAdvance	1021
357 #define CID_Counter_is_SideB	1022
358 #define CID_Counter_isnt_SideB	1023
359 #define CID_CounterPercent	1024
360 #define CID_CounterAdd		1025
361 #define CID_LSBPercent		1026
362 #define CID_LSBAdd		1027
363 #define CID_RSBPercent		1028
364 #define CID_RSBAdd		1029
365 
366 #define CID_UseVerticalCounters	1040
367 #define CID_VCounterPercent	1041
368 #define CID_VCounterAdd		1042
369 #define CID_UseVerticalMappings	1043
370 #define CID_VerticalScale	1044
371 #define CID_VMappings		1045
372 
373 #define CID_VerticalOff		1060
374 
375 #define CID_Letter_Ext		1081
376 #define CID_Symbol_Ext		1082
377 #define CID_Symbols_Too		1083
378 #define CID_SmallCaps		1084
379 #define CID_PetiteCaps		1085
380 
381 #define CID_TabSet		1100
382 
383 static GTextInfo ss_features[] = {
384     { (unichar_t *) N_("Superscript"), NULL, 0, 0, (void *) CHR('s','u','p','s'), NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
385     { (unichar_t *) N_("Scientific Inferiors"), NULL, 0, 0, (void *) CHR('s','i','n','f'), NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
386     { (unichar_t *) N_("Subscript"), NULL, 0, 0, (void *) CHR('s','u','b','s'), NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
387     { (unichar_t *) N_("Denominators"), NULL, 0, 0, (void *) CHR('d','n','o','m'), NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
388     { (unichar_t *) N_("Numerators"), NULL, 0, 0, (void *) CHR('n','u','m','r'), NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
389     GTEXTINFO_EMPTY
390 };
391 /* Not translated */
392 static char *ss_extensions[] = {
393     "superior",
394     "inferior",
395     "subscript",
396     "denominator",
397     "numerator",
398     NULL
399 };
400 static int ss_percent_xh_up[] = {
401     90,
402     -100,
403     -70,
404     -50,
405     50
406 };
407 
GuessStemThreshold(SplineFont * sf)408 static double GuessStemThreshold(SplineFont *sf) {
409     double stdvw = 0, stdhw = 0, avg;
410     char *ret;
411 
412     if ( sf->private!=NULL ) {
413 	if ((ret=PSDictHasEntry(sf->private,"StdVW"))!=NULL ) {
414 	    if ( ret[0] == '[' ) ret++;
415 	    stdvw = strtod(ret,NULL);
416 	}
417 	if ((ret=PSDictHasEntry(sf->private,"StdHW"))!=NULL ) {
418 	    if ( ret[0] == '[' ) ret++;
419 	    stdhw = strtod(ret,NULL);
420 	}
421     }
422     avg = (stdvw + stdhw)/2;
423     if ( avg<=0 )
424 	avg = (sf->ascent+sf->descent)/25;
425 return( avg );
426 }
427 
SS_Feature_Changed(GGadget * g,GEvent * e)428 static int SS_Feature_Changed(GGadget *g, GEvent *e) {
429 
430     if ( e->type==et_controlevent && e->u.control.subtype == et_textchanged &&
431 	    e->u.control.u.tf_changed.from_pulldown!=-1 ) {
432 	GWindow ew = GGadgetGetWindow(g);
433 	StyleDlg *ed = GDrawGetUserData(ew);
434 	int index = e->u.control.u.tf_changed.from_pulldown;
435 	uint32 tag = (intpt) ss_features[index].userdata;
436 	char tagbuf[5], offset[40];
437 
438 	tagbuf[0] = tag>>24; tagbuf[1] = tag>>16; tagbuf[2] = tag>>8; tagbuf[3] = tag; tagbuf[4] = 0;
439 	GGadgetSetTitle8(g,tagbuf);
440 	GGadgetSetTitle8(GWidgetGetControl(ew,CID_Extension), ss_extensions[index]);
441 
442 	sprintf( offset, "%g", rint( ed->small->xheight*ss_percent_xh_up[index]/100.0 ));
443 	GGadgetSetTitle8(GWidgetGetControl(ew,CID_VerticalOff), offset);
444     }
445 return( true );
446 }
447 
GlyphChange_OK(GGadget * g,GEvent * e)448 static int GlyphChange_OK(GGadget *g, GEvent *e) {
449     int err = false;
450 
451     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
452 	GWindow ew = GGadgetGetWindow(g);
453 	StyleDlg *ed = GDrawGetUserData(ew);
454 	struct genericchange genchange;
455 	int stem_xy_same = GGadgetIsChecked(GWidgetGetControl(ew,CID_StemsUniform));
456 	int stem_bywidth = GGadgetIsChecked(GWidgetGetControl(ew,CID_Stems_by_Width));
457 	enum glyphchange_type gc = ed->gc;
458 
459 	memset(&genchange,0,sizeof(genchange));
460 	genchange.gc = gc;
461 	genchange.small = ed->small;
462 	genchange.stem_height_scale = GetReal8(ew,CID_StemHeight,_("Horizontal Stem Height Scale"),&err)/100.;
463 	genchange.stem_height_add   = GetReal8(ew,CID_StemHeightAdd,_("Horizontal Stem Height Add"),&err);
464 	genchange.stem_threshold = stem_bywidth ? GetReal8(ew,CID_StemThreshold,_("Threshold between Thin and Thick Stems"),&err) : 0;
465 	if ( stem_xy_same ) {
466 	    genchange.stem_width_scale = genchange.stem_height_scale;
467 	    genchange.stem_width_add   = genchange.stem_height_add;
468 	} else {
469 	    genchange.stem_width_scale = GetReal8(ew,CID_StemWidth,_("Vertical Stem Width Scale"),&err)/100.;
470 	    genchange.stem_width_add   = stem_bywidth ? genchange.stem_height_add : GetReal8(ew,CID_StemWidthAdd,_("Vertical Stem Width Add"),&err);
471 	}
472 	genchange.dstem_control        = GGadgetIsChecked(GWidgetGetControl(ew,CID_DStemOn));
473 	if ( err )
474 return( true );
475 	if (stem_bywidth && genchange.stem_threshold <= 0)
476 	    ff_post_error(_("Unlikely stem threshold"), _("Stem threshold should be positive"));
477 	if ( genchange.stem_width_scale<.03 || genchange.stem_width_scale>10 ||
478 		genchange.stem_height_scale<.03 || genchange.stem_height_scale>10 ) {
479 	    ff_post_error(_("Unlikely scale factor"), _("Scale factors must be between 3 and 1000 percent"));
480 return( true );
481 	}
482 	if ( genchange.stem_height_add!=genchange.stem_width_add ) {
483 	    if (( genchange.stem_height_add==0 && genchange.stem_width_add!=0 ) ||
484 		    ( genchange.stem_height_add!=0 && genchange.stem_width_add==0 )) {
485 		ff_post_error(_("Bad stem add"), _("The horizontal and vertical stem add amounts must either both be zero, or neither may be 0"));
486 return( true );
487 	    }
488 	    /* if width_add has a different sign than height_add that's also */
489 	    /*  a problem, but this test will catch that too */
490 	    if (( genchange.stem_height_add/genchange.stem_width_add>4 ) ||
491 		    ( genchange.stem_height_add/genchange.stem_width_add<.25 )) {
492 		ff_post_error(_("Bad stem add"), _("The horizontal and vertical stem add amounts may not differ by more than a factor of 4"));
493 return( true );
494 	    }
495 	}
496 	if ( gc==gc_subsuper ) {
497 	    const unichar_t *tag_str = _GGadgetGetTitle(GWidgetGetControl(ew,CID_Feature));
498 	    char tag[4];
499 
500 	    memset(tag,' ',sizeof(tag));
501 	    if ( *tag_str=='\0' )
502 		genchange.feature_tag = 0;		/* Perfectly valid to have no tag */
503 	    else {
504 		tag[0] = *tag_str;
505 		if ( tag_str[1]!='\0' ) {
506 		    tag[1] = tag_str[1];
507 		    if ( tag_str[2]!='\0' ) {
508 			tag[2] = tag_str[2];
509 			if ( tag_str[3]!='\0' ) {
510 			    tag[3] = tag_str[3];
511 			    if ( tag_str[4]!='\0' ) {
512 				ff_post_error(_("Bad tag"), _("Feature tags are limited to 4 letters"));
513 return( true );
514 			    }
515 			}
516 		    }
517 		}
518 		genchange.feature_tag = (tag[0]<<24) | (tag[1]<<16) | (tag[2]<<8) | tag[3];
519 	    }
520 	    genchange.glyph_extension = GGadgetGetTitle8(GWidgetGetControl(ew,CID_Extension));
521 	    if ( *genchange.glyph_extension=='\0' ) {
522 		ff_post_error(_("Missing glyph extension"),_("You must specify a glyph extension"));
523 		free(genchange.glyph_extension);
524 return( true );
525 	    }
526 	    genchange.vertical_offset = GetReal8(ew,CID_VerticalOff,_("Vertical Offset"),&err);
527 	    if ( err )
528 return( true );
529 	} else if ( gc==gc_smallcaps ) {
530 	    genchange.do_smallcap_symbols = GGadgetIsChecked(GWidgetGetControl(ew,CID_Symbols_Too));
531 	    genchange.petite              = GGadgetIsChecked(GWidgetGetControl(ew,CID_PetiteCaps));
532 	    genchange.extension_for_letters = GGadgetGetTitle8(GWidgetGetControl(ew,CID_Letter_Ext));
533 	    genchange.extension_for_symbols = GGadgetGetTitle8(GWidgetGetControl(ew,CID_Symbol_Ext));
534 	    if ( *genchange.extension_for_letters=='\0' || (*genchange.extension_for_symbols=='\0' && genchange.do_smallcap_symbols )) {
535 		free( genchange.extension_for_letters );
536 		free( genchange.extension_for_symbols );
537 		ff_post_error(_("Missing extension"),_("You must provide a glyph extension"));
538 return( true );
539 	    }
540 	}
541 
542 	if (GGadgetIsChecked(GWidgetGetControl(ew,CID_Counter_SameAdvance)))
543 	    genchange.center_in_hor_advance = 1;
544 	else if (GGadgetIsChecked(GWidgetGetControl(ew,CID_Counter_PropAdvance)))
545 	    genchange.center_in_hor_advance = 2;
546 	else
547 	    genchange.center_in_hor_advance = 0;
548 	genchange.hcounter_scale = GetReal8(ew,CID_CounterPercent,_("Horizontal Counter Scale"),&err)/100.;
549 	genchange.hcounter_add   = GetReal8(ew,CID_CounterAdd,_("Horizontal Counter Add"),&err);
550 	if ( GGadgetIsChecked(GWidgetGetControl(ew,CID_Counter_is_SideB)) ) {
551 	    genchange.lsb_scale = genchange.hcounter_scale;
552 	    genchange.lsb_add   = genchange.hcounter_add;
553 	    genchange.rsb_scale = genchange.hcounter_scale;
554 	    genchange.rsb_add   = genchange.hcounter_add;
555 	} else {
556 	    genchange.lsb_scale = GetReal8(ew,CID_LSBPercent,_("Left Side Bearing Scale"),&err)/100.;
557 	    genchange.lsb_add   = GetReal8(ew,CID_LSBAdd,_("Left Side Bearing Add"),&err);
558 	    genchange.rsb_scale = GetReal8(ew,CID_RSBPercent,_("Right Side Bearing Scale"),&err)/100.;
559 	    genchange.rsb_add   = GetReal8(ew,CID_RSBAdd,_("Right Side Bearing Add"),&err);
560 	}
561 	if ( err )
562 return( true );
563 
564 	genchange.use_vert_mapping = GGadgetIsChecked(GWidgetGetControl(ew,CID_UseVerticalMappings));
565 	if ( genchange.use_vert_mapping ) {
566 	    GGadget *map = GWidgetGetControl(ew,CID_VMappings);
567 	    int i,j;
568 	    int rows, cols = GMatrixEditGetColCnt(map);
569 	    struct matrix_data *mappings = GMatrixEditGet(map, &rows);
570 
571 	    genchange.v_scale = GetReal8(ew,CID_VerticalScale,_("Vertical Scale"),&err)/100.;
572 	    if ( err )
573 return( true );
574 	    genchange.m.cnt = rows;
575 	    genchange.m.maps = malloc(rows*sizeof(struct position_maps));
576 	    for ( i=0; i<rows; ++i ) {
577 		genchange.m.maps[i].current   = mappings[cols*i+0].u.md_real;
578 		genchange.m.maps[i].desired   = mappings[cols*i+2].u.md_real;
579 		genchange.m.maps[i].cur_width = mappings[cols*i+1].u.md_real;
580 	    }
581 	    /* Order maps */
582 	    for ( i=0; i<rows; ++i ) for ( j=i+1; j<rows; ++j ) {
583 		if ( genchange.m.maps[i].current > genchange.m.maps[j].current ) {
584 		    struct position_maps temp;
585 		    temp = genchange.m.maps[i];
586 		    genchange.m.maps[i] = genchange.m.maps[j];
587 		    genchange.m.maps[j] =  temp;
588 		}
589 	    }
590 	} else {
591 	    genchange.vcounter_scale = GetReal8(ew,CID_VCounterPercent,_("Vertical Counter Scale"),&err)/100.;
592 	    genchange.vcounter_add   = GetReal8(ew,CID_VCounterAdd,_("Vertical Counter Add"),&err);
593 	    if ( err )
594 return( true );
595 	}
596 	if ( ed->gc == gc_smallcaps )
597 	    FVAddSmallCaps( (FontViewBase *) ed->fv, &genchange );
598 	else if ( ed->fv!=NULL )
599 	    FVGenericChange( (FontViewBase *) ed->fv, &genchange );
600 	else
601 	    CVGenericChange( (CharViewBase *) ed->cv, &genchange );
602 	free(genchange.glyph_extension);
603 	free(genchange.m.maps);
604 	free( genchange.extension_for_letters );
605 	free( genchange.extension_for_symbols );
606 	ed->done = true;
607     }
608 return( true );
609 }
610 
611 static GTextInfo stemwidth[] = {
612     { (unichar_t *) N_("Width of Vertical Stems:"), NULL, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
613     { (unichar_t *) N_("Width/Height of Thick Stems:"), NULL, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
614     GTEXTINFO_EMPTY
615 };
616 static GTextInfo stemheight[] = {
617     { (unichar_t *) N_("Height of Horizontal Stems:"), NULL, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
618     { (unichar_t *) N_("Width/Height of Thin Stems:"), NULL, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
619     GTEXTINFO_EMPTY
620 };
621 
CG_SameAs_Changed(GGadget * g,GEvent * e)622 static int CG_SameAs_Changed(GGadget *g, GEvent *e) {
623 
624     if ( e==NULL || (e->type==et_controlevent && e->u.control.subtype == et_radiochanged )) {
625 	GWindow ew = GGadgetGetWindow(g);
626 	int uniform = GGadgetIsChecked(GWidgetGetControl(ew,CID_StemsUniform));
627 	int by_dir = GGadgetIsChecked(GWidgetGetControl(ew,CID_Stems_H_V));
628 	int by_width = GGadgetIsChecked(GWidgetGetControl(ew,CID_Stems_by_Width));
629 	unichar_t *v_label = by_width ? stemwidth[1].text : stemwidth[0].text;
630 	unichar_t *h_label = by_width ? stemheight[1].text : stemheight[0].text;
631 
632 	GGadgetSetEnabled(GWidgetGetControl(ew,CID_StemWidth), !uniform);
633 	GGadgetSetEnabled(GWidgetGetControl(ew,CID_StemWidthAdd), by_dir);
634 	GGadgetSetEnabled(GWidgetGetControl(ew,CID_StemThreshold), by_width);
635 	if ( uniform ) {
636 	    GGadgetSetTitle(GWidgetGetControl(ew,CID_StemWidth),
637 		    _GGadgetGetTitle(GWidgetGetControl(ew,CID_StemHeight)));
638 	    GGadgetSetTitle(GWidgetGetControl(ew,CID_StemWidthAdd),
639 		    _GGadgetGetTitle(GWidgetGetControl(ew,CID_StemHeightAdd)));
640 	} else if ( by_width ) {
641 	    GGadgetSetTitle(GWidgetGetControl(ew,CID_StemWidthAdd),
642 		    _GGadgetGetTitle(GWidgetGetControl(ew,CID_StemHeightAdd)));
643 	}
644 
645 	GGadgetSetTitle8(GWidgetGetControl(ew,CID_StemWidthLabel), (char *) v_label);
646 	GGadgetSetTitle8(GWidgetGetControl(ew,CID_StemHeightLabel), (char *) h_label);
647     }
648 return( true );
649 }
650 
CG_VStem_Changed(GGadget * g,GEvent * e)651 static int CG_VStem_Changed(GGadget *g, GEvent *e) {
652 
653     if ( e->type==et_controlevent && e->u.control.subtype == et_textchanged ) {
654 	GWindow ew = GGadgetGetWindow(g);
655 	if ( GGadgetIsChecked(GWidgetGetControl(ew,CID_StemsUniform))) {
656 	    GGadgetSetTitle(GWidgetGetControl(ew,CID_StemWidth),
657 		    _GGadgetGetTitle(GWidgetGetControl(ew,CID_StemHeight)));
658 	    GGadgetSetTitle(GWidgetGetControl(ew,CID_StemWidthAdd),
659 		    _GGadgetGetTitle(GWidgetGetControl(ew,CID_StemHeightAdd)));
660 
661 	} else if ( GGadgetIsChecked(GWidgetGetControl(ew,CID_Stems_by_Width))) {
662 	    GGadgetSetTitle(GWidgetGetControl(ew,CID_StemWidthAdd),
663 		    _GGadgetGetTitle(GWidgetGetControl(ew,CID_StemHeightAdd)));
664 
665 	}
666     }
667 return( true );
668 }
669 
CG_CounterSameAs_Changed(GGadget * g,GEvent * e)670 static int CG_CounterSameAs_Changed(GGadget *g, GEvent *e) {
671 
672     if ( e==NULL || (e->type==et_controlevent && e->u.control.subtype == et_radiochanged )) {
673 	GWindow ew = GGadgetGetWindow(g);
674 	int on = GGadgetIsChecked(GWidgetGetControl(ew,CID_Counter_is_SideB));
675 	int enabled = GGadgetIsChecked(GWidgetGetControl(ew,CID_Counter_isnt_SideB));
676 	GGadgetSetEnabled(GWidgetGetControl(ew,CID_LSBPercent), enabled);
677 	GGadgetSetEnabled(GWidgetGetControl(ew,CID_LSBAdd), enabled);
678 	GGadgetSetEnabled(GWidgetGetControl(ew,CID_RSBPercent), enabled);
679 	GGadgetSetEnabled(GWidgetGetControl(ew,CID_RSBAdd), enabled);
680 	if ( on ) {
681 	    GGadgetSetTitle(GWidgetGetControl(ew,CID_LSBPercent),
682 		    _GGadgetGetTitle(GWidgetGetControl(ew,CID_CounterPercent)));
683 	    GGadgetSetTitle(GWidgetGetControl(ew,CID_LSBAdd),
684 		    _GGadgetGetTitle(GWidgetGetControl(ew,CID_CounterAdd)));
685 	    GGadgetSetTitle(GWidgetGetControl(ew,CID_RSBPercent),
686 		    _GGadgetGetTitle(GWidgetGetControl(ew,CID_CounterPercent)));
687 	    GGadgetSetTitle(GWidgetGetControl(ew,CID_RSBAdd),
688 		    _GGadgetGetTitle(GWidgetGetControl(ew,CID_CounterAdd)));
689 	}
690     }
691 return( true );
692 }
693 
CG_Counter_Changed(GGadget * g,GEvent * e)694 static int CG_Counter_Changed(GGadget *g, GEvent *e) {
695 
696     if ( e->type==et_controlevent && e->u.control.subtype == et_textchanged ) {
697 	GWindow ew = GGadgetGetWindow(g);
698 	if ( GGadgetIsChecked(GWidgetGetControl(ew,CID_Counter_is_SideB))) {
699 	    GGadgetSetTitle(GWidgetGetControl(ew,CID_LSBPercent),
700 		    _GGadgetGetTitle(GWidgetGetControl(ew,CID_CounterPercent)));
701 	    GGadgetSetTitle(GWidgetGetControl(ew,CID_LSBAdd),
702 		    _GGadgetGetTitle(GWidgetGetControl(ew,CID_CounterAdd)));
703 	    GGadgetSetTitle(GWidgetGetControl(ew,CID_RSBPercent),
704 		    _GGadgetGetTitle(GWidgetGetControl(ew,CID_CounterPercent)));
705 	    GGadgetSetTitle(GWidgetGetControl(ew,CID_RSBAdd),
706 		    _GGadgetGetTitle(GWidgetGetControl(ew,CID_CounterAdd)));
707 	}
708     }
709 return( true );
710 }
711 
CG_UseVCounters(GGadget * g,GEvent * e)712 static int CG_UseVCounters(GGadget *g, GEvent *e) {
713 
714     if ( e==NULL || (e->type==et_controlevent && e->u.control.subtype == et_radiochanged )) {
715 	GWindow ew = GGadgetGetWindow(g);
716 	int on = GGadgetIsChecked(GWidgetGetControl(ew,CID_UseVerticalCounters));
717 	GGadgetSetEnabled(GWidgetGetControl(ew,CID_VCounterPercent), on);
718 	GGadgetSetEnabled(GWidgetGetControl(ew,CID_VCounterAdd), on);
719 	GGadgetSetEnabled(GWidgetGetControl(ew,CID_VerticalScale), !on);
720 	GGadgetSetEnabled(GWidgetGetControl(ew,CID_VMappings), !on);
721     }
722 return( true );
723 }
724 
CG_VScale_Changed(GGadget * g,GEvent * e)725 static int CG_VScale_Changed(GGadget *g, GEvent *e) {
726 
727     if ( e->type==et_controlevent && e->u.control.subtype == et_textchanged ) {
728 	GWindow ew = GGadgetGetWindow(g);
729 	StyleDlg *ed = GDrawGetUserData(ew);
730 	int err=0;
731 	bigreal scale;
732 	GGadget *map = GWidgetGetControl(ew,CID_VMappings);
733 	int rows, cols = GMatrixEditGetColCnt(map);
734 	struct matrix_data *mappings = GMatrixEditGet(map, &rows);
735 	int i;
736 
737 	scale = GetCalmReal8(ew,CID_VerticalScale,"unused",&err)/100.0;
738 	if ( err || scale<=0 || RealNear(ed->scale,scale) )
739 return( true );
740 	for ( i=0; i<rows; ++i ) {
741 	    bigreal offset = mappings[cols*i+2].u.md_real - rint(ed->scale*mappings[cols*i+0].u.md_real);
742 	    mappings[cols*i+2].u.md_real =
743 		    rint(scale * mappings[cols*i+0].u.md_real) + offset;
744 	}
745 	ed->scale = scale;
746 	GGadgetRedraw(map);
747     }
748 return( true );
749 }
750 
CG_PetiteCapsChange(GGadget * g,GEvent * e)751 static int CG_PetiteCapsChange(GGadget *g, GEvent *e) {
752 
753     if ( e->type==et_controlevent && e->u.control.subtype == et_radiochanged ) {
754 	GWindow ew = GGadgetGetWindow(g);
755 	int petite = GGadgetIsChecked(GWidgetGetControl(ew,CID_PetiteCaps));
756 	GGadgetSetTitle8(GWidgetGetControl(ew,CID_Letter_Ext), petite ? "pc" : "sc" );
757     }
758 return( true );
759 }
760 
CG_SmallCapSymbols(GGadget * g,GEvent * e)761 static int CG_SmallCapSymbols(GGadget *g, GEvent *e) {
762 
763     if ( e->type==et_controlevent && e->u.control.subtype == et_radiochanged ) {
764 	GWindow ew = GGadgetGetWindow(g);
765 	int on = GGadgetIsChecked(g);
766 	GGadgetSetEnabled(GWidgetGetControl(ew,CID_Symbol_Ext), on);
767     }
768 return( true );
769 }
770 
ParseBlue(double blues[14],struct psdict * private,char * key)771 static int ParseBlue(double blues[14],struct psdict *private,char *key) {
772     int i;
773     char *val, *end;
774 
775     if ( private==NULL )
776 return( 0 );
777     if ( (val = PSDictHasEntry(private,key))==NULL )
778 return( 0 );
779     while ( isspace( *val ) || *val=='[' ) ++val;
780 
781     for ( i=0; i<14; ++i ) {
782 	while ( isspace( *val )) ++val;
783 	if ( *val==']' || *val=='\0' )
784 return( i );
785 	blues[i] = strtod(val,&end);
786 	if ( end==val )		/* Not a number */
787 return( 0 );
788 	val = end;
789     }
790 return( i );
791 }
792 
793 static struct col_init mapci[5] = {
794     { me_real, NULL, NULL, NULL, N_("Original Y Position") },
795     { me_real, NULL, NULL, NULL, N_("Extent") },
796     { me_real, NULL, NULL, NULL, N_("Resultant Y Position") },
797 };
MappingMatrixInit(struct matrixinit * mi,SplineFont * sf,double xheight,double capheight,double scale)798 static void MappingMatrixInit(struct matrixinit *mi,SplineFont *sf,
799 	double xheight, double capheight, double scale) {
800     struct matrix_data *md;
801     int cnt;
802     double blues[14], others[14];
803     int b=0,o=0,i,j;
804 
805     memset(mi,0,sizeof(*mi));
806     mi->col_cnt = 3;
807     mi->col_init = mapci;
808 
809     if ( sf->private!=NULL ) {
810 	b = ParseBlue(blues,sf->private,"BlueValues");
811 	o = ParseBlue(others,sf->private,"OtherBlues");
812     }
813 
814     if ( (b>1 && (b&1)==0) || (o>1 && (o&1)==0)) {
815 	b>>=1; o>>=1;
816 	md = calloc(3*(b+o),sizeof(struct matrix_data));
817 	mi->initial_row_cnt = b+o;
818 	mi->matrix_data = md;
819 
820 	for ( i=0; i<o; ++i ) {
821 	    md[3*i+0].u.md_real = others[2*i+1];
822 	    md[3*i+1].u.md_real = others[2*i] - others[2*i+1];
823 	    md[3*i+2].u.md_real = rint(scale*md[3*i+0].u.md_real);
824 	}
825 	for ( j=0; j<b; ++j ) {
826 	    if ( j==0 ) {
827 		md[3*(i+j)+0].u.md_real = blues[1];
828 		md[3*(i+j)+1].u.md_real = blues[0] - blues[1];
829 	    } else {
830 		md[3*(i+j)+0].u.md_real = blues[2*j];
831 		md[3*(i+j)+1].u.md_real = blues[2*j+1] - blues[2*j];
832 	    }
833 	    md[3*(i+j)+2].u.md_real = rint(scale*md[3*(i+j)+0].u.md_real);
834 	}
835     } else if ( xheight==0 && capheight==0 ) {
836 	md = calloc(3,sizeof(struct matrix_data));
837 	mi->initial_row_cnt = 1;
838 	mi->matrix_data = md;
839     } else {
840 	cnt = 1;	/* For the baseline */
841 	if ( xheight!=0 )
842 	    ++cnt;
843 	if ( capheight!=0 )
844 	    ++cnt;
845 	md = calloc(3*cnt,sizeof(struct matrix_data));
846 	mi->initial_row_cnt = cnt;
847 	mi->matrix_data = md;
848 	md[3*0+1].u.md_real = -1;
849 	cnt = 1;
850 	if ( xheight!=0 ) {
851 	    md[3*cnt+0].u.md_real =       xheight;
852 	    md[3*cnt+1].u.md_real =       1;
853 	    md[3*cnt+2].u.md_real = scale*xheight;
854 	    ++cnt;
855 	}
856 	if ( capheight!=0 ) {
857 	    md[3*cnt+0].u.md_real =       capheight;
858 	    md[3*cnt+1].u.md_real =       1;
859 	    md[3*cnt+2].u.md_real = scale*capheight;
860 	    ++cnt;
861 	}
862     }
863 }
864 
GlyphChange_Default(GGadget * g,GEvent * e)865 static int GlyphChange_Default(GGadget *g, GEvent *e) {
866 
867     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
868 	GWindow ew = GGadgetGetWindow(g);
869 	StyleDlg *ed = GDrawGetUserData(ew);
870 	enum glyphchange_type gc = ed->gc;
871 	bigreal glyph_scale = 1.0, stem_scale=1.0;
872 	char glyph_factor[40], stem_factor[40];
873 	struct matrixinit mapmi;
874 
875 	if ( gc==gc_subsuper ) {
876 	    GGadgetSetTitle8(GWidgetGetControl(ew,CID_Feature),"");
877 	    GGadgetSetTitle8(GWidgetGetControl(ew,CID_Extension),"");
878 	    GGadgetSetTitle8(GWidgetGetControl(ew,CID_VerticalOff),"");
879 
880 	    glyph_scale = 2.0/3.0;
881 	    stem_scale  = 3.0/4.0;
882 	} else if ( gc == gc_smallcaps ) {
883 	    GGadgetSetTitle8(GWidgetGetControl(ew,CID_Letter_Ext),"sc");
884 	    GGadgetSetTitle8(GWidgetGetControl(ew,CID_Symbol_Ext),"taboldstyle");
885 	    GGadgetSetChecked(GWidgetGetControl(ew,CID_Symbols_Too),false);
886 	    GGadgetSetChecked(GWidgetGetControl(ew,CID_SmallCaps),true);
887 
888 	    if ( ed->small->xheight!=0 && ed->small->capheight!=0 )
889 		glyph_scale = ed->small->xheight/ed->small->capheight;
890 	    if ( ed->small->lc_stem_width!=0 && ed->small->uc_stem_width!=0 )
891 		stem_scale  = ed->small->lc_stem_width/ed->small->uc_stem_width;
892 	}
893 	ed->scale = glyph_scale;
894 	sprintf( glyph_factor, "%.2f", (double) (100*glyph_scale) );
895 	sprintf( stem_factor , "%.2f", (double) (100* stem_scale) );
896 
897 	GGadgetSetChecked(GWidgetGetControl(ew,CID_StemsUniform),true);
898 	GGadgetSetTitle8(GWidgetGetControl(ew,CID_StemHeight),stem_factor);
899 	GGadgetSetTitle8(GWidgetGetControl(ew,CID_StemHeightAdd),"0");
900 	GGadgetSetTitle8(GWidgetGetControl(ew,CID_StemWidth),stem_factor);
901 	GGadgetSetTitle8(GWidgetGetControl(ew,CID_StemWidthAdd),"0");
902 	GGadgetSetChecked(GWidgetGetControl(ew,CID_DStemOn),true);
903 
904 	GGadgetSetChecked(GWidgetGetControl(ew,CID_Counter_is_SideB),true);
905 	GGadgetSetTitle8(GWidgetGetControl(ew,CID_CounterPercent),glyph_factor);
906 	GGadgetSetTitle8(GWidgetGetControl(ew,CID_CounterAdd),"0");
907 	GGadgetSetTitle8(GWidgetGetControl(ew,CID_LSBPercent),glyph_factor);
908 	GGadgetSetTitle8(GWidgetGetControl(ew,CID_LSBAdd),"0");
909 	GGadgetSetTitle8(GWidgetGetControl(ew,CID_RSBPercent),glyph_factor);
910 	GGadgetSetTitle8(GWidgetGetControl(ew,CID_RSBAdd),"0");
911 
912 	GGadgetSetChecked(GWidgetGetControl(ew,CID_UseVerticalMappings),true);
913 	GGadgetSetTitle8(GWidgetGetControl(ew,CID_VCounterPercent),glyph_factor);
914 	GGadgetSetTitle8(GWidgetGetControl(ew,CID_VCounterAdd),"0");
915 	GGadgetSetTitle8(GWidgetGetControl(ew,CID_VerticalScale),glyph_factor);
916 
917 	MappingMatrixInit(&mapmi,
918 		ed->sf,
919 		gc==gc_smallcaps?0:ed->small->xheight,
920 		ed->small->capheight,glyph_scale);
921 	GMatrixEditSet(GWidgetGetControl(ew,CID_VMappings),
922 		mapmi.matrix_data,mapmi.initial_row_cnt,false);
923 
924 	CG_SameAs_Changed(GWidgetGetControl(ew,CID_StemsUniform),NULL);
925 	CG_CounterSameAs_Changed(GWidgetGetControl(ew,CID_Counter_is_SideB),NULL);
926 	CG_UseVCounters(GWidgetGetControl(ew,CID_UseVerticalMappings),NULL);
927     }
928 return( true );
929 }
930 
GlyphChangeDlg(FontView * fv,CharView * cv,enum glyphchange_type gc)931 void GlyphChangeDlg(FontView *fv,CharView *cv, enum glyphchange_type gc) {
932     StyleDlg ed;
933     SplineFont *sf = fv!=NULL ? fv->b.sf : cv->b.sc->parent;
934     GRect pos;
935     GWindow gw;
936     GWindowAttrs wattrs;
937     GGadgetCreateData gcd[64], boxes[19], *barray[11], *stemarray[22], *stemtarray[6],
938 	    *stemarrayhc[20], *stemarrayvc[8], *varrayi[16], *varrays[15],
939 	    *varrayhc[14], *varrayvc[12], *pcarray[4],
940 	    *varray[7], *harray[6], *voarray[6], *extarray[7], *exarray[6];
941     GTextInfo label[64];
942     GTabInfo aspects[5];
943     int i,k,l,s, a;
944     struct smallcaps small;
945     struct matrixinit mapmi;
946     bigreal glyph_scale = 1.0, stem_scale=1.0;
947     char glyph_factor[40], stem_factor[40], stem_threshold[10];
948     int layer = fv!=NULL ? fv->b.active_layer : CVLayer((CharViewBase *) cv);
949     static GWindow last_dlg[gc_max] = { NULL };
950     static SplineFont *last_sf[gc_max] = { NULL };
951     static int intldone = false;
952 
953     memset(&ed,0,sizeof(ed));
954     ed.fv = fv;
955     ed.cv = cv;
956     ed.sf = sf;
957     ed.small = &small;
958     ed.gc = gc;
959 
960     if (!intldone) {
961 	intldone = true;
962 	for ( i=0; stemwidth[i].text; ++i )
963 	    stemwidth[i].text = (unichar_t *) _((char *) stemwidth[i].text);
964 	for ( i=0; stemheight[i].text; ++i )
965 	    stemheight[i].text = (unichar_t *) _((char *) stemheight[i].text);
966     }
967 
968     SmallCapsFindConstants(&small,sf,layer); /* I want to know the xheight... */
969 
970     if ( last_dlg[gc] == NULL || last_sf[gc] != sf ) {
971 	if ( last_dlg[gc]!=NULL )
972 	    GDrawDestroyWindow(last_dlg[gc]);
973 
974 	memset(&wattrs,0,sizeof(wattrs));
975 	wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_undercursor|wam_isdlg|wam_restrict;
976 	wattrs.event_masks = ~(1<<et_charup);
977 	wattrs.restrict_input_to_me = 1;
978 	wattrs.undercursor = 1;
979 	wattrs.cursor = ct_pointer;
980 	wattrs.utf8_window_title =  gc==gc_subsuper  ? _("Create Subscript/Superscript") :
981 				    gc==gc_smallcaps ? _("Create Small Caps") :
982 							_("Change Glyphs");
983 	wattrs.is_dlg = true;
984 	pos.x = pos.y = 0;
985 	pos.width = 100;
986 	pos.height = 100;
987 	ed.gw = gw = GDrawCreateTopWindow(NULL,&pos,style_e_h,&ed,&wattrs);
988 
989 
990 	k=l=s=a=0;
991 
992 	memset(aspects,0,sizeof(aspects));
993 	memset(gcd,0,sizeof(gcd));
994 	memset(boxes,0,sizeof(boxes));
995 	memset(label,0,sizeof(label));
996 	memset(stemarray,0,sizeof(stemarray));
997 
998 	if ( gc==gc_subsuper ) {
999 	    label[k].text = (unichar_t *) _(
1000 		"Unlike most commands this one does not work directly on the\n"
1001 		"selected glyphs. Instead, if you select a glyph FontForge will\n"
1002 		"create (or reuse) another glyph named by appending the extension\n"
1003 		"to the original name, and it will copy a modified version of\n"
1004 		"the original glyph into the new one.");
1005 	    label[k].text_is_1byte = true;
1006 	    label[k].text_in_resource = true;
1007 	    gcd[k].gd.label = &label[k];
1008 	    gcd[k].gd.flags = gg_enabled | gg_visible;
1009 	    gcd[k++].creator = GLabelCreate;
1010 	    varrayi[l++] = &gcd[k-1]; varrayi[l++] = NULL;
1011 
1012 
1013 	    gcd[k].gd.pos.width = 10; gcd[k].gd.pos.height = 10;
1014 	    gcd[k].gd.flags = gg_enabled | gg_visible;
1015 	    gcd[k++].creator = GSpacerCreate;
1016 	    varrayi[l++] = &gcd[k-1]; varrayi[l++] = NULL;
1017 
1018 	    label[k].text = (unichar_t *) _("Feature Tag:");
1019 	    label[k].text_is_1byte = true;
1020 	    label[k].text_in_resource = true;
1021 	    gcd[k].gd.label = &label[k];
1022 	    gcd[k].gd.pos.x = 5; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y+31;
1023 	    gcd[k].gd.flags = gg_enabled | gg_visible;
1024 	    gcd[k++].creator = GLabelCreate;
1025 	    extarray[0] = &gcd[k-1];
1026 
1027 	    label[k].text = (unichar_t *) "";
1028 	    label[k].text_is_1byte = true;
1029 	    gcd[k].gd.label = &label[k];
1030 	    gcd[k].gd.flags = gg_enabled | gg_visible;
1031 	    gcd[k].gd.cid = CID_Feature;
1032 	    gcd[k].gd.u.list = ss_features;
1033 	    gcd[k].gd.handle_controlevent = SS_Feature_Changed;
1034 	    gcd[k++].creator = GListFieldCreate;
1035 	    extarray[1] = &gcd[k-1];
1036 
1037 	    label[k].text = (unichar_t *) _("Glyph Extension:");
1038 	    label[k].text_is_1byte = true;
1039 	    label[k].text_in_resource = true;
1040 	    gcd[k].gd.label = &label[k];
1041 	    gcd[k].gd.pos.x = 5; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y+31;
1042 	    gcd[k].gd.flags = gg_enabled | gg_visible;
1043 	    gcd[k++].creator = GLabelCreate;
1044 	    extarray[2] = &gcd[k-1];
1045 
1046 	    label[k].text = (unichar_t *) "";
1047 	    label[k].text_is_1byte = true;
1048 	    gcd[k].gd.label = &label[k];
1049 	    gcd[k].gd.flags = gg_enabled | gg_visible;
1050 	    gcd[k].gd.cid = CID_Extension;
1051 	    gcd[k++].creator = GTextFieldCreate;
1052 	    extarray[3] = &gcd[k-1]; extarray[4] = NULL;
1053 
1054 	    boxes[2].gd.flags = gg_enabled|gg_visible;
1055 	    boxes[2].gd.u.boxelements = extarray;
1056 	    boxes[2].creator = GHBoxCreate;
1057 	    varrayi[l++] = &boxes[2]; varrayi[l++] = NULL;
1058 
1059 	    label[k].text = (unichar_t *) _("Vertical Offset:");
1060 	    label[k].text_is_1byte = true;
1061 	    label[k].text_in_resource = true;
1062 	    gcd[k].gd.label = &label[k];
1063 	    gcd[k].gd.pos.x = 5; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y+31;
1064 	    gcd[k].gd.flags = gg_enabled | gg_visible;
1065 	    gcd[k++].creator = GLabelCreate;
1066 	    voarray[0] = &gcd[k-1];
1067 
1068 	    label[k].text = (unichar_t *) "0";
1069 	    label[k].text_is_1byte = true;
1070 	    gcd[k].gd.label = &label[k];
1071 	    gcd[k].gd.flags = gg_enabled | gg_visible;
1072 	    gcd[k].gd.pos.width = 60;
1073 	    gcd[k].gd.cid = CID_VerticalOff;
1074 	    gcd[k++].creator = GTextFieldCreate;
1075 	    voarray[1]= &gcd[k-1]; voarray[2] = GCD_Glue; voarray[3] = NULL;
1076 
1077 	    boxes[3].gd.flags = gg_enabled|gg_visible;
1078 	    boxes[3].gd.u.boxelements = voarray;
1079 	    boxes[3].creator = GHBoxCreate;
1080 	    varrayi[l++] = &boxes[3]; varrayi[l++] = NULL;
1081 	    varrayi[l++] = GCD_Glue; varrayi[l++] = NULL; varrayi[l++] = NULL;
1082 
1083 	    boxes[4].gd.flags = gg_enabled|gg_visible;
1084 	    boxes[4].gd.u.boxelements = varrayi;
1085 	    boxes[4].creator = GHVBoxCreate;
1086 
1087 	    aspects[a].text = (unichar_t *) _("Introduction");
1088 	    aspects[a].text_is_1byte = true;
1089 	    aspects[a++].gcd = &boxes[4];
1090 
1091 	    glyph_scale = 2.0/3.0;
1092 	    stem_scale  = 3.0/4.0;
1093 	} else if ( gc == gc_smallcaps ) {
1094 	    label[k].text = (unichar_t *) _(
1095 		"Unlike most commands this one does not work directly on the\n"
1096 		"selected glyphs. Instead, if you select an \"A\" (or an \"a\")\n"
1097 		"FontForge will create (or reuse) a glyph named \"a.sc\", and\n"
1098 		"it will copy a modified version of the \"A\" glyph into \"a.sc\".");
1099 	    label[k].text_is_1byte = true;
1100 	    label[k].text_in_resource = true;
1101 	    gcd[k].gd.label = &label[k];
1102 	    gcd[k].gd.flags = gg_enabled | gg_visible;
1103 	    gcd[k++].creator = GLabelCreate;
1104 	    varrayi[l++] = &gcd[k-1]; varrayi[l++] = NULL;
1105 
1106 	    gcd[k].gd.pos.width = 10; gcd[k].gd.pos.height = 10;
1107 	    gcd[k].gd.flags = gg_enabled | gg_visible;
1108 	    gcd[k++].creator = GSpacerCreate;
1109 	    varrayi[l++] = &gcd[k-1]; varrayi[l++] = NULL;
1110 
1111 	    label[k].text = (unichar_t *) _("Small Caps");
1112 	    label[k].text_is_1byte = true;
1113 	    label[k].text_in_resource = true;
1114 	    gcd[k].gd.label = &label[k];
1115 	    gcd[k].gd.pos.x = 5; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y+31;
1116 	    gcd[k].gd.flags = gg_visible | gg_enabled | gg_cb_on;
1117 	    gcd[k].gd.handle_controlevent = CG_PetiteCapsChange;
1118 	    gcd[k].gd.cid = CID_SmallCaps;
1119 	    gcd[k++].creator = GRadioCreate;
1120 	    pcarray[0] = &gcd[k-1];
1121 
1122 	    label[k].text = (unichar_t *) _("Petite Caps");
1123 	    label[k].text_is_1byte = true;
1124 	    label[k].text_in_resource = true;
1125 	    gcd[k].gd.label = &label[k];
1126 	    gcd[k].gd.pos.x = 5; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y+31;
1127 	    gcd[k].gd.flags = gg_visible | gg_enabled ;
1128 	    gcd[k].gd.handle_controlevent = CG_PetiteCapsChange;
1129 	    gcd[k].gd.cid = CID_PetiteCaps;
1130 	    gcd[k++].creator = GRadioCreate;
1131 	    pcarray[1] = &gcd[k-1]; pcarray[2] = GCD_Glue; pcarray[3] = NULL;
1132 
1133 	    boxes[2].gd.flags = gg_enabled|gg_visible;
1134 	    boxes[2].gd.u.boxelements = pcarray;
1135 	    boxes[2].creator = GHBoxCreate;
1136 	    varrayi[l++] = &boxes[2]; varrayi[l++] = NULL;
1137 
1138 	    label[k].text = (unichar_t *) _("Glyph Extensions");
1139 	    label[k].text_is_1byte = true;
1140 	    label[k].text_in_resource = true;
1141 	    gcd[k].gd.label = &label[k];
1142 	    gcd[k].gd.pos.x = 5; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y+31;
1143 	    gcd[k].gd.flags = gg_visible | gg_enabled;
1144 	    gcd[k++].creator = GLabelCreate;
1145 	    varrayi[l++] = &gcd[k-1]; varrayi[l++] = NULL;
1146 
1147 	    label[k].text = (unichar_t *) _("Letters:");
1148 	    label[k].text_is_1byte = true;
1149 	    label[k].text_in_resource = true;
1150 	    gcd[k].gd.label = &label[k];
1151 	    gcd[k].gd.pos.x = 5; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y+31;
1152 	    gcd[k].gd.flags = gg_visible | gg_enabled;
1153 	    gcd[k++].creator = GLabelCreate;
1154 
1155 	    label[k].text = (unichar_t *) "sc";
1156 	    label[k].text_is_1byte = true;
1157 	    gcd[k].gd.label = &label[k];
1158 	    gcd[k].gd.pos.width = 80;
1159 	    gcd[k].gd.flags = gg_visible | gg_enabled;
1160 	    gcd[k].gd.cid = CID_Letter_Ext;
1161 	    gcd[k++].creator = GTextFieldCreate;
1162 
1163 	    label[k].text = (unichar_t *) _("Symbols:");
1164 	    label[k].text_is_1byte = true;
1165 	    label[k].text_in_resource = true;
1166 	    gcd[k].gd.label = &label[k];
1167 	    gcd[k].gd.pos.x = 5; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y+31;
1168 	    gcd[k].gd.flags = gg_visible | gg_enabled;
1169 	    gcd[k++].creator = GLabelCreate;
1170 
1171 	    label[k].text = (unichar_t *) "taboldstyle";
1172 	    label[k].text_is_1byte = true;
1173 	    gcd[k].gd.label = &label[k];
1174 	    gcd[k].gd.pos.width = 80;
1175 	    gcd[k].gd.flags = gg_visible;
1176 	    gcd[k].gd.cid = CID_Symbol_Ext;
1177 	    gcd[k++].creator = GTextFieldCreate;
1178 	    exarray[0] = &gcd[k-4]; exarray[1] = &gcd[k-3]; exarray[2] = &gcd[k-2]; exarray[3] = &gcd[k-1];
1179 	    exarray[4] = NULL;
1180 
1181 	    boxes[3].gd.flags = gg_enabled|gg_visible;
1182 	    boxes[3].gd.u.boxelements = exarray;
1183 	    boxes[3].creator = GHBoxCreate;
1184 	    varrayi[l++] = &boxes[3]; varrayi[l++] = NULL;
1185 
1186 	    label[k].text = (unichar_t *) _("Create small caps variants for symbols as well as letters");
1187 	    label[k].text_is_1byte = true;
1188 	    label[k].text_in_resource = true;
1189 	    gcd[k].gd.label = &label[k];
1190 	    gcd[k].gd.pos.x = 5; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y+31;
1191 	    gcd[k].gd.flags = gg_enabled | gg_visible;
1192 	    gcd[k].gd.handle_controlevent = CG_SmallCapSymbols;
1193 	    gcd[k].gd.cid = CID_Symbols_Too;
1194 	    gcd[k++].creator = GCheckBoxCreate;
1195 	    varrayi[l++] = &gcd[k-1]; varrayi[l++] = NULL;
1196 	    varrayi[l++] = GCD_Glue; varrayi[l++] = NULL; varrayi[l++] = NULL;
1197 
1198 	    boxes[4].gd.flags = gg_enabled|gg_visible;
1199 	    boxes[4].gd.u.boxelements = varrayi;
1200 	    boxes[4].creator = GHVBoxCreate;
1201 
1202 	    aspects[a].text = (unichar_t *) _("Introduction");
1203 	    aspects[a].text_is_1byte = true;
1204 	    aspects[a++].gcd = &boxes[4];
1205 
1206 	    if ( small.xheight!=0 && small.capheight!=0 )
1207 		glyph_scale = small.xheight/small.capheight;
1208 	    if ( small.lc_stem_width!=0 && small.uc_stem_width!=0 )
1209 		stem_scale  = small.lc_stem_width/small.uc_stem_width;
1210 	}
1211 
1212 	l = 0;
1213 
1214 	ed.scale = glyph_scale;
1215 	sprintf( glyph_factor, "%.2f", (double) (100*glyph_scale) );
1216 	sprintf( stem_factor , "%.2f", (double) (100* stem_scale) );
1217 
1218 	label[k].text = (unichar_t *) _("Uniform scaling for stems of any width and direction");
1219 	label[k].text_is_1byte = true;
1220 	label[k].text_in_resource = true;
1221 	gcd[k].gd.label = &label[k];
1222 	gcd[k].gd.pos.x = 5; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y+31;
1223 	gcd[k].gd.flags = gg_enabled | gg_visible | gg_cb_on;
1224 	gcd[k].gd.cid = CID_StemsUniform;
1225 	gcd[k].gd.handle_controlevent = CG_SameAs_Changed;
1226 	gcd[k++].creator = GRadioCreate;
1227 	varrays[l++] = &gcd[k-1]; varrays[l++] = NULL;
1228 
1229 	label[k].text = (unichar_t *) _("Separate ratios for thin and thick stems");
1230 	label[k].text_is_1byte = true;
1231 	label[k].text_in_resource = true;
1232 	gcd[k].gd.label = &label[k];
1233 	gcd[k].gd.pos.x = 5; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y+31;
1234 	gcd[k].gd.flags = gg_enabled | gg_visible;
1235 	gcd[k].gd.cid = CID_Stems_by_Width;
1236 	gcd[k].gd.handle_controlevent = CG_SameAs_Changed;
1237 	gcd[k++].creator = GRadioCreate;
1238 	varrays[l++] = &gcd[k-1]; varrays[l++] = NULL;
1239 
1240 	label[k].text = (unichar_t *) _("Threshold between \"thin\" and \"thick\":");
1241 	label[k].text_is_1byte = true;
1242 	label[k].text_in_resource = true;
1243 	gcd[k].gd.label = &label[k];
1244 	gcd[k].gd.pos.x = 5; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y+31;
1245 	gcd[k].gd.flags = gg_enabled | gg_visible;
1246 	gcd[k++].creator = GLabelCreate;
1247 	stemtarray[s++] = &gcd[k-1];
1248 
1249 	sprintf(stem_threshold,"%.0f",GuessStemThreshold(sf));
1250 	label[k].text = (unichar_t *) stem_threshold;
1251 	label[k].text_is_1byte = true;
1252 	gcd[k].gd.label = &label[k];
1253 	gcd[k].gd.flags = gg_visible;
1254 	gcd[k].gd.cid = CID_StemThreshold;
1255 	gcd[k].gd.pos.width = 60;
1256 	gcd[k++].creator = GTextFieldCreate;
1257 	stemtarray[s++] = &gcd[k-1];
1258 
1259 	label[k].text = (unichar_t *) _("em-units");
1260 	label[k].text_is_1byte = true;
1261 	label[k].text_in_resource = true;
1262 	gcd[k].gd.label = &label[k];
1263 	gcd[k].gd.pos.x = 5; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y+31;
1264 	gcd[k].gd.flags = gg_enabled | gg_visible;
1265 	gcd[k++].creator = GLabelCreate;
1266 	stemtarray[s++] = &gcd[k-1];
1267 	stemtarray[s++] = NULL;
1268 	stemtarray[s++] = NULL;
1269 
1270 	boxes[6].gd.flags = gg_enabled|gg_visible;
1271 	boxes[6].gd.u.boxelements = stemtarray;
1272 	boxes[6].creator = GHVBoxCreate;
1273 	varrays[l++] = &boxes[6]; varrays[l++] = NULL;
1274 
1275 	label[k].text = (unichar_t *) _("Separate ratios for horizontal and vertical stems");
1276 	label[k].text_is_1byte = true;
1277 	label[k].text_in_resource = true;
1278 	gcd[k].gd.label = &label[k];
1279 	gcd[k].gd.pos.x = 5; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y+31;
1280 	gcd[k].gd.flags = gg_enabled | gg_visible | gg_rad_continueold;
1281 	gcd[k].gd.cid = CID_Stems_H_V;
1282 	gcd[k].gd.handle_controlevent = CG_SameAs_Changed;
1283 	gcd[k++].creator = GRadioCreate;
1284 	varrays[l++] = &gcd[k-1]; varrays[l++] = NULL;
1285 
1286 	s = 0;
1287 	gcd[k].gd.pos.x = 5; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y+31;
1288 	gcd[k].gd.flags = gg_enabled | gg_visible;
1289 	gcd[k].gd.cid = CID_StemHeightLabel;
1290 	gcd[k].gd.u.list = stemheight;
1291 	gcd[k++].creator = GLabelCreate;
1292 	stemarray[s++] = &gcd[k-1];
1293 
1294 	label[k].text = (unichar_t *) stem_factor;
1295 	label[k].text_is_1byte = true;
1296 	gcd[k].gd.label = &label[k];
1297 	gcd[k].gd.flags = gg_enabled | gg_visible;
1298 	gcd[k].gd.cid = CID_StemHeight;
1299 	gcd[k].gd.handle_controlevent = CG_VStem_Changed;
1300 	gcd[k].gd.pos.width = 60;
1301 	gcd[k++].creator = GTextFieldCreate;
1302 	stemarray[s++] = &gcd[k-1];
1303 
1304 	label[k].text = (unichar_t *) _("% +");
1305 	label[k].text_is_1byte = true;
1306 	label[k].text_in_resource = true;
1307 	gcd[k].gd.label = &label[k];
1308 	gcd[k].gd.pos.x = 5; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y+31;
1309 	gcd[k].gd.flags = gg_enabled | gg_visible;
1310 	gcd[k++].creator = GLabelCreate;
1311 	stemarray[s++] = &gcd[k-1];
1312 
1313 	label[k].text = (unichar_t *) "0";
1314 	label[k].text_is_1byte = true;
1315 	gcd[k].gd.label = &label[k];
1316 	gcd[k].gd.flags = gg_enabled | gg_visible;
1317 	gcd[k].gd.pos.width = 60;
1318 	gcd[k].gd.cid = CID_StemHeightAdd;
1319 	gcd[k].gd.handle_controlevent = CG_VStem_Changed;
1320 	gcd[k++].creator = GTextFieldCreate;
1321 	stemarray[s++] = &gcd[k-1];
1322 
1323 	label[k].text = (unichar_t *) _("em-units");
1324 	label[k].text_is_1byte = true;
1325 	label[k].text_in_resource = true;
1326 	gcd[k].gd.label = &label[k];
1327 	gcd[k].gd.pos.x = 5; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y+31;
1328 	gcd[k].gd.flags = gg_enabled | gg_visible;
1329 	gcd[k++].creator = GLabelCreate;
1330 	stemarray[s++] = &gcd[k-1];
1331 	stemarray[s++] = NULL;
1332 
1333 	gcd[k].gd.pos.x = 5; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y+31;
1334 	gcd[k].gd.flags = gg_enabled | gg_visible;
1335 	gcd[k].gd.cid = CID_StemWidthLabel;
1336 	gcd[k].gd.u.list = stemwidth;
1337 	gcd[k++].creator = GLabelCreate;
1338 	stemarray[s++] = &gcd[k-1];
1339 
1340 	label[k].text = (unichar_t *) stem_factor;
1341 	label[k].text_is_1byte = true;
1342 	gcd[k].gd.label = &label[k];
1343 	gcd[k].gd.flags = gg_visible;
1344 	gcd[k].gd.cid = CID_StemWidth;
1345 	gcd[k].gd.pos.width = 60;
1346 	gcd[k++].creator = GTextFieldCreate;
1347 	stemarray[s++] = &gcd[k-1];
1348 
1349 	label[k].text = (unichar_t *) _("% +");
1350 	label[k].text_is_1byte = true;
1351 	label[k].text_in_resource = true;
1352 	gcd[k].gd.label = &label[k];
1353 	gcd[k].gd.pos.x = 5; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y+31;
1354 	gcd[k].gd.flags = gg_enabled | gg_visible;
1355 	gcd[k++].creator = GLabelCreate;
1356 	stemarray[s++] = &gcd[k-1];
1357 
1358 	label[k].text = (unichar_t *) "0";
1359 	label[k].text_is_1byte = true;
1360 	gcd[k].gd.label = &label[k];
1361 	gcd[k].gd.flags = gg_visible;
1362 	gcd[k].gd.pos.width = 60;
1363 	gcd[k].gd.cid = CID_StemWidthAdd;
1364 	gcd[k++].creator = GTextFieldCreate;
1365 	stemarray[s++] = &gcd[k-1];
1366 
1367 	label[k].text = (unichar_t *) _("em-units");
1368 	label[k].text_is_1byte = true;
1369 	label[k].text_in_resource = true;
1370 	gcd[k].gd.label = &label[k];
1371 	gcd[k].gd.pos.x = 5; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y+31;
1372 	gcd[k].gd.flags = gg_enabled | gg_visible;
1373 	gcd[k++].creator = GLabelCreate;
1374 	stemarray[s++] = &gcd[k-1];
1375 	stemarray[s++] = NULL;
1376 	stemarray[s++] = NULL;
1377 
1378 	boxes[7].gd.flags = gg_enabled|gg_visible;
1379 	boxes[7].gd.u.boxelements = stemarray;
1380 	boxes[7].creator = GHVBoxCreate;
1381 	varrays[l++] = &boxes[7]; varrays[l++] = NULL;
1382 
1383 	label[k].text = (unichar_t *) _("Activate diagonal stem processing");
1384 	label[k].text_is_1byte = true;
1385 	label[k].text_in_resource = true;
1386 	gcd[k].gd.label = &label[k];
1387 	gcd[k].gd.pos.x = 5; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y+31;
1388 	gcd[k].gd.flags = gg_enabled | gg_visible | gg_cb_on;
1389 	gcd[k].gd.cid = CID_DStemOn;
1390 	gcd[k++].creator = GCheckBoxCreate;
1391 	varrays[l++] = &gcd[k-1]; varrays[l++] = NULL;
1392 	varrays[l++] = GCD_Glue;  varrays[l++] = NULL; varrays[l++] = NULL;
1393 
1394 	boxes[8].gd.flags = gg_enabled|gg_visible;
1395 	boxes[8].gd.u.boxelements = varrays;
1396 	boxes[8].creator = GHVBoxCreate;
1397 
1398 	aspects[a].text = (unichar_t *) _("Stems");
1399 	aspects[a].text_is_1byte = true;
1400 	aspects[a++].gcd = &boxes[8];
1401 
1402 	l=s=0;
1403 
1404 	label[k].text = (unichar_t *) _("Retain current advance width, center glyph within that width");
1405 	label[k].text_is_1byte = true;
1406 	label[k].text_in_resource = true;
1407 	gcd[k].gd.label = &label[k];
1408 	gcd[k].gd.pos.x = 5; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y+31;
1409 	gcd[k].gd.flags = gg_enabled | gg_visible;
1410 	gcd[k].gd.cid = CID_Counter_SameAdvance;
1411 	gcd[k].gd.handle_controlevent = CG_CounterSameAs_Changed;
1412 	gcd[k++].creator = GRadioCreate;
1413 	varrayhc[l++] = &gcd[k-1]; varrayhc[l++] = NULL;
1414 
1415 	label[k].text = (unichar_t *) _("Retain current advance width, scale side bearings proportionally");
1416 	label[k].text_is_1byte = true;
1417 	label[k].text_in_resource = true;
1418 	gcd[k].gd.label = &label[k];
1419 	gcd[k].gd.pos.x = 5; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y+31;
1420 	gcd[k].gd.flags = gg_enabled | gg_visible;
1421 	gcd[k].gd.cid = CID_Counter_PropAdvance;
1422 	gcd[k].gd.handle_controlevent = CG_CounterSameAs_Changed;
1423 	gcd[k++].creator = GRadioCreate;
1424 	varrayhc[l++] = &gcd[k-1]; varrayhc[l++] = NULL;
1425 
1426 	label[k].text = (unichar_t *) _("Uniform scaling for horizontal counters and side bearings");
1427 	label[k].text_is_1byte = true;
1428 	label[k].text_in_resource = true;
1429 	gcd[k].gd.label = &label[k];
1430 	gcd[k].gd.pos.x = 5; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y+31;
1431 	gcd[k].gd.flags = gg_enabled | gg_visible | gg_cb_on;
1432 	gcd[k].gd.cid = CID_Counter_is_SideB;
1433 	gcd[k].gd.handle_controlevent = CG_CounterSameAs_Changed;
1434 	gcd[k++].creator = GRadioCreate;
1435 	varrayhc[l++] = &gcd[k-1]; varrayhc[l++] = NULL;
1436 
1437 	label[k].text = (unichar_t *) _("Non uniform scaling for horizontal counters and side bearings");
1438 	label[k].text_is_1byte = true;
1439 	label[k].text_in_resource = true;
1440 	gcd[k].gd.label = &label[k];
1441 	gcd[k].gd.pos.x = 5; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y+31;
1442 	gcd[k].gd.flags = gg_enabled | gg_visible;
1443 	gcd[k].gd.cid = CID_Counter_isnt_SideB;
1444 	gcd[k].gd.handle_controlevent = CG_CounterSameAs_Changed;
1445 	gcd[k++].creator = GRadioCreate;
1446 	varrayhc[l++] = &gcd[k-1]; varrayhc[l++] = NULL;
1447 
1448 	label[k].text = (unichar_t *) _("Counter Size:");
1449 	label[k].text_is_1byte = true;
1450 	label[k].text_in_resource = true;
1451 	gcd[k].gd.label = &label[k];
1452 	gcd[k].gd.flags = gg_enabled | gg_visible;
1453 	gcd[k++].creator = GLabelCreate;
1454 	stemarrayhc[s++] = &gcd[k-1];
1455 
1456 	label[k].text = (unichar_t *) glyph_factor;
1457 	label[k].text_is_1byte = true;
1458 	gcd[k].gd.label = &label[k];
1459 	gcd[k].gd.flags = gg_enabled | gg_visible;
1460 	gcd[k].gd.cid = CID_CounterPercent;
1461 	gcd[k].gd.handle_controlevent = CG_Counter_Changed;
1462 	gcd[k].gd.pos.width = 60;
1463 	gcd[k++].creator = GTextFieldCreate;
1464 	stemarrayhc[s++] = &gcd[k-1];
1465 
1466 	label[k].text = (unichar_t *) _("% +");
1467 	label[k].text_is_1byte = true;
1468 	label[k].text_in_resource = true;
1469 	gcd[k].gd.label = &label[k];
1470 	gcd[k].gd.flags = gg_enabled | gg_visible;
1471 	gcd[k++].creator = GLabelCreate;
1472 	stemarrayhc[s++] = &gcd[k-1];
1473 
1474 	label[k].text = (unichar_t *) "0";
1475 	label[k].text_is_1byte = true;
1476 	gcd[k].gd.label = &label[k];
1477 	gcd[k].gd.flags = gg_enabled | gg_visible;
1478 	gcd[k].gd.pos.width = 60;
1479 	gcd[k].gd.cid = CID_CounterAdd;
1480 	gcd[k].gd.handle_controlevent = CG_Counter_Changed;
1481 	gcd[k++].creator = GTextFieldCreate;
1482 	stemarrayhc[s++] = &gcd[k-1];
1483 
1484 	label[k].text = (unichar_t *) _("em-units");
1485 	label[k].text_is_1byte = true;
1486 	label[k].text_in_resource = true;
1487 	gcd[k].gd.label = &label[k];
1488 	gcd[k].gd.flags = gg_enabled | gg_visible;
1489 	gcd[k++].creator = GLabelCreate;
1490 	stemarrayhc[s++] = &gcd[k-1];
1491 	stemarrayhc[s++] = NULL;
1492 
1493 	label[k].text = (unichar_t *) _("Left Side Bearing:");
1494 	label[k].text_is_1byte = true;
1495 	label[k].text_in_resource = true;
1496 	gcd[k].gd.label = &label[k];
1497 	gcd[k].gd.flags = gg_enabled | gg_visible;
1498 	gcd[k++].creator = GLabelCreate;
1499 	stemarrayhc[s++] = &gcd[k-1];
1500 
1501 	label[k].text = (unichar_t *) glyph_factor;
1502 	label[k].text_is_1byte = true;
1503 	gcd[k].gd.label = &label[k];
1504 	gcd[k].gd.flags = gg_visible;
1505 	gcd[k].gd.cid = CID_LSBPercent;
1506 	gcd[k].gd.pos.width = 60;
1507 	gcd[k++].creator = GTextFieldCreate;
1508 	stemarrayhc[s++] = &gcd[k-1];
1509 
1510 	label[k].text = (unichar_t *) _("% +");
1511 	label[k].text_is_1byte = true;
1512 	label[k].text_in_resource = true;
1513 	gcd[k].gd.label = &label[k];
1514 	gcd[k].gd.flags = gg_enabled | gg_visible;
1515 	gcd[k++].creator = GLabelCreate;
1516 	stemarrayhc[s++] = &gcd[k-1];
1517 
1518 	label[k].text = (unichar_t *) "0";
1519 	label[k].text_is_1byte = true;
1520 	gcd[k].gd.label = &label[k];
1521 	gcd[k].gd.flags = gg_visible;
1522 	gcd[k].gd.pos.width = 60;
1523 	gcd[k].gd.cid = CID_LSBAdd;
1524 	gcd[k++].creator = GTextFieldCreate;
1525 	stemarrayhc[s++] = &gcd[k-1];
1526 
1527 	label[k].text = (unichar_t *) _("em-units");
1528 	label[k].text_is_1byte = true;
1529 	label[k].text_in_resource = true;
1530 	gcd[k].gd.label = &label[k];
1531 	gcd[k].gd.flags = gg_enabled | gg_visible;
1532 	gcd[k++].creator = GLabelCreate;
1533 	stemarrayhc[s++] = &gcd[k-1];
1534 	stemarrayhc[s++] = NULL;
1535 
1536 	label[k].text = (unichar_t *) _("Right Side Bearing:");
1537 	label[k].text_is_1byte = true;
1538 	label[k].text_in_resource = true;
1539 	gcd[k].gd.label = &label[k];
1540 	gcd[k].gd.flags = gg_enabled | gg_visible;
1541 	gcd[k++].creator = GLabelCreate;
1542 	stemarrayhc[s++] = &gcd[k-1];
1543 
1544 	label[k].text = (unichar_t *) glyph_factor;
1545 	label[k].text_is_1byte = true;
1546 	gcd[k].gd.label = &label[k];
1547 	gcd[k].gd.flags = gg_visible;
1548 	gcd[k].gd.cid = CID_RSBPercent;
1549 	gcd[k].gd.pos.width = 60;
1550 	gcd[k++].creator = GTextFieldCreate;
1551 	stemarrayhc[s++] = &gcd[k-1];
1552 
1553 	label[k].text = (unichar_t *) _("% +");
1554 	label[k].text_is_1byte = true;
1555 	label[k].text_in_resource = true;
1556 	gcd[k].gd.label = &label[k];
1557 	gcd[k].gd.flags = gg_enabled | gg_visible;
1558 	gcd[k++].creator = GLabelCreate;
1559 	stemarrayhc[s++] = &gcd[k-1];
1560 
1561 	label[k].text = (unichar_t *) "0";
1562 	label[k].text_is_1byte = true;
1563 	gcd[k].gd.label = &label[k];
1564 	gcd[k].gd.flags = gg_visible;
1565 	gcd[k].gd.pos.width = 60;
1566 	gcd[k].gd.cid = CID_RSBAdd;
1567 	gcd[k++].creator = GTextFieldCreate;
1568 	stemarrayhc[s++] = &gcd[k-1];
1569 
1570 	label[k].text = (unichar_t *) _("em-units");
1571 	label[k].text_is_1byte = true;
1572 	label[k].text_in_resource = true;
1573 	gcd[k].gd.label = &label[k];
1574 	gcd[k].gd.flags = gg_enabled | gg_visible;
1575 	gcd[k++].creator = GLabelCreate;
1576 	stemarrayhc[s++] = &gcd[k-1];
1577 	stemarrayhc[s++] = NULL;
1578 	stemarrayhc[s++] = NULL;
1579 
1580 	boxes[10].gd.flags = gg_enabled|gg_visible;
1581 	boxes[10].gd.u.boxelements = stemarrayhc;
1582 	boxes[10].creator = GHVBoxCreate;
1583 	varrayhc[l++] = &boxes[10]; varrayhc[l++] = NULL;
1584 	varrayhc[l++] = GCD_Glue; varrayhc[l++] = NULL; varrayhc[l++] = NULL;
1585 
1586 	boxes[11].gd.flags = gg_enabled|gg_visible;
1587 	boxes[11].gd.u.boxelements = varrayhc;
1588 	boxes[11].creator = GHVBoxCreate;
1589 
1590 	aspects[a].text = (unichar_t *) _("Horizontal");
1591 	aspects[a].text_is_1byte = true;
1592 	aspects[a++].gcd = &boxes[11];
1593 
1594 	l=s=0;
1595 
1596 	label[k].text = (unichar_t *) _("Control Vertical Counters (use for CJK)");
1597 	label[k].text_is_1byte = true;
1598 	label[k].text_in_resource = true;
1599 	gcd[k].gd.label = &label[k];
1600 	gcd[k].gd.flags = gg_enabled | gg_visible;
1601 	gcd[k].gd.handle_controlevent = CG_UseVCounters;
1602 	gcd[k].gd.cid = CID_UseVerticalCounters;
1603 	gcd[k++].creator = GRadioCreate;
1604 	varrayvc[l++] = &gcd[k-1]; varrayvc[l++] = NULL;
1605 
1606 	label[k].text = (unichar_t *) _("Vertical Counters:");
1607 	label[k].text_is_1byte = true;
1608 	label[k].text_in_resource = true;
1609 	gcd[k].gd.label = &label[k];
1610 	gcd[k].gd.flags = gg_enabled | gg_visible;
1611 	gcd[k++].creator = GLabelCreate;
1612 	stemarrayvc[s++] = &gcd[k-1];
1613 
1614 	label[k].text = (unichar_t *) glyph_factor;
1615 	label[k].text_is_1byte = true;
1616 	gcd[k].gd.label = &label[k];
1617 	gcd[k].gd.flags = gg_visible;
1618 	gcd[k].gd.cid = CID_VCounterPercent;
1619 	gcd[k].gd.pos.width = 60;
1620 	gcd[k++].creator = GTextFieldCreate;
1621 	stemarrayvc[s++] = &gcd[k-1];
1622 
1623 	label[k].text = (unichar_t *) _("% +");
1624 	label[k].text_is_1byte = true;
1625 	label[k].text_in_resource = true;
1626 	gcd[k].gd.label = &label[k];
1627 	gcd[k].gd.flags = gg_enabled | gg_visible;
1628 	gcd[k++].creator = GLabelCreate;
1629 	stemarrayvc[s++] = &gcd[k-1];
1630 
1631 	label[k].text = (unichar_t *) "0";
1632 	label[k].text_is_1byte = true;
1633 	gcd[k].gd.label = &label[k];
1634 	gcd[k].gd.flags = gg_visible;
1635 	gcd[k].gd.pos.width = 60;
1636 	gcd[k].gd.cid = CID_VCounterAdd;
1637 	gcd[k++].creator = GTextFieldCreate;
1638 	stemarrayvc[s++] = &gcd[k-1];
1639 
1640 	label[k].text = (unichar_t *) _("em-units");
1641 	label[k].text_is_1byte = true;
1642 	label[k].text_in_resource = true;
1643 	gcd[k].gd.label = &label[k];
1644 	gcd[k].gd.flags = gg_enabled | gg_visible;
1645 	gcd[k++].creator = GLabelCreate;
1646 	stemarrayvc[s++] = &gcd[k-1];
1647 	stemarrayvc[s++] = NULL; stemarrayvc[s++] = NULL;
1648 
1649 	if ( s > sizeof(stemarrayvc)/sizeof(stemarrayvc[0]) )
1650 	    IError( "Increase size of stemarrayvc" );
1651 
1652 	boxes[13].gd.flags = gg_enabled|gg_visible;
1653 	boxes[13].gd.u.boxelements = stemarrayvc;
1654 	boxes[13].creator = GHBoxCreate;
1655 	varrayvc[l++] = &boxes[13]; varrayvc[l++] = NULL;
1656 
1657 	label[k].text = (unichar_t *) _("Control Vertical Mapping (use for Latin, Greek, Cyrillic)");
1658 	label[k].text_is_1byte = true;
1659 	label[k].text_in_resource = true;
1660 	gcd[k].gd.label = &label[k];
1661 	gcd[k].gd.flags = gg_enabled | gg_visible| gg_cb_on | gg_rad_continueold;
1662 	gcd[k].gd.popup_msg = _("These mappings may be used to fix certain standard heights.");
1663 	gcd[k].gd.cid = CID_UseVerticalMappings;
1664 	gcd[k].gd.handle_controlevent = CG_UseVCounters;
1665 	gcd[k++].creator = GRadioCreate;
1666 	varrayvc[l++] = &gcd[k-1]; varrayvc[l++] = NULL;
1667 
1668 	s = 0;
1669 	label[k].text = (unichar_t *) _("Vertical Scale:");
1670 	label[k].text_is_1byte = true;
1671 	label[k].text_in_resource = true;
1672 	gcd[k].gd.label = &label[k];
1673 	gcd[k].gd.flags = gg_enabled | gg_visible;
1674 	gcd[k++].creator = GLabelCreate;
1675 	harray[s++] = &gcd[k-1];
1676 
1677 	label[k].text = (unichar_t *) glyph_factor;
1678 	label[k].text_is_1byte = true;
1679 	gcd[k].gd.label = &label[k];
1680 	gcd[k].gd.flags = gg_enabled | gg_visible;
1681 	gcd[k].gd.cid = CID_VerticalScale;
1682 	gcd[k].gd.pos.width = 60;
1683 	gcd[k].gd.handle_controlevent = CG_VScale_Changed;
1684 	gcd[k++].creator = GTextFieldCreate;
1685 	harray[s++] = &gcd[k-1];
1686 
1687 	label[k].text = (unichar_t *) _("%");
1688 	label[k].text_is_1byte = true;
1689 	label[k].text_in_resource = true;
1690 	gcd[k].gd.label = &label[k];
1691 	gcd[k].gd.flags = gg_enabled | gg_visible;
1692 	gcd[k++].creator = GLabelCreate;
1693 	harray[s++] = &gcd[k-1]; harray[s++] = GCD_Glue; harray[s++] = NULL;
1694 
1695 	boxes[14].gd.flags = gg_enabled|gg_visible;
1696 	boxes[14].gd.u.boxelements = harray;
1697 	boxes[14].creator = GHBoxCreate;
1698 	varrayvc[l++] = &boxes[14]; varrayvc[l++] = NULL;
1699 
1700 
1701 	MappingMatrixInit(&mapmi,
1702 		sf,
1703 		gc==gc_smallcaps?0:small.xheight,
1704 		small.capheight,glyph_scale);
1705 
1706 	gcd[k].gd.flags = gg_enabled | gg_visible;
1707 	gcd[k].gd.cid = CID_VMappings;
1708 	gcd[k].gd.u.matrix = &mapmi;
1709 	gcd[k++].creator = GMatrixEditCreate;
1710 	varrayvc[l++] = &gcd[k-1]; varrayvc[l++] = NULL; varrayvc[l++] = NULL;
1711 
1712 	boxes[15].gd.flags = gg_enabled|gg_visible;
1713 	boxes[15].gd.u.boxelements = varrayvc;
1714 	boxes[15].creator = GHVBoxCreate;
1715 
1716 	aspects[a].text = (unichar_t *) _("Vertical");
1717 	aspects[a].text_is_1byte = true;
1718 	aspects[a++].gcd = &boxes[15];
1719 
1720 	l=0;
1721 
1722 	gcd[k].gd.u.tabs = aspects;
1723 	gcd[k].gd.flags = gg_visible | gg_enabled | gg_tabset_scroll;
1724 	gcd[k].gd.cid = CID_TabSet;
1725 	gcd[k++].creator = GTabSetCreate;
1726 	varray[l++] = &gcd[k-1]; varray[l++] = NULL;
1727 
1728 
1729 	gcd[k].gd.pos.x = 30-3; gcd[k].gd.pos.y = 5;
1730 	gcd[k].gd.pos.width = -1;
1731 	gcd[k].gd.flags = gg_visible | gg_enabled | gg_but_default;
1732 	label[k].text = (unichar_t *) _("_OK");
1733 	label[k].text_is_1byte = true;
1734 	label[k].text_in_resource = true;
1735 	gcd[k].gd.label = &label[k];
1736 	gcd[k].gd.handle_controlevent = GlyphChange_OK;
1737 	gcd[k++].creator = GButtonCreate;
1738 	barray[0] = GCD_Glue; barray[1] = &gcd[k-1]; barray[2] = GCD_Glue;
1739 
1740 	gcd[k].gd.flags = gg_visible | gg_enabled;
1741 	gcd[k].gd.popup_msg = _("Everything to its default value");
1742 	label[k].text = (unichar_t *) _("Reset");
1743 	label[k].text_is_1byte = true;
1744 	label[k].text_in_resource = true;
1745 	gcd[k].gd.label = &label[k];
1746 	gcd[k].gd.handle_controlevent = GlyphChange_Default;
1747 	gcd[k++].creator = GButtonCreate;
1748 	barray[3] = GCD_Glue; barray[4] = &gcd[k-1]; barray[5] = GCD_Glue;
1749 
1750 	gcd[k].gd.pos.x = -30; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y+3;
1751 	gcd[k].gd.pos.width = -1;
1752 	gcd[k].gd.flags = gg_visible | gg_enabled | gg_but_cancel;
1753 	label[k].text = (unichar_t *) _("_Cancel");
1754 	label[k].text_is_1byte = true;
1755 	label[k].text_in_resource = true;
1756 	gcd[k].gd.label = &label[k];
1757 	gcd[k].gd.handle_controlevent = CondenseExtend_Cancel;
1758 	gcd[k].creator = GButtonCreate;
1759 	barray[6] = GCD_Glue; barray[7] = &gcd[k]; barray[8] = GCD_Glue;
1760 	barray[9] = NULL;
1761 
1762 	boxes[17].gd.flags = gg_enabled|gg_visible;
1763 	boxes[17].gd.u.boxelements = barray;
1764 	boxes[17].creator = GHBoxCreate;
1765 	varray[l++] = &boxes[17]; varray[l++] = NULL; varray[l++] = NULL;
1766 
1767 	if ( l>=sizeof(varray)/sizeof(varray[0]))
1768 	    IError("Increase size of varray" );
1769 	if ( k>=sizeof(gcd)/sizeof(gcd[0]))
1770 	    IError("Increase size of gcd" );
1771 	if ( k>=sizeof(label)/sizeof(label[0]))
1772 	    IError("Increase size of label" );
1773 
1774 	boxes[0].gd.pos.x = boxes[0].gd.pos.y = 2;
1775 	boxes[0].gd.flags = gg_enabled|gg_visible;
1776 	boxes[0].gd.u.boxelements = varray;
1777 	boxes[0].creator = GHVGroupCreate;
1778 
1779 	GGadgetsCreate(gw,boxes);
1780 	GHVBoxSetExpandableCol(boxes[13].ret,gb_expandglue);
1781 	if ( boxes[2].ret!=NULL )
1782 	    GHVBoxSetExpandableCol(boxes[2].ret,gb_expandglue);
1783 	if ( boxes[3].ret!=NULL )
1784 	    GHVBoxSetExpandableCol(boxes[3].ret,gb_expandglue);
1785 	if ( boxes[4].ret!=NULL )
1786 	    GHVBoxSetExpandableRow(boxes[4].ret,gb_expandglue);
1787 	GHVBoxSetExpandableRow(boxes[8].ret,gb_expandglue);
1788 	GHVBoxSetExpandableRow(boxes[11].ret,gb_expandglue);
1789 	GHVBoxSetExpandableRow(boxes[15].ret,4);
1790 	GHVBoxSetExpandableCol(boxes[17].ret,gb_expandgluesame);
1791 	GHVBoxSetExpandableRow(boxes[0].ret,0);
1792 	GHVBoxFitWindow(boxes[0].ret);
1793 	/* if ( gc==gc_subsuper ) */
1794 	    /* GMatrixEditShowColumn(GWidgetGetControl(gw,CID_VMappings),2,false);*/
1795 	last_dlg[gc] = gw;
1796 	last_sf[gc] = sf;
1797     } else {
1798 	int err = false;
1799 	ed.gw = gw = last_dlg[gc];
1800 	ed.scale = GetCalmReal8(gw,CID_VerticalScale,"unused",&err)/100.0;
1801 	if ( err )
1802 	    ed.scale = 1;
1803 	GDrawSetUserData(last_dlg[gc],&ed);
1804 	GDrawSetTransientFor(last_dlg[gc],(GWindow) -1);
1805     }
1806     GDrawSetVisible(gw,true);
1807 
1808     while ( !ed.done )
1809 	GDrawProcessOneEvent(NULL);
1810     GDrawSetVisible(gw,false);
1811 }
1812 
1813 /* ************************************************************************** */
1814 /* ***************************** Embolden Dialog **************************** */
1815 /* ************************************************************************** */
1816 
1817 #define CID_EmBdWidth	1001
1818 #define CID_LCG		1002
1819 #define CID_CJK		1003
1820 #define CID_Auto	1004
1821 #define CID_Custom	1005
1822 #define CID_TopZone	1006
1823 #define CID_BottomZone	1007
1824 #define CID_CleanupSelfIntersect	1008
1825 #define CID_TopHint	1009
1826 #define CID_BottomHint	1010
1827 #define CID_Squish	1011
1828 #define CID_Retain	1012
1829 #define CID_CounterAuto	1013
1830 #define CID_SerifHeight	1014
1831 #define CID_SerifHFuzz	1015
1832 
1833 static SplineFont *lastsf = NULL;
1834 static enum embolden_type last_type = embolden_auto;
1835 static struct lcg_zones last_zones;
1836 static int last_width;
1837 static int last_overlap = true;
1838 
Embolden_OK(GGadget * g,GEvent * e)1839 static int Embolden_OK(GGadget *g, GEvent *e) {
1840     enum embolden_type type;
1841     struct lcg_zones zones;
1842     int err = false;
1843 
1844     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
1845 	GWindow ew = GGadgetGetWindow(g);
1846 	StyleDlg *ed = GDrawGetUserData(ew);
1847 	memset(&zones,0,sizeof(zones));
1848 	err = false;
1849 	zones.stroke_width = GetReal8(ew,CID_EmBdWidth,_("Embolden by"),&err);
1850 	type = GGadgetIsChecked( GWidgetGetControl(ew,CID_LCG)) ? embolden_lcg :
1851 		GGadgetIsChecked( GWidgetGetControl(ew,CID_CJK)) ? embolden_cjk :
1852 		GGadgetIsChecked( GWidgetGetControl(ew,CID_Auto)) ? embolden_auto :
1853 			embolden_custom;
1854 	zones.serif_height = GetReal8(ew,CID_SerifHeight,_("Serif Height"),&err);
1855 	zones.serif_fuzz = GetReal8(ew,CID_SerifHFuzz,_("Serif Height Fuzz"),&err);
1856 	if ( type == embolden_custom ) {
1857 	    zones.top_zone = GetReal8(ew,CID_TopZone,_("Top Zone"),&err);
1858 	    zones.bottom_zone = GetReal8(ew,CID_BottomZone,_("Bottom Zone"),&err);
1859 	    zones.top_bound = GetReal8(ew,CID_TopHint,_("Top Hint"),&err);
1860 	    zones.bottom_bound = GetReal8(ew,CID_BottomHint,_("Bottom Hint"),&err);
1861 	}
1862 	if ( err )
1863 return( true );
1864 	zones.counter_type = GGadgetIsChecked( GWidgetGetControl(ew,CID_Squish)) ? ct_squish :
1865 		GGadgetIsChecked( GWidgetGetControl(ew,CID_Retain)) ? ct_retain :
1866 			ct_auto;
1867 
1868 	lastsf = ed->sf;
1869 	last_type = type;
1870 	last_width = zones.stroke_width;
1871 	last_overlap = zones.removeoverlap = GGadgetIsChecked( GWidgetGetControl(ew,CID_CleanupSelfIntersect));
1872 	if ( type == embolden_custom )
1873 	    last_zones = zones;
1874 
1875 	if ( ed->fv!=NULL )
1876 	    FVEmbolden((FontViewBase *) ed->fv, type, &zones);
1877 	else
1878 	    CVEmbolden((CharViewBase *) ed->cv, type, &zones);
1879 	ed->done = true;
1880     }
1881 return( true );
1882 }
1883 
Embolden_Cancel(GGadget * g,GEvent * e)1884 static int Embolden_Cancel(GGadget *g, GEvent *e) {
1885     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
1886 	StyleDlg *ed = GDrawGetUserData(GGadgetGetWindow(g));
1887 	ed->done = true;
1888     }
1889 return( true );
1890 }
1891 
Embolden_Radio(GGadget * g,GEvent * e)1892 static int Embolden_Radio(GGadget *g, GEvent *e) {
1893     if ( e->type==et_controlevent && e->u.control.subtype == et_radiochanged ) {
1894 	StyleDlg *ed = GDrawGetUserData(GGadgetGetWindow(g));
1895 	int en;
1896 	en = GGadgetIsChecked( GWidgetGetControl(ed->gw,CID_Custom));
1897 	GGadgetSetEnabled(GWidgetGetControl(ed->gw,CID_TopZone),en);
1898 	GGadgetSetEnabled(GWidgetGetControl(ed->gw,CID_BottomZone),en);
1899 	GGadgetSetEnabled(GWidgetGetControl(ed->gw,CID_TopHint),en);
1900 	GGadgetSetEnabled(GWidgetGetControl(ed->gw,CID_BottomHint),en);
1901     }
1902 return( true );
1903 }
1904 
EmboldenDlg(FontView * fv,CharView * cv)1905 void EmboldenDlg(FontView *fv, CharView *cv) {
1906     StyleDlg ed;
1907     SplineFont *sf = fv!=NULL ? fv->b.sf : cv->b.sc->parent;
1908     BlueData bd;
1909     GRect pos;
1910     GWindow gw;
1911     GWindowAttrs wattrs;
1912     GGadgetCreateData gcd[27], boxes[6], *barray[8], *rarray[6], *carray[6], *hvarray[10][5];
1913     GTextInfo label[27];
1914     int k;
1915     char topzone[40], botzone[40], emb_width[40], tophint[40], bothint[40], serifh[40];
1916 
1917     memset(&ed,0,sizeof(ed));
1918     ed.fv = fv;
1919     ed.cv = cv;
1920     ed.sf = sf;
1921     ed.layer = cv==NULL ? fv->b.active_layer : CVLayer((CharViewBase *) cv);
1922 
1923     QuickBlues(sf, ed.layer, &bd);
1924 
1925     memset(&wattrs,0,sizeof(wattrs));
1926     wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_undercursor|wam_isdlg|wam_restrict;
1927     wattrs.event_masks = ~(1<<et_charup);
1928     wattrs.restrict_input_to_me = 1;
1929     wattrs.undercursor = 1;
1930     wattrs.cursor = ct_pointer;
1931     wattrs.utf8_window_title = _("Change Weight");
1932     wattrs.is_dlg = true;
1933     pos.x = pos.y = 0;
1934     pos.width = 100;
1935     pos.height = 100;
1936     ed.gw = gw = GDrawCreateTopWindow(NULL,&pos,style_e_h,&ed,&wattrs);
1937 
1938 
1939     k=0;
1940 
1941     memset(gcd,0,sizeof(gcd));
1942     memset(boxes,0,sizeof(boxes));
1943     memset(label,0,sizeof(label));
1944     label[k].text = (unichar_t *) _("Embolden by:");
1945     label[k].text_is_1byte = true;
1946     label[k].text_in_resource = true;
1947     gcd[k].gd.label = &label[k];
1948     gcd[k].gd.flags = gg_enabled | gg_visible;
1949     gcd[k++].creator = GLabelCreate;
1950     hvarray[0][0] = &gcd[k-1];
1951 
1952     sprintf( emb_width, "%d", sf==lastsf ? last_width : (sf->ascent+sf->descent)/20 );
1953     label[k].text = (unichar_t *) emb_width;
1954     label[k].text_is_1byte = true;
1955     gcd[k].gd.label = &label[k];
1956     gcd[k].gd.pos.width = 60;
1957     gcd[k].gd.flags = gg_enabled | gg_visible;
1958     gcd[k].gd.cid = CID_EmBdWidth;
1959     gcd[k++].creator = GNumericFieldCreate;
1960     hvarray[0][1] = &gcd[k-1];
1961 
1962     label[k].text = (unichar_t *) _("em units");
1963     label[k].text_is_1byte = true;
1964     label[k].text_in_resource = true;
1965     gcd[k].gd.label = &label[k];
1966     gcd[k].gd.pos.x = 5; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y+31;
1967     gcd[k].gd.flags = gg_enabled | gg_visible;
1968     gcd[k++].creator = GLabelCreate;
1969     hvarray[0][2] = &gcd[k-1];
1970     hvarray[0][3] = GCD_Glue; hvarray[0][4] = NULL;
1971 
1972     label[k].text = (unichar_t *) _("_LCG");
1973     gcd[k].gd.popup_msg = _("Embolden as appropriate for Latin, Cyrillic and Greek scripts");
1974     label[k].text_is_1byte = true;
1975     label[k].text_in_resource = true;
1976     gcd[k].gd.label = &label[k];
1977     gcd[k].gd.flags = gg_enabled | gg_visible;
1978     gcd[k].gd.cid = CID_LCG;
1979     gcd[k].gd.handle_controlevent = Embolden_Radio;
1980     gcd[k++].creator = GRadioCreate;
1981     rarray[0] = &gcd[k-1];
1982 
1983     label[k].text = (unichar_t *) _("_CJK");
1984     gcd[k].gd.popup_msg = _("Embolden as appropriate for Chinese, Japanese, Korean scripts");
1985     label[k].text_is_1byte = true;
1986     label[k].text_in_resource = true;
1987     gcd[k].gd.label = &label[k];
1988     gcd[k].gd.flags = gg_enabled | gg_visible;
1989     gcd[k].gd.cid = CID_CJK;
1990     gcd[k].gd.handle_controlevent = Embolden_Radio;
1991     gcd[k++].creator = GRadioCreate;
1992     rarray[1] = &gcd[k-1];
1993 
1994     label[k].text = (unichar_t *) _("_Auto");
1995     gcd[k].gd.popup_msg = _("Choose the appropriate method depending on the glyph's script");
1996     label[k].text_is_1byte = true;
1997     label[k].text_in_resource = true;
1998     gcd[k].gd.label = &label[k];
1999     gcd[k].gd.flags = gg_enabled | gg_visible;
2000     gcd[k].gd.cid = CID_Auto;
2001     gcd[k].gd.handle_controlevent = Embolden_Radio;
2002     gcd[k++].creator = GRadioCreate;
2003     rarray[2] = &gcd[k-1];
2004 
2005     label[k].text = (unichar_t *) _("C_ustom");
2006     gcd[k].gd.popup_msg = _("User controls the emboldening with the next two fields");
2007     label[k].text_is_1byte = true;
2008     label[k].text_in_resource = true;
2009     gcd[k].gd.label = &label[k];
2010     gcd[k].gd.flags = gg_enabled | gg_visible;
2011     gcd[k].gd.cid = CID_Custom;
2012     gcd[k].gd.handle_controlevent = Embolden_Radio;
2013     gcd[k++].creator = GRadioCreate;
2014     rarray[3] = &gcd[k-1]; rarray[4] = GCD_Glue; rarray[5] = NULL;
2015 
2016     if ( lastsf!=sf )
2017 	gcd[k-4 + embolden_auto].gd.flags |= gg_cb_on;
2018     else
2019 	gcd[k-4 + last_type].gd.flags |= gg_cb_on;
2020 
2021     boxes[3].gd.flags = gg_enabled|gg_visible;
2022     boxes[3].gd.u.boxelements = rarray;
2023     boxes[3].creator = GHBoxCreate;
2024     hvarray[1][0] = &boxes[3]; hvarray[1][1] = hvarray[1][2] = hvarray[1][3] = GCD_ColSpan; hvarray[1][4] = NULL;
2025 
2026     label[k].text = (unichar_t *) _("_Top hint:");
2027     label[k].text_is_1byte = true;
2028     label[k].text_in_resource = true;
2029     gcd[k].gd.label = &label[k];
2030     gcd[k].gd.pos.x = 5; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y+31;
2031     gcd[k].gd.flags = gg_enabled | gg_visible;
2032     gcd[k++].creator = GLabelCreate;
2033     hvarray[2][0] = &gcd[k-1];
2034 
2035     sprintf( tophint, "%d", lastsf==sf && last_type==embolden_custom ? last_zones.top_bound :
2036 			(int) rint(bd.xheight>0 ? bd.xheight : bd.caph>0 ? 2*bd.caph/3 :
2037 			    sf->ascent/2 ));
2038     label[k].text = (unichar_t *) tophint;
2039     label[k].text_is_1byte = true;
2040     gcd[k].gd.label = &label[k];
2041     gcd[k].gd.pos.x = 80; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y-3;
2042     gcd[k].gd.pos.width = 60;
2043     gcd[k].gd.flags = gg_visible;
2044     gcd[k].gd.cid = CID_TopHint;
2045     gcd[k++].creator = GNumericFieldCreate;
2046     hvarray[2][1] = &gcd[k-1];
2047 
2048     label[k].text = (unichar_t *) _("_Zone:");
2049     label[k].text_is_1byte = true;
2050     label[k].text_in_resource = true;
2051     gcd[k].gd.label = &label[k];
2052     gcd[k].gd.pos.x = 5; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y+31;
2053     gcd[k].gd.flags = gg_enabled | gg_visible;
2054     gcd[k++].creator = GLabelCreate;
2055     hvarray[2][2] = &gcd[k-1];
2056 
2057     sprintf( topzone, "%d", lastsf==sf && last_type==embolden_custom ? last_zones.top_zone :
2058 			(int) rint(bd.xheight>0 ? 2*bd.xheight/3 :
2059 			bd.caph>0 ? 2*bd.caph/3 :
2060 			(sf->ascent/3)) );
2061     label[k].text = (unichar_t *) topzone;
2062     label[k].text_is_1byte = true;
2063     gcd[k].gd.label = &label[k];
2064     gcd[k].gd.pos.x = 80; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y-3;
2065     gcd[k].gd.pos.width = 60;
2066     gcd[k].gd.flags = gg_visible;
2067     gcd[k].gd.cid = CID_TopZone;
2068     gcd[k++].creator = GNumericFieldCreate;
2069     hvarray[2][3] = &gcd[k-1]; hvarray[2][4] = NULL;
2070 
2071     label[k].text = (unichar_t *) _("_Bottom hint:");
2072     label[k].text_is_1byte = true;
2073     label[k].text_in_resource = true;
2074     gcd[k].gd.label = &label[k];
2075     gcd[k].gd.pos.x = 5; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y+31;
2076     gcd[k].gd.flags = gg_enabled | gg_visible;
2077     gcd[k++].creator = GLabelCreate;
2078     hvarray[3][0] = &gcd[k-1];
2079 
2080     sprintf( bothint, "%d", lastsf==sf && last_type==embolden_custom ? last_zones.bottom_bound :
2081 			0 );
2082     label[k].text = (unichar_t *) bothint;
2083     label[k].text_is_1byte = true;
2084     gcd[k].gd.label = &label[k];
2085     gcd[k].gd.pos.x = 80; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y-3;
2086     gcd[k].gd.pos.width = 60;
2087     gcd[k].gd.flags = gg_visible;
2088     gcd[k].gd.cid = CID_BottomHint;
2089     gcd[k++].creator = GNumericFieldCreate;
2090     hvarray[3][1] = &gcd[k-1];
2091 
2092     label[k].text = (unichar_t *) _("Zone:");
2093     label[k].text_is_1byte = true;
2094     label[k].text_in_resource = true;
2095     gcd[k].gd.label = &label[k];
2096     gcd[k].gd.pos.x = 5; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y+31;
2097     gcd[k].gd.flags = gg_enabled | gg_visible;
2098     gcd[k++].creator = GLabelCreate;
2099     hvarray[3][2] = &gcd[k-1];
2100 
2101     sprintf( botzone, "%d", lastsf==sf && last_type==embolden_custom ? last_zones.bottom_zone :
2102 			(int) rint(bd.xheight>0 ? bd.xheight/3 :
2103 			bd.caph>0 ? bd.caph/3 :
2104 			(sf->ascent/4)) );
2105     label[k].text = (unichar_t *) botzone;
2106     label[k].text_is_1byte = true;
2107     gcd[k].gd.label = &label[k];
2108     gcd[k].gd.pos.x = 80; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y-3;
2109     gcd[k].gd.pos.width = 60;
2110     gcd[k].gd.flags = gg_visible;
2111     gcd[k].gd.cid = CID_BottomZone;
2112     gcd[k++].creator = GNumericFieldCreate;
2113     hvarray[3][3] = &gcd[k-1]; hvarray[3][4] = NULL;
2114 
2115     label[k].text = (unichar_t *) _("Serif Height");
2116     label[k].text_is_1byte = true;
2117     label[k].text_in_resource = true;
2118     gcd[k].gd.label = &label[k];
2119     gcd[k].gd.flags = gg_enabled | gg_visible;
2120     gcd[k].gd.popup_msg = _("Any points this high will be assumed to be on serifs,\nand will remain at that height after processing.\n(So serifs should remain the same size).\n(If you do wish the serifs to grow, set this to 0)");
2121     gcd[k++].creator = GLabelCreate;
2122     hvarray[4][0] = &gcd[k-1];
2123 
2124     sprintf( serifh, "%g", SFSerifHeight(sf));
2125     label[k].text = (unichar_t *) serifh;
2126     label[k].text_is_1byte = true;
2127     gcd[k].gd.label = &label[k];
2128     gcd[k].gd.pos.x = 80; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y-3;
2129     gcd[k].gd.pos.width = 60;
2130     gcd[k].gd.flags = gg_enabled | gg_visible;
2131     gcd[k].gd.cid = CID_SerifHeight;
2132     gcd[k].gd.popup_msg = gcd[k-1].gd.popup_msg;
2133     gcd[k++].creator = GNumericFieldCreate;
2134     hvarray[4][1] = &gcd[k-1];
2135 
2136     label[k].text = (unichar_t *) _("Fuzz");
2137     label[k].text_is_1byte = true;
2138     label[k].text_in_resource = true;
2139     gcd[k].gd.label = &label[k];
2140     gcd[k].gd.flags = gg_enabled | gg_visible;
2141     gcd[k].gd.popup_msg = _("Allow the height match to differ by this much");
2142     gcd[k++].creator = GLabelCreate;
2143     hvarray[4][2] = &gcd[k-1];
2144 
2145     label[k].text = (unichar_t *) ".9";
2146     label[k].text_is_1byte = true;
2147     gcd[k].gd.label = &label[k];
2148     gcd[k].gd.pos.x = 80; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y-3;
2149     gcd[k].gd.pos.width = 60;
2150     gcd[k].gd.flags = gg_enabled | gg_visible;
2151     gcd[k].gd.cid = CID_SerifHFuzz;
2152     gcd[k].gd.popup_msg = gcd[k-1].gd.popup_msg;
2153     gcd[k++].creator = GNumericFieldCreate;
2154     hvarray[4][3] = &gcd[k-1];
2155     hvarray[4][4] = NULL;
2156 
2157     label[k].text = (unichar_t *) _("Counters:");
2158     gcd[k].gd.popup_msg = _("The simple application of this algorithm will squeeze counters\nThat is not normally seen in bold latin fonts");
2159     label[k].text_is_1byte = true;
2160     label[k].text_in_resource = true;
2161     gcd[k].gd.label = &label[k];
2162     gcd[k].gd.flags = gg_enabled | gg_visible;
2163     gcd[k++].creator = GLabelCreate;
2164     carray[0] = &gcd[k-1];
2165 
2166     label[k].text = (unichar_t *) _("Squish");
2167     gcd[k].gd.popup_msg = _("Make the counters narrower");
2168     label[k].text_is_1byte = true;
2169     label[k].text_in_resource = true;
2170     gcd[k].gd.label = &label[k];
2171     gcd[k].gd.flags = gg_enabled | gg_visible;
2172     gcd[k].gd.cid = CID_Squish;
2173     /*gcd[k].gd.handle_controlevent = Embolden_Counter;*/
2174     gcd[k++].creator = GRadioCreate;
2175     carray[1] = &gcd[k-1];
2176 
2177     label[k].text = (unichar_t *) _("Retain");
2178     gcd[k].gd.popup_msg = _("Try to insure that the counters are as wide\nafterward as they were before");
2179     label[k].text_is_1byte = true;
2180     label[k].text_in_resource = true;
2181     gcd[k].gd.label = &label[k];
2182     gcd[k].gd.flags = gg_enabled | gg_visible;
2183     gcd[k].gd.cid = CID_Retain;
2184     /*gcd[k].gd.handle_controlevent = Embolden_Counter;*/
2185     gcd[k++].creator = GRadioCreate;
2186     carray[2] = &gcd[k-1];
2187 
2188     label[k].text = (unichar_t *) _("Auto");
2189     gcd[k].gd.popup_msg = _("Retain counter size for glyphs using latin algorithm\nSquish them for those using CJK." );
2190     label[k].text_is_1byte = true;
2191     label[k].text_in_resource = true;
2192     gcd[k].gd.label = &label[k];
2193     gcd[k].gd.flags = gg_enabled | gg_visible| gg_cb_on;
2194     gcd[k].gd.cid = CID_CounterAuto;
2195     /* gcd[k].gd.handle_controlevent = Embolden_Counter;*/
2196     gcd[k++].creator = GRadioCreate;
2197     carray[3] = &gcd[k-1];
2198     carray[4] = GCD_Glue; carray[5] = NULL;
2199 
2200     boxes[5].gd.flags = gg_enabled|gg_visible;
2201     boxes[5].gd.u.boxelements = carray;
2202     boxes[5].creator = GHBoxCreate;
2203     hvarray[5][0] = &boxes[5]; hvarray[5][1] = hvarray[5][2] = hvarray[5][3] = GCD_ColSpan; hvarray[5][4] = NULL;
2204 
2205     label[k].text = (unichar_t *) _("Cleanup Self Intersect");
2206     label[k].text_is_1byte = true;
2207     label[k].text_in_resource = true;
2208     gcd[k].gd.label = &label[k];
2209     gcd[k].gd.flags = gg_enabled | gg_visible| (last_overlap?gg_cb_on:0);
2210     gcd[k].gd.cid = CID_CleanupSelfIntersect;
2211     gcd[k].gd.popup_msg = _("When FontForge detects that an expanded stroke will self-intersect,\nthen setting this option will cause it to try to make things nice\nby removing the intersections");
2212     gcd[k++].creator = GCheckBoxCreate;
2213     hvarray[6][0] = &gcd[k-1]; hvarray[6][1] = hvarray[6][2] = hvarray[6][3] = GCD_ColSpan; hvarray[6][4] = NULL;
2214 
2215     hvarray[7][0] = hvarray[7][1] = hvarray[7][2] = hvarray[7][3] = GCD_Glue; hvarray[7][4] = NULL;
2216 
2217     gcd[k].gd.pos.x = 30-3; gcd[k].gd.pos.y = 5;
2218     gcd[k].gd.pos.width = -1;
2219     gcd[k].gd.flags = gg_visible | gg_enabled | gg_but_default;
2220     label[k].text = (unichar_t *) _("_OK");
2221     label[k].text_is_1byte = true;
2222     label[k].text_in_resource = true;
2223     gcd[k].gd.label = &label[k];
2224     gcd[k].gd.handle_controlevent = Embolden_OK;
2225     gcd[k++].creator = GButtonCreate;
2226     barray[0] = GCD_Glue; barray[1] = &gcd[k-1]; barray[2] = GCD_Glue;
2227 
2228     gcd[k].gd.pos.x = -30; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y+3;
2229     gcd[k].gd.pos.width = -1;
2230     gcd[k].gd.flags = gg_visible | gg_enabled | gg_but_cancel;
2231     label[k].text = (unichar_t *) _("_Cancel");
2232     label[k].text_is_1byte = true;
2233     label[k].text_in_resource = true;
2234     gcd[k].gd.label = &label[k];
2235     gcd[k].gd.handle_controlevent = Embolden_Cancel;
2236     gcd[k].creator = GButtonCreate;
2237     barray[3] = GCD_Glue; barray[4] = &gcd[k]; barray[5] = GCD_Glue;
2238     barray[6] = NULL;
2239 
2240     boxes[4].gd.flags = gg_enabled|gg_visible;
2241     boxes[4].gd.u.boxelements = barray;
2242     boxes[4].creator = GHBoxCreate;
2243     hvarray[8][0] = &boxes[4]; hvarray[8][1] = hvarray[8][2] = hvarray[8][3] = GCD_ColSpan; hvarray[8][4] = NULL;
2244     hvarray[9][0] = NULL;
2245 
2246     boxes[0].gd.pos.x = boxes[0].gd.pos.y = 2;
2247     boxes[0].gd.flags = gg_enabled|gg_visible;
2248     boxes[0].gd.u.boxelements = hvarray[0];
2249     boxes[0].creator = GHVGroupCreate;
2250 
2251     GGadgetsCreate(gw,boxes);
2252     GHVBoxSetExpandableRow(boxes[0].ret,gb_expandglue);
2253     GHVBoxSetExpandableCol(boxes[3].ret,gb_expandglue);
2254     GHVBoxSetExpandableCol(boxes[4].ret,gb_expandgluesame);
2255     GHVBoxSetExpandableCol(boxes[5].ret,gb_expandglue);
2256     GHVBoxFitWindow(boxes[0].ret);
2257     GDrawSetVisible(gw,true);
2258 
2259     while ( !ed.done )
2260 	GDrawProcessOneEvent(NULL);
2261     GDrawDestroyWindow(gw);
2262 }
2263 
2264 /* ************************************************************************** */
2265 /* ***************************** Oblique Dialog ***************************** */
2266 /* ************************************************************************** */
2267 
2268 static ItalicInfo last_ii = {
2269     -13,		/* Italic angle (in degrees) */
2270     .95,		/* xheight percent */
2271     /* horizontal squash, lsb, stemsize, countersize, rsb */
2272     { .91, .89, .90, .91 },	/* For lower case */
2273     { .91, .93, .93, .91 },	/* For upper case */
2274     { .91, .93, .93, .91 },	/* For things which are neither upper nor lower case */
2275     srf_flat,		/* Secondary serifs (initial, medial on "m", descender on "p", "q" */
2276     true,		/* Transform bottom serifs */
2277     true,		/* Transform serifs at x-height */
2278     false,		/* Transform serifs on ascenders */
2279     true,		/* Transform serifs on diagonal stems at baseline and x-height */
2280 
2281     true,		/* Change the shape of an "a" to look like a "d" without ascender */
2282     false,		/* Change the shape of "f" so it descends below baseline (straight down no flag at end) */
2283     true,		/* Change the shape of "f" so the bottom looks like the top */
2284     true,		/* Remove serifs from the bottom of descenders */
2285 
2286     true,		/* Make the cyrillic "phi" glyph have a top like an "f" */
2287     true,		/* Make the cyrillic "i" glyph look like a latin "u" */
2288     true,		/* Make the cyrillic "pi" glyph look like a latin "n" */
2289     true,		/* Make the cyrillic "te" glyph look like a latin "m" */
2290     true,		/* Make the cyrillic "sha" glyph look like a latin "m" rotated 180 */
2291     true,		/* Make the cyrillic "dje" glyph look like a latin smallcaps T (not implemented) */
2292     true,		/* Make the cyrillic "dzhe" glyph look like a latin "u" (same glyph used for cyrillic "i") */
2293 
2294     ITALICINFO_REMAINDER
2295 };
2296 
ObliqueDlg(FontView * fv,CharView * cv)2297 void ObliqueDlg(FontView *fv, CharView *cv) {
2298     bigreal temp;
2299     char def[40], *ret, *end;
2300     real transform[6];
2301 
2302     sprintf( def, "%g", last_ii.italic_angle );
2303     ret = gwwv_ask_string(_("Oblique Slant..."),def,_("By what angle (in degrees) do you want to slant the font?"));
2304     if ( ret==NULL )
2305 return;
2306     temp = strtod(ret,&end);
2307     if ( *end || temp>90 || temp<-90 ) {
2308 	free(ret);
2309 	ff_post_error( _("Bad Number"),_("Bad Number") );
2310 return;
2311     }
2312     free(ret);
2313     last_ii.italic_angle = temp;
2314     memset(transform,0,sizeof(transform));
2315     transform[0] = transform[3] = 1;
2316     transform[2] = -tan( last_ii.italic_angle * FF_PI/180.0 );
2317     if ( cv!=NULL ) {
2318 	CVPreserveState((CharViewBase *) cv);
2319 	CVTransFunc(cv,transform,fvt_dontmovewidth);
2320 	CVCharChangedUpdate(&cv->b);
2321     } else {
2322 	int i, gid;
2323 	SplineChar *sc;
2324 
2325 	for ( i=0; i<fv->b.map->enccount; ++i ) if ( fv->b.selected[i] &&
2326 		(gid = fv->b.map->map[i])!=-1 && (sc=fv->b.sf->glyphs[gid])!=NULL ) {
2327 	    FVTrans((FontViewBase *) fv,sc,transform,NULL,fvt_dontmovewidth);
2328 	}
2329     }
2330 }
2331 
2332 
2333 /* ************************************************************************** */
2334 /* ********************************* Italic ********************************* */
2335 /* ************************************************************************** */
2336 
2337 #define CID_A		1001
2338 #define CID_F		1002
2339 #define CID_F2		1003
2340 #define CID_P		1004
2341 #define CID_Cyrl_I	1011
2342 #define CID_Cyrl_Pi	1012
2343 #define CID_Cyrl_Te	1013
2344 #define CID_Cyrl_Phi	1014
2345 #define CID_Cyrl_Sha	1015
2346 #define CID_Cyrl_Dje	1016
2347 #define CID_Cyrl_Dzhe	1017
2348 #define CID_BottomSerifs	2001
2349 #define CID_XHeightSerifs	2002
2350 #define CID_AscenderSerifs	2003
2351 #define CID_DiagSerifs		2004
2352 #define CID_Flat		2011
2353 #define CID_Slanted		2012
2354 #define CID_PenSlant		2013
2355 #define CID_CompressLSB		3001		/* for lc, 3011 for uc, 3021 for others */
2356 #define CID_CompressStem	3002		/* for lc, 3012 for uc, 3022 for others */
2357 #define CID_CompressCounter	3003		/* for lc, 3013 for uc, 3023 for others */
2358 #define CID_CompressRSB		3004		/* for lc, 3014 for uc, 3024 for others */
2359 #define CID_XHeightPercent	4001
2360 #define CID_ItalicAngle		4002
2361 
Ital_Ok(GGadget * g,GEvent * e)2362 static int Ital_Ok(GGadget *g, GEvent *e) {
2363     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
2364 	GWindow ew = GGadgetGetWindow(g);
2365 	StyleDlg *ed = GDrawGetUserData(ew);
2366 	ItalicInfo ii;
2367 	int err = false, i;
2368 
2369 	memset(&ii,0,sizeof(ii));
2370 	for ( i=0; i<3; ++i ) {
2371 	    struct hsquash *hs = &(&ii.lc)[i];
2372 	    hs->lsb_percent = GetReal8(ew,CID_CompressLSB+i*10,_("LSB Compression Percent"),&err)/100.0;
2373 	    hs->stem_percent = GetReal8(ew,CID_CompressStem+i*10,_("Stem Compression Percent"),&err)/100.0;
2374 	    hs->counter_percent = GetReal8(ew,CID_CompressCounter+i*10,_("Counter Compression Percent"),&err)/100.0;
2375 	    hs->rsb_percent = GetReal8(ew,CID_CompressRSB+i*10,_("RSB Compression Percent"),&err)/100.0;
2376 	    if ( err )
2377 return( true );
2378 	}
2379 	ii.xheight_percent = GetReal8(ew,CID_XHeightPercent,_("XHeight Percent"),&err)/100;
2380 	ii.italic_angle = GetReal8(ew,CID_ItalicAngle,_("Italic Angle"),&err);
2381 	if ( err )
2382 return( true );
2383 
2384 	ii.secondary_serif = GGadgetIsChecked(GWidgetGetControl(ew,CID_Flat)) ? srf_flat :
2385 		GGadgetIsChecked(GWidgetGetControl(ew,CID_Slanted)) ? srf_simpleslant :
2386 			 srf_complexslant;
2387 
2388 	ii.transform_bottom_serifs= GGadgetIsChecked(GWidgetGetControl(ew,CID_BottomSerifs));
2389 	ii.transform_top_xh_serifs= GGadgetIsChecked(GWidgetGetControl(ew,CID_XHeightSerifs));
2390 	ii.transform_top_as_serifs= GGadgetIsChecked(GWidgetGetControl(ew,CID_AscenderSerifs));
2391 	ii.transform_diagon_serifs= GGadgetIsChecked(GWidgetGetControl(ew,CID_DiagSerifs));
2392 
2393 	ii.a_from_d = GGadgetIsChecked(GWidgetGetControl(ew,CID_A));
2394 	ii.f_rotate_top = GGadgetIsChecked(GWidgetGetControl(ew,CID_F));
2395 	ii.f_long_tail = GGadgetIsChecked(GWidgetGetControl(ew,CID_F2));
2396 	ii.pq_deserif = GGadgetIsChecked(GWidgetGetControl(ew,CID_P));
2397 	if ( ii.f_rotate_top && ii.f_long_tail ) {
2398 	    ff_post_error(_("Bad setting"),_("You may not select both variants of 'f'"));
2399 return( true );
2400 	}
2401 
2402 	ii.cyrl_i = GGadgetIsChecked(GWidgetGetControl(ew,CID_Cyrl_I));
2403 	ii.cyrl_pi = GGadgetIsChecked(GWidgetGetControl(ew,CID_Cyrl_Pi));
2404 	ii.cyrl_te = GGadgetIsChecked(GWidgetGetControl(ew,CID_Cyrl_Te));
2405 	ii.cyrl_phi = GGadgetIsChecked(GWidgetGetControl(ew,CID_Cyrl_Phi));
2406 	ii.cyrl_sha = GGadgetIsChecked(GWidgetGetControl(ew,CID_Cyrl_Sha));
2407 	ii.cyrl_dje = GGadgetIsChecked(GWidgetGetControl(ew,CID_Cyrl_Dje));
2408 	ii.cyrl_dzhe = GGadgetIsChecked(GWidgetGetControl(ew,CID_Cyrl_Dzhe));
2409 
2410 	last_ii = ii;
2411 	MakeItalic((FontViewBase *) ed->fv,(CharViewBase *) ed->cv,&ii);
2412 	ed->done = true;
2413     }
2414 return( true );
2415 }
2416 
ItalicDlg(FontView * fv,CharView * cv)2417 void ItalicDlg(FontView *fv, CharView *cv) {
2418     StyleDlg ed;
2419     SplineFont *sf = fv!=NULL ? fv->b.sf : cv->b.sc->parent;
2420     GRect pos;
2421     GWindow gw;
2422     GWindowAttrs wattrs;
2423     GGadgetCreateData gcd[54], boxes[7], *forms[30], *compress[5][6], *sarray[5],
2424 	    *iaarray[3][3], *barray[10], *varray[39];
2425     GTextInfo label[54];
2426     int k,f,r,i;
2427     char lsb[3][40], stems[3][40], counters[3][40], rsb[3][40], ia[40], xp[40];
2428 
2429     memset(&ed,0,sizeof(ed));
2430     ed.fv = fv;
2431     ed.cv = cv;
2432     ed.sf = sf;
2433 
2434     memset(&wattrs,0,sizeof(wattrs));
2435     wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_undercursor|wam_isdlg|wam_restrict;
2436     wattrs.event_masks = ~(1<<et_charup);
2437     wattrs.restrict_input_to_me = 1;
2438     wattrs.undercursor = 1;
2439     wattrs.cursor = ct_pointer;
2440     wattrs.utf8_window_title = _("Italic");
2441     wattrs.is_dlg = true;
2442     pos.x = pos.y = 0;
2443     pos.width = 100;
2444     pos.height = 100;
2445     ed.gw = gw = GDrawCreateTopWindow(NULL,&pos,style_e_h,&ed,&wattrs);
2446 
2447     k=f=r=0;
2448 
2449     memset(gcd,0,sizeof(gcd));
2450     memset(boxes,0,sizeof(boxes));
2451     memset(label,0,sizeof(label));
2452 
2453     label[k].image = &GIcon_aItalic;
2454     gcd[k].gd.label = &label[k];
2455     gcd[k].gd.flags = gg_enabled | gg_visible;
2456     if ( last_ii.a_from_d ) gcd[k].gd.flags |= gg_cb_on;
2457     gcd[k].gd.cid = CID_A;
2458     gcd[k++].creator = GCheckBoxCreate;
2459     forms[f++] = &gcd[k-1];
2460 
2461     label[k].image = &GIcon_fItalic;
2462     gcd[k].gd.label = &label[k];
2463     gcd[k].gd.flags = gg_enabled | gg_visible;
2464     if ( last_ii.f_rotate_top ) gcd[k].gd.flags |= gg_cb_on;
2465     gcd[k].gd.cid = CID_F;
2466     gcd[k++].creator = GCheckBoxCreate;
2467     forms[f++] = &gcd[k-1];
2468 
2469     label[k].image = &GIcon_f2Italic;
2470     gcd[k].gd.label = &label[k];
2471     gcd[k].gd.flags = gg_enabled | gg_visible;
2472     if ( last_ii.f_long_tail ) gcd[k].gd.flags |= gg_cb_on;
2473     gcd[k].gd.cid = CID_F2;
2474     gcd[k++].creator = GCheckBoxCreate;
2475     forms[f++] = &gcd[k-1];
2476     forms[f++] = GCD_Glue; forms[f++] = NULL;
2477 
2478     gcd[k].gd.pos.width = 10; gcd[k].gd.pos.height = 10;
2479     gcd[k].gd.flags = gg_enabled | gg_visible;
2480     gcd[k++].creator = GSpacerCreate;
2481     forms[f++] = GCD_Glue;
2482     forms[f++] = GCD_Glue; forms[f++] = GCD_Glue;
2483     forms[f++] = GCD_Glue; forms[f++] = NULL;
2484 
2485     label[k].image = &GIcon_u438Italic;
2486     gcd[k].gd.label = &label[k];
2487     gcd[k].gd.flags = gg_enabled | gg_visible;
2488     if ( last_ii.cyrl_i ) gcd[k].gd.flags |= gg_cb_on;
2489     gcd[k].gd.cid = CID_Cyrl_I;
2490     gcd[k++].creator = GCheckBoxCreate;
2491     forms[f++] = &gcd[k-1];
2492 
2493     label[k].image = &GIcon_u43fItalic;
2494     gcd[k].gd.label = &label[k];
2495     gcd[k].gd.flags = gg_enabled | gg_visible;
2496     if ( last_ii.cyrl_pi ) gcd[k].gd.flags |= gg_cb_on;
2497     gcd[k].gd.cid = CID_Cyrl_Pi;
2498     gcd[k++].creator = GCheckBoxCreate;
2499     forms[f++] = &gcd[k-1];
2500 
2501     label[k].image = &GIcon_u442Italic;
2502     gcd[k].gd.label = &label[k];
2503     gcd[k].gd.flags = gg_enabled | gg_visible;
2504     if ( last_ii.cyrl_te ) gcd[k].gd.flags |= gg_cb_on;
2505     gcd[k].gd.cid = CID_Cyrl_Te;
2506     gcd[k++].creator = GCheckBoxCreate;
2507     forms[f++] = &gcd[k-1];
2508     forms[f++] = GCD_Glue; forms[f++] = NULL;
2509 
2510     label[k].image = &GIcon_u444Italic;
2511     gcd[k].gd.label = &label[k];
2512     gcd[k].gd.flags = gg_enabled | gg_visible;
2513     if ( last_ii.cyrl_phi ) gcd[k].gd.flags |= gg_cb_on;
2514     gcd[k].gd.cid = CID_Cyrl_Phi;
2515     gcd[k++].creator = GCheckBoxCreate;
2516     forms[f++] = &gcd[k-1];
2517 
2518     label[k].image = &GIcon_u448Italic;
2519     gcd[k].gd.label = &label[k];
2520     gcd[k].gd.flags = gg_enabled | gg_visible;
2521     if ( last_ii.cyrl_sha ) gcd[k].gd.flags |= gg_cb_on;
2522     gcd[k].gd.cid = CID_Cyrl_Sha;
2523     gcd[k++].creator = GCheckBoxCreate;
2524     forms[f++] = &gcd[k-1];
2525 
2526     label[k].image = &GIcon_u452Italic;
2527     gcd[k].gd.label = &label[k];
2528     gcd[k].gd.flags = gg_enabled | gg_visible;
2529     if ( last_ii.cyrl_dje ) gcd[k].gd.flags |= gg_cb_on;
2530     gcd[k].gd.cid = CID_Cyrl_Dje;
2531     gcd[k++].creator = GCheckBoxCreate;
2532     forms[f++] = &gcd[k-1];
2533     forms[f++] = GCD_Glue; forms[f++] = NULL;
2534 
2535     label[k].image = &GIcon_u45fItalic;
2536     gcd[k].gd.label = &label[k];
2537     gcd[k].gd.flags = gg_enabled | gg_visible;
2538     if ( last_ii.cyrl_dzhe ) gcd[k].gd.flags |= gg_cb_on;
2539     gcd[k].gd.cid = CID_Cyrl_Dzhe;
2540     gcd[k++].creator = GCheckBoxCreate;
2541     forms[f++] = &gcd[k-1];
2542     forms[f++] = GCD_Glue; forms[f++] = GCD_Glue; forms[f++] = GCD_Glue; forms[f++] = NULL;
2543     forms[f++] = NULL;
2544 
2545     boxes[2].gd.flags = gg_enabled|gg_visible;
2546     boxes[2].gd.u.boxelements = forms;
2547     boxes[2].creator = GHVBoxCreate;
2548     varray[r++] = &boxes[2]; varray[r++] = NULL;
2549 
2550     gcd[k].gd.flags = gg_visible|gg_enabled ;
2551     gcd[k].gd.pos.height = 5; gcd[k].gd.pos.width = 20;
2552     gcd[k++].creator = GSpacerCreate;
2553     varray[r++] = &gcd[k-1]; varray[r++] = NULL;
2554 
2555     label[k].text = (unichar_t *) _("Transform baseline serifs");
2556     label[k].text_is_1byte = true;
2557     label[k].text_in_resource = true;
2558     label[k].image_precedes = true;
2559     label[k].image = &GIcon_BottomSerifs;
2560     gcd[k].gd.label = &label[k];
2561     gcd[k].gd.flags = gg_enabled | gg_visible;
2562     if ( last_ii.transform_bottom_serifs ) gcd[k].gd.flags |= gg_cb_on;
2563     gcd[k].gd.cid = CID_BottomSerifs;
2564     gcd[k++].creator = GCheckBoxCreate;
2565     varray[r++] = &gcd[k-1]; varray[r++] = NULL;
2566 
2567     label[k].text = (unichar_t *) _("Transform x-height serifs");
2568     label[k].text_is_1byte = true;
2569     label[k].text_in_resource = true;
2570     label[k].image_precedes = true;
2571     label[k].image = &GIcon_TopSerifs;
2572     gcd[k].gd.label = &label[k];
2573     gcd[k].gd.flags = gg_enabled | gg_visible;
2574     if ( last_ii.transform_top_xh_serifs ) gcd[k].gd.flags |= gg_cb_on;
2575     gcd[k].gd.cid = CID_XHeightSerifs;
2576     gcd[k++].creator = GCheckBoxCreate;
2577     varray[r++] = &gcd[k-1]; varray[r++] = NULL;
2578 
2579     label[k].text = (unichar_t *) _("Transform ascender serifs");
2580     label[k].text_is_1byte = true;
2581     label[k].text_in_resource = true;
2582     label[k].image_precedes = true;
2583     label[k].image = &GIcon_TopSerifs;
2584     gcd[k].gd.label = &label[k];
2585     gcd[k].gd.flags = gg_enabled | gg_visible;
2586     if ( last_ii.transform_top_as_serifs ) gcd[k].gd.flags |= gg_cb_on;
2587     gcd[k].gd.cid = CID_AscenderSerifs;
2588     gcd[k++].creator = GCheckBoxCreate;
2589     varray[r++] = &gcd[k-1]; varray[r++] = NULL;
2590 
2591     label[k].text = (unichar_t *) _("Transform descender serifs");
2592     label[k].text_is_1byte = true;
2593     label[k].text_in_resource = true;
2594     label[k].image_precedes = true;
2595     label[k].image = &GIcon_pItalic;
2596     gcd[k].gd.label = &label[k];
2597     gcd[k].gd.flags = gg_enabled | gg_visible;
2598     if ( last_ii.pq_deserif ) gcd[k].gd.flags |= gg_cb_on;
2599     gcd[k].gd.cid = CID_P;
2600     gcd[k++].creator = GCheckBoxCreate;
2601     varray[r++] = &gcd[k-1]; varray[r++] = NULL;
2602 
2603     label[k].text = (unichar_t *) _("Transform diagonal serifs");
2604     label[k].text_is_1byte = true;
2605     label[k].text_in_resource = true;
2606     label[k].image_precedes = true;
2607     label[k].image = &GIcon_DiagSerifs;
2608     gcd[k].gd.label = &label[k];
2609     gcd[k].gd.flags = gg_enabled | gg_visible;
2610     if ( last_ii.transform_diagon_serifs ) gcd[k].gd.flags |= gg_cb_on;
2611     gcd[k].gd.cid = CID_DiagSerifs;
2612     gcd[k++].creator = GCheckBoxCreate;
2613     varray[r++] = &gcd[k-1]; varray[r++] = NULL;
2614 
2615     label[k].text = (unichar_t *) _("When serifs are removed (as first two in \"m\"), replace with:");
2616     label[k].text_is_1byte = true;
2617     gcd[k].gd.label = &label[k];
2618     gcd[k].gd.flags = gg_enabled | gg_visible;
2619     gcd[k++].creator = GLabelCreate;
2620     varray[r++] = &gcd[k-1]; varray[r++] = NULL;
2621 
2622     label[k].text = (unichar_t *) _("Flat");
2623     label[k].text_is_1byte = true;
2624     label[k].text_in_resource = true;
2625     label[k].image_precedes = true;
2626     label[k].image = &GIcon_FlatSerif;
2627     gcd[k].gd.label = &label[k];
2628     gcd[k].gd.flags = gg_enabled | gg_visible;
2629     if ( last_ii.secondary_serif==srf_flat ) gcd[k].gd.flags |= gg_cb_on;
2630     gcd[k].gd.cid = CID_Flat;
2631     gcd[k++].creator = GRadioCreate;
2632     sarray[0] = &gcd[k-1];
2633 
2634     label[k].text = (unichar_t *) _("Slanted");
2635     label[k].text_is_1byte = true;
2636     label[k].text_in_resource = true;
2637     label[k].image_precedes = true;
2638     label[k].image = &GIcon_SlantSerif;
2639     gcd[k].gd.label = &label[k];
2640     gcd[k].gd.flags = gg_enabled | gg_visible;
2641     if ( last_ii.secondary_serif==srf_simpleslant ) gcd[k].gd.flags |= gg_cb_on;
2642     gcd[k].gd.cid = CID_Slanted;
2643     gcd[k++].creator = GRadioCreate;
2644     sarray[1] = &gcd[k-1];
2645 
2646     label[k].text = (unichar_t *) _("Pen Slanted");
2647     label[k].text_is_1byte = true;
2648     label[k].text_in_resource = true;
2649     label[k].image_precedes = true;
2650     label[k].image = &GIcon_PenSerif;
2651     gcd[k].gd.label = &label[k];
2652     gcd[k].gd.flags = gg_enabled | gg_visible;
2653     if ( last_ii.secondary_serif==srf_complexslant ) gcd[k].gd.flags |= gg_cb_on;
2654     gcd[k].gd.cid = CID_PenSlant;
2655     gcd[k++].creator = GRadioCreate;
2656     sarray[2] = &gcd[k-1]; sarray[3] = GCD_Glue; sarray[4] = NULL;
2657 
2658     boxes[3].gd.flags = gg_enabled|gg_visible;
2659     boxes[3].gd.u.boxelements = sarray;
2660     boxes[3].creator = GHBoxCreate;
2661     varray[r++] = &boxes[3]; varray[r++] = NULL;
2662 
2663     gcd[k].gd.flags = gg_visible|gg_enabled ;
2664     gcd[k].gd.pos.height = 5; gcd[k].gd.pos.width = 20;
2665     gcd[k++].creator = GSpacerCreate;
2666     varray[r++] = &gcd[k-1]; varray[r++] = NULL;
2667 
2668     label[k].text = (unichar_t *) _("Compress (as a percentage)");
2669     label[k].text_is_1byte = true;
2670     gcd[k].gd.label = &label[k];
2671     gcd[k].gd.flags = gg_enabled | gg_visible;
2672     gcd[k++].creator = GLabelCreate;
2673     varray[r++] = &gcd[k-1]; varray[r++] = NULL;
2674 
2675     compress[0][0] = GCD_Glue;
2676 
2677     label[k].text = (unichar_t *) _("LSB");
2678     label[k].text_is_1byte = true;
2679     gcd[k].gd.label = &label[k];
2680     gcd[k].gd.flags = gg_enabled | gg_visible;
2681     gcd[k].gd.popup_msg = _("Left Side Bearing");
2682     gcd[k++].creator = GLabelCreate;
2683     compress[0][1] = &gcd[k-1];
2684 
2685     label[k].text = (unichar_t *) _("Stems");
2686     label[k].text_is_1byte = true;
2687     gcd[k].gd.label = &label[k];
2688     gcd[k].gd.flags = gg_enabled | gg_visible;
2689     gcd[k++].creator = GLabelCreate;
2690     compress[0][2] = &gcd[k-1];
2691 
2692     label[k].text = (unichar_t *) _("Counters");
2693     label[k].text_is_1byte = true;
2694     gcd[k].gd.label = &label[k];
2695     gcd[k].gd.flags = gg_enabled | gg_visible;
2696     gcd[k++].creator = GLabelCreate;
2697     compress[0][3] = &gcd[k-1];
2698 
2699     label[k].text = (unichar_t *) _("RSB");
2700     label[k].text_is_1byte = true;
2701     gcd[k].gd.label = &label[k];
2702     gcd[k].gd.flags = gg_enabled | gg_visible;
2703     gcd[k].gd.popup_msg = _("Right Side Bearing");
2704     gcd[k++].creator = GLabelCreate;
2705     compress[0][4] = &gcd[k-1]; compress[0][5] = NULL;
2706 
2707     for ( i=0; i<3; ++i ) {
2708 	struct hsquash *hs = &(&last_ii.lc)[i];
2709 
2710 	label[k].text = (unichar_t *) (i==0 ? _("Lower Case") : i==1 ? _("Upper Case") : _("Others"));
2711 	label[k].text_is_1byte = true;
2712 	gcd[k].gd.label = &label[k];
2713 	gcd[k].gd.flags = gg_enabled | gg_visible;
2714 	gcd[k++].creator = GLabelCreate;
2715 	compress[i+1][0] = &gcd[k-1];
2716 
2717 	sprintf( lsb[i], "%g", 100.0* hs->lsb_percent );
2718 	label[k].text = (unichar_t *) lsb[i];
2719 	label[k].text_is_1byte = true;
2720 	gcd[k].gd.label = &label[k];
2721 	gcd[k].gd.pos.width = 50;
2722 	gcd[k].gd.flags = gg_enabled|gg_visible;
2723 	gcd[k].gd.cid = CID_CompressLSB+10*i;
2724 	gcd[k++].creator = GTextFieldCreate;
2725 	compress[i+1][1] = &gcd[k-1];
2726 
2727 	sprintf( stems[i], "%g", 100.0* hs->stem_percent );
2728 	label[k].text = (unichar_t *) stems[i];
2729 	label[k].text_is_1byte = true;
2730 	gcd[k].gd.label = &label[k];
2731 	gcd[k].gd.pos.width = 50;
2732 	gcd[k].gd.flags = gg_enabled|gg_visible;
2733 	gcd[k].gd.cid = CID_CompressStem+10*i;
2734 	gcd[k++].creator = GTextFieldCreate;
2735 	compress[i+1][2] = &gcd[k-1];
2736 
2737 	sprintf( counters[i], "%g", 100.0* hs->counter_percent );
2738 	label[k].text = (unichar_t *) counters[i];
2739 	label[k].text_is_1byte = true;
2740 	gcd[k].gd.label = &label[k];
2741 	gcd[k].gd.pos.width = 50;
2742 	gcd[k].gd.flags = gg_enabled|gg_visible;
2743 	gcd[k].gd.cid = CID_CompressCounter+10*i;
2744 	gcd[k++].creator = GTextFieldCreate;
2745 	compress[i+1][3] = &gcd[k-1];
2746 
2747 	sprintf( rsb[i], "%g", 100.0* hs->rsb_percent );
2748 	label[k].text = (unichar_t *) rsb[i];
2749 	label[k].text_is_1byte = true;
2750 	gcd[k].gd.label = &label[k];
2751 	gcd[k].gd.pos.width = 50;
2752 	gcd[k].gd.flags = gg_enabled|gg_visible;
2753 	gcd[k].gd.cid = CID_CompressRSB+10*i;
2754 	gcd[k++].creator = GTextFieldCreate;
2755 	compress[i+1][4] = &gcd[k-1]; compress[i+1][5] = NULL;
2756     }
2757     compress[i+1][0] = NULL;
2758 
2759     boxes[4].gd.flags = gg_enabled|gg_visible;
2760     boxes[4].gd.u.boxelements = compress[0];
2761     boxes[4].creator = GHVBoxCreate;
2762     varray[r++] = &boxes[4]; varray[r++] = NULL;
2763 
2764     gcd[k].gd.flags = gg_visible|gg_enabled ;
2765     gcd[k].gd.pos.height = 5; gcd[k].gd.pos.width = 20;
2766     gcd[k++].creator = GSpacerCreate;
2767     varray[r++] = &gcd[k-1]; varray[r++] = NULL;
2768 
2769     label[k].text = (unichar_t *) _("XHeight Percent:");
2770     label[k].text_is_1byte = true;
2771     gcd[k].gd.label = &label[k];
2772     gcd[k].gd.flags = gg_enabled | gg_visible;
2773     gcd[k++].creator = GLabelCreate;
2774     iaarray[0][0] = &gcd[k-1];
2775 
2776     sprintf( xp, "%g", rint(last_ii.xheight_percent*100) );
2777     label[k].text = (unichar_t *) xp;
2778     label[k].text_is_1byte = true;
2779     gcd[k].gd.label = &label[k];
2780     gcd[k].gd.pos.width = 50;
2781     gcd[k].gd.flags = gg_enabled|gg_visible;
2782     gcd[k].gd.cid = CID_XHeightPercent;
2783     gcd[k].gd.popup_msg = _("Traditionally the x-height of an italic face is slightly less\nthan the x-height of the companion roman");
2784     gcd[k++].creator = GTextFieldCreate;
2785     iaarray[0][1] = &gcd[k-1]; iaarray[0][2] = NULL;
2786 
2787     label[k].text = (unichar_t *) _("Italic Angle:");
2788     label[k].text_is_1byte = true;
2789     gcd[k].gd.label = &label[k];
2790     gcd[k].gd.flags = gg_enabled | gg_visible;
2791     gcd[k++].creator = GLabelCreate;
2792     iaarray[1][0] = &gcd[k-1];
2793 
2794     sprintf( ia, "%g", last_ii.italic_angle );
2795     label[k].text = (unichar_t *) ia;
2796     label[k].text_is_1byte = true;
2797     gcd[k].gd.label = &label[k];
2798     gcd[k].gd.pos.width = 50;
2799     gcd[k].gd.flags = gg_enabled|gg_visible;
2800     gcd[k].gd.cid = CID_ItalicAngle;
2801     gcd[k++].creator = GTextFieldCreate;
2802     iaarray[1][1] = &gcd[k-1]; iaarray[1][2] = NULL; iaarray[2][0] = NULL;
2803 
2804     boxes[5].gd.flags = gg_enabled|gg_visible;
2805     boxes[5].gd.u.boxelements = iaarray[0];
2806     boxes[5].creator = GHVBoxCreate;
2807     varray[r++] = &boxes[5]; varray[r++] = NULL;
2808 
2809     gcd[k].gd.pos.x = 5; gcd[k].gd.pos.y = 17+31+16;
2810     gcd[k].gd.pos.width = 190-10;
2811     gcd[k].gd.flags = gg_enabled|gg_visible;
2812     gcd[k++].creator = GLineCreate;
2813     varray[r++] = &gcd[k-1]; varray[r++] = NULL;
2814 
2815     label[k].text = (unichar_t *) U_(
2816 	"This italic conversion will be incomplete!\n"
2817 	"You will probably want to do manual fixups on e, g, k, and v-z\n"
2818 	"And on в, г, д, е, ж, л, м, ц, щ, ъ, ђ\n"
2819 	"And on all Greek lower case letters. And maybe everything else.");
2820     label[k].text_is_1byte = true;
2821     gcd[k].gd.label = &label[k];
2822     gcd[k].gd.flags = gg_enabled | gg_visible;
2823     gcd[k++].creator = GLabelCreate;
2824     varray[r++] = &gcd[k-1]; varray[r++] = NULL;
2825 
2826     gcd[k].gd.pos.x = 5; gcd[k].gd.pos.y = 17+31+16;
2827     gcd[k].gd.pos.width = 190-10;
2828     gcd[k].gd.flags = gg_enabled|gg_visible;
2829     gcd[k++].creator = GLineCreate;
2830     varray[r++] = &gcd[k-1]; varray[r++] = NULL;
2831 
2832     label[k].text = (unichar_t *) _("_OK");
2833     label[k].text_is_1byte = true;
2834     label[k].text_in_resource = true;
2835     gcd[k].gd.label = &label[k];
2836     gcd[k].gd.flags = gg_enabled|gg_visible|gg_but_default;
2837     gcd[k].gd.handle_controlevent = Ital_Ok;
2838     gcd[k++].creator = GButtonCreate;
2839 
2840     label[k].text = (unichar_t *) _("_Cancel");
2841     label[k].text_is_1byte = true;
2842     label[k].text_in_resource = true;
2843     gcd[k].gd.label = &label[k];
2844     gcd[k].gd.flags = gg_enabled|gg_visible|gg_but_cancel;
2845     gcd[k].gd.handle_controlevent = CondenseExtend_Cancel;
2846     gcd[k++].creator = GButtonCreate;
2847 
2848     if ( k>sizeof(gcd)/sizeof(gcd[0]) )
2849 	IError( "Too many options in Italic Dlg");
2850 
2851     barray[0] = GCD_Glue; barray[1] = &gcd[k-2]; barray[2] = GCD_Glue;
2852     barray[3] = GCD_Glue; barray[4] = &gcd[k-1]; barray[5] = GCD_Glue;
2853     barray[6] = NULL;
2854 
2855     boxes[6].gd.flags = gg_enabled|gg_visible;
2856     boxes[6].gd.u.boxelements = barray;
2857     boxes[6].creator = GHBoxCreate;
2858     varray[r++] = &boxes[6]; varray[r++] = NULL;
2859     varray[r++] = NULL;
2860     if ( r>sizeof(varray)/sizeof(varray[0]) )
2861 	IError( "Too many rows in Italic Dlg");
2862 
2863     boxes[0].gd.pos.x = boxes[0].gd.pos.y = 2;
2864     boxes[0].gd.flags = gg_enabled|gg_visible;
2865     boxes[0].gd.u.boxelements = varray;
2866     boxes[0].creator = GHVGroupCreate;
2867 
2868     GGadgetsCreate(gw,boxes);
2869 
2870     GHVBoxSetExpandableCol(boxes[2].ret,gb_expandglue);
2871     GHVBoxSetExpandableCol(boxes[3].ret,gb_expandglue);
2872     GHVBoxSetExpandableCol(boxes[5].ret,gb_expandglue);
2873     GHVBoxSetExpandableCol(boxes[6].ret,gb_expandgluesame);
2874     GHVBoxFitWindow(boxes[0].ret);
2875 
2876     GDrawSetVisible(gw,true);
2877 
2878     while ( !ed.done )
2879 	GDrawProcessOneEvent(NULL);
2880 
2881     GDrawDestroyWindow(gw);
2882 }
2883 
2884 /* ************************************************************************** */
2885 /* ************************* Change XHeight Dialog ************************** */
2886 /* ************************************************************************** */
2887 #define CID_XHeight_Current	1001
2888 #define CID_XHeight_Desired	1002
2889 #define CID_Serif_Height	1003
2890 
XHeight_OK(GGadget * g,GEvent * e)2891 static int XHeight_OK(GGadget *g, GEvent *e) {
2892     int err = false;
2893     struct xheightinfo xi;
2894 
2895     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
2896 	GWindow ew = GGadgetGetWindow(g);
2897 	StyleDlg *ed = GDrawGetUserData(ew);
2898 	xi.xheight_current = GetReal8(ew,CID_XHeight_Current,_("Current X-Height"),&err);
2899 	xi.xheight_desired = GetReal8(ew,CID_XHeight_Desired,_("Desired X-Height"),&err);
2900 	xi.serif_height    = GetReal8(ew,CID_Serif_Height   ,_("Serif Height"),&err);
2901 	if ( err )
2902 return( true );
2903 
2904 	ChangeXHeight( (FontViewBase *) ed->fv, (CharViewBase *) ed->cv, &xi );
2905 	ed->done = true;
2906     }
2907 return( true );
2908 }
2909 
ChangeXHeightDlg(FontView * fv,CharView * cv)2910 void ChangeXHeightDlg(FontView *fv,CharView *cv) {
2911     StyleDlg ed;
2912     SplineFont *sf = fv!=NULL ? fv->b.sf : cv->b.sc->parent;
2913     GRect pos;
2914     GWindow gw;
2915     GWindowAttrs wattrs;
2916     GGadgetCreateData gcd[31], boxes[7], *barray[8], *hvarray[40];
2917     GTextInfo label[31];
2918     int k;
2919     char xh_c[40], xh_d[40], sh[40];
2920     struct xheightinfo xi;
2921 
2922     memset(&ed,0,sizeof(ed));
2923     ed.fv = fv;
2924     ed.cv = cv;
2925     ed.sf = sf;
2926 
2927     InitXHeightInfo(sf,fv!=NULL ? fv->b.active_layer: CVLayer((CharViewBase *) cv),&xi);
2928 
2929     memset(&wattrs,0,sizeof(wattrs));
2930     wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_undercursor|wam_isdlg|wam_restrict;
2931     wattrs.event_masks = ~(1<<et_charup);
2932     wattrs.restrict_input_to_me = 1;
2933     wattrs.undercursor = 1;
2934     wattrs.cursor = ct_pointer;
2935     wattrs.utf8_window_title = _("Change XHeight");
2936     wattrs.is_dlg = true;
2937     pos.x = pos.y = 0;
2938     pos.width = 100;
2939     pos.height = 100;
2940     ed.gw = gw = GDrawCreateTopWindow(NULL,&pos,style_e_h,&ed,&wattrs);
2941 
2942 
2943     k=0;
2944 
2945     memset(gcd,0,sizeof(gcd));
2946     memset(boxes,0,sizeof(boxes));
2947     memset(label,0,sizeof(label));
2948 
2949     label[k].text = (unichar_t *) _("Current x-height:");
2950     label[k].text_is_1byte = true;
2951     label[k].text_in_resource = true;
2952     gcd[k].gd.label = &label[k];
2953     gcd[k].gd.pos.x = 5; gcd[k].gd.pos.y = 0;
2954     gcd[k].gd.flags = gg_visible | gg_enabled ;
2955     gcd[k++].creator = GLabelCreate;
2956 
2957     sprintf( xh_c, "%g", rint( xi.xheight_current ));
2958     label[k].text = (unichar_t *) xh_c;
2959     label[k].text_is_1byte = true;
2960     gcd[k].gd.label = &label[k];
2961     gcd[k].gd.flags = gg_visible | gg_enabled;
2962     gcd[k].gd.cid = CID_XHeight_Current;
2963     gcd[k++].creator = GTextFieldCreate;
2964     hvarray[0] = &gcd[k-2]; hvarray[1] = &gcd[k-1]; hvarray[2] = NULL;
2965 
2966     label[k].text = (unichar_t *) _("Desired x-height:");
2967     label[k].text_is_1byte = true;
2968     label[k].text_in_resource = true;
2969     gcd[k].gd.label = &label[k];
2970     gcd[k].gd.pos.x = 5; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y+31;
2971     gcd[k].gd.flags = gg_visible  | gg_enabled;
2972     gcd[k++].creator = GLabelCreate;
2973 
2974     sprintf( xh_d, "%g", rint( xi.xheight_current ));
2975     label[k].text = (unichar_t *) xh_d;
2976     label[k].text_is_1byte = true;
2977     gcd[k].gd.label = &label[k];
2978     gcd[k].gd.flags = gg_visible | gg_enabled;
2979     gcd[k].gd.cid = CID_XHeight_Desired;
2980     gcd[k++].creator = GTextFieldCreate;
2981     hvarray[3] = &gcd[k-2]; hvarray[4] = &gcd[k-1]; hvarray[5] = NULL;
2982 
2983     label[k].text = (unichar_t *) _("Serif height:");
2984     label[k].text_is_1byte = true;
2985     label[k].text_in_resource = true;
2986     gcd[k].gd.label = &label[k];
2987     gcd[k].gd.pos.x = 5; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y+31;
2988     gcd[k].gd.flags = gg_visible  | gg_enabled;
2989     gcd[k++].creator = GLabelCreate;
2990 
2991     sprintf( sh, "%g", rint( xi.xheight_desired ));
2992     label[k].text = (unichar_t *) sh;
2993     label[k].text_is_1byte = true;
2994     gcd[k].gd.label = &label[k];
2995     gcd[k].gd.flags = gg_visible | gg_enabled;
2996     gcd[k].gd.cid = CID_Serif_Height;
2997     gcd[k++].creator = GTextFieldCreate;
2998     hvarray[6] = &gcd[k-2]; hvarray[7] = &gcd[k-1]; hvarray[8] = NULL;
2999 
3000     gcd[k].gd.pos.x = 30-3; gcd[k].gd.pos.y = 5;
3001     gcd[k].gd.pos.width = -1;
3002     gcd[k].gd.flags = gg_visible | gg_enabled | gg_but_default;
3003     label[k].text = (unichar_t *) _("_OK");
3004     label[k].text_is_1byte = true;
3005     label[k].text_in_resource = true;
3006     gcd[k].gd.label = &label[k];
3007     gcd[k].gd.handle_controlevent = XHeight_OK;
3008     gcd[k++].creator = GButtonCreate;
3009     barray[0] = GCD_Glue; barray[1] = &gcd[k-1]; barray[2] = GCD_Glue;
3010 
3011     gcd[k].gd.pos.x = -30; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y+3;
3012     gcd[k].gd.pos.width = -1;
3013     gcd[k].gd.flags = gg_visible | gg_enabled | gg_but_cancel;
3014     label[k].text = (unichar_t *) _("_Cancel");
3015     label[k].text_is_1byte = true;
3016     label[k].text_in_resource = true;
3017     gcd[k].gd.label = &label[k];
3018     gcd[k].gd.handle_controlevent = CondenseExtend_Cancel;
3019     gcd[k].creator = GButtonCreate;
3020     barray[3] = GCD_Glue; barray[4] = &gcd[k]; barray[5] = GCD_Glue;
3021     barray[6] = NULL;
3022 
3023     boxes[3].gd.flags = gg_enabled|gg_visible;
3024     boxes[3].gd.u.boxelements = barray;
3025     boxes[3].creator = GHBoxCreate;
3026     hvarray[9] = &boxes[3]; hvarray[10] = GCD_ColSpan; hvarray[11] = NULL;
3027     hvarray[12] = NULL;
3028 
3029     boxes[0].gd.pos.x = boxes[0].gd.pos.y = 2;
3030     boxes[0].gd.flags = gg_enabled|gg_visible;
3031     boxes[0].gd.u.boxelements = hvarray;
3032     boxes[0].creator = GHVGroupCreate;
3033 
3034     GGadgetsCreate(gw,boxes);
3035     GHVBoxSetExpandableCol(boxes[3].ret,gb_expandgluesame);
3036     GHVBoxFitWindow(boxes[0].ret);
3037     GDrawSetVisible(gw,true);
3038 
3039     while ( !ed.done )
3040 	GDrawProcessOneEvent(NULL);
3041     GDrawDestroyWindow(gw);
3042 }
3043