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 "fontforgeui.h"
32 #include "fvfonts.h"
33 #include "gkeysym.h"
34 #include "splinestroke.h"
35 #include "splineutil.h"
36 #include "splineutil2.h"
37 #include "splineoverlap.h"
38 #include "ustring.h"
39 #include "utype.h"
40 
41 #include <assert.h>
42 #include <math.h>
43 
44 extern GDevEventMask input_em[];
45 extern const int input_em_cnt;
46 
47 #define CID_ButtCap	1001
48 #define CID_RoundCap	1002
49 #define CID_NibCap	1003
50 #define CID_BevelJoin	1004
51 #define CID_NibJoin	1005
52 #define CID_MiterJoin	1006
53 #define CID_Width	1007
54 #define CID_MinorAxis	1008
55 #define CID_PenAngle	1009
56 #define CID_Circle	1010
57 #define CID_Calligraphic 1011
58 #define CID_Convex	1012
59 #define CID_JoinLimitVal 1013
60 #define CID_JoinLimitLen 1014
61 #define CID_JoinLimitRel 1015
62 #define CID_JoinLimitTxt 1016
63 #define CID_MinorAxisTxt 1017
64 	/* For Kanou (& me) */
65 #define CID_RmInternal	1019
66 #define CID_RmExternal	1020
67 #define CID_RmOvLayer	1021
68 #define CID_Apply	1022
69 #define CID_Nib		1023
70 #define CID_WidthTxt	1024
71 #define CID_TopBox	1025
72 #define CID_RmOvContour	1027
73 #define CID_RmOvNone	1028
74 #define CID_Simplify	1029
75 #define CID_Extrema	1030
76 #define CID_MiterClipJoin	1031
77 #define CID_ArcsJoin	1032
78 #define CID_BevelCap	1033
79 #define CID_ExtendCapVal 1034
80 #define CID_ExtendCapLen 1035
81 #define CID_ExtendCapRel 1036
82 #define CID_ExtendCapTxt 1037
83 #define CID_AccTar       1038
84 #define CID_RoundJoin	1039
85 #define CID_AlText	1040
86 #define CID_AlAuto	1041
87 #define CID_AlSVG2	1042
88 #define CID_AlRatio	1043
89 
90 	/* For freehand */
91 #define CID_CenterLine	1050
92 
93 /* Used in other structures and tools */
94 #define CID_SquareCap	1051
95 #define CID_LineJoinTxt 1053
96 #define CID_LineCapTxt  1054
97 
CVStrokeIt(void * _cv,StrokeInfo * si,int justapply)98 static void CVStrokeIt(void *_cv, StrokeInfo *si, int justapply) {
99     CharView *cv = _cv;
100     int anypoints;
101     SplineSet *spl, *prev, *head=NULL, *cur, *snext;
102 
103     if ( cv->b.layerheads[cv->b.drawmode]->undoes!=NULL &&
104 	    cv->b.layerheads[cv->b.drawmode]->undoes->undotype==ut_tstate )
105 	CVDoUndo(&cv->b);
106 
107     if ( justapply )
108 	CVPreserveTState(cv);
109     else
110 	CVPreserveState(&cv->b);
111     if ( CVAnySel(cv,&anypoints,NULL,NULL,NULL) && anypoints ) {
112 	prev = NULL;
113 	for ( spl= cv->b.layerheads[cv->b.drawmode]->splines; spl!=NULL; spl = snext ) {
114 	    snext = spl->next;
115 	    spl->next = NULL;
116 	    if ( PointListIsSelected(spl)) {
117 		cur = SplineSetStroke(spl,si,cv->b.layerheads[cv->b.drawmode]->order2);
118 		SplinePointListSelect(cur, true);
119 		SplinePointListMDFree(cv->b.sc,spl);
120 	    } else
121 		cur = spl;
122 	    if ( cur!=NULL ) {
123 		if ( prev==NULL )
124 		    prev = cv->b.layerheads[cv->b.drawmode]->splines = cur;
125 		else
126 		    prev->next = cur;
127 		while ( prev->next )
128 		    prev=prev->next;
129 	    }
130 	}
131 	if ( si->rmov==srmov_layer )
132 	    cv->b.layerheads[cv->b.drawmode]->splines = SplineSetRemoveOverlap(cv->b.sc,
133 	      cv->b.layerheads[cv->b.drawmode]->splines, over_rmselected);
134     } else {
135 	head = SplineSetStroke(cv->b.layerheads[cv->b.drawmode]->splines,si,
136 		cv->b.layerheads[cv->b.drawmode]->order2);
137 	SplinePointListsFree( cv->b.layerheads[cv->b.drawmode]->splines );
138 	cv->b.layerheads[cv->b.drawmode]->splines = head;
139     }
140     SCClearSelPt(cv->b.sc);
141     CVCharChangedUpdate(&cv->b);
142 }
143 
_Stroke_OK(StrokeDlg * sd,int isapply)144 static int _Stroke_OK(StrokeDlg *sd,int isapply) {
145     StrokeInfo *si, apply_si;
146     int err;
147     GWindow sw = sd->gw;
148     GGadget *clg;
149     const char *msg;
150 
151     assert( sd->si!=NULL );
152     if ( isapply )
153 	si = InitializeStrokeInfo(&apply_si);
154     else
155 	si = sd->si;
156     err = false;
157 
158     si->stroke_type = si_round;
159     if ( GGadgetIsChecked( GWidgetGetControl(sw,CID_Calligraphic)) )
160 	si->stroke_type = si_calligraphic;
161     else if ( GGadgetIsChecked( GWidgetGetControl(sw,CID_Convex)) )
162 	si->stroke_type = si_nib;
163     else if (   (clg=GWidgetGetControl(sw,CID_CenterLine))!=NULL
164 	     && GGadgetIsChecked(clg) )
165 	si->stroke_type = si_centerline;
166     if ( si->stroke_type==si_nib ) {
167 	si->nib = sd->sc_stroke.layers[ly_fore].splines;
168 	if ( sd->sc_stroke.layers[ly_fore].refs != NULL ) {
169 	    ff_post_error(_("No References"),_("No references allowed in a pen."));
170 	    err = true;
171 	} else if ( si->nib==NULL ) {
172 	    ff_post_error(_("Nothing specified"),_("Please draw a convex polygon in the drawing area."));
173 	    err = true;
174 	} else {
175 	    SplineSet *ss;
176 	    SplinePointListSelect(si->nib, false);
177 	    for ( ss=si->nib ; ss!=NULL && !err; ss=ss->next ) {
178 		enum ShapeType pt = NibIsValid(ss);
179 		if ( pt!=Shape_Convex ) {
180 		    GDrawRequestExpose(sd->cv_stroke.v,NULL,false);
181 		    ff_post_error(_("Nib shape not valid"), NibShapeTypeMsg(pt));
182 		    err = true;
183 		}
184 	    }
185 	}
186 	if (!err)
187 	    GDrawRequestExpose(sd->cv_stroke.v,NULL,false);
188     } else {
189 	si->width = GetReal8(sw,CID_Width,_("Stroke _Width:"),&err);
190 	if ( si->width==0 && (   si->stroke_type==si_round
191 	                      || si->stroke_type==si_calligraphic )) {
192 	    ff_post_error(_("Bad Value"), _("Stroke width cannot be zero"));
193 	    err = true;
194 	}
195 	if ( si->width<0 )
196 	    si->width = -si->width;
197 	si->height = GetReal8(sw,CID_MinorAxis,_("Minor A_xis:"),&err);
198 	if ( si->height<0 )
199 	    si->height = -si->height;
200     }
201     si->penangle = GetReal8(sw,CID_PenAngle,_("Pen _Angle:"),&err);
202     if ( si->penangle>180 || si->penangle < -180 ) {
203 	si->penangle = fmod(si->penangle,360);
204     if ( si->penangle>180 )
205 	si->penangle -= 360;
206     else if ( si->penangle<-180 )
207 	si->penangle += 360;
208     }
209     si->penangle *= FF_PI/180;
210     si->cap = GGadgetIsChecked( GWidgetGetControl(sw,CID_ButtCap))?lc_butt:
211               GGadgetIsChecked( GWidgetGetControl(sw,CID_BevelCap))?lc_bevel:
212               GGadgetIsChecked( GWidgetGetControl(sw,CID_RoundCap))?lc_round:
213               lc_nib;
214     si->join = GGadgetIsChecked( GWidgetGetControl(sw,CID_BevelJoin))?lj_bevel:
215                GGadgetIsChecked( GWidgetGetControl(sw,CID_MiterJoin))?lj_miter:
216                GGadgetIsChecked( GWidgetGetControl(sw,CID_MiterClipJoin))?lj_miterclip:
217                GGadgetIsChecked( GWidgetGetControl(sw,CID_RoundJoin))?lj_round:
218                GGadgetIsChecked( GWidgetGetControl(sw,CID_ArcsJoin))?lj_arcs:
219                lj_nib;
220     si->rmov = GGadgetIsChecked( GWidgetGetControl(sw,CID_RmOvNone))?srmov_none:
221                GGadgetIsChecked( GWidgetGetControl(sw,CID_RmOvContour))?srmov_contour:
222                srmov_layer;
223     si->al = GGadgetIsChecked( GWidgetGetControl(sw,CID_AlSVG2))?sal_svg2:
224                GGadgetIsChecked( GWidgetGetControl(sw,CID_AlRatio))?sal_ratio:
225                sal_auto;
226     si->removeinternal = GGadgetIsChecked( GWidgetGetControl(sw,CID_RmInternal));
227     si->removeexternal = GGadgetIsChecked( GWidgetGetControl(sw,CID_RmExternal));
228     si->simplify = GGadgetIsChecked( GWidgetGetControl(sw,CID_Simplify));
229     si->extrema = GGadgetIsChecked( GWidgetGetControl(sw,CID_Extrema));
230     si->joinlimit = GetReal8(sw,CID_JoinLimitVal,_("Join Limit:"),&err);
231     si->jlrelative = GGadgetIsChecked( GWidgetGetControl(sw,CID_JoinLimitLen))
232                        ? false : true;
233     si->extendcap = GetReal8(sw,CID_ExtendCapVal,_("Extend Cap:"),&err);
234     si->ecrelative = GGadgetIsChecked( GWidgetGetControl(sw,CID_ExtendCapRel))
235                          ? true : false;
236     si->accuracy_target = GetReal8(sw,CID_AccTar,_("Accuracy Target:"),&err);
237     if ( si->removeinternal && si->removeexternal ) {
238 	ff_post_error(_("Bad Value"),_("Removing both the internal and the external contours makes no sense"));
239 	err = true;
240     }
241     if ( err )
242 	return( true );
243     if ( sd->strokeit!=NULL )
244 	(sd->strokeit)(sd->cv,si,isapply);
245     sd->done = !isapply;
246     return( true );
247 }
248 
Stroke_OK(GGadget * g,GEvent * e)249 static int Stroke_OK(GGadget *g, GEvent *e) {
250 
251     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
252 	GWindow sw = GGadgetGetWindow(g);
253 	StrokeDlg *sd = (StrokeDlg *) ((CharViewBase *) GDrawGetUserData(sw))->container;
254 return( _Stroke_OK(sd,GGadgetGetCid(g) == CID_Apply));
255     }
256 return( true );
257 }
258 
_Stroke_Cancel(StrokeDlg * sd)259 static void _Stroke_Cancel(StrokeDlg *sd ) {
260     if ( sd->strokeit==CVStrokeIt && sd->cv->b.layerheads[sd->cv->b.drawmode]->undoes!=NULL &&
261 	    sd->cv->b.layerheads[sd->cv->b.drawmode]->undoes->undotype==ut_tstate )
262 	CVDoUndo(&sd->cv->b);
263     sd->done = -1;
264 }
265 
Stroke_Cancel(GGadget * g,GEvent * e)266 static int Stroke_Cancel(GGadget *g, GEvent *e) {
267     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
268 	StrokeDlg *sd = (StrokeDlg *) ((CharViewBase *) GDrawGetUserData(GGadgetGetWindow(g)))->container;
269 	_Stroke_Cancel(sd);
270     }
271 return( true );
272 }
273 
Stroke_ShowNib(StrokeDlg * sd)274 static void Stroke_ShowNib(StrokeDlg *sd) {
275     SplineSet *ss;
276     real transform[6];
277     double angle,c,s, width, height;
278     int err=0;
279 
280     SplinePointListsFree(sd->dummy_sf.grid.splines);
281     sd->dummy_sf.grid.splines = NULL;
282     if ( GGadgetIsChecked(GWidgetGetControl(sd->gw,CID_Convex)) ) {
283 	if ( sd->sc_stroke.layers[ly_fore].splines==NULL ) {
284 	    sd->sc_stroke.layers[ly_fore].splines = sd->old_convex;
285 	    sd->old_convex = NULL;
286 	}
287     } else {
288 	if ( sd->old_convex==NULL ) {
289 	    sd->old_convex = sd->sc_stroke.layers[ly_fore].splines;
290 	    sd->sc_stroke.layers[ly_fore].splines = NULL;
291 	}
292     }
293     if ( GGadgetIsChecked(GWidgetGetControl(sd->gw,CID_Circle)) ||
294 	    GGadgetIsChecked(GWidgetGetControl(sd->gw,CID_Calligraphic)) ) {
295 	// UnitShape(1) presumably returns a square for this line's benefit.
296 	ss = UnitShape( GGadgetIsChecked(GWidgetGetControl(sd->gw,CID_Calligraphic)) );
297 	memset(transform,0,sizeof(transform));
298 	width = GetCalmReal8(sd->gw,CID_Width,"",&err);
299 	height = GetCalmReal8(sd->gw,CID_MinorAxis,"",&err);
300 	angle = GetCalmReal8(sd->gw,CID_PenAngle,"",&err)*FF_PI/180;
301 	c = cos(angle); s=sin(angle);
302 	transform[0] = transform[3] = c;
303 	transform[1] = s; transform[2] = -s;
304 	transform[0] *= width/2;
305 	transform[1] *= width/2;
306 	transform[2] *= height/2;
307 	transform[3] *= height/2;
308 	SplinePointListTransform(ss,transform,tpt_AllPoints);
309 	sd->dummy_sf.grid.splines = ss;
310     }
311     GDrawRequestExpose(sd->cv_stroke.v,NULL,false);
312 }
313 
StrokeSetup(StrokeDlg * sd,enum si_type stroke_type)314 static void StrokeSetup(StrokeDlg *sd, enum si_type stroke_type) {
315 
316     sd->dontexpand = ( stroke_type==si_centerline );
317 
318     GGadgetSetEnabled(GWidgetGetControl(sd->gw,CID_WidthTxt    ), stroke_type==si_round || stroke_type==si_calligraphic);
319     GGadgetSetEnabled(GWidgetGetControl(sd->gw,CID_Width       ), stroke_type==si_round || stroke_type==si_calligraphic);
320     GGadgetSetEnabled(GWidgetGetControl(sd->gw,CID_MinorAxisTxt), stroke_type==si_round || stroke_type==si_calligraphic);
321     GGadgetSetEnabled(GWidgetGetControl(sd->gw,CID_MinorAxis   ), stroke_type==si_round || stroke_type==si_calligraphic);
322 }
323 
Stroke_TextChanged(GGadget * g,GEvent * e)324 static int Stroke_TextChanged(GGadget *g, GEvent *e) {
325     if ( e->type==et_controlevent && e->u.control.subtype == et_textchanged ) {
326 	StrokeDlg *sd = (StrokeDlg *) ((CharViewBase *) GDrawGetUserData(GGadgetGetWindow(g)))->container;
327 	Stroke_ShowNib(sd);
328     }
329 return( true );
330 }
331 
Stroke_CenterLine(GGadget * g,GEvent * e)332 static int Stroke_CenterLine(GGadget *g, GEvent *e) {
333     if ( e->type==et_controlevent && e->u.control.subtype == et_radiochanged ) {
334 	StrokeDlg *sd = (StrokeDlg *) ((CharViewBase *) GDrawGetUserData(GGadgetGetWindow(g)))->container;
335 	StrokeSetup(sd,si_centerline);
336 	Stroke_ShowNib(sd);
337     }
338 return( true );
339 }
340 
Stroke_Calligraphic(GGadget * g,GEvent * e)341 static int Stroke_Calligraphic(GGadget *g, GEvent *e) {
342     if ( e->type==et_controlevent && e->u.control.subtype == et_radiochanged ) {
343 	StrokeDlg *sd = (StrokeDlg *) ((CharViewBase *) GDrawGetUserData(GGadgetGetWindow(g)))->container;
344 	StrokeSetup(sd,si_calligraphic);
345 	Stroke_ShowNib(sd);
346     }
347 return( true );
348 }
349 
Stroke_Stroke(GGadget * g,GEvent * e)350 static int Stroke_Stroke(GGadget *g, GEvent *e) {
351     if ( e->type==et_controlevent && e->u.control.subtype == et_radiochanged ) {
352 	StrokeDlg *sd = (StrokeDlg *) ((CharViewBase *) GDrawGetUserData(GGadgetGetWindow(g)))->container;
353 	StrokeSetup(sd,si_round);
354 	Stroke_ShowNib(sd);
355     }
356 return( true );
357 }
358 
Stroke_Convex(GGadget * g,GEvent * e)359 static int Stroke_Convex(GGadget *g, GEvent *e) {
360     if ( e->type==et_controlevent && e->u.control.subtype == et_radiochanged ) {
361 	StrokeDlg *sd = (StrokeDlg *) ((CharViewBase *) GDrawGetUserData(GGadgetGetWindow(g)))->container;
362 	StrokeSetup(sd,si_nib);
363 	Stroke_ShowNib(sd);
364     }
365 return( true );
366 }
367 
JoinSetup(StrokeDlg * sd,int type)368 static void JoinSetup(StrokeDlg *sd, int type) {
369     GGadgetSetEnabled(GWidgetGetControl(sd->gw,CID_JoinLimitTxt ), type>0);
370     GGadgetSetEnabled(GWidgetGetControl(sd->gw,CID_JoinLimitVal ), type>0);
371     GGadgetSetEnabled(GWidgetGetControl(sd->gw,CID_JoinLimitLen ), type>0);
372     GGadgetSetEnabled(GWidgetGetControl(sd->gw,CID_JoinLimitRel ), type>0);
373     GGadgetSetEnabled(GWidgetGetControl(sd->gw,CID_AlText       ), type==2);
374     GGadgetSetEnabled(GWidgetGetControl(sd->gw,CID_AlAuto       ), type==2);
375     GGadgetSetEnabled(GWidgetGetControl(sd->gw,CID_AlSVG2       ), type==2);
376     GGadgetSetEnabled(GWidgetGetControl(sd->gw,CID_AlRatio      ), type==2);
377 }
378 
Join_Arcs(GGadget * g,GEvent * e)379 static int Join_Arcs(GGadget *g, GEvent *e) {
380     if ( e->type==et_controlevent && e->u.control.subtype == et_radiochanged ) {
381 	StrokeDlg *sd = (StrokeDlg *) ((CharViewBase *) GDrawGetUserData(GGadgetGetWindow(g)))->container;
382 	JoinSetup(sd,2);
383     }
384 return( true );
385 }
386 
Join_Miter(GGadget * g,GEvent * e)387 static int Join_Miter(GGadget *g, GEvent *e) {
388     if ( e->type==et_controlevent && e->u.control.subtype == et_radiochanged ) {
389 	StrokeDlg *sd = (StrokeDlg *) ((CharViewBase *) GDrawGetUserData(GGadgetGetWindow(g)))->container;
390 	JoinSetup(sd,1);
391     }
392 return( true );
393 }
394 
Join_Other(GGadget * g,GEvent * e)395 static int Join_Other(GGadget *g, GEvent *e) {
396     if ( e->type==et_controlevent && e->u.control.subtype == et_radiochanged ) {
397 	StrokeDlg *sd = (StrokeDlg *) ((CharViewBase *) GDrawGetUserData(GGadgetGetWindow(g)))->container;
398 	JoinSetup(sd,0);
399     }
400 return( true );
401 }
402 
ExtendSetup(StrokeDlg * sd,int enabled)403 static void ExtendSetup(StrokeDlg *sd, int enabled) {
404     GGadgetSetEnabled(GWidgetGetControl(sd->gw,CID_ExtendCapTxt ), enabled);
405     GGadgetSetEnabled(GWidgetGetControl(sd->gw,CID_ExtendCapVal ), enabled);
406     GGadgetSetEnabled(GWidgetGetControl(sd->gw,CID_ExtendCapLen ), enabled);
407     GGadgetSetEnabled(GWidgetGetControl(sd->gw,CID_ExtendCapRel ), enabled);
408 }
409 
Cap_Extendable(GGadget * g,GEvent * e)410 static int Cap_Extendable(GGadget *g, GEvent *e) {
411     if ( e->type==et_controlevent && e->u.control.subtype == et_radiochanged ) {
412 	StrokeDlg *sd = (StrokeDlg *) ((CharViewBase *) GDrawGetUserData(GGadgetGetWindow(g)))->container;
413 	ExtendSetup(sd,1);
414     }
415 return( true );
416 }
417 
Cap_Other(GGadget * g,GEvent * e)418 static int Cap_Other(GGadget *g, GEvent *e) {
419     if ( e->type==et_controlevent && e->u.control.subtype == et_radiochanged ) {
420 	StrokeDlg *sd = (StrokeDlg *) ((CharViewBase *) GDrawGetUserData(GGadgetGetWindow(g)))->container;
421 	ExtendSetup(sd,0);
422     }
423 return( true );
424 }
425 
Stroke_SubResize(StrokeDlg * sd,GEvent * event)426 static void Stroke_SubResize(StrokeDlg *sd, GEvent *event) {
427     int width, height;
428 
429     if ( !event->u.resize.sized )
430 return;
431 
432     width = event->u.resize.size.width;
433     height = event->u.resize.size.height;
434     if ( width!=sd->cv_width || height!=sd->cv_height ) {
435 	sd->cv_width = width; sd->cv_height = height;
436 	GDrawResize(sd->cv_stroke.gw,width,height);
437     }
438 
439     GDrawSync(NULL);
440     GDrawProcessPendingEvents(NULL);
441 }
442 
Stroke_Draw(StrokeDlg * sd,GWindow pixmap,GEvent * event)443 static void Stroke_Draw(StrokeDlg *sd, GWindow pixmap, GEvent *event) {
444     GRect r,pos;
445 
446     GGadgetGetSize(GWidgetGetControl(sd->gw,CID_Nib),&pos);
447     r.x = pos.x-1; r.y = pos.y-1;
448     r.width = pos.width+1; r.height = pos.height+1;
449     GDrawDrawRect(pixmap,&r,0);
450 }
451 
Stroke_MakeActive(StrokeDlg * sd,CharView * cv)452 static void Stroke_MakeActive(StrokeDlg *sd,CharView *cv) {
453 
454     if ( sd==NULL )
455 return;
456     cv->inactive = false;
457     GDrawSetUserData(sd->gw,cv);
458     GDrawRequestExpose(cv->v,NULL,false);
459     GDrawRequestExpose(sd->gw,NULL,false);
460 }
461 
Stroke_Char(StrokeDlg * sd,GEvent * event)462 static void Stroke_Char(StrokeDlg *sd, GEvent *event) {
463 
464     if ( event->u.chr.keysym == GK_F1 || event->u.chr.keysym == GK_Help ) {
465 	help("ui/menus/elementmenu.html", "#elementmenu-expand");
466 return;
467     } else if ( event->u.chr.keysym == GK_Return ) {
468 	_Stroke_OK(sd,false);
469 return;
470     } else if ( event->u.chr.keysym == GK_Escape ) {
471 	_Stroke_Cancel(sd);
472 return;
473     }
474 
475     CVChar((&sd->cv_stroke),event);
476 }
477 
Stroke_DoClose(struct cvcontainer * cvc)478 static void Stroke_DoClose(struct cvcontainer *cvc) {
479     StrokeDlg *sd = (StrokeDlg *) cvc;
480 
481      {
482 	SplineChar *msc = &sd->sc_stroke;
483 	SplinePointListsFree(msc->layers[0].splines);
484 	SplinePointListsFree(msc->layers[1].splines);
485 	free( msc->layers );
486     }
487 
488     sd->done = -1;
489 }
490 
stroke_sub_e_h(GWindow gw,GEvent * event)491 static int stroke_sub_e_h(GWindow gw, GEvent *event) {
492     StrokeDlg *sd = (StrokeDlg *) ((CharViewBase *) GDrawGetUserData(gw))->container;
493 
494     switch ( event->type ) {
495       case et_resize:
496 	if ( event->u.resize.sized )
497 	    Stroke_SubResize(sd,event);
498       break;
499       case et_char:
500 	Stroke_Char(sd,event);
501       break;
502       case et_mouseup: case et_mousedown: case et_mousemove:
503 return( false );
504       break;
505     }
506 return( true );
507 }
508 
Stroke_Can_Navigate(struct cvcontainer * cvc,enum nav_type type)509 static int Stroke_Can_Navigate(struct cvcontainer *cvc, enum nav_type type) {
510 return( false );
511 }
512 
Stroke_Can_Open(struct cvcontainer * cvc)513 static int Stroke_Can_Open(struct cvcontainer *cvc) {
514 return( false );
515 }
516 
SF_Of_Stroke(struct cvcontainer * foo)517 static SplineFont *SF_Of_Stroke(struct cvcontainer *foo) {
518 return( NULL );
519 }
520 
521 struct cvcontainer_funcs stroke_funcs = {
522     cvc_stroke,
523     (void (*) (struct cvcontainer *cvc,CharViewBase *cv)) Stroke_MakeActive,
524     (void (*) (struct cvcontainer *cvc,void *)) Stroke_Char,
525     Stroke_Can_Navigate,
526     NULL,
527     Stroke_Can_Open,
528     Stroke_DoClose,
529     SF_Of_Stroke
530 };
531 
532 
StrokeInit(StrokeDlg * sd)533 static void StrokeInit(StrokeDlg *sd) {
534     real transform[6];
535 
536     sd->base.funcs = &stroke_funcs;
537 
538     {
539 	SplineChar *msc = (&sd->sc_stroke);
540 	CharView *mcv = (&sd->cv_stroke);
541 	msc->orig_pos = 0;
542 	msc->unicodeenc = -1;
543 	msc->name = "Nib";
544 	msc->parent = &sd->dummy_sf;
545 	msc->layer_cnt = 2;
546 	msc->layers = calloc(2,sizeof(Layer));
547 	msc->width = 200;
548 	LayerDefault(&msc->layers[0]);
549 	LayerDefault(&msc->layers[1]);
550 	sd->chars[0] = msc;
551 
552 	mcv->b.sc = msc;
553 	mcv->b.layerheads[dm_fore] = &msc->layers[ly_fore];
554 	mcv->b.layerheads[dm_back] = &msc->layers[ly_back];
555 	mcv->b.layerheads[dm_grid] = &sd->dummy_sf.grid;
556 	mcv->b.drawmode = dm_fore;
557 	mcv->b.container = (struct cvcontainer *) sd;
558 	mcv->inactive = false;
559     }
560     sd->dummy_sf.glyphs = sd->chars;
561     sd->dummy_sf.glyphcnt = sd->dummy_sf.glyphmax = 1;
562     sd->dummy_sf.pfminfo.fstype = -1;
563     sd->dummy_sf.pfminfo.stylemap = -1;
564     sd->dummy_sf.fontname = sd->dummy_sf.fullname = sd->dummy_sf.familyname = "dummy";
565     sd->dummy_sf.weight = "Medium";
566     sd->dummy_sf.origname = "dummy";
567     sd->dummy_sf.ascent = 200;
568     sd->dummy_sf.descent = 200;
569     sd->dummy_sf.layers = sd->layerinfo;
570     sd->dummy_sf.layer_cnt = 2;
571     sd->layerinfo[ly_back].order2 = false;
572     sd->layerinfo[ly_back].name = _("Back");
573     sd->layerinfo[ly_fore].order2 = false;
574     sd->layerinfo[ly_fore].name = _("Fore");
575     sd->dummy_sf.grid.order2 = false;
576     sd->dummy_sf.anchor = NULL;
577 
578     sd->dummy_sf.fv = (FontViewBase *) &sd->dummy_fv;
579     sd->dummy_fv.b.active_layer = ly_fore;
580     sd->dummy_fv.b.sf = &sd->dummy_sf;
581     sd->dummy_fv.b.selected = sd->sel;
582     sd->dummy_fv.cbw = sd->dummy_fv.cbh = default_fv_font_size+1;
583     sd->dummy_fv.magnify = 1;
584 
585     sd->dummy_fv.b.map = &sd->dummy_map;
586     sd->dummy_map.map = sd->map;
587     sd->dummy_map.backmap = sd->backmap;
588     sd->dummy_map.enccount = sd->dummy_map.encmax = sd->dummy_map.backmax = 1;
589     sd->dummy_map.enc = &custom;
590 
591 }
592 
stroke_e_h(GWindow gw,GEvent * event)593 static int stroke_e_h(GWindow gw, GEvent *event) {
594     StrokeDlg *sd = (StrokeDlg *) ((CharViewBase *) GDrawGetUserData(gw))->container;
595     switch (event->type) {
596         case et_expose:
597             Stroke_Draw(sd, gw, event);
598             break;
599         case et_close:
600             sd->done = -1;
601             break;
602         case et_destroy:
603             sd->gw = NULL; // some flag to indicate that we're finally gone
604             break;
605         case et_char:
606             if (event->u.chr.keysym == GK_F1 || event->u.chr.keysym == GK_Help) {
607                 help("ui/menus/elementmenu.html", "#elementmenu-expand");
608                 return true;
609             }
610             return false;
611         case et_map:
612             if (event->u.map.is_visible) {
613                 /* Above palettes */
614                 GDrawRaise(gw);
615             }
616             break;
617         default:
618             break;
619     }
620     return true;
621 }
622 
623 #define SD_Width	400
624 #define SD_Height	400
625 #define FH_Height	(SD_Height+75)
626 
MakeStrokeDlg(void * cv,void (* strokeit)(void *,StrokeInfo *,int),StrokeInfo * si,int apply)627 static void MakeStrokeDlg(void *cv, void (*strokeit)(void *,StrokeInfo *,int),
628                            StrokeInfo *si, int apply) {
629     StrokeDlg sd;
630     GRect pos;
631     GWindow gw;
632     GWindowAttrs wattrs;
633     SplineSet *nib_bk = NULL;
634     GGadgetCreateData gcd[54], boxes[7], *buttons[13], *mainarray[11][2],
635 	    *radoptarray[4][9], *split[13][6], *checkarray[5],
636 	    *jlexarray[3][8];
637     GTextInfo label[54];
638     int i, gcdoff, mi, sp, tfpos[6];
639     char anglebuf[20], ecbuf[20], jlbuf[20], accbuf[20];
640     char widthbuf[20], axisbuf[20];
641 
642     assert( si!=NULL );
643 
644     memset(&sd, 0, sizeof(sd));
645     sd.si = si;
646     if ( si->nib!=NULL ) {
647 	sd.old_convex = si->nib;
648 	nib_bk = SplinePointListCopy(si->nib);
649 	si->nib=NULL;
650     }
651 
652     {
653 	StrokeInit(&sd);
654 	memset(&wattrs,0,sizeof(wattrs));
655 	wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_undercursor|wam_isdlg|wam_restrict;
656 	wattrs.event_masks = ~(1<<et_charup);
657 	wattrs.restrict_input_to_me = 1;
658 	wattrs.undercursor = 1;
659 	wattrs.cursor = ct_pointer;
660 	wattrs.utf8_window_title = strokeit!=NULL ? _("Expand Stroke") :
661 /* GT: This does not mean the program, but freehand drawing */
662 		    _("Freehand");
663 	wattrs.is_dlg = true;
664 	pos.x = pos.y = 0;
665 	pos.width = GGadgetScale(GDrawPointsToPixels(NULL,SD_Width));
666 	pos.height = GDrawPointsToPixels(NULL,strokeit!=NULL ? SD_Height : FH_Height);
667 	sd.gw = gw = GDrawCreateTopWindow(NULL,&pos,stroke_e_h,&sd.cv_stroke,&wattrs);
668 	GDrawSetWindowTypeName(gw, "CharView"); // For hotkeys
669 	GDrawRequestDeviceEvents(gw,input_em_cnt,input_em);
670 
671 	memset(&label,0,sizeof(label));
672 	memset(&gcd,0,sizeof(gcd));
673 	memset(&boxes,0,sizeof(boxes));
674 	memset(&split,0,sizeof(split));
675 	memset(&jlexarray,0,sizeof(jlexarray));
676 	memset(&radoptarray,0,sizeof(radoptarray));
677 	gcdoff = mi = sp = 0;
678 
679 	gcd[gcdoff].gd.flags = gg_visible|gg_enabled ;		/* This space is for the menubar */
680 	gcd[gcdoff].gd.pos.height = 18; gcd[gcdoff].gd.pos.width = 20;
681 	gcd[gcdoff++].creator = GSpacerCreate;
682 	mainarray[mi][0] = &gcd[gcdoff-1]; mainarray[mi++][1] = NULL;
683 
684 	gcd[gcdoff].gd.pos.width = gcd[gcdoff].gd.pos.height = 200;
685 	gcd[gcdoff].gd.flags = gg_visible | gg_enabled;
686 	gcd[gcdoff].gd.cid = CID_Nib;
687 	gcd[gcdoff].gd.u.drawable_e_h = stroke_sub_e_h;
688 	gcd[gcdoff++].creator = GDrawableCreate;
689 	split[sp][0] = &gcd[gcdoff-1];
690 
691 	label[gcdoff].text = (unichar_t *) _("Nib Type:");
692 	label[gcdoff].text_is_1byte = true;
693 	label[gcdoff].text_in_resource = true;
694 	gcd[gcdoff].gd.label = &label[gcdoff];
695 	gcd[gcdoff].gd.flags = gg_enabled | gg_visible;
696 	gcd[gcdoff++].creator = GLabelCreate;
697 	split[sp][1] = GCD_HPad10; split[sp][2] = &gcd[gcdoff-1];
698 
699 	label[gcdoff].text = (unichar_t *) _("_Circular (Elliptical)");
700 	label[gcdoff].text_is_1byte = true;
701 	label[gcdoff].text_in_resource = true;
702 	gcd[gcdoff].gd.label = &label[gcdoff];
703 	gcd[gcdoff].gd.flags = gg_enabled | gg_visible | (si->stroke_type==si_round? gg_cb_on : 0);
704 	gcd[gcdoff].gd.u.radiogroup = 1;
705 	gcd[gcdoff].gd.cid = CID_Circle;
706 	gcd[gcdoff].gd.handle_controlevent = Stroke_Stroke;
707 	gcd[gcdoff++].creator = GRadioCreate;
708 	split[sp][3] = &gcd[gcdoff-1]; split[sp][4] = GCD_ColSpan;
709 	split[sp++][5] = NULL;
710 
711 	label[gcdoff].text = (unichar_t *) _("Ca_lligraphic (Rectangular)");
712 	label[gcdoff].text_is_1byte = true;
713 	label[gcdoff].text_in_resource = true;
714 	gcd[gcdoff].gd.label = &label[gcdoff];
715 	gcd[gcdoff].gd.flags = gg_enabled | gg_visible | (si->stroke_type == si_calligraphic ? gg_cb_on : 0);
716 	gcd[gcdoff].gd.u.radiogroup = 1;
717 	gcd[gcdoff].gd.cid = CID_Calligraphic;
718 	gcd[gcdoff].gd.handle_controlevent = Stroke_Calligraphic;
719 	gcd[gcdoff++].creator = GRadioCreate;
720 	split[sp][0] = GCD_RowSpan;
721 	split[sp][1] = GCD_HPad10; split[sp][2] = GCD_Glue;
722 	split[sp][3] = &gcd[gcdoff-1]; split[sp][4] = GCD_ColSpan;
723 	split[sp++][5] = NULL;
724 
725 	label[gcdoff].text = (unichar_t *) _("Conve_x (Polygonal)");
726 	label[gcdoff].text_is_1byte = true;
727 	label[gcdoff].text_in_resource = true;
728 	gcd[gcdoff].gd.label = &label[gcdoff];
729 	gcd[gcdoff].gd.flags = gg_enabled | gg_visible | (si->stroke_type == si_nib ? gg_cb_on : 0);
730 	gcd[gcdoff].gd.u.radiogroup = 1;
731 	gcd[gcdoff].gd.cid = CID_Convex;
732 	gcd[gcdoff].gd.handle_controlevent = Stroke_Convex;
733 	gcd[gcdoff++].creator = GRadioCreate;
734 	split[sp][0] = GCD_RowSpan;
735 	split[sp][1] = GCD_HPad10; split[sp][2] = GCD_Glue;
736 	split[sp][3] = &gcd[gcdoff-1]; split[sp][4] = GCD_ColSpan;
737 	split[sp++][5] = NULL;
738 
739 	if ( strokeit==NULL ) {
740 	    label[gcdoff].text = (unichar_t *) _("_Don't Expand");
741 	    label[gcdoff].text_is_1byte = true;
742 	    label[gcdoff].text_in_resource = true;
743 	    gcd[gcdoff].gd.label = &label[gcdoff];
744 	    gcd[gcdoff].gd.flags = gg_enabled | gg_visible | (si->stroke_type==si_centerline ? gg_cb_on : 0 );
745 	    gcd[gcdoff].gd.u.radiogroup = 1;
746 	    gcd[gcdoff].gd.cid = CID_CenterLine;
747 	    gcd[gcdoff].gd.handle_controlevent = Stroke_CenterLine;
748 	    gcd[gcdoff++].creator = GRadioCreate;
749 	    split[sp][0] = GCD_RowSpan;
750 	    split[sp][1] = GCD_HPad10; split[sp][2] = GCD_Glue;
751 	    split[sp][3] = &gcd[gcdoff-1]; split[sp][4] = GCD_ColSpan;
752 	    split[sp++][5] = NULL;
753 	}
754 
755 	label[gcdoff].text = (unichar_t *) _("Major Axis (_Width):");
756 	label[gcdoff].text_is_1byte = true;
757 	label[gcdoff].text_in_resource = true;
758 	gcd[gcdoff].gd.label = &label[gcdoff];
759 	gcd[gcdoff].gd.flags = gg_enabled | gg_visible;
760 	gcd[gcdoff].gd.cid = CID_WidthTxt;
761 	gcd[gcdoff++].creator = GLabelCreate;
762 	split[sp][0] = GCD_RowSpan;
763 	split[sp][1] = GCD_HPad10; split[sp][2] = &gcd[gcdoff-1];
764 	split[sp][3] = GCD_ColSpan;
765 
766 	sprintf( widthbuf, "%g", (double) (si->width) );
767 	label[gcdoff].text = (unichar_t *) widthbuf;
768 	label[gcdoff].text_is_1byte = true;
769 	gcd[gcdoff].gd.pos.width = 50;
770 	gcd[gcdoff].gd.label = &label[gcdoff];
771 	gcd[gcdoff].gd.flags = gg_enabled | gg_visible;
772 	gcd[gcdoff].gd.cid = CID_Width;
773 	gcd[gcdoff].gd.handle_controlevent = Stroke_TextChanged;
774 	tfpos[0] = gcdoff;
775 	gcd[gcdoff++].creator = GTextFieldCreate;
776 	split[sp][4] = &gcd[gcdoff-1];
777 	split[sp++][5] = NULL;
778 
779 	label[gcdoff].text = (unichar_t *) _("Minor Axis (_Height):");
780 	label[gcdoff].text_is_1byte = true;
781 	label[gcdoff].text_in_resource = true;
782 	gcd[gcdoff].gd.label = &label[gcdoff];
783 	gcd[gcdoff].gd.flags = gg_visible | gg_enabled;
784 	gcd[gcdoff].gd.cid = CID_MinorAxisTxt;
785 	gcd[gcdoff++].creator = GLabelCreate;
786 	split[sp][0] = GCD_RowSpan;
787 	split[sp][1] = GCD_HPad10; split[sp][2] = &gcd[gcdoff-1];
788 	split[sp][3] = GCD_ColSpan;
789 
790 	sprintf( axisbuf, "%g", (double) (si->height) );
791 	label[gcdoff].text = (unichar_t *) axisbuf;
792 	label[gcdoff].text_is_1byte = true;
793 	gcd[gcdoff].gd.pos.width = 50;
794 	gcd[gcdoff].gd.label = &label[gcdoff];
795 	gcd[gcdoff].gd.flags = gg_visible | gg_enabled;
796 	gcd[gcdoff].gd.cid = CID_MinorAxis;
797 	gcd[gcdoff].gd.handle_controlevent = Stroke_TextChanged;
798 	gcd[gcdoff].gd.popup_msg = _(
799 	    "A calligraphic pen or an elliptical pen has two widths\n"
800 	    "(which may be the same, giving a circular or square pen,\n"
801 	    "or different giving an eliptical or rectangular pen).");
802 	tfpos[1] = gcdoff;
803 	gcd[gcdoff++].creator = GTextFieldCreate;
804 	split[sp][4] = &gcd[gcdoff-1];
805 	split[sp++][5] = NULL;
806 
807 	label[gcdoff].text = (unichar_t *) _("Ni_b Angle:");
808 	label[gcdoff].text_is_1byte = true;
809 	label[gcdoff].text_in_resource = true;
810 	gcd[gcdoff].gd.label = &label[gcdoff];
811 	gcd[gcdoff].gd.flags = gg_visible | gg_enabled;
812 	gcd[gcdoff++].creator = GLabelCreate;
813 	split[sp][0] = GCD_RowSpan;
814 	split[sp][1] = GCD_HPad10; split[sp][2] = &gcd[gcdoff-1];
815 	split[sp][3] = GCD_ColSpan;
816 
817 	sprintf( anglebuf, "%g", (double) (si->penangle*180/FF_PI) );
818 	label[gcdoff].text = (unichar_t *) anglebuf;
819 	label[gcdoff].text_is_1byte = true;
820 	gcd[gcdoff].gd.pos.width = 50;
821 	gcd[gcdoff].gd.label = &label[gcdoff];
822 	gcd[gcdoff].gd.flags = gg_visible | gg_enabled;
823 	gcd[gcdoff].gd.cid = CID_PenAngle;
824 	gcd[gcdoff].gd.handle_controlevent = Stroke_TextChanged;
825 	gcd[gcdoff].gd.popup_msg = _(
826 	    "A Convex nib will also be rotated by this amount\n"
827 	    "although this is not displayed in the dialog.");
828 	tfpos[2] = gcdoff;
829 	gcd[gcdoff++].creator = GTextFieldCreate;
830 	split[sp][4] = &gcd[gcdoff-1];
831 	split[sp++][5] = NULL;
832 
833 	label[gcdoff].text = (unichar_t *) _("Line Cap:");
834 	label[gcdoff].text_is_1byte = true;
835 	gcd[gcdoff].gd.label = &label[gcdoff];
836 	gcd[gcdoff].gd.flags = gg_enabled | gg_visible;
837 	gcd[gcdoff++].creator = GLabelCreate;
838 	split[sp][0] = GCD_RowSpan;
839 	split[sp][1] = GCD_HPad10; split[sp][2] = &gcd[gcdoff-1];
840 
841 	label[gcdoff].text = (unichar_t *) _("_Nib");
842 	label[gcdoff].text_is_1byte = true;
843 	label[gcdoff].text_in_resource = true;
844 	gcd[gcdoff].gd.label = &label[gcdoff];
845 	gcd[gcdoff].gd.flags = gg_enabled | gg_visible | (si->cap==lc_nib?gg_cb_on:0);
846 	gcd[gcdoff].gd.cid = CID_NibCap;
847 	gcd[gcdoff].gd.handle_controlevent = Cap_Other;
848 	gcd[gcdoff++].creator = GRadioCreate;
849 	split[sp][3] = &gcd[gcdoff-1];
850 
851 //	label[gcdoff].image = &GIcon_squarecap;
852 	label[gcdoff].text = (unichar_t *) _("_Butt");
853 	label[gcdoff].text_is_1byte = true;
854 	label[gcdoff].text_in_resource = true;
855 	label[gcdoff].image = &GIcon_buttcap;
856 	gcd[gcdoff].gd.mnemonic = 'q';
857 	gcd[gcdoff].gd.label = &label[gcdoff];
858 	gcd[gcdoff].gd.flags = gg_enabled | gg_visible | (si->cap==lc_butt?gg_cb_on:0);
859 	gcd[gcdoff].gd.cid = CID_ButtCap;
860 	gcd[gcdoff].gd.handle_controlevent = Cap_Extendable;
861 	gcd[gcdoff++].creator = GRadioCreate;
862 	split[sp][4] = &gcd[gcdoff-1];
863 	split[sp++][5] = NULL;
864 
865 	label[gcdoff].text = (unichar_t *) _("_Round");
866 	label[gcdoff].text_is_1byte = true;
867 	label[gcdoff].text_in_resource = true;
868 	label[gcdoff].image = &GIcon_roundcap;
869 	gcd[gcdoff].gd.mnemonic = 'R';
870 	gcd[gcdoff].gd.label = &label[gcdoff];
871 	gcd[gcdoff].gd.flags = gg_enabled | gg_visible | (si->cap==lc_round?gg_cb_on:0);
872 	gcd[gcdoff].gd.cid = CID_RoundCap;
873 	gcd[gcdoff].gd.handle_controlevent = Cap_Extendable;
874 	gcd[gcdoff++].creator = GRadioCreate;
875 	split[sp][0] = GCD_RowSpan;
876 	split[sp][1] = GCD_HPad10; split[sp][2] = GCD_Glue;
877 	split[sp][3] = &gcd[gcdoff-1];
878 
879 	label[gcdoff].text = (unichar_t *) _("Be_vel");
880 	label[gcdoff].text_is_1byte = true;
881 	label[gcdoff].text_in_resource = true;
882 //	label[gcdoff].image = &GIcon_roundcap;
883 	gcd[gcdoff].gd.label = &label[gcdoff];
884 	gcd[gcdoff].gd.flags = gg_enabled | gg_visible | (si->cap==lc_bevel?gg_cb_on:0);
885 	gcd[gcdoff].gd.cid = CID_BevelCap;
886 	gcd[gcdoff].gd.handle_controlevent = Cap_Other;
887 	gcd[gcdoff++].creator = GRadioCreate;
888 	split[sp][4] = &gcd[gcdoff-1];
889 	split[sp++][5] = NULL;
890 
891 	label[gcdoff].text = (unichar_t *) _("Line Join:");
892 	label[gcdoff].text_is_1byte = true;
893 	label[gcdoff].text_in_resource = true;
894 	gcd[gcdoff].gd.label = &label[gcdoff];
895 	gcd[gcdoff].gd.flags = gg_enabled | gg_visible;
896 	gcd[gcdoff++].creator = GLabelCreate;
897 	split[sp][0] = GCD_RowSpan;
898 	split[sp][1] = GCD_HPad10; split[sp][2] = &gcd[gcdoff-1];
899 
900 	label[gcdoff].text = (unichar_t *) _("Ni_b");
901 	label[gcdoff].text_is_1byte = true;
902 	label[gcdoff].text_in_resource = true;
903 	gcd[gcdoff].gd.label = &label[gcdoff];
904 	gcd[gcdoff].gd.flags = gg_enabled | gg_visible | (si->join==lj_nib?gg_cb_on:0);
905 	gcd[gcdoff].gd.cid = CID_NibJoin;
906 	gcd[gcdoff].gd.handle_controlevent = Join_Other;
907 	gcd[gcdoff++].creator = GRadioCreate;
908 	split[sp][3] = &gcd[gcdoff-1];
909 
910 	label[gcdoff].text = (unichar_t *) _("B_evel");
911 	label[gcdoff].text_is_1byte = true;
912 	label[gcdoff].text_in_resource = true;
913 	label[gcdoff].image = &GIcon_beveljoin;
914 	gcd[gcdoff].gd.label = &label[gcdoff];
915 	gcd[gcdoff].gd.flags = gg_enabled | gg_visible | (si->join==lj_bevel?gg_cb_on:0);
916 	gcd[gcdoff].gd.cid = CID_BevelJoin;
917 	gcd[gcdoff].gd.handle_controlevent = Join_Other;
918 	gcd[gcdoff++].creator = GRadioCreate;
919 	split[sp][4] = &gcd[gcdoff-1];
920 	split[sp++][5] = NULL;
921 
922 	label[gcdoff].text = (unichar_t *) _("Round");
923 	label[gcdoff].text_is_1byte = true;
924 	label[gcdoff].text_in_resource = true;
925 	gcd[gcdoff].gd.label = &label[gcdoff];
926 	gcd[gcdoff].gd.flags = gg_visible | gg_enabled | (si->join==lj_round?gg_cb_on:0);
927 	gcd[gcdoff].gd.cid = CID_RoundJoin;
928 	gcd[gcdoff].gd.handle_controlevent = Join_Other;
929 	gcd[gcdoff++].creator = GRadioCreate;
930 	split[sp][0] = GCD_RowSpan;
931 	split[sp][1] = GCD_HPad10; split[sp][2] = GCD_Glue;
932 	split[sp][3] = &gcd[gcdoff-1];
933 
934 	label[gcdoff].text = (unichar_t *) _("Arcs");
935 	label[gcdoff].text_is_1byte = true;
936 	label[gcdoff].text_in_resource = true;
937 	gcd[gcdoff].gd.label = &label[gcdoff];
938 	gcd[gcdoff].gd.flags = gg_visible | gg_enabled | (si->join==lj_arcs?gg_cb_on:0);
939 	gcd[gcdoff].gd.cid = CID_ArcsJoin;
940 	gcd[gcdoff].gd.handle_controlevent = Join_Arcs;
941 	gcd[gcdoff++].creator = GRadioCreate;
942 	split[sp][4] = &gcd[gcdoff-1];
943 	split[sp++][5] = NULL;
944 
945 	label[gcdoff].text = (unichar_t *) _("_Miter");
946 	label[gcdoff].text_is_1byte = true;
947 	label[gcdoff].text_in_resource = true;
948 	label[gcdoff].image = &GIcon_miterjoin;
949 	gcd[gcdoff].gd.label = &label[gcdoff];
950 	gcd[gcdoff].gd.flags = gg_enabled | gg_visible | (si->join==lj_miter?gg_cb_on:0);
951 	gcd[gcdoff].gd.cid = CID_MiterJoin;
952 	gcd[gcdoff].gd.handle_controlevent = Join_Miter;
953 	gcd[gcdoff++].creator = GRadioCreate;
954 	split[sp][0] = GCD_RowSpan;
955 	split[sp][1] = GCD_HPad10; split[sp][2] = GCD_Glue;
956 	split[sp][3] = &gcd[gcdoff-1];
957 
958 	label[gcdoff].text = (unichar_t *) _("Miter Cli_p");
959 	label[gcdoff].text_is_1byte = true;
960 	label[gcdoff].text_in_resource = true;
961 	gcd[gcdoff].gd.label = &label[gcdoff];
962 	gcd[gcdoff].gd.flags = gg_enabled | gg_visible | (si->join==lj_miterclip?gg_cb_on:0);
963 	gcd[gcdoff].gd.cid = CID_MiterClipJoin;
964 	gcd[gcdoff].gd.handle_controlevent = Join_Miter;
965 	gcd[gcdoff++].creator = GRadioCreate;
966 	split[sp][4] = &gcd[gcdoff-1];
967 	split[sp++][5] = NULL;
968 	split[sp][0] = NULL;
969 
970 	boxes[2].gd.flags = gg_enabled|gg_visible;
971 	boxes[2].gd.u.boxelements = split[0];
972 	boxes[2].creator = GHVGroupCreate;
973 	mainarray[mi][0] = &boxes[2]; mainarray[mi++][1] = NULL;
974 
975 	gcd[gcdoff].gd.flags = gg_enabled|gg_visible;
976 	gcd[gcdoff++].creator = GLineCreate;
977 	mainarray[mi][0] = &gcd[gcdoff-1]; mainarray[mi++][1] = NULL;
978 
979 	label[gcdoff].text = (unichar_t *) _("_Join Limit:");
980 	label[gcdoff].text_is_1byte = true;
981 	label[gcdoff].text_in_resource = true;
982 	gcd[gcdoff].gd.label = &label[gcdoff];
983 	gcd[gcdoff].gd.flags = gg_enabled | gg_visible;
984 	gcd[gcdoff].gd.cid = CID_JoinLimitTxt;
985 	gcd[gcdoff++].creator = GLabelCreate;
986 	jlexarray[0][0] = &gcd[gcdoff-1];
987 
988 	sprintf( jlbuf, "%g", (double) (si->joinlimit) );
989 	label[gcdoff].text = (unichar_t *) jlbuf;
990 	label[gcdoff].text_is_1byte = true;
991 	gcd[gcdoff].gd.pos.width = 50;
992 	gcd[gcdoff].gd.label = &label[gcdoff];
993 	gcd[gcdoff].gd.flags = gg_enabled | gg_visible;
994 	gcd[gcdoff].gd.cid = CID_JoinLimitVal;
995 	gcd[gcdoff].gd.handle_controlevent = Stroke_TextChanged;
996 	tfpos[3] = gcdoff;
997 	gcd[gcdoff++].creator = GTextFieldCreate;
998 	jlexarray[0][1] = &gcd[gcdoff-1];
999 
1000 	label[gcdoff].text = (unichar_t *) _("as _Length");
1001 	label[gcdoff].text_is_1byte = true;
1002 	label[gcdoff].text_in_resource = true;
1003 	gcd[gcdoff].gd.label = &label[gcdoff];
1004 	gcd[gcdoff].gd.flags = gg_enabled | gg_visible | (!si->jlrelative?gg_cb_on:0);
1005 	gcd[gcdoff].gd.cid = CID_JoinLimitLen;
1006 	gcd[gcdoff++].creator = GRadioCreate;
1007 	jlexarray[0][2] = &gcd[gcdoff-1];
1008 
1009 	label[gcdoff].text = (unichar_t *) _("* Nib _Span");
1010 	label[gcdoff].text_is_1byte = true;
1011 	label[gcdoff].text_in_resource = true;
1012 	gcd[gcdoff].gd.label = &label[gcdoff];
1013 	gcd[gcdoff].gd.flags = gg_enabled | gg_visible | (si->jlrelative?gg_cb_on:0);
1014 	gcd[gcdoff].gd.cid = CID_JoinLimitRel;
1015 	gcd[gcdoff++].creator = GRadioCreate;
1016 	jlexarray[0][3] = &gcd[gcdoff-1];
1017 	jlexarray[0][4] = GCD_Glue;
1018 
1019 	label[gcdoff].text = (unichar_t *) _("Accuracy _Target:");
1020 	label[gcdoff].text_is_1byte = true;
1021 	label[gcdoff].text_in_resource = true;
1022 	gcd[gcdoff].gd.label = &label[gcdoff];
1023 	gcd[gcdoff].gd.flags = gg_visible | gg_enabled;
1024 	gcd[gcdoff++].creator = GLabelCreate;
1025 	jlexarray[0][5] = &gcd[gcdoff-1];
1026 
1027 	sprintf( accbuf, "%g", (double) (si->accuracy_target) );
1028 	label[gcdoff].text = (unichar_t *) accbuf;
1029 	label[gcdoff].text_is_1byte = true;
1030 	gcd[gcdoff].gd.pos.width = 50;
1031 	gcd[gcdoff].gd.label = &label[gcdoff];
1032 	gcd[gcdoff].gd.flags = gg_visible | gg_enabled;
1033 	gcd[gcdoff].gd.cid = CID_AccTar;
1034 	gcd[gcdoff].gd.handle_controlevent = Stroke_TextChanged;
1035 	gcd[gcdoff].gd.popup_msg = _(
1036 	    "The stroke algorithm will attempt to be (at least)\n"
1037 	    "this accurate, but there may be exceptions.");
1038 	tfpos[5] = gcdoff;
1039 	gcd[gcdoff++].creator = GTextFieldCreate;
1040 	jlexarray[0][6] = &gcd[gcdoff-1]; jlexarray[0][7] = NULL;
1041 
1042 	label[gcdoff].text = (unichar_t *) _("_Extend Cap:");
1043 	label[gcdoff].text_is_1byte = true;
1044 	label[gcdoff].text_in_resource = true;
1045 	gcd[gcdoff].gd.label = &label[gcdoff];
1046 	gcd[gcdoff].gd.flags = gg_enabled | gg_visible;
1047 	gcd[gcdoff].gd.cid = CID_ExtendCapTxt;
1048 	gcd[gcdoff++].creator = GLabelCreate;
1049 	jlexarray[1][0] = &gcd[gcdoff-1];
1050 
1051 	sprintf( ecbuf, "%g", (double) (si->extendcap) );
1052 	label[gcdoff].text = (unichar_t *) ecbuf;
1053 	label[gcdoff].text_is_1byte = true;
1054 	gcd[gcdoff].gd.pos.width = 50;
1055 	gcd[gcdoff].gd.label = &label[gcdoff];
1056 	gcd[gcdoff].gd.flags = gg_enabled | gg_visible;
1057 	gcd[gcdoff].gd.cid = CID_ExtendCapVal;
1058 	gcd[gcdoff].gd.handle_controlevent = Stroke_TextChanged;
1059 	tfpos[4] = gcdoff;
1060 	gcd[gcdoff++].creator = GTextFieldCreate;
1061 	jlexarray[1][1] = &gcd[gcdoff-1];
1062 
1063 	label[gcdoff].text = (unichar_t *) _("as Len_gth");
1064 	label[gcdoff].text_is_1byte = true;
1065 	label[gcdoff].text_in_resource = true;
1066 	gcd[gcdoff].gd.label = &label[gcdoff];
1067 	gcd[gcdoff].gd.flags = gg_enabled | gg_visible | (!si->ecrelative?gg_cb_on:0);
1068 	gcd[gcdoff].gd.cid = CID_ExtendCapLen;
1069 	gcd[gcdoff++].creator = GRadioCreate;
1070 	jlexarray[1][2] = &gcd[gcdoff-1];
1071 
1072 	label[gcdoff].text = (unichar_t *) _("* Cap Widt_h");
1073 	label[gcdoff].text_is_1byte = true;
1074 	label[gcdoff].text_in_resource = true;
1075 	gcd[gcdoff].gd.label = &label[gcdoff];
1076 	gcd[gcdoff].gd.flags = gg_enabled | gg_visible | (si->ecrelative?gg_cb_on:0);
1077 	gcd[gcdoff].gd.cid = CID_ExtendCapRel;
1078 	gcd[gcdoff++].creator = GRadioCreate;
1079 	jlexarray[1][3] = &gcd[gcdoff-1];
1080 	jlexarray[1][4] = GCD_Glue; jlexarray[1][5] = GCD_Glue;
1081 	jlexarray[1][6] = GCD_Glue; jlexarray[1][7] = NULL;
1082 	jlexarray[2][0] = NULL;
1083 
1084 	boxes[3].gd.flags = gg_enabled|gg_visible;
1085 	boxes[3].gd.u.boxelements = jlexarray[0];
1086 	boxes[3].creator = GHVBoxCreate;
1087 	mainarray[mi][0] = &boxes[3]; mainarray[mi++][1] = NULL;
1088 
1089 	gcd[gcdoff].gd.flags = gg_enabled|gg_visible;
1090 	gcd[gcdoff++].creator = GLineCreate;
1091 	mainarray[mi][0] = &gcd[gcdoff-1]; mainarray[mi++][1] = NULL;
1092 
1093 	label[gcdoff].text = (unichar_t *) _("Remove Overlap:");
1094 	label[gcdoff].text_is_1byte = true;
1095 	label[gcdoff].text_in_resource = true;
1096 	gcd[gcdoff].gd.label = &label[gcdoff];
1097 	gcd[gcdoff].gd.flags = gg_enabled | gg_visible;
1098 	gcd[gcdoff++].creator = GLabelCreate;
1099 	radoptarray[0][0] = &gcd[gcdoff-1]; radoptarray[0][1] = GCD_Glue;
1100 
1101 	label[gcdoff].text = (unichar_t *) _("By La_yer");
1102 	label[gcdoff].text_is_1byte = true;
1103 	label[gcdoff].text_in_resource = true;
1104 	gcd[gcdoff].gd.label = &label[gcdoff];
1105 	gcd[gcdoff].gd.flags = gg_enabled | gg_visible | (si->rmov==srmov_layer?gg_cb_on:0);
1106 	gcd[gcdoff].gd.cid = CID_RmOvLayer;
1107 	gcd[gcdoff++].creator = GRadioCreate;
1108 	radoptarray[0][2] = &gcd[gcdoff-1]; radoptarray[0][3] = GCD_Glue;
1109 
1110 	label[gcdoff].text = (unichar_t *) _("By Con_tour");
1111 	label[gcdoff].text_is_1byte = true;
1112 	label[gcdoff].text_in_resource = true;
1113 	gcd[gcdoff].gd.label = &label[gcdoff];
1114 	gcd[gcdoff].gd.flags = gg_enabled | gg_visible | (si->rmov==srmov_contour?gg_cb_on:0);
1115 	gcd[gcdoff].gd.cid = CID_RmOvContour;
1116 	gcd[gcdoff++].creator = GRadioCreate;
1117 	radoptarray[0][4] = &gcd[gcdoff-1]; radoptarray[0][5] = GCD_Glue;
1118 
1119 	label[gcdoff].text = (unichar_t *) _("N_one (Debug)");
1120 	label[gcdoff].text_is_1byte = true;
1121 	label[gcdoff].text_in_resource = true;
1122 	gcd[gcdoff].gd.label = &label[gcdoff];
1123 	gcd[gcdoff].gd.flags = gg_enabled | gg_visible | (si->rmov==srmov_none?gg_cb_on:0);
1124 	gcd[gcdoff].gd.cid = CID_RmOvNone;
1125 	gcd[gcdoff++].creator = GRadioCreate;
1126 	radoptarray[0][6] = &gcd[gcdoff-1]; radoptarray[0][7] = GCD_Glue;
1127 	radoptarray[0][8] = NULL;
1128 
1129 	label[gcdoff].text = (unichar_t *) _("Contours (from closed):");
1130 	label[gcdoff].text_is_1byte = true;
1131 	label[gcdoff].text_in_resource = true;
1132 	gcd[gcdoff].gd.label = &label[gcdoff];
1133 	gcd[gcdoff].gd.flags = gg_enabled | gg_visible;
1134 	gcd[gcdoff++].creator = GLabelCreate;
1135 	radoptarray[1][0] = &gcd[gcdoff-1]; radoptarray[1][1] = GCD_Glue;
1136 
1137 	label[gcdoff].text = (unichar_t *) _("Both");
1138 	label[gcdoff].text_is_1byte = true;
1139 	label[gcdoff].text_in_resource = true;
1140 	gcd[gcdoff].gd.label = &label[gcdoff];
1141 	gcd[gcdoff].gd.flags = gg_enabled | gg_visible | ((!si->removeinternal && !si->removeexternal)?gg_cb_on:0);
1142 	gcd[gcdoff++].creator = GRadioCreate;
1143 	radoptarray[1][2] = &gcd[gcdoff-1]; radoptarray[1][3] = GCD_Glue;
1144 
1145 	label[gcdoff].text = (unichar_t *) _("External Only");
1146 	label[gcdoff].text_is_1byte = true;
1147 	label[gcdoff].text_in_resource = true;
1148 	gcd[gcdoff].gd.label = &label[gcdoff];
1149 	gcd[gcdoff].gd.flags = gg_enabled | gg_visible | (si->removeinternal?gg_cb_on:0);
1150 	gcd[gcdoff].gd.cid = CID_RmInternal;
1151 	gcd[gcdoff++].creator = GRadioCreate;
1152 	radoptarray[1][4] = &gcd[gcdoff-1]; radoptarray[1][5] = GCD_Glue;
1153 
1154 	label[gcdoff].text = (unichar_t *) _("Internal Only");
1155 	label[gcdoff].text_is_1byte = true;
1156 	label[gcdoff].text_in_resource = true;
1157 	gcd[gcdoff].gd.label = &label[gcdoff];
1158 	gcd[gcdoff].gd.flags = gg_enabled | gg_visible | (si->removeexternal?gg_cb_on:0);
1159 	gcd[gcdoff].gd.cid = CID_RmExternal;
1160 	gcd[gcdoff++].creator = GRadioCreate;
1161 	radoptarray[1][6] = &gcd[gcdoff-1]; radoptarray[1][7] = GCD_Glue;
1162 	radoptarray[1][8] = NULL;
1163 
1164 	label[gcdoff].text = (unichar_t *) _("Arcs Clip:");
1165 	label[gcdoff].text_is_1byte = true;
1166 	label[gcdoff].text_in_resource = true;
1167 	gcd[gcdoff].gd.label = &label[gcdoff];
1168 	gcd[gcdoff].gd.flags = gg_enabled | gg_visible;
1169 	gcd[gcdoff].gd.cid = CID_AlText;
1170 	gcd[gcdoff++].creator = GLabelCreate;
1171 	radoptarray[2][0] = &gcd[gcdoff-1]; radoptarray[2][1] = GCD_Glue;
1172 
1173 	label[gcdoff].text = (unichar_t *) _("Auto");
1174 	label[gcdoff].text_is_1byte = true;
1175 	label[gcdoff].text_in_resource = true;
1176 	gcd[gcdoff].gd.label = &label[gcdoff];
1177 	gcd[gcdoff].gd.flags = gg_enabled | gg_visible | (si->al==sal_auto?gg_cb_on:0);
1178 	gcd[gcdoff].gd.cid = CID_AlAuto;
1179 	gcd[gcdoff++].creator = GRadioCreate;
1180 	radoptarray[2][2] = &gcd[gcdoff-1]; radoptarray[2][3] = GCD_Glue;
1181 
1182 	label[gcdoff].text = (unichar_t *) _("SVG 2");
1183 	label[gcdoff].text_is_1byte = true;
1184 	label[gcdoff].text_in_resource = true;
1185 	gcd[gcdoff].gd.label = &label[gcdoff];
1186 	gcd[gcdoff].gd.flags = gg_enabled | gg_visible | (si->al==sal_svg2?gg_cb_on:0);
1187 	gcd[gcdoff].gd.cid = CID_AlSVG2;
1188 	gcd[gcdoff++].creator = GRadioCreate;
1189 	radoptarray[2][4] = &gcd[gcdoff-1]; radoptarray[2][5] = GCD_Glue;
1190 
1191 	label[gcdoff].text = (unichar_t *) _("Ratio");
1192 	label[gcdoff].text_is_1byte = true;
1193 	label[gcdoff].text_in_resource = true;
1194 	gcd[gcdoff].gd.label = &label[gcdoff];
1195 	gcd[gcdoff].gd.flags = gg_enabled | gg_visible | (si->al==sal_ratio?gg_cb_on:0);
1196 	gcd[gcdoff].gd.cid = CID_AlRatio;
1197 	gcd[gcdoff++].creator = GRadioCreate;
1198 	radoptarray[2][6] = &gcd[gcdoff-1]; radoptarray[2][7] = GCD_Glue;
1199 	radoptarray[2][8] = NULL; radoptarray[3][0] = NULL;
1200 
1201 	boxes[4].gd.flags = gg_enabled|gg_visible;
1202 	boxes[4].gd.u.boxelements = radoptarray[0];
1203 	boxes[4].creator = GHVBoxCreate;
1204 	mainarray[mi][0] = &boxes[4]; mainarray[mi++][1] = NULL;
1205 
1206 	label[gcdoff].text = (unichar_t *) _("S_implify");
1207 	label[gcdoff].text_is_1byte = true;
1208 	label[gcdoff].text_in_resource = true;
1209 	gcd[gcdoff].gd.label = &label[gcdoff];
1210 	gcd[gcdoff].gd.flags = gg_enabled | gg_visible | (si->simplify?gg_cb_on:0);
1211 	gcd[gcdoff].gd.cid = CID_Simplify;
1212 	gcd[gcdoff++].creator = GCheckBoxCreate;
1213 	checkarray[0] = &gcd[gcdoff-1]; checkarray[1] = GCD_Glue;
1214 
1215 	label[gcdoff].text = (unichar_t *) _("A_dd Extrema");
1216 	label[gcdoff].text_is_1byte = true;
1217 	label[gcdoff].text_in_resource = true;
1218 	gcd[gcdoff].gd.label = &label[gcdoff];
1219 	gcd[gcdoff].gd.flags = gg_enabled | gg_visible | (si->extrema?gg_cb_on:0);
1220 	gcd[gcdoff].gd.cid = CID_Extrema;
1221 	gcd[gcdoff++].creator = GCheckBoxCreate;
1222 	checkarray[2] = &gcd[gcdoff-1]; checkarray[3] = GCD_Glue;
1223 	checkarray[4] = NULL;
1224 
1225 	boxes[5].gd.flags = gg_enabled|gg_visible;
1226 	boxes[5].gd.u.boxelements = checkarray;
1227 	boxes[5].creator = GHBoxCreate;
1228 	mainarray[mi][0] = &boxes[5]; mainarray[mi++][1] = NULL;
1229 
1230 	gcd[gcdoff].gd.flags = gg_visible | gg_enabled | gg_but_default;
1231 	label[gcdoff].text = (unichar_t *) _("_OK");
1232 	label[gcdoff].text_is_1byte = true;
1233 	label[gcdoff].text_in_resource = true;
1234 	gcd[gcdoff].gd.label = &label[gcdoff];
1235 	gcd[gcdoff].gd.handle_controlevent = Stroke_OK;
1236 	gcd[gcdoff++].creator = GButtonCreate;
1237 	buttons[0] = GCD_Glue; buttons[1] = &gcd[gcdoff-1]; buttons[2] = GCD_Glue; buttons[3] = GCD_Glue;
1238 
1239 	gcd[gcdoff].gd.flags = gg_visible | gg_enabled;
1240 	label[gcdoff].text = (unichar_t *) _("_Apply");
1241 	label[gcdoff].text_is_1byte = true;
1242 	label[gcdoff].text_in_resource = true;
1243 	gcd[gcdoff].gd.label = &label[gcdoff];
1244 	gcd[gcdoff].gd.handle_controlevent = Stroke_OK;
1245 	gcd[gcdoff].gd.cid = CID_Apply;
1246 	gcd[gcdoff++].creator = GButtonCreate;
1247 	buttons[4] = GCD_Glue; buttons[5] = &gcd[gcdoff-1]; buttons[6] = GCD_Glue; buttons[7] = GCD_Glue;
1248 
1249 	gcd[gcdoff].gd.flags = gg_visible | gg_enabled | gg_but_cancel;
1250 	label[gcdoff].text = (unichar_t *) _("_Cancel");
1251 	label[gcdoff].text_is_1byte = true;
1252 	label[gcdoff].text_in_resource = true;
1253 	gcd[gcdoff].gd.label = &label[gcdoff];
1254 	gcd[gcdoff].gd.handle_controlevent = Stroke_Cancel;
1255 	gcd[gcdoff].creator = GButtonCreate;
1256 	buttons[8] = GCD_Glue; buttons[9] = &gcd[gcdoff]; buttons[10] = GCD_Glue;
1257 	buttons[11] = NULL;
1258 
1259 	boxes[6].gd.flags = gg_enabled|gg_visible;
1260 	boxes[6].gd.u.boxelements = buttons;
1261 	boxes[6].creator = GHBoxCreate;
1262 	mainarray[mi][0] = &boxes[6]; mainarray[mi++][1] = NULL;
1263 	mainarray[mi][0] = GCD_Glue; mainarray[mi++][1] = NULL;
1264 	mainarray[mi][0] = NULL;
1265 
1266 	boxes[0].gd.pos.x = boxes[0].gd.pos.y = 2;
1267 	boxes[0].gd.flags = gg_enabled|gg_visible;
1268 	boxes[0].gd.u.boxelements = mainarray[0];
1269 	boxes[0].gd.cid = CID_TopBox;
1270 	boxes[0].creator = GHVGroupCreate;
1271 
1272 	GGadgetsCreate(gw,boxes);
1273 	GHVBoxSetExpandableRow(boxes[0].ret,1);
1274 	GHVBoxSetExpandableCol(boxes[2].ret,0);
1275 	for (i=3; i<=5; ++i) {
1276 	    GHVBoxSetExpandableCol(boxes[i].ret,gb_expandglue);
1277 	}
1278 	GHVBoxSetExpandableCol(boxes[6].ret,gb_expandgluesame);
1279 	for (i=0; i<6; ++i)
1280 	    GGadgetSetSkipUnQualifiedHotkeyProcessing(gcd[tfpos[i]].ret, 1);
1281 
1282 	StrokeCharViewInits(&sd,CID_Nib);
1283 	sd.cv_stroke.showfore = true;
1284 	sd.cv_stroke.showgrids = true;
1285     }
1286 
1287     Stroke_MakeActive(&sd,&sd.cv_stroke);
1288     Stroke_ShowNib(&sd);
1289 
1290     sd.cv = cv;
1291     sd.strokeit = strokeit;
1292     sd.done = false;
1293     sd.up[0] = sd.up[1] = true;
1294 
1295     GWidgetHidePalettes();
1296     GWidgetIndicateFocusGadget(GWidgetGetControl(sd.gw,CID_Width));
1297 
1298     StrokeSetup(&sd,si->stroke_type);
1299     JoinSetup(&sd,si->join==lj_arcs?2:((si->join==lj_miterclip||si->join==lj_miter)?1:0));
1300     ExtendSetup(&sd,si->cap==lc_butt||si->cap==lc_round);
1301 
1302     GGadgetSetVisible(GWidgetGetControl(sd.gw,CID_Apply), apply);
1303     GWidgetToDesiredSize(sd.gw);
1304 
1305     GDrawSetVisible(sd.gw,true);
1306     while ( !sd.done )
1307 	GDrawProcessOneEvent(NULL);
1308 
1309     CVPalettesHideIfMine(&sd.cv_stroke);
1310     GDrawDestroyWindow(sd.gw);
1311 
1312     do {
1313         GDrawSync(NULL);
1314         GDrawProcessPendingEvents(NULL);
1315     } while (sd.gw != NULL);
1316 
1317     if ( sd.done==1 && si->stroke_type!=si_nib ) {
1318 	assert( si->nib==NULL );
1319 	// Return the edited nib in this case
1320 	si->nib = sd.old_convex;
1321 	sd.old_convex = NULL;
1322 	SplinePointListFree(nib_bk);
1323     } else if ( sd.done==1 ) {
1324 	SplinePointListFree(nib_bk);
1325     } else {
1326 	assert( si->nib==NULL );
1327 	si->nib = nib_bk;
1328 	SplinePointListFree(sd.old_convex);
1329     }
1330 }
1331 
CVStroke(CharView * cv)1332 void CVStroke(CharView *cv) {
1333     if ( cv->b.layerheads[cv->b.drawmode]->splines==NULL )
1334 	return;
1335     MakeStrokeDlg(cv, CVStrokeIt, CVStrokeInfo(), true);
1336 }
1337 
FVStroke(FontView * fv)1338 void FVStroke(FontView *fv) {
1339     MakeStrokeDlg(fv, FVStrokeItScript, CVStrokeInfo(), false);
1340 }
1341 
FreeHandStrokeDlg(StrokeInfo * si)1342 void FreeHandStrokeDlg(StrokeInfo *si) {
1343     MakeStrokeDlg(NULL,NULL,si,false);
1344 }
1345 
1346 /* ************************************************************************** */
1347 /* ****************************** Layer Dialog ****************************** */
1348 /* ************************************************************************** */
1349 #define LY_Width	300
1350 #define LY_Height	336
1351 
1352 #define CID_FillColor		2001
1353 #define CID_FillCInherit	2002
1354 #define CID_FillOpacity		2003
1355 #define CID_FillOInherit	2004
1356 #define CID_StrokeColor		2005
1357 #define CID_StrokeCInherit	2006
1358 #define CID_StrokeOpacity	2007
1359 #define CID_StrokeOInherit	2008
1360 #define CID_StrokeWInherit	2009
1361 #define CID_Trans		2010
1362 #define CID_InheritCap		2011
1363 #define CID_InheritJoin		2012
1364 #define CID_Fill		2013
1365 #define CID_Dashes		2014
1366 #define CID_DashesTxt		2015
1367 #define CID_DashesInherit	2016
1368 #define CID_Stroke		2017
1369 
1370 #define CID_FillGradAdd		2100
1371 #define CID_FillGradEdit	2101
1372 #define CID_FillGradDelete	2102
1373 #define CID_StrokeGradAdd	2110
1374 #define CID_StrokeGradEdit	2111
1375 #define CID_StrokeGradDelete	2112
1376 
1377 #define CID_FillPatAdd		2200
1378 #define CID_FillPatEdit		2201
1379 #define CID_FillPatDelete	2202
1380 #define CID_StrokePatAdd	2210
1381 #define CID_StrokePatEdit	2211
1382 #define CID_StrokePatDelete	2212
1383 
1384 struct layer_dlg {
1385     int done;
1386     int ok;
1387     Layer *layer;
1388     SplineFont *sf;
1389     GWindow gw;
1390     struct gradient *fillgrad, *strokegrad;
1391     struct pattern  *fillpat,  *strokepat;
1392 
1393     int pat_done;
1394     struct pattern *curpat;
1395 };
1396 
1397 #define CID_Gradient	1001
1398 #define CID_Stops	1002
1399 #define CID_Pad		1003
1400 #define	CID_Repeat	1004
1401 #define CID_Reflect	1005
1402 #define CID_Linear	1006
1403 #define CID_Radial	1007
1404 #define CID_GradStops	1008
1405 
GDDSubResize(GradientDlg * gdd,GEvent * event)1406 static void GDDSubResize(GradientDlg *gdd, GEvent *event) {
1407     int width, height;
1408 
1409     if ( !event->u.resize.sized )
1410 return;
1411 
1412     width = event->u.resize.size.width;
1413     height = event->u.resize.size.height;
1414     if ( width!=gdd->cv_width || height!=gdd->cv_height ) {
1415 	gdd->cv_width = width; gdd->cv_height = height;
1416 	GDrawResize(gdd->cv_grad.gw,width,height);
1417     }
1418 
1419     GDrawSync(NULL);
1420     GDrawProcessPendingEvents(NULL);
1421 }
1422 
GDDDraw(GradientDlg * gdd,GWindow pixmap,GEvent * event)1423 static void GDDDraw(GradientDlg *gdd, GWindow pixmap, GEvent *event) {
1424     GRect r,pos;
1425 
1426     GGadgetGetSize(GWidgetGetControl(gdd->gw,CID_Gradient),&pos);
1427     r.x = pos.x-1; r.y = pos.y-1;
1428     r.width = pos.width+1; r.height = pos.height+1;
1429     GDrawDrawRect(pixmap,&r,0);
1430 }
1431 
GDDMakeActive(GradientDlg * gdd,CharView * cv)1432 static void GDDMakeActive(GradientDlg *gdd,CharView *cv) {
1433 
1434     if ( gdd==NULL )
1435 return;
1436     cv->inactive = false;
1437     GDrawSetUserData(gdd->gw,cv);
1438     GDrawRequestExpose(cv->v,NULL,false);
1439     GDrawRequestExpose(gdd->gw,NULL,false);
1440 }
1441 
GDDChar(GradientDlg * gdd,GEvent * event)1442 static void GDDChar(GradientDlg *gdd, GEvent *event) {
1443     CVChar((&gdd->cv_grad),event);
1444 }
1445 
GDD_DoClose(struct cvcontainer * cvc)1446 static void GDD_DoClose(struct cvcontainer *cvc) {
1447     GradientDlg *gdd = (GradientDlg *) cvc;
1448 
1449      {
1450 	SplineChar *msc = &gdd->sc_grad;
1451 	SplinePointListsFree(msc->layers[0].splines);
1452 	SplinePointListsFree(msc->layers[1].splines);
1453 	free( msc->layers );
1454     }
1455 
1456     gdd->done = true;
1457 }
1458 
gdd_sub_e_h(GWindow gw,GEvent * event)1459 static int gdd_sub_e_h(GWindow gw, GEvent *event) {
1460     GradientDlg *gdd = (GradientDlg *) ((CharViewBase *) GDrawGetUserData(gw))->container;
1461 
1462     switch ( event->type ) {
1463       case et_resize:
1464 	if ( event->u.resize.sized )
1465 	    GDDSubResize(gdd,event);
1466       break;
1467       case et_char:
1468 	GDDChar(gdd,event);
1469       break;
1470       case et_mouseup: case et_mousedown: case et_mousemove:
1471 return( false );
1472       break;
1473     }
1474 return( true );
1475 }
1476 
gdd_e_h(GWindow gw,GEvent * event)1477 static int gdd_e_h(GWindow gw, GEvent *event) {
1478     GradientDlg *gdd = (GradientDlg *) ((CharViewBase *) GDrawGetUserData(gw))->container;
1479 
1480     switch ( event->type ) {
1481       case et_expose:
1482 	GDDDraw(gdd, gw, event);
1483       break;
1484       case et_char:
1485 	GDDChar(gdd,event);
1486       break;
1487       case et_close:
1488 	GDD_DoClose((struct cvcontainer *) gdd);
1489       break;
1490       case et_create:
1491       break;
1492       case et_map:
1493 	 {
1494 	    CharView *cv = (&gdd->cv_grad);
1495 	    if ( !cv->inactive ) {
1496 		if ( event->u.map.is_visible )
1497 		    CVPaletteActivate(cv);
1498 		else
1499 		    CVPalettesHideIfMine(cv);
1500 	    }
1501 	}
1502 	/* gdd->isvisible = event->u.map.is_visible; */
1503       break;
1504     }
1505 return( true );
1506 }
1507 
Gradient_Cancel(GGadget * g,GEvent * e)1508 static int Gradient_Cancel(GGadget *g, GEvent *e) {
1509     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
1510 	GradientDlg *gdd = (GradientDlg *) (((CharViewBase *) GDrawGetUserData(GGadgetGetWindow(g)))->container);
1511 	GDD_DoClose(&gdd->base);
1512     }
1513 return( true );
1514 }
1515 
orderstops(const void * _md1,const void * _md2)1516 static int orderstops(const void *_md1, const void *_md2) {
1517     const struct matrix_data *md1 = _md1, *md2 = _md2;
1518 
1519     if ( md1->u.md_real>md2->u.md_real )
1520 return( 1 );
1521     else if ( md1->u.md_real==md2->u.md_real )
1522 return( 0 );
1523     else
1524 return( -1 );
1525 }
1526 
Gradient_OK(GGadget * g,GEvent * e)1527 static int Gradient_OK(GGadget *g, GEvent *e) {
1528     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
1529 	GradientDlg *gdd = (GradientDlg *) (((CharViewBase *) GDrawGetUserData(GGadgetGetWindow(g)))->container);
1530 	struct gradient *gradient = gdd->active;
1531 	BasePoint start, end, offset;
1532 	real radius;
1533 	int pad, linear;
1534 	SplineSet *ss, *ss2;
1535 	int i, rows, cols = GMatrixEditGetColCnt(GWidgetGetControl(gdd->gw,CID_GradStops));
1536 	struct matrix_data *md = GMatrixEditGet(GWidgetGetControl(gdd->gw,CID_GradStops), &rows);
1537 
1538 	if ( rows<2 ) {
1539 	    ff_post_error(_("Bad Gradient"),_("There must be at least 2 gradient stops"));
1540 return( true );
1541 	}
1542 	for ( i=0; i<rows; ++i ) {
1543 	    if ( md[cols*i+0].u.md_real<0 || md[cols*i+0].u.md_real>100.0 ) {
1544 		ff_post_error(_("Bad Gradient"),_("Bad offset on line %d, must be between 0% and 100%."), i );
1545 return( true );
1546 	    }
1547 	    if ( md[cols*i+1].u.md_ival<0 || md[cols*i+1].u.md_ival>0xffffff ) {
1548 		ff_post_error(_("Bad Gradient"),_("Bad color on line %d, must be between 000000 and ffffff."), i );
1549 return( true );
1550 	    }
1551 	    if ( md[cols*i+2].u.md_real<0 || md[cols*i+2].u.md_real>1.0 ) {
1552 		ff_post_error(_("Bad Gradient"),_("Bad opacity on line %d, must be between 0.0 and 1.0."), i );
1553 return( true );
1554 	    }
1555 	}
1556 
1557 	linear = GGadgetIsChecked(GWidgetGetControl(gdd->gw,CID_Linear));
1558 	if ( GGadgetIsChecked(GWidgetGetControl(gdd->gw,CID_Pad)) )
1559 	    pad = sm_pad;
1560 	else if ( GGadgetIsChecked(GWidgetGetControl(gdd->gw,CID_Repeat)) )
1561 	    pad = sm_repeat;
1562 	else
1563 	    pad = sm_reflect;
1564 	ss = gdd->sc_grad.layers[ly_fore].splines;
1565 	if ( ss==NULL || gdd->sc_grad.layers[ly_fore].refs!=NULL ||
1566 		(linear && ss->next!=NULL) ||
1567 		(!linear && ss->next!=NULL && ss->next->next!=NULL)) {
1568 	    ff_post_error(_("Bad Gradient"),_("You must draw a line"));
1569 return( true );
1570 	}
1571 	ss2 = NULL;
1572 	if ( !linear && ss->next!=NULL ) {
1573 	    if ( ss->first->next==NULL ) {
1574 		ss2 = ss;
1575 		ss = ss2->next;
1576 	    } else {
1577 		ss2 = ss->next;
1578 		if ( ss2->first->next!=NULL ) {
1579 		    ff_post_error(_("Bad Gradient"),_("You must draw a line, with at most one additional point"));
1580 return( true );
1581 		}
1582 	    }
1583 	}
1584 	if ( (ss->first->next==NULL || ss->first==ss->last ||
1585 		ss->first->next->to->next!=NULL ) ||
1586 		!ss->first->next->islinear ) {
1587 	    ff_post_error(_("Bad Gradient"),_("You must draw a line"));
1588 return( true );
1589 	}
1590 
1591 	if ( linear ) {
1592 	    start = ss->first->me;
1593 	    end = ss->last->me;
1594 	    radius = 0;
1595 	} else {
1596 	    end = ss->first->me;
1597 	    offset.x = ss->last->me.x-end.x;
1598 	    offset.y = ss->last->me.y-end.y;
1599 	    radius = sqrt(offset.x*offset.x + offset.y*offset.y);
1600 	    if ( ss2!=NULL )
1601 		start = ss2->first->me;
1602 	    else
1603 		start = end;
1604 	}
1605 	if ( gradient==NULL )
1606 	    gdd->active = gradient = chunkalloc(sizeof(struct gradient));
1607 	gradient->start = start;
1608 	gradient->stop = end;
1609 	gradient->radius = radius;
1610 	gradient->sm = pad;
1611 
1612 	/* Stops must be stored in ascending order */
1613 	qsort(md,rows,cols*sizeof(struct matrix_data),orderstops);
1614 	gradient->grad_stops = realloc(gradient->grad_stops,rows*sizeof(struct grad_stops));
1615 	gradient->stop_cnt = rows;
1616 	for ( i=0; i<rows; ++i ) {
1617 	    gradient->grad_stops[i].offset  = md[cols*i+0].u.md_real/100.0;
1618 	    gradient->grad_stops[i].col     = md[cols*i+1].u.md_ival;
1619 	    gradient->grad_stops[i].opacity = md[cols*i+2].u.md_real;
1620 	}
1621 
1622 	GDD_DoClose(&gdd->base);
1623 	gdd->oked = true;
1624     }
1625 return( true );
1626 }
1627 
GDD_Can_Navigate(struct cvcontainer * cvc,enum nav_type type)1628 static int GDD_Can_Navigate(struct cvcontainer *cvc, enum nav_type type) {
1629 return( false );
1630 }
1631 
GDD_Can_Open(struct cvcontainer * cvc)1632 static int GDD_Can_Open(struct cvcontainer *cvc) {
1633 return( false );
1634 }
1635 
SF_Of_GDD(struct cvcontainer * foo)1636 static SplineFont *SF_Of_GDD(struct cvcontainer *foo) {
1637 return( NULL );
1638 }
1639 
1640 struct cvcontainer_funcs gradient_funcs = {
1641     cvc_gradient,
1642     (void (*) (struct cvcontainer *cvc,CharViewBase *cv)) GDDMakeActive,
1643     (void (*) (struct cvcontainer *cvc,void *)) GDDChar,
1644     GDD_Can_Navigate,
1645     NULL,
1646     GDD_Can_Open,
1647     GDD_DoClose,
1648     SF_Of_GDD
1649 };
1650 
1651 
GDDInit(GradientDlg * gdd,SplineFont * sf,Layer * ly,struct gradient * grad)1652 static void GDDInit(GradientDlg *gdd,SplineFont *sf,Layer *ly,struct gradient *grad) {
1653 
1654     memset(gdd,0,sizeof(*gdd));
1655     gdd->base.funcs = &gradient_funcs;
1656 
1657     {
1658 	SplineChar *msc = (&gdd->sc_grad);
1659 	CharView *mcv = (&gdd->cv_grad);
1660 	msc->orig_pos = 0;
1661 	msc->unicodeenc = -1;
1662 	msc->name = "Gradient";
1663 	msc->parent = &gdd->dummy_sf;
1664 	msc->layer_cnt = 2;
1665 	msc->layers = calloc(2,sizeof(Layer));
1666 	LayerDefault(&msc->layers[0]);
1667 	LayerDefault(&msc->layers[1]);
1668 	gdd->chars[0] = msc;
1669 
1670 	mcv->b.sc = msc;
1671 	mcv->b.layerheads[dm_fore] = &msc->layers[ly_fore];
1672 	mcv->b.layerheads[dm_back] = &msc->layers[ly_back];
1673 	mcv->b.layerheads[dm_grid] = &gdd->dummy_sf.grid;
1674 	mcv->b.drawmode = dm_fore;
1675 	mcv->b.container = (struct cvcontainer *) gdd;
1676 	mcv->inactive = false;
1677     }
1678     gdd->dummy_sf.glyphs = gdd->chars;
1679     gdd->dummy_sf.glyphcnt = gdd->dummy_sf.glyphmax = 1;
1680     gdd->dummy_sf.pfminfo.fstype = -1;
1681     gdd->dummy_sf.pfminfo.stylemap = -1;
1682     gdd->dummy_sf.fontname = gdd->dummy_sf.fullname = gdd->dummy_sf.familyname = "dummy";
1683     gdd->dummy_sf.weight = "Medium";
1684     gdd->dummy_sf.origname = "dummy";
1685     gdd->dummy_sf.ascent = sf->ascent;
1686     gdd->dummy_sf.descent = sf->descent;
1687     gdd->dummy_sf.layers = gdd->layerinfo;
1688     gdd->dummy_sf.layer_cnt = 2;
1689     gdd->layerinfo[ly_back].order2 = sf->layers[ly_back].order2;
1690     gdd->layerinfo[ly_back].name = _("Back");
1691     gdd->layerinfo[ly_fore].order2 = sf->layers[ly_fore].order2;
1692     gdd->layerinfo[ly_fore].name = _("Fore");
1693     gdd->dummy_sf.grid.order2 = sf->grid.order2;
1694     gdd->dummy_sf.anchor = NULL;
1695 
1696     gdd->dummy_sf.fv = (FontViewBase *) &gdd->dummy_fv;
1697     gdd->dummy_fv.b.active_layer = ly_fore;
1698     gdd->dummy_fv.b.sf = &gdd->dummy_sf;
1699     gdd->dummy_fv.b.selected = gdd->sel;
1700     gdd->dummy_fv.cbw = gdd->dummy_fv.cbh = default_fv_font_size+1;
1701     gdd->dummy_fv.magnify = 1;
1702 
1703     gdd->dummy_fv.b.map = &gdd->dummy_map;
1704     gdd->dummy_map.map = gdd->map;
1705     gdd->dummy_map.backmap = gdd->backmap;
1706     gdd->dummy_map.enccount = gdd->dummy_map.encmax = gdd->dummy_map.backmax = 1;
1707     gdd->dummy_map.enc = &custom;
1708 
1709     if ( grad!=NULL ) {
1710 	SplineSet *ss1, *ss2;
1711 	SplinePoint *sp1, *sp2, *sp3;
1712 	ss1 = chunkalloc(sizeof(SplineSet));
1713 	sp2 = SplinePointCreate(grad->stop.x,grad->stop.y);
1714 	if ( grad->radius==0 ) {
1715 	    sp1 = SplinePointCreate(grad->start.x,grad->start.y);
1716 	    SplineMake(sp1,sp2,sf->layers[ly_fore].order2);
1717 	    ss1->first = sp1; ss1->last = sp2;
1718 	} else {
1719 	    sp3 = SplinePointCreate(grad->start.x+grad->radius,grad->start.y);
1720 	    SplineMake(sp2,sp3,sf->layers[ly_fore].order2);
1721 	    ss1->first = sp2; ss1->last = sp3;
1722 	    if ( grad->start.x!=grad->stop.x || grad->start.y!=grad->stop.y ) {
1723 		ss2 = chunkalloc(sizeof(SplineSet));
1724 		sp1 = SplinePointCreate(grad->start.x,grad->start.y);
1725 		ss2->first = ss2->last = sp1;
1726 		ss1->next = ss2;
1727 	    }
1728 	}
1729 	gdd->sc_grad.layers[ly_fore].splines = ss1;
1730     }
1731 
1732     gdd->sc_grad.layers[ly_back]. splines = SplinePointListCopy( LayerAllSplines(ly));
1733     LayerUnAllSplines(ly);
1734 }
1735 
1736 static struct col_init stopci[] = {
1737     { me_real , NULL, NULL, NULL, N_("Offset %") },
1738     { me_hex, NULL, NULL, NULL, N_("Color") },
1739     { me_real, NULL, NULL, NULL, N_("Opacity") }
1740     };
1741 
Grad_CanDelete(GGadget * g,int row)1742 static int Grad_CanDelete(GGadget *g,int row) {
1743     int rows;
1744     struct matrix_data *md = GMatrixEditGet(g, &rows);
1745     if ( md==NULL )
1746 return( false );
1747 
1748     /* There must always be at least two entries in the table */
1749 return( rows>2 );
1750 }
1751 
Grad_NewRow(GGadget * g,int row)1752 static void Grad_NewRow(GGadget *g,int row) {
1753     int rows;
1754     struct matrix_data *md = GMatrixEditGet(g, &rows);
1755     if ( md==NULL )
1756 return;
1757 
1758     md[3*row+2].u.md_real = 1.0;
1759 }
1760 
StopMatrixInit(struct matrixinit * mi,struct gradient * grad)1761 static void StopMatrixInit(struct matrixinit *mi,struct gradient *grad) {
1762     int i;
1763     struct matrix_data *md;
1764 
1765     memset(mi,0,sizeof(*mi));
1766     mi->col_cnt = 3;
1767     mi->col_init = stopci;
1768 
1769     if ( grad==NULL ) {
1770 	md = calloc(2*mi->col_cnt,sizeof(struct matrix_data));
1771 	md[3*0+0].u.md_real = 0;
1772 	md[3*0+1].u.md_ival = 0x000000;
1773 	md[3*0+2].u.md_real = 1;
1774 	md[3*1+0].u.md_real = 100;
1775 	md[3*1+1].u.md_ival = 0xffffff;
1776 	md[3*1+2].u.md_real = 1;
1777 	mi->initial_row_cnt = 2;
1778     } else {
1779 	md = calloc(3*grad->stop_cnt,sizeof(struct matrix_data));
1780 	for ( i=0; i<grad->stop_cnt; ++i ) {
1781 	    md[3*i+0].u.md_real = grad->grad_stops[i].offset*100.0;
1782 	    md[3*i+1].u.md_ival = grad->grad_stops[i].col;
1783 	    md[3*i+2].u.md_real = grad->grad_stops[i].opacity;
1784 	}
1785 	mi->initial_row_cnt = grad->stop_cnt;
1786     }
1787     mi->matrix_data = md;
1788 
1789     mi->initrow = Grad_NewRow;
1790     mi->candelete = Grad_CanDelete;
1791 }
1792 
GradientEdit(struct layer_dlg * ld,struct gradient * active)1793 static struct gradient *GradientEdit(struct layer_dlg *ld,struct gradient *active) {
1794     GradientDlg gdd;
1795     GRect pos;
1796     GWindow gw;
1797     GWindowAttrs wattrs;
1798     GGadgetCreateData gcd[14], boxes[5], *harray[8], *varray[10],
1799 	*rharray[5], *gtarray[5];
1800     GTextInfo label[14];
1801     int j,k;
1802     struct matrixinit stopmi;
1803 
1804     GDDInit( &gdd,ld->sf,ld->layer,active );
1805     gdd.active = active;
1806 
1807     memset(&wattrs,0,sizeof(wattrs));
1808     wattrs.mask = wam_events|wam_cursor|wam_isdlg|wam_restrict|wam_undercursor|wam_utf8_wtitle;
1809     wattrs.is_dlg = true;
1810     wattrs.restrict_input_to_me = 1;
1811     wattrs.undercursor = 1;
1812     wattrs.event_masks = -1;
1813     wattrs.cursor = ct_pointer;
1814     wattrs.utf8_window_title = _("Gradient");
1815     pos.width = 600;
1816     pos.height = 300;
1817     gdd.gw = gw = GDrawCreateTopWindow(NULL,&pos,gdd_e_h,&gdd.cv_grad,&wattrs);
1818 
1819     memset(&label,0,sizeof(label));
1820     memset(&gcd,0,sizeof(gcd));
1821     memset(&boxes,0,sizeof(boxes));
1822 
1823     k = j = 0;
1824     gcd[k].gd.flags = gg_visible|gg_enabled ;		/* This space is for the menubar */
1825     gcd[k].gd.pos.height = 18; gcd[k].gd.pos.width = 20;
1826     gcd[k++].creator = GSpacerCreate;
1827     varray[j++] = &gcd[k-1];
1828 
1829     label[k].text = (unichar_t *) _(
1830 	"  A linear gradient is represented by a line drawn\n"
1831 	"from its start point to its end point.\n"
1832 	"  A radial gradient is represented by a line drawn\n"
1833 	"from its center whose length is the ultimate radius.\n"
1834 	"If there is a single additional point, that point\n"
1835 	"represents the gradient's focus, if omitted the focus\n"
1836 	"is the same as the radius." );
1837     label[k].text_is_1byte = true;
1838     gcd[k].gd.label = &label[k];
1839     gcd[k].gd.flags = gg_enabled | gg_visible;
1840     gcd[k++].creator = GLabelCreate;
1841     varray[j++] = &gcd[k-1];
1842 
1843     gcd[k].gd.flags = gg_visible | gg_enabled;
1844     label[k].text = (unichar_t *) _("Linear");
1845     label[k].text_is_1byte = true;
1846     label[k].text_in_resource = true;
1847     gcd[k].gd.label = &label[k];
1848     gcd[k].gd.popup_msg = _(
1849 	    "The gradient will be a linear gradient,\n"
1850 	    "With the color change happening along\n"
1851 	    "the line drawn in the view" );
1852     gcd[k].gd.cid = CID_Linear;
1853     gcd[k++].creator = GRadioCreate;
1854     gtarray[0] = &gcd[k-1];
1855 
1856     gcd[k].gd.flags = gg_visible | gg_enabled;
1857     label[k].text = (unichar_t *) _("Radial");
1858     label[k].text_is_1byte = true;
1859     label[k].text_in_resource = true;
1860     gcd[k].gd.label = &label[k];
1861     gcd[k].gd.popup_msg = _(
1862 	    "The gradient will be a radial gradient,\n"
1863 	    "With the color change happening in circles\n"
1864 	    "starting at the focus (if specified) and\n"
1865 	    "extending outward until it reaches the\n"
1866 	    "specified radius." );
1867     gcd[k].gd.cid = CID_Radial;
1868     gcd[k++].creator = GRadioCreate;
1869     gtarray[1] = &gcd[k-1]; gtarray[2] = GCD_Glue; gtarray[3] = NULL;
1870 
1871     boxes[4].gd.flags = gg_enabled|gg_visible;
1872     boxes[4].gd.u.boxelements = gtarray;
1873     boxes[4].creator = GHBoxCreate;
1874     varray[j++] = &boxes[4];
1875 
1876     gcd[k].gd.pos.width = gcd[k].gd.pos.height = 200;
1877     gcd[k].gd.flags = gg_visible | gg_enabled;
1878     gcd[k].gd.cid = CID_Gradient;
1879     gcd[k].gd.u.drawable_e_h = gdd_sub_e_h;
1880     gcd[k++].creator = GDrawableCreate;
1881     varray[j++] = &gcd[k-1];
1882 
1883     gcd[k].gd.flags = gg_visible | gg_enabled;
1884     label[k].text = (unichar_t *) _("_Pad");
1885     label[k].text_is_1byte = true;
1886     label[k].text_in_resource = true;
1887     gcd[k].gd.label = &label[k];
1888     gcd[k].gd.popup_msg = _("Beyond the endpoints, the gradient takes on the color at the end-points\n"
1889 		"This does not work for PostScript linear gradients");
1890     gcd[k].gd.cid = CID_Pad;
1891     gcd[k++].creator = GRadioCreate;
1892     rharray[0] = &gcd[k-1];
1893 
1894     gcd[k].gd.flags = gg_visible | gg_enabled;
1895     label[k].text = (unichar_t *) _("Repeat");
1896     label[k].text_is_1byte = true;
1897     label[k].text_in_resource = true;
1898     gcd[k].gd.label = &label[k];
1899     gcd[k].gd.popup_msg = _("Beyond the endpoints the gradient repeats itself\n"
1900 	    "This does not work for PostScript gradients." );
1901     gcd[k].gd.cid = CID_Repeat;
1902     gcd[k++].creator = GRadioCreate;
1903     rharray[1] = &gcd[k-1];
1904 
1905     gcd[k].gd.flags = gg_visible | gg_enabled;
1906     label[k].text = (unichar_t *) _("Reflect");
1907     label[k].text_is_1byte = true;
1908     label[k].text_in_resource = true;
1909     gcd[k].gd.label = &label[k];
1910     gcd[k].gd.popup_msg = _("Beyond the endpoint the gradient repeats itself, but reflected.\n"
1911 	    "This does not work for PostScript gradients");
1912     gcd[k].gd.cid = CID_Reflect;
1913     gcd[k++].creator = GRadioCreate;
1914     rharray[2] = &gcd[k-1];
1915     rharray[3] = GCD_Glue; rharray[4] = NULL;
1916 
1917     boxes[2].gd.flags = gg_enabled|gg_visible;
1918     boxes[2].gd.u.boxelements = rharray;
1919     boxes[2].creator = GHBoxCreate;
1920     varray[j++] = &boxes[2];
1921 
1922     label[k].text = (unichar_t *) _(
1923 	    "Specify the color (& opacity) at stop points\n"
1924 	    "along the line drawn above. The offset is a\n"
1925 	    "percentage of the distance from the start to\n"
1926 	    "the end of the line. The color is a 6 (hex)\n"
1927 	    "digit number expressing an RGB color.");
1928     label[k].text_is_1byte = true;
1929     gcd[k].gd.label = &label[k];
1930     gcd[k].gd.flags = gg_enabled | gg_visible;
1931     gcd[k++].creator = GLabelCreate;
1932     varray[j++] = &gcd[k-1];
1933 
1934     StopMatrixInit(&stopmi,active);
1935 
1936     gcd[k].gd.pos.width = 300; gcd[k].gd.pos.height = 200;
1937     gcd[k].gd.flags = gg_enabled | gg_visible;
1938     gcd[k].gd.cid = CID_GradStops;
1939     gcd[k].gd.u.matrix = &stopmi;
1940     gcd[k++].creator = GMatrixEditCreate;
1941     varray[j++] = &gcd[k-1];
1942 
1943     label[k].text = (unichar_t *) _("_OK");
1944     label[k].text_is_1byte = true;
1945     label[k].text_in_resource = true;
1946     gcd[k].gd.label = &label[k];
1947     gcd[k].gd.flags = gg_enabled|gg_visible|gg_but_default;
1948     gcd[k].gd.handle_controlevent = Gradient_OK;
1949     gcd[k++].creator = GButtonCreate;
1950 
1951     label[k].text = (unichar_t *) _("_Cancel");
1952     label[k].text_is_1byte = true;
1953     label[k].text_in_resource = true;
1954     gcd[k].gd.label = &label[k];
1955     gcd[k].gd.flags = gg_enabled|gg_visible|gg_but_cancel;
1956     gcd[k].gd.handle_controlevent = Gradient_Cancel;
1957     gcd[k++].creator = GButtonCreate;
1958 
1959     harray[0] = GCD_Glue; harray[1] = &gcd[k-2]; harray[2] = GCD_Glue;
1960     harray[3] = GCD_Glue; harray[4] = &gcd[k-1]; harray[5] = GCD_Glue;
1961     harray[6] = NULL;
1962 
1963     boxes[3].gd.flags = gg_enabled|gg_visible;
1964     boxes[3].gd.u.boxelements = harray;
1965     boxes[3].creator = GHBoxCreate;
1966     varray[j++] = &boxes[3];
1967     varray[j] = NULL;
1968 
1969     boxes[0].gd.flags = gg_enabled|gg_visible;
1970     boxes[0].gd.u.boxelements = varray;
1971     boxes[0].creator = GVBoxCreate;
1972 
1973     GGadgetsCreate(gw,boxes);
1974 
1975     GDDCharViewInits(&gdd,CID_Gradient);
1976 
1977     GHVBoxSetExpandableRow(boxes[0].ret,3);
1978     GHVBoxSetExpandableCol(boxes[2].ret,gb_expandgluesame);
1979     GHVBoxSetExpandableRow(boxes[3].ret,gb_expandgluesame);
1980     GGadgetResize(boxes[0].ret,pos.width,pos.height);
1981 
1982     if ( active!=NULL ) {
1983 	GGadgetSetChecked(GWidgetGetControl(gw,CID_Linear),active->radius==0);
1984 	GGadgetSetChecked(GWidgetGetControl(gw,CID_Radial),active->radius!=0);
1985 	GGadgetSetChecked(GWidgetGetControl(gw,CID_Pad),active->sm==sm_pad);
1986 	GGadgetSetChecked(GWidgetGetControl(gw,CID_Reflect),active->sm==sm_reflect);
1987 	GGadgetSetChecked(GWidgetGetControl(gw,CID_Repeat),active->sm==sm_repeat);
1988     } else {
1989 	GGadgetSetChecked(GWidgetGetControl(gw,CID_Linear),true);
1990 	GGadgetSetChecked(GWidgetGetControl(gw,CID_Pad),true);
1991     }
1992 
1993     GDDMakeActive(&gdd,&gdd.cv_grad);
1994 
1995     GDrawResize(gw,400,768);		/* Force a resize event */
1996 
1997     GDrawSetVisible(gdd.gw,true);
1998 
1999     while ( !gdd.done )
2000 	GDrawProcessOneEvent(NULL);
2001 
2002     {
2003 	CharView *cv = &gdd.cv_grad;
2004 	if ( cv->backimgs!=NULL ) {
2005 	    GDrawDestroyWindow(cv->backimgs);
2006 	    cv->backimgs = NULL;
2007 	}
2008 	CVPalettesHideIfMine(cv);
2009     }
2010     GDrawDestroyWindow(gdd.gw);
2011     /* Now because the cv of the nested window is on the stack, we need to */
2012     /*  handle its destruction HERE while that stack location still makes */
2013     /*  sense. Can't do it in whoever calls us */
2014     GDrawSync(NULL);
2015     GDrawProcessPendingEvents(NULL);
2016     GDrawSync(NULL);
2017     GDrawProcessPendingEvents(NULL);
2018 return( gdd.active );
2019 }
2020 
Layer_GradSet(struct layer_dlg * ld)2021 static void Layer_GradSet(struct layer_dlg *ld) {
2022     GGadgetSetEnabled(GWidgetGetControl(ld->gw,CID_FillGradAdd),ld->fillgrad==NULL);
2023     GGadgetSetEnabled(GWidgetGetControl(ld->gw,CID_FillGradEdit),ld->fillgrad!=NULL);
2024     GGadgetSetEnabled(GWidgetGetControl(ld->gw,CID_FillGradDelete),ld->fillgrad!=NULL);
2025     GGadgetSetEnabled(GWidgetGetControl(ld->gw,CID_StrokeGradAdd),ld->strokegrad==NULL);
2026     GGadgetSetEnabled(GWidgetGetControl(ld->gw,CID_StrokeGradEdit),ld->strokegrad!=NULL);
2027     GGadgetSetEnabled(GWidgetGetControl(ld->gw,CID_StrokeGradDelete),ld->strokegrad!=NULL);
2028 }
2029 
Layer_FillGradDelete(GGadget * g,GEvent * e)2030 static int Layer_FillGradDelete(GGadget *g, GEvent *e) {
2031 
2032     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
2033 	struct layer_dlg *ld = GDrawGetUserData(GGadgetGetWindow(g));
2034 	GradientFree(ld->fillgrad);
2035 	ld->fillgrad=NULL;
2036 	Layer_GradSet(ld);
2037     }
2038 return( true );
2039 }
2040 
Layer_FillGradAddEdit(GGadget * g,GEvent * e)2041 static int Layer_FillGradAddEdit(GGadget *g, GEvent *e) {
2042 
2043     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
2044 	struct layer_dlg *ld = GDrawGetUserData(GGadgetGetWindow(g));
2045 	ld->fillgrad = GradientEdit(ld,ld->fillgrad);
2046 	Layer_GradSet(ld);
2047     }
2048 return( true );
2049 }
2050 
Layer_StrokeGradDelete(GGadget * g,GEvent * e)2051 static int Layer_StrokeGradDelete(GGadget *g, GEvent *e) {
2052 
2053     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
2054 	struct layer_dlg *ld = GDrawGetUserData(GGadgetGetWindow(g));
2055 	GradientFree(ld->strokegrad);
2056 	ld->strokegrad=NULL;
2057 	Layer_GradSet(ld);
2058     }
2059 return( true );
2060 }
2061 
Layer_StrokeGradAddEdit(GGadget * g,GEvent * e)2062 static int Layer_StrokeGradAddEdit(GGadget *g, GEvent *e) {
2063 
2064     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
2065 	struct layer_dlg *ld = GDrawGetUserData(GGadgetGetWindow(g));
2066 	ld->strokegrad = GradientEdit(ld,ld->strokegrad);
2067 	Layer_GradSet(ld);
2068     }
2069 return( true );
2070 }
2071 
2072 #define CID_PatternName	1001
2073 #define CID_Skew	1002
2074 #define CID_Rotate	1003
2075 #define	CID_TransX	1004
2076 #define CID_TransY	1005
2077 #define CID_Transform	1006
2078 #define CID_Aspect	1007
2079 #define CID_TWidth	1008
2080 #define CID_THeight	1009
2081 
Pat_WidthChanged(GGadget * g,GEvent * e)2082 static int Pat_WidthChanged(GGadget *g, GEvent *e) {
2083 
2084     if ( e->type==et_controlevent &&
2085 	    (e->u.control.subtype == et_textchanged ||
2086 	     e->u.control.subtype == et_radiochanged)) {
2087 	GWindow gw = GGadgetGetWindow(g);
2088 	struct layer_dlg *ld = GDrawGetUserData(gw);
2089 	char *name = GGadgetGetTitle8(GWidgetGetControl(gw,CID_PatternName));
2090 	SplineChar *patternsc = SFGetChar(ld->sf,-1,name);
2091 	DBounds b;
2092 	int err = false;
2093 	real height, width;
2094 	char buffer[50];
2095 
2096 	free(name);
2097 	if ( patternsc==NULL )
2098 return( true );
2099 	if ( !GGadgetIsChecked(GWidgetGetControl(gw,CID_Aspect)))
2100 return( true );
2101 	width = GetCalmReal8(gw,CID_TWidth,_("Width"),&err);
2102 	if ( err )
2103 return( true );
2104 	PatternSCBounds(patternsc,&b);
2105 	height = width * (b.maxy - b.miny)/(b.maxx - b.minx);
2106 	sprintf( buffer, "%g", (double) height );
2107 	GGadgetSetTitle8(GWidgetGetControl(gw,CID_THeight), buffer);
2108     }
2109 return( true );
2110 }
2111 
Pat_HeightChanged(GGadget * g,GEvent * e)2112 static int Pat_HeightChanged(GGadget *g, GEvent *e) {
2113 
2114     if ( e->type==et_controlevent && e->u.control.subtype == et_textchanged ) {
2115 	GWindow gw = GGadgetGetWindow(g);
2116 	struct layer_dlg *ld = GDrawGetUserData(gw);
2117 	char *name = GGadgetGetTitle8(GWidgetGetControl(gw,CID_PatternName));
2118 	SplineChar *patternsc = SFGetChar(ld->sf,-1,name);
2119 	DBounds b;
2120 	int err = false;
2121 	real height, width;
2122 	char buffer[50];
2123 
2124 	free(name);
2125 	if ( patternsc==NULL )
2126 return( true );
2127 	if ( !GGadgetIsChecked(GWidgetGetControl(gw,CID_Aspect)))
2128 return( true );
2129 	height = GetCalmReal8(gw,CID_THeight,_("Height"),&err);
2130 	if ( err )
2131 return( true );
2132 	PatternSCBounds(patternsc,&b);
2133 	width = height * (b.maxx - b.minx)/(b.maxy - b.miny);
2134 	sprintf( buffer, "%g", (double) width );
2135 	GGadgetSetTitle8(GWidgetGetControl(gw,CID_TWidth), buffer);
2136     }
2137 return( true );
2138 }
2139 
Pat_TransformChanged(GGadget * g,GEvent * e)2140 static int Pat_TransformChanged(GGadget *g, GEvent *e) {
2141 
2142     if ( e==NULL ||
2143 	    (e->type==et_controlevent && e->u.control.subtype == et_textchanged )) {
2144 	GWindow gw = GGadgetGetWindow(g);
2145 	double trans[6];
2146 	char *name = GGadgetGetTitle8(g);
2147 	double c, s, t;
2148 	char buffer[50];
2149 
2150 	if ( sscanf( name, "[%lg %lg %lg %lg %lg %lg]", &trans[0], &trans[1], &trans[2],
2151 		&trans[3], &trans[4], &trans[5])!=6 ) {
2152 	    free(name );
2153 return( true );
2154 	}
2155 	free(name );
2156 
2157 	c = trans[0]; s = trans[1];
2158 	if ( c!=0 )
2159 	    t = (trans[2]+s)/c;
2160 	else if ( s!=0 )
2161 	    t = (trans[3]-c)/s;
2162 	else
2163 	    t = 9999;
2164 	if ( RealWithin(c*c+s*s,1,.005) && RealWithin(t*c-s,trans[2],.01) && RealWithin(t*s+c,trans[3],.01)) {
2165 	    double skew = atan(t)*180/FF_PI;
2166 	    double rot  = atan2(s,c)*180/FF_PI;
2167 	    sprintf( buffer, "%g", skew );
2168 	    GGadgetSetTitle8(GWidgetGetControl(gw,CID_Skew), buffer);
2169 	    sprintf( buffer, "%g", rot );
2170 	    GGadgetSetTitle8(GWidgetGetControl(gw,CID_Rotate), buffer);
2171 	    sprintf( buffer, "%g", trans[4] );
2172 	    GGadgetSetTitle8(GWidgetGetControl(gw,CID_TransX), buffer);
2173 	    sprintf( buffer, "%g", trans[5] );
2174 	    GGadgetSetTitle8(GWidgetGetControl(gw,CID_TransY), buffer);
2175 	} else {
2176 	    GGadgetSetTitle8(GWidgetGetControl(gw,CID_Skew), "");
2177 	    GGadgetSetTitle8(GWidgetGetControl(gw,CID_Rotate), "");
2178 	    GGadgetSetTitle8(GWidgetGetControl(gw,CID_TransX), "");
2179 	    GGadgetSetTitle8(GWidgetGetControl(gw,CID_TransY), "");
2180 	}
2181     }
2182 return( true );
2183 }
2184 
Pat_AnglesChanged(GGadget * g,GEvent * e)2185 static int Pat_AnglesChanged(GGadget *g, GEvent *e) {
2186 
2187     if ( e==NULL ||
2188 	    (e->type==et_controlevent && e->u.control.subtype == et_textchanged )) {
2189 	GWindow gw = GGadgetGetWindow(g);
2190 	double rotate, skew, x, y;
2191 	double c, s, t;
2192 	char buffer[340];
2193 	int err=false;
2194 
2195 	skew   = GetCalmReal8(gw,CID_Skew,_("Skew"),&err)*FF_PI/180;
2196 	rotate = GetCalmReal8(gw,CID_Rotate,_("Rotate"),&err)*FF_PI/180;
2197 	x      = GetCalmReal8(gw,CID_TransX,_("Translation in X"),&err);
2198 	y      = GetCalmReal8(gw,CID_TransY,_("Translation in Y"),&err);
2199 	if ( err )
2200 return( true );
2201 	t = tan(skew);
2202 	c = cos(rotate); s = sin(rotate);
2203 	sprintf( buffer, "[%g %g %g %g %g %g]", c, s, t*c-s, t*s+c, x, y );
2204 	GGadgetSetTitle8(GWidgetGetControl(gw,CID_Transform),buffer );
2205     }
2206 return( true );
2207 }
2208 
Pat_GlyphNameCompletion(GGadget * t,int from_tab)2209 static unichar_t **Pat_GlyphNameCompletion(GGadget *t,int from_tab) {
2210     struct layer_dlg *ld = GDrawGetUserData(GGadgetGetWindow(t));
2211 
2212 return( SFGlyphNameCompletion(ld->sf,t,from_tab,false));
2213 }
2214 
Pat_OK(GGadget * g,GEvent * e)2215 static int Pat_OK(GGadget *g, GEvent *e) {
2216     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
2217 	GWindow gw = GGadgetGetWindow(g);
2218 	struct layer_dlg *ld = GDrawGetUserData(gw);
2219 	char *transstring = GGadgetGetTitle8(GWidgetGetControl(gw,CID_Transform));
2220 	char *name;
2221 	double width, height;
2222 	double trans[6];
2223 	int i;
2224 	SplineChar *patternsc;
2225 	int err;
2226 
2227 	if ( sscanf( transstring, "[%lg %lg %lg %lg %lg %lg]", &trans[0], &trans[1], &trans[2],
2228 		&trans[3], &trans[4], &trans[5])!=6 ) {
2229 	    free( transstring );
2230 	    ff_post_error(_("Bad Transformation matrix"),_("Bad Transformation matrix"));
2231 return( true );
2232 	}
2233 	free(transstring);
2234 
2235 	name = GGadgetGetTitle8(GWidgetGetControl(gw,CID_PatternName));
2236 	patternsc = SFGetChar(ld->sf,-1,name);
2237 	if ( patternsc==NULL ) {
2238 	    ff_post_error(_("No Glyph"),_("This font does not contain a glyph named \"%.40s\""), name);
2239 	    free(name);
2240 return( true );
2241 	}
2242 
2243 	err = false;
2244 	width = GetReal8(gw,CID_TWidth,_("Width"),&err);
2245 	height = GetReal8(gw,CID_THeight,_("Height"),&err);
2246 	if ( err )
2247 return( true );
2248 
2249 	if ( ld->curpat == NULL )
2250 	    ld->curpat = chunkalloc(sizeof(struct pattern));
2251 	free( ld->curpat->pattern );
2252 	ld->curpat->pattern = name;
2253 	for ( i=0; i<6; ++i )
2254 	    ld->curpat->transform[i] = trans[i];
2255 	ld->curpat->width = width;
2256 	ld->curpat->height = height;
2257 	ld->pat_done = true;
2258     }
2259 return( true );
2260 }
2261 
Pat_Cancel(GGadget * g,GEvent * e)2262 static int Pat_Cancel(GGadget *g, GEvent *e) {
2263     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
2264 	GWindow gw = GGadgetGetWindow(g);
2265 	struct layer_dlg *ld = GDrawGetUserData(gw);
2266 	ld->pat_done = true;
2267     }
2268 return( true );
2269 }
2270 
pat_e_h(GWindow gw,GEvent * event)2271 static int pat_e_h(GWindow gw, GEvent *event) {
2272     struct layer_dlg *ld = GDrawGetUserData(gw);
2273 
2274     switch ( event->type ) {
2275       case et_char:
2276 return( false );
2277       break;
2278       case et_close:
2279 	ld->pat_done = true;
2280       break;
2281     }
2282 return( true );
2283 }
2284 
PatternEdit(struct layer_dlg * ld,struct pattern * active)2285 static struct pattern *PatternEdit(struct layer_dlg *ld,struct pattern *active) {
2286     GRect pos;
2287     GWindow gw;
2288     GWindowAttrs wattrs;
2289     GGadgetCreateData gcd[25], boxes[5], *harray[8], *varray[10],
2290 	*hvarray[42];
2291     GTextInfo label[25];
2292     int j,k;
2293     char *name;
2294     char width[50], height[50], transform[340];
2295     int aspect_fixed = true;
2296 
2297     ld->pat_done = false;
2298     ld->curpat = active;
2299 
2300     name = "";
2301     width[0] = height[0] = '\0';
2302     strcpy(transform,"[1 0 0 1 0 0]");
2303     aspect_fixed = true;
2304     if ( active!=NULL ) {
2305 	SplineChar *patternsc = SFGetChar(ld->sf,-1,active->pattern);
2306 	name = active->pattern;
2307 	sprintf( width, "%g", (double) active->width );
2308 	sprintf( height, "%g", (double) active->height );
2309 	sprintf( transform, "[%g %g %g %g %g %g]",
2310 		(double) active->transform[0], (double) active->transform[1],
2311 		(double) active->transform[2], (double) active->transform[3],
2312 		(double) active->transform[4], (double) active->transform[5]);
2313 	if ( patternsc!=NULL ) {
2314 	    DBounds b;
2315 	    PatternSCBounds(patternsc,&b);
2316 	    aspect_fixed = RealNear(active->width*(b.maxy-b.miny),active->height*(b.maxx-b.minx));
2317 	}
2318     }
2319 
2320     memset(&wattrs,0,sizeof(wattrs));
2321     wattrs.mask = wam_events|wam_cursor|wam_isdlg|wam_restrict|wam_undercursor|wam_utf8_wtitle;
2322     wattrs.is_dlg = true;
2323     wattrs.restrict_input_to_me = 1;
2324     wattrs.undercursor = 1;
2325     wattrs.event_masks = -1;
2326     wattrs.cursor = ct_pointer;
2327     wattrs.utf8_window_title = _("Tile Pattern");
2328     pos.width = 600;
2329     pos.height = 300;
2330     gw = GDrawCreateTopWindow(NULL,&pos,pat_e_h,ld,&wattrs);
2331 
2332     memset(&label,0,sizeof(label));
2333     memset(&gcd,0,sizeof(gcd));
2334     memset(&boxes,0,sizeof(boxes));
2335 
2336     k = j = 0;
2337 
2338     label[k].text = (unichar_t *) _(
2339 	"The pattern itself should be drawn in another glyph\n"
2340 	"of the current font. Specify a glyph name:");
2341     label[k].text_is_1byte = true;
2342     gcd[k].gd.label = &label[k];
2343     gcd[k].gd.flags = gg_enabled | gg_visible;
2344     gcd[k++].creator = GLabelCreate;
2345     varray[j++] = &gcd[k-1];
2346 
2347     label[k].text = (unichar_t *) name;
2348     label[k].text_is_1byte = true;
2349     gcd[k].gd.label = &label[k];
2350     gcd[k].gd.flags = gg_enabled|gg_visible;
2351     gcd[k].gd.handle_controlevent = Pat_WidthChanged;		/* That will make sure the aspect ratio stays correct */
2352     gcd[k].gd.cid = CID_PatternName;
2353     gcd[k++].creator = GTextCompletionCreate;
2354     varray[j++] = &gcd[k-1];
2355 
2356     gcd[k].gd.flags = gg_visible | gg_enabled;
2357     if ( aspect_fixed )
2358 	gcd[k].gd.flags |= gg_cb_on;
2359     label[k].text = (unichar_t *) _("Aspect Ratio same as Tile Glyph");
2360     label[k].text_is_1byte = true;
2361     label[k].text_in_resource = true;
2362     gcd[k].gd.label = &label[k];
2363     gcd[k].gd.cid = CID_Aspect;
2364     gcd[k].gd.handle_controlevent = Pat_WidthChanged;		/* That will make sure the aspect ratio stays correct */
2365     gcd[k++].creator = GCheckBoxCreate;
2366     varray[j++] = &gcd[k-1];
2367 
2368     label[k].text = (unichar_t *) _("Width:");
2369     label[k].text_is_1byte = true;
2370     gcd[k].gd.label = &label[k];
2371     gcd[k].gd.flags = gg_enabled | gg_visible;
2372     gcd[k++].creator = GLabelCreate;
2373     hvarray[0] = &gcd[k-1];
2374 
2375     label[k].text = (unichar_t *) width;
2376     label[k].text_is_1byte = true;
2377     gcd[k].gd.label = &label[k];
2378     gcd[k].gd.flags = gg_enabled|gg_visible;
2379     gcd[k].gd.handle_controlevent = Pat_WidthChanged;
2380     gcd[k].gd.cid = CID_TWidth;
2381     gcd[k++].creator = GTextFieldCreate;
2382     hvarray[1] = &gcd[k-1]; hvarray[2] = GCD_Glue; hvarray[3] = NULL;
2383 
2384     label[k].text = (unichar_t *) _("Height:");
2385     label[k].text_is_1byte = true;
2386     gcd[k].gd.label = &label[k];
2387     gcd[k].gd.flags = gg_enabled | gg_visible;
2388     gcd[k++].creator = GLabelCreate;
2389     hvarray[4] = &gcd[k-1];
2390 
2391     label[k].text = (unichar_t *) height;
2392     label[k].text_is_1byte = true;
2393     gcd[k].gd.label = &label[k];
2394     gcd[k].gd.flags = gg_enabled|gg_visible;
2395     gcd[k].gd.handle_controlevent = Pat_HeightChanged;
2396     gcd[k].gd.cid = CID_THeight;
2397     gcd[k++].creator = GTextFieldCreate;
2398     hvarray[5] = &gcd[k-1]; hvarray[6] = GCD_Glue; hvarray[7] = NULL;
2399 
2400     gcd[k].gd.flags = gg_enabled | gg_visible;
2401     gcd[k++].creator = GLineCreate;
2402     hvarray[8] = &gcd[k-1];
2403     hvarray[9] = GCD_ColSpan; hvarray[10] = GCD_Glue; hvarray[11] = NULL;
2404 
2405     label[k].text = (unichar_t *) _("Rotate:");
2406     label[k].text_is_1byte = true;
2407     gcd[k].gd.label = &label[k];
2408     gcd[k].gd.flags = gg_enabled | gg_visible;
2409     gcd[k++].creator = GLabelCreate;
2410     hvarray[12] = &gcd[k-1];
2411 
2412     gcd[k].gd.flags = gg_enabled|gg_visible;
2413     gcd[k].gd.handle_controlevent = Pat_AnglesChanged;
2414     gcd[k].gd.cid = CID_Rotate;
2415     gcd[k++].creator = GTextFieldCreate;
2416     hvarray[13] = &gcd[k-1]; hvarray[14] = GCD_Glue; hvarray[15] = NULL;
2417 
2418     label[k].text = (unichar_t *) _("Skew:");
2419     label[k].text_is_1byte = true;
2420     gcd[k].gd.label = &label[k];
2421     gcd[k].gd.flags = gg_enabled | gg_visible;
2422     gcd[k++].creator = GLabelCreate;
2423     hvarray[16] = &gcd[k-1];
2424 
2425     gcd[k].gd.flags = gg_enabled|gg_visible;
2426     gcd[k].gd.handle_controlevent = Pat_AnglesChanged;
2427     gcd[k].gd.cid = CID_Skew;
2428     gcd[k++].creator = GTextFieldCreate;
2429     hvarray[17] = &gcd[k-1]; hvarray[18] = GCD_Glue; hvarray[19] = NULL;
2430 
2431     label[k].text = (unichar_t *) _("Translate By");
2432     label[k].text_is_1byte = true;
2433     gcd[k].gd.label = &label[k];
2434     gcd[k].gd.flags = gg_enabled | gg_visible;
2435     gcd[k++].creator = GLabelCreate;
2436     hvarray[20] = &gcd[k-1];
2437     hvarray[21] = GCD_ColSpan; hvarray[22] = GCD_Glue; hvarray[23] = NULL;
2438 
2439     label[k].text = (unichar_t *) _("X:");
2440     label[k].text_is_1byte = true;
2441     gcd[k].gd.label = &label[k];
2442     gcd[k].gd.flags = gg_enabled | gg_visible;
2443     gcd[k++].creator = GLabelCreate;
2444     hvarray[24] = &gcd[k-1];
2445 
2446     gcd[k].gd.flags = gg_enabled|gg_visible;
2447     gcd[k].gd.handle_controlevent = Pat_AnglesChanged;
2448     gcd[k].gd.cid = CID_TransX;
2449     gcd[k++].creator = GTextFieldCreate;
2450     hvarray[25] = &gcd[k-1]; hvarray[26] = GCD_Glue; hvarray[27] = NULL;
2451 
2452     label[k].text = (unichar_t *) _("Y:");
2453     label[k].text_is_1byte = true;
2454     gcd[k].gd.label = &label[k];
2455     gcd[k].gd.flags = gg_enabled | gg_visible;
2456     gcd[k++].creator = GLabelCreate;
2457     hvarray[28] = &gcd[k-1];
2458 
2459     gcd[k].gd.flags = gg_enabled|gg_visible;
2460     gcd[k].gd.handle_controlevent = Pat_AnglesChanged;
2461     gcd[k].gd.cid = CID_TransY;
2462     gcd[k++].creator = GTextFieldCreate;
2463     hvarray[29] = &gcd[k-1]; hvarray[30] = GCD_Glue; hvarray[31] = NULL;
2464 
2465     gcd[k].gd.flags = gg_enabled | gg_visible;
2466     gcd[k++].creator = GLineCreate;
2467     hvarray[32] = &gcd[k-1];
2468     hvarray[33] = GCD_ColSpan; hvarray[34] = GCD_Glue; hvarray[35] = NULL;
2469 
2470     label[k].text = (unichar_t *) _("Transform:");
2471     label[k].text_is_1byte = true;
2472     gcd[k].gd.label = &label[k];
2473     gcd[k].gd.flags = gg_enabled | gg_visible;
2474     gcd[k++].creator = GLabelCreate;
2475     hvarray[36] = &gcd[k-1];
2476 
2477     label[k].text = (unichar_t *) transform;
2478     label[k].text_is_1byte = true;
2479     gcd[k].gd.label = &label[k];
2480     gcd[k].gd.flags = gg_enabled|gg_visible;
2481     gcd[k].gd.handle_controlevent = Pat_TransformChanged;
2482     gcd[k].gd.cid = CID_Transform;
2483     gcd[k++].creator = GTextFieldCreate;
2484     hvarray[37] = &gcd[k-1]; hvarray[38] = GCD_ColSpan; hvarray[39] = NULL;
2485     hvarray[40] = NULL;
2486 
2487     boxes[2].gd.flags = gg_enabled|gg_visible;
2488     boxes[2].gd.u.boxelements = hvarray;
2489     boxes[2].creator = GHVBoxCreate;
2490     varray[j++] = &boxes[2];
2491 
2492     label[k].text = (unichar_t *) _("_OK");
2493     label[k].text_is_1byte = true;
2494     label[k].text_in_resource = true;
2495     gcd[k].gd.label = &label[k];
2496     gcd[k].gd.flags = gg_enabled|gg_visible|gg_but_default;
2497     gcd[k].gd.handle_controlevent = Pat_OK;
2498     gcd[k++].creator = GButtonCreate;
2499 
2500     label[k].text = (unichar_t *) _("_Cancel");
2501     label[k].text_is_1byte = true;
2502     label[k].text_in_resource = true;
2503     gcd[k].gd.label = &label[k];
2504     gcd[k].gd.flags = gg_enabled|gg_visible|gg_but_cancel;
2505     gcd[k].gd.handle_controlevent = Pat_Cancel;
2506     gcd[k++].creator = GButtonCreate;
2507 
2508     harray[0] = GCD_Glue; harray[1] = &gcd[k-2]; harray[2] = GCD_Glue;
2509     harray[3] = GCD_Glue; harray[4] = &gcd[k-1]; harray[5] = GCD_Glue;
2510     harray[6] = NULL;
2511 
2512     boxes[3].gd.flags = gg_enabled|gg_visible;
2513     boxes[3].gd.u.boxelements = harray;
2514     boxes[3].creator = GHBoxCreate;
2515     varray[j++] = &boxes[3];
2516     varray[j++] = GCD_Glue;
2517     varray[j] = NULL;
2518 
2519     boxes[0].gd.flags = gg_enabled|gg_visible;
2520     boxes[0].gd.u.boxelements = varray;
2521     boxes[0].creator = GVBoxCreate;
2522 
2523     GGadgetsCreate(gw,boxes);
2524 
2525     GHVBoxSetExpandableRow(boxes[0].ret,gb_expandglue);
2526     GHVBoxSetExpandableCol(boxes[2].ret,2);
2527     GHVBoxSetExpandableRow(boxes[3].ret,gb_expandgluesame);
2528     GHVBoxFitWindow(boxes[0].ret);
2529 
2530 
2531     Pat_TransformChanged(GWidgetGetControl(gw,CID_Transform),NULL);
2532     GCompletionFieldSetCompletion(gcd[1].ret,Pat_GlyphNameCompletion);
2533 
2534     GDrawSetVisible(gw,true);
2535 
2536     while ( !ld->pat_done )
2537 	GDrawProcessOneEvent(NULL);
2538 
2539     GDrawDestroyWindow(gw);
2540 return( ld->curpat );
2541 }
2542 
Layer_PatSet(struct layer_dlg * ld)2543 static void Layer_PatSet(struct layer_dlg *ld) {
2544     GGadgetSetEnabled(GWidgetGetControl(ld->gw,CID_FillPatAdd),ld->fillpat==NULL);
2545     GGadgetSetEnabled(GWidgetGetControl(ld->gw,CID_FillPatEdit),ld->fillpat!=NULL);
2546     GGadgetSetEnabled(GWidgetGetControl(ld->gw,CID_FillPatDelete),ld->fillpat!=NULL);
2547     GGadgetSetEnabled(GWidgetGetControl(ld->gw,CID_StrokePatAdd),ld->strokepat==NULL);
2548     GGadgetSetEnabled(GWidgetGetControl(ld->gw,CID_StrokePatEdit),ld->strokepat!=NULL);
2549     GGadgetSetEnabled(GWidgetGetControl(ld->gw,CID_StrokePatDelete),ld->strokepat!=NULL);
2550 }
2551 
Layer_FillPatDelete(GGadget * g,GEvent * e)2552 static int Layer_FillPatDelete(GGadget *g, GEvent *e) {
2553 
2554     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
2555 	struct layer_dlg *ld = GDrawGetUserData(GGadgetGetWindow(g));
2556 	PatternFree(ld->fillpat);
2557 	ld->fillpat=NULL;
2558 	Layer_PatSet(ld);
2559     }
2560 return( true );
2561 }
2562 
Layer_FillPatAddEdit(GGadget * g,GEvent * e)2563 static int Layer_FillPatAddEdit(GGadget *g, GEvent *e) {
2564 
2565     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
2566 	struct layer_dlg *ld = GDrawGetUserData(GGadgetGetWindow(g));
2567 	ld->fillpat = PatternEdit(ld,ld->fillpat);
2568 	Layer_PatSet(ld);
2569     }
2570 return( true );
2571 }
2572 
Layer_StrokePatDelete(GGadget * g,GEvent * e)2573 static int Layer_StrokePatDelete(GGadget *g, GEvent *e) {
2574 
2575     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
2576 	struct layer_dlg *ld = GDrawGetUserData(GGadgetGetWindow(g));
2577 	PatternFree(ld->strokepat);
2578 	ld->strokepat=NULL;
2579 	Layer_PatSet(ld);
2580     }
2581 return( true );
2582 }
2583 
Layer_StrokePatAddEdit(GGadget * g,GEvent * e)2584 static int Layer_StrokePatAddEdit(GGadget *g, GEvent *e) {
2585 
2586     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
2587 	struct layer_dlg *ld = GDrawGetUserData(GGadgetGetWindow(g));
2588 	ld->strokepat = PatternEdit(ld,ld->strokepat);
2589 	Layer_PatSet(ld);
2590     }
2591 return( true );
2592 }
2593 
getcol(GGadget * g,int * err)2594 static uint32 getcol(GGadget *g,int *err) {
2595     const unichar_t *ret=_GGadgetGetTitle(g);
2596     unichar_t *end;
2597     uint32 col = COLOR_INHERITED;
2598 
2599     if ( *ret=='#' ) ++ret;
2600     col = u_strtol(ret,&end,16);
2601     if ( col<0 || col>0xffffff || *end!='\0' ) {
2602 	*err = true;
2603 	ff_post_error(_("Bad Color"),_("Bad Color"));
2604     }
2605 return( col );
2606 }
2607 
Layer_OK(GGadget * g,GEvent * e)2608 static int Layer_OK(GGadget *g, GEvent *e) {
2609 
2610     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
2611 	GWindow gw = GGadgetGetWindow(g);
2612 	struct layer_dlg *ld = GDrawGetUserData(GGadgetGetWindow(g));
2613 	Layer temp;
2614 	int err=false;
2615 	const unichar_t *ret;
2616 	unichar_t *end, *end2;
2617 	int i;
2618 
2619 	LayerDefault(&temp);
2620 	temp.dofill = GGadgetIsChecked(GWidgetGetControl(gw,CID_Fill));
2621 	temp.dostroke = GGadgetIsChecked(GWidgetGetControl(gw,CID_Stroke));
2622 	if ( GGadgetIsChecked(GWidgetGetControl(gw,CID_FillCInherit)) )
2623 	    temp.fill_brush.col = COLOR_INHERITED;
2624 	else
2625 	    temp.fill_brush.col = getcol(GWidgetGetControl(gw,CID_FillColor),&err);
2626 	if ( GGadgetIsChecked(GWidgetGetControl(gw,CID_FillOInherit)) )
2627 	    temp.fill_brush.opacity = -1;
2628 	else
2629 	    temp.fill_brush.opacity = GetReal8(gw,CID_FillOpacity,_("Opacity:"),&err);
2630 
2631 	if ( GGadgetIsChecked(GWidgetGetControl(gw,CID_StrokeCInherit)) )
2632 	    temp.stroke_pen.brush.col = COLOR_INHERITED;
2633 	else
2634 	    temp.stroke_pen.brush.col = getcol(GWidgetGetControl(gw,CID_StrokeColor),&err);
2635 	if ( GGadgetIsChecked(GWidgetGetControl(gw,CID_StrokeOInherit)) )
2636 	    temp.stroke_pen.brush.opacity = -1;
2637 	else
2638 	    temp.stroke_pen.brush.opacity = GetReal8(gw,CID_StrokeOpacity,_("Opacity:"),&err);
2639 	if ( GGadgetIsChecked(GWidgetGetControl(gw,CID_StrokeWInherit)) )
2640 	    temp.stroke_pen.width = WIDTH_INHERITED;
2641 	else
2642 	    temp.stroke_pen.width = GetReal8(gw,CID_Width,_("_Width"),&err);
2643 	if ( err )
2644 return( true );
2645 
2646 	ret = _GGadgetGetTitle(GWidgetGetControl(gw,CID_Trans));
2647 	while ( *ret==' ' || *ret=='[' ) ++ret;
2648 	temp.stroke_pen.trans[0] = u_strtod(ret,&end);
2649 	temp.stroke_pen.trans[1] = u_strtod(end,&end);
2650 	temp.stroke_pen.trans[2] = u_strtod(end,&end);
2651 	temp.stroke_pen.trans[3] = u_strtod(end,&end2);
2652 	for ( ret = end2 ; *ret==' ' || *ret==']' ; ++ret );
2653 	if ( end2==end || *ret!='\0' || temp.stroke_pen.trans[0] ==0 || temp.stroke_pen.trans[3]==0 ) {
2654 	    ff_post_error(_("Bad Transformation Matrix"),_("Bad Transformation Matrix"));
2655 return( true );
2656 	}
2657 	if ( GGadgetIsChecked(GWidgetGetControl(gw,CID_DashesInherit)) ) {
2658 	    temp.stroke_pen.dashes[0] = 0; temp.stroke_pen.dashes[1] = DASH_INHERITED;
2659 	} else {
2660 	    ret = _GGadgetGetTitle(GWidgetGetControl(gw,CID_Dashes));
2661 	    while ( *ret==' ' || *ret=='[' ) ++ret;
2662 	    for ( i=0; ; ++i ) {
2663 		long val = u_strtol(ret,&end,10);
2664 		if ( *end=='\0' )
2665 	    break;
2666 		if ( val<0 || val>255 ) {
2667 		    ff_post_error(_("Bad dash list"),_("Value out of range"));
2668 return( true );
2669 		} else if ( *end!=' ' ) {
2670 		    ff_post_error(_("Bad dash list"),_("Bad Number"));
2671 return( true );
2672 		} else if ( i>=DASH_MAX ) {
2673 		    ff_post_error(_("Bad dash list"),_("Too many dashes (at most %d allowed)"), DASH_MAX);
2674 return( true );
2675 		}
2676 		temp.stroke_pen.dashes[i] = val;
2677 		ret = end;
2678 		while ( *ret==' ' ) ++ret;
2679 	    }
2680 	    if ( i<DASH_MAX ) temp.stroke_pen.dashes[i] = 0;
2681 	}
2682 	temp.stroke_pen.linecap =
2683 		GGadgetIsChecked(GWidgetGetControl(gw,CID_ButtCap))?lc_butt:
2684 		GGadgetIsChecked(GWidgetGetControl(gw,CID_RoundCap))?lc_round:
2685 		GGadgetIsChecked(GWidgetGetControl(gw,CID_SquareCap))?lc_square:
2686 			lc_inherited;
2687 	temp.stroke_pen.linejoin =
2688 		GGadgetIsChecked(GWidgetGetControl(gw,CID_BevelJoin))?lj_bevel:
2689 		GGadgetIsChecked(GWidgetGetControl(gw,CID_RoundJoin))?lj_round:
2690 		GGadgetIsChecked(GWidgetGetControl(gw,CID_MiterJoin))?lj_miter:
2691 			lj_inherited;
2692 
2693 	GradientFree(ld->layer->fill_brush.gradient);
2694 	PatternFree(ld->layer->fill_brush.pattern);
2695 	GradientFree(ld->layer->stroke_pen.brush.gradient);
2696 	PatternFree(ld->layer->stroke_pen.brush.pattern);
2697 
2698 	ld->done = ld->ok = true;
2699 	ld->layer->stroke_pen = temp.stroke_pen;
2700 	ld->layer->fill_brush = temp.fill_brush;
2701 	ld->layer->dofill = temp.dofill;
2702 	ld->layer->dostroke = temp.dostroke;
2703 	ld->layer->fillfirst = temp.fillfirst;
2704 
2705 	ld->layer->fill_brush.gradient = ld->fillgrad;
2706 	ld->layer->stroke_pen.brush.gradient = ld->strokegrad;
2707 	ld->layer->fill_brush.pattern = ld->fillpat;
2708 	ld->layer->stroke_pen.brush.pattern = ld->strokepat;
2709     }
2710 return( true );
2711 }
2712 
Layer_Cancel(GGadget * g,GEvent * e)2713 static int Layer_Cancel(GGadget *g, GEvent *e) {
2714     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
2715 	struct layer_dlg *ld = GDrawGetUserData(GGadgetGetWindow(g));
2716 	ld->done = true;
2717     }
2718 return( true );
2719 }
2720 
Layer_Inherit(GGadget * g,GEvent * e)2721 static int Layer_Inherit(GGadget *g, GEvent *e) {
2722     if ( e->type==et_controlevent && e->u.control.subtype == et_radiochanged ) {
2723 	GWindow gw = GGadgetGetWindow(g);
2724 	int cid = (intpt) GGadgetGetUserData(g);
2725 	GGadgetSetEnabled(GWidgetGetControl(gw,cid),
2726 		!GGadgetIsChecked(g));
2727     }
2728 return( true );
2729 }
2730 
Layer_DoColorWheel(GGadget * g,GEvent * e)2731 static int Layer_DoColorWheel(GGadget *g, GEvent *e) {
2732     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
2733 	GWindow gw = GGadgetGetWindow(g);
2734 	int cid = (intpt) GGadgetGetUserData(g);
2735 	GGadget *tf = GWidgetGetControl(gw,cid);
2736 	if ( GGadgetIsEnabled(tf)) {
2737 	    char *pt, *text = GGadgetGetTitle8(tf);
2738 	    char buf[12];
2739 	    Color val;
2740 	    struct hslrgb col;
2741 	    pt = text;
2742 	    while ( isspace(*pt)) ++pt;
2743 	    if ( *pt=='0' && (pt[1]=='x' || pt[1]=='X')) pt += 2;
2744 	    else if ( *pt=='#' ) ++pt;
2745 	    val = strtoul(pt,NULL,16);
2746 	    gColor2Hslrgb(&col,val);
2747 	    col = GWidgetColor(_("Pick a color"),&col,NULL);
2748 	    if ( col.rgb ) {
2749 		val = gHslrgb2Color(&col);
2750 		sprintf(buf,"#%06x", val );
2751 		GGadgetSetTitle8(tf,buf);
2752 	    }
2753 	}
2754     }
2755 return( true );
2756 }
2757 
layer_e_h(GWindow gw,GEvent * event)2758 static int layer_e_h(GWindow gw, GEvent *event) {
2759     if ( event->type==et_close ) {
2760 	struct layer_dlg *ld = GDrawGetUserData(gw);
2761 	ld->done = true;
2762     } else if ( event->type == et_char ) {
2763 	if ( event->u.chr.keysym == GK_F1 || event->u.chr.keysym == GK_Help ) {
2764 	    help("ui/dialogs/multilayer.html", "#multilayer-layer");
2765 return( true );
2766 	}
2767 return( false );
2768     }
2769 return( true );
2770 }
2771 
LayerDialog(Layer * layer,SplineFont * sf)2772 int LayerDialog(Layer *layer,SplineFont *sf) {
2773     GRect pos;
2774     GWindow gw;
2775     GWindowAttrs wattrs;
2776     GGadgetCreateData gcd[62], boxes[12];
2777     GGadgetCreateData *barray[10], *varray[4], *fhvarray[22], *shvarray[46],
2778 	    *lcarray[6], *ljarray[6], *fgarray[5], *fparray[5], *sgarray[5],
2779 	    *sparray[5];
2780     GTextInfo label[62];
2781     struct layer_dlg ld;
2782     int yoff=0;
2783     int gcdoff, fill_gcd, stroke_gcd, k, j;
2784     char widthbuf[20], fcol[12], scol[12], fopac[30], sopac[30], transbuf[150],
2785 	    dashbuf[60];
2786     int i;
2787     char *pt;
2788 
2789     memset(&ld,0,sizeof(ld));
2790     ld.layer = layer;
2791     ld.sf    = sf;
2792 
2793     memset(&wattrs,0,sizeof(wattrs));
2794     wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_undercursor|wam_isdlg|wam_restrict;
2795     wattrs.event_masks = ~(1<<et_charup);
2796     wattrs.restrict_input_to_me = 1;
2797     wattrs.undercursor = 1;
2798     wattrs.cursor = ct_pointer;
2799     wattrs.utf8_window_title = _("Layer");
2800     wattrs.is_dlg = true;
2801     pos.x = pos.y = 0;
2802     pos.width = GGadgetScale(GDrawPointsToPixels(NULL,LY_Width));
2803     pos.height = GDrawPointsToPixels(NULL,LY_Height);
2804     ld.gw = gw = GDrawCreateTopWindow(NULL,&pos,layer_e_h,&ld,&wattrs);
2805 
2806     ld.fillgrad = GradientCopy(layer->fill_brush.gradient,NULL);
2807     ld.strokegrad = GradientCopy(layer->stroke_pen.brush.gradient,NULL);
2808     ld.fillpat = PatternCopy(layer->fill_brush.pattern,NULL);
2809     ld.strokepat = PatternCopy(layer->stroke_pen.brush.pattern,NULL);
2810 
2811     memset(&label,0,sizeof(label));
2812     memset(&gcd,0,sizeof(gcd));
2813     memset(&boxes,0,sizeof(boxes));
2814 
2815     gcdoff = k = 0;
2816 
2817     label[gcdoff].text = (unichar_t *) _("Fi_ll");
2818     label[gcdoff].text_is_1byte = true;
2819     label[gcdoff].text_in_resource = true;
2820     gcd[gcdoff].gd.label = &label[gcdoff];
2821     gcd[gcdoff].gd.pos.x = 5; gcd[gcdoff].gd.pos.y = 5+yoff;
2822     gcd[gcdoff].gd.flags = gg_enabled | gg_visible | (layer->dofill? gg_cb_on : 0);
2823     gcd[gcdoff].gd.cid = CID_Fill;
2824     gcd[gcdoff++].creator = GCheckBoxCreate;
2825 
2826     fill_gcd = gcdoff;
2827 
2828     label[gcdoff].text = (unichar_t *) _("Color:");
2829     label[gcdoff].text_is_1byte = true;
2830     gcd[gcdoff].gd.label = &label[gcdoff];
2831     gcd[gcdoff].gd.pos.x = 5; gcd[gcdoff].gd.pos.y = gcd[gcdoff-1].gd.pos.y+12;
2832     gcd[gcdoff].gd.flags = gg_enabled | gg_visible;
2833     gcd[gcdoff++].creator = GLabelCreate;
2834     fhvarray[k++] = &gcd[gcdoff-1];
2835 
2836     sprintf( fcol, "#%06x", layer->fill_brush.col );
2837     label[gcdoff].text = (unichar_t *) fcol;
2838     label[gcdoff].text_is_1byte = true;
2839     if ( layer->fill_brush.col==COLOR_INHERITED )
2840 	gcd[gcdoff].gd.flags = gg_visible;
2841     else {
2842 	gcd[gcdoff].gd.label = &label[gcdoff];
2843 	gcd[gcdoff].gd.flags = gg_enabled | gg_visible;
2844     }
2845     gcd[gcdoff].gd.pos.x = 80; gcd[gcdoff].gd.pos.y = gcd[gcdoff-1].gd.pos.y-3;
2846     gcd[gcdoff].gd.pos.width = 80;
2847     gcd[gcdoff].gd.cid = CID_FillColor;
2848     gcd[gcdoff++].creator = GTextFieldCreate;
2849     fhvarray[k++] = &gcd[gcdoff-1];
2850 
2851     label[gcdoff].text = (unichar_t *) _("Inherited");
2852     label[gcdoff].text_is_1byte = true;
2853     gcd[gcdoff].gd.label = &label[gcdoff];
2854     gcd[gcdoff].gd.pos.x = 165; gcd[gcdoff].gd.pos.y = gcd[gcdoff-1].gd.pos.y+2;
2855     gcd[gcdoff].gd.flags = gg_enabled | gg_visible | (layer->fill_brush.col==COLOR_INHERITED? gg_cb_on : 0);
2856     gcd[gcdoff].data = (void *) CID_FillColor;
2857     gcd[gcdoff].gd.cid = CID_FillCInherit;
2858     gcd[gcdoff].gd.handle_controlevent = Layer_Inherit;
2859     gcd[gcdoff++].creator = GCheckBoxCreate;
2860     fhvarray[k++] = &gcd[gcdoff-1];
2861 
2862     label[gcdoff].image = GGadgetImageCache("colorwheel.png");
2863     gcd[gcdoff].gd.label = &label[gcdoff];
2864     gcd[gcdoff].gd.flags = gg_enabled|gg_visible;
2865     gcd[gcdoff].data = (void *) CID_FillColor;
2866     gcd[gcdoff].gd.handle_controlevent = Layer_DoColorWheel;
2867     gcd[gcdoff++].creator = GButtonCreate;
2868     fhvarray[k++] = &gcd[gcdoff-1];
2869     fhvarray[k++] = NULL;
2870 
2871     label[gcdoff].text = (unichar_t *) _("Opacity:");
2872     label[gcdoff].text_is_1byte = true;
2873     gcd[gcdoff].gd.label = &label[gcdoff];
2874     gcd[gcdoff].gd.pos.x = 5; gcd[gcdoff].gd.pos.y = gcd[gcdoff-1].gd.pos.y+25;
2875     gcd[gcdoff].gd.flags = gg_enabled | gg_visible;
2876     gcd[gcdoff++].creator = GLabelCreate;
2877     fhvarray[k++] = &gcd[gcdoff-1];
2878 
2879     sprintf( fopac, "%g", layer->fill_brush.opacity );
2880     label[gcdoff].text = (unichar_t *) fopac;
2881     label[gcdoff].text_is_1byte = true;
2882     if ( layer->fill_brush.opacity<0 )
2883 	gcd[gcdoff].gd.flags = gg_visible;
2884     else {
2885 	gcd[gcdoff].gd.label = &label[gcdoff];
2886 	gcd[gcdoff].gd.flags = gg_enabled | gg_visible;
2887     }
2888     gcd[gcdoff].gd.pos.x = 80; gcd[gcdoff].gd.pos.y = gcd[gcdoff-1].gd.pos.y-3;
2889     gcd[gcdoff].gd.pos.width = 80;
2890     gcd[gcdoff].gd.cid = CID_FillOpacity;
2891     gcd[gcdoff++].creator = GTextFieldCreate;
2892     fhvarray[k++] = &gcd[gcdoff-1];
2893 
2894     label[gcdoff].text = (unichar_t *) _("Inherited");
2895     label[gcdoff].text_is_1byte = true;
2896     gcd[gcdoff].gd.label = &label[gcdoff];
2897     gcd[gcdoff].gd.pos.x = 165; gcd[gcdoff].gd.pos.y = gcd[gcdoff-1].gd.pos.y+2;
2898     gcd[gcdoff].gd.flags = gg_enabled | gg_visible | (layer->fill_brush.opacity<0? gg_cb_on : 0);
2899     gcd[gcdoff].data = (void *) CID_FillOpacity;
2900     gcd[gcdoff].gd.cid = CID_FillOInherit;
2901     gcd[gcdoff].gd.handle_controlevent = Layer_Inherit;
2902     gcd[gcdoff++].creator = GCheckBoxCreate;
2903     fhvarray[k++] = &gcd[gcdoff-1];
2904     fhvarray[k++] = GCD_Glue;
2905     fhvarray[k++] = NULL;
2906 
2907     label[gcdoff].text = (unichar_t *) _("Gradient:");
2908     label[gcdoff].text_is_1byte = true;
2909     gcd[gcdoff].gd.label = &label[gcdoff];
2910     gcd[gcdoff].gd.pos.x = 5; gcd[gcdoff].gd.pos.y = gcd[gcdoff-1].gd.pos.y+25;
2911     gcd[gcdoff].gd.flags = gg_enabled | gg_visible;
2912     gcd[gcdoff++].creator = GLabelCreate;
2913     fhvarray[k++] = &gcd[gcdoff-1];
2914 
2915     gcd[gcdoff].gd.flags = layer->fill_brush.gradient==NULL ? (gg_visible | gg_enabled) : gg_visible;
2916     label[gcdoff].text = (unichar_t *) _("Add");
2917     label[gcdoff].text_is_1byte = true;
2918     label[gcdoff].text_in_resource = true;
2919     gcd[gcdoff].gd.label = &label[gcdoff];
2920     gcd[gcdoff].gd.handle_controlevent = Layer_FillGradAddEdit;
2921     gcd[gcdoff].gd.cid = CID_FillGradAdd;
2922     gcd[gcdoff++].creator = GButtonCreate;
2923     fgarray[0] = &gcd[gcdoff-1];
2924 
2925     gcd[gcdoff].gd.flags = layer->fill_brush.gradient!=NULL ? (gg_visible | gg_enabled) : gg_visible;
2926     label[gcdoff].text = (unichar_t *) _("Edit");
2927     label[gcdoff].text_is_1byte = true;
2928     label[gcdoff].text_in_resource = true;
2929     gcd[gcdoff].gd.label = &label[gcdoff];
2930     gcd[gcdoff].gd.handle_controlevent = Layer_FillGradAddEdit;
2931     gcd[gcdoff].gd.cid = CID_FillGradEdit;
2932     gcd[gcdoff++].creator = GButtonCreate;
2933     fgarray[1] = &gcd[gcdoff-1];
2934 
2935     gcd[gcdoff].gd.flags = layer->fill_brush.gradient!=NULL ? (gg_visible | gg_enabled) : gg_visible;
2936     label[gcdoff].text = (unichar_t *) _("Delete");
2937     label[gcdoff].text_is_1byte = true;
2938     label[gcdoff].text_in_resource = true;
2939     gcd[gcdoff].gd.label = &label[gcdoff];
2940     gcd[gcdoff].gd.handle_controlevent = Layer_FillGradDelete;
2941     gcd[gcdoff].gd.cid = CID_FillGradDelete;
2942     gcd[gcdoff++].creator = GButtonCreate;
2943     fgarray[2] = &gcd[gcdoff-1];
2944     fgarray[3] = GCD_Glue;
2945     fgarray[4] = NULL;
2946 
2947     boxes[7].gd.flags = gg_enabled|gg_visible;
2948     boxes[7].gd.u.boxelements = fgarray;
2949     boxes[7].creator = GHBoxCreate;
2950     fhvarray[k++] = &boxes[7];
2951     fhvarray[k++] = GCD_ColSpan;
2952     fhvarray[k++] = GCD_Glue;
2953     fhvarray[k++] = NULL;
2954 
2955     label[gcdoff].text = (unichar_t *) _("Pattern:");
2956     label[gcdoff].text_is_1byte = true;
2957     gcd[gcdoff].gd.label = &label[gcdoff];
2958     gcd[gcdoff].gd.pos.x = 5; gcd[gcdoff].gd.pos.y = gcd[gcdoff-1].gd.pos.y+25;
2959     gcd[gcdoff].gd.flags = gg_enabled | gg_visible;
2960     gcd[gcdoff++].creator = GLabelCreate;
2961     fhvarray[k++] = &gcd[gcdoff-1];
2962 
2963     gcd[gcdoff].gd.flags = layer->fill_brush.pattern==NULL ? (gg_visible | gg_enabled) : gg_visible;
2964     label[gcdoff].text = (unichar_t *) _("Add");
2965     label[gcdoff].text_is_1byte = true;
2966     label[gcdoff].text_in_resource = true;
2967     gcd[gcdoff].gd.label = &label[gcdoff];
2968     gcd[gcdoff].gd.handle_controlevent = Layer_FillPatAddEdit;
2969     gcd[gcdoff].gd.cid = CID_FillPatAdd;
2970     gcd[gcdoff++].creator = GButtonCreate;
2971     fparray[0] = &gcd[gcdoff-1];
2972 
2973     gcd[gcdoff].gd.flags = layer->fill_brush.pattern!=NULL ? (gg_visible | gg_enabled) : gg_visible;
2974     label[gcdoff].text = (unichar_t *) _("Edit");
2975     label[gcdoff].text_is_1byte = true;
2976     label[gcdoff].text_in_resource = true;
2977     gcd[gcdoff].gd.label = &label[gcdoff];
2978     gcd[gcdoff].gd.handle_controlevent = Layer_FillPatAddEdit;
2979     gcd[gcdoff].gd.cid = CID_FillPatEdit;
2980     gcd[gcdoff++].creator = GButtonCreate;
2981     fparray[1] = &gcd[gcdoff-1];
2982 
2983     gcd[gcdoff].gd.flags = layer->fill_brush.pattern!=NULL ? (gg_visible | gg_enabled) : gg_visible;
2984     label[gcdoff].text = (unichar_t *) _("Delete");
2985     label[gcdoff].text_is_1byte = true;
2986     label[gcdoff].text_in_resource = true;
2987     gcd[gcdoff].gd.label = &label[gcdoff];
2988     gcd[gcdoff].gd.handle_controlevent = Layer_FillPatDelete;
2989     gcd[gcdoff].gd.cid = CID_FillPatDelete;
2990     gcd[gcdoff++].creator = GButtonCreate;
2991     fparray[2] = &gcd[gcdoff-1];
2992     fparray[3] = GCD_Glue;
2993     fparray[4] = NULL;
2994 
2995     boxes[8].gd.flags = gg_enabled|gg_visible;
2996     boxes[8].gd.u.boxelements = fparray;
2997     boxes[8].creator = GHBoxCreate;
2998     fhvarray[k++] = &boxes[8];
2999     fhvarray[k++] = GCD_ColSpan;
3000     fhvarray[k++] = GCD_Glue;
3001     fhvarray[k++] = NULL;
3002     fhvarray[k++] = NULL;
3003 
3004 
3005     boxes[2].gd.pos.x = boxes[2].gd.pos.y = 2;
3006     boxes[2].gd.flags = gg_enabled|gg_visible;
3007     boxes[2].gd.u.boxelements = fhvarray;
3008     boxes[2].gd.label = (GTextInfo *) &gcd[fill_gcd-1];
3009     boxes[2].creator = GHVGroupCreate;
3010 
3011     label[gcdoff].text = (unichar_t *) _("Stroke");
3012     label[gcdoff].text_is_1byte = true;
3013     gcd[gcdoff].gd.mnemonic = 'S';
3014     gcd[gcdoff].gd.label = &label[gcdoff];
3015     gcd[gcdoff].gd.pos.x = 5; gcd[gcdoff].gd.pos.y = gcd[fill_gcd].gd.pos.y+gcd[fill_gcd].gd.pos.height+4;
3016     gcd[gcdoff].gd.flags = gg_enabled | gg_visible | (layer->dostroke? gg_cb_on : 0);
3017     gcd[gcdoff].gd.cid = CID_Stroke;
3018     gcd[gcdoff++].creator = GCheckBoxCreate;
3019 
3020     stroke_gcd = gcdoff;
3021     k = 0;
3022 
3023     label[gcdoff].text = (unichar_t *) _("Color:");
3024     label[gcdoff].text_is_1byte = true;
3025     gcd[gcdoff].gd.label = &label[gcdoff];
3026     gcd[gcdoff].gd.pos.x = 5; gcd[gcdoff].gd.pos.y = gcd[gcdoff-1].gd.pos.y+12;
3027     gcd[gcdoff].gd.flags = gg_enabled | gg_visible;
3028     gcd[gcdoff++].creator = GLabelCreate;
3029     shvarray[k++] = &gcd[gcdoff-1];
3030 
3031     sprintf( scol, "#%06x", layer->stroke_pen.brush.col );
3032     label[gcdoff].text = (unichar_t *) scol;
3033     label[gcdoff].text_is_1byte = true;
3034     if ( layer->stroke_pen.brush.col==COLOR_INHERITED )
3035 	gcd[gcdoff].gd.flags = gg_visible;
3036     else {
3037 	gcd[gcdoff].gd.label = &label[gcdoff];
3038 	gcd[gcdoff].gd.flags = gg_enabled | gg_visible;
3039     }
3040     gcd[gcdoff].gd.pos.x = 80; gcd[gcdoff].gd.pos.y = gcd[gcdoff-1].gd.pos.y-3;
3041     gcd[gcdoff].gd.pos.width = 80;
3042     gcd[gcdoff].gd.cid = CID_StrokeColor;
3043     gcd[gcdoff++].creator = GTextFieldCreate;
3044     shvarray[k++] = &gcd[gcdoff-1];
3045 
3046     label[gcdoff].text = (unichar_t *) _("Inherited");
3047     label[gcdoff].text_is_1byte = true;
3048     gcd[gcdoff].gd.label = &label[gcdoff];
3049     gcd[gcdoff].gd.pos.x = 165; gcd[gcdoff].gd.pos.y = gcd[gcdoff-1].gd.pos.y+2;
3050     gcd[gcdoff].gd.flags = gg_enabled | gg_visible | (layer->stroke_pen.brush.col==COLOR_INHERITED? gg_cb_on : 0);
3051     gcd[gcdoff].data = (void *) CID_StrokeColor;
3052     gcd[gcdoff].gd.cid = CID_StrokeCInherit;
3053     gcd[gcdoff].gd.handle_controlevent = Layer_Inherit;
3054     gcd[gcdoff++].creator = GCheckBoxCreate;
3055     shvarray[k++] = &gcd[gcdoff-1];
3056 
3057     label[gcdoff].image = GGadgetImageCache("colorwheel.png");
3058     gcd[gcdoff].gd.label = &label[gcdoff];
3059     gcd[gcdoff].gd.flags = gg_enabled|gg_visible;
3060     gcd[gcdoff].data = (void *) CID_StrokeColor;
3061     gcd[gcdoff].gd.handle_controlevent = Layer_DoColorWheel;
3062     gcd[gcdoff++].creator = GButtonCreate;
3063     shvarray[k++] = &gcd[gcdoff-1];
3064     shvarray[k++] = NULL;
3065 
3066     label[gcdoff].text = (unichar_t *) _("Opacity:");
3067     label[gcdoff].text_is_1byte = true;
3068     gcd[gcdoff].gd.mnemonic = 'W';
3069     gcd[gcdoff].gd.label = &label[gcdoff];
3070     gcd[gcdoff].gd.pos.x = 5; gcd[gcdoff].gd.pos.y = gcd[gcdoff-1].gd.pos.y+25;
3071     gcd[gcdoff].gd.flags = gg_enabled | gg_visible;
3072     gcd[gcdoff++].creator = GLabelCreate;
3073     shvarray[k++] = &gcd[gcdoff-1];
3074 
3075     sprintf( sopac, "%g", layer->stroke_pen.brush.opacity );
3076     label[gcdoff].text = (unichar_t *) sopac;
3077     label[gcdoff].text_is_1byte = true;
3078     if ( layer->stroke_pen.brush.opacity<0 )
3079 	gcd[gcdoff].gd.flags = gg_visible;
3080     else {
3081 	gcd[gcdoff].gd.label = &label[gcdoff];
3082 	gcd[gcdoff].gd.flags = gg_enabled | gg_visible;
3083     }
3084     gcd[gcdoff].gd.pos.x = 80; gcd[gcdoff].gd.pos.y = gcd[gcdoff-1].gd.pos.y-3;
3085     gcd[gcdoff].gd.pos.width = 80;
3086     gcd[gcdoff].gd.cid = CID_StrokeOpacity;
3087     gcd[gcdoff++].creator = GTextFieldCreate;
3088     shvarray[k++] = &gcd[gcdoff-1];
3089 
3090     label[gcdoff].text = (unichar_t *) _("Inherited");
3091     label[gcdoff].text_is_1byte = true;
3092     gcd[gcdoff].gd.label = &label[gcdoff];
3093     gcd[gcdoff].gd.pos.x = 165; gcd[gcdoff].gd.pos.y = gcd[gcdoff-1].gd.pos.y+2;
3094     gcd[gcdoff].gd.flags = gg_enabled | gg_visible | (layer->stroke_pen.brush.opacity<0? gg_cb_on : 0);
3095     gcd[gcdoff].data = (void *) CID_StrokeOpacity;
3096     gcd[gcdoff].gd.cid = CID_StrokeOInherit;
3097     gcd[gcdoff].gd.handle_controlevent = Layer_Inherit;
3098     gcd[gcdoff++].creator = GCheckBoxCreate;
3099     shvarray[k++] = &gcd[gcdoff-1];
3100     shvarray[k++] = GCD_Glue;
3101     shvarray[k++] = NULL;
3102 
3103     label[gcdoff].text = (unichar_t *) _("Gradient:");
3104     label[gcdoff].text_is_1byte = true;
3105     gcd[gcdoff].gd.label = &label[gcdoff];
3106     gcd[gcdoff].gd.pos.x = 5; gcd[gcdoff].gd.pos.y = gcd[gcdoff-1].gd.pos.y+25;
3107     gcd[gcdoff].gd.flags = gg_enabled | gg_visible;
3108     gcd[gcdoff++].creator = GLabelCreate;
3109     shvarray[k++] = &gcd[gcdoff-1];
3110 
3111     gcd[gcdoff].gd.flags = layer->stroke_pen.brush.gradient==NULL ? (gg_visible | gg_enabled) : gg_visible;
3112     label[gcdoff].text = (unichar_t *) _("Add");
3113     label[gcdoff].text_is_1byte = true;
3114     label[gcdoff].text_in_resource = true;
3115     gcd[gcdoff].gd.label = &label[gcdoff];
3116     gcd[gcdoff].gd.handle_controlevent = Layer_StrokeGradAddEdit;
3117     gcd[gcdoff].gd.cid = CID_StrokeGradAdd;
3118     gcd[gcdoff++].creator = GButtonCreate;
3119     sgarray[0] = &gcd[gcdoff-1];
3120 
3121     gcd[gcdoff].gd.flags = layer->stroke_pen.brush.gradient!=NULL ? (gg_visible | gg_enabled) : gg_visible;
3122     label[gcdoff].text = (unichar_t *) _("Edit");
3123     label[gcdoff].text_is_1byte = true;
3124     label[gcdoff].text_in_resource = true;
3125     gcd[gcdoff].gd.label = &label[gcdoff];
3126     gcd[gcdoff].gd.handle_controlevent = Layer_StrokeGradAddEdit;
3127     gcd[gcdoff].gd.cid = CID_StrokeGradEdit;
3128     gcd[gcdoff++].creator = GButtonCreate;
3129     sgarray[1] = &gcd[gcdoff-1];
3130 
3131     gcd[gcdoff].gd.flags = layer->stroke_pen.brush.gradient!=NULL ? (gg_visible | gg_enabled) : gg_visible;
3132     label[gcdoff].text = (unichar_t *) _("Delete");
3133     label[gcdoff].text_is_1byte = true;
3134     label[gcdoff].text_in_resource = true;
3135     gcd[gcdoff].gd.label = &label[gcdoff];
3136     gcd[gcdoff].gd.handle_controlevent = Layer_StrokeGradDelete;
3137     gcd[gcdoff].gd.cid = CID_StrokeGradDelete;
3138     gcd[gcdoff++].creator = GButtonCreate;
3139     sgarray[2] = &gcd[gcdoff-1];
3140     sgarray[3] = GCD_Glue;
3141     sgarray[4] = NULL;
3142 
3143     boxes[9].gd.flags = gg_enabled|gg_visible;
3144     boxes[9].gd.u.boxelements = sgarray;
3145     boxes[9].creator = GHBoxCreate;
3146     shvarray[k++] = &boxes[9];
3147     shvarray[k++] = GCD_ColSpan;
3148     shvarray[k++] = GCD_Glue;
3149     shvarray[k++] = NULL;
3150 
3151     label[gcdoff].text = (unichar_t *) _("Pattern:");
3152     label[gcdoff].text_is_1byte = true;
3153     gcd[gcdoff].gd.label = &label[gcdoff];
3154     gcd[gcdoff].gd.pos.x = 5; gcd[gcdoff].gd.pos.y = gcd[gcdoff-1].gd.pos.y+25;
3155     gcd[gcdoff].gd.flags = gg_enabled | gg_visible;
3156     gcd[gcdoff++].creator = GLabelCreate;
3157     shvarray[k++] = &gcd[gcdoff-1];
3158 
3159     gcd[gcdoff].gd.flags = layer->stroke_pen.brush.pattern==NULL ? (gg_visible | gg_enabled) : gg_visible;
3160     label[gcdoff].text = (unichar_t *) _("Add");
3161     label[gcdoff].text_is_1byte = true;
3162     label[gcdoff].text_in_resource = true;
3163     gcd[gcdoff].gd.label = &label[gcdoff];
3164     gcd[gcdoff].gd.handle_controlevent = Layer_StrokePatAddEdit;
3165     gcd[gcdoff].gd.cid = CID_StrokePatAdd;
3166     gcd[gcdoff++].creator = GButtonCreate;
3167     sparray[0] = &gcd[gcdoff-1];
3168 
3169     gcd[gcdoff].gd.flags = layer->stroke_pen.brush.pattern!=NULL ? (gg_visible | gg_enabled) : gg_visible;
3170     label[gcdoff].text = (unichar_t *) _("Edit");
3171     label[gcdoff].text_is_1byte = true;
3172     label[gcdoff].text_in_resource = true;
3173     gcd[gcdoff].gd.label = &label[gcdoff];
3174     gcd[gcdoff].gd.handle_controlevent = Layer_StrokePatAddEdit;
3175     gcd[gcdoff].gd.cid = CID_StrokePatEdit;
3176     gcd[gcdoff++].creator = GButtonCreate;
3177     sparray[1] = &gcd[gcdoff-1];
3178 
3179     gcd[gcdoff].gd.flags = layer->stroke_pen.brush.pattern!=NULL ? (gg_visible | gg_enabled) : gg_visible;
3180     label[gcdoff].text = (unichar_t *) _("Delete");
3181     label[gcdoff].text_is_1byte = true;
3182     label[gcdoff].text_in_resource = true;
3183     gcd[gcdoff].gd.label = &label[gcdoff];
3184     gcd[gcdoff].gd.handle_controlevent = Layer_StrokePatDelete;
3185     gcd[gcdoff].gd.cid = CID_StrokePatDelete;
3186     gcd[gcdoff++].creator = GButtonCreate;
3187     sparray[2] = &gcd[gcdoff-1];
3188     sparray[3] = GCD_Glue;
3189     sparray[4] = NULL;
3190 
3191     boxes[10].gd.flags = gg_enabled|gg_visible;
3192     boxes[10].gd.u.boxelements = sparray;
3193     boxes[10].creator = GHBoxCreate;
3194     shvarray[k++] = &boxes[10];
3195     shvarray[k++] = GCD_ColSpan;
3196     shvarray[k++] = GCD_Glue;
3197     shvarray[k++] = NULL;
3198 
3199     label[gcdoff].text = (unichar_t *) _("Stroke _Width:");
3200     label[gcdoff].text_is_1byte = true;
3201     label[gcdoff].text_in_resource = true;
3202     gcd[gcdoff].gd.label = &label[gcdoff];
3203     gcd[gcdoff].gd.label = &label[gcdoff];
3204     gcd[gcdoff].gd.pos.x = 5; gcd[gcdoff].gd.pos.y = gcd[gcdoff-1].gd.pos.y+26;
3205     gcd[gcdoff].gd.flags = gg_enabled | gg_visible;
3206     gcd[gcdoff].gd.cid = CID_WidthTxt;
3207     gcd[gcdoff++].creator = GLabelCreate;
3208     shvarray[k++] = &gcd[gcdoff-1];
3209 
3210     sprintf( widthbuf, "%g", layer->stroke_pen.width );
3211     label[gcdoff].text = (unichar_t *) widthbuf;
3212     label[gcdoff].text_is_1byte = true;
3213     if ( layer->stroke_pen.width==WIDTH_INHERITED )
3214 	gcd[gcdoff].gd.flags = gg_visible;
3215     else {
3216 	gcd[gcdoff].gd.label = &label[gcdoff];
3217 	gcd[gcdoff].gd.flags = gg_enabled | gg_visible;
3218     }
3219     gcd[gcdoff].gd.pos.x = 80; gcd[gcdoff].gd.pos.y = gcd[gcdoff-1].gd.pos.y-3;
3220     gcd[gcdoff].gd.pos.width = 80;
3221     gcd[gcdoff].gd.cid = CID_Width;
3222     gcd[gcdoff++].creator = GTextFieldCreate;
3223     shvarray[k++] = &gcd[gcdoff-1];
3224 
3225     label[gcdoff].text = (unichar_t *) _("Inherited");
3226     label[gcdoff].text_is_1byte = true;
3227     gcd[gcdoff].gd.label = &label[gcdoff];
3228     gcd[gcdoff].gd.pos.x = 165; gcd[gcdoff].gd.pos.y = gcd[gcdoff-1].gd.pos.y+2;
3229     gcd[gcdoff].gd.flags = gg_enabled | gg_visible | (layer->stroke_pen.width==WIDTH_INHERITED? gg_cb_on : 0);
3230     gcd[gcdoff].data = (void *) CID_Width;
3231     gcd[gcdoff].gd.cid = CID_StrokeWInherit;
3232     gcd[gcdoff].gd.handle_controlevent = Layer_Inherit;
3233     gcd[gcdoff++].creator = GCheckBoxCreate;
3234     shvarray[k++] = &gcd[gcdoff-1];
3235     shvarray[k++] = GCD_Glue;
3236     shvarray[k++] = NULL;
3237 
3238     label[gcdoff].text = (unichar_t *) _("Dashes");
3239     label[gcdoff].text_is_1byte = true;
3240     gcd[gcdoff].gd.label = &label[gcdoff];
3241     gcd[gcdoff].gd.pos.x = 5; gcd[gcdoff].gd.pos.y = gcd[gcdoff-1].gd.pos.y+26;
3242     gcd[gcdoff].gd.flags = gg_enabled | gg_visible;
3243     gcd[gcdoff].gd.cid = CID_DashesTxt;
3244     gcd[gcdoff].gd.popup_msg = _("This specifies the dash pattern for a line.\nLeave this field blank for a solid line.\nOtherwise specify a list of up to 8 integers\n(between 0 and 255) which give the dash pattern\nin em-units. So \"10 10\" will draw the first\n10 units of a line, leave the next 10 blank,\ndraw the next 10, and so on.");
3245     gcd[gcdoff++].creator = GLabelCreate;
3246     shvarray[k++] = &gcd[gcdoff-1];
3247 
3248     pt = dashbuf; dashbuf[0] = '\0';
3249     for ( i=0; i<DASH_MAX && layer->stroke_pen.dashes[i]!=0; ++i ) {
3250 	sprintf( pt, "%d ", layer->stroke_pen.dashes[i]);
3251 	pt += strlen(pt);
3252     }
3253     if ( pt>dashbuf ) pt[-1] = '\0';
3254     label[gcdoff].text = (unichar_t *) dashbuf;
3255     label[gcdoff].text_is_1byte = true;
3256     if ( layer->stroke_pen.dashes[0]==0 && layer->stroke_pen.dashes[1]==DASH_INHERITED )
3257 	gcd[gcdoff].gd.flags = gg_visible;
3258     else {
3259 	gcd[gcdoff].gd.label = &label[gcdoff];
3260 	gcd[gcdoff].gd.flags = gg_enabled | gg_visible;
3261     }
3262     gcd[gcdoff].gd.pos.x = 80; gcd[gcdoff].gd.pos.y = gcd[gcdoff-1].gd.pos.y-3;
3263     gcd[gcdoff].gd.pos.width = 80;
3264     gcd[gcdoff].gd.cid = CID_Dashes;
3265     gcd[gcdoff++].creator = GTextFieldCreate;
3266     shvarray[k++] = &gcd[gcdoff-1];
3267 
3268     label[gcdoff].text = (unichar_t *) _("Inherited");
3269     label[gcdoff].text_is_1byte = true;
3270     gcd[gcdoff].gd.label = &label[gcdoff];
3271     gcd[gcdoff].gd.pos.x = 165; gcd[gcdoff].gd.pos.y = gcd[gcdoff-1].gd.pos.y+2;
3272     if ( layer->stroke_pen.dashes[0]==0 && layer->stroke_pen.dashes[1]==DASH_INHERITED )
3273 	gcd[gcdoff].gd.flags = gg_enabled | gg_visible | gg_cb_on;
3274     else
3275 	gcd[gcdoff].gd.flags = gg_enabled | gg_visible;
3276     gcd[gcdoff].data = (void *) CID_Dashes;
3277     gcd[gcdoff].gd.cid = CID_DashesInherit;
3278     gcd[gcdoff].gd.handle_controlevent = Layer_Inherit;
3279     gcd[gcdoff].gd.popup_msg = _("This specifies the dash pattern for a line.\nLeave this field blank for a solid line.\nOtherwise specify a list of up to 8 integers\n(between 0 and 255) which give the dash pattern\nin em-units. So \"10 10\" will draw the first\n10 units of a line, leave the next 10 blank,\ndraw the next 10, and so on.");
3280     gcd[gcdoff++].creator = GCheckBoxCreate;
3281     shvarray[k++] = &gcd[gcdoff-1];
3282     shvarray[k++] = GCD_Glue;
3283     shvarray[k++] = NULL;
3284 
3285     label[gcdoff].text = (unichar_t *) _("_Transform Pen:");
3286     label[gcdoff].text_in_resource = true;
3287     label[gcdoff].text_is_1byte = true;
3288     gcd[gcdoff].gd.label = &label[gcdoff];
3289     gcd[gcdoff].gd.pos.x = 5; gcd[gcdoff].gd.pos.y = gcd[gcdoff-1].gd.pos.y+25;
3290     gcd[gcdoff].gd.flags = gg_enabled | gg_visible;
3291     gcd[gcdoff++].creator = GLabelCreate;
3292     shvarray[k++] = &gcd[gcdoff-1];
3293 
3294     sprintf( transbuf, "[%.4g %.4g %.4g %.4g]", (double) layer->stroke_pen.trans[0],
3295 	    (double) layer->stroke_pen.trans[1], (double) layer->stroke_pen.trans[2],
3296 	    (double) layer->stroke_pen.trans[3]);
3297     label[gcdoff].text = (unichar_t *) transbuf;
3298     label[gcdoff].text_is_1byte = true;
3299     gcd[gcdoff].gd.label = &label[gcdoff];
3300     gcd[gcdoff].gd.pos.x = 80; gcd[gcdoff].gd.pos.y = gcd[gcdoff-1].gd.pos.y-3;
3301     gcd[gcdoff].gd.pos.width = 210;
3302     gcd[gcdoff].gd.flags = gg_enabled | gg_visible;
3303     gcd[gcdoff].gd.cid = CID_Trans;
3304     gcd[gcdoff++].creator = GTextFieldCreate;
3305     shvarray[k++] = &gcd[gcdoff-1];
3306     shvarray[k++] = GCD_ColSpan;
3307     shvarray[k++] = GCD_ColSpan;
3308     shvarray[k++] = NULL;
3309 
3310     j = 0;
3311     label[gcdoff].text = (unichar_t *) _("Line Cap");
3312     label[gcdoff].text_is_1byte = true;
3313     gcd[gcdoff].gd.label = &label[gcdoff];
3314     gcd[gcdoff].gd.pos.x = 10; gcd[gcdoff].gd.pos.y = gcd[gcdoff-2].gd.pos.y+20;
3315     gcd[gcdoff].gd.flags = gg_enabled | gg_visible;
3316     gcd[gcdoff].gd.cid = CID_LineCapTxt;
3317     gcd[gcdoff++].creator = GLabelCreate;
3318 
3319     label[gcdoff].text = (unichar_t *) _("_Butt");
3320     label[gcdoff].text_is_1byte = true;
3321     label[gcdoff].text_in_resource = true;
3322     label[gcdoff].image = &GIcon_buttcap;
3323     gcd[gcdoff].gd.mnemonic = 'B';
3324     gcd[gcdoff].gd.label = &label[gcdoff];
3325     gcd[gcdoff].gd.pos.x = 15; gcd[gcdoff].gd.pos.y = gcd[gcdoff-2].gd.pos.y+12;
3326     gcd[gcdoff].gd.flags = gg_enabled | gg_visible | (layer->stroke_pen.linecap==lc_butt?gg_cb_on:0);
3327     gcd[gcdoff].gd.cid = CID_ButtCap;
3328     gcd[gcdoff++].creator = GRadioCreate;
3329     lcarray[j++] = &gcd[gcdoff-1];
3330 
3331     label[gcdoff].text = (unichar_t *) _("_Round");
3332     label[gcdoff].text_is_1byte = true;
3333     label[gcdoff].text_in_resource = true;
3334     label[gcdoff].image = &GIcon_roundcap;
3335     gcd[gcdoff].gd.mnemonic = 'R';
3336     gcd[gcdoff].gd.label = &label[gcdoff];
3337     gcd[gcdoff].gd.pos.x = 80; gcd[gcdoff].gd.pos.y = gcd[gcdoff-1].gd.pos.y;
3338     gcd[gcdoff].gd.flags = gg_enabled | gg_visible | (layer->stroke_pen.linecap==lc_round?gg_cb_on:0);
3339     gcd[gcdoff].gd.cid = CID_RoundCap;
3340     gcd[gcdoff++].creator = GRadioCreate;
3341     lcarray[j++] = &gcd[gcdoff-1];
3342 
3343     label[gcdoff].text = (unichar_t *) _("S_quare");
3344     label[gcdoff].text_is_1byte = true;
3345     label[gcdoff].text_in_resource = true;
3346     label[gcdoff].image = &GIcon_squarecap;
3347     gcd[gcdoff].gd.mnemonic = 'q';
3348     gcd[gcdoff].gd.label = &label[gcdoff];
3349     gcd[gcdoff].gd.pos.x = 150; gcd[gcdoff].gd.pos.y = gcd[gcdoff-2].gd.pos.y;
3350     gcd[gcdoff].gd.flags = gg_enabled | gg_visible | (layer->stroke_pen.linecap==lc_square?gg_cb_on:0);
3351     gcd[gcdoff].gd.cid = CID_SquareCap;
3352     gcd[gcdoff++].creator = GRadioCreate;
3353     lcarray[j++] = &gcd[gcdoff-1];
3354 
3355     label[gcdoff].text = (unichar_t *) _("Inherited");
3356     label[gcdoff].text_is_1byte = true;
3357     gcd[gcdoff].gd.label = &label[gcdoff];
3358     gcd[gcdoff].gd.pos.x = 220; gcd[gcdoff].gd.pos.y = gcd[gcdoff-2].gd.pos.y;
3359     gcd[gcdoff].gd.flags = gg_enabled | gg_visible | (layer->stroke_pen.linecap==lc_inherited?gg_cb_on:0);
3360     gcd[gcdoff].gd.cid = CID_InheritCap;
3361     gcd[gcdoff++].creator = GRadioCreate;
3362     lcarray[j++] = &gcd[gcdoff-1];
3363     lcarray[j++] = NULL;
3364     lcarray[j++] = NULL;
3365 
3366     boxes[3].gd.pos.x = boxes[3].gd.pos.y = 2;
3367     boxes[3].gd.flags = gg_enabled|gg_visible;
3368     boxes[3].gd.u.boxelements = lcarray;
3369     boxes[3].gd.label = (GTextInfo *) &gcd[gcdoff-5];
3370     boxes[3].creator = GHVGroupCreate;
3371     shvarray[k++] = &boxes[3];
3372     shvarray[k++] = GCD_ColSpan;
3373     shvarray[k++] = GCD_ColSpan;
3374     shvarray[k++] = GCD_ColSpan;
3375     shvarray[k++] = NULL;
3376 
3377     j=0;
3378     label[gcdoff].text = (unichar_t *) _("Line Join");
3379     label[gcdoff].text_is_1byte = true;
3380     gcd[gcdoff].gd.label = &label[gcdoff];
3381     gcd[gcdoff].gd.pos.x = gcd[gcdoff-6].gd.pos.x; gcd[gcdoff].gd.pos.y = gcd[gcdoff-3].gd.pos.y+25;
3382     gcd[gcdoff].gd.flags = gg_enabled | gg_visible;
3383     gcd[gcdoff].gd.cid = CID_LineJoinTxt;
3384     gcd[gcdoff++].creator = GLabelCreate;
3385 
3386     label[gcdoff].text = (unichar_t *) _("_Miter");
3387     label[gcdoff].text_is_1byte = true;
3388     label[gcdoff].text_in_resource = true;
3389     label[gcdoff].image = &GIcon_miterjoin;
3390     gcd[gcdoff].gd.mnemonic = 'M';
3391     gcd[gcdoff].gd.label = &label[gcdoff];
3392     gcd[gcdoff].gd.pos.x = gcd[gcdoff-6].gd.pos.x; gcd[gcdoff].gd.pos.y = gcd[gcdoff-2].gd.pos.y+12;
3393     gcd[gcdoff].gd.flags = gg_enabled | gg_visible | (layer->stroke_pen.linejoin==lj_miter?gg_cb_on:0);
3394     gcd[gcdoff].gd.cid = CID_MiterJoin;
3395     gcd[gcdoff++].creator = GRadioCreate;
3396     ljarray[j++] = &gcd[gcdoff-1];
3397 
3398     label[gcdoff].text = (unichar_t *) _("Ro_und");
3399     label[gcdoff].text_is_1byte = true;
3400     label[gcdoff].text_in_resource = true;
3401     label[gcdoff].image = &GIcon_roundjoin;
3402     gcd[gcdoff].gd.mnemonic = 'u';
3403     gcd[gcdoff].gd.label = &label[gcdoff];
3404     gcd[gcdoff].gd.pos.x = gcd[gcdoff-6].gd.pos.x; gcd[gcdoff].gd.pos.y = gcd[gcdoff-1].gd.pos.y;
3405     gcd[gcdoff].gd.flags = gg_enabled | gg_visible | (layer->stroke_pen.linejoin==lj_round?gg_cb_on:0);
3406     gcd[gcdoff].gd.cid = CID_RoundJoin;
3407     gcd[gcdoff++].creator = GRadioCreate;
3408     ljarray[j++] = &gcd[gcdoff-1];
3409 
3410     label[gcdoff].text = (unichar_t *) _("Be_vel");
3411     label[gcdoff].text_is_1byte = true;
3412     label[gcdoff].text_in_resource = true;
3413     label[gcdoff].image = &GIcon_beveljoin;
3414     gcd[gcdoff].gd.mnemonic = 'v';
3415     gcd[gcdoff].gd.label = &label[gcdoff];
3416     gcd[gcdoff].gd.pos.x = gcd[gcdoff-6].gd.pos.x; gcd[gcdoff].gd.pos.y = gcd[gcdoff-1].gd.pos.y;
3417     gcd[gcdoff].gd.flags = gg_enabled | gg_visible | (layer->stroke_pen.linejoin==lj_bevel?gg_cb_on:0);
3418     gcd[gcdoff].gd.cid = CID_BevelJoin;
3419     gcd[gcdoff++].creator = GRadioCreate;
3420     ljarray[j++] = &gcd[gcdoff-1];
3421 
3422     label[gcdoff].text = (unichar_t *) _("Inherited");
3423     label[gcdoff].text_is_1byte = true;
3424     gcd[gcdoff].gd.mnemonic = 'q';
3425     gcd[gcdoff].gd.label = &label[gcdoff];
3426     gcd[gcdoff].gd.pos.x = 220; gcd[gcdoff].gd.pos.y = gcd[gcdoff-2].gd.pos.y;
3427     gcd[gcdoff].gd.flags = gg_enabled | gg_visible | (layer->stroke_pen.linejoin==lj_inherited?gg_cb_on:0);
3428     gcd[gcdoff].gd.cid = CID_InheritCap;
3429     gcd[gcdoff++].creator = GRadioCreate;
3430     ljarray[j++] = &gcd[gcdoff-1];
3431     ljarray[j++] = NULL;
3432     ljarray[j++] = NULL;
3433 
3434     boxes[4].gd.pos.x = boxes[4].gd.pos.y = 2;
3435     boxes[4].gd.flags = gg_enabled|gg_visible;
3436     boxes[4].gd.u.boxelements = ljarray;
3437     boxes[4].gd.label = (GTextInfo *) &gcd[gcdoff-5];
3438     boxes[4].creator = GHVGroupCreate;
3439     shvarray[k++] = &boxes[4];
3440     shvarray[k++] = GCD_ColSpan;
3441     shvarray[k++] = GCD_ColSpan;
3442     shvarray[k++] = NULL;
3443     shvarray[k++] = NULL;
3444 
3445     boxes[5].gd.pos.x = boxes[5].gd.pos.y = 2;
3446     boxes[5].gd.flags = gg_enabled|gg_visible;
3447     boxes[5].gd.u.boxelements = shvarray;
3448     boxes[5].gd.label = (GTextInfo *) &gcd[stroke_gcd-1];
3449     boxes[5].creator = GHVGroupCreate;
3450 
3451 
3452     gcd[gcdoff].gd.pos.x = 30-3; gcd[gcdoff].gd.pos.y = LY_Height-30-3;
3453     gcd[gcdoff].gd.pos.width = -1;
3454     gcd[gcdoff].gd.flags = gg_visible | gg_enabled | gg_but_default;
3455     label[gcdoff].text = (unichar_t *) _("_OK");
3456     label[gcdoff].text_is_1byte = true;
3457     label[gcdoff].text_in_resource = true;
3458     gcd[gcdoff].gd.label = &label[gcdoff];
3459     gcd[gcdoff].gd.handle_controlevent = Layer_OK;
3460     gcd[gcdoff++].creator = GButtonCreate;
3461     barray[0] = GCD_Glue; barray[1] = &gcd[gcdoff-1]; barray[2] = GCD_Glue; barray[3] = GCD_Glue;
3462 
3463     gcd[gcdoff].gd.pos.x = -30; gcd[gcdoff].gd.pos.y = gcd[gcdoff-1].gd.pos.y+3;
3464     gcd[gcdoff].gd.pos.width = -1;
3465     gcd[gcdoff].gd.flags = gg_visible | gg_enabled | gg_but_cancel;
3466     label[gcdoff].text = (unichar_t *) _("_Cancel");
3467     label[gcdoff].text_is_1byte = true;
3468     label[gcdoff].text_in_resource = true;
3469     gcd[gcdoff].gd.label = &label[gcdoff];
3470     gcd[gcdoff].gd.handle_controlevent = Layer_Cancel;
3471     gcd[gcdoff++].creator = GButtonCreate;
3472     barray[4] = GCD_Glue; barray[5] = &gcd[gcdoff-1]; barray[6] = GCD_Glue; barray[7] = NULL;
3473 
3474     boxes[6].gd.flags = gg_enabled|gg_visible;
3475     boxes[6].gd.u.boxelements = barray;
3476     boxes[6].creator = GHBoxCreate;
3477 
3478     varray[0] = &boxes[2]; varray[1] = &boxes[5]; varray[2] = &boxes[6]; varray[3] = NULL;
3479 
3480     boxes[0].gd.flags = gg_enabled|gg_visible;
3481     boxes[0].gd.u.boxelements = varray;
3482     boxes[0].creator = GVBoxCreate;
3483 
3484     GGadgetsCreate(gw,boxes);
3485     GHVBoxSetExpandableCol(boxes[2].ret,2);
3486     GHVBoxSetExpandableCol(boxes[5].ret,2);
3487     GHVBoxSetExpandableCol(boxes[6].ret,gb_expandgluesame);
3488     GHVBoxSetExpandableCol(boxes[7].ret,gb_expandgluesame);
3489     GHVBoxSetExpandableCol(boxes[8].ret,gb_expandgluesame);
3490     GHVBoxSetExpandableCol(boxes[9].ret,gb_expandgluesame);
3491     GHVBoxSetExpandableCol(boxes[10].ret,gb_expandgluesame);
3492     GHVBoxFitWindow(boxes[0].ret);
3493 
3494     GWidgetHidePalettes();
3495     /*GWidgetIndicateFocusGadget(GWidgetGetControl(ld.gw,CID_Width));*/
3496     GDrawSetVisible(ld.gw,true);
3497     while ( !ld.done )
3498 	GDrawProcessOneEvent(NULL);
3499     GDrawDestroyWindow(ld.gw);
3500     if ( !ld.ok ) {
3501 	GradientFree(ld.fillgrad);
3502 	GradientFree(ld.strokegrad);
3503 	PatternFree(ld.fillpat);
3504 	PatternFree(ld.strokepat);
3505     }
3506 return( ld.ok );
3507 }
3508