1 /* Copyright (C) 2000-2012 by George Williams */
2 /*
3  * Redistribution and use in source and binary forms, with or without
4  * modification, are permitted provided that the following conditions are met:
5 
6  * Redistributions of source code must retain the above copyright notice, this
7  * list of conditions and the following disclaimer.
8 
9  * Redistributions in binary form must reproduce the above copyright notice,
10  * this list of conditions and the following disclaimer in the documentation
11  * and/or other materials provided with the distribution.
12 
13  * The name of the author may not be used to endorse or promote products
14  * derived from this software without specific prior written permission.
15 
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include <fontforge-config.h>
29 
30 #include "cvundoes.h"
31 #include "dlist.h"
32 #include "fontforgeui.h"
33 #include "gkeysym.h"
34 #include "lookups.h"
35 #include "parsettf.h"
36 #include "spiro.h"
37 #include "splineorder2.h"
38 #include "splineutil.h"
39 #include "splineutil2.h"
40 #include "tottfgpos.h"
41 #include "ustring.h"
42 #include "utype.h"
43 
44 #include <math.h>
45 
46 #define RAD2DEG	(180/FF_PI)
47 #define TCnt	3
48 
49 typedef struct gidata {
50     struct dlistnode ln;
51     CharView *cv;
52     SplineChar *sc;
53     RefChar *rf;
54     ImageList *img;
55     AnchorPoint *ap;
56     SplinePoint *cursp;
57     spiro_cp *curcp;
58     SplinePointList *curspl;
59     SplinePointList *oldstate;
60     AnchorPoint *oldaps;
61     GWindow gw;
62     int done, first, changed;
63     int prevchanged, nextchanged;
64     int normal_start, normal_end;
65     int interp_start, interp_end;
66     GGadgetCreateData* gcd;
67     GGadget *group1ret, *group2ret;
68 } GIData;
69 
70 #define CID_BaseX	2001
71 #define CID_BaseY	2002
72 #define CID_NextXOff	2003
73 #define CID_NextYOff	2004
74 #define CID_NextPos	2005
75 #define CID_PrevXOff	2006
76 #define CID_PrevYOff	2007
77 #define CID_PrevPos	2008
78 #define CID_NextDef	2009
79 #define CID_PrevDef	2010
80 #define CID_NextR	2014
81 #define CID_NextTheta	2015
82 #define CID_PrevR	2016
83 #define CID_PrevTheta	2017
84 #define CID_HintMask	2020
85 #define CID_ActiveHints	2030
86 #define CID_NextX	2031
87 #define CID_NextY	2032
88 #define CID_PrevX	2033
89 #define CID_PrevY	2034
90 #define CID_BasePos	2035
91 #define CID_Normal	2036
92 #define CID_Interpolated 2037
93 #define CID_NeverInterpolate	2038
94 /* Also use CID_Next, CID_Prev below */
95 #define CID_NextC	2041
96 #define CID_PrevC	2042
97 #define CID_PrevCurvature	2043
98 #define CID_NextCurvature	2044
99 #define CID_DeltaCurvature	2045
100 #define CID_Curve	2050		/* Next four must be in order */
101 #define CID_Corner	2051
102 #define CID_Tangent	2052
103 #define CID_HVCurve	2053
104 #define CID_SpiroLeft	2054
105 #define CID_SpiroRight	2055
106 #define CID_TabSet	2100
107 
108 #define CID_X		3001
109 #define CID_Y		3002
110 #define CID_NameList	3003
111 #define CID_Mark	3004
112 #define CID_BaseChar	3005
113 #define CID_BaseLig	3006
114 #define CID_BaseMark	3007
115 #define CID_CursEntry	3008
116 #define CID_CursExit	3009
117 #define CID_LigIndex	3010
118 #define CID_Next	3011
119 #define CID_Prev	3012
120 #define CID_Delete	3013
121 #define CID_New		3014
122 #define CID_MatchPt	3015
123 
124 #define RI_Width	225
125 #define RI_Height	246
126 #define CID_Match_Pt_Base	1010
127 #define CID_Match_Pt_Ref	1011
128 
129 #define II_Width	130
130 #define II_Height	70
131 
132 #define PI_Width	228
133 #define PI_Height	434
134 
135 #define AI_Width	160
136 #define AI_Height	258
137 
GI_Cancel(GGadget * g,GEvent * e)138 static int GI_Cancel(GGadget *g, GEvent *e) {
139     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
140 	GIData *ci = GDrawGetUserData(GGadgetGetWindow(g));
141 	ci->done = true;
142     }
143 return( true );
144 }
145 
GI_TransChange(GGadget * g,GEvent * e)146 static int GI_TransChange(GGadget *g, GEvent *e) {
147     if ( e->type==et_controlevent && e->u.control.subtype == et_textchanged ) {
148 	GIData *ci = GDrawGetUserData(GGadgetGetWindow(g));
149 	ci->changed = true;
150     }
151 return( true );
152 }
153 
GI_MatchPtChange(GGadget * g,GEvent * e)154 static int GI_MatchPtChange(GGadget *g, GEvent *e) {
155     if ( e->type==et_controlevent && e->u.control.subtype == et_textchanged ) {
156 	GIData *ci = GDrawGetUserData(GGadgetGetWindow(g));
157 	const unichar_t *t1 = _GGadgetGetTitle(GWidgetGetControl(ci->gw,CID_Match_Pt_Base));
158 	const unichar_t *t2 = _GGadgetGetTitle(GWidgetGetControl(ci->gw,CID_Match_Pt_Ref));
159 	while ( *t1==' ' ) ++t1;
160 	while ( *t2==' ' ) ++t2;
161 	GGadgetSetEnabled(GWidgetGetControl(ci->gw,1004),*t1=='\0' && *t2=='\0' );
162 	GGadgetSetEnabled(GWidgetGetControl(ci->gw,1005),*t1=='\0' && *t2=='\0' );
163 	if ( isdigit(*t1) && isdigit(*t2)) {
164 	    BasePoint inbase, inref;
165 	    int basept, refpt;
166 	    basept = u_strtol(t1,NULL,10);
167 	    refpt = u_strtol(t2,NULL,10);
168 	    if ( ttfFindPointInSC(ci->cv->b.sc,CVLayer((CharViewBase *) ci->cv),basept,&inbase,ci->rf)==-1 &&
169 		    ttfFindPointInSC(ci->rf->sc,CVLayer((CharViewBase *) ci->cv),refpt,&inref,NULL)==-1 ) {
170 		char buffer[40];
171 		sprintf(buffer,"%g",(double) (inbase.x-inref.x));
172 		GGadgetSetTitle8(GWidgetGetControl(ci->gw,1004),buffer);
173 		sprintf(buffer,"%g",(double) (inbase.y-inref.y));
174 		GGadgetSetTitle8(GWidgetGetControl(ci->gw,1005),buffer);
175 	    }
176 	}
177     }
178 return( true );
179 }
180 
GI_ROK_Do(GIData * ci)181 static int GI_ROK_Do(GIData *ci) {
182     int errs=false,i;
183     real trans[6];
184     SplinePointList *spl, *new;
185     RefChar *ref = ci->rf, *subref;
186     int usemy = GGadgetIsChecked(GWidgetGetControl(ci->gw,6+1000));
187     int round = GGadgetIsChecked(GWidgetGetControl(ci->gw,7+1000));
188     int basept=-1, refpt=-1;
189     BasePoint inbase, inref;
190 
191     for ( i=0; i<6; ++i ) {
192 	trans[i] = GetReal8(ci->gw,1000+i,_("Transformation Matrix"),&errs);
193 	if ( !errs &&
194 		((i<4 && (trans[i]>30 || trans[i]<-30)) ||
195 		 (i>=4 && (trans[i]>16000 || trans[i]<-16000))) ) {
196 	    /* Don't want the user to insert an enormous scale factor or */
197 	    /*  it will move points outside the legal range. */
198 	    GTextFieldSelect(GWidgetGetControl(ci->gw,1000+i),0,-1);
199 	    ff_post_error(_("Value out of range"),_("Value out of range"));
200 	    errs = true;
201 	}
202 	if ( errs )
203 return( false );
204     }
205     if ( !ci->cv->b.sc->layers[ly_fore].order2 )
206 	/* No point matching */;
207     else {
208 	const unichar_t *txt;
209 	txt = _GGadgetGetTitle(GWidgetGetControl(ci->gw,CID_Match_Pt_Base));
210 	while ( isspace(*txt)) ++txt;
211 	if ( *txt!='\0' )
212 	    basept = GetInt8(ci->gw,CID_Match_Pt_Base,_("_Base:"),&errs);
213 	txt = _GGadgetGetTitle(GWidgetGetControl(ci->gw,CID_Match_Pt_Ref));
214 	while ( isspace(*txt)) ++txt;
215 	if ( *txt!='\0' )
216 	    refpt = GetInt8(ci->gw,CID_Match_Pt_Ref,_("Ref:"),&errs);
217 	if ( errs )
218 return( false );
219 	if ( (basept!=-1) ^ (refpt!=-1) ) {
220 	    ff_post_error(_("Bad Point Match"),_("Both points must be specified, or neither"));
221 	}
222 	if ( basept!=-1 ) {
223 	    if ( ttfFindPointInSC(ci->cv->b.sc,CVLayer((CharViewBase *) ci->cv),basept,&inbase,ci->rf)!=-1 ) {
224 		ff_post_error(_("Bad Point Match"),_("Couldn't find base point"));
225 return( false );
226 	    } else if ( ttfFindPointInSC(ci->rf->sc,CVLayer((CharViewBase *) ci->cv),refpt,&inref,NULL)!=-1 ) {
227 		ff_post_error(_("Bad Point Match"),_("Couldn't find point in reference"));
228 return( false );
229 	    }
230 	    /* Override user specified value */
231 	    trans[4] = inbase.x-inref.x;
232 	    trans[5] = inbase.y-inref.y;
233 	}
234     }
235 
236     for ( i=0; i<6 && ref->transform[i]==trans[i]; ++i );
237     if ( i==6 &&
238 	    usemy==ref->use_my_metrics &&
239 	    round==ref->round_translation_to_grid &&
240 	    (basept!=-1)==ref->point_match &&
241 	    (basept==-1 ||
242 		(ref->match_pt_base==basept && ref->match_pt_ref==refpt))) {
243 	ref->point_match_out_of_date = false;
244 return( true );		/* Didn't really change */
245     }
246 
247     for ( i=0; i<6; ++i )
248 	ref->transform[i] = trans[i];
249     SplinePointListsFree(ref->layers[0].splines);
250     ref->layers[0].splines = SplinePointListTransform(SplinePointListCopy(ref->sc->layers[ly_fore].splines),trans,tpt_AllPoints);
251     spl = NULL;
252     if ( ref->layers[0].splines!=NULL )
253 	for ( spl = ref->layers[0].splines; spl->next!=NULL; spl = spl->next );
254     for ( subref = ref->sc->layers[ly_fore].refs; subref!=NULL; subref=subref->next ) {
255 	new = SplinePointListTransform(SplinePointListCopy(subref->layers[0].splines),trans,tpt_AllPoints);
256 	if ( spl==NULL )
257 	    ref->layers[0].splines = new;
258 	else
259 	    spl->next = new;
260 	if ( new!=NULL )
261 	    for ( spl = new; spl->next!=NULL; spl = spl->next );
262     }
263     ref->use_my_metrics = usemy;
264     ref->round_translation_to_grid = round;
265     ref->point_match = basept!=-1;
266     ref->match_pt_base = basept; ref->match_pt_ref = refpt;
267     ref->point_match_out_of_date = false;
268 
269     SplineSetFindBounds(ref->layers[0].splines,&ref->bb);
270     CVCharChangedUpdate(&ci->cv->b);
271 return( true );
272 }
273 
GI_ROK(GGadget * g,GEvent * e)274 static int GI_ROK(GGadget *g, GEvent *e) {
275     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
276 	GIData *ci = GDrawGetUserData(GGadgetGetWindow(g));
277 	if ( GI_ROK_Do(ci))
278 	    ci->done = true;
279     }
280 return( true );
281 }
282 
GI_Show(GGadget * g,GEvent * e)283 static int GI_Show(GGadget *g, GEvent *e) {
284     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
285 	GIData *ci = GDrawGetUserData(GGadgetGetWindow(g));
286 	if ( ci->changed ) {
287 	    char *buts[4];
288 	    int ans;
289 	    buts[0] = _("C_hange");
290 	    buts[1] = _("_Retain");
291 	    buts[2] = _("_Cancel");
292 	    buts[3] = NULL;
293 	    ans = gwwv_ask(_("Transformation Matrix Changed"),(const char **)buts,0,2,_("You have changed the transformation matrix, do you wish to use the new version?"));
294 	    if ( ans==2 )
295 return( true );
296 	    else if ( ans==0 ) {
297 		if ( !GI_ROK_Do(ci))
298 return( true );
299 	    }
300 	}
301 	ci->done = true;
302 	CharViewCreate(ci->rf->sc,(FontView *) (ci->cv->b.fv),-1);
303     }
304 return( true );
305 }
306 
gi_e_h(GWindow gw,GEvent * event)307 static int gi_e_h(GWindow gw, GEvent *event) {
308     if ( event->type==et_close ) {
309 	GIData *ci = GDrawGetUserData(gw);
310 	ci->done = true;
311     } else if ( event->type==et_char ) {
312 	if ( event->u.chr.keysym == GK_F1 || event->u.chr.keysym == GK_Help ) {
313 	    help("ui/dialogs/getinfo.html", NULL);
314 return( true );
315 	}
316 return( false );
317     } else if ( event->type == et_map ) {
318 	/* Above palettes */
319 	GDrawRaise(gw);
320     }
321 return( true );
322 }
323 
RefGetInfo(CharView * cv,RefChar * ref)324 static void RefGetInfo(CharView *cv, RefChar *ref) {
325     static GIData gi;
326     GRect pos;
327     GWindowAttrs wattrs;
328     GGadgetCreateData gcd[33], boxes[7];
329     GGadgetCreateData *varray[19], *hvarray[16], *harray1[6], *harray2[4],
330 	    *harray3[7], *hvarray2[4][6];
331     GTextInfo label[33];
332     char tbuf[6][40], bbbuf[4][40];
333     char basebuf[20], refbuf[20];
334     char namebuf[100];
335     char ubuf[40];
336     int i,j,l;
337 
338     gi.cv = cv;
339     gi.sc = cv->b.sc;
340     gi.rf = ref;
341     gi.changed = false;
342     gi.done = false;
343 
344 	memset(&wattrs,0,sizeof(wattrs));
345 	wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_undercursor|wam_isdlg|wam_restrict;
346 	wattrs.event_masks = ~(1<<et_charup);
347 	wattrs.restrict_input_to_me = 1;
348 	wattrs.undercursor = 1;
349 	wattrs.cursor = ct_pointer;
350 	wattrs.utf8_window_title = _("Reference Info");
351 	wattrs.is_dlg = true;
352 	pos.x = pos.y = 0;
353 	pos.width = GGadgetScale(GDrawPointsToPixels(NULL,RI_Width));
354 	pos.height = GDrawPointsToPixels(NULL,
355 		ref->sc->unicodeenc!=-1?RI_Height+12:RI_Height);
356 	gi.gw = GDrawCreateTopWindow(NULL,&pos,gi_e_h,&gi,&wattrs);
357 
358 	memset(&gcd,0,sizeof(gcd));
359 	memset(&label,0,sizeof(label));
360 	memset(&boxes,0,sizeof(boxes));
361 
362 	snprintf( namebuf, sizeof(namebuf),
363 		_("Reference to character %1$.20s at %2$d"),
364 		ref->sc->name, (int) cv->b.fv->map->backmap[ref->sc->orig_pos]);
365 	label[0].text = (unichar_t *) namebuf;
366 	label[0].text_is_1byte = true;
367 	gcd[0].gd.label = &label[0];
368 	gcd[0].gd.pos.x = 5; gcd[0].gd.pos.y = 5;
369 	gcd[0].gd.flags = gg_enabled|gg_visible;
370 	gcd[0].creator = GLabelCreate;
371 	l = 0;
372 	varray[l++] = &gcd[0];
373 	j = 1;
374 
375 	if ( ref->sc->unicodeenc!=-1 ) {
376 	    sprintf( ubuf, " Unicode: U+%04x", ref->sc->unicodeenc );
377 	    label[1].text = (unichar_t *) ubuf;
378 	    label[1].text_is_1byte = true;
379 	    gcd[1].gd.label = &label[1];
380 	    gcd[1].gd.pos.x = 5; gcd[1].gd.pos.y = 17;
381 	    gcd[1].gd.flags = gg_enabled|gg_visible;
382 	    gcd[1].creator = GLabelCreate;
383 	    varray[l++] = &gcd[1];
384 	    j=2;
385 	}
386 
387 	label[j].text = (unichar_t *) _("Transformed by:");
388 	label[j].text_is_1byte = true;
389 	gcd[j].gd.label = &label[j];
390 	gcd[j].gd.pos.x = 5; gcd[j].gd.pos.y = gcd[j-1].gd.pos.y+14;
391 	gcd[j].gd.flags = gg_enabled|gg_visible;
392 	gcd[j].gd.popup_msg = _("The transformation matrix specifies how the points in\nthe source glyph should be transformed before\nthey are drawn in the current glyph.\n x(new) = tm[1,1]*x + tm[2,1]*y + tm[3,1]\n y(new) = tm[1,2]*x + tm[2,2]*y + tm[3,2]");
393 	gcd[j].creator = GLabelCreate;
394 	varray[l++] = &gcd[j];
395 	++j;
396 
397 	for ( i=0; i<6; ++i ) {
398 	    if ( !(i&1) ) hvarray[5*(i/2)] = GCD_Glue;
399 	    sprintf(tbuf[i],"%g", (double) ref->transform[i]);
400 	    label[i+j].text = (unichar_t *) tbuf[i];
401 	    label[i+j].text_is_1byte = true;
402 	    gcd[i+j].gd.label = &label[i+j];
403 	    gcd[i+j].gd.pos.x = 20+((i&1)?85:0); gcd[i+j].gd.pos.width=75;
404 	    gcd[i+j].gd.pos.y = gcd[j-1].gd.pos.y+14+(i/2)*26;
405 	    gcd[i+j].gd.flags = gg_enabled|gg_visible;
406 	    gcd[i+j].gd.cid = i+1000;
407 	    gcd[i+j].gd.handle_controlevent = GI_TransChange;
408 	    gcd[i+j].creator = (i>=4 ? GNumericFieldCreate : GTextFieldCreate);
409 	    hvarray[5*(i/2)+1+(i&1)] = &gcd[i+j];
410 	    if ( (i&1) ) { hvarray[5*(i/2)+3] = GCD_Glue; hvarray[5*(i/2)+4] = NULL; }
411 	}
412 	if ( ref->point_match )
413 	    gcd[4+j].gd.flags = gcd[5+j].gd.flags = gg_visible;
414 	hvarray[15] = NULL;
415 
416 	boxes[2].gd.flags = gg_enabled|gg_visible;
417 	boxes[2].gd.u.boxelements = hvarray;
418 	boxes[2].creator = GHVBoxCreate;
419 	varray[l++] = &boxes[2];
420 
421 	label[6+j].text = (unichar_t *) _("_Use My Metrics");
422 	label[6+j].text_in_resource = true;
423 	label[6+j].text_is_1byte = true;
424 	gcd[6+j].gd.label = &label[6+j];
425 	gcd[6+j].gd.pos.x = 5; gcd[6+j].gd.pos.y = gcd[6+j-1].gd.pos.y+21;
426 	gcd[6+j].gd.flags = gg_enabled|gg_visible| (ref->use_my_metrics?gg_cb_on:0);
427 	gcd[i+j].gd.cid = 6+1000;
428 	gcd[6+j].gd.popup_msg = _("Only relevant in a truetype font, this flag indicates that the width\nof the composite glyph should be the same as the width of this reference.");
429 	varray[l++] = &gcd[6+j];
430 	gcd[6+j++].creator = GCheckBoxCreate;
431 
432 	label[6+j].text = (unichar_t *) _("_Round To Grid");
433 	label[6+j].text_in_resource = true;
434 	label[6+j].text_is_1byte = true;
435 	gcd[6+j].gd.label = &label[6+j];
436 	gcd[6+j].gd.pos.x = 5; gcd[6+j].gd.pos.y = gcd[6+j-1].gd.pos.y+14;
437 	gcd[6+j].gd.flags = gg_enabled|gg_visible| (ref->round_translation_to_grid?gg_cb_on:0);
438 	gcd[i+j].gd.cid = 7+1000;
439 	gcd[6+j].gd.popup_msg = _("Only relevant in a truetype font, this flag indicates that if the reference\nis translated, then the translation should be rounded during grid fitting.");
440 	varray[l++] = &gcd[6+j];
441 	gcd[6+j++].creator = GCheckBoxCreate;
442 
443 	label[6+j].text = (unichar_t *) _("TrueType Point _Matching:");
444 	label[6+j].text_in_resource = true;
445 	label[6+j].text_is_1byte = true;
446 	gcd[6+j].gd.label = &label[6+j];
447 	gcd[6+j].gd.pos.x = 5; gcd[6+j].gd.pos.y = gcd[6+j-1].gd.pos.y+17;
448 	gcd[6+j].gd.flags = cv->b.sc->layers[ly_fore].order2 ? (gg_enabled|gg_visible) : (gg_visible);
449 	gcd[6+j].gd.popup_msg = _("Only relevant in a truetype font, this flag indicates that this\nreference should not be translated normally, but rather its position\nshould be determined by moving the reference so that the indicated\npoint in the reference falls on top of the indicated point in the base\ncharacter.");
450 	varray[l++] = &gcd[6+j];
451 	gcd[6+j++].creator = GLabelCreate;
452 
453 	label[6+j].text = (unichar_t *) _("_Base:");
454 	label[6+j].text_is_1byte = true;
455 	label[6+j].text_in_resource = true;
456 	gcd[6+j].gd.label = &label[6+j];
457 	gcd[6+j].gd.pos.x = 8; gcd[6+j].gd.pos.y = gcd[6+j-1].gd.pos.y+19;
458 	gcd[6+j].gd.flags = cv->b.sc->layers[ly_fore].order2 ? (gg_enabled|gg_visible) : (gg_visible);
459 	gcd[6+j].gd.popup_msg = _("Only relevant in a truetype font, this flag indicates that this\nreference should not be translated normally, but rather its position\nshould be determined by moving the reference so that the indicated\npoint in the reference falls on top of the indicated point in the base\ncharacter.");
460 	harray1[0] = &gcd[6+j];
461 	gcd[6+j++].creator = GLabelCreate;
462 
463 	if ( ref->point_match ) {
464 	    sprintf(basebuf,"%d", ref->match_pt_base);
465 	    label[6+j].text = (unichar_t *) basebuf;
466 	    label[6+j].text_is_1byte = true;
467 	    gcd[6+j].gd.label = &label[6+j];
468 	}
469 	gcd[6+j].gd.pos.x = 40; gcd[6+j].gd.pos.width=50;
470 	gcd[6+j].gd.pos.y = gcd[6+j-1].gd.pos.y-4;
471 	gcd[6+j].gd.flags = gcd[6+j-1].gd.flags;
472 	gcd[6+j].gd.cid = CID_Match_Pt_Base;
473 	gcd[6+j].gd.handle_controlevent = GI_MatchPtChange;
474 	harray1[1] = &gcd[6+j];
475 	gcd[6+j++].creator = GTextFieldCreate;
476 
477 	label[6+j].text = (unichar_t *) _("Ref:");
478 	label[6+j].text_is_1byte = true;
479 	gcd[6+j].gd.label = &label[6+j];
480 	gcd[6+j].gd.pos.x = 95; gcd[6+j].gd.pos.y = gcd[6+j-2].gd.pos.y;
481 	gcd[6+j].gd.flags = gcd[6+j-1].gd.flags;
482 	gcd[6+j].gd.popup_msg = _("Only relevant in a truetype font, this flag indicates that this\nreference should not be translated normally, but rather its position\nshould be determined by moving the reference so that the indicated\npoint in the reference falls on top of the indicated point in the base\ncharacter.");
483 	harray1[2] = &gcd[6+j];
484 	gcd[6+j++].creator = GLabelCreate;
485 
486 	if ( ref->point_match ) {
487 	    sprintf(refbuf,"%d", ref->match_pt_ref);
488 	    label[6+j].text = (unichar_t *) refbuf;
489 	    label[6+j].text_is_1byte = true;
490 	    gcd[6+j].gd.label = &label[6+j];
491 	}
492 	gcd[6+j].gd.pos.x = 127; gcd[6+j].gd.pos.width=50;
493 	gcd[6+j].gd.pos.y = gcd[6+j-2].gd.pos.y;
494 	gcd[6+j].gd.flags = gcd[6+j-1].gd.flags;
495 	gcd[6+j].gd.cid = CID_Match_Pt_Ref;
496 	gcd[6+j].gd.handle_controlevent = GI_MatchPtChange;
497 	harray1[3] = &gcd[6+j];
498 	gcd[6+j++].creator = GTextFieldCreate;
499 	harray1[4] = GCD_Glue; harray1[5] = NULL;
500 
501 	boxes[3].gd.flags = gg_enabled|gg_visible;
502 	boxes[3].gd.u.boxelements = harray1;
503 	boxes[3].creator = GHBoxCreate;
504 	varray[l++] = &boxes[3];
505 
506 	varray[l++] = GCD_Glue;
507 
508 	gcd[6+j].gd.pos.x = 5; gcd[6+j].gd.pos.y = RI_Height+(j==10?12:0)-70;
509 	gcd[6+j].gd.pos.width = RI_Width-10;
510 	gcd[6+j].gd.flags = gg_visible | gg_enabled;
511 	varray[l++] = &gcd[6+j];
512 	gcd[6+j++].creator = GLineCreate;
513 
514 	label[6+j].text = (unichar_t *) _("Bounding Box:");
515 	label[6+j].text_is_1byte = true;
516 	gcd[6+j].gd.label = &label[6+j];
517 	gcd[6+j].gd.flags = gg_enabled|gg_visible;
518 	gcd[6+j].creator = GLabelCreate;
519 	varray[l++] = &gcd[6+j];
520 	++j;
521 
522 	hvarray2[0][0] = GCD_Glue; hvarray2[0][1] = GCD_Glue;
523 
524 	label[6+j].text = (unichar_t *) _("Min");
525 	label[6+j].text_is_1byte = true;
526 	gcd[6+j].gd.label = &label[6+j];
527 	gcd[6+j].gd.flags = gg_enabled|gg_visible;
528 	gcd[6+j].creator = GLabelCreate;
529 	hvarray2[0][2] = &gcd[6+j++];
530 
531 	label[6+j].text = (unichar_t *) _("Max");
532 	label[6+j].text_is_1byte = true;
533 	gcd[6+j].gd.label = &label[6+j];
534 	gcd[6+j].gd.flags = gg_enabled|gg_visible;
535 	gcd[6+j].creator = GLabelCreate;
536 	hvarray2[0][3] = &gcd[6+j++]; hvarray2[0][4] = GCD_Glue; hvarray2[0][5] = NULL;
537 
538 	hvarray2[1][0] = hvarray2[1][4] = GCD_Glue; hvarray2[1][5] = NULL;
539 	hvarray2[2][0] = hvarray2[2][4] = GCD_Glue; hvarray2[2][5] = NULL;
540 
541 	label[6+j].text = (unichar_t *) _("X:");
542 	label[6+j].text_is_1byte = true;
543 	gcd[6+j].gd.label = &label[6+j];
544 	gcd[6+j].gd.flags = gg_enabled|gg_visible;
545 	gcd[6+j].creator = GLabelCreate;
546 	hvarray2[1][1] = &gcd[6+j++];
547 
548 	label[6+j].text = (unichar_t *) _("Y:");
549 	label[6+j].text_is_1byte = true;
550 	gcd[6+j].gd.label = &label[6+j];
551 	gcd[6+j].gd.flags = gg_enabled|gg_visible;
552 	gcd[6+j].creator = GLabelCreate;
553 	hvarray2[2][1] = &gcd[6+j++];
554 
555 	for ( i=0; i<4; ++i ) {
556 	    sprintf(bbbuf[i],"%g", (double) ((&ref->bb.minx)[i]));
557 	    label[6+j].text = (unichar_t *) bbbuf[i];
558 	    label[6+j].text_is_1byte = true;
559 	    gcd[6+j].gd.label = &label[6+j];
560 	    gcd[6+j].gd.flags = gg_enabled|gg_visible;
561 	    gcd[6+j].creator = GLabelCreate;
562 	    hvarray2[1+i/2][2+(i&1)] = &gcd[6+j++];
563 	}
564 	hvarray2[3][0] = NULL;
565 
566 	boxes[4].gd.flags = gg_enabled|gg_visible;
567 	boxes[4].gd.u.boxelements = hvarray2[0];
568 	boxes[4].creator = GHVBoxCreate;
569 	varray[l++] = &boxes[4];
570 
571 	gcd[6+j].gd.pos.x = 5; gcd[6+j].gd.pos.y = RI_Height+(j==10?12:0)-70;
572 	gcd[6+j].gd.pos.width = RI_Width-10;
573 	gcd[6+j].gd.flags = gg_visible | gg_enabled;
574 	varray[l++] = &gcd[6+j];
575 	gcd[6+j++].creator = GLineCreate;
576 
577 	gcd[6+j].gd.pos.x = (RI_Width-GIntGetResource(_NUM_Buttonsize))/2;
578 	gcd[6+j].gd.pos.y = gcd[6+j-1].gd.pos.y+6;
579 	gcd[6+j].gd.pos.width = -1; gcd[6+j].gd.pos.height = 0;
580 	gcd[6+j].gd.flags = gg_visible | gg_enabled ;
581 	label[6+j].text = (unichar_t *) _("_Show");
582 	label[6+j].text_is_1byte = true;
583 	label[6+j].text_in_resource = true;
584 	gcd[6+j].gd.mnemonic = 'S';
585 	gcd[6+j].gd.label = &label[6+j];
586 	gcd[6+j].gd.handle_controlevent = GI_Show;
587 	harray2[0] = GCD_Glue; harray2[1] = &gcd[6+j]; harray2[2] = GCD_Glue; harray2[3] = NULL;
588 	gcd[6+j++].creator = GButtonCreate;
589 
590 	boxes[5].gd.flags = gg_enabled|gg_visible;
591 	boxes[5].gd.u.boxelements = harray2;
592 	boxes[5].creator = GHBoxCreate;
593 	varray[l++] = &boxes[5];
594 
595 	gcd[6+j] = gcd[6+j-2];
596 	varray[l++] = &gcd[6+j++];
597 
598 	gcd[6+j].gd.pos.x = 30-3; gcd[6+j].gd.pos.y = RI_Height+(j==13?12:0)-30-3;
599 	gcd[6+j].gd.pos.width = -1; gcd[6+j].gd.pos.height = 0;
600 	gcd[6+j].gd.flags = gg_visible | gg_enabled | gg_but_default;
601 	label[6+j].text = (unichar_t *) _("_OK");
602 	label[6+j].text_is_1byte = true;
603 	label[6+j].text_in_resource = true;
604 	gcd[6+j].gd.mnemonic = 'O';
605 	gcd[6+j].gd.label = &label[6+j];
606 	gcd[6+j].gd.handle_controlevent = GI_ROK;
607 	gcd[6+j++].creator = GButtonCreate;
608 
609 	gcd[6+j].gd.pos.x = -30; gcd[6+j].gd.pos.y = gcd[6+j-1].gd.pos.y+3;
610 	gcd[6+j].gd.pos.width = -1; gcd[6+j].gd.pos.height = 0;
611 	gcd[6+j].gd.flags = gg_visible | gg_enabled | gg_but_cancel;
612 	label[6+j].text = (unichar_t *) _("_Cancel");
613 	label[6+j].text_is_1byte = true;
614 	label[6+j].text_in_resource = true;
615 	gcd[6+j].gd.mnemonic = 'C';
616 	gcd[6+j].gd.label = &label[6+j];
617 	gcd[6+j].gd.handle_controlevent = GI_Cancel;
618 	gcd[6+j].creator = GButtonCreate;
619 
620 	harray3[0] = GCD_Glue; harray3[1] = &gcd[6+j-1]; harray3[2] = GCD_Glue;
621 	 harray3[3] = GCD_Glue; harray3[4] = &gcd[6+j]; harray3[5] = GCD_Glue;
622 	 harray3[6] = NULL;
623 	boxes[6].gd.flags = gg_enabled|gg_visible;
624 	boxes[6].gd.u.boxelements = harray3;
625 	boxes[6].creator = GHBoxCreate;
626 	varray[l++] = &boxes[6];
627 	varray[l] = NULL;
628 
629 	boxes[0].gd.flags = gg_enabled|gg_visible;
630 	boxes[0].gd.u.boxelements = varray;
631 	boxes[0].creator = GVBoxCreate;
632 
633 	GGadgetsCreate(gi.gw,boxes);
634 	GWidgetIndicateFocusGadget(gcd[j].ret);
635     GHVBoxSetExpandableRow(boxes[0].ret,0);
636     GHVBoxSetExpandableCol(boxes[2].ret,gb_expandglue);
637     GHVBoxSetExpandableCol(boxes[3].ret,gb_expandglue);
638     GHVBoxSetPadding(boxes[3].ret,6,2);
639     GHVBoxSetExpandableCol(boxes[4].ret,gb_expandglue);
640     GHVBoxSetExpandableCol(boxes[5].ret,gb_expandglue);
641     GHVBoxSetExpandableCol(boxes[6].ret,gb_expandgluesame);
642     GHVBoxFitWindow(boxes[0].ret);
643 
644     GWidgetHidePalettes();
645     GDrawSetVisible(gi.gw,true);
646     while ( !gi.done )
647 	GDrawProcessOneEvent(NULL);
648     GDrawDestroyWindow(gi.gw);
649 }
650 
ImgGetInfo(CharView * cv,ImageList * img)651 static void ImgGetInfo(CharView *cv, ImageList *img) {
652     static GIData gi;
653     GRect pos;
654     GWindowAttrs wattrs;
655     GGadgetCreateData gcd[12], boxes[3], *varray[11], *harray[6];
656     GTextInfo label[12];
657     char posbuf[100], scalebuf[100], sizebuf[100];
658     struct _GImage *base = img->image->list_len==0?
659 	    img->image->u.image:img->image->u.images[0];
660 
661     gi.cv = cv;
662     gi.sc = cv->b.sc;
663     gi.img = img;
664     gi.done = false;
665 
666 	memset(&wattrs,0,sizeof(wattrs));
667 	wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_undercursor|wam_isdlg|wam_restrict;
668 	wattrs.event_masks = ~(1<<et_charup);
669 	wattrs.restrict_input_to_me = 1;
670 	wattrs.undercursor = 1;
671 	wattrs.cursor = ct_pointer;
672 	wattrs.utf8_window_title = _("Image Info");
673 	wattrs.is_dlg = true;
674 	pos.x = pos.y = 0;
675 	pos.width = GGadgetScale(GDrawPointsToPixels(NULL,II_Width));
676 	pos.height = GDrawPointsToPixels(NULL,II_Height);
677 	gi.gw = GDrawCreateTopWindow(NULL,&pos,gi_e_h,&gi,&wattrs);
678 
679 	memset(&gcd,0,sizeof(gcd));
680 	memset(&label,0,sizeof(label));
681 
682 	sprintf( posbuf, _("Image at:      (%.0f,%.0f)"), (double) img->xoff,
683 		(double) (img->yoff-GImageGetHeight(img->image)*img->yscale));
684 	label[0].text = (unichar_t *) posbuf;
685 	label[0].text_is_1byte = true;
686 	gcd[0].gd.label = &label[0];
687 	gcd[0].gd.pos.x = 5; gcd[0].gd.pos.y = 5;
688 	gcd[0].gd.flags = gg_enabled|gg_visible;
689 	gcd[0].creator = GLabelCreate;
690 	varray[0] = &gcd[0]; varray[1] = NULL;
691 
692 	sprintf( scalebuf, _("Scaled by:    (%.2f,%.2f)"), (double) img->xscale, (double) img->yscale );
693 	label[1].text = (unichar_t *) scalebuf;
694 	label[1].text_is_1byte = true;
695 	gcd[1].gd.label = &label[1];
696 	gcd[1].gd.pos.x = 5; gcd[1].gd.pos.y = 19;
697 	gcd[1].gd.flags = gg_enabled|gg_visible;
698 	gcd[1].creator = GLabelCreate;
699 	varray[2] = &gcd[1]; varray[3] = NULL;
700 
701 	sprintf( sizebuf, _("Image Size:  %d x %d  pixels"), (int) base->width, (int) base->height );
702 	label[2].text = (unichar_t *) sizebuf;
703 	label[2].text_is_1byte = true;
704 	gcd[2].gd.label = &label[2];
705 	gcd[2].gd.pos.x = 5; gcd[2].gd.pos.y = 19;
706 	gcd[2].gd.flags = gg_enabled|gg_visible;
707 	gcd[2].creator = GLabelCreate;
708 	varray[4] = &gcd[2]; varray[5] = NULL;
709 	varray[6] = GCD_Glue; varray[7] = NULL;
710 
711 	gcd[3].gd.pos.x = (II_Width-GIntGetResource(_NUM_Buttonsize)*100/GIntGetResource(_NUM_ScaleFactor)-6)/2; gcd[3].gd.pos.y = II_Height-32-3;
712 	gcd[3].gd.pos.width = -1; gcd[3].gd.pos.height = 0;
713 	gcd[3].gd.flags = gg_visible | gg_enabled | gg_but_default | gg_but_cancel;
714 	label[3].text = (unichar_t *) _("_OK");
715 	label[3].text_is_1byte = true;
716 	label[3].text_in_resource = true;
717 	gcd[3].gd.mnemonic = 'O';
718 	gcd[3].gd.label = &label[3];
719 	gcd[3].gd.handle_controlevent = GI_Cancel;
720 	gcd[3].creator = GButtonCreate;
721 	harray[0] = GCD_Glue; harray[1] = &gcd[3]; harray[2] = GCD_Glue; harray[3] = NULL;
722 	varray[8] = &boxes[2]; varray[9] = NULL;
723 	varray[10] = NULL;
724 
725 	memset(boxes,0,sizeof(boxes));
726 	boxes[0].gd.pos.x = boxes[0].gd.pos.y = 2;
727 	boxes[0].gd.flags = gg_enabled|gg_visible;
728 	boxes[0].gd.u.boxelements = varray;
729 	boxes[0].creator = GHVGroupCreate;
730 
731 	boxes[2].gd.flags = gg_enabled|gg_visible;
732 	boxes[2].gd.u.boxelements = harray;
733 	boxes[2].creator = GHBoxCreate;
734 
735 	GGadgetsCreate(gi.gw,boxes);
736 	GHVBoxSetExpandableRow(boxes[0].ret,gb_expandglue);
737 	GHVBoxSetExpandableCol(boxes[2].ret,gb_expandglue);
738 	GHVBoxFitWindow(boxes[0].ret);
739 
740     GWidgetHidePalettes();
741     GDrawSetVisible(gi.gw,true);
742     while ( !gi.done )
743 	GDrawProcessOneEvent(NULL);
744     GDrawDestroyWindow(gi.gw);
745 }
746 
_AnchorClassUnused(SplineChar * sc,int * waslig,int classmatch)747 static AnchorClass *_AnchorClassUnused(SplineChar *sc,int *waslig, int classmatch) {
748     AnchorClass *an, *maybe;
749     int val, maybelig;
750     SplineFont *sf;
751     int ismarkglyph, isligatureglyph;
752     PST *pst;
753     /* Are there any anchors with this name? If so can't reuse it */
754     /*  unless they are ligature anchors */
755     /*  or 'curs' anchors, which allow exactly two points (entry, exit) */
756     /*  or 'mkmk' anchors, which allow a mark to be both a base and an attach */
757 
758     ismarkglyph = (sc->width==0) || sc->glyph_class==(3+1) ||
759 	    ( sc->unicodeenc!=-1 && sc->unicodeenc<0x10000 && iscombining(sc->unicodeenc)) ||
760 	    ( sc->anchor!=NULL && (sc->anchor->type == at_mark || sc->anchor->type == at_basemark));
761     for ( pst = sc->possub; pst!=NULL && pst->type!=pst_ligature; pst=pst->next );
762     isligatureglyph = (pst!=NULL) || sc->glyph_class==2+1;
763 
764     *waslig = false; maybelig = false; maybe = NULL;
765     sf = sc->parent;
766     if ( sf->cidmaster!=NULL ) sf = sf->cidmaster;
767     for ( an=sf->anchor; an!=NULL; an=an->next ) {
768 	if ( classmatch ) {
769 	    if (( an->type == act_mklg && !isligatureglyph && !ismarkglyph ) ||
770 		    ( an->type == act_mkmk && !ismarkglyph ))
771     continue;
772 	}
773 	val = IsAnchorClassUsed(sc,an);
774 	if ( val>=0 ) {
775 	    *waslig = val;
776 return( an );
777 	} else if ( val!=-1 && maybe==NULL ) {
778 	    maybe = an;
779 	    maybelig = val;
780 	}
781     }
782     *waslig = maybelig;
783 return( maybe );
784 }
785 
AnchorClassUnused(SplineChar * sc,int * waslig)786 AnchorClass *AnchorClassUnused(SplineChar *sc,int *waslig) {
787 return( _AnchorClassUnused(sc,waslig,false));
788 }
789 
AnchorPointNew(CharView * cv)790 static AnchorPoint *AnchorPointNew(CharView *cv) {
791     AnchorClass *an;
792     AnchorPoint *ap;
793     int waslig;
794     SplineChar *sc = cv->b.sc;
795     PST *pst;
796 
797     an = _AnchorClassUnused(sc,&waslig,true);
798     if ( an==NULL )
799 	an = AnchorClassUnused(sc,&waslig);
800 
801     if ( an==NULL )
802 return(NULL);
803     ap = chunkalloc(sizeof(AnchorPoint));
804     ap->anchor = an;
805     ap->me.x = cv->p.cx; /* cv->p.cx = 0; */
806     ap->me.y = cv->p.cy; /* cv->p.cy = 0; */
807     ap->type = an->type==act_mark ? at_basechar :
808 		an->type==act_mkmk ? at_basemark :
809 		an->type==act_mklg ? at_baselig :
810 		an->type==act_curs ? at_centry :
811                                      at_basechar;
812     for ( pst = cv->b.sc->possub; pst!=NULL && pst->type!=pst_ligature; pst=pst->next );
813     if ( waslig<-1 && an->type==act_mkmk ) {
814 	ap->type = waslig==-2 ? at_basemark : at_mark;
815     } else if ( waslig==-2  && an->type==act_curs )
816 	ap->type = at_cexit;
817     else if ( waslig==-3 || an->type==act_curs )
818 	ap->type = at_centry;
819     else if (( sc->unicodeenc!=-1 && sc->unicodeenc<0x10000 &&
820 	    iscombining(sc->unicodeenc)) || sc->width==0 || sc->glyph_class==(3+1) /* mark class+1 */)
821 	ap->type = at_mark;
822     else if ( an->type==act_mkmk )
823 	ap->type = at_basemark;
824     else if (( pst!=NULL || waslig || sc->glyph_class==2+1) && an->type==act_mklg )
825 	ap->type = at_baselig;
826     if (( ap->type==at_basechar || ap->type==at_baselig ) && an->type==act_mkmk )
827 	ap->type = at_basemark;
828     ap->next = sc->anchor;
829     if ( waslig>=0 )
830 	ap->lig_index = waslig;
831     sc->anchor = ap;
832 return( ap );
833 }
834 
AI_SelectList(GIData * ci,AnchorPoint * ap)835 static void AI_SelectList(GIData *ci,AnchorPoint *ap) {
836     int i;
837     AnchorClass *an;
838     SplineFont *sf = ci->sc->parent;
839 
840     if ( sf->cidmaster ) sf = sf->cidmaster;
841 
842     for ( i=0, an=sf->anchor; an!=ap->anchor; ++i, an=an->next );
843     GGadgetSelectOneListItem(GWidgetGetControl(ci->gw,CID_NameList),i);
844 }
845 
AI_DisplayClass(GIData * ci,AnchorPoint * ap)846 static void AI_DisplayClass(GIData *ci,AnchorPoint *ap) {
847     AnchorClass *ac = ap->anchor;
848     AnchorPoint *aps;
849     int saw[at_max];
850 
851     GGadgetSetEnabled(GWidgetGetControl(ci->gw,CID_BaseChar),ac->type==act_mark || ac->type==act_unknown);
852     GGadgetSetEnabled(GWidgetGetControl(ci->gw,CID_BaseLig),ac->type==act_mklg);
853     GGadgetSetEnabled(GWidgetGetControl(ci->gw,CID_BaseMark),ac->type==act_mkmk);
854     GGadgetSetEnabled(GWidgetGetControl(ci->gw,CID_CursEntry),ac->type==act_curs);
855     GGadgetSetEnabled(GWidgetGetControl(ci->gw,CID_CursExit),ac->type==act_curs);
856     GGadgetSetEnabled(GWidgetGetControl(ci->gw,CID_Mark),ac->type!=act_curs);
857 
858     GGadgetSetEnabled(GWidgetGetControl(ci->gw,CID_LigIndex),ap->type==at_baselig);
859 
860     if ( ac->type==act_mkmk && (ap->type==at_basechar || ap->type==at_baselig)) {
861 	GGadgetSetChecked(GWidgetGetControl(ci->gw,CID_BaseMark),true);
862 	ap->type = at_basemark;
863     } else if ( ac->type==act_mark && ap->type==at_basemark ) {
864 	GGadgetSetChecked(GWidgetGetControl(ci->gw,CID_BaseChar),true);
865 	ap->type = at_basechar;
866     } else if ( ac->type==act_curs && ap->type!=at_centry && ap->type!=at_cexit ) {
867 	GGadgetSetChecked(GWidgetGetControl(ci->gw,CID_CursEntry),true);
868 	ap->type = at_centry;
869     }
870 
871     memset(saw,0,sizeof(saw));
872     for ( aps=ci->sc->anchor; aps!=NULL; aps=aps->next ) if ( aps!=ap ) {
873 	if ( aps->anchor==ac ) saw[aps->type] = true;
874     }
875     if ( ac->type==act_curs ) {
876 	GGadgetSetEnabled(GWidgetGetControl(ci->gw,CID_CursEntry),!saw[at_centry]);
877 	GGadgetSetEnabled(GWidgetGetControl(ci->gw,CID_CursExit),!saw[at_cexit]);
878     } else {
879 	GGadgetSetEnabled(GWidgetGetControl(ci->gw,CID_Mark),!saw[at_mark]);
880 	if ( saw[at_basechar]) GGadgetSetEnabled(GWidgetGetControl(ci->gw,CID_BaseChar),false);
881 	if ( saw[at_basemark]) GGadgetSetEnabled(GWidgetGetControl(ci->gw,CID_BaseMark),false);
882     }
883 }
884 
AI_DisplayIndex(GIData * ci,AnchorPoint * ap)885 static void AI_DisplayIndex(GIData *ci,AnchorPoint *ap) {
886     char buffer[12];
887 
888     sprintf(buffer,"%d", ap->lig_index );
889 
890     GGadgetSetTitle8(GWidgetGetControl(ci->gw,CID_LigIndex),buffer);
891 }
892 
AI_DisplayRadio(GIData * ci,enum anchor_type type)893 static void AI_DisplayRadio(GIData *ci,enum anchor_type type) {
894     switch ( type ) {
895       case at_mark:
896 	GGadgetSetChecked(GWidgetGetControl(ci->gw,CID_Mark),true);
897       break;
898       case at_basechar:
899 	GGadgetSetChecked(GWidgetGetControl(ci->gw,CID_BaseChar),true);
900       break;
901       case at_baselig:
902 	GGadgetSetChecked(GWidgetGetControl(ci->gw,CID_BaseLig),true);
903       break;
904       case at_basemark:
905 	GGadgetSetChecked(GWidgetGetControl(ci->gw,CID_BaseMark),true);
906       break;
907       case at_centry:
908 	GGadgetSetChecked(GWidgetGetControl(ci->gw,CID_CursEntry),true);
909       break;
910       case at_cexit:
911 	GGadgetSetChecked(GWidgetGetControl(ci->gw,CID_CursExit),true);
912       break;
913     }
914 }
915 
AI_Display(GIData * ci,AnchorPoint * ap)916 static void AI_Display(GIData *ci,AnchorPoint *ap) {
917     char val[40];
918     unichar_t uval[40];
919     AnchorPoint *aps;
920 
921     if ( ap==NULL) {
922 	SCUpdateAll(ci->sc);
923 return;
924     }
925 
926     ci->ap = ap;
927     for ( aps=ci->sc->anchor; aps!=NULL; aps=aps->next )
928 	aps->selected = false;
929     ap->selected = true;
930     sprintf(val,"%g",(double) ap->me.x);
931     uc_strcpy(uval,val);
932     GGadgetSetTitle(GWidgetGetControl(ci->gw,CID_X),uval);
933     sprintf(val,"%g",(double) ap->me.y);
934     uc_strcpy(uval,val);
935     GGadgetSetTitle(GWidgetGetControl(ci->gw,CID_Y),uval);
936     sprintf(val,"%d",ap->type==at_baselig?ap->lig_index:0);
937     uc_strcpy(uval,val);
938     GGadgetSetTitle(GWidgetGetControl(ci->gw,CID_LigIndex),uval);
939     GGadgetSetEnabled(GWidgetGetControl(ci->gw,CID_LigIndex),ap->type==at_baselig);
940     GGadgetSetEnabled(GWidgetGetControl(ci->gw,CID_Next),ap->next!=NULL);
941     GGadgetSetEnabled(GWidgetGetControl(ci->gw,CID_Prev),ci->sc->anchor!=ap);
942     if ( ap->has_ttf_pt )
943 	sprintf(val,"%d",ap->ttf_pt_index);
944     else
945 	val[0] = '\0';
946     GGadgetSetTitle8(GWidgetGetControl(ci->gw,CID_MatchPt),val);
947     GGadgetSetEnabled(GWidgetGetControl(ci->gw,CID_X),!ap->has_ttf_pt);
948     GGadgetSetEnabled(GWidgetGetControl(ci->gw,CID_Y),!ap->has_ttf_pt);
949 
950     AI_DisplayClass(ci,ap);
951     AI_DisplayRadio(ci,ap->type);
952 
953     AI_SelectList(ci,ap);
954     SCUpdateAll(ci->sc);
955 }
956 
AI_Next(GGadget * g,GEvent * e)957 static int AI_Next(GGadget *g, GEvent *e) {
958     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
959 	GIData *ci = GDrawGetUserData(GGadgetGetWindow(g));
960 
961 	if ( ci->ap->next==NULL )
962 return( true );
963 	AI_Display(ci,ci->ap->next);
964     }
965 return( true );
966 }
967 
AI_Prev(GGadget * g,GEvent * e)968 static int AI_Prev(GGadget *g, GEvent *e) {
969     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
970 	GIData *ci = GDrawGetUserData(GGadgetGetWindow(g));
971 	AnchorPoint *ap, *prev;
972 
973 	prev = NULL;
974 	for ( ap=ci->sc->anchor; ap!=ci->ap; ap = ap->next )
975 	    prev = ap;
976 	if ( prev==NULL )
977 return( true );
978 	AI_Display(ci,prev);
979     }
980 return( true );
981 }
982 
983 static int AI_Ok(GGadget *g, GEvent *e);
AI_Delete(GGadget * g,GEvent * e)984 static int AI_Delete(GGadget *g, GEvent *e) {
985     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
986 	GIData *ci = GDrawGetUserData(GGadgetGetWindow(g));
987 	AnchorPoint *ap, *prev, *delete_it;
988 
989 	prev=NULL;
990 	for ( ap=ci->sc->anchor; ap!=ci->ap; ap=ap->next )
991 	    prev = ap;
992 	if ( prev==NULL && ci->ap->next==NULL ) {
993 	    static char *buts[3];
994 	    buts[0] = _("_Yes"); buts[1] = _("_No"); buts[2] = NULL;
995 	    if ( gwwv_ask(_("Last Anchor Point"),(const char **) buts,0,1, _("You are deleting the last anchor point in this character.\nDoing so will cause this dialog to close, is that what you want?"))==1 ) {
996 		AI_Ok(g,e);
997 return( true );
998 	    }
999 	}
1000 
1001 	delete_it = ci->ap;
1002 
1003 	if ((prev == NULL) && (ci->ap->next == NULL)) {
1004 	    ci->sc->anchor = NULL;
1005 	    AnchorPointsFree(delete_it);
1006 	    AI_Ok(g,e);
1007 	    SCUpdateAll(ci->sc);
1008 	}
1009 	else if (ci->ap->next == NULL) {
1010 	    prev->next = NULL;
1011 	    AnchorPointsFree(delete_it);
1012 	    AI_Display(ci,prev);
1013 	}
1014 	else if (prev == NULL) {
1015 	    ci->sc->anchor = delete_it->next;
1016 	    delete_it->next = NULL;
1017 	    AnchorPointsFree(delete_it);
1018 	    AI_Display(ci,ci->sc->anchor);
1019 	}
1020 	else {
1021 	    prev->next = delete_it->next;
1022 	    delete_it->next = NULL;
1023 	    AnchorPointsFree(delete_it);
1024 	    AI_Display(ci,prev->next);
1025 	}
1026 
1027 	_CVCharChangedUpdate(&ci->cv->b,2);
1028     }
1029 return( true );
1030 }
1031 
AnchorClassesLList(SplineFont * sf)1032 static GTextInfo **AnchorClassesLList(SplineFont *sf) {
1033     AnchorClass *an;
1034     int cnt;
1035     GTextInfo **ti;
1036 
1037     if ( sf->cidmaster ) sf=sf->cidmaster;
1038 
1039     for ( cnt=0, an=sf->anchor; an!=NULL; ++cnt, an=an->next );
1040     ti = calloc(cnt+1,sizeof(GTextInfo*));
1041     for ( cnt=0, an=sf->anchor; an!=NULL; ++cnt, an=an->next ) {
1042 	ti[cnt] = calloc(1,sizeof(GTextInfo));
1043 	ti[cnt]->text = utf82u_copy(an->name);
1044 	ti[cnt]->fg = ti[cnt]->bg = COLOR_DEFAULT;
1045 	ti[cnt]->userdata = an;
1046     }
1047     ti[cnt] = calloc(1,sizeof(GTextInfo));
1048 return( ti );
1049 }
1050 
AI_NewClass(GGadget * g,GEvent * e)1051 static int AI_NewClass(GGadget *g, GEvent *e) {
1052     GIData *ci = GDrawGetUserData(GGadgetGetWindow(g));
1053     SplineFont *sf = ci->sc->parent;
1054     AnchorClass *ac;
1055     GTextInfo **ti;
1056     int j;
1057     char *name = gwwv_ask_string(_("Anchor Class Name"),"",_("Please enter the name of a Anchor point class to create"));
1058     if ( name==NULL )
1059 return( true );
1060     ac = SFFindOrAddAnchorClass(sf,name,NULL);
1061     GGadgetSetList(GWidgetGetControl(ci->gw,CID_NameList),
1062     ti = AnchorClassesLList(sf),false);
1063     for ( j=0; ti[j]->text!=NULL && ti[j]->userdata!=ac; ++j )
1064         GGadgetSelectOneListItem(GWidgetGetControl(ci->gw,CID_NameList),j);
1065 return( true );
1066 }
1067 
AI_New(GGadget * g,GEvent * e)1068 static int AI_New(GGadget *g, GEvent *e) {
1069     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
1070 	GIData *ci = GDrawGetUserData(GGadgetGetWindow(g));
1071 	int waslig;
1072 	AnchorPoint *ap;
1073 	SplineFont *sf = ci->sc->parent;
1074 
1075 	if ( sf->cidmaster ) sf = sf->cidmaster;
1076 
1077 	if ( AnchorClassUnused(ci->sc,&waslig)==NULL ) {
1078             if ( !AI_NewClass(g, e) )
1079 return( false );
1080 	}
1081 	ap = AnchorPointNew(ci->cv);
1082 	if ( ap==NULL )
1083 return( true );
1084 	AI_Display(ci,ap);
1085     }
1086 return( true );
1087 }
1088 
AI_TypeChanged(GGadget * g,GEvent * e)1089 static int AI_TypeChanged(GGadget *g, GEvent *e) {
1090     if ( e->type==et_controlevent && e->u.control.subtype == et_radiochanged ) {
1091 	GIData *ci = GDrawGetUserData(GGadgetGetWindow(g));
1092 	AnchorPoint *ap = ci->ap;
1093 
1094 	if ( GGadgetIsChecked(GWidgetGetControl(ci->gw,CID_Mark)) )
1095 	    ap->type = at_mark;
1096 	else if ( GGadgetIsChecked(GWidgetGetControl(ci->gw,CID_BaseChar)) )
1097 	    ap->type = at_basechar;
1098 	else if ( GGadgetIsChecked(GWidgetGetControl(ci->gw,CID_BaseLig)) )
1099 	    ap->type = at_baselig;
1100 	else if ( GGadgetIsChecked(GWidgetGetControl(ci->gw,CID_BaseMark)) )
1101 	    ap->type = at_basemark;
1102 	else if ( GGadgetIsChecked(GWidgetGetControl(ci->gw,CID_CursEntry)) )
1103 	    ap->type = at_centry;
1104 	else if ( GGadgetIsChecked(GWidgetGetControl(ci->gw,CID_CursExit)) )
1105 	    ap->type = at_cexit;
1106 	GGadgetSetEnabled(GWidgetGetControl(ci->gw,CID_LigIndex),ap->type==at_baselig);
1107 	_CVCharChangedUpdate(&ci->cv->b,2);
1108     }
1109 return( true );
1110 }
1111 
AI_TestOrdering(GIData * ci,real x)1112 static void AI_TestOrdering(GIData *ci,real x) {
1113     AnchorPoint *aps, *ap=ci->ap;
1114     AnchorClass *ac = ap->anchor;
1115     int isr2l;
1116 
1117     isr2l = SCRightToLeft(ci->sc);
1118     for ( aps=ci->sc->anchor; aps!=NULL; aps=aps->next ) {
1119 	if ( aps->anchor==ac && aps!=ci->ap ) {
1120 	    if (( aps->lig_index<ap->lig_index &&
1121 		    ((!isr2l && aps->me.x>x) ||
1122 		     ( isr2l && aps->me.x<x))) ||
1123 		( aps->lig_index>ap->lig_index &&
1124 		    (( isr2l && aps->me.x>x) ||
1125 		     (!isr2l && aps->me.x<x))) ) {
1126 		ff_post_error(_("Out Of Order"),_("Marks within a ligature should be ordered with the direction of writing.\nThis one and %d are out of order."),aps->lig_index);
1127 return;
1128 	    }
1129 	}
1130     }
1131 return;
1132 }
1133 
AI_LigIndexChanged(GGadget * g,GEvent * e)1134 static int AI_LigIndexChanged(GGadget *g, GEvent *e) {
1135     if ( e->type==et_controlevent && e->u.control.subtype == et_textchanged ) {
1136 	GIData *ci = GDrawGetUserData(GGadgetGetWindow(g));
1137 	int index, max;
1138 	int err=false;
1139 	AnchorPoint *ap = ci->ap, *aps;
1140 
1141 	index = GetCalmReal8(ci->gw,CID_LigIndex,_("Lig Index:"),&err);
1142 	if ( index<0 || err )
1143 return( true );
1144 	if ( *_GGadgetGetTitle(g)=='\0' )
1145 return( true );
1146 	max = 0;
1147 	AI_TestOrdering(ci,ap->me.x);
1148 	for ( aps=ci->sc->anchor; aps!=NULL; aps=aps->next ) {
1149 	    if ( aps->anchor==ap->anchor && aps!=ap ) {
1150 		if ( aps->lig_index==index ) {
1151 		    ff_post_error(_("Index in use"),_("This ligature index is already in use"));
1152 return( true );
1153 		} else if ( aps->lig_index>max )
1154 		    max = aps->lig_index;
1155 	    }
1156 	}
1157 	if ( index>max+10 ) {
1158 	    char buf[20];
1159 	    ff_post_error(_("Too Big"),_("This index is much larger than the closest neighbor"));
1160 	    sprintf(buf,"%d", max+1);
1161 	    GGadgetSetTitle8(g,buf);
1162 	    index = max+1;
1163 	}
1164 	ap->lig_index = index;
1165 	_CVCharChangedUpdate(&ci->cv->b,2);
1166     }
1167 return( true );
1168 }
1169 
AI_ANameChanged(GGadget * g,GEvent * e)1170 static int AI_ANameChanged(GGadget *g, GEvent *e) {
1171     if ( e->type==et_controlevent && e->u.control.subtype == et_listselected ) {
1172 	GIData *ci = GDrawGetUserData(GGadgetGetWindow(g));
1173 	AnchorPoint *ap;
1174 	GTextInfo *ti = GGadgetGetListItemSelected(g);
1175 	AnchorClass *an = ti->userdata;
1176 	int change=0, max=0;
1177 	int ntype;
1178 	int sawentry, sawexit;
1179 
1180 	if ( an==ci->ap->anchor )
1181 return( true );			/* No op */
1182 
1183 	ntype = ci->ap->type;
1184 	if ( an->type==act_curs ) {
1185 	    if ( ntype!=at_centry && ntype!=at_cexit )
1186 		ntype = at_centry;
1187 	} else if ( an->type==act_mkmk ) {
1188 	    if ( ntype!=at_basemark && ntype!=at_mark )
1189 		ntype = at_basemark;
1190 	} else if ( ntype==at_centry || ntype==at_cexit || ntype==at_basemark ||
1191 		ntype==at_baselig || ntype == at_basechar ) {
1192 	    PST *pst;
1193 	    for ( pst = ci->sc->possub; pst!=NULL && pst->type!=pst_ligature; pst=pst->next );
1194 	    if (ci->sc->glyph_class==3+1 ||
1195 		    (ci->sc->unicodeenc!=-1 && ci->sc->unicodeenc<0x10000 &&
1196 		    iscombining(ci->sc->unicodeenc)))
1197 		ntype = at_mark;
1198 	    else if (( pst!=NULL || ci->sc->glyph_class==2+1 ) && an->type==act_mklg )
1199 		ntype = at_baselig;
1200 	    else
1201 		ntype = at_basechar;
1202 	}
1203 
1204 	sawentry = sawexit = false;
1205 	for ( ap=ci->sc->anchor; ap!=NULL; ap = ap->next ) {
1206 	    if ( ap!=ci->ap && ap->anchor==an ) {
1207 		if ( an->type==act_curs ) {
1208 		    if ( ap->type == at_centry ) sawentry = true;
1209 		    else if ( ap->type== at_cexit ) sawexit = true;
1210 		} else if ( an->type==act_mkmk ) {
1211 		    if ( ap->type == at_mark ) sawentry = true;
1212 		    else if ( ap->type== at_basemark ) sawexit = true;
1213 		} else {
1214 		    if ( ap->type!=at_baselig )
1215 	break;
1216 		    if ( ap->lig_index==ci->ap->lig_index )
1217 			change = true;
1218 		    else if ( ap->lig_index>max )
1219 			max = ap->lig_index;
1220 		}
1221 	    } else if ( ap!=ci->ap && ap->anchor->subtable==an->subtable &&
1222 		    ap->type==at_mark )
1223 	break;
1224 	}
1225 	if ( ap!=NULL || (sawentry && sawexit)) {
1226 	    AI_SelectList(ci,ci->ap);
1227 	    ff_post_error(_("Class already used"),_("This anchor class already is associated with a point in this character"));
1228 	} else {
1229 	    ci->ap->anchor = an;
1230 	    if ( an->type==act_curs ) {
1231 		if ( sawentry ) ntype = at_cexit;
1232 		else if ( sawexit ) ntype = at_centry;
1233 	    } else if ( an->type==act_mkmk ) {
1234 		if ( sawentry ) ntype = at_basemark;
1235 		else if ( sawexit ) ntype = at_mark;
1236 	    }
1237 	    if ( ci->ap->type!=ntype ) {
1238 		ci->ap->type = ntype;
1239 		AI_DisplayRadio(ci,ntype);
1240 	    }
1241 	    if ( ci->ap->type!=at_baselig )
1242 		ci->ap->lig_index = 0;
1243 	    else if ( change ) {
1244 		ci->ap->lig_index = max+1;
1245 		AI_DisplayIndex(ci,ci->ap);
1246 	    }
1247 	    AI_DisplayClass(ci,ci->ap);
1248 	    AI_TestOrdering(ci,ci->ap->me.x);
1249 	}
1250 	_CVCharChangedUpdate(&ci->cv->b,2);
1251     }
1252 return( true );
1253 }
1254 
AI_PosChanged(GGadget * g,GEvent * e)1255 static int AI_PosChanged(GGadget *g, GEvent *e) {
1256     if ( e->type==et_controlevent && e->u.control.subtype == et_textchanged ) {
1257 	GIData *ci = GDrawGetUserData(GGadgetGetWindow(g));
1258 	real dx=0, dy=0;
1259 	int err=false;
1260 	AnchorPoint *ap = ci->ap;
1261 
1262 	if ( GGadgetGetCid(g)==CID_X ) {
1263 	    dx = GetCalmReal8(ci->gw,CID_X,_("_X"),&err)-ap->me.x;
1264 	    AI_TestOrdering(ci,ap->me.x+dx);
1265 	} else
1266 	    dy = GetCalmReal8(ci->gw,CID_Y,_("_Y"),&err)-ap->me.y;
1267 	if ( (dx==0 && dy==0) || err )
1268 return( true );
1269 	ap->me.x += dx;
1270 	ap->me.y += dy;
1271 	_CVCharChangedUpdate(&ci->cv->b,2);
1272     }
1273 return( true );
1274 }
1275 
AI_MatchChanged(GGadget * g,GEvent * e)1276 static int AI_MatchChanged(GGadget *g, GEvent *e) {
1277     if ( e->type==et_controlevent && e->u.control.subtype == et_textchanged ) {
1278 	GIData *ci = GDrawGetUserData(GGadgetGetWindow(g));
1279 	const unichar_t *t1 = _GGadgetGetTitle(GWidgetGetControl(ci->gw,CID_MatchPt));
1280 	unichar_t *end;
1281 	AnchorPoint *ap = ci->ap;
1282 
1283 	while ( *t1==' ' ) ++t1;
1284 	GGadgetSetEnabled(GWidgetGetControl(ci->gw,CID_X),*t1=='\0');
1285 	GGadgetSetEnabled(GWidgetGetControl(ci->gw,CID_Y),*t1=='\0');
1286 	if ( isdigit(*t1)) {
1287 	    BasePoint here;
1288 	    int pt;
1289 	    pt = u_strtol(t1,&end,10);
1290 	    if ( *end=='\0' && ttfFindPointInSC(ci->cv->b.sc,CVLayer((CharViewBase *) ci->cv),pt,&here,NULL)==-1 ) {
1291 		char buffer[40];
1292 		sprintf(buffer,"%g",(double) here.x);
1293 		GGadgetSetTitle8(GWidgetGetControl(ci->gw,CID_X),buffer);
1294 		sprintf(buffer,"%g",(double) here.y);
1295 		GGadgetSetTitle8(GWidgetGetControl(ci->gw,CID_Y),buffer);
1296 		ap->me = here;
1297 		ap->has_ttf_pt = true;
1298 		ap->ttf_pt_index = pt;
1299 		_CVCharChangedUpdate(&ci->cv->b,2);
1300 	    }
1301 	} else
1302 	    ap->has_ttf_pt = false;
1303     }
1304 return( true );
1305 }
1306 
AI_DoCancel(GIData * ci)1307 static void AI_DoCancel(GIData *ci) {
1308     CharView *cv = ci->cv;
1309     ci->done = true;
1310     AnchorPointsFree(cv->b.sc->anchor);
1311     cv->b.sc->anchor = ci->oldaps;
1312     ci->oldaps = NULL;
1313     CVRemoveTopUndo(&cv->b);
1314     SCUpdateAll(cv->b.sc);
1315 }
1316 
ai_e_h(GWindow gw,GEvent * event)1317 static int ai_e_h(GWindow gw, GEvent *event) {
1318     if ( event->type==et_close ) {
1319 	AI_DoCancel( GDrawGetUserData(gw));
1320     } else if ( event->type==et_char ) {
1321 	if ( event->u.chr.keysym == GK_F1 || event->u.chr.keysym == GK_Help ) {
1322 	    help("ui/dialogs/getinfo.html", NULL);
1323 return( true );
1324 	}
1325 return( false );
1326     } else if ( event->type == et_map ) {
1327 	/* Above palettes */
1328 	GDrawRaise(gw);
1329     }
1330 return( true );
1331 }
1332 
AI_Cancel(GGadget * g,GEvent * e)1333 static int AI_Cancel(GGadget *g, GEvent *e) {
1334     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
1335 	AI_DoCancel( GDrawGetUserData(GGadgetGetWindow(g)));
1336     }
1337 return( true );
1338 }
1339 
AI_Ok(GGadget * g,GEvent * e)1340 static int AI_Ok(GGadget *g, GEvent *e) {
1341     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
1342 	GIData *ci = GDrawGetUserData(GGadgetGetWindow(g));
1343 	ci->done = true;
1344 	/* All the work has been done as we've gone along */
1345 	/* Well, we should reorder the list... */
1346 	SCOrderAP(ci->cv->b.sc);
1347     }
1348 return( true );
1349 }
1350 
ApGetInfo(CharView * cv,AnchorPoint * ap)1351 void ApGetInfo(CharView *cv, AnchorPoint *ap) {
1352     static GIData gi;
1353     GRect pos;
1354     GWindowAttrs wattrs;
1355     GGadgetCreateData gcd[25], boxes[10], *varray[21], *harray1[5], *harray2[3],
1356 	*hvarray[13], *harray3[4], *harray4[6], *harray5[6], *harray6[7];
1357     GTextInfo label[25];
1358     int j;
1359     SplineFont *sf;
1360     GTextInfo **ti;
1361 
1362     memset(&gi,0,sizeof(gi));
1363     gi.cv = cv;
1364     gi.sc = cv->b.sc;
1365     gi.oldaps = AnchorPointsCopy(cv->b.sc->anchor);
1366     CVPreserveState(&cv->b);
1367     if ( ap==NULL ) {
1368 	ap = AnchorPointNew(cv);
1369 	if ( ap==NULL )
1370 return;
1371     }
1372 
1373     gi.ap = ap;
1374     gi.changed = false;
1375     gi.done = false;
1376 
1377 	memset(&wattrs,0,sizeof(wattrs));
1378 	wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_undercursor|wam_isdlg|wam_restrict;
1379 	wattrs.event_masks = ~(1<<et_charup);
1380 	wattrs.restrict_input_to_me = 1;
1381 	wattrs.undercursor = 1;
1382 	wattrs.cursor = ct_pointer;
1383 	wattrs.utf8_window_title = _("Anchor Point Info");
1384 	wattrs.is_dlg = true;
1385 	pos.x = pos.y = 0;
1386 	pos.width = GGadgetScale(GDrawPointsToPixels(NULL,AI_Width));
1387 	pos.height = GDrawPointsToPixels(NULL,AI_Height);
1388 	gi.gw = GDrawCreateTopWindow(NULL,&pos,ai_e_h,&gi,&wattrs);
1389 
1390 	memset(&gcd,0,sizeof(gcd));
1391 	memset(&label,0,sizeof(label));
1392 	memset(&boxes,0,sizeof(boxes));
1393 
1394 	j=0;
1395 	label[j].text = (unichar_t *) ap->anchor->name;
1396 	label[j].text_is_1byte = true;
1397 	gcd[j].gd.label = &label[j];
1398 	gcd[j].gd.pos.x = 5; gcd[j].gd.pos.y = 5;
1399 	gcd[j].gd.pos.width = AI_Width-10;
1400 	gcd[j].gd.flags = gg_enabled|gg_visible;
1401 	gcd[j].gd.cid = CID_NameList;
1402 	sf = cv->b.sc->parent;
1403 	if ( sf->cidmaster ) sf = sf->cidmaster;
1404 	gcd[j].gd.handle_controlevent = AI_ANameChanged;
1405 	gcd[j].creator = GListButtonCreate;
1406 	varray[0] = &gcd[j]; varray[1] = NULL;
1407 	++j;
1408 
1409 	label[j].text = (unichar_t *) _("_X:");
1410 	label[j].text_is_1byte = true;
1411 	label[j].text_in_resource = true;
1412 	gcd[j].gd.label = &label[j];
1413 	gcd[j].gd.pos.x = 5; gcd[j].gd.pos.y = gcd[j-1].gd.pos.y+34;
1414 	gcd[j].gd.flags = gg_enabled|gg_visible;
1415 	gcd[j].creator = GLabelCreate;
1416 	harray1[0] = &gcd[j];
1417 	++j;
1418 
1419 	gcd[j].gd.pos.x = 23; gcd[j].gd.pos.y = gcd[j-1].gd.pos.y-4;
1420 	gcd[j].gd.pos.width = 50;
1421 	gcd[j].gd.flags = gg_enabled|gg_visible;
1422 	gcd[j].gd.cid = CID_X;
1423 	gcd[j].gd.handle_controlevent = AI_PosChanged;
1424 	gcd[j].creator = GNumericFieldCreate;
1425 	harray1[1] = &gcd[j];
1426 	++j;
1427 
1428 	label[j].text = (unichar_t *) _("_Y:");
1429 	label[j].text_is_1byte = true;
1430 	label[j].text_in_resource = true;
1431 	gcd[j].gd.label = &label[j];
1432 	gcd[j].gd.pos.x = 85; gcd[j].gd.pos.y = gcd[j-2].gd.pos.y;
1433 	gcd[j].gd.flags = gg_enabled|gg_visible;
1434 	gcd[j].creator = GLabelCreate;
1435 	harray1[2] = &gcd[j];
1436 	++j;
1437 
1438 	gcd[j].gd.pos.x = 103; gcd[j].gd.pos.y = gcd[j-2].gd.pos.y;
1439 	gcd[j].gd.pos.width = 50;
1440 	gcd[j].gd.flags = gg_enabled|gg_visible;
1441 	gcd[j].gd.cid = CID_Y;
1442 	gcd[j].gd.handle_controlevent = AI_PosChanged;
1443 	gcd[j].creator = GNumericFieldCreate;
1444 	harray1[3] = &gcd[j]; harray1[4] = NULL;
1445 	++j;
1446 
1447 	boxes[2].gd.flags = gg_enabled|gg_visible;
1448 	boxes[2].gd.u.boxelements = harray1;
1449 	boxes[2].creator = GHBoxCreate;
1450 	varray[2] = &boxes[2]; varray[3] = NULL;
1451 
1452 	label[j].text = (unichar_t *) _("Matching TTF Point:");
1453 	label[j].text_is_1byte = true;
1454 	gcd[j].gd.label = &label[j];
1455 	gcd[j].gd.pos.x = 5; gcd[j].gd.pos.y = gcd[j-2].gd.pos.y+24;
1456 	gcd[j].gd.flags = cv->b.sc->layers[ly_fore].order2 ? (gg_enabled|gg_visible) : gg_visible;
1457 	gcd[j].creator = GLabelCreate;
1458 	harray2[0] = &gcd[j];
1459 	++j;
1460 
1461 	gcd[j].gd.pos.x = 103; gcd[j].gd.pos.y = gcd[j-1].gd.pos.y-2;
1462 	gcd[j].gd.pos.width = 50;
1463 	gcd[j].gd.flags = gcd[j-1].gd.flags;
1464 	gcd[j].gd.cid = CID_MatchPt;
1465 	gcd[j].gd.handle_controlevent = AI_MatchChanged;
1466 	gcd[j].creator = GTextFieldCreate;
1467 	harray2[1] = &gcd[j]; harray2[2] = NULL;
1468 	++j;
1469 
1470 	boxes[3].gd.flags = gg_enabled|gg_visible;
1471 	boxes[3].gd.u.boxelements = harray2;
1472 	boxes[3].creator = GHBoxCreate;
1473 	varray[4] = &boxes[3]; varray[5] = NULL;
1474 
1475 	label[j].text = (unichar_t *) _("Mark");
1476 	label[j].text_is_1byte = true;
1477 	gcd[j].gd.label = &label[j];
1478 	gcd[j].gd.pos.x = 5; gcd[j].gd.pos.y = gcd[j-1].gd.pos.y+28;
1479 	gcd[j].gd.flags = gg_enabled|gg_visible;
1480 	gcd[j].gd.cid = CID_Mark;
1481 	gcd[j].gd.handle_controlevent = AI_TypeChanged;
1482 	gcd[j].creator = GRadioCreate;
1483 	hvarray[0] = &gcd[j];
1484 	++j;
1485 
1486 	label[j].text = (unichar_t *) _("Base Glyph");
1487 	label[j].text_is_1byte = true;
1488 	gcd[j].gd.label = &label[j];
1489 	gcd[j].gd.pos.x = 70; gcd[j].gd.pos.y = gcd[j-1].gd.pos.y;
1490 	gcd[j].gd.flags = gg_enabled|gg_visible;
1491 	gcd[j].gd.cid = CID_BaseChar;
1492 	gcd[j].gd.handle_controlevent = AI_TypeChanged;
1493 	gcd[j].creator = GRadioCreate;
1494 	hvarray[1] = &gcd[j]; hvarray[2] = NULL;
1495 	++j;
1496 
1497 	label[j].text = (unichar_t *) _("Base Lig");
1498 	label[j].text_is_1byte = true;
1499 	gcd[j].gd.label = &label[j];
1500 	gcd[j].gd.pos.x = gcd[j-2].gd.pos.x; gcd[j].gd.pos.y = gcd[j-1].gd.pos.y+14;
1501 	gcd[j].gd.flags = gg_enabled|gg_visible;
1502 	gcd[j].gd.cid = CID_BaseLig;
1503 	gcd[j].gd.handle_controlevent = AI_TypeChanged;
1504 	gcd[j].creator = GRadioCreate;
1505 	hvarray[3] = &gcd[j];
1506 	++j;
1507 
1508 	label[j].text = (unichar_t *) _("Base Mark");
1509 	label[j].text_is_1byte = true;
1510 	gcd[j].gd.label = &label[j];
1511 	gcd[j].gd.pos.x = gcd[j-2].gd.pos.x; gcd[j].gd.pos.y = gcd[j-1].gd.pos.y;
1512 	gcd[j].gd.flags = gg_enabled|gg_visible;
1513 	gcd[j].gd.cid = CID_BaseMark;
1514 	gcd[j].gd.handle_controlevent = AI_TypeChanged;
1515 	gcd[j].creator = GRadioCreate;
1516 	hvarray[4] = &gcd[j]; hvarray[5] = NULL;
1517 	++j;
1518 
1519 /* GT: Cursive Entry. This defines a point on the glyph that should be matched */
1520 /* GT: with the "Cursive Exit" point of the preceding glyph.  */
1521 /* GT: This is a special way of joining letters which was developed for Urdu */
1522 /* GT: fonts. Essentially every glyph has an entry point and an exit point. */
1523 /* GT: When written the glyphs in sequence are aligned so that the exit point */
1524 /* GT: of each glyph matches the entry point of the following. It means you */
1525 /* GT: get a join such as might be expected for script. Urdu is odd because */
1526 /* GT: letters within a word crawl diagonally up the page, but with each word */
1527 /* GT: the writing point starts at the baseline. */
1528 	label[j].text = (unichar_t *) _("CursEntry");
1529 	label[j].text_is_1byte = true;
1530 	gcd[j].gd.label = &label[j];
1531 	gcd[j].gd.pos.x = gcd[j-2].gd.pos.x; gcd[j].gd.pos.y = gcd[j-1].gd.pos.y+14;
1532 	gcd[j].gd.flags = gg_enabled|gg_visible;
1533 	gcd[j].gd.cid = CID_CursEntry;
1534 	gcd[j].gd.handle_controlevent = AI_TypeChanged;
1535 	gcd[j].creator = GRadioCreate;
1536 	hvarray[6] = &gcd[j];
1537 	++j;
1538 
1539 /* GT: Cursive Exit. This defines a point on the glyph that should be matched */
1540 /* GT: with the "Cursive Entry" point of the following glyph. This allows */
1541 /* GT: scripts such as Urdu to work */
1542 	label[j].text = (unichar_t *) _("CursExit");
1543 	label[j].text_is_1byte = true;
1544 	gcd[j].gd.label = &label[j];
1545 	gcd[j].gd.pos.x = gcd[j-2].gd.pos.x; gcd[j].gd.pos.y = gcd[j-1].gd.pos.y;
1546 	gcd[j].gd.flags = gg_enabled|gg_visible;
1547 	gcd[j].gd.cid = CID_CursExit;
1548 	gcd[j].gd.handle_controlevent = AI_TypeChanged;
1549 	gcd[j].creator = GRadioCreate;
1550 	hvarray[7] = &gcd[j]; hvarray[8] = NULL; hvarray[9] = NULL;
1551 	++j;
1552 
1553 	boxes[4].gd.flags = gg_enabled|gg_visible;
1554 	boxes[4].gd.u.boxelements = hvarray;
1555 	boxes[4].creator = GHVBoxCreate;
1556 	varray[6] = &boxes[4]; varray[7] = NULL;
1557 
1558 	label[j].text = (unichar_t *) _("Lig Index:");
1559 	label[j].text_is_1byte = true;
1560 	gcd[j].gd.label = &label[j];
1561 	gcd[j].gd.pos.x = 5; gcd[j].gd.pos.y = gcd[j-1].gd.pos.y+26;
1562 	gcd[j].gd.flags = gg_enabled|gg_visible;
1563 	gcd[j].creator = GLabelCreate;
1564 	harray3[0] = &gcd[j];
1565 	++j;
1566 
1567 	gcd[j].gd.pos.x = 65; gcd[j].gd.pos.y = gcd[j-1].gd.pos.y-4;
1568 	gcd[j].gd.pos.width = 50;
1569 	gcd[j].gd.flags = gg_enabled|gg_visible;
1570 	gcd[j].gd.cid = CID_LigIndex;
1571 	gcd[j].gd.handle_controlevent = AI_LigIndexChanged;
1572 	gcd[j].creator = GNumericFieldCreate;
1573 	harray3[1] = &gcd[j]; harray3[2] = NULL;
1574 	++j;
1575 
1576 	boxes[5].gd.flags = gg_enabled|gg_visible;
1577 	boxes[5].gd.u.boxelements = harray3;
1578 	boxes[5].creator = GHBoxCreate;
1579 	varray[8] = &boxes[5]; varray[9] = NULL;
1580 
1581 	label[j].text = (unichar_t *) S_("AnchorPoint|_New");
1582 	label[j].text_is_1byte = true;
1583 	label[j].text_in_resource = true;
1584 	gcd[j].gd.label = &label[j];
1585 	gcd[j].gd.pos.x = 5; gcd[j].gd.pos.y = gcd[j-1].gd.pos.y+30;
1586 	gcd[j].gd.pos.width = -1;
1587 	gcd[j].gd.flags = gg_enabled|gg_visible;
1588 	gcd[j].gd.cid = CID_New;
1589 	gcd[j].gd.handle_controlevent = AI_New;
1590 	gcd[j].creator = GButtonCreate;
1591 	harray4[0] = &gcd[j]; harray4[1] = GCD_Glue;
1592 	++j;
1593 
1594 	label[j].text = (unichar_t *) S_("AnchorClass|New _Class");
1595 	label[j].text_is_1byte = true;
1596 	label[j].text_in_resource = true;
1597 	gcd[j].gd.label = &label[j];
1598 	gcd[j].gd.pos.x = 30; gcd[j].gd.pos.y = gcd[j-1].gd.pos.y;
1599 	gcd[j].gd.pos.width = -1;
1600 	gcd[j].gd.flags = gg_enabled|gg_visible;
1601 	gcd[j].gd.cid = CID_New;
1602 	gcd[j].gd.handle_controlevent = AI_NewClass;
1603 	gcd[j].creator = GButtonCreate;
1604 	harray4[2] = &gcd[j]; harray4[3] = GCD_Glue;
1605 	++j;
1606 
1607 	label[j].text = (unichar_t *) _("_Delete");
1608 	label[j].text_is_1byte = true;
1609 	label[j].text_in_resource = true;
1610 	gcd[j].gd.label = &label[j];
1611 	gcd[j].gd.pos.x = -5; gcd[j].gd.pos.y = gcd[j-1].gd.pos.y;
1612 	gcd[j].gd.pos.width = -1;
1613 	gcd[j].gd.flags = gg_enabled|gg_visible;
1614 	gcd[j].gd.cid = CID_Delete;
1615 	gcd[j].gd.handle_controlevent = AI_Delete;
1616 	gcd[j].creator = GButtonCreate;
1617 	harray4[4] = &gcd[j]; harray4[5] = NULL;
1618 	++j;
1619 
1620 	boxes[6].gd.flags = gg_enabled|gg_visible;
1621 	boxes[6].gd.u.boxelements = harray4;
1622 	boxes[6].creator = GHBoxCreate;
1623 	varray[10] = &boxes[6]; varray[11] = NULL;
1624 
1625 	label[j].text = (unichar_t *) _("< _Prev");
1626 	label[j].text_is_1byte = true;
1627 	label[j].text_in_resource = true;
1628 	gcd[j].gd.label = &label[j];
1629 	gcd[j].gd.pos.x = 15; gcd[j].gd.pos.y = gcd[j-1].gd.pos.y+28;
1630 	gcd[j].gd.pos.width = -1;
1631 	gcd[j].gd.flags = gg_enabled|gg_visible;
1632 	gcd[j].gd.cid = CID_Prev;
1633 	gcd[j].gd.handle_controlevent = AI_Prev;
1634 	gcd[j].creator = GButtonCreate;
1635 	harray5[0] = GCD_Glue; harray5[1] = &gcd[j]; harray5[2] = GCD_Glue;
1636 	++j;
1637 
1638 	label[j].text = (unichar_t *) _("_Next >");
1639 	label[j].text_is_1byte = true;
1640 	label[j].text_in_resource = true;
1641 	gcd[j].gd.label = &label[j];
1642 	gcd[j].gd.pos.x = -15; gcd[j].gd.pos.y = gcd[j-1].gd.pos.y;
1643 	gcd[j].gd.pos.width = -1;
1644 	gcd[j].gd.flags = gg_enabled|gg_visible;
1645 	gcd[j].gd.cid = CID_Next;
1646 	gcd[j].gd.handle_controlevent = AI_Next;
1647 	gcd[j].creator = GButtonCreate;
1648 	harray5[3] = &gcd[j]; harray5[4] = GCD_Glue; harray5[5] = NULL;
1649 	++j;
1650 
1651 	boxes[7].gd.flags = gg_enabled|gg_visible;
1652 	boxes[7].gd.u.boxelements = harray5;
1653 	boxes[7].creator = GHBoxCreate;
1654 	varray[12] = &boxes[7]; varray[13] = NULL;
1655 
1656 	gcd[j].gd.pos.x = 5; gcd[j].gd.pos.y = gcd[j-1].gd.pos.y+26;
1657 	gcd[j].gd.pos.width = AI_Width-10;
1658 	gcd[j].gd.flags = gg_enabled|gg_visible;
1659 	gcd[j].creator = GLineCreate;
1660 	varray[14] = GCD_Glue; varray[15] = NULL;
1661 	varray[16] = &gcd[j]; varray[17] = NULL;
1662 	++j;
1663 
1664 	label[j].text = (unichar_t *) _("_OK");
1665 	label[j].text_is_1byte = true;
1666 	label[j].text_in_resource = true;
1667 	gcd[j].gd.label = &label[j];
1668 	gcd[j].gd.pos.x = 5; gcd[j].gd.pos.y = gcd[j-1].gd.pos.y+4;
1669 	gcd[j].gd.pos.width = -1;
1670 	gcd[j].gd.flags = gg_enabled|gg_visible|gg_but_default;
1671 	gcd[j].gd.handle_controlevent = AI_Ok;
1672 	gcd[j].creator = GButtonCreate;
1673 	harray6[0] = &gcd[j]; harray6[1] = GCD_Glue;
1674 	++j;
1675 
1676 	label[j].text = (unichar_t *) _("_Cancel");
1677 	label[j].text_is_1byte = true;
1678 	label[j].text_in_resource = true;
1679 	gcd[j].gd.label = &label[j];
1680 	gcd[j].gd.pos.x = -5; gcd[j].gd.pos.y = gcd[j-1].gd.pos.y+3;
1681 	gcd[j].gd.pos.width = -1;
1682 	gcd[j].gd.flags = gg_enabled|gg_visible|gg_but_cancel;
1683 	gcd[j].gd.handle_controlevent = AI_Cancel;
1684 	gcd[j].creator = GButtonCreate;
1685 	harray6[2] = &gcd[j]; harray6[3] = NULL;
1686 	++j;
1687 
1688 	boxes[8].gd.flags = gg_enabled|gg_visible;
1689 	boxes[8].gd.u.boxelements = harray6;
1690 	boxes[8].creator = GHBoxCreate;
1691 	varray[18] = &boxes[8]; varray[19] = NULL;
1692 	varray[20] = NULL;
1693 
1694 	boxes[0].gd.pos.x = boxes[0].gd.pos.y = 2;
1695 	boxes[0].gd.flags = gg_enabled|gg_visible;
1696 	boxes[0].gd.u.boxelements = varray;
1697 	boxes[0].creator = GHVGroupCreate;
1698 
1699 	GGadgetsCreate(gi.gw,boxes);
1700 	GHVBoxSetExpandableRow(boxes[0].ret,gb_expandglue);
1701 	GHVBoxSetExpandableCol(boxes[8].ret,gb_expandgluesame);
1702 	GHVBoxSetExpandableCol(boxes[7].ret,gb_expandgluesame);
1703 	GHVBoxSetExpandableCol(boxes[6].ret,gb_expandgluesame);
1704 	GHVBoxFitWindow(boxes[0].ret);
1705 
1706 	GGadgetSetList(GWidgetGetControl(gi.gw,CID_NameList),
1707 		    ti = AnchorClassesLList(gi.sc->parent),false);
1708 	for ( j=0; ti[j]->text!=NULL && ti[j]->userdata!=ap->anchor; ++j )
1709 	GGadgetSelectOneListItem(GWidgetGetControl(gi.gw,CID_NameList),j);
1710 
1711 	AI_Display(&gi,ap);
1712 	GWidgetIndicateFocusGadget(GWidgetGetControl(gi.gw,CID_X));
1713 
1714     GWidgetHidePalettes();
1715     GDrawSetVisible(gi.gw,true);
1716     while ( !gi.done )
1717 	GDrawProcessOneEvent(NULL);
1718     GDrawDestroyWindow(gi.gw);
1719     AnchorPointsFree(gi.oldaps);
1720 }
1721 
PI_ShowHints(SplineChar * sc,GGadget * list,int set)1722 void PI_ShowHints(SplineChar *sc, GGadget *list, int set) {
1723     StemInfo *h;
1724     int32 i, len;
1725 
1726     if ( !set ) {
1727 	for ( h = sc->hstem; h!=NULL; h=h->next )
1728 	    h->active = false;
1729 	for ( h = sc->vstem; h!=NULL; h=h->next )
1730 	    h->active = false;
1731     } else {
1732 	GTextInfo **ti = GGadgetGetList(list,&len);
1733 	for ( h = sc->hstem, i=0; h!=NULL && i<len; h=h->next, ++i )
1734 	    h->active = ti[i]->selected;
1735 	for ( h = sc->vstem; h!=NULL && i<len; h=h->next, ++i )
1736 	    h->active = ti[i]->selected;
1737     }
1738     SCOutOfDateBackground(sc);
1739     SCUpdateAll(sc);
1740 }
1741 
_PI_ShowHints(GIData * ci,int set)1742 static void _PI_ShowHints(GIData *ci,int set) {
1743     PI_ShowHints(ci->cv->b.sc,GWidgetGetControl(ci->gw,CID_HintMask),set);
1744 }
1745 
PI_DoCancel(GIData * ci)1746 static void PI_DoCancel(GIData *ci) {
1747     CharView *cv = ci->cv;
1748     ci->done = true;
1749     if ( cv->b.drawmode==dm_fore )
1750 	MDReplace(cv->b.sc->md,cv->b.sc->layers[ly_fore].splines,ci->oldstate);
1751     SplinePointListsFree(cv->b.layerheads[cv->b.drawmode]->splines);
1752     cv->b.layerheads[cv->b.drawmode]->splines = ci->oldstate;
1753     CVRemoveTopUndo(&cv->b);
1754     SCClearSelPt(cv->b.sc);
1755     _PI_ShowHints(ci,false);
1756     SCUpdateAll(cv->b.sc);
1757 }
1758 
1759 static void PIFillup(GIData *ci, int except_cid);
1760 
PI_FigureNext(GIData * ci)1761 static void PI_FigureNext(GIData *ci) {
1762     if ( ci->prevchanged ) {
1763 	SplinePoint *cursp = ci->cursp;
1764 	if ( !ci->cv->b.layerheads[ci->cv->b.drawmode]->order2 && (cursp->pointtype==pt_curve || cursp->pointtype==pt_hvcurve)) {
1765 	    double dx, dy, len, len2;
1766 	    dx = cursp->prevcp.x - cursp->me.x;
1767 	    dy = cursp->prevcp.y - cursp->me.y;
1768 	    len = sqrt(dx*dx+dy*dy);
1769 	    if ( len!=0 ) {
1770 		len2 = sqrt((cursp->nextcp.x-cursp->me.x)*(cursp->nextcp.x-cursp->me.x)+
1771 			(cursp->nextcp.y-cursp->me.y)*(cursp->nextcp.y-cursp->me.y));
1772 		cursp->nextcp.x=cursp->me.x-dx*len2/len;
1773 		cursp->nextcp.y=cursp->me.y-dy*len2/len;
1774 		if ( cursp->next!=NULL )
1775 		    SplineRefigure(cursp->next);
1776 		CVCharChangedUpdate(&ci->cv->b);
1777 		PIFillup(ci,-1);
1778 	    }
1779 	}
1780     }
1781     ci->prevchanged = false;
1782 }
1783 
PI_FigurePrev(GIData * ci)1784 static void PI_FigurePrev(GIData *ci) {
1785     if ( ci->nextchanged ) {
1786 	SplinePoint *cursp = ci->cursp;
1787 	if ( !ci->cv->b.layerheads[ci->cv->b.drawmode]->order2 && (cursp->pointtype==pt_curve || cursp->pointtype==pt_hvcurve)) {
1788 	    double dx, dy, len, len2;
1789 	    dx = cursp->nextcp.x - cursp->me.x;
1790 	    dy = cursp->nextcp.y - cursp->me.y;
1791 	    len = sqrt(dx*dx+dy*dy);
1792 	    if ( len!=0 ) {
1793 		len2 = sqrt((cursp->prevcp.x-cursp->me.x)*(cursp->prevcp.x-cursp->me.x)+
1794 			(cursp->prevcp.y-cursp->me.y)*(cursp->prevcp.y-cursp->me.y));
1795 		cursp->prevcp.x=cursp->me.x-dx*len2/len;
1796 		cursp->prevcp.y=cursp->me.y-dy*len2/len;
1797 		if ( cursp->prev!=NULL )
1798 		    SplineRefigure(cursp->prev);
1799 		CVCharChangedUpdate(&ci->cv->b);
1800 		PIFillup(ci,-1);
1801 	    }
1802 	}
1803     }
1804     ci->nextchanged = false;
1805 }
1806 
PI_FigureHintMask(GIData * ci)1807 static void PI_FigureHintMask(GIData *ci) {
1808     int32 i, len;
1809     GTextInfo **ti = GGadgetGetList(GWidgetGetControl(ci->gw,CID_HintMask),&len);
1810 
1811     for ( i=0; i<len; ++i )
1812 	if ( ti[i]->selected )
1813     break;
1814 
1815     if ( i==len ) {
1816 	chunkfree(ci->cursp->hintmask,sizeof(HintMask));
1817 	ci->cursp->hintmask = NULL;
1818     } else {
1819 	if ( ci->cursp->hintmask==NULL )
1820 	    ci->cursp->hintmask = chunkalloc(sizeof(HintMask));
1821 	else
1822 	    memset(ci->cursp->hintmask,0,sizeof(HintMask));
1823 	for ( i=0; i<len; ++i )
1824 	    if ( ti[i]->selected )
1825 		(*ci->cursp->hintmask)[i>>3] |= (0x80>>(i&7));
1826     }
1827 }
1828 
PI_FixStuff(GIData * ci)1829 static void PI_FixStuff(GIData *ci) {
1830     SplinePoint *sp = ci->cursp;
1831 
1832     PI_FigureHintMask(ci);
1833     PI_FigureNext(ci);
1834     PI_FigurePrev(ci);
1835 
1836     if ( sp->pointtype == pt_hvcurve ) {
1837 	if (
1838 		((sp->nextcp.x==sp->me.x && sp->prevcp.x==sp->me.x && sp->nextcp.y!=sp->me.y) ||
1839 		 (sp->nextcp.y==sp->me.y && sp->prevcp.y==sp->me.y && sp->nextcp.x!=sp->me.x)))
1840 	    /* Do Nothing */;
1841 	else
1842 	    sp->pointtype = pt_curve;
1843     } else if ( sp->pointtype == pt_tangent )
1844 	SplinePointCategorize(sp);	/* Users can change cps so it isn't a tangent, so check */
1845 }
1846 
PI_Destroy(struct dlistnode * node)1847 void PI_Destroy(struct dlistnode *node) {
1848     GIData *d = (GIData *)node;
1849     GDrawDestroyWindow(d->gw);
1850     dlist_erase(&d->cv->pointInfoDialogs,(struct dlistnode *)d);
1851     free(d);
1852 }
1853 
PI_Close(GIData * d)1854 static void PI_Close(GIData *d) {
1855     PI_Destroy((struct dlistnode *)d);
1856 }
1857 
PI_Cancel(GGadget * g,GEvent * e)1858 static int PI_Cancel(GGadget *g, GEvent *e) {
1859     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
1860 	GIData *d = GDrawGetUserData(GGadgetGetWindow(g));
1861 	PI_DoCancel(d);
1862 	PI_Close(d);
1863     }
1864 return( true );
1865 }
1866 
PI_DoOk(GIData * ci)1867 static void PI_DoOk(GIData *ci) {
1868 	PI_FixStuff(ci);
1869 	_PI_ShowHints(ci,false);
1870 
1871 	ci->done = true;
1872 	/* All the work has been done as we've gone along */
1873 	PI_Close(ci);
1874 }
1875 
PI_Ok(GGadget * g,GEvent * e)1876 static int PI_Ok(GGadget *g, GEvent *e) {
1877     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
1878 	GIData *ci = GDrawGetUserData(GGadgetGetWindow(g));
1879 	PI_DoOk(ci);
1880     }
1881     return( true );
1882 }
1883 
pi_e_h(GWindow gw,GEvent * event)1884 static int pi_e_h(GWindow gw, GEvent *event) {
1885     if ( event->type==et_close ) {
1886 	PI_DoOk(GDrawGetUserData(gw));
1887     } else if ( event->type==et_char ) {
1888 	if ( event->u.chr.keysym == GK_F1 || event->u.chr.keysym == GK_Help ) {
1889 	    help("ui/dialogs/getinfo.html", NULL);
1890 return( true );
1891 	}
1892 return( false );
1893     } else if ( event->type == et_map ) {
1894 	/* Above palettes */
1895 	GDrawRaise(gw);
1896     }
1897 return( true );
1898 }
1899 
mysprintf(char * buffer,char * format,real v)1900 static void mysprintf( char *buffer, char *format, real v) {
1901     char *pt;
1902 
1903     if ( v<.0001 && v>-.0001 && v!=0 )
1904 	sprintf( buffer, "%e", (double) v );
1905     else if ( v<1 && v>0 )
1906 	sprintf( buffer, "%f", (double) v );
1907     else if ( v<0 && v>-1 )
1908 	sprintf( buffer, "%.5f", (double) v );
1909     else
1910 	sprintf( buffer, format, (double) v );
1911     pt = buffer + strlen(buffer);
1912     while ( pt>buffer && pt[-1]=='0' )
1913 	*--pt = '\0';
1914     if ( pt>buffer && pt[-1]=='.' )
1915 	pt[-1] = '\0';
1916 }
1917 
mysprintf2(char * buffer,real v1,real v2)1918 static void mysprintf2( char *buffer, real v1, real v2) {
1919     char *pt;
1920 
1921     mysprintf(buffer,"%.2f", v1);
1922     pt = buffer+strlen(buffer);
1923     *pt++ = ',';
1924     mysprintf(pt,"%.2f", v2);
1925 }
1926 
PIFillup(GIData * ci,int except_cid)1927 static void PIFillup(GIData *ci, int except_cid) {
1928     char buffer[51];
1929     double dx, dy;
1930     double kappa, kappa2;
1931     int emsize;
1932 
1933     mysprintf(buffer, "%.2f", ci->cursp->me.x );
1934     if ( except_cid!=CID_BaseX )
1935 	GGadgetSetTitle8(GWidgetGetControl(ci->gw,CID_BaseX),buffer);
1936 
1937     mysprintf(buffer, "%.2f", ci->cursp->me.y );
1938     if ( except_cid!=CID_BaseY )
1939 	GGadgetSetTitle8(GWidgetGetControl(ci->gw,CID_BaseY),buffer);
1940 
1941     dx = ci->cursp->nextcp.x-ci->cursp->me.x;
1942     dy = ci->cursp->nextcp.y-ci->cursp->me.y;
1943     mysprintf(buffer, "%.2f", dx );
1944     if ( except_cid!=CID_NextXOff )
1945 	GGadgetSetTitle8(GWidgetGetControl(ci->gw,CID_NextXOff),buffer);
1946 
1947     mysprintf(buffer, "%.2f", dy );
1948     if ( except_cid!=CID_NextYOff )
1949 	GGadgetSetTitle8(GWidgetGetControl(ci->gw,CID_NextYOff),buffer);
1950 
1951     if ( except_cid!=CID_NextR ) {
1952 	mysprintf(buffer, "%.2f", sqrt( dx*dx+dy*dy ));
1953 	GGadgetSetTitle8(GWidgetGetControl(ci->gw,CID_NextR),buffer);
1954     }
1955 
1956     if ( except_cid!=CID_NextTheta ) {
1957 	if ( ci->cursp->pointtype==pt_tangent && ci->cursp->prev!=NULL ) {
1958 	    dx = ci->cursp->me.x-ci->cursp->prev->from->me.x;
1959 	    dy = ci->cursp->me.y-ci->cursp->prev->from->me.y;
1960 	}
1961 	mysprintf(buffer, "%.1f", atan2(dy,dx)*RAD2DEG);
1962 	GGadgetSetTitle8(GWidgetGetControl(ci->gw,CID_NextTheta),buffer);
1963     }
1964 
1965     mysprintf2(buffer, ci->cursp->nextcp.x,ci->cursp->nextcp.y );
1966     GGadgetSetTitle8(GWidgetGetControl(ci->gw,CID_NextPos),buffer);
1967 
1968     GGadgetSetChecked(GWidgetGetControl(ci->gw,CID_NextDef), ci->cursp->nextcpdef );
1969 
1970     dx = ci->cursp->prevcp.x-ci->cursp->me.x;
1971     dy = ci->cursp->prevcp.y-ci->cursp->me.y;
1972     mysprintf(buffer, "%.2f", dx );
1973     if ( except_cid!=CID_PrevXOff )
1974 	GGadgetSetTitle8(GWidgetGetControl(ci->gw,CID_PrevXOff),buffer);
1975 
1976     mysprintf(buffer, "%.2f", dy );
1977     if ( except_cid!=CID_PrevYOff )
1978 	GGadgetSetTitle8(GWidgetGetControl(ci->gw,CID_PrevYOff),buffer);
1979 
1980     if ( except_cid!=CID_PrevR ) {
1981 	mysprintf(buffer, "%.2f", sqrt( dx*dx+dy*dy ));
1982 	GGadgetSetTitle8(GWidgetGetControl(ci->gw,CID_PrevR),buffer);
1983     }
1984 
1985     if ( except_cid!=CID_PrevTheta ) {
1986 	if ( ci->cursp->pointtype==pt_tangent && ci->cursp->next!=NULL ) {
1987 	    dx = ci->cursp->me.x-ci->cursp->next->to->me.x;
1988 	    dy = ci->cursp->me.y-ci->cursp->next->to->me.y;
1989 	}
1990 	mysprintf(buffer, "%.1f", atan2(dy,dx)*RAD2DEG);
1991 	GGadgetSetTitle8(GWidgetGetControl(ci->gw,CID_PrevTheta),buffer);
1992     }
1993 
1994     mysprintf2(buffer, ci->cursp->prevcp.x,ci->cursp->prevcp.y );
1995     GGadgetSetTitle8(GWidgetGetControl(ci->gw,CID_PrevPos),buffer);
1996 
1997 
1998     mysprintf2(buffer, ci->cursp->me.x,ci->cursp->me.y );
1999     GGadgetSetTitle8(GWidgetGetControl(ci->gw,CID_BasePos),buffer);
2000 
2001     mysprintf(buffer, "%.2f", ci->cursp->nextcp.x );
2002     if ( except_cid!=CID_NextX )
2003 	GGadgetSetTitle8(GWidgetGetControl(ci->gw,CID_NextX),buffer);
2004 
2005     mysprintf(buffer, "%.2f", ci->cursp->nextcp.y );
2006     if ( except_cid!=CID_NextY )
2007 	GGadgetSetTitle8(GWidgetGetControl(ci->gw,CID_NextY),buffer);
2008 
2009     mysprintf(buffer, "%.2f", ci->cursp->prevcp.x );
2010     if ( except_cid!=CID_PrevX )
2011 	GGadgetSetTitle8(GWidgetGetControl(ci->gw,CID_PrevX),buffer);
2012 
2013     mysprintf(buffer, "%.2f", ci->cursp->prevcp.y );
2014     if ( except_cid!=CID_PrevY )
2015 	GGadgetSetTitle8(GWidgetGetControl(ci->gw,CID_PrevY),buffer);
2016 
2017 
2018     GGadgetSetChecked(GWidgetGetControl(ci->gw,CID_PrevDef), ci->cursp->prevcpdef );
2019 
2020     GGadgetSetChecked(GWidgetGetControl(ci->gw,CID_Curve), ci->cursp->pointtype==pt_curve );
2021     GGadgetSetChecked(GWidgetGetControl(ci->gw,CID_HVCurve), ci->cursp->pointtype==pt_hvcurve );
2022     GGadgetSetChecked(GWidgetGetControl(ci->gw,CID_Corner), ci->cursp->pointtype==pt_corner );
2023     GGadgetSetChecked(GWidgetGetControl(ci->gw,CID_Tangent), ci->cursp->pointtype==pt_tangent );
2024 
2025     GGadgetSetEnabled(GWidgetGetControl(ci->gw,CID_PrevTheta), ci->cursp->pointtype!=pt_tangent );
2026     GGadgetSetEnabled(GWidgetGetControl(ci->gw,CID_NextTheta), ci->cursp->pointtype!=pt_tangent );
2027 
2028     kappa = SplineCurvature(ci->cursp->next,0);
2029     kappa2 = SplineCurvature(ci->cursp->prev,1);
2030     GGadgetSetEnabled(GWidgetGetControl(ci->gw,CID_PrevCurvature), kappa2!=CURVATURE_ERROR );
2031     GGadgetSetEnabled(GWidgetGetControl(ci->gw,CID_NextCurvature), kappa!=CURVATURE_ERROR );
2032     GGadgetSetEnabled(GWidgetGetControl(ci->gw,CID_DeltaCurvature),
2033 	    kappa!=CURVATURE_ERROR && kappa2!=CURVATURE_ERROR );
2034     emsize = ci->cv->b.sc->parent->ascent + ci->cv->b.sc->parent->descent;
2035     /* If we normalize by the em-size, the curvature is often more */
2036     /*  readable */
2037     if ( kappa!=CURVATURE_ERROR )
2038 	sprintf( buffer, _("Curvature: %g"), kappa*emsize );
2039     else
2040 	strcpy( buffer, _("Curvature: ?"));
2041     GGadgetSetTitle8(GWidgetGetControl(ci->gw,CID_NextCurvature),buffer);
2042     if ( kappa2!=CURVATURE_ERROR )
2043 	sprintf( buffer, _("Curvature: %g"), kappa2*emsize );
2044     else
2045 	strncpy( buffer, _("Curvature: ?"),sizeof(buffer)-1 );
2046     GGadgetSetTitle8(GWidgetGetControl(ci->gw,CID_PrevCurvature),buffer);
2047     if ( kappa!=CURVATURE_ERROR && kappa2!=CURVATURE_ERROR )
2048 	sprintf( buffer, "∆: %g", (kappa-kappa2)*emsize );
2049     else
2050 	strcpy( buffer, "∆: ?");
2051     GGadgetSetTitle8(GWidgetGetControl(ci->gw,CID_DeltaCurvature),buffer);
2052 }
2053 
PIShowHide(GIData * ci)2054 static void PIShowHide(GIData *ci) {
2055     int normal = GGadgetIsChecked(GWidgetGetControl(ci->gw,CID_Normal));
2056     int i;
2057 
2058     for ( i=ci->normal_start; i<ci->normal_end; ++i )
2059 	if ( ci->gcd[i].ret!=NULL )
2060 	    GGadgetSetVisible(ci->gcd[i].ret,normal);
2061     GGadgetSetVisible(ci->group1ret,normal);
2062     GGadgetSetVisible(ci->group2ret,normal);
2063     for ( i=ci->interp_start; i<ci->interp_end; ++i )
2064 	if ( ci->gcd[i].ret!=NULL )
2065 	    GGadgetSetVisible(ci->gcd[i].ret,!normal);
2066     GWidgetFlowGadgets(GGadgetGetWindow(GWidgetGetControl(ci->gw,CID_Normal)));
2067 }
2068 
PIChangePoint(GIData * ci)2069 void PIChangePoint(GIData *ci) {
2070     int aspect = GTabSetGetSel(GWidgetGetControl(ci->gw,CID_TabSet));
2071     GGadget *list = GWidgetGetControl(ci->gw,CID_HintMask);
2072     int32 i, len;
2073     HintMask *hm;
2074     SplinePoint *sp;
2075     SplineSet *spl;
2076     int interpolate;
2077 
2078     GGadgetGetList(list,&len);
2079 
2080     PIFillup(ci,0);
2081 
2082     GGadgetSetEnabled(GWidgetGetControl(ci->gw,CID_Interpolated),
2083 	    !ci->cursp->dontinterpolate && !(ci->cursp->nonextcp && ci->cursp->noprevcp) );
2084     interpolate = SPInterpolate(ci->cursp) && ci->cv->b.layerheads[ci->cv->b.drawmode]->order2;
2085     GGadgetSetChecked(GWidgetGetControl(ci->gw,CID_Normal), !interpolate );
2086     GGadgetSetChecked(GWidgetGetControl(ci->gw,CID_Interpolated), interpolate );
2087     GGadgetSetChecked(GWidgetGetControl(ci->gw,CID_NeverInterpolate), ci->cursp->dontinterpolate );
2088     PIShowHide(ci);
2089 
2090     if ( ci->cursp->hintmask==NULL ) {
2091 	for ( i=0; i<len; ++i )
2092 	    GGadgetSelectListItem(list,i,false);
2093     } else {
2094 	for ( i=0; i<len && i<HntMax; ++i )
2095 	    GGadgetSelectListItem(list,i, (*ci->cursp->hintmask)[i>>3]&(0x80>>(i&7))?true:false );
2096     }
2097     _PI_ShowHints(ci,aspect==1);
2098 
2099     list = GWidgetGetControl(ci->gw,CID_ActiveHints);
2100     hm = NULL;
2101     /* Figure out what hintmask is active at the current point */
2102     /* Note: we must walk each ss backwards because we reverse the splineset */
2103     /*  when we output postscript */
2104     for ( spl = ci->sc->layers[ly_fore].splines; spl!=NULL; spl=spl->next ) {
2105 	for ( sp=spl->first; ; ) {
2106 	    if ( sp->hintmask )
2107 		hm = sp->hintmask;
2108 	    if ( sp==ci->cursp )
2109 	break;
2110 	    if ( sp->prev==NULL )
2111 	break;
2112 	    sp = sp->prev->from;
2113 	    if ( sp==spl->first )
2114 	break;
2115 	}
2116 	if ( sp==ci->cursp )
2117     break;
2118     }
2119     if ( hm==NULL ) {
2120 	for ( i=0; i<len; ++i )
2121 	    GGadgetSelectListItem(list,i,false);
2122     } else {
2123 	for ( i=0; i<len && i<HntMax; ++i )
2124 	    GGadgetSelectListItem(list,i, (*hm)[i>>3]&(0x80>>(i&7))?true:false );
2125     }
2126     GGadgetSetEnabled(GWidgetGetControl(ci->gw,CID_NextDef),ci->cursp->next!=NULL);
2127     GGadgetSetEnabled(GWidgetGetControl(ci->gw,CID_PrevDef),ci->cursp->prev!=NULL);
2128 }
2129 
PI_NextPrev(GGadget * g,GEvent * e)2130 static int PI_NextPrev(GGadget *g, GEvent *e) {
2131     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
2132 	GIData *ci = GDrawGetUserData(GGadgetGetWindow(g));
2133 	CharView *cv = ci->cv;
2134 	int cid = GGadgetGetCid(g);
2135 	SplinePointList *spl;
2136 
2137 	PI_FixStuff(ci);
2138 
2139 	ci->cursp->selected = false;
2140 	if ( cid == CID_Next ) {
2141 	    if ( ci->cursp->next!=NULL && ci->cursp->next->to!=ci->curspl->first )
2142 		ci->cursp = ci->cursp->next->to;
2143 	    else {
2144 		if ( ci->curspl->next == NULL ) {
2145 		    ci->curspl = cv->b.layerheads[cv->b.drawmode]->splines;
2146 		    GDrawBeep(NULL);
2147 		} else
2148 		    ci->curspl = ci->curspl->next;
2149 		ci->cursp = ci->curspl->first;
2150 	    }
2151 	} else if ( cid == CID_Prev ) {
2152 	    if ( ci->cursp!=ci->curspl->first ) {
2153 		ci->cursp = ci->cursp->prev->from;
2154 	    } else {
2155 		if ( ci->curspl==cv->b.layerheads[cv->b.drawmode]->splines ) {
2156 		    for ( spl = cv->b.layerheads[cv->b.drawmode]->splines; spl->next!=NULL; spl=spl->next );
2157 		    GDrawBeep(NULL);
2158 		} else {
2159 		    for ( spl = cv->b.layerheads[cv->b.drawmode]->splines; spl->next!=ci->curspl; spl=spl->next );
2160 		}
2161 		ci->curspl = spl;
2162 		ci->cursp = spl->last;
2163 		if ( spl->last==spl->first && spl->last->prev!=NULL )
2164 		    ci->cursp = ci->cursp->prev->from;
2165 	    }
2166 	} else if ( cid==CID_NextC ) {
2167 	    if ( ci->cursp->next!=NULL )
2168 		ci->cursp = ci->cursp->next->to;
2169 	    else {
2170 		ci->cursp = ci->curspl->first;
2171 		GDrawBeep(NULL);
2172 	    }
2173 	} else /* CID_PrevC */ {
2174 	    if ( ci->cursp->prev!=NULL )
2175 		ci->cursp = ci->cursp->prev->from;
2176 	    else {
2177 		ci->cursp = ci->curspl->last;
2178 		GDrawBeep(NULL);
2179 	    }
2180 	}
2181 	ci->cursp->selected = true;
2182 	PIChangePoint(ci);
2183 	CVShowPoint(cv,&ci->cursp->me);
2184 	SCUpdateAll(cv->b.sc);
2185     }
2186 return( true );
2187 }
2188 
PI_InterpChanged(GGadget * g,GEvent * e)2189 static int PI_InterpChanged(GGadget *g, GEvent *e) {
2190     if ( e->type==et_controlevent && e->u.control.subtype == et_radiochanged ) {
2191 	GIData *ci = GDrawGetUserData(GGadgetGetWindow(g));
2192 	SplinePoint *cursp = ci->cursp;
2193 
2194 	if ( GGadgetGetCid(g)==CID_Interpolated ) {
2195 	    if ( cursp->nonextcp && cursp->noprevcp )
2196 		/* Do Nothing */;
2197 	    else {
2198 		if ( cursp->nonextcp && cursp->next ) {
2199 		    SplinePoint *n = cursp->next->to;
2200 		    cursp->nextcp.x = rint((n->me.x+cursp->me.x)/2);
2201 		    cursp->nextcp.y = rint((n->me.y+cursp->me.y)/2);
2202 		    n->prevcp = cursp->nextcp;
2203 		    cursp->nonextcp = n->noprevcp = false;
2204 		}
2205 		if ( cursp->noprevcp && cursp->prev ) {
2206 		    SplinePoint *p = cursp->prev->from;
2207 		    cursp->prevcp.x = rint((p->me.x+cursp->me.x)/2);
2208 		    cursp->prevcp.y = rint((p->me.y+cursp->me.y)/2);
2209 		    p->nextcp = cursp->prevcp;
2210 		    cursp->noprevcp = p->nonextcp = false;
2211 		}
2212 		cursp->me.x = (cursp->nextcp.x + cursp->prevcp.x)/2;
2213 		cursp->me.y = (cursp->nextcp.y + cursp->prevcp.y)/2;
2214 		if ( cursp->pointtype==pt_tangent ) {
2215 		    cursp->pointtype = pt_curve;
2216 		    GGadgetSetChecked(GWidgetGetControl(ci->gw,CID_Curve),true);
2217 		}
2218 		if ( cursp->next!=NULL )
2219 		    SplineRefigure(cursp->next);
2220 		if ( cursp->prev!=NULL )
2221 		    SplineRefigure(cursp->prev);
2222 		SplineSetSpirosClear(ci->curspl);
2223 		CVCharChangedUpdate(&ci->cv->b);
2224 	    }
2225 	    PIFillup(ci,0);
2226 	}
2227 	PIShowHide(ci);
2228     }
2229 return( true );
2230 }
2231 
PI_NeverInterpChanged(GGadget * g,GEvent * e)2232 static int PI_NeverInterpChanged(GGadget *g, GEvent *e) {
2233     if ( e->type==et_controlevent && e->u.control.subtype == et_radiochanged ) {
2234 	GIData *ci = GDrawGetUserData(GGadgetGetWindow(g));
2235 	int never = GGadgetIsChecked(g);
2236 
2237 	GGadgetSetEnabled(GWidgetGetControl(ci->gw,CID_Interpolated),!never);
2238 
2239 	if ( never )
2240 	    GGadgetSetChecked(GWidgetGetControl(ci->gw,CID_Normal),true);
2241 	ci->cursp->dontinterpolate = never;
2242 	PIShowHide(ci);
2243     }
2244 return( true );
2245 }
2246 
PI_BaseChanged(GGadget * g,GEvent * e)2247 static int PI_BaseChanged(GGadget *g, GEvent *e) {
2248     if ( e->type==et_controlevent && e->u.control.subtype == et_textchanged ) {
2249 	GIData *ci = GDrawGetUserData(GGadgetGetWindow(g));
2250 	real dx=0, dy=0;
2251 	int err=false;
2252 	SplinePoint *cursp = ci->cursp;
2253 
2254 	if ( GGadgetGetCid(g)==CID_BaseX )
2255 	    dx = GetCalmReal8(ci->gw,CID_BaseX,_("Base X"),&err)-cursp->me.x;
2256 	else
2257 	    dy = GetCalmReal8(ci->gw,CID_BaseY,_("Base Y"),&err)-cursp->me.y;
2258 	if ( (dx==0 && dy==0) || err )
2259 return( true );
2260 	cursp->me.x += dx;
2261 	cursp->nextcp.x += dx;
2262 	cursp->prevcp.x += dx;
2263 	cursp->me.y += dy;
2264 	cursp->nextcp.y += dy;
2265 	cursp->prevcp.y += dy;
2266 	if ( ci->cv->b.layerheads[ci->cv->b.drawmode]->order2 ) {
2267 	    SplinePointNextCPChanged2(cursp);
2268 	    SplinePointPrevCPChanged2(cursp);
2269 	}
2270 	if ( cursp->next!=NULL )
2271 	    SplineRefigure(cursp->next);
2272 	if ( cursp->prev!=NULL )
2273 	    SplineRefigure(cursp->prev);
2274 	SplineSetSpirosClear(ci->curspl);
2275 	CVCharChangedUpdate(&ci->cv->b);
2276 	PIFillup(ci,GGadgetGetCid(g));
2277     } else if ( e->type==et_controlevent &&
2278 	    e->u.control.subtype == et_textfocuschanged &&
2279 	    e->u.control.u.tf_focus.gained_focus ) {
2280 	GIData *ci = GDrawGetUserData(GGadgetGetWindow(g));
2281 	PI_FigureNext(ci);
2282 	PI_FigurePrev(ci);
2283     }
2284 return( true );
2285 }
2286 
PI_NextChanged(GGadget * g,GEvent * e)2287 static int PI_NextChanged(GGadget *g, GEvent *e) {
2288     if ( e->type==et_controlevent && e->u.control.subtype == et_textchanged ) {
2289 	GIData *ci = GDrawGetUserData(GGadgetGetWindow(g));
2290 	real dx=0, dy=0;
2291 	int err=false;
2292 	SplinePoint *cursp = ci->cursp;
2293 
2294 	if ( GGadgetGetCid(g)==CID_NextXOff ) {
2295 	    dx = GetCalmReal8(ci->gw,CID_NextXOff,_("Next CP X"),&err)-(cursp->nextcp.x-cursp->me.x);
2296 	    if ( cursp->pointtype==pt_tangent && cursp->prev!=NULL ) {
2297 		if ( cursp->prev->from->me.x==cursp->me.x ) {
2298 		    dy = dx; dx = 0;	/* They should be constrained not to change in the x direction */
2299 		} else
2300 		    dy = dx*(cursp->prev->from->me.y-cursp->me.y)/(cursp->prev->from->me.x-cursp->me.x);
2301 	    }
2302 	} else if ( GGadgetGetCid(g)==CID_NextYOff ) {
2303 	    dy = GetCalmReal8(ci->gw,CID_NextYOff,_("Next CP Y"),&err)-(cursp->nextcp.y-cursp->me.y);
2304 	    if ( cursp->pointtype==pt_tangent && cursp->prev!=NULL ) {
2305 		if ( cursp->prev->from->me.y==cursp->me.y ) {
2306 		    dx = dy; dy = 0;	/* They should be constrained not to change in the y direction */
2307 		} else
2308 		    dx = dy*(cursp->prev->from->me.x-cursp->me.x)/(cursp->prev->from->me.y-cursp->me.y);
2309 	    }
2310 	} else {
2311 	    double len, theta;
2312 	    len = GetCalmReal8(ci->gw,CID_NextR,_("Next CP Dist"),&err);
2313 	    theta = GetCalmReal8(ci->gw,CID_NextTheta,_("Next CP Angle"),&err)/RAD2DEG;
2314 	    dx = len*cos(theta) - (cursp->nextcp.x-cursp->me.x);
2315 	    dy = len*sin(theta) - (cursp->nextcp.y-cursp->me.y);
2316 	}
2317 	if ( (dx==0 && dy==0) || err )
2318 return( true );
2319 	if ( cursp->pointtype==pt_hvcurve ) {
2320 	    BasePoint diff;
2321 	    diff.x = cursp->nextcp.x+dx - cursp->me.x;
2322 	    diff.y = cursp->nextcp.y+dy - cursp->me.y;
2323 	    BP_HVForce(&diff);
2324 	    dx = diff.x + (cursp->me.x - cursp->nextcp.x);
2325 	    dy = diff.y + (cursp->me.y - cursp->nextcp.y);
2326 	}
2327 	cursp->nextcp.x += dx;
2328 	cursp->nextcp.y += dy;
2329 	cursp->nonextcp = false;
2330 	SplineSetSpirosClear(ci->curspl);
2331 	ci->nextchanged = true;
2332 	if (( dx>.1 || dx<-.1 || dy>.1 || dy<-.1 ) && cursp->nextcpdef ) {
2333 	    cursp->nextcpdef = false;
2334 	    GGadgetSetChecked(GWidgetGetControl(ci->gw,CID_NextDef), false );
2335 	}
2336 	if (( cursp->pointtype==pt_curve || cursp->pointtype==pt_hvcurve) && cursp->prev!=NULL ) {
2337 	    double plen, ntheta;
2338 	    double ndx, ndy;
2339 	    ndx = ci->cursp->nextcp.x-ci->cursp->me.x;
2340 	    ndy = ci->cursp->nextcp.y-ci->cursp->me.y;
2341 	    ntheta = atan2(ndy,ndx);
2342 	    plen = GetCalmReal8(ci->gw,CID_PrevR,_("Prev CP Dist"),&err);
2343 	    ci->cursp->prevcp.x = ci->cursp->me.x - plen*cos(ntheta);
2344 	    ci->cursp->prevcp.y = ci->cursp->me.y - plen*sin(ntheta);
2345 	    if ( ci->cv->b.layerheads[ci->cv->b.drawmode]->order2 )
2346 		SplinePointPrevCPChanged2(cursp);
2347 	    SplineRefigure(cursp->prev);
2348 	}
2349 	if ( ci->cv->b.layerheads[ci->cv->b.drawmode]->order2 )
2350 	    SplinePointNextCPChanged2(cursp);
2351 	if ( cursp->next!=NULL )
2352 	    SplineRefigure(cursp->next);
2353 	CVCharChangedUpdate(&ci->cv->b);
2354 	PIFillup(ci,GGadgetGetCid(g));
2355     } else if ( e->type==et_controlevent &&
2356 	    e->u.control.subtype == et_textfocuschanged &&
2357 	    e->u.control.u.tf_focus.gained_focus ) {
2358 	GIData *ci = GDrawGetUserData(GGadgetGetWindow(g));
2359 	PI_FigureNext(ci);
2360     }
2361 return( true );
2362 }
2363 
PI_PrevChanged(GGadget * g,GEvent * e)2364 static int PI_PrevChanged(GGadget *g, GEvent *e) {
2365     if ( e->type==et_controlevent && e->u.control.subtype == et_textchanged ) {
2366 	GIData *ci = GDrawGetUserData(GGadgetGetWindow(g));
2367 	real dx=0, dy=0;
2368 	int err=false;
2369 	SplinePoint *cursp = ci->cursp;
2370 
2371 	if ( GGadgetGetCid(g)==CID_PrevXOff ) {
2372 	    dx = GetCalmReal8(ci->gw,CID_PrevXOff,_("Prev CP X"),&err)-(cursp->prevcp.x-cursp->me.x);
2373 	    if ( cursp->pointtype==pt_tangent && cursp->next!=NULL ) {
2374 		if ( cursp->next->to->me.x==cursp->me.x ) {
2375 		    dy = dx; dx = 0;	/* They should be constrained not to change in the x direction */
2376 		} else
2377 		    dy = dx*(cursp->next->to->me.y-cursp->me.y)/(cursp->next->to->me.x-cursp->me.x);
2378 	    }
2379 	} else if ( GGadgetGetCid(g)==CID_PrevYOff ) {
2380 	    dy = GetCalmReal8(ci->gw,CID_PrevYOff,_("Prev CP Y"),&err)-(cursp->prevcp.y-cursp->me.y);
2381 	    if ( cursp->pointtype==pt_tangent && cursp->next!=NULL ) {
2382 		if ( cursp->next->to->me.y==cursp->me.y ) {
2383 		    dx = dy; dy = 0;	/* They should be constrained not to change in the y direction */
2384 		} else
2385 		    dx = dy*(cursp->next->to->me.x-cursp->me.x)/(cursp->next->to->me.y-cursp->me.y);
2386 	    }
2387 	} else {
2388 	    double len, theta;
2389 	    len = GetCalmReal8(ci->gw,CID_PrevR,_("Prev CP Dist"),&err);
2390 	    theta = GetCalmReal8(ci->gw,CID_PrevTheta,_("Prev CP Angle"),&err)/RAD2DEG;
2391 	    dx = len*cos(theta) - (cursp->prevcp.x-cursp->me.x);
2392 	    dy = len*sin(theta) - (cursp->prevcp.y-cursp->me.y);
2393 	}
2394 	if ( (dx==0 && dy==0) || err )
2395 return( true );
2396 	if ( cursp->pointtype==pt_hvcurve ) {
2397 	    BasePoint diff;
2398 	    diff.x = cursp->prevcp.x+dx - cursp->me.x;
2399 	    diff.y = cursp->prevcp.y+dy - cursp->me.y;
2400 	    BP_HVForce(&diff);
2401 	    dx = diff.x - (cursp->prevcp.x - cursp->me.x);
2402 	    dy = diff.y - (cursp->prevcp.y - cursp->me.y);
2403 	}
2404 	cursp->prevcp.x += dx;
2405 	cursp->prevcp.y += dy;
2406 	cursp->noprevcp = false;
2407 	ci->prevchanged = true;
2408 	SplineSetSpirosClear(ci->curspl);
2409 	if (( dx>.1 || dx<-.1 || dy>.1 || dy<-.1 ) && cursp->prevcpdef ) {
2410 	    cursp->prevcpdef = false;
2411 	    GGadgetSetChecked(GWidgetGetControl(ci->gw,CID_PrevDef), false );
2412 	}
2413 	if (( cursp->pointtype==pt_curve || cursp->pointtype==pt_hvcurve) && cursp->next!=NULL ) {
2414 	    double nlen, ptheta;
2415 	    double pdx, pdy;
2416 	    pdx = ci->cursp->prevcp.x-ci->cursp->me.x;
2417 	    pdy = ci->cursp->prevcp.y-ci->cursp->me.y;
2418 	    ptheta = atan2(pdy,pdx);
2419 	    nlen = GetCalmReal8(ci->gw,CID_NextR,_("Next CP Dist"),&err);
2420 	    ci->cursp->nextcp.x = ci->cursp->me.x - nlen*cos(ptheta);
2421 	    ci->cursp->nextcp.y = ci->cursp->me.y - nlen*sin(ptheta);
2422 	    if ( ci->cv->b.layerheads[ci->cv->b.drawmode]->order2 )
2423 		SplinePointNextCPChanged2(cursp);
2424 	    SplineRefigure(cursp->next);
2425 	}
2426 	if ( ci->cv->b.layerheads[ci->cv->b.drawmode]->order2 )
2427 	    SplinePointPrevCPChanged2(cursp);
2428 	if ( cursp->prev!=NULL )
2429 	    SplineRefigure(cursp->prev);
2430 	CVCharChangedUpdate(&ci->cv->b);
2431 	PIFillup(ci,GGadgetGetCid(g));
2432     } else if ( e->type==et_controlevent &&
2433 	    e->u.control.subtype == et_textfocuschanged &&
2434 	    e->u.control.u.tf_focus.gained_focus ) {
2435 	GIData *ci = GDrawGetUserData(GGadgetGetWindow(g));
2436 	PI_FigurePrev(ci);
2437     }
2438 return( true );
2439 }
2440 
PI_NextIntChanged(GGadget * g,GEvent * e)2441 static int PI_NextIntChanged(GGadget *g, GEvent *e) {
2442     if ( e->type==et_controlevent && e->u.control.subtype == et_textchanged ) {
2443 	GIData *ci = GDrawGetUserData(GGadgetGetWindow(g));
2444 	real x=0, y=0;
2445 	int err=false;
2446 	SplinePoint *cursp = ci->cursp;
2447 
2448 	x = GetCalmReal8(ci->gw,CID_NextX,_("Next CP X"),&err);
2449 	y = GetCalmReal8(ci->gw,CID_NextY,_("Next CP Y"),&err);
2450 	if ( err || (x==cursp->nextcp.x && y==cursp->nextcp.y) )
2451 return( true );
2452 	cursp->nextcp.x = x;
2453 	cursp->nextcp.y = y;
2454 	cursp->me.x = (cursp->nextcp.x + cursp->prevcp.x)/2;
2455 	cursp->me.y = (cursp->nextcp.y + cursp->prevcp.y)/2;
2456 	SplineSetSpirosClear(ci->curspl);
2457 	if ( ci->cv->b.layerheads[ci->cv->b.drawmode]->order2 )
2458 	    SplinePointNextCPChanged2(cursp);
2459 	if ( cursp->next!=NULL )
2460 	    SplineRefigure(cursp->next);
2461 	CVCharChangedUpdate(&ci->cv->b);
2462 	PIFillup(ci,GGadgetGetCid(g));
2463     } else if ( e->type==et_controlevent &&
2464 	    e->u.control.subtype == et_textfocuschanged &&
2465 	    e->u.control.u.tf_focus.gained_focus ) {
2466 	GIData *ci = GDrawGetUserData(GGadgetGetWindow(g));
2467 	PI_FigureNext(ci);
2468     }
2469 return( true );
2470 }
2471 
PI_PrevIntChanged(GGadget * g,GEvent * e)2472 static int PI_PrevIntChanged(GGadget *g, GEvent *e) {
2473     if ( e->type==et_controlevent && e->u.control.subtype == et_textchanged ) {
2474 	GIData *ci = GDrawGetUserData(GGadgetGetWindow(g));
2475 	real x=0, y=0;
2476 	int err=false;
2477 	SplinePoint *cursp = ci->cursp;
2478 
2479 	x = GetCalmReal8(ci->gw,CID_PrevX,_("Prev CP X"),&err);
2480 	y = GetCalmReal8(ci->gw,CID_PrevY,_("Prev CP Y"),&err);
2481 	if ( err || (x==cursp->prevcp.x && y==cursp->prevcp.y) )
2482 return( true );
2483 	cursp->prevcp.x = x;
2484 	cursp->prevcp.y = y;
2485 	cursp->me.x = (cursp->nextcp.x + cursp->prevcp.x)/2;
2486 	cursp->me.y = (cursp->nextcp.y + cursp->prevcp.y)/2;
2487 	SplineSetSpirosClear(ci->curspl);
2488 	if ( ci->cv->b.layerheads[ci->cv->b.drawmode]->order2 )
2489 	    SplinePointPrevCPChanged2(cursp);
2490 	if ( cursp->prev!=NULL )
2491 	    SplineRefigure(cursp->prev);
2492 	CVCharChangedUpdate(&ci->cv->b);
2493 	PIFillup(ci,GGadgetGetCid(g));
2494     } else if ( e->type==et_controlevent &&
2495 	    e->u.control.subtype == et_textfocuschanged &&
2496 	    e->u.control.u.tf_focus.gained_focus ) {
2497 	GIData *ci = GDrawGetUserData(GGadgetGetWindow(g));
2498 	PI_FigureNext(ci);
2499     }
2500 return( true );
2501 }
2502 
PI_NextDefChanged(GGadget * g,GEvent * e)2503 static int PI_NextDefChanged(GGadget *g, GEvent *e) {
2504     if ( e->type==et_controlevent && e->u.control.subtype == et_radiochanged ) {
2505 	GIData *ci = GDrawGetUserData(GGadgetGetWindow(g));
2506 	SplinePoint *cursp = ci->cursp;
2507 
2508 	cursp->nextcpdef = GGadgetIsChecked(g);
2509 	/* If they turned def off, that's a noop, but if they turned it on... */
2510 	/*  then set things to the default */
2511 	if ( cursp->nextcpdef ) {
2512 	    BasePoint temp = cursp->prevcp;
2513 	    SplineCharDefaultNextCP(cursp);
2514 	    if ( !cursp->prevcpdef ) {
2515 		cursp->prevcp = temp;
2516 		SplineSetSpirosClear(ci->curspl);
2517 	    }
2518 	    CVCharChangedUpdate(&ci->cv->b);
2519 	    PIFillup(ci,GGadgetGetCid(g));
2520 	}
2521     }
2522 return( true );
2523 }
2524 
PI_PrevDefChanged(GGadget * g,GEvent * e)2525 static int PI_PrevDefChanged(GGadget *g, GEvent *e) {
2526     if ( e->type==et_controlevent && e->u.control.subtype == et_radiochanged ) {
2527 	GIData *ci = GDrawGetUserData(GGadgetGetWindow(g));
2528 	SplinePoint *cursp = ci->cursp;
2529 
2530 	cursp->prevcpdef = GGadgetIsChecked(g);
2531 	/* If they turned def off, that's a noop, but if they turned it on... */
2532 	/*  then set things to the default */
2533 	if ( cursp->prevcpdef ) {
2534 	    BasePoint temp = cursp->nextcp;
2535 	    SplineCharDefaultPrevCP(cursp);
2536 	    if ( !cursp->nextcpdef ) {
2537 		cursp->nextcp = temp;
2538 		SplineSetSpirosClear(ci->curspl);
2539 	    }
2540 	    CVCharChangedUpdate(&ci->cv->b);
2541 	    PIFillup(ci,GGadgetGetCid(g));
2542 	}
2543     }
2544 return( true );
2545 }
2546 
PI_PTypeChanged(GGadget * g,GEvent * e)2547 static int PI_PTypeChanged(GGadget *g, GEvent *e) {
2548     if ( e->type==et_controlevent && e->u.control.subtype == et_radiochanged ) {
2549 	GIData *ci = GDrawGetUserData(GGadgetGetWindow(g));
2550 	SplinePoint *cursp = ci->cursp;
2551 	enum pointtype pt = GGadgetGetCid(g)-CID_Curve + pt_curve;
2552 
2553 	if ( pt==cursp->pointtype ) {
2554 	    /* Can't happen */
2555 	} else if ( pt==pt_corner ) {
2556 	    cursp->pointtype = pt_corner;
2557 	    CVCharChangedUpdate(&ci->cv->b);
2558 	} else {
2559 	    SPChangePointType(cursp,pt);
2560 	    SplineSetSpirosClear(ci->curspl);
2561 	    CVCharChangedUpdate(&ci->cv->b);
2562 	    PIFillup(ci,GGadgetGetCid(g));
2563 	}
2564     }
2565 return( true );
2566 }
2567 
PI_AspectChange(GGadget * g,GEvent * e)2568 static int PI_AspectChange(GGadget *g, GEvent *e) {
2569     if ( e==NULL || (e->type==et_controlevent && e->u.control.subtype == et_radiochanged )) {
2570 	GIData *ci = GDrawGetUserData(GGadgetGetWindow(g));
2571 	int aspect = GTabSetGetSel(g);
2572 
2573 	_PI_ShowHints(ci,aspect==1);
2574     }
2575 return( true );
2576 }
2577 
PI_HintSel(GGadget * g,GEvent * e)2578 static int PI_HintSel(GGadget *g, GEvent *e) {
2579     if ( e->type==et_controlevent && e->u.control.subtype == et_listselected ) {
2580 	GIData *ci = GDrawGetUserData(GGadgetGetWindow(g));
2581 
2582 	_PI_ShowHints(ci,true);
2583 
2584 	if ( GGadgetIsListItemSelected(g,e->u.control.u.list.changed_index)) {
2585 	    /* If we just selected something, check to make sure it doesn't */
2586 	    /*  conflict with any other hints. */
2587 	    /* Adobe says this is an error, but in "three" in AdobeSansMM */
2588 	    /*  (in black,extended) we have a hintmask which contains two */
2589 	    /*  overlapping hints */
2590 	    /* So just make it a warning */
2591 	    int i,j;
2592 	    StemInfo *h, *h2=NULL;
2593 	    for ( i=0, h=ci->cv->b.sc->hstem; h!=NULL && i!=e->u.control.u.list.changed_index; h=h->next, ++i );
2594 	    if ( h!=NULL ) {
2595 		for ( h2 = ci->cv->b.sc->hstem, i=0 ; h2!=NULL; h2=h2->next, ++i ) {
2596 		    if ( h2!=h && GGadgetIsListItemSelected(g,i)) {
2597 			if (( h2->start<h->start && h2->start+h2->width>h->start ) ||
2598 			    ( h2->start>=h->start && h->start+h->width>h2->start ))
2599 		break;
2600 		    }
2601 		}
2602 	    } else {
2603 		j = i;
2604 		for ( h=ci->cv->b.sc->vstem; h!=NULL && i!=e->u.control.u.list.changed_index; h=h->next, ++i );
2605 		if ( h==NULL )
2606 		    IError("Failed to find hint");
2607 		else {
2608 		    for ( h2 = ci->cv->b.sc->vstem, i=j ; h2!=NULL; h2=h2->next, ++i ) {
2609 			if ( h2!=h && GGadgetIsListItemSelected(g,i)) {
2610 			    if (( h2->start<h->start && h2->start+h2->width>h->start ) ||
2611 				( h2->start>=h->start && h->start+h->width>h2->start ))
2612 		    break;
2613 			}
2614 		    }
2615 		}
2616 	    }
2617 	    if ( h2!=NULL )
2618 		ff_post_error(_("Overlapped Hints"),_("The hint you have just selected overlaps with <%.2f,%.2f>. You should deselect one of the two."),
2619 			h2->start,h2->width);
2620 	}
2621     }
2622 return( true );
2623 }
2624 
SCHintList(SplineChar * sc,HintMask * hm)2625 GTextInfo *SCHintList(SplineChar *sc,HintMask *hm) {
2626     StemInfo *h;
2627     int i;
2628     GTextInfo *ti;
2629     char buffer[100];
2630 
2631     for ( h=sc->hstem, i=0; h!=NULL; h=h->next, ++i );
2632     for ( h=sc->vstem     ; h!=NULL; h=h->next, ++i );
2633     ti = calloc(i+1,sizeof(GTextInfo));
2634 
2635     for ( h=sc->hstem, i=0; h!=NULL; h=h->next, ++i ) {
2636 	ti[i].fg = ti[i].bg = COLOR_DEFAULT;
2637 	ti[i].userdata = h;
2638 	if ( h->ghost && h->width>0 )
2639 	    sprintf( buffer, "H<%g,%g>",
2640 		    rint(h->start*100)/100+rint(h->width*100)/100, -rint(h->width*100)/100 );
2641 	else
2642 	    sprintf( buffer, "H<%g,%g>",
2643 		    rint(h->start*100)/100, rint(h->width*100)/100 );
2644 	ti[i].text = uc_copy(buffer);
2645 	if ( hm!=NULL && ((*hm)[i>>3]&(0x80>>(i&7))))
2646 	    ti[i].selected = true;
2647     }
2648 
2649     for ( h=sc->vstem    ; h!=NULL; h=h->next, ++i ) {
2650 	ti[i].fg = ti[i].bg = COLOR_DEFAULT;
2651 	ti[i].userdata = h;
2652 	if ( h->ghost && h->width>0 )
2653 	    sprintf( buffer, "V<%g,%g>",
2654 		    rint(h->start*100)/100+rint(h->width*100)/100, -rint(h->width*100)/100 );
2655 	else
2656 	    sprintf( buffer, "V<%g,%g>",
2657 		    rint(h->start*100)/100, rint(h->width*100)/100 );
2658 	ti[i].text = uc_copy(buffer);
2659 	if ( hm!=NULL && ((*hm)[i>>3]&(0x80>>(i&7))))
2660 	    ti[i].selected = true;
2661     }
2662 return( ti );
2663 }
2664 
PointGetInfo(CharView * cv,SplinePoint * sp,SplinePointList * spl)2665 static void PointGetInfo(CharView *cv, SplinePoint *sp, SplinePointList *spl) {
2666     CharViewTab* tab = CVGetActiveTab(cv);
2667     GIData* gi = 0;
2668     GRect pos;
2669     GWindowAttrs wattrs;
2670     const int gcdcount = 54;
2671     GGadgetCreateData gcd[gcdcount], hgcd[2], h2gcd[2], mgcd[11];
2672     GGadgetCreateData mb[5], pb[9];
2673     GGadgetCreateData *marray[11], *marray2[5], *marray3[5], *marray4[7],
2674 	*varray[11], *harray1[4], *harray2[6], *hvarray1[25], *hvarray2[25],
2675 	*hvarray3[16], *harray3[13];
2676     GTextInfo label[54], mlabel[11];
2677     GTabInfo aspects[4];
2678     static GBox cur, nextcp, prevcp;
2679     extern Color nextcpcol, prevcpcol;
2680     GWindow root;
2681     GRect screensize;
2682     GPoint pt;
2683     int j, defxpos, nextstarty, k, l;
2684 
2685     gi = calloc(1,sizeof(GIData));
2686 
2687     cur.main_background = nextcp.main_background = prevcp.main_background = COLOR_DEFAULT;
2688     cur.main_foreground = 0xff0000;
2689     nextcp.main_foreground = nextcpcol;
2690     prevcp.main_foreground = prevcpcol;
2691     gi->cv = cv;
2692     gi->sc = cv->b.sc;
2693     gi->cursp = sp;
2694     gi->curspl = spl;
2695     gi->oldstate = SplinePointListCopy(cv->b.layerheads[cv->b.drawmode]->splines);
2696     gi->done = false;
2697     CVPreserveState(&cv->b);
2698 
2699     root = GDrawGetRoot(NULL);
2700     GDrawGetSize(root,&screensize);
2701 
2702 	memset(&wattrs,0,sizeof(wattrs));
2703 	wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_positioned|wam_isdlg;
2704 	wattrs.event_masks = ~(1<<et_charup);
2705 	wattrs.restrict_input_to_me = 1;
2706 	wattrs.positioned = 1;
2707 	wattrs.cursor = ct_pointer;
2708 	wattrs.utf8_window_title = _("Point Info");
2709 	wattrs.is_dlg = true;
2710 	pos.width = GGadgetScale(GDrawPointsToPixels(NULL,PI_Width));
2711 	pos.height = GDrawPointsToPixels(NULL,PI_Height);
2712 	pt.x = tab->xoff + rint(sp->me.x*tab->scale);
2713 	pt.y = -tab->yoff + cv->height - rint(sp->me.y*tab->scale);
2714 	GDrawTranslateCoordinates(cv->v,root,&pt);
2715 	if ( pt.x+20+pos.width<=screensize.width )
2716 	    pos.x = pt.x+20;
2717 	else if ( (pos.x = pt.x-10-screensize.width)<0 )
2718 	    pos.x = 0;
2719 	pos.y = pt.y;
2720 	if ( pos.y+pos.height+20 > screensize.height )
2721 	    pos.y = screensize.height - pos.height - 20;
2722 	if ( pos.y<0 ) pos.y = 0;
2723 	gi->gw = GDrawCreateTopWindow(NULL,&pos,pi_e_h,gi,&wattrs);
2724 
2725 	memset(&gcd,0,sizeof(gcd));
2726 	memset(&label,0,sizeof(label));
2727 	memset(&hgcd,0,sizeof(hgcd));
2728 	memset(&h2gcd,0,sizeof(h2gcd));
2729 	memset(&mgcd,0,sizeof(mgcd));
2730 	memset(&mlabel,0,sizeof(mlabel));
2731 	memset(&aspects,0,sizeof(aspects));
2732 	memset(&pb,0,sizeof(pb));
2733 
2734 	j=k=0;
2735 	gi->gcd = malloc( gcdcount*sizeof(GGadgetCreateData) );
2736 	memcpy( gi->gcd, gcd, gcdcount*sizeof(GGadgetCreateData) );
2737 
2738 	label[j].text = (unichar_t *) _("_Normal");
2739 	label[j].text_is_1byte = true;
2740 	label[j].text_in_resource = true;
2741 	gcd[j].gd.label = &label[j];
2742 	gcd[j].gd.pos.x = 5; gcd[j].gd.pos.y = 5;
2743 	gcd[j].gd.flags = gg_enabled|gg_visible|gg_cb_on;
2744 	gcd[j].gd.cid = CID_Normal;
2745 	gcd[j].gd.handle_controlevent = PI_InterpChanged;
2746 	gcd[j].creator = GRadioCreate;
2747 	harray1[0] = &gcd[j];
2748 	++j;
2749 
2750 	label[j].text = (unichar_t *) _("_Interpolated");
2751 	label[j].text_is_1byte = true;
2752 	label[j].text_in_resource = true;
2753 	gcd[j].gd.label = &label[j];
2754 	gcd[j].gd.pos.x = 70; gcd[j].gd.pos.y = 5;
2755 	gcd[j].gd.flags = gg_enabled|gg_visible | gg_rad_continueold;
2756 	gcd[j].gd.cid = CID_Interpolated;
2757 	gcd[j].gd.handle_controlevent = PI_InterpChanged;
2758 	gcd[j].creator = GRadioCreate;
2759 	harray1[1] = &gcd[j]; harray1[2] = GCD_Glue; harray1[3] = NULL;
2760 	++j;
2761 
2762 	pb[2].gd.flags = gg_enabled|gg_visible;
2763 	pb[2].gd.u.boxelements = harray1;
2764 	pb[2].creator = GHBoxCreate;
2765 	varray[k++] = &pb[2];
2766 
2767 	label[j].text = (unichar_t *) _("N_ever Interpolate");
2768 	label[j].text_is_1byte = true;
2769 	label[j].text_in_resource = true;
2770 	gcd[j].gd.label = &label[j];
2771 	gcd[j].gd.pos.x = 5; gcd[j].gd.pos.y = gcd[j-1].gd.pos.y+16;
2772 	gcd[j].gd.flags = cv->b.layerheads[cv->b.drawmode]->order2 ? (gg_enabled|gg_visible) : gg_visible;
2773 	gcd[j].gd.cid = CID_NeverInterpolate;
2774 	gcd[j].gd.handle_controlevent = PI_NeverInterpChanged;
2775 	gcd[j].creator = GCheckBoxCreate;
2776 	varray[k++] = &gcd[j];
2777 	++j;
2778 
2779 	gi->normal_start = j;
2780 	label[j].text = (unichar_t *) _("_Base:");
2781 	label[j].text_is_1byte = true;
2782 	label[j].text_in_resource = true;
2783 	gcd[j].gd.label = &label[j];
2784 	gcd[j].gd.pos.x = 5; gcd[j].gd.pos.y = gcd[j-1].gd.pos.y+17+6;
2785 	gcd[j].gd.flags = gg_enabled|gg_visible|gg_dontcopybox;
2786 	gcd[j].gd.box = &cur;
2787 	gcd[j].creator = GLabelCreate;
2788 	harray2[0] = &gcd[j]; harray2[1] = GCD_Glue;
2789 	++j;
2790 
2791 	gcd[j].gd.pos.x = 60; gcd[j].gd.pos.y = gcd[j-1].gd.pos.y-6; gcd[j].gd.pos.width = 70;
2792 	gcd[j].gd.flags = gg_enabled|gg_visible;
2793 	gcd[j].gd.cid = CID_BaseX;
2794 	gcd[j].gd.handle_controlevent = PI_BaseChanged;
2795 	gcd[j].creator = GNumericFieldCreate;
2796 	harray2[2] = &gcd[j];
2797 	++j;
2798 
2799 	gcd[j].gd.pos.x = 137; gcd[j].gd.pos.y = gcd[j-1].gd.pos.y; gcd[j].gd.pos.width = 70;
2800 	gcd[j].gd.flags = gg_enabled|gg_visible;
2801 	gcd[j].gd.cid = CID_BaseY;
2802 	gcd[j].gd.handle_controlevent = PI_BaseChanged;
2803 	gcd[j].creator = GNumericFieldCreate;
2804 	harray2[3] = &gcd[j]; harray2[4] = GCD_Glue; harray2[5] = NULL;
2805 	++j;
2806 
2807 	pb[3].gd.flags = gg_enabled|gg_visible;
2808 	pb[3].gd.u.boxelements = harray2;
2809 	pb[3].creator = GHBoxCreate;
2810 	varray[k++] = &pb[3];
2811 
2812 	l = 0;
2813 	label[j].text = (unichar_t *) _("Prev CP:");
2814 	label[j].text_is_1byte = true;
2815 	gcd[j].gd.label = &label[j];
2816 	gcd[j].gd.pos.x = 9; gcd[j].gd.pos.y = gcd[j-1].gd.pos.y+24+4;
2817 	gcd[j].gd.flags = gg_enabled|gg_visible|gg_dontcopybox;
2818 	gcd[j].gd.box = &prevcp;
2819 	gcd[j].creator = GLabelCreate;
2820 	hvarray1[l++] = &gcd[j]; hvarray1[l++] = GCD_Glue;
2821 	++j;
2822 
2823 	gcd[j].gd.pos.x = 60; gcd[j].gd.pos.y = gcd[j-1].gd.pos.y; gcd[j].gd.pos.width = 65;
2824 	gcd[j].gd.flags = gg_enabled|gg_visible;
2825 	gcd[j].gd.cid = CID_PrevPos;
2826 	gcd[j].creator = GLabelCreate;
2827 	hvarray1[l++] = &gcd[j];
2828 	++j;
2829 
2830 	defxpos = 130;
2831 	label[j].text = (unichar_t *) S_("ControlPoint|Default");
2832 	label[j].text_is_1byte = true;
2833 	gcd[j].gd.label = &label[j];
2834 	gcd[j].gd.pos.x = defxpos; gcd[j].gd.pos.y = gcd[j-1].gd.pos.y-3;
2835 	gcd[j].gd.flags = (gg_enabled|gg_visible);
2836 	gcd[j].gd.cid = CID_PrevDef;
2837 	gcd[j].gd.handle_controlevent = PI_PrevDefChanged;
2838 	gcd[j].creator = GCheckBoxCreate;
2839 	hvarray1[l++] = &gcd[j]; hvarray1[l++] = GCD_ColSpan; hvarray1[l++] = NULL;
2840 	++j;
2841 
2842 	label[j].text = (unichar_t *) _("Offset");
2843 	label[j].text_is_1byte = true;
2844 	gcd[j].gd.label = &label[j];
2845 	gcd[j].gd.pos.x = gcd[3].gd.pos.x+10; gcd[j].gd.pos.y = gcd[j-1].gd.pos.y+18+4;
2846 	gcd[j].gd.flags = gg_enabled|gg_visible;
2847 	gcd[j].creator = GLabelCreate;
2848 	hvarray1[l++] = &gcd[j]; hvarray1[l++] = GCD_Glue;
2849 	++j;
2850 
2851 	gcd[j].gd.pos.x = 60; gcd[j].gd.pos.y = gcd[j-1].gd.pos.y-4; gcd[j].gd.pos.width = 70;
2852 	gcd[j].gd.flags = gg_enabled|gg_visible;
2853 	gcd[j].gd.cid = CID_PrevXOff;
2854 	gcd[j].gd.handle_controlevent = PI_PrevChanged;
2855 	gcd[j].creator = GNumericFieldCreate;
2856 	hvarray1[l++] = &gcd[j];
2857 	++j;
2858 
2859 	gcd[j].gd.pos.x = 137; gcd[j].gd.pos.y = gcd[j-1].gd.pos.y; gcd[j].gd.pos.width = 70;
2860 	gcd[j].gd.flags = gg_enabled|gg_visible;
2861 	gcd[j].gd.cid = CID_PrevYOff;
2862 	gcd[j].gd.handle_controlevent = PI_PrevChanged;
2863 	gcd[j].creator = GNumericFieldCreate;
2864 	hvarray1[l++] = &gcd[j]; hvarray1[l++] = GCD_ColSpan; hvarray1[l++] = NULL;
2865 	++j;
2866 
2867 	label[j].text = (unichar_t *) _("Dist");
2868 	label[j].text_is_1byte = true;
2869 	gcd[j].gd.label = &label[j];
2870 	gcd[j].gd.pos.x = gcd[3].gd.pos.x+10; gcd[j].gd.pos.y = gcd[j-1].gd.pos.y+28;
2871 	gcd[j].gd.flags = gg_enabled|gg_visible;
2872 	gcd[j].creator = GLabelCreate;
2873 	hvarray1[l++] = &gcd[j]; hvarray1[l++] = GCD_Glue;
2874 	++j;
2875 
2876 	gcd[j].gd.pos.x = 60; gcd[j].gd.pos.y = gcd[j-1].gd.pos.y-4; gcd[j].gd.pos.width = 70;
2877 	gcd[j].gd.flags = gg_enabled|gg_visible;
2878 	gcd[j].gd.cid = CID_PrevR;
2879 	gcd[j].gd.handle_controlevent = PI_PrevChanged;
2880 	gcd[j].creator = GNumericFieldCreate;
2881 	hvarray1[l++] = &gcd[j];
2882 	++j;
2883 
2884 	gcd[j].gd.pos.x = 137; gcd[j].gd.pos.y = gcd[j-1].gd.pos.y; gcd[j].gd.pos.width = 60;
2885 	gcd[j].gd.flags = gg_enabled|gg_visible;
2886 	gcd[j].gd.cid = CID_PrevTheta;
2887 	gcd[j].gd.handle_controlevent = PI_PrevChanged;
2888 	gcd[j].creator = GTextFieldCreate;
2889 	hvarray1[l++] = &gcd[j];
2890 	++j;
2891 
2892 	label[j].text = (unichar_t *) U_("°");
2893 	label[j].text_is_1byte = true;
2894 	gcd[j].gd.label = &label[j];
2895 	gcd[j].gd.pos.x = gcd[j-1].gd.pos.x+gcd[j-1].gd.pos.width+2; gcd[j].gd.pos.y = gcd[j-3].gd.pos.y;
2896 	gcd[j].gd.flags = gg_enabled|gg_visible;
2897 	gcd[j].creator = GLabelCreate;
2898 	hvarray1[l++] = &gcd[j]; hvarray1[l++] = NULL;
2899 	++j;
2900 
2901 	label[j].text = (unichar_t *) _("Curvature: -0.00000000");
2902 	label[j].text_is_1byte = true;
2903 	gcd[j].gd.label = &label[j];
2904 	gcd[j].gd.pos.x = 9; gcd[j].gd.pos.y = gcd[j-1].gd.pos.y+20;
2905 	gcd[j].gd.flags = gg_enabled|gg_visible;
2906 	gcd[j].gd.cid = CID_PrevCurvature;
2907 	gcd[j].creator = GLabelCreate;
2908 	hvarray1[l++] = &gcd[j]; hvarray1[l++] = GCD_ColSpan; hvarray1[l++] = GCD_ColSpan;
2909 	  hvarray1[l++] = GCD_Glue; hvarray1[l++] = GCD_Glue; hvarray1[l++] = NULL;
2910 	 hvarray1[l++] = NULL;
2911 	++j;
2912 
2913 	pb[4].gd.pos.x = pb[4].gd.pos.y = 2;
2914 	pb[4].gd.flags = gg_enabled|gg_visible;
2915 	pb[4].gd.u.boxelements = hvarray1;
2916 	pb[4].creator = GHVGroupCreate;
2917 	varray[k++] = &pb[4];
2918 
2919 	l = 0;
2920 	nextstarty = gcd[j-2].gd.pos.y+28;
2921 	label[j].text = (unichar_t *) _("Next CP:");
2922 	label[j].text_is_1byte = true;
2923 	gcd[j].gd.label = &label[j];
2924 	gcd[j].gd.pos.x = 9; gcd[j].gd.pos.y = nextstarty;
2925 	gcd[j].gd.flags = gg_enabled|gg_visible|gg_dontcopybox;
2926 	gcd[j].gd.box = &nextcp;
2927 	gcd[j].creator = GLabelCreate;
2928 	hvarray2[l++] = &gcd[j]; hvarray2[l++] = GCD_Glue;
2929 	++j;
2930 
2931 	gcd[j].gd.pos.x = 60; gcd[j].gd.pos.y = nextstarty;  gcd[j].gd.pos.width = 65;
2932 	gcd[j].gd.flags = gg_enabled|gg_visible;
2933 	gcd[j].gd.cid = CID_NextPos;
2934 	gcd[j].creator = GLabelCreate;
2935 	hvarray2[l++] = &gcd[j];
2936 	++j;
2937 
2938 	label[j].text = (unichar_t *) S_("ControlPoint|Default");
2939 	label[j].text_is_1byte = true;
2940 	gcd[j].gd.label = &label[j];
2941 	gcd[j].gd.pos.x = defxpos; gcd[j].gd.pos.y = gcd[j-1].gd.pos.y-3;
2942 	gcd[j].gd.flags = (gg_enabled|gg_visible);
2943 	gcd[j].gd.cid = CID_NextDef;
2944 	gcd[j].gd.handle_controlevent = PI_NextDefChanged;
2945 	gcd[j].creator = GCheckBoxCreate;
2946 	hvarray2[l++] = &gcd[j]; hvarray2[l++] = GCD_ColSpan; hvarray2[l++] = NULL;
2947 	++j;
2948 
2949 	label[j].text = (unichar_t *) _("Offset");
2950 	label[j].text_is_1byte = true;
2951 	gcd[j].gd.label = &label[j];
2952 	gcd[j].gd.pos.x = gcd[3].gd.pos.x+10; gcd[j].gd.pos.y = gcd[j-1].gd.pos.y+18+4;
2953 	gcd[j].gd.flags = gg_enabled|gg_visible;
2954 	gcd[j].creator = GLabelCreate;
2955 	hvarray2[l++] = &gcd[j]; hvarray2[l++] = GCD_Glue;
2956 	++j;
2957 
2958 	gcd[j].gd.pos.x = 60; gcd[j].gd.pos.y = gcd[j-1].gd.pos.y-4; gcd[j].gd.pos.width = 70;
2959 	gcd[j].gd.flags = gg_enabled|gg_visible;
2960 	gcd[j].gd.cid = CID_NextXOff;
2961 	gcd[j].gd.handle_controlevent = PI_NextChanged;
2962 	gcd[j].creator = GNumericFieldCreate;
2963 	hvarray2[l++] = &gcd[j];
2964 	++j;
2965 
2966 	gcd[j].gd.pos.x = 137; gcd[j].gd.pos.y = gcd[j-1].gd.pos.y; gcd[j].gd.pos.width = 70;
2967 	gcd[j].gd.flags = gg_enabled|gg_visible;
2968 	gcd[j].gd.cid = CID_NextYOff;
2969 	gcd[j].gd.handle_controlevent = PI_NextChanged;
2970 	gcd[j].creator = GNumericFieldCreate;
2971 	hvarray2[l++] = &gcd[j]; hvarray2[l++] = GCD_ColSpan; hvarray2[l++] = NULL;
2972 	++j;
2973 
2974 	label[j].text = (unichar_t *) _("Dist");
2975 	label[j].text_is_1byte = true;
2976 	gcd[j].gd.label = &label[j];
2977 	gcd[j].gd.pos.x = gcd[3].gd.pos.x+10; gcd[j].gd.pos.y = gcd[j-1].gd.pos.y+28;
2978 	gcd[j].gd.flags = gg_enabled|gg_visible;
2979 	gcd[j].creator = GLabelCreate;
2980 	hvarray2[l++] = &gcd[j]; hvarray2[l++] = GCD_Glue;
2981 	++j;
2982 
2983 	gcd[j].gd.pos.x = 60; gcd[j].gd.pos.y = gcd[j-1].gd.pos.y-4; gcd[j].gd.pos.width = 70;
2984 	gcd[j].gd.flags = gg_enabled|gg_visible;
2985 	gcd[j].gd.cid = CID_NextR;
2986 	gcd[j].gd.handle_controlevent = PI_NextChanged;
2987 	gcd[j].creator = GNumericFieldCreate;
2988 	hvarray2[l++] = &gcd[j];
2989 	++j;
2990 
2991 	gcd[j].gd.pos.x = 137; gcd[j].gd.pos.y = gcd[j-1].gd.pos.y; gcd[j].gd.pos.width = 60;
2992 	gcd[j].gd.flags = gg_enabled|gg_visible;
2993 	gcd[j].gd.cid = CID_NextTheta;
2994 	gcd[j].gd.handle_controlevent = PI_NextChanged;
2995 	gcd[j].creator = GTextFieldCreate;
2996 	hvarray2[l++] = &gcd[j];
2997 	++j;
2998 
2999 	label[j].text = (unichar_t *) U_("°");
3000 	label[j].text_is_1byte = true;
3001 	gcd[j].gd.label = &label[j];
3002 	gcd[j].gd.pos.x = gcd[j-1].gd.pos.x+gcd[j-1].gd.pos.width+2; gcd[j].gd.pos.y = gcd[j-3].gd.pos.y;
3003 	gcd[j].gd.flags = gg_enabled|gg_visible;
3004 	gcd[j].creator = GLabelCreate;
3005 	hvarray2[l++] = &gcd[j]; hvarray2[l++] = NULL;
3006 	++j;
3007 
3008 	label[j].text = (unichar_t *) _("Curvature: -0.00000000");
3009 	label[j].text_is_1byte = true;
3010 	gcd[j].gd.label = &label[j];
3011 	gcd[j].gd.pos.x = 9; gcd[j].gd.pos.y = gcd[j-1].gd.pos.y+20;
3012 	gcd[j].gd.flags = gg_enabled|gg_visible;
3013 	gcd[j].gd.cid = CID_NextCurvature;
3014 	gcd[j].creator = GLabelCreate;
3015 	hvarray2[l++] = &gcd[j]; hvarray2[l++] = GCD_ColSpan; hvarray2[l++] = GCD_ColSpan;
3016 	++j;
3017 
3018 	label[j].text = (unichar_t *) "∆: -0.00000000";
3019 	label[j].text_is_1byte = true;
3020 	gcd[j].gd.label = &label[j];
3021 	gcd[j].gd.pos.x = 130; gcd[j].gd.pos.y = gcd[j-1].gd.pos.y;
3022 	gcd[j].gd.flags = gg_enabled|gg_visible;
3023 	gcd[j].gd.popup_msg = _("This is the difference of the curvature between\nthe next and previous splines. Contours often\nlook nicer as this number approaches 0." );
3024 	gcd[j].gd.cid = CID_DeltaCurvature;
3025 	gcd[j].creator = GLabelCreate;
3026 	hvarray2[l++] = &gcd[j]; hvarray2[l++] = GCD_ColSpan; hvarray2[l++] = NULL;
3027 	hvarray2[l++] = NULL;
3028 	++j;
3029 
3030 	pb[5].gd.pos.x = pb[5].gd.pos.y = 2;
3031 	pb[5].gd.flags = gg_enabled|gg_visible;
3032 	pb[5].gd.u.boxelements = hvarray2;
3033 	pb[5].creator = GHVGroupCreate;
3034 	varray[k++] = &pb[5];
3035 	gi->normal_end = j;
3036 
3037 	gi->interp_start = j;
3038 	l = 0;
3039 	label[j].text = (unichar_t *) _("_Base:");
3040 	label[j].text_is_1byte = true;
3041 	label[j].text_in_resource = true;
3042 	gcd[j].gd.label = &label[j];
3043 	gcd[j].gd.pos.x = 5; gcd[j].gd.pos.y = gcd[gi->normal_start].gd.pos.y;
3044 	gcd[j].gd.flags = gg_enabled|gg_visible|gg_dontcopybox;
3045 	gcd[j].gd.box = &cur;
3046 	gcd[j].creator = GLabelCreate;
3047 	hvarray3[l++] = &gcd[j]; hvarray3[l++] = GCD_Glue;
3048 	++j;
3049 
3050 	gcd[j].gd.pos.x = 60; gcd[j].gd.pos.y = gcd[j-1].gd.pos.y; gcd[j].gd.pos.width = 65;
3051 	gcd[j].gd.flags = gg_enabled|gg_visible;
3052 	gcd[j].gd.cid = CID_BasePos;
3053 	gcd[j].creator = GLabelCreate;
3054 	hvarray3[l++] = &gcd[j]; hvarray3[l++] = GCD_Glue; hvarray3[l++] = NULL;
3055 	++j;
3056 
3057 	label[j].text = (unichar_t *) _("Prev CP:");
3058 	label[j].text_is_1byte = true;
3059 	gcd[j].gd.label = &label[j];
3060 	gcd[j].gd.pos.x = 9; gcd[j].gd.pos.y = gcd[j-1].gd.pos.y+14+4;
3061 	gcd[j].gd.flags = gg_enabled|gg_visible|gg_dontcopybox;
3062 	gcd[j].gd.box = &prevcp;
3063 	gcd[j].creator = GLabelCreate;
3064 	hvarray3[l++] = &gcd[j]; hvarray3[l++] = GCD_Glue;
3065 	++j;
3066 
3067 	gcd[j].gd.pos.x = 60; gcd[j].gd.pos.y = gcd[j-1].gd.pos.y-4; gcd[j].gd.pos.width = 70;
3068 	gcd[j].gd.flags = gg_enabled|gg_visible;
3069 	gcd[j].gd.cid = CID_PrevX;
3070 	gcd[j].gd.handle_controlevent = PI_PrevIntChanged;
3071 	gcd[j].creator = GNumericFieldCreate;
3072 	hvarray3[l++] = &gcd[j];
3073 	++j;
3074 
3075 	gcd[j].gd.pos.x = 137; gcd[j].gd.pos.y = gcd[j-1].gd.pos.y; gcd[j].gd.pos.width = 70;
3076 	gcd[j].gd.flags = gg_enabled|gg_visible;
3077 	gcd[j].gd.cid = CID_PrevY;
3078 	gcd[j].gd.handle_controlevent = PI_PrevIntChanged;
3079 	gcd[j].creator = GNumericFieldCreate;
3080 	hvarray3[l++] = &gcd[j]; hvarray3[l++] = NULL;
3081 	++j;
3082 
3083 	label[j].text = (unichar_t *) _("Next CP:");
3084 	label[j].text_is_1byte = true;
3085 	gcd[j].gd.label = &label[j];
3086 	gcd[j].gd.pos.x = 9; gcd[j].gd.pos.y = gcd[j-1].gd.pos.y+24+4;
3087 	gcd[j].gd.flags = gg_enabled|gg_visible|gg_dontcopybox;
3088 	gcd[j].gd.box = &nextcp;
3089 	gcd[j].creator = GLabelCreate;
3090 	hvarray3[l++] = &gcd[j]; hvarray3[l++] = GCD_Glue;
3091 	++j;
3092 
3093 	gcd[j].gd.pos.x = 60; gcd[j].gd.pos.y = gcd[j-1].gd.pos.y-4; gcd[j].gd.pos.width = 70;
3094 	gcd[j].gd.flags = gg_enabled|gg_visible;
3095 	gcd[j].gd.cid = CID_NextX;
3096 	gcd[j].gd.handle_controlevent = PI_NextIntChanged;
3097 	gcd[j].creator = GNumericFieldCreate;
3098 	hvarray3[l++] = &gcd[j];
3099 	++j;
3100 
3101 	gcd[j].gd.pos.x = 137; gcd[j].gd.pos.y = gcd[j-1].gd.pos.y; gcd[j].gd.pos.width = 70;
3102 	gcd[j].gd.flags = gg_enabled|gg_visible;
3103 	gcd[j].gd.cid = CID_NextY;
3104 	gcd[j].gd.handle_controlevent = PI_NextIntChanged;
3105 	gcd[j].creator = GNumericFieldCreate;
3106 	hvarray3[l++] = &gcd[j]; hvarray3[l++] = NULL; hvarray3[l++] = NULL;
3107 	++j;
3108 	gi->interp_end = j;
3109 
3110 	pb[6].gd.flags = gg_enabled|gg_visible;
3111 	pb[6].gd.u.boxelements = hvarray3;
3112 	pb[6].creator = GHVBoxCreate;
3113 	varray[k++] = &pb[6];
3114 	varray[k++] = GCD_Glue;
3115 
3116 	label[j].text = (unichar_t *) _("Type:");
3117 	label[j].text_is_1byte = true;
3118 	gcd[j].gd.label = &label[j];
3119 	gcd[j].gd.pos.x = gcd[0].gd.pos.x; gcd[j].gd.pos.y = gcd[gi->normal_end-2].gd.pos.y+26;
3120 	gcd[j].gd.flags = gg_enabled|gg_visible;
3121 	gcd[j].creator = GLabelCreate;
3122 	harray3[0] = &gcd[j]; harray3[1] = GCD_Glue; harray3[2] = GCD_Glue;
3123 	++j;
3124 
3125 	label[j].image = &GIcon_midcurve;
3126 	gcd[j].gd.label = &label[j];
3127 	gcd[j].gd.pos.x = 60; gcd[j].gd.pos.y = gcd[j-1].gd.pos.y-2;
3128 	gcd[j].gd.flags = gg_enabled|gg_visible;
3129 	gcd[j].gd.cid = CID_Curve;
3130 	gcd[j].gd.handle_controlevent = PI_PTypeChanged;
3131 	gcd[j].creator = GRadioCreate;
3132 	harray3[3] = &gcd[j]; harray3[4] = GCD_Glue;
3133 	++j;
3134 
3135 	label[j].image = &GIcon_midhvcurve;
3136 	gcd[j].gd.label = &label[j];
3137 	gcd[j].gd.pos.x = 60; gcd[j].gd.pos.y = gcd[j-1].gd.pos.y-2;
3138 	gcd[j].gd.flags = gg_enabled|gg_visible;
3139 	gcd[j].gd.cid = CID_HVCurve;
3140 	gcd[j].gd.handle_controlevent = PI_PTypeChanged;
3141 	gcd[j].creator = GRadioCreate;
3142 	harray3[5] = &gcd[j]; harray3[6] = GCD_Glue;
3143 	++j;
3144 
3145 	label[j].image = &GIcon_midcorner;
3146 	gcd[j].gd.label = &label[j];
3147 	gcd[j].gd.pos.x = 100; gcd[j].gd.pos.y = gcd[j-1].gd.pos.y;
3148 	gcd[j].gd.flags = gg_enabled|gg_visible | gg_rad_continueold;
3149 	gcd[j].gd.cid = CID_Corner;
3150 	gcd[j].gd.handle_controlevent = PI_PTypeChanged;
3151 	gcd[j].creator = GRadioCreate;
3152 	harray3[7] = &gcd[j]; harray3[8] = GCD_Glue;
3153 	++j;
3154 
3155 	label[j].image = &GIcon_midtangent;
3156 	gcd[j].gd.label = &label[j];
3157 	gcd[j].gd.pos.x = 140; gcd[j].gd.pos.y = gcd[j-1].gd.pos.y;
3158 	gcd[j].gd.flags = gg_enabled|gg_visible | gg_rad_continueold;
3159 	gcd[j].gd.cid = CID_Tangent;
3160 	gcd[j].gd.handle_controlevent = PI_PTypeChanged;
3161 	gcd[j].creator = GRadioCreate;
3162 	harray3[9] = &gcd[j]; harray3[10] = GCD_Glue; harray3[11] = GCD_Glue;
3163 	harray3[12] = NULL;
3164 	++j;
3165 
3166 	pb[7].gd.flags = gg_enabled|gg_visible;
3167 	pb[7].gd.u.boxelements = harray3;
3168 	pb[7].creator = GHBoxCreate;
3169 	varray[k++] = &pb[7];
3170 	varray[k++] = NULL;
3171 
3172 	pb[0].gd.flags = gg_enabled|gg_visible;
3173 	pb[0].gd.u.boxelements = varray;
3174 	pb[0].creator = GVBoxCreate;
3175 
3176 	hgcd[0].gd.pos.x = 5; hgcd[0].gd.pos.y = 5;
3177 	hgcd[0].gd.pos.width = PI_Width-20; hgcd[0].gd.pos.height = gcd[j-1].gd.pos.y+10;
3178 	hgcd[0].gd.flags = gg_visible | gg_enabled | gg_list_multiplesel;
3179 	hgcd[0].gd.cid = CID_HintMask;
3180 	hgcd[0].gd.u.list = SCHintList(cv->b.sc,NULL);
3181 	hgcd[0].gd.handle_controlevent = PI_HintSel;
3182 	hgcd[0].creator = GListCreate;
3183 
3184 	h2gcd[0].gd.pos.x = 5; h2gcd[0].gd.pos.y = 5;
3185 	h2gcd[0].gd.pos.width = PI_Width-20; h2gcd[0].gd.pos.height = gcd[j-1].gd.pos.y+10;
3186 	h2gcd[0].gd.flags = gg_visible | gg_list_multiplesel;
3187 	h2gcd[0].gd.cid = CID_ActiveHints;
3188 	h2gcd[0].gd.u.list = SCHintList(cv->b.sc,NULL);
3189 	h2gcd[0].creator = GListCreate;
3190 
3191 	j = 0;
3192 
3193 	aspects[j].text = (unichar_t *) _("Location");
3194 	aspects[j].text_is_1byte = true;
3195 	aspects[j++].gcd = pb;
3196 
3197 	aspects[j].text = (unichar_t *) _("Hint Mask");
3198 	aspects[j].text_is_1byte = true;
3199 	aspects[j++].gcd = hgcd;
3200 
3201 	aspects[j].text = (unichar_t *) _("Active Hints");
3202 	aspects[j].text_is_1byte = true;
3203 	aspects[j++].gcd = h2gcd;
3204 
3205 	j = 0;
3206 
3207 	mgcd[j].gd.pos.x = 4; mgcd[j].gd.pos.y = 6;
3208 	mgcd[j].gd.pos.width = PI_Width-8;
3209 	mgcd[j].gd.pos.height = hgcd[0].gd.pos.height+10+24;
3210 	mgcd[j].gd.u.tabs = aspects;
3211 	mgcd[j].gd.flags = gg_visible | gg_enabled;
3212 	mgcd[j].gd.handle_controlevent = PI_AspectChange;
3213 	mgcd[j].gd.cid = CID_TabSet;
3214 	mgcd[j++].creator = GTabSetCreate;
3215 
3216 	mgcd[j].gd.pos.x = (PI_Width-2*50-10)/2; mgcd[j].gd.pos.y = mgcd[j-1].gd.pos.y+mgcd[j-1].gd.pos.height+5;
3217 	mgcd[j].gd.pos.width = 53; mgcd[j].gd.pos.height = 0;
3218 	mgcd[j].gd.flags = gg_visible | gg_enabled;
3219 	mlabel[j].text = (unichar_t *) _("< _Prev");
3220 	mlabel[j].text_is_1byte = true;
3221 	mlabel[j].text_in_resource = true;
3222 	mgcd[j].gd.label = &mlabel[j];
3223 	mgcd[j].gd.cid = CID_Prev;
3224 	mgcd[j].gd.handle_controlevent = PI_NextPrev;
3225 	mgcd[j].creator = GButtonCreate;
3226 	++j;
3227 
3228 	mgcd[j].gd.pos.x = PI_Width-50-(PI_Width-2*50-10)/2; mgcd[j].gd.pos.y = mgcd[j-1].gd.pos.y;
3229 	mgcd[j].gd.pos.width = 53; mgcd[j].gd.pos.height = 0;
3230 	mgcd[j].gd.flags = gg_visible | gg_enabled;
3231 	mlabel[j].text = (unichar_t *) _("_Next >");
3232 	mlabel[j].text_is_1byte = true;
3233 	mlabel[j].text_in_resource = true;
3234 	mgcd[j].gd.label = &mlabel[j];
3235 	mgcd[j].gd.cid = CID_Next;
3236 	mgcd[j].gd.handle_controlevent = PI_NextPrev;
3237 	mgcd[j].creator = GButtonCreate;
3238 	++j;
3239 
3240 /* Why 3? */
3241 	mgcd[j].gd.pos.x = mgcd[j-2].gd.pos.x-50+3; mgcd[j].gd.pos.y = mgcd[j-1].gd.pos.y+26;
3242 	mgcd[j].gd.flags = gg_visible | gg_enabled;
3243 	mlabel[j].text = (unichar_t *) _("Prev On Contour");
3244 	mlabel[j].text_is_1byte = true;
3245 	mgcd[j].gd.label = &mlabel[j];
3246 	mgcd[j].gd.cid = CID_PrevC;
3247 	mgcd[j].gd.handle_controlevent = PI_NextPrev;
3248 	mgcd[j].creator = GButtonCreate;
3249 	++j;
3250 
3251 	mgcd[j].gd.pos.x = mgcd[j-2].gd.pos.x; mgcd[j].gd.pos.y = mgcd[j-1].gd.pos.y;
3252 	mgcd[j].gd.flags = gg_visible | gg_enabled;
3253 	mlabel[j].text = (unichar_t *) _("Next On Contour");
3254 	mlabel[j].text_is_1byte = true;
3255 	mgcd[j].gd.label = &mlabel[j];
3256 	mgcd[j].gd.cid = CID_NextC;
3257 	mgcd[j].gd.handle_controlevent = PI_NextPrev;
3258 	mgcd[j].creator = GButtonCreate;
3259 	++j;
3260 
3261 	mgcd[j].gd.pos.x = 5; mgcd[j].gd.pos.y = mgcd[j-1].gd.pos.y+28;
3262 	mgcd[j].gd.pos.width = PI_Width-10;
3263 	mgcd[j].gd.flags = gg_enabled|gg_visible;
3264 	mgcd[j].creator = GLineCreate;
3265 	++j;
3266 
3267 	mgcd[j].gd.pos.x = 20-3; mgcd[j].gd.pos.y = PI_Height-33-3;
3268 	mgcd[j].gd.pos.width = -1; mgcd[j].gd.pos.height = 0;
3269 	mgcd[j].gd.flags = gg_visible | gg_enabled | gg_but_default;
3270 	mlabel[j].text = (unichar_t *) _("_OK");
3271 	mlabel[j].text_is_1byte = true;
3272 	mlabel[j].text_in_resource = true;
3273 	mgcd[j].gd.mnemonic = 'O';
3274 	mgcd[j].gd.label = &mlabel[j];
3275 	mgcd[j].gd.handle_controlevent = PI_Ok;
3276 	mgcd[j].creator = GButtonCreate;
3277 	++j;
3278 
3279 	mgcd[j].gd.pos.x = -20; mgcd[j].gd.pos.y = PI_Height-33;
3280 	mgcd[j].gd.pos.width = -1; mgcd[j].gd.pos.height = 0;
3281 	mgcd[j].gd.flags = gg_visible | gg_enabled | gg_but_cancel;
3282 	mlabel[j].text = (unichar_t *) _("_Cancel");
3283 	mlabel[j].text_is_1byte = true;
3284 	mlabel[j].text_in_resource = true;
3285 	mgcd[j].gd.label = &mlabel[j];
3286 	mgcd[j].gd.mnemonic = 'C';
3287 	mgcd[j].gd.handle_controlevent = PI_Cancel;
3288 	mgcd[j].creator = GButtonCreate;
3289 	++j;
3290 
3291 	marray[0] = &mgcd[0]; marray[1] = NULL;
3292 	marray[2] = &mb[2]; marray[3] = NULL;
3293 	marray[4] = &mb[3]; marray[5] = NULL;
3294 	marray[6] = &mgcd[5]; marray[7] = NULL;
3295 	marray[8] = &mb[4]; marray[9] = NULL;
3296 	marray[10] = NULL;
3297 	marray2[0] = GCD_Glue; marray2[1] = &mgcd[1]; marray2[2] = &mgcd[2]; marray2[3] = GCD_Glue; marray2[4] = NULL;
3298 	marray3[0] = GCD_Glue; marray3[1] = &mgcd[3]; marray3[2] = &mgcd[4]; marray3[3] = GCD_Glue; marray3[4] = NULL;
3299 	marray4[0] = GCD_Glue; marray4[1] = &mgcd[6]; marray4[2] = GCD_Glue; marray4[3] = GCD_Glue; marray4[4] = &mgcd[7]; marray4[5] = GCD_Glue; marray4[6] = NULL;
3300 
3301 	memset(mb,0,sizeof(mb));
3302 	mb[0].gd.pos.x = mb[0].gd.pos.y = 2;
3303 	mb[0].gd.flags = gg_enabled|gg_visible;
3304 	mb[0].gd.u.boxelements = marray;
3305 	mb[0].creator = GHVGroupCreate;
3306 
3307 	mb[2].gd.flags = gg_enabled|gg_visible;
3308 	mb[2].gd.u.boxelements = marray2;
3309 	mb[2].creator = GHBoxCreate;
3310 
3311 	mb[3].gd.flags = gg_enabled|gg_visible;
3312 	mb[3].gd.u.boxelements = marray3;
3313 	mb[3].creator = GHBoxCreate;
3314 
3315 	mb[4].gd.flags = gg_enabled|gg_visible;
3316 	mb[4].gd.u.boxelements = marray4;
3317 	mb[4].creator = GHBoxCreate;
3318 
3319 	GGadgetsCreate(gi->gw,mb);
3320 	gi->group1ret = pb[4].ret; gi->group2ret = pb[5].ret;
3321 	memcpy( gi->gcd, gcd, gcdcount*sizeof(GGadgetCreateData) ); // This copies pointers, but only to static things.
3322 	GTextInfoListFree(hgcd[0].gd.u.list);
3323 	GTextInfoListFree(h2gcd[0].gd.u.list);
3324 
3325 	GHVBoxSetExpandableRow(mb[0].ret,0);
3326 	GHVBoxSetExpandableCol(mb[2].ret,gb_expandgluesame);
3327 	GHVBoxSetExpandableCol(mb[3].ret,gb_expandgluesame);
3328 	GHVBoxSetExpandableCol(mb[4].ret,gb_expandgluesame);
3329 	GHVBoxSetExpandableRow(pb[0].ret,gb_expandglue);
3330 	GHVBoxSetExpandableCol(pb[2].ret,gb_expandglue);
3331 	GHVBoxSetExpandableCol(pb[3].ret,gb_expandglue);
3332 	GHVBoxSetExpandableCol(pb[4].ret,gb_expandglue);
3333 	GHVBoxSetExpandableCol(pb[5].ret,gb_expandglue);
3334 	GHVBoxSetExpandableCol(pb[6].ret,gb_expandglue);
3335 	GHVBoxSetExpandableCol(pb[7].ret,gb_expandglue);
3336 
3337 	PIChangePoint(gi);
3338 
3339 	GHVBoxFitWindow(mb[0].ret);
3340 
3341 	dlist_pushfront( &cv->pointInfoDialogs, (struct dlistnode *)gi );
3342 	GWidgetHidePalettes();
3343 	GDrawResize(gi->gw,
3344 		    GGadgetScale(GDrawPointsToPixels(NULL,PI_Width)),
3345 		    GDrawPointsToPixels(NULL,PI_Height));
3346 	GDrawSetVisible(gi->gw,true);
3347 }
3348 
3349 /* ************************************************************************** */
3350 /* ****************************** Spiro Points ****************************** */
3351 /* ************************************************************************** */
3352 
SpiroFillup(GIData * ci,int except_cid)3353 static void SpiroFillup(GIData *ci, int except_cid) {
3354     char buffer[50];
3355     int ty;
3356 
3357     mysprintf(buffer, "%.2f", ci->curcp->x );
3358     if ( except_cid!=CID_BaseX )
3359 	GGadgetSetTitle8(GWidgetGetControl(ci->gw,CID_BaseX),buffer);
3360 
3361     mysprintf(buffer, "%.2f", ci->curcp->y );
3362     if ( except_cid!=CID_BaseY )
3363 	GGadgetSetTitle8(GWidgetGetControl(ci->gw,CID_BaseY),buffer);
3364 
3365     ty = ci->curcp->ty&0x7f;
3366     if ( ty == SPIRO_OPEN_CONTOUR )
3367 	ty = SPIRO_G4;
3368     GGadgetSetChecked(GWidgetGetControl(ci->gw,CID_Curve), ty==SPIRO_G4 );
3369     GGadgetSetChecked(GWidgetGetControl(ci->gw,CID_Tangent), ty==SPIRO_G2 );
3370     GGadgetSetChecked(GWidgetGetControl(ci->gw,CID_Corner), ty==SPIRO_CORNER );
3371     GGadgetSetChecked(GWidgetGetControl(ci->gw,CID_SpiroLeft), ty==SPIRO_LEFT );
3372     GGadgetSetChecked(GWidgetGetControl(ci->gw,CID_SpiroRight), ty==SPIRO_RIGHT );
3373 }
3374 
SpiroChangePoint(GIData * ci)3375 static void SpiroChangePoint(GIData *ci) {
3376 
3377     SpiroFillup(ci,0);
3378 }
3379 
PI_SpiroNextPrev(GGadget * g,GEvent * e)3380 static int PI_SpiroNextPrev(GGadget *g, GEvent *e) {
3381     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
3382 	GIData *ci = GDrawGetUserData(GGadgetGetWindow(g));
3383 	CharView *cv = ci->cv;
3384 	int cid = GGadgetGetCid(g);
3385 	SplinePointList *spl;
3386 	int index = ci->curcp - ci->curspl->spiros;
3387 	BasePoint here;
3388 
3389 	SPIRO_DESELECT(ci->curcp);
3390 	if ( cid == CID_Next ) {
3391 	    if ( index < ci->curspl->spiro_cnt-2 )
3392 		ci->curcp = &ci->curspl->spiros[index+1];
3393 	    else {
3394 		if ( ci->curspl->next == NULL ) {
3395 		    ci->curspl = cv->b.layerheads[cv->b.drawmode]->splines;
3396 		    GDrawBeep(NULL);
3397 		} else
3398 		    ci->curspl = ci->curspl->next;
3399 		ci->curcp = &ci->curspl->spiros[0];
3400 	    }
3401 	} else if ( cid == CID_Prev ) {
3402 	    if ( index!=0 ) {
3403 		ci->curcp = &ci->curspl->spiros[index-1];
3404 	    } else {
3405 		if ( ci->curspl==cv->b.layerheads[cv->b.drawmode]->splines ) {
3406 		    for ( spl = cv->b.layerheads[cv->b.drawmode]->splines; spl->next!=NULL; spl=spl->next );
3407 		    GDrawBeep(NULL);
3408 		} else {
3409 		    for ( spl = cv->b.layerheads[cv->b.drawmode]->splines; spl->next!=ci->curspl; spl=spl->next );
3410 		}
3411 		ci->curspl = spl;
3412 		ci->curcp = &ci->curspl->spiros[ci->curspl->spiro_cnt-2];
3413 	    }
3414 	} else if ( cid==CID_NextC ) {
3415 	    if ( index < ci->curspl->spiro_cnt-2 )
3416 		ci->curcp = &ci->curspl->spiros[index+1];
3417 	    else {
3418 		ci->curcp = &ci->curspl->spiros[0];
3419 		GDrawBeep(NULL);
3420 	    }
3421 	} else /* CID_PrevC */ {
3422 	    if ( index!=0 )
3423 		ci->curcp = &ci->curspl->spiros[index-1];
3424 	    else {
3425 		ci->curcp = &ci->curspl->spiros[ci->curspl->spiro_cnt-2];
3426 		GDrawBeep(NULL);
3427 	    }
3428 	}
3429 	SPIRO_SELECT(ci->curcp);
3430 	SpiroChangePoint(ci);
3431 	here.x = ci->curcp->x; here.y = ci->curcp->y;
3432 	CVShowPoint(cv,&here);
3433 	SCUpdateAll(cv->b.sc);
3434     }
3435 return( true );
3436 }
3437 
PI_SpiroChanged(GGadget * g,GEvent * e)3438 static int PI_SpiroChanged(GGadget *g, GEvent *e) {
3439     if ( e->type==et_controlevent &&
3440 	    (e->u.control.subtype == et_textchanged ||
3441 	     e->u.control.subtype == et_radiochanged)) {
3442 	GIData *ci = GDrawGetUserData(GGadgetGetWindow(g));
3443 	double x,y;
3444 	int ty;
3445 	int err=false;
3446 	spiro_cp *curcp = ci->curcp;
3447 
3448 	x = GetCalmReal8(ci->gw,CID_BaseX,_("X"),&err);
3449 	y = GetCalmReal8(ci->gw,CID_BaseY,_("Y"),&err);
3450 	ty = GGadgetIsChecked(GWidgetGetControl(ci->gw,CID_Curve))? SPIRO_G4 :
3451 	     GGadgetIsChecked(GWidgetGetControl(ci->gw,CID_Tangent))? SPIRO_G2 :
3452 	     GGadgetIsChecked(GWidgetGetControl(ci->gw,CID_Corner))? SPIRO_CORNER :
3453 	     GGadgetIsChecked(GWidgetGetControl(ci->gw,CID_SpiroLeft))? SPIRO_LEFT :
3454 		     SPIRO_RIGHT;
3455 	curcp->x = x;
3456 	curcp->y = y;
3457 	curcp->ty = ty | 0x80;
3458 	SSRegenerateFromSpiros(ci->curspl);
3459 	CVCharChangedUpdate(&ci->cv->b);
3460     }
3461 return( true );
3462 }
3463 
PI_SpiroDoOk(GIData * ci)3464 static void PI_SpiroDoOk(GIData *ci) {
3465 	ci->done = true;
3466 	/* All the work has been done as we've gone along */
3467 	PI_Close(ci);
3468 }
3469 
PI_SpiroOk(GGadget * g,GEvent * e)3470 static int PI_SpiroOk(GGadget *g, GEvent *e) {
3471     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
3472 	GIData *ci = GDrawGetUserData(GGadgetGetWindow(g));
3473 	PI_SpiroDoOk(ci);
3474     }
3475     return( true );
3476 }
3477 
spi_e_h(GWindow gw,GEvent * event)3478 static int spi_e_h(GWindow gw, GEvent *event) {
3479     if ( event->type==et_close ) {
3480 	PI_SpiroDoOk(GDrawGetUserData(gw));
3481     } else if ( event->type==et_char ) {
3482 	if ( event->u.chr.keysym == GK_F1 || event->u.chr.keysym == GK_Help ) {
3483 	    help("ui/dialogs/getinfo.html", NULL);
3484 return( true );
3485 	}
3486 return( false );
3487     } else if ( event->type == et_map ) {
3488 	/* Above palettes */
3489 	GDrawRaise(gw);
3490     }
3491 return( true );
3492 }
3493 
SpiroPointGetInfo(CharView * cv,spiro_cp * scp,SplinePointList * spl)3494 static void SpiroPointGetInfo(CharView *cv, spiro_cp *scp, SplinePointList *spl) {
3495     CharViewTab* tab = CVGetActiveTab(cv);
3496     GIData *gip = calloc(1, sizeof(GIData));
3497     GRect pos;
3498     GWindowAttrs wattrs;
3499     GGadgetCreateData gcd[20];
3500     GGadgetCreateData pb[9];
3501     GGadgetCreateData *varray[20], *harray2[10], *harray3[15], *harray4[6],
3502 	    *harray5[6], *harray6[9];
3503     GTextInfo label[20];
3504     GWindow root;
3505     GRect screensize;
3506     GPoint pt;
3507     int j,k;
3508 
3509     gip->cv = cv;
3510     gip->sc = cv->b.sc;
3511     gip->curcp = scp;
3512     gip->curspl = spl;
3513     gip->oldstate = SplinePointListCopy(cv->b.layerheads[cv->b.drawmode]->splines);
3514     gip->done = false;
3515     CVPreserveState(&cv->b);
3516 
3517     root = GDrawGetRoot(NULL);
3518     GDrawGetSize(root,&screensize);
3519 
3520 	memset(&wattrs,0,sizeof(wattrs));
3521 	wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_positioned|wam_isdlg|wam_restrict;
3522 	wattrs.event_masks = ~(1<<et_charup);
3523 	wattrs.restrict_input_to_me = 1;
3524 	wattrs.positioned = 1;
3525 	wattrs.cursor = ct_pointer;
3526 	wattrs.utf8_window_title = _("Spiro Point Info");
3527 	wattrs.is_dlg = true;
3528 	pos.width = GGadgetScale(GDrawPointsToPixels(NULL,PI_Width));
3529 	pos.height = GDrawPointsToPixels(NULL,PI_Height);
3530 	pt.x = tab->xoff + rint(scp->x*tab->scale);
3531 	pt.y = -tab->yoff + cv->height - rint(scp->y*tab->scale);
3532 	GDrawTranslateCoordinates(cv->v,root,&pt);
3533 	if ( pt.x+20+pos.width<=screensize.width )
3534 	    pos.x = pt.x+20;
3535 	else if ( (pos.x = pt.x-10-screensize.width)<0 )
3536 	    pos.x = 0;
3537 	pos.y = pt.y;
3538 	if ( pos.y+pos.height+20 > screensize.height )
3539 	    pos.y = screensize.height - pos.height - 20;
3540 	if ( pos.y<0 ) pos.y = 0;
3541 	gip->gw = GDrawCreateTopWindow(NULL,&pos,spi_e_h,gip,&wattrs);
3542 
3543 	memset(&gcd,0,sizeof(gcd));
3544 	memset(&label,0,sizeof(label));
3545 	memset(&pb,0,sizeof(pb));
3546 
3547 	j=k=0;
3548 	gip->gcd = gcd;
3549 
3550 	label[j].text = (unichar_t *) _("_X:");
3551 	label[j].text_is_1byte = true;
3552 	label[j].text_in_resource = true;
3553 	gcd[j].gd.label = &label[j];
3554 	gcd[j].gd.flags = gg_enabled|gg_visible;
3555 	gcd[j].creator = GLabelCreate;
3556 	harray2[0] = &gcd[j]; harray2[1] = GCD_Glue;
3557 	++j;
3558 
3559 	gcd[j].gd.pos.x = 60; gcd[j].gd.pos.y = gcd[j-1].gd.pos.y-6; gcd[j].gd.pos.width = 70;
3560 	gcd[j].gd.flags = gg_enabled|gg_visible;
3561 	gcd[j].gd.cid = CID_BaseX;
3562 	gcd[j].gd.handle_controlevent = PI_SpiroChanged;
3563 	gcd[j].creator = GNumericFieldCreate;
3564 	harray2[2] = &gcd[j]; harray2[3] = GCD_Glue; harray2[4] = GCD_Glue;
3565 	++j;
3566 
3567 	label[j].text = (unichar_t *) _("_Y:");
3568 	label[j].text_is_1byte = true;
3569 	label[j].text_in_resource = true;
3570 	gcd[j].gd.label = &label[j];
3571 	gcd[j].gd.flags = gg_enabled|gg_visible;
3572 	gcd[j].creator = GLabelCreate;
3573 	harray2[5] = &gcd[j]; harray2[6] = GCD_Glue;
3574 	++j;
3575 
3576 	gcd[j].gd.pos.x = 137; gcd[j].gd.pos.y = gcd[j-1].gd.pos.y; gcd[j].gd.pos.width = 70;
3577 	gcd[j].gd.flags = gg_enabled|gg_visible;
3578 	gcd[j].gd.cid = CID_BaseY;
3579 	gcd[j].gd.handle_controlevent = PI_SpiroChanged;
3580 	gcd[j].creator = GNumericFieldCreate;
3581 	harray2[7] = &gcd[j]; harray2[8] = NULL;
3582 	++j;
3583 
3584 	pb[2].gd.flags = gg_enabled|gg_visible;
3585 	pb[2].gd.u.boxelements = harray2;
3586 	pb[2].creator = GHBoxCreate;
3587 	varray[k++] = &pb[2]; varray[k++] = NULL;
3588 
3589 	label[j].text = (unichar_t *) _("Type:");
3590 	label[j].text_is_1byte = true;
3591 	gcd[j].gd.label = &label[j];
3592 	gcd[j].gd.pos.x = gcd[0].gd.pos.x;
3593 	gcd[j].gd.flags = gg_enabled|gg_visible;
3594 	gcd[j].creator = GLabelCreate;
3595 	harray3[0] = &gcd[j]; harray3[1] = GCD_Glue; harray3[2] = GCD_Glue;
3596 	++j;
3597 
3598 	label[j].image = &GIcon_smallspirocurve;
3599 	gcd[j].gd.label = &label[j];
3600 	gcd[j].gd.pos.x = 60; gcd[j].gd.pos.y = gcd[j-1].gd.pos.y-2;
3601 	gcd[j].gd.flags = gg_enabled|gg_visible;
3602 	gcd[j].gd.cid = CID_Curve;
3603 	gcd[j].gd.handle_controlevent = PI_SpiroChanged;
3604 	gcd[j].creator = GRadioCreate;
3605 	harray3[3] = &gcd[j]; harray3[4] = GCD_Glue;
3606 	++j;
3607 
3608 	label[j].image = &GIcon_smallspirog2curve;
3609 	gcd[j].gd.label = &label[j];
3610 	gcd[j].gd.pos.x = 60; gcd[j].gd.pos.y = gcd[j-1].gd.pos.y-2;
3611 	gcd[j].gd.flags = gg_enabled|gg_visible;
3612 	gcd[j].gd.cid = CID_Tangent;
3613 	gcd[j].gd.handle_controlevent = PI_SpiroChanged;
3614 	gcd[j].creator = GRadioCreate;
3615 	harray3[5] = &gcd[j]; harray3[6] = GCD_Glue;
3616 	++j;
3617 
3618 	label[j].image = &GIcon_smallspirocorner;
3619 	gcd[j].gd.label = &label[j];
3620 	gcd[j].gd.pos.x = 100; gcd[j].gd.pos.y = gcd[j-1].gd.pos.y;
3621 	gcd[j].gd.flags = gg_enabled|gg_visible | gg_rad_continueold;
3622 	gcd[j].gd.cid = CID_Corner;
3623 	gcd[j].gd.handle_controlevent = PI_SpiroChanged;
3624 	gcd[j].creator = GRadioCreate;
3625 	harray3[7] = &gcd[j]; harray3[8] = GCD_Glue;
3626 	++j;
3627 
3628 	label[j].image = &GIcon_smallspiroleft;
3629 	gcd[j].gd.label = &label[j];
3630 	gcd[j].gd.pos.x = 140; gcd[j].gd.pos.y = gcd[j-1].gd.pos.y;
3631 	gcd[j].gd.flags = gg_enabled|gg_visible | gg_rad_continueold;
3632 	gcd[j].gd.cid = CID_SpiroLeft;
3633 	gcd[j].gd.handle_controlevent = PI_SpiroChanged;
3634 	gcd[j].creator = GRadioCreate;
3635 	harray3[9] = &gcd[j]; harray3[10] = GCD_Glue;
3636 	++j;
3637 
3638 	label[j].image = &GIcon_smallspiroright;
3639 	gcd[j].gd.label = &label[j];
3640 	gcd[j].gd.pos.x = 140; gcd[j].gd.pos.y = gcd[j-1].gd.pos.y;
3641 	gcd[j].gd.flags = gg_enabled|gg_visible | gg_rad_continueold;
3642 	gcd[j].gd.cid = CID_SpiroRight;
3643 	gcd[j].gd.handle_controlevent = PI_SpiroChanged;
3644 	gcd[j].creator = GRadioCreate;
3645 	harray3[11] = &gcd[j]; harray3[12] = GCD_Glue; harray3[13] = GCD_Glue;
3646 	harray3[14] = NULL;
3647 	++j;
3648 
3649 	pb[3].gd.flags = gg_enabled|gg_visible;
3650 	pb[3].gd.u.boxelements = harray3;
3651 	pb[3].creator = GHBoxCreate;
3652 	varray[k++] = &pb[3];
3653 	varray[k++] = NULL;
3654 	varray[k++] = GCD_Glue;
3655 	varray[k++] = NULL;
3656 
3657 	gcd[j].gd.flags = gg_visible | gg_enabled;
3658 	label[j].text = (unichar_t *) _("< _Prev");
3659 	label[j].text_is_1byte = true;
3660 	label[j].text_in_resource = true;
3661 	gcd[j].gd.label = &label[j];
3662 	gcd[j].gd.cid = CID_Prev;
3663 	gcd[j].gd.handle_controlevent = PI_SpiroNextPrev;
3664 	gcd[j].creator = GButtonCreate;
3665 	harray4[0] = GCD_Glue; harray4[1] = &gcd[j];
3666 	++j;
3667 
3668 	gcd[j].gd.flags = gg_visible | gg_enabled;
3669 	label[j].text = (unichar_t *) _("_Next >");
3670 	label[j].text_is_1byte = true;
3671 	label[j].text_in_resource = true;
3672 	gcd[j].gd.label = &label[j];
3673 	gcd[j].gd.cid = CID_Next;
3674 	gcd[j].gd.handle_controlevent = PI_SpiroNextPrev;
3675 	gcd[j].creator = GButtonCreate;
3676 	harray4[2] = &gcd[j]; harray4[3] = GCD_Glue; harray4[4] = NULL;
3677 	++j;
3678 
3679 	pb[4].gd.flags = gg_enabled|gg_visible;
3680 	pb[4].gd.u.boxelements = harray4;
3681 	pb[4].creator = GHBoxCreate;
3682 	varray[k++] = &pb[4];
3683 	varray[k++] = NULL;
3684 
3685 	gcd[j].gd.flags = gg_visible | gg_enabled;
3686 	label[j].text = (unichar_t *) _("Prev On Contour");
3687 	label[j].text_is_1byte = true;
3688 	gcd[j].gd.label = &label[j];
3689 	gcd[j].gd.cid = CID_PrevC;
3690 	gcd[j].gd.handle_controlevent = PI_SpiroNextPrev;
3691 	gcd[j].creator = GButtonCreate;
3692 	harray5[0] = GCD_Glue; harray5[1] = &gcd[j];
3693 	++j;
3694 
3695 	gcd[j].gd.flags = gg_visible | gg_enabled;
3696 	label[j].text = (unichar_t *) _("Next On Contour");
3697 	label[j].text_is_1byte = true;
3698 	gcd[j].gd.label = &label[j];
3699 	gcd[j].gd.cid = CID_NextC;
3700 	gcd[j].gd.handle_controlevent = PI_SpiroNextPrev;
3701 	gcd[j].creator = GButtonCreate;
3702 	harray5[2] = &gcd[j]; harray5[3] = GCD_Glue; harray5[4] = NULL;
3703 	++j;
3704 
3705 	pb[5].gd.flags = gg_enabled|gg_visible;
3706 	pb[5].gd.u.boxelements = harray5;
3707 	pb[5].creator = GHBoxCreate;
3708 	varray[k++] = &pb[5];
3709 	varray[k++] = NULL;
3710 
3711 	gcd[j].gd.pos.x = 5; gcd[j].gd.pos.y = gcd[j-1].gd.pos.y+28;
3712 	gcd[j].gd.pos.width = PI_Width-10;
3713 	gcd[j].gd.flags = gg_enabled|gg_visible;
3714 	gcd[j].creator = GLineCreate;
3715 	++j;
3716 	varray[k++] = &gcd[j-1];
3717 	varray[k++] = NULL;
3718 	varray[k++] = GCD_Glue;
3719 	varray[k++] = NULL;
3720 
3721 	gcd[j].gd.pos.x = 20-3; gcd[j].gd.pos.y = PI_Height-33-3;
3722 	gcd[j].gd.flags = gg_visible | gg_enabled | gg_but_default;
3723 	label[j].text = (unichar_t *) _("_OK");
3724 	label[j].text_is_1byte = true;
3725 	label[j].text_in_resource = true;
3726 	gcd[j].gd.mnemonic = 'O';
3727 	gcd[j].gd.label = &label[j];
3728 	gcd[j].gd.handle_controlevent = PI_SpiroOk;
3729 	gcd[j].creator = GButtonCreate;
3730 	harray6[0] = GCD_Glue; harray6[1] = &gcd[j]; harray6[2] = GCD_Glue; harray6[3] = GCD_Glue;
3731 	++j;
3732 
3733 	gcd[j].gd.pos.x = -20; gcd[j].gd.pos.y = PI_Height-33;
3734 	gcd[j].gd.flags = gg_visible | gg_enabled | gg_but_cancel;
3735 	label[j].text = (unichar_t *) _("_Cancel");
3736 	label[j].text_is_1byte = true;
3737 	label[j].text_in_resource = true;
3738 	gcd[j].gd.label = &label[j];
3739 	gcd[j].gd.mnemonic = 'C';
3740 	gcd[j].gd.handle_controlevent = PI_Cancel;
3741 	gcd[j].creator = GButtonCreate;
3742 	harray6[4] = GCD_Glue; harray6[5] = &gcd[j]; harray6[6] = GCD_Glue; harray6[7] = NULL;
3743 	++j;
3744 
3745 	pb[6].gd.flags = gg_enabled|gg_visible;
3746 	pb[6].gd.u.boxelements = harray6;
3747 	pb[6].creator = GHBoxCreate;
3748 	varray[k++] = &pb[6];
3749 	varray[k++] = NULL;
3750 	varray[k++] = NULL;
3751 
3752 	pb[0].gd.pos.x = pb[0].gd.pos.y = 2;
3753 	pb[0].gd.flags = gg_enabled|gg_visible;
3754 	pb[0].gd.u.boxelements = varray;
3755 	pb[0].creator = GHVGroupCreate;
3756 
3757 	GGadgetsCreate(gip->gw,pb);
3758 
3759 	GHVBoxSetExpandableRow(pb[0].ret,gb_expandglue);
3760 	GHVBoxSetExpandableCol(pb[2].ret,gb_expandglue);
3761 	GHVBoxSetExpandableCol(pb[3].ret,gb_expandglue);
3762 	GHVBoxSetExpandableCol(pb[4].ret,gb_expandglue);
3763 	GHVBoxSetExpandableCol(pb[5].ret,gb_expandglue);
3764 	GHVBoxSetExpandableCol(pb[6].ret,gb_expandgluesame);
3765 
3766 	SpiroChangePoint(gip);
3767 
3768 	GHVBoxFitWindow(pb[0].ret);
3769 
3770     GWidgetHidePalettes();
3771     GDrawSetVisible(gip->gw,true);
3772     while ( !gip->done )
3773 	GDrawProcessOneEvent(NULL);
3774 }
3775 
CVGetInfo(CharView * cv)3776 void CVGetInfo(CharView *cv) {
3777     SplinePoint *sp;
3778     SplinePointList *spl;
3779     RefChar *ref;
3780     ImageList *img;
3781     AnchorPoint *ap;
3782     spiro_cp *scp;
3783 
3784     if ( !CVOneThingSel(cv,&sp,&spl,&ref,&img,&ap,&scp)) {
3785     } else if ( ref!=NULL )
3786 	RefGetInfo(cv,ref);
3787     else if ( img!=NULL )
3788 	ImgGetInfo(cv,img);
3789     else if ( ap!=NULL )
3790 	ApGetInfo(cv,ap);
3791     else if ( scp!=NULL )
3792 	SpiroPointGetInfo(cv,scp,spl);
3793     else
3794 	PointGetInfo(cv,sp,spl);
3795 }
3796 
CVPGetInfo(CharView * cv)3797 void CVPGetInfo(CharView *cv) {
3798 
3799     if ( cv->p.ref!=NULL )
3800 	RefGetInfo(cv,cv->p.ref);
3801     else if ( cv->p.img!=NULL )
3802 	ImgGetInfo(cv,cv->p.img);
3803     else if ( cv->p.ap!=NULL )
3804 	ApGetInfo(cv,cv->p.ap);
3805     else if ( cv->p.sp!=NULL )
3806 	PointGetInfo(cv,cv->p.sp,cv->p.spl);
3807     else if ( cv->p.spiro!=NULL )
3808 	SpiroPointGetInfo(cv,cv->p.spiro,cv->p.spl);
3809 }
3810 
SCRefBy(SplineChar * sc)3811 void SCRefBy(SplineChar *sc) {
3812     int cnt,i,tot=0;
3813     char **deps = NULL;
3814     struct splinecharlist *d;
3815     char *buts[3];
3816 
3817     buts[0] = _("_Show");
3818     buts[1] = _("_Cancel");
3819     buts[2] = NULL;
3820 
3821     for ( i=0; i<2; ++i ) {
3822 	cnt = 0;
3823 	for ( d = sc->dependents; d!=NULL; d=d->next ) {
3824 	    if ( deps!=NULL )
3825 		deps[tot-cnt] = copy(d->sc->name);
3826 	    ++cnt;
3827 	}
3828 	if ( cnt==0 )
3829 return;
3830 	if ( i==0 )
3831 	    deps = calloc(cnt+1,sizeof(unichar_t *));
3832 	tot = cnt-1;
3833     }
3834 
3835     i = gwwv_choose_with_buttons(_("Dependents"),(const char **) deps, cnt, 0, buts, _("Dependents") );
3836     if ( i!=-1 ) {
3837 	i = tot-i;
3838 	for ( d = sc->dependents, cnt=0; d!=NULL && cnt<i; d=d->next, ++cnt );
3839 	CharViewCreate(d->sc,(FontView *) (sc->parent->fv),-1);
3840     }
3841     for ( i=0; i<=tot; ++i )
3842 	free( deps[i] );
3843     free(deps);
3844 }
3845 
UsedIn(char * name,char * subs)3846 static int UsedIn(char *name, char *subs) {
3847     int nlen = strlen( name );
3848     while ( *subs!='\0' ) {
3849 	if ( strncmp(subs,name,nlen)==0 && (subs[nlen]==' ' || subs[nlen]=='\0'))
3850 return( true );
3851 	while ( *subs!=' ' && *subs!='\0' ) ++subs;
3852 	while ( *subs==' ' ) ++subs;
3853     }
3854 return( false );
3855 }
3856 
SCUsedBySubs(SplineChar * sc)3857 int SCUsedBySubs(SplineChar *sc) {
3858     int k, i;
3859     SplineFont *_sf, *sf;
3860     PST *pst;
3861 
3862     if ( sc==NULL )
3863 return( false );
3864 
3865     _sf = sc->parent;
3866     if ( _sf->cidmaster!=NULL ) _sf=_sf->cidmaster;
3867     k=0;
3868     do {
3869 	sf = _sf->subfontcnt==0 ? _sf : _sf->subfonts[k];
3870 	for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL ) {
3871 	    for ( pst=sf->glyphs[i]->possub; pst!=NULL; pst=pst->next ) {
3872 		if ( pst->type==pst_substitution || pst->type==pst_alternate ||
3873 			pst->type==pst_multiple || pst->type==pst_ligature )
3874 		    if ( UsedIn(sc->name,pst->u.mult.components))
3875 return( true );
3876 	    }
3877 	}
3878 	++k;
3879     } while ( k<_sf->subfontcnt );
3880 return( false );
3881 }
3882 
SCSubBy(SplineChar * sc)3883 void SCSubBy(SplineChar *sc) {
3884     int i,j,k,tot;
3885     char **deps = NULL;
3886     SplineChar **depsc;
3887     char ubuf[200];
3888     SplineFont *sf, *_sf;
3889     PST *pst;
3890     char *buts[3];
3891 
3892     buts[0] = _("Show");
3893     buts[1] = _("_Cancel");
3894     buts[2] = NULL;
3895 
3896     if ( sc==NULL )
3897 return;
3898 
3899     _sf = sc->parent;
3900     if ( _sf->cidmaster!=NULL ) _sf=_sf->cidmaster;
3901     for ( j=0; j<2; ++j ) {
3902 	tot = 0;
3903 	k=0;
3904 	do {
3905 	    sf = _sf->subfontcnt==0 ? _sf : _sf->subfonts[k];
3906 	    for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL ) {
3907 		for ( pst=sf->glyphs[i]->possub; pst!=NULL; pst=pst->next ) {
3908 		    if ( pst->type==pst_substitution || pst->type==pst_alternate ||
3909 			    pst->type==pst_multiple || pst->type==pst_ligature )
3910 			if ( UsedIn(sc->name,pst->u.mult.components)) {
3911 			    if ( deps!=NULL ) {
3912 				snprintf(ubuf,sizeof(ubuf),
3913 					_("Subtable %.60s in glyph %.60s"),
3914 			                pst->subtable->subtable_name,
3915 			                sf->glyphs[i]->name);
3916 				deps[tot] = copy(ubuf);
3917 			        depsc[tot] = sf->glyphs[i];
3918 			    }
3919 			    ++tot;
3920 			}
3921 		}
3922 	    }
3923 	    ++k;
3924 	} while ( k<_sf->subfontcnt );
3925 	if ( tot==0 )
3926 return;
3927 	if ( j==0 ) {
3928 	    deps = calloc(tot+1,sizeof(char *));
3929 	    depsc = malloc(tot*sizeof(SplineChar *));
3930 	}
3931     }
3932 
3933     i = gwwv_choose_with_buttons(_("Dependent Substitutions"),(const char **) deps, tot, 0, buts, _("Dependent Substitutions") );
3934     if ( i>-1 ) {
3935 	CharViewCreate(depsc[i],(FontView *) (sc->parent->fv),-1);
3936     }
3937     for ( i=0; i<=tot; ++i )
3938 	free( deps[i] );
3939     free(deps);
3940     free(depsc);
3941 }
3942