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/edit.c,v 1.108 2011/06/18 04:44:51 william Exp $
19 */
20
21 #define _INCLUDE_FROM_EDIT_C_
22
23 #include "tgifdefs.h"
24 #include "cmdids.h"
25
26 #include "align.e"
27 #include "arc.e"
28 #include "attr.e"
29 #include "auxtext.e"
30 #include "button.e"
31 #include "choice.e"
32 #include "cmd.e"
33 #include "color.e"
34 #include "cutpaste.e"
35 #include "cursor.e"
36 #include "dialog.e"
37 #include "drawing.e"
38 #include "dup.e"
39 #include "edit.e"
40 #include "eps.e"
41 #include "exec.e"
42 #include "file.e"
43 #include "font.e"
44 #include "grid.e"
45 #include "group.e"
46 #include "mainloop.e"
47 #include "mainmenu.e"
48 #include "mark.e"
49 #include "menu.e"
50 #include "menuinfo.e"
51 #include "miniline.e"
52 #include "move.e"
53 #include "msg.e"
54 #include "names.e"
55 #include "navigate.e"
56 #include "obj.e"
57 #include "page.e"
58 #include "pattern.e"
59 #include "pin.e"
60 #include "poly.e"
61 #include "polygon.e"
62 #include "raster.e"
63 #include "rect.e"
64 #include "ruler.e"
65 #include "select.e"
66 #include "setup.e"
67 #include "shape.e"
68 #include "special.e"
69 #include "spline.e"
70 #include "stretch.e"
71 #include "strtbl.e"
72 #include "text.e"
73 #include "util.e"
74 #include "xbitmap.e"
75 #include "xpixmap.e"
76
77 struct SelRec *outerSelForFind=NULL;
78 struct SelRec *innerSelForFind=NULL;
79
80 int ignoreObjectShadowInfoInFile=TRUE;
81 int objShadowXOffset=2, objShadowYOffset=2;
82 char objShadowColorStr[MAXSTRING];
83
84 int pngExportHasTransparentColor=FALSE;
85
86 static struct ObjRec *tmpTopObj=NULL, *tmpBotObj=NULL;
87 static struct SelRec *tmpTopSel=NULL, *tmpBotSel=NULL;
88
89 static char *gpszSearch=NULL;
90 static int gnSearchLen=0;
91 static int gnSearchCaseSensitive=TRUE;
92
93 static int gnFoundStartCharIndex=0, gnFoundEndCharIndex=0;
94 static StrBlockInfo *gpFoundStartStrBlock=NULL, *gpFoundEndStrBlock=NULL;
95
96 static int convertToBezierNumSegs=50;
97
CleanOuterInnerSelForFind()98 void CleanOuterInnerSelForFind()
99 {
100 struct SelRec *sel_ptr=NULL, *next_sel=NULL;
101
102 if (outerSelForFind != NULL) {
103 for (sel_ptr=outerSelForFind; sel_ptr != NULL; sel_ptr=next_sel) {
104 next_sel = sel_ptr->next;
105 free(sel_ptr);
106 }
107 outerSelForFind = innerSelForFind = NULL;
108 }
109 }
110
111 static
CopyOuterSelToOuterSelForFind()112 void CopyOuterSelToOuterSelForFind()
113 {
114 struct SelRec *sel_ptr=NULL;
115
116 CleanOuterInnerSelForFind();
117 for (sel_ptr=outerSel; sel_ptr != NULL; sel_ptr=sel_ptr->next) {
118 AddObjIntoSel(sel_ptr->obj, NULL, outerSelForFind, &outerSelForFind,
119 &innerSelForFind);
120 }
121 }
122
CleanUpEdit()123 void CleanUpEdit()
124 {
125 CleanOuterInnerSelForFind();
126 if (gpszSearch != NULL) free(gpszSearch);
127 gpszSearch = NULL;
128 }
129
InitEdit()130 void InitEdit()
131 {
132 char *c_ptr=NULL, spec[MAXSTRING];
133
134 if (PRTGIF && !cmdLineOpenDisplay) return;
135
136 convertToBezierNumSegs = 50;
137 if ((c_ptr=XGetDefault(mainDisplay,TOOL_NAME,
138 "ConvertToBezierSegments")) != NULL) {
139 SetBezierConvertNumSegsValue(c_ptr);
140 }
141 objShadowXOffset = objShadowYOffset = 2;
142 if ((c_ptr=XGetDefault(mainDisplay,TOOL_NAME, "ObjectShadowOffsets")) !=
143 NULL) {
144 UtilStrCpyN(spec, sizeof(spec), c_ptr);
145 UtilTrimBlanks(spec);
146 if (!ParseXYSpec(spec, &objShadowXOffset, &objShadowYOffset)) {
147 fprintf(stderr, TgLoadString(STID_INVALID_XDEF_USE_ALT_STR),
148 TOOL_NAME, "ObjectShadowOffsets", spec, "2,2");
149 fprintf(stderr, "\n");
150 }
151 }
152 strcpy(objShadowColorStr, "#c0c0c0");
153 if ((c_ptr=XGetDefault(mainDisplay,TOOL_NAME,"ObjectShadowColor")) != NULL) {
154 int new_alloc=0;
155
156 UtilStrCpyN(spec, sizeof(spec), c_ptr);
157 UtilTrimBlanks(spec);
158
159 if (QuickFindColorIndex(NULL, spec, &new_alloc, FALSE) == INVALID) {
160 fprintf(stderr, TgLoadString(STID_INVALID_XDEF_COLORXPM_GET),
161 TOOL_NAME, "ObjectShadowColor", spec);
162 fprintf(stderr, "\n");
163 return;
164 }
165 UtilStrCpyN(objShadowColorStr, sizeof(objShadowColorStr), spec);
166 }
167 ignoreObjectShadowInfoInFile = TRUE;
168 if ((c_ptr=XGetDefault(mainDisplay,TOOL_NAME,
169 "IgnoreObjectShadowInfoInFile")) != NULL &&
170 UtilStrICmp(c_ptr, "false") == 0) {
171 ignoreObjectShadowInfoInFile = FALSE;
172 }
173 pngExportHasTransparentColor = FALSE;
174 if ((c_ptr=XGetDefault(mainDisplay,TOOL_NAME,
175 "PNGExportHasTransparentColor")) != NULL &&
176 UtilStrICmp(c_ptr, "true") == 0) {
177 pngExportHasTransparentColor = TRUE;
178 }
179 tighterStructSplines = TRUE;
180 }
181
CanPerformImageProc()182 int CanPerformImageProc()
183 {
184 struct SelRec *sel_ptr=NULL;
185
186 if (topSel == NULL) return FALSE;
187
188 for (sel_ptr=topSel; sel_ptr != NULL; sel_ptr=sel_ptr->next) {
189 if (sel_ptr->obj->type != OBJ_XPM) return FALSE;
190 }
191 return TRUE;
192 /*
193 * if (topSel != NULL && topSel == botSel && topSel->obj->type == OBJ_XPM) {
194 * return !IsLinkedJpegObj(topSel->obj);
195 * }
196 * return FALSE;
197 */
198 }
199
200 /* --------------------- ConvertIntSpline() --------------------- */
201
202 static
ConvertObjIntSpline(ObjPtr)203 int ConvertObjIntSpline(ObjPtr)
204 struct ObjRec *ObjPtr;
205 {
206 register struct ObjRec *obj_ptr;
207 register int i, changed=FALSE;
208
209 switch (ObjPtr->type) {
210 case OBJ_POLY:
211 if (ObjPtr->detail.p->curved == LT_INTSPLINE) {
212 struct PolyRec *poly_ptr=ObjPtr->detail.p;
213 int new_n, n, index=0;
214 char *smooth=poly_ptr->smooth;
215 IntPoint *vs;
216
217 changed = TRUE;
218 if (smooth != NULL) free(smooth);
219 n = poly_ptr->n;
220 new_n = (n == 2 ? n : ((n-2)<<1)+n);
221
222 vs = (IntPoint*)malloc((new_n+1)*sizeof(IntPoint));
223 if (vs == NULL) FailAllocMessage();
224 smooth = (char*)malloc((new_n+1)*sizeof(char));
225 if (smooth == NULL) FailAllocMessage();
226
227 smooth[0] = smooth[new_n-1] = FALSE;
228 vs[0] = poly_ptr->vlist[0];
229 vs[new_n-1] = poly_ptr->vlist[n-1];
230 for (i=1; i < n-1; i++) {
231 index++;
232 smooth[index] = TRUE;
233 vs[index] = poly_ptr->intvlist[(i<<1)-1];
234 index++;
235 smooth[index] = FALSE;
236 vs[index] = poly_ptr->vlist[i];
237 index++;
238 smooth[index] = TRUE;
239 vs[index] = poly_ptr->intvlist[i<<1];
240 }
241 poly_ptr->curved = LT_SPLINE;
242 free(poly_ptr->vlist);
243 free(poly_ptr->intvlist);
244 poly_ptr->vlist = vs;
245 poly_ptr->n = new_n;
246 poly_ptr->smooth = smooth;
247 poly_ptr->intvlist = NULL;
248 poly_ptr->intn = 0;
249 AdjObjSplineVs(ObjPtr);
250 UpdPolyBBox(ObjPtr, poly_ptr->n, poly_ptr->vlist);
251 }
252 break;
253 case OBJ_POLYGON:
254 if (ObjPtr->detail.g->curved == LT_INTSPLINE) {
255 struct PolygonRec *polygon_ptr=ObjPtr->detail.g;
256 int new_n, n, index=0;
257 char *smooth=polygon_ptr->smooth;
258 IntPoint *vs;
259
260 changed = TRUE;
261 if (smooth != NULL) free(smooth);
262 n = polygon_ptr->n;
263 new_n = ((n-1)<<1)+n;
264
265 vs = (IntPoint*)malloc((new_n+1)*sizeof(IntPoint));
266 if (vs == NULL) FailAllocMessage();
267 smooth = (char*)malloc((new_n+1)*sizeof(char));
268 if (smooth == NULL) FailAllocMessage();
269
270 smooth[0] = FALSE;
271 vs[0] = polygon_ptr->vlist[0];
272 for (i=0; i < n-1; i++) {
273 index++;
274 smooth[index] = TRUE;
275 vs[index] = polygon_ptr->intvlist[i<<1];
276 index++;
277 smooth[index] = TRUE;
278 vs[index] = polygon_ptr->intvlist[(i<<1)+1];
279 index++;
280 smooth[index] = FALSE;
281 vs[index] = polygon_ptr->vlist[i+1];
282 }
283 polygon_ptr->curved = LT_SPLINE;
284 free(polygon_ptr->vlist);
285 free(polygon_ptr->intvlist);
286 polygon_ptr->vlist = vs;
287 polygon_ptr->n = new_n;
288 polygon_ptr->smooth = smooth;
289 polygon_ptr->intvlist = NULL;
290 polygon_ptr->intn = 0;
291 AdjObjSplineVs(ObjPtr);
292 UpdPolyBBox(ObjPtr, polygon_ptr->n, polygon_ptr->vlist);
293 }
294 break;
295 case OBJ_GROUP:
296 case OBJ_SYM:
297 for (obj_ptr=ObjPtr->detail.r->last; obj_ptr!=NULL;
298 obj_ptr=obj_ptr->prev) {
299 if (ConvertObjIntSpline(obj_ptr)) {
300 changed = TRUE;
301 }
302 }
303 break;
304 }
305 if (changed) AdjObjBBox(ObjPtr);
306 return changed;
307 }
308
ConvertIntSpline()309 void ConvertIntSpline()
310 {
311 struct SelRec *sel_ptr=NULL;
312 int changed=FALSE;
313
314 if (topSel == NULL) {
315 MsgBox(TgLoadString(STID_NO_INTSPLINE_SELECTED), TOOL_NAME, INFO_MB);
316 return;
317 }
318 HighLightReverse();
319 StartCompositeCmd();
320 for (sel_ptr=botSel; sel_ptr != NULL; sel_ptr=sel_ptr->prev) {
321 PrepareToReplaceAnObj(sel_ptr->obj);
322 if (ConvertObjIntSpline(sel_ptr->obj)) {
323 changed = TRUE;
324 RecordReplaceAnObj(sel_ptr->obj);
325 } else {
326 AbortPrepareCmd(CMD_REPLACE);
327 }
328 }
329 EndCompositeCmd();
330
331 if (changed) {
332 SetFileModified(TRUE);
333 RedrawAnArea(botObj, selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1),
334 selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1));
335 UpdSelBBox();
336 justDupped = FALSE;
337 Msg(TgLoadString(STID_INTSPLINE_CONVERTED_TO_SPLINE));
338 } else {
339 HighLightForward();
340 MsgBox(TgLoadString(STID_NO_INTSPLINE_SELECTED), TOOL_NAME, INFO_MB);
341 return;
342 }
343 HighLightForward();
344 }
345
346 /* --------------------- ConvertToBezier() --------------------- */
347
348 static
SetBezierPoints(n,vs,new_n,bezier_vs)349 void SetBezierPoints(n, vs, new_n, bezier_vs)
350 int n, new_n;
351 IntPoint *vs, *bezier_vs;
352 {
353 int i=0, *n_choose_i=(int*)malloc((n+1)*sizeof(int)), index=0;
354 double t=(double)0, dt=(((double)1.0)/((double)(new_n-1)));
355 double final_t=((double)1)+(dt/((double)2));
356
357 if (n_choose_i == NULL) FailAllocMessage();
358 memset(n_choose_i, 0, (n+1)*sizeof(int));
359
360 n--;
361 n_choose_i[0] = 1;
362 for (i=1; i <= n; i++) {
363 n_choose_i[i] = n_choose_i[i-1] * (n-i+1) / i;
364 }
365 for (t=(double)0; t <= final_t; t+=dt, index++) {
366 double s=((double)1)-t, xt=(double)0, yt=(double)0;
367
368 for (i=0; i <= n; i++) {
369 /* Bi = B_{i,n}(t) */
370 double Bi=((double)(n_choose_i[i]));
371 int j=0;
372
373 for (j=1; j <= (n-i); j++) Bi *= s;
374 for (j=1; j <= i; j++) Bi *= t;
375 xt += Bi * ((double)(vs[i].x));
376 yt += Bi * ((double)(vs[i].y));
377 }
378 bezier_vs[index].x = round(xt);
379 bezier_vs[index].y = round(yt);
380 }
381 free(n_choose_i);
382 }
383
384 static
ConvertObjToBezier(ObjPtr)385 int ConvertObjToBezier(ObjPtr)
386 struct ObjRec *ObjPtr;
387 {
388 struct ObjRec *obj_ptr=NULL;
389 int i=0, changed=FALSE;
390
391 switch (ObjPtr->type) {
392 case OBJ_POLY:
393 if (ObjPtr->detail.p->curved == LT_STRAIGHT ||
394 ObjPtr->detail.p->curved == LT_SPLINE) {
395 struct PolyRec *poly_ptr=ObjPtr->detail.p;
396 int n=poly_ptr->n;
397 char *smooth=poly_ptr->smooth;
398
399 if (n == 3) {
400 if (!smooth[1]) {
401 smooth[1] = TRUE;
402 changed = TRUE;
403 poly_ptr->curved = LT_SPLINE;
404 AdjObjSplineVs(ObjPtr);
405 UpdPolyBBox(ObjPtr, poly_ptr->n, poly_ptr->vlist);
406 }
407 } else if (n > 3) {
408 int new_n=convertToBezierNumSegs+1;
409 IntPoint *vs=NULL;
410
411 changed = TRUE;
412 if (smooth != NULL) free(smooth);
413
414 vs = (IntPoint*)malloc((new_n+1)*sizeof(IntPoint));
415 if (vs == NULL) FailAllocMessage();
416 memset(vs, 0, (new_n+1)*sizeof(IntPoint));
417 smooth = (char*)malloc((new_n+1)*sizeof(char));
418 if (smooth == NULL) FailAllocMessage();
419 memset(smooth, 0, (new_n+1)*sizeof(char));
420
421 SetBezierPoints(n, poly_ptr->vlist, new_n, vs);
422
423 smooth[0] = smooth[new_n-1] = FALSE;
424 for (i=1; i < new_n-1; i++) smooth[i] = TRUE;
425 poly_ptr->curved = LT_SPLINE;
426 free(poly_ptr->vlist);
427 poly_ptr->vlist = vs;
428 poly_ptr->n = new_n;
429 poly_ptr->smooth = smooth;
430 AdjObjSplineVs(ObjPtr);
431 UpdPolyBBox(ObjPtr, poly_ptr->n, poly_ptr->vlist);
432 }
433 }
434 break;
435 case OBJ_GROUP:
436 case OBJ_SYM:
437 for (obj_ptr=ObjPtr->detail.r->last; obj_ptr!=NULL;
438 obj_ptr=obj_ptr->prev) {
439 if (ConvertObjToBezier(obj_ptr)) {
440 changed = TRUE;
441 }
442 }
443 break;
444 }
445 if (changed) AdjObjBBox(ObjPtr);
446 return changed;
447 }
448
ConvertToBezier()449 void ConvertToBezier()
450 {
451 struct SelRec *sel_ptr=NULL;
452 int changed=FALSE;
453
454 if (topSel == NULL) {
455 MsgBox(TgLoadString(STID_NO_SPLINE_SELECTED), TOOL_NAME, INFO_MB);
456 return;
457 }
458 HighLightReverse();
459 StartCompositeCmd();
460 for (sel_ptr=botSel; sel_ptr != NULL; sel_ptr=sel_ptr->prev) {
461 PrepareToReplaceAnObj(sel_ptr->obj);
462 if (ConvertObjToBezier(sel_ptr->obj)) {
463 changed = TRUE;
464 RecordReplaceAnObj(sel_ptr->obj);
465 } else {
466 AbortPrepareCmd(CMD_REPLACE);
467 }
468 }
469 EndCompositeCmd();
470
471 if (changed) {
472 SetFileModified(TRUE);
473 RedrawAnArea(botObj, selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1),
474 selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1));
475 UpdSelBBox();
476 justDupped = FALSE;
477 Msg(TgLoadString(STID_SPLINE_CONVERTED_TO_BEZIER));
478 } else {
479 HighLightForward();
480 MsgBox(TgLoadString(STID_NO_SPLINE_SELECTED), TOOL_NAME, INFO_MB);
481 return;
482 }
483 HighLightForward();
484 }
485
SetBezierConvertNumSegsValue(spec)486 int SetBezierConvertNumSegsValue(spec)
487 char *spec;
488 {
489 int ival=0;
490
491 if (sscanf(spec, "%d", &ival) != 1) {
492 sprintf(gszMsgBox, TgLoadCachedString(CSTID_MALFORMED_INPUT_STR), spec);
493 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
494 return FALSE;
495 } else if (ival < 2) {
496 sprintf(gszMsgBox, TgLoadString(STID_ENT_VAL_RANGE_ENTER_GE_INT),
497 spec, 3);
498 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
499 return FALSE;
500 }
501 convertToBezierNumSegs = ival;
502
503 return TRUE;
504 }
505
SetBezierConvertNumSegs(psz_num_segs)506 void SetBezierConvertNumSegs(psz_num_segs)
507 char *psz_num_segs;
508 {
509 char spec[MAXSTRING+1];
510
511 *spec = '\0';
512 if (psz_num_segs != NULL && strcmp(psz_num_segs, "-1") != 0) {
513 UtilStrCpyN(spec, sizeof(spec), psz_num_segs);
514 } else {
515 sprintf(gszMsgBox, TgLoadString(STID_ENTER_BEZIER_NUM_SEGS_CUR_IS),
516 convertToBezierNumSegs);
517 if (Dialog(gszMsgBox, NULL, spec) == INVALID) return;
518 }
519 UtilTrimBlanks(spec);
520 if (*spec == '\0') return;
521
522 if (SetBezierConvertNumSegsValue(spec)) {
523 sprintf(gszMsgBox, TgLoadString(STID_BEZIER_NUM_SEGS_SET_TO_INT),
524 convertToBezierNumSegs);
525 Msg(gszMsgBox);
526 }
527 }
528
529 static
SelectModeToggleSmoothHinge()530 void SelectModeToggleSmoothHinge()
531 {
532 register struct ObjRec *obj_ptr;
533 struct PolyRec *poly_ptr=NULL;
534 struct PolygonRec *polygon_ptr=NULL;
535 int index, n, pt_toggled=FALSE, toggling=TRUE;
536 int root_x, root_y, old_x, old_y, curved=(-1);
537 unsigned int status;
538 Window root_win, child_win;
539 XEvent input, ev;
540 char *smooth=NULL;
541
542 if (!(topSel != NULL && topSel == botSel &&
543 (topSel->obj->type == OBJ_POLY || topSel->obj->type == OBJ_POLYGON))) {
544 MsgBox(TgLoadString(STID_SELECT_ONLY_ONE_POLY_POLYGON),
545 TOOL_NAME, INFO_MB);
546 return;
547 }
548 obj_ptr = topSel->obj;
549 switch (obj_ptr->type) {
550 case OBJ_POLY:
551 poly_ptr = obj_ptr->detail.p;
552 smooth = poly_ptr->smooth;
553 curved = poly_ptr->curved;
554 break;
555 case OBJ_POLYGON:
556 polygon_ptr = obj_ptr->detail.g;
557 smooth = polygon_ptr->smooth;
558 curved = polygon_ptr->curved;
559 break;
560 }
561 if (curved == LT_INTSPLINE) {
562 MsgBox(TgLoadString(STID_CANNOT_TOGGLE_FOR_INTSPLINE), TOOL_NAME,
563 INFO_MB);
564 return;
565 } else if (curved == LT_STRUCT_SPLINE) {
566 MsgBox(TgLoadString(STID_CANNOT_TOGGLE_FOR_STRUCT_SPLN), TOOL_NAME,
567 INFO_MB);
568 return;
569 }
570 if (smooth == NULL) {
571 FatalUnexpectedError(TgLoadString(STID_BAD_POLY_IN_TOGGLE_SMOOTH), NULL);
572 return;
573 }
574 PrepareToRecord(CMD_REPLACE, topSel, botSel, numObjSelected);
575 SaveStatusStrings();
576 SetMouseStatus(TgLoadCachedString(CSTID_TOGGLE_SMOOTH_HINGE),
577 TgLoadCachedString(CSTID_FINISH), TgLoadCachedString(CSTID_FINISH));
578 TwoLineMsg(TgLoadString(STID_CLICK_LEFT_BUTTON_TO_TOGGLE),
579 TgLoadString(STID_CLICK_OTHER_BUTTON_TO_QUIT));
580
581 if (!debugNoPointerGrab) {
582 XGrabPointer(mainDisplay, drawWindow, False,
583 PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
584 GrabModeAsync, GrabModeAsync, None, defaultCursor, CurrentTime);
585 }
586 XQueryPointer(mainDisplay, drawWindow, &root_win, &child_win,
587 &root_x, &root_y, &old_x, &old_y, &status);
588 XSetFont(mainDisplay, revDefaultGC, defaultFontPtr->fid);
589 /* do not translate -- program constants */
590 XDrawString(mainDisplay, drawWindow, revDefaultGC,
591 old_x+4, old_y+defaultFontAsc, "S/H", 3);
592 MarkRulers(old_x, old_y);
593
594 while (toggling) {
595 XNextEvent(mainDisplay, &input);
596
597 if (input.type == Expose || input.type == VisibilityNotify) {
598 ExposeEventHandler(&input, TRUE);
599 } else if (input.type == ButtonPress) {
600 if (input.xbutton.button == Button1) {
601 if ((obj_ptr->type == OBJ_POLY &&
602 PtInPolyMark(obj_ptr, input.xbutton.x, input.xbutton.y,
603 poly_ptr->n, poly_ptr->vlist, &index) &&
604 index != 0 && index != poly_ptr->n-1) ||
605 (obj_ptr->type == OBJ_POLYGON &&
606 PtInPolyMark(obj_ptr, input.xbutton.x, input.xbutton.y,
607 polygon_ptr->n-1, polygon_ptr->vlist, &index))) {
608 int sel_ltx=selLtX, sel_lty=selLtY;
609 int sel_rbx=selRbX, sel_rby=selRbY;
610
611 pt_toggled = TRUE;
612 HighLightReverse();
613 switch (obj_ptr->type) {
614 case OBJ_POLY:
615 n = poly_ptr->n;
616 if (smooth[index]) {
617 smooth[index] = FALSE;
618 } else {
619 smooth[index] = TRUE;
620 }
621 AdjObjSplineVs(obj_ptr);
622 UpdPolyBBox(obj_ptr, poly_ptr->n, poly_ptr->vlist);
623 break;
624 case OBJ_POLYGON:
625 n = polygon_ptr->n;
626 if (smooth[index]) {
627 smooth[index] = FALSE;
628 } else {
629 smooth[index] = TRUE;
630 }
631 if (index == 0) smooth[n-1] = smooth[0];
632 AdjObjSplineVs(obj_ptr);
633 UpdPolyBBox(obj_ptr, polygon_ptr->n, polygon_ptr->vlist);
634 break;
635 }
636 AdjObjBBox(obj_ptr);
637
638 XDrawString(mainDisplay, drawWindow, revDefaultGC, old_x+4,
639 old_y+defaultFontAsc, "S/H", 3);
640 old_x = input.xbutton.x;
641 old_y = input.xbutton.y;
642 UpdSelBBox();
643 RedrawAreas(botObj,
644 sel_ltx-GRID_ABS_SIZE(1), sel_lty-GRID_ABS_SIZE(1),
645 sel_rbx+GRID_ABS_SIZE(1), sel_rby+GRID_ABS_SIZE(1),
646 selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1),
647 selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1));
648 HighLightForward();
649 if (obj_ptr != NULL) {
650 XDrawString(mainDisplay, drawWindow, revDefaultGC,
651 old_x+4, old_y+defaultFontAsc, "S/H", 3);
652 }
653 SetFileModified(TRUE);
654 justDupped = FALSE;
655 }
656 } else {
657 XUngrabPointer(mainDisplay, CurrentTime);
658 Msg("");
659 toggling = FALSE;
660 XDrawString(mainDisplay, drawWindow, revDefaultGC,
661 old_x+4, old_y+defaultFontAsc, "S/H", 3);
662 }
663 } else if (input.type == MotionNotify) {
664 XDrawString(mainDisplay, drawWindow, revDefaultGC,
665 old_x+4, old_y+defaultFontAsc, "S/H", 3);
666 old_x = input.xmotion.x;
667 old_y = input.xmotion.y;
668 XDrawString(mainDisplay, drawWindow, revDefaultGC,
669 old_x+4, old_y+defaultFontAsc, "S/H", 3);
670 MarkRulers(old_x, old_y);
671 while (XCheckMaskEvent(mainDisplay, PointerMotionMask, &ev)) ;
672 }
673 }
674 RestoreStatusStrings();
675 if (pt_toggled) {
676 RecordCmd(CMD_REPLACE, NULL, topSel, botSel, numObjSelected);
677 } else {
678 AbortPrepareCmd(CMD_REPLACE);
679 }
680 }
681
ToggleSmoothHinge()682 void ToggleSmoothHinge()
683 {
684 register int i;
685 int changed=FALSE, ltx=selLtX, lty=selLtY, rbx=selRbX, rby=selRbY;
686 struct VSelRec *vsel_ptr;
687 struct ObjRec *obj_ptr;
688
689 if (curChoice == NOTHING) {
690 SelectModeToggleSmoothHinge();
691 return;
692 }
693 if (curChoice != VERTEXMODE) {
694 MsgBox(TgLoadString(STID_ONLY_TOGGLE_SMOOTH_IN_MODES), TOOL_NAME,
695 INFO_MB);
696 return;
697 }
698 if (topVSel == NULL) {
699 if (topSel == NULL) return;
700 HighLightReverse();
701 JustRemoveAllVSel();
702 HighLightForward();
703 SelectModeToggleSmoothHinge();
704 return;
705 }
706 for (vsel_ptr=topVSel; vsel_ptr != NULL; vsel_ptr=vsel_ptr->next) {
707 if ((vsel_ptr->obj->type == OBJ_POLY &&
708 vsel_ptr->obj->detail.p->curved == LT_INTSPLINE) ||
709 (vsel_ptr->obj->type == OBJ_POLYGON &&
710 vsel_ptr->obj->detail.g->curved == LT_INTSPLINE)) {
711 MsgBox(TgLoadString(STID_CANNOT_TOGGLE_FOR_INTSPLINE), TOOL_NAME,
712 INFO_MB);
713 return;
714 } else if ((vsel_ptr->obj->type == OBJ_POLY &&
715 vsel_ptr->obj->detail.p->curved == LT_STRUCT_SPLINE) ||
716 (vsel_ptr->obj->type == OBJ_POLYGON &&
717 vsel_ptr->obj->detail.g->curved == LT_STRUCT_SPLINE)) {
718 MsgBox(TgLoadString(STID_CANNOT_TOGGLE_FOR_STRUCT_SPLN), TOOL_NAME,
719 INFO_MB);
720 return;
721 }
722 }
723 HighLightReverse();
724 StartCompositeCmd();
725 for (vsel_ptr=botVSel; vsel_ptr != NULL; vsel_ptr=vsel_ptr->prev) {
726 int obj_changed=FALSE, n;
727 IntPoint *v;
728 char *smooth=NULL;
729
730 obj_ptr = vsel_ptr->obj;
731 switch (obj_ptr->type) {
732 case OBJ_POLY:
733 v = obj_ptr->detail.p->vlist;
734 n = obj_ptr->detail.p->n;
735 smooth = obj_ptr->detail.p->smooth;
736 for (i=0; i < vsel_ptr->n; i++) {
737 if (vsel_ptr->v_index[i] != 0 ||
738 vsel_ptr->v_index[i] != n-1) {
739 break;
740 }
741 }
742 if (i == vsel_ptr->n) continue;
743 break;
744 case OBJ_POLYGON:
745 v = obj_ptr->detail.g->vlist;
746 n = obj_ptr->detail.g->n;
747 smooth = obj_ptr->detail.g->smooth;
748 break;
749 default: continue;
750 }
751 PrepareToReplaceAnObj(obj_ptr);
752 for (i=0; i < vsel_ptr->n; i++) {
753 int index=vsel_ptr->v_index[i];
754
755 if (!(obj_ptr->type == OBJ_POLY && (index == 0 || index == n-1))) {
756 smooth[index] = (smooth[index] ? FALSE : TRUE);
757 obj_changed = TRUE;
758 }
759 }
760 AdjObjSplineVs(obj_ptr);
761 UpdPolyBBox(obj_ptr, n, v);
762 if (obj_changed) {
763 RecordReplaceAnObj(obj_ptr);
764 changed = TRUE;
765 } else {
766 AbortPrepareCmd(CMD_REPLACE);
767 }
768 }
769 EndCompositeCmd();
770 if (changed) {
771 Msg(TgLoadString(STID_SMOOTHNESS_TOGGLED));
772 UpdSelBBox();
773 RedrawAreas(botObj, ltx-GRID_ABS_SIZE(1), lty-GRID_ABS_SIZE(1),
774 rbx+GRID_ABS_SIZE(1), rby+GRID_ABS_SIZE(1),
775 selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1),
776 selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1));
777 SetFileModified(TRUE);
778 justDupped = FALSE;
779 }
780 HighLightForward();
781 }
782
783 static
BreakATextObj(ObjPtr,how,poli)784 void BreakATextObj(ObjPtr, how, poli)
785 struct ObjRec *ObjPtr;
786 int how;
787 ObjListInfo *poli;
788 {
789 struct ObjRec *prototype=NULL;
790 struct TextRec *text_ptr=NULL;
791 struct SelRec *sel_ptr=NULL;
792 MiniLinesInfo *minilines=NULL;
793 int tx_to_move=0, ty_to_move=0;
794 char proto_buf[3];
795
796 prototype = DupObj(ObjPtr);
797 text_ptr = prototype->detail.t;
798 InvalidateTextCache(text_ptr);
799 minilines = (&text_ptr->minilines);
800 FreeMiniLines(minilines, FALSE);
801 /* do not translate -- program constants */
802 strcpy(proto_buf, "XX");
803 CreateMiniLineFromString(proto_buf, &minilines->first, &minilines->last);
804 minilines->first->owner_minilines = minilines;
805 text_ptr->lines = 1;
806
807 text_ptr = ObjPtr->detail.t;
808 minilines = (&text_ptr->minilines);
809
810 PushCurFont();
811 ObjFontInfoToCurFontInfo(text_ptr);
812 SetCanvasFont();
813
814 if (ObjPtr->ctm != NULL) {
815 TransformPointThroughCTM(0, 0, prototype->ctm, &tx_to_move, &ty_to_move);
816 }
817 BreakMiniLines(minilines, how, ObjPtr->x, text_ptr->baseline_y,
818 prototype, tx_to_move, ty_to_move, poli);
819
820 PopCurFont();
821 FreeTextObj(prototype);
822 for (sel_ptr=poli->top_sel; sel_ptr != NULL; sel_ptr=sel_ptr->next) {
823 struct ObjRec *obj_ptr=sel_ptr->obj;
824
825 UpdTextBBox(obj_ptr);
826 AdjObjSplineVs(obj_ptr);
827 AdjObjBBox(obj_ptr);
828 }
829 }
830
831 static
GetBreakSpec()832 int GetBreakSpec()
833 /* return TRUE if breaking into words */
834 {
835 int how=INVALID, can_do_lines=FALSE, can_do_words=FALSE;
836 char spec[MAXSTRING+1];
837 struct SelRec *sel_ptr=NULL;
838
839 for (sel_ptr=topSel; sel_ptr != NULL; sel_ptr=sel_ptr->next) {
840 struct ObjRec *obj_ptr=sel_ptr->obj;
841
842 if (obj_ptr->type == OBJ_TEXT && !obj_ptr->locked) {
843 struct TextRec *text_ptr=obj_ptr->detail.t;
844 MiniLinesInfo *minilines=(&text_ptr->minilines);
845
846 if (text_ptr->read_only) continue;
847 if (CanBreakMiniLinesIntoWords(&text_ptr->minilines)) {
848 can_do_words = TRUE;
849 }
850 if (minilines->first->next != NULL) can_do_lines = TRUE;
851 }
852 if (can_do_lines && can_do_words) break;
853 }
854 if (can_do_lines) {
855 if (can_do_words) {
856 strcpy(gszMsgBox, TgLoadString(STID_BREAK_TEXT_CWL));
857 } else {
858 strcpy(gszMsgBox, TgLoadString(STID_BREAK_TEXT_CL));
859 }
860 } else if (can_do_words) {
861 strcpy(gszMsgBox, TgLoadString(STID_BREAK_TEXT_CW));
862 } else {
863 return BREAK_CHAR;
864 }
865 *spec = '\0';
866 if (Dialog(gszMsgBox, NULL, spec) == INVALID) {
867 return INVALID;
868 }
869 UtilTrimBlanks(spec);
870 if (*spec == '\0') strcpy(spec, "c");
871 strcpy(gszMsgBox, spec);
872 gszMsgBox[1] = '\0';
873 UtilStrLower(gszMsgBox);
874 if (can_do_lines) {
875 if (can_do_words) {
876 switch (*gszMsgBox) {
877 case 'c': how = BREAK_CHAR; break;
878 case 'w': how = BREAK_WORD; break;
879 case 'l': how = BREAK_LINE; break;
880 }
881 } else {
882 switch (*gszMsgBox) {
883 case 'c': how = BREAK_CHAR; break;
884 case 'l': how = BREAK_LINE; break;
885 }
886 }
887 } else if (can_do_words) {
888 switch (*gszMsgBox) {
889 case 'c': how = BREAK_CHAR; break;
890 case 'w': how = BREAK_WORD; break;
891 }
892 }
893 if (how == INVALID) {
894 sprintf(gszMsgBox, TgLoadString(STID_INVALID_SPEC_ON_BREAK_TEXT), spec);
895 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
896 }
897 return how;
898 }
899
900 static
GetBreakSpecFromCh(spec)901 int GetBreakSpecFromCh(spec)
902 char *spec;
903 {
904 char buf[2];
905 int how=INVALID;
906
907 buf[0] = *spec;
908 buf[1] = '\0';
909 UtilStrLower(buf);
910
911 switch (*buf) {
912 case 'c': how = BREAK_CHAR; break;
913 case 'w': how = BREAK_WORD; break;
914 case 'l': how = BREAK_LINE; break;
915 }
916 if (how == INVALID) {
917 sprintf(gszMsgBox, TgLoadString(STID_INVALID_SPEC_ON_BREAK_TEXT), spec);
918 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
919 }
920 return how;
921 }
922
DoBreakUpText(spec,forced_justify)923 void DoBreakUpText(spec, forced_justify)
924 char *spec;
925 int forced_justify;
926 {
927 struct ObjRec *obj_ptr=NULL;
928 struct SelRec *sel_ptr=NULL, *next_sel=NULL;
929 int sel_ltx=selLtX, sel_lty=selLtY, sel_rbx=selRbX, sel_rby=selRbY;
930 int how=INVALID, changed=FALSE, read_only_text_exists=FALSE;
931
932 if (topSel == NULL) {
933 MsgBox(TgLoadString(STID_NO_TEXT_OBJ_TO_BREAK_UP), TOOL_NAME, INFO_MB);
934 return;
935 }
936 if (spec == NULL || *spec == '\0' || strcmp(spec, "-1") == 0) {
937 if ((how=GetBreakSpec()) == INVALID) return;
938 } else {
939 if ((how=GetBreakSpecFromCh(spec)) == INVALID) return;
940 }
941 HighLightReverse();
942
943 StartCompositeCmd();
944 for (sel_ptr=topSel; sel_ptr != NULL; sel_ptr=next_sel) {
945 next_sel = sel_ptr->next;
946 obj_ptr = sel_ptr->obj;
947 if (obj_ptr->type == OBJ_TEXT && !obj_ptr->locked) {
948 ObjListInfo oli;
949
950 if (obj_ptr->detail.t->read_only) {
951 read_only_text_exists = TRUE;
952 continue;
953 }
954 memset(&oli, 0, sizeof(ObjListInfo));
955
956 changed = TRUE;
957
958 PrepareToReplaceAnObj(obj_ptr);
959 BreakATextObj(obj_ptr, how, &oli);
960
961 oli.top_sel->obj->prev = obj_ptr->prev;
962 if (obj_ptr->prev == NULL) {
963 curPage->top = topObj = oli.top_sel->obj;
964 } else {
965 obj_ptr->prev->next = oli.top_sel->obj;
966 }
967 oli.bot_sel->obj->next = obj_ptr->next;
968 if (obj_ptr->next == NULL) {
969 curPage->bot = botObj = oli.bot_sel->obj;
970 } else {
971 obj_ptr->next->prev = oli.bot_sel->obj;
972 }
973 RecordCmd(CMD_ONE_TO_MANY, NULL, oli.top_sel, oli.bot_sel, oli.count);
974
975 oli.top_sel->prev = sel_ptr->prev;
976 if (sel_ptr->prev == NULL) {
977 topSel = oli.top_sel;
978 } else {
979 sel_ptr->prev->next = oli.top_sel;
980 }
981 oli.bot_sel->next = sel_ptr->next;
982 if (sel_ptr->next == NULL) {
983 botSel = oli.bot_sel;
984 } else {
985 sel_ptr->next->prev = oli.bot_sel;
986 }
987 FreeObj(obj_ptr);
988 free(sel_ptr);
989 }
990 }
991 EndCompositeCmd();
992 if (read_only_text_exists) {
993 MsgBox(TgLoadString(STID_SOME_TEXT_NOT_BROKEN_UP_SIZE), TOOL_NAME,
994 INFO_MB);
995 }
996 if (changed) {
997 UpdSelBBox();
998 RedrawAreas(botObj, selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1),
999 selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1),
1000 sel_ltx-GRID_ABS_SIZE(1), sel_lty-GRID_ABS_SIZE(1),
1001 sel_rbx+GRID_ABS_SIZE(1), sel_rby+GRID_ABS_SIZE(1));
1002 SetFileModified(TRUE);
1003 justDupped = FALSE;
1004 Msg(TgLoadString(STID_TEXT_BROKEN_INTO_CHARS));
1005 } else if (!read_only_text_exists) {
1006 MsgBox(TgLoadString(STID_NO_TEXT_OBJ_TO_BREAK_UP), TOOL_NAME, INFO_MB);
1007 }
1008 HighLightForward();
1009 }
1010
BreakUpText(spec)1011 void BreakUpText(spec)
1012 char *spec;
1013 {
1014 DoBreakUpText(spec, '\0');
1015 }
1016
1017 static
DoSetTextFillPatternColor(ObjPtr)1018 int DoSetTextFillPatternColor(ObjPtr)
1019 struct ObjRec *ObjPtr;
1020 {
1021 struct ObjRec *obj_ptr=NULL;
1022 int changed=FALSE;
1023
1024 switch (ObjPtr->type) {
1025 case OBJ_TEXT:
1026 if (ObjPtr->color != colorIndex) {
1027 ObjPtr->color = colorIndex;
1028 if (mainDisplay != NULL) {
1029 UtilStrCpyN(ObjPtr->color_str, sizeof(ObjPtr->color_str),
1030 colorMenuItems[colorIndex]);
1031 }
1032 changed = TRUE;
1033 }
1034 break;
1035
1036 case OBJ_SYM:
1037 case OBJ_GROUP:
1038 case OBJ_ICON:
1039 for (obj_ptr=ObjPtr->detail.r->last; obj_ptr != NULL;
1040 obj_ptr=obj_ptr->prev) {
1041 if (DoSetTextFillPatternColor(obj_ptr)) {
1042 changed = TRUE;
1043 }
1044 }
1045 break;
1046 case OBJ_PIN:
1047 obj_ptr = GetPinObj(ObjPtr);
1048 if (DoSetTextFillPatternColor(obj_ptr)) {
1049 changed = TRUE;
1050 }
1051 break;
1052 }
1053 return changed;
1054 }
1055
SetTextFillPatternColor()1056 void SetTextFillPatternColor()
1057 {
1058 struct SelRec *sel_ptr=NULL;
1059 int changed=FALSE;
1060
1061 if (curChoice == DRAWTEXT) {
1062 if (curTextObj->color != colorIndex) {
1063 curTextObj->color = colorIndex;
1064 if (mainDisplay != NULL) {
1065 UtilStrCpyN(curTextObj->color_str, sizeof(curTextObj->color_str),
1066 colorMenuItems[colorIndex]);
1067 }
1068 SetFileModified(TRUE);
1069 sprintf(gszMsgBox, TgLoadString(STID_CUR_TEXT_BG_SET_TO_NAMED),
1070 colorMenuItems[colorIndex]);
1071 Msg(gszMsgBox);
1072 }
1073 return;
1074 }
1075 if (topSel == NULL) {
1076 MsgBox(TgLoadCachedString(CSTID_NO_OBJ_SELECTED), TOOL_NAME, INFO_MB);
1077 return;
1078 }
1079 HighLightReverse();
1080 StartCompositeCmd();
1081 for (sel_ptr=topSel; sel_ptr != NULL; sel_ptr=sel_ptr->next) {
1082 struct ObjRec *obj_ptr=sel_ptr->obj;
1083
1084 PrepareToReplaceAnObj(obj_ptr);
1085 if (DoSetTextFillPatternColor(obj_ptr)) {
1086 changed = TRUE;
1087 RecordReplaceAnObj(obj_ptr);
1088 } else {
1089 AbortPrepareCmd(CMD_REPLACE);
1090 }
1091 }
1092 EndCompositeCmd();
1093 if (changed) {
1094 RedrawAnArea(botObj,
1095 selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1),
1096 selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1));
1097 HighLightForward();
1098 SetFileModified(TRUE);
1099 justDupped = FALSE;
1100 sprintf(gszMsgBox, TgLoadString(STID_SOME_TEXT_BG_SET_TO_NAMED),
1101 colorMenuItems[colorIndex]);
1102 Msg(gszMsgBox);
1103 }
1104 }
1105
MakeRegularPolygon()1106 void MakeRegularPolygon()
1107 {
1108 register int i;
1109 int vertex_at_right, xc, yc;
1110 int sel_ltx, sel_lty, sel_rbx, sel_rby, sides, radius;
1111 int ltx, lty, rbx, rby;
1112 double inc, angle, r;
1113 struct ObjRec *obj_ptr, *new_obj_ptr;
1114 struct PolygonRec *polygon_ptr;
1115
1116 if (topSel == NULL) {
1117 MsgBox(TgLoadCachedString(CSTID_NO_OBJ_SELECTED), TOOL_NAME, INFO_MB);
1118 return;
1119 } else if (topSel != botSel || topSel->obj->type != OBJ_POLYGON) {
1120 MsgBox(TgLoadString(STID_SEL_ONE_POLYGON_TO_MAKE_REG), TOOL_NAME,
1121 INFO_MB);
1122 return;
1123 } else if (topSel->obj->locked) {
1124 MsgBox(TgLoadString(STID_POLYGON_LOCKED), TOOL_NAME, INFO_MB);
1125 return;
1126 }
1127 PrepareToRecord(CMD_REPLACE, topSel, botSel, numObjSelected);
1128
1129 sel_ltx = selLtX; sel_lty = selLtY;
1130 sel_rbx = selRbX; sel_rby = selRbY;
1131
1132 obj_ptr = topSel->obj;
1133
1134 radius = (min(obj_ptr->obbox.rbx-obj_ptr->obbox.ltx,
1135 obj_ptr->obbox.rby-obj_ptr->obbox.lty))>>1;
1136 if (radius < 1) {
1137 MsgBox(TgLoadString(STID_POLYGON_TOO_SMALL_FOR_REGULAR), TOOL_NAME,
1138 INFO_MB);
1139 return;
1140 }
1141 sprintf(gszMsgBox, TgLoadString(STID_VERTEX_AT_3_OCLOCK_YNC));
1142 if ((vertex_at_right=MsgBox(gszMsgBox, TOOL_NAME, YNC_MB)) ==
1143 MB_ID_CANCEL) {
1144 return;
1145 }
1146 tmpTopObj = tmpBotObj = NULL;
1147 tmpTopSel = tmpBotSel = NULL;
1148
1149 HighLightReverse();
1150
1151 new_obj_ptr = DupObj(obj_ptr);
1152
1153 UnlinkObj(obj_ptr);
1154
1155 polygon_ptr = new_obj_ptr->detail.g;
1156 sides = polygon_ptr->n-1;
1157 inc = 2*M_PI/sides;
1158 angle = (vertex_at_right==MB_ID_YES) ? 0 : inc/2;
1159
1160 xc = obj_ptr->obbox.ltx+radius;
1161 yc = obj_ptr->obbox.lty+radius;
1162
1163 if ((sides%4)==0 && vertex_at_right==MB_ID_NO) {
1164 r = ((double)(min(obj_ptr->obbox.rbx-obj_ptr->obbox.ltx,
1165 obj_ptr->obbox.rby-obj_ptr->obbox.lty)) / cos(angle)) / 2;
1166 } else {
1167 r = radius;
1168 }
1169 ltx = obj_ptr->obbox.rbx;
1170 lty = obj_ptr->obbox.rby;
1171 rbx = obj_ptr->obbox.ltx;
1172 rby = obj_ptr->obbox.lty;
1173 for (i=0; i < sides; i++, angle+=inc) {
1174 polygon_ptr->vlist[i].x = xc + round(r*cos(angle));
1175 polygon_ptr->vlist[i].y = yc - round(r*sin(angle));
1176 if (polygon_ptr->vlist[i].x < ltx) ltx = polygon_ptr->vlist[i].x;
1177 if (polygon_ptr->vlist[i].y < lty) lty = polygon_ptr->vlist[i].y;
1178 if (polygon_ptr->vlist[i].x > rbx) rbx = polygon_ptr->vlist[i].x;
1179 if (polygon_ptr->vlist[i].y > rby) rby = polygon_ptr->vlist[i].y;
1180 }
1181 polygon_ptr->vlist[sides].x = polygon_ptr->vlist[0].x;
1182 polygon_ptr->vlist[sides].y = polygon_ptr->vlist[0].y;
1183 new_obj_ptr->obbox.ltx = ltx;
1184 new_obj_ptr->obbox.lty = lty;
1185 new_obj_ptr->obbox.rbx = rbx;
1186 new_obj_ptr->obbox.rby = rby;
1187 AdjObjSplineVs(new_obj_ptr);
1188 AdjObjBBox(new_obj_ptr);
1189
1190 topSel->obj = botSel->obj = new_obj_ptr;
1191 AddObj(NULL, topObj, new_obj_ptr);
1192 RecordCmd(CMD_REPLACE, NULL, topSel, botSel, numObjSelected);
1193 FreeObj(obj_ptr);
1194
1195 UpdSelBBox();
1196 RedrawAnArea(botObj, sel_ltx-GRID_ABS_SIZE(1), sel_lty-GRID_ABS_SIZE(1),
1197 sel_rbx+GRID_ABS_SIZE(1), sel_rby+GRID_ABS_SIZE(1));
1198 SetFileModified(TRUE);
1199 justDupped = FALSE;
1200 HighLightForward();
1201 }
1202
DeleteStructuredSplinePoint(index,poly_ptr,polygon_ptr)1203 int DeleteStructuredSplinePoint(index, poly_ptr, polygon_ptr)
1204 int index; /* index into ssvlist */
1205 struct PolyRec *poly_ptr;
1206 struct PolygonRec *polygon_ptr;
1207 /* return FALSE if the object should be deleted */
1208 {
1209 int i=0, j=0, n=0, idx=0, num_hinge_points=0, ssn=0;
1210 IntPoint *vs=NULL;
1211 StretchStructuredSplineInfo sssi;
1212
1213 memset(&sssi, 0, sizeof(StretchStructuredSplineInfo));
1214
1215 if (poly_ptr != NULL) {
1216 ssn = poly_ptr->ssn;
1217 n = poly_ptr->n;
1218 vs = poly_ptr->vlist;
1219 SetIPTInfoForStretchPoly(index, n, vs, &sssi);
1220 } else if (polygon_ptr != NULL) {
1221 ssn = polygon_ptr->ssn;
1222 n = polygon_ptr->n;
1223 vs = polygon_ptr->vlist;
1224 SetIPTInfoForStretchPolygon(index, n, vs, &sssi);
1225 }
1226 if (sssi.hinge) {
1227 num_hinge_points = (n+2)/3;
1228 if ((poly_ptr != NULL && num_hinge_points-1 < 2) ||
1229 (polygon_ptr != NULL && num_hinge_points-1 < 3)) {
1230 return FALSE;
1231 }
1232 if (!sssi.prev_valid) {
1233 /* first point of poly */
1234 if (sssi.ipt.later_valid) {
1235 if (ssn-2 < 2) return FALSE;
1236 } else {
1237 if (ssn-1 < 2) return FALSE;
1238 }
1239 for (i=0; i < n-3; i++) {
1240 vs[i].x = vs[i+3].x;
1241 vs[i].y = vs[i+3].y;
1242 }
1243 poly_ptr->n = n-3;
1244 } else if (!sssi.next_valid) {
1245 /* last point of poly */
1246 if (sssi.ipt.earlier_valid) {
1247 if (ssn-2 < 2) return FALSE;
1248 } else {
1249 if (ssn-1 < 2) return FALSE;
1250 }
1251 poly_ptr->n = n-3;
1252 } else {
1253 if (poly_ptr != NULL) {
1254 if (sssi.ipt.earlier_valid) {
1255 if (ssn-3 < 2) return FALSE;
1256 } else {
1257 if (ssn-1 < 2) return FALSE;
1258 }
1259 for (i=0, j=0; i < num_hinge_points; i++, j+=3) {
1260 if (j != sssi.orig_hinge_index) {
1261 if (i == 0) {
1262 vs[idx].x = vs[j].x;
1263 vs[idx].y = vs[j].y;
1264 vs[idx+1].x = vs[j+1].x;
1265 vs[idx+1].y = vs[j+1].y;
1266 idx += 2;
1267 } else if (i == num_hinge_points-1) {
1268 vs[idx].x = vs[j-1].x;
1269 vs[idx].y = vs[j-1].y;
1270 vs[idx+1].x = vs[j].x;
1271 vs[idx+1].y = vs[j].y;
1272 idx += 2;
1273 } else {
1274 vs[idx].x = vs[j-1].x;
1275 vs[idx].y = vs[j-1].y;
1276 vs[idx+1].x = vs[j].x;
1277 vs[idx+1].y = vs[j].y;
1278 vs[idx+2].x = vs[j+1].x;
1279 vs[idx+2].y = vs[j+1].y;
1280 idx += 3;
1281 }
1282 }
1283 }
1284 poly_ptr->n = n-3;
1285 } else if (polygon_ptr != NULL) {
1286 if (sssi.orig_hinge_index == 0 || sssi.orig_hinge_index == n-1) {
1287 IntPoint v2, v3;
1288
1289 if ((sssi.orig_hinge_index == 0 && sssi.ipt.later_valid) ||
1290 (sssi.orig_hinge_index == n-1 && sssi.ipt.earlier_valid)) {
1291 if (ssn-3 < 4) return FALSE;
1292 } else {
1293 if (ssn-1 < 4) return FALSE;
1294 }
1295 v2.x = vs[2].x;
1296 v2.y = vs[2].y;
1297 v3.x = vs[3].x;
1298 v3.y = vs[3].y;
1299 for (j=0; j < n-5; j++) {
1300 vs[j].x = vs[j+3].x;
1301 vs[j].y = vs[j+3].y;
1302 }
1303 vs[n-5].x = v2.x;
1304 vs[n-5].y = v2.y;
1305 vs[n-4].x = v3.x;
1306 vs[n-4].y = v3.y;
1307 } else {
1308 if (sssi.ipt.later_valid) {
1309 if (ssn-3 < 4) return FALSE;
1310 } else {
1311 if (ssn-1 < 4) return FALSE;
1312 }
1313 for (i=0, j=0; i < num_hinge_points; i++, j+=3) {
1314 if (j != sssi.orig_hinge_index) {
1315 if (i == 0) {
1316 vs[idx].x = vs[j].x;
1317 vs[idx].y = vs[j].y;
1318 vs[idx+1].x = vs[j+1].x;
1319 vs[idx+1].y = vs[j+1].y;
1320 idx += 2;
1321 } else if (i == num_hinge_points-1) {
1322 vs[idx].x = vs[j-1].x;
1323 vs[idx].y = vs[j-1].y;
1324 vs[idx+1].x = vs[j].x;
1325 vs[idx+1].y = vs[j].y;
1326 idx += 2;
1327 } else {
1328 vs[idx].x = vs[j-1].x;
1329 vs[idx].y = vs[j-1].y;
1330 vs[idx+1].x = vs[j].x;
1331 vs[idx+1].y = vs[j].y;
1332 vs[idx+2].x = vs[j+1].x;
1333 vs[idx+2].y = vs[j+1].y;
1334 idx += 3;
1335 }
1336 }
1337 }
1338 }
1339 polygon_ptr->n = n-3;
1340 }
1341 }
1342 } else {
1343 if (!sssi.prev_valid) {
1344 /* first point of poly */
1345 ssn--;
1346 if ((poly_ptr != NULL && ssn < 2) ||
1347 (polygon_ptr != NULL && ssn < 4)) {
1348 return FALSE;
1349 }
1350 vs[1].x = vs[0].x;
1351 vs[1].y = vs[0].y;
1352 } else if (!sssi.next_valid) {
1353 /* last point of poly */
1354 ssn--;
1355 if ((poly_ptr != NULL && ssn < 2) ||
1356 (polygon_ptr != NULL && ssn < 4)) {
1357 return FALSE;
1358 }
1359 vs[n-2].x = vs[n-1].x;
1360 vs[n-2].y = vs[n-1].y;
1361 } else {
1362 ssn -= 2;
1363 if ((poly_ptr != NULL && ssn < 2) ||
1364 (polygon_ptr != NULL && ssn < 4)) {
1365 return FALSE;
1366 }
1367 if (poly_ptr != NULL) {
1368 vs[sssi.orig_hinge_index-1].x = vs[sssi.orig_hinge_index].x;
1369 vs[sssi.orig_hinge_index-1].y = vs[sssi.orig_hinge_index].y;
1370 vs[sssi.orig_hinge_index+1].x = vs[sssi.orig_hinge_index].x;
1371 vs[sssi.orig_hinge_index+1].y = vs[sssi.orig_hinge_index].y;
1372 } else if (polygon_ptr != NULL) {
1373 if (sssi.orig_hinge_index == 0 || sssi.orig_hinge_index == n-1) {
1374 vs[1].x = vs[0].x;
1375 vs[1].y = vs[0].y;
1376 vs[n-2].x = vs[n-1].x;
1377 vs[n-2].y = vs[n-1].y;
1378 } else {
1379 vs[sssi.orig_hinge_index-1].x = vs[sssi.orig_hinge_index].x;
1380 vs[sssi.orig_hinge_index-1].y = vs[sssi.orig_hinge_index].y;
1381 vs[sssi.orig_hinge_index+1].x = vs[sssi.orig_hinge_index].x;
1382 vs[sssi.orig_hinge_index+1].y = vs[sssi.orig_hinge_index].y;
1383 }
1384 }
1385 }
1386 }
1387 return TRUE;
1388 }
1389
DeletePoint()1390 void DeletePoint()
1391 {
1392 int i=0, n=0, pt_deleted=FALSE, deleting=TRUE, curved=(-1);
1393 int root_x=0, root_y=0, old_x=0, old_y=0, delete_obj=FALSE;
1394 struct ObjRec *obj_ptr=NULL;
1395 struct PolyRec *poly_ptr=NULL;
1396 struct PolygonRec *polygon_ptr=NULL;
1397 unsigned int status;
1398 Window root_win, child_win;
1399 IntPoint *vs=NULL;
1400 char *smooth=NULL;
1401
1402 if (!(topSel != NULL && topSel == botSel &&
1403 (topSel->obj->type == OBJ_POLY || topSel->obj->type == OBJ_POLYGON))) {
1404 MsgBox(TgLoadString(STID_SELECT_ONLY_ONE_POLY_POLYGON), TOOL_NAME,
1405 INFO_MB);
1406 return;
1407 } else if (topSel->obj->locked) {
1408 MsgBox(TgLoadString(STID_CANNOT_DEL_PT_FOR_LOCKED), TOOL_NAME, INFO_MB);
1409 return;
1410 }
1411 if (curChoice == VERTEXMODE) {
1412 HighLightReverse();
1413 JustRemoveAllVSel();
1414 HighLightForward();
1415 }
1416 PrepareToRecord(CMD_REPLACE, topSel, botSel, numObjSelected);
1417 obj_ptr = topSel->obj;
1418 if (!GetPolyOrPolygonControlPoints(obj_ptr, &poly_ptr, &polygon_ptr, &curved,
1419 &n, &vs, &smooth)) {
1420 return;
1421 }
1422 SaveStatusStrings();
1423 SetMouseStatus(TgLoadCachedString(CSTID_DEL_A_VERTEX),
1424 TgLoadCachedString(CSTID_FINISH), TgLoadCachedString(CSTID_FINISH));
1425 TwoLineMsg(TgLoadString(STID_LEFT_BTN_TO_DEL_PTS),
1426 TgLoadString(STID_CLICK_OTHER_BUTTON_TO_QUIT));
1427
1428 if (!debugNoPointerGrab) {
1429 XGrabPointer(mainDisplay, drawWindow, False,
1430 PointerMotionMask | ButtonPressMask,
1431 GrabModeAsync, GrabModeAsync, None, defaultCursor, CurrentTime);
1432 }
1433 XQueryPointer(mainDisplay, drawWindow, &root_win, &child_win,
1434 &root_x, &root_y, &old_x, &old_y, &status);
1435 XSetFont(mainDisplay, revDefaultGC, defaultFontPtr->fid);
1436 /* do not translate -- program constants */
1437 XDrawString(mainDisplay, drawWindow, revDefaultGC,
1438 old_x+4, old_y+defaultFontAsc, "DEL", 3);
1439 MarkRulers(old_x, old_y);
1440
1441 while (deleting) {
1442 XEvent input;
1443
1444 XNextEvent(mainDisplay, &input);
1445
1446 if (input.type == Expose || input.type == VisibilityNotify) {
1447 ExposeEventHandler(&input, TRUE);
1448 } else if (input.type == ButtonPress) {
1449 if (input.xbutton.button == Button1) {
1450 int index=0;
1451
1452 if (curved == LT_STRUCT_SPLINE) {
1453 if ((poly_ptr != NULL && PtInPolyMark(obj_ptr, input.xbutton.x,
1454 input.xbutton.y, poly_ptr->ssn, poly_ptr->ssvlist,
1455 &index)) || (polygon_ptr != NULL && PtInPolyMark(obj_ptr,
1456 input.xbutton.x, input.xbutton.y, polygon_ptr->ssn-1,
1457 polygon_ptr->ssvlist, &index))) {
1458 int sel_ltx=selLtX, sel_lty=selLtY;
1459 int sel_rbx=selRbX, sel_rby=selRbY;
1460
1461 /* index is the index into ssvlist */
1462 pt_deleted = TRUE;
1463 HighLightReverse();
1464 if (DeleteStructuredSplinePoint(index, poly_ptr,
1465 polygon_ptr)) {
1466 AdjObjSplineVs(obj_ptr);
1467 if (poly_ptr != NULL) {
1468 UpdPolyBBox(obj_ptr, poly_ptr->n, poly_ptr->vlist);
1469 } else if (polygon_ptr != NULL) {
1470 UpdPolyBBox(obj_ptr, polygon_ptr->n,
1471 polygon_ptr->vlist);
1472 }
1473 AdjObjBBox(obj_ptr);
1474
1475 XDrawString(mainDisplay, drawWindow, revDefaultGC, old_x+4,
1476 old_y+defaultFontAsc, "DEL", 3);
1477 old_x = input.xbutton.x;
1478 old_y = input.xbutton.y;
1479 UpdSelBBox();
1480 RedrawAreas(botObj,
1481 sel_ltx-GRID_ABS_SIZE(1), sel_lty-GRID_ABS_SIZE(1),
1482 sel_rbx+GRID_ABS_SIZE(1), sel_rby+GRID_ABS_SIZE(1),
1483 selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1),
1484 selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1));
1485 HighLightForward();
1486 if (obj_ptr != NULL) {
1487 XDrawString(mainDisplay, drawWindow, revDefaultGC,
1488 old_x+4, old_y+defaultFontAsc, "DEL", 3);
1489 }
1490 } else {
1491 XUngrabPointer(mainDisplay, CurrentTime);
1492 Msg("");
1493 deleting = FALSE;
1494 delete_obj = TRUE;
1495 }
1496 SetFileModified(TRUE);
1497 justDupped = FALSE;
1498 }
1499 } else if ((obj_ptr->type == OBJ_POLY &&
1500 PtInPolyMark(obj_ptr, input.xbutton.x, input.xbutton.y,
1501 poly_ptr->n, poly_ptr->vlist, &index)) ||
1502 (obj_ptr->type == OBJ_POLYGON &&
1503 PtInPolyMark(obj_ptr, input.xbutton.x, input.xbutton.y,
1504 polygon_ptr->n-1, polygon_ptr->vlist, &index))) {
1505 pt_deleted = TRUE;
1506 HighLightReverse();
1507 if ((obj_ptr->type == OBJ_POLY && poly_ptr->n == 2) ||
1508 (obj_ptr->type == OBJ_POLYGON && polygon_ptr->n == 4)) {
1509 XUngrabPointer(mainDisplay, CurrentTime);
1510 Msg("");
1511 deleting = FALSE;
1512 delete_obj = TRUE;
1513 } else {
1514 int sel_ltx=selLtX, sel_lty=selLtY;
1515 int sel_rbx=selRbX, sel_rby=selRbY;
1516
1517 switch (obj_ptr->type) {
1518 case OBJ_POLY:
1519 n = poly_ptr->n;
1520 smooth = poly_ptr->smooth;
1521 for (i = index+1; i < n; i++) {
1522 poly_ptr->vlist[i-1] = poly_ptr->vlist[i];
1523 if (smooth != NULL) smooth[i-1] = smooth[i];
1524 }
1525 if (smooth != NULL) {
1526 if (index == 0) {
1527 smooth[0] = FALSE;
1528 } else if (index == n-1) {
1529 smooth[n-2] = FALSE;
1530 }
1531 }
1532 poly_ptr->n--;
1533 AdjObjSplineVs(obj_ptr);
1534 if (poly_ptr->curved != LT_INTSPLINE) {
1535 UpdPolyBBox(obj_ptr, poly_ptr->n, poly_ptr->vlist);
1536 } else {
1537 UpdPolyBBox(obj_ptr, poly_ptr->intn,
1538 poly_ptr->intvlist);
1539 }
1540 break;
1541 case OBJ_POLYGON:
1542 n = polygon_ptr->n;
1543 smooth = polygon_ptr->smooth;
1544 for (i = index+1; i < n; i++) {
1545 polygon_ptr->vlist[i-1] = polygon_ptr->vlist[i];
1546 if (smooth != NULL) smooth[i-1] = smooth[i];
1547 }
1548 polygon_ptr->n--;
1549 n--;
1550 if (index == 0) {
1551 polygon_ptr->vlist[n-1] = polygon_ptr->vlist[0];
1552 if (smooth != NULL) smooth[n-1] = smooth[0];
1553 }
1554 AdjObjSplineVs(obj_ptr);
1555 if (polygon_ptr->curved != LT_INTSPLINE) {
1556 UpdPolyBBox(obj_ptr, polygon_ptr->n,
1557 polygon_ptr->vlist);
1558 } else {
1559 UpdPolyBBox(obj_ptr, polygon_ptr->intn,
1560 polygon_ptr->intvlist);
1561 }
1562 break;
1563 }
1564 AdjObjBBox(obj_ptr);
1565
1566 XDrawString(mainDisplay, drawWindow, revDefaultGC, old_x+4,
1567 old_y+defaultFontAsc, "DEL", 3);
1568 old_x = input.xbutton.x;
1569 old_y = input.xbutton.y;
1570 UpdSelBBox();
1571 RedrawAreas(botObj,
1572 sel_ltx-GRID_ABS_SIZE(1), sel_lty-GRID_ABS_SIZE(1),
1573 sel_rbx+GRID_ABS_SIZE(1), sel_rby+GRID_ABS_SIZE(1),
1574 selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1),
1575 selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1));
1576 HighLightForward();
1577 if (obj_ptr != NULL) {
1578 XDrawString(mainDisplay, drawWindow, revDefaultGC,
1579 old_x+4, old_y+defaultFontAsc, "DEL", 3);
1580 }
1581 }
1582 SetFileModified(TRUE);
1583 justDupped = FALSE;
1584 }
1585 } else {
1586 XUngrabPointer(mainDisplay, CurrentTime);
1587 Msg("");
1588 deleting = FALSE;
1589 XDrawString(mainDisplay, drawWindow, revDefaultGC,
1590 old_x+4, old_y+defaultFontAsc, "DEL", 3);
1591 }
1592 } else if (input.type == MotionNotify &&
1593 input.xany.window == drawWindow) {
1594 XEvent ev;
1595
1596 XDrawString(mainDisplay, drawWindow, revDefaultGC,
1597 old_x+4, old_y+defaultFontAsc, "DEL", 3);
1598 old_x = input.xmotion.x;
1599 old_y = input.xmotion.y;
1600 XDrawString(mainDisplay, drawWindow, revDefaultGC,
1601 old_x+4, old_y+defaultFontAsc, "DEL", 3);
1602 MarkRulers(old_x, old_y);
1603 while (XCheckMaskEvent(mainDisplay, PointerMotionMask, &ev)) ;
1604 }
1605 }
1606 if (delete_obj) {
1607 DelObj(obj_ptr);
1608 obj_ptr = NULL;
1609 free(topSel);
1610 topSel = botSel = NULL;
1611
1612 XDrawString(mainDisplay, drawWindow, revDefaultGC, old_x+4,
1613 old_y+defaultFontAsc, "DEL", 3);
1614 RedrawAnArea(botObj,
1615 selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1),
1616 selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1));
1617 HighLightForward();
1618 UpdSelBBox();
1619 }
1620 RestoreStatusStrings();
1621 if (pt_deleted) {
1622 if (topSel == NULL) {
1623 ChangeReplaceOneCmdToDeleteCmd();
1624 } else {
1625 RecordCmd(CMD_REPLACE, NULL, topSel, botSel, numObjSelected);
1626 }
1627 } else {
1628 AbortPrepareCmd(CMD_REPLACE);
1629 }
1630 }
1631
1632 #define ADDPOINT_DRAW (FALSE)
1633 #define ADDPOINT_ERASE (TRUE)
1634 #define ADDPOINT_CLICK (FALSE)
1635 #define ADDPOINT_DRAG (TRUE)
1636
1637 #define ADDPOINT_STARTSHOW 0
1638 #define ADDPOINT_DOSHOW 1
1639 #define ADDPOINT_ENDSHOW 2
1640
1641 static
AddPointMeasureCursor(start,abs_w,abs_h,abs_x,abs_y)1642 void AddPointMeasureCursor(start, abs_w, abs_h, abs_x, abs_y)
1643 int start, abs_w, abs_h, abs_x, abs_y;
1644 {
1645 char buf[MAXSTRING], w_buf[80], h_buf[80], x_buf[80], y_buf[80];
1646
1647 PixelToMeasurementUnit(w_buf, abs_w);
1648 PixelToMeasurementUnit(h_buf, abs_h);
1649 PixelToMeasurementUnit(x_buf, abs_x);
1650 PixelToMeasurementUnit(y_buf, abs_y);
1651 /* do not translate -- program constants */
1652 sprintf(buf, "ADD: dx=%s\n dy=%s\n x=%s\n y=%s",
1653 w_buf, h_buf, x_buf, y_buf);
1654 switch (start) {
1655 case ADDPOINT_STARTSHOW:
1656 StartShowMeasureCursor(OFFSET_X(abs_x), OFFSET_Y(abs_y), buf, FALSE);
1657 break;
1658 case ADDPOINT_DOSHOW:
1659 ShowMeasureCursor(OFFSET_X(abs_x), OFFSET_Y(abs_y), buf, FALSE);
1660 break;
1661 case ADDPOINT_ENDSHOW:
1662 EndShowMeasureCursor(OFFSET_X(abs_x), OFFSET_Y(abs_y), buf, FALSE);
1663 break;
1664 }
1665 }
1666
1667 static
DetermineBefore(prev_dist,next_dist,new_prev_dist,new_next_dist)1668 int DetermineBefore(prev_dist, next_dist, new_prev_dist, new_next_dist)
1669 double prev_dist, next_dist, new_prev_dist, new_next_dist;
1670 {
1671 double prev_diff, next_diff;
1672 int before=FALSE;
1673
1674 if (new_prev_dist < prev_dist) {
1675 if (new_next_dist < next_dist) {
1676 /* got closer to both previous and next vertices */
1677 prev_diff = prev_dist-new_prev_dist;
1678 next_diff = next_dist-new_next_dist;
1679 if (prev_diff < next_diff) {
1680 before = FALSE;
1681 } else if (prev_diff > next_diff) {
1682 before = TRUE;
1683 } else {
1684 before = INVALID;
1685 }
1686 } else {
1687 /* got closer to previous vertex */
1688 before = TRUE;
1689 }
1690 } else if (new_prev_dist > prev_dist) {
1691 if (new_next_dist > next_dist) {
1692 /* got further from both previous and next vertices */
1693 prev_diff = prev_dist-new_prev_dist;
1694 next_diff = next_dist-new_next_dist;
1695 if (prev_diff < next_diff) {
1696 before = FALSE;
1697 } else if (prev_diff > next_diff) {
1698 before = TRUE;
1699 } else {
1700 before = INVALID;
1701 }
1702 } else {
1703 /* got closer to next vertex */
1704 before = FALSE;
1705 }
1706 } else {
1707 /* same distance from previous vertex */
1708 if (new_next_dist < next_dist) {
1709 before = FALSE;
1710 } else if (new_next_dist > next_dist) {
1711 before = TRUE;
1712 } else {
1713 /* same distance from both previous and next vertices */
1714 before = INVALID;
1715 }
1716 }
1717 return before;
1718 }
1719
1720 static
CanAddSmoothPointForStructuredSpline(button,psssi)1721 int CanAddSmoothPointForStructuredSpline(button, psssi)
1722 unsigned int button;
1723 StretchStructuredSplineInfo *psssi;
1724 {
1725 if (button == Button2) {
1726 if (psssi->hinge) {
1727 if (!psssi->prev_valid) {
1728 /* first point of poly */
1729 if (psssi->ipt.later_valid) {
1730 return FALSE;
1731 }
1732 } else if (!psssi->next_valid) {
1733 /* last point of poly */
1734 if (psssi->ipt.earlier_valid) {
1735 return FALSE;
1736 }
1737 } else {
1738 if (psssi->ipt.later_valid) {
1739 return FALSE;
1740 }
1741 }
1742 } else {
1743 return FALSE;
1744 }
1745 }
1746 return TRUE;
1747 }
1748
1749 typedef struct tagAddStructuredPointInfo {
1750 struct ObjRec *obj_ptr;
1751 struct PolyRec *poly_ptr;
1752 struct PolygonRec *polygon_ptr;
1753 unsigned int button;
1754 int index; /* index into ssvlist */
1755 int start_mouse_x, start_mouse_y, n, ssn, already_moved, before;
1756 IntPoint *vlist, *ssvlist, vs[5], vs2[5];
1757 char smooth[5], smooth2[5];
1758 int num_vs, num_vs2, sn, sn2, saved_sn, saved_sn2;
1759 int dx_off, dy_off, extra_smooth, extra_smooth2;
1760 XPoint *sv, *sv2, dashed_vs[2];
1761 StretchStructuredSplineInfo sssi;
1762 int prev_x, prev_y, prev_tx, prev_ty, x, y, tx, ty;
1763 int next_x, next_y, next_tx, next_ty, ruler_abs_x, ruler_abs_y;
1764 int orig_grid_x, orig_grid_y, grid_x, grid_y, mouse_x, mouse_y;
1765 int sel_ltx, sel_lty, sel_rbx, sel_rby;
1766 double prev_angle, next_angle, prev_dist, next_dist, ddx, ddy;
1767 } AddStructuredPointInfo;
1768
1769 static
ContinueAddStructuredPolyOrPolygonPointSetup(paspi)1770 int ContinueAddStructuredPolyOrPolygonPointSetup(paspi)
1771 AddStructuredPointInfo *paspi;
1772 {
1773 int i=0, tmp_x=0, tmp_y=0;
1774 IntPoint *vs=NULL, *vs2=NULL, *ssvlist=NULL;
1775 IntPoint *obj_ssvlist=NULL, *obj_vlist=NULL;
1776 char *smooth=NULL, *smooth2=NULL;
1777 struct ObjRec *obj_ptr=paspi->obj_ptr;
1778 struct PolyRec *poly_ptr=paspi->poly_ptr;
1779 struct PolygonRec *polygon_ptr=paspi->polygon_ptr;
1780
1781 if (poly_ptr != NULL) {
1782 paspi->ssn = poly_ptr->ssn;
1783 paspi->n = poly_ptr->n;
1784 obj_ssvlist = poly_ptr->ssvlist;
1785 obj_vlist = poly_ptr->vlist;
1786 } else if (polygon_ptr != NULL) {
1787 paspi->ssn = polygon_ptr->ssn;
1788 paspi->n = polygon_ptr->n;
1789 obj_ssvlist = polygon_ptr->ssvlist;
1790 obj_vlist = polygon_ptr->vlist;
1791 }
1792 paspi->ssvlist = (IntPoint*)malloc((paspi->ssn+1)*sizeof(IntPoint));
1793 if (paspi->ssvlist == NULL) FailAllocMessage();
1794 for (i=0; i < paspi->ssn; i++) {
1795 paspi->ssvlist[i].x = obj_ssvlist[i].x;
1796 paspi->ssvlist[i].y = obj_ssvlist[i].y;
1797 }
1798 if (obj_ptr->ctm != NULL) {
1799 for (i=0; i < paspi->ssn; i++) {
1800 TransformPointThroughCTM(paspi->ssvlist[i].x-obj_ptr->x,
1801 paspi->ssvlist[i].y-obj_ptr->y, paspi->obj_ptr->ctm,
1802 &tmp_x, &tmp_y);
1803 paspi->ssvlist[i].x = obj_ptr->x+tmp_x;
1804 paspi->ssvlist[i].y = obj_ptr->y+tmp_y;
1805 }
1806 }
1807 paspi->vlist = (IntPoint*)malloc((paspi->n+1)*sizeof(IntPoint));
1808 if (paspi->vlist == NULL) FailAllocMessage();
1809 for (i=0; i < paspi->n; i++) {
1810 paspi->vlist[i].x = obj_vlist[i].x;
1811 paspi->vlist[i].y = obj_vlist[i].y;
1812 }
1813 if (obj_ptr->ctm != NULL) {
1814 for (i=0; i < paspi->n; i++) {
1815 TransformPointThroughCTM(paspi->vlist[i].x-obj_ptr->x,
1816 paspi->vlist[i].y-obj_ptr->y, paspi->obj_ptr->ctm,
1817 &tmp_x, &tmp_y);
1818 paspi->vlist[i].x = obj_ptr->x+tmp_x;
1819 paspi->vlist[i].y = obj_ptr->y+tmp_y;
1820 }
1821 }
1822 if (poly_ptr != NULL) {
1823 SetIPTInfoForStretchPoly(paspi->index, paspi->n, paspi->vlist,
1824 &paspi->sssi);
1825 } else if (polygon_ptr != NULL) {
1826 SetIPTInfoForStretchPolygon(paspi->index, paspi->n, paspi->vlist,
1827 &paspi->sssi);
1828 }
1829 if (!CanAddSmoothPointForStructuredSpline(paspi->button, &paspi->sssi)) {
1830 Msg(TgLoadString(STID_CANNOT_ADD_SMOOTH_VERTEX));
1831 return FALSE;
1832 }
1833 paspi->sel_ltx = selLtX; paspi->sel_lty = selLtY;
1834 paspi->sel_rbx = selRbX; paspi->sel_rby = selRbY;
1835
1836 ssvlist = paspi->ssvlist;
1837 vs = paspi->vs;
1838 smooth = paspi->smooth;
1839 vs2 = paspi->vs2;
1840 smooth2 = paspi->smooth2;
1841 memset(smooth, 0, sizeof(5*sizeof(char)));
1842 memset(smooth2, 0, sizeof(5*sizeof(char)));
1843
1844 paspi->x = paspi->tx = ssvlist[paspi->index].x;
1845 paspi->y = paspi->ty = ssvlist[paspi->index].y;
1846 if (paspi->sssi.hinge) {
1847 /* hinge point, need to wait */
1848 } else {
1849 /* must be adding a hinge point, i.e., Button1 is clicked */
1850 if (!paspi->sssi.prev_valid) {
1851 /* first point of poly */
1852 paspi->before = FALSE;
1853
1854 paspi->num_vs = 3;
1855 vs[0].x = ssvlist[1].x; vs[0].y = ssvlist[1].y;
1856 vs[1].x = ssvlist[1].x; vs[1].y = ssvlist[1].y;
1857 vs[2].x = ssvlist[0].x; vs[2].y = ssvlist[0].y;
1858 smooth[1] = TRUE;
1859
1860 vs2[0].x = ssvlist[1].x; vs2[0].y = ssvlist[1].y;
1861 if (paspi->sssi.ipt_next.earlier_valid) {
1862 paspi->num_vs2 = 3;
1863 vs2[1].x = paspi->sssi.ipt_next.earlier_smooth_pt.x;
1864 vs2[1].y = paspi->sssi.ipt_next.earlier_smooth_pt.y;
1865 smooth2[1] = TRUE;
1866 } else {
1867 paspi->num_vs2 = 2;
1868 }
1869 vs2[paspi->num_vs2-1].x = paspi->sssi.ipt_next.hinge_pt.x;
1870 vs2[paspi->num_vs2-1].y = paspi->sssi.ipt_next.hinge_pt.y;
1871 } else if (!paspi->sssi.next_valid) {
1872 /* last point of poly */
1873 paspi->before = TRUE;
1874
1875 vs[0].x = ssvlist[paspi->ssn-2].x; vs[0].y = ssvlist[paspi->ssn-2].y;
1876 if (paspi->sssi.ipt_prev.later_valid) {
1877 paspi->num_vs = 3;
1878 vs[1].x = paspi->sssi.ipt_prev.later_smooth_pt.x;
1879 vs[1].y = paspi->sssi.ipt_prev.later_smooth_pt.y;
1880 smooth[1] = TRUE;
1881 } else {
1882 paspi->num_vs = 2;
1883 }
1884 vs[paspi->num_vs-1].x = paspi->sssi.ipt_prev.hinge_pt.x;
1885 vs[paspi->num_vs-1].y = paspi->sssi.ipt_prev.hinge_pt.y;
1886
1887 paspi->num_vs2 = 3;
1888 vs2[0].x = ssvlist[paspi->ssn-2].x; vs2[0].y = ssvlist[paspi->ssn-2].y;
1889 vs2[1].x = ssvlist[paspi->ssn-2].x; vs2[1].y = ssvlist[paspi->ssn-2].y;
1890 vs2[2].x = ssvlist[paspi->ssn-1].x; vs2[2].y = ssvlist[paspi->ssn-1].y;
1891 smooth2[1] = TRUE;
1892 } else {
1893 if (paspi->sssi.earlier_smooth_selected) {
1894 paspi->before = TRUE;
1895
1896 vs[0].x = ssvlist[paspi->index].x;
1897 vs[0].y = ssvlist[paspi->index].y;
1898 if (paspi->sssi.ipt_prev.later_valid) {
1899 paspi->num_vs = 3;
1900 vs[1].x = paspi->sssi.ipt_prev.later_smooth_pt.x;
1901 vs[1].y = paspi->sssi.ipt_prev.later_smooth_pt.y;
1902 smooth[1] = TRUE;
1903 } else {
1904 paspi->num_vs = 2;
1905 }
1906 vs[paspi->num_vs-1].x = paspi->sssi.ipt_prev.hinge_pt.x;
1907 vs[paspi->num_vs-1].y = paspi->sssi.ipt_prev.hinge_pt.y;
1908
1909 vs2[0].x = ssvlist[paspi->index].x;
1910 vs2[0].y = ssvlist[paspi->index].y;
1911 vs2[1].x = paspi->sssi.ipt.earlier_smooth_pt.x;
1912 vs2[1].y = paspi->sssi.ipt.earlier_smooth_pt.y;
1913 vs2[2].x = paspi->sssi.ipt.hinge_pt.x;
1914 vs2[2].y = paspi->sssi.ipt.hinge_pt.y;
1915 smooth2[1] = TRUE;
1916 paspi->num_vs2 = 3;
1917 } else {
1918 paspi->before = FALSE;
1919
1920 vs[0].x = ssvlist[paspi->index].x;
1921 vs[0].y = ssvlist[paspi->index].y;
1922 vs[1].x = paspi->sssi.ipt.later_smooth_pt.x;
1923 vs[1].y = paspi->sssi.ipt.later_smooth_pt.y;
1924 vs[2].x = paspi->sssi.ipt.hinge_pt.x;
1925 vs[2].y = paspi->sssi.ipt.hinge_pt.y;
1926 smooth[1] = TRUE;
1927 paspi->num_vs = 3;
1928
1929 vs2[0].x = ssvlist[paspi->index].x;
1930 vs2[0].y = ssvlist[paspi->index].y;
1931 if (paspi->sssi.ipt_next.earlier_valid) {
1932 paspi->num_vs2 = 3;
1933 vs2[1].x = paspi->sssi.ipt_next.earlier_smooth_pt.x;
1934 vs2[1].y = paspi->sssi.ipt_next.earlier_smooth_pt.y;
1935 smooth2[1] = TRUE;
1936 } else {
1937 paspi->num_vs2 = 2;
1938 }
1939 vs2[paspi->num_vs2-1].x = paspi->sssi.ipt_next.hinge_pt.x;
1940 vs2[paspi->num_vs2-1].y = paspi->sssi.ipt_next.hinge_pt.y;
1941 }
1942 }
1943 paspi->already_moved = TRUE;
1944 paspi->sv = MakeMultiSplinePolyVertex(LT_STRUCT_SPLINE, &paspi->sn,
1945 paspi->smooth, drawOrigX, drawOrigY, paspi->num_vs, vs);
1946 paspi->sv2 = MakeMultiSplinePolyVertex(LT_STRUCT_SPLINE, &paspi->sn2,
1947 paspi->smooth2, drawOrigX, drawOrigY, paspi->num_vs2, vs2);
1948 XDrawLines(mainDisplay, drawWindow, revDefaultGC, paspi->sv, paspi->sn,
1949 CoordModeOrigin);
1950 XDrawLines(mainDisplay, drawWindow, revDefaultGC, paspi->sv2, paspi->sn2,
1951 CoordModeOrigin);
1952
1953 GridXY(paspi->start_mouse_x, paspi->start_mouse_y,
1954 &paspi->orig_grid_x, &paspi->orig_grid_y);
1955 paspi->grid_x = paspi->orig_grid_x;
1956 paspi->grid_y = paspi->orig_grid_y;
1957 paspi->mouse_x = paspi->start_mouse_x;
1958 paspi->mouse_y = paspi->start_mouse_y;
1959 paspi->ruler_abs_x = paspi->tx;
1960 paspi->ruler_abs_y = paspi->ty;
1961
1962 MARKHR(drawWindow, revDefaultGC, OFFSET_X(paspi->ruler_abs_x),
1963 OFFSET_Y(paspi->ruler_abs_y));
1964 AddPointMeasureCursor(ADDPOINT_STARTSHOW, 0, 0, paspi->tx, paspi->ty);
1965
1966 return TRUE;
1967 }
1968 if (paspi->index == 0) {
1969 paspi->next_x = paspi->next_tx = paspi->ssvlist[1].x;
1970 paspi->next_y = paspi->next_ty = paspi->ssvlist[1].y;
1971 paspi->prev_x = paspi->prev_tx = (paspi->x<<1)-paspi->next_x;
1972 paspi->prev_y = paspi->prev_ty = (paspi->y<<1)-paspi->next_y;
1973 } else if (paspi->index == paspi->n-1) {
1974 paspi->prev_x = paspi->prev_tx = paspi->ssvlist[paspi->n-2].x;
1975 paspi->prev_y = paspi->prev_ty = paspi->ssvlist[paspi->n-2].y;
1976 paspi->next_x = paspi->next_tx = (paspi->x<<1)-paspi->prev_x;
1977 paspi->next_y = paspi->next_ty = (paspi->y<<1)-paspi->prev_y;
1978 } else {
1979 paspi->prev_x = paspi->prev_tx = ssvlist[paspi->index-1].x;
1980 paspi->prev_y = paspi->prev_ty = ssvlist[paspi->index-1].y;
1981 paspi->next_x = paspi->next_tx = ssvlist[paspi->index+1].x;
1982 paspi->next_y = paspi->next_ty = ssvlist[paspi->index+1].y;
1983 }
1984 paspi->ddx = (double)(paspi->prev_tx - paspi->tx);
1985 paspi->ddy = (double)(paspi->prev_ty - paspi->ty);
1986 paspi->prev_dist = paspi->ddx*paspi->ddx+paspi->ddy*paspi->ddy;
1987 paspi->ddx = (double)(paspi->next_tx - paspi->tx);
1988 paspi->ddy = (double)(paspi->next_ty - paspi->ty);
1989 paspi->next_dist = paspi->ddx*paspi->ddx+paspi->ddy*paspi->ddy;
1990
1991 paspi->prev_angle = (paspi->prev_tx==paspi->tx) ?
1992 ((paspi->prev_ty>=paspi->ty) ? M_PI/2.0 : -M_PI/2.0) :
1993 atan2((double)(paspi->prev_ty-paspi->ty),
1994 (double)(paspi->prev_tx-paspi->tx));
1995 paspi->next_angle = (paspi->next_tx==paspi->tx) ?
1996 ((paspi->next_ty>=paspi->ty) ? M_PI/2.0 : -M_PI/2.0) :
1997 atan2((double)(paspi->next_ty-paspi->ty),
1998 (double)(paspi->next_tx-paspi->tx));
1999 GridXY(paspi->start_mouse_x, paspi->start_mouse_y,
2000 &paspi->orig_grid_x, &paspi->orig_grid_y);
2001 paspi->grid_x = paspi->orig_grid_x;
2002 paspi->grid_y = paspi->orig_grid_y;
2003 paspi->mouse_x = paspi->start_mouse_x;
2004 paspi->mouse_y = paspi->start_mouse_y;
2005
2006 AddPointMeasureCursor(ADDPOINT_STARTSHOW, 0, 0, paspi->tx, paspi->ty);
2007
2008 return TRUE;
2009 }
2010
2011 static
ContinueAddStructuredPolyOrPolygonPointFirstMoved(paspi)2012 void ContinueAddStructuredPolyOrPolygonPointFirstMoved(paspi)
2013 AddStructuredPointInfo *paspi;
2014 {
2015 double new_prev_dist=(double)0, new_next_dist=(double)0;
2016 int new_x=paspi->ruler_abs_x, new_y=paspi->ruler_abs_y;
2017
2018 paspi->already_moved = TRUE;
2019
2020 paspi->ddx = (double)(paspi->prev_tx - paspi->mouse_x);
2021 paspi->ddy = (double)(paspi->prev_ty - paspi->mouse_y);
2022 new_prev_dist = paspi->ddx*paspi->ddx+paspi->ddy*paspi->ddy;
2023 paspi->ddx = (double)(paspi->next_tx - paspi->mouse_x);
2024 paspi->ddy = (double)(paspi->next_ty - paspi->mouse_y);
2025 new_next_dist = paspi->ddx*paspi->ddx+paspi->ddy*paspi->ddy;
2026
2027 paspi->before = DetermineBefore(paspi->prev_dist, paspi->next_dist,
2028 new_prev_dist, new_next_dist);
2029 if (paspi->before == INVALID) {
2030 double new_angle=(double)0, theta_1=(double)0, theta_2=(double)0;
2031
2032 new_angle = (new_x==paspi->tx) ? ((new_y>=paspi->ty) ?
2033 M_PI/2.0 : -M_PI/2.0) : atan2((double)(new_y-paspi->ty),
2034 (double)(new_x-paspi->tx));
2035 theta_1 = fabs(paspi->prev_angle - new_angle);
2036 theta_2 = fabs(paspi->next_angle - new_angle);
2037 if (theta_1 > M_PI) theta_1 = 2*M_PI-theta_1;
2038 if (theta_2 > M_PI) theta_2 = 2*M_PI-theta_2;
2039 paspi->before = (theta_1 <= theta_2);
2040 }
2041 #ifdef _TGIF_DBG /* debug, do not translate */
2042 TgAssert(paspi->sssi.hinge,
2043 "paspi->sssi.hinge is FALSE in ContinueAddStructuredPolyOrPolygonPointFirstMoved()", NULL);
2044 #endif /* _TGIF_DBG */
2045 if (paspi->button == Button1) {
2046 IntPoint *vs=paspi->vs, *vs2=paspi->vs2;
2047 char *smooth=paspi->smooth, *smooth2=paspi->smooth2;
2048
2049 memset(smooth, 0, sizeof(5*sizeof(char)));
2050 memset(smooth2, 0, sizeof(5*sizeof(char)));
2051
2052 if (paspi->before) {
2053 /* Add a point between the current and the previous point */
2054 if (!paspi->sssi.prev_valid) {
2055 /* first point of poly */
2056 paspi->num_vs = 0;
2057
2058 vs2[0].x = new_x;
2059 vs2[0].y = new_y;
2060 if (paspi->sssi.ipt.later_valid) {
2061 paspi->num_vs2 = 3;
2062 vs2[1].x = (paspi->sssi.ipt.hinge_pt.x<<1) -
2063 paspi->sssi.ipt.later_smooth_pt.x;
2064 vs2[1].y = (paspi->sssi.ipt.hinge_pt.y<<1) -
2065 paspi->sssi.ipt.later_smooth_pt.y;
2066 smooth2[1] = TRUE;
2067 paspi->extra_smooth2 = TRUE;
2068 MARKHO(drawWindow, revDefaultGC, OFFSET_X(vs2[1].x),
2069 OFFSET_Y(vs2[1].y));
2070 } else {
2071 paspi->num_vs2 = 2;
2072 }
2073 vs2[paspi->num_vs2-1].x = paspi->sssi.ipt.hinge_pt.x;
2074 vs2[paspi->num_vs2-1].y = paspi->sssi.ipt.hinge_pt.y;
2075 } else if (!paspi->sssi.next_valid) {
2076 /* last point of poly */
2077 vs[0].x = new_x;
2078 vs[0].y = new_y;
2079 if (paspi->sssi.ipt.earlier_valid) {
2080 paspi->num_vs = 3;
2081 vs[1].x = paspi->sssi.ipt.earlier_smooth_pt.x;
2082 vs[1].y = paspi->sssi.ipt.earlier_smooth_pt.y;
2083 smooth[1] = TRUE;
2084 } else {
2085 paspi->num_vs = 2;
2086 }
2087 vs[paspi->num_vs-1].x = paspi->sssi.ipt.hinge_pt.x;
2088 vs[paspi->num_vs-1].y = paspi->sssi.ipt.hinge_pt.y;
2089
2090 vs2[0].x = new_x;
2091 vs2[0].y = new_y;
2092 if (paspi->sssi.ipt_prev.later_valid) {
2093 paspi->num_vs2 = 3;
2094 vs2[1].x = paspi->sssi.ipt_prev.later_smooth_pt.x;
2095 vs2[1].y = paspi->sssi.ipt_prev.later_smooth_pt.y;
2096 smooth2[1] = TRUE;
2097 } else {
2098 paspi->num_vs2 = 2;
2099 }
2100 vs2[paspi->num_vs2-1].x = paspi->sssi.ipt_prev.hinge_pt.x;
2101 vs2[paspi->num_vs2-1].y = paspi->sssi.ipt_prev.hinge_pt.y;
2102 } else {
2103 vs[0].x = new_x;
2104 vs[0].y = new_y;
2105 if (paspi->sssi.ipt_prev.later_valid) {
2106 paspi->num_vs = 3;
2107 vs[1].x = paspi->sssi.ipt_prev.later_smooth_pt.x;
2108 vs[1].y = paspi->sssi.ipt_prev.later_smooth_pt.y;
2109 smooth[1] = TRUE;
2110 } else {
2111 paspi->num_vs = 2;
2112 }
2113 vs[paspi->num_vs-1].x = paspi->sssi.ipt_prev.hinge_pt.x;
2114 vs[paspi->num_vs-1].y = paspi->sssi.ipt_prev.hinge_pt.y;
2115
2116 vs2[0].x = new_x;
2117 vs2[0].y = new_y;
2118 if (paspi->sssi.ipt.earlier_valid) {
2119 paspi->num_vs2 = 3;
2120 vs2[1].x = paspi->sssi.ipt.earlier_smooth_pt.x;
2121 vs2[1].y = paspi->sssi.ipt.earlier_smooth_pt.y;
2122 smooth2[1] = TRUE;
2123 } else {
2124 paspi->num_vs2 = 2;
2125 }
2126 vs2[paspi->num_vs2-1].x = paspi->sssi.ipt.hinge_pt.x;
2127 vs2[paspi->num_vs2-1].y = paspi->sssi.ipt.hinge_pt.y;
2128 }
2129 } else {
2130 /* Add a point between the current and the next point */
2131 if (!paspi->sssi.prev_valid) {
2132 /* first point of poly */
2133 vs[0].x = new_x;
2134 vs[0].y = new_y;
2135 if (paspi->sssi.ipt.later_valid) {
2136 paspi->num_vs = 3;
2137 vs[1].x = paspi->sssi.ipt.later_smooth_pt.x;
2138 vs[1].y = paspi->sssi.ipt.later_smooth_pt.y;
2139 smooth[1] = TRUE;
2140 } else {
2141 paspi->num_vs = 2;
2142 }
2143 vs[paspi->num_vs-1].x = paspi->sssi.ipt.hinge_pt.x;
2144 vs[paspi->num_vs-1].y = paspi->sssi.ipt.hinge_pt.y;
2145
2146 vs2[0].x = new_x;
2147 vs2[0].y = new_y;
2148 if (paspi->sssi.ipt_next.earlier_valid) {
2149 paspi->num_vs2 = 3;
2150 vs2[1].x = paspi->sssi.ipt_next.earlier_smooth_pt.x;
2151 vs2[1].y = paspi->sssi.ipt_next.earlier_smooth_pt.y;
2152 smooth2[1] = TRUE;
2153 } else {
2154 paspi->num_vs2 = 2;
2155 }
2156 vs2[paspi->num_vs2-1].x = paspi->sssi.ipt_next.hinge_pt.x;
2157 vs2[paspi->num_vs2-1].y = paspi->sssi.ipt_next.hinge_pt.y;
2158 } else if (!paspi->sssi.next_valid) {
2159 /* last point of poly */
2160 vs[0].x = new_x;
2161 vs[0].y = new_y;
2162 if (paspi->sssi.ipt.earlier_valid) {
2163 paspi->num_vs = 3;
2164 vs[1].x = (paspi->sssi.ipt.hinge_pt.x<<1) -
2165 paspi->sssi.ipt.earlier_smooth_pt.x;
2166 vs[1].y = (paspi->sssi.ipt.hinge_pt.y<<1) -
2167 paspi->sssi.ipt.earlier_smooth_pt.y;
2168 smooth[1] = TRUE;
2169 paspi->extra_smooth = TRUE;
2170 MARKHO(drawWindow, revDefaultGC, OFFSET_X(vs[1].x),
2171 OFFSET_Y(vs[1].y));
2172 } else {
2173 paspi->num_vs = 2;
2174 }
2175 vs[paspi->num_vs-1].x = paspi->sssi.ipt.hinge_pt.x;
2176 vs[paspi->num_vs-1].y = paspi->sssi.ipt.hinge_pt.y;
2177
2178 paspi->num_vs2 = 0;
2179 } else {
2180 vs[0].x = new_x;
2181 vs[0].y = new_y;
2182 if (paspi->sssi.ipt.later_valid) {
2183 paspi->num_vs = 3;
2184 vs[1].x = paspi->sssi.ipt.later_smooth_pt.x;
2185 vs[1].y = paspi->sssi.ipt.later_smooth_pt.y;
2186 smooth[1] = TRUE;
2187 } else {
2188 paspi->num_vs = 2;
2189 }
2190 vs[paspi->num_vs-1].x = paspi->sssi.ipt.hinge_pt.x;
2191 vs[paspi->num_vs-1].y = paspi->sssi.ipt.hinge_pt.y;
2192
2193 vs2[0].x = new_x;
2194 vs2[0].y = new_y;
2195 if (paspi->sssi.ipt_next.earlier_valid) {
2196 paspi->num_vs2 = 3;
2197 vs2[1].x = paspi->sssi.ipt_next.earlier_smooth_pt.x;
2198 vs2[1].y = paspi->sssi.ipt_next.earlier_smooth_pt.y;
2199 smooth2[1] = TRUE;
2200 } else {
2201 paspi->num_vs2 = 2;
2202 }
2203 vs2[paspi->num_vs2-1].x = paspi->sssi.ipt_next.hinge_pt.x;
2204 vs2[paspi->num_vs2-1].y = paspi->sssi.ipt_next.hinge_pt.y;
2205 }
2206 }
2207 } else {
2208 IntPoint *vs=paspi->vs, *vs2=paspi->vs2;
2209 char *smooth=paspi->smooth, *smooth2=paspi->smooth2;
2210
2211 memset(smooth, 0, sizeof(5*sizeof(char)));
2212 memset(smooth2, 0, sizeof(5*sizeof(char)));
2213
2214 if (!paspi->sssi.prev_valid) {
2215 /* first point of poly */
2216 paspi->num_vs = 0;
2217
2218 vs2[0].x = paspi->sssi.ipt.hinge_pt.x;
2219 vs2[0].y = paspi->sssi.ipt.hinge_pt.y;
2220 vs2[1].x = new_x;
2221 vs2[1].y = new_y;
2222 smooth2[1] = TRUE;
2223 if (paspi->sssi.ipt_next.earlier_valid) {
2224 paspi->num_vs2 = 4;
2225 vs2[2].x = paspi->sssi.ipt_next.earlier_smooth_pt.x;
2226 vs2[2].y = paspi->sssi.ipt_next.earlier_smooth_pt.y;
2227 smooth2[2] = TRUE;
2228 } else {
2229 paspi->num_vs2 = 3;
2230 }
2231 vs2[paspi->num_vs2-1].x = paspi->sssi.ipt_next.hinge_pt.x;
2232 vs2[paspi->num_vs2-1].y = paspi->sssi.ipt_next.hinge_pt.y;
2233 } else if (!paspi->sssi.next_valid) {
2234 /* last point of poly */
2235 vs[0].x = paspi->sssi.ipt.hinge_pt.x;
2236 vs[0].y = paspi->sssi.ipt.hinge_pt.y;
2237 vs[1].x = new_x;
2238 vs[1].y = new_y;
2239 smooth[1] = TRUE;
2240 if (paspi->sssi.ipt_prev.later_valid) {
2241 paspi->num_vs = 4;
2242 vs[2].x = paspi->sssi.ipt_prev.later_smooth_pt.x;
2243 vs[2].y = paspi->sssi.ipt_prev.later_smooth_pt.y;
2244 smooth[2] = TRUE;
2245 } else {
2246 paspi->num_vs = 3;
2247 }
2248 vs[paspi->num_vs-1].x = paspi->sssi.ipt_prev.hinge_pt.x;
2249 vs[paspi->num_vs-1].y = paspi->sssi.ipt_prev.hinge_pt.y;
2250
2251 paspi->num_vs2 = 0;
2252 } else {
2253 int new_x_prime=(paspi->sssi.ipt.hinge_pt.x<<1)-new_x;
2254 int new_y_prime=(paspi->sssi.ipt.hinge_pt.y<<1)-new_y;
2255
2256 vs[0].x = paspi->sssi.ipt.hinge_pt.x;
2257 vs[0].y = paspi->sssi.ipt.hinge_pt.y;
2258 if (paspi->before) {
2259 vs[1].x = new_x;
2260 vs[1].y = new_y;
2261 } else {
2262 vs[1].x = new_x_prime;
2263 vs[1].y = new_y_prime;
2264 }
2265 smooth[1] = TRUE;
2266 if (paspi->sssi.ipt_prev.later_valid) {
2267 paspi->num_vs = 4;
2268 vs[2].x = paspi->sssi.ipt_prev.later_smooth_pt.x;
2269 vs[2].y = paspi->sssi.ipt_prev.later_smooth_pt.y;
2270 smooth[2] = TRUE;
2271 } else {
2272 paspi->num_vs = 3;
2273 }
2274 vs[paspi->num_vs-1].x = paspi->sssi.ipt_prev.hinge_pt.x;
2275 vs[paspi->num_vs-1].y = paspi->sssi.ipt_prev.hinge_pt.y;
2276
2277 vs2[0].x = paspi->sssi.ipt.hinge_pt.x;
2278 vs2[0].y = paspi->sssi.ipt.hinge_pt.y;
2279 if (paspi->before) {
2280 vs2[1].x = new_x_prime;
2281 vs2[1].y = new_y_prime;
2282 } else {
2283 vs2[1].x = new_x;
2284 vs2[1].y = new_y;
2285 }
2286 smooth2[1] = TRUE;
2287 if (paspi->sssi.ipt_next.earlier_valid) {
2288 paspi->num_vs2 = 4;
2289 vs2[2].x = paspi->sssi.ipt_next.earlier_smooth_pt.x;
2290 vs2[2].y = paspi->sssi.ipt_next.earlier_smooth_pt.y;
2291 smooth2[2] = TRUE;
2292 } else {
2293 paspi->num_vs2 = 3;
2294 }
2295 vs2[paspi->num_vs2-1].x = paspi->sssi.ipt_next.hinge_pt.x;
2296 vs2[paspi->num_vs2-1].y = paspi->sssi.ipt_next.hinge_pt.y;
2297 }
2298 }
2299 }
2300
2301 static
ContinueAddStructuredPolyOrPolygonPointRestMoved(paspi)2302 void ContinueAddStructuredPolyOrPolygonPointRestMoved(paspi)
2303 AddStructuredPointInfo *paspi;
2304 {
2305 if (paspi->button == Button1) {
2306 MARKHR(drawWindow, revDefaultGC, OFFSET_X(paspi->ruler_abs_x),
2307 OFFSET_Y(paspi->ruler_abs_y));
2308 paspi->vs[0].x = paspi->vs2[0].x = paspi->ruler_abs_x;
2309 paspi->vs[0].y = paspi->vs2[0].y = paspi->ruler_abs_y;
2310 } else {
2311 XGCValues values;
2312
2313 XSetDashes(mainDisplay, revDefaultGC, 0, dashList[8], dashListLength[8]);
2314 if (!paspi->sssi.prev_valid) {
2315 /* first point of poly */
2316 paspi->vs2[1].x = paspi->ruler_abs_x;
2317 paspi->vs2[1].y = paspi->ruler_abs_y;
2318 paspi->dashed_vs[0].x = OFFSET_X(paspi->vs2[1].x);
2319 paspi->dashed_vs[0].y = OFFSET_Y(paspi->vs2[1].y);
2320 paspi->dashed_vs[1].x = OFFSET_X(paspi->vs2[0].x);
2321 paspi->dashed_vs[1].y = OFFSET_Y(paspi->vs2[0].y);
2322 MARKHO(drawWindow, revDefaultGC, paspi->dashed_vs[0].x,
2323 paspi->dashed_vs[0].y);
2324
2325 values.line_style = LineOnOffDash;
2326 XChangeGC(mainDisplay, revDefaultGC, GCLineStyle, &values);
2327 MyDashedLine(drawWindow, revDefaultGC, paspi->dashed_vs, 2);
2328 values.line_style = LineSolid;
2329 XChangeGC(mainDisplay, revDefaultGC, GCLineStyle, &values);
2330 } else if (!paspi->sssi.next_valid) {
2331 /* last point of poly */
2332 paspi->vs[1].x = paspi->ruler_abs_x;
2333 paspi->vs[1].y = paspi->ruler_abs_y;
2334 paspi->dashed_vs[0].x = OFFSET_X(paspi->vs[1].x);
2335 paspi->dashed_vs[0].y = OFFSET_Y(paspi->vs[1].y);
2336 paspi->dashed_vs[1].x = OFFSET_X(paspi->vs[0].x);
2337 paspi->dashed_vs[1].y = OFFSET_Y(paspi->vs[0].y);
2338 MARKHO(drawWindow, revDefaultGC, paspi->dashed_vs[0].x,
2339 paspi->dashed_vs[0].y);
2340
2341 values.line_style = LineOnOffDash;
2342 XChangeGC(mainDisplay, revDefaultGC, GCLineStyle, &values);
2343 MyDashedLine(drawWindow, revDefaultGC, paspi->dashed_vs, 2);
2344 values.line_style = LineSolid;
2345 XChangeGC(mainDisplay, revDefaultGC, GCLineStyle, &values);
2346 } else {
2347 if (paspi->before) {
2348 paspi->vs[1].x = paspi->ruler_abs_x;
2349 paspi->vs[1].y = paspi->ruler_abs_y;
2350 paspi->vs2[1].x = (paspi->vs[0].x<<1) - paspi->ruler_abs_x;
2351 paspi->vs2[1].y = (paspi->vs[0].y<<1) - paspi->ruler_abs_y;
2352 paspi->dashed_vs[0].x = OFFSET_X(paspi->vs[1].x);
2353 paspi->dashed_vs[0].y = OFFSET_Y(paspi->vs[1].y);
2354 paspi->dashed_vs[1].x = OFFSET_X(paspi->vs2[1].x);
2355 paspi->dashed_vs[1].y = OFFSET_Y(paspi->vs2[1].y);
2356 MARKHO(drawWindow, revDefaultGC, paspi->dashed_vs[0].x,
2357 paspi->dashed_vs[0].y);
2358 MARKHO(drawWindow, revDefaultGC, paspi->dashed_vs[1].x,
2359 paspi->dashed_vs[1].y);
2360
2361 values.line_style = LineOnOffDash;
2362 XChangeGC(mainDisplay, revDefaultGC, GCLineStyle, &values);
2363 MyDashedLine(drawWindow, revDefaultGC, paspi->dashed_vs, 2);
2364 values.line_style = LineSolid;
2365 XChangeGC(mainDisplay, revDefaultGC, GCLineStyle, &values);
2366 } else {
2367 paspi->vs2[1].x = paspi->ruler_abs_x;
2368 paspi->vs2[1].y = paspi->ruler_abs_y;
2369 paspi->vs[1].x = (paspi->vs2[0].x<<1) - paspi->ruler_abs_x;
2370 paspi->vs[1].y = (paspi->vs2[0].y<<1) - paspi->ruler_abs_y;
2371 paspi->dashed_vs[0].x = OFFSET_X(paspi->vs2[1].x);
2372 paspi->dashed_vs[0].y = OFFSET_Y(paspi->vs2[1].y);
2373 paspi->dashed_vs[1].x = OFFSET_X(paspi->vs[1].x);
2374 paspi->dashed_vs[1].y = OFFSET_Y(paspi->vs[1].y);
2375 MARKHO(drawWindow, revDefaultGC, paspi->dashed_vs[0].x,
2376 paspi->dashed_vs[0].y);
2377 MARKHO(drawWindow, revDefaultGC, paspi->dashed_vs[1].x,
2378 paspi->dashed_vs[1].y);
2379
2380 values.line_style = LineOnOffDash;
2381 XChangeGC(mainDisplay, revDefaultGC, GCLineStyle, &values);
2382 MyDashedLine(drawWindow, revDefaultGC, paspi->dashed_vs, 2);
2383 values.line_style = LineSolid;
2384 XChangeGC(mainDisplay, revDefaultGC, GCLineStyle, &values);
2385 }
2386 }
2387 }
2388 if (paspi->num_vs > 0) {
2389 paspi->sv = MakeMultiSplinePolyVertex(LT_STRUCT_SPLINE, &paspi->sn,
2390 paspi->smooth, drawOrigX, drawOrigY, paspi->num_vs, paspi->vs);
2391 XDrawLines(mainDisplay, drawWindow, revDefaultGC, paspi->sv, paspi->sn,
2392 CoordModeOrigin);
2393 }
2394 if (paspi->num_vs2 > 0) {
2395 paspi->sv2 = MakeMultiSplinePolyVertex(LT_STRUCT_SPLINE, &paspi->sn2,
2396 paspi->smooth2, drawOrigX, drawOrigY, paspi->num_vs2, paspi->vs2);
2397 XDrawLines(mainDisplay, drawWindow, revDefaultGC, paspi->sv2, paspi->sn2,
2398 CoordModeOrigin);
2399 }
2400 MarkRulers(OFFSET_X(paspi->ruler_abs_x), OFFSET_Y(paspi->ruler_abs_y));
2401 AddPointMeasureCursor(ADDPOINT_DOSHOW, ABS_SIZE(paspi->dx_off),
2402 ABS_SIZE(paspi->dy_off), paspi->ruler_abs_x, paspi->ruler_abs_y);
2403 }
2404
2405 static
ContinueAddStructuredPolyOrPolygonPointFinished(paspi)2406 int ContinueAddStructuredPolyOrPolygonPointFinished(paspi)
2407 AddStructuredPointInfo *paspi;
2408 {
2409 int i=0, tmp_x=0, tmp_y=0, new_abs_x=0, new_abs_y=0, orig_hinge_index=0;
2410 int ok=TRUE;
2411 IntPoint *obj_vlist=NULL;
2412 struct ObjRec *obj_ptr=paspi->obj_ptr;
2413 struct PolyRec *poly_ptr=paspi->poly_ptr;
2414 struct PolygonRec *polygon_ptr=paspi->polygon_ptr;
2415
2416 if (paspi->extra_smooth) {
2417 MARKHO(drawWindow, revDefaultGC, OFFSET_X(paspi->vs[1].x),
2418 OFFSET_Y(paspi->vs[1].y));
2419 }
2420 if (paspi->extra_smooth2) {
2421 MARKHO(drawWindow, revDefaultGC, OFFSET_X(paspi->vs2[1].x),
2422 OFFSET_Y(paspi->vs2[1].y));
2423 }
2424 if (!paspi->already_moved) {
2425 ok = FALSE;
2426 } else {
2427 if (paspi->ruler_abs_x == paspi->sssi.ipt.hinge_pt.x &&
2428 paspi->ruler_abs_y == paspi->sssi.ipt.hinge_pt.y) {
2429 ok = FALSE;
2430 }
2431 if (paspi->before) {
2432 if (paspi->ruler_abs_x == paspi->sssi.ipt_prev.hinge_pt.x &&
2433 paspi->ruler_abs_y == paspi->sssi.ipt_prev.hinge_pt.y) {
2434 ok = FALSE;
2435 }
2436 } else {
2437 if (paspi->ruler_abs_x == paspi->sssi.ipt_next.hinge_pt.x &&
2438 paspi->ruler_abs_y == paspi->sssi.ipt_next.hinge_pt.y) {
2439 ok = FALSE;
2440 }
2441 }
2442 }
2443 if (!ok) {
2444 free(paspi->ssvlist);
2445 free(paspi->vlist);
2446
2447 return FALSE;
2448 }
2449 if (poly_ptr != NULL) {
2450 obj_vlist = poly_ptr->vlist;
2451 } else if (polygon_ptr != NULL) {
2452 obj_vlist = polygon_ptr->vlist;
2453 }
2454 HighLightReverse();
2455 if (paspi->button == Button1) {
2456 /* add a hinge point */
2457 IntPoint *new_vlist=(IntPoint*)malloc((paspi->n+4)*sizeof(IntPoint));
2458
2459 if (new_vlist == NULL) FailAllocMessage();
2460 memset(new_vlist, 0, (paspi->n+4)*sizeof(IntPoint));
2461 obj_ptr = paspi->obj_ptr;
2462 new_abs_x = paspi->ruler_abs_x;
2463 new_abs_y = paspi->ruler_abs_y;
2464 if (obj_ptr->ctm != NULL) {
2465 ReverseTransformPointThroughCTM(new_abs_x-obj_ptr->x,
2466 new_abs_y-obj_ptr->y, obj_ptr->ctm, &tmp_x, &tmp_y);
2467 new_abs_x = obj_ptr->x+tmp_x;
2468 new_abs_y = obj_ptr->y+tmp_y;
2469 }
2470 if (paspi->before) {
2471 if (!paspi->sssi.prev_valid) {
2472 /* first point of poly */
2473 new_vlist[0].x = new_vlist[1].x = new_abs_x;
2474 new_vlist[0].y = new_vlist[1].y = new_abs_y;
2475 if (paspi->sssi.ipt.later_valid) {
2476 new_vlist[2].x = (obj_vlist[0].x<<1) -
2477 obj_vlist[1].x;
2478 new_vlist[2].y = (obj_vlist[0].y<<1) -
2479 obj_vlist[1].y;
2480 } else {
2481 new_vlist[2].x = obj_vlist[0].x;
2482 new_vlist[2].y = obj_vlist[0].y;
2483 }
2484 for (i=0; i < paspi->n; i++) {
2485 new_vlist[i+3].x = obj_vlist[i].x;
2486 new_vlist[i+3].y = obj_vlist[i].y;
2487 }
2488 } else if (!paspi->sssi.next_valid) {
2489 /* last point of poly */
2490 for (i=0; i < paspi->n-2; i++) {
2491 new_vlist[i].x = obj_vlist[i].x;
2492 new_vlist[i].y = obj_vlist[i].y;
2493 }
2494 new_vlist[paspi->n-2].x = new_vlist[paspi->n-1].x =
2495 new_vlist[paspi->n].x = new_abs_x;
2496 new_vlist[paspi->n-2].y = new_vlist[paspi->n-1].y =
2497 new_vlist[paspi->n].y = new_abs_y;
2498 new_vlist[paspi->n+1].x = obj_vlist[paspi->n-2].x;
2499 new_vlist[paspi->n+1].y = obj_vlist[paspi->n-2].y;
2500 new_vlist[paspi->n+2].x = obj_vlist[paspi->n-1].x;
2501 new_vlist[paspi->n+2].y = obj_vlist[paspi->n-1].y;
2502 } else {
2503 orig_hinge_index = paspi->sssi.orig_hinge_index;
2504 if (polygon_ptr != NULL && orig_hinge_index == 0) {
2505 orig_hinge_index = polygon_ptr->n-1;
2506 }
2507 for (i=0; i < orig_hinge_index-1; i++) {
2508 new_vlist[i].x = obj_vlist[i].x;
2509 new_vlist[i].y = obj_vlist[i].y;
2510 }
2511 new_vlist[orig_hinge_index-1].x = new_vlist[orig_hinge_index].x =
2512 new_vlist[orig_hinge_index+1].x = new_abs_x;
2513 new_vlist[orig_hinge_index-1].y = new_vlist[orig_hinge_index].y =
2514 new_vlist[orig_hinge_index+1].y = new_abs_y;
2515 for (i=orig_hinge_index-1; i < paspi->n; i++) {
2516 new_vlist[i+3].x = obj_vlist[i].x;
2517 new_vlist[i+3].y = obj_vlist[i].y;
2518 }
2519 }
2520 } else {
2521 if (!paspi->sssi.prev_valid) {
2522 /* first point of poly */
2523 for (i=0; i < 2; i++) {
2524 new_vlist[i].x = obj_vlist[i].x;
2525 new_vlist[i].y = obj_vlist[i].y;
2526 }
2527 new_vlist[2].x = new_vlist[3].x = new_vlist[4].x = new_abs_x;
2528 new_vlist[2].y = new_vlist[3].y = new_vlist[4].y = new_abs_y;
2529 for (i=2; i < paspi->n; i++) {
2530 new_vlist[i+3].x = obj_vlist[i].x;
2531 new_vlist[i+3].y = obj_vlist[i].y;
2532 }
2533 } else if (!paspi->sssi.next_valid) {
2534 /* last point of poly */
2535 for (i=0; i < paspi->n; i++) {
2536 new_vlist[i].x = obj_vlist[i].x;
2537 new_vlist[i].y = obj_vlist[i].y;
2538 }
2539 if (paspi->sssi.ipt.earlier_valid) {
2540 new_vlist[paspi->n].x =
2541 (obj_vlist[paspi->n-1].x<<1) -
2542 obj_vlist[paspi->n-2].x;
2543 new_vlist[paspi->n].y =
2544 (obj_vlist[paspi->n-1].y<<1) -
2545 obj_vlist[paspi->n-2].y;
2546 } else {
2547 new_vlist[paspi->n].x = obj_vlist[paspi->n-1].x;
2548 new_vlist[paspi->n].y = obj_vlist[paspi->n-1].y;
2549 }
2550 new_vlist[paspi->n+1].x = new_vlist[paspi->n+2].x = new_abs_x;
2551 new_vlist[paspi->n+1].y = new_vlist[paspi->n+2].y = new_abs_y;
2552 } else {
2553 orig_hinge_index = paspi->sssi.orig_hinge_index;
2554 for (i=0; i < orig_hinge_index+2; i++) {
2555 new_vlist[i].x = obj_vlist[i].x;
2556 new_vlist[i].y = obj_vlist[i].y;
2557 }
2558 new_vlist[orig_hinge_index+2].x = new_vlist[orig_hinge_index+3].x =
2559 new_vlist[orig_hinge_index+4].x = new_abs_x;
2560 new_vlist[orig_hinge_index+2].y = new_vlist[orig_hinge_index+3].y =
2561 new_vlist[orig_hinge_index+4].y = new_abs_y;
2562 for (i=orig_hinge_index+2; i < paspi->n; i++) {
2563 new_vlist[i+3].x = obj_vlist[i].x;
2564 new_vlist[i+3].y = obj_vlist[i].y;
2565 }
2566 }
2567 }
2568 free(obj_vlist);
2569 if (poly_ptr != NULL) {
2570 paspi->poly_ptr->vlist = new_vlist;
2571 paspi->poly_ptr->n += 3;
2572 } else if (polygon_ptr != NULL) {
2573 paspi->polygon_ptr->vlist = new_vlist;
2574 paspi->polygon_ptr->n += 3;
2575 }
2576 } else { /* paspi->button == Button2 */
2577 obj_ptr = paspi->obj_ptr;
2578 new_abs_x = paspi->ruler_abs_x;
2579 new_abs_y = paspi->ruler_abs_y;
2580 if (obj_ptr->ctm != NULL) {
2581 ReverseTransformPointThroughCTM(new_abs_x-obj_ptr->x,
2582 new_abs_y-obj_ptr->y, obj_ptr->ctm, &tmp_x, &tmp_y);
2583 new_abs_x = obj_ptr->x+tmp_x;
2584 new_abs_y = obj_ptr->y+tmp_y;
2585 }
2586 if (!paspi->sssi.prev_valid) {
2587 /* first point of poly */
2588 obj_vlist[1].x = new_abs_x;
2589 obj_vlist[1].y = new_abs_y;
2590 } else if (!paspi->sssi.next_valid) {
2591 /* last point of poly */
2592 obj_vlist[paspi->n-2].x = new_abs_x;
2593 obj_vlist[paspi->n-2].y = new_abs_y;
2594 } else {
2595 orig_hinge_index = paspi->sssi.orig_hinge_index;
2596 if (paspi->before) {
2597 if (polygon_ptr != NULL && orig_hinge_index == 0) {
2598 obj_vlist[paspi->n-2].x = new_abs_x;
2599 obj_vlist[paspi->n-2].y = new_abs_y;
2600 obj_vlist[orig_hinge_index+1].x =
2601 (obj_vlist[orig_hinge_index].x<<1) - new_abs_x;
2602 obj_vlist[orig_hinge_index+1].y =
2603 (obj_vlist[orig_hinge_index].y<<1) - new_abs_y;
2604 } else {
2605 obj_vlist[orig_hinge_index-1].x = new_abs_x;
2606 obj_vlist[orig_hinge_index-1].y = new_abs_y;
2607 obj_vlist[orig_hinge_index+1].x =
2608 (obj_vlist[orig_hinge_index].x<<1) - new_abs_x;
2609 obj_vlist[orig_hinge_index+1].y =
2610 (obj_vlist[orig_hinge_index].y<<1) - new_abs_y;
2611 }
2612 } else {
2613 if (polygon_ptr != NULL && orig_hinge_index == 0) {
2614 obj_vlist[orig_hinge_index+1].x = new_abs_x;
2615 obj_vlist[orig_hinge_index+1].y = new_abs_y;
2616 obj_vlist[paspi->n-2].x =
2617 (obj_vlist[orig_hinge_index].x<<1) - new_abs_x;
2618 obj_vlist[paspi->n-2].y =
2619 (obj_vlist[orig_hinge_index].y<<1) - new_abs_y;
2620 } else {
2621 obj_vlist[orig_hinge_index+1].x = new_abs_x;
2622 obj_vlist[orig_hinge_index+1].y = new_abs_y;
2623 obj_vlist[orig_hinge_index-1].x =
2624 (obj_vlist[orig_hinge_index].x<<1) - new_abs_x;
2625 obj_vlist[orig_hinge_index-1].y =
2626 (obj_vlist[orig_hinge_index].y<<1) - new_abs_y;
2627 }
2628 }
2629 }
2630 }
2631 AdjObjSplineVs(obj_ptr);
2632 if (poly_ptr != NULL) {
2633 UpdPolyBBox(obj_ptr, poly_ptr->n, poly_ptr->vlist);
2634 } else if (polygon_ptr != NULL) {
2635 UpdPolyBBox(obj_ptr, polygon_ptr->n, polygon_ptr->vlist);
2636 }
2637 AdjObjBBox(obj_ptr);
2638
2639 UpdSelBBox();
2640 RedrawAreas(botObj,
2641 paspi->sel_ltx-GRID_ABS_SIZE(1), paspi->sel_lty-GRID_ABS_SIZE(1),
2642 paspi->sel_rbx+GRID_ABS_SIZE(1), paspi->sel_rby+GRID_ABS_SIZE(1),
2643 selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1),
2644 selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1));
2645 HighLightForward();
2646 SetFileModified(TRUE);
2647 justDupped = FALSE;
2648
2649 free(paspi->ssvlist);
2650 free(paspi->vlist);
2651
2652 return TRUE;
2653 }
2654
2655 static
EraseHighLightForAddStructuredPolyPoint(paspi,abs_dx,abs_dy,measure_cursor_mode)2656 void EraseHighLightForAddStructuredPolyPoint(paspi, abs_dx, abs_dy,
2657 measure_cursor_mode)
2658 AddStructuredPointInfo *paspi;
2659 int abs_dx, abs_dy, measure_cursor_mode;
2660 {
2661 if (paspi->sv != NULL) {
2662 XDrawLines(mainDisplay, drawWindow, revDefaultGC, paspi->sv, paspi->sn,
2663 CoordModeOrigin);
2664 free(paspi->sv);
2665 paspi->sv = NULL;
2666 }
2667 if (paspi->sv2 != NULL) {
2668 XDrawLines(mainDisplay, drawWindow, revDefaultGC, paspi->sv2, paspi->sn2,
2669 CoordModeOrigin);
2670 free(paspi->sv2);
2671 paspi->sv2 = NULL;
2672 }
2673 AddPointMeasureCursor(measure_cursor_mode, abs_dx, abs_dy, paspi->tx+abs_dx,
2674 paspi->ty+abs_dy);
2675 if (paspi->button == Button1) {
2676 MARKHR(drawWindow, revDefaultGC, OFFSET_X(paspi->ruler_abs_x),
2677 OFFSET_Y(paspi->ruler_abs_y));
2678 } else {
2679 XGCValues values;
2680
2681 if (paspi->num_vs > 0) {
2682 MARKHO(drawWindow, revDefaultGC, OFFSET_X(paspi->vs[1].x),
2683 OFFSET_Y(paspi->vs[1].y));
2684 }
2685 if (paspi->num_vs2 > 0) {
2686 MARKHO(drawWindow, revDefaultGC, OFFSET_X(paspi->vs2[1].x),
2687 OFFSET_Y(paspi->vs2[1].y));
2688 }
2689 XSetDashes(mainDisplay, revDefaultGC, 0, dashList[8], dashListLength[8]);
2690 values.line_style = LineOnOffDash;
2691 XChangeGC(mainDisplay, revDefaultGC, GCLineStyle, &values);
2692 MyDashedLine(drawWindow, revDefaultGC, paspi->dashed_vs, 2);
2693 values.line_style = LineSolid;
2694 XChangeGC(mainDisplay, revDefaultGC, GCLineStyle, &values);
2695 }
2696 }
2697
2698 static
ContinueAddStructuredPolyOrPolygonPoint(obj_ptr,button,start_mouse_x,start_mouse_y,index,poly_ptr,polygon_ptr,pn_last_mouse_x,pn_last_mouse_y)2699 int ContinueAddStructuredPolyOrPolygonPoint(obj_ptr, button, start_mouse_x,
2700 start_mouse_y, index, poly_ptr, polygon_ptr, pn_last_mouse_x,
2701 pn_last_mouse_y)
2702 struct ObjRec *obj_ptr;
2703 unsigned int button;
2704 int start_mouse_x, start_mouse_y, index, *pn_last_mouse_x, *pn_last_mouse_y;
2705 struct PolyRec *poly_ptr;
2706 struct PolygonRec *polygon_ptr;
2707 /* (start_mouse_x,start_mouse_y) is the mouse's origin in screen offsets */
2708 {
2709 AddStructuredPointInfo aspi;
2710 int done=FALSE;
2711
2712 memset(&aspi, 0, sizeof(AddStructuredPointInfo));
2713 aspi.before = INVALID;
2714 aspi.obj_ptr = obj_ptr;
2715 aspi.button = button;
2716 aspi.start_mouse_x = start_mouse_x;
2717 aspi.start_mouse_y = start_mouse_y;
2718 aspi.index = index;
2719 if (poly_ptr != NULL) {
2720 aspi.poly_ptr = poly_ptr;
2721 } else if (polygon_ptr != NULL) {
2722 aspi.polygon_ptr = polygon_ptr;
2723 } else {
2724 /* should not come here */
2725 return FALSE;
2726 }
2727 if (!ContinueAddStructuredPolyOrPolygonPointSetup(&aspi)) {
2728 return FALSE;
2729 }
2730 while (!done) {
2731 XEvent input, ev;
2732
2733 XNextEvent(mainDisplay, &input);
2734
2735 if (input.type == Expose || input.type == VisibilityNotify) {
2736 ExposeEventHandler(&input, TRUE);
2737 } else if (input.type == MotionNotify || input.type == KeyPress ||
2738 input.type == KeyRelease) {
2739 if (input.type == KeyPress || input.type == KeyRelease) {
2740 aspi.mouse_x = aspi.grid_x;
2741 aspi.mouse_y = aspi.grid_y;
2742 } else {
2743 aspi.mouse_x = input.xmotion.x;
2744 aspi.mouse_y = input.xmotion.y;
2745 }
2746 if (shiftForDiagMouseMove && DiagEventCheck(&input)) {
2747 if (input.type == KeyRelease) {
2748 aspi.mouse_x = input.xkey.x;
2749 aspi.mouse_y = input.xkey.y;
2750 } else {
2751 DiagGridXY(aspi.orig_grid_x, aspi.orig_grid_y, &aspi.mouse_x,
2752 &aspi.mouse_y);
2753 }
2754 }
2755 GridXY(aspi.mouse_x, aspi.mouse_y, &aspi.grid_x, &aspi.grid_y);
2756 /* erase */
2757 EraseHighLightForAddStructuredPolyPoint(&aspi, ABS_SIZE(aspi.dx_off),
2758 ABS_SIZE(aspi.dy_off), ADDPOINT_DOSHOW);
2759 aspi.dx_off = aspi.grid_x - aspi.orig_grid_x;
2760 aspi.dy_off = aspi.grid_y - aspi.orig_grid_y;
2761 aspi.ruler_abs_x = aspi.tx + ABS_SIZE(aspi.dx_off);
2762 aspi.ruler_abs_y = aspi.ty + ABS_SIZE(aspi.dy_off);
2763 MarkRulers(OFFSET_X(aspi.ruler_abs_x), OFFSET_Y(aspi.ruler_abs_y));
2764
2765 if (!aspi.already_moved) {
2766 ContinueAddStructuredPolyOrPolygonPointFirstMoved(&aspi);
2767 }
2768 ContinueAddStructuredPolyOrPolygonPointRestMoved(&aspi);
2769 while (XCheckMaskEvent(mainDisplay, PointerMotionMask, &ev)) ;
2770 } else if (input.type == ButtonRelease) {
2771 done = TRUE;
2772 *pn_last_mouse_x = aspi.mouse_x;
2773 *pn_last_mouse_y = aspi.mouse_y;
2774 /* erase */
2775 EraseHighLightForAddStructuredPolyPoint(&aspi, ABS_SIZE(aspi.dx_off),
2776 ABS_SIZE(aspi.dy_off), ADDPOINT_DOSHOW);
2777
2778 return ContinueAddStructuredPolyOrPolygonPointFinished(&aspi);
2779 }
2780 }
2781 return TRUE;
2782 }
2783
2784 static
ContinueAddPolyPoint(ObjPtr,MouseX,MouseY,Index,PolyPtr,LastMouseX,LastMouseY)2785 int ContinueAddPolyPoint(ObjPtr, MouseX, MouseY, Index, PolyPtr,
2786 LastMouseX, LastMouseY)
2787 struct ObjRec *ObjPtr;
2788 int MouseX, MouseY, Index;
2789 struct PolyRec *PolyPtr;
2790 int *LastMouseX, *LastMouseY;
2791 /*
2792 * (MouseX,MouseY) is the mouse's origin in screen offsets
2793 *
2794 * This routine is only called for LT_STRAIGHT, LT_SPLINE, or LT_INTSPLINE.
2795 */
2796 {
2797 int n=PolyPtr->n, sn=0, curved=PolyPtr->curved;
2798 int already_moved=FALSE, done=FALSE, before=INVALID;
2799 XPoint v[3], *sv=NULL;
2800 IntPoint *vs=PolyPtr->vlist, *pv=NULL, *cntrlv=NULL;
2801 int prev_x, prev_y, prev_tx, prev_ty, x, y, tx, ty, tmp_x, tmp_y;
2802 int next_x, next_y, next_tx, next_ty;
2803 int orig_x, orig_y, grid_x, grid_y, new_mouse_x, new_mouse_y;
2804 int sel_ltx, sel_lty, sel_rbx, sel_rby, num=0, i, intn=0;
2805 char *smooth=PolyPtr->smooth, *tmp_smooth=NULL;
2806 double prev_angle, next_angle, prev_dist, next_dist, dx, dy;
2807
2808 #ifdef _TGIF_DBG /* debug, do not translate */
2809 TgAssert(curved != LT_STRUCT_SPLINE,
2810 "curved == LT_STRUCT_SPLINE in ContinueAddPolyPoint()", NULL);
2811 #endif /* _TGIF_DBG */
2812 memset(v, 0, sizeof(XPoint)*3);
2813 sel_ltx = selLtX; sel_lty = selLtY;
2814 sel_rbx = selRbX; sel_rby = selRbY;
2815
2816 x = tx = vs[Index].x;
2817 y = ty = vs[Index].y;
2818 if (ObjPtr->ctm != NULL) {
2819 TransformPointThroughCTM(x-ObjPtr->x, y-ObjPtr->y, ObjPtr->ctm,
2820 &tmp_x, &tmp_y);
2821 tx = ObjPtr->x+tmp_x;
2822 ty = ObjPtr->y+tmp_y;
2823 }
2824 if (curved == LT_INTSPLINE || smooth == NULL || !smooth[Index]) {
2825 MARK(drawWindow, revDefaultGC, OFFSET_X(tx), OFFSET_Y(ty));
2826 } else {
2827 MARKO(drawWindow, revDefaultGC, OFFSET_X(tx), OFFSET_Y(ty));
2828 }
2829 if (Index == 0) {
2830 next_x = next_tx = vs[1].x;
2831 next_y = next_ty = vs[1].y;
2832 prev_x = prev_tx = 2*x-next_x;
2833 prev_y = prev_ty = 2*y-next_y;
2834 } else if (Index == n-1) {
2835 prev_x = prev_tx = vs[n-2].x;
2836 prev_y = prev_ty = vs[n-2].y;
2837 next_x = next_tx = 2*x-prev_x;
2838 next_y = next_ty = 2*y-prev_y;
2839 } else {
2840 prev_x = prev_tx = vs[Index-1].x;
2841 prev_y = prev_ty = vs[Index-1].y;
2842 next_x = next_tx = vs[Index+1].x;
2843 next_y = next_ty = vs[Index+1].y;
2844 }
2845 if (ObjPtr->ctm != NULL) {
2846 TransformPointThroughCTM(next_x-ObjPtr->x, next_y-ObjPtr->y,
2847 ObjPtr->ctm, &tmp_x, &tmp_y);
2848 next_tx = ObjPtr->x+tmp_x;
2849 next_ty = ObjPtr->y+tmp_y;
2850 TransformPointThroughCTM(prev_x-ObjPtr->x, prev_y-ObjPtr->y,
2851 ObjPtr->ctm, &tmp_x, &tmp_y);
2852 prev_tx = ObjPtr->x+tmp_x;
2853 prev_ty = ObjPtr->y+tmp_y;
2854 }
2855 dx = (double)(prev_tx - tx);
2856 dy = (double)(prev_ty - ty);
2857 prev_dist = dx*dx+dy*dy;
2858 dx = (double)(next_tx - tx);
2859 dy = (double)(next_ty - ty);
2860 next_dist = dx*dx+dy*dy;
2861
2862 prev_angle = (prev_tx==tx) ? ((prev_ty>=ty) ? M_PI/2.0 : -M_PI/2.0) :
2863 atan2((double)(prev_ty-ty), (double)(prev_tx-tx));
2864 next_angle = (next_tx==tx) ? ((next_ty>=ty) ? M_PI/2.0 : -M_PI/2.0) :
2865 atan2((double)(next_ty-ty), (double)(next_tx-tx));
2866 pv = (IntPoint*)malloc((n+2)*sizeof(IntPoint));
2867 if (pv == NULL) FailAllocMessage();
2868 if (curved != LT_INTSPLINE && smooth != NULL) {
2869 tmp_smooth = (char*)malloc((n+2)*sizeof(char));
2870 if (tmp_smooth == NULL) FailAllocMessage();
2871 }
2872 if (ObjPtr->ctm == NULL) {
2873 for (i = 0; i <= Index; i++) {
2874 pv[i].x = vs[i].x;
2875 pv[i].y = vs[i].y;
2876 if (tmp_smooth != NULL) tmp_smooth[i] = smooth[i];
2877 }
2878 for (i = Index; i < n; i++) {
2879 pv[i+1].x = vs[i].x;
2880 pv[i+1].y = vs[i].y;
2881 if (tmp_smooth != NULL) tmp_smooth[i+1] = smooth[i];
2882 }
2883 } else {
2884 for (i = 0; i <= Index; i++) {
2885 TransformPointThroughCTM(vs[i].x-ObjPtr->x, vs[i].y-ObjPtr->y,
2886 ObjPtr->ctm, &tmp_x, &tmp_y);
2887 pv[i].x = ObjPtr->x+tmp_x;
2888 pv[i].y = ObjPtr->y+tmp_y;
2889 if (tmp_smooth != NULL) tmp_smooth[i] = smooth[i];
2890 }
2891 for (i = Index; i < n; i++) {
2892 TransformPointThroughCTM(vs[i].x-ObjPtr->x, vs[i].y-ObjPtr->y,
2893 ObjPtr->ctm, &tmp_x, &tmp_y);
2894 pv[i+1].x = ObjPtr->x+tmp_x;
2895 pv[i+1].y = ObjPtr->y+tmp_y;
2896 if (tmp_smooth != NULL) tmp_smooth[i+1] = smooth[i];
2897 }
2898 }
2899 GridXY(MouseX, MouseY, &orig_x, &orig_y);
2900 grid_x = orig_x;
2901 grid_y = orig_y;
2902 new_mouse_x = MouseX; new_mouse_y = MouseY;
2903 AddPointMeasureCursor(ADDPOINT_STARTSHOW, 0, 0, tx, ty);
2904
2905 while (!done) {
2906 double new_angle, theta_1, theta_2;
2907 XEvent input, ev;
2908
2909 XNextEvent(mainDisplay, &input);
2910
2911 if (input.type == Expose || input.type == VisibilityNotify) {
2912 ExposeEventHandler(&input, TRUE);
2913 } else if (input.type == MotionNotify || input.type == KeyPress ||
2914 input.type == KeyRelease) {
2915 int new_x, new_y;
2916
2917 if (input.type == KeyPress || input.type == KeyRelease) {
2918 new_mouse_x = grid_x;
2919 new_mouse_y = grid_y;
2920 } else {
2921 new_mouse_x = input.xmotion.x;
2922 new_mouse_y = input.xmotion.y;
2923 }
2924 if (shiftForDiagMouseMove && DiagEventCheck(&input)) {
2925 if (input.type == KeyRelease) {
2926 new_mouse_x = input.xkey.x;
2927 new_mouse_y = input.xkey.y;
2928 } else {
2929 DiagGridXY(orig_x, orig_y, &new_mouse_x, &new_mouse_y);
2930 }
2931 }
2932 GridXY(new_mouse_x, new_mouse_y, &grid_x, &grid_y);
2933 new_x = ABS_SIZE(new_mouse_x-MouseX) + tx;
2934 new_y = ABS_SIZE(new_mouse_y-MouseY) + ty;
2935 if (!already_moved) {
2936 double new_prev_dist, new_next_dist;
2937
2938 already_moved = TRUE;
2939
2940 dx = (double)(prev_tx - new_mouse_x);
2941 dy = (double)(prev_ty - new_mouse_y);
2942 new_prev_dist = dx*dx+dy*dy;
2943 dx = (double)(next_tx - new_mouse_x);
2944 dy = (double)(next_ty - new_mouse_y);
2945 new_next_dist = dx*dx+dy*dy;
2946
2947 before = DetermineBefore(prev_dist, next_dist, new_prev_dist,
2948 new_next_dist);
2949 if (before == INVALID) {
2950 new_angle = (new_x==tx) ? ((new_y>=ty) ? M_PI/2.0 : -M_PI/2.0) :
2951 atan2((double)(new_y-ty), (double)(new_x-tx));
2952 theta_1 = fabs(prev_angle - new_angle);
2953 theta_2 = fabs(next_angle - new_angle);
2954 if (theta_1 > M_PI) theta_1 = 2*M_PI-theta_1;
2955 if (theta_2 > M_PI) theta_2 = 2*M_PI-theta_2;
2956 before = (theta_1 <= theta_2);
2957 }
2958 if (before) {
2959 /* Add a point between the current and the previous point */
2960 if (Index == 0) {
2961 num = 2;
2962 v[0].x = OFFSET_X(tx); v[0].y = OFFSET_Y(ty);
2963 v[1].x = OFFSET_X(tx); v[1].y = OFFSET_Y(ty);
2964 } else {
2965 num = 3;
2966 v[0].x = OFFSET_X(prev_tx); v[0].y = OFFSET_Y(prev_ty);
2967 v[1].x = OFFSET_X(tx); v[1].y = OFFSET_Y(ty);
2968 v[2].x = OFFSET_X(tx); v[2].y = OFFSET_Y(ty);
2969 }
2970 } else {
2971 /* Add a point between the current and the next point */
2972 if (Index == n-1) {
2973 num = 2;
2974 v[0].x = OFFSET_X(tx); v[0].y = OFFSET_Y(ty);
2975 v[1].x = OFFSET_X(tx); v[1].y = OFFSET_Y(ty);
2976 } else {
2977 num = 3;
2978 v[0].x = OFFSET_X(tx); v[0].y = OFFSET_Y(ty);
2979 v[1].x = OFFSET_X(tx); v[1].y = OFFSET_Y(ty);
2980 v[2].x = OFFSET_X(next_tx); v[2].y = OFFSET_Y(next_ty);
2981 }
2982 }
2983 switch (curved) {
2984 case LT_STRAIGHT:
2985 case LT_SPLINE:
2986 sv = MakeMultiSplinePolyVertex(curved, &sn, tmp_smooth,
2987 drawOrigX, drawOrigY, n+1, pv);
2988 break;
2989 case LT_INTSPLINE:
2990 sv = MakeIntSplinePolyVertex(&sn, &intn, &cntrlv,
2991 drawOrigX, drawOrigY, n+1, pv);
2992 break;
2993 case LT_STRUCT_SPLINE:
2994 /* should never get here */
2995 break;
2996 }
2997 XDrawLines(mainDisplay, drawWindow, revDefaultGC, sv, sn,
2998 CoordModeOrigin);
2999 } else {
3000 AddPointMeasureCursor(ADDPOINT_DOSHOW, abs(ABS_X(v[1].x)-tx),
3001 abs(ABS_Y(v[1].y)-ty), ABS_X(v[1].x), ABS_Y(v[1].y));
3002 XDrawLines(mainDisplay, drawWindow, revDefaultGC, sv, sn,
3003 CoordModeOrigin);
3004 v[1].x = OFFSET_X(tx) + grid_x - orig_x;
3005 v[1].y = OFFSET_Y(ty) + grid_y - orig_y;
3006 free(sv);
3007 if (before) {
3008 pv[Index].x = tx + ABS_SIZE(grid_x-orig_x);
3009 pv[Index].y = ty + ABS_SIZE(grid_y-orig_y);
3010 } else {
3011 pv[Index+1].x = tx + ABS_SIZE(grid_x-orig_x);
3012 pv[Index+1].y = ty + ABS_SIZE(grid_y-orig_y);
3013 }
3014 switch (curved) {
3015 case LT_STRAIGHT:
3016 case LT_SPLINE:
3017 sv = MakeMultiSplinePolyVertex(curved, &sn, tmp_smooth,
3018 drawOrigX, drawOrigY, n+1, pv);
3019 break;
3020 case LT_INTSPLINE:
3021 free(cntrlv);
3022 sv = MakeIntSplinePolyVertex(&sn, &intn, &cntrlv,
3023 drawOrigX, drawOrigY, n+1, pv);
3024 break;
3025 case LT_STRUCT_SPLINE:
3026 /* should never get here */
3027 break;
3028 }
3029 XDrawLines(mainDisplay, drawWindow, revDefaultGC, sv, sn,
3030 CoordModeOrigin);
3031 MarkRulers(v[1].x, v[1].y);
3032 AddPointMeasureCursor(ADDPOINT_DOSHOW, abs(ABS_X(v[1].x)-tx),
3033 abs(ABS_Y(v[1].y)-ty), ABS_X(v[1].x), ABS_Y(v[1].y));
3034 }
3035 while (XCheckMaskEvent(mainDisplay, PointerMotionMask, &ev)) ;
3036 } else if (input.type == ButtonRelease) {
3037 done = TRUE;
3038 *LastMouseX = new_mouse_x; *LastMouseY = new_mouse_y;
3039 if (curved == LT_INTSPLINE || smooth == NULL || !smooth[Index]) {
3040 MARK(drawWindow, revDefaultGC, OFFSET_X(tx), OFFSET_Y(ty));
3041 } else {
3042 MARKO(drawWindow, revDefaultGC, OFFSET_X(tx), OFFSET_Y(ty));
3043 }
3044 if (already_moved) {
3045 AddPointMeasureCursor(ADDPOINT_ENDSHOW, abs(ABS_X(v[1].x)-tx),
3046 abs(ABS_Y(v[1].y)-ty), ABS_X(v[1].x), ABS_Y(v[1].y));
3047 } else {
3048 AddPointMeasureCursor(ADDPOINT_STARTSHOW, 0, 0, tx, ty);
3049 }
3050 if (!already_moved) {
3051 return FALSE;
3052 } else {
3053 XDrawLines(mainDisplay, drawWindow, revDefaultGC, sv, sn,
3054 CoordModeOrigin);
3055 if (grid_x == orig_x && grid_y == orig_y) {
3056 return FALSE;
3057 }
3058 }
3059 HighLightReverse();
3060 vs = (IntPoint*)realloc(vs, (n+2)*sizeof(IntPoint));
3061 if (vs == NULL) return FailAllocMessage();
3062 if (smooth != NULL) {
3063 smooth = (char*)realloc(smooth, (n+2)*sizeof(char));
3064 if (smooth == NULL) return FailAllocMessage();
3065 }
3066 PolyPtr->vlist = vs;
3067 PolyPtr->smooth = smooth;
3068 if (before) {
3069 for (i = n-1; i >= Index; i--) {
3070 vs[i+1] = vs[i];
3071 if (smooth != NULL) smooth[i+1] = smooth[i];
3072 }
3073 if (ObjPtr->ctm == NULL) {
3074 vs[Index].x = x + ABS_SIZE(grid_x-orig_x);
3075 vs[Index].y = y + ABS_SIZE(grid_y-orig_y);
3076 } else {
3077 vs[Index].x = tx + ABS_SIZE(grid_x-orig_x);
3078 vs[Index].y = ty + ABS_SIZE(grid_y-orig_y);
3079 ReverseTransformPointThroughCTM(vs[Index].x-ObjPtr->x,
3080 vs[Index].y-ObjPtr->y, ObjPtr->ctm, &tmp_x, &tmp_y);
3081 vs[Index].x = ObjPtr->x+tmp_x;
3082 vs[Index].y = ObjPtr->y+tmp_y;
3083 }
3084 if (smooth != NULL) smooth[Index] = smooth[Index+1];
3085 } else {
3086 for (i = n-1; i > Index; i--) {
3087 vs[i+1] = vs[i];
3088 if (smooth != NULL) smooth[i+1] = smooth[i];
3089 }
3090 if (ObjPtr->ctm == NULL) {
3091 vs[Index+1].x = x + ABS_SIZE(grid_x-orig_x);
3092 vs[Index+1].y = y + ABS_SIZE(grid_y-orig_y);
3093 } else {
3094 vs[Index+1].x = tx + ABS_SIZE(grid_x-orig_x);
3095 vs[Index+1].y = ty + ABS_SIZE(grid_y-orig_y);
3096 ReverseTransformPointThroughCTM(vs[Index+1].x-ObjPtr->x,
3097 vs[Index+1].y-ObjPtr->y, ObjPtr->ctm, &tmp_x, &tmp_y);
3098 vs[Index+1].x = ObjPtr->x+tmp_x;
3099 vs[Index+1].y = ObjPtr->y+tmp_y;
3100 }
3101 if (smooth != NULL) smooth[Index+1] = smooth[Index];
3102 }
3103 if (sv != NULL) {
3104 free(sv);
3105 sv = NULL;
3106 }
3107 if (pv != NULL) {
3108 free(pv);
3109 pv = NULL;
3110 }
3111 if (tmp_smooth != NULL) free(tmp_smooth);
3112 if (curved == LT_INTSPLINE && cntrlv != NULL) free(cntrlv);
3113 PolyPtr->n++;
3114 n++;
3115 AdjObjSplineVs(ObjPtr);
3116 if (curved != LT_INTSPLINE) {
3117 UpdPolyBBox(ObjPtr, PolyPtr->n, PolyPtr->vlist);
3118 } else {
3119 UpdPolyBBox(ObjPtr, PolyPtr->intn, PolyPtr->intvlist);
3120 }
3121 AdjObjBBox(ObjPtr);
3122
3123 UpdSelBBox();
3124 RedrawAreas(botObj,
3125 sel_ltx-GRID_ABS_SIZE(1), sel_lty-GRID_ABS_SIZE(1),
3126 sel_rbx+GRID_ABS_SIZE(1), sel_rby+GRID_ABS_SIZE(1),
3127 selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1),
3128 selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1));
3129 HighLightForward();
3130 SetFileModified(TRUE);
3131 justDupped = FALSE;
3132 } else if (input.type == KeyPress) {
3133 if (KeyPressEventIsEscape(&input.xkey)) {
3134 done = TRUE;
3135 *LastMouseX = new_mouse_x; *LastMouseY = new_mouse_y;
3136 if (curved == LT_INTSPLINE || smooth == NULL || !smooth[Index]) {
3137 MARK(drawWindow, revDefaultGC, OFFSET_X(tx), OFFSET_Y(ty));
3138 } else {
3139 MARKO(drawWindow, revDefaultGC, OFFSET_X(tx), OFFSET_Y(ty));
3140 }
3141 if (already_moved) {
3142 AddPointMeasureCursor(ADDPOINT_ENDSHOW, abs(ABS_X(v[1].x)-tx),
3143 abs(ABS_Y(v[1].y)-ty), ABS_X(v[1].x), ABS_Y(v[1].y));
3144 } else {
3145 AddPointMeasureCursor(ADDPOINT_STARTSHOW, 0, 0, tx, ty);
3146 }
3147 if (already_moved) {
3148 XDrawLines(mainDisplay, drawWindow, revDefaultGC, sv, sn,
3149 CoordModeOrigin);
3150 if (grid_x == orig_x && grid_y == orig_y) {
3151 return FALSE;
3152 }
3153 }
3154 return FALSE;
3155 }
3156 }
3157 }
3158 return TRUE;
3159 }
3160
3161 static
ContinueAddPolygonPoint(ObjPtr,MouseX,MouseY,Index,PolygonPtr,LastMouseX,LastMouseY)3162 int ContinueAddPolygonPoint(ObjPtr, MouseX, MouseY, Index, PolygonPtr,
3163 LastMouseX, LastMouseY)
3164 struct ObjRec *ObjPtr;
3165 int MouseX, MouseY, Index;
3166 struct PolygonRec *PolygonPtr;
3167 int *LastMouseX, *LastMouseY;
3168 /*
3169 * (MouseX,MouseY) is the mouse's origin in screen offsets
3170 *
3171 * This routine is only called for LT_STRAIGHT, LT_SPLINE, or LT_INTSPLINE.
3172 */
3173 {
3174 int n=PolygonPtr->n, sn=0, curved=PolygonPtr->curved;
3175 int already_moved=FALSE, done=FALSE, before=FALSE;
3176 XPoint v[3], *sv=NULL;
3177 IntPoint *vs=PolygonPtr->vlist, *pv=NULL, *cntrlv=NULL;
3178 int prev_x, prev_y, prev_tx, prev_ty, x, y, tx, ty, tmp_x, tmp_y;
3179 int next_x, next_y, next_tx, next_ty;
3180 int orig_x, orig_y, grid_x, grid_y, new_mouse_x, new_mouse_y;
3181 int sel_ltx, sel_lty, sel_rbx, sel_rby, i, intn=0;
3182 char *smooth=PolygonPtr->smooth, *tmp_smooth=NULL;
3183 double prev_angle, next_angle, prev_dist, next_dist, dx, dy;
3184
3185 memset(v, 0, sizeof(XPoint)*3);
3186 #ifdef _TGIF_DBG /* debug, do not translate */
3187 TgAssert(curved != LT_STRUCT_SPLINE,
3188 "curved == LT_STRUCT_SPLINE in ContinueAddPolygonPoint()", NULL);
3189 #endif /* _TGIF_DBG */
3190 sel_ltx = selLtX; sel_lty = selLtY;
3191 sel_rbx = selRbX; sel_rby = selRbY;
3192
3193 x = tx = vs[Index].x;
3194 y = ty = vs[Index].y;
3195 if (ObjPtr->ctm != NULL) {
3196 TransformPointThroughCTM(x-ObjPtr->x, y-ObjPtr->y, ObjPtr->ctm,
3197 &tmp_x, &tmp_y);
3198 tx = ObjPtr->x+tmp_x;
3199 ty = ObjPtr->y+tmp_y;
3200 }
3201 if (curved == LT_INTSPLINE || smooth == NULL || !smooth[Index]) {
3202 MARK(drawWindow, revDefaultGC, OFFSET_X(tx), OFFSET_Y(ty));
3203 } else {
3204 MARKO(drawWindow, revDefaultGC, OFFSET_X(tx), OFFSET_Y(ty));
3205 }
3206 if (Index == 0 || Index == n-1) {
3207 next_x = next_tx = vs[1].x;
3208 next_y = next_ty = vs[1].y;
3209 prev_x = prev_tx = vs[n-2].x;
3210 prev_y = prev_ty = vs[n-2].y;
3211 } else {
3212 prev_x = prev_tx = vs[Index-1].x;
3213 prev_y = prev_ty = vs[Index-1].y;
3214 next_x = next_tx = vs[Index+1].x;
3215 next_y = next_ty = vs[Index+1].y;
3216 }
3217 if (ObjPtr->ctm != NULL) {
3218 TransformPointThroughCTM(next_x-ObjPtr->x, next_y-ObjPtr->y,
3219 ObjPtr->ctm, &tmp_x, &tmp_y);
3220 next_tx = ObjPtr->x+tmp_x;
3221 next_ty = ObjPtr->y+tmp_y;
3222 TransformPointThroughCTM(prev_x-ObjPtr->x, prev_y-ObjPtr->y,
3223 ObjPtr->ctm, &tmp_x, &tmp_y);
3224 prev_tx = ObjPtr->x+tmp_x;
3225 prev_ty = ObjPtr->y+tmp_y;
3226 }
3227 dx = (double)(prev_tx - tx);
3228 dy = (double)(prev_ty - ty);
3229 prev_dist = dx*dx+dy*dy;
3230 dx = (double)(next_tx - tx);
3231 dy = (double)(next_ty - ty);
3232 next_dist = dx*dx+dy*dy;
3233
3234 prev_angle = (prev_tx==tx) ? ((prev_ty>=ty) ? M_PI/2.0 : -M_PI/2.0) :
3235 atan2((double)(prev_ty-ty), (double)(prev_tx-tx));
3236 next_angle = (next_tx==tx) ? ((next_ty>=ty) ? M_PI/2.0 : -M_PI/2.0) :
3237 atan2((double)(next_ty-ty), (double)(next_tx-tx));
3238 pv = (IntPoint *)malloc((n+2)*sizeof(IntPoint));
3239 if (pv == NULL) FailAllocMessage();
3240 if (curved != LT_INTSPLINE && smooth != NULL) {
3241 tmp_smooth = (char*)malloc((n+2)*sizeof(char));
3242 if (tmp_smooth == NULL) FailAllocMessage();
3243 }
3244 if (ObjPtr->ctm == NULL) {
3245 for (i = 0; i <= Index; i++) {
3246 pv[i].x = vs[i].x;
3247 pv[i].y = vs[i].y;
3248 if (tmp_smooth != NULL) tmp_smooth[i] = smooth[i];
3249 }
3250 for (i = Index; i < n; i++) {
3251 pv[i+1].x = vs[i].x;
3252 pv[i+1].y = vs[i].y;
3253 if (tmp_smooth != NULL) tmp_smooth[i+1] = smooth[i];
3254 }
3255 } else {
3256 for (i = 0; i <= Index; i++) {
3257 TransformPointThroughCTM(vs[i].x-ObjPtr->x, vs[i].y-ObjPtr->y,
3258 ObjPtr->ctm, &tmp_x, &tmp_y);
3259 pv[i].x = ObjPtr->x+tmp_x;
3260 pv[i].y = ObjPtr->y+tmp_y;
3261 if (tmp_smooth != NULL) tmp_smooth[i] = smooth[i];
3262 }
3263 for (i = Index; i < n; i++) {
3264 TransformPointThroughCTM(vs[i].x-ObjPtr->x, vs[i].y-ObjPtr->y,
3265 ObjPtr->ctm, &tmp_x, &tmp_y);
3266 pv[i+1].x = ObjPtr->x+tmp_x;
3267 pv[i+1].y = ObjPtr->y+tmp_y;
3268 if (tmp_smooth != NULL) tmp_smooth[i+1] = smooth[i];
3269 }
3270 }
3271 GridXY(MouseX, MouseY, &orig_x, &orig_y);
3272 grid_x = orig_x;
3273 grid_y = orig_y;
3274 new_mouse_x = MouseX; new_mouse_y = MouseY;
3275 AddPointMeasureCursor(ADDPOINT_STARTSHOW, 0, 0, tx, ty);
3276
3277 while (!done) {
3278 double new_angle, theta_1, theta_2;
3279 XEvent input, ev;
3280
3281 XNextEvent(mainDisplay, &input);
3282
3283 if (input.type == Expose || input.type == VisibilityNotify) {
3284 ExposeEventHandler(&input, TRUE);
3285 } else if (input.type == MotionNotify || input.type == KeyPress ||
3286 input.type == KeyRelease) {
3287 int new_x, new_y;
3288
3289 if (input.type == KeyPress || input.type == KeyRelease) {
3290 new_mouse_x = grid_x;
3291 new_mouse_y = grid_y;
3292 } else {
3293 new_mouse_x = input.xmotion.x;
3294 new_mouse_y = input.xmotion.y;
3295 }
3296 if (shiftForDiagMouseMove && DiagEventCheck(&input)) {
3297 if (input.type == KeyRelease) {
3298 new_mouse_x = input.xkey.x;
3299 new_mouse_y = input.xkey.y;
3300 } else {
3301 DiagGridXY(orig_x, orig_y, &new_mouse_x, &new_mouse_y);
3302 }
3303 }
3304 GridXY(new_mouse_x, new_mouse_y, &grid_x, &grid_y);
3305 new_x = ABS_SIZE(new_mouse_x-MouseX) + tx;
3306 new_y = ABS_SIZE(new_mouse_y-MouseY) + ty;
3307 if (!already_moved) {
3308 double new_prev_dist, new_next_dist;
3309
3310 already_moved = TRUE;
3311
3312 dx = (double)(prev_tx - new_mouse_x);
3313 dy = (double)(prev_ty - new_mouse_y);
3314 new_prev_dist = dx*dx+dy*dy;
3315 dx = (double)(next_tx - new_mouse_x);
3316 dy = (double)(next_ty - new_mouse_y);
3317 new_next_dist = dx*dx+dy*dy;
3318
3319 before = DetermineBefore(prev_dist, next_dist, new_prev_dist,
3320 new_next_dist);
3321 if (before == INVALID) {
3322 new_angle = (new_x==tx) ? ((new_y>=ty) ? M_PI/2.0 : -M_PI/2.0) :
3323 atan2((double)(new_y-ty), (double)(new_x-tx));
3324 theta_1 = fabs(prev_angle - new_angle);
3325 theta_2 = fabs(next_angle - new_angle);
3326 if (theta_1 > M_PI) theta_1 = 2*M_PI-theta_1;
3327 if (theta_2 > M_PI) theta_2 = 2*M_PI-theta_2;
3328 before = (theta_1 <= theta_2);
3329 }
3330 if (before) {
3331 /* Add a point between the current and the previous point */
3332 v[0].x = OFFSET_X(prev_tx); v[0].y = OFFSET_Y(prev_ty);
3333 v[1].x = OFFSET_X(tx); v[1].y = OFFSET_Y(ty);
3334 v[2].x = OFFSET_X(tx); v[2].y = OFFSET_Y(ty);
3335 } else {
3336 /* Add a point between the current and the next point */
3337 v[0].x = OFFSET_X(tx); v[0].y = OFFSET_Y(ty);
3338 v[1].x = OFFSET_X(tx); v[1].y = OFFSET_Y(ty);
3339 v[2].x = OFFSET_X(next_tx); v[2].y = OFFSET_Y(next_ty);
3340 }
3341 switch (curved) {
3342 case LT_STRAIGHT:
3343 case LT_SPLINE:
3344 sv = MakeMultiSplinePolygonVertex(curved, &sn, tmp_smooth,
3345 drawOrigX, drawOrigY, n+1, pv);
3346 break;
3347 case LT_INTSPLINE:
3348 sv = MakeIntSplinePolygonVertex(&sn, &intn, &cntrlv,
3349 drawOrigX, drawOrigY, n+1, pv);
3350 break;
3351 case LT_STRUCT_SPLINE:
3352 /* should never get here */
3353 break;
3354 }
3355 XDrawLines(mainDisplay, drawWindow, revDefaultGC, sv, sn,
3356 CoordModeOrigin);
3357 } else {
3358 AddPointMeasureCursor(ADDPOINT_DOSHOW, abs(ABS_X(v[1].x)-tx),
3359 abs(ABS_Y(v[1].y)-ty), ABS_X(v[1].x), ABS_Y(v[1].y));
3360 XDrawLines(mainDisplay, drawWindow, revDefaultGC, sv, sn,
3361 CoordModeOrigin);
3362 v[1].x = OFFSET_X(tx) + grid_x - orig_x;
3363 v[1].y = OFFSET_Y(ty) + grid_y - orig_y;
3364 if (sv != NULL) {
3365 free(sv);
3366 sv = NULL;
3367 }
3368 if (before) {
3369 pv[Index].x = tx + ABS_SIZE(grid_x-orig_x);
3370 pv[Index].y = ty + ABS_SIZE(grid_y-orig_y);
3371 if (Index == 0) {
3372 pv[n].x = tx + ABS_SIZE(grid_x-orig_x);
3373 pv[n].y = ty + ABS_SIZE(grid_y-orig_y);
3374 }
3375 } else {
3376 pv[Index+1].x = tx + ABS_SIZE(grid_x-orig_x);
3377 pv[Index+1].y = ty + ABS_SIZE(grid_y-orig_y);
3378 if (Index == n-1) {
3379 pv[0].x = tx + ABS_SIZE(grid_x-orig_x);
3380 pv[0].y = ty + ABS_SIZE(grid_y-orig_y);
3381 }
3382 }
3383 switch (curved) {
3384 case LT_STRAIGHT:
3385 case LT_SPLINE:
3386 sv = MakeMultiSplinePolygonVertex(curved, &sn, tmp_smooth,
3387 drawOrigX, drawOrigY, n+1, pv);
3388 break;
3389 case LT_INTSPLINE:
3390 free(cntrlv);
3391 sv = MakeIntSplinePolygonVertex(&sn, &intn, &cntrlv,
3392 drawOrigX, drawOrigY, n+1, pv);
3393 break;
3394 case LT_STRUCT_SPLINE:
3395 /* should never get here */
3396 break;
3397 }
3398 XDrawLines(mainDisplay, drawWindow, revDefaultGC, sv, sn,
3399 CoordModeOrigin);
3400 MarkRulers(v[1].x, v[1].y);
3401 AddPointMeasureCursor(ADDPOINT_DOSHOW, abs(ABS_X(v[1].x)-tx),
3402 abs(ABS_Y(v[1].y)-ty), ABS_X(v[1].x), ABS_Y(v[1].y));
3403 }
3404 while (XCheckMaskEvent(mainDisplay, PointerMotionMask, &ev)) ;
3405 } else if (input.type == ButtonRelease) {
3406 done = TRUE;
3407 *LastMouseX = new_mouse_x; *LastMouseY = new_mouse_y;
3408 if (curved == LT_INTSPLINE || smooth == NULL || !smooth[Index]) {
3409 MARK(drawWindow, revDefaultGC, OFFSET_X(tx), OFFSET_Y(ty));
3410 } else {
3411 MARKO(drawWindow, revDefaultGC, OFFSET_X(tx), OFFSET_Y(ty));
3412 }
3413 if (already_moved) {
3414 AddPointMeasureCursor(ADDPOINT_ENDSHOW, abs(ABS_X(v[1].x)-tx),
3415 abs(ABS_Y(v[1].y)-ty), ABS_X(v[1].x), ABS_Y(v[1].y));
3416 } else {
3417 AddPointMeasureCursor(ADDPOINT_STARTSHOW, 0, 0, tx, ty);
3418 }
3419 if (!already_moved) {
3420 return FALSE;
3421 } else {
3422 XDrawLines(mainDisplay, drawWindow, revDefaultGC, sv, sn,
3423 CoordModeOrigin);
3424 if (grid_x == orig_x && grid_y == orig_y) {
3425 return FALSE;
3426 }
3427 }
3428 HighLightReverse();
3429 vs = (IntPoint*)realloc(vs, (n+2)*sizeof(IntPoint));
3430 if (vs == NULL) return FailAllocMessage();
3431 if (smooth != NULL) {
3432 smooth = (char*)realloc(smooth, (n+2)*sizeof(char));
3433 if (smooth == NULL) return FailAllocMessage();
3434 }
3435 PolygonPtr->vlist = vs;
3436 PolygonPtr->smooth = smooth;
3437 if (Index == 0 || Index == n-1) {
3438 if (before) {
3439 vs[n].x = vs[n-1].x;
3440 vs[n].y = vs[n-1].y;
3441 if (ObjPtr->ctm == NULL) {
3442 vs[n-1].x = x + ABS_SIZE(grid_x-orig_x);
3443 vs[n-1].y = y + ABS_SIZE(grid_y-orig_y);
3444 } else {
3445 vs[n-1].x = tx + ABS_SIZE(grid_x-orig_x);
3446 vs[n-1].y = ty + ABS_SIZE(grid_y-orig_y);
3447 ReverseTransformPointThroughCTM(vs[n-1].x-ObjPtr->x,
3448 vs[n-1].y-ObjPtr->y, ObjPtr->ctm, &tmp_x, &tmp_y);
3449 vs[n-1].x = ObjPtr->x+tmp_x;
3450 vs[n-1].y = ObjPtr->y+tmp_y;
3451 }
3452 if (smooth != NULL) smooth[n] = smooth[n-1];
3453 } else {
3454 for (i = n-1; i > 0; i--) {
3455 vs[i+1].x = vs[i].x;
3456 vs[i+1].y = vs[i].y;
3457 if (smooth != NULL) smooth[i+1] = smooth[i];
3458 }
3459 if (ObjPtr->ctm == NULL) {
3460 vs[1].x = x + ABS_SIZE(grid_x-orig_x);
3461 vs[1].y = y + ABS_SIZE(grid_y-orig_y);
3462 } else {
3463 vs[1].x = tx + ABS_SIZE(grid_x-orig_x);
3464 vs[1].y = ty + ABS_SIZE(grid_y-orig_y);
3465 ReverseTransformPointThroughCTM(vs[1].x-ObjPtr->x,
3466 vs[1].y-ObjPtr->y, ObjPtr->ctm, &tmp_x, &tmp_y);
3467 vs[1].x = ObjPtr->x+tmp_x;
3468 vs[1].y = ObjPtr->y+tmp_y;
3469 }
3470 if (smooth != NULL) smooth[1] = smooth[0];
3471 }
3472 } else {
3473 if (before) {
3474 for (i = n-1; i >= Index; i--) {
3475 vs[i+1].x = vs[i].x;
3476 vs[i+1].y = vs[i].y;
3477 if (smooth != NULL) smooth[i+1] = smooth[i];
3478 }
3479 if (ObjPtr->ctm == NULL) {
3480 vs[Index].x = x + ABS_SIZE(grid_x-orig_x);
3481 vs[Index].y = y + ABS_SIZE(grid_y-orig_y);
3482 } else {
3483 vs[Index].x = tx + ABS_SIZE(grid_x-orig_x);
3484 vs[Index].y = ty + ABS_SIZE(grid_y-orig_y);
3485 ReverseTransformPointThroughCTM(vs[Index].x-ObjPtr->x,
3486 vs[Index].y-ObjPtr->y, ObjPtr->ctm, &tmp_x, &tmp_y);
3487 vs[Index].x = ObjPtr->x+tmp_x;
3488 vs[Index].y = ObjPtr->y+tmp_y;
3489 }
3490 if (smooth != NULL) smooth[Index] = smooth[Index+1];
3491 } else {
3492 for (i = n-1; i > Index; i--) {
3493 vs[i+1].x = vs[i].x;
3494 vs[i+1].y = vs[i].y;
3495 if (smooth != NULL) smooth[i+1] = smooth[i];
3496 }
3497 if (ObjPtr->ctm == NULL) {
3498 vs[Index+1].x = x + ABS_SIZE(grid_x-orig_x);
3499 vs[Index+1].y = y + ABS_SIZE(grid_y-orig_y);
3500 } else {
3501 vs[Index+1].x = tx + ABS_SIZE(grid_x-orig_x);
3502 vs[Index+1].y = ty + ABS_SIZE(grid_y-orig_y);
3503 ReverseTransformPointThroughCTM(vs[Index+1].x-ObjPtr->x,
3504 vs[Index+1].y-ObjPtr->y, ObjPtr->ctm, &tmp_x, &tmp_y);
3505 vs[Index+1].x = ObjPtr->x+tmp_x;
3506 vs[Index+1].y = ObjPtr->y+tmp_y;
3507 }
3508 if (smooth != NULL) smooth[Index+1] = smooth[Index];
3509 }
3510 }
3511 if (sv != NULL) { free(sv); sv = NULL; }
3512 if (pv != NULL) { free(pv); pv = NULL; }
3513 if (tmp_smooth != NULL) { free(tmp_smooth); tmp_smooth = NULL; }
3514 if (curved == LT_INTSPLINE && cntrlv != NULL) {
3515 free(cntrlv);
3516 cntrlv = NULL;
3517 }
3518 PolygonPtr->n++;
3519 n++;
3520 AdjObjSplineVs(ObjPtr);
3521 if (curved != LT_INTSPLINE) {
3522 UpdPolyBBox(ObjPtr, PolygonPtr->n, PolygonPtr->vlist);
3523 } else {
3524 UpdPolyBBox(ObjPtr, PolygonPtr->intn, PolygonPtr->intvlist);
3525 }
3526 AdjObjBBox(ObjPtr);
3527
3528 UpdSelBBox();
3529 RedrawAreas(botObj,
3530 sel_ltx-GRID_ABS_SIZE(1), sel_lty-GRID_ABS_SIZE(1),
3531 sel_rbx+GRID_ABS_SIZE(1), sel_rby+GRID_ABS_SIZE(1),
3532 selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1),
3533 selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1));
3534 HighLightForward();
3535 SetFileModified(TRUE);
3536 justDupped = FALSE;
3537 } else if (input.type == KeyPress) {
3538 if (KeyPressEventIsEscape(&input.xkey)) {
3539 done = TRUE;
3540 *LastMouseX = new_mouse_x; *LastMouseY = new_mouse_y;
3541 if (curved == LT_INTSPLINE || smooth == NULL || !smooth[Index]) {
3542 MARK(drawWindow, revDefaultGC, OFFSET_X(tx), OFFSET_Y(ty));
3543 } else {
3544 MARKO(drawWindow, revDefaultGC, OFFSET_X(tx), OFFSET_Y(ty));
3545 }
3546 if (already_moved) {
3547 AddPointMeasureCursor(ADDPOINT_ENDSHOW, abs(ABS_X(v[1].x)-tx),
3548 abs(ABS_Y(v[1].y)-ty), ABS_X(v[1].x), ABS_Y(v[1].y));
3549 } else {
3550 AddPointMeasureCursor(ADDPOINT_STARTSHOW, 0, 0, tx, ty);
3551 }
3552 if (already_moved) {
3553 XDrawLines(mainDisplay, drawWindow, revDefaultGC, sv, sn,
3554 CoordModeOrigin);
3555 if (grid_x == orig_x && grid_y == orig_y) {
3556 return FALSE;
3557 }
3558 }
3559 return FALSE;
3560 }
3561 }
3562 }
3563 return TRUE;
3564 }
3565
AddPoint()3566 void AddPoint()
3567 {
3568 int adding=TRUE, pt_added=FALSE, root_x=0, root_y=0, old_x=0, old_y=0;
3569 int curved=(-1);
3570 struct ObjRec *obj_ptr;
3571 struct PolyRec *poly_ptr=NULL;
3572 struct PolygonRec *polygon_ptr=NULL;
3573 unsigned int status=0;
3574 Window root_win=None, child_win=None;
3575
3576 if (!(topSel != NULL && topSel == botSel &&
3577 (topSel->obj->type == OBJ_POLY || topSel->obj->type == OBJ_POLYGON))) {
3578 MsgBox(TgLoadString(STID_SELECT_ONLY_ONE_POLY_POLYGON), TOOL_NAME,
3579 INFO_MB);
3580 return;
3581 } else if (topSel->obj->locked) {
3582 MsgBox(TgLoadString(STID_CANNOT_ADD_PT_FOR_LOCKED), TOOL_NAME, INFO_MB);
3583 return;
3584 } else if (AutoRetractedArrowAttr(topSel->obj, TRUE)) {
3585 MsgBox(TgLoadString(STID_CANNOT_ADD_PT_FOR_AUTO_ARROW), TOOL_NAME,
3586 INFO_MB);
3587 return;
3588 }
3589 if (curChoice == VERTEXMODE) {
3590 HighLightReverse();
3591 JustRemoveAllVSel();
3592 HighLightForward();
3593 }
3594 PrepareToRecord(CMD_REPLACE, topSel, botSel, numObjSelected);
3595 obj_ptr = topSel->obj;
3596 switch (obj_ptr->type) {
3597 case OBJ_POLY:
3598 poly_ptr = obj_ptr->detail.p;
3599 curved = poly_ptr->curved;
3600 break;
3601 case OBJ_POLYGON:
3602 polygon_ptr = obj_ptr->detail.g;
3603 curved = polygon_ptr->curved;
3604 break;
3605 }
3606 SaveStatusStrings();
3607 if (curved == LT_STRUCT_SPLINE) {
3608 SetMouseStatus(TgLoadString(STID_ADD_HINGE_VERTEX),
3609 TgLoadString(STID_ADD_A_SMOOTH_VERTEX),
3610 TgLoadCachedString(CSTID_FINISH));
3611 TwoLineMsg(TgLoadString(STID_LEFT_ADD_HINGE_MID_ADD_SMOOTH),
3612 TgLoadString(STID_CLICK_RIGHT_BUTTON_TO_QUIT));
3613 } else {
3614 SetMouseStatus(TgLoadCachedString(CSTID_ADD_A_VERTEX),
3615 TgLoadCachedString(CSTID_FINISH), TgLoadCachedString(CSTID_FINISH));
3616 TwoLineMsg(TgLoadString(STID_LEFT_BTN_TO_ADD_PTS),
3617 TgLoadString(STID_CLICK_OTHER_BUTTON_TO_QUIT));
3618 }
3619 if (!debugNoPointerGrab) {
3620 XGrabPointer(mainDisplay, drawWindow, False,
3621 PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
3622 GrabModeAsync, GrabModeAsync, None, defaultCursor, CurrentTime);
3623 }
3624 XQueryPointer(mainDisplay, drawWindow, &root_win, &child_win,
3625 &root_x, &root_y, &old_x, &old_y, &status);
3626 XSetFont(mainDisplay, revDefaultGC, defaultFontPtr->fid);
3627 /* do not translate -- program constants */
3628 XDrawString(mainDisplay, drawWindow, revDefaultGC,
3629 old_x+4, old_y+defaultFontAsc, "ADD", 3);
3630 MarkRulers(old_x, old_y);
3631
3632 while (adding) {
3633 XEvent input;
3634
3635 XNextEvent(mainDisplay, &input);
3636
3637 if (input.type == Expose || input.type == VisibilityNotify) {
3638 ExposeEventHandler(&input, TRUE);
3639 } else if (input.type == ButtonPress) {
3640 int index=0;
3641
3642 /* erase */
3643 XDrawString(mainDisplay, drawWindow, revDefaultGC, old_x+4,
3644 old_y+defaultFontAsc, "ADD", 3);
3645 if (curved == LT_STRUCT_SPLINE) {
3646 if (input.xbutton.button == Button1 ||
3647 input.xbutton.button == Button2) {
3648 if (obj_ptr->type == OBJ_POLY &&
3649 PtInPolyMark(obj_ptr, input.xbutton.x, input.xbutton.y,
3650 poly_ptr->ssn, poly_ptr->ssvlist, &index)) {
3651 if (ContinueAddStructuredPolyOrPolygonPoint(obj_ptr,
3652 input.xbutton.button, input.xbutton.x, input.xbutton.y,
3653 index, poly_ptr, NULL, &old_x, &old_y)) {
3654 pt_added = TRUE;
3655 }
3656 } else if (obj_ptr->type == OBJ_POLYGON &&
3657 PtInPolyMark(obj_ptr, input.xbutton.x, input.xbutton.y,
3658 polygon_ptr->ssn-1, polygon_ptr->ssvlist, &index)) {
3659 if (ContinueAddStructuredPolyOrPolygonPoint(obj_ptr,
3660 input.xbutton.button, input.xbutton.x, input.xbutton.y,
3661 index, NULL, polygon_ptr, &old_x, &old_y)) {
3662 pt_added = TRUE;
3663 }
3664 }
3665 XDrawString(mainDisplay, drawWindow, revDefaultGC, old_x+4,
3666 old_y+defaultFontAsc, "ADD", 3);
3667 } else {
3668 XUngrabPointer(mainDisplay, CurrentTime);
3669 Msg("");
3670 adding = FALSE;
3671 }
3672 } else if (input.xbutton.button == Button1) {
3673 if (obj_ptr->type == OBJ_POLY &&
3674 PtInPolyMark(obj_ptr, input.xbutton.x, input.xbutton.y,
3675 poly_ptr->n, poly_ptr->vlist, &index)) {
3676 if (ContinueAddPolyPoint(obj_ptr, input.xbutton.x,
3677 input.xbutton.y, index, poly_ptr, &old_x, &old_y)) {
3678 pt_added = TRUE;
3679 }
3680 } else if (obj_ptr->type == OBJ_POLYGON &&
3681 PtInPolyMark(obj_ptr, input.xbutton.x, input.xbutton.y,
3682 polygon_ptr->n-1, polygon_ptr->vlist, &index)) {
3683 if (ContinueAddPolygonPoint(obj_ptr, input.xbutton.x,
3684 input.xbutton.y, index, polygon_ptr, &old_x, &old_y)) {
3685 pt_added = TRUE;
3686 }
3687 }
3688 XDrawString(mainDisplay, drawWindow, revDefaultGC,
3689 old_x+4, old_y+defaultFontAsc, "ADD", 3);
3690 } else {
3691 XUngrabPointer(mainDisplay, CurrentTime);
3692 Msg("");
3693 adding = FALSE;
3694 }
3695 } else if (input.type == MotionNotify) {
3696 XEvent ev;
3697
3698 /* erase */
3699 XDrawString(mainDisplay, drawWindow, revDefaultGC,
3700 old_x+4, old_y+defaultFontAsc, "ADD", 3);
3701 old_x = input.xmotion.x;
3702 old_y = input.xmotion.y;
3703 /* draw */
3704 XDrawString(mainDisplay, drawWindow, revDefaultGC,
3705 old_x+4, old_y+defaultFontAsc, "ADD", 3);
3706 MarkRulers(old_x, old_y);
3707 while (XCheckMaskEvent(mainDisplay, PointerMotionMask, &ev)) ;
3708 }
3709 }
3710 RestoreStatusStrings();
3711 if (pt_added) {
3712 RecordCmd(CMD_REPLACE, NULL, topSel, botSel, numObjSelected);
3713 } else {
3714 AbortPrepareCmd(CMD_REPLACE);
3715 }
3716 }
3717
FlushUndoBuffer()3718 void FlushUndoBuffer()
3719 {
3720 CleanUpMsg();
3721 CleanUpCmds();
3722 if (FlushColormap()) {
3723 Msg(TgLoadString(STID_UNDO_BUF_AND_CMAP_FLUSHED));
3724 sprintf(gszMsgBox, TgLoadString(STID_NUM_COLORS_ALLOCATED), maxColors);
3725 Msg(gszMsgBox);
3726 } else {
3727 Msg(TgLoadString(STID_UNDO_BUF_FLUSHED));
3728 }
3729 }
3730
RestoreImageWH()3731 void RestoreImageWH()
3732 {
3733 struct XBmRec *xbm_ptr=NULL;
3734 struct XPmRec *xpm_ptr=NULL;
3735 int w, h, image_w=0, image_h=0;
3736 int ltx, lty, rbx, rby;
3737
3738 if (topSel == NULL) {
3739 MsgBox(TgLoadCachedString(CSTID_NO_OBJ_SELECTED), TOOL_NAME, INFO_MB);
3740 return;
3741 } else if (topSel != botSel || (!(topSel->obj->type==OBJ_XBM ||
3742 topSel->obj->type==OBJ_XPM))) {
3743 MsgBox(TgLoadString(STID_SEL_ONE_XBM_OR_XPM_TO_RESTORE), TOOL_NAME,
3744 INFO_MB);
3745 return;
3746 } else if (topSel->obj->locked) {
3747 MsgBox(TgLoadString(STID_CANNOT_RESTORE_LOCKED), TOOL_NAME, INFO_MB);
3748 return;
3749 }
3750 w = topSel->obj->obbox.rbx - topSel->obj->obbox.ltx;
3751 h = topSel->obj->obbox.rby - topSel->obj->obbox.lty;
3752 switch (topSel->obj->type) {
3753 case OBJ_XBM:
3754 xbm_ptr = topSel->obj->detail.xbm;
3755 if (xbm_ptr->real_type==XBM_EPS && xbm_ptr->bitmap==None) {
3756 image_w = xbm_ptr->eps_w;
3757 image_h = xbm_ptr->eps_h;
3758 } else {
3759 image_w = xbm_ptr->image_w;
3760 image_h = xbm_ptr->image_h;
3761 }
3762 if (w == image_w && h == image_h) return;
3763 break;
3764 case OBJ_XPM:
3765 xpm_ptr = topSel->obj->detail.xpm;
3766 image_w = xpm_ptr->image_w; image_h = xpm_ptr->image_h;
3767 if (w == image_w && h == image_h) return;
3768 break;
3769 }
3770 ltx = selLtX; lty = selLtY; rbx = selRbX; rby = selRbY;
3771 HighLightReverse();
3772
3773 PrepareToReplaceAnObj(topSel->obj);
3774 if (topSel->obj->ctm == NULL) {
3775 topSel->obj->obbox.rbx = topSel->obj->obbox.ltx+image_w;
3776 topSel->obj->obbox.rby = topSel->obj->obbox.lty+image_h;
3777 } else {
3778 topSel->obj->obbox.rbx = topSel->obj->obbox.ltx+image_w;
3779 topSel->obj->obbox.rby = topSel->obj->obbox.lty+image_h;
3780 free(topSel->obj->ctm);
3781 topSel->obj->ctm = NULL;
3782 }
3783 topSel->obj->x = topSel->obj->obbox.ltx;
3784 topSel->obj->y = topSel->obj->obbox.lty;
3785 switch (topSel->obj->type) {
3786 case OBJ_XBM:
3787 if (xbm_ptr->cached_bitmap != None) {
3788 XFreePixmap(mainDisplay, xbm_ptr->cached_bitmap);
3789 }
3790 xbm_ptr->cached_bitmap = None;
3791 xbm_ptr->cached_zoom = 0;
3792 break;
3793 case OBJ_XPM:
3794 if (xpm_ptr->cached_pixmap != None) {
3795 XFreePixmap(mainDisplay, xpm_ptr->cached_pixmap);
3796 }
3797 xpm_ptr->cached_pixmap = None;
3798 if (xpm_ptr->cached_bitmap != None) {
3799 XFreePixmap(mainDisplay, xpm_ptr->cached_bitmap);
3800 }
3801 xpm_ptr->cached_bitmap = None;
3802 if (xpm_ptr->clip_mask != None) {
3803 XFreePixmap(mainDisplay, xpm_ptr->clip_mask);
3804 }
3805 xpm_ptr->clip_mask = None;
3806 xpm_ptr->cached_zoom = 0;
3807 xpm_ptr->cached_color = (-1);
3808 break;
3809 }
3810 AdjObjBBox(topSel->obj);
3811 RecordReplaceAnObj(topSel->obj);
3812
3813 UpdSelBBox();
3814 RedrawAreas(botObj, ltx-GRID_ABS_SIZE(1), lty-GRID_ABS_SIZE(1),
3815 rbx+GRID_ABS_SIZE(1), rby+GRID_ABS_SIZE(1),
3816 selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1),
3817 selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1));
3818 HighLightForward();
3819 SetFileModified(TRUE);
3820 justDupped = FALSE;
3821 }
3822
CutMaps()3823 void CutMaps()
3824 {
3825 if (topSel == NULL || topSel != botSel) {
3826 MsgBox(TgLoadString(STID_SEL_ONE_XBM_OR_XPM_TO_CUT), TOOL_NAME,
3827 INFO_MB);
3828 return;
3829 } else if (topSel->obj->locked) {
3830 MsgBox(TgLoadString(STID_CANNOT_CUT_LOCKED), TOOL_NAME, INFO_MB);
3831 return;
3832 } else if (topSel->obj->ctm != NULL) {
3833 MsgBox(TgLoadString(STID_CANNOT_CUT_TRANSFORMED_X_OBJ), TOOL_NAME,
3834 INFO_MB);
3835 return;
3836 }
3837 switch (topSel->obj->type) {
3838 case OBJ_XBM: CutXBitmap(); break;
3839 case OBJ_XPM: CutXPixmap(NULL, NULL, NULL, NULL, NULL); break;
3840 default:
3841 MsgBox(TgLoadString(STID_SEL_ONE_XBM_OR_XPM_TO_CUT), TOOL_NAME,
3842 INFO_MB);
3843 break;
3844 }
3845 }
3846
BreakUpMaps()3847 void BreakUpMaps()
3848 {
3849 int cols=0, rows=0, cols_and_rows=TRUE, ok=TRUE, image_w=0, image_h=0;
3850 char spec[MAXSTRING+1], *dup_spec=NULL, *part1=NULL, *part2=NULL;
3851 struct ObjRec *obj_ptr=NULL;
3852
3853 if (topSel == NULL || topSel != botSel ||
3854 (topSel->obj->type != OBJ_XBM && topSel->obj->type != OBJ_XPM)) {
3855 MsgBox(TgLoadString(STID_SEL_ONE_XBM_OR_XPM_TO_BREAKUP), TOOL_NAME,
3856 INFO_MB);
3857 return;
3858 } else if (topSel->obj->ctm != NULL) {
3859 MsgBox(TgLoadString(STID_CANNOT_BREAK_XFORMED_X_OBJ), TOOL_NAME,
3860 INFO_MB);
3861 return;
3862 } else if (topSel->obj->locked) {
3863 MsgBox(TgLoadString(STID_CANNOT_BREAKUP_LOCKED), TOOL_NAME,
3864 INFO_MB);
3865 return;
3866 }
3867 obj_ptr = topSel->obj;
3868
3869 switch (obj_ptr->type) {
3870 case OBJ_XBM:
3871 image_w=obj_ptr->detail.xbm->image_w;
3872 image_h=obj_ptr->detail.xbm->image_h;
3873 break;
3874 case OBJ_XPM:
3875 image_w=obj_ptr->detail.xpm->image_w;
3876 image_h=obj_ptr->detail.xpm->image_h;
3877 break;
3878 default: return;
3879 }
3880 sprintf(gszMsgBox, TgLoadString(STID_ENTER_NUM_ROWCOL_TO_BREAK),
3881 image_w, image_h);
3882 *spec = '\0';
3883 if (Dialog(gszMsgBox, TgLoadCachedString(CSTID_DLG_ACCEPT_CANCEL), spec) ==
3884 INVALID) {
3885 return;
3886 }
3887 UtilTrimBlanks(spec);
3888 if (*spec == '\0') return;
3889 if ((dup_spec=UtilStrDup(spec)) == NULL) {
3890 FailAllocMessage();
3891 return;
3892 }
3893 if (*dup_spec == '=') cols_and_rows = FALSE;
3894
3895 /* do not translate -- program constants */
3896 if ((part1=strtok(dup_spec, " ,xX=[]")) != NULL &&
3897 (part2=strtok(NULL, " ,xX=[]")) != NULL) {
3898 cols = atoi(part1);
3899 rows = atoi(part2);
3900 if (cols > 0 && rows > 0) {
3901 switch (obj_ptr->type) {
3902 case OBJ_XBM:
3903 BreakUpXBitmap(obj_ptr, cols_and_rows, cols, rows);
3904 break;
3905 case OBJ_XPM:
3906 BreakUpXPixmap(obj_ptr, cols_and_rows, cols, rows);
3907 break;
3908 }
3909 } else {
3910 ok = FALSE;
3911 }
3912 } else {
3913 ok = FALSE;
3914 }
3915 if (!ok) {
3916 sprintf(gszMsgBox, TgLoadString(STID_INVALID_ROWCOL_SPEC_REENTER),
3917 dup_spec);
3918 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
3919 }
3920 free(dup_spec);
3921 }
3922
3923 /* ----------------------- RemoveTransparentPixel ----------------------- */
3924
3925 static
ReproducePixmap(pixel_to_use,orig_pixmap,orig_image,orig_bitmap,orig_bitmap_image,w,h,pixmap_return,image_return,bitmap_return,bitmap_image_return)3926 int ReproducePixmap(pixel_to_use, orig_pixmap, orig_image, orig_bitmap,
3927 orig_bitmap_image, w, h, pixmap_return, image_return, bitmap_return,
3928 bitmap_image_return)
3929 int pixel_to_use, w, h;
3930 Pixmap orig_pixmap, orig_bitmap, *pixmap_return, *bitmap_return;
3931 XImage *orig_image, *orig_bitmap_image, **image_return, **bitmap_image_return;
3932 {
3933 int i=0;
3934 XImage *src_image=NULL, *src_bitmap_image=NULL;
3935
3936 SetWatchCursor(drawWindow);
3937 SetWatchCursor(mainWindow);
3938
3939 *pixmap_return = XCreatePixmap(mainDisplay, mainWindow, w, h, mainDepth);
3940 *bitmap_return = XCreatePixmap(mainDisplay, mainWindow, w, h, 1);
3941
3942 XFillRectangle(mainDisplay, *pixmap_return, xpmGC, 0, 0, w, h);
3943 XSetForeground(mainDisplay, xbmGC, 1);
3944 XFillRectangle(mainDisplay, *bitmap_return, xbmGC, 0, 0, w, h);
3945 XSetForeground(mainDisplay, xbmGC, 0);
3946
3947 *image_return = (*pixmap_return==None ? NULL : XGetImage(mainDisplay,
3948 *pixmap_return, 0, 0, w, h, AllPlanes, ZPixmap));
3949 *bitmap_image_return = (*bitmap_return==None ? NULL : XGetImage(mainDisplay,
3950 *bitmap_return, 0, 0, w, h, 1, ZPixmap));
3951 if (orig_image != NULL) {
3952 src_image = orig_image;
3953 } else {
3954 src_image = XGetImage(mainDisplay, orig_pixmap, 0, 0, w, h, AllPlanes, ZPixmap);
3955 }
3956 if (orig_bitmap_image != NULL) {
3957 src_bitmap_image = orig_bitmap_image;
3958 } else {
3959 src_bitmap_image = XGetImage(mainDisplay, orig_bitmap, 0, 0, w, h, 1, ZPixmap);
3960 }
3961 if (*pixmap_return == None || *bitmap_return == None || *image_return==NULL ||
3962 *bitmap_image_return==NULL || src_image==NULL || src_bitmap_image==NULL) {
3963 if (*pixmap_return == None) {
3964 FailAllocPixmapMessage(w, h);
3965 } else if (*bitmap_return == None) {
3966 FailAllocBitmapMessage(w, h);
3967 } else {
3968 MsgBox(TgLoadString(STID_XGETIMAGE_MAY_RUN_OUT_VMEM), TOOL_NAME,
3969 INFO_MB);
3970 }
3971 if (*pixmap_return != None) XFreePixmap(mainDisplay, *pixmap_return);
3972 if (*bitmap_return != None) XFreePixmap(mainDisplay, *bitmap_return);
3973 if (*image_return != NULL) XDestroyImage(*image_return);
3974 if (*bitmap_image_return != NULL) XDestroyImage(*bitmap_image_return);
3975 if (orig_image != NULL) XDestroyImage(src_image);
3976 if (orig_bitmap_image != NULL) XDestroyImage(src_bitmap_image);
3977 if (orig_image == NULL && src_image != NULL) XDestroyImage(src_image);
3978 if (orig_bitmap_image == NULL && src_bitmap_image != NULL) XDestroyImage(src_bitmap_image);
3979
3980 *pixmap_return = *bitmap_return = None;
3981 *image_return = *bitmap_image_return = NULL;
3982 SetDefaultCursor(mainWindow);
3983 SetDefaultCursor(drawWindow);
3984 return FALSE;
3985 }
3986 for (i=0; i < h; i++) {
3987 int j=0;
3988
3989 for (j=0; j < w; j++) {
3990 if (src_bitmap_image == NULL) {
3991 XPutPixel(*image_return, j, i, XGetPixel(src_image, j, i));
3992 } else {
3993 if (XGetPixel(src_bitmap_image, j, i) != 0) {
3994 XPutPixel(*image_return, j, i, XGetPixel(src_image, j, i));
3995 } else {
3996 XPutPixel(*image_return, j, i, pixel_to_use);
3997 }
3998 }
3999 }
4000 }
4001 XPutImage(mainDisplay, *pixmap_return, xpmGC, *image_return, 0, 0, 0, 0, w, h);
4002 XPutImage(mainDisplay, *bitmap_return, xbmGC, *bitmap_image_return, 0, 0, 0, 0, w, h);
4003 SetDefaultCursor(mainWindow);
4004 SetDefaultCursor(drawWindow);
4005
4006 if (orig_image == NULL && src_image != NULL) XDestroyImage(src_image);
4007 if (orig_bitmap_image == NULL && src_bitmap_image != NULL) XDestroyImage(src_bitmap_image);
4008
4009 return TRUE;
4010 }
4011
4012 static
RemoveObjTransPixel(obj_ptr,ptci)4013 int RemoveObjTransPixel(obj_ptr, ptci)
4014 struct ObjRec *obj_ptr;
4015 TrueColorInfo *ptci;
4016 {
4017 struct XPmRec *xpm_ptr=obj_ptr->detail.xpm;
4018 Pixmap dest_pixmap=None, dest_bitmap=None;
4019 XImage *dest_image=NULL, *dest_bitmap_image=NULL;
4020 int index=(-1);
4021 unsigned char trans_color_r='\0', trans_color_g='\0', trans_color_b='\0';
4022
4023 switch (xpm_ptr->real_type) {
4024 case XPM_XPM:
4025 if (ObjHasIndexedTransPixel(obj_ptr, &index)) {
4026 xpm_ptr->pixels[index] = colorPixels[colorIndex];
4027 UtilFree(xpm_ptr->color_str[index]);
4028 xpm_ptr->color_str[index] = UtilStrDup(colorMenuItems[colorIndex]);
4029 if (xpm_ptr->color_str[index] == NULL) FailAllocMessage();
4030 if (!ReproducePixmap(colorPixels[colorIndex], xpm_ptr->pixmap, xpm_ptr->image, xpm_ptr->bitmap,
4031 xpm_ptr->bitmap_image, xpm_ptr->image_w, xpm_ptr->image_h,
4032 &dest_pixmap, &dest_image, &dest_bitmap, &dest_bitmap_image)) {
4033 return FALSE;
4034 }
4035 xpm_ptr->pixmap = dest_pixmap;
4036 xpm_ptr->image = dest_image;
4037 xpm_ptr->bitmap = dest_bitmap;
4038 xpm_ptr->bitmap_image = dest_bitmap_image;
4039 return TRUE;
4040 }
4041 break;
4042 case XPM_JPEG: break;
4043 case PPM_TRUE:
4044 if (ObjHasTrueColorTransPixel(obj_ptr, &trans_color_r, &trans_color_g, &trans_color_b)) {
4045 unsigned int r=(unsigned int)trans_color_r;
4046 unsigned int g=(unsigned int)trans_color_g;
4047 unsigned int b=(unsigned int)trans_color_b;
4048 int pixel_to_use=((r << ptci->r_shift) & mainVisual->red_mask) |
4049 ((g << ptci->g_shift) & mainVisual->green_mask) |
4050 ((b << ptci->b_shift) & mainVisual->blue_mask) ;
4051
4052 if (!ReproducePixmap(pixel_to_use, xpm_ptr->pixmap, xpm_ptr->image, xpm_ptr->bitmap,
4053 xpm_ptr->bitmap_image, xpm_ptr->image_w, xpm_ptr->image_h,
4054 &dest_pixmap, &dest_image, &dest_bitmap, &dest_bitmap_image)) {
4055 return FALSE;
4056 }
4057 xpm_ptr->pixmap = dest_pixmap;
4058 xpm_ptr->image = dest_image;
4059 xpm_ptr->bitmap = dest_bitmap;
4060 xpm_ptr->bitmap_image = dest_bitmap_image;
4061 xpm_ptr->has_transparent_color = FALSE;
4062 xpm_ptr->transparent_color[0] = (unsigned char)0;
4063 xpm_ptr->transparent_color[1] = (unsigned char)0;
4064 xpm_ptr->transparent_color[2] = (unsigned char)0;
4065 return TRUE;
4066 }
4067 break;
4068 }
4069 /* no change */
4070 return FALSE;
4071 }
4072
RemoveTransparentPixel()4073 void RemoveTransparentPixel()
4074 {
4075 struct ObjRec *obj_ptr=NULL;
4076 struct SelRec *sel_ptr=NULL, *tmp_top_sel=NULL, *tmp_bot_sel=NULL;
4077 int count=0, ltx=0, lty=0, rbx=0, rby=0;
4078 TrueColorInfo tci;
4079
4080 for (sel_ptr=topSel; sel_ptr != NULL; sel_ptr=sel_ptr->next) {
4081 obj_ptr = sel_ptr->obj;
4082 if (obj_ptr->type == OBJ_XPM && ObjHasTransPixel(obj_ptr)) {
4083 AddObjIntoSel(obj_ptr, tmp_bot_sel, NULL, &tmp_top_sel, &tmp_bot_sel);
4084 count++;
4085 }
4086 }
4087 if (count == 0) {
4088 MsgBox(TgLoadString(STID_SEL_ONE_XPM_TRANSPIX), TOOL_NAME, INFO_MB);
4089 return;
4090 }
4091 if (fullTrueColorMode && !SetupTrueColorInfo(&tci)) return;
4092
4093 HighLightReverse();
4094 RemoveAllSel();
4095 topSel = tmp_top_sel;
4096 botSel = tmp_bot_sel;
4097 tmp_top_sel = tmp_bot_sel = NULL;
4098 ltx = selLtX; lty = selLtY; rbx = selRbX; rby = selRbY;
4099
4100 StartCompositeCmd();
4101 for (sel_ptr=topSel; sel_ptr != NULL; sel_ptr=sel_ptr->next) {
4102 obj_ptr = sel_ptr->obj;
4103 PrepareToReplaceAnObj(obj_ptr);
4104
4105 if (RemoveObjTransPixel(obj_ptr, &tci)) {
4106 RecordReplaceAnObj(obj_ptr);
4107 AdjObjCache(obj_ptr);
4108 } else {
4109 AbortPrepareCmd(CMD_REPLACE);
4110 }
4111 }
4112 EndCompositeCmd();
4113
4114 UpdSelBBox();
4115 RedrawAnArea(botObj, ltx-GRID_ABS_SIZE(1), lty-GRID_ABS_SIZE(1),
4116 rbx+GRID_ABS_SIZE(1), rby+GRID_ABS_SIZE(1));
4117 HighLightForward();
4118 SetFileModified(TRUE);
4119 justDupped = FALSE;
4120 }
4121
4122 /* ----------------------- LayoutOnArc ----------------------- */
4123
4124 typedef struct BoxInfoRec {
4125 struct ObjRec *obj;
4126 int w, h;
4127 int valid_v;
4128 double half_w, angle_in_radian, angle_to_rotate;
4129 XPoint v[5];
4130 } *BoxInfoPtr;
4131
4132 #define LAYOUT_DIR_NONE 0
4133 #define LAYOUT_DIR_S 1 /* convex */
4134 #define LAYOUT_DIR_N 2 /* concave */
4135
4136 int gnLayoutDirection=LAYOUT_DIR_NONE;
4137
4138 static
RotateXY(x,y,angle_in_radian,new_x,new_y)4139 void RotateXY(x, y, angle_in_radian, new_x, new_y)
4140 int x, y;
4141 double angle_in_radian;
4142 short *new_x, *new_y;
4143 {
4144 if (x == 0 && y == 0) {
4145 *new_x = 0;
4146 *new_y = 0;
4147 } else {
4148 double sin_val = sin(angle_in_radian);
4149 double cos_val = cos(angle_in_radian);
4150
4151 *new_x = (short)round(x*cos_val - y*sin_val);
4152 *new_y = (short)round(x*sin_val + y*cos_val);
4153 }
4154 }
4155
4156 static
RotateBBoxByRadian(bbox,angle_in_radian,v)4157 void RotateBBoxByRadian(bbox, angle_in_radian, v)
4158 struct BBRec *bbox;
4159 double angle_in_radian;
4160 XPoint *v; /* array of 5 points */
4161 {
4162 RotateXY(bbox->ltx, bbox->lty, angle_in_radian, &(v[0].x), &(v[0].y));
4163 RotateXY(bbox->rbx, bbox->lty, angle_in_radian, &(v[1].x), &(v[1].y));
4164 RotateXY(bbox->rbx, bbox->rby, angle_in_radian, &(v[2].x), &(v[2].y));
4165 RotateXY(bbox->ltx, bbox->rby, angle_in_radian, &(v[3].x), &(v[3].y));
4166 v[4].x = v[0].x; v[4].y = v[0].y;
4167 }
4168
4169 #define SET_LAYOUT_VS (FALSE)
4170 #define FINALIZE_LAYOUT (TRUE)
4171
4172 static
HighLightOrFinalLayout(arc_ptr,box_info_ptr,grid_x,grid_y,finalize)4173 int HighLightOrFinalLayout(arc_ptr, box_info_ptr, grid_x, grid_y, finalize)
4174 struct ArcRec *arc_ptr;
4175 struct BoxInfoRec *box_info_ptr;
4176 int grid_x, grid_y, finalize;
4177 {
4178 int i, num_objects=numObjSelected-1, circular=FALSE;
4179 int abs_cx, abs_cy, abs_x=ABS_X(grid_x), abs_y=ABS_Y(grid_y), dx, dy;
4180 double abs_radius, total_arc_radian, total_radian=0, inc_radian=0, angle;
4181
4182 if (abs(arc_ptr->angle2) == (360<<6)) {
4183 circular = TRUE;
4184 }
4185 abs_cx = arc_ptr->xc;
4186 abs_cy = arc_ptr->yc;
4187 dx = abs_x - abs_cx;
4188 dy = abs_y - abs_cy;
4189 if (dx == 0 && dy == 0) {
4190 box_info_ptr[0].valid_v = FALSE;
4191 return FALSE;
4192 }
4193 box_info_ptr[0].valid_v = TRUE;
4194 total_arc_radian = ((double)arc_ptr->angle2)*M_PI/((double)180.0*64.0);
4195 abs_radius = (double)sqrt((double)(dx*dx+dy*dy));
4196 for (i=0; i < num_objects; i++) {
4197 if (!finalize) {
4198 box_info_ptr[i].angle_in_radian = atan2(box_info_ptr[i].half_w,
4199 abs_radius) * ((double)2.0);
4200 }
4201 total_radian += fabs(box_info_ptr[i].angle_in_radian);
4202 }
4203 switch (gnLayoutDirection) {
4204 case LAYOUT_DIR_S:
4205 if (circular) {
4206 inc_radian = (total_arc_radian-total_radian)/((double)num_objects);
4207 } else {
4208 inc_radian = (total_arc_radian-total_radian)/((double)(num_objects-1));
4209 }
4210 break;
4211 case LAYOUT_DIR_N:
4212 if (circular) {
4213 inc_radian = (total_arc_radian+total_radian)/((double)num_objects);
4214 } else {
4215 inc_radian = (total_arc_radian+total_radian)/((double)(num_objects-1));
4216 }
4217 break;
4218 }
4219 angle = arc_ptr->angle1*M_PI/((double)180.0*64.0);
4220 for (i=0; i < num_objects; i++, angle+=inc_radian) {
4221 struct ObjRec *obj_ptr=box_info_ptr[i].obj;
4222 int x=0, y=0, w=0, h=0, orig_x=0, orig_y=0;
4223 XPoint v[5];
4224 struct BBRec bbox;
4225 double half_way_angle=(double)0.0;
4226
4227 w = box_info_ptr[i].w;
4228 h = box_info_ptr[i].h;
4229 if (finalize) {
4230 if (obj_ptr->type == OBJ_TEXT &&
4231 obj_ptr->detail.t->minilines.just != JUST_C) {
4232 ChangeObjTextJust(obj_ptr, JUST_C);
4233 }
4234 }
4235 /*
4236 * half_way_angle measures angle in the arc sense (see the beginning
4237 * of "arc.c").
4238 * the RoateaBBoxByRadian() rotates things in the drawing sense
4239 * (the one that's vertically flipped w.r.t. PostScript)
4240 */
4241 switch (gnLayoutDirection) {
4242 case LAYOUT_DIR_S:
4243 half_way_angle = angle+(box_info_ptr[i].angle_in_radian/2.0);
4244 if (finalize) {
4245 orig_x = ((obj_ptr->obbox.rbx+obj_ptr->obbox.ltx)>>1);
4246 orig_y = obj_ptr->obbox.lty;
4247 RotateObjForLayout(obj_ptr, box_info_ptr[i].angle_to_rotate,
4248 CORNER_BOTTOM);
4249 x = abs_cx + (int)((abs_radius-h)*cos(half_way_angle));
4250 y = abs_cy - (int)((abs_radius-h)*sin(half_way_angle));
4251 } else {
4252 SetBBRec(&bbox, -(w>>1), -h, w-(w>>1), 0);
4253 box_info_ptr[i].angle_to_rotate = (-half_way_angle-(M_PI/2.0));
4254 RotateBBoxByRadian(&bbox, box_info_ptr[i].angle_to_rotate, v);
4255 x = abs_cx + (int)(abs_radius*cos(half_way_angle));
4256 y = abs_cy - (int)(abs_radius*sin(half_way_angle));
4257 }
4258 break;
4259 case LAYOUT_DIR_N:
4260 half_way_angle = angle-(box_info_ptr[i].angle_in_radian/2.0);
4261 if (finalize) {
4262 orig_x = ((obj_ptr->obbox.rbx+obj_ptr->obbox.ltx)>>1);
4263 orig_y = obj_ptr->obbox.rby;
4264 RotateObjForLayout(obj_ptr, box_info_ptr[i].angle_to_rotate,
4265 CORNER_TOP);
4266 x = abs_cx + (int)((abs_radius-h)*cos(half_way_angle));
4267 y = abs_cy - (int)((abs_radius-h)*sin(half_way_angle));
4268 } else {
4269 SetBBRec(&bbox, -(w>>1), 0, w-(w>>1), h);
4270 box_info_ptr[i].angle_to_rotate = (-half_way_angle+(M_PI/2.0));
4271 RotateBBoxByRadian(&bbox, box_info_ptr[i].angle_to_rotate, v);
4272 x = abs_cx + (int)(abs_radius*cos(half_way_angle));
4273 y = abs_cy - (int)(abs_radius*sin(half_way_angle));
4274 }
4275 break;
4276 }
4277 if (finalize) {
4278 MoveObj(obj_ptr, x-orig_x, y-orig_y);
4279 } else {
4280 box_info_ptr[i].v[0].x = OFFSET_X(x + v[0].x);
4281 box_info_ptr[i].v[0].y = OFFSET_Y(y + v[0].y);
4282 box_info_ptr[i].v[1].x = OFFSET_X(x + v[1].x);
4283 box_info_ptr[i].v[1].y = OFFSET_Y(y + v[1].y);
4284 box_info_ptr[i].v[2].x = OFFSET_X(x + v[2].x);
4285 box_info_ptr[i].v[2].y = OFFSET_Y(y + v[2].y);
4286 box_info_ptr[i].v[3].x = OFFSET_X(x + v[3].x);
4287 box_info_ptr[i].v[3].y = OFFSET_Y(y + v[3].y);
4288 box_info_ptr[i].v[4].x = box_info_ptr[i].v[0].x;
4289 box_info_ptr[i].v[4].y = box_info_ptr[i].v[0].y;
4290 }
4291 switch (gnLayoutDirection) {
4292 case LAYOUT_DIR_S:
4293 angle += box_info_ptr[i].angle_in_radian;
4294 break;
4295 case LAYOUT_DIR_N:
4296 angle -= box_info_ptr[i].angle_in_radian;
4297 break;
4298 }
4299 }
4300 return TRUE;
4301 }
4302
4303 #define NO_GENERATE 0
4304 #define GENERATE 1
4305
4306 static
HighLightLayout(arc_ptr,box_info_ptr,grid_x,grid_y,generate)4307 void HighLightLayout(arc_ptr, box_info_ptr, grid_x, grid_y, generate)
4308 struct ArcRec *arc_ptr;
4309 struct BoxInfoRec *box_info_ptr;
4310 int grid_x, grid_y, generate;
4311 {
4312 int i, num_objects=numObjSelected-1;
4313
4314 if (generate) {
4315 HighLightOrFinalLayout(arc_ptr, box_info_ptr, grid_x, grid_y,
4316 SET_LAYOUT_VS);
4317 }
4318 if (box_info_ptr[0].valid_v) {
4319 for (i=0; i < num_objects; i++) {
4320 XDrawLines(mainDisplay, drawWindow, revDefaultGC, box_info_ptr[i].v, 5,
4321 CoordModeOrigin);
4322 }
4323 }
4324 }
4325
4326 static
DoLayoutOnArc(arc_obj,box_info_ptr)4327 void DoLayoutOnArc(arc_obj, box_info_ptr)
4328 struct ObjRec *arc_obj;
4329 struct BoxInfoRec *box_info_ptr;
4330 {
4331 struct ArcRec *arc_ptr=arc_obj->detail.a;
4332 int done=FALSE, something_changed=FALSE, grid_x=0, grid_y=0;
4333
4334 SetMouseStatus(TgLoadCachedString(CSTID_START_LAYOUT_ON_ARC),
4335 TgLoadCachedString(CSTID_FINISH), TgLoadCachedString(CSTID_FINISH));
4336 if (!debugNoPointerGrab) {
4337 XGrabPointer(mainDisplay, drawWindow, FALSE,
4338 PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
4339 GrabModeAsync, GrabModeAsync, None, handCursor, CurrentTime);
4340 }
4341 while (!done) {
4342 XEvent input;
4343
4344 XNextEvent(mainDisplay, &input);
4345 switch (input.type) {
4346 case Expose: ExposeEventHandler(&input, TRUE); break;
4347 case VisibilityNotify: ExposeEventHandler(&input, TRUE); break;
4348 case ButtonPress:
4349 if (input.xbutton.button == Button1) {
4350 SetMouseStatus(TgLoadCachedString(CSTID_END_LAYOUT_ON_ARC), "", "");
4351 GridXY(input.xbutton.x, input.xbutton.y, &grid_x, &grid_y);
4352 HighLightLayout(arc_ptr, box_info_ptr, grid_x, grid_y, GENERATE);
4353 something_changed = TRUE;
4354 } else {
4355 XUngrabPointer(mainDisplay, CurrentTime);
4356 XSync(mainDisplay, False);
4357 done = TRUE;
4358 }
4359 break;
4360 case MotionNotify:
4361 if (something_changed) {
4362 HighLightLayout(arc_ptr, box_info_ptr, grid_x, grid_y, NO_GENERATE);
4363 GridXY(input.xmotion.x, input.xmotion.y, &grid_x, &grid_y);
4364 HighLightLayout(arc_ptr, box_info_ptr, grid_x, grid_y, GENERATE);
4365 }
4366 break;
4367 case ButtonRelease:
4368 XUngrabPointer(mainDisplay, CurrentTime);
4369 XSync(mainDisplay, False);
4370 done = TRUE;
4371 HighLightLayout(arc_ptr, box_info_ptr, grid_x, grid_y, NO_GENERATE);
4372 }
4373 }
4374 if (something_changed && box_info_ptr[0].valid_v) {
4375 int ltx=selLtX, lty=selLtY, rbx=selRbX, rby=selRbY;
4376
4377 HighLightReverse();
4378 PrepareToRecord(CMD_REPLACE, topSel, botSel, numObjSelected);
4379 if (HighLightOrFinalLayout(arc_ptr, box_info_ptr, grid_x, grid_y,
4380 FINALIZE_LAYOUT)) {
4381 RecordCmd(CMD_REPLACE, NULL, topSel, botSel, numObjSelected);
4382 UpdSelBBox();
4383 RedrawAreas(botObj, ltx-GRID_ABS_SIZE(1), lty-GRID_ABS_SIZE(1),
4384 rbx+GRID_ABS_SIZE(1), rby+GRID_ABS_SIZE(1),
4385 selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1),
4386 selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1));
4387 SetFileModified(TRUE);
4388 justDupped = FALSE;
4389 } else {
4390 AbortPrepareCmd(CMD_REPLACE);
4391 }
4392 HighLightForward();
4393 }
4394 }
4395
4396 static
ObjsAlreadySorted(box_info_ptr,min_index,max_index)4397 int ObjsAlreadySorted(box_info_ptr, min_index, max_index)
4398 struct BoxInfoRec *box_info_ptr;
4399 int min_index, max_index;
4400 {
4401 int i;
4402
4403 for (i=min_index; i < max_index; i++) {
4404 int d=box_info_ptr[i].obj->obbox.ltx-box_info_ptr[i+1].obj->obbox.ltx;
4405
4406 if (d > 0) {
4407 return FALSE;
4408 } else if (d == 0 &&
4409 box_info_ptr[i].obj->obbox.lty > box_info_ptr[i+1].obj->obbox.lty) {
4410 return FALSE;
4411 }
4412 }
4413 return TRUE;
4414 }
4415
4416 static
QuickSortObjs(box_info_ptr,min_index,max_index,level)4417 void QuickSortObjs(box_info_ptr, min_index, max_index, level)
4418 struct BoxInfoRec *box_info_ptr;
4419 int min_index, max_index, level;
4420 {
4421 int i, j, pivot_index, pivot_x_value, pivot_y_value, something_swapped;
4422 struct ObjRec *tmp_obj;
4423
4424 if (min_index > max_index) return;
4425 if (ObjsAlreadySorted(box_info_ptr, min_index, max_index)) return;
4426 pivot_index = max_index;
4427 pivot_x_value = box_info_ptr[pivot_index].obj->obbox.ltx;
4428 pivot_y_value = box_info_ptr[pivot_index].obj->obbox.lty;
4429 i = min_index;
4430 j = max_index-1;
4431 something_swapped = FALSE;
4432 do {
4433 int d;
4434
4435 while (TRUE) {
4436 d = box_info_ptr[i].obj->obbox.ltx-pivot_x_value;
4437 if (d < 0 || (d == 0 &&
4438 box_info_ptr[i].obj->obbox.lty < pivot_y_value)) {
4439 i++;
4440 } else {
4441 break;
4442 }
4443 }
4444 while (j > i) {
4445 d = box_info_ptr[j].obj->obbox.ltx-pivot_x_value;
4446 if (d > 0 || (d == 0 &&
4447 box_info_ptr[j].obj->obbox.lty > pivot_y_value)) {
4448 j--;
4449 } else {
4450 break;
4451 }
4452 }
4453 if (j > i) {
4454 tmp_obj = box_info_ptr[j].obj;
4455 box_info_ptr[j].obj = box_info_ptr[i].obj;
4456 box_info_ptr[i].obj = tmp_obj;
4457 something_swapped = TRUE;
4458 if (j == i+1) break;
4459 i++; j--;
4460 } else {
4461 break;
4462 }
4463 } while (TRUE);
4464 if (i == max_index) {
4465 /* pivot corresponds to the largest */
4466 if (something_swapped) {
4467 #ifdef _TGIF_DBG /* debug, do not translate */
4468 fprintf(stderr, "Huh? min_index=%1d, max_index=%1d, level=%1d\n",
4469 min_index, max_index, level);
4470 #endif /* _TGIF_DBG */
4471 } else {
4472 QuickSortObjs(box_info_ptr, min_index, j, level+1);
4473 }
4474 } else if (j > i) {
4475 tmp_obj = box_info_ptr[max_index].obj;
4476 box_info_ptr[max_index].obj = box_info_ptr[j].obj;
4477 box_info_ptr[j].obj = tmp_obj;
4478 QuickSortObjs(box_info_ptr, min_index, j-1, level+1);
4479 QuickSortObjs(box_info_ptr, j+1, max_index, level+1);
4480 } else {
4481 tmp_obj = box_info_ptr[max_index].obj;
4482 box_info_ptr[max_index].obj = box_info_ptr[i].obj;
4483 box_info_ptr[i].obj = tmp_obj;
4484 QuickSortObjs(box_info_ptr, min_index, i-1, level+1);
4485 QuickSortObjs(box_info_ptr, i+1, max_index, level+1);
4486 }
4487 }
4488
4489 static
DecideLayoutDirection(obj_ptr)4490 int DecideLayoutDirection(obj_ptr)
4491 struct ObjRec *obj_ptr;
4492 {
4493 struct ArcRec *arc_ptr=obj_ptr->detail.a;
4494 struct BBRec *p_obbox=(&obj_ptr->obbox);
4495 int cx=arc_ptr->xc, cy=arc_ptr->yc, h_slack, v_slack;
4496 char spec[MAXSTRING+1];
4497
4498 h_slack = ((p_obbox->ltx+p_obbox->rbx)>>1) - cx;
4499 v_slack = ((p_obbox->lty+p_obbox->rby)>>1) - cy;
4500 if (h_slack == 0) {
4501 if (v_slack == 0) {
4502 return LAYOUT_DIR_S;
4503 } else if (v_slack > 0) {
4504 return LAYOUT_DIR_S;
4505 } else {
4506 return LAYOUT_DIR_N;
4507 }
4508 }
4509 *spec = '\0';
4510 if (Dialog(TgLoadString(STID_ENTER_CONCAVE_OR_CONVEX), NULL, spec) ==
4511 INVALID) {
4512 return LAYOUT_DIR_NONE;
4513 }
4514 UtilTrimBlanks(spec);
4515 /* do not translate -- program constants */
4516 if (UtilStrICmp(spec, "concave") == 0) {
4517 return LAYOUT_DIR_N;
4518 } else if (UtilStrICmp(spec, "convex") == 0) {
4519 return LAYOUT_DIR_S;
4520 } else {
4521 switch (*spec) {
4522 case 'c': case 'C': return LAYOUT_DIR_N;
4523 case 'v': case 'V': return LAYOUT_DIR_S;
4524 }
4525 }
4526 sprintf(gszMsgBox, TgLoadString(STID_INVALID_SPEC), spec);
4527 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
4528 return LAYOUT_DIR_NONE;
4529 }
4530
LayoutOnArc()4531 void LayoutOnArc()
4532 {
4533 struct SelRec *sel_ptr;
4534 struct ObjRec *arc_obj=NULL;
4535 int arc_obj_count=0, i, something_locked=FALSE;
4536 struct BoxInfoRec *box_info_ptr;
4537
4538 if (curChoice != NOTHING) {
4539 MsgBox(TgLoadString(STID_SEL_AN_ARC_OBJ), TOOL_NAME, INFO_MB);
4540 return;
4541 }
4542 for (sel_ptr=topSel; sel_ptr != NULL; sel_ptr=sel_ptr->next) {
4543 struct ObjRec *obj_ptr=sel_ptr->obj;
4544
4545 if (obj_ptr->type == OBJ_ARC) {
4546 arc_obj_count++;
4547 arc_obj = obj_ptr;
4548 } else if (obj_ptr->locked) {
4549 something_locked = TRUE;
4550 }
4551 }
4552 if (arc_obj_count == 0) {
4553 MsgBox(TgLoadString(STID_NO_ARC_OBJ_SELECTED), TOOL_NAME, INFO_MB);
4554 return;
4555 } else if (arc_obj_count > 1) {
4556 MsgBox(TgLoadString(STID_TOO_MANY_ARC_SEL_ONLY_ONE_ARC), TOOL_NAME,
4557 INFO_MB);
4558 return;
4559 } else if (numObjSelected == 1) {
4560 MsgBox(TgLoadString(STID_NO_OTHER_OBJ_FOR_LAYOUTONARC), TOOL_NAME,
4561 INFO_MB);
4562 return;
4563 } else if (something_locked) {
4564 MsgBox(TgLoadString(STID_CANNOT_LAYOUTONARC_LOCKED), TOOL_NAME, INFO_MB);
4565 return;
4566 }
4567 if (arc_obj->ctm != NULL || arc_obj->detail.a->w != arc_obj->detail.a->h) {
4568 MsgBox(TgLoadString(STID_ARC_XFORMED_FOR_LAYOUTONARC), TOOL_NAME,
4569 INFO_MB);
4570 return;
4571 }
4572 gnLayoutDirection = DecideLayoutDirection(arc_obj);
4573 if (gnLayoutDirection == LAYOUT_DIR_NONE) {
4574 return;
4575 }
4576 box_info_ptr = (struct BoxInfoRec *)malloc(
4577 (numObjSelected-1)*sizeof(struct BoxInfoRec));
4578 if (box_info_ptr == NULL) {
4579 FailAllocMessage();
4580 return;
4581 }
4582 for (i=0, sel_ptr=topSel; sel_ptr != NULL; sel_ptr=sel_ptr->next) {
4583 struct ObjRec *obj_ptr=sel_ptr->obj;
4584
4585 if (obj_ptr->type != OBJ_ARC) {
4586 box_info_ptr[i].obj = obj_ptr;
4587 i++;
4588 }
4589 }
4590 QuickSortObjs(box_info_ptr, 0, numObjSelected-2, 0);
4591 for (i=0; i < numObjSelected-1; i++) {
4592 struct ObjRec *obj_ptr=box_info_ptr[i].obj;
4593
4594 box_info_ptr[i].w = obj_ptr->obbox.rbx-obj_ptr->obbox.ltx;
4595 box_info_ptr[i].h = obj_ptr->obbox.rby-obj_ptr->obbox.lty;
4596 box_info_ptr[i].half_w = (double)(box_info_ptr[i].w>>1);
4597 box_info_ptr[i].valid_v = FALSE;
4598 }
4599 SaveStatusStrings();
4600 DoLayoutOnArc(arc_obj, box_info_ptr);
4601 RestoreStatusStrings();
4602 free(box_info_ptr);
4603 }
4604
4605 /* ----------------------- PreciseRotate ----------------------- */
4606
4607 static
FinishPreciseRotate(angle_spec,pivot_x,pivot_y)4608 int FinishPreciseRotate(angle_spec, pivot_x, pivot_y)
4609 double angle_spec;
4610 int pivot_x, pivot_y;
4611 {
4612 struct SelRec *sel_ptr;
4613 double angle_in_radian=angle_spec*M_PI/180.0;
4614 double sin_val=sin(angle_in_radian);
4615 double cos_val=cos(angle_in_radian);
4616
4617 for (sel_ptr=topSel; sel_ptr != NULL; sel_ptr=sel_ptr->next) {
4618 struct ObjRec *obj_ptr=sel_ptr->obj;
4619 int orig_x=((obj_ptr->obbox.ltx+obj_ptr->obbox.rbx)>>1);
4620 int orig_y=obj_ptr->obbox.lty;
4621 int x=0, y=0, dx=orig_x-pivot_x, dy=orig_y-pivot_y;
4622
4623 if (dx != 0 || dy != 0) {
4624 x = (short)round(dx*cos_val - dy*sin_val);
4625 y = (short)round(dx*sin_val + dy*cos_val);
4626 }
4627 x += pivot_x;
4628 y += pivot_y;
4629 /* RotateObjForLayout() rotates about center-top */
4630 RotateObjForLayout(obj_ptr, angle_in_radian, CORNER_BOTTOM);
4631 MoveObj(obj_ptr, x-orig_x, y-orig_y);
4632 }
4633 return TRUE;
4634 }
4635
PreciseRotate()4636 void PreciseRotate()
4637 {
4638 char spec[MAXSTRING+1];
4639 double angle_spec;
4640 int arc_count=0, pivot_x=0, pivot_y=0, ltx, lty, rbx, rby;
4641 struct SelRec *sel_ptr;
4642 struct ObjRec *arc_obj=NULL;
4643
4644 if (curChoice == VERTEXMODE) {
4645 MsgBox(TgLoadString(STID_ROT_NOT_AVAIL_ON_VERTEX_MODE), TOOL_NAME,
4646 INFO_MB);
4647 return;
4648 } else if (curChoice != NOTHING || topSel == NULL) {
4649 MsgBox(TgLoadCachedString(CSTID_NO_OBJ_SELECTED), TOOL_NAME, INFO_MB);
4650 return;
4651 }
4652 for (sel_ptr=topSel; sel_ptr != NULL; sel_ptr=sel_ptr->next) {
4653 if (sel_ptr->obj->type == OBJ_ARC) {
4654 arc_obj = sel_ptr->obj;
4655 arc_count++;
4656 }
4657 }
4658 if (!autoRotatePivot && rotatePivotAbsXYValid) {
4659 pivot_x = rotatePivotAbsX;
4660 pivot_y = rotatePivotAbsY;
4661 } else {
4662 if (arc_count == 1) {
4663 if (arc_obj->ctm == NULL) {
4664 pivot_x = arc_obj->detail.a->xc;
4665 pivot_y = arc_obj->detail.a->yc;
4666 } else {
4667 struct ArcRec *arc_ptr=arc_obj->detail.a;
4668 int x, y;
4669
4670 TransformPointThroughCTM(arc_ptr->xc-arc_obj->x,
4671 arc_ptr->yc-arc_obj->y, arc_obj->ctm, &x, &y);
4672 pivot_x = x + arc_obj->x;
4673 pivot_y = y + arc_obj->y;
4674 }
4675 } else {
4676 pivot_x = (selObjLtX+selObjRbX)>>1;
4677 pivot_y = (selObjLtY+selObjRbY)>>1;
4678 }
4679 }
4680 *spec = '\0';
4681 Dialog(TgLoadString(STID_ENTER_AN_ANGLE_IN_DEGREES), NULL, spec);
4682 UtilTrimBlanks(spec);
4683 if (*spec == '\0') return;
4684 if (sscanf(spec, "%lf", &angle_spec) != 1) {
4685 sprintf(gszMsgBox, TgLoadString(STID_INVALID_SPEC_NUM_EXPECTED), spec);
4686 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
4687 return;
4688 }
4689 if (fabs(angle_spec) < (1.0e-5)) return;
4690
4691 ltx = selLtX; lty = selLtY; rbx = selRbX; rby = selRbY;
4692 HighLightReverse();
4693 PrepareToRecord(CMD_REPLACE, topSel, botSel, numObjSelected);
4694 if (FinishPreciseRotate(angle_spec, pivot_x, pivot_y)) {
4695 RecordCmd(CMD_REPLACE, NULL, topSel, botSel, numObjSelected);
4696 UpdSelBBox();
4697 RedrawAreas(botObj, ltx-GRID_ABS_SIZE(1), lty-GRID_ABS_SIZE(1),
4698 rbx+GRID_ABS_SIZE(1), rby+GRID_ABS_SIZE(1),
4699 selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1),
4700 selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1));
4701 SetFileModified(TRUE);
4702 justDupped = FALSE;
4703 } else {
4704 AbortPrepareCmd(CMD_REPLACE);
4705 }
4706 HighLightForward();
4707 }
4708
RotateAllSelObj(angle_spec)4709 void RotateAllSelObj(angle_spec)
4710 double angle_spec;
4711 {
4712 int arc_count=0, pivot_x=0, pivot_y=0, ltx, lty, rbx, rby;
4713 struct SelRec *sel_ptr;
4714 struct ObjRec *arc_obj=NULL;
4715
4716 if (curChoice != NOTHING || topSel == NULL) {
4717 MsgBox(TgLoadCachedString(CSTID_NO_OBJ_SELECTED), TOOL_NAME, INFO_MB);
4718 return;
4719 }
4720 for (sel_ptr=topSel; sel_ptr != NULL; sel_ptr=sel_ptr->next) {
4721 if (sel_ptr->obj->type == OBJ_ARC) {
4722 arc_obj = sel_ptr->obj;
4723 arc_count++;
4724 }
4725 }
4726 if (arc_count == 1) {
4727 if (arc_obj->ctm == NULL) {
4728 pivot_x = arc_obj->detail.a->xc;
4729 pivot_y = arc_obj->detail.a->yc;
4730 } else {
4731 struct ArcRec *arc_ptr=arc_obj->detail.a;
4732 int x, y;
4733
4734 TransformPointThroughCTM(arc_ptr->xc-arc_obj->x,
4735 arc_ptr->yc-arc_obj->y, arc_obj->ctm, &x, &y);
4736 pivot_x = x + arc_obj->x;
4737 pivot_y = y + arc_obj->y;
4738 }
4739 } else {
4740 pivot_x = (selObjLtX+selObjRbX)>>1;
4741 pivot_y = (selObjLtY+selObjRbY)>>1;
4742 }
4743 if (fabs(angle_spec) < (1.0e-5)) return;
4744
4745 ltx = selLtX; lty = selLtY; rbx = selRbX; rby = selRbY;
4746 HighLightReverse();
4747 PrepareToRecord(CMD_REPLACE, topSel, botSel, numObjSelected);
4748 FinishPreciseRotate(angle_spec, pivot_x, pivot_y);
4749 RecordCmd(CMD_REPLACE, NULL, topSel, botSel, numObjSelected);
4750 UpdSelBBox();
4751 RedrawAreas(botObj, ltx-GRID_ABS_SIZE(1), lty-GRID_ABS_SIZE(1),
4752 rbx+GRID_ABS_SIZE(1), rby+GRID_ABS_SIZE(1),
4753 selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1),
4754 selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1));
4755 HighLightForward();
4756 SetFileModified(TRUE);
4757 justDupped = FALSE;
4758 }
4759
NoTransform()4760 void NoTransform()
4761 {
4762 struct SelRec *sel_ptr;
4763 int changed=FALSE, grouped=FALSE;
4764 int ltx=selLtX, lty=selLtY, rbx=selRbX, rby=selRbY;
4765
4766 if (topSel == NULL) {
4767 MsgBox(TgLoadCachedString(CSTID_NO_OBJ_SELECTED), TOOL_NAME, INFO_MB);
4768 return;
4769 }
4770 HighLightReverse();
4771 StartCompositeCmd();
4772 for (sel_ptr=topSel; sel_ptr != NULL; sel_ptr=sel_ptr->next) {
4773 struct ObjRec *obj_ptr=sel_ptr->obj;
4774
4775 if (obj_ptr->ctm != NULL) {
4776 int cx=0, cy=0;
4777
4778 switch (obj_ptr->type) {
4779 case OBJ_GROUP:
4780 case OBJ_SYM:
4781 case OBJ_ICON:
4782 case OBJ_PIN:
4783 grouped = TRUE;
4784 break;
4785
4786 default:
4787 cx = ((obj_ptr->obbox.ltx+obj_ptr->obbox.rbx)>>1);
4788 cy = ((obj_ptr->obbox.lty+obj_ptr->obbox.rby)>>1);
4789
4790 changed = TRUE;
4791 PrepareToReplaceAnObj(obj_ptr);
4792 free(obj_ptr->ctm);
4793 obj_ptr->ctm = NULL;
4794 memcpy(&obj_ptr->obbox, &obj_ptr->orig_obbox, sizeof(struct BBRec));
4795 if (obj_ptr->type == OBJ_TEXT) {
4796 memcpy(&obj_ptr->bbox, &obj_ptr->detail.t->orig_bbox,
4797 sizeof(struct BBRec));
4798 }
4799 AdjObjSplineVs(obj_ptr);
4800 AdjObjCache(obj_ptr);
4801 AdjObjBBox(obj_ptr);
4802 MoveObj(obj_ptr,
4803 cx-((obj_ptr->obbox.ltx+obj_ptr->obbox.rbx)>>1),
4804 cy-((obj_ptr->obbox.lty+obj_ptr->obbox.rby)>>1));
4805 RecordReplaceAnObj(obj_ptr);
4806 break;
4807 }
4808 } else {
4809 switch (obj_ptr->type) {
4810 case OBJ_GROUP:
4811 case OBJ_SYM:
4812 case OBJ_ICON:
4813 case OBJ_PIN:
4814 grouped = TRUE;
4815 break;
4816
4817 default: break;
4818 }
4819 }
4820 }
4821 EndCompositeCmd();
4822 if (changed) {
4823 UpdSelBBox();
4824 RedrawAreas(botObj, ltx-GRID_ABS_SIZE(1), lty-GRID_ABS_SIZE(1),
4825 rbx+GRID_ABS_SIZE(1), rby+GRID_ABS_SIZE(1),
4826 selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1),
4827 selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1));
4828 HighLightForward();
4829 SetFileModified(TRUE);
4830 justDupped = FALSE;
4831
4832 if (grouped) {
4833 Msg(TgLoadString(STID_SOME_GROUP_OBJ_NOT_MODIFIED));
4834 }
4835 } else {
4836 if (grouped) {
4837 MsgBox(TgLoadString(STID_CANNOT_REM_XFORM_FOR_GROUPED), TOOL_NAME,
4838 INFO_MB);
4839 }
4840 HighLightForward();
4841 }
4842 }
4843
SetEditTextSize()4844 void SetEditTextSize()
4845 {
4846 char spec[MAXSTRING+1];
4847 int size=0;
4848
4849 MakeQuiescent();
4850 *spec = '\0';
4851 sprintf(gszMsgBox, TgLoadString(STID_ENTER_EDIT_TEXT_SIZE), editTextSize);
4852 *spec = '\0';
4853 Dialog(gszMsgBox, NULL, spec);
4854 UtilTrimBlanks(spec);
4855 if (*spec == '\0') return;
4856 size = atoi(spec);
4857 if (size != 0 && (size < 4 || size > 34)) {
4858 sprintf(gszMsgBox, TgLoadString(STID_EDIT_TEXT_SIZE_OUT_OF_RANGE), spec);
4859 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
4860 } else {
4861 SetEditTextSizeValue(size);
4862
4863 if (editTextSize == 0) {
4864 Msg(TgLoadString(STID_ACTUAL_EDIT_TEXT_SIZE));
4865 } else {
4866 sprintf(gszMsgBox, TgLoadString(STID_USE_SPECIFIED_EDIT_TEXT_SIZE),
4867 editTextSize);
4868 Msg(gszMsgBox);
4869 }
4870 }
4871 }
4872
4873 static
UpdateOuterInnerSelForFind(obj_ptr)4874 void UpdateOuterInnerSelForFind(obj_ptr)
4875 struct ObjRec *obj_ptr;
4876 /* outerSel is at the top of the chain and innerSel is at the bottom */
4877 {
4878 AddObjIntoSel(obj_ptr, NULL, outerSelForFind, &outerSelForFind,
4879 &innerSelForFind);
4880 }
4881
4882 static
DoFind(obj_ptr)4883 struct ObjRec *DoFind(obj_ptr)
4884 struct ObjRec *obj_ptr;
4885 {
4886 int found_starting_point=TRUE;
4887 MiniLinesInfo *minilines=NULL;
4888 struct ObjRec *ptr=NULL;
4889 struct ObjRec *return_obj=NULL;
4890
4891 if (obj_ptr->type != OBJ_TEXT) {
4892 struct AttrRec *attr_ptr;
4893
4894 for (attr_ptr=obj_ptr->fattr; attr_ptr != NULL; attr_ptr=attr_ptr->next) {
4895 if (attr_ptr->shown) {
4896 return_obj = DoFind(attr_ptr->obj);
4897 if (return_obj != NULL) {
4898 return return_obj;
4899 }
4900 }
4901 }
4902 }
4903 switch (obj_ptr->type) {
4904 case OBJ_SYM:
4905 case OBJ_GROUP:
4906 case OBJ_ICON:
4907 for (ptr=obj_ptr->detail.r->last; ptr != NULL; ptr=ptr->prev) {
4908 ptr->tmp_parent = obj_ptr;
4909 return_obj = DoFind(ptr);
4910 if (return_obj != NULL) {
4911 UpdateOuterInnerSelForFind(obj_ptr);
4912 return return_obj;
4913 }
4914 }
4915 break;
4916 case OBJ_PIN:
4917 ptr = GetPinObj(obj_ptr);
4918 ptr->tmp_parent = obj_ptr;
4919 return_obj = DoFind(ptr);
4920 if (return_obj != NULL) {
4921 return return_obj;
4922 }
4923 break;
4924 case OBJ_TEXT:
4925 found_starting_point = TRUE;
4926 minilines = (&obj_ptr->detail.t->minilines);
4927
4928 SaveCursorPositionInCurText();
4929
4930 curStrBlock = minilines->first->first_block;
4931 textCurIndex = 0;
4932 ResetOnCursorKey(FALSE);
4933 SetTextHighlight();
4934 UpdatePinnedMenu(MENU_EDIT);
4935
4936 if (FindStringInMiniLines(minilines, &found_starting_point,
4937 gpszSearch, gnSearchLen, gnSearchCaseSensitive,
4938 &gpFoundStartStrBlock, &gnFoundStartCharIndex,
4939 &gpFoundEndStrBlock, &gnFoundEndCharIndex)) {
4940 return obj_ptr;
4941 }
4942 RestoreCursorPositionInCurText();
4943 break;
4944 default: break;
4945 }
4946 return NULL;
4947 }
4948
4949 static int gnFoundStartingPoint=FALSE;
4950
4951 static
DoFindAlready(obj_ptr,bottom_half,pn_give_up)4952 struct ObjRec *DoFindAlready(obj_ptr, bottom_half, pn_give_up)
4953 struct ObjRec *obj_ptr;
4954 int bottom_half; /* TRUE if searching from curTextObj to topObj */
4955 int *pn_give_up;
4956 {
4957 struct ObjRec *ptr=NULL;
4958 struct ObjRec *return_obj=NULL;
4959
4960 if (obj_ptr->type != OBJ_TEXT) {
4961 struct AttrRec *attr_ptr;
4962
4963 for (attr_ptr=obj_ptr->fattr; attr_ptr != NULL; attr_ptr=attr_ptr->next) {
4964 if (attr_ptr->shown) {
4965 return_obj = DoFindAlready(attr_ptr->obj, bottom_half, pn_give_up);
4966 if (return_obj != NULL) {
4967 return return_obj;
4968 }
4969 if (pn_give_up != NULL && *pn_give_up) {
4970 return NULL;
4971 }
4972 }
4973 }
4974 }
4975 switch (obj_ptr->type) {
4976 case OBJ_SYM:
4977 case OBJ_GROUP:
4978 case OBJ_ICON:
4979 for (ptr=obj_ptr->detail.r->last; ptr != NULL; ptr=ptr->prev) {
4980 ptr->tmp_parent = obj_ptr;
4981 return_obj = DoFindAlready(ptr, bottom_half, pn_give_up);
4982 if (return_obj != NULL) {
4983 UpdateOuterInnerSelForFind(obj_ptr);
4984 return return_obj;
4985 }
4986 if (pn_give_up != NULL && *pn_give_up) {
4987 return NULL;
4988 }
4989 }
4990 break;
4991 case OBJ_PIN:
4992 ptr = GetPinObj(obj_ptr);
4993 ptr->tmp_parent = obj_ptr;
4994 return_obj = DoFindAlready(ptr, bottom_half, pn_give_up);
4995 if (return_obj != NULL) {
4996 return return_obj;
4997 }
4998 if (pn_give_up != NULL && *pn_give_up) {
4999 return NULL;
5000 }
5001 break;
5002 case OBJ_TEXT:
5003 if ((bottom_half && gnFoundStartingPoint) ||
5004 (!bottom_half && obj_ptr != curTextObj)) {
5005 int found_starting_point=TRUE;
5006 MiniLinesInfo *minilines=(&obj_ptr->detail.t->minilines);
5007
5008 SaveCursorPositionInCurText();
5009
5010 curStrBlock = minilines->first->first_block;
5011 textCurIndex = 0;
5012 ResetOnCursorKey(FALSE);
5013 SetTextHighlight();
5014 UpdatePinnedMenu(MENU_EDIT);
5015
5016 if (FindStringInMiniLines(minilines, &found_starting_point,
5017 gpszSearch, gnSearchLen, gnSearchCaseSensitive,
5018 &gpFoundStartStrBlock, &gnFoundStartCharIndex,
5019 &gpFoundEndStrBlock, &gnFoundEndCharIndex)) {
5020 return obj_ptr;
5021 }
5022 RestoreCursorPositionInCurText();
5023 } else if (bottom_half) {
5024 if (obj_ptr == curTextObj) {
5025 gnFoundStartingPoint = TRUE;
5026 }
5027 } else {
5028 if (obj_ptr == curTextObj) {
5029 if (pn_give_up != NULL) *pn_give_up = TRUE;
5030 }
5031 }
5032 break;
5033 default: break;
5034 }
5035 return NULL;
5036 }
5037
5038 static
Find()5039 void Find()
5040 {
5041 int wrapped=FALSE;
5042 struct ObjRec *obj_ptr=NULL;
5043 struct ObjRec *found_obj=NULL;
5044
5045 CleanOuterInnerSelForFind();
5046 UpdatePinnedMenu(MENU_EDIT);
5047
5048 if (gpszSearch == NULL) return;
5049 gnSearchLen = strlen(gpszSearch);
5050
5051 gnFoundStartCharIndex = 0;
5052 gpFoundStartStrBlock = NULL;
5053
5054 SetWatchCursor(drawWindow);
5055 SetWatchCursor(mainWindow);
5056
5057 if (curChoice == DRAWTEXT) {
5058 if (curTextObj != NULL && FindTextInCurTextObj(gpszSearch, gnSearchLen,
5059 gnSearchCaseSensitive, &gpFoundStartStrBlock,
5060 &gnFoundStartCharIndex, &gpFoundEndStrBlock,
5061 &gnFoundEndCharIndex)) {
5062 found_obj = curTextObj;
5063 CopyOuterSelToOuterSelForFind();
5064 }
5065 if (found_obj == NULL) {
5066 gnFoundStartingPoint = FALSE;
5067 for (obj_ptr=botObj; obj_ptr != NULL; obj_ptr=obj_ptr->prev) {
5068 obj_ptr->tmp_parent = NULL;
5069 if (!ObjInVisibleLayer(obj_ptr)) {
5070 continue;
5071 }
5072 found_obj = DoFindAlready(obj_ptr, TRUE, NULL);
5073 if (found_obj != NULL) {
5074 break;
5075 }
5076 }
5077 if (found_obj == NULL && gnFoundStartingPoint) {
5078 wrapped = TRUE;
5079 for (obj_ptr=botObj; obj_ptr != NULL; obj_ptr=obj_ptr->prev) {
5080 int give_up=FALSE;
5081
5082 obj_ptr->tmp_parent = NULL;
5083 if (!ObjInVisibleLayer(obj_ptr)) {
5084 continue;
5085 }
5086 found_obj = DoFindAlready(obj_ptr, FALSE, &give_up);
5087 if (found_obj != NULL) {
5088 break;
5089 }
5090 if (give_up) {
5091 break;
5092 }
5093 }
5094 }
5095 }
5096 }
5097 if (found_obj == NULL) {
5098 if (curChoice == DRAWTEXT) {
5099 wrapped = TRUE;
5100 }
5101 for (obj_ptr=botObj; obj_ptr != NULL; obj_ptr=obj_ptr->prev) {
5102 obj_ptr->tmp_parent = NULL;
5103 if (!ObjInVisibleLayer(obj_ptr)) {
5104 continue;
5105 }
5106 found_obj = DoFind(obj_ptr);
5107 if (found_obj != NULL) {
5108 break;
5109 }
5110 }
5111 if (found_obj != NULL) {
5112 if (curChoice != DRAWTEXT) {
5113 SetCurChoice(DRAWTEXT);
5114 }
5115 }
5116 }
5117 SetDefaultCursor(mainWindow);
5118 ShowCursor();
5119
5120 if (found_obj == NULL) {
5121 sprintf(gszMsgBox, TgLoadString(STID_CANNOT_FIND_NAMED_STRING),
5122 gpszSearch);
5123 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
5124 } else {
5125 HighLightText(found_obj, gpFoundStartStrBlock, gnFoundStartCharIndex,
5126 gpFoundEndStrBlock, gnFoundEndCharIndex);
5127 if (wrapped) {
5128 Msg(TgLoadString(STID_FIND_CMD_WRAPPED));
5129 }
5130 }
5131 }
5132
FindCaseSensitive()5133 void FindCaseSensitive()
5134 {
5135 char spec[MAXSTRING];
5136
5137 *spec = '\0';
5138 Dialog(TgLoadString(STID_ENTER_CASE_STR_TO_FIND), NULL, spec);
5139 if (*spec == '\0') {
5140 return;
5141 }
5142 if (gpszSearch != NULL) free(gpszSearch);
5143 if ((gpszSearch=UtilStrDup(spec)) == NULL) FailAllocMessage();
5144
5145 gnSearchCaseSensitive = TRUE;
5146 if (curChoice != DRAWTEXT) {
5147 MakeQuiescent();
5148 }
5149 Find();
5150 }
5151
FindNoCase()5152 void FindNoCase()
5153 {
5154 char spec[MAXSTRING];
5155
5156 *spec = '\0';
5157 Dialog(TgLoadString(STID_ENTER_NOCASE_STR_TO_FIND), NULL, spec);
5158 if (*spec == '\0') {
5159 return;
5160 }
5161 if (gpszSearch != NULL) free(gpszSearch);
5162 if ((gpszSearch=UtilStrDup(spec)) == NULL) FailAllocMessage();
5163
5164 gnSearchCaseSensitive = FALSE;
5165 if (curChoice != DRAWTEXT) {
5166 MakeQuiescent();
5167 }
5168 Find();
5169 }
5170
FindAgain()5171 void FindAgain()
5172 {
5173 if (gpszSearch == NULL) {
5174 MsgBox(TgLoadString(STID_NO_PREVIOUS_FIND), TOOL_NAME, INFO_MB);
5175 } else {
5176 Find();
5177 }
5178 }
5179
5180 /* ----------------------- EditMenu ----------------------- */
5181
RefreshEditMenu(menu)5182 int RefreshEditMenu(menu)
5183 TgMenu *menu;
5184 {
5185 int ok=TRUE;
5186 StrSegInfo ssi;
5187
5188 memset(&ssi, 0, sizeof(StrSegInfo));
5189
5190 /* CopyPlainTextAsObject */
5191 ok &= TgEnableMenuItemById(menu, CMDID_COPYPLAINTEXTASOBJECT,
5192 (curChoice == DRAWTEXT && textHighlight));
5193
5194 /* CopyUTF8String */
5195 ok &= TgEnableMenuItemById(menu, CMDID_COPYUTF8,
5196 (curChoice == DRAWTEXT && textHighlight &&
5197 CanCopyHighLightedTextAsUTF8Strings(NULL)));
5198 /* PasteUTF8String */
5199 ok &= TgEnableMenuItemById(menu, CMDID_PASTEUTF8,
5200 (curChoice == DRAWTEXT && textCursorShown &&
5201 CanPasteUTF8StringIntoText(&ssi)));
5202
5203 /* ImageProc submenu */
5204 ok &= TgEnableMenuItemById(menu, MENU_IMAGEPROC, CanPerformImageProc());
5205
5206 /* FindAgain */
5207 ok &= TgEnableMenuItemById(menu, CMDID_FINDAGAIN, (gpszSearch != NULL));
5208
5209 return ok;
5210 }
5211
CreateEditMenu(parent_menu,x,y,menu_info,status_str_xlated)5212 TgMenu *CreateEditMenu(parent_menu, x, y, menu_info, status_str_xlated)
5213 TgMenu *parent_menu;
5214 int x, y;
5215 TgMenuInfo *menu_info;
5216 int status_str_xlated; /* ignored, always 0 */
5217 {
5218 TgMenu *menu=TgCreateMenuFromMenuInfo(parent_menu, x, y, menu_info, FALSE);
5219
5220 if (menu != NULL) {
5221 if (!RefreshEditMenu(menu)) {
5222 return TgDestroyMenu(menu, TRUE);
5223 }
5224 menu->refresh_proc = ((RefreshMenuFunc*)RefreshEditMenu);
5225 }
5226 return menu;
5227 }
5228
EditMenu(X,Y,TrackMenubar)5229 int EditMenu(X, Y, TrackMenubar)
5230 int X, Y, TrackMenubar;
5231 {
5232 int rc=INVALID;
5233 TgMenu *menu=(editMenuInfo.create_proc)(NULL, X, Y, &editMenuInfo, INVALID);
5234
5235 activeMenu = MENU_EDIT;
5236 if (menu != NULL) {
5237 menu->track_menubar = TrackMenubar;
5238
5239 rc = TgMenuLoop(menu);
5240 TgDestroyMenu(menu, TRUE);
5241 }
5242 return rc;
5243 }
5244
5245 /* ======================= ArrangeMenu Related ======================= */
5246
FrontProc()5247 void FrontProc()
5248 {
5249 if (topSel != NULL) {
5250 HighLightReverse();
5251 MoveSelToTop();
5252 RedrawAnArea(botObj, selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1),
5253 selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1));
5254 HighLightForward();
5255 SetFileModified(TRUE);
5256 }
5257 }
5258
BackProc()5259 void BackProc()
5260 {
5261 if (topSel != NULL) {
5262 HighLightReverse();
5263 MoveSelToBot();
5264 RedrawAnArea(botObj, selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1),
5265 selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1));
5266 HighLightForward();
5267 SetFileModified(TRUE);
5268 }
5269 }
5270
AlignObjsTop()5271 void AlignObjsTop()
5272 {
5273 register int saved_h_align = horiAlign, saved_v_align = vertAlign;
5274
5275 horiAlign = ALIGN_N; vertAlign = ALIGN_T;
5276 AlignSelObjs();
5277 horiAlign = saved_h_align; vertAlign = saved_v_align;
5278 }
5279
AlignObjsMiddle()5280 void AlignObjsMiddle()
5281 {
5282 register int saved_h_align = horiAlign, saved_v_align = vertAlign;
5283
5284 horiAlign = ALIGN_N; vertAlign = ALIGN_M;
5285 AlignSelObjs();
5286 horiAlign = saved_h_align; vertAlign = saved_v_align;
5287 }
5288
AlignObjsBottom()5289 void AlignObjsBottom()
5290 {
5291 register int saved_h_align = horiAlign, saved_v_align = vertAlign;
5292
5293 horiAlign = ALIGN_N; vertAlign = ALIGN_B;
5294 AlignSelObjs();
5295 horiAlign = saved_h_align; vertAlign = saved_v_align;
5296 }
5297
AlignObjsLeft()5298 void AlignObjsLeft()
5299 {
5300 register int saved_h_align = horiAlign, saved_v_align = vertAlign;
5301
5302 horiAlign = ALIGN_L; vertAlign = ALIGN_N;
5303 AlignSelObjs();
5304 horiAlign = saved_h_align; vertAlign = saved_v_align;
5305 }
5306
AlignObjsCenter()5307 void AlignObjsCenter()
5308 {
5309 register int saved_h_align = horiAlign, saved_v_align = vertAlign;
5310
5311 horiAlign = ALIGN_C; vertAlign = ALIGN_N;
5312 AlignSelObjs();
5313 horiAlign = saved_h_align; vertAlign = saved_v_align;
5314 }
5315
AlignObjsRight()5316 void AlignObjsRight()
5317 {
5318 register int saved_h_align = horiAlign, saved_v_align = vertAlign;
5319
5320 horiAlign = ALIGN_R; vertAlign = ALIGN_N;
5321 AlignSelObjs();
5322 horiAlign = saved_h_align; vertAlign = saved_v_align;
5323 }
5324
5325 static
Abut(Dir)5326 void Abut(Dir)
5327 int Dir;
5328 {
5329 struct ObjRec *obj_ptr=NULL;
5330 struct SelRec *sel_ptr=NULL;
5331 struct SelRec *top_sort=NULL, *bot_sort=NULL, *sort_ptr=NULL;
5332 struct SelRec *new_sort_ptr=NULL, *tmp_sel_ptr=NULL, *next_sort=NULL;
5333 struct ObjRec *sorted_obj=NULL, *locked_obj=NULL;
5334 struct SubCmdRec *sub_cmd=NULL;
5335 int sel_ltx=0, sel_lty=0, sel_rbx=0, sel_rby=0, rbx=0, rby=0;
5336 int found=FALSE, delta=0, dx=0, dy=0;
5337
5338 if (topSel == NULL) {
5339 MsgBox(TgLoadCachedString(CSTID_NO_OBJ_SELECTED), TOOL_NAME, INFO_MB);
5340 return;
5341 } else if (curChoice == VERTEXMODE) {
5342 MsgBox(TgLoadString(STID_CANNOT_ABUT_IN_VERTEX_MODE), TOOL_NAME, INFO_MB);
5343 return;
5344 } else if (numObjLocked > 1) {
5345 MsgBox(TgLoadString(STID_CANNOT_ABUT_LOCKED), TOOL_NAME, INFO_MB);
5346 return;
5347 }
5348 HighLightReverse();
5349 StartCompositeCmd();
5350 sel_ltx = selLtX; sel_lty = selLtY;
5351 sel_rbx = selRbX; sel_rby = selRbY;
5352
5353 top_sort = (struct SelRec *)malloc(sizeof(struct SelRec));
5354 if (top_sort == NULL) FailAllocMessage();
5355 top_sort->next = top_sort->prev = NULL;
5356
5357 top_sort->obj = sorted_obj = botSel->obj;
5358 if (botSel->obj->locked) locked_obj = botSel->obj;
5359 for (sel_ptr=botSel->prev; sel_ptr != NULL; sel_ptr=sel_ptr->prev) {
5360 obj_ptr = sel_ptr->obj;
5361 if (obj_ptr->locked) locked_obj = obj_ptr;
5362 switch (Dir) {
5363 case ABUT_HORIZONTAL:
5364 if (obj_ptr->obbox.ltx < sorted_obj->obbox.ltx ||
5365 (obj_ptr->obbox.ltx == sorted_obj->obbox.ltx &&
5366 obj_ptr->obbox.lty < sorted_obj->obbox.lty)) {
5367 top_sort->obj = sorted_obj = sel_ptr->obj;
5368 }
5369 break;
5370 case ABUT_VERTICAL:
5371 if (obj_ptr->obbox.lty < sorted_obj->obbox.lty ||
5372 (obj_ptr->obbox.lty == sorted_obj->obbox.lty &&
5373 obj_ptr->obbox.ltx < sorted_obj->obbox.ltx)) {
5374 top_sort->obj = sorted_obj = sel_ptr->obj;
5375 }
5376 break;
5377 }
5378 }
5379 bot_sort = top_sort;
5380
5381 for (sel_ptr=botSel; sel_ptr != NULL; sel_ptr=sel_ptr->prev) {
5382 if (sel_ptr->obj == top_sort->obj) continue;
5383
5384 obj_ptr = sel_ptr->obj;
5385 new_sort_ptr = (struct SelRec *)malloc(sizeof(struct SelRec));
5386 if (new_sort_ptr == NULL) FailAllocMessage();
5387 new_sort_ptr->obj = obj_ptr;
5388 found = FALSE;
5389 for (sort_ptr=top_sort->next; sort_ptr!=NULL; sort_ptr=sort_ptr->next) {
5390 switch (Dir) {
5391 case ABUT_HORIZONTAL:
5392 if (sort_ptr->obj->obbox.ltx > obj_ptr->obbox.ltx ||
5393 (sort_ptr->obj->obbox.ltx == obj_ptr->obbox.ltx &&
5394 sort_ptr->obj->obbox.lty > obj_ptr->obbox.lty)) {
5395 found = TRUE;
5396 }
5397 break;
5398 case ABUT_VERTICAL:
5399 if (sort_ptr->obj->obbox.lty > obj_ptr->obbox.lty ||
5400 (sort_ptr->obj->obbox.lty == obj_ptr->obbox.lty &&
5401 sort_ptr->obj->obbox.ltx > obj_ptr->obbox.ltx)) {
5402 found = TRUE;
5403 }
5404 break;
5405 }
5406 if (found) break;
5407 }
5408 new_sort_ptr->next = sort_ptr;
5409 if (sort_ptr == NULL) {
5410 new_sort_ptr->prev = bot_sort;
5411 bot_sort->next = new_sort_ptr;
5412 bot_sort = new_sort_ptr;
5413 } else {
5414 new_sort_ptr->prev = sort_ptr->prev;
5415 sort_ptr->prev->next = new_sort_ptr;
5416 sort_ptr->prev = new_sort_ptr;
5417 }
5418 }
5419
5420 tmp_sel_ptr = (struct SelRec *)malloc(sizeof(struct SelRec));
5421 if (tmp_sel_ptr == NULL) FailAllocMessage();
5422 tmp_sel_ptr->next = tmp_sel_ptr->prev = NULL;
5423
5424 if (locked_obj != NULL) {
5425 switch (Dir) {
5426 case ABUT_HORIZONTAL:
5427 rbx = top_sort->obj->obbox.rbx;
5428 for (sort_ptr=top_sort; sort_ptr->obj!=locked_obj &&
5429 sort_ptr->next!=NULL; sort_ptr=next_sort) {
5430 next_sort = sort_ptr->next;
5431 delta = rbx-next_sort->obj->obbox.ltx;
5432 dx = (-delta);
5433 rbx = next_sort->obj->obbox.rbx+delta;
5434 }
5435 break;
5436 case ABUT_VERTICAL:
5437 rby = top_sort->obj->obbox.rby;
5438 for (sort_ptr=top_sort; sort_ptr->obj!=locked_obj &&
5439 sort_ptr->next!=NULL; sort_ptr=next_sort) {
5440 next_sort = sort_ptr->next;
5441 delta = rby-next_sort->obj->obbox.lty;
5442 dy = (-delta);
5443 rby = next_sort->obj->obbox.rby+delta;
5444 }
5445 break;
5446 }
5447 }
5448 sub_cmd = (struct SubCmdRec *)malloc(sizeof(struct SubCmdRec));
5449 if (sub_cmd == NULL) FailAllocMessage();
5450 memset(sub_cmd, 0, sizeof(struct SubCmdRec));
5451
5452 rbx = top_sort->obj->obbox.rbx;
5453 rby = top_sort->obj->obbox.rby;
5454 found = (locked_obj == NULL);
5455 if (!found && locked_obj != top_sort->obj) {
5456 tmp_sel_ptr->obj = top_sort->obj;
5457 switch (Dir) {
5458 case ABUT_HORIZONTAL:
5459 sub_cmd->detail.move.dx = dx;
5460 sub_cmd->detail.move.dy = 0;
5461 PrepareToRecord(CMD_MOVE, tmp_sel_ptr, tmp_sel_ptr, 1);
5462 RecordCmd(CMD_MOVE, sub_cmd, NULL, NULL, 0);
5463 MoveObj(top_sort->obj, dx, 0);
5464 break;
5465 case ABUT_VERTICAL:
5466 sub_cmd->detail.move.dx = 0;
5467 sub_cmd->detail.move.dy = dy;
5468 PrepareToRecord(CMD_MOVE, tmp_sel_ptr, tmp_sel_ptr, 1);
5469 RecordCmd(CMD_MOVE, sub_cmd, NULL, NULL, 0);
5470 MoveObj(top_sort->obj, 0, dy);
5471 break;
5472 }
5473 }
5474 for (sort_ptr=top_sort; sort_ptr->next!=NULL; sort_ptr=next_sort) {
5475 next_sort = sort_ptr->next;
5476 tmp_sel_ptr->obj = next_sort->obj;
5477 switch (Dir) {
5478 case ABUT_HORIZONTAL:
5479 delta = rbx-next_sort->obj->obbox.ltx;
5480 rbx = next_sort->obj->obbox.rbx+delta;
5481 if (!found) delta += dx;
5482 sub_cmd->detail.move.dx = delta;
5483 sub_cmd->detail.move.dy = 0;
5484 PrepareToRecord(CMD_MOVE, tmp_sel_ptr, tmp_sel_ptr, 1);
5485 RecordCmd(CMD_MOVE, sub_cmd, NULL, NULL, 0);
5486 MoveObj(next_sort->obj, delta, 0);
5487 break;
5488 case ABUT_VERTICAL:
5489 delta = rby-next_sort->obj->obbox.lty;
5490 rby = next_sort->obj->obbox.rby+delta;
5491 if (!found) delta += dy;
5492 sub_cmd->detail.move.dx = 0;
5493 sub_cmd->detail.move.dy = delta;
5494 PrepareToRecord(CMD_MOVE, tmp_sel_ptr, tmp_sel_ptr, 1);
5495 RecordCmd(CMD_MOVE, sub_cmd, NULL, NULL, 0);
5496 MoveObj(next_sort->obj, 0, delta);
5497 break;
5498 }
5499 free(sort_ptr);
5500 }
5501 EndCompositeCmd();
5502 free(sort_ptr);
5503 free(sub_cmd);
5504 free(tmp_sel_ptr);
5505
5506 UpdSelBBox();
5507 RedrawAreas(botObj, selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1),
5508 selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1),
5509 sel_ltx-GRID_ABS_SIZE(1), sel_lty-GRID_ABS_SIZE(1),
5510 sel_rbx+GRID_ABS_SIZE(1), sel_rby+GRID_ABS_SIZE(1));
5511 HighLightForward();
5512 justDupped = FALSE;
5513 switch (Dir) {
5514 case ABUT_HORIZONTAL: Msg(TgLoadString(STID_ABUTTED_HORI)); break;
5515 case ABUT_VERTICAL: Msg(TgLoadString(STID_ABUTTED_VERT)); break;
5516 }
5517 SetFileModified(TRUE);
5518 }
5519
AbutHorizontal()5520 void AbutHorizontal()
5521 {
5522 Abut(ABUT_HORIZONTAL);
5523 }
5524
AbutVertical()5525 void AbutVertical()
5526 {
5527 Abut(ABUT_VERTICAL);
5528 }
5529
RefreshArrangeMenu(menu)5530 void RefreshArrangeMenu(menu)
5531 TgMenu *menu;
5532 {
5533 }
5534
ArrangeMenu(X,Y,TrackMenubar)5535 int ArrangeMenu(X, Y, TrackMenubar)
5536 int X, Y, TrackMenubar;
5537 {
5538 int rc=INVALID;
5539 TgMenu *menu=(arrangeMenuInfo.create_proc)(NULL, X, Y, &arrangeMenuInfo,
5540 FALSE);
5541
5542 activeMenu = MENU_ARRANGE;
5543 if (menu != NULL) {
5544 menu->track_menubar = TrackMenubar;
5545
5546 rc = TgMenuLoop(menu);
5547 TgDestroyMenu(menu, TRUE);
5548 }
5549 return rc;
5550 }
5551
RefreshPropertiesMenu(menu)5552 int RefreshPropertiesMenu(menu)
5553 TgMenu *menu;
5554 {
5555 int ok=TRUE;
5556
5557 /* UseAltEditTextBgColor */
5558 ok &= TgSetMenuItemCheckById(menu, CMDID_TOGGLEALTEDITTEXTBGCOLOR,
5559 useAltEditTextBgColor);
5560 /* AddColor */
5561 ok &= TgEnableMenuItemById(menu, CMDID_ADDCOLOR, colorDisplay);
5562
5563 return ok;
5564 }
5565
CreatePropertiesMenu(parent_menu,x,y,menu_info,status_str_xlated)5566 TgMenu *CreatePropertiesMenu(parent_menu, x, y, menu_info, status_str_xlated)
5567 TgMenu *parent_menu;
5568 int x, y;
5569 TgMenuInfo *menu_info;
5570 int status_str_xlated; /* ignored, always 0 */
5571 {
5572 TgMenu *menu=TgCreateMenuFromMenuInfo(parent_menu, x, y, menu_info, FALSE);
5573
5574 if (menu != NULL) {
5575 if (!RefreshPropertiesMenu(menu)) {
5576 return TgDestroyMenu(menu, TRUE);
5577 }
5578 menu->refresh_proc = ((RefreshMenuFunc*)RefreshPropertiesMenu);
5579 }
5580 return menu;
5581 }
5582
PropertiesMenu(X,Y,TrackMenubar)5583 int PropertiesMenu(X, Y, TrackMenubar)
5584 int X, Y, TrackMenubar;
5585 {
5586 int rc=INVALID;
5587 TgMenu *menu=(propertiesMenuInfo.create_proc)(NULL, X, Y,
5588 &propertiesMenuInfo, INVALID);
5589
5590 activeMenu = MENU_PROPERTIES;
5591 if (menu != NULL) {
5592 menu->track_menubar = TrackMenubar;
5593
5594 rc = TgMenuLoop(menu);
5595 TgDestroyMenu(menu, TRUE);
5596 }
5597 return rc;
5598 }
5599
UpdateSymbols()5600 void UpdateSymbols()
5601 {
5602 int dx=0, dy=0, changed=FALSE;
5603 int sel_ltx, sel_lty, sel_rbx, sel_rby, file_type=INVALID;
5604 char path_name[MAXPATHLENGTH], sym_name[MAXPATHLENGTH];
5605 struct ObjRec *obj_ptr, *new_obj_ptr;
5606 struct SelRec *sel_ptr;
5607 struct GroupRec *icon_ptr;
5608
5609 if (topSel == NULL) {
5610 MsgBox(TgLoadCachedString(CSTID_NO_OBJ_SELECTED), TOOL_NAME, INFO_MB);
5611 return;
5612 }
5613 tmpTopObj = tmpBotObj = NULL;
5614 tmpTopSel = tmpBotSel = NULL;
5615
5616 sel_ltx = selLtX; sel_lty = selLtY;
5617 sel_rbx = selRbX; sel_rby = selRbY;
5618
5619 HighLightReverse();
5620
5621 StartCompositeCmd();
5622 for (sel_ptr=botSel; sel_ptr != NULL; sel_ptr=sel_ptr->prev) {
5623 obj_ptr = sel_ptr->obj;
5624 if (obj_ptr->type != OBJ_ICON && obj_ptr->type != OBJ_PIN) {
5625 continue;
5626 }
5627 icon_ptr = obj_ptr->detail.r;
5628 strcpy(sym_name, icon_ptr->s);
5629 if (obj_ptr->type == OBJ_ICON) {
5630 file_type = SYM_FILE_TYPE;
5631 } else {
5632 file_type = PIN_FILE_TYPE;
5633 }
5634 if (GetSymbolPath(icon_ptr->s, obj_ptr->type==OBJ_PIN, path_name)) {
5635 if ((new_obj_ptr=GetObjRepresentation(path_name, sym_name,
5636 file_type)) != NULL) {
5637 PrepareToReplaceAnObj(obj_ptr);
5638 if (icon_ptr->flip != NO_FLIP) {
5639 if (icon_ptr->flip & HORI_EVEN) FlipIconHorizontal(new_obj_ptr);
5640 if (icon_ptr->flip & VERT_EVEN) FlipIconVertical(new_obj_ptr);
5641 if (icon_ptr->flip & (HORI_ODD | VERT_ODD)) {
5642 RotateIconClockWise(new_obj_ptr);
5643 if (icon_ptr->flip & HORI_ODD) {
5644 FlipIconHorizontal(new_obj_ptr);
5645 }
5646 if (icon_ptr->flip & VERT_ODD) {
5647 FlipIconVertical(new_obj_ptr);
5648 }
5649 RotateIconCounter(new_obj_ptr);
5650 }
5651 }
5652 switch (horiAlign) {
5653 case ALIGN_L:
5654 dx = obj_ptr->obbox.ltx - new_obj_ptr->obbox.ltx;
5655 break;
5656 case ALIGN_N:
5657 case ALIGN_S:
5658 case ALIGN_C:
5659 dx = (int)(((obj_ptr->obbox.ltx+obj_ptr->obbox.rbx) -
5660 (new_obj_ptr->obbox.ltx+new_obj_ptr->obbox.rbx))/2);
5661 break;
5662 case ALIGN_R:
5663 dx = obj_ptr->obbox.rbx - new_obj_ptr->obbox.rbx;
5664 break;
5665 }
5666 switch (vertAlign) {
5667 case ALIGN_T:
5668 dy = obj_ptr->obbox.lty - new_obj_ptr->obbox.lty;
5669 break;
5670 case ALIGN_N:
5671 case ALIGN_S:
5672 case ALIGN_M:
5673 dy = (int)(((obj_ptr->obbox.lty+obj_ptr->obbox.rby) -
5674 (new_obj_ptr->obbox.lty+new_obj_ptr->obbox.rby))/2);
5675 break;
5676 case ALIGN_B:
5677 dy = obj_ptr->obbox.rby - new_obj_ptr->obbox.rby;
5678 break;
5679 }
5680 MoveObj(new_obj_ptr, dx, dy);
5681
5682 changed = TRUE;
5683
5684 UnlinkObj(obj_ptr);
5685 CopyAndUpdateAttrs(new_obj_ptr, obj_ptr);
5686 ExpandCurSelBBoxes(new_obj_ptr);
5687
5688 sel_ptr->obj = new_obj_ptr;
5689 AssignNewObjIds(new_obj_ptr);
5690 AddObj(NULL, topObj, new_obj_ptr);
5691 RecordReplaceAnObj(new_obj_ptr);
5692 FreeObj(obj_ptr);
5693 }
5694 }
5695 }
5696 EndCompositeCmd();
5697
5698 if (changed) {
5699 UpdSelBBox();
5700 RedrawAreas(botObj, sel_ltx-GRID_ABS_SIZE(1), sel_lty-GRID_ABS_SIZE(1),
5701 sel_rbx+GRID_ABS_SIZE(1), sel_rby+GRID_ABS_SIZE(1),
5702 selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1),
5703 selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1));
5704 SetFileModified(TRUE);
5705 justDupped = FALSE;
5706 Msg(TgLoadString(STID_ICONS_BROUGHT_UP_TO_DATE));
5707 }
5708 HighLightForward();
5709 }
5710
SizeToWidest()5711 void SizeToWidest()
5712 {
5713 struct SelRec *sel_ptr=NULL;
5714 int abs_w=0;
5715
5716 if (topSel == NULL || topSel == botSel) {
5717 MsgBox(TgLoadString(STID_SEL_AT_LEAST_TWO_OBJS), TOOL_NAME, INFO_MB);
5718 return;
5719 }
5720 for (sel_ptr=topSel; sel_ptr != NULL; sel_ptr=sel_ptr->next) {
5721 struct ObjRec *obj_ptr=sel_ptr->obj;
5722 int w=obj_ptr->obbox.rbx-obj_ptr->obbox.ltx;
5723
5724 if (w > abs_w) abs_w = w;
5725 }
5726 if (abs_w <= 1) {
5727 sprintf(gszMsgBox, TgLoadString(STID_CANNOT_SIZE_OF_GIVEN_WIDTH), abs_w);
5728 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
5729 return;
5730 }
5731 SizeAllSelToGivenWidth(abs_w);
5732 }
5733
SizeToNarrowest()5734 void SizeToNarrowest()
5735 {
5736 struct SelRec *sel_ptr=NULL;
5737 int abs_w=0;
5738
5739 if (topSel == NULL || topSel == botSel) {
5740 MsgBox(TgLoadString(STID_SEL_AT_LEAST_TWO_OBJS), TOOL_NAME, INFO_MB);
5741 return;
5742 }
5743 abs_w = topSel->obj->obbox.rbx-topSel->obj->obbox.ltx;
5744 for (sel_ptr=topSel; sel_ptr != NULL; sel_ptr=sel_ptr->next) {
5745 struct ObjRec *obj_ptr=sel_ptr->obj;
5746 int w=obj_ptr->obbox.rbx-obj_ptr->obbox.ltx;
5747
5748 if (w < abs_w) abs_w = w;
5749 }
5750 if (abs_w <= 1) {
5751 sprintf(gszMsgBox, TgLoadString(STID_CANNOT_SIZE_OF_GIVEN_WIDTH), abs_w);
5752 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
5753 return;
5754 }
5755 SizeAllSelToGivenWidth(abs_w);
5756 }
5757
SizeToTallest()5758 void SizeToTallest()
5759 {
5760 struct SelRec *sel_ptr=NULL;
5761 int abs_h=0;
5762
5763 if (topSel == NULL || topSel == botSel) {
5764 MsgBox(TgLoadString(STID_SEL_AT_LEAST_TWO_OBJS), TOOL_NAME, INFO_MB);
5765 return;
5766 }
5767 for (sel_ptr=topSel; sel_ptr != NULL; sel_ptr=sel_ptr->next) {
5768 struct ObjRec *obj_ptr=sel_ptr->obj;
5769 int h=obj_ptr->obbox.rby-obj_ptr->obbox.lty;
5770
5771 if (h > abs_h) abs_h = h;
5772 }
5773 if (abs_h <= 1) {
5774 sprintf(gszMsgBox, TgLoadString(STID_CANNOT_SIZE_OF_GIVEN_HEIGHT), abs_h);
5775 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
5776 return;
5777 }
5778 SizeAllSelToGivenHeight(abs_h);
5779 }
5780
SizeToShortest()5781 void SizeToShortest()
5782 {
5783 struct SelRec *sel_ptr=NULL;
5784 int abs_h=0;
5785
5786 if (topSel == NULL || topSel == botSel) {
5787 MsgBox(TgLoadString(STID_SEL_AT_LEAST_TWO_OBJS), TOOL_NAME, INFO_MB);
5788 return;
5789 }
5790 abs_h = topSel->obj->obbox.rby-topSel->obj->obbox.lty;
5791 for (sel_ptr=topSel; sel_ptr != NULL; sel_ptr=sel_ptr->next) {
5792 struct ObjRec *obj_ptr=sel_ptr->obj;
5793 int h=obj_ptr->obbox.rby-obj_ptr->obbox.lty;
5794
5795 if (h < abs_h) abs_h = h;
5796 }
5797 if (abs_h <= 1) {
5798 sprintf(gszMsgBox, TgLoadString(STID_CANNOT_SIZE_OF_GIVEN_HEIGHT), abs_h);
5799 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
5800 return;
5801 }
5802 SizeAllSelToGivenHeight(abs_h);
5803 }
5804
SizeToGivenWidthHeight()5805 void SizeToGivenWidthHeight()
5806 {
5807 int abs_w=0, abs_h=0;
5808 char spec[MAXSTRING];
5809
5810 if (topSel == NULL) {
5811 MsgBox(TgLoadCachedString(CSTID_NO_OBJ_SELECTED), TOOL_NAME, INFO_MB);
5812 return;
5813 }
5814 *spec = '\0';
5815 if (Dialog(TgLoadString(STID_SPECIFY_WIDTH_HEIGHT), NULL, spec) == INVALID) {
5816 return;
5817 }
5818 UtilTrimBlanks(spec);
5819 if (*spec == '\0') return;
5820
5821 if (!ParseWHSpec(spec, &abs_w, &abs_h)) {
5822 sprintf(gszMsgBox, TgLoadString(STID_INVALID_SPEC), spec);
5823 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
5824 return;
5825 }
5826 if (abs_w <= 1) {
5827 sprintf(gszMsgBox, TgLoadString(STID_CANNOT_SIZE_OF_GIVEN_WIDTH), abs_w);
5828 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
5829 return;
5830 }
5831 if (abs_h <= 1) {
5832 sprintf(gszMsgBox, TgLoadString(STID_CANNOT_SIZE_OF_GIVEN_HEIGHT), abs_h);
5833 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
5834 return;
5835 }
5836 SizeAllSelToGivenWidthHeight(abs_w, abs_h);
5837 }
5838
SizeToGivenWidth()5839 void SizeToGivenWidth()
5840 {
5841 int abs_w=0;
5842 char spec[MAXSTRING];
5843
5844 if (topSel == NULL) {
5845 MsgBox(TgLoadCachedString(CSTID_NO_OBJ_SELECTED), TOOL_NAME, INFO_MB);
5846 return;
5847 }
5848 *spec = '\0';
5849 if (Dialog(TgLoadString(STID_SPECIFY_WIDTH), NULL, spec) == INVALID) return;
5850 UtilTrimBlanks(spec);
5851 if (*spec == '\0') return;
5852
5853 if (!GetDimension(spec, FALSE, &abs_w)) {
5854 sprintf(gszMsgBox, TgLoadString(STID_INVALID_SPEC), spec);
5855 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
5856 return;
5857 }
5858 if (abs_w <= 1) {
5859 sprintf(gszMsgBox, TgLoadString(STID_CANNOT_SIZE_OF_GIVEN_WIDTH), abs_w);
5860 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
5861 return;
5862 }
5863 SizeAllSelToGivenWidth(abs_w);
5864 }
5865
SizeToGivenHeight()5866 void SizeToGivenHeight()
5867 {
5868 int abs_h=0;
5869 char spec[MAXSTRING];
5870
5871 if (topSel == NULL) {
5872 MsgBox(TgLoadCachedString(CSTID_NO_OBJ_SELECTED), TOOL_NAME, INFO_MB);
5873 return;
5874 }
5875 *spec = '\0';
5876 if (Dialog(TgLoadString(STID_SPECIFY_HEIGHT), NULL, spec) == INVALID) return;
5877 UtilTrimBlanks(spec);
5878 if (*spec == '\0') return;
5879
5880 if (!GetDimension(spec, FALSE, &abs_h)) {
5881 sprintf(gszMsgBox, TgLoadString(STID_INVALID_SPEC), spec);
5882 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
5883 return;
5884 }
5885 if (abs_h <= 1) {
5886 sprintf(gszMsgBox, TgLoadString(STID_CANNOT_SIZE_OF_GIVEN_HEIGHT), abs_h);
5887 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
5888 return;
5889 }
5890 SizeAllSelToGivenHeight(abs_h);
5891 }
5892
5893 /* ----------------------- Generic Object Shadow ----------------------- */
5894
SetObjectShadowColor()5895 void SetObjectShadowColor()
5896 {
5897 char spec[MAXSTRING], buf[MAXSTRING];
5898 int new_alloc=0;
5899
5900 *spec = '\0';
5901 sprintf(buf, TgLoadString(STID_ENTER_A_COLOR_FOR_OBJ_SHADOW),
5902 objShadowColorStr);
5903 UtilStrCpyN(spec, sizeof(spec), objShadowColorStr);
5904 if (Dialog(buf, TgLoadString(STID_PRESS_ENTER_FOR_DEF_COLOR), spec) ==
5905 INVALID) {
5906 return;
5907 }
5908 UtilTrimBlanks(spec);
5909 if (*spec == '\0') {
5910 strcpy(objShadowColorStr, "#c0c0c0");
5911 sprintf(gszMsgBox, TgLoadString(STID_OBJ_SHADOW_COLOR_SET_TO_NAMED),
5912 objShadowColorStr);
5913 Msg(gszMsgBox);
5914 return;
5915 }
5916 if (QuickFindColorIndex(NULL, spec, &new_alloc, FALSE) == INVALID) {
5917 sprintf(gszMsgBox, TgLoadString(STID_FAIL_ALLOC_NAMED_COLOR), spec);
5918 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
5919 return;
5920 }
5921 UtilStrCpyN(objShadowColorStr, sizeof(objShadowColorStr), spec);
5922
5923 sprintf(gszMsgBox, TgLoadString(STID_OBJ_SHADOW_COLOR_SET_TO_NAMED),
5924 objShadowColorStr);
5925 Msg(gszMsgBox);
5926 }
5927
SetObjectShadowOffsets()5928 void SetObjectShadowOffsets()
5929 {
5930 char spec[MAXSTRING];
5931
5932 *spec = '\0';
5933 sprintf(gszMsgBox, TgLoadString(STID_ENTER_XY_OFFSET_OBJ_SHADOW),
5934 objShadowXOffset, objShadowYOffset);
5935 if (Dialog(gszMsgBox, NULL, spec) == INVALID) return;
5936 UtilTrimBlanks(spec);
5937 if (*spec == '\0') return;
5938
5939 if (ParseXYSpec(spec, &objShadowXOffset, &objShadowYOffset)) {
5940 sprintf(gszMsgBox, TgLoadString(STID_OBJ_SHADOW_XY_OFFSETS_SET_TO),
5941 objShadowXOffset, objShadowYOffset);
5942 Msg(gszMsgBox);
5943 }
5944 }
5945
5946 static
DoAddObjectShadow()5947 void DoAddObjectShadow()
5948 {
5949 struct SelRec *sel_ptr=NULL;
5950 int new_alloc=0, color_index=QuickFindColorIndex(NULL, objShadowColorStr,
5951 &new_alloc, FALSE);
5952
5953 for (sel_ptr=botSel; sel_ptr != NULL; sel_ptr=sel_ptr->prev) {
5954 struct ObjRec *obj_ptr=sel_ptr->obj, *dup_obj_ptr=NULL, *group_obj=NULL;
5955 struct GroupRec *group_ptr=NULL;
5956 struct BBRec obbox, bbox;
5957 int locked=obj_ptr->locked;
5958
5959 dup_obj_ptr = DupObj(obj_ptr);
5960 AdjObjSplineVs(dup_obj_ptr);
5961 MoveObj(dup_obj_ptr, objShadowXOffset, objShadowYOffset);
5962 ChangeObjColor(dup_obj_ptr, color_index);
5963 UnionRect(&(obj_ptr->obbox), &(dup_obj_ptr->obbox), &obbox);
5964 UnionRect(&(obj_ptr->bbox), &(dup_obj_ptr->bbox), &bbox);
5965
5966 group_obj = JustCreateGroupObj();
5967 group_ptr = group_obj->detail.r;
5968
5969 group_obj->prev = obj_ptr->prev;
5970 group_obj->next = obj_ptr->next;
5971 if (obj_ptr == topObj) {
5972 curPage->top = topObj = group_obj;
5973 } else {
5974 obj_ptr->prev->next = group_obj;
5975 }
5976 if (obj_ptr == botObj) {
5977 curPage->bot = botObj = group_obj;
5978 } else {
5979 obj_ptr->next->prev = group_obj;
5980 }
5981 obj_ptr->prev = NULL;
5982 obj_ptr->next = dup_obj_ptr;
5983 dup_obj_ptr->prev = obj_ptr;
5984 dup_obj_ptr->next = NULL;
5985 group_ptr->first = obj_ptr;
5986 group_ptr->last = dup_obj_ptr;
5987
5988 obj_ptr->x = min(obj_ptr->x, dup_obj_ptr->x);
5989 obj_ptr->y = min(obj_ptr->y, dup_obj_ptr->y);
5990
5991 memcpy(&group_obj->obbox, &obbox, sizeof(struct BBRec));
5992 memcpy(&group_obj->bbox, &bbox, sizeof(struct BBRec));
5993
5994 group_obj->locked = locked;
5995
5996 sel_ptr->obj = group_obj;
5997 }
5998 UpdSelBBox();
5999 }
6000
AddObjectShadow()6001 void AddObjectShadow()
6002 {
6003 if (curChoice != NOTHING || topSel == NULL) {
6004 MsgBox(TgLoadCachedString(CSTID_NO_OBJ_SELECTED), TOOL_NAME, INFO_MB);
6005 return;
6006 }
6007 HighLightReverse();
6008 PrepareToRecord(CMD_REPLACE, topSel, botSel, numObjSelected);
6009 DoAddObjectShadow();
6010 RecordCmd(CMD_REPLACE, NULL, topSel, botSel, numObjSelected);
6011 RedrawAnArea(botObj, selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1),
6012 selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1));
6013 HighLightForward();
6014 SetFileModified(TRUE);
6015 justDupped = FALSE;
6016 }
6017
6018 static
DoRemoveObjectShadow()6019 void DoRemoveObjectShadow()
6020 {
6021 struct SelRec *sel_ptr=NULL;
6022
6023 for (sel_ptr=botSel; sel_ptr != NULL; sel_ptr=sel_ptr->prev) {
6024 struct ObjRec *obj_ptr=sel_ptr->obj;
6025
6026 if (obj_ptr->type == OBJ_GROUP) {
6027 struct GroupRec *group_ptr=obj_ptr->detail.r;
6028 struct ObjRec *first_obj=group_ptr->first;
6029
6030 if (first_obj != NULL) {
6031 struct ObjRec *second_obj=first_obj->next;
6032
6033 if (second_obj->next == NULL) {
6034 int first_w=(first_obj->obbox.rbx-first_obj->obbox.ltx);
6035 int first_h=(first_obj->obbox.rby-first_obj->obbox.lty);
6036 int second_w=(second_obj->obbox.rbx-second_obj->obbox.ltx);
6037 int second_h=(second_obj->obbox.rby-second_obj->obbox.lty);
6038
6039 if (first_w == second_w && first_h == second_h) {
6040 group_ptr->first = group_ptr->last = NULL;
6041
6042 first_obj->prev = obj_ptr->prev;
6043 first_obj->next = obj_ptr->next;
6044 if (obj_ptr == topObj) {
6045 curPage->top = topObj = first_obj;
6046 } else {
6047 obj_ptr->prev->next = first_obj;
6048 }
6049 if (obj_ptr == botObj) {
6050 curPage->bot = botObj = first_obj;
6051 } else {
6052 obj_ptr->next->prev = first_obj;
6053 }
6054 obj_ptr->prev = NULL;
6055 obj_ptr->next = NULL;
6056
6057 FreeObj(second_obj);
6058 FreeObj(obj_ptr);
6059
6060 sel_ptr->obj = first_obj;
6061 }
6062 }
6063 }
6064 }
6065 }
6066 }
6067
6068 static
CountObjectWithShadow()6069 int CountObjectWithShadow()
6070 {
6071 struct SelRec *sel_ptr=NULL;
6072 int count=0;
6073
6074 for (sel_ptr=botSel; sel_ptr != NULL; sel_ptr=sel_ptr->prev) {
6075 struct ObjRec *obj_ptr=sel_ptr->obj;
6076
6077 if (obj_ptr->type == OBJ_GROUP) {
6078 struct GroupRec *group_ptr=obj_ptr->detail.r;
6079 struct ObjRec *first_obj=group_ptr->first;
6080
6081 if (first_obj != NULL) {
6082 struct ObjRec *second_obj=first_obj->next;
6083
6084 if (second_obj->next == NULL) {
6085 int first_w=(first_obj->obbox.rbx-first_obj->obbox.ltx);
6086 int first_h=(first_obj->obbox.rby-first_obj->obbox.lty);
6087 int second_w=(second_obj->obbox.rbx-second_obj->obbox.ltx);
6088 int second_h=(second_obj->obbox.rby-second_obj->obbox.lty);
6089
6090 if (first_w == second_w && first_h == second_h) {
6091 count++;
6092 }
6093 }
6094 }
6095 }
6096 }
6097 return count;
6098 }
6099
RemoveObjectShadow()6100 void RemoveObjectShadow()
6101 {
6102 if (curChoice != NOTHING || topSel == NULL) {
6103 MsgBox(TgLoadCachedString(CSTID_NO_OBJ_SELECTED), TOOL_NAME, INFO_MB);
6104 return;
6105 }
6106 if (CountObjectWithShadow() == 0) {
6107 sprintf(gszMsgBox, TgLoadString(STID_NO_OBJ_SHADOW_FOUND));
6108 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
6109 return;
6110 }
6111 HighLightReverse();
6112 PrepareToRecord(CMD_REPLACE, topSel, botSel, numObjSelected);
6113 DoRemoveObjectShadow();
6114 RecordCmd(CMD_REPLACE, NULL, topSel, botSel, numObjSelected);
6115 RedrawAnArea(botObj, selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1),
6116 selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1));
6117 HighLightForward();
6118 SetFileModified(TRUE);
6119 justDupped = FALSE;
6120 }
6121
ReadObjectShadowInfo(buf)6122 int ReadObjectShadowInfo(buf)
6123 char *buf;
6124 {
6125 int x=0, y=0;
6126 char color_str[40], *psz=NULL;
6127
6128 if (importingFile) return TRUE;
6129
6130 psz = FindChar((int)'(', buf);
6131 *color_str = '\0';
6132 psz = ParseStr(psz, (int)',', color_str, sizeof(color_str));
6133 InitScan(psz, "\t\n, []");
6134 if (GETINT("objshadow_info", x, "x offset") == INVALID ||
6135 GETINT("objshadow_info", y, "y offset") == INVALID) {
6136 return FALSE;
6137 }
6138 UtilTrimBlanks(color_str);
6139 if (!ignoreObjectShadowInfoInFile) {
6140 UtilStrCpyN(objShadowColorStr, sizeof(objShadowColorStr), color_str);
6141 objShadowXOffset = x;
6142 objShadowYOffset = y;
6143 }
6144
6145 return TRUE;
6146 }
6147
6148 /* ----------------------- ExtendSegment ----------------------- */
6149
6150 static
ConsecutiveVerticesSelected(pn_index0,pn_index1)6151 int ConsecutiveVerticesSelected(pn_index0, pn_index1)
6152 int *pn_index0, *pn_index1;
6153 {
6154 int index0=topVSel->v_index[0], index1=topVSel->v_index[1];
6155
6156 if (index0+1 == index1) {
6157 *pn_index0 = index0;
6158 *pn_index1 = index1;
6159 return TRUE;
6160 } else if (index1+1 == index0) {
6161 *pn_index0 = index1;
6162 *pn_index1 = index0;
6163 return TRUE;
6164 }
6165 return FALSE;
6166 }
6167
ExtendSegment()6168 void ExtendSegment()
6169 {
6170 char *c_ptr=NULL, sz_value[MAXSTRING+1];
6171 char sz_spec[MAXSTRING+1], sz_spec_copy[MAXSTRING+1];
6172 double dval=(double)0;
6173 struct ObjRec *obj_ptr=NULL;
6174 struct PolyRec *poly_ptr=NULL;
6175 int dx=0, dy=0, x0=0, y0=0, x1=0, y1=0;
6176 double dnew_x=0, dnew_y=0;
6177 double ddx=(double)0, ddy=(double)0;
6178 struct AttrRec *name_attr=NULL, *on_reshape_attr=NULL;
6179 int ltx, lty, rbx, rby, auto_center_attr=FALSE;
6180 int has_on_reshape=FALSE, two_point_polyline=TRUE, index0=0, index1=1;
6181
6182 if (curChoice != NOTHING && curChoice != VERTEXMODE) {
6183 UtilStrCpyN(gszMsgBox, sizeof(gszMsgBox),
6184 TgLoadString(STID_TWO_VERTEX_POLY_ONLY));
6185 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
6186 return;
6187 } else if (curChoice == NOTHING) {
6188 if (topSel == NULL || topSel != botSel ||
6189 topSel->obj->type != OBJ_POLY || topSel->obj->detail.p->n != 2) {
6190 UtilStrCpyN(gszMsgBox, sizeof(gszMsgBox),
6191 TgLoadString(STID_TWO_VERTEX_POLY_ONLY));
6192 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
6193 return;
6194 }
6195 obj_ptr = topSel->obj;
6196 } else if (curChoice == VERTEXMODE) {
6197 if (topVSel == NULL) {
6198 if (topSel == NULL || topSel != botSel ||
6199 topSel->obj->type != OBJ_POLY || topSel->obj->detail.p->n != 2) {
6200 UtilStrCpyN(gszMsgBox, sizeof(gszMsgBox),
6201 TgLoadString(STID_TWO_VERTEX_POLY_ONLY));
6202 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
6203 return;
6204 }
6205 obj_ptr = topSel->obj;
6206 } else if (topVSel == botVSel && topVSel->n == 1 &&
6207 topVSel->obj->type == OBJ_POLY &&
6208 topVSel->obj->detail.p->n == 2) {
6209 /* treat this as if only the poly object is selected */
6210 obj_ptr = topVSel->obj;
6211 } else if (topVSel == botVSel && topVSel->n == 2 &&
6212 topVSel->obj->type == OBJ_POLY &&
6213 ConsecutiveVerticesSelected(&index0, &index1)) {
6214 /* treat this as if only the poly object is selected */
6215 obj_ptr = topVSel->obj;
6216 two_point_polyline = FALSE;
6217 } else {
6218 UtilStrCpyN(gszMsgBox, sizeof(gszMsgBox),
6219 TgLoadString(STID_TWO_CONSEC_VERTICES_ONLY));
6220 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
6221 return;
6222 }
6223 }
6224 ltx = obj_ptr->bbox.ltx; lty = obj_ptr->bbox.lty;
6225 rbx = obj_ptr->bbox.rbx; rby = obj_ptr->bbox.rby;
6226 poly_ptr = obj_ptr->detail.p;
6227
6228 *sz_spec = '\0';
6229 Dialog(TgLoadString(STID_ENTER_MULT_FACTOR),
6230 TgLoadCachedString(CSTID_DLG_ACCEPT_CANCEL), sz_spec);
6231 UtilTrimBlanks(sz_spec);
6232 if (*sz_spec == '\0') return;
6233
6234 strcpy(sz_spec_copy, sz_spec);
6235 if ((c_ptr=strtok(sz_spec, " ,\t\n\r")) == NULL) return;
6236 if (*c_ptr == '+') {
6237 UtilStrCpyN(sz_value, sizeof(sz_value), &c_ptr[1]);
6238 } else {
6239 UtilStrCpyN(sz_value, sizeof(sz_value), c_ptr);
6240 }
6241 if (sscanf(sz_value, "%lf", &dval) != 1) {
6242 sprintf(gszMsgBox, TgLoadString(STID_FAIL_TO_PARSE_FOR_A_VAL),
6243 sz_spec_copy);
6244 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
6245 return;
6246 }
6247 if (obj_ptr->ctm == NULL) {
6248 dx = poly_ptr->vlist[index1].x - poly_ptr->vlist[index0].x;
6249 dy = poly_ptr->vlist[index1].y - poly_ptr->vlist[index0].y;
6250 ddx = ((double)dx) * dval;
6251 ddy = ((double)dy) * dval;
6252 dx = round(ddx);
6253 dy = round(ddy);
6254 if (dx == 0 && dy == 0) {
6255 UtilStrCpyN(gszMsgBox, sizeof(gszMsgBox),
6256 TgLoadString(STID_RES_LINESEG_HAVE_ZERO_LEN));
6257 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
6258 return;
6259 }
6260 } else {
6261 TransformPointThroughCTM(poly_ptr->vlist[index0].x-obj_ptr->x,
6262 poly_ptr->vlist[index0].y-obj_ptr->y, obj_ptr->ctm, &x0, &y0);
6263 TransformPointThroughCTM(poly_ptr->vlist[index1].x-obj_ptr->x,
6264 poly_ptr->vlist[index1].y-obj_ptr->y, obj_ptr->ctm, &x1, &y1);
6265 dx = x1 - x0;
6266 dy = y1 - y0;
6267 ddx = ((double)dx) * dval;
6268 ddy = ((double)dy) * dval;
6269 dx = round(ddx);
6270 dy = round(ddy);
6271 if (dx == 0 && dy == 0) {
6272 UtilStrCpyN(gszMsgBox, sizeof(gszMsgBox),
6273 TgLoadString(STID_RES_LINESEG_HAVE_ZERO_LEN));
6274 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
6275 return;
6276 }
6277 }
6278 auto_center_attr = AutoCenterAttr(obj_ptr);
6279 has_on_reshape = HasOnReshape(obj_ptr, &name_attr);
6280
6281 if (has_on_reshape && name_attr != NULL) {
6282 on_reshape_attr = FindAttrWithName(obj_ptr, "on_reshape=", NULL);
6283 }
6284 HighLightReverse();
6285 if (on_reshape_attr != NULL) {
6286 StartCompositeCmd();
6287 }
6288 PrepareToReplaceAnObj(obj_ptr);
6289 if (obj_ptr->ctm == NULL) {
6290 if (dval > (double)0) {
6291 poly_ptr->vlist[index1].x = poly_ptr->vlist[index0].x + dx;
6292 poly_ptr->vlist[index1].y = poly_ptr->vlist[index0].y + dy;
6293 } else {
6294 poly_ptr->vlist[index0].x = poly_ptr->vlist[index1].x + dx;
6295 poly_ptr->vlist[index0].y = poly_ptr->vlist[index1].y + dy;
6296 }
6297 if (!two_point_polyline) {
6298 topVSel->x[0] = poly_ptr->vlist[index0].x;
6299 topVSel->y[0] = poly_ptr->vlist[index0].y;
6300 topVSel->x[1] = poly_ptr->vlist[index1].x;
6301 topVSel->y[1] = poly_ptr->vlist[index1].y;
6302 }
6303 } else {
6304 if (dval > (double)0) {
6305 x1 = x0 + obj_ptr->x + ddx;
6306 y1 = y0 + obj_ptr->y + ddy;
6307 ReverseTransformDoublePointThroughCTM(((double)x0)+ddx,
6308 ((double)y0)+ddy, obj_ptr->ctm, &dnew_x, &dnew_y);
6309 poly_ptr->vlist[index1].x = round(dnew_x) + obj_ptr->x;
6310 poly_ptr->vlist[index1].y = round(dnew_y) + obj_ptr->y;
6311 } else {
6312 x0 = x1 + obj_ptr->x + dx;
6313 y0 = y1 + obj_ptr->y + dy;
6314 ReverseTransformDoublePointThroughCTM(((double)x1)+ddx,
6315 ((double)y1)+ddy, obj_ptr->ctm, &dnew_x, &dnew_y);
6316 poly_ptr->vlist[index0].x = round(dnew_x) + obj_ptr->x;
6317 poly_ptr->vlist[index0].y = round(dnew_y) + obj_ptr->y;
6318 }
6319 if (!two_point_polyline) {
6320 int new_x=0, new_y=0;
6321
6322 TransformPointThroughCTM(poly_ptr->vlist[index0].x-obj_ptr->x,
6323 poly_ptr->vlist[index0].y-obj_ptr->y, obj_ptr->ctm, &new_x,
6324 &new_y);
6325 topVSel->x[0] = obj_ptr->x + new_x;
6326 topVSel->y[0] = obj_ptr->y + new_y;
6327 TransformPointThroughCTM(poly_ptr->vlist[index1].x-obj_ptr->x,
6328 poly_ptr->vlist[index1].y-obj_ptr->y, obj_ptr->ctm, &new_x,
6329 &new_y);
6330 topVSel->x[1] = obj_ptr->x + new_x;
6331 topVSel->y[1] = obj_ptr->y + new_y;
6332 }
6333 }
6334 AdjObjSplineVs(obj_ptr);
6335 if (poly_ptr->curved != LT_INTSPLINE) {
6336 UpdPolyBBox(obj_ptr, poly_ptr->n, poly_ptr->vlist);
6337 } else {
6338 UpdPolyBBox(obj_ptr, poly_ptr->intn, poly_ptr->intvlist);
6339 }
6340 if (auto_center_attr) {
6341 struct AttrRec *attr_ptr=obj_ptr->fattr;
6342 int modified=FALSE;
6343
6344 for ( ; attr_ptr != NULL; attr_ptr=attr_ptr->next) {
6345 if (attr_ptr->shown) {
6346 struct BBRec bbox;
6347
6348 CenterObjInOBBox(attr_ptr->obj, obj_ptr->obbox, &bbox);
6349 if (bbox.ltx < ltx) ltx = bbox.ltx;
6350 if (bbox.lty < lty) lty = bbox.lty;
6351 if (bbox.rbx > rbx) rbx = bbox.rbx;
6352 if (bbox.rby > rby) rby = bbox.rby;
6353 modified = TRUE;
6354 }
6355 }
6356 if (modified) AdjObjBBox(obj_ptr);
6357 }
6358 RecordReplaceAnObj(obj_ptr);
6359 if (on_reshape_attr != NULL) {
6360 DoExec(on_reshape_attr, obj_ptr);
6361 }
6362 if (on_reshape_attr != NULL) {
6363 EndCompositeCmd();
6364 }
6365 UpdSelBBox();
6366 RedrawAreas(botObj, ltx-GRID_ABS_SIZE(1), lty-GRID_ABS_SIZE(1),
6367 rbx+GRID_ABS_SIZE(1), rby+GRID_ABS_SIZE(1),
6368 obj_ptr->bbox.ltx-GRID_ABS_SIZE(1),
6369 obj_ptr->bbox.lty-GRID_ABS_SIZE(1),
6370 obj_ptr->bbox.rbx+GRID_ABS_SIZE(1),
6371 obj_ptr->bbox.rby+GRID_ABS_SIZE(1));
6372 SetFileModified(TRUE);
6373 justDupped = FALSE;
6374
6375 HighLightForward();
6376 }
6377
6378 /* -------------------- ToggleTighterStructuredSplines() -------------------- */
6379
ToggleTighterStructuredSplines()6380 void ToggleTighterStructuredSplines()
6381 {
6382 tighterStructSplines = !tighterStructSplines;
6383 AdjSplineVs();
6384 SetFileModified(TRUE);
6385 UpdSelBBox();
6386 justDupped = FALSE;
6387 ClearAndRedrawDrawWindow();
6388 UtilStrCpyN(gszMsgBox, sizeof(gszMsgBox), TgLoadString(tighterStructSplines ?
6389 STID_WILL_USE_TIGHTER_SPLINES : STID_WILL_USE_LOOSER_SPLINES));
6390 Msg(gszMsgBox);
6391 }
6392
6393 /* ----------------------- CreatePolySplineMenu() ----------------------- */
6394
RefreshPolySplineMenu(menu)6395 int RefreshPolySplineMenu(menu)
6396 TgMenu *menu;
6397 {
6398 int ok=TRUE;
6399
6400 /* UseTighterSplines */
6401 #ifdef NOT_DEFINED
6402 ok &= TgSetMenuItemCheckById(menu, CMDID_TOGGLETIGHTERSPLINES,
6403 tighterStructSplines);
6404 #endif /* NOT_DEFINED */
6405
6406 return ok;
6407 }
6408
CreatePolySplineMenu(parent_menu,x,y,menu_info,status_str_xlated)6409 TgMenu *CreatePolySplineMenu(parent_menu, x, y, menu_info, status_str_xlated)
6410 TgMenu *parent_menu;
6411 int x, y;
6412 TgMenuInfo *menu_info;
6413 int status_str_xlated; /* ignored, always 0 */
6414 {
6415 TgMenu *menu=TgCreateMenuFromMenuInfo(parent_menu, x, y, menu_info, FALSE);
6416
6417 if (menu != NULL) {
6418 if (!RefreshPolySplineMenu(menu)) {
6419 return TgDestroyMenu(menu, TRUE);
6420 }
6421 menu->refresh_proc = ((RefreshMenuFunc*)RefreshPolySplineMenu);
6422 }
6423 return menu;
6424 }
6425
6426