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/move.c,v 1.34 2011/05/16 16:21:58 william Exp $
19  */
20 
21 #define _INCLUDE_FROM_MOVE_C_
22 
23 #include "tgifdefs.h"
24 
25 #include "arc.e"
26 #include "attr.e"
27 #include "choice.e"
28 #include "cmd.e"
29 #include "cursor.e"
30 #include "dialog.e"
31 #include "drawing.e"
32 #include "dup.e"
33 #include "exec.e"
34 #include "grid.e"
35 #include "mainloop.e"
36 #include "mark.e"
37 #include "move.e"
38 #include "msg.e"
39 #include "names.e"
40 #include "obj.e"
41 #include "oval.e"
42 #include "poly.e"
43 #include "raster.e"
44 #include "rcbox.e"
45 #include "rect.e"
46 #include "ruler.e"
47 #include "select.e"
48 #include "setup.e"
49 #include "spline.e"
50 #include "stretch.e"
51 #include "strtbl.e"
52 
53 int oneMotionTimeout=200;
54 int minMoveInterval=0;
55 
56 static
MovePoly(ObjPtr,Dx,Dy)57 void MovePoly(ObjPtr, Dx, Dy)
58    register struct ObjRec *ObjPtr;
59    register int Dx, Dy;
60 {
61    register int i;
62 
63    for (i=0; i < ObjPtr->detail.p->n; i++) {
64       ObjPtr->detail.p->vlist[i].x += Dx;
65       ObjPtr->detail.p->vlist[i].y += Dy;
66    }
67 }
68 
69 static
MovePolygon(ObjPtr,Dx,Dy)70 void MovePolygon(ObjPtr, Dx, Dy)
71    register struct ObjRec *ObjPtr;
72    register int Dx, Dy;
73 {
74    register int i;
75 
76    for (i=0; i < ObjPtr->detail.g->n; i++) {
77       ObjPtr->detail.g->vlist[i].x += Dx;
78       ObjPtr->detail.g->vlist[i].y += Dy;
79    }
80 }
81 
82 static
MoveArc(ObjPtr,Dx,Dy)83 void MoveArc(ObjPtr, Dx, Dy)
84    struct ObjRec *ObjPtr;
85    register int Dx, Dy;
86 {
87    register struct ArcRec *arc_ptr=ObjPtr->detail.a;
88 
89    arc_ptr->xc += Dx;  arc_ptr->yc += Dy;
90    arc_ptr->x1 += Dx;  arc_ptr->y1 += Dy;
91    arc_ptr->x2 += Dx;  arc_ptr->y2 += Dy;
92    arc_ptr->ltx += Dx; arc_ptr->lty += Dy;
93 }
94 
MoveObj(ObjPtr,Dx,Dy)95 void MoveObj(ObjPtr, Dx, Dy)
96    struct ObjRec *ObjPtr;
97    int Dx, Dy;
98 {
99    struct ObjRec *ptr=NULL;
100    int saved_undoing_or_redoing=undoingOrRedoing;
101 
102    ObjPtr->x += Dx;
103    ObjPtr->y += Dy;
104    ObjPtr->bbox.ltx += Dx;
105    ObjPtr->bbox.lty += Dy;
106    ObjPtr->bbox.rbx += Dx;
107    ObjPtr->bbox.rby += Dy;
108    ObjPtr->obbox.ltx += Dx;
109    ObjPtr->obbox.lty += Dy;
110    ObjPtr->obbox.rbx += Dx;
111    ObjPtr->obbox.rby += Dy;
112    MoveRotatedObjCache(ObjPtr, Dx, Dy);
113    switch (ObjPtr->type) {
114    case OBJ_POLY:
115       MoveAttrs(ObjPtr->fattr, Dx, Dy);
116       MovePoly(ObjPtr, Dx, Dy);
117       /* fake the undoingOrRedoing so that no */
118       /*        actual auto-adjusting is done */
119       undoingOrRedoing = TRUE;
120       AdjObjSplineVs(ObjPtr);
121       undoingOrRedoing = saved_undoing_or_redoing;
122       break;
123    case OBJ_BOX:
124       MoveAttrs(ObjPtr->fattr, Dx, Dy);
125       break;
126    case OBJ_OVAL:
127       MoveAttrs(ObjPtr->fattr, Dx, Dy);
128       break;
129    case OBJ_TEXT:
130       ObjPtr->detail.t->baseline_y += Dy;
131       break;
132    case OBJ_POLYGON:
133       MoveAttrs(ObjPtr->fattr, Dx, Dy);
134       MovePolygon(ObjPtr, Dx, Dy);
135       AdjObjSplineVs(ObjPtr);
136       break;
137    case OBJ_ARC:
138       MoveAttrs(ObjPtr->fattr, Dx, Dy);
139       MoveArc(ObjPtr, Dx, Dy);
140       AdjObjSplineVs(ObjPtr);
141       break;
142    case OBJ_RCBOX:
143       MoveAttrs(ObjPtr->fattr, Dx, Dy);
144       break;
145    case OBJ_XBM:
146       MoveAttrs(ObjPtr->fattr, Dx, Dy);
147       break;
148    case OBJ_XPM:
149       MoveAttrs(ObjPtr->fattr, Dx, Dy);
150       break;
151    case OBJ_GROUP:
152    case OBJ_ICON:
153    case OBJ_SYM:
154    case OBJ_PIN:
155       MoveAttrs(ObjPtr->fattr, Dx, Dy);
156       for (ptr=ObjPtr->detail.r->first; ptr != NULL; ptr=ptr->next) {
157          MoveObj(ptr, Dx, Dy);
158       }
159       break;
160    }
161 }
162 
MoveAllSelObjects(Dx,Dy)163 void MoveAllSelObjects(Dx, Dy)
164    register int Dx, Dy;
165 {
166    register struct SelRec *sel_ptr;
167 
168    for (sel_ptr=topSel; sel_ptr != NULL; sel_ptr=sel_ptr->next) {
169       if (!sel_ptr->obj->locked) {
170          MoveObj(sel_ptr->obj, Dx, Dy);
171       }
172    }
173    if (numObjLocked != 0) Msg(TgLoadCachedString(CSTID_LOCKED_OBJS_NOT_MOVED));
174 }
175 
176 static
MarkObjectsForMove()177 void MarkObjectsForMove()
178 {
179    register struct ObjRec *obj_ptr;
180    register struct SelRec *sel_ptr;
181 
182    for (obj_ptr=botObj; obj_ptr != NULL; obj_ptr=obj_ptr->prev) {
183       obj_ptr->marked = FALSE;
184    }
185    for (sel_ptr=botSel; sel_ptr != NULL; sel_ptr=sel_ptr->prev) {
186       sel_ptr->obj->marked = TRUE;
187    }
188 }
189 
190 static
EndPtInObjList(XOff,YOff,FirstObjPtr)191 int EndPtInObjList(XOff, YOff, FirstObjPtr)
192    int XOff, YOff;
193    struct ObjRec *FirstObjPtr;
194    /* XOff and YOff are screen offsets */
195 {
196    register struct ObjRec *obj_ptr;
197    register struct AttrRec *attr_ptr;
198    int found=FALSE, saved_fill=0, saved_trans_pat=FALSE;
199 
200    for (obj_ptr=FirstObjPtr; obj_ptr != NULL; obj_ptr=obj_ptr->next) {
201       for (attr_ptr=obj_ptr->fattr; attr_ptr!=NULL; attr_ptr=attr_ptr->next) {
202          if (attr_ptr->shown &&
203                XOff >= OFFSET_X(attr_ptr->obj->bbox.ltx)-3 &&
204                YOff >= OFFSET_Y(attr_ptr->obj->bbox.lty)-3 &&
205                XOff <= OFFSET_X(attr_ptr->obj->bbox.rbx)+3 &&
206                YOff <= OFFSET_Y(attr_ptr->obj->bbox.rby)+3) {
207             return TRUE;
208          }
209       }
210       if (XOff >= OFFSET_X(obj_ptr->bbox.ltx)-3 &&
211             YOff >= OFFSET_Y(obj_ptr->bbox.lty)-3 &&
212             XOff <= OFFSET_X(obj_ptr->bbox.rbx)+3 &&
213             YOff <= OFFSET_Y(obj_ptr->bbox.rby)+3) {
214          switch (obj_ptr->type) {
215          case OBJ_TEXT: if (FindGoodText(XOff,YOff,obj_ptr)) return TRUE; break;
216          case OBJ_XBM: if (FindGoodXBm(XOff,YOff,obj_ptr)) return TRUE; break;
217          case OBJ_XPM: if (FindGoodXPm(XOff,YOff,obj_ptr)) return TRUE; break;
218          case OBJ_BOX:
219             saved_trans_pat = obj_ptr->trans_pat;
220             saved_fill = obj_ptr->detail.b->fill;
221             obj_ptr->detail.b->fill = SOLIDPAT;
222             found = FindGoodBox(XOff,YOff,obj_ptr);
223             obj_ptr->detail.b->fill = saved_fill;
224             obj_ptr->trans_pat = saved_trans_pat;
225             if (found) return TRUE;
226             break;
227          case OBJ_OVAL:
228             saved_trans_pat = obj_ptr->trans_pat;
229             saved_fill = obj_ptr->detail.o->fill;
230             obj_ptr->detail.o->fill = SOLIDPAT;
231             found = FindGoodOval(XOff,YOff,obj_ptr);
232             obj_ptr->detail.o->fill = saved_fill;
233             obj_ptr->trans_pat = saved_trans_pat;
234             if (found) return TRUE;
235             break;
236          case OBJ_POLY: if (FindGoodPoly(XOff,YOff,obj_ptr)) return TRUE; break;
237          case OBJ_POLYGON:
238             saved_trans_pat = obj_ptr->trans_pat;
239             saved_fill = obj_ptr->detail.g->fill;
240             obj_ptr->detail.g->fill = SOLIDPAT;
241             found = FindGoodPolygon(XOff,YOff,obj_ptr);
242             obj_ptr->detail.g->fill = saved_fill;
243             obj_ptr->trans_pat = saved_trans_pat;
244             if (found) return TRUE;
245             break;
246          case OBJ_ARC: if (FindGoodArc(XOff,YOff,obj_ptr)) return TRUE; break;
247          case OBJ_RCBOX:
248             saved_trans_pat = obj_ptr->trans_pat;
249             saved_fill = obj_ptr->detail.rcb->fill;
250             obj_ptr->detail.rcb->fill = SOLIDPAT;
251             found = FindGoodRCBox(XOff,YOff,obj_ptr);
252             obj_ptr->detail.rcb->fill = saved_fill;
253             obj_ptr->trans_pat = saved_trans_pat;
254             if (found) return TRUE;
255             break;
256 
257          case OBJ_GROUP:
258          case OBJ_ICON:
259          case OBJ_SYM:
260             if (EndPtInObjList(XOff,YOff,obj_ptr->detail.r->first)) {
261                return TRUE;
262             }
263             break;
264          case OBJ_PIN:
265             if (EndPtInObjList(XOff,YOff,GetPinObj(obj_ptr)->detail.r->first)) {
266                return TRUE;
267             }
268          }
269       }
270    }
271    return FALSE;
272 }
273 
EndPtInSelected(XOff,YOff)274 int EndPtInSelected(XOff, YOff)
275    int XOff, YOff;
276    /* XOff and YOff are screen offsets */
277 {
278    register struct SelRec *sel_ptr;
279    register struct ObjRec *obj_ptr;
280    register struct AttrRec *attr_ptr;
281    int found, saved_fill=0, saved_trans_pat=FALSE;
282 
283    for (sel_ptr=topSel; sel_ptr != NULL; sel_ptr=sel_ptr->next) {
284       obj_ptr = sel_ptr->obj;
285       if (obj_ptr->locked) continue;
286 
287       for (attr_ptr=obj_ptr->fattr; attr_ptr!=NULL; attr_ptr=attr_ptr->next) {
288          if (attr_ptr->shown &&
289                XOff >= OFFSET_X(attr_ptr->obj->bbox.ltx)-3 &&
290                YOff >= OFFSET_Y(attr_ptr->obj->bbox.lty)-3 &&
291                XOff <= OFFSET_X(attr_ptr->obj->bbox.rbx)+3 &&
292                YOff <= OFFSET_Y(attr_ptr->obj->bbox.rby)+3) {
293             return TRUE;
294          }
295       }
296       if (XOff >= OFFSET_X(obj_ptr->bbox.ltx)-3 &&
297             YOff >= OFFSET_Y(obj_ptr->bbox.lty)-3 &&
298             XOff <= OFFSET_X(obj_ptr->bbox.rbx)+3 &&
299             YOff <= OFFSET_Y(obj_ptr->bbox.rby)+3) {
300          switch (obj_ptr->type) {
301          case OBJ_TEXT: if (FindGoodText(XOff,YOff,obj_ptr)) return TRUE; break;
302          case OBJ_XBM: if (FindGoodXBm(XOff,YOff,obj_ptr)) return TRUE; break;
303          case OBJ_XPM: if (FindGoodXPm(XOff,YOff,obj_ptr)) return TRUE; break;
304          case OBJ_BOX:
305             saved_trans_pat = obj_ptr->trans_pat;
306             saved_fill = obj_ptr->detail.b->fill;
307             obj_ptr->detail.b->fill = SOLIDPAT;
308             found = FindGoodBox(XOff,YOff,obj_ptr);
309             obj_ptr->detail.b->fill = saved_fill;
310             obj_ptr->trans_pat = saved_trans_pat;
311             if (found) return TRUE;
312             break;
313          case OBJ_OVAL:
314             saved_trans_pat = obj_ptr->trans_pat;
315             saved_fill = obj_ptr->detail.o->fill;
316             obj_ptr->detail.o->fill = SOLIDPAT;
317             found = FindGoodOval(XOff,YOff,obj_ptr);
318             obj_ptr->detail.o->fill = saved_fill;
319             obj_ptr->trans_pat = saved_trans_pat;
320             if (found) return TRUE;
321             break;
322          case OBJ_POLY: if (FindGoodPoly(XOff,YOff,obj_ptr)) return TRUE; break;
323          case OBJ_POLYGON:
324             saved_trans_pat = obj_ptr->trans_pat;
325             saved_fill = obj_ptr->detail.g->fill;
326             obj_ptr->detail.g->fill = SOLIDPAT;
327             found = FindGoodPolygon(XOff,YOff,obj_ptr);
328             obj_ptr->detail.g->fill = saved_fill;
329             obj_ptr->trans_pat = saved_trans_pat;
330             if (found) return TRUE;
331             break;
332          case OBJ_ARC: if (FindGoodArc(XOff,YOff,obj_ptr)) return TRUE; break;
333          case OBJ_RCBOX:
334             saved_trans_pat = obj_ptr->trans_pat;
335             saved_fill = obj_ptr->detail.rcb->fill;
336             obj_ptr->detail.rcb->fill = SOLIDPAT;
337             found = FindGoodRCBox(XOff,YOff,obj_ptr);
338             obj_ptr->detail.rcb->fill = saved_fill;
339             obj_ptr->trans_pat = saved_trans_pat;
340             if (found) return TRUE;
341             break;
342 
343          case OBJ_GROUP:
344          case OBJ_ICON:
345          case OBJ_SYM:
346             if (EndPtInObjList(XOff,YOff,obj_ptr->detail.r->first)) {
347                return TRUE;
348             }
349             break;
350          case OBJ_PIN:
351             if (EndPtInObjList(XOff,YOff,GetPinObj(obj_ptr)->detail.r->first)) {
352                return TRUE;
353             }
354             break;
355          }
356       }
357    }
358    return FALSE;
359 }
360 
361 static
ConstrainedMoveAllSel(Dx,Dy,ltx,lty,rbx,rby)362 int ConstrainedMoveAllSel(Dx, Dy, ltx, lty, rbx, rby)
363    register int Dx, Dy;
364    int *ltx, *lty, *rbx, *rby;
365 {
366    struct ObjRec *obj_ptr=NULL;
367    int something_stretched=FALSE;
368 
369    for (obj_ptr=botObj; obj_ptr != NULL; obj_ptr=obj_ptr->prev) {
370       if (!obj_ptr->marked && obj_ptr->type==OBJ_POLY && !obj_ptr->locked) {
371          struct PolyRec *poly_ptr=obj_ptr->detail.p;
372          IntPoint *v=obj_ptr->detail.p->vlist;
373          int num_pts=obj_ptr->detail.p->n;
374          int x_off=0, y_off=0, move_first=FALSE, move_last=FALSE;
375          int move_2nd=FALSE, move_2nd_to_last=FALSE;
376          int possibly_move_3rd=FALSE, possibly_move_3rd_to_last=FALSE;
377 
378          if (obj_ptr->ctm == NULL) {
379             x_off = OFFSET_X(v[0].x); y_off = OFFSET_Y(v[0].y);
380             move_first = EndPtInSelected(x_off, y_off);
381             x_off = OFFSET_X(v[num_pts-1].x); y_off = OFFSET_Y(v[num_pts-1].y);
382             move_last = EndPtInSelected(x_off, y_off);
383          } else {
384             int tmp_x, tmp_y;
385 
386             TransformPointThroughCTM(v[0].x-obj_ptr->x, v[0].y-obj_ptr->y,
387                   obj_ptr->ctm, &tmp_x, &tmp_y);
388             tmp_x += obj_ptr->x;
389             tmp_y += obj_ptr->y;
390             x_off = OFFSET_X(tmp_x); y_off = OFFSET_Y(tmp_y);
391             move_first = EndPtInSelected(x_off, y_off);
392             TransformPointThroughCTM(v[num_pts-1].x-obj_ptr->x,
393                   v[num_pts-1].y-obj_ptr->y, obj_ptr->ctm, &tmp_x, &tmp_y);
394             tmp_x += obj_ptr->x;
395             tmp_y += obj_ptr->y;
396             x_off = OFFSET_X(tmp_x); y_off = OFFSET_Y(tmp_y);
397             move_last = EndPtInSelected(x_off, y_off);
398          }
399          if (move_first && poly_ptr->curved == LT_STRUCT_SPLINE &&
400                v[0].x == v[1].x && v[0].y == v[1].y) {
401             move_2nd = TRUE;
402             if (num_pts > 4 &&
403                   v[2].x == v[3].x && v[2].y == v[3].y &&
404                   v[4].x == v[3].x && v[4].y == v[3].y) {
405                possibly_move_3rd = TRUE;
406             }
407          }
408          if (move_last && poly_ptr->curved == LT_STRUCT_SPLINE &&
409                v[num_pts-1].x == v[num_pts-2].x &&
410                v[num_pts-1].y == v[num_pts-2].y) {
411             move_2nd_to_last = TRUE;
412             if (num_pts > 4 &&
413                   v[num_pts-3].x == v[num_pts-4].x &&
414                   v[num_pts-3].y == v[num_pts-4].y &&
415                   v[num_pts-5].x == v[num_pts-4].x &&
416                   v[num_pts-5].y == v[num_pts-4].y) {
417                possibly_move_3rd_to_last = TRUE;
418             }
419          }
420          if (move_first || move_last) {
421             PrepareToReplaceAnObj(obj_ptr);
422 
423             if (obj_ptr->ctm != NULL) {
424                /* Remove the transformations! */
425                int i;
426 
427                for (i=0; i < num_pts; i++) {
428                   int tmp_x, tmp_y;
429 
430                   TransformPointThroughCTM(v[i].x-obj_ptr->x, v[i].y-obj_ptr->y,
431                         obj_ptr->ctm, &tmp_x, &tmp_y);
432                   v[i].x = tmp_x+obj_ptr->x;
433                   v[i].y = tmp_y+obj_ptr->y;
434                }
435                free(obj_ptr->ctm);
436                obj_ptr->ctm = NULL;
437                UpdPolyBBox(obj_ptr, num_pts, v);
438             }
439             if (something_stretched) {
440                if (obj_ptr->bbox.ltx < *ltx) *ltx = obj_ptr->bbox.ltx;
441                if (obj_ptr->bbox.lty < *lty) *lty = obj_ptr->bbox.lty;
442                if (obj_ptr->bbox.rbx > *rbx) *rbx = obj_ptr->bbox.rbx;
443                if (obj_ptr->bbox.rby > *rby) *rby = obj_ptr->bbox.rby;
444             } else {
445                *ltx = obj_ptr->bbox.ltx; *lty = obj_ptr->bbox.lty;
446                *rbx = obj_ptr->bbox.rbx; *rby = obj_ptr->bbox.rby;
447             }
448             something_stretched = TRUE;
449             if (move_first && move_last) {
450                MoveObj(obj_ptr, Dx, Dy);
451             } else {
452                int index=INVALID, seg_dx=0, seg_dy=0;
453                int cur_seg_dx=0, cur_seg_dy=0;
454 
455                if (move_first) {
456                   if (num_pts > 2) {
457                      if (possibly_move_3rd) {
458                         /* only for LT_STRUCT_SPLINE */
459                         index = 3;
460                         cur_seg_dx = v[index-3].x - v[index].x;
461                         cur_seg_dy = v[index-3].y - v[index].y;
462                         seg_dx = v[index].x - v[index+3].x;
463                         seg_dy = v[index].y - v[index+3].y;
464                      } else {
465                         index = 1;
466                         cur_seg_dx = v[index-1].x - v[index].x;
467                         cur_seg_dy = v[index-1].y - v[index].y;
468                         seg_dx = v[index].x - v[index+1].x;
469                         seg_dy = v[index].y - v[index+1].y;
470                      }
471                   }
472                   v[0].x += Dx; v[0].y += Dy;
473                   if (move_2nd) {
474                      v[1].x += Dx; v[1].y += Dy;
475                   }
476                } else {
477                   if (num_pts > 2) {
478                      if (possibly_move_3rd_to_last) {
479                         /* only for LT_STRUCT_SPLINE */
480                         index = num_pts-4;
481                         cur_seg_dx = v[index+3].x - v[index].x;
482                         cur_seg_dy = v[index+3].y - v[index].y;
483                         seg_dx = v[index].x - v[index-3].x;
484                         seg_dy = v[index].y - v[index-3].y;
485                      } else {
486                         index = num_pts-2;
487                         cur_seg_dx = v[index+1].x - v[index].x;
488                         cur_seg_dy = v[index+1].y - v[index].y;
489                         seg_dx = v[index].x - v[index-1].x;
490                         seg_dy = v[index].y - v[index-1].y;
491                      }
492                   }
493                   v[num_pts-1].x += Dx; v[num_pts-1].y += Dy;
494                   if (move_2nd_to_last) {
495                      v[num_pts-2].x += Dx; v[num_pts-2].y += Dy;
496                   }
497                }
498                if (poly_ptr->curved == LT_STRUCT_SPLINE) {
499                   if (possibly_move_3rd_to_last) {
500                      if (cur_seg_dy==0 && cur_seg_dx!=0 &&
501                            (seg_dy!=0 || (seg_dy==0 && Dx==0))) {
502                         v[index-1].y += Dy;
503                         v[index].y += Dy;
504                         v[index+1].y += Dy;
505                      } else if (cur_seg_dx==0 && cur_seg_dy!=0 &&
506                            (seg_dx!=0 || (seg_dx==0 && Dy==0))) {
507                         v[index-1].x += Dx;
508                         v[index].x += Dx;
509                         v[index+1].x += Dx;
510                      }
511                   }
512                } else {
513                   if (num_pts>2 && cur_seg_dy==0 && cur_seg_dx!=0 &&
514                         (seg_dy!=0 || (seg_dy==0 && Dx==0))) {
515                      v[index].y += Dy;
516                   } else if (num_pts>2 && cur_seg_dx==0 && cur_seg_dy!=0 &&
517                         (seg_dx!=0 || (seg_dx==0 && Dy==0))) {
518                      v[index].x += Dx;
519                   }
520                }
521             }
522             AdjObjSplineVs(obj_ptr);
523             if (obj_ptr->detail.p->curved != LT_INTSPLINE) {
524                UpdPolyBBox(obj_ptr, num_pts, v);
525             } else {
526                UpdPolyBBox(obj_ptr, obj_ptr->detail.p->intn,
527                      obj_ptr->detail.p->intvlist);
528             }
529             if (AutoCenterAttr(obj_ptr)) {
530                struct AttrRec *attr_ptr=obj_ptr->fattr;
531                int modified=FALSE;
532 
533                for ( ; attr_ptr != NULL; attr_ptr=attr_ptr->next) {
534                   if (attr_ptr->shown) {
535                      struct BBRec bbox;
536 
537                      CenterObjInOBBox(attr_ptr->obj, obj_ptr->obbox,
538                            &bbox);
539                      if (bbox.ltx < *ltx) *ltx = bbox.ltx;
540                      if (bbox.lty < *lty) *lty = bbox.lty;
541                      if (bbox.rbx > *rbx) *rbx = bbox.rbx;
542                      if (bbox.rby > *rby) *rby = bbox.rby;
543                      modified = TRUE;
544                   }
545                }
546                if (modified) AdjObjBBox(obj_ptr);
547             }
548             if (obj_ptr->bbox.ltx < *ltx) *ltx = obj_ptr->bbox.ltx;
549             if (obj_ptr->bbox.lty < *lty) *lty = obj_ptr->bbox.lty;
550             if (obj_ptr->bbox.rbx > *rbx) *rbx = obj_ptr->bbox.rbx;
551             if (obj_ptr->bbox.rby > *rby) *rby = obj_ptr->bbox.rby;
552             RecordReplaceAnObj(obj_ptr);
553          }
554       }
555    }
556    MoveAllSelObjects(Dx, Dy);
557    return something_stretched;
558 }
559 
MoveAllSel(Dx,Dy)560 void MoveAllSel(Dx, Dy)
561    register int Dx, Dy;
562 {
563    int ltx=0, lty=0, rbx=0, rby=0;
564    struct SubCmdRec *sub_cmd=NULL;
565 
566    sub_cmd = (struct SubCmdRec *)malloc(sizeof(struct SubCmdRec));
567    if (sub_cmd == NULL) FailAllocMessage();
568    memset(sub_cmd, 0, sizeof(struct SubCmdRec));
569    sub_cmd->detail.move.dx = Dx;
570    sub_cmd->detail.move.dy = Dy;
571 
572    if (moveMode==CONST_MOVE && !justDupped) {
573       MarkObjectsForMove();
574 
575       StartCompositeCmd();
576       PrepareToRecord(CMD_MOVE, topSel, botSel, numObjSelected);
577       RecordCmd(CMD_MOVE, sub_cmd, NULL, NULL, 0);
578       if (ConstrainedMoveAllSel(Dx, Dy, &ltx, &lty, &rbx, &rby)) {
579          ltx = min(ltx,min(selLtX,selLtX+Dx));
580          lty = min(lty,min(selLtY,selLtY+Dy));
581          rbx = max(rbx,max(selRbX,selRbX+Dx));
582          rby = max(rby,max(selRbY,selRbY+Dy));
583          RedrawAnArea(botObj, ltx-GRID_ABS_SIZE(1), lty-GRID_ABS_SIZE(1),
584                rbx+GRID_ABS_SIZE(1), rby+GRID_ABS_SIZE(1));
585       } else {
586          RedrawAreas(botObj, selLtX-GRID_ABS_SIZE(1),
587                selLtY-GRID_ABS_SIZE(1),
588                selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1),
589                selLtX-GRID_ABS_SIZE(1)+Dx, selLtY-GRID_ABS_SIZE(1)+Dy,
590                selRbX+GRID_ABS_SIZE(1)+Dx, selRbY+GRID_ABS_SIZE(1)+Dy);
591       }
592       EndCompositeCmd();
593    } else {
594       MoveAllSelObjects(Dx, Dy);
595       PrepareToRecord(CMD_MOVE, topSel, botSel, numObjSelected);
596       RecordCmd(CMD_MOVE, sub_cmd, NULL, NULL, 0);
597       RedrawAreas(botObj, selLtX-GRID_ABS_SIZE(1),
598             selLtY-GRID_ABS_SIZE(1),
599             selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1),
600             selLtX-GRID_ABS_SIZE(1)+Dx, selLtY-GRID_ABS_SIZE(1)+Dy,
601             selRbX+GRID_ABS_SIZE(1)+Dx, selRbY+GRID_ABS_SIZE(1)+Dy);
602    }
603    free(sub_cmd);
604 }
605 
MoveAnObj(ObjPtr,TopOwner,Dx,Dy)606 void MoveAnObj(ObjPtr, TopOwner, Dx, Dy)
607    struct ObjRec *ObjPtr, *TopOwner;
608    int Dx, Dy;
609    /* This function is meant to be called from within an internal command */
610 {
611    if (execCurDepth <= 0) {
612 #ifdef _TGIF_DBG /* debug, do not translate */
613       TgAssert(FALSE,
614             "MoveAnObj() called not from an internal command!", NULL);
615       return;
616 #endif /* _TGIF_DBG */
617    }
618    if (ObjPtr == TopOwner) {
619       struct SelRec *saved_top_sel=topSel, *saved_bot_sel=botSel;
620       int ltx=ObjPtr->bbox.ltx, lty=ObjPtr->bbox.lty;
621       int rbx=ObjPtr->bbox.rbx, rby=ObjPtr->bbox.rby;
622       struct SubCmdRec *sub_cmd=NULL;
623 
624       topSel = botSel = (struct SelRec *)malloc(sizeof(struct SelRec));
625       if (topSel == NULL) FailAllocMessage();
626       memset(topSel, 0, sizeof(struct SelRec));
627       topSel->next = topSel->prev = NULL;
628       topSel->obj = ObjPtr;
629       UpdSelBBox();
630 
631       sub_cmd = (struct SubCmdRec *)malloc(sizeof(struct SubCmdRec));
632       if (sub_cmd == NULL) FailAllocMessage();
633       memset(sub_cmd, 0, sizeof(struct SubCmdRec));
634       sub_cmd->detail.move.dx = Dx;
635       sub_cmd->detail.move.dy = Dy;
636 
637       MoveAllSelObjects(Dx, Dy);
638       PrepareToRecord(CMD_MOVE, topSel, botSel, numObjSelected);
639       RecordCmd(CMD_MOVE, sub_cmd, NULL, NULL, 0);
640       RedrawAreas(botObj, ltx-GRID_ABS_SIZE(1), lty-GRID_ABS_SIZE(1),
641             rbx+GRID_ABS_SIZE(1), rby+GRID_ABS_SIZE(1),
642             ltx-GRID_ABS_SIZE(1)+Dx, lty-GRID_ABS_SIZE(1)+Dy,
643             rbx+GRID_ABS_SIZE(1)+Dx, rby+GRID_ABS_SIZE(1)+Dy);
644 
645       free(sub_cmd);
646 
647       free(topSel);
648       topSel = saved_top_sel;
649       botSel = saved_bot_sel;
650       UpdSelBBox();
651    } else {
652       int ltx=TopOwner->bbox.ltx, lty=TopOwner->bbox.lty;
653       int rbx=TopOwner->bbox.rbx, rby=TopOwner->bbox.rby;
654 
655       PrepareToReplaceAnObj(TopOwner);
656       MoveAttrs(ObjPtr->fattr, Dx, Dy);
657       MoveObj(ObjPtr, Dx, Dy);
658       if (ObjPtr->bbox.ltx < ltx) ltx = ObjPtr->bbox.ltx;
659       if (ObjPtr->bbox.lty < lty) lty = ObjPtr->bbox.lty;
660       if (ObjPtr->bbox.rbx > rbx) rbx = ObjPtr->bbox.rbx;
661       if (ObjPtr->bbox.rby > rby) rby = ObjPtr->bbox.rby;
662       while (ObjPtr != TopOwner) {
663          ObjPtr = ObjPtr->tmp_parent;
664          AdjObjBBox(ObjPtr);
665          if (ObjPtr->bbox.ltx < ltx) ltx = ObjPtr->bbox.ltx;
666          if (ObjPtr->bbox.lty < lty) lty = ObjPtr->bbox.lty;
667          if (ObjPtr->bbox.rbx > rbx) rbx = ObjPtr->bbox.rbx;
668          if (ObjPtr->bbox.rby > rby) rby = ObjPtr->bbox.rby;
669       }
670       RecordReplaceAnObj(TopOwner);
671       RedrawAnArea(botObj, ltx-GRID_ABS_SIZE(1), lty-GRID_ABS_SIZE(1),
672             rbx+GRID_ABS_SIZE(1), rby+GRID_ABS_SIZE(1));
673       UpdSelBBox();
674    }
675 }
676 
677 typedef struct tagRubberRec {
678    struct BBRec obbox;
679    XPoint *sv, *pv;
680    int sn;
681    int radius; /* for rcbox */
682 
683    XPoint *v; /* for oval, poly or polygon */
684    int num_pts, curved, intn; /* for oval, poly or polygon */
685    IntPoint *cntrlv, *polyv; /* for poly or polygon */
686    char *smooth; /* for poly or polygon */
687 
688    int ltx, lty, w, h, angle1, angle2, fill; /* for arc */
689    int saved_xc, saved_yc, saved_x1, saved_y1; /* for arc */
690    int saved_x2, saved_y2, saved_ltx, saved_lty; /* for arc */
691    int xc, yc, x1, y1, x2, y2; /* for arc */
692 } RubberInfo;
693 
694 static
FreeRubberInfo(pInnerObj,pRubberInfo)695 void FreeRubberInfo(pInnerObj, pRubberInfo)
696    struct ObjRec *pInnerObj;
697    RubberInfo *pRubberInfo;
698 {
699    switch (pInnerObj->type) {
700    case OBJ_ARC:
701       if (pInnerObj->ctm != NULL) {
702          free(pRubberInfo->sv);
703          free(pRubberInfo->pv);
704       }
705       break;
706 
707    case OBJ_RCBOX:
708    case OBJ_OVAL:
709       if (pInnerObj->ctm != NULL) {
710          free(pRubberInfo->sv);
711          free(pRubberInfo->pv);
712       }
713       break;
714 
715    case OBJ_POLY:
716    case OBJ_POLYGON:
717       if (pRubberInfo->sv != NULL) free(pRubberInfo->sv);
718       if (pRubberInfo->polyv != NULL) free(pRubberInfo->polyv);
719       if (pRubberInfo->smooth != NULL) free(pRubberInfo->smooth);
720       if (pRubberInfo->curved == LT_INTSPLINE &&
721             pRubberInfo->cntrlv != NULL) {
722          free(pRubberInfo->cntrlv);
723       }
724       break;
725    }
726 }
727 
728 static
SetRubberInfo(pInnerObj,pRubberInfo)729 void SetRubberInfo(pInnerObj, pRubberInfo)
730    struct ObjRec *pInnerObj;
731    RubberInfo *pRubberInfo;
732 {
733    int i=0, n=0;
734    IntPoint *vs=NULL;
735    char *smooth=NULL;
736    struct PolyRec *poly_ptr=NULL;
737    struct PolygonRec *polygon_ptr=NULL;
738 
739    switch (pInnerObj->type) {
740    case OBJ_BOX:
741    case OBJ_XBM:
742    case OBJ_XPM:
743    case OBJ_TEXT:
744       if (pInnerObj->ctm == NULL) {
745          pRubberInfo->obbox.ltx = OFFSET_X(pInnerObj->obbox.ltx);
746          pRubberInfo->obbox.lty = OFFSET_Y(pInnerObj->obbox.lty);
747          pRubberInfo->obbox.rbx = OFFSET_X(pInnerObj->obbox.rbx);
748          pRubberInfo->obbox.rby = OFFSET_Y(pInnerObj->obbox.rby);
749       } else {
750          /* no need to do anything here, everything is computed */
751       }
752       break;
753    case OBJ_RCBOX:
754       if (pInnerObj->ctm == NULL) {
755          pRubberInfo->obbox.ltx = OFFSET_X(pInnerObj->obbox.ltx);
756          pRubberInfo->obbox.lty = OFFSET_Y(pInnerObj->obbox.lty);
757          pRubberInfo->obbox.rbx = OFFSET_X(pInnerObj->obbox.rbx);
758          pRubberInfo->obbox.rby = OFFSET_Y(pInnerObj->obbox.rby);
759          pRubberInfo->radius = pInnerObj->detail.rcb->radius;
760       } else {
761          pRubberInfo->sn = pInnerObj->detail.rcb->rotated_n;
762          pRubberInfo->sv = (XPoint*)malloc(pRubberInfo->sn*sizeof(XPoint));
763          pRubberInfo->pv = (XPoint*)malloc(pRubberInfo->sn*sizeof(XPoint));
764          if (pRubberInfo->sv == NULL || pRubberInfo->pv == NULL) {
765             FailAllocMessage();
766          }
767          for (i=0; i < pRubberInfo->sn; i++) {
768             pRubberInfo->pv[i].x = pInnerObj->detail.rcb->rotated_vlist[i].x;
769             pRubberInfo->pv[i].y = pInnerObj->detail.rcb->rotated_vlist[i].y;
770          }
771       }
772       break;
773    case OBJ_ARC:
774       if (pInnerObj->ctm == NULL) {
775          struct ObjRec *arc_obj_ptr=DupObj(pInnerObj);
776          struct ArcRec *arc_ptr=arc_obj_ptr->detail.a;
777 
778          pRubberInfo->fill = arc_ptr->fill;
779          pRubberInfo->ltx = OFFSET_X(arc_ptr->ltx);
780          pRubberInfo->lty = OFFSET_Y(arc_ptr->lty);
781          pRubberInfo->w = OFFSET_X(arc_ptr->ltx+arc_ptr->w)-pRubberInfo->ltx;
782          pRubberInfo->h = OFFSET_Y(arc_ptr->lty+arc_ptr->h)-pRubberInfo->lty;
783          pRubberInfo->angle1 = arc_ptr->angle1;
784          pRubberInfo->angle2 = arc_ptr->angle2;
785          pRubberInfo->xc = OFFSET_X(arc_ptr->xc);
786          pRubberInfo->yc = OFFSET_Y(arc_ptr->yc);
787          pRubberInfo->x1 = OFFSET_X(arc_ptr->x1);
788          pRubberInfo->y1 = OFFSET_Y(arc_ptr->y1);
789          ArcRealX2Y2(arc_ptr, &pRubberInfo->x2, &pRubberInfo->y2);
790          pRubberInfo->x2 = OFFSET_X(pRubberInfo->x2);
791          pRubberInfo->y2 = OFFSET_Y(pRubberInfo->y2);
792          pRubberInfo->saved_xc = pRubberInfo->xc;
793          pRubberInfo->saved_yc = pRubberInfo->yc;
794          pRubberInfo->saved_x1 = pRubberInfo->x1;
795          pRubberInfo->saved_y1 = pRubberInfo->y1;
796          pRubberInfo->saved_x2 = pRubberInfo->x2;
797          pRubberInfo->saved_y2 = pRubberInfo->y2;
798          pRubberInfo->saved_ltx = pRubberInfo->ltx;
799          pRubberInfo->saved_lty = pRubberInfo->lty;
800 
801          FreeArcObj(arc_obj_ptr);
802       } else {
803          pRubberInfo->sn = pInnerObj->detail.a->rotated_n;
804          pRubberInfo->sv = (XPoint*)malloc((pRubberInfo->sn+2)*sizeof(XPoint));
805          pRubberInfo->pv = (XPoint*)malloc((pRubberInfo->sn+2)*sizeof(XPoint));
806          if (pRubberInfo->sv == NULL || pRubberInfo->pv == NULL) {
807             FailAllocMessage();
808          }
809          for (i=0; i < pRubberInfo->sn+2; i++) {
810             pRubberInfo->pv[i].x = pInnerObj->detail.a->rotated_vlist[i].x;
811             pRubberInfo->pv[i].y = pInnerObj->detail.a->rotated_vlist[i].y;
812          }
813       }
814       break;
815    case OBJ_OVAL:
816       if (pInnerObj->ctm == NULL) {
817          pRubberInfo->num_pts = 13;
818          pRubberInfo->obbox.ltx = OFFSET_X(pInnerObj->obbox.ltx);
819          pRubberInfo->obbox.lty = OFFSET_Y(pInnerObj->obbox.lty);
820          pRubberInfo->obbox.rbx = OFFSET_X(pInnerObj->obbox.rbx);
821          pRubberInfo->obbox.rby = OFFSET_Y(pInnerObj->obbox.rby);
822       } else {
823          pRubberInfo->sn = pInnerObj->detail.o->rotated_n;
824          pRubberInfo->sv = (XPoint*)malloc(pRubberInfo->sn*sizeof(XPoint));
825          pRubberInfo->pv = (XPoint*)malloc(pRubberInfo->sn*sizeof(XPoint));
826          if (pRubberInfo->sv == NULL || pRubberInfo->pv == NULL) {
827             FailAllocMessage();
828          }
829          for (i=0; i < pRubberInfo->sn; i++) {
830             pRubberInfo->pv[i].x = pInnerObj->detail.o->rotated_vlist[i].x;
831             pRubberInfo->pv[i].y = pInnerObj->detail.o->rotated_vlist[i].y;
832          }
833       }
834       break;
835    case OBJ_POLY:
836       poly_ptr = pInnerObj->detail.p;
837       pRubberInfo->curved = poly_ptr->curved;
838       if (pRubberInfo->curved == LT_STRUCT_SPLINE) {
839          n = poly_ptr->ssn;
840          vs = poly_ptr->ssvlist;
841          smooth = poly_ptr->ssmooth;
842       } else {
843          n = poly_ptr->n;
844          vs = poly_ptr->vlist;
845          smooth = poly_ptr->smooth;
846       }
847       pRubberInfo->num_pts = n;
848       pRubberInfo->polyv =
849             (IntPoint*)malloc((pRubberInfo->num_pts+1)*sizeof(IntPoint));
850       if (pRubberInfo->polyv == NULL) FailAllocMessage();
851       if (pRubberInfo->curved != LT_INTSPLINE && smooth != NULL) {
852          pRubberInfo->smooth = (char*)malloc((n+1)*sizeof(char));
853          if (pRubberInfo->smooth == NULL) FailAllocMessage();
854       }
855       if (pInnerObj->ctm == NULL) {
856          for (i=0; i < pRubberInfo->num_pts; i++) {
857             pRubberInfo->polyv[i].x = vs[i].x;
858             pRubberInfo->polyv[i].y = vs[i].y;
859             if (pRubberInfo->smooth != NULL) {
860                pRubberInfo->smooth[i] = smooth[i];
861             }
862          }
863       } else {
864          for (i=0; i < pRubberInfo->num_pts; i++) {
865             int x=0, y=0;
866 
867             TransformPointThroughCTM(vs[i].x-pInnerObj->x, vs[i].y-pInnerObj->y,
868                   pInnerObj->ctm, &x, &y);
869             pRubberInfo->polyv[i].x = x+pInnerObj->x;
870             pRubberInfo->polyv[i].y = y+pInnerObj->y;
871             if (pRubberInfo->smooth != NULL) {
872                pRubberInfo->smooth[i] = smooth[i];
873             }
874          }
875       }
876       if (pRubberInfo->curved != LT_INTSPLINE) {
877          pRubberInfo->sv = MakeMultiSplinePolyVertex(pRubberInfo->curved,
878                &pRubberInfo->sn, pRubberInfo->smooth, drawOrigX, drawOrigY,
879                pRubberInfo->num_pts, pRubberInfo->polyv);
880       } else {
881          pRubberInfo->sv = MakeIntSplinePolyVertex(&pRubberInfo->sn,
882                &pRubberInfo->intn, &pRubberInfo->cntrlv, drawOrigX,
883                drawOrigY, pRubberInfo->num_pts, pRubberInfo->polyv);
884       }
885       break;
886    case OBJ_POLYGON:
887       polygon_ptr = pInnerObj->detail.g;
888       pRubberInfo->curved = polygon_ptr->curved;
889       if (pRubberInfo->curved == LT_STRUCT_SPLINE) {
890          n = polygon_ptr->ssn;
891          vs = polygon_ptr->ssvlist;
892          smooth = polygon_ptr->ssmooth;
893       } else {
894          n = polygon_ptr->n;
895          vs = polygon_ptr->vlist;
896          smooth = polygon_ptr->smooth;
897       }
898       pRubberInfo->num_pts = n;
899       pRubberInfo->polyv =
900             (IntPoint*)malloc((pRubberInfo->num_pts+1)*sizeof(IntPoint));
901       if (pRubberInfo->polyv == NULL) FailAllocMessage();
902       if (pRubberInfo->curved != LT_INTSPLINE && smooth != NULL) {
903          pRubberInfo->smooth =
904                (char*)malloc((pRubberInfo->num_pts+1)*sizeof(char));
905          if (pRubberInfo->smooth == NULL) FailAllocMessage();
906       }
907       if (pInnerObj->ctm == NULL) {
908          for (i=0; i < pRubberInfo->num_pts; i++) {
909             pRubberInfo->polyv[i].x = vs[i].x;
910             pRubberInfo->polyv[i].y = vs[i].y;
911             if (pRubberInfo->smooth != NULL) {
912                pRubberInfo->smooth[i] = smooth[i];
913             }
914          }
915       } else {
916          for (i=0; i < pRubberInfo->num_pts; i++) {
917             int x=0, y=0;
918 
919             TransformPointThroughCTM(vs[i].x-pInnerObj->x, vs[i].y-pInnerObj->y,
920                   pInnerObj->ctm, &x, &y);
921             pRubberInfo->polyv[i].x = x+pInnerObj->x;
922             pRubberInfo->polyv[i].y = y+pInnerObj->y;
923             if (pRubberInfo->smooth != NULL) {
924                pRubberInfo->smooth[i] = smooth[i];
925             }
926          }
927       }
928       if (pRubberInfo->curved != LT_INTSPLINE) {
929          pRubberInfo->sv = MakeMultiSplinePolygonVertex(pRubberInfo->curved,
930                &pRubberInfo->sn, pRubberInfo->smooth, drawOrigX, drawOrigY,
931                pRubberInfo->num_pts, pRubberInfo->polyv);
932       } else {
933          pRubberInfo->sv = MakeIntSplinePolygonVertex(&pRubberInfo->sn,
934                &pRubberInfo->intn, &pRubberInfo->cntrlv, drawOrigX,
935                drawOrigY, pRubberInfo->num_pts, pRubberInfo->polyv);
936       }
937       break;
938    case OBJ_GROUP:
939    case OBJ_ICON:
940    case OBJ_SYM:
941    case OBJ_PIN:
942       pRubberInfo->obbox.ltx = OFFSET_X(pInnerObj->obbox.ltx);
943       pRubberInfo->obbox.lty = OFFSET_Y(pInnerObj->obbox.lty);
944       pRubberInfo->obbox.rbx = OFFSET_X(pInnerObj->obbox.rbx);
945       pRubberInfo->obbox.rby = OFFSET_Y(pInnerObj->obbox.rby);
946       break;
947    }
948 }
949 
950 static
DrawInnerRubberObj(pInnerObj,pRubberInfo,dx,dy)951 void DrawInnerRubberObj(pInnerObj, pRubberInfo, dx, dy)
952    struct ObjRec *pInnerObj;
953    RubberInfo *pRubberInfo;
954    int dx, dy;
955 {
956    int i=0;
957 
958    switch (pInnerObj->type) {
959    case OBJ_BOX:
960    case OBJ_XBM:
961    case OBJ_XPM:
962    case OBJ_TEXT:
963       if (pInnerObj->ctm == NULL) {
964          SelBox(drawWindow, revDefaultGC,
965                pRubberInfo->obbox.ltx+dx, pRubberInfo->obbox.lty+dy,
966                pRubberInfo->obbox.rbx+dx, pRubberInfo->obbox.rby+dy);
967       } else {
968          XPoint obj_obbox_vs[5];
969 
970          for (i=0; i < 5; i++) {
971             obj_obbox_vs[i].x = pInnerObj->rotated_obbox[i].x+dx;
972             obj_obbox_vs[i].y = pInnerObj->rotated_obbox[i].y+dy;
973          }
974          XDrawLines(mainDisplay, drawWindow, revDefaultGC,
975                obj_obbox_vs, 5, CoordModeOrigin);
976       }
977       break;
978    case OBJ_RCBOX:
979       if (pInnerObj->ctm == NULL) {
980          SetRCBoxVertex(
981                pRubberInfo->obbox.ltx+dx, pRubberInfo->obbox.lty+dy,
982                pRubberInfo->obbox.rbx+dx, pRubberInfo->obbox.rby+dy,
983                pRubberInfo->radius);
984          MyRCBox(drawWindow, revDefaultGC,
985                pRubberInfo->obbox.ltx, pRubberInfo->obbox.lty,
986                pRubberInfo->obbox.rbx, pRubberInfo->obbox.rby,
987                pRubberInfo->radius);
988       } else {
989          for (i=0; i < pRubberInfo->sn; i++) {
990             pRubberInfo->sv[i].x = pRubberInfo->pv[i].x + dx;
991             pRubberInfo->sv[i].y = pRubberInfo->pv[i].y + dy;
992          }
993          XDrawLines(mainDisplay, drawWindow, revDefaultGC,
994                pRubberInfo->sv, pRubberInfo->sn, CoordModeOrigin);
995       }
996       break;
997    case OBJ_ARC:
998       if (pInnerObj->ctm == NULL) {
999          if (!(pRubberInfo->fill == NONEPAT ||
1000                (pInnerObj->trans_pat && pRubberInfo->fill == BACKPAT))) {
1001             XDrawLine(mainDisplay, drawWindow, revDefaultGC,
1002                   pRubberInfo->xc, pRubberInfo->yc,
1003                   pRubberInfo->x1, pRubberInfo->y1);
1004             XDrawLine(mainDisplay, drawWindow, revDefaultGC,
1005                   pRubberInfo->xc, pRubberInfo->yc,
1006                   pRubberInfo->x2, pRubberInfo->y2);
1007          }
1008          XDrawArc(mainDisplay, drawWindow, revDefaultGC,
1009                pRubberInfo->ltx, pRubberInfo->lty,
1010                pRubberInfo->w, pRubberInfo->h,
1011                pRubberInfo->angle1, pRubberInfo->angle2);
1012       } else {
1013          for (i=0; i < pRubberInfo->sn+2; i++) {
1014             pRubberInfo->sv[i].x = pRubberInfo->pv[i].x + dx;
1015             pRubberInfo->sv[i].y = pRubberInfo->pv[i].y + dy;
1016          }
1017          if (!(pRubberInfo->fill == NONEPAT ||
1018                (pInnerObj->trans_pat && pRubberInfo->fill == BACKPAT))) {
1019             XDrawLines(mainDisplay, drawWindow, revDefaultGC,
1020                   pRubberInfo->sv, pRubberInfo->sn+2, CoordModeOrigin);
1021          } else {
1022             XDrawLines(mainDisplay, drawWindow, revDefaultGC,
1023                   pRubberInfo->sv, pRubberInfo->sn, CoordModeOrigin);
1024          }
1025       }
1026       break;
1027    case OBJ_OVAL:
1028       if (pInnerObj->ctm == NULL) {
1029          struct BBRec o_bbox;
1030 
1031          o_bbox.ltx = pRubberInfo->obbox.ltx+dx;
1032          o_bbox.lty = pRubberInfo->obbox.lty+dy;
1033          o_bbox.rbx = pRubberInfo->obbox.rbx+dx;
1034          o_bbox.rby = pRubberInfo->obbox.rby+dy;
1035          MyOval(drawWindow, revDefaultGC, o_bbox);
1036       } else {
1037          for (i=0; i < pRubberInfo->sn; i++) {
1038             pRubberInfo->sv[i].x = pRubberInfo->pv[i].x + dx;
1039             pRubberInfo->sv[i].y = pRubberInfo->pv[i].y + dy;
1040          }
1041          XDrawLines(mainDisplay, drawWindow, revDefaultGC,
1042                pRubberInfo->sv, pRubberInfo->sn, CoordModeOrigin);
1043       }
1044       break;
1045    case OBJ_POLY:
1046    case OBJ_POLYGON:
1047       XDrawLines(mainDisplay, drawWindow, revDefaultGC,
1048             pRubberInfo->sv, pRubberInfo->sn, CoordModeOrigin);
1049       break;
1050    case OBJ_GROUP:
1051    case OBJ_ICON:
1052    case OBJ_SYM:
1053    case OBJ_PIN:
1054       SelBox(drawWindow, revDefaultGC,
1055             pRubberInfo->obbox.ltx+dx, pRubberInfo->obbox.lty+dy,
1056             pRubberInfo->obbox.rbx+dx, pRubberInfo->obbox.rby+dy);
1057       break;
1058    }
1059 }
1060 
1061 static
UpdateInnerRubberObj(pInnerObj,pRubberInfo,dx,dy)1062 void UpdateInnerRubberObj(pInnerObj, pRubberInfo, dx, dy)
1063    struct ObjRec *pInnerObj;
1064    RubberInfo *pRubberInfo;
1065    int dx, dy;
1066 {
1067    int i=0, n=0;
1068    IntPoint *vs=NULL;
1069    struct PolyRec *poly_ptr=NULL;
1070    struct PolygonRec *polygon_ptr=NULL;
1071 
1072    switch (pInnerObj->type) {
1073    case OBJ_ARC:
1074       if (pInnerObj->ctm == NULL) {
1075          pRubberInfo->xc = pRubberInfo->saved_xc+dx;
1076          pRubberInfo->yc = pRubberInfo->saved_yc+dy;
1077          pRubberInfo->x1 = pRubberInfo->saved_x1+dx;
1078          pRubberInfo->y1 = pRubberInfo->saved_y1+dy;
1079          pRubberInfo->x2 = pRubberInfo->saved_x2+dx;
1080          pRubberInfo->y2 = pRubberInfo->saved_y2+dy;
1081          pRubberInfo->ltx = pRubberInfo->saved_ltx+dx;
1082          pRubberInfo->lty = pRubberInfo->saved_lty+dy;
1083       }
1084       break;
1085    case OBJ_POLY:
1086    case OBJ_POLYGON:
1087       if (pRubberInfo->sv != NULL) {
1088          free(pRubberInfo->sv);
1089          pRubberInfo->sv = NULL;
1090       }
1091       switch (pInnerObj->type) {
1092       case OBJ_POLY:
1093          poly_ptr = pInnerObj->detail.p;
1094          if (poly_ptr->curved == LT_STRUCT_SPLINE) {
1095             n = poly_ptr->ssn;
1096             vs = poly_ptr->ssvlist;
1097          } else {
1098             n = poly_ptr->n;
1099             vs = poly_ptr->vlist;
1100          }
1101          if (pInnerObj->ctm == NULL) {
1102             for (i=0; i < pRubberInfo->num_pts; i++) {
1103                pRubberInfo->polyv[i].x = vs[i].x+ABS_SIZE(dx);
1104                pRubberInfo->polyv[i].y = vs[i].y+ABS_SIZE(dy);
1105             }
1106          } else {
1107             for (i=0; i < pRubberInfo->num_pts; i++) {
1108                int x=0, y=0;
1109 
1110                TransformPointThroughCTM(vs[i].x-pInnerObj->x,
1111                      vs[i].y-pInnerObj->y, pInnerObj->ctm, &x, &y);
1112                pRubberInfo->polyv[i].x = x+pInnerObj->x+ABS_SIZE(dx);
1113                pRubberInfo->polyv[i].y = y+pInnerObj->y+ABS_SIZE(dy);
1114             }
1115          }
1116          if (pRubberInfo->curved != LT_INTSPLINE) {
1117             pRubberInfo->sv = MakeMultiSplinePolyVertex(pRubberInfo->curved,
1118                   &pRubberInfo->sn, pRubberInfo->smooth, drawOrigX,
1119                   drawOrigY, pRubberInfo->num_pts, pRubberInfo->polyv);
1120          } else {
1121             free(pRubberInfo->cntrlv);
1122             pRubberInfo->sv = MakeIntSplinePolyVertex(&pRubberInfo->sn,
1123                   &pRubberInfo->intn, &pRubberInfo->cntrlv, drawOrigX,
1124                   drawOrigY, pRubberInfo->num_pts, pRubberInfo->polyv);
1125          }
1126          break;
1127       case OBJ_POLYGON:
1128          polygon_ptr = pInnerObj->detail.g;
1129          if (polygon_ptr->curved == LT_STRUCT_SPLINE) {
1130             n = polygon_ptr->ssn;
1131             vs = polygon_ptr->ssvlist;
1132          } else {
1133             n = polygon_ptr->n;
1134             vs = polygon_ptr->vlist;
1135          }
1136          if (pInnerObj->ctm == NULL) {
1137             for (i=0; i < pRubberInfo->num_pts; i++) {
1138                pRubberInfo->polyv[i].x = vs[i].x+ABS_SIZE(dx);
1139                pRubberInfo->polyv[i].y = vs[i].y+ABS_SIZE(dy);
1140             }
1141          } else {
1142             for (i=0; i < pRubberInfo->num_pts; i++) {
1143                int x=0, y=0;
1144 
1145                TransformPointThroughCTM(vs[i].x-pInnerObj->x,
1146                      vs[i].y-pInnerObj->y, pInnerObj->ctm, &x, &y);
1147                pRubberInfo->polyv[i].x = x+pInnerObj->x+ABS_SIZE(dx);
1148                pRubberInfo->polyv[i].y = y+pInnerObj->y+ABS_SIZE(dy);
1149             }
1150          }
1151          if (pRubberInfo->curved != LT_INTSPLINE) {
1152             pRubberInfo->sv = MakeMultiSplinePolygonVertex(pRubberInfo->curved,
1153                   &pRubberInfo->sn, pRubberInfo->smooth, drawOrigX, drawOrigY,
1154                   pRubberInfo->num_pts, pRubberInfo->polyv);
1155          } else {
1156             free(pRubberInfo->cntrlv);
1157             pRubberInfo->sv = MakeIntSplinePolygonVertex(&pRubberInfo->sn,
1158                   &pRubberInfo->intn, &pRubberInfo->cntrlv, drawOrigX,
1159                   drawOrigY, pRubberInfo->num_pts, pRubberInfo->polyv);
1160          }
1161          break;
1162       }
1163       break;
1164    }
1165 }
1166 
1167 static
MoveSubObjEventCheck(ev,pn_move_sub_obj)1168 void MoveSubObjEventCheck(ev, pn_move_sub_obj)
1169    XEvent *ev;
1170    int *pn_move_sub_obj;
1171 {
1172    if (ev->type == MotionNotify) {
1173       *pn_move_sub_obj = (ev->xmotion.state & ControlMask) &&
1174             (!(ev->xmotion.state & ShiftMask));
1175    } else if (ev->type == KeyPress || ev->type == KeyRelease) {
1176       char s[80];
1177       KeySym key_sym;
1178 
1179       XLookupString(&(ev->xkey), s, sizeof(s), &key_sym, NULL);
1180       if (key_sym == XK_Control_L || key_sym == XK_Control_R) {
1181          *pn_move_sub_obj = (ev->type == KeyPress);
1182       }
1183    }
1184 }
1185 
MoveAnAttr(attr_ptr,attr_owner_obj,dx,dy)1186 void MoveAnAttr(attr_ptr, attr_owner_obj, dx, dy)
1187    struct AttrRec *attr_ptr;
1188    struct ObjRec *attr_owner_obj;
1189    int dx, dy;
1190 {
1191    struct ObjRec *text_obj_ptr=attr_ptr->obj;
1192    int ltx, lty, rbx, rby;
1193 
1194    if (attr_owner_obj == NULL) {
1195       attr_owner_obj = GetTopOwner(attr_ptr->owner);
1196    }
1197    ltx = attr_owner_obj->bbox.ltx;
1198    lty = attr_owner_obj->bbox.lty;
1199    rbx = attr_owner_obj->bbox.rbx;
1200    rby = attr_owner_obj->bbox.rby;
1201    PrepareToReplaceAnObj(attr_owner_obj);
1202    MoveObj(text_obj_ptr, dx, dy);
1203    RecursivelyAdjObjBBox(attr_ptr->owner, attr_ptr->owner, attr_owner_obj);
1204    RecordReplaceAnObj(attr_owner_obj);
1205    RedrawAreas(botObj, ltx-GRID_ABS_SIZE(1), lty-GRID_ABS_SIZE(1),
1206          rbx+GRID_ABS_SIZE(1), rby+GRID_ABS_SIZE(1),
1207          attr_owner_obj->bbox.ltx-GRID_ABS_SIZE(1),
1208          attr_owner_obj->bbox.lty-GRID_ABS_SIZE(1),
1209          attr_owner_obj->bbox.rbx+GRID_ABS_SIZE(1),
1210          attr_owner_obj->bbox.rby+GRID_ABS_SIZE(1));
1211    SetFileModified(TRUE);
1212 }
1213 
MoveSel(OrigX,OrigY,ObjPtr,down_button_ev)1214 void MoveSel(OrigX, OrigY, ObjPtr, down_button_ev)
1215    int OrigX, OrigY;
1216    struct ObjRec *ObjPtr;
1217    XButtonEvent *down_button_ev;
1218 {
1219    int sel_ltx=0, sel_lty=0, sel_rbx=0, sel_rby=0;
1220    int ruler_ltx=0, ruler_lty=0, ruler_rbx=0, ruler_rby=0;
1221    int moving=TRUE, dx=0, dy=0, grid_x=OrigX, grid_y=OrigY;
1222    int can_move_sub_obj=FALSE, move_sub_obj=FALSE, no_no_lock_sel=FALSE;
1223    char buf[80], x_buf[80], y_buf[80];
1224    XEvent ev;
1225    Time down_click_time=(Time)0;
1226    RubberInfo rubber_info;
1227 
1228    if (down_button_ev != NULL) {
1229       down_click_time = down_button_ev->time;
1230    }
1231    if (numObjSelected == numObjLocked || ObjPtr->locked) {
1232       no_no_lock_sel = TRUE;
1233    }
1234    XFlush(mainDisplay);
1235    XSync(mainDisplay, False);
1236 
1237    if (XCheckMaskEvent(mainDisplay, ExposureMask, &ev) ||
1238          XCheckMaskEvent(mainDisplay, VisibilityChangeMask, &ev)) {
1239       ExposeEventHandler(&ev, TRUE);
1240    }
1241    if (ObjPtr->type == OBJ_TEXT && ObjPtr->detail.t->attr != NULL) {
1242       can_move_sub_obj = TRUE;
1243       SetStringStatus(TgLoadString(STID_HINT_CTL_MOVE_ATTR_ONLY));
1244    }
1245    if (!move_sub_obj && !no_no_lock_sel) {
1246       sel_ltx = OFFSET_X(selNoLockLtX)-1; sel_lty = OFFSET_Y(selNoLockLtY)-1;
1247       sel_rbx = OFFSET_X(selNoLockRbX)+1; sel_rby = OFFSET_Y(selNoLockRbY)+1;
1248    }
1249    ruler_ltx = OFFSET_X(selNoLockObjLtX); ruler_lty = OFFSET_Y(selNoLockObjLtY);
1250    ruler_rbx = OFFSET_X(selNoLockObjRbX); ruler_rby = OFFSET_Y(selNoLockObjRbY);
1251 
1252    if (!move_sub_obj && !no_no_lock_sel) {
1253       SelBox(drawWindow, revDefaultGC, sel_ltx, sel_lty, sel_rbx, sel_rby);
1254    }
1255    PixelToMeasurementUnit(x_buf, 0);
1256    PixelToMeasurementUnit(y_buf, 0);
1257    if (VerboseMeasureTooltip()) {
1258       sprintf(buf, "dx=%s dy=%s", x_buf, y_buf);
1259    } else {
1260       sprintf(buf, "dx=%s\ndy=%s", x_buf, y_buf);
1261    }
1262    StartShowMeasureCursor(OrigX, OrigY, buf, TRUE);
1263    BeginIntervalRulers(ruler_ltx, ruler_lty, ruler_rbx, ruler_rby);
1264 
1265    memset(&rubber_info, 0, sizeof(RubberInfo));
1266    SetRubberInfo(ObjPtr, &rubber_info);
1267    DrawInnerRubberObj(ObjPtr, &rubber_info, 0, 0);
1268 
1269    if (!debugNoPointerGrab) {
1270       XGrabPointer(mainDisplay, drawWindow, FALSE,
1271             PointerMotionMask | ButtonReleaseMask,
1272             GrabModeAsync, GrabModeAsync, None, moveCursor, CurrentTime);
1273    }
1274    dx = dy = 0;
1275 
1276    while (moving) {
1277       XEvent input;
1278 
1279       XNextEvent(mainDisplay, &input);
1280 
1281       if (input.type == Expose || input.type == VisibilityNotify) {
1282          ExposeEventHandler(&input, TRUE);
1283       } else if (input.type == ButtonRelease) {
1284          Time release_time=input.xbutton.time;
1285 
1286          XUngrabPointer(mainDisplay, CurrentTime);
1287          XSync(mainDisplay, False);
1288          moving = FALSE;
1289 
1290          EndIntervalRulers(grid_x, grid_y);
1291          PixelToMeasurementUnit(x_buf, ABS_SIZE(dx));
1292          PixelToMeasurementUnit(y_buf, ABS_SIZE(dy));
1293          if (VerboseMeasureTooltip()) {
1294             sprintf(buf, "dx=%s dy=%s", x_buf, y_buf);
1295          } else {
1296             sprintf(buf, "dx=%s\ndy=%s", x_buf, y_buf);
1297          }
1298          EndShowMeasureCursor(grid_x, grid_y, buf, TRUE);
1299          if (!move_sub_obj && !no_no_lock_sel) {
1300             SelBox(drawWindow, revDefaultGC, sel_ltx+dx, sel_lty+dy, sel_rbx+dx,
1301                   sel_rby+dy);
1302          }
1303          DrawInnerRubberObj(ObjPtr, &rubber_info, dx, dy);
1304 
1305          dx = grid_x - OrigX;
1306          dy = grid_y - OrigY;
1307 
1308          if (oneMotionSelectMove && down_button_ev != NULL &&
1309                (release_time-down_click_time) < oneMotionTimeout) {
1310             dx = dy = 0;
1311          } else if (!oneMotionSelectMove && down_button_ev != NULL &&
1312                (release_time-down_click_time) < minMoveInterval) {
1313             dx = dy = 0;
1314          }
1315       } else if (input.type == MotionNotify || input.type == KeyPress ||
1316             input.type == KeyRelease) {
1317          int x=0, y=0, saved_move_sub_obj=move_sub_obj;
1318 
1319          PixelToMeasurementUnit(x_buf, ABS_SIZE(dx));
1320          PixelToMeasurementUnit(y_buf, ABS_SIZE(dy));
1321          if (VerboseMeasureTooltip()) {
1322             sprintf(buf, "dx=%s dy=%s", x_buf, y_buf);
1323          } else {
1324             sprintf(buf, "dx=%s\ndy=%s", x_buf, y_buf);
1325          }
1326          ShowMeasureCursor(grid_x, grid_y, buf, TRUE);
1327          if (input.type == KeyPress || input.type == KeyRelease) {
1328             x = grid_x;
1329             y = grid_y;
1330          } else {
1331             x = input.xmotion.x;
1332             y = input.xmotion.y;
1333          }
1334          if (shiftForDiagMouseMove && DiagEventCheck(&input)) {
1335             if (useRecentDupDistance && justDupped &&
1336                   useRecentForDiagMouseMove) {
1337                DiagGridXY(OrigX-ZOOMED_SIZE(dupDx), OrigY-ZOOMED_SIZE(dupDy),
1338                      &x, &y);
1339             } else {
1340                DiagGridXY(OrigX, OrigY, &x, &y);
1341             }
1342          } else if (can_move_sub_obj) {
1343             MoveSubObjEventCheck(&input, &move_sub_obj);
1344          }
1345          GridXY(x, y, &grid_x, &grid_y);
1346 
1347          /* erase */
1348          DrawInnerRubberObj(ObjPtr, &rubber_info, dx, dy);
1349          if (!saved_move_sub_obj && !no_no_lock_sel) {
1350             SelBox(drawWindow, revDefaultGC, sel_ltx+dx, sel_lty+dy, sel_rbx+dx,
1351                   sel_rby+dy);
1352          }
1353          dx = grid_x - OrigX;
1354          dy = grid_y - OrigY;
1355 
1356          if ((dx != 0 || dy != 0) &&
1357                (numObjSelected == numObjLocked || ObjPtr->locked)) {
1358             XUngrabPointer(mainDisplay, CurrentTime);
1359             XSync(mainDisplay, False);
1360 
1361             EndIntervalRulers(grid_x, grid_y);
1362             PixelToMeasurementUnit(x_buf, ABS_SIZE(dx));
1363             PixelToMeasurementUnit(y_buf, ABS_SIZE(dy));
1364             if (VerboseMeasureTooltip()) {
1365                sprintf(buf, "dx=%s dy=%s", x_buf, y_buf);
1366             } else {
1367                sprintf(buf, "dx=%s\ndy=%s", x_buf, y_buf);
1368             }
1369             ShowMeasureCursor(grid_x, grid_y, buf, TRUE);
1370             EndShowMeasureCursor(grid_x, grid_y, buf, TRUE);
1371             if (!move_sub_obj && !no_no_lock_sel) {
1372                SelBox(drawWindow, revDefaultGC, sel_ltx+dx, sel_lty+dy,
1373                      sel_rbx+dx, sel_rby+dy);
1374             }
1375             MsgBox(TgLoadString(STID_LOCKED_OBJS_CANT_BE_MOVED), TOOL_NAME,
1376                   INFO_MB);
1377             return;
1378          }
1379          PixelToMeasurementUnit(x_buf, ABS_SIZE(dx));
1380          PixelToMeasurementUnit(y_buf, ABS_SIZE(dy));
1381          if (VerboseMeasureTooltip()) {
1382             sprintf(buf, "dx=%s dy=%s", x_buf, y_buf);
1383          } else {
1384             sprintf(buf, "dx=%s\ndy=%s", x_buf, y_buf);
1385          }
1386          DrawIntervalRulers(ruler_ltx+dx, ruler_lty+dy, ruler_rbx+dx,
1387                ruler_rby+dy, buf);
1388          if (!move_sub_obj && !no_no_lock_sel) {
1389             SelBox(drawWindow, revDefaultGC, sel_ltx+dx, sel_lty+dy, sel_rbx+dx,
1390                   sel_rby+dy);
1391          }
1392          ShowMeasureCursor(grid_x, grid_y, buf, TRUE);
1393 
1394          UpdateInnerRubberObj(ObjPtr, &rubber_info, dx, dy);
1395          DrawInnerRubberObj(ObjPtr, &rubber_info, dx, dy);
1396 
1397          while (XCheckMaskEvent(mainDisplay, PointerMotionMask, &ev)) ;
1398       }
1399    }
1400    FreeRubberInfo(ObjPtr, &rubber_info);
1401 
1402    if (dx != 0 || dy != 0) {
1403       if (numObjSelected == numObjLocked || ObjPtr->locked) {
1404          MsgBox(TgLoadString(STID_LOCKED_OBJS_CANT_BE_MOVED), TOOL_NAME,
1405                INFO_MB);
1406          return;
1407       }
1408       HighLightReverse();
1409       dx = ABS_SIZE(dx);
1410       dy = ABS_SIZE(dy);
1411       if (numObjSelected == numObjLocked) {
1412          HighLightForward();
1413          return;
1414       }
1415       if (can_move_sub_obj && move_sub_obj) {
1416          MoveAnAttr(ObjPtr->detail.t->attr, NULL, dx, dy);
1417       } else {
1418          MoveAllSel(dx, dy);
1419       }
1420       HighLightForward();
1421       UpdSelBBox();
1422       if (justDupped) {
1423          dupDx += dx;
1424          dupDy += dy;
1425       }
1426       SetFileModified(TRUE);
1427    }
1428    if (can_move_sub_obj) {
1429       ShowCurChoiceMouseStatus(curChoice, 0, FALSE);
1430    }
1431 }
1432 
1433 static
IsSmoothForStructuredSpline(vlist_index,n,vlist)1434 int IsSmoothForStructuredSpline(vlist_index, n, vlist)
1435    int vlist_index, n;
1436    IntPoint *vlist;
1437 {
1438    int i=0, j=0, num_hinge_vs=(n+2)/3;
1439 
1440 #ifdef _TGIF_DBG /* debug, do not translate */
1441    TgAssert((n+2)%3 == 0,
1442          "invalid n in IsSmoothForStructuredSpline()", NULL);
1443 #endif /* _TGIF_DBG */
1444    for (i=0, j=0; i < num_hinge_vs; i++, j+=3) {
1445       if (vlist_index > j+1) continue;
1446       if (i == 0) {
1447          if (vlist_index == j) {
1448             return FALSE;
1449          }
1450          return (vlist[0].x != vlist[1].x || vlist[0].y != vlist[1].y);
1451       } else if (i == num_hinge_vs-1) {
1452          if (vlist_index == j) {
1453             return FALSE;
1454          }
1455          return (vlist[n-1].x != vlist[n-2].x || vlist[n-1].y != vlist[n-2].y);
1456       } else {
1457          if (vlist_index == j) {
1458             return FALSE;
1459          }
1460          return (vlist[j-1].x != vlist[j].x || vlist[j-1].y != vlist[j].y);
1461       }
1462    }
1463    return FALSE;
1464 }
1465 
FinishMoveVertexForStretchStructSpline(vsel_ptr,abs_dx,abs_dy,psssi)1466 void FinishMoveVertexForStretchStructSpline(vsel_ptr, abs_dx, abs_dy, psssi)
1467    struct VSelRec *vsel_ptr;
1468    int abs_dx, abs_dy;
1469    StretchStructuredSplineInfo *psssi;
1470 {
1471    struct ObjRec *obj_ptr=NULL;
1472    struct PolyRec *poly_ptr=NULL;
1473    struct PolygonRec *polygon_ptr=NULL;
1474    int was_smooth_point=(!psssi->hinge), vlist_index=0;
1475 
1476    obj_ptr = vsel_ptr->obj;
1477    switch (obj_ptr->type) {
1478    case OBJ_POLY:
1479       poly_ptr = obj_ptr->detail.p;
1480       break;
1481    case OBJ_POLYGON:
1482       polygon_ptr = obj_ptr->detail.g;
1483       break;
1484    }
1485    if (was_smooth_point) {
1486       vlist_index = GetVlistIndexFromStretchStructuredSplineInfo(psssi,
1487             vsel_ptr->v_index[0]);
1488    }
1489    if (poly_ptr != NULL) {
1490       UpdateObjForStretchStructSpline(obj_ptr, poly_ptr->n,
1491             poly_ptr->vlist, abs_dx, abs_dy, psssi);
1492       if (was_smooth_point && !IsSmoothForStructuredSpline(vlist_index,
1493             poly_ptr->n, poly_ptr->vlist)) {
1494          if (!psssi->prev_valid) {
1495             /* first poly point */
1496             vsel_ptr->v_index[0] -= 1;
1497          } else if (!psssi->next_valid) {
1498             /* last poly point */
1499             /* merge with next point, so don't need to do anything */
1500          } else {
1501             if (!psssi->earlier_smooth_selected) {
1502                vsel_ptr->v_index[0] -= 2;
1503             } else {
1504                /* merge with next point, so don't need to do anything */
1505             }
1506          }
1507          SetIPTInfoForStretchPoly(vsel_ptr->v_index[0], poly_ptr->n,
1508                poly_ptr->vlist, psssi);
1509       }
1510    } else if (polygon_ptr != NULL) {
1511       UpdateObjForStretchStructSpline(obj_ptr, polygon_ptr->n,
1512             polygon_ptr->vlist, abs_dx, abs_dy, psssi);
1513       if (was_smooth_point && !IsSmoothForStructuredSpline(vlist_index,
1514             polygon_ptr->n, polygon_ptr->vlist)) {
1515          if (psssi->orig_hinge_index == 0 ||
1516                psssi->orig_hinge_index == polygon_ptr->n-1) {
1517             vsel_ptr->v_index[0] = 0;
1518          } else if (!psssi->earlier_smooth_selected) {
1519             if (vsel_ptr->v_index[0] == 1) {
1520                vsel_ptr->v_index[0] -= 1;
1521             } else {
1522                vsel_ptr->v_index[0] -= 2;
1523             }
1524          }
1525          SetIPTInfoForStretchPolygon(vsel_ptr->v_index[0], polygon_ptr->n,
1526                polygon_ptr->vlist, psssi);
1527       }
1528    }
1529 }
1530 
MoveAllSelVs(abs_dx,abs_dy)1531 void MoveAllSelVs(abs_dx, abs_dy)
1532    int abs_dx, abs_dy;
1533 {
1534    int i;
1535    IntPoint *v=NULL;
1536    struct ObjRec *obj_ptr=NULL;
1537    struct VSelRec *vsel_ptr=NULL;
1538    int n=0, ltx=selLtX, lty=selLtY, rbx=selRbX, rby=selRbY;
1539 
1540    StartCompositeCmd();
1541    for (vsel_ptr=botVSel; vsel_ptr != NULL; vsel_ptr=vsel_ptr->prev) {
1542       int auto_retracted_arrow=FALSE, curved=(-1);
1543       struct PolyRec *poly_ptr=NULL;
1544       struct PolygonRec *polygon_ptr=NULL;
1545       StretchStructuredSplineInfo *psssi=NULL;
1546 
1547       obj_ptr = vsel_ptr->obj;
1548       switch (obj_ptr->type) {
1549       case OBJ_POLY:
1550          poly_ptr = obj_ptr->detail.p;
1551          curved = poly_ptr->curved;
1552          if (curved == LT_STRUCT_SPLINE) {
1553             v = poly_ptr->ssvlist;
1554             n = poly_ptr->ssn;
1555             psssi = (StretchStructuredSplineInfo*)(obj_ptr->userdata);
1556             if (psssi == NULL) {
1557                psssi = (StretchStructuredSplineInfo*)malloc(
1558                      sizeof(StretchStructuredSplineInfo));
1559                if (psssi == NULL) FailAllocMessage();
1560                memset(psssi, 0, sizeof(StretchStructuredSplineInfo));
1561                obj_ptr->userdata = vsel_ptr->obj->userdata = psssi;
1562                SetIPTInfoForStretchPoly(vsel_ptr->v_index[0], poly_ptr->n,
1563                      poly_ptr->vlist, psssi);
1564             }
1565          } else {
1566             v = poly_ptr->vlist;
1567             n = poly_ptr->n;
1568          }
1569          auto_retracted_arrow = AutoRetractedArrowAttr(obj_ptr, TRUE);
1570          break;
1571       case OBJ_POLYGON:
1572          polygon_ptr = obj_ptr->detail.g;
1573          curved = polygon_ptr->curved;
1574          if (curved == LT_STRUCT_SPLINE) {
1575             v = polygon_ptr->ssvlist;
1576             n = polygon_ptr->ssn;
1577             psssi = (StretchStructuredSplineInfo*)(obj_ptr->userdata);
1578             if (psssi == NULL) {
1579                psssi = (StretchStructuredSplineInfo*)malloc(
1580                      sizeof(StretchStructuredSplineInfo));
1581                if (psssi == NULL) FailAllocMessage();
1582                memset(psssi, 0, sizeof(StretchStructuredSplineInfo));
1583                obj_ptr->userdata = vsel_ptr->obj->userdata = psssi;
1584                SetIPTInfoForStretchPolygon(vsel_ptr->v_index[0], polygon_ptr->n,
1585                      polygon_ptr->vlist, psssi);
1586             }
1587          } else {
1588             v = polygon_ptr->vlist;
1589             n = polygon_ptr->n;
1590          }
1591          break;
1592       }
1593       PrepareToReplaceAnObj(obj_ptr);
1594       if (obj_ptr->ctm == NULL) {
1595          for (i=0; i < vsel_ptr->n; i++) {
1596             vsel_ptr->x[i] += abs_dx;
1597             vsel_ptr->y[i] += abs_dy;
1598             v[vsel_ptr->v_index[i]].x += abs_dx;
1599             v[vsel_ptr->v_index[i]].y += abs_dy;
1600          }
1601       } else {
1602          for (i=0; i < vsel_ptr->n; i++) {
1603             int x=0, y=0, x2=0, y2=0;
1604 
1605             /*
1606              * vsel_ptr->x[i] += abs_dx;
1607              * vsel_ptr->y[i] += abs_dy;
1608              */
1609             ReverseTransformPointThroughCTM(vsel_ptr->x[i]+abs_dx-obj_ptr->x,
1610                   vsel_ptr->y[i]+abs_dy-obj_ptr->y, obj_ptr->ctm, &x, &y);
1611             v[vsel_ptr->v_index[i]].x = x + obj_ptr->x;
1612             v[vsel_ptr->v_index[i]].y = y + obj_ptr->y;
1613             TransformPointThroughCTM(x, y, obj_ptr->ctm, &x2, &y2);
1614             vsel_ptr->x[i] = x2 + obj_ptr->x;
1615             vsel_ptr->y[i] = y2 + obj_ptr->y;
1616          }
1617       }
1618       if (curved == LT_STRUCT_SPLINE) {
1619 #ifdef _TGIF_DBG /* debug, do not translate */
1620          TgAssert(obj_ptr->userdata != NULL,
1621                "obj_ptr is NULL in MoveAllSelVs()", NULL);
1622 #endif /* _TGIF_DBG */
1623          FinishMoveVertexForStretchStructSpline(vsel_ptr, abs_dx, abs_dy,
1624                psssi);
1625          free(psssi);
1626          obj_ptr->userdata = NULL;
1627       }
1628       AdjObjSplineVs(obj_ptr);
1629       if (auto_retracted_arrow) {
1630          for (i=0; i < vsel_ptr->n; i++) {
1631             if (vsel_ptr->v_index[i] == 1) {
1632                vsel_ptr->x[i] = v[1].x;
1633                vsel_ptr->y[i] = v[1].y;
1634             }
1635          }
1636       }
1637       switch (obj_ptr->type) {
1638       case OBJ_POLY:
1639          if (obj_ptr->detail.p->curved != LT_INTSPLINE) {
1640             UpdPolyBBox(obj_ptr, n, v);
1641          } else {
1642             UpdPolyBBox(obj_ptr, obj_ptr->detail.p->intn,
1643                   obj_ptr->detail.p->intvlist);
1644          }
1645          break;
1646       case OBJ_POLYGON:
1647          if (obj_ptr->detail.g->curved != LT_INTSPLINE) {
1648             UpdPolyBBox(obj_ptr, n, v);
1649          } else {
1650             UpdPolyBBox(obj_ptr, obj_ptr->detail.g->intn,
1651                   obj_ptr->detail.g->intvlist);
1652          }
1653          break;
1654       }
1655       RecordReplaceAnObj(obj_ptr);
1656    }
1657    EndCompositeCmd();
1658    UpdSelBBox();
1659    RedrawAreas(botObj, ltx-GRID_ABS_SIZE(1), lty-GRID_ABS_SIZE(1),
1660          rbx+GRID_ABS_SIZE(1), rby+GRID_ABS_SIZE(1),
1661          selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1),
1662          selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1));
1663 }
1664 
1665 static struct ObjRec *tmpTopObj=NULL, *tmpBotObj=NULL;
1666 
1667 #define FORWARD 0
1668 #define REVERSE 1
1669 
1670 static
EndMoveVsForStructuredSpline(obj_ptr,abs_dx,abs_dy)1671 void EndMoveVsForStructuredSpline(obj_ptr, abs_dx, abs_dy)
1672    struct ObjRec *obj_ptr;
1673    int abs_dx, abs_dy;
1674 {
1675    StretchStructuredSplineInfo *psssi=
1676          (StretchStructuredSplineInfo*)(obj_ptr->userdata);
1677 
1678    if (psssi != NULL) {
1679       if (psssi->sv != NULL) {
1680          XDrawLines(mainDisplay, drawWindow, revDefaultGC,
1681                psssi->sv, psssi->sn, CoordModeOrigin);
1682          free(psssi->sv);
1683          psssi->sv = NULL;
1684       }
1685       if (psssi->sv2 != NULL) {
1686          XDrawLines(mainDisplay, drawWindow, revDefaultGC,
1687                psssi->sv2, psssi->sn2, CoordModeOrigin);
1688          free(psssi->sv2);
1689          psssi->sv2 = NULL;
1690       }
1691       EraseHighLightForStretchStructSpline(psssi, abs_dx, abs_dy, FALSE, TRUE);
1692    }
1693 }
1694 
1695 static
EndMoveVs(abs_dx,abs_dy)1696 void EndMoveVs(abs_dx, abs_dy)
1697    int abs_dx, abs_dy;
1698 {
1699    int i=0;
1700    struct ObjRec *obj_ptr=NULL, *next_obj=NULL;
1701    struct PolyRec *poly_ptr=NULL;
1702    struct PolygonRec *polygon_ptr=NULL;
1703 
1704    for (obj_ptr=tmpTopObj; obj_ptr != NULL; obj_ptr = next_obj) {
1705       next_obj = obj_ptr->next;
1706       switch (obj_ptr->type) {
1707       case OBJ_POLY:
1708          poly_ptr = obj_ptr->detail.p;
1709          if (poly_ptr->vlist != NULL) {
1710             free(poly_ptr->vlist);
1711             poly_ptr->vlist = NULL;
1712          }
1713          if (poly_ptr->svlist != NULL) {
1714             free(poly_ptr->svlist);
1715             poly_ptr->svlist = NULL;
1716          }
1717          if (poly_ptr->curved == LT_INTSPLINE &&
1718                poly_ptr->intvlist != NULL) {
1719             free(poly_ptr->intvlist);
1720             poly_ptr->intvlist = NULL;
1721          } else if (poly_ptr->curved == LT_STRUCT_SPLINE) {
1722             EndMoveVsForStructuredSpline(obj_ptr, 0, 0);
1723             for (i=0; i < poly_ptr->ssn; i++) {
1724                if (poly_ptr->ssmooth[i]) {
1725                   MARKHO(drawWindow, revDefaultGC,
1726                         OFFSET_X(poly_ptr->ssvlist[i].x),
1727                         OFFSET_Y(poly_ptr->ssvlist[i].y));
1728                } else {
1729                   MARKHR(drawWindow, revDefaultGC,
1730                         OFFSET_X(poly_ptr->ssvlist[i].x),
1731                         OFFSET_Y(poly_ptr->ssvlist[i].y));
1732                }
1733             }
1734          }
1735          free(poly_ptr);
1736          break;
1737       case OBJ_POLYGON:
1738          polygon_ptr = obj_ptr->detail.g;
1739          if (polygon_ptr->vlist != NULL) {
1740             free(polygon_ptr->vlist);
1741             polygon_ptr->vlist = NULL;
1742          }
1743          if (polygon_ptr->svlist != NULL) {
1744             free(polygon_ptr->svlist);
1745             polygon_ptr->svlist = NULL;
1746          }
1747          if (polygon_ptr->curved == LT_INTSPLINE &&
1748                polygon_ptr->intvlist != NULL) {
1749             free(polygon_ptr->intvlist);
1750             polygon_ptr->intvlist = NULL;
1751          } else if (polygon_ptr->curved == LT_STRUCT_SPLINE) {
1752             EndMoveVsForStructuredSpline(obj_ptr, 0, 0);
1753             for (i=0; i < polygon_ptr->ssn; i++) {
1754                if (polygon_ptr->ssmooth[i]) {
1755                   MARKHO(drawWindow, revDefaultGC,
1756                         OFFSET_X(polygon_ptr->ssvlist[i].x),
1757                         OFFSET_Y(polygon_ptr->ssvlist[i].y));
1758                } else {
1759                   MARKHR(drawWindow, revDefaultGC,
1760                         OFFSET_X(polygon_ptr->ssvlist[i].x),
1761                         OFFSET_Y(polygon_ptr->ssvlist[i].y));
1762                }
1763             }
1764          }
1765          free(polygon_ptr);
1766          break;
1767       }
1768       free(obj_ptr);
1769    }
1770 }
1771 
1772 static
PrepareToMoveVs()1773 void PrepareToMoveVs()
1774 {
1775    struct VSelRec *vsel_ptr=NULL;
1776 
1777    tmpTopObj = tmpBotObj = NULL;
1778    for (vsel_ptr=botVSel; vsel_ptr != NULL; vsel_ptr=vsel_ptr->prev) {
1779       struct ObjRec *obj_ptr=NULL;
1780       struct PolyRec *poly_ptr=NULL, *poly_copy=NULL;
1781       struct PolygonRec *polygon_ptr=NULL, *polygon_copy=NULL;
1782       XPoint *sv=NULL;
1783       IntPoint *polyv=NULL, *polyssv=NULL, *cntrlv=NULL;
1784       int i=0, num_pts=0, sn=0, curved=(-1), intn=0, ssn=0;
1785       char *smooth=NULL, *ssmooth=NULL;
1786       StretchStructuredSplineInfo *psssi=NULL;
1787 
1788       obj_ptr = (struct ObjRec *)malloc(sizeof(struct ObjRec));
1789       if (obj_ptr == NULL) FailAllocMessage();
1790       memset(obj_ptr, 0, sizeof(struct ObjRec));
1791       obj_ptr->prev = NULL;
1792       obj_ptr->next = tmpTopObj;
1793       obj_ptr->ctm = NULL;
1794       if (tmpTopObj == NULL) {
1795          tmpBotObj = obj_ptr;
1796       } else {
1797          tmpTopObj->prev = obj_ptr;
1798       }
1799       tmpTopObj = obj_ptr;
1800       obj_ptr->type = vsel_ptr->obj->type;
1801 
1802       switch (vsel_ptr->obj->type) {
1803       case OBJ_POLY:
1804          poly_copy = (struct PolyRec *)malloc(sizeof(struct PolyRec));
1805          if (poly_copy == NULL) FailAllocMessage();
1806          memset(poly_copy, 0, sizeof(struct PolyRec));
1807          obj_ptr->detail.p = poly_copy;
1808 
1809          poly_ptr = vsel_ptr->obj->detail.p;
1810          curved = poly_copy->curved = poly_ptr->curved;
1811          num_pts = poly_copy->n = poly_ptr->n;
1812          if (curved == LT_STRUCT_SPLINE) {
1813             ssn = poly_copy->ssn = poly_ptr->ssn;
1814          }
1815          polyv = (IntPoint*)malloc((num_pts+1)*sizeof(IntPoint));
1816          if (polyv == NULL) FailAllocMessage();
1817          if (curved == LT_STRUCT_SPLINE) {
1818             polyssv = (IntPoint*)malloc((ssn+2)*sizeof(IntPoint));
1819             if (polyssv == NULL) FailAllocMessage();
1820          }
1821          if (curved == LT_STRUCT_SPLINE || ((curved == LT_STRAIGHT ||
1822                curved == LT_SPLINE) && poly_ptr->smooth != NULL)) {
1823             if (poly_ptr->smooth != NULL) {
1824                smooth = (char*)malloc((num_pts+1)*sizeof(char));
1825                if (smooth == NULL) FailAllocMessage();
1826             }
1827             if (curved == LT_STRUCT_SPLINE) {
1828                ssmooth = (char*)malloc((ssn+2)*sizeof(char));
1829                if (ssmooth == NULL) FailAllocMessage();
1830             }
1831          }
1832          if (vsel_ptr->obj->ctm == NULL) {
1833             for (i=0; i < num_pts; i++) {
1834                polyv[i].x = poly_ptr->vlist[i].x;
1835                polyv[i].y = poly_ptr->vlist[i].y;
1836                if (smooth != NULL) smooth[i] = poly_ptr->smooth[i];
1837             }
1838             if (curved == LT_STRUCT_SPLINE) {
1839                for (i=0; i < ssn; i++) {
1840                   polyssv[i].x = poly_ptr->ssvlist[i].x;
1841                   polyssv[i].y = poly_ptr->ssvlist[i].y;
1842                   if (ssmooth != NULL) ssmooth[i] = poly_ptr->ssmooth[i];
1843                }
1844             }
1845          } else {
1846             int x, y;
1847 
1848             for (i=0; i < num_pts; i++) {
1849                TransformPointThroughCTM(
1850                      poly_ptr->vlist[i].x-vsel_ptr->obj->x,
1851                      poly_ptr->vlist[i].y-vsel_ptr->obj->y,
1852                      vsel_ptr->obj->ctm, &x, &y);
1853                polyv[i].x = x+vsel_ptr->obj->x;
1854                polyv[i].y = y+vsel_ptr->obj->y;
1855                if (smooth != NULL) smooth[i] = poly_ptr->smooth[i];
1856             }
1857             if (curved == LT_STRUCT_SPLINE) {
1858                for (i=0; i < ssn; i++) {
1859                   TransformPointThroughCTM(
1860                         poly_ptr->ssvlist[i].x-vsel_ptr->obj->x,
1861                         poly_ptr->ssvlist[i].y-vsel_ptr->obj->y,
1862                         vsel_ptr->obj->ctm, &x, &y);
1863                   polyssv[i].x = x+vsel_ptr->obj->x;
1864                   polyssv[i].y = y+vsel_ptr->obj->y;
1865                   if (ssmooth != NULL) ssmooth[i] = poly_ptr->ssmooth[i];
1866                }
1867             }
1868          }
1869          if (curved != LT_INTSPLINE) {
1870             if (curved == LT_STRUCT_SPLINE) {
1871                sv = MakeMultiSplinePolyVertex(curved, &sn, ssmooth,
1872                      drawOrigX, drawOrigY, ssn, polyssv);
1873                poly_copy->ssvlist = polyssv;
1874                poly_copy->ssmooth = ssmooth;
1875                poly_copy->ssn = ssn;
1876             } else {
1877                sv = MakeMultiSplinePolyVertex(curved, &sn, smooth,
1878                      drawOrigX, drawOrigY, num_pts, polyv);
1879             }
1880          } else {
1881             sv = MakeIntSplinePolyVertex(&sn, &intn, &cntrlv,
1882                   drawOrigX, drawOrigY, num_pts, polyv);
1883          }
1884          poly_copy->vlist = polyv;
1885          poly_copy->smooth = smooth;
1886          poly_copy->svlist = sv;
1887          poly_copy->sn = sn;
1888 
1889          if (curved == LT_STRUCT_SPLINE) {
1890             for (i=0; i < ssn; i++) {
1891                if (ssmooth[i]) {
1892                   MARKHO(drawWindow, revDefaultGC, OFFSET_X(polyssv[i].x),
1893                         OFFSET_Y(polyssv[i].y));
1894                } else {
1895                   MARKHR(drawWindow, revDefaultGC, OFFSET_X(polyssv[i].x),
1896                         OFFSET_Y(polyssv[i].y));
1897                }
1898             }
1899          }
1900          break;
1901       case OBJ_POLYGON:
1902          polygon_copy = (struct PolygonRec *)malloc(sizeof(struct PolygonRec));
1903          if (polygon_copy == NULL) FailAllocMessage();
1904          memset(polygon_copy, 0, sizeof(struct PolygonRec));
1905          obj_ptr->detail.g = polygon_copy;
1906 
1907          polygon_ptr = vsel_ptr->obj->detail.g;
1908          curved = polygon_copy->curved = polygon_ptr->curved;
1909          num_pts = polygon_copy->n = polygon_ptr->n;
1910          if (curved == LT_STRUCT_SPLINE) {
1911             ssn = polygon_copy->ssn = polygon_ptr->ssn;
1912          }
1913          polyv = (IntPoint*)malloc((num_pts+1)*sizeof(IntPoint));
1914          if (polyv == NULL) FailAllocMessage();
1915          if (curved == LT_STRUCT_SPLINE) {
1916             polyssv = (IntPoint*)malloc((ssn+2)*sizeof(IntPoint));
1917             if (polyssv == NULL) FailAllocMessage();
1918          }
1919          if (curved == LT_STRUCT_SPLINE || ((curved == LT_STRAIGHT ||
1920                curved == LT_SPLINE) && polygon_ptr->smooth != NULL)) {
1921             if (polygon_ptr->smooth != NULL) {
1922                smooth = (char*)malloc((num_pts+1)*sizeof(char));
1923                if (smooth == NULL) FailAllocMessage();
1924             }
1925             if (curved == LT_STRUCT_SPLINE) {
1926                ssmooth = (char*)malloc((ssn+1)*sizeof(char));
1927                if (ssmooth == NULL) FailAllocMessage();
1928             }
1929          }
1930          if (vsel_ptr->obj->ctm == NULL) {
1931             for (i=0; i < num_pts; i++) {
1932                polyv[i].x = polygon_ptr->vlist[i].x;
1933                polyv[i].y = polygon_ptr->vlist[i].y;
1934                if (smooth != NULL) smooth[i] = polygon_ptr->smooth[i];
1935             }
1936             if (curved == LT_STRUCT_SPLINE) {
1937                for (i=0; i < ssn; i++) {
1938                   polyssv[i].x = polygon_ptr->ssvlist[i].x;
1939                   polyssv[i].y = polygon_ptr->ssvlist[i].y;
1940                   if (ssmooth != NULL) ssmooth[i] = polygon_ptr->ssmooth[i];
1941                }
1942             }
1943          } else {
1944             int x, y;
1945 
1946             for (i=0; i < num_pts; i++) {
1947                TransformPointThroughCTM(
1948                      polygon_ptr->vlist[i].x-vsel_ptr->obj->x,
1949                      polygon_ptr->vlist[i].y-vsel_ptr->obj->y,
1950                      vsel_ptr->obj->ctm, &x, &y);
1951                polyv[i].x = x+vsel_ptr->obj->x;
1952                polyv[i].y = y+vsel_ptr->obj->y;
1953                if (smooth != NULL) smooth[i] = polygon_ptr->smooth[i];
1954             }
1955             if (curved == LT_STRUCT_SPLINE) {
1956                for (i=0; i < num_pts; i++) {
1957                   TransformPointThroughCTM(
1958                         polygon_ptr->ssvlist[i].x-vsel_ptr->obj->x,
1959                         polygon_ptr->ssvlist[i].y-vsel_ptr->obj->y,
1960                         vsel_ptr->obj->ctm, &x, &y);
1961                   polyssv[i].x = x+vsel_ptr->obj->x;
1962                   polyssv[i].y = y+vsel_ptr->obj->y;
1963                   if (ssmooth != NULL) ssmooth[i] = polygon_ptr->ssmooth[i];
1964                }
1965             }
1966          }
1967          if (curved != LT_INTSPLINE) {
1968             if (curved == LT_STRUCT_SPLINE) {
1969                sv = MakeMultiSplinePolygonVertex(curved, &sn, ssmooth,
1970                      drawOrigX, drawOrigY, ssn, polyssv);
1971                polygon_copy->ssvlist = polyssv;
1972                polygon_copy->ssmooth = ssmooth;
1973                polygon_copy->ssn = ssn;
1974             } else {
1975                sv = MakeMultiSplinePolygonVertex(curved, &sn, smooth,
1976                      drawOrigX, drawOrigY, num_pts,polyv);
1977             }
1978          } else {
1979             sv = MakeIntSplinePolygonVertex(&sn, &intn, &cntrlv,
1980                   drawOrigX, drawOrigY, num_pts,polyv);
1981          }
1982          polygon_copy->vlist = polyv;
1983          polygon_copy->smooth = smooth;
1984          polygon_copy->svlist = sv;
1985          polygon_copy->sn = sn;
1986 
1987          if (curved == LT_STRUCT_SPLINE) {
1988             for (i=0; i < ssn; i++) {
1989                if (ssmooth[i]) {
1990                   MARKHO(drawWindow, revDefaultGC, OFFSET_X(polyssv[i].x),
1991                         OFFSET_Y(polyssv[i].y));
1992                } else {
1993                   MARKHR(drawWindow, revDefaultGC, OFFSET_X(polyssv[i].x),
1994                         OFFSET_Y(polyssv[i].y));
1995                }
1996             }
1997          }
1998          break;
1999       }
2000       if (curved == LT_STRUCT_SPLINE) {
2001          psssi = (StretchStructuredSplineInfo*)malloc(
2002                sizeof(StretchStructuredSplineInfo));
2003          if (psssi == NULL) FailAllocMessage();
2004          memset(psssi, 0, sizeof(StretchStructuredSplineInfo));
2005 #ifdef _TGIF_DBG /* debug, do not translate */
2006          TgAssert(obj_ptr->userdata == NULL,
2007                "obj_ptr is not NULL in PrepareToMoveVs()", NULL);
2008 #endif /* _TGIF_DBG */
2009          obj_ptr->userdata = vsel_ptr->obj->userdata = psssi;
2010          if (poly_ptr != NULL) {
2011             SetIPTInfoForStretchPoly(vsel_ptr->v_index[0], num_pts,
2012                   polyv, psssi);
2013          } else if (polygon_ptr != NULL) {
2014             SetIPTInfoForStretchPolygon(vsel_ptr->v_index[0], num_pts,
2015                   polyv, psssi);
2016          }
2017          SetVsAndVs2ForStretchStructSpline(psssi, 0, 0, &psssi->num_vs,
2018                psssi->vs, &psssi->num_vs2, psssi->vs2);
2019          FixUpSmoothAndSmooth2ForStretchStructSpline(psssi->num_vs,
2020                psssi->smooth, psssi->num_vs2, psssi->smooth2);
2021          if (psssi->prev_valid) {
2022             psssi->sv = MakeMultiSplinePolyVertex(LT_STRUCT_SPLINE,
2023                   &psssi->sn, psssi->smooth, drawOrigX, drawOrigY,
2024                   psssi->num_vs, psssi->vs);
2025             psssi->saved_sv = DupVs(&psssi->saved_sn, psssi->sv, psssi->sn);
2026          }
2027          if (psssi->next_valid) {
2028             psssi->sv2 = MakeMultiSplinePolyVertex(LT_STRUCT_SPLINE,
2029                   &psssi->sn2, psssi->smooth2, drawOrigX, drawOrigY,
2030                   psssi->num_vs2, psssi->vs2);
2031             psssi->saved_sv2 = DupVs(&psssi->saved_sn2, psssi->sv2, psssi->sn2);
2032          }
2033          EraseHighLightForStretchStructSpline(psssi, 0, 0, FALSE, TRUE);
2034       }
2035    }
2036 }
2037 
2038 static
MarkVsForStructuredSplines(Dir,abs_dx,abs_dy)2039 void MarkVsForStructuredSplines(Dir, abs_dx, abs_dy)
2040    int Dir, abs_dx, abs_dy;
2041 {
2042    struct ObjRec *obj_ptr=NULL;
2043 
2044    switch (Dir) {
2045    case FORWARD: obj_ptr = tmpBotObj; break;
2046    case REVERSE: obj_ptr = tmpTopObj; break;
2047    }
2048    while (obj_ptr != NULL) {
2049       StretchStructuredSplineInfo *psssi=
2050             (StretchStructuredSplineInfo*)(obj_ptr->userdata);
2051 
2052       if (psssi != NULL) {
2053          switch (Dir) {
2054          case REVERSE:
2055             /* erase */
2056             if (psssi->sv != NULL) {
2057                XDrawLines(mainDisplay, drawWindow, revDefaultGC,
2058                      psssi->sv, psssi->sn, CoordModeOrigin);
2059                free(psssi->sv);
2060                psssi->sv = NULL;
2061             }
2062             if (psssi->sv2 != NULL) {
2063                XDrawLines(mainDisplay, drawWindow, revDefaultGC,
2064                      psssi->sv2, psssi->sn2, CoordModeOrigin);
2065                free(psssi->sv2);
2066                psssi->sv2 = NULL;
2067             }
2068             EraseHighLightForStretchStructSpline(psssi, abs_dx, abs_dy, TRUE,
2069                   TRUE);
2070             break;
2071          case FORWARD:
2072             /* draw */
2073             SetVsAndVs2ForStretchStructSpline(psssi, abs_dx, abs_dy,
2074                   &psssi->num_vs, psssi->vs, &psssi->num_vs2, psssi->vs2);
2075             FixUpSmoothAndSmooth2ForStretchStructSpline(psssi->num_vs,
2076                   psssi->smooth, psssi->num_vs2,
2077                   psssi->smooth2);
2078             if (psssi->prev_valid) {
2079                psssi->sv = MakeMultiSplinePolyVertex(LT_STRUCT_SPLINE,
2080                      &psssi->sn, psssi->smooth, drawOrigX, drawOrigY,
2081                      psssi->num_vs, psssi->vs);
2082                XDrawLines(mainDisplay, drawWindow, revDefaultGC,
2083                      psssi->sv, psssi->sn, CoordModeOrigin);
2084             }
2085             if (psssi->next_valid) {
2086                psssi->sv2 = MakeMultiSplinePolyVertex(LT_STRUCT_SPLINE,
2087                      &psssi->sn2, psssi->smooth2, drawOrigX, drawOrigY,
2088                      psssi->num_vs2, psssi->vs2);
2089                XDrawLines(mainDisplay, drawWindow, revDefaultGC,
2090                      psssi->sv2, psssi->sn2, CoordModeOrigin);
2091             }
2092             EraseHighLightForStretchStructSpline(psssi, abs_dx, abs_dy, TRUE,
2093                   TRUE);
2094             break;
2095          }
2096          if (psssi->hinge) {
2097             MARKHR(drawWindow, revDefaultGC,
2098                   OFFSET_X(psssi->ipt.hinge_pt.x+abs_dx),
2099                   OFFSET_Y(psssi->ipt.hinge_pt.y+abs_dy));
2100          } else if (psssi->earlier_smooth_selected) {
2101             MARKHO(drawWindow, revDefaultGC,
2102                   OFFSET_X(psssi->ipt.earlier_smooth_pt.x+abs_dx),
2103                   OFFSET_Y(psssi->ipt.earlier_smooth_pt.y+abs_dy));
2104          } else {
2105             MARKHO(drawWindow, revDefaultGC,
2106                   OFFSET_X(psssi->ipt.later_smooth_pt.x+abs_dx),
2107                   OFFSET_Y(psssi->ipt.later_smooth_pt.y+abs_dy));
2108          }
2109       }
2110       switch (Dir) {
2111       case FORWARD: obj_ptr = obj_ptr->prev; break;
2112       case REVERSE: obj_ptr = obj_ptr->next; break;
2113       }
2114    }
2115 }
2116 
2117 static
HighLightVs(Dir,abs_dx,abs_dy)2118 void HighLightVs(Dir, abs_dx, abs_dy)
2119    int Dir, abs_dx, abs_dy;
2120 {
2121    int i=0, n=0, curved=(-1);
2122    struct ObjRec *obj_ptr=NULL;
2123    IntPoint *v=NULL;
2124    char *smooth=NULL;
2125 
2126    switch (Dir) {
2127    case FORWARD: obj_ptr = tmpBotObj; break;
2128    case REVERSE: obj_ptr = tmpTopObj; break;
2129    }
2130    while (obj_ptr != NULL) {
2131       switch (obj_ptr->type) {
2132       case OBJ_POLY:
2133          curved = obj_ptr->detail.p->curved;
2134          if (curved == LT_STRUCT_SPLINE) {
2135             n = obj_ptr->detail.p->ssn;
2136             v = obj_ptr->detail.p->ssvlist;
2137             smooth = obj_ptr->detail.p->ssmooth;
2138          } else {
2139             n = obj_ptr->detail.p->n;
2140             v = obj_ptr->detail.p->vlist;
2141             smooth = obj_ptr->detail.p->smooth;
2142          }
2143          if (curved != LT_INTSPLINE && smooth != NULL) {
2144             if (curved == LT_STRUCT_SPLINE) {
2145                /* nothing to do here */
2146             } else {
2147                for (i=0; i < n; i++) {
2148                   if (smooth[i]) {
2149                      MARKO(drawWindow, revDefaultGC, OFFSET_X(v[i].x),
2150                            OFFSET_Y(v[i].y));
2151                   } else {
2152                      MARK(drawWindow, revDefaultGC, OFFSET_X(v[i].x),
2153                            OFFSET_Y(v[i].y));
2154                   }
2155                }
2156             }
2157          } else {
2158             for (i=0; i < n; i++) {
2159                MARK(drawWindow, revDefaultGC, OFFSET_X(v[i].x),
2160                      OFFSET_Y(v[i].y));
2161             }
2162          }
2163          if (curved == LT_STRUCT_SPLINE) {
2164             /* nothing to do here */
2165          } else {
2166             XDrawLines(mainDisplay, drawWindow, revDefaultGC,
2167                   obj_ptr->detail.p->svlist, obj_ptr->detail.p->sn,
2168                   CoordModeOrigin);
2169          }
2170          break;
2171       case OBJ_POLYGON:
2172          curved = obj_ptr->detail.g->curved;
2173          if (curved == LT_STRUCT_SPLINE) {
2174             n = obj_ptr->detail.g->ssn;
2175             v = obj_ptr->detail.g->ssvlist;
2176             smooth = obj_ptr->detail.g->ssmooth;
2177          } else {
2178             n = obj_ptr->detail.g->n;
2179             v = obj_ptr->detail.g->vlist;
2180             smooth = obj_ptr->detail.g->smooth;
2181          }
2182          if (obj_ptr->detail.g->curved != LT_INTSPLINE && smooth != NULL) {
2183             if (curved == LT_STRUCT_SPLINE) {
2184                /* nothing to do */
2185             } else {
2186                for (i=0; i < obj_ptr->detail.g->n-1; i++) {
2187                   if (smooth[i]) {
2188                      MARKO(drawWindow, revDefaultGC, OFFSET_X(v[i].x),
2189                            OFFSET_Y(v[i].y));
2190                   } else {
2191                      MARK(drawWindow, revDefaultGC, OFFSET_X(v[i].x),
2192                            OFFSET_Y(v[i].y));
2193                   }
2194                }
2195             }
2196          } else {
2197             for (i=0; i < obj_ptr->detail.g->n-1; i++) {
2198                MARK(drawWindow, revDefaultGC, OFFSET_X(v[i].x),
2199                      OFFSET_Y(v[i].y));
2200             }
2201          }
2202          if (curved == LT_STRUCT_SPLINE) {
2203             /* nothing to do here */
2204          } else {
2205             XDrawLines(mainDisplay, drawWindow, revDefaultGC,
2206                   obj_ptr->detail.g->svlist, obj_ptr->detail.g->sn,
2207                   CoordModeOrigin);
2208          }
2209          break;
2210       }
2211       switch (Dir) {
2212       case FORWARD: obj_ptr = obj_ptr->prev; break;
2213       case REVERSE: obj_ptr = obj_ptr->next; break;
2214       }
2215    }
2216 }
2217 
2218 static
MarkVs(Dir,Dx,Dy)2219 void MarkVs(Dir, Dx, Dy)
2220    int Dir, Dx, Dy; /* Dx and Dy are screen offsets */
2221 {
2222    register int i, x, y;
2223    register struct VSelRec *vsel_ptr=NULL;
2224 
2225    switch (Dir) {
2226    case FORWARD: vsel_ptr = botVSel; break;
2227    case REVERSE: vsel_ptr = topVSel; break;
2228    }
2229    while (vsel_ptr != NULL) {
2230       char *smooth=NULL;
2231       int curved=(-1);
2232 
2233       switch (vsel_ptr->obj->type) {
2234       case OBJ_POLY:
2235          smooth = vsel_ptr->obj->detail.p->smooth;
2236          curved = vsel_ptr->obj->detail.p->curved;
2237          break;
2238       case OBJ_POLYGON:
2239          smooth = vsel_ptr->obj->detail.g->smooth;
2240          curved = vsel_ptr->obj->detail.g->curved;
2241          break;
2242       }
2243       for (i=0; i < vsel_ptr->n; i++) {
2244          if (!(vsel_ptr->obj->type==OBJ_POLYGON &&
2245                vsel_ptr->obj->detail.g->n-1==vsel_ptr->v_index[i])) {
2246             x = OFFSET_X(vsel_ptr->x[i])+Dx;
2247             y = OFFSET_Y(vsel_ptr->y[i])+Dy;
2248             if (curved == LT_STRUCT_SPLINE || ((curved == LT_STRAIGHT ||
2249                   curved == LT_SPLINE) && smooth != NULL)) {
2250                if (curved == LT_STRUCT_SPLINE) {
2251                   /* nothing to do here */
2252                } else {
2253                   if (smooth[vsel_ptr->v_index[i]]) {
2254                      if (curved == LT_STRUCT_SPLINE) {
2255                         MARKHO(drawWindow, revDefaultGC, x, y);
2256                      } else {
2257                         MARKO(drawWindow, revDefaultGC, x, y);
2258                      }
2259                   } else {
2260                      if (curved == LT_STRUCT_SPLINE) {
2261                         MARKHR(drawWindow, revDefaultGC, x, y);
2262                      } else {
2263                         MARK(drawWindow, revDefaultGC, x, y);
2264                      }
2265                   }
2266                }
2267             } else {
2268                MARK(drawWindow, revDefaultGC, x, y);
2269             }
2270             MARKV(drawWindow, revDefaultGC, x, y);
2271          }
2272       }
2273       switch (Dir) {
2274       case FORWARD: vsel_ptr = vsel_ptr->prev; break;
2275       case REVERSE: vsel_ptr = vsel_ptr->next; break;
2276       }
2277    }
2278 }
2279 
2280 static
GetSelectedVsBBox(pBBox)2281 void GetSelectedVsBBox(pBBox)
2282    struct BBRec *pBBox;
2283 {
2284    int found=FALSE, ltx=0, lty=0, rbx=0, rby=0;
2285    struct VSelRec *vsel_ptr=NULL;
2286 
2287    vsel_ptr = botVSel;
2288    while (vsel_ptr != NULL) {
2289       int i=0;
2290 
2291       for (i=0; i < vsel_ptr->n; i++) {
2292          if (!(vsel_ptr->obj->type==OBJ_POLYGON &&
2293                vsel_ptr->obj->detail.g->n-1==vsel_ptr->v_index[i])) {
2294             int x=OFFSET_X(vsel_ptr->x[i]);
2295             int y=OFFSET_Y(vsel_ptr->y[i]);
2296 
2297             if (found) {
2298                if (x < ltx) ltx = x;
2299                if (x > rbx) rbx = x;
2300                if (y < lty) lty = y;
2301                if (y > rby) rby = y;
2302             } else {
2303                found = TRUE;
2304                ltx = rbx = x;
2305                lty = rby = y;
2306             }
2307          }
2308       }
2309       vsel_ptr = vsel_ptr->prev;
2310    }
2311    if (found) {
2312       pBBox->ltx = ltx; pBBox->lty = lty; pBBox->rbx = rbx; pBBox->rby = rby;
2313    }
2314 }
2315 
MoveSelVs(OrigX,OrigY)2316 void MoveSelVs(OrigX, OrigY)
2317    int OrigX, OrigY;
2318 {
2319    int x=0, y=0, i=0;
2320    struct ObjRec *obj_ptr=NULL;
2321    struct VSelRec *vsel_ptr=NULL;
2322    struct PolyRec *poly_ptr=NULL;
2323    struct PolygonRec *polygon_ptr=NULL;
2324    IntPoint *pv=NULL;
2325    int moving=TRUE, dx=0, dy=0, num_pts=0, curved=FALSE;
2326    int grid_x=OrigX, grid_y=OrigY, abs_dx_from_orig=0, abs_dy_from_orig=0;
2327    int saved_grid_x=OrigX, saved_grid_y=OrigY;
2328    struct BBRec ruler_bbox;
2329    char buf[80], x_buf[80], y_buf[80];
2330    XEvent ev;
2331 
2332    XFlush(mainDisplay);
2333    XSync(mainDisplay, False);
2334 
2335    if (XCheckMaskEvent(mainDisplay, ExposureMask, &ev) ||
2336          XCheckMaskEvent(mainDisplay, VisibilityChangeMask, &ev)) {
2337       ExposeEventHandler(&ev, TRUE);
2338    }
2339    HighLightReverse();
2340 
2341    PrepareToMoveVs();
2342    MarkVsForStructuredSplines(FORWARD, 0, 0);
2343    HighLightVs(FORWARD, 0, 0);
2344    MarkVs(FORWARD, 0, 0);
2345 
2346    memset(&ruler_bbox, 0, sizeof(struct BBRec));
2347    GetSelectedVsBBox(&ruler_bbox);
2348 
2349    PixelToMeasurementUnit(x_buf, 0);
2350    PixelToMeasurementUnit(y_buf, 0);
2351    sprintf(buf, "dx=%s\ndy=%s", x_buf, y_buf);
2352    if (VerboseMeasureTooltip()) {
2353       sprintf(buf, "dx=%s dy=%s", x_buf, y_buf);
2354    } else {
2355       sprintf(buf, "dx=%s\ndy=%s", x_buf, y_buf);
2356    }
2357    StartShowMeasureCursor(grid_x, grid_y, buf, TRUE);
2358    BeginIntervalRulers(ruler_bbox.ltx, ruler_bbox.lty, ruler_bbox.rbx,
2359          ruler_bbox.rby);
2360 
2361    if (!debugNoPointerGrab) {
2362       XGrabPointer(mainDisplay, drawWindow, FALSE,
2363             PointerMotionMask | ButtonReleaseMask,
2364             GrabModeAsync, GrabModeAsync, None, moveCursor, CurrentTime);
2365    }
2366    while (moving) {
2367       XEvent input;
2368 
2369       XNextEvent(mainDisplay, &input);
2370 
2371       if (input.type == Expose || input.type == VisibilityNotify) {
2372          ExposeEventHandler(&input, TRUE);
2373       } else if (input.type == ButtonRelease) {
2374          XUngrabPointer(mainDisplay, CurrentTime);
2375          XSync(mainDisplay, False);
2376 
2377          EndIntervalRulers(grid_x, grid_y);
2378          PixelToMeasurementUnit(x_buf, ABS_SIZE(grid_x-OrigX));
2379          PixelToMeasurementUnit(y_buf, ABS_SIZE(grid_y-OrigY));
2380          if (VerboseMeasureTooltip()) {
2381             sprintf(buf, "dx=%s dy=%s", x_buf, y_buf);
2382          } else {
2383             sprintf(buf, "dx=%s\ndy=%s", x_buf, y_buf);
2384          }
2385          EndShowMeasureCursor(grid_x, grid_y, buf, TRUE);
2386          MarkRulers(grid_x, grid_y);
2387          moving = FALSE;
2388 
2389          dx = grid_x - OrigX;
2390          dy = grid_y - OrigY;
2391 
2392          MarkVs(REVERSE, dx, dy);
2393          MarkVsForStructuredSplines(REVERSE, ABS_SIZE(dx), ABS_SIZE(dy));
2394          HighLightVs(REVERSE, ABS_SIZE(dx), ABS_SIZE(dy));
2395          EndMoveVs(ABS_SIZE(dx), ABS_SIZE(dy));
2396 
2397          if (dx != 0 || dy != 0) {
2398             MoveAllSelVs(ABS_SIZE(dx), ABS_SIZE(dy));
2399             HighLightForward();
2400             SetFileModified(TRUE);
2401          } else {
2402             HighLightForward();
2403          }
2404       } else if (input.type == MotionNotify || input.type == KeyPress ||
2405             input.type == KeyRelease) {
2406          PixelToMeasurementUnit(x_buf, ABS_SIZE(grid_x-OrigX));
2407          PixelToMeasurementUnit(y_buf, ABS_SIZE(grid_y-OrigY));
2408          if (VerboseMeasureTooltip()) {
2409             sprintf(buf, "dx=%s dy=%s", x_buf, y_buf);
2410          } else {
2411             sprintf(buf, "dx=%s\ndy=%s", x_buf, y_buf);
2412          }
2413          ShowMeasureCursor(grid_x, grid_y, buf, TRUE);
2414          /* erase */
2415          MarkVs(REVERSE, grid_x-OrigX, grid_y-OrigY);
2416          MarkVsForStructuredSplines(REVERSE, ABS_SIZE(grid_x-OrigX),
2417                ABS_SIZE(grid_y-OrigY));
2418          HighLightVs(REVERSE, ABS_SIZE(grid_x-OrigX), ABS_SIZE(grid_x-OrigX));
2419 
2420          if (input.type == KeyPress || input.type == KeyRelease) {
2421             x = saved_grid_x;
2422             y = saved_grid_y;
2423          } else {
2424             x = input.xmotion.x;
2425             y = input.xmotion.y;
2426          }
2427          if (shiftForDiagMouseMove && DiagEventCheck(&input)) {
2428             if (useRecentDupDistance && justDupped &&
2429                   useRecentForDiagMouseMove) {
2430                DiagGridXY(OrigX-ZOOMED_SIZE(dupDx), OrigY-ZOOMED_SIZE(dupDy),
2431                      &x, &y);
2432             } else {
2433                DiagGridXY(OrigX, OrigY, &x, &y);
2434             }
2435          }
2436          GridXY(x, y, &grid_x, &grid_y);
2437 
2438          dx = grid_x - saved_grid_x;
2439          dy = grid_y - saved_grid_y;
2440 
2441          saved_grid_x = grid_x;
2442          saved_grid_y = grid_y;
2443 
2444          abs_dx_from_orig = ABS_SIZE(grid_x-OrigX);
2445          abs_dy_from_orig = ABS_SIZE(grid_y-OrigY);
2446 
2447          for (vsel_ptr=botVSel, obj_ptr=tmpBotObj; vsel_ptr != NULL;
2448                vsel_ptr=vsel_ptr->prev, obj_ptr=obj_ptr->prev) {
2449             switch (obj_ptr->type) {
2450             case OBJ_POLY:
2451                poly_ptr = obj_ptr->detail.p;
2452                curved = poly_ptr->curved;
2453                num_pts = poly_ptr->n;
2454                pv = poly_ptr->vlist;
2455                for (i=0; i < vsel_ptr->n; i++) {
2456                   pv[vsel_ptr->v_index[i]].x += ABS_SIZE(dx);
2457                   pv[vsel_ptr->v_index[i]].y += ABS_SIZE(dy);
2458                }
2459                if (poly_ptr->svlist != NULL) {
2460                   free(poly_ptr->svlist);
2461                   poly_ptr->svlist = NULL;
2462                }
2463                switch (curved) {
2464                case LT_STRAIGHT:
2465                case LT_SPLINE:
2466                   poly_ptr->svlist = MakeMultiSplinePolyVertex(
2467                         curved, &(poly_ptr->sn), poly_ptr->smooth,
2468                         drawOrigX, drawOrigY, num_pts, pv);
2469                   break;
2470                case LT_STRUCT_SPLINE:
2471                   /* nothing to do here */
2472                   break;
2473                case LT_INTSPLINE:
2474                   if (poly_ptr->intvlist != NULL) {
2475                      free(poly_ptr->intvlist);
2476                      poly_ptr->intvlist = NULL;
2477                   }
2478                   poly_ptr->svlist = MakeIntSplinePolyVertex(
2479                         &(poly_ptr->sn), &(poly_ptr->intn),
2480                         &(poly_ptr->intvlist), drawOrigX, drawOrigY,
2481                         num_pts, pv);
2482                   break;
2483                }
2484                break;
2485             case OBJ_POLYGON:
2486                polygon_ptr = obj_ptr->detail.g;
2487                curved = polygon_ptr->curved;
2488                num_pts = polygon_ptr->n;
2489                pv = polygon_ptr->vlist;
2490                for (i=0; i < vsel_ptr->n; i++) {
2491                   pv[vsel_ptr->v_index[i]].x += ABS_SIZE(dx);
2492                   pv[vsel_ptr->v_index[i]].y += ABS_SIZE(dy);
2493                }
2494                if (polygon_ptr->svlist != NULL) {
2495                   free(polygon_ptr->svlist);
2496                   polygon_ptr->svlist = NULL;
2497                }
2498                switch (curved) {
2499                case LT_STRAIGHT:
2500                case LT_SPLINE:
2501                   polygon_ptr->svlist =
2502                         MakeMultiSplinePolygonVertex(curved,
2503                         &(polygon_ptr->sn), polygon_ptr->smooth,
2504                         drawOrigX, drawOrigY, num_pts, pv);
2505                   break;
2506                case LT_STRUCT_SPLINE:
2507                   /* nothing to do here */
2508                   break;
2509                case LT_INTSPLINE:
2510                   if (polygon_ptr->intvlist != NULL) {
2511                      free(polygon_ptr->intvlist);
2512                      polygon_ptr->intvlist = NULL;
2513                   }
2514                   polygon_ptr->svlist =
2515                         MakeIntSplinePolygonVertex(&(polygon_ptr->sn),
2516                         &(polygon_ptr->intn), &(polygon_ptr->intvlist),
2517                         drawOrigX, drawOrigY, num_pts, pv);
2518                   break;
2519                }
2520                break;
2521             }
2522          }
2523          /* draw */
2524          MarkVsForStructuredSplines(FORWARD, abs_dx_from_orig,
2525                abs_dy_from_orig);
2526          HighLightVs(FORWARD, abs_dx_from_orig, abs_dy_from_orig);
2527          MarkVs(FORWARD, grid_x-OrigX, grid_y-OrigY);
2528          PixelToMeasurementUnit(x_buf, abs_dx_from_orig);
2529          PixelToMeasurementUnit(y_buf, abs_dy_from_orig);
2530          if (VerboseMeasureTooltip()) {
2531             sprintf(buf, "dx=%s dy=%s", x_buf, y_buf);
2532          } else {
2533             sprintf(buf, "dx=%s\ndy=%s", x_buf, y_buf);
2534          }
2535          DrawIntervalRulers(ruler_bbox.ltx+abs_dx_from_orig,
2536                ruler_bbox.lty+abs_dy_from_orig, ruler_bbox.rbx+abs_dx_from_orig,
2537                ruler_bbox.rby+abs_dy_from_orig, buf);
2538          ShowMeasureCursor(grid_x, grid_y, buf, TRUE);
2539          while (XCheckMaskEvent(mainDisplay, PointerMotionMask, &ev)) ;
2540       }
2541    }
2542 }
2543