1 /*
2  * Author:      William Chia-Wei Cheng (bill.cheng@acm.org)
3  *
4  * Copyright (C) 2001-2009, William Chia-Wei Cheng.
5  *
6  * This file may be distributed under the terms of the Q Public License
7  * as defined by Trolltech AS of Norway and appearing in the file
8  * LICENSE.QPL included in the packaging of this file.
9  *
10  * THIS FILE IS PROVIDED AS IS WITH NO WARRANTY OF ANY KIND, INCLUDING
11  * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
12  * PURPOSE.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL,
13  * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
14  * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
15  * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
16  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  *
18  * @(#)$Header: /mm2/home/cvs/bc-src/tgif/shape.c,v 1.8 2011/05/16 16:21:59 william Exp $
19  */
20 
21 #define _INCLUDE_FROM_SHAPE_C_
22 
23 #include "tgifdefs.h"
24 #include "cmdids.h"
25 
26 #include "arc.e"
27 #include "attr.e"
28 #include "auxtext.e"
29 #include "box.e"
30 #include "cmd.e"
31 #include "color.e"
32 #include "cursor.e"
33 #include "dialog.e"
34 #include "drawing.e"
35 #include "dup.e"
36 #include "grid.e"
37 #include "group.e"
38 #include "mainloop.e"
39 #include "menu.e"
40 #include "menuinfo.e"
41 #include "move.e"
42 #include "msg.e"
43 #include "navigate.e"
44 #include "obj.e"
45 #include "oval.e"
46 #include "page.e"
47 #include "pattern.e"
48 #include "poly.e"
49 #include "polygon.e"
50 #include "raster.e"
51 #include "ruler.e"
52 #include "select.e"
53 #include "setup.e"
54 #include "shape.e"
55 #include "spline.e"
56 #include "strtbl.e"
57 #include "text.e"
58 #include "util.e"
59 
60 int numShapes=MAXSHAPES;
61 int curShape=(-1);
62 int shapeShadowInResource=FALSE;
63 int shapeShadowDx=0;
64 int shapeShadowDy=0;
65 
66 /* ----------------------- String Functions ----------------------- */
67 
68 static struct MouseStatusStrRec shapeDescMouseStatus[] = {
69    /*
70     * note: the m field is used for the localized strings
71     */
72    { N_("Create a box"),                NULL, NULL },
73    { N_("Create a parallelegram"),      NULL, NULL },
74    { N_("Create a trapezoid"),          NULL, NULL },
75    { N_("Create a rhombus"),            NULL, NULL },
76    { N_("Create a rounded-corner box"), NULL, NULL },
77    { N_("Create an octagon"),           NULL, NULL },
78    { N_("Create a cross"),              NULL, NULL },
79    { N_("Create an oval"),              NULL, NULL },
80    { N_("Create a word box"),           NULL, NULL },
81    { N_("Create a hexagon"),            NULL, NULL },
82    { N_("Create a triangle"),           NULL, NULL },
83    { N_("Create a blast box"),          NULL, NULL },
84    { N_("Create a star"),               NULL, NULL },
85    { N_("Create a disk"),               NULL, NULL },
86    { N_("Create a right arrow"),        NULL, NULL },
87    { N_("Create a up arrow"),           NULL, NULL },
88    { N_("Create a fat right arrow"),    NULL, NULL },
89    { N_("Create a fat up arrow"),       NULL, NULL },
90    { N_("Create a right tab"),          NULL, NULL },
91    { N_("Create a up tab"),             NULL, NULL },
92    { NULL, NULL, NULL }
93 };
94 
95 static
CleanUpShapeDescMouseStatusStrings()96 void CleanUpShapeDescMouseStatusStrings()
97 {
98    int index=0;
99 
100    for (index=0; index < MAXCHOICES; index++) {
101       UtilFree(shapeDescMouseStatus[index].m);
102       shapeDescMouseStatus[index].m = NULL;
103    }
104 }
105 
106 static
GetShapeDesc(index)107 char *GetShapeDesc(index)
108    int index;
109    /* returned string has been translated */
110 {
111    if (shapeDescMouseStatus[index].m == NULL) {
112       shapeDescMouseStatus[index].m =
113             UtilStrDup(_(shapeDescMouseStatus[index].l));
114       if (shapeDescMouseStatus[index].m == NULL) FailAllocMessage();
115    }
116    return shapeDescMouseStatus[index].m;
117 }
118 
119 /* ----------------------- Create Shape Functions ----------------------- */
120 
121 static IntPoint *gpVertices=NULL;
122 static int gnNumVs=0;
123 
124 static XPoint *gpRubberVertices=NULL;
125 static int gnNumSplineVs=0;
126 
127 static char *gpnSmooth=NULL;
128 
129 static int gnOrigX=0, gnOrigY=0, gnEndX=0, gnEndY=0;
130 static struct BBRec gShapeBBox;
131 
132 static
CreatePolygonShape(num_pts,has_smooth)133 int CreatePolygonShape(num_pts, has_smooth)
134    int num_pts, has_smooth;
135 {
136    gpVertices = (IntPoint*)malloc(num_pts*sizeof(IntPoint));
137    if (gpVertices == NULL) return FailAllocMessage();
138    memset(gpVertices, 0, num_pts*sizeof(IntPoint));
139    if (has_smooth) {
140       gpnSmooth = (char*)malloc(num_pts*sizeof(char));
141       if (gpnSmooth == NULL) {
142          free(gpVertices);
143          gpVertices = NULL;
144          return FailAllocMessage();
145       }
146       memset(gpnSmooth, 0, num_pts*sizeof(char));
147    }
148    gnNumVs = num_pts;
149    return TRUE;
150 }
151 
152 static
CreateOvalShape()153 int CreateOvalShape()
154 {
155    gpVertices = NULL;
156    gpnSmooth = NULL;
157    gnNumVs = gnNumSplineVs = 0;
158 
159    memset(&gShapeBBox, 0, sizeof(struct BBRec));
160    return TRUE;
161 }
162 
163 static
CreateDiskShape()164 int CreateDiskShape()
165 {
166    gpVertices = NULL;
167    gpnSmooth = NULL;
168    gnNumVs = gnNumSplineVs = 0;
169 
170    memset(&gShapeBBox, 0, sizeof(struct BBRec));
171    return TRUE;
172 }
173 
174 static
StartCreateShape(orig_x,orig_y)175 int StartCreateShape(orig_x, orig_y)
176    int orig_x, orig_y;
177 {
178    gnOrigX = gnEndX = orig_x;
179    gnOrigY = gnEndY = orig_y;
180 
181    switch (curShape) {
182    case SHAPE_BOX: return CreatePolygonShape(5, FALSE);
183    case SHAPE_PARALLEL: return CreatePolygonShape(5, FALSE);
184    case SHAPE_TRAPEZOID: return CreatePolygonShape(5, FALSE);
185    case SHAPE_RHOMBUS: return CreatePolygonShape(5, FALSE);
186    case SHAPE_RCBOX: return CreatePolygonShape(13, TRUE);
187    case SHAPE_OCTAGON: return CreatePolygonShape(9, FALSE);
188    case SHAPE_CROSS: return CreatePolygonShape(13, FALSE);
189    case SHAPE_OVAL: return CreateOvalShape();
190    case SHAPE_WORDS: return CreatePolygonShape(16, TRUE);
191    case SHAPE_HEXAGON: return CreatePolygonShape(7, FALSE);
192    case SHAPE_TRIANGLE: return CreatePolygonShape(4, FALSE);
193    case SHAPE_BLAST: return CreatePolygonShape(34, FALSE);
194    case SHAPE_STAR: return CreatePolygonShape(12, FALSE);
195    case SHAPE_DISK: return CreateDiskShape();
196    case SHAPE_RIGHTARROW: return CreatePolygonShape(8, FALSE);
197    case SHAPE_UPARROW: return CreatePolygonShape(8, FALSE);
198    case SHAPE_FATRIGHTARROW: return CreatePolygonShape(8, FALSE);
199    case SHAPE_FATUPARROW: return CreatePolygonShape(8, FALSE);
200    case SHAPE_RIGHTTAB: return CreatePolygonShape(6, FALSE);
201    case SHAPE_UPTAB: return CreatePolygonShape(6, FALSE);
202    }
203    return FALSE;
204 }
205 
206 static
EndCreateShape()207 void EndCreateShape()
208 {
209    if (gpVertices != NULL) free(gpVertices);
210    gpVertices = NULL;
211    if (gpRubberVertices != NULL) free(gpRubberVertices);
212    gpRubberVertices = NULL;
213    if (gpnSmooth != NULL) free(gpnSmooth);
214    gpnSmooth = NULL;
215    gnNumVs = gnNumSplineVs = 0;
216 }
217 
218 /* ----------------------- HighLight Calc Functions ----------------------- */
219 
220 #define SHAPE_ANGLE (((double)15.0)*M_PI/((double)180.0))
221 
222 static
TangentOfAngle()223 double TangentOfAngle()
224 {
225    static int nInitialized=FALSE;
226    static double dval=(double)0.0;
227 
228    if (nInitialized) return dval;
229    nInitialized = TRUE;
230    dval = ((double)sin(SHAPE_ANGLE)) / ((double)cos(SHAPE_ANGLE));
231    return dval;
232 }
233 
234 static
CalcRegularPolygonVs(sides,vertex_at_right,start_degree,scale,start_index,index_step)235 void CalcRegularPolygonVs(sides, vertex_at_right, start_degree, scale,
236       start_index, index_step)
237    int sides, vertex_at_right, start_degree, start_index, index_step;
238    double scale;
239    /* if (vertex_at_right), easy */
240    /* if (!vertex_at_right && start_degree == 0) self-determined */
241    /* if (!vertex_at_right && start_degree != 0) start_degree is the */
242    /*    real start angle in degrees */
243 {
244    int i, w=gnEndX-gnOrigX, h=gnEndY-gnOrigY, index=start_index;
245    int xc=((gnEndX+gnOrigX)>>1), yc=((gnEndY+gnOrigY)>>1);
246    double inc=((double)2.0)*M_PI/((double)sides), radius, rx, ry;
247    double angle=(vertex_at_right ? (double)0.0 : inc/((double)2.0));
248 
249    if (vertex_at_right) {
250       radius = (double)0.5;
251       angle = (double)0.0;
252    } else {
253       angle = inc/((double)2.0);
254       radius = (((sides%4)==0) ? (double)(cos(angle)/2.0) : (double)0.5);
255       if (start_degree != 0) {
256          angle = ((double)start_degree)*M_PI/((double)180.0);
257       }
258    }
259    rx = radius*((double)w)*scale;
260    ry = radius*((double)h)*scale;
261    for (i=0; i < sides; i++, angle += inc, index += index_step) {
262       double dw=rx*((double)cos(angle));
263       double dh=ry*((double)sin(angle));
264 
265       gpVertices[index].x = xc + round(dw);
266       gpVertices[index].y = yc + round(dh);
267    }
268    gpVertices[index].x = gpVertices[start_index].x;
269    gpVertices[index].y = gpVertices[start_index].y;
270    gnNumVs = sides+1;
271 }
272 
273 static
CalcBoxShapeVs()274 void CalcBoxShapeVs()
275 {
276    gpVertices[0].x = gnOrigX; gpVertices[0].y = gnOrigY;
277    gpVertices[1].x = gnOrigX; gpVertices[1].y = gnEndY;
278    gpVertices[2].x = gnEndX;  gpVertices[2].y = gnEndY;
279    gpVertices[3].x = gnEndX;  gpVertices[3].y = gnOrigY;
280 
281    gpVertices[4].x = gpVertices[0].x;
282    gpVertices[4].y = gpVertices[0].y;
283 }
284 
285 static
CalcParallelShapeVs()286 void CalcParallelShapeVs()
287 {
288    int h=gnEndY-gnOrigY, dx;
289    double dval;
290 
291    dval = ((double)h) * TangentOfAngle();
292    dx = (int)round(dval);
293    gpVertices[0].x = gnOrigX+dx; gpVertices[0].y = gnOrigY;
294    gpVertices[1].x = gnOrigX;    gpVertices[1].y = gnEndY;
295    gpVertices[2].x = gnEndX-dx;  gpVertices[2].y = gnEndY;
296    gpVertices[3].x = gnEndX;     gpVertices[3].y = gnOrigY;
297 
298    gpVertices[4].x = gpVertices[0].x;
299    gpVertices[4].y = gpVertices[0].y;
300 }
301 
302 static
CalcTrapezoidShapeVs()303 void CalcTrapezoidShapeVs()
304 {
305    int h=gnEndY-gnOrigY, dx;
306    double dval;
307 
308    dval = ((double)h) * TangentOfAngle();
309    dx = (int)round(dval);
310    gpVertices[0].x = gnOrigX;    gpVertices[0].y = gnOrigY;
311    gpVertices[1].x = gnOrigX+dx; gpVertices[1].y = gnEndY;
312    gpVertices[2].x = gnEndX-dx;  gpVertices[2].y = gnEndY;
313    gpVertices[3].x = gnEndX;     gpVertices[3].y = gnOrigY;
314 
315    gpVertices[4].x = gpVertices[0].x;
316    gpVertices[4].y = gpVertices[0].y;
317 }
318 
319 static
CalcRhombusShapeVs()320 void CalcRhombusShapeVs()
321 {
322    int cx=((gnOrigX+gnEndX)>>1), cy=((gnOrigY+gnEndY)>>1);
323 
324    gpVertices[0].x = cx;      gpVertices[0].y = gnOrigY;
325    gpVertices[1].x = gnOrigX; gpVertices[1].y = cy;
326    gpVertices[2].x = cx;      gpVertices[2].y = gnEndY;
327    gpVertices[3].x = gnEndX;  gpVertices[3].y = cy;
328 
329    gpVertices[4].x = gpVertices[0].x;
330    gpVertices[4].y = gpVertices[0].y;
331 }
332 
333 static
CalcRCBoxShapeVs()334 void CalcRCBoxShapeVs()
335 {
336    int w=gnEndX-gnOrigX, h=gnEndY-gnOrigY;
337 
338    if (abs(w) >= (rcbRadius<<1) && abs(h) >= (rcbRadius<<1)) {
339       int dx=(w>0 ? rcbRadius : -rcbRadius), dy=(h>0 ? rcbRadius : -rcbRadius);
340 
341       gpVertices[0].x = gnOrigX;     gpVertices[0].y = gnOrigY+dy;
342       gpVertices[1].x = gnOrigX;     gpVertices[1].y = gnEndY-dy;
343       gpVertices[2].x = gnOrigX;     gpVertices[2].y = gnEndY;
344       gpVertices[3].x = gnOrigX+dx;  gpVertices[3].y = gnEndY;
345       gpVertices[4].x = gnEndX-dx;   gpVertices[4].y = gnEndY;
346       gpVertices[5].x = gnEndX;      gpVertices[5].y = gnEndY;
347       gpVertices[6].x = gnEndX;      gpVertices[6].y = gnEndY-dy;
348       gpVertices[7].x = gnEndX;      gpVertices[7].y = gnOrigY+dy;
349       gpVertices[8].x = gnEndX;      gpVertices[8].y = gnOrigY;
350       gpVertices[9].x = gnEndX-dx;   gpVertices[9].y = gnOrigY;
351       gpVertices[10].x = gnOrigX+dx; gpVertices[10].y = gnOrigY;
352       gpVertices[11].x = gnOrigX;    gpVertices[11].y = gnOrigY;
353 
354       gpVertices[12].x = gpVertices[0].x;
355       gpVertices[12].y = gpVertices[0].y;
356       gnNumVs = 13;
357       memset(gpnSmooth, 0, gnNumVs*sizeof(char));
358       gpnSmooth[2] = gpnSmooth[5] = gpnSmooth[8] = gpnSmooth[11] = TRUE;
359    } else {
360       gpVertices[0].x = gnOrigX; gpVertices[0].y = gnOrigY;
361       gpVertices[1].x = gnOrigX; gpVertices[1].y = gnEndY;
362       gpVertices[2].x = gnEndX;  gpVertices[2].y = gnEndY;
363       gpVertices[3].x = gnEndX;  gpVertices[3].y = gnOrigY;
364 
365       gpVertices[4].x = gpVertices[0].x;
366       gpVertices[4].y = gpVertices[0].y;
367       gnNumVs = 5;
368       memset(gpnSmooth, 0, gnNumVs*sizeof(char));
369    }
370 }
371 
372 static
CalcOctagonShapeVs()373 void CalcOctagonShapeVs()
374 {
375    CalcRegularPolygonVs(8, FALSE, 0, (double)1.0, 0, 1);
376 }
377 
378 static
CalcCrossShapeVs()379 void CalcCrossShapeVs()
380 {
381    int w=gnEndX-gnOrigX, h=gnEndY-gnOrigY;
382    int dx=(int)(w/3), dy=(int)(h/3);
383 
384    gpVertices[0].x = gnOrigX;     gpVertices[0].y = gnOrigY+dy;
385    gpVertices[1].x = gnOrigX;     gpVertices[1].y = gnEndY-dy;
386    gpVertices[2].x = gnOrigX+dx;  gpVertices[2].y = gnEndY-dy;
387    gpVertices[3].x = gnOrigX+dx;  gpVertices[3].y = gnEndY;
388    gpVertices[4].x = gnEndX-dx;   gpVertices[4].y = gnEndY;
389    gpVertices[5].x = gnEndX-dx;   gpVertices[5].y = gnEndY-dy;
390    gpVertices[6].x = gnEndX;      gpVertices[6].y = gnEndY-dy;
391    gpVertices[7].x = gnEndX;      gpVertices[7].y = gnOrigY+dy;
392    gpVertices[8].x = gnEndX-dx;   gpVertices[8].y = gnOrigY+dy;
393    gpVertices[9].x = gnEndX-dx;   gpVertices[9].y = gnOrigY;
394    gpVertices[10].x = gnOrigX+dx; gpVertices[10].y = gnOrigY;
395    gpVertices[11].x = gnOrigX+dx; gpVertices[11].y = gnOrigY+dy;
396 
397    gpVertices[12].x = gpVertices[0].x;
398    gpVertices[12].y = gpVertices[0].y;
399 }
400 
401 static
CalcOvalShapeVs()402 void CalcOvalShapeVs()
403 {
404    CalcBBox(gnOrigX, gnOrigY, gnEndX, gnEndY, &(gShapeBBox.ltx),
405          &(gShapeBBox.lty), &(gShapeBBox.rbx), &(gShapeBBox.rby));
406 }
407 
408 static
CalcWordsShapeVs()409 void CalcWordsShapeVs()
410 {
411    int w=gnEndX-gnOrigX, h=gnEndY-gnOrigY;
412    int min_h=(rcbRadius<<1)+rcbRadius;
413    int min_w=min_h+(rcbRadius>>1);
414 
415    if (abs(w) >= min_w && abs(h) >= min_h) {
416       int dx=(w>0 ? rcbRadius : -rcbRadius), dy=(h>0 ? rcbRadius : -rcbRadius);
417       int dy2=(dy<<1);
418 
419       gpVertices[0].x = gnOrigX;     gpVertices[0].y = gnOrigY+dy;
420       gpVertices[1].x = gnOrigX;     gpVertices[1].y = gnEndY-dy2;
421       gpVertices[2].x = gnOrigX;     gpVertices[2].y = gnEndY-dy;
422       gpVertices[3].x = gnOrigX+dx;  gpVertices[3].y = gnEndY-dy;
423       gpVertices[4].x = gnOrigX+dx+(dx>>1);      gpVertices[4].y = gnEndY-dy;
424       gpVertices[5].x = gnOrigX+dx+(dx>>1);      gpVertices[5].y = gnEndY;
425       gpVertices[6].x = gnOrigX+(dx<<1)+(dx>>1); gpVertices[6].y = gnEndY-dy;
426       gpVertices[7].x = gnEndX-dx;   gpVertices[7].y = gnEndY-dy;
427       gpVertices[8].x = gnEndX;      gpVertices[8].y = gnEndY-dy;
428       gpVertices[9].x = gnEndX;      gpVertices[9].y = gnEndY-dy2;
429       gpVertices[10].x = gnEndX;     gpVertices[10].y = gnOrigY+dy;
430       gpVertices[11].x = gnEndX;     gpVertices[11].y = gnOrigY;
431       gpVertices[12].x = gnEndX-dx;  gpVertices[12].y = gnOrigY;
432       gpVertices[13].x = gnOrigX+dx; gpVertices[13].y = gnOrigY;
433       gpVertices[14].x = gnOrigX;    gpVertices[14].y = gnOrigY;
434 
435       gpVertices[15].x = gpVertices[0].x;
436       gpVertices[15].y = gpVertices[0].y;
437       gnNumVs = 16;
438       memset(gpnSmooth, 0, gnNumVs*sizeof(char));
439       gpnSmooth[2] = gpnSmooth[8] = gpnSmooth[11] = gpnSmooth[14] = TRUE;
440    } else {
441       gpVertices[0].x = gnOrigX; gpVertices[0].y = gnOrigY;
442       gpVertices[1].x = gnOrigX; gpVertices[1].y = gnEndY;
443       gpVertices[2].x = gnEndX; gpVertices[2].y = gnEndY;
444       gpVertices[3].x = gnEndX; gpVertices[3].y = gnOrigY;
445 
446       gpVertices[4].x = gpVertices[0].x;
447       gpVertices[4].y = gpVertices[0].y;
448       gnNumVs = 5;
449       memset(gpnSmooth, 0, gnNumVs*sizeof(char));
450    }
451 }
452 
453 static
CalcHexagonShapeVs()454 void CalcHexagonShapeVs()
455 {
456    CalcRegularPolygonVs(6, TRUE, 0, (double)1.0, 0, 1);
457 }
458 
459 static
CalcTriangleShapeVs()460 void CalcTriangleShapeVs()
461 {
462    gpVertices[0].x = ((gnOrigX+gnEndX)>>1); gpVertices[0].y = gnOrigY;
463    gpVertices[1].x = gnOrigX;               gpVertices[1].y = gnEndY;
464    gpVertices[2].x = gnEndX;                gpVertices[2].y = gnEndY;
465 
466    gpVertices[3].x = gpVertices[0].x;
467    gpVertices[3].y = gpVertices[0].y;
468 }
469 
470 static
CalcBlastShapeVs()471 void CalcBlastShapeVs()
472 {
473    CalcRegularPolygonVs(16, TRUE, 0, (double)1.0, 0, 2);
474    CalcRegularPolygonVs(16, FALSE, 0, (double)0.66, 1, 2);
475    gnNumVs = 33;
476 }
477 
478 static
CalcStarShapeVs()479 void CalcStarShapeVs()
480 {
481    int i;
482    IntPoint vs[5];
483 
484    CalcRegularPolygonVs(5, FALSE, -90, (double)1.0, 0, 2);
485    CalcRegularPolygonVs(5, FALSE, 90, (double)0.375, 1, 2);
486    for (i=0; i < 5; i++) {
487       memcpy(&vs[i], &gpVertices[((i<<1)+7) % 10], sizeof(IntPoint));
488    }
489    for (i=0; i < 5; i++) {
490       memcpy(&gpVertices[(i<<1)+1], &vs[i], sizeof(IntPoint));
491    }
492    gnNumVs = 11;
493 }
494 
495 static
CalcDiskShapeVs()496 void CalcDiskShapeVs()
497 {
498    CalcBBox(gnOrigX, gnOrigY, gnEndX, gnEndY, &(gShapeBBox.ltx),
499          &(gShapeBBox.lty), &(gShapeBBox.rbx), &(gShapeBBox.rby));
500 }
501 
502 static
CalcRightArrowShapeVs()503 void CalcRightArrowShapeVs()
504 {
505    int w=gnEndX-gnOrigX, h=gnEndY-gnOrigY;
506    int dx=(w>>1), dy=(h>>2);
507 
508    gpVertices[0].x = gnOrigX;    gpVertices[0].y = gnOrigY+dy;
509    gpVertices[1].x = gnOrigX;    gpVertices[1].y = gnEndY-dy;
510    gpVertices[2].x = gnOrigX+dx; gpVertices[2].y = gnEndY-dy;
511    gpVertices[3].x = gnOrigX+dx; gpVertices[3].y = gnEndY;
512    gpVertices[4].x = gnEndX;     gpVertices[4].y = gnOrigY+(h>>1);
513    gpVertices[5].x = gnOrigX+dx; gpVertices[5].y = gnOrigY;
514    gpVertices[6].x = gnOrigX+dx; gpVertices[6].y = gnOrigY+dy;
515 
516    gpVertices[7].x = gpVertices[0].x;
517    gpVertices[7].y = gpVertices[0].y;
518 }
519 
520 static
CalcUpArrowShapeVs()521 void CalcUpArrowShapeVs()
522 {
523    int w=gnEndX-gnOrigX, h=gnEndY-gnOrigY;
524    int dx=(w>>2), dy=(h>>1);
525 
526    gpVertices[0].x = gnOrigX;        gpVertices[0].y = gnEndY-dy;
527    gpVertices[1].x = gnOrigX+dx;     gpVertices[1].y = gnEndY-dy;
528    gpVertices[2].x = gnOrigX+dx;     gpVertices[2].y = gnEndY;
529    gpVertices[3].x = gnEndX-dx;      gpVertices[3].y = gnEndY;
530    gpVertices[4].x = gnEndX-dx;      gpVertices[4].y = gnEndY-dy;
531    gpVertices[5].x = gnEndX;         gpVertices[5].y = gnEndY-dy;
532    gpVertices[6].x = gnOrigX+(w>>1); gpVertices[6].y = gnOrigY;
533 
534    gpVertices[7].x = gpVertices[0].x;
535    gpVertices[7].y = gpVertices[0].y;
536 }
537 
538 static
CalcFatRightArrowShapeVs()539 void CalcFatRightArrowShapeVs()
540 {
541    int w=gnEndX-gnOrigX, h=gnEndY-gnOrigY;
542    int dx=(w>>1), dy=(h>>3);
543 
544    gpVertices[0].x = gnOrigX;    gpVertices[0].y = gnOrigY+dy;
545    gpVertices[1].x = gnOrigX;    gpVertices[1].y = gnEndY-dy;
546    gpVertices[2].x = gnOrigX+dx; gpVertices[2].y = gnEndY-dy;
547    gpVertices[3].x = gnOrigX+dx; gpVertices[3].y = gnEndY;
548    gpVertices[4].x = gnEndX;     gpVertices[4].y = gnOrigY+(h>>1);
549    gpVertices[5].x = gnOrigX+dx; gpVertices[5].y = gnOrigY;
550    gpVertices[6].x = gnOrigX+dx; gpVertices[6].y = gnOrigY+dy;
551 
552    gpVertices[7].x = gpVertices[0].x;
553    gpVertices[7].y = gpVertices[0].y;
554 }
555 
556 static
CalcFatUpArrowShapeVs()557 void CalcFatUpArrowShapeVs()
558 {
559    int w=gnEndX-gnOrigX, h=gnEndY-gnOrigY;
560    int dx=(w>>3), dy=(h>>1);
561 
562    gpVertices[0].x = gnOrigX;        gpVertices[0].y = gnEndY-dy;
563    gpVertices[1].x = gnOrigX+dx;     gpVertices[1].y = gnEndY-dy;
564    gpVertices[2].x = gnOrigX+dx;     gpVertices[2].y = gnEndY;
565    gpVertices[3].x = gnEndX-dx;      gpVertices[3].y = gnEndY;
566    gpVertices[4].x = gnEndX-dx;      gpVertices[4].y = gnEndY-dy;
567    gpVertices[5].x = gnEndX;         gpVertices[5].y = gnEndY-dy;
568    gpVertices[6].x = gnOrigX+(w>>1); gpVertices[6].y = gnOrigY;
569 
570    gpVertices[7].x = gpVertices[0].x;
571    gpVertices[7].y = gpVertices[0].y;
572 }
573 
574 static
CalcRightTabShapeVs()575 void CalcRightTabShapeVs()
576 {
577    int w=gnEndX-gnOrigX, h=gnEndY-gnOrigY;
578    int dx=(int)(w/3), dy=(h>>1);
579 
580    gpVertices[0].x = gnOrigX;   gpVertices[0].y = gnOrigY;
581    gpVertices[1].x = gnOrigX;   gpVertices[1].y = gnEndY;
582    gpVertices[2].x = gnEndX-dx; gpVertices[2].y = gnEndY;
583    gpVertices[3].x = gnEndX;    gpVertices[3].y = gnOrigY+dy;
584    gpVertices[4].x = gnEndX-dx; gpVertices[4].y = gnOrigY;
585 
586    gpVertices[5].x = gpVertices[0].x;
587    gpVertices[5].y = gpVertices[0].y;
588 }
589 
590 static
CalcUpTabShapeVs()591 void CalcUpTabShapeVs()
592 {
593    int w=gnEndX-gnOrigX, h=gnEndY-gnOrigY;
594    int dx=(w>>1), dy=(int)(h/3);
595 
596    gpVertices[0].x = gnOrigX;    gpVertices[0].y = gnOrigY+dy;
597    gpVertices[1].x = gnOrigX;    gpVertices[1].y = gnEndY;
598    gpVertices[2].x = gnEndX;     gpVertices[2].y = gnEndY;
599    gpVertices[3].x = gnEndX;     gpVertices[3].y = gnOrigY+dy;
600    gpVertices[4].x = gnOrigX+dx; gpVertices[4].y = gnOrigY;
601 
602    gpVertices[5].x = gpVertices[0].x;
603    gpVertices[5].y = gpVertices[0].y;
604 }
605 
606 /* ----------------------- HighLight Shape Functions ----------------------- */
607 
608 static
CalcCreateShapeVs(end_x,end_y)609 int CalcCreateShapeVs(end_x, end_y)
610    int end_x, end_y;
611 {
612    gnEndX = end_x;
613    gnEndY = end_y;
614    if (gnEndX == gnOrigX || gnEndY == gnOrigY) return FALSE;
615 
616    switch (curShape) {
617    case SHAPE_BOX: CalcBoxShapeVs(); break;
618    case SHAPE_PARALLEL: CalcParallelShapeVs(); break;
619    case SHAPE_TRAPEZOID: CalcTrapezoidShapeVs(); break;
620    case SHAPE_RHOMBUS: CalcRhombusShapeVs(); break;
621    case SHAPE_RCBOX: CalcRCBoxShapeVs(); break;
622    case SHAPE_OCTAGON: CalcOctagonShapeVs(); break;
623    case SHAPE_CROSS: CalcCrossShapeVs(); break;
624    case SHAPE_OVAL: CalcOvalShapeVs(); break;
625    case SHAPE_WORDS: CalcWordsShapeVs(); break;
626    case SHAPE_HEXAGON: CalcHexagonShapeVs(); break;
627    case SHAPE_TRIANGLE: CalcTriangleShapeVs(); break;
628    case SHAPE_BLAST: CalcBlastShapeVs(); break;
629    case SHAPE_STAR: CalcStarShapeVs(); break;
630    case SHAPE_DISK: CalcDiskShapeVs(); break;
631    case SHAPE_RIGHTARROW: CalcRightArrowShapeVs(); break;
632    case SHAPE_UPARROW: CalcUpArrowShapeVs(); break;
633    case SHAPE_FATRIGHTARROW: CalcFatRightArrowShapeVs(); break;
634    case SHAPE_FATUPARROW: CalcFatUpArrowShapeVs(); break;
635    case SHAPE_RIGHTTAB: CalcRightTabShapeVs(); break;
636    case SHAPE_UPTAB: CalcUpTabShapeVs(); break;
637    }
638    return TRUE;
639 }
640 
641 #define NO_GENERATE 0
642 #define GENERATE 1
643 
644 static
HighLightCreateShape(end_x,end_y,generate,pn_need_to_draw)645 void HighLightCreateShape(end_x, end_y, generate, pn_need_to_draw)
646    int end_x, end_y, generate, *pn_need_to_draw;
647 {
648    if (generate) {
649       *pn_need_to_draw = CalcCreateShapeVs(end_x, end_y);
650 
651       if (*pn_need_to_draw && gpVertices != NULL) {
652          int saved_draw_orig_x=drawOrigX, saved_draw_orig_y=drawOrigY;
653          int saved_zoomed_in=zoomedIn, saved_zoom_scale=zoomScale;
654 
655          if (gpRubberVertices != NULL) free(gpRubberVertices);
656          gnNumSplineVs = 0;
657          drawOrigX = drawOrigY = 0;
658          zoomedIn = FALSE;
659          zoomScale = 0;
660 
661          if (gpnSmooth == NULL) {
662             gpRubberVertices = MakePolygonVertex(drawOrigX, drawOrigY,
663                   gnNumVs, gpVertices);
664             gnNumSplineVs = gnNumVs;
665          } else {
666             gpRubberVertices = MakeMultiSplinePolygonVertex(LT_SPLINE,
667                   &gnNumSplineVs, gpnSmooth, drawOrigX, drawOrigY, gnNumVs,
668                   gpVertices);
669          }
670          if (gpRubberVertices == NULL) FailAllocMessage();
671          drawOrigX = saved_draw_orig_x;
672          drawOrigY = saved_draw_orig_y;
673          zoomedIn = saved_zoomed_in;
674          zoomScale = saved_zoom_scale;
675       }
676    }
677    if (*pn_need_to_draw) {
678       int w, h, diam_y, radius_y, side_h;
679 
680       switch (curShape) {
681       case SHAPE_OVAL:
682          XDrawArc(mainDisplay, drawWindow, revDefaultGC,
683                gShapeBBox.ltx, gShapeBBox.lty,
684                gShapeBBox.rbx-gShapeBBox.ltx, gShapeBBox.rby-gShapeBBox.lty,
685                0, 360<<6);
686          break;
687       case SHAPE_DISK:
688          w = gShapeBBox.rbx-gShapeBBox.ltx;
689          h = gShapeBBox.rby-gShapeBBox.lty;
690          radius_y = (int)(h/6);
691          diam_y = (radius_y<<1);
692          side_h = h-diam_y;
693          XDrawArc(mainDisplay, drawWindow, revDefaultGC,
694                gShapeBBox.ltx, gShapeBBox.lty, w, diam_y, 0, 360<<6);
695          XDrawArc(mainDisplay, drawWindow, revDefaultGC,
696                gShapeBBox.ltx, gShapeBBox.rby-diam_y, w, diam_y,
697                180<<6, 180<<6);
698          XDrawLine(mainDisplay, drawWindow, revDefaultGC,
699                gShapeBBox.ltx, gShapeBBox.lty+radius_y,
700                gShapeBBox.ltx, gShapeBBox.rby-radius_y);
701          XDrawLine(mainDisplay, drawWindow, revDefaultGC,
702                gShapeBBox.rbx, gShapeBBox.lty+radius_y,
703                gShapeBBox.rbx, gShapeBBox.rby-radius_y);
704          break;
705       default:
706          if (gpVertices != NULL) {
707             XDrawLines(mainDisplay, drawWindow, revDefaultGC,
708                   gpRubberVertices, gnNumSplineVs, CoordModeOrigin);
709          }
710          break;
711       }
712    }
713 }
714 
715 /* ----------------------- Generate Object Functions ----------------------- */
716 
717 static
GenerateInvisibleBox()718 struct AttrRec *GenerateInvisibleBox()
719 {
720    int w, h, saved_text_just=textJust, attr_w, attr_h, attr_ltx, attr_lty;
721    int saved_fill=objFill, saved_trans_pat=transPat;
722    struct BBRec bbox;
723    struct BoxRec *box_ptr;
724    struct AttrRec *attr_ptr, *label_attr=NULL;
725 
726    textJust = JUST_C;
727    memcpy(&bbox, &gShapeBBox, sizeof(struct BBRec));
728    w = bbox.rbx-bbox.ltx;
729    h = bbox.rby-bbox.lty;
730 
731    switch (curShape) {
732    case SHAPE_WORDS:
733       if (gnEndY >= gnOrigY) {
734          bbox.rby -= rcbRadius;
735       } else {
736          bbox.lty += rcbRadius;
737       }
738       break;
739    case SHAPE_TRIANGLE:
740       if (gnEndY >= gnOrigY) {
741          bbox.lty += (int)(h/3);
742       } else {
743          bbox.rby -= (int)(h/3);
744       }
745       break;
746    case SHAPE_DISK:
747       bbox.lty += (int)(h/3);
748       break;
749    case SHAPE_RIGHTARROW:
750    case SHAPE_FATRIGHTARROW:
751    case SHAPE_RIGHTTAB:
752       if (gnEndX >= gnOrigX) {
753          bbox.rbx -= (w>>2);
754       } else {
755          bbox.ltx += (w>>2);
756       }
757       break;
758    case SHAPE_UPARROW:
759    case SHAPE_FATUPARROW:
760    case SHAPE_UPTAB:
761       if (gnEndY >= gnOrigY) {
762          bbox.lty += (h>>2);
763       } else {
764          bbox.rby -= (h>>2);
765       }
766       break;
767    }
768    if (bbox.rbx-bbox.ltx >= 12) {
769       bbox.ltx += 4;
770       bbox.rbx -= 4;
771    }
772    if (bbox.rby-bbox.lty >= 12) {
773       bbox.lty += 4;
774       bbox.rby -= 4;
775    }
776    CreateBoxObj(bbox.ltx, bbox.lty, bbox.rbx, bbox.rby, FALSE);
777    box_ptr = topObj->detail.b;
778    box_ptr->fill = NONEPAT;
779    box_ptr->pen = NONEPAT;
780    objFill = NONEPAT;
781    transPat = FALSE;
782    AddAttrByNameAndValue(topObj, "", "auto_center_attr");
783    attr_ptr = topObj->fattr;
784    if (attr_ptr != NULL) {
785       attr_ptr->shown = FALSE;
786       UpdAttr(attr_ptr);
787       AdjObjBBox(attr_ptr->obj);
788       attr_w = attr_ptr->obj->obbox.rbx-attr_ptr->obj->obbox.ltx;
789       attr_h = attr_ptr->obj->bbox.rby-attr_ptr->obj->bbox.lty;
790       attr_ltx = ((topObj->obbox.ltx+topObj->obbox.rbx)>>1)-(attr_w>>1);
791       attr_lty = topObj->bbox.lty;
792       MoveObj(attr_ptr->obj, attr_ltx-attr_ptr->obj->obbox.ltx,
793             attr_lty-attr_ptr->obj->obbox.lty);
794    }
795    AddAttrByNameAndValue(topObj, "label=", "");
796    transPat = saved_trans_pat;
797    objFill = saved_fill;
798    label_attr = FindAttrWithName(topObj, "label=", NULL);
799    if (label_attr != NULL) {
800       label_attr->nameshown = FALSE;
801       label_attr->shown = TRUE;
802       UpdAttr(label_attr);
803       AdjObjBBox(label_attr->obj);
804       attr_w = label_attr->obj->obbox.rbx-label_attr->obj->obbox.ltx;
805       attr_h = label_attr->obj->bbox.rby-label_attr->obj->bbox.lty;
806       attr_ltx = ((topObj->obbox.ltx+topObj->obbox.rbx)>>1)-(attr_w>>1);
807       attr_lty = ((topObj->obbox.lty+topObj->obbox.rby)>>1)-(attr_h>>1);
808       MoveObj(label_attr->obj, attr_ltx-label_attr->obj->obbox.ltx,
809             attr_lty-label_attr->obj->obbox.lty);
810    }
811    AdjObjBBox(topObj);
812    textJust = saved_text_just;
813    return label_attr;
814 }
815 
816 static
GenerateShadow()817 void GenerateShadow()
818 {
819    struct ObjRec *obj_ptr;
820    struct SelRec *tmp_top_sel=NULL, *tmp_bot_sel=NULL;
821 
822    SelAllObj(FALSE, FALSE);
823 
824    JustDupSelObj(&tmp_top_sel, &tmp_bot_sel);
825    /*
826     * At this point, the objects pointed by tmp_top_sel and
827     *      tmp_bot_sel are dangling.
828     */
829    if (tmp_top_sel != tmp_bot_sel) {
830       CreateGroupObj(tmp_top_sel->obj, tmp_bot_sel->obj);
831    } else {
832       obj_ptr = tmp_top_sel->obj;
833       obj_ptr->next = topObj;
834       obj_ptr->prev = NULL;
835       if (topObj == NULL) {
836          botObj = obj_ptr;
837       } else {
838          topObj->prev = obj_ptr;
839       }
840       topObj = obj_ptr;
841    }
842    RemoveAllSel();
843    UpdSelBBox();
844 
845    /* move the new object to the bottom */
846    obj_ptr = topObj;
847    UnlinkObj(topObj);
848    obj_ptr->next = NULL;
849    obj_ptr->prev = botObj;
850    if (botObj == NULL) {
851       topObj = obj_ptr;
852    } else {
853       botObj->next = obj_ptr;
854    }
855    botObj = obj_ptr;
856 
857    ChangeObjTransPat(obj_ptr, NO_TRANSPAT_MODE);
858    ChangeObjFill(obj_ptr, SOLIDPAT);
859    ChangeObjPen(obj_ptr, SOLIDPAT);
860    MoveObj(obj_ptr, shapeShadowDx, shapeShadowDy);
861 }
862 
863 static
GenerateShape()864 struct AttrRec *GenerateShape()
865 {
866    struct ObjRec *saved_top_obj, *saved_bot_obj, *tmp_top_obj, *tmp_bot_obj;
867    int w, h, diam_y, radius_y, side_h, saved_cur_spline, saved_line_style;
868    struct AttrRec *label_attr=NULL;
869    struct BBRec bbox;
870 
871    saved_top_obj = topObj;
872    saved_bot_obj = botObj;
873    curPage->top = curPage->bot = topObj = botObj = NULL;
874 
875    switch (curShape) {
876    case SHAPE_OVAL:
877       CreateOvalObj(&gShapeBBox, FALSE);
878       break;
879    case SHAPE_DISK:
880       saved_cur_spline = curSpline;
881       saved_line_style = lineStyle;
882 
883       curSpline = LT_STRAIGHT;
884       lineStyle = LS_PLAIN;
885       w = gShapeBBox.rbx-gShapeBBox.ltx;
886       h = gShapeBBox.rby-gShapeBBox.lty;
887       radius_y = (int)(h/6);
888       diam_y = (radius_y<<1);
889       side_h = h-diam_y;
890       if (penPat != NONEPAT) {
891          int saved_pen=penPat;
892 
893          penPat = NONEPAT;
894          CreateBoxObj(gShapeBBox.ltx, gShapeBBox.lty+radius_y,
895                gShapeBBox.rbx, gShapeBBox.rby-radius_y, FALSE);
896          penPat = saved_pen;
897       }
898       bbox.ltx = gShapeBBox.ltx;
899       bbox.lty = gShapeBBox.lty;
900       bbox.rbx = bbox.ltx+w;
901       bbox.rby = bbox.lty+diam_y;
902       CreateOvalObj(&bbox, FALSE);
903       CreateArcObj(gShapeBBox.ltx+(w>>1), gShapeBBox.rby-radius_y,
904             gShapeBBox.ltx, gShapeBBox.rby-radius_y,
905             gShapeBBox.ltx+w, gShapeBBox.rby-radius_y, ARC_CCW,
906             gShapeBBox.ltx, gShapeBBox.rby-diam_y, w, diam_y, 180<<6, 180<<6,
907             FALSE);
908       ResetCreatePoly();
909       AddPtToCreatePoly(gShapeBBox.ltx, gShapeBBox.lty+radius_y);
910       AddPtToCreatePoly(gShapeBBox.ltx, gShapeBBox.rby-radius_y);
911       CreatePolyObj(2, FALSE);
912       ResetCreatePoly();
913       AddPtToCreatePoly(gShapeBBox.rbx, gShapeBBox.lty+radius_y);
914       AddPtToCreatePoly(gShapeBBox.rbx, gShapeBBox.rby-radius_y);
915       CreatePolyObj(2, FALSE);
916 
917       curSpline = saved_cur_spline;
918       lineStyle = saved_line_style;
919       break;
920    default:
921       CalcBBox(gnOrigX, gnOrigY, gnEndX, gnEndY, &(gShapeBBox.ltx),
922             &(gShapeBBox.lty), &(gShapeBBox.rbx), &(gShapeBBox.rby));
923       if (gpVertices != NULL) {
924          int i;
925 
926          saved_cur_spline = curSpline;
927          curSpline = LT_STRAIGHT;
928          ResetCreatePolygon();
929          for (i=0; i < gnNumVs; i++) {
930             AddPtToCreatePolygon(gpVertices[i].x, gpVertices[i].y);
931          }
932          CreatePolygonObj(gnNumVs, FALSE);
933          if (gpnSmooth != NULL) {
934             struct PolygonRec *polygon_ptr=topObj->detail.g;
935 
936             if (polygon_ptr->smooth == NULL) {
937                polygon_ptr->smooth = (char*)malloc((gnNumVs+1)*sizeof(char));
938                if (polygon_ptr->smooth == NULL) FailAllocMessage();
939                memset(polygon_ptr->smooth, 0, (gnNumVs+1)*sizeof(char));
940             }
941             for (i=0; i < gnNumVs; i++) {
942                polygon_ptr->smooth[i] = gpnSmooth[i];
943             }
944             AdjObjSplineVs(topObj);
945             UpdPolyBBox(topObj, polygon_ptr->n, polygon_ptr->vlist);
946             AdjObjBBox(topObj);
947          }
948          curSpline = saved_cur_spline;
949       }
950       break;
951    }
952    if (shapeShadowDx != 0 || shapeShadowDy != 0) {
953       GenerateShadow();
954    }
955    label_attr = GenerateInvisibleBox();
956 
957    /*
958     * Use the next two functions to set selLtX, etc. to be used
959     *    in CreateGroupObj().
960     */
961    SelAllObj(FALSE, FALSE);
962    RemoveAllSel();
963 
964    tmp_top_obj = topObj;
965    tmp_bot_obj = botObj;
966    curPage->top = topObj = saved_top_obj;
967    curPage->bot = botObj = saved_bot_obj;
968    CreateGroupObj(tmp_top_obj, tmp_bot_obj);
969    return label_attr;
970 }
971 
972 /* ----------------------- Event Loop ----------------------- */
973 
974 #define START_SHOW 0
975 #define MOTION_SHOW 1
976 #define END_SHOW 2
977 
978 static
DoCursor(x,y,w,h,which)979 void DoCursor(x, y, w, h, which)
980    int x, y, w, h, which;
981 {
982    char w_buf[80], h_buf[80], x_buf[80], y_buf[80];
983 
984    PixelToMeasurementUnit(w_buf, ABS_SIZE(abs(w)));
985    PixelToMeasurementUnit(h_buf, ABS_SIZE(abs(h)));
986    PixelToMeasurementUnit(x_buf, ABS_X(x));
987    PixelToMeasurementUnit(y_buf, ABS_Y(y));
988    sprintf(gszMsgBox, "w=%s\nh=%s\nx=%s\ny=%s", w_buf, h_buf, x_buf, y_buf);
989    switch (which) {
990    case START_SHOW: StartShowMeasureCursor(x, y, gszMsgBox, TRUE); break;
991    case MOTION_SHOW: ShowMeasureCursor(x, y, gszMsgBox, TRUE); break;
992    case END_SHOW: EndShowMeasureCursor(x, y, gszMsgBox, TRUE); break;
993    }
994 }
995 
996 static
ContinueCreateShape(orig_x,orig_y)997 void ContinueCreateShape(orig_x, orig_y)
998    int orig_x, orig_y;
999 {
1000    int done=FALSE, something_created=FALSE, grid_x=orig_x, grid_y=orig_y;
1001    int need_to_draw=FALSE;
1002    struct AttrRec *label_attr=NULL;
1003 
1004    BeginIntervalRulers(orig_x, orig_y, orig_x, orig_y);
1005    DoCursor(orig_x, orig_y, 0, 0, START_SHOW);
1006 
1007    if (!debugNoPointerGrab) {
1008       XGrabPointer(mainDisplay, drawWindow, False,
1009             PointerMotionMask | ButtonReleaseMask | ButtonReleaseMask,
1010             GrabModeAsync, GrabModeAsync, None, handCursor, CurrentTime);
1011    }
1012    if (!StartCreateShape(orig_x, orig_y)) {
1013       Msg(TgLoadString(STID_CREATE_A_SHAPE_FAILED));
1014       return;
1015    }
1016    HighLightCreateShape(grid_x, grid_y, GENERATE, &need_to_draw);
1017    while (!done) {
1018       XEvent input, ev;
1019 
1020       XNextEvent(mainDisplay, &input);
1021       switch (input.type) {
1022       case Expose: ExposeEventHandler(&input, TRUE); break;
1023       case VisibilityNotify: ExposeEventHandler(&input, TRUE); break;
1024       case MotionNotify:
1025          HighLightCreateShape(grid_x, grid_y, NO_GENERATE, &need_to_draw);
1026          DoCursor(grid_x, grid_y, grid_x-orig_x, grid_y-orig_y, MOTION_SHOW);
1027          GridXY(input.xmotion.x, input.xmotion.y, &grid_x, &grid_y);
1028          if (input.xmotion.state & (ShiftMask | ControlMask)) {
1029             int w=grid_x-orig_x, h=grid_y-orig_y, pos_w=TRUE, pos_h=TRUE;
1030 
1031             if (w < 0) {
1032                w = (-w);
1033                pos_w = FALSE;
1034             }
1035             if (h < 0) {
1036                h = (-h);
1037                pos_h = FALSE;
1038             }
1039             if (w > h) {
1040                grid_x = (pos_w ? orig_x+h : orig_x-h);
1041             } else {
1042                grid_y = (pos_h ? orig_y+w : orig_y-w);
1043             }
1044          }
1045          DoCursor(grid_x, grid_y, grid_x-orig_x, grid_y-orig_y, MOTION_SHOW);
1046          HighLightCreateShape(grid_x, grid_y, GENERATE, &need_to_draw);
1047          DrawIntervalRulers(orig_x, orig_y, grid_x, grid_y, NULL);
1048          while (XCheckMaskEvent(mainDisplay, PointerMotionMask, &ev)) ;
1049          break;
1050       case KeyPress:
1051          if (KeyPressEventIsEscape(&input.xkey)) {
1052             done = TRUE;
1053          }
1054          break;
1055       case ButtonRelease:
1056          if (grid_x != orig_x && grid_y != orig_y) {
1057             something_created = TRUE;
1058          }
1059          done = TRUE;
1060          break;
1061       }
1062    }
1063    XUngrabPointer(mainDisplay, CurrentTime);
1064    XSync(mainDisplay, False);
1065    done = TRUE;
1066    DoCursor(grid_x, grid_y, grid_x-orig_x, grid_y-orig_y, END_SHOW);
1067    HighLightCreateShape(grid_x, grid_y, NO_GENERATE, &need_to_draw);
1068    EndIntervalRulers(grid_x, grid_y);
1069 
1070    if (something_created) {
1071       label_attr = GenerateShape();
1072       numRedrawBBox = 0;
1073       topObj->tmp_parent = NULL;
1074       DrawObj(drawWindow, topObj);
1075       RecordNewObjCmd();
1076       SetFileModified(TRUE);
1077       justDupped = FALSE;
1078    }
1079    EndCreateShape();
1080    if (something_created && label_attr != NULL) {
1081       EditTextInAttr(label_attr);
1082    }
1083 }
1084 
1085 static
DoCreateShape()1086 void DoCreateShape()
1087 {
1088    unsigned int button;
1089    int mouse_x=0, mouse_y=0;
1090 
1091    Msg(TgLoadCachedString(CSTID_DRAG_MOUSE_CREATE_SHAPE_DOTS));
1092    SetMouseStatus(GetShapeDesc(curShape), TgLoadCachedString(CSTID_CANCEL),
1093          TgLoadCachedString(CSTID_CANCEL));
1094    button = DrawWindowLoop(&mouse_x, &mouse_y, cornerCursor, TRUE);
1095    if (button == Button1) {
1096       int grid_x=0, grid_y=0;
1097 
1098       GridXY(mouse_x, mouse_y, &grid_x, &grid_y);
1099       ContinueCreateShape(grid_x, grid_y);
1100    } else {
1101       Msg(TgLoadCachedString(CSTID_CREATE_A_SHAPE_ABORTED));
1102    }
1103 }
1104 
1105 static
CreateShape()1106 void CreateShape()
1107 {
1108    int force_no_shadow=FALSE, saved_dx=shapeShadowDx, saved_dy=shapeShadowDy;
1109 
1110    MakeQuiescent();
1111 
1112    if ((objFill == NONEPAT || (objFill == BACKPAT && transPat)) &&
1113          (shapeShadowDx != 0 || shapeShadowDy != 0)) {
1114       sprintf(gszMsgBox, TgLoadString(objFill==NONEPAT ?
1115             STID_CREATE_SHADOW_SHAPE_NO_FILL :
1116             STID_CREATE_SHADOW_SHAPE_TRAN_FILL));
1117       switch (MsgBox(gszMsgBox, TOOL_NAME, YNC_MB)) {
1118       case MB_ID_YES: force_no_shadow = TRUE; break;
1119       case MB_ID_NO: break;
1120       default: return;
1121       }
1122    }
1123    if (force_no_shadow) {
1124       shapeShadowDx = shapeShadowDy = 0;
1125    }
1126    SaveStatusStrings();
1127    DoCreateShape();
1128    RestoreStatusStrings();
1129    if (force_no_shadow) {
1130       shapeShadowDx = saved_dx;
1131       shapeShadowDy = saved_dy;
1132    }
1133 }
1134 
1135 /* ----------------------- Init and Clean Up ----------------------- */
1136 
CleanUpShape()1137 void CleanUpShape()
1138 {
1139    CleanUpShapeDescMouseStatusStrings();
1140 }
1141 
InitShape()1142 void InitShape()
1143 {
1144    char *c_ptr;
1145 
1146    shapeShadowInResource = FALSE;
1147    shapeShadowDx = shapeShadowDy = 0;
1148    if ((c_ptr=XGetDefault(mainDisplay,TOOL_NAME,"ShapeShadowSpec")) != NULL) {
1149       if (ParseXYSpec(c_ptr, &shapeShadowDx, &shapeShadowDy)) {
1150          shapeShadowInResource = TRUE;
1151       }
1152    }
1153 }
1154 
1155 /* ----------------------- Menu Functions ----------------------- */
1156 
ShapeSubMenu(nIndex)1157 void ShapeSubMenu(nIndex)
1158    int nIndex;
1159 {
1160    if (nIndex < 0 || nIndex >= MAXSHAPES) return;
1161    curShape = nIndex;
1162    CreateShape();
1163    curShape = (-1);
1164 }
1165 
RefreshShapeMenu(menu)1166 void RefreshShapeMenu(menu)
1167    TgMenu *menu;
1168 {
1169 }
1170 
CreateShapeMenu(parent_menu,x,y,menu_info,status_str_xlated)1171 TgMenu *CreateShapeMenu(parent_menu, x, y, menu_info, status_str_xlated)
1172    TgMenu *parent_menu;
1173    int x, y;
1174    TgMenuInfo *menu_info;
1175    int status_str_xlated; /* ignored, always 0 */
1176 {
1177    int i=0;
1178    TgMenu *menu=NULL;
1179    TgMenuInfo stMenuInfo;
1180    TgMenuItemInfo *item_info=NULL;
1181 
1182    memcpy(&stMenuInfo, menu_info, sizeof(TgMenuInfo));
1183    stMenuInfo.items = (TgMenuItemInfo*)malloc(
1184          (MAXSHAPES+1)*sizeof(TgMenuItemInfo));
1185    if (stMenuInfo.items == NULL) FailAllocMessage();
1186    memset(stMenuInfo.items, 0, (MAXSHAPES+1)*sizeof(TgMenuItemInfo));
1187    for (item_info=stMenuInfo.items, i=0; i < MAXSHAPES; item_info++, i++) {
1188       item_info->menu_str = (char*)(Pixmap*)(&shapePixmap[i]);
1189       item_info->shortcut_str = NULL;
1190       sprintf(gszMsgBox, "%s", GetShapeDesc(i));
1191       item_info->status_str = UtilStrDup(gszMsgBox);
1192       if (item_info->status_str == NULL) FailAllocMessage();
1193       item_info->submenu_info = NULL;
1194       item_info->cmdid = CMDID_CREATESHAPE;
1195    }
1196    stMenuInfo.items[MAXSHAPES].cmdid = INVALID;
1197 
1198    /* the status_str has been translated in GetShapeDesc() */
1199    menu = TgCreateMenuFromMenuInfo(parent_menu, x, y, &stMenuInfo, TRUE);
1200    for (item_info=stMenuInfo.items, i=0; i < MAXSHAPES; item_info++, i++) {
1201       UtilFree(item_info->status_str);
1202    }
1203    memset(stMenuInfo.items, 0, (MAXSHAPES+1)*sizeof(TgMenuItemInfo));
1204    free(stMenuInfo.items);
1205    stMenuInfo.items = NULL;
1206    if (menu != NULL) {
1207       menu->track_menubar = TRUE;
1208       TgAdjustMenuGeometry(menu, choiceImageW, choiceImageH, 8);
1209    }
1210    return menu;
1211 }
1212 
ShapeMenu(X,Y,TrackMenubar)1213 int ShapeMenu(X, Y, TrackMenubar)
1214    int X, Y, TrackMenubar;
1215 {
1216    int rc=INVALID;
1217    TgMenu *menu=(shapeMenuInfo. create_proc)(NULL, X, Y, &shapeMenuInfo,
1218          INVALID);
1219 
1220    activeMenu = MENU_SHAPE;
1221    if (menu != NULL) {
1222       menu->track_menubar = TrackMenubar;
1223 
1224       rc = TgMenuLoop(menu);
1225       TgDestroyMenu(menu, TRUE);
1226    }
1227    return rc;
1228 }
1229 
1230 /* ----------------------- Public Functions ----------------------- */
1231 
SetShapeShadow()1232 void SetShapeShadow()
1233 {
1234    char spec[MAXSTRING+1];
1235 
1236    *spec = '\0';
1237    sprintf(gszMsgBox, TgLoadString(STID_ENTER_XY_OFFSET_FOR_SHP_SHDW),
1238          shapeShadowDx, shapeShadowDy);
1239    Dialog(gszMsgBox, NULL, spec);
1240    if (ParseXYSpec(spec, &shapeShadowDx, &shapeShadowDy)) {
1241       sprintf(gszMsgBox, TgLoadString(STID_SHAPE_SHDW_XY_OFFSETS_SET_TO),
1242             shapeShadowDx, shapeShadowDy);
1243       Msg(gszMsgBox);
1244    }
1245 }
1246 
1247