1 /* -*- coding: utf-8 -*- */
2 /* Copyright (C) 2000-2012 by George Williams */
3 /*
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6
7 * Redistributions of source code must retain the above copyright notice, this
8 * list of conditions and the following disclaimer.
9
10 * Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13
14 * The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
20 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
23 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
25 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
26 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include <fontforge-config.h>
30
31 #include "bvedit.h"
32 #include "fontforgeui.h"
33 #include "gkeysym.h"
34 #include "ustring.h"
35
36 #include <math.h>
37
38 #define TCnt 3
39
40 typedef struct transdata {
41 void *userdata;
42 void (*transfunc)(void *,real trans[6],int otype,BVTFunc *,enum fvtrans_flags);
43 int (*getorigin)(void *,BasePoint *bp,int otype);
44 GWindow gw;
45 int applied;
46 int done;
47 } TransData;
48
49 #define CID_Origin 3001
50 #define CID_AllLayers 3002
51 #define CID_Round2Int 3003
52 #define CID_DoKerns 3004
53 #define CID_DoSimplePos 3005
54 #define CID_DoGrid 3006
55 #define CID_DoWidth 3007
56 #define CID_Apply 3008
57
58 #define CID_Type 1001
59 #define CID_XMove 1002
60 #define CID_YMove 1003
61 #define CID_Angle 1004
62 #define CID_Scale 1005
63 #define CID_XScale 1006
64 #define CID_YScale 1007
65 #define CID_Horizontal 1008
66 #define CID_Vertical 1009
67 #define CID_SkewAng 1010
68 #define CID_XLab 1011
69 #define CID_YLab 1012
70 #define CID_CounterClockwise 1013
71 #define CID_Clockwise 1014
72 #define CID_XPercent 1015
73 #define CID_YPercent 1016
74 #define CID_XDegree 1017
75 #define CID_YDegree 1018
76 #define CID_XAxis 1019
77 #define CID_YAxis 1020
78
79 #define CID_First CID_Type
80 #define CID_Last CID_YAxis
81
82 #define CID_ClockBox 1021
83 #define CID_HVBox 1022
84 #define CID_HBox 1023
85
86 #define TBlock_Width 270
87 #define TBlock_Height 40
88 #define TBlock_Top 32
89 #define TBlock_XStart 130
90 #define TBlock_CIDOffset 100
91
92 static GTextInfo origin[] = {
93 { (unichar_t *) N_("Glyph Origin"), NULL, 0, 0, NULL, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0' },
94 { (unichar_t *) N_("Center of Selection"), NULL, 0, 0, NULL, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0' },
95 /* GT: The (x,y) position on the window where the user last pressed a mouse button */
96 { (unichar_t *) N_("Last Press"), NULL, 0, 0, NULL, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0' },
97 GTEXTINFO_EMPTY
98 };
99
100 static int selcid[] = { 0, CID_XMove, CID_Angle, CID_Scale, CID_XScale, 0, CID_SkewAng, CID_XAxis };
101 static GTextInfo transformtypes[] = {
102 { (unichar_t *) N_("Do Nothing"), NULL, 0, 0, (void *) 0x1000, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0' },
103 { (unichar_t *) N_("Move..."), NULL, 0, 0, (void *) 0x1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0' },
104 { (unichar_t *) N_("Rotate..."), NULL, 0, 0, (void *) 0x2, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0' },
105 { (unichar_t *) N_("Scale Uniformly..."), NULL, 0, 0, (void *) 0x4, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0' },
106 { (unichar_t *) N_("Scale..."), NULL, 0, 0, (void *) 0x8, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0' },
107 { (unichar_t *) N_("Flip..."), NULL, 0, 0, (void *) 0x10, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0' },
108 { (unichar_t *) N_("Skew..."), NULL, 0, 0, (void *) 0x20, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0' },
109 { (unichar_t *) N_("Rotate 3D Around..."), NULL, 0, 0, (void *) 0x40, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0' },
110 { (unichar_t *) N_("Move by Ruler..."), NULL, 0, 0, (void *) 0x401, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0' },
111 { (unichar_t *) N_("Rotate by Ruler..."), NULL, 0, 0, (void *) 0x402, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0' },
112 { (unichar_t *) N_("Skew by Ruler..."), NULL, 0, 0, (void *) 0x420, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0' },
113 GTEXTINFO_EMPTY
114 };
115
Trans_OK(GGadget * g,GEvent * e)116 static int Trans_OK(GGadget *g, GEvent *e) {
117 real transform[6], trans[6], t[6];
118 bigreal angle, angle2;
119 int i, index, err;
120 int alllayers = false, round_2_int = false, dokerns = false, dokp=false;
121 int dogrid = false, dowidth = false;
122 BasePoint base;
123 int origin, bvpos=0;
124 BVTFunc bvts[TCnt+1];
125 static int warned = false;
126 int isapply = GGadgetGetCid(g) == CID_Apply;
127
128 if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
129 TransData *td = GDrawGetUserData(GGadgetGetWindow(g));
130
131 transform[0] = transform[3] = 1.0;
132 transform[1] = transform[2] = transform[4] = transform[5] = 0;
133 base.x = base.y = 0;
134
135 origin = GGadgetGetFirstListSelectedItem( GWidgetGetControl(td->gw,CID_Origin));
136 if ( GWidgetGetControl(td->gw,CID_AllLayers)!=NULL )
137 alllayers = GGadgetIsChecked(GWidgetGetControl(td->gw,CID_AllLayers));
138 if ( GWidgetGetControl(td->gw,CID_DoGrid)!=NULL )
139 dogrid = GGadgetIsChecked(GWidgetGetControl(td->gw,CID_DoGrid));
140 if ( GWidgetGetControl(td->gw,CID_DoWidth)!=NULL )
141 dowidth = GGadgetIsChecked(GWidgetGetControl(td->gw,CID_DoWidth));
142 else
143 dowidth = true;
144 if ( GWidgetGetControl(td->gw,CID_DoSimplePos)!=NULL )
145 dokp = GGadgetIsChecked(GWidgetGetControl(td->gw,CID_DoSimplePos));
146 if ( GWidgetGetControl(td->gw,CID_DoKerns)!=NULL )
147 dokerns = GGadgetIsChecked(GWidgetGetControl(td->gw,CID_DoKerns));
148 round_2_int = GGadgetIsChecked(GWidgetGetControl(td->gw,CID_Round2Int));
149 if ( isapply )
150 alllayers = dogrid = dokp = dokerns = false;
151 if ( td->getorigin!=NULL ) {
152 (td->getorigin)(td->userdata,&base,origin );
153 transform[4] = -base.x;
154 transform[5] = -base.y;
155 }
156 for ( i=0; i<TCnt; ++i ) {
157 index = GGadgetGetFirstListSelectedItem(
158 GWidgetGetControl(td->gw,CID_Type+i*TBlock_CIDOffset));
159 trans[0] = trans[3] = 1.0;
160 trans[1] = trans[2] = trans[4] = trans[5] = 0;
161 err = 0;
162 switch ( index ) {
163 case 0: /* Do Nothing */
164 break;
165 case 1: /* Move */
166 trans[4] = GetReal8(td->gw,CID_XMove+i*TBlock_CIDOffset,_("X Movement"),&err);
167 trans[5] = GetReal8(td->gw,CID_YMove+i*TBlock_CIDOffset,_("Y Movement"),&err);
168 bvts[bvpos].x = trans[4]; bvts[bvpos].y = trans[5]; bvts[bvpos++].func = bvt_transmove;
169 break;
170 case 2: /* Rotate */
171 angle = GetReal8(td->gw,CID_Angle+i*TBlock_CIDOffset,_("Rotation Angle"),&err);
172 if ( GGadgetIsChecked( GWidgetGetControl(td->gw,CID_Clockwise+i*TBlock_CIDOffset)) )
173 angle = -angle;
174 if ( fmod(angle,90)!=0 )
175 bvts[0].func = bvt_none; /* Bad trans=> No trans */
176 else {
177 angle = fmod(angle,360);
178 if ( angle<0 ) angle+=360;
179 if ( angle==90 ) bvts[bvpos++].func = bvt_rotate90ccw;
180 else if ( angle==180 ) bvts[bvpos++].func = bvt_rotate180;
181 else if ( angle==270 ) bvts[bvpos++].func = bvt_rotate90cw;
182 }
183 angle *= FF_PI/180;
184 trans[0] = trans[3] = cos(angle);
185 trans[2] = -(trans[1] = sin(angle));
186 break;
187 case 3: /* Scale Uniformly */
188 trans[0] = trans[3] = GetReal8(td->gw,CID_Scale+i*TBlock_CIDOffset,_("Scale Factor"),&err)/100.0;
189 bvts[0].func = bvt_none; /* Bad trans=> No trans */
190 break;
191 case 4: /* Scale */
192 trans[0] = GetReal8(td->gw,CID_XScale+i*TBlock_CIDOffset,_("X Scale Factor"),&err)/100.0;
193 trans[3] = GetReal8(td->gw,CID_YScale+i*TBlock_CIDOffset,_("Y Scale Factor"),&err)/100.0;
194 bvts[0].func = bvt_none; /* Bad trans=> No trans */
195 break;
196 case 5: /* Flip */
197 if ( GGadgetIsChecked( GWidgetGetControl(td->gw,CID_Horizontal+i*TBlock_CIDOffset)) ) {
198 trans[0] = -1;
199 bvts[bvpos++].func = bvt_fliph;
200 } else {
201 trans[3] = -1;
202 bvts[bvpos++].func = bvt_flipv;
203 }
204 break;
205 case 6: /* Skew */
206 angle = GetReal8(td->gw,CID_SkewAng+i*TBlock_CIDOffset,_("Skew Angle"),&err);
207 if ( GGadgetIsChecked( GWidgetGetControl(td->gw,CID_CounterClockwise+i*TBlock_CIDOffset)) )
208 angle = -angle;
209 angle *= FF_PI/180;
210 trans[2] = tan(angle);
211 skewselect(&bvts[bvpos],trans[2]); ++bvpos;
212 break;
213 case 7: /* 3D rotate */
214 angle = GetReal8(td->gw,CID_XAxis+i*TBlock_CIDOffset,_("Rotation about X Axis"),&err) * FF_PI/180;
215 angle2 = GetReal8(td->gw,CID_YAxis+i*TBlock_CIDOffset,_("Rotation about Y Axis"),&err) * FF_PI/180;
216 trans[0] = cos(angle2);
217 trans[3] = cos(angle );
218 bvts[0].func = bvt_none; /* Bad trans=> No trans */
219 break;
220 default:
221 IError("Unexpected selection in Transform");
222 err = 1;
223 break;
224 }
225 if ( err )
226 return(true);
227 t[0] = transform[0]*trans[0] +
228 transform[1]*trans[2];
229 t[1] = transform[0]*trans[1] +
230 transform[1]*trans[3];
231 t[2] = transform[2]*trans[0] +
232 transform[3]*trans[2];
233 t[3] = transform[2]*trans[1] +
234 transform[3]*trans[3];
235 t[4] = transform[4]*trans[0] +
236 transform[5]*trans[2] +
237 trans[4];
238 t[5] = transform[4]*trans[1] +
239 transform[5]*trans[3] +
240 trans[5];
241 memcpy(transform,t,sizeof(t));
242 }
243 bvts[bvpos++].func = bvt_none; /* Done */
244 for ( i=0; i<6; ++i )
245 if ( RealNear(transform[i],0)) transform[i] = 0;
246 transform[4] += base.x;
247 transform[5] += base.y;
248
249 if (( transform[1]!=0 || transform[2]!=0 ) && !warned ) {
250 ff_post_notice(_("Warning"),_("After rotating or skewing a glyph you should probably apply Element->Add Extrema"));
251 warned = true;
252 }
253 (td->transfunc)(td->userdata,transform,origin,bvts,
254 (alllayers?fvt_alllayers:0)|
255 (dogrid?fvt_dogrid:0)|
256 (dowidth?0:fvt_dontmovewidth)|
257 (round_2_int?fvt_round_to_int:0)|
258 (dokp?fvt_scalepstpos:0)|
259 (dokerns?fvt_scalekernclasses:0)|
260 (isapply?fvt_justapply:0));
261 td->done = !isapply;
262 td->applied = isapply;
263 }
264 return( true );
265 }
266
Trans_Cancel(GGadget * g,GEvent * e)267 static int Trans_Cancel(GGadget *g, GEvent *e) {
268 if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
269 TransData *td = GDrawGetUserData(GGadgetGetWindow(g));
270 if ( td->applied )
271 (td->transfunc)(td->userdata,NULL,0,NULL,fvt_revert);
272 td->done = true;
273 }
274 return( true );
275 }
276
Trans_TypeChange(GGadget * g,GEvent * e)277 static int Trans_TypeChange(GGadget *g, GEvent *e) {
278 if ( e->type==et_controlevent && e->u.control.subtype == et_listselected ) {
279 GWindow bw = GGadgetGetWindow(g);
280 int offset = GGadgetGetCid(g)-CID_Type;
281 int index = GGadgetGetFirstListSelectedItem(g);
282 if ( index < 0 ) return( false );
283 int mask = (intpt) transformtypes[index].userdata;
284 int i;
285
286 if ( mask & 0x400 ) {
287 real xoff = last_ruler_offset[0].x, yoff = last_ruler_offset[0].y;
288 char buf[24]; unichar_t ubuf[24];
289 if ( mask & 0x20 )
290 index -= 4; /* skew */
291 else
292 index -= 7; /* move or rotate */
293 GGadgetSelectOneListItem( g,index );
294 mask &= ~0x400;
295 if ( mask&1 ) { /* Move */
296 sprintf( buf, "%.1f", (double) xoff );
297 uc_strcpy(ubuf,buf);
298 GGadgetSetTitle(GWidgetGetControl(bw,CID_XMove+offset), ubuf );
299 sprintf( buf, "%.1f", (double) yoff );
300 uc_strcpy(ubuf,buf);
301 GGadgetSetTitle(GWidgetGetControl(bw,CID_YMove+offset), ubuf );
302 } else {
303 sprintf( buf, "%.0f", atan2(yoff,xoff)*180/FF_PI );
304 uc_strcpy(ubuf,buf);
305 GGadgetSetTitle(GWidgetGetControl(bw,((mask&0x2)?CID_Angle:CID_SkewAng)+offset), ubuf );
306 GGadgetSetChecked(GWidgetGetControl(bw,CID_Clockwise+offset), false );
307 GGadgetSetChecked(GWidgetGetControl(bw,CID_CounterClockwise+offset), true );
308 }
309 }
310
311 for ( i=CID_First; i<=CID_Last; ++i ) {
312 GGadget *sg;
313 sg = GWidgetGetControl(bw,i+offset);
314 GGadgetSetVisible(sg, ( ((intpt) GGadgetGetUserData(sg))&mask )?1:0);
315 }
316 if ( selcid[index]!=0 ) {
317 GGadget *tf = GWidgetGetControl(bw,selcid[index]+offset);
318 GWidgetIndicateFocusGadget(tf);
319 GTextFieldSelect(tf,0,-1);
320 }
321 GWidgetToDesiredSize(bw);
322 GDrawRequestExpose(bw,NULL,false);
323 }
324 return( true );
325 }
326
trans_e_h(GWindow gw,GEvent * event)327 static int trans_e_h(GWindow gw, GEvent *event) {
328 if ( event->type==et_close ) {
329 TransData *td = GDrawGetUserData(gw);
330 td->done = true;
331 } else if ( event->type == et_map && event->u.map.is_visible ) {
332 /* Above palettes */
333 GDrawRaise(gw);
334 } else if ( event->type==et_char ) {
335 if ( event->u.chr.keysym == GK_F1 || event->u.chr.keysym == GK_Help ) {
336 help("ui/dialogs/transform.html", NULL);
337 return( true );
338 }
339 return( false );
340 }
341 return( true );
342 }
343
MakeTransBlock(TransData * td,int bnum,GGadgetCreateData * gcd,GTextInfo * label,GGadgetCreateData ** array)344 static GGadgetCreateData *MakeTransBlock(TransData *td,int bnum,
345 GGadgetCreateData *gcd, GTextInfo *label, GGadgetCreateData **array) {
346 int offset = bnum*TBlock_CIDOffset;
347
348 gcd[0].gd.pos.x = 5; gcd[0].gd.pos.y = 9;
349 gcd[0].gd.flags = gg_visible | gg_enabled;
350 gcd[0].gd.label = &transformtypes[0];
351 gcd[0].gd.u.list = transformtypes;
352 gcd[0].gd.cid = CID_Type+offset;
353 gcd[0].creator = GListButtonCreate;
354 gcd[0].data = (void *) -1;
355 gcd[0].gd.handle_controlevent = Trans_TypeChange;
356 transformtypes[0].selected = true;
357
358 label[1].text = (unichar_t *) _("_X");
359 label[1].text_is_1byte = true;
360 label[1].text_in_resource = true;
361 gcd[1].gd.label = &label[1];
362 gcd[1].gd.pos.x = TBlock_XStart; gcd[1].gd.pos.y = 15;
363 gcd[1].gd.flags = bnum==0? (gg_enabled|gg_visible) : gg_enabled;
364 gcd[1].data = (void *) 0x49;
365 gcd[1].gd.cid = CID_XLab+offset;
366 gcd[1].creator = GLabelCreate;
367
368 label[2].text = (unichar_t *) "0";
369 label[2].text_is_1byte = true;
370 gcd[2].gd.label = &label[2];
371 gcd[2].gd.pos.x = TBlock_XStart+10; gcd[2].gd.pos.y = 9; gcd[2].gd.pos.width = 40;
372 gcd[2].gd.flags = bnum==0? (gg_enabled|gg_visible) : gg_enabled;
373 gcd[2].data = (void *) 0x1;
374 gcd[2].gd.cid = CID_XMove+offset;
375 gcd[2].creator = GTextFieldCreate;
376
377 label[3].text = (unichar_t *) _("_Y");
378 label[3].text_is_1byte = true;
379 label[3].text_in_resource = true;
380 gcd[3].gd.label = &label[3];
381 gcd[3].gd.pos.x = TBlock_XStart+70; gcd[3].gd.pos.y = 15;
382 gcd[3].gd.flags = bnum==0? (gg_enabled|gg_visible) : gg_enabled;
383 gcd[3].data = (void *) 0x49;
384 gcd[3].gd.cid = CID_YLab+offset;
385 gcd[3].creator = GLabelCreate;
386
387 label[4].text = (unichar_t *) "0";
388 label[4].text_is_1byte = true;
389 gcd[4].gd.label = &label[4];
390 gcd[4].gd.pos.x = TBlock_XStart+80; gcd[4].gd.pos.y = 9; gcd[4].gd.pos.width = 40;
391 gcd[4].gd.flags = bnum==0? (gg_enabled|gg_visible) : gg_enabled;
392 gcd[4].data = (void *) 0x1;
393 gcd[4].gd.cid = CID_YMove+offset;
394 gcd[4].creator = GTextFieldCreate;
395
396 label[5].text = (unichar_t *) "100";
397 label[5].text_is_1byte = true;
398 gcd[5].gd.label = &label[5];
399 gcd[5].gd.pos.x = TBlock_XStart+10; gcd[5].gd.pos.y = 9; gcd[5].gd.pos.width = 40;
400 gcd[5].gd.flags = gg_enabled;
401 gcd[5].data = (void *) 0x8;
402 gcd[5].gd.cid = CID_XScale+offset;
403 gcd[5].creator = GTextFieldCreate;
404
405 label[6].text = (unichar_t *) "100";
406 label[6].text_is_1byte = true;
407 gcd[6].gd.label = &label[6];
408 gcd[6].gd.pos.x = TBlock_XStart+80; gcd[6].gd.pos.y = 9; gcd[6].gd.pos.width = 40;
409 gcd[6].gd.flags = gg_enabled;
410 gcd[6].data = (void *) 0x8;
411 gcd[6].gd.cid = CID_YScale+offset;
412 gcd[6].creator = GTextFieldCreate;
413
414 label[7].text = (unichar_t *) "100";
415 label[7].text_is_1byte = true;
416 gcd[7].gd.label = &label[7];
417 gcd[7].gd.pos.x = TBlock_XStart+10; gcd[7].gd.pos.y = 9; gcd[7].gd.pos.width = 40;
418 gcd[7].gd.flags = gg_enabled;
419 gcd[7].data = (void *) 0x4;
420 gcd[7].gd.cid = CID_Scale+offset;
421 gcd[7].creator = GTextFieldCreate;
422
423 label[8].text = (unichar_t *) U_("° Clockwise");
424 label[8].text_is_1byte = true;
425 gcd[8].gd.label = &label[8];
426 gcd[8].gd.pos.x = TBlock_XStart+53; gcd[8].gd.pos.y = 2; gcd[8].gd.pos.height = 12;
427 gcd[8].gd.flags = gg_enabled;
428 gcd[8].data = (void *) 0x22;
429 gcd[8].gd.cid = CID_Clockwise+offset;
430 gcd[8].creator = GRadioCreate;
431
432 /* GT: Sometimes spelled Widdershins. An old word which means counter clockwise. */
433 /* GT: I used it because "counter clockwise" took too much space. */
434 label[9].text = (unichar_t *) U_("° Withershins"); /* deiseal */
435 label[9].text_is_1byte = true;
436 gcd[9].gd.label = &label[9];
437 gcd[9].gd.pos.x = TBlock_XStart+53; gcd[9].gd.pos.y = 17; gcd[9].gd.pos.height = 12;
438 gcd[9].gd.flags = gg_enabled | gg_cb_on;
439 gcd[9].data = (void *) 0x22;
440 gcd[9].gd.cid = CID_CounterClockwise+offset;
441 gcd[9].creator = GRadioCreate;
442
443 label[10].text = (unichar_t *) "180";
444 label[10].text_is_1byte = true;
445 gcd[10].gd.label = &label[10];
446 gcd[10].gd.pos.x = TBlock_XStart+10; gcd[10].gd.pos.y = 9; gcd[10].gd.pos.width = 40;
447 gcd[10].gd.flags = gg_enabled;
448 gcd[10].data = (void *) 0x2;
449 gcd[10].gd.cid = CID_Angle+offset;
450 gcd[10].creator = GTextFieldCreate;
451
452 label[11].text = (unichar_t *) "10"; /* -10 if we default clockwise */
453 label[11].text_is_1byte = true;
454 gcd[11].gd.label = &label[11];
455 gcd[11].gd.pos.x = TBlock_XStart+10; gcd[11].gd.pos.y = 9; gcd[11].gd.pos.width = 40;
456 gcd[11].gd.flags = gg_enabled;
457 gcd[11].data = (void *) 0x20;
458 gcd[11].gd.cid = CID_SkewAng+offset;
459 gcd[11].creator = GTextFieldCreate;
460
461 label[12].text = (unichar_t *) _("Horizontal");
462 label[12].text_is_1byte = true;
463 gcd[12].gd.label = &label[12];
464 gcd[12].gd.pos.x = TBlock_XStart; gcd[12].gd.pos.y = 2; gcd[12].gd.pos.height = 12;
465 gcd[12].gd.flags = gg_enabled | gg_cb_on;
466 gcd[12].data = (void *) 0x10;
467 gcd[12].gd.cid = CID_Horizontal+offset;
468 gcd[12].creator = GRadioCreate;
469
470 label[13].text = (unichar_t *) _("Vertical");
471 label[13].text_is_1byte = true;
472 gcd[13].gd.label = &label[13];
473 gcd[13].gd.pos.x = TBlock_XStart; gcd[13].gd.pos.y = 17; gcd[13].gd.pos.height = 12;
474 gcd[13].gd.flags = gg_enabled;
475 gcd[13].data = (void *) 0x10;
476 gcd[13].gd.cid = CID_Vertical+offset;
477 gcd[13].creator = GRadioCreate;
478
479 label[14].text = (unichar_t *) _("%");
480 label[14].text_is_1byte = true;
481 gcd[14].gd.label = &label[14];
482 gcd[14].gd.pos.x = TBlock_XStart+51; gcd[14].gd.pos.y = 15;
483 gcd[14].gd.flags = gg_enabled;
484 gcd[14].data = (void *) 0xc;
485 gcd[14].gd.cid = CID_XPercent+offset;
486 gcd[14].creator = GLabelCreate;
487
488 label[15].text = (unichar_t *) _("%");
489 label[15].text_is_1byte = true;
490 gcd[15].gd.label = &label[15];
491 gcd[15].gd.pos.x = TBlock_XStart+121; gcd[15].gd.pos.y = 15;
492 gcd[15].gd.flags = gg_enabled;
493 gcd[15].data = (void *) 0x8;
494 gcd[15].gd.cid = CID_YPercent+offset;
495 gcd[15].creator = GLabelCreate;
496
497 label[16].text = (unichar_t *) U_("°");
498 label[16].text_is_1byte = true;
499 gcd[16].gd.label = &label[16];
500 gcd[16].gd.pos.x = TBlock_XStart+51; gcd[16].gd.pos.y = 15;
501 gcd[16].gd.flags = gg_enabled;
502 gcd[16].data = (void *) 0x40;
503 gcd[16].gd.cid = CID_XDegree+offset;
504 gcd[16].creator = GLabelCreate;
505
506 label[17].text = (unichar_t *) U_("°");
507 label[17].text_is_1byte = true;
508 gcd[17].gd.label = &label[17];
509 gcd[17].gd.pos.x = TBlock_XStart+121; gcd[17].gd.pos.y = 15;
510 gcd[17].gd.flags = gg_enabled;
511 gcd[17].data = (void *) 0x40;
512 gcd[17].gd.cid = CID_YDegree+offset;
513 gcd[17].creator = GLabelCreate;
514
515 label[18].text = (unichar_t *) "45";
516 label[18].text_is_1byte = true;
517 gcd[18].gd.label = &label[18];
518 gcd[18].gd.pos.x = TBlock_XStart+10; gcd[18].gd.pos.y = 9; gcd[18].gd.pos.width = 40;
519 gcd[18].gd.flags = gg_enabled;
520 gcd[18].data = (void *) 0x40;
521 gcd[18].gd.cid = CID_XAxis+offset;
522 gcd[18].creator = GTextFieldCreate;
523
524 label[19].text = (unichar_t *) "0";
525 label[19].text_is_1byte = true;
526 gcd[19].gd.label = &label[19];
527 gcd[19].gd.pos.x = TBlock_XStart+80; gcd[19].gd.pos.y = 9; gcd[19].gd.pos.width = 40;
528 gcd[19].gd.flags = gg_enabled;
529 gcd[19].data = (void *) 0x40;
530 gcd[19].gd.cid = CID_YAxis+offset;
531 gcd[19].creator = GTextFieldCreate;
532
533
534 array[0] = &gcd[12]; array[1] = &gcd[13]; array[2] = NULL;
535 array[3] = &gcd[8]; array[4] = &gcd[9]; array[5] = NULL;
536
537 gcd[20].gd.flags = gg_enabled|gg_visible;
538 gcd[20].gd.u.boxelements = array;
539 gcd[20].gd.cid = CID_HVBox+offset;
540 gcd[20].creator = GVBoxCreate;
541
542 gcd[21].gd.flags = gg_enabled|gg_visible;
543 gcd[21].gd.u.boxelements = array+3;
544 gcd[21].gd.cid = CID_ClockBox+offset;
545 gcd[21].creator = GVBoxCreate;
546
547 array[6] = &gcd[0];
548 array[7] = &gcd[20];
549 array[8] = &gcd[1];
550 array[9] = &gcd[2];
551 array[10] = &gcd[5];
552 array[11] = &gcd[7];
553 array[12] = &gcd[10];
554 array[13] = &gcd[11];
555 array[14] = &gcd[18];
556 array[15] = &gcd[14];
557 array[16] = &gcd[16];
558 array[17] = &gcd[21];
559 array[18] = &gcd[3];
560 array[19] = &gcd[4];
561 array[20] = &gcd[6];
562 array[21] = &gcd[19];
563 array[22] = &gcd[15];
564 array[23] = &gcd[17];
565 array[24] = GCD_Glue;
566 array[25] = NULL;
567 array[26] = NULL;
568
569 gcd[22].gd.flags = gg_enabled|gg_visible;
570 gcd[22].gd.u.boxelements = array+6;
571 gcd[22].gd.cid = CID_HBox+offset;
572 gcd[22].creator = GHVGroupCreate;
573 return( gcd+22 );
574 }
575
TransformDlgCreate(void * data,void (* transfunc)(void *,real *,int,BVTFunc *,enum fvtrans_flags),int (* getorigin)(void *,BasePoint *,int),enum transdlg_flags flags,enum cvtools cvt)576 void TransformDlgCreate(void *data,void (*transfunc)(void *,real *,int,BVTFunc *,enum fvtrans_flags),
577 int (*getorigin)(void *,BasePoint *,int), enum transdlg_flags flags,
578 enum cvtools cvt) {
579 GRect pos;
580 GWindow gw;
581 GWindowAttrs wattrs;
582 GGadgetCreateData gcd[12+TCnt*25], boxes[4], *subarray[TCnt*27], *array[2*(TCnt+8)+4], *buttons[13], *origarray[4];
583 GTextInfo label[9+TCnt*24];
584 static TransData td;
585 int i, y, gci, subai, ai;
586 int32 len;
587 GGadget *orig;
588 BasePoint junk;
589 GTextInfo **ti;
590 static int done = false;
591
592 if ( !done ) {
593 int i;
594 for ( i=0; transformtypes[i].text!=NULL; ++i )
595 transformtypes[i].text = (unichar_t *) _((char *) transformtypes[i].text);
596 for ( i=0; origin[i].text!=NULL; ++i )
597 origin[i].text = (unichar_t *) _((char *) origin[i].text);
598 done = true;
599 }
600
601 td.userdata = data;
602 td.transfunc = transfunc;
603 td.getorigin = getorigin;
604 td.done = false;
605
606 if ( td.gw==NULL ) {
607 memset(&wattrs,0,sizeof(wattrs));
608 wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_undercursor|wam_isdlg|wam_restrict;
609 wattrs.event_masks = ~(1<<et_charup);
610 wattrs.restrict_input_to_me = 1;
611 wattrs.undercursor = 1;
612 wattrs.cursor = ct_pointer;
613 wattrs.utf8_window_title = _("Transform");
614 wattrs.is_dlg = true;
615 pos.x = pos.y = 0;
616 pos.width = GGadgetScale(GDrawPointsToPixels(NULL,TBlock_Width));
617 pos.height = GDrawPointsToPixels(NULL,TBlock_Top+TCnt*TBlock_Height+110);
618 td.gw = gw = GDrawCreateTopWindow(NULL,&pos,trans_e_h,&td,&wattrs);
619
620 memset(&label,0,sizeof(label));
621 memset(&gcd,0,sizeof(gcd));
622 memset(&boxes,0,sizeof(boxes));
623
624 label[0].text = (unichar_t *) _("Origin:");
625 label[0].text_is_1byte = true;
626 label[0].text_in_resource = true;
627 gcd[0].gd.label = &label[0];
628 gcd[0].gd.pos.x = 5; gcd[0].gd.pos.y = 4;
629 gcd[0].gd.flags = (getorigin==NULL) ? gg_visible : (gg_visible | gg_enabled);
630 gcd[0].creator = GLabelCreate;
631
632 gcd[1].gd.pos.x = 5; gcd[1].gd.pos.y = 4;
633 gcd[1].gd.flags = (getorigin==NULL) ? gg_visible : (gg_visible | gg_enabled);
634 gcd[1].gd.label = &origin[1];
635 gcd[1].gd.u.list = origin;
636 gcd[1].gd.cid = CID_Origin;
637 gcd[1].creator = GListButtonCreate;
638 origin[1].selected = true;
639
640 origarray[0] = &gcd[0]; origarray[1] = &gcd[1]; origarray[2] = GCD_Glue; origarray[3] = NULL;
641
642 boxes[3].gd.flags = gg_enabled|gg_visible;
643 boxes[3].gd.u.boxelements = origarray;
644 boxes[3].creator = GHBoxCreate;
645
646 array[0] = &boxes[3]; array[1] = NULL;
647
648 gci = 2; subai = 0; ai = 2;
649 for ( i=0; i<TCnt; ++i ) {
650 array[ai++] = MakeTransBlock(&td,i,gcd+gci,label+gci,subarray+subai);
651 array[ai++] = NULL;
652 gci += 23; subai += 27;
653 }
654
655 y = TBlock_Top+TCnt*TBlock_Height+4;
656
657 gcd[gci].gd.pos.x = 10; gcd[gci].gd.pos.y = y;
658 gcd[gci].gd.flags = (flags&tdf_enableback) ? (gg_visible | gg_enabled) : gg_visible;
659 label[gci].text = (unichar_t *) _("Transform _All Layers");
660 label[gci].text_is_1byte = true;
661 label[gci].text_in_resource = true;
662 gcd[gci].gd.label = &label[gci];
663 gcd[gci].gd.cid = CID_AllLayers;
664 gcd[gci++].creator = GCheckBoxCreate;
665 array[ai++] = &gcd[gci-1]; array[ai++] = NULL;
666 y += 16;
667
668 gcd[gci].gd.pos.x = 10; gcd[gci].gd.pos.y = y;
669 gcd[gci].gd.flags = (flags&tdf_enableback) ? (gg_visible | gg_enabled) : gg_visible;
670 label[gci].text = (unichar_t *) _("Transform _Guide Layer Too");
671 label[gci].text_is_1byte = true;
672 label[gci].text_in_resource = true;
673 gcd[gci].gd.label = &label[gci];
674 gcd[gci].gd.cid = CID_DoGrid;
675 gcd[gci++].creator = GCheckBoxCreate;
676 array[ai++] = &gcd[gci-1]; array[ai++] = NULL;
677 y += 16;
678
679 gcd[gci].gd.pos.x = 10; gcd[gci].gd.pos.y = y;
680 gcd[gci].gd.flags = (flags&tdf_enableback) ? (gg_visible | gg_enabled | gg_cb_on) : gg_visible;
681 label[gci].text = (unichar_t *) _("Transform _Width Too");
682 label[gci].text_is_1byte = true;
683 label[gci].text_in_resource = true;
684 gcd[gci].gd.label = &label[gci];
685 gcd[gci].gd.cid = CID_DoWidth;
686 gcd[gci++].creator = GCheckBoxCreate;
687 array[ai++] = &gcd[gci-1]; array[ai++] = NULL;
688 y += 16;
689
690 gcd[gci].gd.pos.x = 10; gcd[gci].gd.pos.y = y;
691 gcd[gci].gd.flags = gg_visible | (flags&tdf_enablekerns ? gg_enabled : 0) |
692 (flags&tdf_defaultkerns ? gg_cb_on : 0);
693 label[gci].text = (unichar_t *) _("Transform kerning _classes too");
694 label[gci].text_is_1byte = true;
695 label[gci].text_in_resource = true;
696 gcd[gci].gd.label = &label[gci];
697 gcd[gci].gd.cid = CID_DoKerns;
698 gcd[gci++].creator = GCheckBoxCreate;
699 array[ai++] = &gcd[gci-1]; array[ai++] = NULL;
700 y += 16;
701
702 gcd[gci].gd.pos.x = 10; gcd[gci].gd.pos.y = y;
703 gcd[gci].gd.flags = gg_visible |
704 (flags&tdf_enableback ? gg_enabled : 0) |
705 (flags&tdf_enablekerns ? gg_cb_on : 0);
706 label[gci].text = (unichar_t *) _("Transform simple positioning features & _kern pairs");
707 label[gci].text_is_1byte = true;
708 label[gci].text_in_resource = true;
709 gcd[gci].gd.label = &label[gci];
710 gcd[gci].gd.cid = CID_DoSimplePos;
711 gcd[gci++].creator = GCheckBoxCreate;
712 array[ai++] = &gcd[gci-1]; array[ai++] = NULL;
713 y += 16;
714
715 gcd[gci].gd.pos.x = 10; gcd[gci].gd.pos.y = y;
716 gcd[gci].gd.flags = gg_visible | gg_enabled;
717 label[gci].text = (unichar_t *) _("Round To _Int");
718 label[gci].text_is_1byte = true;
719 label[gci].text_in_resource = true;
720 gcd[gci].gd.label = &label[gci];
721 gcd[gci].gd.cid = CID_Round2Int;
722 gcd[gci++].creator = GCheckBoxCreate;
723 array[ai++] = &gcd[gci-1]; array[ai++] = NULL;
724 y += 24;
725
726 array[ai++] = GCD_Glue; array[ai++] = NULL;
727
728 gcd[gci].gd.pos.x = 30-3; gcd[gci].gd.pos.y = y;
729 gcd[gci].gd.flags = gg_visible | gg_enabled | gg_but_default;
730 label[gci].text = (unichar_t *) _("_OK");
731 label[gci].text_is_1byte = true;
732 label[gci].text_in_resource = true;
733 gcd[gci].gd.mnemonic = 'O';
734 gcd[gci].gd.label = &label[gci];
735 gcd[gci].gd.handle_controlevent = Trans_OK;
736 gcd[gci++].creator = GButtonCreate;
737 buttons[0] = GCD_Glue; buttons[1] = &gcd[gci-1]; buttons[2] = GCD_Glue; buttons[3] = GCD_Glue;
738
739 gcd[gci].gd.flags = gg_visible | gg_enabled;
740 label[gci].text = (unichar_t *) _("_Apply");
741 label[gci].text_is_1byte = true;
742 label[gci].text_in_resource = true;
743 gcd[gci].gd.label = &label[gci];
744 gcd[gci].gd.handle_controlevent = Trans_OK;
745 gcd[gci].gd.cid = CID_Apply;
746 gcd[gci++].creator = GButtonCreate;
747 buttons[4] = GCD_Glue; buttons[5] = &gcd[gci-1]; buttons[6] = GCD_Glue; buttons[7] = GCD_Glue;
748
749 gcd[gci].gd.pos.x = -30; gcd[gci].gd.pos.y = gcd[gci-1].gd.pos.y+3;
750 gcd[gci].gd.flags = gg_visible | gg_enabled | gg_but_cancel;
751 label[gci].text = (unichar_t *) _("_Cancel");
752 label[gci].text_is_1byte = true;
753 label[gci].text_in_resource = true;
754 gcd[gci].gd.label = &label[gci];
755 gcd[gci].gd.mnemonic = 'C';
756 gcd[gci].gd.handle_controlevent = Trans_Cancel;
757 gcd[gci++].creator = GButtonCreate;
758 buttons[8] = GCD_Glue; buttons[9] = &gcd[gci-1]; buttons[10] = GCD_Glue;
759 buttons[11] = NULL;
760
761 boxes[2].gd.flags = gg_enabled|gg_visible;
762 boxes[2].gd.u.boxelements = buttons;
763 boxes[2].creator = GHBoxCreate;
764
765 array[ai++] = &boxes[2]; array[ai++] = NULL; array[ai++] = NULL;
766
767 boxes[0].gd.pos.x = boxes[0].gd.pos.y = 2;
768 boxes[0].gd.flags = gg_enabled|gg_visible;
769 boxes[0].gd.u.boxelements = array;
770 boxes[0].creator = GHVGroupCreate;
771
772 GGadgetsCreate(gw,boxes);
773 GHVBoxSetExpandableRow(boxes[0].ret,gb_expandglue);
774 GHVBoxSetExpandableCol(boxes[2].ret,gb_expandgluesame);
775 GHVBoxSetExpandableCol(boxes[3].ret,gb_expandglue);
776 for ( i=0; i<TCnt; ++i ) {
777 GHVBoxSetPadding( GWidgetGetControl(gw,CID_ClockBox+i*TBlock_CIDOffset),0,0);
778 GHVBoxSetPadding( GWidgetGetControl(gw,CID_HVBox+i*TBlock_CIDOffset),0,0);
779 GHVBoxSetExpandableCol( GWidgetGetControl(gw,CID_HBox+i*TBlock_CIDOffset),gb_expandglue);
780 }
781 GGadgetSelectOneListItem( GWidgetGetControl(gw,CID_Type), 1);
782 GWidgetToDesiredSize(gw);
783 } else
784 GDrawSetTransientFor(td.gw,(GWindow) -1);
785 gw = td.gw;
786
787 GGadgetSetEnabled( GWidgetGetControl(gw,CID_AllLayers), flags&tdf_enableback);
788 GGadgetSetEnabled( GWidgetGetControl(gw,CID_DoGrid), flags&tdf_enableback);
789 GGadgetSetEnabled( GWidgetGetControl(gw,CID_DoSimplePos), flags&tdf_enableback);
790 GGadgetSetEnabled( GWidgetGetControl(gw,CID_DoKerns), flags&tdf_enablekerns);
791 GGadgetSetVisible( GWidgetGetControl(gw,CID_Apply), flags&tdf_addapply);
792 if ( !(flags&tdf_enableback) ) {
793 GGadgetSetChecked( GWidgetGetControl(gw,CID_AllLayers), false );
794 GGadgetSetChecked( GWidgetGetControl(gw,CID_DoGrid), false );
795 }
796 GGadgetSetChecked( GWidgetGetControl(gw,CID_DoKerns),
797 !(flags&tdf_enablekerns)?false:(flags&tdf_defaultkerns)?true:false );
798 /* Yes, this is set differently from the previous, that's intended */
799 GGadgetSetChecked( GWidgetGetControl(gw,CID_DoSimplePos),
800 !(flags&tdf_enableback)?false:(flags&tdf_enablekerns)?true:false );
801 orig = GWidgetGetControl(gw,CID_Origin);
802 GGadgetSetEnabled( orig, getorigin!=NULL );
803 ti = GGadgetGetList(orig,&len);
804 for ( i=0; i<len; ++i ) {
805 ti[i]->disabled = !getorigin(data,&junk,i);
806 if ( ti[i]->disabled && ti[i]->selected ) {
807 ti[i]->selected = false;
808 ti[0]->selected = true;
809 GGadgetSetTitle(orig,ti[0]->text);
810 }
811 }
812
813 if ( cvt!=cvt_none ) {
814 int index = cvt == cvt_scale ? 4 :
815 cvt == cvt_flip ? 5 :
816 cvt == cvt_rotate ? 2 :
817 cvt == cvt_skew ? 6 :
818 /* 3d rot*/ 7 ;
819 GGadget *firstoption = GWidgetGetControl(td.gw,CID_Type);
820 GEvent dummy;
821 GGadgetSelectOneListItem( firstoption, index );
822 memset(&dummy,0,sizeof(dummy));
823 dummy.type = et_controlevent; dummy.u.control.subtype = et_listselected;
824 Trans_TypeChange( firstoption, &dummy );
825 }
826
827 for ( i=0; i<TCnt; ++i ) {
828 int index = GGadgetGetFirstListSelectedItem(GWidgetGetControl(td.gw,CID_Type+i*TBlock_CIDOffset));
829 if ( selcid[index]>0 ) {
830 GGadget *tf = GWidgetGetControl(td.gw,selcid[index]+i*TBlock_CIDOffset);
831 GWidgetIndicateFocusGadget(tf);
832 GTextFieldSelect(tf,0,-1);
833 break;
834 }
835 }
836
837 GWidgetHidePalettes();
838 GDrawSetVisible(gw,true);
839 while ( !td.done )
840 GDrawProcessOneEvent(NULL);
841 GDrawSetVisible(gw,false);
842 }
843