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/stretch.c,v 1.63 2011/05/16 16:21:59 william Exp $
19 */
20
21 #define _INCLUDE_FROM_STRETCH_C_
22
23 #include "tgifdefs.h"
24 #include "cmdids.h"
25
26 #include "align.e"
27 #include "arc.e"
28 #include "auxtext.e"
29 #include "choice.e"
30 #include "cmd.e"
31 #include "color.e"
32 #include "cursor.e"
33 #include "dialog.e"
34 #include "drawing.e"
35 #include "dup.e"
36 #include "exec.e"
37 #include "file.e"
38 #include "font.e"
39 #include "grid.e"
40 #include "mainloop.e"
41 #include "mainmenu.e"
42 #include "mark.e"
43 #include "menu.e"
44 #include "menuinfo.e"
45 #include "miniline.e"
46 #include "move.e"
47 #include "msg.e"
48 #include "navigate.e"
49 #include "obj.e"
50 #include "page.e"
51 #include "poly.e"
52 #include "raster.e"
53 #include "rect.e"
54 #include "ruler.e"
55 #include "scroll.e"
56 #include "select.e"
57 #include "setup.e"
58 #include "spline.e"
59 #include "stretch.e"
60 #include "strtbl.e"
61 #include "text.e"
62 #include "util.e"
63 #include "xbitmap.e"
64 #include "xpixmap.e"
65
66 int stretchableText=FALSE;
67 int compoundObjWithTextStretchableForPSE=TRUE;
68 int rotationIncrement=(45<<6); /* degrees*64 */
69
70 int autoRotatePivot=FALSE;
71 int rotatePivotAbsXYValid=FALSE;
72 int rotatePivotAbsX=0;
73 int rotatePivotAbsY=0;
74
75 static int stretchingEverything=FALSE;
76
77 static
PtIn4Corners(XOff,YOff,BBox,Corner)78 int PtIn4Corners(XOff, YOff, BBox, Corner)
79 int XOff, YOff, * Corner;
80 struct BBRec BBox;
81 {
82 if (PtInMark(XOff, YOff, OFFSET_X(BBox.ltx), OFFSET_Y(BBox.lty))) {
83 *Corner = 1;
84 return TRUE;
85 }
86 if (PtInMark(XOff, YOff, OFFSET_X(BBox.ltx), OFFSET_Y(BBox.rby))) {
87 *Corner = 7;
88 return TRUE;
89 }
90 if (PtInMark(XOff, YOff, OFFSET_X(BBox.rbx), OFFSET_Y(BBox.lty))) {
91 *Corner = 3;
92 return TRUE;
93 }
94 if (PtInMark(XOff, YOff, OFFSET_X(BBox.rbx), OFFSET_Y(BBox.rby))) {
95 *Corner = 5;
96 return TRUE;
97 }
98 return FALSE;
99 }
100
101 static
PtIn8Places(XOff,YOff,BBox,Corner)102 int PtIn8Places(XOff, YOff, BBox, Corner)
103 int XOff, YOff, *Corner;
104 struct BBRec BBox;
105 {
106 register int xmid, ymid;
107
108 if (PtIn4Corners(XOff, YOff, BBox, Corner)) return TRUE;
109
110 xmid = ((BBox.ltx+BBox.rbx)>>1);
111 if (PtInMark(XOff, YOff, OFFSET_X(xmid), OFFSET_Y(BBox.lty))) {
112 *Corner = 2;
113 return TRUE;
114 }
115 if (PtInMark(XOff, YOff, OFFSET_X(xmid), OFFSET_Y(BBox.rby))) {
116 *Corner = 6;
117 return TRUE;
118 }
119 ymid = ((BBox.lty+BBox.rby)>>1);
120 if (PtInMark(XOff, YOff, OFFSET_X(BBox.ltx), OFFSET_Y(ymid))) {
121 *Corner = 8;
122 return TRUE;
123 }
124 if (PtInMark(XOff, YOff, OFFSET_X(BBox.rbx), OFFSET_Y(ymid))) {
125 *Corner = 4;
126 return TRUE;
127 }
128 return FALSE;
129 }
130
PtInPolyMark(ObjPtr,XOff,YOff,NumPts,V,Index)131 int PtInPolyMark(ObjPtr, XOff, YOff, NumPts, V, Index)
132 struct ObjRec *ObjPtr;
133 int XOff, YOff, NumPts, * Index;
134 IntPoint *V;
135 {
136 int i;
137
138 if (ObjPtr->ctm == NULL) {
139 for (i = 0; i < NumPts; i++) {
140 if (PtInMark(XOff, YOff, OFFSET_X(V[i].x), OFFSET_Y(V[i].y))) {
141 *Index = i;
142 return TRUE;
143 }
144 }
145 } else {
146 for (i = 0; i < NumPts; i++) {
147 int x, y;
148
149 TransformPointThroughCTM(V[i].x-ObjPtr->x, V[i].y-ObjPtr->y,
150 ObjPtr->ctm, &x, &y);
151 if (PtInMark(XOff, YOff, OFFSET_X(x+ObjPtr->x),
152 OFFSET_Y(y+ObjPtr->y))) {
153 *Index = i;
154 return TRUE;
155 }
156 }
157 }
158 return FALSE;
159 }
160
RetractedArrowAttr(obj_ptr)161 int RetractedArrowAttr(obj_ptr)
162 struct ObjRec *obj_ptr;
163 {
164 register struct AttrRec *attr_ptr;
165
166 if (obj_ptr->type != OBJ_POLY) return FALSE;
167
168 if (obj_ptr->detail.p->n <= 2) return FALSE;
169 for (attr_ptr=obj_ptr->lattr; attr_ptr!=NULL; attr_ptr=attr_ptr->prev) {
170 if (*attr_ptr->attr_name.s=='\0' && strcmp(attr_ptr->attr_value.s,
171 "retracted_arrows")==0) {
172 return TRUE;
173 }
174 }
175 return FALSE;
176 }
177
AutoRetractedArrowAttr(obj_ptr,check_v_count)178 int AutoRetractedArrowAttr(obj_ptr, check_v_count)
179 /* if check_v_count == TRUE: return FALSE if poly_ptr->n != 3 */
180 /* if check_v_count == FALSE: skip the poly_ptr->n check */
181 struct ObjRec *obj_ptr;
182 int check_v_count;
183 {
184 register struct AttrRec *attr_ptr;
185
186 if (obj_ptr->type == OBJ_POLY) {
187 struct PolyRec *poly_ptr=obj_ptr->detail.p;
188
189 if (poly_ptr->style == LS_PLAIN || poly_ptr->style == LS_DOUBLE ||
190 (check_v_count && poly_ptr->n != 3)) {
191 return FALSE;
192 }
193 } else {
194 return FALSE;
195 }
196 for (attr_ptr=obj_ptr->lattr; attr_ptr!=NULL; attr_ptr=attr_ptr->prev) {
197 if (*attr_ptr->attr_name.s=='\0' &&
198 strcmp(attr_ptr->attr_value.s, "auto_retracted_arrows")==0) {
199 return TRUE;
200 }
201 }
202 return FALSE;
203 }
204
AutoCenterAttr(obj_ptr)205 int AutoCenterAttr(obj_ptr)
206 struct ObjRec *obj_ptr;
207 {
208 register struct AttrRec *attr_ptr;
209
210 for (attr_ptr=obj_ptr->lattr; attr_ptr!=NULL; attr_ptr=attr_ptr->prev) {
211 if (*attr_ptr->attr_name.s=='\0' && strcmp(attr_ptr->attr_value.s,
212 "auto_center_attr")==0) {
213 return TRUE;
214 }
215 }
216 return FALSE;
217 }
218
CenterObjInOBBox(TextObjPtr,OBBox,BBoxReturn)219 void CenterObjInOBBox(TextObjPtr, OBBox, BBoxReturn)
220 struct ObjRec *TextObjPtr;
221 struct BBRec OBBox, *BBoxReturn;
222 {
223 int text_w, text_h, bbox_w, bbox_h, dx, dy;
224
225 if (BBoxReturn != NULL) {
226 BBoxReturn->ltx = TextObjPtr->bbox.ltx;
227 BBoxReturn->lty = TextObjPtr->bbox.lty;
228 BBoxReturn->rbx = TextObjPtr->bbox.rbx;
229 BBoxReturn->rby = TextObjPtr->bbox.rby;
230 }
231 text_w = TextObjPtr->obbox.rbx-TextObjPtr->obbox.ltx;
232 text_h = TextObjPtr->obbox.rby-TextObjPtr->obbox.lty;
233 bbox_w = OBBox.rbx - OBBox.ltx;
234 bbox_h = OBBox.rby - OBBox.lty;
235 if (text_w > bbox_w) {
236 dx = OBBox.ltx-((text_w-bbox_w)>>1)-TextObjPtr->obbox.ltx;
237 } else {
238 dx = OBBox.ltx+((bbox_w-text_w)>>1)-TextObjPtr->obbox.ltx;
239 }
240 if (text_h > bbox_h) {
241 dy = OBBox.lty-((text_h-bbox_h)>>1)-TextObjPtr->obbox.lty;
242 } else {
243 dy = OBBox.lty+((bbox_h-text_h)>>1)-TextObjPtr->obbox.lty;
244 }
245 MoveObj(TextObjPtr, dx, dy);
246 if (BBoxReturn != NULL) {
247 if (TextObjPtr->bbox.ltx < BBoxReturn->ltx) {
248 BBoxReturn->ltx = TextObjPtr->bbox.ltx;
249 }
250 if (TextObjPtr->bbox.lty < BBoxReturn->lty) {
251 BBoxReturn->lty = TextObjPtr->bbox.lty;
252 }
253 if (TextObjPtr->bbox.rbx > BBoxReturn->rbx) {
254 BBoxReturn->rbx = TextObjPtr->bbox.rbx;
255 }
256 if (TextObjPtr->bbox.rby > BBoxReturn->rby) {
257 BBoxReturn->rby = TextObjPtr->bbox.rby;
258 }
259 }
260 }
261
PtInSelMark(XOff,YOff,Corner)262 struct SelRec *PtInSelMark(XOff, YOff, Corner)
263 int XOff, YOff, *Corner;
264 /* XOff and YOff are screen offsets */
265 /* 1 2 3 */
266 /* 8 4 */
267 /* 7 6 5 */
268 {
269 register struct SelRec *sel_ptr;
270 register struct ObjRec *obj_ptr;
271
272 for (sel_ptr=topSel; sel_ptr != NULL; sel_ptr=sel_ptr->next) {
273 obj_ptr = sel_ptr->obj;
274
275 switch (obj_ptr->type) {
276 case OBJ_POLY:
277 if (obj_ptr->detail.p->curved == LT_STRUCT_SPLINE) {
278 if (PtInPolyMark(obj_ptr, XOff, YOff, obj_ptr->detail.p->ssn,
279 obj_ptr->detail.p->ssvlist, Corner)) {
280 return sel_ptr;
281 }
282 } else {
283 if (PtInPolyMark(obj_ptr, XOff, YOff, obj_ptr->detail.p->n,
284 obj_ptr->detail.p->vlist, Corner)) {
285 return sel_ptr;
286 }
287 }
288 break;
289 case OBJ_POLYGON:
290 if (obj_ptr->detail.g->curved == LT_STRUCT_SPLINE) {
291 if (PtInPolyMark(obj_ptr, XOff, YOff, obj_ptr->detail.g->ssn-1,
292 obj_ptr->detail.g->ssvlist, Corner)) {
293 return sel_ptr;
294 }
295 } else {
296 if (PtInPolyMark(obj_ptr, XOff, YOff, obj_ptr->detail.g->n-1,
297 obj_ptr->detail.g->vlist, Corner)) {
298 return sel_ptr;
299 }
300 }
301 break;
302 case OBJ_BOX:
303 case OBJ_GROUP:
304 case OBJ_ICON:
305 case OBJ_SYM:
306 case OBJ_PIN:
307 case OBJ_OVAL:
308 case OBJ_ARC:
309 case OBJ_RCBOX:
310 case OBJ_XBM:
311 case OBJ_XPM:
312 if (PtIn8Places(XOff, YOff, obj_ptr->obbox, Corner)) {
313 return sel_ptr;
314 }
315 break;
316 case OBJ_TEXT:
317 if (curChoice == ROTATEMODE) {
318 if (PtIn8Places(XOff, YOff, obj_ptr->obbox, Corner)) {
319 return sel_ptr;
320 }
321 } else if (curChoice == NOTHING) {
322 if (stretchableText &&
323 PtIn8Places(XOff, YOff, obj_ptr->obbox, Corner)) {
324 return sel_ptr;
325 }
326 }
327 break;
328 }
329 }
330 return NULL;
331 }
332
HasOnReshape(obj_ptr,pp_name_attr)333 int HasOnReshape(obj_ptr, pp_name_attr)
334 struct ObjRec *obj_ptr;
335 struct AttrRec **pp_name_attr;
336 /* returns the name attribute pointer */
337 {
338 if (pp_name_attr != NULL) *pp_name_attr = NULL;
339 if ((obj_ptr->type == OBJ_POLY || obj_ptr->type == OBJ_POLYGON) &&
340 obj_ptr->ctm == NULL) {
341 if (FindAttrWithName(obj_ptr, "on_reshape=", NULL) != NULL) {
342 struct AttrRec *attr=FindAttrWithName(obj_ptr, "name=", NULL);
343
344 if (attr != NULL && *attr->attr_value.s != '\0') {
345 if (pp_name_attr != NULL) *pp_name_attr = attr;
346 return TRUE;
347 }
348 }
349 }
350 return FALSE;
351 }
352
353 static
SkipOnResize(obj_ptr)354 int SkipOnResize(obj_ptr)
355 struct ObjRec *obj_ptr;
356 {
357 if (obj_ptr->type != OBJ_GROUP &&
358 obj_ptr->type != OBJ_ICON &&
359 obj_ptr->type != OBJ_SYM &&
360 obj_ptr->type != OBJ_PIN) {
361 if (obj_ptr->ctm != NULL) {
362 return TRUE;
363 }
364 } else {
365 struct ObjRec *sub_obj=obj_ptr->detail.r->last;
366
367 for ( ; sub_obj != NULL; sub_obj=sub_obj->prev) {
368 if (sub_obj->type != OBJ_GROUP &&
369 sub_obj->type != OBJ_ICON &&
370 sub_obj->type != OBJ_SYM &&
371 sub_obj->type != OBJ_PIN &&
372 sub_obj->ctm != NULL) {
373 return TRUE;
374 }
375 }
376 }
377 return FALSE;
378 }
379
380 static
HasOnResize(obj_ptr,pp_name_attr)381 int HasOnResize(obj_ptr, pp_name_attr)
382 struct ObjRec *obj_ptr;
383 struct AttrRec **pp_name_attr;
384 /* returns the name attribute pointer */
385 {
386 if (pp_name_attr != NULL) *pp_name_attr = NULL;
387 if (!SkipOnResize(obj_ptr)) {
388 if (FindAttrWithName(obj_ptr, "on_resize=", NULL) != NULL) {
389 struct AttrRec *attr=FindAttrWithName(obj_ptr, "name=", NULL);
390
391 if (attr != NULL && *attr->attr_value.s != '\0') {
392 if (pp_name_attr != NULL) *pp_name_attr = attr;
393 return TRUE;
394 }
395 }
396 }
397 return FALSE;
398 }
399
400 static
NeedToProcessOnResize(pn_num_to_resize)401 char **NeedToProcessOnResize(pn_num_to_resize)
402 int *pn_num_to_resize;
403 {
404 int num_to_resize=0;
405 char **ppsz_names=NULL;
406 struct SelRec *sel_ptr=NULL;
407
408 *pn_num_to_resize = 0;
409 for (sel_ptr=botSel; sel_ptr != NULL; sel_ptr=sel_ptr->prev) {
410 struct AttrRec *name_attr=NULL;
411
412 if (HasOnResize(sel_ptr->obj, &name_attr) && name_attr != NULL) {
413 num_to_resize++;
414 if (ppsz_names == NULL) {
415 ppsz_names = (char**)malloc(sizeof(char*));
416 } else {
417 ppsz_names = (char**)realloc(ppsz_names,
418 num_to_resize*sizeof(char*));
419 }
420 if (ppsz_names == NULL) FailAllocMessage();
421 ppsz_names[num_to_resize-1] = (char*)(long)(sel_ptr->obj->id);
422 }
423 }
424 if (num_to_resize == 0) return NULL;
425
426 *pn_num_to_resize = num_to_resize;
427 return ppsz_names;
428 }
429
430 static
FindObjWithOID(oid)431 struct ObjRec *FindObjWithOID(oid)
432 int oid;
433 {
434 struct ObjRec *obj_ptr=NULL;
435
436 for (obj_ptr=botObj; obj_ptr != NULL; obj_ptr=obj_ptr->prev) {
437 if (obj_ptr->id == oid) {
438 return obj_ptr;
439 }
440 }
441 return NULL;
442 }
443
444 static
DoOnResize(ppsz_names,num_to_resize)445 void DoOnResize(ppsz_names, num_to_resize)
446 char **ppsz_names;
447 int num_to_resize;
448 {
449 int i=0;
450
451 RemoveAllSel();
452 for (i=0; i < num_to_resize; i++) {
453 struct AttrRec *exec_attr=NULL;
454 struct ObjRec *obj_ptr=FindObjWithOID((int)(long)(ppsz_names[i]));
455
456 if (obj_ptr != NULL && !SkipOnResize(obj_ptr)) {
457 exec_attr = FindAttrWithName(obj_ptr, "on_resize=", NULL);
458 }
459 if (exec_attr != NULL) {
460 DoExecLoop(obj_ptr, exec_attr);
461 } else {
462 sprintf(gszMsgBox,
463 TgLoadCachedString(CSTID_CANT_FIND_OBJ_NAME_ON_RESIZE),
464 ppsz_names[i]);
465 Msg(gszMsgBox);
466 *ppsz_names[i] = '\0';
467 }
468 }
469 for (i=0; i < num_to_resize; i++) {
470 struct ObjRec *obj_ptr=FindObjWithOID((int)(long)(ppsz_names[i]));
471
472 if (obj_ptr != NULL) {
473 if (!AlreadySelected(obj_ptr)) {
474 AddNewSelObj(obj_ptr);
475 }
476 }
477 }
478 free(ppsz_names);
479
480 UpdSelBBox();
481 }
482
483 #define STRETCH_DRAW (FALSE)
484 #define STRETCH_ERASE (TRUE)
485 #define STRETCH_CLICK (FALSE)
486 #define STRETCH_DRAG (TRUE)
487
488 #define STRETCH_STARTSHOW 0
489 #define STRETCH_DOSHOW 1
490 #define STRETCH_ENDSHOW 2
491
GetVlistIndexFromStretchStructuredSplineInfo(psssi,ss_index)492 int GetVlistIndexFromStretchStructuredSplineInfo(psssi, ss_index)
493 StretchStructuredSplineInfo *psssi;
494 int ss_index;
495 {
496 if (psssi->hinge) {
497 return psssi->orig_hinge_index;
498 } if (psssi->earlier_smooth_selected) {
499 return psssi->orig_hinge_index-1;
500 } else {
501 return psssi->orig_hinge_index+1;
502 }
503 }
504
505 static
DoStretchPolyMeasureCursor(start,num_pts,vs,index,dx,dy,erase,drag,obj_type,grid_x,grid_y)506 void DoStretchPolyMeasureCursor(start, num_pts, vs, index, dx, dy, erase, drag,
507 obj_type, grid_x, grid_y)
508 int start, num_pts, index, dx, dy, erase, drag, obj_type, grid_x, grid_y;
509 IntPoint *vs;
510 {
511 static IntPoint prev_pt={0,0}, mid_pt={0,0}, next_pt={0,0};
512 char buf[80], x_buf[80], y_buf[80], a_buf[80];
513 int x=vs[index].x+dx, y=vs[index].y+dy, angle2=0;
514
515 #ifdef _TGIF_DBG /* debug, do not translate */
516 TgAssert((obj_type == OBJ_POLY || index != num_pts-1),
517 "index == num_pts-1 for a polygon in DoStretchPolyMeasureCursor()",
518 NULL);
519 #endif /* _TGIF_DBG */
520 if (index == 0 || index == num_pts-1) {
521 if (obj_type == OBJ_POLY) {
522 if (num_pts > 2) {
523 if (index == 0) {
524 prev_pt.x = x; prev_pt.y = y;
525 mid_pt.x = vs[1].x; mid_pt.y = vs[1].y;
526 next_pt.x = vs[2].x; next_pt.y = vs[2].y;
527 } else {
528 prev_pt.x = vs[num_pts-3].x; prev_pt.y = vs[num_pts-3].y;
529 mid_pt.x = vs[num_pts-2].x; mid_pt.y = vs[num_pts-2].y;
530 next_pt.x = x; next_pt.y = y;
531 }
532 } else {
533 if (index == 0) {
534 prev_pt.x = x; prev_pt.y = y;
535 mid_pt.x = vs[1].x; mid_pt.y = vs[1].y;
536 next_pt.x = vs[1].x+100; next_pt.y = vs[1].y;
537 } else {
538 prev_pt.x = x; prev_pt.y = y;
539 mid_pt.x = vs[0].x; mid_pt.y = vs[0].y;
540 next_pt.x = vs[0].x+100; next_pt.y = vs[0].y;
541 }
542 }
543 } else {
544 prev_pt.x = vs[1].x; prev_pt.y = vs[1].y;
545 mid_pt.x = x; mid_pt.y = y;
546 next_pt.x = vs[num_pts-2].x; next_pt.y = vs[num_pts-2].y;
547 }
548 } else {
549 prev_pt.x = vs[index-1].x; prev_pt.y = vs[index-1].y;
550 mid_pt.x = x; mid_pt.y = y;
551 next_pt.x = vs[index+1].x; next_pt.y = vs[index+1].y;
552 }
553 if (num_pts == 2) {
554 if (index == 0 && x == mid_pt.x && y == mid_pt.y) {
555 strcpy(a_buf, "0");
556 } else {
557 PointsToArc(mid_pt.x, mid_pt.y, x, y, mid_pt.x+100, mid_pt.y,
558 ARC_CCW, FALSE, NULL, NULL, NULL, NULL, NULL, &angle2);
559 if (angle2 > 180*64) angle2=(360*64)-angle2;
560 FormatAngle(angle2, a_buf);
561 }
562 } else {
563 if ((index == 0 || index == num_pts-1) &&
564 (x == mid_pt.x && y == mid_pt.y)) {
565 strcpy(a_buf, "0");
566 } else if ((index != 0 && index != num_pts-1) &&
567 ((x == prev_pt.x && y == prev_pt.y) ||
568 (x == next_pt.x && y == next_pt.y))) {
569 strcpy(a_buf, "180");
570 } else {
571 PointsToArc(mid_pt.x, mid_pt.y, prev_pt.x, prev_pt.y, next_pt.x,
572 next_pt.y, ARC_CCW, FALSE, NULL, NULL, NULL, NULL, NULL,
573 &angle2);
574 if (angle2 > 180*64) angle2=(360*64)-angle2;
575 FormatAngle(angle2, a_buf);
576 }
577 }
578 PixelToMeasurementUnit(x_buf, x);
579 PixelToMeasurementUnit(y_buf, y);
580 if (curChoice == FREEHAND) {
581 sprintf(buf, "x=%s\ny=%s", x_buf, y_buf);
582 } else {
583 sprintf(buf, "x=%s\ny=%s\nangle=%s", x_buf, y_buf, a_buf);
584 }
585 switch (start) {
586 case STRETCH_STARTSHOW:
587 StartShowMeasureCursor(grid_x, grid_y, buf, TRUE);
588 break;
589 case STRETCH_DOSHOW: ShowMeasureCursor(grid_x, grid_y, buf, TRUE); break;
590 case STRETCH_ENDSHOW: EndShowMeasureCursor(grid_x, grid_y, buf, TRUE); break;
591 }
592 }
593
594 static
DoStretchStructSplineMeasureCursor(start,start_v,dx,dy,grid_x,grid_y)595 void DoStretchStructSplineMeasureCursor(start, start_v, dx, dy, grid_x, grid_y)
596 int start, dx, dy, grid_x, grid_y;
597 IntPoint *start_v;
598 {
599 int x=0, y=0;
600 char buf[MAXSTRING], x_buf[80], y_buf[80], dx_buf[80], dy_buf[80];
601
602 x = start_v->x + dx;
603 y = start_v->y + dy;
604 PixelToMeasurementUnit(x_buf, x);
605 PixelToMeasurementUnit(y_buf, y);
606 PixelToMeasurementUnit(dx_buf, dx);
607 PixelToMeasurementUnit(dy_buf, dy);
608 sprintf(buf, "x=%s\ny=%s\ndx=%s\ndy=%s", x_buf, y_buf, dx_buf, dy_buf);
609
610 switch (start) {
611 case STRETCH_STARTSHOW:
612 StartShowMeasureCursor(grid_x, grid_y, buf, TRUE);
613 break;
614 case STRETCH_DOSHOW: ShowMeasureCursor(grid_x, grid_y, buf, TRUE); break;
615 case STRETCH_ENDSHOW: EndShowMeasureCursor(grid_x, grid_y, buf, TRUE); break;
616 }
617 }
618
SetIPTInfoForStretchPoly(index,n,vs,psssi)619 void SetIPTInfoForStretchPoly(index, n, vs, psssi)
620 int index, n; /* 0 <= index < ssn */
621 IntPoint *vs;
622 StretchStructuredSplineInfo *psssi;
623 {
624 int i=0, j=0, k=0, num_hinge_vs=(n+2)/3;
625
626 #ifdef _TGIF_DBG /* debug, do not translate */
627 TgAssert((n+2)%3 == 0, "invalid n in SetIPTInfoForStretchPoly()", NULL);
628 #endif /* _TGIF_DBG */
629
630 memset(psssi, 0, sizeof(StretchStructuredSplineInfo));
631 for (i=0, j=0, k=0; i < num_hinge_vs; i++, j+=3, k++) {
632 int set_the_rest_for_this=FALSE;
633
634 if (i == 0) {
635 if (k == index) {
636 psssi->hinge = TRUE;
637 set_the_rest_for_this = TRUE;
638 }
639 if (vs[0].x != vs[1].x || vs[0].y != vs[1].y) {
640 k++;
641 if (k == index) {
642 psssi->hinge = FALSE;
643 psssi->earlier_smooth_selected = FALSE;
644 set_the_rest_for_this = TRUE;
645 }
646 }
647 if (set_the_rest_for_this) {
648 psssi->orig_hinge_index = j;
649 psssi->prev_valid = FALSE;
650 psssi->next_valid = TRUE;
651 psssi->ipt.earlier_smooth_pt.x = vs[0].x;
652 psssi->ipt.earlier_smooth_pt.y = vs[0].y;
653 psssi->ipt.hinge_pt.x = vs[0].x;
654 psssi->ipt.hinge_pt.y = vs[0].y;
655 psssi->ipt.later_smooth_pt.x = vs[1].x;
656 psssi->ipt.later_smooth_pt.y = vs[1].y;
657 if (vs[0].x != vs[1].x || vs[0].y != vs[1].y) {
658 psssi->ipt.later_valid = TRUE;
659 }
660 psssi->ipt_next.earlier_smooth_pt.x = vs[2].x;
661 psssi->ipt_next.earlier_smooth_pt.y = vs[2].y;
662 psssi->ipt_next.hinge_pt.x = vs[3].x;
663 psssi->ipt_next.hinge_pt.y = vs[3].y;
664 if (num_hinge_vs > 2) {
665 psssi->ipt_next.later_smooth_pt.x = vs[4].x;
666 psssi->ipt_next.later_smooth_pt.y = vs[4].y;
667 } else {
668 /* this may not be necessary */
669 psssi->ipt_next.later_smooth_pt.x = vs[3].x;
670 psssi->ipt_next.later_smooth_pt.y = vs[3].y;
671 }
672 if (vs[2].x != vs[3].x || vs[2].y != vs[3].y) {
673 psssi->ipt_next.earlier_valid = TRUE;
674 }
675 if (vs[4].x != vs[3].x || vs[4].y != vs[3].y) {
676 psssi->ipt_next.later_valid = TRUE;
677 }
678 }
679 } else if (i == num_hinge_vs-1) {
680 if (vs[n-1].x != vs[n-2].x || vs[n-1].y != vs[n-2].y) {
681 if (k == index) {
682 psssi->hinge = FALSE;
683 psssi->earlier_smooth_selected = TRUE;
684 set_the_rest_for_this = TRUE;
685 }
686 k++;
687 }
688 if (k == index) {
689 psssi->hinge = TRUE;
690 set_the_rest_for_this = TRUE;
691 }
692 if (set_the_rest_for_this) {
693 psssi->orig_hinge_index = j;
694 psssi->prev_valid = TRUE;
695 psssi->next_valid = FALSE;
696 psssi->ipt.later_smooth_pt.x = vs[n-1].x;
697 psssi->ipt.later_smooth_pt.y = vs[n-1].y;
698 psssi->ipt.hinge_pt.x = vs[n-1].x;
699 psssi->ipt.hinge_pt.y = vs[n-1].y;
700 psssi->ipt.earlier_smooth_pt.x = vs[n-2].x;
701 psssi->ipt.earlier_smooth_pt.y = vs[n-2].y;
702 if (vs[n-1].x != vs[n-2].x || vs[n-1].y != vs[n-2].y) {
703 psssi->ipt.earlier_valid = TRUE;
704 }
705 psssi->ipt_prev.later_smooth_pt.x = vs[n-3].x;
706 psssi->ipt_prev.later_smooth_pt.y = vs[n-3].y;
707 psssi->ipt_prev.hinge_pt.x = vs[n-4].x;
708 psssi->ipt_prev.hinge_pt.y = vs[n-4].y;
709 if (num_hinge_vs > 2) {
710 psssi->ipt_prev.earlier_smooth_pt.x = vs[n-5].x;
711 psssi->ipt_prev.earlier_smooth_pt.y = vs[n-5].y;
712 } else {
713 /* this may not be necessary */
714 psssi->ipt_prev.earlier_smooth_pt.x = vs[n-4].x;
715 psssi->ipt_prev.earlier_smooth_pt.y = vs[n-4].y;
716 }
717 if (vs[n-5].x != vs[n-4].x || vs[n-5].y != vs[n-4].y) {
718 psssi->ipt_prev.earlier_valid = TRUE;
719 }
720 if (vs[n-3].x != vs[n-4].x || vs[n-3].y != vs[n-4].y) {
721 psssi->ipt_prev.later_valid = TRUE;
722 }
723 }
724 } else {
725 if (vs[j-1].x != vs[j].x || vs[j-1].y != vs[j].y) {
726 if (k == index) {
727 psssi->hinge = FALSE;
728 psssi->earlier_smooth_selected = TRUE;
729 set_the_rest_for_this = TRUE;
730 }
731 k++;
732 }
733 if (k == index) {
734 psssi->hinge = TRUE;
735 set_the_rest_for_this = TRUE;
736 }
737 if (vs[j+1].x != vs[j].x || vs[j+1].y != vs[j].y) {
738 k++;
739 if (k == index) {
740 psssi->hinge = FALSE;
741 psssi->earlier_smooth_selected = FALSE;
742 set_the_rest_for_this = TRUE;
743 }
744 }
745 if (set_the_rest_for_this) {
746 psssi->orig_hinge_index = j;
747 psssi->prev_valid = TRUE;
748 psssi->next_valid = TRUE;
749 if (i > 1) {
750 psssi->ipt_prev.earlier_smooth_pt.x = vs[j-4].x;
751 psssi->ipt_prev.earlier_smooth_pt.y = vs[j-4].y;
752 if (vs[j-4].x != vs[j-3].x || vs[j-4].y != vs[j-3].y) {
753 psssi->ipt_prev.earlier_valid = TRUE;
754 }
755 } else {
756 /* this may not be necessary */
757 psssi->ipt_prev.earlier_smooth_pt.x = vs[j-3].x;
758 psssi->ipt_prev.earlier_smooth_pt.y = vs[j-3].y;
759 }
760 psssi->ipt_prev.hinge_pt.x = vs[j-3].x;
761 psssi->ipt_prev.hinge_pt.y = vs[j-3].y;
762 psssi->ipt_prev.later_smooth_pt.x = vs[j-2].x;
763 psssi->ipt_prev.later_smooth_pt.y = vs[j-2].y;
764 if (vs[j-2].x != vs[j-3].x || vs[j-2].y != vs[j-3].y) {
765 psssi->ipt_prev.later_valid = TRUE;
766 }
767
768 psssi->ipt.earlier_smooth_pt.x = vs[j-1].x;
769 psssi->ipt.earlier_smooth_pt.y = vs[j-1].y;
770 psssi->ipt.hinge_pt.x = vs[j].x;
771 psssi->ipt.hinge_pt.y = vs[j].y;
772 psssi->ipt.later_smooth_pt.x = vs[j+1].x;
773 psssi->ipt.later_smooth_pt.y = vs[j+1].y;
774 if (vs[j-1].x != vs[j].x || vs[j-1].y != vs[j].y) {
775 psssi->ipt.earlier_valid = TRUE;
776 }
777 if (vs[j+1].x != vs[j].x || vs[j+1].y != vs[j].y) {
778 psssi->ipt.later_valid = TRUE;
779 }
780
781 psssi->ipt_next.earlier_smooth_pt.x = vs[j+2].x;
782 psssi->ipt_next.earlier_smooth_pt.y = vs[j+2].y;
783 psssi->ipt_next.hinge_pt.x = vs[j+3].x;
784 psssi->ipt_next.hinge_pt.y = vs[j+3].y;
785 if (i < num_hinge_vs-2) {
786 psssi->ipt_next.later_smooth_pt.x = vs[j+4].x;
787 psssi->ipt_next.later_smooth_pt.y = vs[j+4].y;
788 if (vs[j+4].x != vs[j+3].x || vs[j+4].y != vs[j+3].y) {
789 psssi->ipt_next.later_valid = TRUE;
790 }
791 } else {
792 /* this may not be necessary */
793 psssi->ipt_next.later_smooth_pt.x = vs[j+3].x;
794 psssi->ipt_next.later_smooth_pt.y = vs[j+3].y;
795 }
796 if (vs[j+2].x != vs[j+3].x || vs[j+2].y != vs[j+3].y) {
797 psssi->ipt_next.earlier_valid = TRUE;
798 }
799 }
800 }
801 }
802 }
803
SetIPTInfoForStretchPolygon(index,n,vs,psssi)804 void SetIPTInfoForStretchPolygon(index, n, vs, psssi)
805 int index, n; /* 0 <= index < ssn */
806 IntPoint *vs;
807 StretchStructuredSplineInfo *psssi;
808 {
809 int i=0, j=0, k=0, num_hinge_vs=(n+2)/3;
810
811 #ifdef _TGIF_DBG /* debug, do not translate */
812 TgAssert((n+2)%3 == 0, "invalid n in SetIPTInfoForStretchPolygon()", NULL);
813 #endif /* _TGIF_DBG */
814
815 memset(psssi, 0, sizeof(StretchStructuredSplineInfo));
816 psssi->prev_valid = psssi->next_valid = TRUE;
817 for (i=0, j=0, k=0; i < num_hinge_vs; i++, j+=3, k++) {
818 int set_the_rest_for_this=FALSE;
819
820 if (i == 0) {
821 if (k == index) {
822 psssi->hinge = TRUE;
823 set_the_rest_for_this = TRUE;
824 }
825 if (vs[0].x != vs[1].x || vs[0].y != vs[1].y) {
826 k++;
827 if (k == index) {
828 psssi->hinge = FALSE;
829 psssi->earlier_smooth_selected = FALSE;
830 set_the_rest_for_this = TRUE;
831 }
832 }
833 if (set_the_rest_for_this) {
834 psssi->orig_hinge_index = j;
835 psssi->ipt_prev.earlier_smooth_pt.x = vs[n-5].x;
836 psssi->ipt_prev.earlier_smooth_pt.y = vs[n-5].y;
837 psssi->ipt_prev.hinge_pt.x = vs[n-4].x;
838 psssi->ipt_prev.hinge_pt.y = vs[n-4].y;
839 psssi->ipt_prev.later_smooth_pt.x = vs[n-3].x;
840 psssi->ipt_prev.later_smooth_pt.y = vs[n-3].y;
841 if (vs[n-3].x != vs[n-4].x || vs[n-3].y != vs[n-4].y) {
842 psssi->ipt_prev.later_valid = TRUE;
843 }
844 if (vs[n-5].x != vs[n-4].x || vs[n-5].y != vs[n-4].y) {
845 psssi->ipt_prev.earlier_valid = TRUE;
846 }
847
848 psssi->ipt.earlier_smooth_pt.x = vs[n-2].x;
849 psssi->ipt.earlier_smooth_pt.y = vs[n-2].y;
850 psssi->ipt.hinge_pt.x = vs[0].x;
851 psssi->ipt.hinge_pt.y = vs[0].y;
852 psssi->ipt.later_smooth_pt.x = vs[1].x;
853 psssi->ipt.later_smooth_pt.y = vs[1].y;
854 if (vs[1].x != vs[0].x || vs[1].y != vs[0].y) {
855 psssi->ipt.later_valid = TRUE;
856 }
857 if (vs[n-2].x != vs[0].x || vs[n-2].y != vs[0].y) {
858 psssi->ipt.earlier_valid = TRUE;
859 }
860
861 psssi->ipt_next.earlier_smooth_pt.x = vs[2].x;
862 psssi->ipt_next.earlier_smooth_pt.y = vs[2].y;
863 psssi->ipt_next.hinge_pt.x = vs[3].x;
864 psssi->ipt_next.hinge_pt.y = vs[3].y;
865 psssi->ipt_next.later_smooth_pt.x = vs[4].x;
866 psssi->ipt_next.later_smooth_pt.y = vs[4].y;
867 if (vs[4].x != vs[3].x || vs[4].y != vs[3].y) {
868 psssi->ipt_next.later_valid = TRUE;
869 }
870 if (vs[2].x != vs[3].x || vs[2].y != vs[3].y) {
871 psssi->ipt_next.earlier_valid = TRUE;
872 }
873 }
874 } else if (i == num_hinge_vs-1) {
875 if (vs[n-1].x != vs[n-2].x || vs[n-1].y != vs[n-2].y) {
876 if (k == index) {
877 psssi->hinge = FALSE;
878 psssi->earlier_smooth_selected = TRUE;
879 set_the_rest_for_this = TRUE;
880 }
881 k++;
882 }
883 if (k == index) {
884 psssi->hinge = TRUE;
885 set_the_rest_for_this = TRUE;
886 }
887 if (set_the_rest_for_this) {
888 psssi->orig_hinge_index = j;
889 psssi->ipt_prev.earlier_smooth_pt.x = vs[n-5].x;
890 psssi->ipt_prev.earlier_smooth_pt.y = vs[n-5].y;
891 psssi->ipt_prev.hinge_pt.x = vs[n-4].x;
892 psssi->ipt_prev.hinge_pt.y = vs[n-4].y;
893 psssi->ipt_prev.later_smooth_pt.x = vs[n-3].x;
894 psssi->ipt_prev.later_smooth_pt.y = vs[n-3].y;
895 if (vs[n-3].x != vs[n-4].x || vs[n-3].y != vs[n-4].y) {
896 psssi->ipt_prev.later_valid = TRUE;
897 }
898 if (vs[n-5].x != vs[n-4].x || vs[n-5].y != vs[n-4].y) {
899 psssi->ipt_prev.earlier_valid = TRUE;
900 }
901
902 psssi->ipt.earlier_smooth_pt.x = vs[n-2].x;
903 psssi->ipt.earlier_smooth_pt.y = vs[n-2].y;
904 psssi->ipt.hinge_pt.x = vs[n-1].x;
905 psssi->ipt.hinge_pt.y = vs[n-1].y;
906 psssi->ipt.later_smooth_pt.x = vs[1].x;
907 psssi->ipt.later_smooth_pt.y = vs[1].y;
908 if (vs[1].x != vs[n-1].x || vs[1].y != vs[n-1].y) {
909 psssi->ipt.later_valid = TRUE;
910 }
911 if (vs[n-2].x != vs[n-1].x || vs[n-2].y != vs[n-1].y) {
912 psssi->ipt.earlier_valid = TRUE;
913 }
914
915 psssi->ipt_next.earlier_smooth_pt.x = vs[2].x;
916 psssi->ipt_next.earlier_smooth_pt.y = vs[2].y;
917 psssi->ipt_next.hinge_pt.x = vs[3].x;
918 psssi->ipt_next.hinge_pt.y = vs[3].y;
919 psssi->ipt_next.later_smooth_pt.x = vs[4].x;
920 psssi->ipt_next.later_smooth_pt.y = vs[4].y;
921 if (vs[4].x != vs[3].x || vs[4].y != vs[3].y) {
922 psssi->ipt_next.later_valid = TRUE;
923 }
924 if (vs[2].x != vs[3].x || vs[2].y != vs[3].y) {
925 psssi->ipt_next.earlier_valid = TRUE;
926 }
927 }
928 } else {
929 if (vs[j-1].x != vs[j].x || vs[j-1].y != vs[j].y) {
930 if (k == index) {
931 psssi->hinge = FALSE;
932 psssi->earlier_smooth_selected = TRUE;
933 set_the_rest_for_this = TRUE;
934 }
935 k++;
936 }
937 if (k == index) {
938 psssi->hinge = TRUE;
939 set_the_rest_for_this = TRUE;
940 }
941 if (vs[j+1].x != vs[j].x || vs[j+1].y != vs[j].y) {
942 k++;
943 if (k == index) {
944 psssi->hinge = FALSE;
945 psssi->earlier_smooth_selected = FALSE;
946 set_the_rest_for_this = TRUE;
947 }
948 }
949 if (set_the_rest_for_this) {
950 psssi->orig_hinge_index = j;
951 if (i > 1) {
952 psssi->ipt_prev.earlier_smooth_pt.x = vs[j-4].x;
953 psssi->ipt_prev.earlier_smooth_pt.y = vs[j-4].y;
954 if (vs[j-4].x != vs[j-3].x || vs[j-4].y != vs[j-3].y) {
955 psssi->ipt_prev.earlier_valid = TRUE;
956 }
957 } else {
958 psssi->ipt_prev.earlier_smooth_pt.x = vs[n-2].x;
959 psssi->ipt_prev.earlier_smooth_pt.y = vs[n-2].y;
960 if (vs[n-2].x != vs[j-3].x || vs[n-2].y != vs[j-3].y) {
961 psssi->ipt_prev.earlier_valid = TRUE;
962 }
963 }
964 psssi->ipt_prev.hinge_pt.x = vs[j-3].x;
965 psssi->ipt_prev.hinge_pt.y = vs[j-3].y;
966 psssi->ipt_prev.later_smooth_pt.x = vs[j-2].x;
967 psssi->ipt_prev.later_smooth_pt.y = vs[j-2].y;
968 if (vs[j-2].x != vs[j-3].x || vs[j-2].y != vs[j-3].y) {
969 psssi->ipt_prev.later_valid = TRUE;
970 }
971
972 psssi->ipt.earlier_smooth_pt.x = vs[j-1].x;
973 psssi->ipt.earlier_smooth_pt.y = vs[j-1].y;
974 psssi->ipt.hinge_pt.x = vs[j].x;
975 psssi->ipt.hinge_pt.y = vs[j].y;
976 psssi->ipt.later_smooth_pt.x = vs[j+1].x;
977 psssi->ipt.later_smooth_pt.y = vs[j+1].y;
978 if (vs[j-1].x != vs[j].x || vs[j-1].y != vs[j].y) {
979 psssi->ipt.earlier_valid = TRUE;
980 }
981 if (vs[j+1].x != vs[j].x || vs[j+1].y != vs[j].y) {
982 psssi->ipt.later_valid = TRUE;
983 }
984
985 psssi->ipt_next.earlier_smooth_pt.x = vs[j+2].x;
986 psssi->ipt_next.earlier_smooth_pt.y = vs[j+2].y;
987 psssi->ipt_next.hinge_pt.x = vs[j+3].x;
988 psssi->ipt_next.hinge_pt.y = vs[j+3].y;
989 if (i < num_hinge_vs-2) {
990 psssi->ipt_next.later_smooth_pt.x = vs[j+4].x;
991 psssi->ipt_next.later_smooth_pt.y = vs[j+4].y;
992 if (vs[j+4].x != vs[j+3].x || vs[j+4].y != vs[j+3].y) {
993 psssi->ipt_next.earlier_valid = TRUE;
994 }
995 } else {
996 psssi->ipt_next.later_smooth_pt.x = vs[1].x;
997 psssi->ipt_next.later_smooth_pt.y = vs[1].y;
998 if (vs[1].x != vs[j+3].x || vs[1].y != vs[j+3].y) {
999 psssi->ipt_next.earlier_valid = TRUE;
1000 }
1001 }
1002 if (vs[j+2].x != vs[j+3].x || vs[j+2].y != vs[j+3].y) {
1003 psssi->ipt_next.earlier_valid = TRUE;
1004 }
1005 }
1006 }
1007 }
1008 }
1009
1010 static
SetVsAndVs2ForHinge(psssi,dx,dy,pn_num_vs,vs,pn_num_vs2,vs2)1011 void SetVsAndVs2ForHinge(psssi, dx, dy, pn_num_vs, vs, pn_num_vs2, vs2)
1012 StretchStructuredSplineInfo *psssi;
1013 int dx, dy, *pn_num_vs, *pn_num_vs2;
1014 IntPoint *vs, *vs2;
1015 {
1016 int num_vs=0, num_vs2=0;
1017
1018 if (!psssi->prev_valid) {
1019 /* first poly point */
1020 num_vs = 0;
1021 vs2[0].x = psssi->ipt.hinge_pt.x + dx;
1022 vs2[0].y = psssi->ipt.hinge_pt.y + dy;
1023 if (psssi->ipt.later_valid) {
1024 vs2[1].x = psssi->ipt.later_smooth_pt.x + dx;
1025 vs2[1].y = psssi->ipt.later_smooth_pt.y + dy;
1026 if (psssi->ipt_next.earlier_valid) {
1027 num_vs2 = 4;
1028 vs2[2].x = psssi->ipt_next.earlier_smooth_pt.x;
1029 vs2[2].y = psssi->ipt_next.earlier_smooth_pt.y;
1030 } else {
1031 num_vs2 = 3;
1032 }
1033 } else {
1034 if (psssi->ipt_next.earlier_valid) {
1035 num_vs2 = 3;
1036 vs2[1].x = psssi->ipt_next.earlier_smooth_pt.x;
1037 vs2[1].y = psssi->ipt_next.earlier_smooth_pt.y;
1038 } else {
1039 num_vs2 = 2;
1040 }
1041 }
1042 vs2[num_vs2-1].x = psssi->ipt_next.hinge_pt.x;
1043 vs2[num_vs2-1].y = psssi->ipt_next.hinge_pt.y;
1044 } else if (!psssi->next_valid) {
1045 /* last poly point */
1046 num_vs2 = 0;
1047 vs[0].x = psssi->ipt.hinge_pt.x + dx;
1048 vs[0].y = psssi->ipt.hinge_pt.y + dy;
1049 if (psssi->ipt.earlier_valid) {
1050 vs[1].x = psssi->ipt.earlier_smooth_pt.x + dx;
1051 vs[1].y = psssi->ipt.earlier_smooth_pt.y + dy;
1052 if (psssi->ipt_prev.later_valid) {
1053 num_vs = 4;
1054 vs[2].x = psssi->ipt_prev.later_smooth_pt.x;
1055 vs[2].y = psssi->ipt_prev.later_smooth_pt.y;
1056 } else {
1057 num_vs = 3;
1058 }
1059 } else {
1060 if (psssi->ipt_prev.later_valid) {
1061 num_vs = 3;
1062 vs[1].x = psssi->ipt_prev.later_smooth_pt.x;
1063 vs[1].y = psssi->ipt_prev.later_smooth_pt.y;
1064 } else {
1065 num_vs = 2;
1066 }
1067 }
1068 vs[num_vs-1].x = psssi->ipt_prev.hinge_pt.x;
1069 vs[num_vs-1].y = psssi->ipt_prev.hinge_pt.y;
1070 } else {
1071 /* set the vs */
1072 vs[0].x = psssi->ipt.hinge_pt.x + dx;
1073 vs[0].y = psssi->ipt.hinge_pt.y + dy;
1074 if (psssi->ipt.earlier_valid) {
1075 vs[1].x = psssi->ipt.earlier_smooth_pt.x + dx;
1076 vs[1].y = psssi->ipt.earlier_smooth_pt.y + dy;
1077 if (psssi->ipt_prev.later_valid) {
1078 num_vs = 4;
1079 vs[2].x = psssi->ipt_prev.later_smooth_pt.x;
1080 vs[2].y = psssi->ipt_prev.later_smooth_pt.y;
1081 } else {
1082 num_vs = 3;
1083 }
1084 } else {
1085 if (psssi->ipt_prev.later_valid) {
1086 num_vs = 3;
1087 vs[1].x = psssi->ipt_prev.later_smooth_pt.x;
1088 vs[1].y = psssi->ipt_prev.later_smooth_pt.y;
1089 } else {
1090 num_vs = 2;
1091 }
1092 }
1093 vs[num_vs-1].x = psssi->ipt_prev.hinge_pt.x;
1094 vs[num_vs-1].y = psssi->ipt_prev.hinge_pt.y;
1095
1096 /* set the vs2 */
1097 vs2[0].x = psssi->ipt.hinge_pt.x + dx;
1098 vs2[0].y = psssi->ipt.hinge_pt.y + dy;
1099 if (psssi->ipt.later_valid) {
1100 vs2[1].x = psssi->ipt.later_smooth_pt.x + dx;
1101 vs2[1].y = psssi->ipt.later_smooth_pt.y + dy;
1102 if (psssi->ipt_next.earlier_valid) {
1103 num_vs2 = 4;
1104 vs2[2].x = psssi->ipt_next.earlier_smooth_pt.x;
1105 vs2[2].y = psssi->ipt_next.earlier_smooth_pt.y;
1106 } else {
1107 num_vs2 = 3;
1108 }
1109 } else {
1110 if (psssi->ipt_next.earlier_valid) {
1111 num_vs2 = 3;
1112 vs2[1].x = psssi->ipt_next.earlier_smooth_pt.x;
1113 vs2[1].y = psssi->ipt_next.earlier_smooth_pt.y;
1114 } else {
1115 num_vs2 = 2;
1116 }
1117 }
1118 vs2[num_vs2-1].x = psssi->ipt_next.hinge_pt.x;
1119 vs2[num_vs2-1].y = psssi->ipt_next.hinge_pt.y;
1120 }
1121 *pn_num_vs = num_vs;
1122 *pn_num_vs2 = num_vs2;
1123 }
1124
1125 static
SetVsAndVs2ForSmooth(psssi,dx,dy,pn_num_vs,vs,pn_num_vs2,vs2)1126 void SetVsAndVs2ForSmooth(psssi, dx, dy, pn_num_vs, vs, pn_num_vs2, vs2)
1127 StretchStructuredSplineInfo *psssi;
1128 int dx, dy, *pn_num_vs, *pn_num_vs2;
1129 IntPoint *vs, *vs2;
1130 {
1131 int num_vs=0, num_vs2=0;
1132
1133 if (!psssi->prev_valid) {
1134 /* first poly point */
1135 num_vs = 0;
1136 vs2[0].x = psssi->ipt.hinge_pt.x;
1137 vs2[0].y = psssi->ipt.hinge_pt.y;
1138 #ifdef _TGIF_DBG /* debug, do not translate */
1139 TgAssert(psssi->ipt.later_valid,
1140 "psssi->ipt.later_valid is FALSE in SetVsAndVs2ForSmooth()", NULL);
1141 #endif /* _TGIF_DBG */
1142 vs2[1].x = psssi->ipt.later_smooth_pt.x + dx;
1143 vs2[1].y = psssi->ipt.later_smooth_pt.y + dy;
1144 if (psssi->ipt_next.earlier_valid) {
1145 num_vs2 = 4;
1146 vs2[2].x = psssi->ipt_next.earlier_smooth_pt.x;
1147 vs2[2].y = psssi->ipt_next.earlier_smooth_pt.y;
1148 } else {
1149 num_vs2 = 3;
1150 }
1151 vs2[num_vs2-1].x = psssi->ipt_next.hinge_pt.x;
1152 vs2[num_vs2-1].y = psssi->ipt_next.hinge_pt.y;
1153 } else if (!psssi->next_valid) {
1154 /* last poly point */
1155 num_vs2 = 0;
1156 vs[0].x = psssi->ipt.hinge_pt.x;
1157 vs[0].y = psssi->ipt.hinge_pt.y;
1158 #ifdef _TGIF_DBG /* debug, do not translate */
1159 TgAssert(psssi->ipt.earlier_valid,
1160 "psssi->ipt.earlier_valid is FALSE in SetVsAndVs2ForSmooth()",
1161 NULL);
1162 #endif /* _TGIF_DBG */
1163 vs[1].x = psssi->ipt.earlier_smooth_pt.x + dx;
1164 vs[1].y = psssi->ipt.earlier_smooth_pt.y + dy;
1165 if (psssi->ipt_prev.later_valid) {
1166 num_vs = 4;
1167 vs[2].x = psssi->ipt_prev.later_smooth_pt.x;
1168 vs[2].y = psssi->ipt_prev.later_smooth_pt.y;
1169 } else {
1170 num_vs = 3;
1171 }
1172 vs[num_vs-1].x = psssi->ipt_prev.hinge_pt.x;
1173 vs[num_vs-1].y = psssi->ipt_prev.hinge_pt.y;
1174 } else {
1175 if (psssi->earlier_smooth_selected) {
1176 #ifdef _TGIF_DBG /* debug, do not translate */
1177 TgAssert(psssi->ipt.earlier_valid,
1178 "psssi->ipt.earlier_valid is FALSE with psssi->earlier_smooth_selected in SetVsAndVs2ForSmooth()",
1179 NULL);
1180 #endif /* _TGIF_DBG */
1181 /* set the vs */
1182 vs[0].x = psssi->ipt.hinge_pt.x;
1183 vs[0].y = psssi->ipt.hinge_pt.y;
1184 vs[1].x = psssi->ipt.earlier_smooth_pt.x + dx;
1185 vs[1].y = psssi->ipt.earlier_smooth_pt.y + dy;
1186 if (psssi->ipt_prev.later_valid) {
1187 num_vs = 4;
1188 vs[2].x = psssi->ipt_prev.later_smooth_pt.x;
1189 vs[2].y = psssi->ipt_prev.later_smooth_pt.y;
1190 } else {
1191 num_vs = 3;
1192 }
1193 vs[num_vs-1].x = psssi->ipt_prev.hinge_pt.x;
1194 vs[num_vs-1].y = psssi->ipt_prev.hinge_pt.y;
1195
1196 /* set the vs2 */
1197 vs2[0].x = psssi->ipt.hinge_pt.x;
1198 vs2[0].y = psssi->ipt.hinge_pt.y;
1199 if (psssi->ipt.later_valid) {
1200 vs2[1].x = ((psssi->ipt.hinge_pt.x) << 1) -
1201 psssi->ipt.earlier_smooth_pt.x - dx;
1202 vs2[1].y = ((psssi->ipt.hinge_pt.y) << 1) -
1203 psssi->ipt.earlier_smooth_pt.y - dy;
1204 if (psssi->ipt_next.earlier_valid) {
1205 num_vs2 = 4;
1206 vs2[2].x = psssi->ipt_next.earlier_smooth_pt.x;
1207 vs2[2].y = psssi->ipt_next.earlier_smooth_pt.y;
1208 } else {
1209 num_vs2 = 3;
1210 }
1211 } else {
1212 if (psssi->ipt_next.earlier_valid) {
1213 num_vs2 = 3;
1214 vs2[1].x = psssi->ipt_next.earlier_smooth_pt.x;
1215 vs2[1].y = psssi->ipt_next.earlier_smooth_pt.y;
1216 } else {
1217 num_vs2 = 2;
1218 }
1219 }
1220 vs2[num_vs2-1].x = psssi->ipt_next.hinge_pt.x;
1221 vs2[num_vs2-1].y = psssi->ipt_next.hinge_pt.y;
1222 } else {
1223 /* set the vs */
1224 vs[0].x = psssi->ipt.hinge_pt.x;
1225 vs[0].y = psssi->ipt.hinge_pt.y;
1226 if (psssi->ipt.earlier_valid) {
1227 vs[1].x = ((psssi->ipt.hinge_pt.x) << 1) -
1228 psssi->ipt.later_smooth_pt.x - dx;
1229 vs[1].y = ((psssi->ipt.hinge_pt.y) << 1) -
1230 psssi->ipt.later_smooth_pt.y - dy;
1231 if (psssi->ipt_prev.later_valid) {
1232 num_vs = 4;
1233 vs[2].x = psssi->ipt_prev.later_smooth_pt.x;
1234 vs[2].y = psssi->ipt_prev.later_smooth_pt.y;
1235 } else {
1236 num_vs = 3;
1237 }
1238 } else {
1239 if (psssi->ipt_prev.later_valid) {
1240 num_vs = 3;
1241 vs[1].x = psssi->ipt_prev.later_smooth_pt.x;
1242 vs[1].y = psssi->ipt_prev.later_smooth_pt.y;
1243 } else {
1244 num_vs = 2;
1245 }
1246 }
1247 vs[num_vs-1].x = psssi->ipt_prev.hinge_pt.x;
1248 vs[num_vs-1].y = psssi->ipt_prev.hinge_pt.y;
1249
1250 #ifdef _TGIF_DBG /* debug, do not translate */
1251 TgAssert(psssi->ipt.later_valid,
1252 "psssi->ipt.later_valid is FALSE with !psssi->earlier_smooth_selected in SetVsAndVs2ForSmooth()",
1253 NULL);
1254 #endif /* _TGIF_DBG */
1255 /* set the vs2 */
1256 vs2[0].x = psssi->ipt.hinge_pt.x;
1257 vs2[0].y = psssi->ipt.hinge_pt.y;
1258 vs2[1].x = psssi->ipt.later_smooth_pt.x + dx;
1259 vs2[1].y = psssi->ipt.later_smooth_pt.y + dy;
1260 if (psssi->ipt_next.earlier_valid) {
1261 num_vs2 = 4;
1262 vs2[2].x = psssi->ipt_next.earlier_smooth_pt.x;
1263 vs2[2].y = psssi->ipt_next.earlier_smooth_pt.y;
1264 } else {
1265 num_vs2 = 3;
1266 }
1267 vs2[num_vs2-1].x = psssi->ipt_next.hinge_pt.x;
1268 vs2[num_vs2-1].y = psssi->ipt_next.hinge_pt.y;
1269 }
1270 }
1271 *pn_num_vs = num_vs;
1272 *pn_num_vs2 = num_vs2;
1273 }
1274
SetVsAndVs2ForStretchStructSpline(psssi,dx,dy,pn_num_vs,vs,pn_num_vs2,vs2)1275 void SetVsAndVs2ForStretchStructSpline(psssi, dx, dy, pn_num_vs, vs, pn_num_vs2,
1276 vs2)
1277 StretchStructuredSplineInfo *psssi;
1278 int dx, dy, *pn_num_vs, *pn_num_vs2;
1279 IntPoint *vs, *vs2;
1280 {
1281 if (psssi->hinge) {
1282 SetVsAndVs2ForHinge(psssi, dx, dy, pn_num_vs, vs, pn_num_vs2, vs2);
1283 } else {
1284 SetVsAndVs2ForSmooth(psssi, dx, dy, pn_num_vs, vs, pn_num_vs2, vs2);
1285 }
1286 }
1287
FixUpSmoothAndSmooth2ForStretchStructSpline(num_vs,smooth,num_vs2,smooth2)1288 void FixUpSmoothAndSmooth2ForStretchStructSpline(num_vs, smooth, num_vs2,
1289 smooth2)
1290 int num_vs, num_vs2;
1291 char *smooth, *smooth2;
1292 {
1293 int i=0;
1294
1295 smooth[0] = FALSE;
1296 smooth[num_vs-1] = FALSE;
1297 for (i=1; i < num_vs-1; i++) smooth[i] = TRUE;
1298
1299 smooth2[0] = FALSE;
1300 smooth2[num_vs2-1] = FALSE;
1301 for (i=1; i < num_vs2-1; i++) smooth2[i] = TRUE;
1302 }
1303
EraseHighLightForHinge(psssi,dx,dy,draw_dashed_line,draw_vertices)1304 void EraseHighLightForHinge(psssi, dx, dy, draw_dashed_line, draw_vertices)
1305 StretchStructuredSplineInfo *psssi;
1306 int dx, dy, draw_dashed_line, draw_vertices;
1307 {
1308 int x=0, y=0;
1309 XPoint vs[2];
1310 XGCValues values;
1311
1312 if (draw_dashed_line) {
1313 XSetDashes(mainDisplay, revDefaultGC, 0, dashList[8], dashListLength[8]);
1314 }
1315 if (!psssi->prev_valid) {
1316 /* first poly point */
1317 x = psssi->ipt.hinge_pt.x + dx;
1318 y = psssi->ipt.hinge_pt.y + dy;
1319 if (draw_vertices) {
1320 MARKHR(drawWindow, revDefaultGC, OFFSET_X(x), OFFSET_Y(y));
1321 }
1322 vs[0].x = OFFSET_X(x);
1323 vs[0].y = OFFSET_Y(y);
1324 if (psssi->ipt.later_valid) {
1325 x = psssi->ipt.later_smooth_pt.x + dx;
1326 y = psssi->ipt.later_smooth_pt.y + dy;
1327 if (draw_vertices) {
1328 MARKHO(drawWindow, revDefaultGC, OFFSET_X(x), OFFSET_Y(y));
1329 }
1330 vs[1].x = OFFSET_X(x);
1331 vs[1].y = OFFSET_Y(y);
1332 if (draw_dashed_line) {
1333 values.line_style = LineOnOffDash;
1334 XChangeGC(mainDisplay, revDefaultGC, GCLineStyle, &values);
1335 MyDashedLine(drawWindow, revDefaultGC, vs, 2);
1336 values.line_style = LineSolid;
1337 XChangeGC(mainDisplay, revDefaultGC, GCLineStyle, &values);
1338 }
1339 }
1340 } else if (!psssi->next_valid) {
1341 /* last poly point */
1342 x = psssi->ipt.hinge_pt.x + dx;
1343 y = psssi->ipt.hinge_pt.y + dy;
1344 if (draw_vertices) {
1345 MARKHR(drawWindow, revDefaultGC, OFFSET_X(x), OFFSET_Y(y));
1346 }
1347 vs[0].x = OFFSET_X(x);
1348 vs[0].y = OFFSET_Y(y);
1349 if (psssi->ipt.earlier_valid) {
1350 x = psssi->ipt.earlier_smooth_pt.x + dx;
1351 y = psssi->ipt.earlier_smooth_pt.y + dy;
1352 if (draw_vertices) {
1353 MARKHO(drawWindow, revDefaultGC, OFFSET_X(x), OFFSET_Y(y));
1354 }
1355 vs[1].x = OFFSET_X(x);
1356 vs[1].y = OFFSET_Y(y);
1357 if (draw_dashed_line) {
1358 values.line_style = LineOnOffDash;
1359 XChangeGC(mainDisplay, revDefaultGC, GCLineStyle, &values);
1360 MyDashedLine(drawWindow, revDefaultGC, vs, 2);
1361 values.line_style = LineSolid;
1362 XChangeGC(mainDisplay, revDefaultGC, GCLineStyle, &values);
1363 }
1364 }
1365 } else {
1366 x = psssi->ipt.hinge_pt.x + dx;
1367 y = psssi->ipt.hinge_pt.y + dy;
1368 if (draw_vertices) {
1369 MARKHR(drawWindow, revDefaultGC, OFFSET_X(x), OFFSET_Y(y));
1370 }
1371 vs[0].x = OFFSET_X(x);
1372 vs[0].y = OFFSET_Y(y);
1373 if (psssi->ipt.later_valid) {
1374 x = psssi->ipt.later_smooth_pt.x + dx;
1375 y = psssi->ipt.later_smooth_pt.y + dy;
1376 if (draw_vertices) {
1377 MARKHO(drawWindow, revDefaultGC, OFFSET_X(x), OFFSET_Y(y));
1378 }
1379 vs[1].x = OFFSET_X(x);
1380 vs[1].y = OFFSET_Y(y);
1381 if (draw_dashed_line) {
1382 values.line_style = LineOnOffDash;
1383 XChangeGC(mainDisplay, revDefaultGC, GCLineStyle, &values);
1384 MyDashedLine(drawWindow, revDefaultGC, vs, 2);
1385 values.line_style = LineSolid;
1386 XChangeGC(mainDisplay, revDefaultGC, GCLineStyle, &values);
1387 }
1388 }
1389 if (psssi->ipt.earlier_valid) {
1390 x = psssi->ipt.earlier_smooth_pt.x + dx;
1391 y = psssi->ipt.earlier_smooth_pt.y + dy;
1392 if (draw_vertices) {
1393 MARKHO(drawWindow, revDefaultGC, OFFSET_X(x), OFFSET_Y(y));
1394 }
1395 vs[1].x = OFFSET_X(x);
1396 vs[1].y = OFFSET_Y(y);
1397 if (draw_dashed_line) {
1398 values.line_style = LineOnOffDash;
1399 XChangeGC(mainDisplay, revDefaultGC, GCLineStyle, &values);
1400 MyDashedLine(drawWindow, revDefaultGC, vs, 2);
1401 values.line_style = LineSolid;
1402 XChangeGC(mainDisplay, revDefaultGC, GCLineStyle, &values);
1403 }
1404 }
1405 }
1406 }
1407
EraseHighLightForSmooth(psssi,dx,dy,draw_dashed_line,draw_vertices)1408 void EraseHighLightForSmooth(psssi, dx, dy, draw_dashed_line, draw_vertices)
1409 StretchStructuredSplineInfo *psssi;
1410 int dx, dy, draw_dashed_line, draw_vertices;
1411 {
1412 int x=0, y=0;
1413 XPoint vs[2];
1414 XGCValues values;
1415
1416 if (draw_dashed_line) {
1417 XSetDashes(mainDisplay, revDefaultGC, 0, dashList[8], dashListLength[8]);
1418 }
1419 if (!psssi->prev_valid) {
1420 /* first poly point */
1421 x = psssi->ipt.hinge_pt.x;
1422 y = psssi->ipt.hinge_pt.y;
1423 if (draw_vertices) {
1424 MARKHR(drawWindow, revDefaultGC, OFFSET_X(x), OFFSET_Y(y));
1425 }
1426 vs[0].x = OFFSET_X(x);
1427 vs[0].y = OFFSET_Y(y);
1428 if (psssi->ipt.later_valid) {
1429 x = psssi->ipt.later_smooth_pt.x + dx;
1430 y = psssi->ipt.later_smooth_pt.y + dy;
1431 if (draw_vertices) {
1432 MARKHO(drawWindow, revDefaultGC, OFFSET_X(x), OFFSET_Y(y));
1433 }
1434 vs[1].x = OFFSET_X(x);
1435 vs[1].y = OFFSET_Y(y);
1436 if (draw_dashed_line) {
1437 values.line_style = LineOnOffDash;
1438 XChangeGC(mainDisplay, revDefaultGC, GCLineStyle, &values);
1439 MyDashedLine(drawWindow, revDefaultGC, vs, 2);
1440 values.line_style = LineSolid;
1441 XChangeGC(mainDisplay, revDefaultGC, GCLineStyle, &values);
1442 }
1443 }
1444 } else if (!psssi->next_valid) {
1445 /* last poly point */
1446 x = psssi->ipt.hinge_pt.x;
1447 y = psssi->ipt.hinge_pt.y;
1448 if (draw_vertices) {
1449 MARKHR(drawWindow, revDefaultGC, OFFSET_X(x), OFFSET_Y(y));
1450 }
1451 vs[0].x = OFFSET_X(x);
1452 vs[0].y = OFFSET_Y(y);
1453 if (psssi->ipt.earlier_valid) {
1454 x = psssi->ipt.earlier_smooth_pt.x + dx;
1455 y = psssi->ipt.earlier_smooth_pt.y + dy;
1456 if (draw_vertices) {
1457 MARKHO(drawWindow, revDefaultGC, OFFSET_X(x), OFFSET_Y(y));
1458 }
1459 vs[1].x = OFFSET_X(x);
1460 vs[1].y = OFFSET_Y(y);
1461 if (draw_dashed_line) {
1462 values.line_style = LineOnOffDash;
1463 XChangeGC(mainDisplay, revDefaultGC, GCLineStyle, &values);
1464 MyDashedLine(drawWindow, revDefaultGC, vs, 2);
1465 values.line_style = LineSolid;
1466 XChangeGC(mainDisplay, revDefaultGC, GCLineStyle, &values);
1467 }
1468 }
1469 } else {
1470 if (psssi->earlier_smooth_selected) {
1471 x = psssi->ipt.hinge_pt.x;
1472 y = psssi->ipt.hinge_pt.y;
1473 if (draw_vertices) {
1474 MARKHR(drawWindow, revDefaultGC, OFFSET_X(x), OFFSET_Y(y));
1475 }
1476 vs[0].x = OFFSET_X(x);
1477 vs[0].y = OFFSET_Y(y);
1478 if (psssi->ipt.later_valid) {
1479 x = ((psssi->ipt.hinge_pt.x) << 1) -
1480 psssi->ipt.earlier_smooth_pt.x - dx;
1481 y = ((psssi->ipt.hinge_pt.y) << 1) -
1482 psssi->ipt.earlier_smooth_pt.y - dy;
1483 if (draw_vertices) {
1484 MARKHO(drawWindow, revDefaultGC, OFFSET_X(x), OFFSET_Y(y));
1485 }
1486 vs[1].x = OFFSET_X(x);
1487 vs[1].y = OFFSET_Y(y);
1488 if (draw_dashed_line) {
1489 values.line_style = LineOnOffDash;
1490 XChangeGC(mainDisplay, revDefaultGC, GCLineStyle, &values);
1491 MyDashedLine(drawWindow, revDefaultGC, vs, 2);
1492 values.line_style = LineSolid;
1493 XChangeGC(mainDisplay, revDefaultGC, GCLineStyle, &values);
1494 }
1495 }
1496 if (psssi->ipt.earlier_valid) {
1497 x = psssi->ipt.earlier_smooth_pt.x + dx;
1498 y = psssi->ipt.earlier_smooth_pt.y + dy;
1499 if (draw_vertices) {
1500 MARKHO(drawWindow, revDefaultGC, OFFSET_X(x), OFFSET_Y(y));
1501 }
1502 vs[1].x = OFFSET_X(x);
1503 vs[1].y = OFFSET_Y(y);
1504 if (draw_dashed_line) {
1505 values.line_style = LineOnOffDash;
1506 XChangeGC(mainDisplay, revDefaultGC, GCLineStyle, &values);
1507 MyDashedLine(drawWindow, revDefaultGC, vs, 2);
1508 values.line_style = LineSolid;
1509 XChangeGC(mainDisplay, revDefaultGC, GCLineStyle, &values);
1510 }
1511 }
1512 } else {
1513 x = psssi->ipt.hinge_pt.x;
1514 y = psssi->ipt.hinge_pt.y;
1515 if (draw_vertices) {
1516 MARKHR(drawWindow, revDefaultGC, OFFSET_X(x), OFFSET_Y(y));
1517 }
1518 vs[0].x = OFFSET_X(x);
1519 vs[0].y = OFFSET_Y(y);
1520 if (psssi->ipt.later_valid) {
1521 x = psssi->ipt.later_smooth_pt.x + dx;
1522 y = psssi->ipt.later_smooth_pt.y + dy;
1523 if (draw_vertices) {
1524 MARKHO(drawWindow, revDefaultGC, OFFSET_X(x), OFFSET_Y(y));
1525 }
1526 vs[1].x = OFFSET_X(x);
1527 vs[1].y = OFFSET_Y(y);
1528 if (draw_dashed_line) {
1529 values.line_style = LineOnOffDash;
1530 XChangeGC(mainDisplay, revDefaultGC, GCLineStyle, &values);
1531 MyDashedLine(drawWindow, revDefaultGC, vs, 2);
1532 values.line_style = LineSolid;
1533 XChangeGC(mainDisplay, revDefaultGC, GCLineStyle, &values);
1534 }
1535 }
1536 if (psssi->ipt.earlier_valid) {
1537 x = ((psssi->ipt.hinge_pt.x) << 1) -
1538 psssi->ipt.later_smooth_pt.x - dx;
1539 y = ((psssi->ipt.hinge_pt.y) << 1) -
1540 psssi->ipt.later_smooth_pt.y - dy;
1541 if (draw_vertices) {
1542 MARKHO(drawWindow, revDefaultGC, OFFSET_X(x), OFFSET_Y(y));
1543 }
1544 vs[1].x = OFFSET_X(x);
1545 vs[1].y = OFFSET_Y(y);
1546 if (draw_dashed_line) {
1547 values.line_style = LineOnOffDash;
1548 XChangeGC(mainDisplay, revDefaultGC, GCLineStyle, &values);
1549 MyDashedLine(drawWindow, revDefaultGC, vs, 2);
1550 values.line_style = LineSolid;
1551 XChangeGC(mainDisplay, revDefaultGC, GCLineStyle, &values);
1552 }
1553 }
1554 }
1555 }
1556 }
1557
EraseHighLightForStretchStructSpline(psssi,dx,dy,draw_dashed_line,draw_vertices)1558 void EraseHighLightForStretchStructSpline(psssi, dx, dy, draw_dashed_line,
1559 draw_vertices)
1560 StretchStructuredSplineInfo *psssi;
1561 int dx, dy, draw_dashed_line, draw_vertices;
1562 {
1563 if (psssi->hinge) {
1564 EraseHighLightForHinge(psssi, dx, dy, draw_dashed_line, draw_vertices);
1565 } else {
1566 EraseHighLightForSmooth(psssi, dx, dy, draw_dashed_line, draw_vertices);
1567 }
1568 }
1569
DupVs(pn_return,vs,n)1570 XPoint *DupVs(pn_return, vs, n)
1571 int *pn_return, n;
1572 XPoint *vs;
1573 {
1574 XPoint *vs_return=(XPoint*)malloc(n*sizeof(XPoint));
1575
1576 if (vs_return == NULL) FailAllocMessage();
1577 memcpy(vs_return, vs, n*sizeof(XPoint));
1578 *pn_return = n;
1579
1580 return vs_return;
1581 }
1582
MoveATransformedPoint(obj_ptr,vs,abs_dx,abs_dy)1583 void MoveATransformedPoint(obj_ptr, vs, abs_dx, abs_dy)
1584 struct ObjRec *obj_ptr;
1585 IntPoint *vs;
1586 int abs_dx, abs_dy;
1587 {
1588 int x=0, y=0;
1589
1590 TransformPointThroughCTM(vs->x-obj_ptr->x, vs->y-obj_ptr->y,
1591 obj_ptr->ctm, &x, &y);
1592 x += obj_ptr->x + abs_dx;
1593 y += obj_ptr->y + abs_dy;
1594 ReverseTransformPointThroughCTM(x-obj_ptr->x, y-obj_ptr->y,
1595 obj_ptr->ctm, &x, &y);
1596 vs->x = x + obj_ptr->x;
1597 vs->y = y + obj_ptr->y;
1598 }
1599
UpdateObjForStretchStructSpline(obj_ptr,n,vs,abs_dx,abs_dy,psssi)1600 void UpdateObjForStretchStructSpline(obj_ptr, n, vs, abs_dx, abs_dy, psssi)
1601 struct ObjRec *obj_ptr;
1602 int n, abs_dx, abs_dy;
1603 IntPoint *vs;
1604 StretchStructuredSplineInfo *psssi;
1605 {
1606 int index=psssi->orig_hinge_index;
1607
1608 if (obj_ptr->ctm == NULL) {
1609 if (psssi->hinge) {
1610 if (!psssi->prev_valid) {
1611 /* first poly point */
1612 vs[0].x += abs_dx;
1613 vs[0].y += abs_dy;
1614 vs[1].x += abs_dx;
1615 vs[1].y += abs_dy;
1616 } else if (!psssi->next_valid) {
1617 /* last poly point */
1618 vs[n-1].x += abs_dx;
1619 vs[n-1].y += abs_dy;
1620 vs[n-2].x += abs_dx;
1621 vs[n-2].y += abs_dy;
1622 } else {
1623 if (obj_ptr->type == OBJ_POLYGON && index == 0) {
1624 vs[0].x += abs_dx;
1625 vs[0].y += abs_dy;
1626 vs[1].x += abs_dx;
1627 vs[1].y += abs_dy;
1628 /* since it's a polygon */
1629 vs[n-1].x += abs_dx;
1630 vs[n-1].y += abs_dy;
1631 vs[n-2].x += abs_dx;
1632 vs[n-2].y += abs_dy;
1633 } else if (obj_ptr->type == OBJ_POLYGON && index == n-1) {
1634 vs[n-1].x += abs_dx;
1635 vs[n-1].y += abs_dy;
1636 vs[n-2].x += abs_dx;
1637 vs[n-2].y += abs_dy;
1638 /* since it's a polygon */
1639 vs[0].x += abs_dx;
1640 vs[0].y += abs_dy;
1641 vs[1].x += abs_dx;
1642 vs[1].y += abs_dy;
1643 } else {
1644 vs[index-1].x += abs_dx;
1645 vs[index-1].y += abs_dy;
1646 vs[index].x += abs_dx;
1647 vs[index].y += abs_dy;
1648 vs[index+1].x += abs_dx;
1649 vs[index+1].y += abs_dy;
1650 }
1651 }
1652 } else {
1653 if (!psssi->prev_valid) {
1654 /* first poly point */
1655 vs[1].x += abs_dx;
1656 vs[1].y += abs_dy;
1657 if (obj_ptr->type == OBJ_POLYGON && index == 0) {
1658 vs[n-2].x = ((vs[0].x) << 1) - vs[1].x;
1659 vs[n-2].y = ((vs[0].y) << 1) - vs[1].y;
1660 }
1661 } else if (!psssi->next_valid) {
1662 /* last poly point */
1663 vs[n-2].x += abs_dx;
1664 vs[n-2].y += abs_dy;
1665 if (obj_ptr->type == OBJ_POLYGON && index == n-1) {
1666 vs[1].x = ((vs[n-1].x) << 1) - vs[n-2].x;
1667 vs[1].y = ((vs[n-1].y) << 1) - vs[n-2].y;
1668 }
1669 } else {
1670 if (psssi->earlier_smooth_selected) {
1671 if (obj_ptr->type == OBJ_POLYGON &&
1672 (index == 0 || index == n-1)) {
1673 vs[n-2].x += abs_dx;
1674 vs[n-2].y += abs_dy;
1675 /* since it's a polygon */
1676 vs[1].x = ((vs[n-1].x) << 1) - vs[n-2].x;
1677 vs[1].y = ((vs[n-1].y) << 1) - vs[n-2].y;
1678 } else {
1679 vs[index-1].x += abs_dx;
1680 vs[index-1].y += abs_dy;
1681 vs[index+1].x = ((vs[index].x) << 1) - vs[index-1].x;
1682 vs[index+1].y = ((vs[index].y) << 1) - vs[index-1].y;
1683 }
1684 } else {
1685 if (obj_ptr->type == OBJ_POLYGON &&
1686 (index == 0 || index == n-1)) {
1687 vs[1].x += abs_dx;
1688 vs[1].y += abs_dy;
1689 /* since it's a polygon */
1690 vs[n-2].x = ((vs[0].x) << 1) - vs[1].x;
1691 vs[n-2].y = ((vs[0].y) << 1) - vs[1].y;
1692 } else {
1693 vs[index+1].x += abs_dx;
1694 vs[index+1].y += abs_dy;
1695 vs[index-1].x = ((vs[index].x) << 1) - vs[index+1].x;
1696 vs[index-1].y = ((vs[index].y) << 1) - vs[index+1].y;
1697 }
1698 }
1699 }
1700 }
1701 } else {
1702 if (psssi->hinge) {
1703 if (!psssi->prev_valid) {
1704 /* first poly point */
1705 MoveATransformedPoint(obj_ptr, &vs[0], abs_dx, abs_dy);
1706 MoveATransformedPoint(obj_ptr, &vs[1], abs_dx, abs_dy);
1707 if (obj_ptr->type == OBJ_POLYGON && index == 0) {
1708 MoveATransformedPoint(obj_ptr, &vs[n-1], abs_dx, abs_dy);
1709 MoveATransformedPoint(obj_ptr, &vs[n-2], abs_dx, abs_dy);
1710 }
1711 } else if (!psssi->next_valid) {
1712 /* last poly point */
1713 MoveATransformedPoint(obj_ptr, &vs[n-1], abs_dx, abs_dy);
1714 MoveATransformedPoint(obj_ptr, &vs[n-2], abs_dx, abs_dy);
1715 if (obj_ptr->type == OBJ_POLYGON &&
1716 index == n-1) {
1717 MoveATransformedPoint(obj_ptr, &vs[0], abs_dx, abs_dy);
1718 MoveATransformedPoint(obj_ptr, &vs[1], abs_dx, abs_dy);
1719 }
1720 } else {
1721 if (obj_ptr->type == OBJ_POLYGON && index == 0) {
1722 MoveATransformedPoint(obj_ptr, &vs[0], abs_dx, abs_dy);
1723 MoveATransformedPoint(obj_ptr, &vs[1], abs_dx, abs_dy);
1724 /* since it's a polygon */
1725 MoveATransformedPoint(obj_ptr, &vs[n-1], abs_dx, abs_dy);
1726 MoveATransformedPoint(obj_ptr, &vs[n-2], abs_dx, abs_dy);
1727 } else if (obj_ptr->type == OBJ_POLYGON && index == n-1) {
1728 MoveATransformedPoint(obj_ptr, &vs[n-1], abs_dx, abs_dy);
1729 MoveATransformedPoint(obj_ptr, &vs[n-2], abs_dx, abs_dy);
1730 /* since it's a polygon */
1731 MoveATransformedPoint(obj_ptr, &vs[0], abs_dx, abs_dy);
1732 MoveATransformedPoint(obj_ptr, &vs[1], abs_dx, abs_dy);
1733 } else {
1734 MoveATransformedPoint(obj_ptr, &vs[index-1], abs_dx, abs_dy);
1735 MoveATransformedPoint(obj_ptr, &vs[index], abs_dx, abs_dy);
1736 MoveATransformedPoint(obj_ptr, &vs[index+1], abs_dx, abs_dy);
1737 }
1738 }
1739 } else {
1740 if (!psssi->prev_valid) {
1741 /* first poly point */
1742 MoveATransformedPoint(obj_ptr, &vs[1], abs_dx, abs_dy);
1743 if (obj_ptr->type == OBJ_POLYGON && index == 0) {
1744 vs[n-2].x = ((vs[0].x) << 1) - vs[1].x;
1745 vs[n-2].y = ((vs[0].y) << 1) - vs[1].y;
1746 }
1747 } else if (!psssi->next_valid) {
1748 /* last poly point */
1749 MoveATransformedPoint(obj_ptr, &vs[n-2], abs_dx, abs_dy);
1750 if (obj_ptr->type == OBJ_POLYGON && index == n-1) {
1751 vs[1].x = ((vs[n-1].x) << 1) - vs[n-2].x;
1752 vs[1].y = ((vs[n-1].y) << 1) - vs[n-2].y;
1753 }
1754 } else {
1755 if (psssi->earlier_smooth_selected) {
1756 if (obj_ptr->type == OBJ_POLYGON &&
1757 (index == 0 || index == n-1)) {
1758 MoveATransformedPoint(obj_ptr, &vs[n-2], abs_dx, abs_dy);
1759 /* since it's a polygon */
1760 vs[1].x = ((vs[n-1].x) << 1) - vs[n-2].x;
1761 vs[1].y = ((vs[n-1].y) << 1) - vs[n-2].y;
1762 } else {
1763 MoveATransformedPoint(obj_ptr, &vs[index-1], abs_dx, abs_dy);
1764 vs[index+1].x = ((vs[index].x) << 1) - vs[index-1].x;
1765 vs[index+1].y = ((vs[index].y) << 1) - vs[index-1].y;
1766 }
1767 } else {
1768 if (obj_ptr->type == OBJ_POLYGON &&
1769 (index == 0 || index == n-1)) {
1770 MoveATransformedPoint(obj_ptr, &vs[1], abs_dx, abs_dy);
1771 /* since it's a polygon */
1772 vs[n-2].x = ((vs[0].x) << 1) - vs[1].x;
1773 vs[n-2].y = ((vs[0].y) << 1) - vs[1].y;
1774 } else {
1775 MoveATransformedPoint(obj_ptr, &vs[index+1], abs_dx, abs_dy);
1776 vs[index-1].x = ((vs[index].x) << 1) - vs[index+1].x;
1777 vs[index-1].y = ((vs[index].y) << 1) - vs[index+1].y;
1778 }
1779 }
1780 }
1781 }
1782 }
1783 }
1784
1785 static
StretchStructSpline(XGridOff,YGridOff,ObjPtr,Index)1786 void StretchStructSpline(XGridOff, YGridOff, ObjPtr, Index)
1787 int XGridOff, YGridOff, Index;
1788 struct ObjRec *ObjPtr;
1789 {
1790 struct PolyRec *poly_ptr=NULL;
1791 struct PolygonRec *polygon_ptr=NULL;
1792 struct AttrRec *name_attr=NULL, *on_reshape_attr=NULL;
1793 int i, x, y, dx, dy, stretching=TRUE;
1794 int ltx=0, lty=0, rbx=0, rby=0;
1795 int grid_x=XGridOff, grid_y=YGridOff, sn=0, sn2=0, saved_sn=0, saved_sn2=0;
1796 int auto_center_attr=AutoCenterAttr(ObjPtr);
1797 int has_on_reshape=HasOnReshape(ObjPtr, &name_attr);
1798 int num_vs=0, num_vs2=0, ruler_x=0, ruler_y=0, n=0;
1799 char smooth[5], smooth2[5];
1800 XEvent input, ev;
1801 XPoint *sv=NULL, *sv2=NULL, *saved_sv=NULL, *saved_sv2=NULL;
1802 IntPoint vs[5], vs2[5], start_v, *vlist=NULL, *pvs=NULL;
1803 StretchStructuredSplineInfo sssi;
1804
1805 if (ObjPtr->locked) {
1806 Msg(TgLoadString(STID_LOCKED_OBJS_CANT_BE_STRETCHED));
1807 return;
1808 }
1809 memset(&sssi, 0, sizeof(StretchStructuredSplineInfo));
1810 memset(vs, 0, 5*sizeof(IntPoint));
1811 memset(vs2, 0, 5*sizeof(IntPoint));
1812
1813 switch (ObjPtr->type) {
1814 case OBJ_POLY:
1815 poly_ptr = ObjPtr->detail.p;
1816 start_v.x = poly_ptr->ssvlist[Index].x;
1817 start_v.y = poly_ptr->ssvlist[Index].y;
1818 n = poly_ptr->n;
1819 pvs = poly_ptr->vlist;
1820 break;
1821 case OBJ_POLYGON:
1822 polygon_ptr = ObjPtr->detail.g;
1823 start_v.x = polygon_ptr->ssvlist[Index].x;
1824 start_v.y = polygon_ptr->ssvlist[Index].y;
1825 n = polygon_ptr->n;
1826 pvs = polygon_ptr->vlist;
1827 break;
1828 }
1829 vlist = (IntPoint*)malloc((n+1)*sizeof(IntPoint));
1830 if (vlist == NULL) FailAllocMessage();
1831 memset(vlist, 0, (n+1)*sizeof(IntPoint));
1832
1833 if (ObjPtr->ctm == NULL) {
1834 for (i=0; i < n; i++) {
1835 vlist[i].x = pvs[i].x;
1836 vlist[i].y = pvs[i].y;
1837 }
1838 } else {
1839 for (i=0; i < n; i++) {
1840 TransformPointThroughCTM(pvs[i].x-ObjPtr->x, pvs[i].y-ObjPtr->y,
1841 ObjPtr->ctm, &x, &y);
1842 vlist[i].x = x+ObjPtr->x;
1843 vlist[i].y = y+ObjPtr->y;
1844 }
1845 }
1846 if (poly_ptr != NULL) {
1847 SetIPTInfoForStretchPoly(Index, n, vlist, &sssi);
1848 } else if (polygon_ptr != NULL) {
1849 SetIPTInfoForStretchPolygon(Index, n, vlist, &sssi);
1850 }
1851 SetVsAndVs2ForStretchStructSpline(&sssi, 0, 0, &num_vs, vs, &num_vs2, vs2);
1852 FixUpSmoothAndSmooth2ForStretchStructSpline(num_vs, smooth, num_vs2,
1853 smooth2);
1854 if (sssi.prev_valid) {
1855 sv = MakeMultiSplinePolyVertex(LT_STRUCT_SPLINE, &sn, smooth,
1856 drawOrigX, drawOrigY, num_vs, vs);
1857 saved_sv = DupVs(&saved_sn, sv, sn);
1858 }
1859 if (sssi.next_valid) {
1860 sv2 = MakeMultiSplinePolyVertex(LT_STRUCT_SPLINE, &sn2, smooth2,
1861 drawOrigX, drawOrigY, num_vs2, vs2);
1862 saved_sv2 = DupVs(&saved_sn2, sv2, sn2);
1863 }
1864 ltx = ObjPtr->bbox.ltx - handleSize;
1865 lty = ObjPtr->bbox.lty - handleSize;
1866 rbx = ObjPtr->bbox.rbx + handleSize;
1867 rby = ObjPtr->bbox.rby + handleSize;
1868
1869 XFlush(mainDisplay);
1870 XSync(mainDisplay, False);
1871
1872 if (XCheckMaskEvent(mainDisplay, ExposureMask, &ev) ||
1873 XCheckMaskEvent(mainDisplay, VisibilityChangeMask, &ev)) {
1874 ExposeEventHandler(&ev, TRUE);
1875 }
1876 EraseHighLightForStretchStructSpline(&sssi, 0, 0, TRUE, FALSE);
1877 DoStretchStructSplineMeasureCursor(STRETCH_STARTSHOW, &start_v, 0, 0, grid_x,
1878 grid_y);
1879 if (!debugNoPointerGrab) {
1880 XGrabPointer(mainDisplay, drawWindow, False,
1881 PointerMotionMask | ButtonReleaseMask,
1882 GrabModeAsync, GrabModeAsync, None, handCursor, CurrentTime);
1883 }
1884 dx = dy = 0;
1885 while (stretching) {
1886 XNextEvent(mainDisplay, &input);
1887
1888 if (input.type == Expose || input.type == VisibilityNotify) {
1889 ExposeEventHandler(&input, TRUE);
1890 } else if (input.type == ButtonRelease) {
1891 XUngrabPointer(mainDisplay, CurrentTime);
1892 XSync(mainDisplay, False);
1893 stretching = FALSE;
1894 } else if (input.type == MotionNotify || input.type == KeyPress ||
1895 input.type == KeyRelease) {
1896 DoStretchStructSplineMeasureCursor(STRETCH_DOSHOW, &start_v,
1897 ABS_SIZE(grid_x-XGridOff), ABS_SIZE(grid_y-YGridOff),
1898 grid_x, grid_y);
1899 if (input.type == KeyPress || input.type == KeyRelease ) {
1900 x = grid_x;
1901 y = grid_y;
1902 } else {
1903 x = input.xmotion.x;
1904 y = input.xmotion.y;
1905 }
1906 if (shiftForDiagMouseMove && DiagEventCheck(&input)) {
1907 if (input.type == KeyRelease) {
1908 x = input.xkey.x;
1909 y = input.xkey.y;
1910 } else {
1911 DiagGridXY(XGridOff, YGridOff, &x, &y);
1912 }
1913 }
1914 GridXY(x, y, &grid_x, &grid_y);
1915
1916 /* erase */
1917 if (sv != NULL) {
1918 XDrawLines(mainDisplay, drawWindow, revDefaultGC, sv, sn,
1919 CoordModeOrigin);
1920 free(sv);
1921 sv = NULL;
1922 }
1923 if (sv2 != NULL) {
1924 XDrawLines(mainDisplay, drawWindow, revDefaultGC, sv2, sn2,
1925 CoordModeOrigin);
1926 free(sv2);
1927 sv2 = NULL;
1928 }
1929 EraseHighLightForStretchStructSpline(&sssi, ABS_SIZE(dx), ABS_SIZE(dy),
1930 TRUE, TRUE);
1931 dx = grid_x - XGridOff;
1932 dy = grid_y - YGridOff;
1933 ruler_x = OFFSET_X(start_v.x) + dx;
1934 ruler_y = OFFSET_Y(start_v.y) + dy;
1935 MarkRulers(ruler_x, ruler_y);
1936
1937 /* draw */
1938 SetVsAndVs2ForStretchStructSpline(&sssi, ABS_SIZE(dx), ABS_SIZE(dy),
1939 &num_vs, vs, &num_vs2, vs2);
1940 FixUpSmoothAndSmooth2ForStretchStructSpline(num_vs, smooth, num_vs2,
1941 smooth2);
1942 if (sssi.prev_valid) {
1943 sv = MakeMultiSplinePolyVertex(LT_STRUCT_SPLINE, &sn, smooth,
1944 drawOrigX, drawOrigY, num_vs, vs);
1945 XDrawLines(mainDisplay, drawWindow, revDefaultGC, sv, sn,
1946 CoordModeOrigin);
1947 }
1948 if (sssi.next_valid) {
1949 sv2 = MakeMultiSplinePolyVertex(LT_STRUCT_SPLINE, &sn2, smooth2,
1950 drawOrigX, drawOrigY, num_vs2, vs2);
1951 XDrawLines(mainDisplay, drawWindow, revDefaultGC, sv2, sn2,
1952 CoordModeOrigin);
1953 }
1954 EraseHighLightForStretchStructSpline(&sssi, ABS_SIZE(dx), ABS_SIZE(dy),
1955 TRUE, TRUE);
1956 DoStretchStructSplineMeasureCursor(STRETCH_DOSHOW, &start_v,
1957 ABS_SIZE(grid_x-XGridOff), ABS_SIZE(grid_y-YGridOff),
1958 grid_x, grid_y);
1959 while (XCheckMaskEvent(mainDisplay, PointerMotionMask, &ev)) ;
1960 }
1961 }
1962 DoStretchStructSplineMeasureCursor(STRETCH_ENDSHOW, &start_v,
1963 ABS_SIZE(grid_x-XGridOff), ABS_SIZE(grid_y-YGridOff), grid_x, grid_y);
1964 /* erase */
1965 if (sv != NULL) {
1966 XDrawLines(mainDisplay, drawWindow, revDefaultGC, sv, sn,
1967 CoordModeOrigin);
1968 free(sv);
1969 sv = NULL;
1970 }
1971 if (sv2 != NULL) {
1972 XDrawLines(mainDisplay, drawWindow, revDefaultGC, sv2, sn2,
1973 CoordModeOrigin);
1974 free(sv2);
1975 sv2 = NULL;
1976 }
1977 if (saved_sv != NULL) {
1978 XDrawLines(mainDisplay, drawWindow, revDefaultGC, saved_sv, saved_sn,
1979 CoordModeOrigin);
1980 free(saved_sv);
1981 saved_sv = NULL;
1982 }
1983 if (saved_sv2 != NULL) {
1984 XDrawLines(mainDisplay, drawWindow, revDefaultGC, saved_sv2, saved_sn2,
1985 CoordModeOrigin);
1986 free(saved_sv2);
1987 saved_sv2 = NULL;
1988 }
1989 EraseHighLightForStretchStructSpline(&sssi, ABS_SIZE(dx), ABS_SIZE(dy), TRUE,
1990 TRUE);
1991 EraseHighLightForHinge(&sssi, 0, 0, FALSE, TRUE);
1992
1993 if (dx != 0 || dy != 0) {
1994 if (has_on_reshape && name_attr != NULL) {
1995 on_reshape_attr = FindAttrWithName(ObjPtr, "on_reshape=", NULL);
1996 }
1997 HighLightReverse();
1998
1999 if (on_reshape_attr != NULL) {
2000 StartCompositeCmd();
2001 }
2002 PrepareToReplaceAnObj(ObjPtr);
2003
2004 if (poly_ptr != NULL) {
2005 UpdateObjForStretchStructSpline(ObjPtr, poly_ptr->n, poly_ptr->vlist,
2006 ABS_SIZE(dx), ABS_SIZE(dy), &sssi);
2007 AdjObjSplineVs(ObjPtr);
2008 UpdPolyBBox(ObjPtr, poly_ptr->ssn, poly_ptr->ssvlist);
2009 } else if (polygon_ptr != NULL) {
2010 UpdateObjForStretchStructSpline(ObjPtr, polygon_ptr->n,
2011 polygon_ptr->vlist, ABS_SIZE(dx), ABS_SIZE(dy), &sssi);
2012 AdjObjSplineVs(ObjPtr);
2013 UpdPolyBBox(ObjPtr, polygon_ptr->ssn, polygon_ptr->ssvlist);
2014 }
2015 if (auto_center_attr) {
2016 struct AttrRec *attr_ptr=ObjPtr->fattr;
2017 int modified=FALSE;
2018
2019 for ( ; attr_ptr != NULL; attr_ptr=attr_ptr->next) {
2020 if (attr_ptr->shown) {
2021 struct BBRec bbox;
2022
2023 CenterObjInOBBox(attr_ptr->obj, ObjPtr->obbox, &bbox);
2024 if (bbox.ltx < ltx) ltx = bbox.ltx;
2025 if (bbox.lty < lty) lty = bbox.lty;
2026 if (bbox.rbx > rbx) rbx = bbox.rbx;
2027 if (bbox.rby > rby) rby = bbox.rby;
2028 modified = TRUE;
2029 }
2030 }
2031 if (modified) AdjObjBBox(ObjPtr);
2032 }
2033 RecordReplaceAnObj(ObjPtr);
2034 if (on_reshape_attr != NULL) {
2035 DoExec(on_reshape_attr, ObjPtr);
2036 }
2037 if (on_reshape_attr != NULL) {
2038 EndCompositeCmd();
2039 }
2040 UpdSelBBox();
2041 RedrawAreas(botObj, ltx-GRID_ABS_SIZE(1), lty-GRID_ABS_SIZE(1),
2042 rbx+GRID_ABS_SIZE(1), rby+GRID_ABS_SIZE(1),
2043 ObjPtr->bbox.ltx-GRID_ABS_SIZE(1),
2044 ObjPtr->bbox.lty-GRID_ABS_SIZE(1),
2045 ObjPtr->bbox.rbx+GRID_ABS_SIZE(1),
2046 ObjPtr->bbox.rby+GRID_ABS_SIZE(1));
2047 SetFileModified(TRUE);
2048 justDupped = FALSE;
2049
2050 HighLightForward();
2051 }
2052 if (sv != NULL) free(sv);
2053 if (sv2 != NULL) free(sv2);
2054 if (vlist != NULL) free(vlist);
2055 }
2056
2057 static XPoint v[5];
2058
2059 static
StretchPoly(XGridOff,YGridOff,ObjPtr,NumPts,V,Index)2060 void StretchPoly(XGridOff, YGridOff, ObjPtr, NumPts, V, Index)
2061 int XGridOff, YGridOff, NumPts, Index;
2062 IntPoint *V;
2063 struct ObjRec *ObjPtr;
2064 {
2065 struct AttrRec *name_attr=NULL, *on_reshape_attr=NULL;
2066 int i, x, y, dx, dy, stretching=TRUE;
2067 int ltx, lty, rbx, rby, curved=LT_STRAIGHT;
2068 int grid_x=XGridOff, grid_y=YGridOff, sn, intn;
2069 int auto_center_attr=AutoCenterAttr(ObjPtr);
2070 int has_on_reshape=HasOnReshape(ObjPtr, &name_attr);
2071 char *smooth=NULL;
2072 XEvent input, ev;
2073 XPoint *sv=NULL;
2074 IntPoint *pv=NULL, *cntrlv=NULL;
2075
2076 if (ObjPtr->locked) {
2077 Msg(TgLoadString(STID_LOCKED_OBJS_CANT_BE_STRETCHED));
2078 return;
2079 }
2080 pv = (IntPoint*)malloc((NumPts+1)*sizeof(IntPoint));
2081 if (pv == NULL) FailAllocMessage();
2082 memset(pv, 0, (NumPts+1)*sizeof(IntPoint));
2083
2084 switch (ObjPtr->type) {
2085 case OBJ_POLY:
2086 curved = ObjPtr->detail.p->curved;
2087 if (curved != LT_INTSPLINE && ObjPtr->detail.p->smooth != NULL) {
2088 smooth = (char*)malloc((NumPts+1)*sizeof(char));
2089 if (smooth == NULL) FailAllocMessage();
2090 }
2091 if (ObjPtr->ctm == NULL) {
2092 for (i = 0; i < NumPts; i++) {
2093 pv[i].x = V[i].x;
2094 pv[i].y = V[i].y;
2095 if (smooth != NULL) smooth[i] = ObjPtr->detail.p->smooth[i];
2096 }
2097 } else {
2098 for (i = 0; i < NumPts; i++) {
2099 int x, y;
2100
2101 TransformPointThroughCTM(V[i].x-ObjPtr->x, V[i].y-ObjPtr->y,
2102 ObjPtr->ctm, &x, &y);
2103 pv[i].x = x+ObjPtr->x;
2104 pv[i].y = y+ObjPtr->y;
2105 if (smooth != NULL) smooth[i] = ObjPtr->detail.p->smooth[i];
2106 }
2107 }
2108 switch (curved) {
2109 case LT_STRAIGHT:
2110 case LT_SPLINE:
2111 sv = MakeMultiSplinePolyVertex(curved, &sn, smooth,
2112 drawOrigX, drawOrigY, NumPts, pv);
2113 break;
2114 case LT_INTSPLINE:
2115 sv = MakeIntSplinePolyVertex(&sn, &intn, &cntrlv, drawOrigX,
2116 drawOrigY, NumPts, pv);
2117 break;
2118 }
2119 break;
2120 case OBJ_POLYGON:
2121 curved = ObjPtr->detail.g->curved;
2122 if (curved != LT_INTSPLINE && ObjPtr->detail.g->smooth != NULL) {
2123 smooth = (char*)malloc((NumPts+1)*sizeof(char));
2124 if (smooth == NULL) FailAllocMessage();
2125 }
2126 if (ObjPtr->ctm == NULL) {
2127 for (i = 0; i < NumPts; i++) {
2128 pv[i].x = V[i].x;
2129 pv[i].y = V[i].y;
2130 if (smooth != NULL) smooth[i] = ObjPtr->detail.g->smooth[i];
2131 }
2132 } else {
2133 for (i = 0; i < NumPts; i++) {
2134 int x, y;
2135
2136 TransformPointThroughCTM(V[i].x-ObjPtr->x, V[i].y-ObjPtr->y,
2137 ObjPtr->ctm, &x, &y);
2138 pv[i].x = x+ObjPtr->x;
2139 pv[i].y = y+ObjPtr->y;
2140 if (smooth != NULL) smooth[i] = ObjPtr->detail.g->smooth[i];
2141 }
2142 }
2143 switch (curved) {
2144 case LT_STRAIGHT:
2145 case LT_SPLINE:
2146 sv = MakeMultiSplinePolygonVertex(curved, &sn, smooth,
2147 drawOrigX, drawOrigY, NumPts, pv);
2148 break;
2149 case LT_INTSPLINE:
2150 sv = MakeIntSplinePolygonVertex(&sn, &intn, &cntrlv,
2151 drawOrigX, drawOrigY, NumPts, pv);
2152 break;
2153 }
2154 break;
2155 }
2156 ltx = ObjPtr->bbox.ltx;
2157 lty = ObjPtr->bbox.lty;
2158 rbx = ObjPtr->bbox.rbx;
2159 rby = ObjPtr->bbox.rby;
2160
2161 XFlush(mainDisplay);
2162 XSync(mainDisplay, False);
2163
2164 if (XCheckMaskEvent(mainDisplay, ExposureMask, &ev) ||
2165 XCheckMaskEvent(mainDisplay, VisibilityChangeMask, &ev)) {
2166 ExposeEventHandler(&ev, TRUE);
2167 }
2168 DoStretchPolyMeasureCursor(STRETCH_STARTSHOW, NumPts, pv, Index, 0, 0,
2169 STRETCH_DRAW, STRETCH_CLICK, ObjPtr->type, grid_x, grid_y);
2170 if (!debugNoPointerGrab) {
2171 XGrabPointer(mainDisplay, drawWindow, False,
2172 PointerMotionMask | ButtonReleaseMask,
2173 GrabModeAsync, GrabModeAsync, None, handCursor, CurrentTime);
2174 }
2175 dx = dy = 0;
2176 while (stretching) {
2177 XNextEvent(mainDisplay, &input);
2178
2179 if (input.type == Expose || input.type == VisibilityNotify) {
2180 ExposeEventHandler(&input, TRUE);
2181 } else if (input.type == ButtonRelease) {
2182 XUngrabPointer(mainDisplay, CurrentTime);
2183 XSync(mainDisplay, False);
2184 stretching = FALSE;
2185 } else if (input.type == MotionNotify || input.type == KeyPress ||
2186 input.type == KeyRelease) {
2187 DoStretchPolyMeasureCursor(STRETCH_DOSHOW, NumPts, pv, Index,
2188 ABS_SIZE(grid_x-XGridOff), ABS_SIZE(grid_y-YGridOff),
2189 STRETCH_ERASE, STRETCH_DRAG, ObjPtr->type, grid_x, grid_y);
2190 if (input.type == KeyPress || input.type == KeyRelease ) {
2191 x = grid_x;
2192 y = grid_y;
2193 } else {
2194 x = input.xmotion.x;
2195 y = input.xmotion.y;
2196 }
2197 if (shiftForDiagMouseMove && DiagEventCheck(&input)) {
2198 if (input.type == KeyRelease) {
2199 x = input.xkey.x;
2200 y = input.xkey.y;
2201 } else {
2202 DiagGridXY(XGridOff, YGridOff, &x, &y);
2203 }
2204 }
2205 GridXY(x, y, &grid_x, &grid_y);
2206
2207 XDrawLines(mainDisplay, drawWindow, revDefaultGC, sv, sn,
2208 CoordModeOrigin);
2209 dx = grid_x - XGridOff;
2210 dy = grid_y - YGridOff;
2211 v[1].x = OFFSET_X(V[Index].x) + dx;
2212 v[1].y = OFFSET_Y(V[Index].y) + dy;
2213 MarkRulers(v[1].x, v[1].y);
2214
2215 if (sv != NULL) {
2216 free(sv);
2217 sv = NULL;
2218 }
2219 if (ObjPtr->type==OBJ_POLYGON && (Index==0 || Index==NumPts-1)) {
2220 if (ObjPtr->ctm == NULL) {
2221 pv[0].x = pv[NumPts-1].x = V[0].x + ABS_SIZE(dx);
2222 pv[0].y = pv[NumPts-1].y = V[0].y + ABS_SIZE(dy);
2223 } else {
2224 int x, y;
2225
2226 TransformPointThroughCTM(V[0].x-ObjPtr->x, V[0].y-ObjPtr->y,
2227 ObjPtr->ctm, &x, &y);
2228 pv[0].x = pv[NumPts-1].x = x + ObjPtr->x + ABS_SIZE(dx);
2229 pv[0].y = pv[NumPts-1].y = y + ObjPtr->y + ABS_SIZE(dy);
2230 }
2231 } else {
2232 if (ObjPtr->ctm == NULL) {
2233 pv[Index].x = V[Index].x + ABS_SIZE(dx);
2234 pv[Index].y = V[Index].y + ABS_SIZE(dy);
2235 } else {
2236 int x, y;
2237
2238 TransformPointThroughCTM(V[Index].x-ObjPtr->x,
2239 V[Index].y-ObjPtr->y, ObjPtr->ctm, &x, &y);
2240 pv[Index].x = x + ObjPtr->x + ABS_SIZE(dx);
2241 pv[Index].y = y + ObjPtr->y + ABS_SIZE(dy);
2242 }
2243 }
2244 switch (ObjPtr->type) {
2245 case OBJ_POLY:
2246 switch (curved) {
2247 case LT_STRAIGHT:
2248 case LT_SPLINE:
2249 sv = MakeMultiSplinePolyVertex(curved, &sn, smooth,
2250 drawOrigX, drawOrigY, NumPts, pv);
2251 break;
2252 case LT_INTSPLINE:
2253 free(cntrlv);
2254 sv = MakeIntSplinePolyVertex(&sn, &intn, &cntrlv,
2255 drawOrigX, drawOrigY, NumPts, pv);
2256 break;
2257 }
2258 break;
2259 case OBJ_POLYGON:
2260 switch (curved) {
2261 case LT_STRAIGHT:
2262 case LT_SPLINE:
2263 sv = MakeMultiSplinePolygonVertex(curved, &sn, smooth,
2264 drawOrigX, drawOrigY, NumPts, pv);
2265 break;
2266 case LT_INTSPLINE:
2267 free(cntrlv);
2268 sv = MakeIntSplinePolygonVertex(&sn, &intn, &cntrlv,
2269 drawOrigX, drawOrigY, NumPts, pv);
2270 break;
2271 }
2272 break;
2273 }
2274 XDrawLines(mainDisplay, drawWindow, revDefaultGC, sv, sn,
2275 CoordModeOrigin);
2276 DoStretchPolyMeasureCursor(STRETCH_DOSHOW, NumPts, pv, Index,
2277 ABS_SIZE(grid_x-XGridOff), ABS_SIZE(grid_y-YGridOff),
2278 STRETCH_DRAW, STRETCH_DRAG, ObjPtr->type, grid_x, grid_y);
2279 while (XCheckMaskEvent(mainDisplay, PointerMotionMask, &ev)) ;
2280 }
2281 }
2282 DoStretchPolyMeasureCursor(STRETCH_ENDSHOW, NumPts, pv, Index,
2283 ABS_SIZE(grid_x-XGridOff), ABS_SIZE(grid_y-YGridOff),
2284 STRETCH_ERASE, STRETCH_DRAG, ObjPtr->type, grid_x, grid_y);
2285 if (dx != 0 || dy != 0) {
2286 if (has_on_reshape && name_attr != NULL) {
2287 on_reshape_attr = FindAttrWithName(ObjPtr, "on_reshape=", NULL);
2288 }
2289 XDrawLines(mainDisplay, drawWindow, revDefaultGC, sv, sn,
2290 CoordModeOrigin);
2291 HighLightReverse();
2292
2293 if (on_reshape_attr != NULL) {
2294 StartCompositeCmd();
2295 }
2296 PrepareToReplaceAnObj(ObjPtr);
2297
2298 dx = ABS_SIZE(dx);
2299 dy = ABS_SIZE(dy);
2300 switch (ObjPtr->type) {
2301 case OBJ_POLY:
2302 if (ObjPtr->ctm == NULL) {
2303 V[Index].x += dx; V[Index].y += dy;
2304 } else {
2305 int x, y, new_x, new_y;
2306
2307 TransformPointThroughCTM(V[Index].x-ObjPtr->x,
2308 V[Index].y-ObjPtr->y, ObjPtr->ctm, &x, &y);
2309 x += ObjPtr->x + dx;
2310 y += ObjPtr->y + dy;
2311 ReverseTransformPointThroughCTM(x-ObjPtr->x, y-ObjPtr->y,
2312 ObjPtr->ctm, &new_x, &new_y);
2313 V[Index].x = new_x + ObjPtr->x;
2314 V[Index].y = new_y + ObjPtr->y;
2315 }
2316 AdjObjSplineVs(ObjPtr);
2317 if (ObjPtr->detail.p->curved != LT_INTSPLINE) {
2318 UpdPolyBBox(ObjPtr, NumPts, V);
2319 } else {
2320 UpdPolyBBox(ObjPtr, ObjPtr->detail.p->intn,
2321 ObjPtr->detail.p->intvlist);
2322 }
2323 break;
2324 case OBJ_POLYGON:
2325 if (ObjPtr->ctm == NULL) {
2326 V[Index].x += dx; V[Index].y += dy;
2327 } else {
2328 int x, y, new_x, new_y;
2329
2330 TransformPointThroughCTM(V[Index].x-ObjPtr->x,
2331 V[Index].y-ObjPtr->y, ObjPtr->ctm, &x, &y);
2332 x += ObjPtr->x + dx;
2333 y += ObjPtr->y + dy;
2334 ReverseTransformPointThroughCTM(x-ObjPtr->x, y-ObjPtr->y,
2335 ObjPtr->ctm, &new_x, &new_y);
2336 V[Index].x = new_x + ObjPtr->x;
2337 V[Index].y = new_y + ObjPtr->y;
2338 }
2339 if (Index == 0) {
2340 V[NumPts-1].x = V[Index].x; V[NumPts-1].y = V[Index].y;
2341 } else if (Index == NumPts-1) {
2342 V[0].x = V[Index].x; V[0].y = V[Index].y;
2343 }
2344 AdjObjSplineVs(ObjPtr);
2345 if (ObjPtr->detail.g->curved != LT_INTSPLINE) {
2346 UpdPolyBBox(ObjPtr, NumPts, V);
2347 } else {
2348 UpdPolyBBox(ObjPtr, ObjPtr->detail.g->intn,
2349 ObjPtr->detail.g->intvlist);
2350 }
2351 break;
2352 }
2353 if (auto_center_attr) {
2354 struct AttrRec *attr_ptr=ObjPtr->fattr;
2355 int modified=FALSE;
2356
2357 for ( ; attr_ptr != NULL; attr_ptr=attr_ptr->next) {
2358 if (attr_ptr->shown) {
2359 struct BBRec bbox;
2360
2361 CenterObjInOBBox(attr_ptr->obj, ObjPtr->obbox, &bbox);
2362 if (bbox.ltx < ltx) ltx = bbox.ltx;
2363 if (bbox.lty < lty) lty = bbox.lty;
2364 if (bbox.rbx > rbx) rbx = bbox.rbx;
2365 if (bbox.rby > rby) rby = bbox.rby;
2366 modified = TRUE;
2367 }
2368 }
2369 if (modified) AdjObjBBox(ObjPtr);
2370 }
2371 RecordReplaceAnObj(ObjPtr);
2372 if (on_reshape_attr != NULL) {
2373 DoExec(on_reshape_attr, ObjPtr);
2374 }
2375 if (on_reshape_attr != NULL) {
2376 EndCompositeCmd();
2377 }
2378 UpdSelBBox();
2379 RedrawAreas(botObj, ltx-GRID_ABS_SIZE(1), lty-GRID_ABS_SIZE(1),
2380 rbx+GRID_ABS_SIZE(1), rby+GRID_ABS_SIZE(1),
2381 ObjPtr->bbox.ltx-GRID_ABS_SIZE(1),
2382 ObjPtr->bbox.lty-GRID_ABS_SIZE(1),
2383 ObjPtr->bbox.rbx+GRID_ABS_SIZE(1),
2384 ObjPtr->bbox.rby+GRID_ABS_SIZE(1));
2385 SetFileModified(TRUE);
2386 justDupped = FALSE;
2387
2388 HighLightForward();
2389 }
2390 free(pv);
2391 if (sv != NULL) free(sv);
2392 if (smooth != NULL) free(smooth);
2393 if (curved == LT_INTSPLINE && cntrlv != NULL) free(cntrlv);
2394 }
2395
2396 static double multX=(double)0.0, multY=(double)0.0;
2397 static int pivotX=0, pivotY=0, changeX=0, changeY=0, moveX=0, moveY=0;
2398 static int absPivotX=0, absPivotY=0;
2399
2400 static
StretchedXY(X,Y,NewX,NewY)2401 void StretchedXY(X, Y, NewX, NewY)
2402 int X, Y, * NewX, * NewY; /* screen offsets */
2403 {
2404 register int dx, dy;
2405
2406 dx = round((double)((double)(X - pivotX) * multX));
2407 dy = round((double)((double)(Y - pivotY) * multY));
2408 *NewX = pivotX + dx;
2409 *NewY = pivotY + dy;
2410 }
2411
2412 static
StretchedAbsXY(X,Y,NewX,NewY)2413 void StretchedAbsXY(X, Y, NewX, NewY)
2414 int X, Y, * NewX, * NewY; /* screen offsets */
2415 {
2416 register int dx, dy;
2417
2418 dx = round((double)((double)(X - absPivotX) * multX));
2419 dy = round((double)((double)(Y - absPivotY) * multY));
2420 *NewX = absPivotX + dx;
2421 *NewY = absPivotY + dy;
2422 }
2423
2424 static
ShearedXY(Corner,x,y,dx_shear,dy_shear,dx_scale,dy_scale,new_x,new_y)2425 void ShearedXY(Corner, x, y, dx_shear, dy_shear, dx_scale, dy_scale,
2426 new_x, new_y)
2427 int Corner, x, y, *new_x, *new_y;
2428 double dx_shear, dy_shear, dx_scale, dy_scale;
2429 {
2430 double val, dx, dy;
2431
2432 if (Corner != CORNER_NONE && Corner != CORNER_RIGHT &&
2433 Corner != CORNER_LEFT) {
2434 if (y == pivotY) {
2435 *new_x = x;
2436 *new_y = y;
2437 } else {
2438 dy = ((double)(y-pivotY))*dy_scale/1000.0;
2439 val = tan(dx_shear/1000.0)*dy;
2440 *new_x = round(val + x);
2441 *new_y = round(dy + pivotY);
2442 }
2443 }
2444 if (Corner != CORNER_NONE && Corner != CORNER_TOP &&
2445 Corner != CORNER_BOTTOM) {
2446 if (x == pivotX) {
2447 *new_x = x;
2448 *new_y = y;
2449 } else {
2450 dx = ((double)(x-pivotX))*dx_scale/1000.0;
2451 val = tan(dy_shear/1000.0)*dx;
2452 *new_x = round(dx + pivotX);
2453 *new_y = round(val + y);
2454 }
2455 }
2456 }
2457
2458 static
ShearedAbsXY(Corner,abs_x,abs_y,dx_shear,dy_shear,dx_scale,dy_scale,new_x,new_y)2459 void ShearedAbsXY(Corner, abs_x, abs_y, dx_shear, dy_shear, dx_scale, dy_scale,
2460 new_x, new_y)
2461 int Corner, abs_x, abs_y, *new_x, *new_y;
2462 double dx_shear, dy_shear, dx_scale, dy_scale;
2463 {
2464 double val, dx, dy;
2465
2466 if (Corner != CORNER_NONE && Corner != CORNER_RIGHT &&
2467 Corner != CORNER_LEFT) {
2468 if (abs_y == absPivotY) {
2469 *new_x = abs_x;
2470 *new_y = abs_y;
2471 } else {
2472 dy = ((double)(abs_y-absPivotY))*dy_scale/1000.0;
2473 val = tan(dx_shear/1000.0)*dy;
2474 *new_x = round(val + abs_x);
2475 *new_y = round(dy + absPivotY);
2476 }
2477 }
2478 if (Corner != CORNER_NONE && Corner != CORNER_TOP &&
2479 Corner != CORNER_BOTTOM) {
2480 if (abs_x == absPivotX) {
2481 *new_x = abs_x;
2482 *new_y = abs_y;
2483 } else {
2484 dx = ((double)(abs_x-absPivotX))*dx_scale/1000.0;
2485 val = tan(dy_shear/1000.0)*dx;
2486 *new_x = round(dx + absPivotX);
2487 *new_y = round(val + abs_y);
2488 }
2489 }
2490 }
2491
2492 static
SetPivot(Corner,pOBBox)2493 void SetPivot(Corner, pOBBox)
2494 int Corner;
2495 struct BBRec *pOBBox;
2496 /* pivotX, pivotY, moveX, moveY will be set to screen offsets */
2497 {
2498 switch (Corner) {
2499 case CORNER_NONE: /* same as CORNER_CC */
2500 pivotX = moveX = ((pOBBox->ltx+pOBBox->rbx)>>1);
2501 pivotY = moveY = ((pOBBox->lty+pOBBox->rby)>>1);
2502 changeX = TRUE; changeY = TRUE;
2503 break;
2504 case CORNER_LT:
2505 pivotX = pOBBox->rbx; pivotY = pOBBox->rby;
2506 moveX = pOBBox->ltx; moveY = pOBBox->lty;
2507 changeX = changeY = TRUE;
2508 break;
2509 case CORNER_TOP:
2510 pivotX = moveX = ((pOBBox->ltx+pOBBox->rbx)>>1); pivotY = pOBBox->rby;
2511 moveY = pOBBox->lty;
2512 changeX = FALSE; changeY = TRUE;
2513 break;
2514 case CORNER_RT:
2515 pivotX = pOBBox->ltx; pivotY = pOBBox->rby;
2516 moveX = pOBBox->rbx; moveY = pOBBox->lty;
2517 changeX = changeY = TRUE;
2518 break;
2519 case CORNER_RIGHT:
2520 pivotX = pOBBox->ltx; pivotY = moveY = ((pOBBox->lty+pOBBox->rby)>>1);
2521 moveX = pOBBox->rbx;
2522 changeX = TRUE; changeY = FALSE;
2523 break;
2524 case CORNER_RB:
2525 pivotX = pOBBox->ltx; pivotY = pOBBox->lty;
2526 moveX = pOBBox->rbx; moveY = pOBBox->rby;
2527 changeX = changeY = TRUE;
2528 break;
2529 case CORNER_BOTTOM:
2530 pivotX = moveX = ((pOBBox->ltx+pOBBox->rbx)>>1); pivotY = pOBBox->lty;
2531 moveY = pOBBox->rby;
2532 changeX = FALSE; changeY = TRUE;
2533 break;
2534 case CORNER_LB:
2535 pivotX = pOBBox->rbx; pivotY = pOBBox->lty;
2536 moveX = pOBBox->ltx; moveY = pOBBox->rby;
2537 changeX = changeY = TRUE;
2538 break;
2539 case CORNER_LEFT:
2540 pivotX = pOBBox->rbx; pivotY = moveY = ((pOBBox->lty+pOBBox->rby)>>1);
2541 moveX = pOBBox->ltx;
2542 changeX = TRUE; changeY = FALSE;
2543 break;
2544 }
2545 multX = 1.0;
2546 multY = 1.0;
2547 absPivotX = pivotX;
2548 absPivotY = pivotY;
2549 pivotX = OFFSET_X(absPivotX);
2550 pivotY = OFFSET_Y(absPivotY);
2551 moveX = OFFSET_X(moveX);
2552 moveY = OFFSET_Y(moveY);
2553 }
2554
ShearObj(ObjPtr,Corner,dxShear,dyShear,dxScale,dyScale,RealLtX,RealLtY)2555 void ShearObj(ObjPtr, Corner, dxShear, dyShear, dxScale, dyScale,
2556 RealLtX, RealLtY)
2557 struct ObjRec *ObjPtr;
2558 int Corner;
2559 double dxShear, dyShear, dxScale, dyScale; /* scaled by 1000 */
2560 int *RealLtX, *RealLtY;
2561 {
2562 IntPoint abs_obj_obbox_vs[5];
2563 int x, y, new_ltx, new_lty, new_rbx, new_rby;
2564 double tan_val;
2565 struct XfrmMtrxRec ctm, new_ctm;
2566 struct ObjRec *obj_ptr;
2567 struct AttrRec *attr_ptr;
2568 int auto_center_attr=AutoCenterAttr(ObjPtr);
2569
2570 switch (ObjPtr->type) {
2571 case OBJ_GROUP:
2572 case OBJ_ICON:
2573 case OBJ_SYM:
2574 case OBJ_PIN:
2575 for (obj_ptr=ObjPtr->detail.r->first; obj_ptr != NULL;
2576 obj_ptr=obj_ptr->next) {
2577 ShearObj(obj_ptr, Corner, dxShear, dyShear, dxScale, dyScale,
2578 RealLtX, RealLtY);
2579 }
2580 break;
2581
2582 default:
2583 if (ObjPtr->ctm == NULL) {
2584 memcpy(&ObjPtr->orig_obbox, &ObjPtr->obbox, sizeof(struct BBRec));
2585 if (ObjPtr->type == OBJ_TEXT) {
2586 memcpy(&ObjPtr->detail.t->orig_bbox, &ObjPtr->bbox,
2587 sizeof(struct BBRec));
2588 }
2589 ObjPtr->ctm = (struct XfrmMtrxRec *)malloc(sizeof(struct XfrmMtrxRec));
2590 if (ObjPtr->ctm == NULL) FailAllocMessage();
2591 ObjPtr->ctm->m[CTM_SX] = ObjPtr->ctm->m[CTM_SY] = (double)1000;
2592 ObjPtr->ctm->m[CTM_SIN] = ObjPtr->ctm->m[CTM_MSIN] = (double)0;
2593 ObjPtr->ctm->t[CTM_TX] = ObjPtr->ctm->t[CTM_TY] = 0;
2594 }
2595 ShearedAbsXY(Corner, ObjPtr->x+ObjPtr->ctm->t[CTM_TX],
2596 ObjPtr->y+ObjPtr->ctm->t[CTM_TY], dxShear, dyShear,
2597 dxScale, dyScale, &x, &y);
2598 switch (Corner) {
2599 case CORNER_TOP:
2600 case CORNER_BOTTOM:
2601 tan_val = tan(dxShear/1000.0);
2602 ctm.m[CTM_SX] = (double)1000;
2603 ctm.m[CTM_SY] = dyScale;
2604 ctm.m[CTM_SIN] = (double)0;
2605 ctm.m[CTM_MSIN] = dyScale*tan_val;
2606 break;
2607 case CORNER_RIGHT:
2608 case CORNER_LEFT:
2609 tan_val = tan(dyShear/1000.0);
2610 ctm.m[CTM_SX] = dxScale;
2611 ctm.m[CTM_SY] = (double)1000;
2612 ctm.m[CTM_SIN] = dxScale*tan_val;
2613 ctm.m[CTM_MSIN] = (double)0;
2614 break;
2615 default:
2616 ctm.m[CTM_SX] = dxScale;
2617 ctm.m[CTM_SY] = dyScale;
2618 ctm.m[CTM_SIN] = (double)0;
2619 ctm.m[CTM_MSIN] = (double)0;
2620 break;
2621 }
2622 ctm.t[CTM_TX] = 0;
2623 ctm.t[CTM_TY] = 0;
2624 ConcatCTM(ObjPtr->ctm, &ctm, &new_ctm);
2625 new_ctm.t[CTM_TX] = x-ObjPtr->x;
2626 new_ctm.t[CTM_TY] = y-ObjPtr->y;
2627 memcpy(ObjPtr->ctm, &new_ctm, sizeof(struct XfrmMtrxRec));
2628
2629 GetTransformedOBBoxAbsVs(ObjPtr, abs_obj_obbox_vs);
2630
2631 new_ltx = min(min(abs_obj_obbox_vs[0].x,abs_obj_obbox_vs[1].x),
2632 min(abs_obj_obbox_vs[2].x,abs_obj_obbox_vs[3].x));
2633 new_rbx = max(max(abs_obj_obbox_vs[0].x,abs_obj_obbox_vs[1].x),
2634 max(abs_obj_obbox_vs[2].x,abs_obj_obbox_vs[3].x));
2635 new_lty = min(min(abs_obj_obbox_vs[0].y,abs_obj_obbox_vs[1].y),
2636 min(abs_obj_obbox_vs[2].y,abs_obj_obbox_vs[3].y));
2637 new_rby = max(max(abs_obj_obbox_vs[0].y,abs_obj_obbox_vs[1].y),
2638 max(abs_obj_obbox_vs[2].y,abs_obj_obbox_vs[3].y));
2639
2640 ObjPtr->obbox.ltx = new_ltx; ObjPtr->obbox.lty = new_lty;
2641 ObjPtr->obbox.rbx = new_rbx; ObjPtr->obbox.rby = new_rby;
2642 if (RealLtX != NULL && RealLtY != NULL) {
2643 MoveObj(ObjPtr, (*RealLtX)-new_ltx, (*RealLtY)-new_lty);
2644 }
2645 if (ObjPtr->ctm->m[CTM_SX] >= 999.0 &&
2646 ObjPtr->ctm->m[CTM_SX] <= 1001.0 &&
2647 ObjPtr->ctm->m[CTM_SY] >= 999.0 &&
2648 ObjPtr->ctm->m[CTM_SY] <= 1001.0 &&
2649 ObjPtr->ctm->m[CTM_SIN] >= (-1.0) &&
2650 ObjPtr->ctm->m[CTM_SIN] <= 1.0 &&
2651 ObjPtr->ctm->m[CTM_MSIN] >= (-1.0) &&
2652 ObjPtr->ctm->m[CTM_MSIN] <= 1.0) {
2653 int dx=ObjPtr->ctm->t[CTM_TX], dy=ObjPtr->ctm->t[CTM_TY];
2654
2655 free(ObjPtr->ctm);
2656 ObjPtr->ctm = NULL;
2657
2658 memcpy(&ObjPtr->obbox, &ObjPtr->orig_obbox, sizeof(struct BBRec));
2659 if (ObjPtr->type == OBJ_TEXT) {
2660 memcpy(&ObjPtr->bbox, &ObjPtr->detail.t->orig_bbox,
2661 sizeof(struct BBRec));
2662 }
2663 MoveObj(ObjPtr, dx, dy);
2664 }
2665 break;
2666 }
2667 AdjObjOBBox(ObjPtr);
2668 if (auto_center_attr) {
2669 for (attr_ptr=ObjPtr->fattr; attr_ptr != NULL; attr_ptr=attr_ptr->next) {
2670 ShearObj(attr_ptr->obj, Corner, dxShear, dyShear, dxScale, dyScale,
2671 NULL, NULL);
2672 if (attr_ptr->shown) {
2673 CenterObjInOBBox(attr_ptr->obj, ObjPtr->obbox, NULL);
2674 }
2675 }
2676 } else {
2677 for (attr_ptr=ObjPtr->fattr; attr_ptr != NULL; attr_ptr=attr_ptr->next) {
2678 ShearObj(attr_ptr->obj, Corner, dxShear, dyShear, dxScale, dyScale,
2679 NULL, NULL);
2680 }
2681 }
2682 AdjObjSplineVs(ObjPtr);
2683 AdjObjCache(ObjPtr);
2684 AdjObjBBox(ObjPtr);
2685 }
2686
2687 static
StretchSimpleText(ObjPtr,Corner)2688 void StretchSimpleText(ObjPtr, Corner)
2689 struct ObjRec *ObjPtr;
2690 int Corner;
2691 {
2692 /* !stretchableText */
2693 if (ObjPtr->ctm == NULL) {
2694 int new_x, new_y, h=ABS_SIZE(ObjPtr->obbox.rby-ObjPtr->obbox.lty);
2695
2696 StretchedAbsXY(ObjPtr->x, ObjPtr->y, &new_x, &new_y);
2697 MoveObj(ObjPtr, new_x-ObjPtr->x, new_y-ObjPtr->y);
2698 ObjPtr->x = new_x;
2699 ObjPtr->y = new_y;
2700 if (multX < 0) {
2701 ObjPtr->detail.t->minilines.just =
2702 MAXJUSTS-1-ObjPtr->detail.t->minilines.just;
2703 }
2704 if (multY < 0) {
2705 MoveObj(ObjPtr, 0, -h);
2706 }
2707 } else {
2708 int abs_x, abs_y, new_x, new_y;
2709
2710 abs_x = ObjPtr->x+ObjPtr->ctm->t[CTM_TX];
2711 abs_y = ObjPtr->y+ObjPtr->ctm->t[CTM_TY];
2712 StretchedAbsXY(abs_x, abs_y, &new_x, &new_y);
2713 if (multX < 0.0 || multY < 0.0) {
2714 int new_ltx, new_lty, new_rbx, new_rby;
2715 IntPoint abs_obj_obbox_vs[5];
2716 struct XfrmMtrxRec ctm, new_ctm;
2717
2718 ctm.m[CTM_SX] = ctm.m[CTM_SY] = (double)1000;
2719 ctm.m[CTM_SIN] = ctm.m[CTM_MSIN] = (double)0;
2720 ctm.t[CTM_TX] = ctm.t[CTM_TY] = 0;
2721 ctm.m[CTM_SX] = (multX < 0.0) ? (double)(-1000) : (double)1000;
2722 ctm.m[CTM_SY] = (multY < 0.0) ? (double)(-1000) : (double)1000;
2723 ConcatCTM(ObjPtr->ctm, &ctm, &new_ctm);
2724 new_ctm.t[CTM_TX] = new_x-ObjPtr->x;
2725 new_ctm.t[CTM_TY] = new_y-ObjPtr->y;
2726 memcpy(ObjPtr->ctm, &new_ctm, sizeof(struct XfrmMtrxRec));
2727
2728 GetTransformedOBBoxAbsVs(ObjPtr, abs_obj_obbox_vs);
2729
2730 new_ltx = min(min(abs_obj_obbox_vs[0].x,abs_obj_obbox_vs[1].x),
2731 min(abs_obj_obbox_vs[2].x,abs_obj_obbox_vs[3].x));
2732 new_rbx = max(max(abs_obj_obbox_vs[0].x,abs_obj_obbox_vs[1].x),
2733 max(abs_obj_obbox_vs[2].x,abs_obj_obbox_vs[3].x));
2734 new_lty = min(min(abs_obj_obbox_vs[0].y,abs_obj_obbox_vs[1].y),
2735 min(abs_obj_obbox_vs[2].y,abs_obj_obbox_vs[3].y));
2736 new_rby = max(max(abs_obj_obbox_vs[0].y,abs_obj_obbox_vs[1].y),
2737 max(abs_obj_obbox_vs[2].y,abs_obj_obbox_vs[3].y));
2738
2739 ObjPtr->obbox.ltx = new_ltx; ObjPtr->obbox.lty = new_lty;
2740 ObjPtr->obbox.rbx = new_rbx; ObjPtr->obbox.rby = new_rby;
2741 abs_x = ObjPtr->x+ObjPtr->ctm->t[CTM_TX];
2742 abs_y = ObjPtr->y+ObjPtr->ctm->t[CTM_TY];
2743 }
2744 MoveObj(ObjPtr, new_x-abs_x, new_y-abs_y);
2745 }
2746 UpdTextBBox(ObjPtr);
2747 AdjObjSplineVs(ObjPtr);
2748 AdjObjBBox(ObjPtr);
2749 }
2750
2751 static
CompoundObjHasTextSubObj(ObjPtr)2752 int CompoundObjHasTextSubObj(ObjPtr)
2753 struct ObjRec *ObjPtr;
2754 {
2755 struct ObjRec *sub_obj=ObjPtr->detail.r->last;
2756
2757 for ( ; sub_obj != NULL; sub_obj=sub_obj->prev) {
2758 if (sub_obj->type == OBJ_GROUP ||
2759 sub_obj->type == OBJ_ICON ||
2760 sub_obj->type == OBJ_SYM ||
2761 sub_obj->type == OBJ_PIN) {
2762 if (CompoundObjHasTextSubObj(sub_obj)) {
2763 return TRUE;
2764 }
2765 } else {
2766 return (sub_obj->type == OBJ_TEXT);
2767 }
2768 }
2769 return FALSE;
2770 }
2771
2772 static
JustMoveSimpleCompoundObj(ObjPtr,Corner)2773 void JustMoveSimpleCompoundObj(ObjPtr, Corner)
2774 struct ObjRec *ObjPtr;
2775 int Corner;
2776 {
2777 /* !stretchableText && !compoundObjWithTextStretchableForPSE */
2778 if (ObjPtr->ctm == NULL) {
2779 int new_x, new_y, h=ABS_SIZE(ObjPtr->obbox.rby-ObjPtr->obbox.lty);
2780
2781 StretchedAbsXY(ObjPtr->x, ObjPtr->y, &new_x, &new_y);
2782 MoveObj(ObjPtr, new_x-ObjPtr->x, new_y-ObjPtr->y);
2783 ObjPtr->x = new_x;
2784 ObjPtr->y = new_y;
2785 if (multY < 0) {
2786 MoveObj(ObjPtr, 0, -h);
2787 }
2788 } else {
2789 int abs_x, abs_y, new_x, new_y;
2790
2791 abs_x = ObjPtr->x+ObjPtr->ctm->t[CTM_TX];
2792 abs_y = ObjPtr->y+ObjPtr->ctm->t[CTM_TY];
2793 StretchedAbsXY(abs_x, abs_y, &new_x, &new_y);
2794 if (multX < 0.0 || multY < 0.0) {
2795 int new_ltx, new_lty, new_rbx, new_rby;
2796 IntPoint abs_obj_obbox_vs[5];
2797 struct XfrmMtrxRec ctm, new_ctm;
2798
2799 ctm.m[CTM_SX] = ctm.m[CTM_SY] = (double)1000;
2800 ctm.m[CTM_SIN] = ctm.m[CTM_MSIN] = (double)0;
2801 ctm.t[CTM_TX] = ctm.t[CTM_TY] = 0;
2802 ctm.m[CTM_SX] = (multX < 0.0) ? (double)(-1000) : (double)1000;
2803 ctm.m[CTM_SY] = (multY < 0.0) ? (double)(-1000) : (double)1000;
2804 ConcatCTM(ObjPtr->ctm, &ctm, &new_ctm);
2805 new_ctm.t[CTM_TX] = new_x-ObjPtr->x;
2806 new_ctm.t[CTM_TY] = new_y-ObjPtr->y;
2807 memcpy(ObjPtr->ctm, &new_ctm, sizeof(struct XfrmMtrxRec));
2808
2809 GetTransformedOBBoxAbsVs(ObjPtr, abs_obj_obbox_vs);
2810
2811 new_ltx = min(min(abs_obj_obbox_vs[0].x,abs_obj_obbox_vs[1].x),
2812 min(abs_obj_obbox_vs[2].x,abs_obj_obbox_vs[3].x));
2813 new_rbx = max(max(abs_obj_obbox_vs[0].x,abs_obj_obbox_vs[1].x),
2814 max(abs_obj_obbox_vs[2].x,abs_obj_obbox_vs[3].x));
2815 new_lty = min(min(abs_obj_obbox_vs[0].y,abs_obj_obbox_vs[1].y),
2816 min(abs_obj_obbox_vs[2].y,abs_obj_obbox_vs[3].y));
2817 new_rby = max(max(abs_obj_obbox_vs[0].y,abs_obj_obbox_vs[1].y),
2818 max(abs_obj_obbox_vs[2].y,abs_obj_obbox_vs[3].y));
2819
2820 ObjPtr->obbox.ltx = new_ltx; ObjPtr->obbox.lty = new_lty;
2821 ObjPtr->obbox.rbx = new_rbx; ObjPtr->obbox.rby = new_rby;
2822 abs_x = ObjPtr->x+ObjPtr->ctm->t[CTM_TX];
2823 abs_y = ObjPtr->y+ObjPtr->ctm->t[CTM_TY];
2824 }
2825 MoveObj(ObjPtr, new_x-abs_x, new_y-abs_y);
2826 }
2827 AdjObjSplineVs(ObjPtr);
2828 AdjObjBBox(ObjPtr);
2829 }
2830
2831 static
StretchAttr(ObjPtr,Corner,dxScale,dyScale,AutoCenterAttr)2832 void StretchAttr(ObjPtr, Corner, dxScale, dyScale, AutoCenterAttr)
2833 struct ObjRec *ObjPtr;
2834 int Corner, AutoCenterAttr;
2835 double dxScale, dyScale;
2836 {
2837 struct AttrRec *attr_ptr=ObjPtr->fattr;
2838
2839 if (attr_ptr == NULL) return;
2840
2841 if (stretchingEverything) {
2842 struct BBRec final_obbox;
2843 double dz=(double)0;
2844
2845 if (AutoCenterAttr) {
2846 for (attr_ptr=ObjPtr->fattr; attr_ptr != NULL;
2847 attr_ptr=attr_ptr->next) {
2848 struct ObjRec *obj_ptr=attr_ptr->obj;
2849 int ltx=0, lty=0, rbx=0, rby=0;
2850
2851 StretchedAbsXY(obj_ptr->obbox.ltx, obj_ptr->obbox.lty, <x, <y);
2852 StretchedAbsXY(obj_ptr->obbox.rbx, obj_ptr->obbox.rby, &rbx, &rby);
2853 CalcBBox(ltx, lty, rbx, rby, &final_obbox.ltx, &final_obbox.lty,
2854 &final_obbox.rbx, &final_obbox.rby);
2855
2856 ShearObj(attr_ptr->obj, Corner, dz, dz, dxScale, dyScale,
2857 &final_obbox.ltx, &final_obbox.lty);
2858 if (attr_ptr->shown) {
2859 CenterObjInOBBox(attr_ptr->obj, ObjPtr->obbox, NULL);
2860 }
2861 }
2862 } else {
2863 for (attr_ptr=ObjPtr->fattr; attr_ptr != NULL;
2864 attr_ptr=attr_ptr->next) {
2865 struct ObjRec *obj_ptr=attr_ptr->obj;
2866 int ltx=0, lty=0, rbx=0, rby=0;
2867
2868 StretchedAbsXY(obj_ptr->obbox.ltx, obj_ptr->obbox.lty, <x, <y);
2869 StretchedAbsXY(obj_ptr->obbox.rbx, obj_ptr->obbox.rby, &rbx, &rby);
2870 CalcBBox(ltx, lty, rbx, rby, &final_obbox.ltx, &final_obbox.lty,
2871 &final_obbox.rbx, &final_obbox.rby);
2872
2873 ShearObj(obj_ptr, Corner, dz, dz, dxScale, dyScale,
2874 &final_obbox.ltx, &final_obbox.lty);
2875 }
2876 }
2877 } else {
2878 if (AutoCenterAttr) {
2879 for (attr_ptr=ObjPtr->fattr; attr_ptr != NULL;
2880 attr_ptr=attr_ptr->next) {
2881 if (attr_ptr->shown) {
2882 CenterObjInOBBox(attr_ptr->obj, ObjPtr->obbox, NULL);
2883 } else {
2884 StretchSimpleText(attr_ptr->obj, Corner);
2885 }
2886 }
2887 } else {
2888 for (attr_ptr=ObjPtr->fattr; attr_ptr != NULL;
2889 attr_ptr=attr_ptr->next) {
2890 StretchSimpleText(attr_ptr->obj, Corner);
2891 }
2892 }
2893 }
2894 }
2895
2896 static
StretchSimpleArc(ObjPtr)2897 void StretchSimpleArc(ObjPtr)
2898 struct ObjRec *ObjPtr;
2899 {
2900 struct ArcRec *arc_ptr=ObjPtr->detail.a;
2901 int x, y;
2902
2903 StretchedAbsXY(arc_ptr->xc, arc_ptr->yc, &x, &y);
2904 arc_ptr->xc = ObjPtr->x = x;
2905 arc_ptr->yc = ObjPtr->y = y;
2906 StretchedAbsXY(arc_ptr->x1, arc_ptr->y1, &x, &y);
2907 arc_ptr->x1 = x;
2908 arc_ptr->y1 = y;
2909 StretchedAbsXY(arc_ptr->x2, arc_ptr->y2, &x, &y);
2910 arc_ptr->x2 = x;
2911 arc_ptr->y2 = y;
2912 StretchedAbsXY(arc_ptr->ltx, arc_ptr->lty, &x, &y);
2913 arc_ptr->ltx = arc_ptr->xc-abs(x-arc_ptr->xc);
2914 arc_ptr->lty = arc_ptr->yc-abs(y-arc_ptr->yc);
2915 arc_ptr->w = (arc_ptr->xc-arc_ptr->ltx)<<1;
2916 arc_ptr->h = (arc_ptr->yc-arc_ptr->lty)<<1;
2917
2918 if (multX < 0) {
2919 arc_ptr->dir = !(arc_ptr->dir);
2920 arc_ptr->angle2 = -(arc_ptr->angle2);
2921 if (arc_ptr->angle1 > 0) {
2922 arc_ptr->angle1 = (180*64) - arc_ptr->angle1;
2923 } else {
2924 arc_ptr->angle1 = (-180*64) - arc_ptr->angle1;
2925 }
2926 }
2927 if (multY < 0) {
2928 arc_ptr->dir = !(arc_ptr->dir);
2929 arc_ptr->angle1 = -(arc_ptr->angle1);
2930 arc_ptr->angle2 = -(arc_ptr->angle2);
2931 }
2932 AdjObjSplineVs(ObjPtr);
2933 AdjObjBBox(ObjPtr);
2934 }
2935
2936 static
StretchSimplePoly(ObjPtr)2937 void StretchSimplePoly(ObjPtr)
2938 struct ObjRec *ObjPtr;
2939 {
2940 int i, ltx=0, lty=0, rbx=0, rby=0;
2941 struct PolyRec *poly_ptr= ObjPtr->detail.p;
2942 IntPoint *vs=poly_ptr->vlist;
2943
2944 for (i = 0; i < poly_ptr->n; i++) {
2945 int x, y;
2946
2947 StretchedAbsXY(vs[i].x, vs[i].y, &x, &y);
2948 vs[i].x = x;
2949 vs[i].y = y;
2950 if (i == 0) {
2951 ltx = rbx = x;
2952 lty = rby = y;
2953 } else {
2954 if (x < ltx) ltx = x; if (y < lty) lty = y;
2955 if (x > rbx) rbx = x; if (y > rby) rby = y;
2956 }
2957 }
2958 ObjPtr->obbox.ltx = ObjPtr->x = ltx;
2959 ObjPtr->obbox.lty = ObjPtr->y = lty;
2960 ObjPtr->obbox.rbx = rbx;
2961 ObjPtr->obbox.rby = rby;
2962 AdjObjSplineVs(ObjPtr);
2963 if (poly_ptr->curved == LT_INTSPLINE) {
2964 UpdPolyBBox(ObjPtr, poly_ptr->intn, poly_ptr->intvlist);
2965 }
2966 }
2967
2968 static
StretchSimplePolygon(ObjPtr)2969 void StretchSimplePolygon(ObjPtr)
2970 struct ObjRec *ObjPtr;
2971 {
2972 int i, ltx=0, lty=0, rbx=0, rby=0;
2973 struct PolygonRec *polygon_ptr= ObjPtr->detail.g;
2974 IntPoint *vs=polygon_ptr->vlist;
2975
2976 for (i = 0; i < polygon_ptr->n; i++) {
2977 int x, y;
2978
2979 StretchedAbsXY(vs[i].x, vs[i].y, &x, &y);
2980 vs[i].x = x;
2981 vs[i].y = y;
2982 if (i == 0) {
2983 ltx = rbx = x;
2984 lty = rby = y;
2985 } else {
2986 if (x < ltx) ltx = x; if (y < lty) lty = y;
2987 if (x > rbx) rbx = x; if (y > rby) rby = y;
2988 }
2989 }
2990 ObjPtr->obbox.ltx = ObjPtr->x = ltx;
2991 ObjPtr->obbox.lty = ObjPtr->y = lty;
2992 ObjPtr->obbox.rbx = rbx;
2993 ObjPtr->obbox.rby = rby;
2994 AdjObjSplineVs(ObjPtr);
2995 if (polygon_ptr->curved == LT_INTSPLINE) {
2996 UpdPolyBBox(ObjPtr, polygon_ptr->intn, polygon_ptr->intvlist);
2997 }
2998 }
2999
3000 static
StretchSimpleObj(ObjPtr,Corner,dxScale,dyScale,FinalOBBox,auto_center_attr)3001 void StretchSimpleObj(ObjPtr, Corner, dxScale, dyScale, FinalOBBox,
3002 auto_center_attr)
3003 struct ObjRec *ObjPtr;
3004 int Corner, auto_center_attr;
3005 double dxScale, dyScale;
3006 struct BBRec *FinalOBBox;
3007 {
3008 ObjPtr->obbox.ltx = ObjPtr->x = FinalOBBox->ltx;
3009 ObjPtr->obbox.lty = ObjPtr->y = FinalOBBox->lty;
3010 ObjPtr->obbox.rbx = FinalOBBox->rbx;
3011 ObjPtr->obbox.rby = FinalOBBox->rby;
3012
3013 switch (ObjPtr->type) {
3014 case OBJ_ARC: StretchSimpleArc(ObjPtr); break;
3015 case OBJ_POLY: StretchSimplePoly(ObjPtr); break;
3016 case OBJ_POLYGON: StretchSimplePolygon(ObjPtr); break;
3017 case OBJ_RCBOX: AdjObjSplineVs(ObjPtr); break;
3018 case OBJ_BOX: AdjObjSplineVs(ObjPtr); break;
3019 case OBJ_OVAL: AdjObjSplineVs(ObjPtr); break;
3020 }
3021 AdjObjOBBox(ObjPtr);
3022 StretchAttr(ObjPtr, Corner, dxScale, dyScale, auto_center_attr);
3023 AdjObjBBox(ObjPtr);
3024 }
3025
3026 static
ScaleLineWidth(ObjPtr,dScale)3027 void ScaleLineWidth(ObjPtr, dScale)
3028 struct ObjRec *ObjPtr;
3029 double dScale;
3030 {
3031 double dscale=(double)(dScale/1000.0);
3032
3033 if (!stretchingEverything) return;
3034
3035 switch (ObjPtr->type) {
3036 case OBJ_POLY:
3037 ScaleWidthAndSpec(dscale, &ObjPtr->detail.p->width,
3038 ObjPtr->detail.p->width_spec);
3039 ScaleWidthAndSpec(dscale, &ObjPtr->detail.p->aw,
3040 ObjPtr->detail.p->aw_spec);
3041 ScaleWidthAndSpec(dscale, &ObjPtr->detail.p->ah,
3042 ObjPtr->detail.p->ah_spec);
3043 break;
3044 case OBJ_POLYGON:
3045 ScaleWidthAndSpec(dscale, &ObjPtr->detail.g->width,
3046 ObjPtr->detail.g->width_spec);
3047 break;
3048 case OBJ_BOX:
3049 ScaleWidthAndSpec(dscale, &ObjPtr->detail.b->width,
3050 ObjPtr->detail.b->width_spec);
3051 break;
3052 case OBJ_OVAL:
3053 ScaleWidthAndSpec(dscale, &ObjPtr->detail.o->width,
3054 ObjPtr->detail.o->width_spec);
3055 break;
3056 case OBJ_ARC:
3057 ScaleWidthAndSpec(dscale, &ObjPtr->detail.a->width,
3058 ObjPtr->detail.a->width_spec);
3059 ScaleWidthAndSpec(dscale, &ObjPtr->detail.a->aw,
3060 ObjPtr->detail.a->aw_spec);
3061 ScaleWidthAndSpec(dscale, &ObjPtr->detail.a->ah,
3062 ObjPtr->detail.a->ah_spec);
3063 break;
3064 case OBJ_RCBOX:
3065 ScaleWidthAndSpec(dscale, &ObjPtr->detail.rcb->width,
3066 ObjPtr->detail.rcb->width_spec);
3067 break;
3068 }
3069 }
3070
3071 static
StretchObj(ObjPtr,Corner,dxScale,dyScale,ForceToUseCTM)3072 void StretchObj(ObjPtr, Corner, dxScale, dyScale, ForceToUseCTM)
3073 struct ObjRec *ObjPtr;
3074 int Corner, ForceToUseCTM;
3075 double dxScale, dyScale;
3076 {
3077 int ltx, lty, rbx, rby;
3078 int auto_center_attr=AutoCenterAttr(ObjPtr);
3079 struct BBRec final_obbox;
3080 struct ObjRec *obj_ptr=NULL;
3081 struct AttrRec *saved_fattr=NULL, *saved_lattr=NULL;
3082 double dz=(double)0;
3083
3084 StretchedAbsXY(ObjPtr->obbox.ltx, ObjPtr->obbox.lty, <x, <y);
3085 StretchedAbsXY(ObjPtr->obbox.rbx, ObjPtr->obbox.rby, &rbx, &rby);
3086 CalcBBox(ltx, lty, rbx, rby, &final_obbox.ltx, &final_obbox.lty,
3087 &final_obbox.rbx, &final_obbox.rby);
3088
3089 if (ForceToUseCTM && ObjPtr->ctm == NULL &&
3090 ObjPtr->type != OBJ_GROUP && ObjPtr->type != OBJ_ICON &&
3091 ObjPtr->type != OBJ_SYM && ObjPtr->type != OBJ_PIN) {
3092 memcpy(&ObjPtr->orig_obbox, &ObjPtr->obbox, sizeof(struct BBRec));
3093 if (ObjPtr->type == OBJ_TEXT) {
3094 memcpy(&ObjPtr->detail.t->orig_bbox, &ObjPtr->bbox,
3095 sizeof(struct BBRec));
3096 }
3097 ObjPtr->ctm = (struct XfrmMtrxRec *)malloc(sizeof(struct XfrmMtrxRec));
3098 if (ObjPtr->ctm == NULL) FailAllocMessage();
3099 ObjPtr->ctm->m[CTM_SX] = ObjPtr->ctm->m[CTM_SY] = (double)1000;
3100 ObjPtr->ctm->m[CTM_SIN] = ObjPtr->ctm->m[CTM_MSIN] = (double)0;
3101 ObjPtr->ctm->t[CTM_TX] = ObjPtr->ctm->t[CTM_TY] = 0;
3102 }
3103 switch (ObjPtr->type) {
3104 case OBJ_POLY:
3105 case OBJ_POLYGON:
3106 case OBJ_BOX:
3107 case OBJ_OVAL:
3108 case OBJ_ARC:
3109 case OBJ_RCBOX:
3110 ScaleLineWidth(ObjPtr, dxScale);
3111 if (ObjPtr->ctm == NULL) {
3112 StretchSimpleObj(ObjPtr, Corner, dxScale, dyScale, &final_obbox,
3113 auto_center_attr);
3114 } else {
3115 ShearObj(ObjPtr, Corner, dz, dz, dxScale, dyScale,
3116 &final_obbox.ltx, &final_obbox.lty);
3117 }
3118 break;
3119 case OBJ_TEXT:
3120 if (stretchableText) {
3121 ShearObj(ObjPtr, Corner, dz, dz, dxScale, dyScale,
3122 &final_obbox.ltx, &final_obbox.lty);
3123 } else {
3124 StretchSimpleText(ObjPtr, Corner);
3125 }
3126 break;
3127 case OBJ_GROUP:
3128 case OBJ_ICON:
3129 case OBJ_SYM:
3130 case OBJ_PIN:
3131 if (!stretchableText && !compoundObjWithTextStretchableForPSE &&
3132 CompoundObjHasTextSubObj(ObjPtr)) {
3133 JustMoveSimpleCompoundObj(ObjPtr, Corner);
3134 } else {
3135 for (obj_ptr=ObjPtr->detail.r->first; obj_ptr != NULL;
3136 obj_ptr=obj_ptr->next) {
3137 StretchObj(obj_ptr, Corner, dxScale, dyScale, ForceToUseCTM);
3138 }
3139 AdjObjOBBox(ObjPtr);
3140 StretchAttr(ObjPtr, Corner, dxScale, dyScale, auto_center_attr);
3141 AdjObjSplineVs(ObjPtr);
3142 AdjObjBBox(ObjPtr);
3143 }
3144 break;
3145 case OBJ_XBM:
3146 case OBJ_XPM:
3147 saved_fattr = ObjPtr->fattr;
3148 saved_lattr = ObjPtr->lattr;
3149 ObjPtr->fattr = ObjPtr->lattr = NULL;
3150 ShearObj(ObjPtr, Corner, dz, dz, dxScale, dyScale,
3151 &final_obbox.ltx, &final_obbox.lty);
3152 ObjPtr->fattr = saved_fattr;
3153 ObjPtr->lattr = saved_lattr;
3154 StretchAttr(ObjPtr, Corner, dxScale, dyScale, auto_center_attr);
3155 AdjObjBBox(ObjPtr);
3156 break;
3157 }
3158 }
3159
3160 static
StretchAllSelObjects(Corner,dxScale,dyScale)3161 void StretchAllSelObjects(Corner, dxScale, dyScale)
3162 int Corner;
3163 double dxScale, dyScale;
3164 {
3165 struct SelRec *sel_ptr;
3166
3167 for (sel_ptr = topSel; sel_ptr != NULL; sel_ptr = sel_ptr->next) {
3168 if (!sel_ptr->obj->locked) {
3169 StretchObj(sel_ptr->obj, Corner, dxScale, dyScale, FALSE);
3170 }
3171 }
3172 if (numObjLocked != 0) {
3173 Msg(TgLoadString(STID_LOCKED_OBJS_ARE_NOT_STRETCHED));
3174 }
3175 }
3176
3177 static
MarkObjectsForStretch()3178 void MarkObjectsForStretch()
3179 {
3180 register struct ObjRec *obj_ptr;
3181 register struct SelRec *sel_ptr;
3182
3183 for (obj_ptr = botObj; obj_ptr != NULL; obj_ptr = obj_ptr->prev) {
3184 obj_ptr->marked = FALSE;
3185 }
3186 for (sel_ptr = botSel; sel_ptr != NULL; sel_ptr = sel_ptr->prev) {
3187 sel_ptr->obj->marked = TRUE;
3188 }
3189 }
3190
3191 static
ConstrainedStretchAllSel(Corner,ltx,lty,rbx,rby)3192 int ConstrainedStretchAllSel(Corner, ltx, lty, rbx, rby)
3193 int Corner;
3194 int *ltx, *lty, *rbx, *rby;
3195 {
3196 register struct ObjRec *obj_ptr;
3197 int something_stretched=FALSE, num_pts;
3198 int x_off, y_off, move_first, move_last, x, y;
3199 IntPoint *v;
3200
3201 for (obj_ptr=botObj; obj_ptr != NULL; obj_ptr=obj_ptr->prev) {
3202 if (!obj_ptr->marked && obj_ptr->type==OBJ_POLY && !obj_ptr->locked) {
3203 num_pts = obj_ptr->detail.p->n;
3204 v = obj_ptr->detail.p->vlist;
3205
3206 if (obj_ptr->ctm == NULL) {
3207 x_off = OFFSET_X(v[0].x); y_off = OFFSET_Y(v[0].y);
3208 move_first = EndPtInSelected(x_off, y_off);
3209 x_off = OFFSET_X(v[num_pts-1].x); y_off = OFFSET_Y(v[num_pts-1].y);
3210 move_last = EndPtInSelected(x_off, y_off);
3211 } else {
3212 int tmp_x, tmp_y;
3213
3214 TransformPointThroughCTM(v[0].x-obj_ptr->x, v[0].y-obj_ptr->y,
3215 obj_ptr->ctm, &tmp_x, &tmp_y);
3216 tmp_x += obj_ptr->x;
3217 tmp_y += obj_ptr->y;
3218 x_off = OFFSET_X(tmp_x); y_off = OFFSET_Y(tmp_y);
3219 move_first = EndPtInSelected(x_off, y_off);
3220 TransformPointThroughCTM(v[num_pts-1].x-obj_ptr->x,
3221 v[num_pts-1].y-obj_ptr->y, obj_ptr->ctm, &tmp_x, &tmp_y);
3222 tmp_x += obj_ptr->x;
3223 tmp_y += obj_ptr->y;
3224 x_off = OFFSET_X(tmp_x); y_off = OFFSET_Y(tmp_y);
3225 move_last = EndPtInSelected(x_off, y_off);
3226 }
3227
3228 if (move_first || move_last) {
3229 int index=INVALID, seg_dx, seg_dy, dx, dy, cur_seg_dx, cur_seg_dy;
3230
3231 PrepareToReplaceAnObj(obj_ptr);
3232
3233 if (obj_ptr->ctm != NULL) {
3234 /* Remove the transformations! */
3235 int i;
3236
3237 for (i=0; i < num_pts; i++) {
3238 int tmp_x, tmp_y;
3239
3240 TransformPointThroughCTM(v[i].x-obj_ptr->x, v[i].y-obj_ptr->y,
3241 obj_ptr->ctm, &tmp_x, &tmp_y);
3242 v[i].x = tmp_x+obj_ptr->x;
3243 v[i].y = tmp_y+obj_ptr->y;
3244 }
3245 free(obj_ptr->ctm);
3246 obj_ptr->ctm = NULL;
3247 UpdPolyBBox(obj_ptr, num_pts, v);
3248 }
3249 if (something_stretched) {
3250 if (obj_ptr->bbox.ltx < *ltx) *ltx = obj_ptr->bbox.ltx;
3251 if (obj_ptr->bbox.lty < *lty) *lty = obj_ptr->bbox.lty;
3252 if (obj_ptr->bbox.rbx > *rbx) *rbx = obj_ptr->bbox.rbx;
3253 if (obj_ptr->bbox.rby > *rby) *rby = obj_ptr->bbox.rby;
3254 } else {
3255 *ltx = obj_ptr->bbox.ltx; *lty = obj_ptr->bbox.lty;
3256 *rbx = obj_ptr->bbox.rbx; *rby = obj_ptr->bbox.rby;
3257 }
3258 something_stretched = TRUE;
3259 if (move_first && move_last && num_pts==3) {
3260 StretchedAbsXY(v[0].x, v[0].y, &x, &y);
3261 dx = x-v[0].x; dy = y-v[0].y;
3262 index = 1;
3263 cur_seg_dx = v[index-1].x - v[index].x;
3264 cur_seg_dy = v[index-1].y - v[index].y;
3265 seg_dx = v[index].x - v[index+1].x;
3266 seg_dy = v[index].y - v[index+1].y;
3267
3268 if (cur_seg_dy==0 && seg_dx==0 &&
3269 (seg_dy!=0 || (seg_dy==0 && dx==0))) {
3270 v[index].y += dy;
3271 } else if (cur_seg_dx==0 && seg_dy==0 &&
3272 (seg_dx!=0 || (seg_dx==0 && dy==0))) {
3273 v[index].x += dx;
3274 }
3275 } else {
3276 if (move_first && num_pts>2) {
3277 StretchedAbsXY(v[0].x, v[0].y, &x, &y);
3278 dx = x-v[0].x; dy = y-v[0].y;
3279 index = 1;
3280 cur_seg_dx = v[index-1].x - v[index].x;
3281 cur_seg_dy = v[index-1].y - v[index].y;
3282 seg_dx = v[index].x - v[index+1].x;
3283 seg_dy = v[index].y - v[index+1].y;
3284
3285 if (cur_seg_dy==0 && cur_seg_dx!=0 &&
3286 (seg_dy!=0 || (seg_dy==0 && dx==0))) {
3287 v[index].y += dy;
3288 } else if (cur_seg_dx==0 && cur_seg_dy!=0 &&
3289 (seg_dx!=0 || (seg_dx==0 && dy==0))) {
3290 v[index].x += dx;
3291 }
3292 }
3293 if (move_last && num_pts>2) {
3294 StretchedAbsXY(v[num_pts-1].x, v[num_pts-1].y, &x, &y);
3295 dx = x-v[num_pts-1].x; dy = y-v[num_pts-1].y;
3296 index = num_pts-2;
3297 cur_seg_dx = v[index+1].x - v[index].x;
3298 cur_seg_dy = v[index+1].y - v[index].y;
3299 seg_dx = v[index].x - v[index-1].x;
3300 seg_dy = v[index].y - v[index-1].y;
3301
3302 if (cur_seg_dy==0 && cur_seg_dx!=0 &&
3303 (seg_dy!=0 || (seg_dy==0 && dx==0))) {
3304 v[index].y += dy;
3305 } else if (cur_seg_dx==0 && cur_seg_dy!=0 &&
3306 (seg_dx!=0 || (seg_dx==0 && dy==0))) {
3307 v[index].x += dx;
3308 }
3309 }
3310 }
3311 if (move_first) {
3312 StretchedAbsXY(v[0].x, v[0].y, &x, &y);
3313 v[0].x = x; v[0].y = y;
3314 }
3315 if (move_last) {
3316 StretchedAbsXY(v[num_pts-1].x, v[num_pts-1].y, &x, &y);
3317 v[num_pts-1].x = x; v[num_pts-1].y = y;
3318 }
3319 AdjObjSplineVs(obj_ptr);
3320 switch (obj_ptr->type) {
3321 case OBJ_POLY:
3322 if (obj_ptr->detail.p->curved != LT_INTSPLINE) {
3323 UpdPolyBBox(obj_ptr, num_pts, v);
3324 } else {
3325 UpdPolyBBox(obj_ptr, obj_ptr->detail.p->intn,
3326 obj_ptr->detail.p->intvlist);
3327 }
3328 break;
3329 case OBJ_POLYGON:
3330 if (obj_ptr->detail.g->curved != LT_INTSPLINE) {
3331 UpdPolyBBox(obj_ptr, num_pts, v);
3332 } else {
3333 UpdPolyBBox(obj_ptr, obj_ptr->detail.g->intn,
3334 obj_ptr->detail.g->intvlist);
3335 }
3336 break;
3337 }
3338 AdjObjBBox(obj_ptr);
3339 if (AutoCenterAttr(obj_ptr)) {
3340 struct AttrRec *attr_ptr=obj_ptr->fattr;
3341 int modified=FALSE;
3342
3343 for ( ; attr_ptr != NULL; attr_ptr = attr_ptr->next) {
3344 if (attr_ptr->shown) {
3345 struct BBRec bbox;
3346
3347 CenterObjInOBBox(attr_ptr->obj, obj_ptr->obbox, &bbox);
3348 if (bbox.ltx < *ltx) *ltx = bbox.ltx;
3349 if (bbox.lty < *lty) *lty = bbox.lty;
3350 if (bbox.rbx > *rbx) *rbx = bbox.rbx;
3351 if (bbox.rby > *rby) *rby = bbox.rby;
3352 modified = TRUE;
3353 }
3354 }
3355 if (modified) AdjObjBBox(obj_ptr);
3356 }
3357 if (obj_ptr->bbox.ltx < *ltx) *ltx = obj_ptr->bbox.ltx;
3358 if (obj_ptr->bbox.lty < *lty) *lty = obj_ptr->bbox.lty;
3359 if (obj_ptr->bbox.rbx > *rbx) *rbx = obj_ptr->bbox.rbx;
3360 if (obj_ptr->bbox.rby > *rby) *rby = obj_ptr->bbox.rby;
3361 RecordReplaceAnObj(obj_ptr);
3362 }
3363 }
3364 }
3365 return something_stretched;
3366 }
3367
3368 static
StretchAllSel(Corner,dxScale,dyScale)3369 void StretchAllSel(Corner, dxScale, dyScale)
3370 int Corner;
3371 double dxScale, dyScale; /* dxScale and dyScale are scaled by 1000 */
3372 {
3373 int ltx, lty, rbx, rby, saved_ltx, saved_lty, saved_rbx, saved_rby;
3374 int poly_stretched;
3375
3376 saved_ltx = selLtX; saved_lty = selLtY;
3377 saved_rbx = selRbX; saved_rby = selRbY;
3378
3379 if (moveMode==CONST_MOVE) {
3380 MarkObjectsForStretch();
3381
3382 StartCompositeCmd();
3383 PrepareToRecord(CMD_STRETCH, topSel, botSel, numObjSelected);
3384 RecordCmd(CMD_STRETCH, NULL, topSel, botSel, numObjSelected);
3385
3386 poly_stretched = ConstrainedStretchAllSel(Corner, <x, <y, &rbx, &rby);
3387 StretchAllSelObjects(Corner, dxScale, dyScale);
3388 UpdSelBBox();
3389 if (poly_stretched) {
3390 ltx = min(ltx,min(selLtX,saved_ltx));
3391 lty = min(lty,min(selLtY,saved_lty));
3392 rbx = max(rbx,max(selRbX,saved_rbx));
3393 rby = max(rby,max(selRbY,saved_rby));
3394 RedrawAnArea(botObj, ltx-GRID_ABS_SIZE(1), lty-GRID_ABS_SIZE(1),
3395 rbx+GRID_ABS_SIZE(1), rby+GRID_ABS_SIZE(1));
3396 } else {
3397 RedrawAreas(botObj, saved_ltx-GRID_ABS_SIZE(1),
3398 saved_lty-GRID_ABS_SIZE(1),
3399 saved_rbx+GRID_ABS_SIZE(1), saved_rby+GRID_ABS_SIZE(1),
3400 selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1),
3401 selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1));
3402 }
3403 EndCompositeCmd();
3404 } else {
3405 PrepareToRecord(CMD_REPLACE, topSel, botSel, numObjSelected);
3406 StretchAllSelObjects(Corner, dxScale, dyScale);
3407 RecordCmd(CMD_REPLACE, NULL, topSel, botSel, numObjSelected);
3408 UpdSelBBox();
3409 RedrawAreas(botObj, saved_ltx-GRID_ABS_SIZE(1),
3410 saved_lty-GRID_ABS_SIZE(1),
3411 saved_rbx+GRID_ABS_SIZE(1), saved_rby+GRID_ABS_SIZE(1),
3412 selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1),
3413 selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1));
3414 }
3415 }
3416
3417 static
DiagonalDistance(dx,dy)3418 int DiagonalDistance(dx, dy)
3419 double dx, dy;
3420 {
3421 double dval=sqrt(dx*dx+dy*dy);
3422
3423 return round(dval);
3424 }
3425
3426 static
DiagonalAngle(dx,dy)3427 double DiagonalAngle(dx, dy)
3428 int dx, dy;
3429 {
3430 double theta=((dx==0) ? ((dy>=0) ? M_PI/2.0 : -M_PI/2.0) :
3431 atan2((double)(dy), (double)(dx)));
3432
3433 return theta*((double)180.0)/M_PI;
3434 }
3435
3436 static
GetMeasurement(ObjPtr,buf,buf1)3437 void GetMeasurement(ObjPtr, buf, buf1)
3438 struct ObjRec *ObjPtr;
3439 char *buf, *buf1;
3440 {
3441 int ltx, lty, rbx, rby, real_ltx, real_lty, real_rbx, real_rby, dx, dy;
3442 char x_buf[80], y_buf[80], d_buf[80];
3443 double diag_angle;
3444
3445 StretchedAbsXY(ObjPtr->obbox.ltx, ObjPtr->obbox.lty, <x, <y);
3446 StretchedAbsXY(ObjPtr->obbox.rbx, ObjPtr->obbox.rby, &rbx, &rby);
3447 CalcBBox(ltx, lty, rbx, rby, &real_ltx, &real_lty, &real_rbx, &real_rby);
3448 PixelToMeasurementUnit(x_buf, abs(real_rbx-real_ltx));
3449 PixelToMeasurementUnit(y_buf, abs(real_rby-real_lty));
3450 sprintf(buf, "w=%s\nh=%s", x_buf, y_buf);
3451 dx = real_rbx-real_ltx;
3452 dy = real_rby-real_lty;
3453 PixelToMeasurementUnit(d_buf, abs(DiagonalDistance((double)dx, (double)dy)));
3454 diag_angle = DiagonalAngle(dx, dy);
3455 sprintf(buf1, "Diagonal: length=%s angle=%.2f or %.2f", d_buf,
3456 (float)diag_angle, (float)(((double)360.0)-diag_angle));
3457 }
3458
3459 static
PointsToShearScale(Corner,x_pivot,y_pivot,x_move,y_move,x_current,y_current,dx_shear,dy_shear,dx_scale,dy_scale)3460 void PointsToShearScale(Corner, x_pivot, y_pivot, x_move, y_move,
3461 x_current, y_current, dx_shear, dy_shear, dx_scale, dy_scale)
3462 int Corner, x_pivot, y_pivot, x_move, y_move, x_current, y_current;
3463 double *dx_shear, *dy_shear, *dx_scale, *dy_scale;
3464 /* the returned shear value is 1000*arctan() */
3465 /* the returned scale value is 1000*scaling */
3466 {
3467 int dx=x_current-x_move, dy=y_current-y_move;
3468
3469 switch (Corner) {
3470 case CORNER_TOP:
3471 case CORNER_BOTTOM:
3472 if (dx_scale != NULL) *dx_scale = (double)1000;
3473 if (dy_scale != NULL) {
3474 *dy_scale = (dy == 0 ? (double)1000 :
3475 (double)(((double)(y_current-y_pivot)) /
3476 ((double)(y_move-y_pivot))*1000.0));
3477 }
3478 if (dx_shear != NULL) {
3479 *dx_shear = (dx == 0 ? (double)0 :
3480 (double)(atan2((double)dx,(double)y_current-y_pivot)*1000.0));
3481 }
3482 if (dy_shear != NULL) *dy_shear = (double)0;
3483 break;
3484 case CORNER_RIGHT:
3485 case CORNER_LEFT:
3486 if (dx_scale != NULL) {
3487 *dx_scale = (dx == 0 ? (double)1000 :
3488 (double)(((double)(x_current-x_pivot)) /
3489 ((double)(x_move-x_pivot))*1000.0));
3490 }
3491 if (dy_scale != NULL) *dy_scale = (double)1000;
3492 if (dx_shear != NULL) *dx_shear = (double)0;
3493 if (dy_shear != NULL) {
3494 *dy_shear = (dy == 0 ? (double)0 :
3495 (double)(atan2((double)dy,(double)x_current-x_pivot)*1000.0));
3496 }
3497 break;
3498 default: /* scaling only, no shearing */
3499 if (dx_scale != NULL) {
3500 *dx_scale = (dx == 0 ? (double)1000 :
3501 (double)(((double)(x_current-x_pivot)) /
3502 ((double)(x_move-x_pivot))*1000.0));
3503 }
3504 if (dy_scale != NULL) {
3505 *dy_scale = (dy == 0 ? (double)1000 :
3506 (double)(((double)(y_current-y_pivot)) /
3507 ((double)(y_move-y_pivot))*1000.0));
3508 }
3509 if (dx_shear != NULL) *dx_shear = (double)0;
3510 if (dy_shear != NULL) *dy_shear = (double)0;
3511 break;
3512 }
3513 }
3514
3515 static
StretchBox(XGridOff,YGridOff,ObjPtr,Corner)3516 void StretchBox(XGridOff, YGridOff, ObjPtr, Corner)
3517 int XGridOff, YGridOff, Corner;
3518 struct ObjRec *ObjPtr;
3519 {
3520 int x, y, stretching=TRUE;
3521 int ltx, lty, rbx, rby, sel_ltx, sel_lty, sel_rbx, sel_rby;
3522 int stretched_ltx, stretched_lty, stretched_rbx, stretched_rby;
3523 int stretched_sel_ltx, stretched_sel_lty, stretched_sel_rbx;
3524 int stretched_sel_rby;
3525 int ruler_ltx, ruler_lty, ruler_rbx, ruler_rby;
3526 int sel_obj_ltx, sel_obj_lty, sel_obj_rbx, sel_obj_rby;
3527 int grid_x=XGridOff, grid_y=YGridOff, proportional=FALSE;
3528 char buf[80], buf1[80];
3529 double obj_w, obj_h;
3530 XEvent input, ev;
3531
3532 if (numObjSelected == numObjLocked || ObjPtr->locked) {
3533 MsgBox(TgLoadString(STID_LOCKED_OBJS_CANT_BE_STRETCHED), TOOL_NAME,
3534 INFO_MB);
3535 return;
3536 }
3537 XFlush(mainDisplay);
3538 XSync(mainDisplay, False);
3539
3540 if (XCheckMaskEvent(mainDisplay, ExposureMask, &ev) ||
3541 XCheckMaskEvent(mainDisplay, VisibilityChangeMask, &ev)) {
3542 ExposeEventHandler(&ev, TRUE);
3543 }
3544 SetPivot(Corner, &ObjPtr->obbox);
3545
3546 stretched_sel_ltx = sel_ltx = OFFSET_X(selNoLockLtX);
3547 stretched_sel_lty = sel_lty = OFFSET_Y(selNoLockLtY);
3548 stretched_sel_rbx = sel_rbx = OFFSET_X(selNoLockRbX);
3549 stretched_sel_rby = sel_rby = OFFSET_Y(selNoLockRbY);
3550 SelBox(drawWindow, revDefaultGC, stretched_sel_ltx-2, stretched_sel_lty-2,
3551 stretched_sel_rbx+2, stretched_sel_rby+2);
3552
3553 ruler_ltx = sel_obj_ltx = OFFSET_X(selNoLockObjLtX);
3554 ruler_lty = sel_obj_lty = OFFSET_Y(selNoLockObjLtY);
3555 ruler_rbx = sel_obj_rbx = OFFSET_X(selNoLockObjRbX);
3556 ruler_rby = sel_obj_rby = OFFSET_Y(selNoLockObjRbY);
3557
3558 stretched_ltx = ltx = OFFSET_X(ObjPtr->obbox.ltx);
3559 stretched_lty = lty = OFFSET_Y(ObjPtr->obbox.lty);
3560 stretched_rbx = rbx = OFFSET_X(ObjPtr->obbox.rbx);
3561 stretched_rby = rby = OFFSET_Y(ObjPtr->obbox.rby);
3562 SelBox(drawWindow, revDefaultGC, stretched_ltx, stretched_lty,
3563 stretched_rbx, stretched_rby);
3564
3565 if (ltx == rbx || lty == rby) {
3566 Msg(TgLoadString(ltx == rbx ? STID_CANT_STRETCH_OBJ_HAS_0_WIDTH :
3567 STID_CANT_STRETCH_OBJ_HAS_0_HEIGHT));
3568 SelBox(drawWindow, revDefaultGC, stretched_ltx, stretched_lty,
3569 stretched_rbx, stretched_rby);
3570 SelBox(drawWindow, revDefaultGC, stretched_sel_ltx-2,
3571 stretched_sel_lty-2, stretched_sel_rbx+2, stretched_sel_rby+2);
3572 return;
3573 }
3574 SaveStatusStrings();
3575
3576 obj_w = (double)(moveX - pivotX);
3577 obj_h = (double)(moveY - pivotY);
3578
3579 GetMeasurement(ObjPtr, buf, buf1);
3580 StartShowMeasureCursor(grid_x, grid_y, buf, TRUE);
3581 if (showMeasurement) SetStringStatus(buf1);
3582
3583 BeginIntervalRulers(ruler_ltx, ruler_lty, ruler_rbx, ruler_rby);
3584 if (!debugNoPointerGrab) {
3585 XGrabPointer(mainDisplay, drawWindow, False,
3586 PointerMotionMask | ButtonReleaseMask,
3587 GrabModeAsync, GrabModeAsync, None, handCursor, CurrentTime);
3588 }
3589 while (stretching) {
3590 XNextEvent(mainDisplay, &input);
3591
3592 if (input.type == Expose || input.type == VisibilityNotify) {
3593 ExposeEventHandler(&input, TRUE);
3594 } else if (input.type == ButtonRelease) {
3595 proportional = (input.xbutton.state & (ShiftMask|ControlMask));
3596 XUngrabPointer(mainDisplay, CurrentTime);
3597 XSync(mainDisplay, False);
3598 stretching = FALSE;
3599 } else if (input.type == MotionNotify || input.type == KeyPress ||
3600 input.type == KeyRelease) {
3601 proportional = (input.xmotion.state & (ShiftMask|ControlMask));
3602
3603 GetMeasurement(ObjPtr, buf, buf1);
3604 EndShowMeasureCursor(grid_x, grid_y, buf, TRUE);
3605 if (showMeasurement) SetStringStatus(buf1);
3606
3607 if (input.type == KeyPress || input.type == KeyRelease) {
3608 x = grid_x;
3609 y = grid_y;
3610 } else {
3611 x = input.xmotion.x;
3612 y = input.xmotion.y;
3613 }
3614 GridXY(x, y, &grid_x, &grid_y);
3615
3616 SelBox(drawWindow, revDefaultGC, stretched_ltx, stretched_lty,
3617 stretched_rbx, stretched_rby);
3618 SelBox(drawWindow, revDefaultGC, stretched_sel_ltx-2,
3619 stretched_sel_lty-2, stretched_sel_rbx+2, stretched_sel_rby+2);
3620
3621 if (proportional) {
3622 int new_w, new_h;
3623 double w_ratio, h_ratio;
3624
3625 new_w = moveX + grid_x - XGridOff - pivotX;
3626 new_h = moveY + grid_y - YGridOff - pivotY;
3627 w_ratio = (moveX!=pivotX) ? fabs(((double)new_w)/obj_w) : 0.0;
3628 h_ratio = (moveY!=pivotY) ? fabs(((double)new_h)/obj_h) : 0.0;
3629 if (changeX && changeY) {
3630 if (w_ratio >= h_ratio) {
3631 multX = (moveX!=pivotX) ? ((double)new_w)/obj_w : 1.0;
3632 multY = fabs(multX) * ((new_h*obj_h>=0) ? 1.0 : -1.0);
3633 } else {
3634 multX = fabs(multY) * ((new_w*obj_w>=0) ? 1.0 : -1.0);
3635 multY = (moveY!=pivotY) ? ((double)new_h)/obj_h : 1.0;
3636 }
3637 } else if (changeX) {
3638 multX = (moveX!=pivotX) ? ((double)new_w)/obj_w : 1.0;
3639 multY = fabs(multX);
3640 } else if (changeY) {
3641 multX = fabs(multY);
3642 multY = (moveY!=pivotY) ? ((double)new_h)/obj_h : 1.0;
3643 }
3644 } else {
3645 if (changeX) {
3646 multX = (moveX!=pivotX) ?
3647 (double)(moveX+grid_x-XGridOff-pivotX)/obj_w : 1.0;
3648 } else {
3649 multX = (double)1.0;
3650 }
3651 if (changeY) {
3652 multY = (moveY!=pivotY) ?
3653 (double)(moveY+grid_y-YGridOff-pivotY)/obj_h : 1.0;
3654 } else {
3655 multY = (double)1.0;
3656 }
3657 }
3658 StretchedXY(sel_ltx, sel_lty, &stretched_sel_ltx, &stretched_sel_lty);
3659 StretchedXY(sel_rbx, sel_rby, &stretched_sel_rbx, &stretched_sel_rby);
3660 StretchedXY(ltx, lty, &stretched_ltx, &stretched_lty);
3661 StretchedXY(rbx, rby, &stretched_rbx, &stretched_rby);
3662 StretchedXY(sel_obj_ltx, sel_obj_lty, &ruler_ltx, &ruler_lty);
3663 StretchedXY(sel_obj_rbx, sel_obj_rby, &ruler_rbx, &ruler_rby);
3664
3665 DrawIntervalRulers(ruler_ltx, ruler_lty, ruler_rbx, ruler_rby, NULL);
3666 SelBox(drawWindow, revDefaultGC, stretched_sel_ltx-2,
3667 stretched_sel_lty-2, stretched_sel_rbx+2, stretched_sel_rby+2);
3668 SelBox(drawWindow, revDefaultGC, stretched_ltx, stretched_lty,
3669 stretched_rbx, stretched_rby);
3670 GetMeasurement(ObjPtr, buf, buf1);
3671 EndShowMeasureCursor(grid_x, grid_y, buf, TRUE);
3672 if (showMeasurement) SetStringStatus(buf1);
3673 while (XCheckMaskEvent(mainDisplay, PointerMotionMask, &ev)) ;
3674 }
3675 }
3676 EndIntervalRulers(grid_x, grid_y);
3677 GetMeasurement(ObjPtr, buf, buf1);
3678 EndShowMeasureCursor(grid_x, grid_y, buf, TRUE);
3679 if (showMeasurement) SetStringStatus(buf1);
3680
3681 RestoreStatusStrings();
3682
3683 SelBox(drawWindow, revDefaultGC, stretched_ltx, stretched_lty,
3684 stretched_rbx, stretched_rby);
3685 SelBox(drawWindow, revDefaultGC, stretched_sel_ltx-2,
3686 stretched_sel_lty-2, stretched_sel_rbx+2, stretched_sel_rby+2);
3687 if (multX != (double)1.0 || multY != (double)1.0) {
3688 int num_to_resize=0;
3689 double dx_scale=(double)1000, dy_scale=(double)1000;
3690 char **ppsz_names_to_resize=NULL;
3691
3692 PointsToShearScale(Corner, pivotX, pivotY, moveX, moveY,
3693 moveX+grid_x-XGridOff, moveY+grid_y-YGridOff,
3694 NULL, NULL, &dx_scale, &dy_scale);
3695 if (proportional) {
3696 int abs_x_scale=round(dx_scale), abs_y_scale=round(dy_scale);
3697
3698 if (abs_x_scale > abs_y_scale) {
3699 dy_scale = dx_scale;
3700 } else if (abs_x_scale < abs_y_scale) {
3701 dx_scale = dy_scale;
3702 }
3703 }
3704 HighLightReverse();
3705 ppsz_names_to_resize = NeedToProcessOnResize(&num_to_resize);
3706 if (ppsz_names_to_resize == NULL) {
3707 StretchAllSel(Corner, dx_scale, dy_scale);
3708 } else {
3709 StartCompositeCmd();
3710 StretchAllSel(Corner, dx_scale, dy_scale);
3711 DoOnResize(ppsz_names_to_resize, num_to_resize);
3712 EndCompositeCmd();
3713 }
3714 HighLightForward();
3715 SetFileModified(TRUE);
3716 justDupped = FALSE;
3717 }
3718 }
3719
StretchSel(XGridOff,YGridOff,ObjPtr,Corner)3720 void StretchSel(XGridOff, YGridOff, ObjPtr, Corner)
3721 int XGridOff, YGridOff, Corner;
3722 struct ObjRec *ObjPtr;
3723 {
3724 switch (ObjPtr->type) {
3725 case OBJ_BOX:
3726 case OBJ_OVAL:
3727 case OBJ_GROUP:
3728 case OBJ_ICON:
3729 case OBJ_SYM:
3730 case OBJ_PIN:
3731 case OBJ_ARC:
3732 case OBJ_RCBOX:
3733 case OBJ_XBM:
3734 case OBJ_XPM:
3735 StretchBox(XGridOff, YGridOff, ObjPtr, Corner);
3736 break;
3737 case OBJ_POLY:
3738 if (ObjPtr->detail.p->curved == LT_STRUCT_SPLINE) {
3739 StretchStructSpline(XGridOff, YGridOff, ObjPtr, Corner);
3740 } else {
3741 StretchPoly(XGridOff, YGridOff, ObjPtr, ObjPtr->detail.p->n,
3742 ObjPtr->detail.p->vlist, Corner);
3743 }
3744 break;
3745 case OBJ_POLYGON:
3746 if (ObjPtr->detail.g->curved == LT_STRUCT_SPLINE) {
3747 StretchStructSpline(XGridOff, YGridOff, ObjPtr, Corner);
3748 } else {
3749 StretchPoly(XGridOff, YGridOff, ObjPtr, ObjPtr->detail.g->n,
3750 ObjPtr->detail.g->vlist, Corner);
3751 }
3752 break;
3753 case OBJ_TEXT:
3754 if (stretchableText) {
3755 StretchBox(XGridOff, YGridOff, ObjPtr, Corner);
3756 }
3757 break;
3758 }
3759 }
3760
ScaleAnEPSObj(ObjPtr,ScalingFactor)3761 void ScaleAnEPSObj(ObjPtr, ScalingFactor)
3762 struct ObjRec *ObjPtr;
3763 float *ScalingFactor;
3764 {
3765 struct BBRec *obbox=(&(ObjPtr->obbox));
3766
3767 multX = multY = (double)(*ScalingFactor);
3768 changeX = changeY = (fabs(multX-1.0) > 1.0e-6);
3769 if (!changeX && !changeY) return;;
3770
3771 absPivotX = obbox->ltx;
3772 absPivotY = obbox->lty;
3773 moveX = obbox->rbx;
3774 moveY = obbox->rby;
3775 StretchObj(ObjPtr, CORNER_RB, (double)(multX*1000.0), (double)(multY*1000.0),
3776 FALSE);
3777 }
3778
3779 static
ScaleAllSelObjects(Corner,dxScale,dyScale)3780 void ScaleAllSelObjects(Corner, dxScale, dyScale)
3781 int Corner;
3782 double dxScale, dyScale;
3783 /*
3784 * Force to use CTM!
3785 */
3786 {
3787 struct SelRec *sel_ptr=NULL;
3788
3789 for (sel_ptr=topSel; sel_ptr != NULL; sel_ptr=sel_ptr->next) {
3790 sel_ptr->obj->tmp_parent = NULL;
3791 }
3792 for (sel_ptr=topSel; sel_ptr != NULL; sel_ptr=sel_ptr->next) {
3793 if (stretchingEverything || !sel_ptr->obj->locked) {
3794 StretchObj(sel_ptr->obj, Corner, dxScale, dyScale, TRUE);
3795 }
3796 }
3797 if (!stretchingEverything && numObjLocked != 0) {
3798 Msg(TgLoadString(STID_LOCKED_OBJS_CANT_BE_SCALED));
3799 }
3800 }
3801
3802 static
ScaleAllSel(Corner,dxScale,dyScale,redraw)3803 void ScaleAllSel(Corner, dxScale, dyScale, redraw)
3804 int Corner, redraw;
3805 double dxScale, dyScale;
3806 {
3807 int ltx, lty, rbx, rby, saved_ltx, saved_lty, saved_rbx, saved_rby;
3808 int poly_stretched;
3809
3810 saved_ltx = selLtX; saved_lty = selLtY;
3811 saved_rbx = selRbX; saved_rby = selRbY;
3812
3813 if (moveMode == CONST_MOVE) {
3814 MarkObjectsForStretch();
3815
3816 StartCompositeCmd();
3817 PrepareToRecord(CMD_STRETCH, topSel, botSel, numObjSelected);
3818 RecordCmd(CMD_STRETCH, NULL, topSel, botSel, numObjSelected);
3819
3820 poly_stretched = ConstrainedStretchAllSel(Corner, <x, <y, &rbx, &rby);
3821 ScaleAllSelObjects(Corner, dxScale, dyScale);
3822 UpdSelBBox();
3823 if (redraw) {
3824 if (poly_stretched) {
3825 ltx = min(ltx,min(selLtX,saved_ltx));
3826 lty = min(lty,min(selLtY,saved_lty));
3827 rbx = max(rbx,max(selRbX,saved_rbx));
3828 rby = max(rby,max(selRbY,saved_rby));
3829 RedrawAnArea(botObj, ltx-GRID_ABS_SIZE(1), lty-GRID_ABS_SIZE(1),
3830 rbx+GRID_ABS_SIZE(1), rby+GRID_ABS_SIZE(1));
3831 } else {
3832 RedrawAreas(botObj, saved_ltx-GRID_ABS_SIZE(1),
3833 saved_lty-GRID_ABS_SIZE(1),
3834 saved_rbx+GRID_ABS_SIZE(1), saved_rby+GRID_ABS_SIZE(1),
3835 selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1),
3836 selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1));
3837 }
3838 }
3839 EndCompositeCmd();
3840 } else {
3841 PrepareToRecord(CMD_REPLACE, topSel, botSel, numObjSelected);
3842 ScaleAllSelObjects(Corner, dxScale, dyScale);
3843 RecordCmd(CMD_REPLACE, NULL, topSel, botSel, numObjSelected);
3844 UpdSelBBox();
3845 if (redraw) {
3846 RedrawAreas(botObj, saved_ltx-GRID_ABS_SIZE(1),
3847 saved_lty-GRID_ABS_SIZE(1),
3848 saved_rbx+GRID_ABS_SIZE(1), saved_rby+GRID_ABS_SIZE(1),
3849 selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1),
3850 selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1));
3851 }
3852 }
3853 }
3854
3855 static
FindColon(s)3856 char *FindColon(s)
3857 register char *s;
3858 {
3859 while (*s!=':' && *s!='x' && *s!='X' && *s!=' ' && *s!='\0') s++;
3860 return ((*s==':' || *s=='x' || *s=='X' || *s==' ') ? (s) : (char *)NULL);
3861 }
3862
ScaleAllSelObj()3863 void ScaleAllSelObj()
3864 {
3865 char spec[MAXSTRING], *y_spec=NULL, **ppsz_names_to_resize=NULL;
3866 int corner=INVALID, saved_h_align=horiAlign, saved_v_align=vertAlign;
3867 int num_to_resize=0;
3868 struct BBRec obbox;
3869
3870 if (topSel == NULL) {
3871 MsgBox(TgLoadCachedString(CSTID_NO_OBJ_SELECTED), TOOL_NAME, INFO_MB);
3872 return;
3873 }
3874 if (numObjSelected == numObjLocked) {
3875 MsgBox(TgLoadString(STID_LOCKED_OBJS_CANT_BE_SCALED), TOOL_NAME, INFO_MB);
3876 return;
3877 }
3878 *spec = '\0';
3879 Dialog(TgLoadString(STID_ENTER_SCALING_FACTORS_XY), NULL, spec);
3880 UtilTrimBlanks(spec);
3881 if (*spec == '\0') return;
3882
3883 horiAlign = ALIGN_L;
3884 vertAlign = ALIGN_T;
3885 corner = CORNER_RB;
3886
3887 obbox.ltx = selNoLockObjLtX; obbox.lty = selNoLockObjLtY;
3888 obbox.rbx = selNoLockObjRbX; obbox.rby = selNoLockObjRbY;
3889 SetPivot(corner, &obbox);
3890 horiAlign = saved_h_align;
3891 vertAlign = saved_v_align;
3892 if ((y_spec=FindColon(spec)) == NULL) {
3893 if (sscanf(spec, "%lf", &multX) != 1 || multX <= 0.0) {
3894 sprintf(gszMsgBox, TgLoadString(STID_INVALID_SPEC), spec);
3895 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
3896 return;
3897 }
3898 multY = multX;
3899 } else {
3900 *y_spec++ = '\0';
3901 if (sscanf(spec, "%lf", &multX) != 1 ||
3902 sscanf(y_spec, "%lf", &multY) != 1 ||
3903 multX <= 0.0 || multY <= 0.0) {
3904 sprintf(gszMsgBox, TgLoadString(STID_INVALID_SPEC), spec);
3905 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
3906 return;
3907 }
3908 }
3909 changeX = (fabs(multX-1.0) > 1.0e-6);
3910 changeY = (fabs(multY-1.0) > 1.0e-6);
3911 if (!changeX && !changeY) return;
3912
3913 horiAlign = ALIGN_L;
3914 vertAlign = ALIGN_T;
3915 HighLightReverse();
3916 ppsz_names_to_resize = NeedToProcessOnResize(&num_to_resize);
3917 if (ppsz_names_to_resize == NULL) {
3918 ScaleAllSel(corner, (double)(multX*1000.0), (double)(multY*1000.0), TRUE);
3919 } else {
3920 StartCompositeCmd();
3921 ScaleAllSel(corner, (double)(multX*1000.0), (double)(multY*1000.0), TRUE);
3922 DoOnResize(ppsz_names_to_resize, num_to_resize);
3923 EndCompositeCmd();
3924 }
3925 HighLightForward();
3926 SetFileModified(TRUE);
3927 justDupped = FALSE;
3928 horiAlign = saved_h_align;
3929 vertAlign = saved_v_align;
3930 }
3931
PreciseScaleEverything()3932 void PreciseScaleEverything()
3933 {
3934 int corner=CORNER_RB, saved_h_align=horiAlign, saved_v_align=vertAlign;
3935 int saved_cur_page_num=curPageNum, prev_page_num=curPageNum;
3936 int saved_stretchable_text=stretchableText;
3937 char spec[MAXSTRING], buf[MAXSTRING];
3938 struct BBRec obbox;
3939
3940 *spec = '\0';
3941 Dialog(TgLoadString(STID_ENTER_A_SCALING_FACTOR), NULL, spec);
3942 UtilTrimBlanks(spec);
3943 if (*spec == '\0') return;
3944
3945 obbox.ltx = obbox.lty = 0;
3946 obbox.rbx = onePageWidth; obbox.rby = onePageHeight;
3947 SetPivot(corner, &obbox);
3948
3949 if (FindColon(spec) != NULL) {
3950 MsgBox(TgLoadString(STID_ONLY_INPUT_ONE_NUMERIC_VAL), TOOL_NAME, INFO_MB);
3951 return;
3952 } else if (sscanf(spec, "%lf", &multX) != 1 || multX <= 0.0) {
3953 sprintf(gszMsgBox, TgLoadString(STID_INVALID_SPEC), spec);
3954 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
3955 return;
3956 } else if (fabs(multX-((float)1.0)) < INT_TOL) {
3957 return;
3958 }
3959 if (round(multX) >= 10) {
3960 sprintf(gszMsgBox, TgLoadString(STID_SCALING_EVERYTHING_LARGE_SURE),
3961 multX);
3962 if (MsgBox(gszMsgBox, TOOL_NAME, YNC_MB) != MB_ID_YES) {
3963 return;
3964 }
3965 }
3966 multY = multX;
3967
3968 changeX = (fabs(multX-1.0) > 1.0e-6);
3969 changeY = (fabs(multY-1.0) > 1.0e-6);
3970 if (!changeX && !changeY) return;
3971
3972 MakeQuiescent();
3973
3974 if (firstCmd != NULL) {
3975 if (!OkToFlushUndoBuffer(
3976 TgLoadString(STID_PRECISE_SCALE_EV_CAUSE_FLUSH))) {
3977 SetCurChoice(curChoiceBeforeMakeQuiescent);
3978 return;
3979 }
3980 }
3981 corner = CORNER_RB;
3982 horiAlign = ALIGN_L;
3983 vertAlign = ALIGN_T;
3984 stretchableText = saved_stretchable_text;
3985
3986 printMag /= multX;
3987 if (UpdPageStyle(pageStyle)) {
3988 UpdDrawWinBBox();
3989 AdjSplineVs();
3990 }
3991 FormatFloat(&printMag, buf);
3992 if (printMag <= 100.0) {
3993 sprintf(gszMsgBox, TgLoadString(STID_NEW_REDUCTION_IS_PERCENT), buf);
3994 } else {
3995 sprintf(gszMsgBox, TgLoadString(STID_NEW_ENLARGEMENT_IS_PERCENT), buf);
3996 }
3997 Msg(gszMsgBox);
3998 SaveStatusStrings();
3999
4000 StartCompositeCmd();
4001 for (curPageNum=1; curPageNum <= lastPageNum; curPageNum++) {
4002 int num_to_resize=0;
4003 char **ppsz_names_to_resize=NULL;
4004
4005 /* No need for the CMD_GOTO_PAGE stuff since CleanUpCmds will be called */
4006 /* PrepareToRecord(CMD_GOTO_PAGE, NULL, NULL, prev_page_num); */
4007 GotoPageNum(curPageNum);
4008 ShowPage();
4009 XSync(mainDisplay, False);
4010 /* RecordCmd(CMD_GOTO_PAGE, NULL, NULL, NULL, curPageNum); */
4011 prev_page_num = curPageNum;
4012 sprintf(gszMsgBox, TgLoadCachedString(CSTID_SCALING_EVERYTHING_PAGE),
4013 curPageNum, lastPageNum);
4014 SetStringStatus(gszMsgBox);
4015
4016 SelAllObj(FALSE, FALSE);
4017
4018 ppsz_names_to_resize = NeedToProcessOnResize(&num_to_resize);
4019 stretchingEverything = TRUE;
4020 ScaleAllSel(corner, (double)(multX*1000.0), (double)(multY*1000.0), TRUE);
4021 stretchingEverything = FALSE;
4022 if (ppsz_names_to_resize != NULL) {
4023 DoOnResize(ppsz_names_to_resize, num_to_resize);
4024 }
4025 RemoveAllSel();
4026 }
4027 /* PrepareToRecord(CMD_GOTO_PAGE, NULL, NULL, prev_page_num); */
4028 GotoPageNum(saved_cur_page_num);
4029 ShowPage();
4030 /* RecordCmd(CMD_GOTO_PAGE, NULL, NULL, NULL, saved_cur_page_num); */
4031
4032 EndCompositeCmd();
4033 CleanUpCmds();
4034
4035 RestoreStatusStrings();
4036 SetFileModified(TRUE);
4037 justDupped = FALSE;
4038
4039 stretchableText = saved_stretchable_text;
4040 horiAlign = saved_h_align;
4041 vertAlign = saved_v_align;
4042
4043 RedrawScrollBars();
4044 RedrawRulers();
4045 RedrawTitleWindow();
4046 ClearAndRedrawDrawWindow();
4047 SetCurChoice(curChoiceBeforeMakeQuiescent);
4048 }
4049
ScaleObjLikeScaleEverything(obj_ptr,scale,redraw)4050 void ScaleObjLikeScaleEverything(obj_ptr, scale, redraw)
4051 struct ObjRec *obj_ptr;
4052 double scale;
4053 int redraw;
4054 {
4055 int corner=CORNER_RB, saved_h_align=horiAlign, saved_v_align=vertAlign;
4056 int saved_stretchable_text=stretchableText, saved_move_mode=moveMode;
4057 float saved_print_mag=printMag;
4058 struct BBRec obbox;
4059
4060 obbox.ltx = obbox.lty = 0;
4061 obbox.rbx = onePageWidth; obbox.rby = onePageHeight;
4062 SetPivot(corner, &obbox);
4063
4064 if (fabs(scale-((float)1.0)) < INT_TOL) {
4065 return;
4066 }
4067 multX = multY = ((double)1)/scale;
4068
4069 changeX = (fabs(multX-1.0) > 1.0e-6);
4070 changeY = (fabs(multY-1.0) > 1.0e-6);
4071 if (!changeX && !changeY) return;
4072
4073 corner = CORNER_RB;
4074 horiAlign = ALIGN_L;
4075 vertAlign = ALIGN_T;
4076 stretchableText = TRUE;
4077 moveMode = UNCONST_MOVE;
4078
4079 printMag /= multX;
4080 if (UpdPageStyle(pageStyle)) {
4081 UpdDrawWinBBox();
4082 AdjSplineVs();
4083 }
4084 if (multX < 100.0) {
4085 sprintf(gszMsgBox, TgLoadString(STID_REDUCE_BY_FACTOR), multX);
4086 } else {
4087 sprintf(gszMsgBox, TgLoadString(STID_ENLARGE_BY_FACTOR), multX);
4088 }
4089 SetStringStatus(gszMsgBox);
4090 SaveStatusStrings();
4091
4092 AddObj(NULL, topObj, obj_ptr);
4093 topSel = botSel = SelectThisObject(obj_ptr);
4094 UpdSelBBox();
4095
4096 StartCompositeCmd();
4097
4098 stretchingEverything = TRUE;
4099 ScaleAllSel(corner, (double)(multX*1000.0), (double)(multY*1000.0), redraw);
4100 stretchingEverything = FALSE;
4101 RemoveAllSel();
4102
4103 EndCompositeCmd();
4104 CleanUpCmds();
4105
4106 UnlinkObj(topObj);
4107
4108 RestoreStatusStrings();
4109 SetFileModified(TRUE);
4110 justDupped = FALSE;
4111
4112 moveMode = saved_move_mode;
4113 stretchableText = saved_stretchable_text;
4114 horiAlign = saved_h_align;
4115 vertAlign = saved_v_align;
4116 printMag = saved_print_mag;
4117
4118 if (UpdPageStyle(pageStyle)) {
4119 UpdDrawWinBBox();
4120 AdjSplineVs();
4121 }
4122 }
4123
SizeAllSelObj(AbsW,AbsH)4124 void SizeAllSelObj(AbsW, AbsH)
4125 int AbsW, AbsH;
4126 {
4127 int saved_h_align=horiAlign, saved_v_align=vertAlign, num_to_resize=0;
4128 char **ppsz_names_to_resize=NULL;
4129 struct BBRec obbox;
4130
4131 if (topSel == NULL) {
4132 MsgBox(TgLoadCachedString(CSTID_NO_OBJ_SELECTED), TOOL_NAME, INFO_MB);
4133 return;
4134 }
4135 if (AbsW == selObjRbX-selObjLtX && AbsH == selObjRbY-selObjLtY) return;
4136
4137 obbox.ltx = selObjLtX; obbox.lty = selObjLtY;
4138 obbox.rbx = selObjRbX; obbox.rby = selObjRbY;
4139 SetPivot(CORNER_RB, &obbox);
4140
4141 horiAlign = ALIGN_L;
4142 vertAlign = ALIGN_T;
4143 multX = (selObjRbX==selObjLtX ? ((double)1.0) :
4144 ((double)AbsW) / ((double)selObjRbX-selObjLtX));
4145 multY = (selObjRbY==selObjLtY ? ((double)1.0) :
4146 ((double)AbsH) / ((double)selObjRbY-selObjLtY));
4147 changeX = (fabs(multX-1.0) > 1.0e-6);
4148 changeY = (fabs(multY-1.0) > 1.0e-6);
4149 ppsz_names_to_resize = NeedToProcessOnResize(&num_to_resize);
4150 if (ppsz_names_to_resize == NULL) {
4151 ScaleAllSel(CORNER_RB, (double)(multX*1000.0), (double)(multY*1000.0),
4152 TRUE);
4153 } else {
4154 StartCompositeCmd();
4155 ScaleAllSel(CORNER_RB, (double)(multX*1000.0), (double)(multY*1000.0),
4156 TRUE);
4157 DoOnResize(ppsz_names_to_resize, num_to_resize);
4158 EndCompositeCmd();
4159 }
4160 horiAlign = saved_h_align;
4161 vertAlign = saved_v_align;
4162
4163 UpdSelBBox();
4164 SetFileModified(TRUE);
4165 justDupped = FALSE;
4166 }
4167
SizeAnObj(ObjPtr,TopOwner,AbsW,AbsH)4168 void SizeAnObj(ObjPtr, TopOwner, AbsW, AbsH)
4169 struct ObjRec *ObjPtr, *TopOwner;
4170 int AbsW, AbsH;
4171 /* This function is meant to be called from within an internal command */
4172 {
4173 int obj_w=ObjPtr->obbox.rbx-ObjPtr->obbox.ltx;
4174 int obj_h=ObjPtr->obbox.rby-ObjPtr->obbox.lty;
4175
4176 if (execCurDepth <= 0) {
4177 #ifdef _TGIF_DBG /* debug, do not translate */
4178 TgAssert(FALSE,
4179 "SizeAnObj() called not from an internal command!", NULL);
4180 return;
4181 #endif /* _TGIF_DBG */
4182 }
4183 if (obj_w == AbsW && obj_h == AbsH) {
4184 return;
4185 }
4186 if (ObjPtr == TopOwner) {
4187 struct SelRec *saved_top_sel=topSel, *saved_bot_sel=botSel;
4188
4189 topSel = botSel = NULL;
4190 AddObjIntoSel(ObjPtr, NULL, topSel, &topSel, &botSel);
4191 UpdSelBBox();
4192
4193 SizeAllSelObj(AbsW, AbsH);
4194
4195 RemoveAllSel();
4196 topSel = saved_top_sel;
4197 botSel = saved_bot_sel;
4198 UpdSelBBox();
4199 } else {
4200 int saved_h_align=horiAlign, saved_v_align=vertAlign;
4201 int ltx=TopOwner->bbox.ltx, lty=TopOwner->bbox.lty;
4202 int rbx=TopOwner->bbox.rbx, rby=TopOwner->bbox.rby;
4203 struct SelRec *saved_top_sel=topSel, *saved_bot_sel=botSel;
4204
4205 SetPivot(CORNER_RB, &ObjPtr->obbox);
4206
4207 multX = (obj_w == 0) ? ((double)1.0) : ((double)AbsW) / ((double)obj_w);
4208 multY = (obj_h == 0) ? ((double)1.0) : ((double)AbsH) / ((double)obj_h);
4209 changeX = (fabs(multX-1.0) > 1.0e-6);
4210 changeY = (fabs(multY-1.0) > 1.0e-6);
4211 if (!changeX && !changeY) {
4212 return;
4213 }
4214 horiAlign = ALIGN_L;
4215 vertAlign = ALIGN_T;
4216
4217 topSel = botSel = NULL;
4218 UpdSelBBox();
4219
4220 PrepareToReplaceAnObj(TopOwner);
4221
4222 StretchObj(ObjPtr, CORNER_RB, (double)(multX*1000.0),
4223 (double)(multY*1000.0), FALSE);
4224 while (ObjPtr != TopOwner) {
4225 ObjPtr = ObjPtr->tmp_parent;
4226 AdjObjBBox(ObjPtr);
4227 }
4228 RecordReplaceAnObj(TopOwner);
4229 RedrawAreas(botObj, ltx-GRID_ABS_SIZE(1), lty-GRID_ABS_SIZE(1),
4230 rbx+GRID_ABS_SIZE(1), rby+GRID_ABS_SIZE(1),
4231 TopOwner->bbox.ltx-GRID_ABS_SIZE(1),
4232 TopOwner->bbox.lty-GRID_ABS_SIZE(1),
4233 TopOwner->bbox.rbx+GRID_ABS_SIZE(1),
4234 TopOwner->bbox.rby+GRID_ABS_SIZE(1));
4235
4236 RemoveAllSel();
4237 topSel = saved_top_sel;
4238 botSel = saved_bot_sel;
4239 UpdSelBBox();
4240
4241 SetFileModified(TRUE);
4242 justDupped = FALSE;
4243 horiAlign = saved_h_align;
4244 vertAlign = saved_v_align;
4245 }
4246 }
4247
4248 static
DoSizeAllSelToGivenWidthHeight(abs_w,abs_h,do_width,do_height)4249 void DoSizeAllSelToGivenWidthHeight(abs_w, abs_h, do_width, do_height)
4250 int abs_h, do_width, do_height;
4251 {
4252 struct SelRec *saved_top_sel=topSel, *saved_bot_sel=botSel, *sel_ptr=NULL;
4253 int saved_h_align=horiAlign, saved_v_align=vertAlign, num_to_resize=0;
4254 char **ppsz_names_to_resize=NULL;
4255
4256 if (topSel == NULL || (!do_width && !do_height)) {
4257 return;
4258 }
4259 horiAlign = ALIGN_L;
4260 vertAlign = ALIGN_T;
4261
4262 ppsz_names_to_resize = NeedToProcessOnResize(&num_to_resize);
4263
4264 HighLightReverse();
4265 StartCompositeCmd();
4266 for (sel_ptr=saved_top_sel; sel_ptr != NULL; sel_ptr=sel_ptr->next) {
4267 struct ObjRec *obj_ptr=sel_ptr->obj;
4268 int w=(obj_ptr->obbox.rbx-obj_ptr->obbox.ltx);
4269 int h=(obj_ptr->obbox.rby-obj_ptr->obbox.lty);
4270
4271 topSel = botSel = SelectThisObject(obj_ptr);
4272 UpdSelBBox();
4273 if (do_width && do_height) {
4274 SetPivot(CORNER_RB, &obj_ptr->obbox);
4275 multX = (w == 0 ? ((double)1.0) : ((double)abs_w) / ((double)w));
4276 multY = (h == 0 ? ((double)1.0) : ((double)abs_h) / ((double)h));
4277 changeX = (fabs(multX-1.0) > 1.0e-6);
4278 changeY = (fabs(multY-1.0) > 1.0e-6);
4279 ScaleAllSel(CORNER_RB, (double)(multX*1000.0), (double)(multY*1000.0),
4280 TRUE);
4281 } else if (do_width) {
4282 SetPivot(CORNER_RIGHT, &obj_ptr->obbox);
4283 multX = (w == 0 ? ((double)1.0) : ((double)abs_w) / ((double)w));
4284 changeX = (fabs(multX-1.0) > 1.0e-6);
4285 ScaleAllSel(CORNER_RIGHT, (double)(multX*1000.0), (double)1000, TRUE);
4286 } else {
4287 SetPivot(CORNER_BOTTOM, &obj_ptr->obbox);
4288 multY = (h == 0 ? ((double)1.0) : ((double)abs_h) / ((double)h));
4289 changeY = (fabs(multY-1.0) > 1.0e-6);
4290 ScaleAllSel(CORNER_BOTTOM, (double)1000, (double)(multY*1000.0), TRUE);
4291 }
4292 free(topSel);
4293 }
4294 if (ppsz_names_to_resize != NULL) {
4295 DoOnResize(ppsz_names_to_resize, num_to_resize);
4296 }
4297 EndCompositeCmd();
4298
4299 horiAlign = saved_h_align;
4300 vertAlign = saved_v_align;
4301
4302 topSel = saved_top_sel;
4303 botSel = saved_bot_sel;
4304 UpdSelBBox();
4305
4306 HighLightForward();
4307 SetFileModified(TRUE);
4308 justDupped = FALSE;
4309 }
4310
SizeAllSelToGivenWidthHeight(AbsW,AbsH)4311 void SizeAllSelToGivenWidthHeight(AbsW, AbsH)
4312 int AbsW, AbsH;
4313 {
4314 DoSizeAllSelToGivenWidthHeight(AbsW, AbsH, TRUE, TRUE);
4315 }
4316
SizeAllSelToGivenWidth(AbsW)4317 void SizeAllSelToGivenWidth(AbsW)
4318 int AbsW;
4319 {
4320 DoSizeAllSelToGivenWidthHeight(AbsW, INVALID, TRUE, FALSE);
4321 }
4322
SizeAllSelToGivenHeight(AbsH)4323 void SizeAllSelToGivenHeight(AbsH)
4324 int AbsH;
4325 {
4326 DoSizeAllSelToGivenWidthHeight(INVALID, AbsH, FALSE, TRUE);
4327 }
4328
FlipObjHorizontal(ObjPtr)4329 void FlipObjHorizontal(ObjPtr)
4330 struct ObjRec *ObjPtr;
4331 {
4332 int two_x_pivot=selNoLockObjLtX+selNoLockObjRbX;
4333 int new_obj_ltx=two_x_pivot-ObjPtr->obbox.rbx;
4334 int new_obj_rbx=two_x_pivot-ObjPtr->obbox.ltx;
4335 int new_obj_lty=ObjPtr->obbox.lty;
4336
4337 if (ObjPtr->ctm == NULL && ObjPtr->type != OBJ_XBM &&
4338 ObjPtr->type != OBJ_XPM) {
4339 register IntPoint *v;
4340 register int i;
4341 int num_pts;
4342 struct ObjRec *obj_ptr;
4343 struct AttrRec *attr_ptr;
4344 struct ArcRec *arc_ptr;
4345
4346 switch (ObjPtr->type) {
4347 case OBJ_TEXT:
4348 if (ObjPtr->detail.t->minilines.just != JUST_C) {
4349 ObjPtr->detail.t->minilines.just =
4350 MAXJUSTS-1-ObjPtr->detail.t->minilines.just;
4351 if (ObjPtr->detail.t->cached_bitmap != None) {
4352 XFreePixmap(mainDisplay, ObjPtr->detail.t->cached_bitmap);
4353 }
4354 ObjPtr->detail.t->cached_bitmap = None;
4355
4356 if (zoomScale != 0) {
4357 ObjPtr->detail.t->cached_zoom = 0;
4358 }
4359 }
4360 MoveObj(ObjPtr, two_x_pivot-((ObjPtr->x)<<1), 0);
4361 UpdTextBBox(ObjPtr);
4362 break;
4363
4364 default:
4365 switch (ObjPtr->type) {
4366 case OBJ_XBM:
4367 ObjPtr->detail.xbm->flip ^= HORI_EVEN;
4368 if (ObjPtr->detail.xbm->cached_bitmap != None) {
4369 XFreePixmap(mainDisplay, ObjPtr->detail.xbm->cached_bitmap);
4370 }
4371 ObjPtr->detail.xbm->cached_bitmap = None;
4372
4373 if (zoomScale != 0) {
4374 ObjPtr->detail.xbm->cached_zoom = 0;
4375 }
4376 break;
4377 case OBJ_XPM:
4378 ObjPtr->detail.xpm->flip ^= HORI_EVEN;
4379 if (ObjPtr->detail.xpm->cached_pixmap != None) {
4380 XFreePixmap(mainDisplay, ObjPtr->detail.xpm->cached_pixmap);
4381 }
4382 ObjPtr->detail.xpm->cached_pixmap = None;
4383 if (ObjPtr->detail.xpm->cached_bitmap != None) {
4384 XFreePixmap(mainDisplay, ObjPtr->detail.xpm->cached_bitmap);
4385 }
4386 ObjPtr->detail.xpm->cached_bitmap = None;
4387 ObjPtr->detail.xpm->cached_color = (-1);
4388
4389 if (zoomScale != 0) {
4390 ObjPtr->detail.xpm->cached_zoom = 0;
4391 }
4392 break;
4393 case OBJ_ICON:
4394 case OBJ_PIN:
4395 ObjPtr->detail.r->flip ^= HORI_EVEN;
4396 break;
4397 }
4398 ObjPtr->obbox.ltx = ObjPtr->x = new_obj_ltx;
4399 ObjPtr->obbox.rbx = new_obj_rbx;
4400 break;
4401 }
4402
4403 switch (ObjPtr->type) {
4404 case OBJ_POLY:
4405 num_pts = ObjPtr->detail.p->n;
4406 v = ObjPtr->detail.p->vlist;
4407 for (i = 0; i < num_pts; i++, v++) (*v).x = two_x_pivot - (*v).x;
4408 AdjObjSplineVs(ObjPtr);
4409 attr_ptr = ObjPtr->fattr;
4410 for ( ; attr_ptr != NULL; attr_ptr = attr_ptr->next) {
4411 FlipObjHorizontal(attr_ptr->obj);
4412 }
4413 break;
4414 case OBJ_POLYGON:
4415 num_pts = ObjPtr->detail.g->n;
4416 v = ObjPtr->detail.g->vlist;
4417 for (i = 0; i < num_pts; i++, v++) (*v).x = two_x_pivot - (*v).x;
4418 AdjObjSplineVs(ObjPtr);
4419 attr_ptr = ObjPtr->fattr;
4420 for ( ; attr_ptr != NULL; attr_ptr = attr_ptr->next) {
4421 FlipObjHorizontal(attr_ptr->obj);
4422 }
4423 break;
4424 case OBJ_BOX:
4425 case OBJ_OVAL:
4426 case OBJ_RCBOX:
4427 case OBJ_XBM:
4428 case OBJ_XPM:
4429 attr_ptr = ObjPtr->fattr;
4430 for ( ; attr_ptr != NULL; attr_ptr = attr_ptr->next) {
4431 FlipObjHorizontal(attr_ptr->obj);
4432 }
4433 AdjObjSplineVs(ObjPtr);
4434 break;
4435 case OBJ_TEXT:
4436 AdjObjSplineVs(ObjPtr);
4437 break;
4438 case OBJ_ARC:
4439 arc_ptr = ObjPtr->detail.a;
4440 arc_ptr->xc = two_x_pivot - arc_ptr->xc;
4441 arc_ptr->x1 = two_x_pivot - arc_ptr->x1;
4442 arc_ptr->x2 = two_x_pivot - arc_ptr->x2;
4443 arc_ptr->dir = !(arc_ptr->dir);
4444 arc_ptr->ltx = two_x_pivot - arc_ptr->ltx - arc_ptr->w;
4445 if (arc_ptr->angle1 > 0) {
4446 arc_ptr->angle1 = (180*64) - arc_ptr->angle1;
4447 } else {
4448 arc_ptr->angle1 = (-180)*64 - arc_ptr->angle1;
4449 }
4450 arc_ptr->angle2 = -(arc_ptr->angle2);
4451 AdjObjBBox(ObjPtr);
4452 attr_ptr = ObjPtr->fattr;
4453 for ( ; attr_ptr != NULL; attr_ptr = attr_ptr->next) {
4454 FlipObjHorizontal(attr_ptr->obj);
4455 }
4456 AdjObjSplineVs(ObjPtr);
4457 break;
4458 case OBJ_GROUP:
4459 case OBJ_ICON:
4460 case OBJ_SYM:
4461 case OBJ_PIN:
4462 obj_ptr = ObjPtr->detail.r->first;
4463 for ( ; obj_ptr != NULL; obj_ptr = obj_ptr->next) {
4464 FlipObjHorizontal(obj_ptr);
4465 }
4466 attr_ptr = ObjPtr->fattr;
4467 for ( ; attr_ptr != NULL; attr_ptr = attr_ptr->next) {
4468 FlipObjHorizontal(attr_ptr->obj);
4469 }
4470 AdjObjSplineVs(ObjPtr);
4471 break;
4472 }
4473 AdjObjBBox(ObjPtr);
4474 } else {
4475 double dz=(double)0, d1=(double)1000, dm1=(double)-1000;
4476
4477 ShearObj(ObjPtr, CORNER_LEFT, dz, dz, dm1, d1, NULL, NULL);
4478 MoveObj(ObjPtr, new_obj_ltx-ObjPtr->obbox.ltx,
4479 new_obj_lty-ObjPtr->obbox.lty);
4480 }
4481 SetFileModified(TRUE);
4482 }
4483
FlipIconHorizontal(ObjPtr)4484 void FlipIconHorizontal(ObjPtr)
4485 struct ObjRec *ObjPtr;
4486 {
4487 register int two_x_pivot;
4488 int new_obj_ltx, new_obj_rbx;
4489 struct ObjRec *obj_ptr;
4490 struct AttrRec *attr_ptr;
4491
4492 two_x_pivot = selNoLockObjLtX + selNoLockObjRbX;
4493 new_obj_ltx = two_x_pivot - ObjPtr->obbox.rbx;
4494 new_obj_rbx = two_x_pivot - ObjPtr->obbox.ltx;
4495
4496 ObjPtr->detail.r->flip ^= HORI_EVEN;
4497
4498 ObjPtr->obbox.ltx = ObjPtr->x = new_obj_ltx;
4499 ObjPtr->obbox.rbx = new_obj_rbx;
4500
4501 obj_ptr = ObjPtr->detail.r->first;
4502 for ( ; obj_ptr != NULL; obj_ptr = obj_ptr->next) {
4503 FlipObjHorizontal(obj_ptr);
4504 }
4505 attr_ptr = ObjPtr->fattr;
4506 for ( ; attr_ptr != NULL; attr_ptr = attr_ptr->next) {
4507 FlipObjHorizontal(attr_ptr->obj);
4508 }
4509 AdjObjBBox(ObjPtr);
4510 }
4511
FlipObjVertical(ObjPtr)4512 void FlipObjVertical(ObjPtr)
4513 struct ObjRec *ObjPtr;
4514 {
4515 int two_x_pivot=selNoLockObjLtY+selNoLockObjRbY;
4516 int new_obj_lty=two_x_pivot-ObjPtr->obbox.rby;
4517 int new_obj_rby=two_x_pivot-ObjPtr->obbox.lty;
4518 int new_obj_ltx=ObjPtr->obbox.ltx;
4519
4520 if (ObjPtr->ctm == NULL && ObjPtr->type != OBJ_XBM &&
4521 ObjPtr->type != OBJ_XPM) {
4522 register IntPoint *v;
4523 register int i;
4524 int num_pts;
4525 struct ObjRec *obj_ptr;
4526 struct AttrRec *attr_ptr;
4527 struct ArcRec *arc_ptr;
4528
4529 switch (ObjPtr->type) {
4530 case OBJ_TEXT:
4531 MoveObj(ObjPtr, 0, new_obj_lty-ObjPtr->y);
4532 UpdTextBBox(ObjPtr);
4533 break;
4534
4535 default:
4536 switch (ObjPtr->type) {
4537 case OBJ_XBM:
4538 ObjPtr->detail.xbm->flip ^= VERT_EVEN;
4539 if (ObjPtr->detail.xbm->cached_bitmap != None) {
4540 XFreePixmap(mainDisplay, ObjPtr->detail.xbm->cached_bitmap);
4541 }
4542 ObjPtr->detail.xbm->cached_bitmap = None;
4543
4544 if (zoomScale != 0) {
4545 ObjPtr->detail.xbm->cached_zoom = 0;
4546 }
4547 break;
4548 case OBJ_XPM:
4549 ObjPtr->detail.xpm->flip ^= VERT_EVEN;
4550 if (ObjPtr->detail.xpm->cached_pixmap != None) {
4551 XFreePixmap(mainDisplay, ObjPtr->detail.xpm->cached_pixmap);
4552 }
4553 ObjPtr->detail.xpm->cached_pixmap = None;
4554 if (ObjPtr->detail.xpm->cached_bitmap != None) {
4555 XFreePixmap(mainDisplay, ObjPtr->detail.xpm->cached_bitmap);
4556 }
4557 ObjPtr->detail.xpm->cached_bitmap = None;
4558 ObjPtr->detail.xpm->cached_color = (-1);
4559
4560 if (zoomScale != 0) {
4561 ObjPtr->detail.xpm->cached_zoom = 0;
4562 }
4563 break;
4564 case OBJ_ICON:
4565 case OBJ_PIN:
4566 ObjPtr->detail.r->flip ^= VERT_EVEN;
4567 break;
4568 }
4569 ObjPtr->obbox.lty = ObjPtr->y = new_obj_lty;
4570 ObjPtr->obbox.rby = new_obj_rby;
4571 break;
4572 }
4573
4574 switch (ObjPtr->type) {
4575 case OBJ_POLY:
4576 num_pts = ObjPtr->detail.p->n;
4577 v = ObjPtr->detail.p->vlist;
4578 for (i = 0; i < num_pts; i++, v++) (*v).y = two_x_pivot - (*v).y;
4579 AdjObjSplineVs(ObjPtr);
4580 attr_ptr = ObjPtr->fattr;
4581 for ( ; attr_ptr != NULL; attr_ptr = attr_ptr->next) {
4582 FlipObjVertical(attr_ptr->obj);
4583 }
4584 break;
4585 case OBJ_POLYGON:
4586 num_pts = ObjPtr->detail.g->n;
4587 v = ObjPtr->detail.g->vlist;
4588 for (i = 0; i < num_pts; i++, v++) (*v).y = two_x_pivot - (*v).y;
4589 AdjObjSplineVs(ObjPtr);
4590 attr_ptr = ObjPtr->fattr;
4591 for ( ; attr_ptr != NULL; attr_ptr = attr_ptr->next) {
4592 FlipObjVertical(attr_ptr->obj);
4593 }
4594 break;
4595 case OBJ_BOX:
4596 case OBJ_OVAL:
4597 case OBJ_RCBOX:
4598 case OBJ_XBM:
4599 case OBJ_XPM:
4600 attr_ptr = ObjPtr->fattr;
4601 for ( ; attr_ptr != NULL; attr_ptr = attr_ptr->next) {
4602 FlipObjVertical(attr_ptr->obj);
4603 }
4604 AdjObjSplineVs(ObjPtr);
4605 break;
4606 case OBJ_TEXT:
4607 AdjObjSplineVs(ObjPtr);
4608 break;
4609 case OBJ_ARC:
4610 arc_ptr = ObjPtr->detail.a;
4611 arc_ptr->yc = two_x_pivot - arc_ptr->yc;
4612 arc_ptr->y1 = two_x_pivot - arc_ptr->y1;
4613 arc_ptr->y2 = two_x_pivot - arc_ptr->y2;
4614 arc_ptr->dir = !(arc_ptr->dir);
4615 arc_ptr->lty = two_x_pivot - arc_ptr->lty - arc_ptr->h;
4616 arc_ptr->angle1 = -(arc_ptr->angle1);
4617 arc_ptr->angle2 = -(arc_ptr->angle2);
4618 AdjObjBBox(ObjPtr);
4619 attr_ptr = ObjPtr->fattr;
4620 for ( ; attr_ptr != NULL; attr_ptr = attr_ptr->next) {
4621 FlipObjVertical(attr_ptr->obj);
4622 }
4623 AdjObjSplineVs(ObjPtr);
4624 break;
4625 case OBJ_GROUP:
4626 case OBJ_ICON:
4627 case OBJ_SYM:
4628 case OBJ_PIN:
4629 obj_ptr = ObjPtr->detail.r->first;
4630 for ( ; obj_ptr != NULL; obj_ptr = obj_ptr->next) {
4631 FlipObjVertical(obj_ptr);
4632 }
4633 attr_ptr = ObjPtr->fattr;
4634 for ( ; attr_ptr != NULL; attr_ptr = attr_ptr->next) {
4635 FlipObjVertical(attr_ptr->obj);
4636 }
4637 AdjObjSplineVs(ObjPtr);
4638 break;
4639 }
4640 AdjObjBBox(ObjPtr);
4641 } else {
4642 double dz=(double)0, d1=(double)1000, dm1=(double)-1000;
4643
4644 ShearObj(ObjPtr, CORNER_TOP, dz, dz, d1, dm1, NULL, NULL);
4645 MoveObj(ObjPtr, new_obj_ltx-ObjPtr->obbox.ltx,
4646 new_obj_lty-ObjPtr->obbox.lty);
4647 }
4648 SetFileModified(TRUE);
4649 }
4650
FlipIconVertical(ObjPtr)4651 void FlipIconVertical(ObjPtr)
4652 struct ObjRec *ObjPtr;
4653 {
4654 register int two_x_pivot;
4655 int new_obj_lty, new_obj_rby;
4656 struct ObjRec *obj_ptr;
4657 struct AttrRec *attr_ptr;
4658
4659 two_x_pivot = selNoLockObjLtY + selNoLockObjRbY;
4660 new_obj_lty = two_x_pivot - ObjPtr->obbox.rby;
4661 new_obj_rby = two_x_pivot - ObjPtr->obbox.lty;
4662
4663 ObjPtr->detail.r->flip ^= VERT_EVEN;
4664
4665 ObjPtr->obbox.lty = ObjPtr->y = new_obj_lty;
4666 ObjPtr->obbox.rby = new_obj_rby;
4667
4668 obj_ptr = ObjPtr->detail.r->first;
4669 for ( ; obj_ptr != NULL; obj_ptr = obj_ptr->next) {
4670 FlipObjVertical(obj_ptr);
4671 }
4672 attr_ptr = ObjPtr->fattr;
4673 for ( ; attr_ptr != NULL; attr_ptr = attr_ptr->next) {
4674 FlipObjVertical(attr_ptr->obj);
4675 }
4676 AdjObjBBox(ObjPtr);
4677 }
4678
4679 /* --------------------- Rotation --------------------- */
4680
4681 static int rotatePivotX=0;
4682 static int rotatePivotY=0;
4683
4684 static
OkToTransform(obj_ptr,stid)4685 int OkToTransform(obj_ptr, stid)
4686 struct ObjRec *obj_ptr;
4687 int stid;
4688 {
4689 char obj_name[MAXSTRING];
4690 struct AttrRec *name_attr=NULL;
4691
4692 if (obj_ptr->locked) return FALSE;
4693
4694 *obj_name = '\0';
4695 if (HasOnResize(obj_ptr, &name_attr) && name_attr != NULL) {
4696 UtilStrCpyN(obj_name, sizeof(obj_name), name_attr->attr_value.s);
4697 sprintf(gszMsgBox, TgLoadString(stid), obj_name);
4698 if (MsgBox(gszMsgBox, TOOL_NAME, YN_MB) != MB_ID_YES) {
4699 return FALSE;
4700 }
4701 }
4702 return TRUE;
4703 }
4704
SetRotatePivot()4705 void SetRotatePivot()
4706 {
4707 if (!autoRotatePivot && rotatePivotAbsXYValid) {
4708 rotatePivotX = rotatePivotAbsX;
4709 rotatePivotY = rotatePivotAbsY;
4710 } else {
4711 rotatePivotX = ((selNoLockObjLtX + selNoLockObjRbX)>>1);
4712 rotatePivotY = ((selNoLockObjLtY + selNoLockObjRbY)>>1);
4713 }
4714 }
4715
SetRotatePivotByObject(ObjPtr)4716 void SetRotatePivotByObject(ObjPtr)
4717 struct ObjRec *ObjPtr;
4718 {
4719 rotatePivotX = ((ObjPtr->obbox.ltx + ObjPtr->obbox.rbx)>>1);
4720 rotatePivotY = ((ObjPtr->obbox.lty + ObjPtr->obbox.rby)>>1);
4721 }
4722
4723 static
RotatePtClockWise(X,Y,NewX,NewY)4724 void RotatePtClockWise(X, Y, NewX, NewY)
4725 int X, Y, *NewX, *NewY;
4726 {
4727 *NewX = rotatePivotX + rotatePivotY - Y;
4728 *NewY = rotatePivotY - rotatePivotX + X;
4729 }
4730
4731 static
RotatedXY(X,Y,AngleDelta,NewX,NewY)4732 void RotatedXY(X, Y, AngleDelta, NewX, NewY)
4733 int X, Y, AngleDelta, *NewX, *NewY; /* AngleDelta is degree*64 */
4734 {
4735 register double radian, sin_val, cos_val;
4736 int dx=X-pivotX, dy=Y-pivotY;
4737
4738 if (dx == 0 && dy == 0) {
4739 *NewX = pivotX;
4740 *NewY = pivotY;
4741 } else {
4742 radian = (((double)AngleDelta)*M_PI/180.0/64.0);
4743 sin_val = sin(radian);
4744 cos_val = cos(radian);
4745 *NewX = pivotX + round(dx*cos_val - dy*sin_val);
4746 *NewY = pivotY + round(dx*sin_val + dy*cos_val);
4747 }
4748 }
4749
4750 static
RotatedAbsXY(X,Y,AngleDelta,NewX,NewY)4751 void RotatedAbsXY(X, Y, AngleDelta, NewX, NewY)
4752 int X, Y, AngleDelta, *NewX, *NewY; /* AngleDelta is degree*64 */
4753 {
4754 register double radian, sin_val, cos_val;
4755 int dx=X-absPivotX, dy=Y-absPivotY;
4756
4757 if (dx == 0 && dy == 0) {
4758 *NewX = absPivotX;
4759 *NewY = absPivotY;
4760 } else {
4761 radian = (((double)AngleDelta)*M_PI/180.0/64.0);
4762 sin_val = sin(radian);
4763 cos_val = cos(radian);
4764 *NewX = absPivotX + round(dx*cos_val - dy*sin_val);
4765 *NewY = absPivotY + round(dx*sin_val + dy*cos_val);
4766 }
4767 }
4768
RotateObj(ObjPtr,Corner,AngleDelta,RealLtX,RealLtY)4769 void RotateObj(ObjPtr, Corner, AngleDelta, RealLtX, RealLtY)
4770 struct ObjRec *ObjPtr;
4771 int Corner, AngleDelta; /* AngleDelta is degree*64 */
4772 int *RealLtX, *RealLtY;
4773 {
4774 IntPoint abs_obj_obbox_vs[5];
4775 int x, y, new_ltx, new_lty, new_rbx, new_rby;
4776 double radian=(((double)AngleDelta)*M_PI/180.0/64.0);
4777 double sin_val=sin(radian), cos_val=cos(radian);
4778 struct XfrmMtrxRec ctm, new_ctm;
4779 struct ObjRec *obj_ptr;
4780 struct AttrRec *attr_ptr;
4781
4782 switch (ObjPtr->type) {
4783 case OBJ_GROUP:
4784 case OBJ_ICON:
4785 case OBJ_SYM:
4786 case OBJ_PIN:
4787 for (obj_ptr=ObjPtr->detail.r->first; obj_ptr != NULL;
4788 obj_ptr=obj_ptr->next) {
4789 RotateObj(obj_ptr, Corner, AngleDelta, RealLtX, RealLtY);
4790 }
4791 break;
4792
4793 default:
4794 if (ObjPtr->ctm == NULL) {
4795 memcpy(&ObjPtr->orig_obbox, &ObjPtr->obbox, sizeof(struct BBRec));
4796 if (ObjPtr->type == OBJ_TEXT) {
4797 memcpy(&ObjPtr->detail.t->orig_bbox, &ObjPtr->bbox,
4798 sizeof(struct BBRec));
4799 }
4800 ObjPtr->ctm = (struct XfrmMtrxRec *)malloc(sizeof(struct XfrmMtrxRec));
4801 if (ObjPtr->ctm == NULL) FailAllocMessage();
4802 ObjPtr->ctm->m[CTM_SX] = ObjPtr->ctm->m[CTM_SY] = (double)1000;
4803 ObjPtr->ctm->m[CTM_SIN] = ObjPtr->ctm->m[CTM_MSIN] = (double)0;
4804 ObjPtr->ctm->t[CTM_TX] = ObjPtr->ctm->t[CTM_TY] = 0;
4805 }
4806 RotatedAbsXY(ObjPtr->x+ObjPtr->ctm->t[CTM_TX],
4807 ObjPtr->y+ObjPtr->ctm->t[CTM_TY], AngleDelta, &x, &y);
4808 ctm.m[CTM_SX] = ctm.m[CTM_SY] = ((double)1000.0)*cos_val;
4809 ctm.m[CTM_SIN] = ((double)1000.0)*sin_val;
4810 ctm.m[CTM_MSIN] = (-ctm.m[CTM_SIN]);
4811 ctm.t[CTM_TX] = 0;
4812 ctm.t[CTM_TY] = 0;
4813 ConcatCTM(ObjPtr->ctm, &ctm, &new_ctm);
4814 new_ctm.t[CTM_TX] = x-ObjPtr->x;
4815 new_ctm.t[CTM_TY] = y-ObjPtr->y;
4816 memcpy(ObjPtr->ctm, &new_ctm, sizeof(struct XfrmMtrxRec));
4817
4818 GetTransformedOBBoxAbsVs(ObjPtr, abs_obj_obbox_vs);
4819
4820 new_ltx = min(min(abs_obj_obbox_vs[0].x,abs_obj_obbox_vs[1].x),
4821 min(abs_obj_obbox_vs[2].x,abs_obj_obbox_vs[3].x));
4822 new_rbx = max(max(abs_obj_obbox_vs[0].x,abs_obj_obbox_vs[1].x),
4823 max(abs_obj_obbox_vs[2].x,abs_obj_obbox_vs[3].x));
4824 new_lty = min(min(abs_obj_obbox_vs[0].y,abs_obj_obbox_vs[1].y),
4825 min(abs_obj_obbox_vs[2].y,abs_obj_obbox_vs[3].y));
4826 new_rby = max(max(abs_obj_obbox_vs[0].y,abs_obj_obbox_vs[1].y),
4827 max(abs_obj_obbox_vs[2].y,abs_obj_obbox_vs[3].y));
4828
4829 ObjPtr->obbox.ltx = new_ltx; ObjPtr->obbox.lty = new_lty;
4830 ObjPtr->obbox.rbx = new_rbx; ObjPtr->obbox.rby = new_rby;
4831 if (RealLtX != NULL && RealLtY != NULL) {
4832 int dx=(*RealLtX)-new_ltx, dy=(*RealLtY)-new_lty;
4833
4834 ObjPtr->x += dx; ObjPtr->y += dy;
4835 ObjPtr->bbox.ltx += dx; ObjPtr->bbox.lty += dy;
4836 ObjPtr->bbox.rbx += dx; ObjPtr->bbox.rby += dy;
4837 ObjPtr->obbox.ltx += dx; ObjPtr->obbox.lty += dy;
4838 ObjPtr->obbox.rbx += dx; ObjPtr->obbox.rby += dy;
4839 MoveRotatedObjCache(ObjPtr, dx, dy);
4840 }
4841 if (ObjPtr->ctm->m[CTM_SX] >= 999.0 &&
4842 ObjPtr->ctm->m[CTM_SX] <= 1001.0 &&
4843 ObjPtr->ctm->m[CTM_SY] >= 999.0 &&
4844 ObjPtr->ctm->m[CTM_SY] <= 1001.0 &&
4845 ObjPtr->ctm->m[CTM_SIN] >= (-1.0) &&
4846 ObjPtr->ctm->m[CTM_SIN] <= 1.0 &&
4847 ObjPtr->ctm->m[CTM_MSIN] >= (-1.0) &&
4848 ObjPtr->ctm->m[CTM_MSIN] <= 1.0) {
4849 int dx=ObjPtr->ctm->t[CTM_TX], dy=ObjPtr->ctm->t[CTM_TY];
4850 struct AttrRec *saved_fattr=NULL, *saved_lattr=NULL;
4851
4852 free(ObjPtr->ctm);
4853 ObjPtr->ctm = NULL;
4854
4855 memcpy(&ObjPtr->obbox, &ObjPtr->orig_obbox, sizeof(struct BBRec));
4856 if (ObjPtr->type == OBJ_TEXT) {
4857 memcpy(&ObjPtr->bbox, &ObjPtr->detail.t->orig_bbox,
4858 sizeof(struct BBRec));
4859 }
4860 saved_fattr = ObjPtr->fattr;
4861 saved_lattr = ObjPtr->lattr;
4862 ObjPtr->fattr = ObjPtr->lattr = NULL;
4863 MoveObj(ObjPtr, dx, dy);
4864 ObjPtr->fattr = saved_fattr;
4865 ObjPtr->lattr = saved_lattr;
4866 }
4867 break;
4868 }
4869 for (attr_ptr=ObjPtr->fattr; attr_ptr != NULL; attr_ptr=attr_ptr->next) {
4870 RotateObj(attr_ptr->obj, Corner, AngleDelta, RealLtX, RealLtY);
4871 }
4872 AdjObjCache(ObjPtr);
4873 AdjObjBBox(ObjPtr);
4874 }
4875
RotateObjForLayout(ObjPtr,AngleInRadian,Corner)4876 void RotateObjForLayout(ObjPtr, AngleInRadian, Corner)
4877 struct ObjRec *ObjPtr;
4878 double AngleInRadian;
4879 int Corner;
4880 {
4881 double angle=AngleInRadian*64.0*180.0/M_PI;
4882
4883 SetPivot(Corner, &ObjPtr->obbox);
4884 RotateObj(ObjPtr, Corner, round(angle), NULL, NULL);
4885 }
4886
RotateObjClockWise(ObjPtr)4887 void RotateObjClockWise(ObjPtr)
4888 struct ObjRec *ObjPtr;
4889 {
4890 double angle_in_radian=((double)(rotationIncrement))*M_PI/180.0/64.0;
4891 double sin_val=sin(angle_in_radian);
4892 double cos_val=cos(angle_in_radian);
4893 int orig_x=((ObjPtr->obbox.ltx+ObjPtr->obbox.rbx)>>1);
4894 int orig_y=ObjPtr->obbox.lty;
4895 int x=0, y=0, dx=orig_x-rotatePivotX, dy=orig_y-rotatePivotY;
4896
4897 if (dx != 0 || dy != 0) {
4898 x = (int)round(dx*cos_val - dy*sin_val);
4899 y = (int)round(dx*sin_val + dy*cos_val);
4900 }
4901 x += rotatePivotX;
4902 y += rotatePivotY;
4903 /* RotateObjForLayout() rotates about center-top */
4904 RotateObjForLayout(ObjPtr, angle_in_radian, CORNER_BOTTOM);
4905 MoveObj(ObjPtr, x-orig_x, y-orig_y);
4906 SetFileModified(TRUE);
4907 }
4908
RotateIconClockWise(ObjPtr)4909 void RotateIconClockWise(ObjPtr)
4910 struct ObjRec *ObjPtr;
4911 {
4912 int ltx, lty, rbx, rby;
4913 struct ObjRec *obj_ptr;
4914 struct AttrRec *attr_ptr;
4915
4916 SetRotatePivot();
4917 RotatePtClockWise(ObjPtr->obbox.ltx, ObjPtr->obbox.rby, <x, <y);
4918 RotatePtClockWise(ObjPtr->obbox.rbx, ObjPtr->obbox.lty, &rbx, &rby);
4919 ObjPtr->obbox.ltx = ObjPtr->x = ltx;
4920 ObjPtr->obbox.lty = ObjPtr->y = lty;
4921 ObjPtr->obbox.rbx = rbx;
4922 ObjPtr->obbox.rby = rby;
4923
4924 obj_ptr = ObjPtr->detail.r->first;
4925 for ( ; obj_ptr != NULL; obj_ptr = obj_ptr->next) {
4926 RotateObjClockWise(obj_ptr);
4927 }
4928 attr_ptr = ObjPtr->fattr;
4929 for ( ; attr_ptr != NULL; attr_ptr = attr_ptr->next) {
4930 RotateObjClockWise(attr_ptr->obj);
4931 }
4932 AdjObjBBox(ObjPtr);
4933 }
4934
4935 static
RotatePtCounter(X,Y,NewX,NewY)4936 void RotatePtCounter(X, Y, NewX, NewY)
4937 int X, Y, *NewX, *NewY;
4938 {
4939 *NewX = rotatePivotX - rotatePivotY + Y;
4940 *NewY = rotatePivotY + rotatePivotX - X;
4941 }
4942
RotateObjCounter(ObjPtr)4943 void RotateObjCounter(ObjPtr)
4944 struct ObjRec *ObjPtr;
4945 {
4946 double angle_in_radian=((double)(-rotationIncrement))*M_PI/180.0/64.0;
4947 double sin_val=sin(angle_in_radian);
4948 double cos_val=cos(angle_in_radian);
4949 int orig_x=((ObjPtr->obbox.ltx+ObjPtr->obbox.rbx)>>1);
4950 int orig_y=ObjPtr->obbox.lty;
4951 int x=0, y=0, dx=orig_x-rotatePivotX, dy=orig_y-rotatePivotY;
4952
4953 if (dx != 0 || dy != 0) {
4954 x = (int)round(dx*cos_val - dy*sin_val);
4955 y = (int)round(dx*sin_val + dy*cos_val);
4956 }
4957 x += rotatePivotX;
4958 y += rotatePivotY;
4959 /* RotateObjForLayout() rotates about center-top */
4960 RotateObjForLayout(ObjPtr, angle_in_radian, CORNER_BOTTOM);
4961 MoveObj(ObjPtr, x-orig_x, y-orig_y);
4962 SetFileModified(TRUE);
4963 }
4964
RotateIconCounter(ObjPtr)4965 void RotateIconCounter(ObjPtr)
4966 struct ObjRec *ObjPtr;
4967 {
4968 int ltx, lty, rbx, rby;
4969 struct ObjRec *obj_ptr;
4970 struct AttrRec *attr_ptr;
4971
4972 SetRotatePivot();
4973 /* ObjPtr->detail.r->rotate = (ObjPtr->detail.r->rotate+4-1) % 4; */
4974 RotatePtCounter(ObjPtr->obbox.rbx, ObjPtr->obbox.lty, <x, <y);
4975 RotatePtCounter(ObjPtr->obbox.ltx, ObjPtr->obbox.rby, &rbx, &rby);
4976 ObjPtr->obbox.ltx = ObjPtr->x = ltx;
4977 ObjPtr->obbox.lty = ObjPtr->y = lty;
4978 ObjPtr->obbox.rbx = rbx;
4979 ObjPtr->obbox.rby = rby;
4980
4981 obj_ptr = ObjPtr->detail.r->first;
4982 for ( ; obj_ptr != NULL; obj_ptr = obj_ptr->next) {
4983 RotateObjCounter(obj_ptr);
4984 }
4985 attr_ptr = ObjPtr->fattr;
4986 for ( ; attr_ptr != NULL; attr_ptr = attr_ptr->next) {
4987 RotateObjCounter(attr_ptr->obj);
4988 }
4989 AdjObjBBox(ObjPtr);
4990 }
4991
4992 static
FlipAllSelHorizontal(saved_ltx,saved_lty,saved_rbx,saved_rby)4993 void FlipAllSelHorizontal(saved_ltx, saved_lty, saved_rbx, saved_rby)
4994 int saved_ltx, saved_lty, saved_rbx, saved_rby;
4995 {
4996 struct SelRec *sel_ptr;
4997
4998 PrepareToRecord(CMD_REPLACE, topSel, botSel, numObjSelected);
4999 JustRemoveAllVSel();
5000 for (sel_ptr = topSel; sel_ptr != NULL; sel_ptr = sel_ptr->next) {
5001 if (!sel_ptr->obj->locked) {
5002 FlipObjHorizontal(sel_ptr->obj);
5003 }
5004 }
5005 UpdSelBBox();
5006 RecordCmd(CMD_REPLACE, NULL, topSel, botSel, numObjSelected);
5007 RedrawAreas(botObj, saved_ltx-GRID_ABS_SIZE(1), saved_lty-GRID_ABS_SIZE(1),
5008 saved_rbx+GRID_ABS_SIZE(1), saved_rby+GRID_ABS_SIZE(1),
5009 selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1),
5010 selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1));
5011 }
5012
FlipHorizontal()5013 void FlipHorizontal()
5014 {
5015 int saved_ltx, saved_lty, saved_rbx, saved_rby, num_to_resize=0;
5016 struct BBRec sel_obbox;
5017 char **ppsz_names_to_resize=NULL;
5018
5019 if (topSel == NULL) {
5020 MsgBox(TgLoadCachedString(CSTID_NO_OBJ_SELECTED), TOOL_NAME, INFO_MB);
5021 return;
5022 }
5023 if (numObjSelected == numObjLocked) {
5024 Msg(TgLoadString(STID_LOCKED_OBJS_CANT_BE_FLIPPED));
5025 return;
5026 }
5027 sel_obbox.ltx = selNoLockObjLtX; sel_obbox.lty = selNoLockObjLtY;
5028 sel_obbox.rbx = selNoLockObjRbX; sel_obbox.rby = selNoLockObjRbY;
5029 SetPivot(CORNER_LEFT, &sel_obbox);
5030
5031 saved_ltx = selLtX; saved_lty = selLtY;
5032 saved_rbx = selRbX; saved_rby = selRbY;
5033 HighLightReverse();
5034 ppsz_names_to_resize = NeedToProcessOnResize(&num_to_resize);
5035 if (ppsz_names_to_resize == NULL) {
5036 FlipAllSelHorizontal(saved_ltx, saved_lty, saved_rbx, saved_rby);
5037 } else {
5038 StartCompositeCmd();
5039 FlipAllSelHorizontal(saved_ltx, saved_lty, saved_rbx, saved_rby);
5040 DoOnResize(ppsz_names_to_resize, num_to_resize);
5041 EndCompositeCmd();
5042 }
5043 HighLightForward();
5044 justDupped = FALSE;
5045 if (numObjLocked != 0) {
5046 Msg(TgLoadString(STID_LOCKED_OBJS_ARE_NOT_FLIPPED));
5047 } else {
5048 Msg(TgLoadString(STID_FLIPPED_HORIZONTALLY));
5049 }
5050 }
5051
5052 static
FlipAllSelVertical(saved_ltx,saved_lty,saved_rbx,saved_rby)5053 void FlipAllSelVertical(saved_ltx, saved_lty, saved_rbx, saved_rby)
5054 int saved_ltx, saved_lty, saved_rbx, saved_rby;
5055 {
5056 struct SelRec *sel_ptr;
5057
5058 PrepareToRecord(CMD_REPLACE, topSel, botSel, numObjSelected);
5059 JustRemoveAllVSel();
5060 for (sel_ptr = topSel; sel_ptr != NULL; sel_ptr = sel_ptr->next) {
5061 if (!sel_ptr->obj->locked) {
5062 FlipObjVertical(sel_ptr->obj);
5063 }
5064 }
5065 UpdSelBBox();
5066 RecordCmd(CMD_REPLACE, NULL, topSel, botSel, numObjSelected);
5067 RedrawAreas(botObj, saved_ltx-GRID_ABS_SIZE(1), saved_lty-GRID_ABS_SIZE(1),
5068 saved_rbx+GRID_ABS_SIZE(1), saved_rby+GRID_ABS_SIZE(1),
5069 selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1),
5070 selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1));
5071 }
5072
FlipVertical()5073 void FlipVertical()
5074 {
5075 int saved_ltx, saved_lty, saved_rbx, saved_rby, num_to_resize=0;
5076 struct BBRec sel_obbox;
5077 char **ppsz_names_to_resize=NULL;
5078
5079 if (topSel == NULL) {
5080 MsgBox(TgLoadCachedString(CSTID_NO_OBJ_SELECTED), TOOL_NAME, INFO_MB);
5081 return;
5082 }
5083 if (numObjSelected == numObjLocked) {
5084 Msg(TgLoadString(STID_LOCKED_OBJS_CANT_BE_FLIPPED));
5085 return;
5086 }
5087 sel_obbox.ltx = selNoLockObjLtX; sel_obbox.lty = selNoLockObjLtY;
5088 sel_obbox.rbx = selNoLockObjRbX; sel_obbox.rby = selNoLockObjRbY;
5089 SetPivot(CORNER_TOP, &sel_obbox);
5090
5091 saved_ltx = selLtX; saved_lty = selLtY;
5092 saved_rbx = selRbX; saved_rby = selRbY;
5093 HighLightReverse();
5094 ppsz_names_to_resize = NeedToProcessOnResize(&num_to_resize);
5095 if (ppsz_names_to_resize == NULL) {
5096 FlipAllSelVertical(saved_ltx, saved_lty, saved_rbx, saved_rby);
5097 } else {
5098 StartCompositeCmd();
5099 FlipAllSelVertical(saved_ltx, saved_lty, saved_rbx, saved_rby);
5100 DoOnResize(ppsz_names_to_resize, num_to_resize);
5101 EndCompositeCmd();
5102 }
5103 HighLightForward();
5104 justDupped = FALSE;
5105 if (numObjLocked != 0) {
5106 Msg(TgLoadString(STID_LOCKED_OBJS_ARE_NOT_FLIPPED));
5107 } else {
5108 Msg(TgLoadString(STID_FLIPPED_VERTICALLY));
5109 }
5110 }
5111
5112 /* --------------------- Rotate --------------------- */
5113
RotateClockWise()5114 void RotateClockWise()
5115 {
5116 register struct SelRec *sel_ptr;
5117 int saved_ltx, saved_lty, saved_rbx, saved_rby;
5118 int text_obj_created, text_cursor_shown;
5119
5120 if (topSel == NULL) {
5121 text_cursor_shown = textCursorShown;
5122 text_obj_created = TieLooseEnds();
5123 textRotation += rotationIncrement;
5124 while (textRotation < 0) textRotation += (360<<6);
5125 while (textRotation >= (360<<6)) textRotation -= (360<<6);
5126 ShowRotate();
5127 if (!text_obj_created && curChoice == DRAWTEXT && text_cursor_shown) {
5128 NewCurText();
5129 RedrawCurText();
5130 } else {
5131 textCursorShown = FALSE;
5132 }
5133 return;
5134 }
5135 if (numObjSelected == numObjLocked) {
5136 MsgBox(TgLoadString(STID_LOCKED_OBJS_CANT_BE_ROTATED), TOOL_NAME,
5137 INFO_MB);
5138 return;
5139 }
5140 saved_ltx = selLtX; saved_lty = selLtY;
5141 saved_rbx = selRbX; saved_rby = selRbY;
5142 HighLightReverse();
5143 PrepareToRecord(CMD_REPLACE, topSel, botSel, numObjSelected);
5144 JustRemoveAllVSel();
5145 SetRotatePivot();
5146 for (sel_ptr=topSel; sel_ptr != NULL; sel_ptr=sel_ptr->next) {
5147 if (OkToTransform(sel_ptr->obj, STID_DISABLE_ON_RESIZE_ROTATE)) {
5148 RotateObjClockWise(sel_ptr->obj);
5149 }
5150 }
5151 UpdSelBBox();
5152 RecordCmd(CMD_REPLACE, NULL, topSel, botSel, numObjSelected);
5153 RedrawAreas(botObj, saved_ltx-GRID_ABS_SIZE(1), saved_lty-GRID_ABS_SIZE(1),
5154 saved_rbx+GRID_ABS_SIZE(1), saved_rby+GRID_ABS_SIZE(1),
5155 selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1),
5156 selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1));
5157 HighLightForward();
5158 justDupped = FALSE;
5159 if (numObjLocked != 0) {
5160 Msg(TgLoadString(STID_LOCKED_OBJS_ARE_NOT_ROTATED));
5161 } else {
5162 Msg(TgLoadString(STID_ROTATED_CLOCKWISE));
5163 }
5164 }
5165
RotateCounter()5166 void RotateCounter()
5167 {
5168 register struct SelRec *sel_ptr;
5169 int saved_ltx, saved_lty, saved_rbx, saved_rby;
5170 int text_obj_created, text_cursor_shown;
5171
5172 if (topSel == NULL) {
5173 text_cursor_shown = textCursorShown;
5174 text_obj_created = TieLooseEnds();
5175 textRotation -= rotationIncrement;
5176 while (textRotation < 0) textRotation += (360<<6);
5177 while (textRotation >= (360<<6)) textRotation -= (360<<6);
5178 ShowRotate();
5179 if (!text_obj_created && curChoice == DRAWTEXT && text_cursor_shown) {
5180 NewCurText();
5181 RedrawCurText();
5182 } else {
5183 textCursorShown = FALSE;
5184 }
5185 return;
5186 }
5187 if (numObjSelected == numObjLocked) {
5188 MsgBox(TgLoadString(STID_LOCKED_OBJS_CANT_BE_ROTATED), TOOL_NAME,
5189 INFO_MB);
5190 return;
5191 }
5192 saved_ltx = selLtX; saved_lty = selLtY;
5193 saved_rbx = selRbX; saved_rby = selRbY;
5194 HighLightReverse();
5195 PrepareToRecord(CMD_REPLACE, topSel, botSel, numObjSelected);
5196 JustRemoveAllVSel();
5197 SetRotatePivot();
5198 for (sel_ptr = topSel; sel_ptr != NULL; sel_ptr = sel_ptr->next) {
5199 if (OkToTransform(sel_ptr->obj, STID_DISABLE_ON_RESIZE_ROTATE)) {
5200 RotateObjCounter(sel_ptr->obj);
5201 }
5202 }
5203 UpdSelBBox();
5204 RecordCmd(CMD_REPLACE, NULL, topSel, botSel, numObjSelected);
5205 RedrawAreas(botObj, saved_ltx-GRID_ABS_SIZE(1), saved_lty-GRID_ABS_SIZE(1),
5206 saved_rbx+GRID_ABS_SIZE(1), saved_rby+GRID_ABS_SIZE(1),
5207 selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1),
5208 selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1));
5209 HighLightForward();
5210 justDupped = FALSE;
5211 if (numObjLocked != 0) {
5212 Msg(TgLoadString(STID_LOCKED_OBJS_ARE_NOT_ROTATED));
5213 } else {
5214 Msg(TgLoadString(STID_ROTATED_COUNTER_CLOCKWISE));
5215 }
5216 }
5217
SetTextRotation(pszBuf)5218 void SetTextRotation(pszBuf)
5219 char *pszBuf;
5220 {
5221 char spec[80], buf[80];
5222 float fval;
5223 int ival;
5224
5225 *spec = '\0';
5226 if (pszBuf != NULL) {
5227 strcpy(spec, pszBuf);
5228 } else {
5229 FormatAngle(textRotation, buf);
5230 sprintf(gszMsgBox, TgLoadString(STID_ENTER_TEXT_ROT_IN_DEGREE_CUR), buf);
5231 if (Dialog(gszMsgBox, NULL, spec) == INVALID) return;
5232 }
5233 UtilTrimBlanks(spec);
5234 if (*spec == '\0') return;
5235
5236 if (sscanf(spec, "%f", &fval) != 1) {
5237 sprintf(gszMsgBox, TgLoadString(STID_CANT_PARSE_ENTER_ONE_NUM_VAL),
5238 spec);
5239 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
5240 return;
5241 }
5242 fval *= (float)64.0;
5243 ival = round(fval);
5244 if (ival < 0 || ival >= (360<<6)) {
5245 sprintf(gszMsgBox, TgLoadString(STID_INVALID_VAL_ENTERED_RNG_INC),
5246 spec, 0, 360);
5247 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
5248 return;
5249 }
5250 textRotation = ival;
5251 ShowRotate();
5252 FormatAngle(textRotation, buf);
5253 sprintf(gszMsgBox, TgLoadString(STID_TEXT_ROTATION_SET_TO_GIVEN), buf);
5254 Msg(gszMsgBox);
5255 }
5256
SetRotationIncrement(pszBuf)5257 void SetRotationIncrement(pszBuf)
5258 char *pszBuf;
5259 {
5260 char spec[80], buf[80];
5261 float fval;
5262 int ival;
5263
5264 *spec = '\0';
5265 if (pszBuf != NULL) {
5266 strcpy(spec, pszBuf);
5267 } else {
5268 FormatAngle(rotationIncrement, buf);
5269 sprintf(gszMsgBox, TgLoadString(STID_ENTER_ROT_INC_IN_DEGREE_CUR), buf);
5270 if (Dialog(gszMsgBox, NULL, spec) == INVALID) return;
5271 }
5272 UtilTrimBlanks(spec);
5273 if (*spec == '\0') return;
5274
5275 if (sscanf(spec, "%f", &fval) != 1) {
5276 sprintf(gszMsgBox, TgLoadString(STID_CANT_PARSE_ENTER_ONE_NUM_VAL),
5277 spec);
5278 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
5279 return;
5280 }
5281 fval *= (float)64.0;
5282 ival = round(fval);
5283 if (ival <= 0 || ival >= (360<<6)) {
5284 sprintf(gszMsgBox, TgLoadString(STID_INVALID_VAL_ENTERED_RNG_EXC),
5285 spec, 0, 360);
5286 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
5287 return;
5288 }
5289 rotationIncrement = ival;
5290 FormatAngle(rotationIncrement, buf);
5291 sprintf(gszMsgBox, TgLoadString(STID_TEXT_ROT_INC_SET_TO_GIVEN), buf);
5292 Msg(gszMsgBox);
5293 }
5294
5295 static
IdentCTM(ctm1,ctm2)5296 int IdentCTM(ctm1, ctm2)
5297 struct XfrmMtrxRec *ctm1, *ctm2;
5298 {
5299 return ((fabs(ctm1->m[CTM_SX]-ctm2->m[CTM_SX]) < EQ_TOL) &&
5300 (fabs(ctm1->m[CTM_SY]-ctm2->m[CTM_SY]) < EQ_TOL) &&
5301 (fabs(ctm1->m[CTM_SIN]-ctm2->m[CTM_SIN]) < EQ_TOL) &&
5302 (fabs(ctm1->m[CTM_MSIN]-ctm2->m[CTM_MSIN]) < EQ_TOL));
5303 }
5304
5305 static
SetObjCTM(ObjPtr,nTransformed,ctm)5306 int SetObjCTM(ObjPtr, nTransformed, ctm)
5307 struct ObjRec *ObjPtr;
5308 int nTransformed;
5309 struct XfrmMtrxRec *ctm;
5310 {
5311 int nReturn=FALSE, cx=0, cy=0;
5312
5313 switch (ObjPtr->type) {
5314 case OBJ_GROUP:
5315 case OBJ_ICON:
5316 case OBJ_SYM:
5317 case OBJ_PIN:
5318 break;
5319
5320 default:
5321 cx = ((ObjPtr->obbox.ltx+ObjPtr->obbox.rbx)>>1);
5322 cy = ((ObjPtr->obbox.lty+ObjPtr->obbox.rby)>>1);
5323 if (nTransformed) {
5324 struct XfrmMtrxRec *saved_ctm=NULL;
5325
5326 if (ObjPtr->ctm == NULL) {
5327 SetCTM(ObjPtr, ctm);
5328 nReturn = TRUE;
5329 } else {
5330 if (!IdentCTM(ObjPtr->ctm, ctm)) {
5331 if (ObjPtr->type == OBJ_TEXT) {
5332 saved_ctm = ObjPtr->ctm;
5333 ObjPtr->ctm = NULL;
5334 if (!UpdTextBBox(ObjPtr)) {
5335 /* read-only text */
5336 ObjPtr->ctm = saved_ctm;
5337 } else {
5338 free(saved_ctm);
5339 SetCTM(ObjPtr, ctm);
5340 UpdTextBBox(ObjPtr);
5341 nReturn = TRUE;
5342 }
5343 } else {
5344 free(ObjPtr->ctm);
5345 ObjPtr->ctm = NULL;
5346 SetCTM(ObjPtr, ctm);
5347 nReturn = TRUE;
5348 }
5349 }
5350 }
5351 } else {
5352 if (ObjPtr->ctm != NULL) {
5353 free(ObjPtr->ctm);
5354 ObjPtr->ctm = NULL;
5355 nReturn = TRUE;
5356 }
5357 }
5358 if (nReturn) {
5359 int new_cx=0, new_cy=0;
5360
5361 new_cx = ((ObjPtr->obbox.ltx+ObjPtr->obbox.rbx)>>1);
5362 new_cy = ((ObjPtr->obbox.lty+ObjPtr->obbox.rby)>>1);
5363 MoveObj(ObjPtr, cx-new_cx, cy-new_cy);
5364 AdjObjCache(ObjPtr);
5365 AdjObjSplineVs(ObjPtr);
5366 AdjObjBBox(ObjPtr);
5367 }
5368 break;
5369 }
5370 return nReturn;
5371 }
5372
SetSelCTM(nTransformed,ctm)5373 void SetSelCTM(nTransformed, ctm)
5374 int nTransformed;
5375 struct XfrmMtrxRec *ctm;
5376 {
5377 struct SelRec *sel_ptr=NULL;
5378 int ltx=selLtX, lty=selLtY, rbx=selRbX, rby=selRbY, changed=FALSE;
5379
5380 if (topSel == NULL) {
5381 MsgBox(TgLoadCachedString(CSTID_NO_OBJ_SELECTED), TOOL_NAME, INFO_MB);
5382 return;
5383 }
5384 if (numObjSelected == numObjLocked) {
5385 MsgBox(TgLoadString(STID_LOCKED_OBJS_CANT_BE_XFORMED), TOOL_NAME,
5386 INFO_MB);
5387 return;
5388 }
5389 HighLightReverse();
5390 StartCompositeCmd();
5391 for (sel_ptr=botSel; sel_ptr != NULL; sel_ptr=sel_ptr->prev) {
5392 if (OkToTransform(sel_ptr->obj, STID_DISABLE_ON_RESIZE_TRANSFORM)) {
5393 PrepareToReplaceAnObj(sel_ptr->obj);
5394 if (SetObjCTM(sel_ptr->obj, nTransformed, ctm)) {
5395 changed = TRUE;
5396 RecordReplaceAnObj(sel_ptr->obj);
5397 } else {
5398 AbortPrepareCmd(CMD_REPLACE);
5399 }
5400 }
5401 }
5402 EndCompositeCmd();
5403 if (changed) {
5404 SetFileModified(TRUE);
5405 UpdSelBBox();
5406 RedrawAreas(botObj, ltx-GRID_ABS_SIZE(1), lty-GRID_ABS_SIZE(1),
5407 rbx+GRID_ABS_SIZE(1), rby+GRID_ABS_SIZE(1),
5408 selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1),
5409 selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1));
5410 justDupped = FALSE;
5411 if (numObjLocked != 0) {
5412 Msg(TgLoadString(STID_LOCKED_OBJS_ARE_NOT_XFORMED));
5413 }
5414 }
5415 HighLightForward();
5416 }
5417
5418 /* --------------------- Rotate Any Angle --------------------- */
5419
5420 static
RotateBBoxByAnAngle(bbox,d_angle,vs)5421 void RotateBBoxByAnAngle(bbox, d_angle, vs)
5422 struct BBRec *bbox; /* the original bounding box */
5423 int d_angle; /* d_angle is degree*64 */
5424 XPoint *vs; /* array of 5 points */
5425 {
5426 int x, y;
5427
5428 RotatedXY(bbox->ltx, bbox->lty, d_angle, &x, &y);
5429 vs[0].x = vs[4].x = x; vs[0].y = vs[4].y = y;
5430 RotatedXY(bbox->rbx, bbox->lty, d_angle, &x, &y);
5431 vs[1].x = x; vs[1].y = y;
5432 RotatedXY(bbox->rbx, bbox->rby, d_angle, &x, &y);
5433 vs[2].x = x; vs[2].y = y;
5434 RotatedXY(bbox->ltx, bbox->rby, d_angle, &x, &y);
5435 vs[3].x = x; vs[3].y = y;
5436 }
5437
5438 static
RotateVsByAnAngle(InVs,NumPts,d_angle,OutVs)5439 void RotateVsByAnAngle(InVs, NumPts, d_angle, OutVs)
5440 XPoint *InVs, *OutVs;
5441 int NumPts, d_angle;
5442 {
5443 register int i;
5444
5445 for (i=0; i < NumPts; i++) {
5446 int x, y;
5447
5448 RotatedXY(InVs[i].x, InVs[i].y, d_angle, &x, &y);
5449 OutVs[i].x = x;
5450 OutVs[i].y = y;
5451 }
5452 }
5453
5454 static
RotateAllSelObjects(Corner,AngleDelta)5455 void RotateAllSelObjects(Corner, AngleDelta)
5456 int Corner, AngleDelta; /* AngleDelta is degree*64 */
5457 {
5458 register struct SelRec *sel_ptr;
5459
5460 for (sel_ptr = topSel; sel_ptr != NULL; sel_ptr = sel_ptr->next) {
5461 if (OkToTransform(sel_ptr->obj, STID_DISABLE_ON_RESIZE_ROTATE)) {
5462 RotateObj(sel_ptr->obj, Corner, AngleDelta, NULL, NULL);
5463 }
5464 }
5465 if (numObjLocked != 0) {
5466 Msg(TgLoadString(STID_LOCKED_OBJS_ARE_NOT_ROTATED));
5467 }
5468 }
5469
5470 static
ConstrainedRotateAllSel(Corner,AngleDelta,ltx,lty,rbx,rby)5471 int ConstrainedRotateAllSel(Corner, AngleDelta, ltx, lty, rbx, rby)
5472 int Corner, AngleDelta, *ltx, *lty, *rbx, *rby;
5473 {
5474 register struct ObjRec *obj_ptr;
5475 int something_stretched=FALSE, num_pts;
5476 int x_off, y_off, move_first, move_last, x, y;
5477 IntPoint *v;
5478
5479 for (obj_ptr=botObj; obj_ptr != NULL; obj_ptr=obj_ptr->prev) {
5480 if (!obj_ptr->marked && obj_ptr->type==OBJ_POLY && !obj_ptr->locked) {
5481 num_pts = obj_ptr->detail.p->n;
5482 v = obj_ptr->detail.p->vlist;
5483
5484 if (obj_ptr->ctm == NULL) {
5485 x_off = OFFSET_X(v[0].x); y_off = OFFSET_Y(v[0].y);
5486 move_first = EndPtInSelected(x_off, y_off);
5487 x_off = OFFSET_X(v[num_pts-1].x); y_off = OFFSET_Y(v[num_pts-1].y);
5488 move_last = EndPtInSelected(x_off, y_off);
5489 } else {
5490 int tmp_x, tmp_y;
5491
5492 TransformPointThroughCTM(v[0].x-obj_ptr->x, v[0].y-obj_ptr->y,
5493 obj_ptr->ctm, &tmp_x, &tmp_y);
5494 tmp_x += obj_ptr->x;
5495 tmp_y += obj_ptr->y;
5496 x_off = OFFSET_X(tmp_x); y_off = OFFSET_Y(tmp_y);
5497 move_first = EndPtInSelected(x_off, y_off);
5498 TransformPointThroughCTM(v[num_pts-1].x-obj_ptr->x,
5499 v[num_pts-1].y-obj_ptr->y, obj_ptr->ctm, &tmp_x, &tmp_y);
5500 tmp_x += obj_ptr->x;
5501 tmp_y += obj_ptr->y;
5502 x_off = OFFSET_X(tmp_x); y_off = OFFSET_Y(tmp_y);
5503 move_last = EndPtInSelected(x_off, y_off);
5504 }
5505 if (move_first || move_last) {
5506 int index=INVALID, seg_dx, seg_dy, dx, dy, cur_seg_dx, cur_seg_dy;
5507
5508 PrepareToReplaceAnObj(obj_ptr);
5509
5510 if (obj_ptr->ctm != NULL) {
5511 /* Remove the transformations! */
5512 int i;
5513
5514 for (i=0; i < num_pts; i++) {
5515 int tmp_x, tmp_y;
5516
5517 TransformPointThroughCTM(v[i].x-obj_ptr->x, v[i].y-obj_ptr->y,
5518 obj_ptr->ctm, &tmp_x, &tmp_y);
5519 v[i].x = tmp_x+obj_ptr->x;
5520 v[i].y = tmp_y+obj_ptr->y;
5521 }
5522 free(obj_ptr->ctm);
5523 obj_ptr->ctm = NULL;
5524 UpdPolyBBox(obj_ptr, num_pts, v);
5525 }
5526 if (something_stretched) {
5527 if (obj_ptr->bbox.ltx < *ltx) *ltx = obj_ptr->bbox.ltx;
5528 if (obj_ptr->bbox.lty < *lty) *lty = obj_ptr->bbox.lty;
5529 if (obj_ptr->bbox.rbx > *rbx) *rbx = obj_ptr->bbox.rbx;
5530 if (obj_ptr->bbox.rby > *rby) *rby = obj_ptr->bbox.rby;
5531 } else {
5532 *ltx = obj_ptr->bbox.ltx; *lty = obj_ptr->bbox.lty;
5533 *rbx = obj_ptr->bbox.rbx; *rby = obj_ptr->bbox.rby;
5534 }
5535 something_stretched = TRUE;
5536 if (move_first && move_last && num_pts==3) {
5537 RotatedAbsXY(v[0].x, v[0].y, AngleDelta, &x, &y);
5538 dx = x-v[0].x; dy = y-v[0].y;
5539 index = 1;
5540 cur_seg_dx = v[index-1].x - v[index].x;
5541 cur_seg_dy = v[index-1].y - v[index].y;
5542 seg_dx = v[index].x - v[index+1].x;
5543 seg_dy = v[index].y - v[index+1].y;
5544
5545 if (cur_seg_dy==0 && seg_dx==0 &&
5546 (seg_dy!=0 || (seg_dy==0 && dx==0))) {
5547 v[index].y += dy;
5548 } else if (cur_seg_dx==0 && seg_dy==0 &&
5549 (seg_dx!=0 || (seg_dx==0 && dy==0))) {
5550 v[index].x += dx;
5551 }
5552 } else {
5553 if (move_first && num_pts>2) {
5554 RotatedAbsXY(v[0].x, v[0].y, AngleDelta, &x, &y);
5555 dx = x-v[0].x; dy = y-v[0].y;
5556 index = 1;
5557 cur_seg_dx = v[index-1].x - v[index].x;
5558 cur_seg_dy = v[index-1].y - v[index].y;
5559 seg_dx = v[index].x - v[index+1].x;
5560 seg_dy = v[index].y - v[index+1].y;
5561
5562 if (cur_seg_dy==0 && cur_seg_dx!=0 &&
5563 (seg_dy!=0 || (seg_dy==0 && dx==0))) {
5564 v[index].y += dy;
5565 } else if (cur_seg_dx==0 && cur_seg_dy!=0 &&
5566 (seg_dx!=0 || (seg_dx==0 && dy==0))) {
5567 v[index].x += dx;
5568 }
5569 }
5570 if (move_last && num_pts>2) {
5571 RotatedAbsXY(v[num_pts-1].x, v[num_pts-1].y, AngleDelta,
5572 &x, &y);
5573 dx = x-v[num_pts-1].x; dy = y-v[num_pts-1].y;
5574 index = num_pts-2;
5575 cur_seg_dx = v[index+1].x - v[index].x;
5576 cur_seg_dy = v[index+1].y - v[index].y;
5577 seg_dx = v[index].x - v[index-1].x;
5578 seg_dy = v[index].y - v[index-1].y;
5579
5580 if (cur_seg_dy==0 && cur_seg_dx!=0 &&
5581 (seg_dy!=0 || (seg_dy==0 && dx==0))) {
5582 v[index].y += dy;
5583 } else if (cur_seg_dx==0 && cur_seg_dy!=0 &&
5584 (seg_dx!=0 || (seg_dx==0 && dy==0))) {
5585 v[index].x += dx;
5586 }
5587 }
5588 }
5589 if (move_first) {
5590 RotatedAbsXY(v[0].x, v[0].y, AngleDelta, &x, &y);
5591 v[0].x = x; v[0].y = y;
5592 }
5593 if (move_last) {
5594 RotatedAbsXY(v[num_pts-1].x, v[num_pts-1].y, AngleDelta,
5595 &x, &y);
5596 v[num_pts-1].x = x; v[num_pts-1].y = y;
5597 }
5598 AdjObjSplineVs(obj_ptr);
5599 switch (obj_ptr->type) {
5600 case OBJ_POLY:
5601 if (obj_ptr->detail.p->curved != LT_INTSPLINE) {
5602 UpdPolyBBox(obj_ptr, num_pts, v);
5603 } else {
5604 UpdPolyBBox(obj_ptr, obj_ptr->detail.p->intn,
5605 obj_ptr->detail.p->intvlist);
5606 }
5607 break;
5608 case OBJ_POLYGON:
5609 if (obj_ptr->detail.g->curved != LT_INTSPLINE) {
5610 UpdPolyBBox(obj_ptr, num_pts, v);
5611 } else {
5612 UpdPolyBBox(obj_ptr, obj_ptr->detail.g->intn,
5613 obj_ptr->detail.g->intvlist);
5614 }
5615 break;
5616 }
5617 AdjObjBBox(obj_ptr);
5618 if (AutoCenterAttr(obj_ptr)) {
5619 struct AttrRec *attr_ptr=obj_ptr->fattr;
5620 int modified=FALSE;
5621
5622 for ( ; attr_ptr != NULL; attr_ptr = attr_ptr->next) {
5623 if (attr_ptr->shown) {
5624 struct BBRec bbox;
5625
5626 CenterObjInOBBox(attr_ptr->obj, obj_ptr->obbox, &bbox);
5627 if (bbox.ltx < *ltx) *ltx = bbox.ltx;
5628 if (bbox.lty < *lty) *lty = bbox.lty;
5629 if (bbox.rbx > *rbx) *rbx = bbox.rbx;
5630 if (bbox.rby > *rby) *rby = bbox.rby;
5631 modified = TRUE;
5632 }
5633 }
5634 if (modified) AdjObjBBox(obj_ptr);
5635 }
5636 if (obj_ptr->bbox.ltx < *ltx) *ltx = obj_ptr->bbox.ltx;
5637 if (obj_ptr->bbox.lty < *lty) *lty = obj_ptr->bbox.lty;
5638 if (obj_ptr->bbox.rbx > *rbx) *rbx = obj_ptr->bbox.rbx;
5639 if (obj_ptr->bbox.rby > *rby) *rby = obj_ptr->bbox.rby;
5640 RecordReplaceAnObj(obj_ptr);
5641 }
5642 }
5643 }
5644 return something_stretched;
5645 }
5646
5647 static
RotateAllSel(Corner,AngleDelta)5648 void RotateAllSel(Corner, AngleDelta)
5649 int Corner, AngleDelta; /* AngleDelta is degree*64 */
5650 {
5651 int ltx=0, lty=0, rbx=0, rby=0, saved_ltx, saved_lty, saved_rbx, saved_rby;
5652 int poly_stretched;
5653
5654 saved_ltx = selLtX; saved_lty = selLtY;
5655 saved_rbx = selRbX; saved_rby = selRbY;
5656
5657 if (moveMode==CONST_MOVE) {
5658 MarkObjectsForStretch();
5659
5660 StartCompositeCmd();
5661 PrepareToRecord(CMD_STRETCH, topSel, botSel, numObjSelected);
5662 RecordCmd(CMD_STRETCH, NULL, topSel, botSel, numObjSelected);
5663
5664 poly_stretched = ConstrainedRotateAllSel(Corner, AngleDelta,
5665 <x, <y, &rbx, &rby);
5666 RotateAllSelObjects(Corner, AngleDelta);
5667 UpdSelBBox();
5668 if (poly_stretched) {
5669 ltx = min(ltx,min(selLtX,saved_ltx));
5670 lty = min(lty,min(selLtY,saved_lty));
5671 rbx = max(rbx,max(selRbX,saved_rbx));
5672 rby = max(rby,max(selRbY,saved_rby));
5673 RedrawAnArea(botObj, ltx-GRID_ABS_SIZE(1), lty-GRID_ABS_SIZE(1),
5674 rbx+GRID_ABS_SIZE(1), rby+GRID_ABS_SIZE(1));
5675 } else {
5676 RedrawAreas(botObj, saved_ltx-GRID_ABS_SIZE(1),
5677 saved_lty-GRID_ABS_SIZE(1),
5678 saved_rbx+GRID_ABS_SIZE(1), saved_rby+GRID_ABS_SIZE(1),
5679 selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1),
5680 selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1));
5681 }
5682 EndCompositeCmd();
5683 } else {
5684 PrepareToRecord(CMD_REPLACE, topSel, botSel, numObjSelected);
5685 RotateAllSelObjects(Corner, AngleDelta);
5686 RecordCmd(CMD_REPLACE, NULL, topSel, botSel, numObjSelected);
5687 UpdSelBBox();
5688 RedrawAreas(botObj, saved_ltx-GRID_ABS_SIZE(1),
5689 saved_lty-GRID_ABS_SIZE(1),
5690 saved_rbx+GRID_ABS_SIZE(1), saved_rby+GRID_ABS_SIZE(1),
5691 selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1),
5692 selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1));
5693 }
5694 }
5695
5696 static
FormatAngleForRotate(buf,angle)5697 void FormatAngleForRotate(buf, angle)
5698 char *buf;
5699 int angle;
5700 {
5701 float fval=(float)(((float)angle)/((float)64.0));
5702
5703 sprintf(buf, "degree=%.2f", fval);
5704 }
5705
5706 static
RotateSel(XGridOff,YGridOff,ObjPtr,Corner)5707 void RotateSel(XGridOff, YGridOff, ObjPtr, Corner)
5708 int XGridOff, YGridOff, Corner;
5709 struct ObjRec *ObjPtr;
5710 {
5711 register int i;
5712 XEvent ev;
5713 XPoint all_bbox_vs[5], obj_obbox_vs[5], *vs=NULL, *orig_vs=NULL;
5714 int grid_x=XGridOff, grid_y=YGridOff, dx, dy, d_angle=0;
5715 int saved_x=XGridOff, saved_y=YGridOff;
5716 int rotating=TRUE, deg360=(360<<6), n=0;
5717 char buf[80];
5718 struct BBRec orig_all_bbox, orig_obj_obbox;
5719
5720 if (numObjSelected == numObjLocked || ObjPtr->locked) {
5721 MsgBox(TgLoadString(STID_LOCKED_OBJS_CANT_BE_ROTATED), TOOL_NAME,
5722 INFO_MB);
5723 return;
5724 }
5725 XFlush(mainDisplay);
5726 XSync(mainDisplay, False);
5727 if (XCheckMaskEvent(mainDisplay, ExposureMask, &ev) ||
5728 XCheckMaskEvent(mainDisplay, VisibilityChangeMask, &ev)) {
5729 ExposeEventHandler(&ev, TRUE);
5730 }
5731 if (ObjPtr->type==OBJ_POLY || ObjPtr->type==OBJ_POLYGON) {
5732 IntPoint *pv;
5733 int px, py;
5734
5735 if (ObjPtr->ctm == NULL) {
5736 pv = (ObjPtr->type==OBJ_POLY ? &ObjPtr->detail.p->vlist[Corner] :
5737 &ObjPtr->detail.g->vlist[Corner]);
5738 px = pv->x;
5739 py = pv->y;
5740 } else {
5741 pv = (ObjPtr->type==OBJ_POLY ? &ObjPtr->detail.p->vlist[Corner] :
5742 &ObjPtr->detail.g->vlist[Corner]);
5743 TransformPointThroughCTM(pv->x-ObjPtr->x, pv->y-ObjPtr->y,
5744 ObjPtr->ctm, &px, &py);
5745 px += ObjPtr->x;
5746 py += ObjPtr->y;
5747 }
5748 absPivotX = (ObjPtr->obbox.ltx+ObjPtr->obbox.rbx)>>1;
5749 absPivotY = (ObjPtr->obbox.lty+ObjPtr->obbox.rby)>>1;
5750 moveX = OFFSET_X(px);
5751 moveY = OFFSET_Y(py);
5752 changeX = changeY = TRUE;
5753 multX = multY = 1.0;
5754 pivotX = OFFSET_X(absPivotX);
5755 pivotY = OFFSET_Y(absPivotY);
5756 } else {
5757 SetPivot(Corner, &ObjPtr->obbox);
5758 }
5759 if (!autoRotatePivot && rotatePivotAbsXYValid) {
5760 absPivotX = rotatePivotAbsX;
5761 absPivotY = rotatePivotAbsY;
5762 pivotX = OFFSET_X(absPivotX);
5763 pivotY = OFFSET_Y(absPivotY);
5764 }
5765 SetBBRec(&orig_all_bbox, OFFSET_X(selNoLockLtX)-2, OFFSET_Y(selNoLockLtY)-2,
5766 OFFSET_X(selNoLockRbX)+2, OFFSET_Y(selNoLockRbY)+2);
5767 SetRotateVs(all_bbox_vs, orig_all_bbox.ltx, orig_all_bbox.lty,
5768 orig_all_bbox.rbx, orig_all_bbox.rby);
5769 XDrawLines(mainDisplay, drawWindow, revDefaultGC, all_bbox_vs, 5,
5770 CoordModeOrigin);
5771
5772 if (ObjPtr->type==OBJ_POLY || ObjPtr->type==OBJ_POLYGON) {
5773 if (ObjPtr->type == OBJ_POLY) {
5774 if (ObjPtr->ctm == NULL) {
5775 n = ObjPtr->detail.p->sn;
5776 orig_vs = (XPoint*)malloc(n*sizeof(XPoint));
5777 vs = (XPoint*)malloc(n*sizeof(XPoint));
5778 if (orig_vs == NULL || vs == NULL) FailAllocMessage();
5779 for (i=0; i < n; i++) {
5780 vs[i].x = orig_vs[i].x = ObjPtr->detail.p->svlist[i].x;
5781 vs[i].y = orig_vs[i].y = ObjPtr->detail.p->svlist[i].y;
5782 }
5783 } else {
5784 n = ObjPtr->detail.p->rotated_n;
5785 orig_vs = (XPoint*)malloc(n*sizeof(XPoint));
5786 vs = (XPoint*)malloc(n*sizeof(XPoint));
5787 if (orig_vs == NULL || vs == NULL) FailAllocMessage();
5788 for (i=0; i < n; i++) {
5789 vs[i].x = orig_vs[i].x = ObjPtr->detail.p->rotated_vlist[i].x;
5790 vs[i].y = orig_vs[i].y = ObjPtr->detail.p->rotated_vlist[i].y;
5791 }
5792 }
5793 } else {
5794 if (ObjPtr->ctm == NULL) {
5795 n = ObjPtr->detail.g->sn;
5796 orig_vs = (XPoint*)malloc(n*sizeof(XPoint));
5797 vs = (XPoint*)malloc(n*sizeof(XPoint));
5798 if (orig_vs == NULL || vs == NULL) FailAllocMessage();
5799 for (i=0; i < n; i++) {
5800 vs[i].x = orig_vs[i].x = ObjPtr->detail.g->svlist[i].x;
5801 vs[i].y = orig_vs[i].y = ObjPtr->detail.g->svlist[i].y;
5802 }
5803 } else {
5804 n = ObjPtr->detail.g->rotated_n;
5805 orig_vs = (XPoint*)malloc(n*sizeof(XPoint));
5806 vs = (XPoint*)malloc(n*sizeof(XPoint));
5807 if (orig_vs == NULL || vs == NULL) FailAllocMessage();
5808 for (i=0; i < n; i++) {
5809 vs[i].x = orig_vs[i].x = ObjPtr->detail.g->rotated_vlist[i].x;
5810 vs[i].y = orig_vs[i].y = ObjPtr->detail.g->rotated_vlist[i].y;
5811 }
5812 }
5813 }
5814 XDrawLines(mainDisplay, drawWindow, revDefaultGC, vs, n,
5815 CoordModeOrigin);
5816 } else {
5817 if (ObjPtr->ctm == NULL) {
5818 SetBBRec(&orig_obj_obbox, OFFSET_X(ObjPtr->obbox.ltx),
5819 OFFSET_Y(ObjPtr->obbox.lty), OFFSET_X(ObjPtr->obbox.rbx),
5820 OFFSET_Y(ObjPtr->obbox.rby));
5821 SetRotateVs(obj_obbox_vs, orig_obj_obbox.ltx, orig_obj_obbox.lty,
5822 orig_obj_obbox.rbx, orig_obj_obbox.rby);
5823 XDrawLines(mainDisplay, drawWindow, revDefaultGC, obj_obbox_vs, 5,
5824 CoordModeOrigin);
5825 } else {
5826 memcpy(obj_obbox_vs, ObjPtr->rotated_obbox, 5*sizeof(XPoint));
5827 XDrawLines(mainDisplay, drawWindow, revDefaultGC, obj_obbox_vs, 5,
5828 CoordModeOrigin);
5829 }
5830 }
5831 dx = OFFSET_X(ObjPtr->obbox.rbx) - OFFSET_X(ObjPtr->obbox.ltx);
5832 dy = OFFSET_Y(ObjPtr->obbox.rby) - OFFSET_Y(ObjPtr->obbox.lty);
5833 if (dx == 0 && dy == 0) {
5834 MsgBox(TgLoadString(STID_SEL_OBJ_TOO_SMALL_ROT_ANOTHER), TOOL_NAME,
5835 INFO_MB);
5836 return;
5837 }
5838 grid_x = moveX;
5839 grid_y = moveY;
5840 FormatAngleForRotate(buf, 0);
5841 StartShowMeasureCursor(grid_x, grid_y, buf, TRUE);
5842 if (!debugNoPointerGrab) {
5843 XGrabPointer(mainDisplay, drawWindow, False,
5844 PointerMotionMask | ButtonReleaseMask,
5845 GrabModeAsync, GrabModeAsync, None, rotatingCursor, CurrentTime);
5846 }
5847 while (rotating) {
5848 XEvent input;
5849
5850 XNextEvent(mainDisplay, &input);
5851
5852 if (input.type == Expose || input.type == VisibilityNotify) {
5853 ExposeEventHandler(&input, TRUE);
5854 } else if (input.type == ButtonRelease) {
5855 XUngrabPointer(mainDisplay, CurrentTime);
5856 XSync(mainDisplay, False);
5857 rotating = FALSE;
5858 FormatAngleForRotate(buf, d_angle);
5859 EndShowMeasureCursor(grid_x, grid_y, buf, TRUE);
5860 if (ObjPtr->type==OBJ_POLY || ObjPtr->type==OBJ_POLYGON) {
5861 XDrawLines(mainDisplay, drawWindow, revDefaultGC, vs, n,
5862 CoordModeOrigin);
5863 } else {
5864 XDrawLines(mainDisplay, drawWindow, revDefaultGC, obj_obbox_vs, 5,
5865 CoordModeOrigin);
5866 }
5867 XDrawLines(mainDisplay, drawWindow, revDefaultGC, all_bbox_vs, 5,
5868 CoordModeOrigin);
5869 } else if (input.type == MotionNotify || input.type == KeyPress ||
5870 input.type == KeyRelease) {
5871 int end_x=0, end_y=0;
5872
5873 FormatAngleForRotate(buf, d_angle);
5874 ShowMeasureCursor(grid_x, grid_y, buf, TRUE);
5875 if (ObjPtr->type==OBJ_POLY || ObjPtr->type==OBJ_POLYGON) {
5876 XDrawLines(mainDisplay, drawWindow, revDefaultGC, vs, n,
5877 CoordModeOrigin);
5878 } else {
5879 XDrawLines(mainDisplay, drawWindow, revDefaultGC, obj_obbox_vs, 5,
5880 CoordModeOrigin);
5881 }
5882 XDrawLines(mainDisplay, drawWindow, revDefaultGC, all_bbox_vs, 5,
5883 CoordModeOrigin);
5884
5885 if (input.type == KeyPress || input.type == KeyRelease) {
5886 end_x = grid_x;
5887 end_y = grid_y;
5888 } else {
5889 end_x = input.xmotion.x;
5890 end_y = input.xmotion.y;
5891 }
5892 GridXY(end_x, end_y, &grid_x, &grid_y);
5893 dx = grid_x - saved_x;
5894 dy = grid_y - saved_y;
5895 grid_x = moveX + dx;
5896 grid_y = moveY + dy;
5897 MarkRulers(grid_x, grid_y);
5898 PointsToArc(pivotX, pivotY, moveX, moveY, grid_x, grid_y,
5899 ARC_CW, FALSE, NULL, NULL, NULL, NULL, NULL, &d_angle);
5900 if (shiftForDiagMouseMove && DiagEventCheck(&input)) {
5901 int tmp_angle=(int)(((double)d_angle) / ((double)(45<<5)));
5902
5903 if (tmp_angle & 0x1) {
5904 if (tmp_angle > 0) {
5905 tmp_angle = ((tmp_angle+1)>>1);
5906 } else {
5907 tmp_angle = ((tmp_angle-1)>>1);
5908 }
5909 } else {
5910 tmp_angle >>= 1;
5911 }
5912 d_angle = tmp_angle * (45<<6);
5913 }
5914 if (d_angle == deg360) d_angle = 0;
5915 d_angle = (-d_angle);
5916 while (d_angle >= (deg360)) d_angle -= (deg360);
5917
5918 RotateBBoxByAnAngle(&orig_all_bbox, d_angle, all_bbox_vs);
5919 XDrawLines(mainDisplay, drawWindow, revDefaultGC, all_bbox_vs, 5,
5920 CoordModeOrigin);
5921 if (ObjPtr->type==OBJ_POLY || ObjPtr->type==OBJ_POLYGON) {
5922 RotateVsByAnAngle(orig_vs, n, d_angle, vs);
5923 XDrawLines(mainDisplay, drawWindow, revDefaultGC, vs, n,
5924 CoordModeOrigin);
5925 } else {
5926 if (ObjPtr->ctm == NULL) {
5927 RotateBBoxByAnAngle(&orig_obj_obbox, d_angle, obj_obbox_vs);
5928 } else {
5929 RotateVsByAnAngle(ObjPtr->rotated_obbox, 5, d_angle,
5930 obj_obbox_vs);
5931 }
5932 XDrawLines(mainDisplay, drawWindow, revDefaultGC, obj_obbox_vs, 5,
5933 CoordModeOrigin);
5934 }
5935 FormatAngleForRotate(buf, d_angle);
5936 ShowMeasureCursor(grid_x, grid_y, buf, TRUE);
5937 while (XCheckMaskEvent(mainDisplay, PointerMotionMask, &ev)) ;
5938 }
5939 }
5940 if (d_angle != 0) {
5941 HighLightReverse();
5942 RotateAllSel(Corner, d_angle);
5943 HighLightForward();
5944 SetFileModified(TRUE);
5945 justDupped = FALSE;
5946 }
5947 if (vs != NULL) free(vs);
5948 if (orig_vs != NULL) free(orig_vs);
5949 }
5950
5951 /* --------------------- Shearing --------------------- */
5952
5953 static
ShearBBox(Corner,bbox,dx_shear,dy_shear,dx_scale,dy_scale,vs)5954 void ShearBBox(Corner, bbox, dx_shear, dy_shear, dx_scale, dy_scale, vs)
5955 int Corner;
5956 double dx_shear, dy_shear, dx_scale, dy_scale;
5957 struct BBRec *bbox; /* the original bounding box */
5958 XPoint *vs; /* array of 5 points */
5959 {
5960 int x, y;
5961
5962 switch (Corner) {
5963 case CORNER_TOP:
5964 case CORNER_BOTTOM:
5965 if (bbox->lty == pivotY) {
5966 vs[0].x = vs[4].x = bbox->ltx;
5967 vs[0].y = vs[4].y = bbox->lty;
5968 vs[1].x = bbox->rbx; vs[1].y = bbox->lty;
5969 } else {
5970 ShearedXY(Corner, bbox->ltx, bbox->lty, dx_shear, dy_shear,
5971 dx_scale, dy_scale, &x, &y);
5972 vs[0].x = vs[4].x = x; vs[0].y = vs[4].y = y;
5973 ShearedXY(Corner, bbox->rbx, bbox->lty, dx_shear, dy_shear,
5974 dx_scale, dy_scale, &x, &y);
5975 vs[1].x = x; vs[1].y = y;
5976 }
5977 if (bbox->rby == pivotY) {
5978 vs[2].x = bbox->rbx; vs[2].y = bbox->rby;
5979 vs[3].x = bbox->ltx; vs[3].y = bbox->rby;
5980 } else {
5981 ShearedXY(Corner, bbox->rbx, bbox->rby, dx_shear, dy_shear,
5982 dx_scale, dy_scale, &x, &y);
5983 vs[2].x = x; vs[2].y = y;
5984 ShearedXY(Corner, bbox->ltx, bbox->rby, dx_shear, dy_shear,
5985 dx_scale, dy_scale, &x, &y);
5986 vs[3].x = x; vs[3].y = y;
5987 }
5988 break;
5989 case CORNER_RIGHT:
5990 case CORNER_LEFT:
5991 if (bbox->ltx == pivotX) {
5992 vs[0].x = vs[4].x = bbox->ltx;
5993 vs[0].y = vs[4].y = bbox->lty;
5994 vs[3].x = bbox->ltx; vs[3].y = bbox->rby;
5995 } else {
5996 ShearedXY(Corner, bbox->ltx, bbox->lty, dx_shear, dy_shear,
5997 dx_scale, dy_scale, &x, &y);
5998 vs[0].x = vs[4].x = x; vs[0].y = vs[4].y = y;
5999 ShearedXY(Corner, bbox->ltx, bbox->rby, dx_shear, dy_shear,
6000 dx_scale, dy_scale, &x, &y);
6001 vs[3].x = x; vs[3].y = y;
6002 }
6003 if (bbox->rbx == pivotX) {
6004 vs[1].x = bbox->rbx; vs[1].y = bbox->lty;
6005 vs[2].x = bbox->rbx; vs[2].y = bbox->rby;
6006 } else {
6007 ShearedXY(Corner, bbox->rbx, bbox->lty, dx_shear, dy_shear,
6008 dx_scale, dy_scale, &x, &y);
6009 vs[1].x = x; vs[1].y = y;
6010 ShearedXY(Corner, bbox->rbx, bbox->rby, dx_shear, dy_shear,
6011 dx_scale, dy_scale, &x, &y);
6012 vs[2].x = x; vs[2].y = y;
6013 }
6014 break;
6015 }
6016 }
6017
6018 static
ShearVs(Corner,InVs,NumPts,dx_shear,dy_shear,dx_scale,dy_scale,OutVs)6019 void ShearVs(Corner, InVs, NumPts, dx_shear, dy_shear, dx_scale, dy_scale,
6020 OutVs)
6021 int Corner, NumPts;
6022 double dx_shear, dy_shear, dx_scale, dy_scale;
6023 XPoint *InVs, *OutVs; /* array of 5 points */
6024 {
6025 register int i;
6026 int x, y;
6027
6028 switch (Corner) {
6029 case CORNER_TOP:
6030 case CORNER_BOTTOM:
6031 for (i=0; i < NumPts; i++) {
6032 if (InVs[i].y == pivotY) {
6033 OutVs[i].x = InVs[i].x;
6034 OutVs[i].y = InVs[i].y;
6035 } else {
6036 ShearedXY(Corner, InVs[i].x, InVs[i].y, dx_shear, dy_shear,
6037 dx_scale, dy_scale, &x, &y);
6038 OutVs[i].x = x;
6039 OutVs[i].y = y;
6040 }
6041 }
6042 break;
6043 case CORNER_RIGHT:
6044 case CORNER_LEFT:
6045 for (i=0; i < NumPts; i++) {
6046 if (InVs[i].x == pivotX) {
6047 OutVs[i].x = InVs[i].x;
6048 OutVs[i].y = InVs[i].y;
6049 } else {
6050 ShearedXY(Corner, InVs[i].x, InVs[i].y, dx_shear, dy_shear,
6051 dx_scale, dy_scale, &x, &y);
6052 OutVs[i].x = x;
6053 OutVs[i].y = y;
6054 }
6055 }
6056 break;
6057 }
6058 }
6059
6060 static
ShearAllSelObjects(Corner,dxShear,dyShear,dxScale,dyScale)6061 void ShearAllSelObjects(Corner, dxShear, dyShear, dxScale, dyScale)
6062 int Corner;
6063 double dxShear, dyShear, dxScale, dyScale; /* everything scaled by 1000 */
6064 {
6065 register struct SelRec *sel_ptr;
6066
6067 for (sel_ptr = topSel; sel_ptr != NULL; sel_ptr = sel_ptr->next) {
6068 if (OkToTransform(sel_ptr->obj, STID_DISABLE_ON_RESIZE_SHEAR)) {
6069 ShearObj(sel_ptr->obj, Corner, dxShear, dyShear, dxScale, dyScale,
6070 NULL, NULL);
6071 }
6072 }
6073 if (numObjLocked != 0) {
6074 Msg(TgLoadString(STID_LOCKED_OBJS_ARE_NOT_SHEARED));
6075 }
6076 }
6077
6078 static
ConstrainedShearAllSel(Corner,dxShear,dyShear,dxScale,dyScale,ltx,lty,rbx,rby)6079 int ConstrainedShearAllSel(Corner, dxShear, dyShear, dxScale, dyScale,
6080 ltx, lty, rbx, rby)
6081 int Corner, *ltx, *lty, *rbx, *rby;
6082 double dxShear, dyShear, dxScale, dyScale;
6083 {
6084 register struct ObjRec *obj_ptr;
6085 int something_stretched=FALSE, num_pts;
6086 int x_off, y_off, move_first, move_last, x, y;
6087 IntPoint *v;
6088
6089 for (obj_ptr=botObj; obj_ptr != NULL; obj_ptr=obj_ptr->prev) {
6090 if (!obj_ptr->marked && obj_ptr->type==OBJ_POLY && !obj_ptr->locked) {
6091 num_pts = obj_ptr->detail.p->n;
6092 v = obj_ptr->detail.p->vlist;
6093
6094 if (obj_ptr->ctm == NULL) {
6095 x_off = OFFSET_X(v[0].x); y_off = OFFSET_Y(v[0].y);
6096 move_first = EndPtInSelected(x_off, y_off);
6097 x_off = OFFSET_X(v[num_pts-1].x); y_off = OFFSET_Y(v[num_pts-1].y);
6098 move_last = EndPtInSelected(x_off, y_off);
6099 } else {
6100 int tmp_x, tmp_y;
6101
6102 TransformPointThroughCTM(v[0].x-obj_ptr->x, v[0].y-obj_ptr->y,
6103 obj_ptr->ctm, &tmp_x, &tmp_y);
6104 tmp_x += obj_ptr->x;
6105 tmp_y += obj_ptr->y;
6106 x_off = OFFSET_X(tmp_x); y_off = OFFSET_Y(tmp_y);
6107 move_first = EndPtInSelected(x_off, y_off);
6108 TransformPointThroughCTM(v[num_pts-1].x-obj_ptr->x,
6109 v[num_pts-1].y-obj_ptr->y, obj_ptr->ctm, &tmp_x, &tmp_y);
6110 tmp_x += obj_ptr->x;
6111 tmp_y += obj_ptr->y;
6112 x_off = OFFSET_X(tmp_x); y_off = OFFSET_Y(tmp_y);
6113 move_last = EndPtInSelected(x_off, y_off);
6114 }
6115
6116 if (move_first || move_last) {
6117 int index=INVALID, seg_dx, seg_dy, dx, dy, cur_seg_dx, cur_seg_dy;
6118
6119 PrepareToReplaceAnObj(obj_ptr);
6120
6121 if (obj_ptr->ctm != NULL) {
6122 /* Remove the transformations! */
6123 int i;
6124
6125 for (i=0; i < num_pts; i++) {
6126 int tmp_x, tmp_y;
6127
6128 TransformPointThroughCTM(v[i].x-obj_ptr->x, v[i].y-obj_ptr->y,
6129 obj_ptr->ctm, &tmp_x, &tmp_y);
6130 v[i].x = tmp_x+obj_ptr->x;
6131 v[i].y = tmp_y+obj_ptr->y;
6132 }
6133 free(obj_ptr->ctm);
6134 obj_ptr->ctm = NULL;
6135 UpdPolyBBox(obj_ptr, num_pts, v);
6136 }
6137 if (something_stretched) {
6138 if (obj_ptr->bbox.ltx < *ltx) *ltx = obj_ptr->bbox.ltx;
6139 if (obj_ptr->bbox.lty < *lty) *lty = obj_ptr->bbox.lty;
6140 if (obj_ptr->bbox.rbx > *rbx) *rbx = obj_ptr->bbox.rbx;
6141 if (obj_ptr->bbox.rby > *rby) *rby = obj_ptr->bbox.rby;
6142 } else {
6143 *ltx = obj_ptr->bbox.ltx; *lty = obj_ptr->bbox.lty;
6144 *rbx = obj_ptr->bbox.rbx; *rby = obj_ptr->bbox.rby;
6145 }
6146 something_stretched = TRUE;
6147 if (move_first && move_last && num_pts==3) {
6148 ShearedAbsXY(Corner, v[0].x, v[0].y, dxShear, dyShear,
6149 dxScale, dyScale, &x, &y);
6150 dx = x-v[0].x; dy = y-v[0].y;
6151 index = 1;
6152 cur_seg_dx = v[index-1].x - v[index].x;
6153 cur_seg_dy = v[index-1].y - v[index].y;
6154 seg_dx = v[index].x - v[index+1].x;
6155 seg_dy = v[index].y - v[index+1].y;
6156
6157 if (cur_seg_dy==0 && seg_dx==0 &&
6158 (seg_dy!=0 || (seg_dy==0 && dx==0))) {
6159 v[index].y += dy;
6160 } else if (cur_seg_dx==0 && seg_dy==0 &&
6161 (seg_dx!=0 || (seg_dx==0 && dy==0))) {
6162 v[index].x += dx;
6163 }
6164 } else {
6165 if (move_first && num_pts>2) {
6166 ShearedAbsXY(Corner, v[0].x, v[0].y, dxShear, dyShear,
6167 dxScale, dyScale, &x, &y);
6168 dx = x-v[0].x; dy = y-v[0].y;
6169 index = 1;
6170 cur_seg_dx = v[index-1].x - v[index].x;
6171 cur_seg_dy = v[index-1].y - v[index].y;
6172 seg_dx = v[index].x - v[index+1].x;
6173 seg_dy = v[index].y - v[index+1].y;
6174
6175 if (cur_seg_dy==0 && cur_seg_dx!=0 &&
6176 (seg_dy!=0 || (seg_dy==0 && dx==0))) {
6177 v[index].y += dy;
6178 } else if (cur_seg_dx==0 && cur_seg_dy!=0 &&
6179 (seg_dx!=0 || (seg_dx==0 && dy==0))) {
6180 v[index].x += dx;
6181 }
6182 }
6183 if (move_last && num_pts>2) {
6184 ShearedAbsXY(Corner, v[num_pts-1].x, v[num_pts-1].y,
6185 dxShear, dyShear, dxScale, dyScale, &x, &y);
6186 dx = x-v[num_pts-1].x; dy = y-v[num_pts-1].y;
6187 index = num_pts-2;
6188 cur_seg_dx = v[index+1].x - v[index].x;
6189 cur_seg_dy = v[index+1].y - v[index].y;
6190 seg_dx = v[index].x - v[index-1].x;
6191 seg_dy = v[index].y - v[index-1].y;
6192
6193 if (cur_seg_dy==0 && cur_seg_dx!=0 &&
6194 (seg_dy!=0 || (seg_dy==0 && dx==0))) {
6195 v[index].y += dy;
6196 } else if (cur_seg_dx==0 && cur_seg_dy!=0 &&
6197 (seg_dx!=0 || (seg_dx==0 && dy==0))) {
6198 v[index].x += dx;
6199 }
6200 }
6201 }
6202 if (move_first) {
6203 ShearedAbsXY(Corner, v[0].x, v[0].y, dxShear, dyShear,
6204 dxScale, dyScale, &x, &y);
6205 v[0].x = x; v[0].y = y;
6206 }
6207 if (move_last) {
6208 ShearedAbsXY(Corner, v[num_pts-1].x, v[num_pts-1].y,
6209 dxShear, dyShear, dxScale, dyScale, &x, &y);
6210 v[num_pts-1].x = x; v[num_pts-1].y = y;
6211 }
6212 AdjObjSplineVs(obj_ptr);
6213 switch (obj_ptr->type) {
6214 case OBJ_POLY:
6215 if (obj_ptr->detail.p->curved != LT_INTSPLINE) {
6216 UpdPolyBBox(obj_ptr, num_pts, v);
6217 } else {
6218 UpdPolyBBox(obj_ptr, obj_ptr->detail.p->intn,
6219 obj_ptr->detail.p->intvlist);
6220 }
6221 break;
6222 case OBJ_POLYGON:
6223 if (obj_ptr->detail.g->curved != LT_INTSPLINE) {
6224 UpdPolyBBox(obj_ptr, num_pts, v);
6225 } else {
6226 UpdPolyBBox(obj_ptr, obj_ptr->detail.g->intn,
6227 obj_ptr->detail.g->intvlist);
6228 }
6229 break;
6230 }
6231 AdjObjBBox(obj_ptr);
6232 if (AutoCenterAttr(obj_ptr)) {
6233 struct AttrRec *attr_ptr=obj_ptr->fattr;
6234 int modified=FALSE;
6235
6236 for ( ; attr_ptr != NULL; attr_ptr = attr_ptr->next) {
6237 if (attr_ptr->shown) {
6238 struct BBRec bbox;
6239
6240 CenterObjInOBBox(attr_ptr->obj, obj_ptr->obbox, &bbox);
6241 if (bbox.ltx < *ltx) *ltx = bbox.ltx;
6242 if (bbox.lty < *lty) *lty = bbox.lty;
6243 if (bbox.rbx > *rbx) *rbx = bbox.rbx;
6244 if (bbox.rby > *rby) *rby = bbox.rby;
6245 modified = TRUE;
6246 }
6247 }
6248 if (modified) AdjObjBBox(obj_ptr);
6249 }
6250 if (obj_ptr->bbox.ltx < *ltx) *ltx = obj_ptr->bbox.ltx;
6251 if (obj_ptr->bbox.lty < *lty) *lty = obj_ptr->bbox.lty;
6252 if (obj_ptr->bbox.rbx > *rbx) *rbx = obj_ptr->bbox.rbx;
6253 if (obj_ptr->bbox.rby > *rby) *rby = obj_ptr->bbox.rby;
6254 RecordReplaceAnObj(obj_ptr);
6255 }
6256 }
6257 }
6258 return something_stretched;
6259 }
6260
6261 static
ShearAllSel(Corner,dxShear,dyShear,dxScale,dyScale)6262 void ShearAllSel(Corner, dxShear, dyShear, dxScale, dyScale)
6263 int Corner;
6264 double dxShear, dyShear, dxScale, dyScale; /* everything scaled by 1000 */
6265 {
6266 int ltx=0, lty=0, rbx=0, rby=0, saved_ltx, saved_lty, saved_rbx, saved_rby;
6267 int poly_stretched;
6268
6269 saved_ltx = selLtX; saved_lty = selLtY;
6270 saved_rbx = selRbX; saved_rby = selRbY;
6271
6272 if (moveMode==CONST_MOVE) {
6273 MarkObjectsForStretch();
6274
6275 StartCompositeCmd();
6276 PrepareToRecord(CMD_STRETCH, topSel, botSel, numObjSelected);
6277 RecordCmd(CMD_STRETCH, NULL, topSel, botSel, numObjSelected);
6278
6279 poly_stretched = ConstrainedShearAllSel(Corner, dxShear, dyShear, dxScale,
6280 dyScale, <x, <y, &rbx, &rby);
6281 ShearAllSelObjects(Corner, dxShear, dyShear, dxScale, dyScale);
6282 UpdSelBBox();
6283 if (poly_stretched) {
6284 ltx = min(ltx,min(selLtX,saved_ltx));
6285 lty = min(lty,min(selLtY,saved_lty));
6286 rbx = max(rbx,max(selRbX,saved_rbx));
6287 rby = max(rby,max(selRbY,saved_rby));
6288 RedrawAnArea(botObj, ltx-GRID_ABS_SIZE(1), lty-GRID_ABS_SIZE(1),
6289 rbx+GRID_ABS_SIZE(1), rby+GRID_ABS_SIZE(1));
6290 } else {
6291 RedrawAreas(botObj, saved_ltx-GRID_ABS_SIZE(1),
6292 saved_lty-GRID_ABS_SIZE(1),
6293 saved_rbx+GRID_ABS_SIZE(1), saved_rby+GRID_ABS_SIZE(1),
6294 selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1),
6295 selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1));
6296 }
6297 EndCompositeCmd();
6298 } else {
6299 PrepareToRecord(CMD_REPLACE, topSel, botSel, numObjSelected);
6300 ShearAllSelObjects(Corner, dxShear, dyShear, dxScale, dyScale);
6301 RecordCmd(CMD_REPLACE, NULL, topSel, botSel, numObjSelected);
6302 UpdSelBBox();
6303 RedrawAreas(botObj, saved_ltx-GRID_ABS_SIZE(1),
6304 saved_lty-GRID_ABS_SIZE(1),
6305 saved_rbx+GRID_ABS_SIZE(1), saved_rby+GRID_ABS_SIZE(1),
6306 selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1),
6307 selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1));
6308 }
6309 }
6310
6311 static
ShearSel(XGridOff,YGridOff,ObjPtr,Corner)6312 void ShearSel(XGridOff, YGridOff, ObjPtr, Corner)
6313 int XGridOff, YGridOff, Corner;
6314 struct ObjRec *ObjPtr;
6315 {
6316 XEvent ev;
6317 XPoint all_bbox_vs[5], obj_obbox_vs[5];
6318 int grid_x=XGridOff, grid_y=YGridOff, dx, dy;
6319 int saved_x=XGridOff, saved_y=YGridOff;
6320 int shearing=TRUE, shear_hori=FALSE;
6321 double dx_scale=(double)1000, dy_scale=(double)1000;
6322 double dx_shear=(double)0, dy_shear=(double)0;
6323 char buf[80];
6324 struct BBRec orig_all_bbox, orig_obj_obbox;
6325
6326 if (numObjSelected == numObjLocked || ObjPtr->locked) {
6327 MsgBox(TgLoadString(STID_LOCKED_OBJS_CANT_BE_ROTATED), TOOL_NAME,
6328 INFO_MB);
6329 return;
6330 }
6331 XFlush(mainDisplay);
6332 XSync(mainDisplay, False);
6333 if (XCheckMaskEvent(mainDisplay, ExposureMask, &ev) ||
6334 XCheckMaskEvent(mainDisplay, VisibilityChangeMask, &ev)) {
6335 ExposeEventHandler(&ev, TRUE);
6336 }
6337 SetPivot(Corner, &ObjPtr->obbox);
6338
6339 SetBBRec(&orig_all_bbox, OFFSET_X(selNoLockLtX)-2, OFFSET_Y(selNoLockLtY)-2,
6340 OFFSET_X(selNoLockRbX)+2, OFFSET_Y(selNoLockRbY)+2);
6341 SetRotateVs(all_bbox_vs, orig_all_bbox.ltx, orig_all_bbox.lty,
6342 orig_all_bbox.rbx, orig_all_bbox.rby);
6343 XDrawLines(mainDisplay, drawWindow, revDefaultGC, all_bbox_vs, 5,
6344 CoordModeOrigin);
6345
6346 if (ObjPtr->ctm == NULL) {
6347 SetBBRec(&orig_obj_obbox, OFFSET_X(ObjPtr->obbox.ltx),
6348 OFFSET_Y(ObjPtr->obbox.lty), OFFSET_X(ObjPtr->obbox.rbx),
6349 OFFSET_Y(ObjPtr->obbox.rby));
6350 SetRotateVs(obj_obbox_vs, orig_obj_obbox.ltx, orig_obj_obbox.lty,
6351 orig_obj_obbox.rbx, orig_obj_obbox.rby);
6352 XDrawLines(mainDisplay, drawWindow, revDefaultGC, obj_obbox_vs, 5,
6353 CoordModeOrigin);
6354 } else {
6355 memcpy(obj_obbox_vs, ObjPtr->rotated_obbox, 5*sizeof(XPoint));
6356 XDrawLines(mainDisplay, drawWindow, revDefaultGC, obj_obbox_vs, 5,
6357 CoordModeOrigin);
6358 }
6359
6360 dx = OFFSET_X(ObjPtr->obbox.rbx) - OFFSET_X(ObjPtr->obbox.ltx);
6361 dy = OFFSET_Y(ObjPtr->obbox.rby) - OFFSET_Y(ObjPtr->obbox.lty);
6362 if (dx == 0 || dy == 0) {
6363 MsgBox(TgLoadString(STID_SEL_OBJ_TOO_SMALL_SHEAR_ANO), TOOL_NAME,
6364 INFO_MB);
6365 return;
6366 }
6367 if (Corner == CORNER_TOP || Corner == CORNER_BOTTOM) {
6368 shear_hori = TRUE;
6369 multX = 0.0;
6370 multY = (Corner == CORNER_BOTTOM ? 1.0 : (-1.0));
6371 } else {
6372 shear_hori = FALSE;
6373 multX = (Corner == CORNER_RIGHT ? 1.0 : (-1.0));
6374 multY = 0.0;
6375 }
6376 dx = dy = 0;
6377 grid_x = moveX;
6378 grid_y = moveY;
6379 sprintf(buf, "dx=0\ndy=0");
6380 StartShowMeasureCursor(grid_x, grid_y, buf, TRUE);
6381 if (!debugNoPointerGrab) {
6382 XGrabPointer(mainDisplay, drawWindow, False,
6383 PointerMotionMask | ButtonReleaseMask,
6384 GrabModeAsync, GrabModeAsync, None,
6385 ((Corner==CORNER_TOP || Corner==CORNER_BOTTOM) ? horiShearCursor :
6386 vertShearCursor), CurrentTime);
6387 }
6388 while (shearing) {
6389 XEvent input;
6390
6391 XNextEvent(mainDisplay, &input);
6392
6393 if (input.type == Expose || input.type == VisibilityNotify) {
6394 ExposeEventHandler(&input, TRUE);
6395 } else if (input.type == ButtonRelease) {
6396 XUngrabPointer(mainDisplay, CurrentTime);
6397 XSync(mainDisplay, False);
6398 shearing = FALSE;
6399 sprintf(buf, "dx=%1d\ndy=%1d", dx, dy);
6400 EndShowMeasureCursor(grid_x, grid_y, buf, TRUE);
6401 XDrawLines(mainDisplay, drawWindow, revDefaultGC, obj_obbox_vs, 5,
6402 CoordModeOrigin);
6403 XDrawLines(mainDisplay, drawWindow, revDefaultGC, all_bbox_vs, 5,
6404 CoordModeOrigin);
6405 } else if (input.type == MotionNotify) {
6406 sprintf(buf, "dx=%1d\ndy=%1d", dx, dy);
6407 ShowMeasureCursor(grid_x, grid_y, buf, TRUE);
6408 XDrawLines(mainDisplay, drawWindow, revDefaultGC, obj_obbox_vs, 5,
6409 CoordModeOrigin);
6410 XDrawLines(mainDisplay, drawWindow, revDefaultGC, all_bbox_vs, 5,
6411 CoordModeOrigin);
6412
6413 GridXY(input.xmotion.x, input.xmotion.y, &grid_x, &grid_y);
6414 dx = grid_x - saved_x;
6415 dy = grid_y - saved_y;
6416 grid_x = moveX + dx;
6417 grid_y = moveY + dy;
6418 MarkRulers(grid_x, grid_y);
6419 PointsToShearScale(Corner, pivotX, pivotY, moveX, moveY,
6420 grid_x, grid_y, &dx_shear, &dy_shear, &dx_scale, &dy_scale);
6421
6422 ShearBBox(Corner, &orig_all_bbox, dx_shear, dy_shear,
6423 dx_scale, dy_scale, all_bbox_vs);
6424 XDrawLines(mainDisplay, drawWindow, revDefaultGC, all_bbox_vs, 5,
6425 CoordModeOrigin);
6426 if (ObjPtr->ctm == NULL) {
6427 ShearBBox(Corner, &orig_obj_obbox, dx_shear, dy_shear, dx_scale,
6428 dy_scale, obj_obbox_vs);
6429 } else {
6430 ShearVs(Corner, ObjPtr->rotated_obbox, 5, dx_shear, dy_shear,
6431 dx_scale, dy_scale, obj_obbox_vs);
6432 }
6433 XDrawLines(mainDisplay, drawWindow, revDefaultGC, obj_obbox_vs, 5,
6434 CoordModeOrigin);
6435 sprintf(buf, "dx=%1d\ndy=%1d", dx, dy);
6436 ShowMeasureCursor(grid_x, grid_y, buf, TRUE);
6437 while (XCheckMaskEvent(mainDisplay, PointerMotionMask, &ev)) ;
6438 }
6439 }
6440 ShowCursor();
6441 if (dx != 0 || dy != 0) {
6442 PointsToShearScale(Corner, pivotX, pivotY, moveX, moveY,
6443 moveX+dx, moveY+dy, &dx_shear, &dy_shear, &dx_scale, &dy_scale);
6444 HighLightReverse();
6445 ShearAllSel(Corner, dx_shear, dy_shear, dx_scale, dy_scale);
6446 HighLightForward();
6447 SetFileModified(TRUE);
6448 justDupped = FALSE;
6449 }
6450 }
6451
RotateShearSel(XGridOff,YGridOff,ObjPtr,Corner)6452 void RotateShearSel(XGridOff, YGridOff, ObjPtr, Corner)
6453 int XGridOff, YGridOff, Corner;
6454 struct ObjRec *ObjPtr;
6455 /* 1 2 3 */
6456 /* 8 4 */
6457 /* 7 6 5 */
6458 {
6459 if (ObjPtr->type==OBJ_POLY || ObjPtr->type==OBJ_POLYGON || (Corner & 0x1)) {
6460 RotateSel(XGridOff, YGridOff, ObjPtr, Corner);
6461 } else {
6462 ShearSel(XGridOff, YGridOff, ObjPtr, Corner);
6463 }
6464 }
6465
6466 /* --------------------- Rotation Pivot --------------------- */
6467
6468 static
RefreshFlipRotateMenu(menu)6469 int RefreshFlipRotateMenu(menu)
6470 TgMenu *menu;
6471 {
6472 int ok=TRUE, can_suggest_poly=FALSE, can_suggest_arc=FALSE;
6473
6474 /* ResetRotationPivot */
6475 ok &= TgEnableMenuItemById(menu, CMDID_RESETROTATEPIVOT,
6476 !autoRotatePivot && topSel != NULL);
6477 /* SpecifyRotationPivot */
6478 ok &= TgEnableMenuItemById(menu, CMDID_SPECIFYROTATEPIVOT,
6479 curChoice == ROTATEMODE && topSel != NULL);
6480
6481 /* NextPolyRotationPivot */
6482 /* MoveRotationPivotToArcCenter */
6483 if (!autoRotatePivot && curChoice == ROTATEMODE && topSel != NULL &&
6484 topSel == botSel) {
6485 struct ObjRec *obj_ptr=topSel->obj;
6486
6487 if (obj_ptr->type == OBJ_POLY || obj_ptr->type == OBJ_POLYGON) {
6488 can_suggest_poly = TRUE;
6489 } else if (obj_ptr->type == OBJ_ARC) {
6490 can_suggest_arc = TRUE;
6491 }
6492 }
6493 ok &= TgEnableMenuItemById(menu, CMDID_NEXTPOLYROTATEPIVOT,
6494 can_suggest_poly);
6495 ok &= TgEnableMenuItemById(menu, CMDID_MOVEROTATEPIVOTARCCNTR,
6496 can_suggest_arc);
6497
6498 return ok;
6499 }
6500
CreateFlipRotateMenu(parent_menu,x,y,menu_info,status_str_xlated)6501 TgMenu *CreateFlipRotateMenu(parent_menu, x, y, menu_info, status_str_xlated)
6502 TgMenu *parent_menu;
6503 int x, y;
6504 TgMenuInfo *menu_info;
6505 int status_str_xlated; /* ignored, always 0 */
6506 {
6507 TgMenu *menu=TgCreateMenuFromMenuInfo(parent_menu, x, y, menu_info, FALSE);
6508
6509 if (menu != NULL) {
6510 menu->track_menubar = TRUE;
6511 if (!RefreshFlipRotateMenu(menu)) {
6512 return TgDestroyMenu(menu, TRUE);
6513 }
6514 }
6515 return menu;
6516 }
6517
6518 static
HighLightRotatePivotXY(abs_x,abs_y,Dir)6519 void HighLightRotatePivotXY(abs_x, abs_y, Dir)
6520 int abs_x, abs_y, Dir;
6521 {
6522 int scr_x=OFFSET_X(abs_x), scr_y=OFFSET_Y(abs_y);
6523
6524 switch (Dir) {
6525 case FORWARD:
6526 XDrawLine(mainDisplay, drawWindow, revDefaultGC,
6527 scr_x-((handleSize<<1)+1), scr_y, scr_x+((handleSize<<1)+1), scr_y);
6528 XDrawLine(mainDisplay, drawWindow, revDefaultGC,
6529 scr_x, scr_y-((handleSize<<1)+1), scr_x, scr_y+((handleSize<<1)+1));
6530 XDrawArc(mainDisplay, drawWindow, revDefaultGC,
6531 scr_x-((handleSize<<1)+1), scr_y-((handleSize<<1)+1),
6532 ((handleSize<<2)+2), ((handleSize<<2)+2), 0, (360<<6));
6533 break;
6534 case REVERSE:
6535 XDrawArc(mainDisplay, drawWindow, revDefaultGC,
6536 scr_x-((handleSize<<1)+1), scr_y-((handleSize<<1)+1),
6537 ((handleSize<<2)+2), ((handleSize<<2)+2), 0, (360<<6));
6538 XDrawLine(mainDisplay, drawWindow, revDefaultGC,
6539 scr_x, scr_y-((handleSize<<1)+1), scr_x, scr_y+((handleSize<<1)+1));
6540 XDrawLine(mainDisplay, drawWindow, revDefaultGC,
6541 scr_x-((handleSize<<1)+1), scr_y, scr_x+((handleSize<<1)+1), scr_y);
6542 break;
6543 }
6544 }
6545
HighLightRotatePivot(Dir)6546 void HighLightRotatePivot(Dir)
6547 int Dir;
6548 {
6549 int scr_x=0, scr_y=0;
6550
6551 if (topSel == NULL || autoRotatePivot) return;
6552
6553 if (!rotatePivotAbsXYValid) {
6554 rotatePivotAbsX = ((selObjLtX+selObjRbX)>>1);
6555 rotatePivotAbsY = ((selObjLtY+selObjRbY)>>1);
6556 rotatePivotAbsXYValid = TRUE;
6557
6558 sprintf(gszMsgBox, TgLoadString(STID_NEW_ROTATE_PIVOT_IS),
6559 rotatePivotAbsX, rotatePivotAbsY);
6560 Msg(gszMsgBox);
6561 }
6562 scr_x = OFFSET_X(rotatePivotAbsX);
6563 scr_y = OFFSET_Y(rotatePivotAbsY);
6564
6565 switch (Dir) {
6566 case FORWARD:
6567 XDrawLine(mainDisplay, drawWindow, revDefaultGC,
6568 scr_x-((handleSize<<1)+1), scr_y, scr_x+((handleSize<<1)+1), scr_y);
6569 XDrawLine(mainDisplay, drawWindow, revDefaultGC,
6570 scr_x, scr_y-((handleSize<<1)+1), scr_x, scr_y+((handleSize<<1)+1));
6571 XDrawArc(mainDisplay, drawWindow, revDefaultGC,
6572 scr_x-((handleSize<<1)+1), scr_y-((handleSize<<1)+1),
6573 ((handleSize<<2)+2), ((handleSize<<2)+2), 0, (360<<6));
6574 break;
6575 case REVERSE:
6576 XDrawArc(mainDisplay, drawWindow, revDefaultGC,
6577 scr_x-((handleSize<<1)+1), scr_y-((handleSize<<1)+1),
6578 ((handleSize<<2)+2), ((handleSize<<2)+2), 0, (360<<6));
6579 XDrawLine(mainDisplay, drawWindow, revDefaultGC,
6580 scr_x, scr_y-((handleSize<<1)+1), scr_x, scr_y+((handleSize<<1)+1));
6581 XDrawLine(mainDisplay, drawWindow, revDefaultGC,
6582 scr_x-((handleSize<<1)+1), scr_y, scr_x+((handleSize<<1)+1), scr_y);
6583 break;
6584 }
6585 }
6586
PtInRotatePivot(mouse_x,mouse_y)6587 int PtInRotatePivot(mouse_x, mouse_y)
6588 int mouse_x, mouse_y;
6589 {
6590 int scr_x=0, scr_y=0;
6591 struct BBRec bbox;
6592
6593 if (!rotatePivotAbsXYValid) return FALSE;
6594
6595 scr_x = OFFSET_X(rotatePivotAbsX);
6596 scr_y = OFFSET_Y(rotatePivotAbsY);
6597
6598 bbox.ltx = scr_x-((handleSize<<1)+1);
6599 bbox.lty = scr_y-((handleSize<<1)+1);
6600 bbox.rbx = scr_x+((handleSize<<1)+1);
6601 bbox.rby = scr_y+((handleSize<<1)+1);
6602
6603 return PointInBBox(mouse_x, mouse_y, bbox);
6604 }
6605
6606 static
RefreshMoveStdRotatePivotMenu(menu)6607 int RefreshMoveStdRotatePivotMenu(menu)
6608 TgMenu *menu;
6609 {
6610 int ok=TRUE;
6611
6612 /* MoveRotationPivotToCenter */
6613 ok &= TgEnableMenuItemById(menu, CMDID_MOVEROTATEPIVOTCENTER,
6614 !autoRotatePivot && curChoice == ROTATEMODE && topSel != NULL);
6615 /* MoveRotationPivotToLeftTopCorner */
6616 ok &= TgEnableMenuItemById(menu, CMDID_MOVEROTATEPIVOTLT,
6617 !autoRotatePivot && curChoice == ROTATEMODE && topSel != NULL);
6618 /* MoveRotationPivotToRightTopCorner */
6619 ok &= TgEnableMenuItemById(menu, CMDID_MOVEROTATEPIVOTRT,
6620 !autoRotatePivot && curChoice == ROTATEMODE && topSel != NULL);
6621 /* MoveRotationPivotToLeftBottomCorner */
6622 ok &= TgEnableMenuItemById(menu, CMDID_MOVEROTATEPIVOTLB,
6623 !autoRotatePivot && curChoice == ROTATEMODE && topSel != NULL);
6624 /* MoveRotationPivotToRightBottomCorner */
6625 ok &= TgEnableMenuItemById(menu, CMDID_MOVEROTATEPIVOTRB,
6626 !autoRotatePivot && curChoice == ROTATEMODE && topSel != NULL);
6627 /* MoveRotationPivotToLeftCorner */
6628 ok &= TgEnableMenuItemById(menu, CMDID_MOVEROTATEPIVOTLEFT,
6629 !autoRotatePivot && curChoice == ROTATEMODE && topSel != NULL);
6630 /* MoveRotationPivotToRightCorner */
6631 ok &= TgEnableMenuItemById(menu, CMDID_MOVEROTATEPIVOTRIGHT,
6632 !autoRotatePivot && curChoice == ROTATEMODE && topSel != NULL);
6633 /* MoveRotationPivotToTopCorner */
6634 ok &= TgEnableMenuItemById(menu, CMDID_MOVEROTATEPIVOTTOP,
6635 !autoRotatePivot && curChoice == ROTATEMODE && topSel != NULL);
6636 /* MoveRotationPivotToBottomCorner */
6637 ok &= TgEnableMenuItemById(menu, CMDID_MOVEROTATEPIVOTBOTTOM,
6638 !autoRotatePivot && curChoice == ROTATEMODE && topSel != NULL);
6639
6640 return ok;
6641 }
6642
CreateMoveStdRotatePivotMenu(parent_menu,x,y,menu_info,status_str_xlated)6643 TgMenu *CreateMoveStdRotatePivotMenu(parent_menu, x, y, menu_info,
6644 status_str_xlated)
6645 TgMenu *parent_menu;
6646 int x, y;
6647 TgMenuInfo *menu_info;
6648 int status_str_xlated; /* ignored, always 0 */
6649 {
6650 TgMenu *menu=TgCreateMenuFromMenuInfo(parent_menu, x, y, menu_info, FALSE);
6651
6652 if (menu != NULL) {
6653 menu->track_menubar = TRUE;
6654 if (!RefreshMoveStdRotatePivotMenu(menu)) {
6655 return TgDestroyMenu(menu, TRUE);
6656 }
6657 }
6658 return menu;
6659 }
6660
RefreshAutoRotatePivotMenu(menu)6661 void RefreshAutoRotatePivotMenu(menu)
6662 TgMenu *menu;
6663 {
6664 int i, num_items=menu->num_items;
6665 TgMenuItem *menuitems=menu->menuitems;
6666
6667 for (i=0; i < num_items; i++) {
6668 TgMenuItem *menu_item=(&menuitems[i]);
6669 TgMenuItem stMenuItem;
6670
6671 memset(&stMenuItem, 0, sizeof(TgMenuItem));
6672 stMenuItem.state = TGBS_NORMAL;
6673 stMenuItem.checked = (i == (!autoRotatePivot));
6674 TgSetMenuItemInfo(menu_item, TGMU_MASK_STATE|TGMU_MASK_CHECK,
6675 &stMenuItem);
6676 }
6677 }
6678
CreateAutoRotatePivotMenu(parent_menu,x,y,menu_info,status_str_xlated)6679 TgMenu *CreateAutoRotatePivotMenu(parent_menu, x, y, menu_info,
6680 status_str_xlated)
6681 TgMenu *parent_menu;
6682 int x, y;
6683 TgMenuInfo *menu_info;
6684 int status_str_xlated; /* ignored, always 0 */
6685 {
6686 TgMenu *menu=TgCreateMenuFromMenuInfo(parent_menu, x, y, menu_info, FALSE);
6687
6688 if (menu != NULL) {
6689 TgMenuItem *menu_item=NULL;
6690 TgMenuItem stMenuItem;
6691
6692 menu->track_menubar = TRUE;
6693 TgAdjustMenuGeometry(menu, choiceImageW, choiceImageH, MAX_ROTATE_PIVOT);
6694 menu_item = (&menu->menuitems[!autoRotatePivot]);
6695
6696 memset(&stMenuItem, 0, sizeof(TgMenuItem));
6697 stMenuItem.checked = TRUE;
6698 if (!TgSetMenuItemInfo(menu_item, TGMU_MASK_CHECK, &stMenuItem)) {
6699 return TgDestroyMenu(menu, TRUE);
6700 }
6701 menu->refresh_proc = ((RefreshMenuFunc*)RefreshAutoRotatePivotMenu);
6702 }
6703 return menu;
6704 }
6705
AutoRotatePivotMenu(X,Y,TrackMenubar)6706 int AutoRotatePivotMenu(X, Y, TrackMenubar)
6707 int X, Y, TrackMenubar;
6708 {
6709 int rc=INVALID;
6710 TgMenu *menu=(autoRotatePivotMenuInfo.create_proc)(NULL, X, Y,
6711 &autoRotatePivotMenuInfo, INVALID);
6712
6713 activeMenu = INVALID;
6714 if (menu != NULL) {
6715 menu->track_menubar = TrackMenubar;
6716
6717 rc = TgMenuLoop(menu);
6718 TgDestroyMenu(menu, TRUE);
6719 }
6720 return rc;
6721 }
6722
ResetRotatePivotValidInfo()6723 void ResetRotatePivotValidInfo()
6724 {
6725 rotatePivotAbsXYValid = FALSE;
6726 rotatePivotAbsX = 0;
6727 rotatePivotAbsY = 0;
6728 }
6729
ReadRotatePivotInfo(buf)6730 int ReadRotatePivotInfo(buf)
6731 char *buf;
6732 {
6733 int auto_pivot=TRUE, xy_valid=0, abs_x=0, abs_y=0;
6734 char *psz=NULL;
6735
6736 if (importingFile) return TRUE;
6737
6738 psz = FindChar((int)'(', buf);
6739 InitScan(psz, "\t\n, ");
6740 if (GETINT("rotate_pivot", auto_pivot, "auto_pivot") == INVALID ||
6741 GETINT("rotate_pivot", xy_valid, "xy_valid") == INVALID ||
6742 GETINT("rotate_pivot", abs_x, "x") == INVALID ||
6743 GETINT("rotate_pivot", abs_y, "y") == INVALID) {
6744 return FALSE;
6745 }
6746 autoRotatePivot = auto_pivot;
6747 rotatePivotAbsXYValid = xy_valid;
6748 rotatePivotAbsX = abs_x;
6749 rotatePivotAbsY = abs_y;
6750 if (!PRTGIF || cmdLineOpenDisplay) {
6751 choicePixmap[ROTATEMODE] = rotateModePixmap[!autoRotatePivot];
6752 RedrawModeWindow();
6753 UpdatePinnedMenu(MENU_MODE);
6754 }
6755 return TRUE;
6756 }
6757
ContinueMoveRotatePivot(OrigX,OrigY)6758 void ContinueMoveRotatePivot(OrigX, OrigY)
6759 int OrigX, OrigY;
6760 {
6761 int moving=TRUE, dx=0, dy=0, grid_x=OrigX, grid_y=OrigY;
6762 char buf[80], x_buf[80], y_buf[80];
6763 XEvent ev;
6764
6765 XFlush(mainDisplay);
6766 XSync(mainDisplay, False);
6767
6768 if (XCheckMaskEvent(mainDisplay, ExposureMask, &ev) ||
6769 XCheckMaskEvent(mainDisplay, VisibilityChangeMask, &ev)) {
6770 ExposeEventHandler(&ev, TRUE);
6771 }
6772 PixelToMeasurementUnit(x_buf, rotatePivotAbsX);
6773 PixelToMeasurementUnit(y_buf, rotatePivotAbsY);
6774 sprintf(buf, "x=%s\ny=%s", x_buf, y_buf);
6775 StartShowMeasureCursor(OrigX, OrigY, buf, TRUE);
6776
6777 if (!debugNoPointerGrab) {
6778 XGrabPointer(mainDisplay, drawWindow, FALSE,
6779 PointerMotionMask | ButtonReleaseMask,
6780 GrabModeAsync, GrabModeAsync, None, moveCursor, CurrentTime);
6781 }
6782 dx = dy = 0;
6783
6784 while (moving) {
6785 XEvent input;
6786
6787 XNextEvent(mainDisplay, &input);
6788
6789 if (input.type == Expose || input.type == VisibilityNotify) {
6790 ExposeEventHandler(&input, TRUE);
6791 } else if (input.type == ButtonRelease) {
6792 XUngrabPointer(mainDisplay, CurrentTime);
6793 XSync(mainDisplay, False);
6794 moving = FALSE;
6795
6796 /* erase */
6797 PixelToMeasurementUnit(x_buf, rotatePivotAbsX+ABS_SIZE(dx));
6798 PixelToMeasurementUnit(y_buf, rotatePivotAbsY+ABS_SIZE(dy));
6799 sprintf(buf, "x=%s\ny=%s", x_buf, y_buf);
6800 ShowMeasureCursor(grid_x, grid_y, buf, TRUE);
6801 HighLightRotatePivotXY(rotatePivotAbsX+ABS_SIZE(dx),
6802 rotatePivotAbsY+ABS_SIZE(dy), REVERSE);
6803
6804 dx = grid_x - OrigX;
6805 dy = grid_y - OrigY;
6806 } else if (input.type == MotionNotify) {
6807 int x=0, y=0;
6808
6809 /* erase */
6810 PixelToMeasurementUnit(x_buf, rotatePivotAbsX+ABS_SIZE(dx));
6811 PixelToMeasurementUnit(y_buf, rotatePivotAbsY+ABS_SIZE(dy));
6812 sprintf(buf, "x=%s\ny=%s", x_buf, y_buf);
6813 ShowMeasureCursor(grid_x, grid_y, buf, TRUE);
6814 HighLightRotatePivotXY(rotatePivotAbsX+ABS_SIZE(dx),
6815 rotatePivotAbsY+ABS_SIZE(dy), REVERSE);
6816
6817 x = input.xmotion.x;
6818 y = input.xmotion.y;
6819 GridXY(x, y, &grid_x, &grid_y);
6820
6821 dx = grid_x - OrigX;
6822 dy = grid_y - OrigY;
6823
6824 HighLightRotatePivotXY(rotatePivotAbsX+ABS_SIZE(dx),
6825 rotatePivotAbsY+ABS_SIZE(dy), FORWARD);
6826 PixelToMeasurementUnit(x_buf, rotatePivotAbsX+ABS_SIZE(dx));
6827 PixelToMeasurementUnit(y_buf, rotatePivotAbsY+ABS_SIZE(dy));
6828 sprintf(buf, "x=%s\ny=%s", x_buf, y_buf);
6829 ShowMeasureCursor(grid_x, grid_y, buf, TRUE);
6830
6831 while (XCheckMaskEvent(mainDisplay, PointerMotionMask, &ev)) ;
6832 }
6833 }
6834 if (dx != 0 || dy != 0) {
6835 rotatePivotAbsX += ABS_SIZE(dx);
6836 rotatePivotAbsY += ABS_SIZE(dy);
6837 sprintf(gszMsgBox, TgLoadString(STID_NEW_ROTATE_PIVOT_IS),
6838 rotatePivotAbsX, rotatePivotAbsY);
6839 Msg(gszMsgBox);
6840 }
6841 HighLightRotatePivotXY(rotatePivotAbsX, rotatePivotAbsY, FORWARD);
6842 }
6843
ToggleAutoRotatePivot()6844 void ToggleAutoRotatePivot()
6845 {
6846 if (topSel != NULL && curChoice == ROTATEMODE) {
6847 if (somethingHighLighted) HighLightReverse();
6848 }
6849 autoRotatePivot = !autoRotatePivot;
6850 if (autoRotatePivot) {
6851 ResetRotatePivotValidInfo();
6852 Msg(TgLoadString(STID_SWITCHED_TO_AUTO_ROTATE_PIVOT));
6853 } else {
6854 Msg(TgLoadString(STID_SWITCHED_TO_USER_ROTATE_PIVOT));
6855 }
6856 choicePixmap[ROTATEMODE] = rotateModePixmap[!autoRotatePivot];
6857 RedrawModeWindow();
6858 UpdatePinnedMenu(MENU_MODE);
6859 if (topSel != NULL && curChoice == ROTATEMODE) {
6860 if (!somethingHighLighted) HighLightForward();
6861 }
6862 }
6863
SpecifyRotatePivot()6864 void SpecifyRotatePivot()
6865 {
6866 char spec[MAXSTRING];
6867 int abs_x=0, abs_y=0;
6868
6869 if (autoRotatePivot) {
6870 UtilStrCpyN(gszMsgBox, sizeof(gszMsgBox),
6871 TgLoadString(STID_ENTER_ROT_PIVOT));
6872 } else if (rotatePivotAbsXYValid) {
6873 sprintf(gszMsgBox, TgLoadString(STID_ENTER_ROT_PIVOT_CUR_IS),
6874 rotatePivotAbsX, rotatePivotAbsY);
6875 } else {
6876 UtilStrCpyN(gszMsgBox, sizeof(gszMsgBox),
6877 TgLoadString(STID_ENTER_ROT_PIVOT));
6878 }
6879 *spec = '\0';
6880 Dialog(gszMsgBox, TgLoadCachedString(CSTID_DLG_ACCEPT_CANCEL), spec);
6881 UtilTrimBlanks(spec);
6882 if (*spec == '\0') return;
6883
6884 if (ParseXYSpec(spec, &abs_x, &abs_y)) {
6885 if (autoRotatePivot) {
6886 ToggleAutoRotatePivot();
6887 rotatePivotAbsXYValid = TRUE;
6888 } else if (rotatePivotAbsXYValid) {
6889 /* nothing to do here */
6890 } else {
6891 rotatePivotAbsXYValid = TRUE;
6892 }
6893 rotatePivotAbsX = abs_x;
6894 rotatePivotAbsY = abs_y;
6895 sprintf(gszMsgBox, TgLoadString(STID_ROT_PIVOT_SET_TO),
6896 rotatePivotAbsX, rotatePivotAbsY);
6897 Msg(gszMsgBox);
6898 }
6899 }
6900
ResetRotatePivot()6901 void ResetRotatePivot()
6902 {
6903 if (topSel != NULL && curChoice == ROTATEMODE) {
6904 if (somethingHighLighted) HighLightReverse();
6905 }
6906 ResetRotatePivotValidInfo();
6907 if (topSel != NULL && curChoice == ROTATEMODE) {
6908 if (!somethingHighLighted) HighLightForward();
6909 }
6910 }
6911
6912 static
GetPolyVertices(N,ObjPtr,NumPts,V,Curved,pn_need_to_free)6913 IntPoint *GetPolyVertices(N, ObjPtr, NumPts, V, Curved, pn_need_to_free)
6914 int *N, NumPts, Curved, *pn_need_to_free;
6915 struct ObjRec *ObjPtr;
6916 IntPoint *V;
6917 {
6918 if (ObjPtr->ctm == NULL) {
6919 *pn_need_to_free = FALSE;
6920 *N = NumPts;
6921 return V;
6922 } else {
6923 int i=0;
6924 IntPoint *v=(IntPoint*)malloc(NumPts*sizeof(IntPoint));
6925
6926 if (v == NULL) FailAllocMessage();
6927 memset(v, 0, NumPts*sizeof(IntPoint));
6928
6929 for (i=0; i < NumPts; i++) {
6930 int x=0, y=0;
6931
6932 TransformPointThroughCTM(V[i].x-ObjPtr->x, V[i].y-ObjPtr->y,
6933 ObjPtr->ctm, &x, &y);
6934 v[i].x = x+ObjPtr->x;
6935 v[i].y = y+ObjPtr->y;
6936 }
6937 *pn_need_to_free = TRUE;
6938 *N = NumPts;
6939 return v;
6940 }
6941 }
6942
NextPolyRotationPivot()6943 void NextPolyRotationPivot()
6944 {
6945 int i=0, can_suggest=FALSE, num_pts=0, need_to_free=FALSE, min_index=0;
6946 struct ObjRec *obj_ptr=NULL;
6947 IntPoint *v=NULL;
6948 double min_dist=(double)0;
6949
6950 if (!autoRotatePivot && curChoice == ROTATEMODE && topSel != NULL &&
6951 topSel == botSel) {
6952 obj_ptr = topSel->obj;
6953 if (obj_ptr->type == OBJ_POLY) {
6954 struct PolyRec *poly_ptr=obj_ptr->detail.p;
6955
6956 v = GetPolyVertices(&num_pts, obj_ptr, poly_ptr->n, poly_ptr->vlist,
6957 poly_ptr->curved, &need_to_free);
6958 can_suggest = TRUE;
6959 } else if (obj_ptr->type == OBJ_POLYGON) {
6960 struct PolygonRec *polygon_ptr=obj_ptr->detail.g;
6961
6962 v = GetPolyVertices(&num_pts, obj_ptr, polygon_ptr->n-1,
6963 polygon_ptr->vlist, polygon_ptr->curved, &need_to_free);
6964 can_suggest = TRUE;
6965 }
6966 }
6967 if (!can_suggest) {
6968 MsgBox(TgLoadString(STID_SELONLYONEPOLYOBJ), TOOL_NAME, INFO_MB);
6969 return;
6970 }
6971 HighLightReverse();
6972 if (rotatePivotAbsXYValid) {
6973 int dx=rotatePivotAbsX-v[0].x, dy=rotatePivotAbsY-v[0].y;
6974 int coincide_index=(-1);
6975 double ddx=(double)0, ddy=(double)0, dist=(double)0;
6976
6977 min_index = 0;
6978 if (dx == 0 && dy == 0) {
6979 coincide_index = 0;
6980 min_dist = (double)0;
6981 } else {
6982 ddx = (double)dx;
6983 ddy = (double)dy;
6984 min_dist = (double)sqrt(ddx*ddx+ddy+ddy);
6985 }
6986 for (i=1; i < num_pts; i++) {
6987 dx = rotatePivotAbsX-v[i].x;
6988 dy = rotatePivotAbsY-v[i].y;
6989 if (dx == 0 && dy == 0) {
6990 if (coincide_index == (-1)) {
6991 coincide_index = i;
6992 min_index = i;
6993 min_dist = (double)0;
6994 } else if (coincide_index+1 == i) {
6995 coincide_index = i;
6996 min_index = i;
6997 min_dist = (double)0;
6998 } else {
6999 /* stick to the original coincide_index */
7000 }
7001 } else {
7002 ddx = (double)dx;
7003 ddy = (double)dy;
7004 dist = (double)sqrt(ddx*ddx+ddy+ddy);
7005 if (dist < min_dist) {
7006 min_index = i;
7007 min_dist = dist;
7008 }
7009 }
7010 }
7011 if (coincide_index != (-1)) {
7012 min_index = coincide_index+1;
7013 }
7014 if (min_index >= num_pts) {
7015 min_index = 0;
7016 }
7017 } else {
7018 min_index = 0;
7019 }
7020 rotatePivotAbsXYValid = TRUE;
7021 rotatePivotAbsX = v[min_index].x;
7022 rotatePivotAbsY = v[min_index].y;
7023
7024 if (need_to_free) free(v);
7025
7026 sprintf(gszMsgBox, TgLoadString(STID_NEW_ROTATE_PIVOT_IS),
7027 rotatePivotAbsX, rotatePivotAbsY);
7028 Msg(gszMsgBox);
7029
7030 HighLightForward();
7031 }
7032
MoveRotationPivotToArcCenter()7033 void MoveRotationPivotToArcCenter()
7034 {
7035 int can_suggest=FALSE, x=0, y=0;
7036 struct ObjRec *obj_ptr=NULL;
7037 struct ArcRec *arc_ptr=NULL;
7038
7039 if (!autoRotatePivot && curChoice == ROTATEMODE && topSel != NULL &&
7040 topSel == botSel) {
7041 obj_ptr = topSel->obj;
7042 if (obj_ptr->type == OBJ_ARC) {
7043 arc_ptr = obj_ptr->detail.a;
7044 can_suggest = TRUE;
7045 }
7046 }
7047 if (!can_suggest) {
7048 MsgBox(TgLoadString(STID_SELONLYONEARCOBJ), TOOL_NAME, INFO_MB);
7049 return;
7050 }
7051 HighLightReverse();
7052 if (obj_ptr->ctm == NULL) {
7053 x = arc_ptr->xc;
7054 y = arc_ptr->yc;
7055 } else {
7056 TransformPointThroughCTM(arc_ptr->xc-obj_ptr->x,
7057 arc_ptr->yc-obj_ptr->y, obj_ptr->ctm, &x, &y);
7058 x += obj_ptr->x;
7059 y += obj_ptr->y;
7060 }
7061 rotatePivotAbsXYValid = TRUE;
7062 rotatePivotAbsX = x;
7063 rotatePivotAbsY = y;
7064
7065 sprintf(gszMsgBox, TgLoadString(STID_NEW_ROTATE_PIVOT_IS),
7066 rotatePivotAbsX, rotatePivotAbsY);
7067 Msg(gszMsgBox);
7068
7069 HighLightForward();
7070 }
7071
MoveRotatePivot(Corner)7072 void MoveRotatePivot(Corner)
7073 int Corner;
7074 {
7075 if (topSel == NULL || curChoice != ROTATEMODE) return;
7076
7077 HighLightReverse();
7078 switch (Corner) {
7079 case CORNER_NONE:
7080 rotatePivotAbsX = ((selObjLtX+selObjRbX)>>1);
7081 rotatePivotAbsY = ((selObjLtY+selObjRbY)>>1);
7082 break;
7083 case CORNER_LT:
7084 rotatePivotAbsX = selObjLtX;
7085 rotatePivotAbsY = selObjLtY;
7086 break;
7087 case CORNER_RT:
7088 rotatePivotAbsX = selObjRbX;
7089 rotatePivotAbsY = selObjLtY;
7090 break;
7091 case CORNER_LB:
7092 rotatePivotAbsX = selObjLtX;
7093 rotatePivotAbsY = selObjRbY;
7094 break;
7095 case CORNER_RB:
7096 rotatePivotAbsX = selObjRbX;
7097 rotatePivotAbsY = selObjRbY;
7098 break;
7099 case CORNER_LEFT:
7100 rotatePivotAbsX = selObjLtX;
7101 rotatePivotAbsY = ((selObjLtY+selObjRbY)>>1);
7102 break;
7103 case CORNER_RIGHT:
7104 rotatePivotAbsX = selObjRbX;
7105 rotatePivotAbsY = ((selObjLtY+selObjRbY)>>1);
7106 break;
7107 case CORNER_TOP:
7108 rotatePivotAbsX = ((selObjLtX+selObjRbX)>>1);
7109 rotatePivotAbsY = selObjLtY;
7110 break;
7111 case CORNER_BOTTOM:
7112 rotatePivotAbsX = ((selObjLtX+selObjRbX)>>1);
7113 rotatePivotAbsY = selObjRbY;
7114 break;
7115 }
7116 rotatePivotAbsXYValid = TRUE;
7117
7118 sprintf(gszMsgBox, TgLoadString(STID_NEW_ROTATE_PIVOT_IS),
7119 rotatePivotAbsX, rotatePivotAbsY);
7120 Msg(gszMsgBox);
7121
7122 HighLightForward();
7123 }
7124
AutoRotatePivotSubMenu(index)7125 void AutoRotatePivotSubMenu(index)
7126 int index;
7127 {
7128 if (!autoRotatePivot == index) return;
7129
7130 ToggleAutoRotatePivot();
7131 }
7132
7133