/* * Author: William Chia-Wei Cheng (bill.cheng@acm.org) * * Copyright (C) 2001-2006, William Chia-Wei Cheng. * * This file may be distributed under the terms of the Q Public License * as defined by Trolltech AS of Norway and appearing in the file * LICENSE.QPL included in the packaging of this file. * * THIS FILE IS PROVIDED AS IS WITH NO WARRANTY OF ANY KIND, INCLUDING * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * @(#)$Header: /mm2/home/cvs/bc-src/tgif/stretch.c,v 1.6 2006/02/10 23:21:21 william Exp $ */ #define _INCLUDE_FROM_STRETCH_C_ #include "tgifdefs.h" #include "align.e" #include "arc.e" #include "auxtext.e" #include "choice.e" #include "cmd.e" #include "color.e" #include "cursor.e" #include "dialog.e" #include "drawing.e" #include "dup.e" #include "exec.e" #include "file.e" #include "font.e" #include "grid.e" #include "mainloop.e" #include "mark.e" #include "menu.e" #include "miniline.e" #include "move.e" #include "msg.e" #include "obj.e" #include "page.e" #include "poly.e" #include "raster.e" #include "rect.e" #include "ruler.e" #include "scroll.e" #include "select.e" #include "setup.e" #include "spline.e" #include "stretch.e" #include "strtbl.e" #include "text.e" #include "util.e" #include "xbitmap.e" #include "xpixmap.e" int stretchableText=FALSE; int compoundObjWithTextStretchableForPSE=TRUE; int rotationIncrement=(45<<6); /* degrees*64 */ static int stretchingEverything=FALSE; static int PtIn4Corners(XOff, YOff, BBox, Corner) int XOff, YOff, * Corner; struct BBRec BBox; { if (PtInMark(XOff, YOff, OFFSET_X(BBox.ltx), OFFSET_Y(BBox.lty))) { *Corner = 1; return TRUE; } if (PtInMark(XOff, YOff, OFFSET_X(BBox.ltx), OFFSET_Y(BBox.rby))) { *Corner = 7; return TRUE; } if (PtInMark(XOff, YOff, OFFSET_X(BBox.rbx), OFFSET_Y(BBox.lty))) { *Corner = 3; return TRUE; } if (PtInMark(XOff, YOff, OFFSET_X(BBox.rbx), OFFSET_Y(BBox.rby))) { *Corner = 5; return TRUE; } return FALSE; } static int PtIn8Places(XOff, YOff, BBox, Corner) int XOff, YOff, *Corner; struct BBRec BBox; { register int xmid, ymid; if (PtIn4Corners(XOff, YOff, BBox, Corner)) return TRUE; xmid = ((BBox.ltx+BBox.rbx)>>1); if (PtInMark(XOff, YOff, OFFSET_X(xmid), OFFSET_Y(BBox.lty))) { *Corner = 2; return TRUE; } if (PtInMark(XOff, YOff, OFFSET_X(xmid), OFFSET_Y(BBox.rby))) { *Corner = 6; return TRUE; } ymid = ((BBox.lty+BBox.rby)>>1); if (PtInMark(XOff, YOff, OFFSET_X(BBox.ltx), OFFSET_Y(ymid))) { *Corner = 8; return TRUE; } if (PtInMark(XOff, YOff, OFFSET_X(BBox.rbx), OFFSET_Y(ymid))) { *Corner = 4; return TRUE; } return FALSE; } int PtInPolyMark(ObjPtr, XOff, YOff, NumPts, V, Index) struct ObjRec *ObjPtr; int XOff, YOff, NumPts, * Index; IntPoint *V; { int i; if (ObjPtr->ctm == NULL) { for (i = 0; i < NumPts; i++) { if (PtInMark(XOff, YOff, OFFSET_X(V[i].x), OFFSET_Y(V[i].y))) { *Index = i; return TRUE; } } } else { for (i = 0; i < NumPts; i++) { int x, y; TransformPointThroughCTM(V[i].x-ObjPtr->x, V[i].y-ObjPtr->y, ObjPtr->ctm, &x, &y); if (PtInMark(XOff, YOff, OFFSET_X(x+ObjPtr->x), OFFSET_Y(y+ObjPtr->y))) { *Index = i; return TRUE; } } } return FALSE; } int RetractedArrowAttr(obj_ptr) struct ObjRec *obj_ptr; { register struct AttrRec *attr_ptr; if (obj_ptr->type != OBJ_POLY) return FALSE; if (obj_ptr->detail.p->n <= 2) return FALSE; for (attr_ptr=obj_ptr->lattr; attr_ptr!=NULL; attr_ptr=attr_ptr->prev) { if (*attr_ptr->attr_name.s=='\0' && strcmp(attr_ptr->attr_value.s, "retracted_arrows")==0) { return TRUE; } } return FALSE; } int AutoRetractedArrowAttr(obj_ptr, check_v_count) /* if check_v_count == TRUE: return FALSE if poly_ptr->n != 3 */ /* if check_v_count == FALSE: skip the poly_ptr->n check */ struct ObjRec *obj_ptr; int check_v_count; { register struct AttrRec *attr_ptr; if (obj_ptr->type == OBJ_POLY) { struct PolyRec *poly_ptr=obj_ptr->detail.p; if (poly_ptr->style == LS_PLAIN || poly_ptr->style == LS_DOUBLE || (check_v_count && poly_ptr->n != 3)) { return FALSE; } } else { return FALSE; } for (attr_ptr=obj_ptr->lattr; attr_ptr!=NULL; attr_ptr=attr_ptr->prev) { if (*attr_ptr->attr_name.s=='\0' && strcmp(attr_ptr->attr_value.s, "auto_retracted_arrows")==0) { return TRUE; } } return FALSE; } int AutoCenterAttr(obj_ptr) struct ObjRec *obj_ptr; { register struct AttrRec *attr_ptr; for (attr_ptr=obj_ptr->lattr; attr_ptr!=NULL; attr_ptr=attr_ptr->prev) { if (*attr_ptr->attr_name.s=='\0' && strcmp(attr_ptr->attr_value.s, "auto_center_attr")==0) { return TRUE; } } return FALSE; } void CenterObjInOBBox(TextObjPtr, OBBox, BBoxReturn) struct ObjRec *TextObjPtr; struct BBRec OBBox, *BBoxReturn; { int text_w, text_h, bbox_w, bbox_h, dx, dy; if (BBoxReturn != NULL) { BBoxReturn->ltx = TextObjPtr->bbox.ltx; BBoxReturn->lty = TextObjPtr->bbox.lty; BBoxReturn->rbx = TextObjPtr->bbox.rbx; BBoxReturn->rby = TextObjPtr->bbox.rby; } text_w = TextObjPtr->obbox.rbx-TextObjPtr->obbox.ltx; text_h = TextObjPtr->obbox.rby-TextObjPtr->obbox.lty; bbox_w = OBBox.rbx - OBBox.ltx; bbox_h = OBBox.rby - OBBox.lty; if (text_w > bbox_w) { dx = OBBox.ltx-((text_w-bbox_w)>>1)-TextObjPtr->obbox.ltx; } else { dx = OBBox.ltx+((bbox_w-text_w)>>1)-TextObjPtr->obbox.ltx; } if (text_h > bbox_h) { dy = OBBox.lty-((text_h-bbox_h)>>1)-TextObjPtr->obbox.lty; } else { dy = OBBox.lty+((bbox_h-text_h)>>1)-TextObjPtr->obbox.lty; } MoveObj(TextObjPtr, dx, dy); if (BBoxReturn != NULL) { if (TextObjPtr->bbox.ltx < BBoxReturn->ltx) { BBoxReturn->ltx = TextObjPtr->bbox.ltx; } if (TextObjPtr->bbox.lty < BBoxReturn->lty) { BBoxReturn->lty = TextObjPtr->bbox.lty; } if (TextObjPtr->bbox.rbx > BBoxReturn->rbx) { BBoxReturn->rbx = TextObjPtr->bbox.rbx; } if (TextObjPtr->bbox.rby > BBoxReturn->rby) { BBoxReturn->rby = TextObjPtr->bbox.rby; } } } struct SelRec *PtInSelMark(XOff, YOff, Corner) int XOff, YOff, *Corner; /* XOff and YOff are screen offsets */ /* 1 2 3 */ /* 8 4 */ /* 7 6 5 */ { register struct SelRec *sel_ptr; register struct ObjRec *obj_ptr; for (sel_ptr=topSel; sel_ptr != NULL; sel_ptr=sel_ptr->next) { obj_ptr = sel_ptr->obj; switch (obj_ptr->type) { case OBJ_POLY: if (PtInPolyMark(obj_ptr, XOff, YOff, obj_ptr->detail.p->n, obj_ptr->detail.p->vlist, Corner)) { return sel_ptr; } break; case OBJ_POLYGON: if (PtInPolyMark(obj_ptr, XOff, YOff, obj_ptr->detail.g->n-1, obj_ptr->detail.g->vlist, Corner)) { return sel_ptr; } break; case OBJ_BOX: case OBJ_GROUP: case OBJ_ICON: case OBJ_SYM: case OBJ_PIN: case OBJ_OVAL: case OBJ_ARC: case OBJ_RCBOX: case OBJ_XBM: case OBJ_XPM: if (PtIn8Places(XOff, YOff, obj_ptr->obbox, Corner)) { return sel_ptr; } break; case OBJ_TEXT: if (curChoice == ROTATEMODE) { if (PtIn8Places(XOff, YOff, obj_ptr->obbox, Corner)) { return sel_ptr; } } else if (curChoice == NOTHING) { if (stretchableText && PtIn8Places(XOff, YOff, obj_ptr->obbox, Corner)) { return sel_ptr; } } break; } } return NULL; } static int HasOnReshape(obj_ptr, pp_name_attr) struct ObjRec *obj_ptr; struct AttrRec **pp_name_attr; /* returns the name attribute pointer */ { if (pp_name_attr != NULL) *pp_name_attr = NULL; if ((obj_ptr->type == OBJ_POLY || obj_ptr->type == OBJ_POLYGON) && obj_ptr->ctm == NULL) { if (FindAttrWithName(obj_ptr, "on_reshape=", NULL) != NULL) { struct AttrRec *attr=FindAttrWithName(obj_ptr, "name=", NULL); if (attr != NULL && *attr->attr_value.s != '\0') { if (pp_name_attr != NULL) *pp_name_attr = attr; return TRUE; } } } return FALSE; } static int SkipOnResize(obj_ptr) struct ObjRec *obj_ptr; { if (obj_ptr->type != OBJ_GROUP && obj_ptr->type != OBJ_ICON && obj_ptr->type != OBJ_SYM && obj_ptr->type != OBJ_PIN) { if (obj_ptr->ctm != NULL) { return TRUE; } } else { struct ObjRec *sub_obj=obj_ptr->detail.r->last; for ( ; sub_obj != NULL; sub_obj=sub_obj->prev) { if (sub_obj->type != OBJ_GROUP && sub_obj->type != OBJ_ICON && sub_obj->type != OBJ_SYM && sub_obj->type != OBJ_PIN && sub_obj->ctm != NULL) { return TRUE; } } } return FALSE; } static int HasOnResize(obj_ptr, pp_name_attr) struct ObjRec *obj_ptr; struct AttrRec **pp_name_attr; /* returns the name attribute pointer */ { if (pp_name_attr != NULL) *pp_name_attr = NULL; if (!SkipOnResize(obj_ptr)) { if (FindAttrWithName(obj_ptr, "on_resize=", NULL) != NULL) { struct AttrRec *attr=FindAttrWithName(obj_ptr, "name=", NULL); if (attr != NULL && *attr->attr_value.s != '\0') { if (pp_name_attr != NULL) *pp_name_attr = attr; return TRUE; } } } return FALSE; } static char **NeedToProcessOnResize(pn_num_to_resize) int *pn_num_to_resize; { int num_to_resize=0; char **ppsz_names=NULL; struct SelRec *sel_ptr=NULL; *pn_num_to_resize = 0; for (sel_ptr=botSel; sel_ptr != NULL; sel_ptr=sel_ptr->prev) { struct AttrRec *name_attr=NULL; if (HasOnResize(sel_ptr->obj, &name_attr) && name_attr != NULL) { num_to_resize++; if (ppsz_names == NULL) { ppsz_names = (char**)malloc(sizeof(char*)); } else { ppsz_names = (char**)realloc(ppsz_names, num_to_resize*sizeof(char*)); } if (ppsz_names == NULL) FailAllocMessage(); ppsz_names[num_to_resize-1] = (char*)(sel_ptr->obj->id); } } if (num_to_resize == 0) return NULL; *pn_num_to_resize = num_to_resize; return ppsz_names; } static struct ObjRec *FindObjWithOID(oid) int oid; { struct ObjRec *obj_ptr=NULL; for (obj_ptr=botObj; obj_ptr != NULL; obj_ptr=obj_ptr->prev) { if (obj_ptr->id == oid) { return obj_ptr; } } return NULL; } static void DoOnResize(ppsz_names, num_to_resize) char **ppsz_names; int num_to_resize; { int i=0; RemoveAllSel(); for (i=0; i < num_to_resize; i++) { struct AttrRec *exec_attr=NULL; struct ObjRec *obj_ptr=FindObjWithOID((int)(ppsz_names[i])); if (obj_ptr != NULL && !SkipOnResize(obj_ptr)) { exec_attr = FindAttrWithName(obj_ptr, "on_resize=", NULL); } if (exec_attr != NULL) { DoExecLoop(obj_ptr, exec_attr); } else { sprintf(gszMsgBox, TgLoadCachedString(CSTID_CANT_FIND_OBJ_NAME_ON_RESIZE), ppsz_names[i]); Msg(gszMsgBox); *ppsz_names[i] = '\0'; } } for (i=0; i < num_to_resize; i++) { struct ObjRec *obj_ptr=FindObjWithOID((int)(ppsz_names[i])); if (obj_ptr != NULL) { if (!AlreadySelected(obj_ptr)) { AddNewSelObj(obj_ptr); } } } free(ppsz_names); UpdSelBBox(); } #define STRETCH_DRAW (FALSE) #define STRETCH_ERASE (TRUE) #define STRETCH_CLICK (FALSE) #define STRETCH_DRAG (TRUE) #define STRETCH_STARTSHOW 0 #define STRETCH_DOSHOW 1 #define STRETCH_ENDSHOW 2 static void DoStretchPolyMeasureCursor(start, num_pts, vs, index, dx, dy, erase, drag, obj_type, grid_x, grid_y) int start, num_pts, index, dx, dy, erase, drag, obj_type, grid_x, grid_y; IntPoint *vs; { static IntPoint prev_pt={0,0}, mid_pt={0,0}, next_pt={0,0}; char buf[80], x_buf[80], y_buf[80], a_buf[80]; int x=vs[index].x+dx, y=vs[index].y+dy, angle2=0; #ifdef _TGIF_DBG /* debug, do not translate */ TgAssert((obj_type == OBJ_POLY || index != num_pts-1), "index == num_pts-1 for a polygon in DoStretchPolyMeasureCursor()", NULL); #endif /* _TGIF_DBG */ if (index == 0 || index == num_pts-1) { if (obj_type == OBJ_POLY) { if (num_pts > 2) { if (index == 0) { prev_pt.x = x; prev_pt.y = y; mid_pt.x = vs[1].x; mid_pt.y = vs[1].y; next_pt.x = vs[2].x; next_pt.y = vs[2].y; } else { prev_pt.x = vs[num_pts-3].x; prev_pt.y = vs[num_pts-3].y; mid_pt.x = vs[num_pts-2].x; mid_pt.y = vs[num_pts-2].y; next_pt.x = x; next_pt.y = y; } } else { if (index == 0) { prev_pt.x = x; prev_pt.y = y; mid_pt.x = vs[1].x; mid_pt.y = vs[1].y; next_pt.x = vs[1].x+100; next_pt.y = vs[1].y; } else { prev_pt.x = x; prev_pt.y = y; mid_pt.x = vs[0].x; mid_pt.y = vs[0].y; next_pt.x = vs[0].x+100; next_pt.y = vs[0].y; } } } else { prev_pt.x = vs[1].x; prev_pt.y = vs[1].y; mid_pt.x = x; mid_pt.y = y; next_pt.x = vs[num_pts-2].x; next_pt.y = vs[num_pts-2].y; } } else { prev_pt.x = vs[index-1].x; prev_pt.y = vs[index-1].y; mid_pt.x = x; mid_pt.y = y; next_pt.x = vs[index+1].x; next_pt.y = vs[index+1].y; } if (num_pts == 2) { if (index == 0 && x == mid_pt.x && y == mid_pt.y) { strcpy(a_buf, "0"); } else { PointsToArc(mid_pt.x, mid_pt.y, x, y, mid_pt.x+100, mid_pt.y, ARC_CCW, FALSE, NULL, NULL, NULL, NULL, NULL, &angle2); if (angle2 > 180*64) angle2=(360*64)-angle2; FormatAngle(angle2, a_buf); } } else { if ((index == 0 || index == num_pts-1) && (x == mid_pt.x && y == mid_pt.y)) { strcpy(a_buf, "0"); } else if ((index != 0 && index != num_pts-1) && ((x == prev_pt.x && y == prev_pt.y) || (x == next_pt.x && y == next_pt.y))) { strcpy(a_buf, "180"); } else { PointsToArc(mid_pt.x, mid_pt.y, prev_pt.x, prev_pt.y, next_pt.x, next_pt.y, ARC_CCW, FALSE, NULL, NULL, NULL, NULL, NULL, &angle2); if (angle2 > 180*64) angle2=(360*64)-angle2; FormatAngle(angle2, a_buf); } } PixelToMeasurementUnit(x_buf, x); PixelToMeasurementUnit(y_buf, y); if (curChoice == FREEHAND) { sprintf(buf, "x=%s\ny=%s", x_buf, y_buf); } else { sprintf(buf, "x=%s\ny=%s\nangle=%s", x_buf, y_buf, a_buf); } switch (start) { case STRETCH_STARTSHOW: StartShowMeasureCursor(grid_x, grid_y, buf, TRUE); break; case STRETCH_DOSHOW: ShowMeasureCursor(grid_x, grid_y, buf, TRUE); break; case STRETCH_ENDSHOW: EndShowMeasureCursor(grid_x, grid_y, buf, TRUE); break; } } static XPoint v[5]; static void StretchPoly(XGridOff, YGridOff, ObjPtr, NumPts, V, Index) int XGridOff, YGridOff, NumPts, Index; IntPoint *V; struct ObjRec *ObjPtr; { struct AttrRec *name_attr=NULL, *on_reshape_attr=NULL; int i, x, y, dx, dy, num=0, stretching=TRUE; int ltx, lty, rbx, rby, curved=LT_STRAIGHT; int grid_x=XGridOff, grid_y=YGridOff, sn, intn; int auto_center_attr=AutoCenterAttr(ObjPtr); int has_on_reshape=HasOnReshape(ObjPtr, &name_attr); char *smooth=NULL; XEvent input, ev; XPoint *sv=NULL; IntPoint *pv=NULL, *cntrlv=NULL; if (ObjPtr->locked) { Msg(TgLoadString(STID_LOCKED_OBJS_CANT_BE_STRETCHED)); return; } pv = (IntPoint*)malloc((NumPts+1)*sizeof(IntPoint)); if (pv == NULL) FailAllocMessage(); memset(pv, 0, (NumPts+1)*sizeof(IntPoint)); switch (ObjPtr->type) { case OBJ_POLY: curved = ObjPtr->detail.p->curved; if (splineRubberband) { if (curved != LT_INTSPLINE && ObjPtr->detail.p->smooth != NULL) { smooth = (char*)malloc((NumPts+1)*sizeof(char)); if (smooth == NULL) FailAllocMessage(); } if (ObjPtr->ctm == NULL) { for (i = 0; i < NumPts; i++) { pv[i].x = V[i].x; pv[i].y = V[i].y; if (smooth != NULL) smooth[i] = ObjPtr->detail.p->smooth[i]; } } else { for (i = 0; i < NumPts; i++) { int x, y; TransformPointThroughCTM(V[i].x-ObjPtr->x, V[i].y-ObjPtr->y, ObjPtr->ctm, &x, &y); pv[i].x = x+ObjPtr->x; pv[i].y = y+ObjPtr->y; if (smooth != NULL) smooth[i] = ObjPtr->detail.p->smooth[i]; } } switch (curved) { case LT_STRAIGHT: case LT_SPLINE: sv = MakeMultiSplinePolyVertex(&sn, smooth, drawOrigX, drawOrigY, NumPts, pv); break; case LT_INTSPLINE: sv = MakeIntSplinePolyVertex(&sn, &intn, &cntrlv, drawOrigX, drawOrigY, NumPts, pv); break; } } else if (Index == 0 || Index == NumPts-1) { num = 2; if (Index == 0) { v[0].x = OFFSET_X(V[1].x); v[0].y = OFFSET_Y(V[1].y); v[1].x = OFFSET_X(V[0].x); v[1].y = OFFSET_Y(V[0].y); } else { v[0].x = OFFSET_X(V[NumPts-2].x); v[0].y = OFFSET_Y(V[NumPts-2].y); v[1].x = OFFSET_X(V[NumPts-1].x); v[1].y = OFFSET_Y(V[NumPts-1].y); } } else { num = 3; v[0].x = OFFSET_X(V[Index-1].x); v[0].y = OFFSET_Y(V[Index-1].y); v[1].x = OFFSET_X(V[Index].x); v[1].y = OFFSET_Y(V[Index].y); v[2].x = OFFSET_X(V[Index+1].x); v[2].y = OFFSET_Y(V[Index+1].y); } break; case OBJ_POLYGON: curved = ObjPtr->detail.g->curved; if (splineRubberband) { if (curved != LT_INTSPLINE && ObjPtr->detail.g->smooth != NULL) { smooth = (char*)malloc((NumPts+1)*sizeof(char)); if (smooth == NULL) FailAllocMessage(); } if (ObjPtr->ctm == NULL) { for (i = 0; i < NumPts; i++) { pv[i].x = V[i].x; pv[i].y = V[i].y; if (smooth != NULL) smooth[i] = ObjPtr->detail.g->smooth[i]; } } else { for (i = 0; i < NumPts; i++) { int x, y; TransformPointThroughCTM(V[i].x-ObjPtr->x, V[i].y-ObjPtr->y, ObjPtr->ctm, &x, &y); pv[i].x = x+ObjPtr->x; pv[i].y = y+ObjPtr->y; if (smooth != NULL) smooth[i] = ObjPtr->detail.g->smooth[i]; } } switch (curved) { case LT_STRAIGHT: case LT_SPLINE: sv = MakeMultiSplinePolygonVertex(&sn, smooth, drawOrigX, drawOrigY, NumPts, pv); break; case LT_INTSPLINE: sv = MakeIntSplinePolygonVertex(&sn, &intn, &cntrlv, drawOrigX, drawOrigY, NumPts, pv); break; } } else if (Index == 0 || Index == NumPts-1) { num = 3; v[0].x = OFFSET_X(V[1].x); v[0].y = OFFSET_Y(V[1].y); v[1].x = OFFSET_X(V[0].x); v[1].y = OFFSET_Y(V[0].y); v[2].x = OFFSET_X(V[NumPts-2].x); v[2].y = OFFSET_Y(V[NumPts-2].y); } else { num = 3; v[0].x = OFFSET_X(V[Index-1].x); v[0].y = OFFSET_Y(V[Index-1].y); v[1].x = OFFSET_X(V[Index].x); v[1].y = OFFSET_Y(V[Index].y); v[2].x = OFFSET_X(V[Index+1].x); v[2].y = OFFSET_Y(V[Index+1].y); } break; } if (!splineRubberband) { for (i=0; i < NumPts+1; i++) { pv[i].x = (int)(V[i].x); pv[i].y = (int)(V[i].y); } } ltx = ObjPtr->bbox.ltx; lty = ObjPtr->bbox.lty; rbx = ObjPtr->bbox.rbx; rby = ObjPtr->bbox.rby; XFlush(mainDisplay); XSync(mainDisplay, False); if (XCheckMaskEvent(mainDisplay, ExposureMask, &ev) || XCheckMaskEvent(mainDisplay, VisibilityChangeMask, &ev)) { ExposeEventHandler(&ev, TRUE); } DoStretchPolyMeasureCursor(STRETCH_STARTSHOW, NumPts, pv, Index, 0, 0, STRETCH_DRAW, STRETCH_CLICK, ObjPtr->type, grid_x, grid_y); if (!debugNoPointerGrab) { XGrabPointer(mainDisplay, drawWindow, False, PointerMotionMask | ButtonReleaseMask, GrabModeAsync, GrabModeAsync, None, handCursor, CurrentTime); } dx = dy = 0; while (stretching) { XNextEvent(mainDisplay, &input); if (input.type == Expose || input.type == VisibilityNotify) { ExposeEventHandler(&input, TRUE); } else if (input.type == ButtonRelease) { XUngrabPointer(mainDisplay, CurrentTime); XSync(mainDisplay, False); stretching = FALSE; } else if (input.type == MotionNotify || input.type == KeyPress || input.type == KeyRelease) { DoStretchPolyMeasureCursor(STRETCH_DOSHOW, NumPts, pv, Index, ABS_SIZE(grid_x-XGridOff), ABS_SIZE(grid_y-YGridOff), STRETCH_ERASE, STRETCH_DRAG, ObjPtr->type, grid_x, grid_y); if (input.type == KeyPress || input.type == KeyRelease ) { x = grid_x; y = grid_y; } else { x = input.xmotion.x; y = input.xmotion.y; } if (shiftForDiagMouseMove && DiagEventCheck(&input)) { if (input.type == KeyRelease) { x = input.xkey.x; y = input.xkey.y; } else { DiagGridXY(XGridOff, YGridOff, &x, &y); } } GridXY(x, y, &grid_x, &grid_y); if (splineRubberband) { XDrawLines(mainDisplay, drawWindow, revDefaultGC, sv, sn, CoordModeOrigin); } else { MyDashedLine(drawWindow, revDefaultGC, v, num); } dx = grid_x - XGridOff; dy = grid_y - YGridOff; v[1].x = OFFSET_X(V[Index].x) + dx; v[1].y = OFFSET_Y(V[Index].y) + dy; MarkRulers(v[1].x, v[1].y); if (splineRubberband) { free(sv); if (ObjPtr->type==OBJ_POLYGON && (Index==0 || Index==NumPts-1)) { if (ObjPtr->ctm == NULL) { pv[0].x = pv[NumPts-1].x = V[0].x + ABS_SIZE(dx); pv[0].y = pv[NumPts-1].y = V[0].y + ABS_SIZE(dy); } else { int x, y; TransformPointThroughCTM(V[0].x-ObjPtr->x, V[0].y-ObjPtr->y, ObjPtr->ctm, &x, &y); pv[0].x = pv[NumPts-1].x = x + ObjPtr->x + ABS_SIZE(dx); pv[0].y = pv[NumPts-1].y = y + ObjPtr->y + ABS_SIZE(dy); } } else { if (ObjPtr->ctm == NULL) { pv[Index].x = V[Index].x + ABS_SIZE(dx); pv[Index].y = V[Index].y + ABS_SIZE(dy); } else { int x, y; TransformPointThroughCTM(V[Index].x-ObjPtr->x, V[Index].y-ObjPtr->y, ObjPtr->ctm, &x, &y); pv[Index].x = x + ObjPtr->x + ABS_SIZE(dx); pv[Index].y = y + ObjPtr->y + ABS_SIZE(dy); } } switch (ObjPtr->type) { case OBJ_POLY: switch (curved) { case LT_STRAIGHT: case LT_SPLINE: sv = MakeMultiSplinePolyVertex(&sn, smooth, drawOrigX, drawOrigY, NumPts, pv); break; case LT_INTSPLINE: free(cntrlv); sv = MakeIntSplinePolyVertex(&sn, &intn, &cntrlv, drawOrigX, drawOrigY, NumPts, pv); break; } break; case OBJ_POLYGON: switch (curved) { case LT_STRAIGHT: case LT_SPLINE: sv = MakeMultiSplinePolygonVertex(&sn, smooth, drawOrigX, drawOrigY, NumPts, pv); break; case LT_INTSPLINE: free(cntrlv); sv = MakeIntSplinePolygonVertex(&sn, &intn, &cntrlv, drawOrigX, drawOrigY, NumPts, pv); break; } break; } XDrawLines(mainDisplay, drawWindow, revDefaultGC, sv, sn, CoordModeOrigin); } else { MyDashedLine(drawWindow, revDefaultGC, v, num); } DoStretchPolyMeasureCursor(STRETCH_DOSHOW, NumPts, pv, Index, ABS_SIZE(grid_x-XGridOff), ABS_SIZE(grid_y-YGridOff), STRETCH_DRAW, STRETCH_DRAG, ObjPtr->type, grid_x, grid_y); while (XCheckMaskEvent(mainDisplay, PointerMotionMask, &ev)) ; } } DoStretchPolyMeasureCursor(STRETCH_ENDSHOW, NumPts, pv, Index, ABS_SIZE(grid_x-XGridOff), ABS_SIZE(grid_y-YGridOff), STRETCH_ERASE, STRETCH_DRAG, ObjPtr->type, grid_x, grid_y); if (dx != 0 || dy != 0) { if (has_on_reshape && name_attr != NULL) { on_reshape_attr = FindAttrWithName(ObjPtr, "on_reshape=", NULL); } if (splineRubberband) { XDrawLines(mainDisplay, drawWindow, revDefaultGC, sv, sn, CoordModeOrigin); } else { MyDashedLine(drawWindow, revDefaultGC, v, num); } HighLightReverse(); if (on_reshape_attr != NULL) { StartCompositeCmd(); } PrepareToReplaceAnObj(ObjPtr); dx = ABS_SIZE(dx); dy = ABS_SIZE(dy); switch (ObjPtr->type) { case OBJ_POLY: if (ObjPtr->ctm == NULL) { V[Index].x += dx; V[Index].y += dy; } else { int x, y, new_x, new_y; TransformPointThroughCTM(V[Index].x-ObjPtr->x, V[Index].y-ObjPtr->y, ObjPtr->ctm, &x, &y); x += ObjPtr->x + dx; y += ObjPtr->y + dy; ReverseTransformPointThroughCTM(x-ObjPtr->x, y-ObjPtr->y, ObjPtr->ctm, &new_x, &new_y); V[Index].x = new_x + ObjPtr->x; V[Index].y = new_y + ObjPtr->y; } AdjObjSplineVs(ObjPtr); if (ObjPtr->detail.p->curved != LT_INTSPLINE) { UpdPolyBBox(ObjPtr, NumPts, V); } else { UpdPolyBBox(ObjPtr, ObjPtr->detail.p->intn, ObjPtr->detail.p->intvlist); } break; case OBJ_POLYGON: if (ObjPtr->ctm == NULL) { V[Index].x += dx; V[Index].y += dy; } else { int x, y, new_x, new_y; TransformPointThroughCTM(V[Index].x-ObjPtr->x, V[Index].y-ObjPtr->y, ObjPtr->ctm, &x, &y); x += ObjPtr->x + dx; y += ObjPtr->y + dy; ReverseTransformPointThroughCTM(x-ObjPtr->x, y-ObjPtr->y, ObjPtr->ctm, &new_x, &new_y); V[Index].x = new_x + ObjPtr->x; V[Index].y = new_y + ObjPtr->y; } if (Index == 0) { V[NumPts-1].x = V[Index].x; V[NumPts-1].y = V[Index].y; } else if (Index == NumPts-1) { V[0].x = V[Index].x; V[0].y = V[Index].y; } AdjObjSplineVs(ObjPtr); if (ObjPtr->detail.g->curved != LT_INTSPLINE) { UpdPolyBBox(ObjPtr, NumPts, V); } else { UpdPolyBBox(ObjPtr, ObjPtr->detail.g->intn, ObjPtr->detail.g->intvlist); } break; } if (auto_center_attr) { struct AttrRec *attr_ptr=ObjPtr->fattr; int modified=FALSE; for ( ; attr_ptr != NULL; attr_ptr=attr_ptr->next) { if (attr_ptr->shown) { struct BBRec bbox; CenterObjInOBBox(attr_ptr->obj, ObjPtr->obbox, &bbox); if (bbox.ltx < ltx) ltx = bbox.ltx; if (bbox.lty < lty) lty = bbox.lty; if (bbox.rbx > rbx) rbx = bbox.rbx; if (bbox.rby > rby) rby = bbox.rby; modified = TRUE; } } if (modified) AdjObjBBox(ObjPtr); } RecordReplaceAnObj(ObjPtr); if (on_reshape_attr != NULL) { DoExec(on_reshape_attr, ObjPtr); } if (on_reshape_attr != NULL) { EndCompositeCmd(); } UpdSelBBox(); RedrawAreas(botObj, ltx-GRID_ABS_SIZE(1), lty-GRID_ABS_SIZE(1), rbx+GRID_ABS_SIZE(1), rby+GRID_ABS_SIZE(1), ObjPtr->bbox.ltx-GRID_ABS_SIZE(1), ObjPtr->bbox.lty-GRID_ABS_SIZE(1), ObjPtr->bbox.rbx+GRID_ABS_SIZE(1), ObjPtr->bbox.rby+GRID_ABS_SIZE(1)); SetFileModified(TRUE); justDupped = FALSE; HighLightForward(); } free(pv); if (splineRubberband) { free(sv); if (smooth != NULL) free(smooth); if (curved == LT_INTSPLINE && cntrlv != NULL) free(cntrlv); } } static double multX=(double)0.0, multY=(double)0.0; static int pivotX=0, pivotY=0, changeX=0, changeY=0, moveX=0, moveY=0; static int absPivotX=0, absPivotY=0; static void StretchedXY(X, Y, NewX, NewY) int X, Y, * NewX, * NewY; /* screen offsets */ { register int dx, dy; dx = round((double)((double)(X - pivotX) * multX)); dy = round((double)((double)(Y - pivotY) * multY)); *NewX = pivotX + dx; *NewY = pivotY + dy; } static void StretchedAbsXY(X, Y, NewX, NewY) int X, Y, * NewX, * NewY; /* screen offsets */ { register int dx, dy; dx = round((double)((double)(X - absPivotX) * multX)); dy = round((double)((double)(Y - absPivotY) * multY)); *NewX = absPivotX + dx; *NewY = absPivotY + dy; } static void ShearedXY(Corner, x, y, dx_shear, dy_shear, dx_scale, dy_scale, new_x, new_y) int Corner, x, y, *new_x, *new_y; double dx_shear, dy_shear, dx_scale, dy_scale; { double val, dx, dy; if (Corner != CORNER_NONE && Corner != CORNER_RIGHT && Corner != CORNER_LEFT) { if (y == pivotY) { *new_x = x; *new_y = y; } else { dy = ((double)(y-pivotY))*dy_scale/1000.0; val = tan(dx_shear/1000.0)*dy; *new_x = round(val + x); *new_y = round(dy + pivotY); } } if (Corner != CORNER_NONE && Corner != CORNER_TOP && Corner != CORNER_BOTTOM) { if (x == pivotX) { *new_x = x; *new_y = y; } else { dx = ((double)(x-pivotX))*dx_scale/1000.0; val = tan(dy_shear/1000.0)*dx; *new_x = round(dx + pivotX); *new_y = round(val + y); } } } static void ShearedAbsXY(Corner, abs_x, abs_y, dx_shear, dy_shear, dx_scale, dy_scale, new_x, new_y) int Corner, abs_x, abs_y, *new_x, *new_y; double dx_shear, dy_shear, dx_scale, dy_scale; { double val, dx, dy; if (Corner != CORNER_NONE && Corner != CORNER_RIGHT && Corner != CORNER_LEFT) { if (abs_y == absPivotY) { *new_x = abs_x; *new_y = abs_y; } else { dy = ((double)(abs_y-absPivotY))*dy_scale/1000.0; val = tan(dx_shear/1000.0)*dy; *new_x = round(val + abs_x); *new_y = round(dy + absPivotY); } } if (Corner != CORNER_NONE && Corner != CORNER_TOP && Corner != CORNER_BOTTOM) { if (abs_x == absPivotX) { *new_x = abs_x; *new_y = abs_y; } else { dx = ((double)(abs_x-absPivotX))*dx_scale/1000.0; val = tan(dy_shear/1000.0)*dx; *new_x = round(dx + absPivotX); *new_y = round(val + abs_y); } } } static void SetPivot(Corner, pOBBox) int Corner; struct BBRec *pOBBox; /* pivotX, pivotY, moveX, moveY will be set to screen offsets */ { switch (Corner) { case CORNER_NONE: /* same as CORNER_CC */ pivotX = moveX = ((pOBBox->ltx+pOBBox->rbx)>>1); pivotY = moveY = ((pOBBox->lty+pOBBox->rby)>>1); changeX = TRUE; changeY = TRUE; break; case CORNER_LT: pivotX = pOBBox->rbx; pivotY = pOBBox->rby; moveX = pOBBox->ltx; moveY = pOBBox->lty; changeX = changeY = TRUE; break; case CORNER_TOP: pivotX = moveX = ((pOBBox->ltx+pOBBox->rbx)>>1); pivotY = pOBBox->rby; moveY = pOBBox->lty; changeX = FALSE; changeY = TRUE; break; case CORNER_RT: pivotX = pOBBox->ltx; pivotY = pOBBox->rby; moveX = pOBBox->rbx; moveY = pOBBox->lty; changeX = changeY = TRUE; break; case CORNER_RIGHT: pivotX = pOBBox->ltx; pivotY = moveY = ((pOBBox->lty+pOBBox->rby)>>1); moveX = pOBBox->rbx; changeX = TRUE; changeY = FALSE; break; case CORNER_RB: pivotX = pOBBox->ltx; pivotY = pOBBox->lty; moveX = pOBBox->rbx; moveY = pOBBox->rby; changeX = changeY = TRUE; break; case CORNER_BOTTOM: pivotX = moveX = ((pOBBox->ltx+pOBBox->rbx)>>1); pivotY = pOBBox->lty; moveY = pOBBox->rby; changeX = FALSE; changeY = TRUE; break; case CORNER_LB: pivotX = pOBBox->rbx; pivotY = pOBBox->lty; moveX = pOBBox->ltx; moveY = pOBBox->rby; changeX = changeY = TRUE; break; case CORNER_LEFT: pivotX = pOBBox->rbx; pivotY = moveY = ((pOBBox->lty+pOBBox->rby)>>1); moveX = pOBBox->ltx; changeX = TRUE; changeY = FALSE; break; } multX = 1.0; multY = 1.0; absPivotX = pivotX; absPivotY = pivotY; pivotX = OFFSET_X(absPivotX); pivotY = OFFSET_Y(absPivotY); moveX = OFFSET_X(moveX); moveY = OFFSET_Y(moveY); } void ShearObj(ObjPtr, Corner, dxShear, dyShear, dxScale, dyScale, RealLtX, RealLtY) struct ObjRec *ObjPtr; int Corner; double dxShear, dyShear, dxScale, dyScale; /* scaled by 1000 */ int *RealLtX, *RealLtY; { IntPoint abs_obj_obbox_vs[5]; int x, y, new_ltx, new_lty, new_rbx, new_rby; double tan_val; struct XfrmMtrxRec ctm, new_ctm; struct ObjRec *obj_ptr; struct AttrRec *attr_ptr; int auto_center_attr=AutoCenterAttr(ObjPtr); switch (ObjPtr->type) { case OBJ_GROUP: case OBJ_ICON: case OBJ_SYM: case OBJ_PIN: for (obj_ptr=ObjPtr->detail.r->first; obj_ptr != NULL; obj_ptr=obj_ptr->next) { ShearObj(obj_ptr, Corner, dxShear, dyShear, dxScale, dyScale, RealLtX, RealLtY); } break; default: if (ObjPtr->ctm == NULL) { memcpy(&ObjPtr->orig_obbox, &ObjPtr->obbox, sizeof(struct BBRec)); if (ObjPtr->type == OBJ_TEXT) { memcpy(&ObjPtr->detail.t->orig_bbox, &ObjPtr->bbox, sizeof(struct BBRec)); } ObjPtr->ctm = (struct XfrmMtrxRec *)malloc(sizeof(struct XfrmMtrxRec)); if (ObjPtr->ctm == NULL) FailAllocMessage(); ObjPtr->ctm->m[CTM_SX] = ObjPtr->ctm->m[CTM_SY] = (double)1000; ObjPtr->ctm->m[CTM_SIN] = ObjPtr->ctm->m[CTM_MSIN] = (double)0; ObjPtr->ctm->t[CTM_TX] = ObjPtr->ctm->t[CTM_TY] = 0; } ShearedAbsXY(Corner, ObjPtr->x+ObjPtr->ctm->t[CTM_TX], ObjPtr->y+ObjPtr->ctm->t[CTM_TY], dxShear, dyShear, dxScale, dyScale, &x, &y); switch (Corner) { case CORNER_TOP: case CORNER_BOTTOM: tan_val = tan(dxShear/1000.0); ctm.m[CTM_SX] = (double)1000; ctm.m[CTM_SY] = dyScale; ctm.m[CTM_SIN] = (double)0; ctm.m[CTM_MSIN] = dyScale*tan_val; break; case CORNER_RIGHT: case CORNER_LEFT: tan_val = tan(dyShear/1000.0); ctm.m[CTM_SX] = dxScale; ctm.m[CTM_SY] = (double)1000; ctm.m[CTM_SIN] = dxScale*tan_val; ctm.m[CTM_MSIN] = (double)0; break; default: ctm.m[CTM_SX] = dxScale; ctm.m[CTM_SY] = dyScale; ctm.m[CTM_SIN] = (double)0; ctm.m[CTM_MSIN] = (double)0; break; } ctm.t[CTM_TX] = 0; ctm.t[CTM_TY] = 0; ConcatCTM(ObjPtr->ctm, &ctm, &new_ctm); new_ctm.t[CTM_TX] = x-ObjPtr->x; new_ctm.t[CTM_TY] = y-ObjPtr->y; memcpy(ObjPtr->ctm, &new_ctm, sizeof(struct XfrmMtrxRec)); GetTransformedOBBoxAbsVs(ObjPtr, abs_obj_obbox_vs); new_ltx = min(min(abs_obj_obbox_vs[0].x,abs_obj_obbox_vs[1].x), min(abs_obj_obbox_vs[2].x,abs_obj_obbox_vs[3].x)); new_rbx = max(max(abs_obj_obbox_vs[0].x,abs_obj_obbox_vs[1].x), max(abs_obj_obbox_vs[2].x,abs_obj_obbox_vs[3].x)); new_lty = min(min(abs_obj_obbox_vs[0].y,abs_obj_obbox_vs[1].y), min(abs_obj_obbox_vs[2].y,abs_obj_obbox_vs[3].y)); new_rby = max(max(abs_obj_obbox_vs[0].y,abs_obj_obbox_vs[1].y), max(abs_obj_obbox_vs[2].y,abs_obj_obbox_vs[3].y)); ObjPtr->obbox.ltx = new_ltx; ObjPtr->obbox.lty = new_lty; ObjPtr->obbox.rbx = new_rbx; ObjPtr->obbox.rby = new_rby; if (RealLtX != NULL && RealLtY != NULL) { MoveObj(ObjPtr, (*RealLtX)-new_ltx, (*RealLtY)-new_lty); } if (ObjPtr->ctm->m[CTM_SX] >= 999.0 && ObjPtr->ctm->m[CTM_SX] <= 1001.0 && ObjPtr->ctm->m[CTM_SY] >= 999.0 && ObjPtr->ctm->m[CTM_SY] <= 1001.0 && ObjPtr->ctm->m[CTM_SIN] >= (-1.0) && ObjPtr->ctm->m[CTM_SIN] <= 1.0 && ObjPtr->ctm->m[CTM_MSIN] >= (-1.0) && ObjPtr->ctm->m[CTM_MSIN] <= 1.0) { int dx=ObjPtr->ctm->t[CTM_TX], dy=ObjPtr->ctm->t[CTM_TY]; free(ObjPtr->ctm); ObjPtr->ctm = NULL; memcpy(&ObjPtr->obbox, &ObjPtr->orig_obbox, sizeof(struct BBRec)); if (ObjPtr->type == OBJ_TEXT) { memcpy(&ObjPtr->bbox, &ObjPtr->detail.t->orig_bbox, sizeof(struct BBRec)); } MoveObj(ObjPtr, dx, dy); } break; } AdjObjOBBox(ObjPtr); if (auto_center_attr) { for (attr_ptr=ObjPtr->fattr; attr_ptr != NULL; attr_ptr=attr_ptr->next) { ShearObj(attr_ptr->obj, Corner, dxShear, dyShear, dxScale, dyScale, NULL, NULL); if (attr_ptr->shown) { CenterObjInOBBox(attr_ptr->obj, ObjPtr->obbox, NULL); } } } else { for (attr_ptr=ObjPtr->fattr; attr_ptr != NULL; attr_ptr=attr_ptr->next) { ShearObj(attr_ptr->obj, Corner, dxShear, dyShear, dxScale, dyScale, NULL, NULL); } } AdjObjSplineVs(ObjPtr); AdjObjCache(ObjPtr); AdjObjBBox(ObjPtr); } static void StretchSimpleText(ObjPtr, Corner) struct ObjRec *ObjPtr; int Corner; { /* !stretchableText */ if (ObjPtr->ctm == NULL) { int new_x, new_y, h=ABS_SIZE(ObjPtr->obbox.rby-ObjPtr->obbox.lty); StretchedAbsXY(ObjPtr->x, ObjPtr->y, &new_x, &new_y); MoveObj(ObjPtr, new_x-ObjPtr->x, new_y-ObjPtr->y); ObjPtr->x = new_x; ObjPtr->y = new_y; if (multX < 0) { ObjPtr->detail.t->minilines.just = MAXJUSTS-1-ObjPtr->detail.t->minilines.just; } if (multY < 0) { MoveObj(ObjPtr, 0, -h); } } else { int abs_x, abs_y, new_x, new_y; abs_x = ObjPtr->x+ObjPtr->ctm->t[CTM_TX]; abs_y = ObjPtr->y+ObjPtr->ctm->t[CTM_TY]; StretchedAbsXY(abs_x, abs_y, &new_x, &new_y); if (multX < 0.0 || multY < 0.0) { int new_ltx, new_lty, new_rbx, new_rby; IntPoint abs_obj_obbox_vs[5]; struct XfrmMtrxRec ctm, new_ctm; ctm.m[CTM_SX] = ctm.m[CTM_SY] = (double)1000; ctm.m[CTM_SIN] = ctm.m[CTM_MSIN] = (double)0; ctm.t[CTM_TX] = ctm.t[CTM_TY] = 0; ctm.m[CTM_SX] = (multX < 0.0) ? (double)(-1000) : (double)1000; ctm.m[CTM_SY] = (multY < 0.0) ? (double)(-1000) : (double)1000; ConcatCTM(ObjPtr->ctm, &ctm, &new_ctm); new_ctm.t[CTM_TX] = new_x-ObjPtr->x; new_ctm.t[CTM_TY] = new_y-ObjPtr->y; memcpy(ObjPtr->ctm, &new_ctm, sizeof(struct XfrmMtrxRec)); GetTransformedOBBoxAbsVs(ObjPtr, abs_obj_obbox_vs); new_ltx = min(min(abs_obj_obbox_vs[0].x,abs_obj_obbox_vs[1].x), min(abs_obj_obbox_vs[2].x,abs_obj_obbox_vs[3].x)); new_rbx = max(max(abs_obj_obbox_vs[0].x,abs_obj_obbox_vs[1].x), max(abs_obj_obbox_vs[2].x,abs_obj_obbox_vs[3].x)); new_lty = min(min(abs_obj_obbox_vs[0].y,abs_obj_obbox_vs[1].y), min(abs_obj_obbox_vs[2].y,abs_obj_obbox_vs[3].y)); new_rby = max(max(abs_obj_obbox_vs[0].y,abs_obj_obbox_vs[1].y), max(abs_obj_obbox_vs[2].y,abs_obj_obbox_vs[3].y)); ObjPtr->obbox.ltx = new_ltx; ObjPtr->obbox.lty = new_lty; ObjPtr->obbox.rbx = new_rbx; ObjPtr->obbox.rby = new_rby; abs_x = ObjPtr->x+ObjPtr->ctm->t[CTM_TX]; abs_y = ObjPtr->y+ObjPtr->ctm->t[CTM_TY]; } MoveObj(ObjPtr, new_x-abs_x, new_y-abs_y); } UpdTextBBox(ObjPtr); AdjObjSplineVs(ObjPtr); AdjObjBBox(ObjPtr); } static int CompoundObjHasTextSubObj(ObjPtr) struct ObjRec *ObjPtr; { struct ObjRec *sub_obj=ObjPtr->detail.r->last; for ( ; sub_obj != NULL; sub_obj=sub_obj->prev) { if (sub_obj->type == OBJ_GROUP || sub_obj->type == OBJ_ICON || sub_obj->type == OBJ_SYM || sub_obj->type == OBJ_PIN) { if (CompoundObjHasTextSubObj(sub_obj)) { return TRUE; } } else { return (sub_obj->type == OBJ_TEXT); } } return FALSE; } static void JustMoveSimpleCompoundObj(ObjPtr, Corner) struct ObjRec *ObjPtr; int Corner; { /* !stretchableText && !compoundObjWithTextStretchableForPSE */ if (ObjPtr->ctm == NULL) { int new_x, new_y, h=ABS_SIZE(ObjPtr->obbox.rby-ObjPtr->obbox.lty); StretchedAbsXY(ObjPtr->x, ObjPtr->y, &new_x, &new_y); MoveObj(ObjPtr, new_x-ObjPtr->x, new_y-ObjPtr->y); ObjPtr->x = new_x; ObjPtr->y = new_y; if (multY < 0) { MoveObj(ObjPtr, 0, -h); } } else { int abs_x, abs_y, new_x, new_y; abs_x = ObjPtr->x+ObjPtr->ctm->t[CTM_TX]; abs_y = ObjPtr->y+ObjPtr->ctm->t[CTM_TY]; StretchedAbsXY(abs_x, abs_y, &new_x, &new_y); if (multX < 0.0 || multY < 0.0) { int new_ltx, new_lty, new_rbx, new_rby; IntPoint abs_obj_obbox_vs[5]; struct XfrmMtrxRec ctm, new_ctm; ctm.m[CTM_SX] = ctm.m[CTM_SY] = (double)1000; ctm.m[CTM_SIN] = ctm.m[CTM_MSIN] = (double)0; ctm.t[CTM_TX] = ctm.t[CTM_TY] = 0; ctm.m[CTM_SX] = (multX < 0.0) ? (double)(-1000) : (double)1000; ctm.m[CTM_SY] = (multY < 0.0) ? (double)(-1000) : (double)1000; ConcatCTM(ObjPtr->ctm, &ctm, &new_ctm); new_ctm.t[CTM_TX] = new_x-ObjPtr->x; new_ctm.t[CTM_TY] = new_y-ObjPtr->y; memcpy(ObjPtr->ctm, &new_ctm, sizeof(struct XfrmMtrxRec)); GetTransformedOBBoxAbsVs(ObjPtr, abs_obj_obbox_vs); new_ltx = min(min(abs_obj_obbox_vs[0].x,abs_obj_obbox_vs[1].x), min(abs_obj_obbox_vs[2].x,abs_obj_obbox_vs[3].x)); new_rbx = max(max(abs_obj_obbox_vs[0].x,abs_obj_obbox_vs[1].x), max(abs_obj_obbox_vs[2].x,abs_obj_obbox_vs[3].x)); new_lty = min(min(abs_obj_obbox_vs[0].y,abs_obj_obbox_vs[1].y), min(abs_obj_obbox_vs[2].y,abs_obj_obbox_vs[3].y)); new_rby = max(max(abs_obj_obbox_vs[0].y,abs_obj_obbox_vs[1].y), max(abs_obj_obbox_vs[2].y,abs_obj_obbox_vs[3].y)); ObjPtr->obbox.ltx = new_ltx; ObjPtr->obbox.lty = new_lty; ObjPtr->obbox.rbx = new_rbx; ObjPtr->obbox.rby = new_rby; abs_x = ObjPtr->x+ObjPtr->ctm->t[CTM_TX]; abs_y = ObjPtr->y+ObjPtr->ctm->t[CTM_TY]; } MoveObj(ObjPtr, new_x-abs_x, new_y-abs_y); } AdjObjSplineVs(ObjPtr); AdjObjBBox(ObjPtr); } static void StretchAttr(ObjPtr, Corner, dxScale, dyScale, AutoCenterAttr) struct ObjRec *ObjPtr; int Corner, AutoCenterAttr; double dxScale, dyScale; { struct AttrRec *attr_ptr=ObjPtr->fattr; if (attr_ptr == NULL) return; if (stretchingEverything) { struct BBRec final_obbox; double dz=(double)0; if (AutoCenterAttr) { for (attr_ptr=ObjPtr->fattr; attr_ptr != NULL; attr_ptr=attr_ptr->next) { struct ObjRec *obj_ptr=attr_ptr->obj; int ltx=0, lty=0, rbx=0, rby=0; StretchedAbsXY(obj_ptr->obbox.ltx, obj_ptr->obbox.lty, <x, <y); StretchedAbsXY(obj_ptr->obbox.rbx, obj_ptr->obbox.rby, &rbx, &rby); CalcBBox(ltx, lty, rbx, rby, &final_obbox.ltx, &final_obbox.lty, &final_obbox.rbx, &final_obbox.rby); ShearObj(attr_ptr->obj, Corner, dz, dz, dxScale, dyScale, &final_obbox.ltx, &final_obbox.lty); if (attr_ptr->shown) { CenterObjInOBBox(attr_ptr->obj, ObjPtr->obbox, NULL); } } } else { for (attr_ptr=ObjPtr->fattr; attr_ptr != NULL; attr_ptr=attr_ptr->next) { struct ObjRec *obj_ptr=attr_ptr->obj; int ltx=0, lty=0, rbx=0, rby=0; StretchedAbsXY(obj_ptr->obbox.ltx, obj_ptr->obbox.lty, <x, <y); StretchedAbsXY(obj_ptr->obbox.rbx, obj_ptr->obbox.rby, &rbx, &rby); CalcBBox(ltx, lty, rbx, rby, &final_obbox.ltx, &final_obbox.lty, &final_obbox.rbx, &final_obbox.rby); ShearObj(obj_ptr, Corner, dz, dz, dxScale, dyScale, &final_obbox.ltx, &final_obbox.lty); } } } else { if (AutoCenterAttr) { for (attr_ptr=ObjPtr->fattr; attr_ptr != NULL; attr_ptr=attr_ptr->next) { if (attr_ptr->shown) { CenterObjInOBBox(attr_ptr->obj, ObjPtr->obbox, NULL); } else { StretchSimpleText(attr_ptr->obj, Corner); } } } else { for (attr_ptr=ObjPtr->fattr; attr_ptr != NULL; attr_ptr=attr_ptr->next) { StretchSimpleText(attr_ptr->obj, Corner); } } } } static void StretchSimpleArc(ObjPtr) struct ObjRec *ObjPtr; { struct ArcRec *arc_ptr=ObjPtr->detail.a; int x, y; StretchedAbsXY(arc_ptr->xc, arc_ptr->yc, &x, &y); arc_ptr->xc = ObjPtr->x = x; arc_ptr->yc = ObjPtr->y = y; StretchedAbsXY(arc_ptr->x1, arc_ptr->y1, &x, &y); arc_ptr->x1 = x; arc_ptr->y1 = y; StretchedAbsXY(arc_ptr->x2, arc_ptr->y2, &x, &y); arc_ptr->x2 = x; arc_ptr->y2 = y; StretchedAbsXY(arc_ptr->ltx, arc_ptr->lty, &x, &y); arc_ptr->ltx = arc_ptr->xc-abs(x-arc_ptr->xc); arc_ptr->lty = arc_ptr->yc-abs(y-arc_ptr->yc); arc_ptr->w = (arc_ptr->xc-arc_ptr->ltx)<<1; arc_ptr->h = (arc_ptr->yc-arc_ptr->lty)<<1; if (multX < 0) { arc_ptr->dir = !(arc_ptr->dir); arc_ptr->angle2 = -(arc_ptr->angle2); if (arc_ptr->angle1 > 0) { arc_ptr->angle1 = (180*64) - arc_ptr->angle1; } else { arc_ptr->angle1 = (-180*64) - arc_ptr->angle1; } } if (multY < 0) { arc_ptr->dir = !(arc_ptr->dir); arc_ptr->angle1 = -(arc_ptr->angle1); arc_ptr->angle2 = -(arc_ptr->angle2); } AdjObjSplineVs(ObjPtr); AdjObjBBox(ObjPtr); } static void StretchSimplePoly(ObjPtr) struct ObjRec *ObjPtr; { int i, ltx=0, lty=0, rbx=0, rby=0; struct PolyRec *poly_ptr= ObjPtr->detail.p; IntPoint *vs=poly_ptr->vlist; for (i = 0; i < poly_ptr->n; i++) { int x, y; StretchedAbsXY(vs[i].x, vs[i].y, &x, &y); vs[i].x = x; vs[i].y = y; if (i == 0) { ltx = rbx = x; lty = rby = y; } else { if (x < ltx) ltx = x; if (y < lty) lty = y; if (x > rbx) rbx = x; if (y > rby) rby = y; } } ObjPtr->obbox.ltx = ObjPtr->x = ltx; ObjPtr->obbox.lty = ObjPtr->y = lty; ObjPtr->obbox.rbx = rbx; ObjPtr->obbox.rby = rby; AdjObjSplineVs(ObjPtr); if (poly_ptr->curved == LT_INTSPLINE) { UpdPolyBBox(ObjPtr, poly_ptr->intn, poly_ptr->intvlist); } } static void StretchSimplePolygon(ObjPtr) struct ObjRec *ObjPtr; { int i, ltx=0, lty=0, rbx=0, rby=0; struct PolygonRec *polygon_ptr= ObjPtr->detail.g; IntPoint *vs=polygon_ptr->vlist; for (i = 0; i < polygon_ptr->n; i++) { int x, y; StretchedAbsXY(vs[i].x, vs[i].y, &x, &y); vs[i].x = x; vs[i].y = y; if (i == 0) { ltx = rbx = x; lty = rby = y; } else { if (x < ltx) ltx = x; if (y < lty) lty = y; if (x > rbx) rbx = x; if (y > rby) rby = y; } } ObjPtr->obbox.ltx = ObjPtr->x = ltx; ObjPtr->obbox.lty = ObjPtr->y = lty; ObjPtr->obbox.rbx = rbx; ObjPtr->obbox.rby = rby; AdjObjSplineVs(ObjPtr); if (polygon_ptr->curved == LT_INTSPLINE) { UpdPolyBBox(ObjPtr, polygon_ptr->intn, polygon_ptr->intvlist); } } static void StretchSimpleObj(ObjPtr, Corner, dxScale, dyScale, FinalOBBox, auto_center_attr) struct ObjRec *ObjPtr; int Corner, auto_center_attr; double dxScale, dyScale; struct BBRec *FinalOBBox; { ObjPtr->obbox.ltx = ObjPtr->x = FinalOBBox->ltx; ObjPtr->obbox.lty = ObjPtr->y = FinalOBBox->lty; ObjPtr->obbox.rbx = FinalOBBox->rbx; ObjPtr->obbox.rby = FinalOBBox->rby; switch (ObjPtr->type) { case OBJ_ARC: StretchSimpleArc(ObjPtr); break; case OBJ_POLY: StretchSimplePoly(ObjPtr); break; case OBJ_POLYGON: StretchSimplePolygon(ObjPtr); break; case OBJ_RCBOX: AdjObjSplineVs(ObjPtr); break; case OBJ_BOX: AdjObjSplineVs(ObjPtr); break; case OBJ_OVAL: AdjObjSplineVs(ObjPtr); break; } AdjObjOBBox(ObjPtr); StretchAttr(ObjPtr, Corner, dxScale, dyScale, auto_center_attr); AdjObjBBox(ObjPtr); } static void ScaleLineWidth(ObjPtr, dScale) struct ObjRec *ObjPtr; double dScale; { double dscale=(double)(dScale/1000.0); if (!stretchingEverything) return; switch (ObjPtr->type) { case OBJ_POLY: ScaleWidthAndSpec(dscale, &ObjPtr->detail.p->width, ObjPtr->detail.p->width_spec); ScaleWidthAndSpec(dscale, &ObjPtr->detail.p->aw, ObjPtr->detail.p->aw_spec); ScaleWidthAndSpec(dscale, &ObjPtr->detail.p->ah, ObjPtr->detail.p->ah_spec); break; case OBJ_POLYGON: ScaleWidthAndSpec(dscale, &ObjPtr->detail.g->width, ObjPtr->detail.g->width_spec); break; case OBJ_BOX: ScaleWidthAndSpec(dscale, &ObjPtr->detail.b->width, ObjPtr->detail.b->width_spec); break; case OBJ_OVAL: ScaleWidthAndSpec(dscale, &ObjPtr->detail.o->width, ObjPtr->detail.o->width_spec); break; case OBJ_ARC: ScaleWidthAndSpec(dscale, &ObjPtr->detail.a->width, ObjPtr->detail.a->width_spec); ScaleWidthAndSpec(dscale, &ObjPtr->detail.a->aw, ObjPtr->detail.a->aw_spec); ScaleWidthAndSpec(dscale, &ObjPtr->detail.a->ah, ObjPtr->detail.a->ah_spec); break; case OBJ_RCBOX: ScaleWidthAndSpec(dscale, &ObjPtr->detail.rcb->width, ObjPtr->detail.rcb->width_spec); break; } } static void StretchObj(ObjPtr, Corner, dxScale, dyScale, ForceToUseCTM) struct ObjRec *ObjPtr; int Corner, ForceToUseCTM; double dxScale, dyScale; { int ltx, lty, rbx, rby; int auto_center_attr=AutoCenterAttr(ObjPtr); struct BBRec final_obbox; struct ObjRec *obj_ptr=NULL; struct AttrRec *saved_fattr=NULL, *saved_lattr=NULL; double dz=(double)0; StretchedAbsXY(ObjPtr->obbox.ltx, ObjPtr->obbox.lty, <x, <y); StretchedAbsXY(ObjPtr->obbox.rbx, ObjPtr->obbox.rby, &rbx, &rby); CalcBBox(ltx, lty, rbx, rby, &final_obbox.ltx, &final_obbox.lty, &final_obbox.rbx, &final_obbox.rby); if (ForceToUseCTM && ObjPtr->ctm == NULL && ObjPtr->type != OBJ_GROUP && ObjPtr->type != OBJ_ICON && ObjPtr->type != OBJ_SYM && ObjPtr->type != OBJ_PIN) { memcpy(&ObjPtr->orig_obbox, &ObjPtr->obbox, sizeof(struct BBRec)); if (ObjPtr->type == OBJ_TEXT) { memcpy(&ObjPtr->detail.t->orig_bbox, &ObjPtr->bbox, sizeof(struct BBRec)); } ObjPtr->ctm = (struct XfrmMtrxRec *)malloc(sizeof(struct XfrmMtrxRec)); if (ObjPtr->ctm == NULL) FailAllocMessage(); ObjPtr->ctm->m[CTM_SX] = ObjPtr->ctm->m[CTM_SY] = (double)1000; ObjPtr->ctm->m[CTM_SIN] = ObjPtr->ctm->m[CTM_MSIN] = (double)0; ObjPtr->ctm->t[CTM_TX] = ObjPtr->ctm->t[CTM_TY] = 0; } switch (ObjPtr->type) { case OBJ_POLY: case OBJ_POLYGON: case OBJ_BOX: case OBJ_OVAL: case OBJ_ARC: case OBJ_RCBOX: ScaleLineWidth(ObjPtr, dxScale); if (ObjPtr->ctm == NULL) { StretchSimpleObj(ObjPtr, Corner, dxScale, dyScale, &final_obbox, auto_center_attr); } else { ShearObj(ObjPtr, Corner, dz, dz, dxScale, dyScale, &final_obbox.ltx, &final_obbox.lty); } break; case OBJ_TEXT: if (stretchableText) { ShearObj(ObjPtr, Corner, dz, dz, dxScale, dyScale, &final_obbox.ltx, &final_obbox.lty); } else { StretchSimpleText(ObjPtr, Corner); } break; case OBJ_GROUP: case OBJ_ICON: case OBJ_SYM: case OBJ_PIN: if (!stretchableText && !compoundObjWithTextStretchableForPSE && CompoundObjHasTextSubObj(ObjPtr)) { JustMoveSimpleCompoundObj(ObjPtr, Corner); } else { for (obj_ptr=ObjPtr->detail.r->first; obj_ptr != NULL; obj_ptr=obj_ptr->next) { StretchObj(obj_ptr, Corner, dxScale, dyScale, ForceToUseCTM); } AdjObjOBBox(ObjPtr); StretchAttr(ObjPtr, Corner, dxScale, dyScale, auto_center_attr); AdjObjSplineVs(ObjPtr); AdjObjBBox(ObjPtr); } break; case OBJ_XBM: case OBJ_XPM: saved_fattr = ObjPtr->fattr; saved_lattr = ObjPtr->lattr; ObjPtr->fattr = ObjPtr->lattr = NULL; ShearObj(ObjPtr, Corner, dz, dz, dxScale, dyScale, &final_obbox.ltx, &final_obbox.lty); ObjPtr->fattr = saved_fattr; ObjPtr->lattr = saved_lattr; StretchAttr(ObjPtr, Corner, dxScale, dyScale, auto_center_attr); AdjObjBBox(ObjPtr); break; } } static void StretchAllSelObjects(Corner, dxScale, dyScale) int Corner; double dxScale, dyScale; { struct SelRec *sel_ptr; for (sel_ptr = topSel; sel_ptr != NULL; sel_ptr = sel_ptr->next) { if (!sel_ptr->obj->locked) { StretchObj(sel_ptr->obj, Corner, dxScale, dyScale, FALSE); } } if (numObjLocked != 0) { Msg(TgLoadString(STID_LOCKED_OBJS_ARE_NOT_STRETCHED)); } } static void MarkObjectsForStretch() { register struct ObjRec *obj_ptr; register struct SelRec *sel_ptr; for (obj_ptr = botObj; obj_ptr != NULL; obj_ptr = obj_ptr->prev) { obj_ptr->marked = FALSE; } for (sel_ptr = botSel; sel_ptr != NULL; sel_ptr = sel_ptr->prev) { sel_ptr->obj->marked = TRUE; } } static int ConstrainedStretchAllSel(Corner, ltx, lty, rbx, rby) int Corner; int *ltx, *lty, *rbx, *rby; { register struct ObjRec *obj_ptr; int something_stretched=FALSE, num_pts; int x_off, y_off, move_first, move_last, x, y; IntPoint *v; for (obj_ptr=botObj; obj_ptr != NULL; obj_ptr=obj_ptr->prev) { if (!obj_ptr->marked && obj_ptr->type==OBJ_POLY && !obj_ptr->locked) { num_pts = obj_ptr->detail.p->n; v = obj_ptr->detail.p->vlist; if (obj_ptr->ctm == NULL) { x_off = OFFSET_X(v[0].x); y_off = OFFSET_Y(v[0].y); move_first = EndPtInSelected(x_off, y_off); x_off = OFFSET_X(v[num_pts-1].x); y_off = OFFSET_Y(v[num_pts-1].y); move_last = EndPtInSelected(x_off, y_off); } else { int tmp_x, tmp_y; TransformPointThroughCTM(v[0].x-obj_ptr->x, v[0].y-obj_ptr->y, obj_ptr->ctm, &tmp_x, &tmp_y); tmp_x += obj_ptr->x; tmp_y += obj_ptr->y; x_off = OFFSET_X(tmp_x); y_off = OFFSET_Y(tmp_y); move_first = EndPtInSelected(x_off, y_off); TransformPointThroughCTM(v[num_pts-1].x-obj_ptr->x, v[num_pts-1].y-obj_ptr->y, obj_ptr->ctm, &tmp_x, &tmp_y); tmp_x += obj_ptr->x; tmp_y += obj_ptr->y; x_off = OFFSET_X(tmp_x); y_off = OFFSET_Y(tmp_y); move_last = EndPtInSelected(x_off, y_off); } if (move_first || move_last) { int index=INVALID, seg_dx, seg_dy, dx, dy, cur_seg_dx, cur_seg_dy; PrepareToReplaceAnObj(obj_ptr); if (obj_ptr->ctm != NULL) { /* Remove the transformations! */ int i; for (i=0; i < num_pts; i++) { int tmp_x, tmp_y; TransformPointThroughCTM(v[i].x-obj_ptr->x, v[i].y-obj_ptr->y, obj_ptr->ctm, &tmp_x, &tmp_y); v[i].x = tmp_x+obj_ptr->x; v[i].y = tmp_y+obj_ptr->y; } free(obj_ptr->ctm); obj_ptr->ctm = NULL; UpdPolyBBox(obj_ptr, num_pts, v); } if (something_stretched) { if (obj_ptr->bbox.ltx < *ltx) *ltx = obj_ptr->bbox.ltx; if (obj_ptr->bbox.lty < *lty) *lty = obj_ptr->bbox.lty; if (obj_ptr->bbox.rbx > *rbx) *rbx = obj_ptr->bbox.rbx; if (obj_ptr->bbox.rby > *rby) *rby = obj_ptr->bbox.rby; } else { *ltx = obj_ptr->bbox.ltx; *lty = obj_ptr->bbox.lty; *rbx = obj_ptr->bbox.rbx; *rby = obj_ptr->bbox.rby; } something_stretched = TRUE; if (move_first && move_last && num_pts==3) { StretchedAbsXY(v[0].x, v[0].y, &x, &y); dx = x-v[0].x; dy = y-v[0].y; index = 1; cur_seg_dx = v[index-1].x - v[index].x; cur_seg_dy = v[index-1].y - v[index].y; seg_dx = v[index].x - v[index+1].x; seg_dy = v[index].y - v[index+1].y; if (cur_seg_dy==0 && seg_dx==0 && (seg_dy!=0 || (seg_dy==0 && dx==0))) { v[index].y += dy; } else if (cur_seg_dx==0 && seg_dy==0 && (seg_dx!=0 || (seg_dx==0 && dy==0))) { v[index].x += dx; } } else { if (move_first && num_pts>2) { StretchedAbsXY(v[0].x, v[0].y, &x, &y); dx = x-v[0].x; dy = y-v[0].y; index = 1; cur_seg_dx = v[index-1].x - v[index].x; cur_seg_dy = v[index-1].y - v[index].y; seg_dx = v[index].x - v[index+1].x; seg_dy = v[index].y - v[index+1].y; if (cur_seg_dy==0 && cur_seg_dx!=0 && (seg_dy!=0 || (seg_dy==0 && dx==0))) { v[index].y += dy; } else if (cur_seg_dx==0 && cur_seg_dy!=0 && (seg_dx!=0 || (seg_dx==0 && dy==0))) { v[index].x += dx; } } if (move_last && num_pts>2) { StretchedAbsXY(v[num_pts-1].x, v[num_pts-1].y, &x, &y); dx = x-v[num_pts-1].x; dy = y-v[num_pts-1].y; index = num_pts-2; cur_seg_dx = v[index+1].x - v[index].x; cur_seg_dy = v[index+1].y - v[index].y; seg_dx = v[index].x - v[index-1].x; seg_dy = v[index].y - v[index-1].y; if (cur_seg_dy==0 && cur_seg_dx!=0 && (seg_dy!=0 || (seg_dy==0 && dx==0))) { v[index].y += dy; } else if (cur_seg_dx==0 && cur_seg_dy!=0 && (seg_dx!=0 || (seg_dx==0 && dy==0))) { v[index].x += dx; } } } if (move_first) { StretchedAbsXY(v[0].x, v[0].y, &x, &y); v[0].x = x; v[0].y = y; } if (move_last) { StretchedAbsXY(v[num_pts-1].x, v[num_pts-1].y, &x, &y); v[num_pts-1].x = x; v[num_pts-1].y = y; } AdjObjSplineVs(obj_ptr); switch (obj_ptr->type) { case OBJ_POLY: if (obj_ptr->detail.p->curved != LT_INTSPLINE) { UpdPolyBBox(obj_ptr, num_pts, v); } else { UpdPolyBBox(obj_ptr, obj_ptr->detail.p->intn, obj_ptr->detail.p->intvlist); } break; case OBJ_POLYGON: if (obj_ptr->detail.g->curved != LT_INTSPLINE) { UpdPolyBBox(obj_ptr, num_pts, v); } else { UpdPolyBBox(obj_ptr, obj_ptr->detail.g->intn, obj_ptr->detail.g->intvlist); } break; } AdjObjBBox(obj_ptr); if (AutoCenterAttr(obj_ptr)) { struct AttrRec *attr_ptr=obj_ptr->fattr; int modified=FALSE; for ( ; attr_ptr != NULL; attr_ptr = attr_ptr->next) { if (attr_ptr->shown) { struct BBRec bbox; CenterObjInOBBox(attr_ptr->obj, obj_ptr->obbox, &bbox); if (bbox.ltx < *ltx) *ltx = bbox.ltx; if (bbox.lty < *lty) *lty = bbox.lty; if (bbox.rbx > *rbx) *rbx = bbox.rbx; if (bbox.rby > *rby) *rby = bbox.rby; modified = TRUE; } } if (modified) AdjObjBBox(obj_ptr); } if (obj_ptr->bbox.ltx < *ltx) *ltx = obj_ptr->bbox.ltx; if (obj_ptr->bbox.lty < *lty) *lty = obj_ptr->bbox.lty; if (obj_ptr->bbox.rbx > *rbx) *rbx = obj_ptr->bbox.rbx; if (obj_ptr->bbox.rby > *rby) *rby = obj_ptr->bbox.rby; RecordReplaceAnObj(obj_ptr); } } } return something_stretched; } static void StretchAllSel(Corner, dxScale, dyScale) int Corner; double dxScale, dyScale; /* dxScale and dyScale are scaled by 1000 */ { int ltx, lty, rbx, rby, saved_ltx, saved_lty, saved_rbx, saved_rby; int poly_stretched; saved_ltx = selLtX; saved_lty = selLtY; saved_rbx = selRbX; saved_rby = selRbY; if (moveMode==CONST_MOVE) { MarkObjectsForStretch(); StartCompositeCmd(); PrepareToRecord(CMD_STRETCH, topSel, botSel, numObjSelected); RecordCmd(CMD_STRETCH, NULL, topSel, botSel, numObjSelected); poly_stretched = ConstrainedStretchAllSel(Corner, <x, <y, &rbx, &rby); StretchAllSelObjects(Corner, dxScale, dyScale); UpdSelBBox(); if (poly_stretched) { ltx = min(ltx,min(selLtX,saved_ltx)); lty = min(lty,min(selLtY,saved_lty)); rbx = max(rbx,max(selRbX,saved_rbx)); rby = max(rby,max(selRbY,saved_rby)); RedrawAnArea(botObj, ltx-GRID_ABS_SIZE(1), lty-GRID_ABS_SIZE(1), rbx+GRID_ABS_SIZE(1), rby+GRID_ABS_SIZE(1)); } else { RedrawAreas(botObj, saved_ltx-GRID_ABS_SIZE(1), saved_lty-GRID_ABS_SIZE(1), saved_rbx+GRID_ABS_SIZE(1), saved_rby+GRID_ABS_SIZE(1), selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1), selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1)); } EndCompositeCmd(); } else { PrepareToRecord(CMD_REPLACE, topSel, botSel, numObjSelected); StretchAllSelObjects(Corner, dxScale, dyScale); RecordCmd(CMD_REPLACE, NULL, topSel, botSel, numObjSelected); UpdSelBBox(); RedrawAreas(botObj, saved_ltx-GRID_ABS_SIZE(1), saved_lty-GRID_ABS_SIZE(1), saved_rbx+GRID_ABS_SIZE(1), saved_rby+GRID_ABS_SIZE(1), selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1), selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1)); } } static int DiagonalDistance(dx, dy) double dx, dy; { double dval=sqrt(dx*dx+dy*dy); return round(dval); } static double DiagonalAngle(dx, dy) int dx, dy; { double theta=((dx==0) ? ((dy>=0) ? M_PI/2.0 : -M_PI/2.0) : atan2((double)(dy), (double)(dx))); return theta*((double)180.0)/M_PI; } static void GetMeasurement(ObjPtr, buf, buf1) struct ObjRec *ObjPtr; char *buf, *buf1; { int ltx, lty, rbx, rby, real_ltx, real_lty, real_rbx, real_rby, dx, dy; char x_buf[80], y_buf[80], d_buf[80]; double diag_angle; StretchedAbsXY(ObjPtr->obbox.ltx, ObjPtr->obbox.lty, <x, <y); StretchedAbsXY(ObjPtr->obbox.rbx, ObjPtr->obbox.rby, &rbx, &rby); CalcBBox(ltx, lty, rbx, rby, &real_ltx, &real_lty, &real_rbx, &real_rby); PixelToMeasurementUnit(x_buf, abs(real_rbx-real_ltx)); PixelToMeasurementUnit(y_buf, abs(real_rby-real_lty)); sprintf(buf, "w=%s\nh=%s", x_buf, y_buf); dx = real_rbx-real_ltx; dy = real_rby-real_lty; PixelToMeasurementUnit(d_buf, abs(DiagonalDistance((double)dx, (double)dy))); diag_angle = DiagonalAngle(dx, dy); sprintf(buf1, "Diagonal: length=%s angle=%.2f or %.2f", d_buf, (float)diag_angle, (float)(((double)360.0)-diag_angle)); } static void PointsToShearScale(Corner, x_pivot, y_pivot, x_move, y_move, x_current, y_current, dx_shear, dy_shear, dx_scale, dy_scale) int Corner, x_pivot, y_pivot, x_move, y_move, x_current, y_current; double *dx_shear, *dy_shear, *dx_scale, *dy_scale; /* the returned shear value is 1000*arctan() */ /* the returned scale value is 1000*scaling */ { int dx=x_current-x_move, dy=y_current-y_move; switch (Corner) { case CORNER_TOP: case CORNER_BOTTOM: if (dx_scale != NULL) *dx_scale = (double)1000; if (dy_scale != NULL) { *dy_scale = (dy == 0 ? (double)1000 : (double)(((double)(y_current-y_pivot)) / ((double)(y_move-y_pivot))*1000.0)); } if (dx_shear != NULL) { *dx_shear = (dx == 0 ? (double)0 : (double)(atan2((double)dx,(double)y_current-y_pivot)*1000.0)); } if (dy_shear != NULL) *dy_shear = (double)0; break; case CORNER_RIGHT: case CORNER_LEFT: if (dx_scale != NULL) { *dx_scale = (dx == 0 ? (double)1000 : (double)(((double)(x_current-x_pivot)) / ((double)(x_move-x_pivot))*1000.0)); } if (dy_scale != NULL) *dy_scale = (double)1000; if (dx_shear != NULL) *dx_shear = (double)0; if (dy_shear != NULL) { *dy_shear = (dy == 0 ? (double)0 : (double)(atan2((double)dy,(double)x_current-x_pivot)*1000.0)); } break; default: /* scaling only, no shearing */ if (dx_scale != NULL) { *dx_scale = (dx == 0 ? (double)1000 : (double)(((double)(x_current-x_pivot)) / ((double)(x_move-x_pivot))*1000.0)); } if (dy_scale != NULL) { *dy_scale = (dy == 0 ? (double)1000 : (double)(((double)(y_current-y_pivot)) / ((double)(y_move-y_pivot))*1000.0)); } if (dx_shear != NULL) *dx_shear = (double)0; if (dy_shear != NULL) *dy_shear = (double)0; break; } } static void StretchBox(XGridOff, YGridOff, ObjPtr, Corner) int XGridOff, YGridOff, Corner; struct ObjRec *ObjPtr; { int x, y, stretching=TRUE; int ltx, lty, rbx, rby, sel_ltx, sel_lty, sel_rbx, sel_rby; int stretched_ltx, stretched_lty, stretched_rbx, stretched_rby; int stretched_sel_ltx, stretched_sel_lty, stretched_sel_rbx; int stretched_sel_rby; int ruler_ltx, ruler_lty, ruler_rbx, ruler_rby; int sel_obj_ltx, sel_obj_lty, sel_obj_rbx, sel_obj_rby; int grid_x=XGridOff, grid_y=YGridOff, proportional=FALSE; char buf[80], buf1[80]; double obj_w, obj_h; XEvent input, ev; if (numObjSelected == numObjLocked || ObjPtr->locked) { MsgBox(TgLoadString(STID_LOCKED_OBJS_CANT_BE_STRETCHED), TOOL_NAME, INFO_MB); return; } XFlush(mainDisplay); XSync(mainDisplay, False); if (XCheckMaskEvent(mainDisplay, ExposureMask, &ev) || XCheckMaskEvent(mainDisplay, VisibilityChangeMask, &ev)) { ExposeEventHandler(&ev, TRUE); } SetPivot(Corner, &ObjPtr->obbox); stretched_sel_ltx = sel_ltx = OFFSET_X(selNoLockLtX); stretched_sel_lty = sel_lty = OFFSET_Y(selNoLockLtY); stretched_sel_rbx = sel_rbx = OFFSET_X(selNoLockRbX); stretched_sel_rby = sel_rby = OFFSET_Y(selNoLockRbY); SelBox(drawWindow, revDefaultGC, stretched_sel_ltx-2, stretched_sel_lty-2, stretched_sel_rbx+2, stretched_sel_rby+2); ruler_ltx = sel_obj_ltx = OFFSET_X(selNoLockObjLtX); ruler_lty = sel_obj_lty = OFFSET_Y(selNoLockObjLtY); ruler_rbx = sel_obj_rbx = OFFSET_X(selNoLockObjRbX); ruler_rby = sel_obj_rby = OFFSET_Y(selNoLockObjRbY); stretched_ltx = ltx = OFFSET_X(ObjPtr->obbox.ltx); stretched_lty = lty = OFFSET_Y(ObjPtr->obbox.lty); stretched_rbx = rbx = OFFSET_X(ObjPtr->obbox.rbx); stretched_rby = rby = OFFSET_Y(ObjPtr->obbox.rby); SelBox(drawWindow, revDefaultGC, stretched_ltx, stretched_lty, stretched_rbx, stretched_rby); if (ltx == rbx || lty == rby) { Msg(TgLoadString(ltx == rbx ? STID_CANT_STRETCH_OBJ_HAS_0_WIDTH : STID_CANT_STRETCH_OBJ_HAS_0_HEIGHT)); SelBox(drawWindow, revDefaultGC, stretched_ltx, stretched_lty, stretched_rbx, stretched_rby); SelBox(drawWindow, revDefaultGC, stretched_sel_ltx-2, stretched_sel_lty-2, stretched_sel_rbx+2, stretched_sel_rby+2); return; } SaveStatusStrings(); obj_w = (double)(moveX - pivotX); obj_h = (double)(moveY - pivotY); GetMeasurement(ObjPtr, buf, buf1); StartShowMeasureCursor(grid_x, grid_y, buf, TRUE); if (showMeasurement) SetStringStatus(buf1); BeginIntervalRulers(ruler_ltx, ruler_lty, ruler_rbx, ruler_rby); if (!debugNoPointerGrab) { XGrabPointer(mainDisplay, drawWindow, False, PointerMotionMask | ButtonReleaseMask, GrabModeAsync, GrabModeAsync, None, handCursor, CurrentTime); } while (stretching) { XNextEvent(mainDisplay, &input); if (input.type == Expose || input.type == VisibilityNotify) { ExposeEventHandler(&input, TRUE); } else if (input.type == ButtonRelease) { proportional = (input.xbutton.state & (ShiftMask|ControlMask)); XUngrabPointer(mainDisplay, CurrentTime); XSync(mainDisplay, False); stretching = FALSE; } else if (input.type == MotionNotify || input.type == KeyPress || input.type == KeyRelease) { proportional = (input.xmotion.state & (ShiftMask|ControlMask)); GetMeasurement(ObjPtr, buf, buf1); EndShowMeasureCursor(grid_x, grid_y, buf, TRUE); if (showMeasurement) SetStringStatus(buf1); if (input.type == KeyPress || input.type == KeyRelease) { x = grid_x; y = grid_y; } else { x = input.xmotion.x; y = input.xmotion.y; } GridXY(x, y, &grid_x, &grid_y); SelBox(drawWindow, revDefaultGC, stretched_ltx, stretched_lty, stretched_rbx, stretched_rby); SelBox(drawWindow, revDefaultGC, stretched_sel_ltx-2, stretched_sel_lty-2, stretched_sel_rbx+2, stretched_sel_rby+2); if (proportional) { int new_w, new_h; double w_ratio, h_ratio; new_w = moveX + grid_x - XGridOff - pivotX; new_h = moveY + grid_y - YGridOff - pivotY; w_ratio = (moveX!=pivotX) ? fabs(((double)new_w)/obj_w) : 0.0; h_ratio = (moveY!=pivotY) ? fabs(((double)new_h)/obj_h) : 0.0; if (changeX && changeY) { if (w_ratio >= h_ratio) { multX = (moveX!=pivotX) ? ((double)new_w)/obj_w : 1.0; multY = fabs(multX) * ((new_h*obj_h>=0) ? 1.0 : -1.0); } else { multX = fabs(multY) * ((new_w*obj_w>=0) ? 1.0 : -1.0); multY = (moveY!=pivotY) ? ((double)new_h)/obj_h : 1.0; } } else if (changeX) { multX = (moveX!=pivotX) ? ((double)new_w)/obj_w : 1.0; multY = fabs(multX); } else if (changeY) { multX = fabs(multY); multY = (moveY!=pivotY) ? ((double)new_h)/obj_h : 1.0; } } else { if (changeX) { multX = (moveX!=pivotX) ? (double)(moveX+grid_x-XGridOff-pivotX)/obj_w : 1.0; } else { multX = (double)1.0; } if (changeY) { multY = (moveY!=pivotY) ? (double)(moveY+grid_y-YGridOff-pivotY)/obj_h : 1.0; } else { multY = (double)1.0; } } StretchedXY(sel_ltx, sel_lty, &stretched_sel_ltx, &stretched_sel_lty); StretchedXY(sel_rbx, sel_rby, &stretched_sel_rbx, &stretched_sel_rby); StretchedXY(ltx, lty, &stretched_ltx, &stretched_lty); StretchedXY(rbx, rby, &stretched_rbx, &stretched_rby); StretchedXY(sel_obj_ltx, sel_obj_lty, &ruler_ltx, &ruler_lty); StretchedXY(sel_obj_rbx, sel_obj_rby, &ruler_rbx, &ruler_rby); DrawIntervalRulers(ruler_ltx, ruler_lty, ruler_rbx, ruler_rby, NULL); SelBox(drawWindow, revDefaultGC, stretched_sel_ltx-2, stretched_sel_lty-2, stretched_sel_rbx+2, stretched_sel_rby+2); SelBox(drawWindow, revDefaultGC, stretched_ltx, stretched_lty, stretched_rbx, stretched_rby); GetMeasurement(ObjPtr, buf, buf1); EndShowMeasureCursor(grid_x, grid_y, buf, TRUE); if (showMeasurement) SetStringStatus(buf1); while (XCheckMaskEvent(mainDisplay, PointerMotionMask, &ev)) ; } } EndIntervalRulers(grid_x, grid_y); GetMeasurement(ObjPtr, buf, buf1); EndShowMeasureCursor(grid_x, grid_y, buf, TRUE); if (showMeasurement) SetStringStatus(buf1); RestoreStatusStrings(); SelBox(drawWindow, revDefaultGC, stretched_ltx, stretched_lty, stretched_rbx, stretched_rby); SelBox(drawWindow, revDefaultGC, stretched_sel_ltx-2, stretched_sel_lty-2, stretched_sel_rbx+2, stretched_sel_rby+2); if (multX != (double)1.0 || multY != (double)1.0) { int num_to_resize=0; double dx_scale=(double)1000, dy_scale=(double)1000; char **ppsz_names_to_resize=NULL; PointsToShearScale(Corner, pivotX, pivotY, moveX, moveY, moveX+grid_x-XGridOff, moveY+grid_y-YGridOff, NULL, NULL, &dx_scale, &dy_scale); if (proportional) { int abs_x_scale=round(dx_scale), abs_y_scale=round(dy_scale); if (abs_x_scale > abs_y_scale) { dy_scale = dx_scale; } else if (abs_x_scale < abs_y_scale) { dx_scale = dy_scale; } } HighLightReverse(); ppsz_names_to_resize = NeedToProcessOnResize(&num_to_resize); if (ppsz_names_to_resize == NULL) { StretchAllSel(Corner, dx_scale, dy_scale); } else { StartCompositeCmd(); StretchAllSel(Corner, dx_scale, dy_scale); DoOnResize(ppsz_names_to_resize, num_to_resize); EndCompositeCmd(); } HighLightForward(); SetFileModified(TRUE); justDupped = FALSE; } } void StretchSel(XGridOff, YGridOff, ObjPtr, Corner) int XGridOff, YGridOff, Corner; struct ObjRec *ObjPtr; { switch (ObjPtr->type) { case OBJ_BOX: case OBJ_OVAL: case OBJ_GROUP: case OBJ_ICON: case OBJ_SYM: case OBJ_PIN: case OBJ_ARC: case OBJ_RCBOX: case OBJ_XBM: case OBJ_XPM: StretchBox(XGridOff, YGridOff, ObjPtr, Corner); break; case OBJ_POLY: StretchPoly(XGridOff, YGridOff, ObjPtr, ObjPtr->detail.p->n, ObjPtr->detail.p->vlist, Corner); break; case OBJ_POLYGON: StretchPoly(XGridOff, YGridOff, ObjPtr, ObjPtr->detail.g->n, ObjPtr->detail.g->vlist, Corner); break; case OBJ_TEXT: if (stretchableText) { StretchBox(XGridOff, YGridOff, ObjPtr, Corner); } break; } } void ScaleAnEPSObj(ObjPtr, ScalingFactor) struct ObjRec *ObjPtr; float *ScalingFactor; { struct BBRec *obbox=(&(ObjPtr->obbox)); multX = multY = (double)(*ScalingFactor); changeX = changeY = (fabs(multX-1.0) > 1.0e-6); if (!changeX && !changeY) return;; absPivotX = obbox->ltx; absPivotY = obbox->lty; moveX = obbox->rbx; moveY = obbox->rby; StretchObj(ObjPtr, CORNER_RB, (double)(multX*1000.0), (double)(multY*1000.0), FALSE); } static void ScaleAllSelObjects(Corner, dxScale, dyScale) int Corner; double dxScale, dyScale; /* * Force to use CTM! */ { struct SelRec *sel_ptr=NULL; for (sel_ptr=topSel; sel_ptr != NULL; sel_ptr=sel_ptr->next) { sel_ptr->obj->tmp_parent = NULL; } for (sel_ptr=topSel; sel_ptr != NULL; sel_ptr=sel_ptr->next) { if (stretchingEverything || !sel_ptr->obj->locked) { StretchObj(sel_ptr->obj, Corner, dxScale, dyScale, TRUE); } } if (!stretchingEverything && numObjLocked != 0) { Msg(TgLoadString(STID_LOCKED_OBJS_CANT_BE_SCALED)); } } static void ScaleAllSel(Corner, dxScale, dyScale, redraw) int Corner, redraw; double dxScale, dyScale; { int ltx, lty, rbx, rby, saved_ltx, saved_lty, saved_rbx, saved_rby; int poly_stretched; saved_ltx = selLtX; saved_lty = selLtY; saved_rbx = selRbX; saved_rby = selRbY; if (moveMode == CONST_MOVE) { MarkObjectsForStretch(); StartCompositeCmd(); PrepareToRecord(CMD_STRETCH, topSel, botSel, numObjSelected); RecordCmd(CMD_STRETCH, NULL, topSel, botSel, numObjSelected); poly_stretched = ConstrainedStretchAllSel(Corner, <x, <y, &rbx, &rby); ScaleAllSelObjects(Corner, dxScale, dyScale); UpdSelBBox(); if (redraw) { if (poly_stretched) { ltx = min(ltx,min(selLtX,saved_ltx)); lty = min(lty,min(selLtY,saved_lty)); rbx = max(rbx,max(selRbX,saved_rbx)); rby = max(rby,max(selRbY,saved_rby)); RedrawAnArea(botObj, ltx-GRID_ABS_SIZE(1), lty-GRID_ABS_SIZE(1), rbx+GRID_ABS_SIZE(1), rby+GRID_ABS_SIZE(1)); } else { RedrawAreas(botObj, saved_ltx-GRID_ABS_SIZE(1), saved_lty-GRID_ABS_SIZE(1), saved_rbx+GRID_ABS_SIZE(1), saved_rby+GRID_ABS_SIZE(1), selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1), selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1)); } } EndCompositeCmd(); } else { PrepareToRecord(CMD_REPLACE, topSel, botSel, numObjSelected); ScaleAllSelObjects(Corner, dxScale, dyScale); RecordCmd(CMD_REPLACE, NULL, topSel, botSel, numObjSelected); UpdSelBBox(); if (redraw) { RedrawAreas(botObj, saved_ltx-GRID_ABS_SIZE(1), saved_lty-GRID_ABS_SIZE(1), saved_rbx+GRID_ABS_SIZE(1), saved_rby+GRID_ABS_SIZE(1), selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1), selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1)); } } } static char *FindColon(s) register char *s; { while (*s!=':' && *s!='x' && *s!='X' && *s!=' ' && *s!='\0') s++; return ((*s==':' || *s=='x' || *s=='X' || *s==' ') ? (s) : (char *)NULL); } void ScaleAllSelObj() { char spec[MAXSTRING], *y_spec=NULL, **ppsz_names_to_resize=NULL; int corner=INVALID, saved_h_align=horiAlign, saved_v_align=vertAlign; int num_to_resize=0; struct BBRec obbox; if (topSel == NULL) { MsgBox(TgLoadCachedString(CSTID_NO_OBJ_SELECTED), TOOL_NAME, INFO_MB); return; } if (numObjSelected == numObjLocked) { MsgBox(TgLoadString(STID_LOCKED_OBJS_CANT_BE_SCALED), TOOL_NAME, INFO_MB); return; } *spec = '\0'; Dialog(TgLoadString(STID_ENTER_SCALING_FACTORS_XY), NULL, spec); UtilTrimBlanks(spec); if (*spec == '\0') return; horiAlign = ALIGN_L; vertAlign = ALIGN_T; corner = CORNER_RB; obbox.ltx = selNoLockObjLtX; obbox.lty = selNoLockObjLtY; obbox.rbx = selNoLockObjRbX; obbox.rby = selNoLockObjRbY; SetPivot(corner, &obbox); horiAlign = saved_h_align; vertAlign = saved_v_align; if ((y_spec=FindColon(spec)) == NULL) { if (sscanf(spec, "%lf", &multX) != 1 || multX <= 0.0) { sprintf(gszMsgBox, TgLoadString(STID_INVALID_SPEC), spec); MsgBox(gszMsgBox, TOOL_NAME, INFO_MB); return; } multY = multX; } else { *y_spec++ = '\0'; if (sscanf(spec, "%lf", &multX) != 1 || sscanf(y_spec, "%lf", &multY) != 1 || multX <= 0.0 || multY <= 0.0) { sprintf(gszMsgBox, TgLoadString(STID_INVALID_SPEC), spec); MsgBox(gszMsgBox, TOOL_NAME, INFO_MB); return; } } changeX = (fabs(multX-1.0) > 1.0e-6); changeY = (fabs(multY-1.0) > 1.0e-6); if (!changeX && !changeY) return; horiAlign = ALIGN_L; vertAlign = ALIGN_T; HighLightReverse(); ppsz_names_to_resize = NeedToProcessOnResize(&num_to_resize); if (ppsz_names_to_resize == NULL) { ScaleAllSel(corner, (double)(multX*1000.0), (double)(multY*1000.0), TRUE); } else { StartCompositeCmd(); ScaleAllSel(corner, (double)(multX*1000.0), (double)(multY*1000.0), TRUE); DoOnResize(ppsz_names_to_resize, num_to_resize); EndCompositeCmd(); } HighLightForward(); SetFileModified(TRUE); justDupped = FALSE; horiAlign = saved_h_align; vertAlign = saved_v_align; } void PreciseScaleEverything() { int corner=CORNER_RB, saved_h_align=horiAlign, saved_v_align=vertAlign; int saved_cur_page_num=curPageNum, prev_page_num=curPageNum; int saved_stretchable_text=stretchableText; char spec[MAXSTRING], buf[MAXSTRING]; struct BBRec obbox; *spec = '\0'; Dialog(TgLoadString(STID_ENTER_A_SCALING_FACTOR), NULL, spec); UtilTrimBlanks(spec); if (*spec == '\0') return; obbox.ltx = obbox.lty = 0; obbox.rbx = onePageWidth; obbox.rby = onePageHeight; SetPivot(corner, &obbox); if (FindColon(spec) != NULL) { MsgBox(TgLoadString(STID_ONLY_INPUT_ONE_NUMERIC_VAL), TOOL_NAME, INFO_MB); return; } else if (sscanf(spec, "%lf", &multX) != 1 || multX <= 0.0) { sprintf(gszMsgBox, TgLoadString(STID_INVALID_SPEC), spec); MsgBox(gszMsgBox, TOOL_NAME, INFO_MB); return; } else if (fabs(multX-((float)1.0)) < INT_TOL) { return; } if (round(multX) >= 10) { sprintf(gszMsgBox, TgLoadString(STID_SCALING_EVERYTHING_LARGE_SURE), multX); if (MsgBox(gszMsgBox, TOOL_NAME, YNC_MB) != MB_ID_YES) { return; } } multY = multX; changeX = (fabs(multX-1.0) > 1.0e-6); changeY = (fabs(multY-1.0) > 1.0e-6); if (!changeX && !changeY) return; MakeQuiescent(); if (firstCmd != NULL) { if (!OkToFlushUndoBuffer( TgLoadString(STID_PRECISE_SCALE_EV_CAUSE_FLUSH))) { SetCurChoice(curChoiceBeforeMakeQuiescent); return; } } corner = CORNER_RB; horiAlign = ALIGN_L; vertAlign = ALIGN_T; stretchableText = saved_stretchable_text; printMag /= multX; if (UpdPageStyle(pageStyle)) { UpdDrawWinBBox(); AdjSplineVs(); } FormatFloat(&printMag, buf); if (printMag <= 100.0) { sprintf(gszMsgBox, TgLoadString(STID_NEW_REDUCTION_IS_PERCENT), buf); } else { sprintf(gszMsgBox, TgLoadString(STID_NEW_ENLARGEMENT_IS_PERCENT), buf); } Msg(gszMsgBox); SaveStatusStrings(); StartCompositeCmd(); for (curPageNum=1; curPageNum <= lastPageNum; curPageNum++) { int num_to_resize=0; char **ppsz_names_to_resize=NULL; /* No need for the CMD_GOTO_PAGE stuff since CleanUpCmds will be called */ /* PrepareToRecord(CMD_GOTO_PAGE, NULL, NULL, prev_page_num); */ GotoPageNum(curPageNum); ShowPage(); XSync(mainDisplay, False); /* RecordCmd(CMD_GOTO_PAGE, NULL, NULL, NULL, curPageNum); */ prev_page_num = curPageNum; sprintf(gszMsgBox, TgLoadCachedString(CSTID_SCALING_EVERYTHING_PAGE), curPageNum, lastPageNum); SetStringStatus(gszMsgBox); SelAllObj(FALSE, FALSE); ppsz_names_to_resize = NeedToProcessOnResize(&num_to_resize); stretchingEverything = TRUE; ScaleAllSel(corner, (double)(multX*1000.0), (double)(multY*1000.0), TRUE); stretchingEverything = FALSE; if (ppsz_names_to_resize != NULL) { DoOnResize(ppsz_names_to_resize, num_to_resize); } RemoveAllSel(); } /* PrepareToRecord(CMD_GOTO_PAGE, NULL, NULL, prev_page_num); */ GotoPageNum(saved_cur_page_num); ShowPage(); /* RecordCmd(CMD_GOTO_PAGE, NULL, NULL, NULL, saved_cur_page_num); */ EndCompositeCmd(); CleanUpCmds(); RestoreStatusStrings(); SetFileModified(TRUE); justDupped = FALSE; stretchableText = saved_stretchable_text; horiAlign = saved_h_align; vertAlign = saved_v_align; RedrawScrollBars(); RedrawRulers(); RedrawTitleWindow(); ClearAndRedrawDrawWindow(); SetCurChoice(curChoiceBeforeMakeQuiescent); } void ScaleObjLikeScaleEverything(obj_ptr, scale, redraw) struct ObjRec *obj_ptr; double scale; int redraw; { int corner=CORNER_RB, saved_h_align=horiAlign, saved_v_align=vertAlign; int saved_stretchable_text=stretchableText, saved_move_mode=moveMode; float saved_print_mag=printMag; struct BBRec obbox; obbox.ltx = obbox.lty = 0; obbox.rbx = onePageWidth; obbox.rby = onePageHeight; SetPivot(corner, &obbox); if (fabs(scale-((float)1.0)) < INT_TOL) { return; } multX = multY = ((double)1)/scale; changeX = (fabs(multX-1.0) > 1.0e-6); changeY = (fabs(multY-1.0) > 1.0e-6); if (!changeX && !changeY) return; corner = CORNER_RB; horiAlign = ALIGN_L; vertAlign = ALIGN_T; stretchableText = TRUE; moveMode = UNCONST_MOVE; printMag /= multX; if (UpdPageStyle(pageStyle)) { UpdDrawWinBBox(); AdjSplineVs(); } if (multX < 100.0) { sprintf(gszMsgBox, TgLoadString(STID_REDUCE_BY_FACTOR), multX); } else { sprintf(gszMsgBox, TgLoadString(STID_ENLARGE_BY_FACTOR), multX); } SetStringStatus(gszMsgBox); SaveStatusStrings(); AddObj(NULL, topObj, obj_ptr); topSel = botSel = SelectThisObject(obj_ptr); UpdSelBBox(); StartCompositeCmd(); stretchingEverything = TRUE; ScaleAllSel(corner, (double)(multX*1000.0), (double)(multY*1000.0), redraw); stretchingEverything = FALSE; RemoveAllSel(); EndCompositeCmd(); CleanUpCmds(); UnlinkObj(topObj); RestoreStatusStrings(); SetFileModified(TRUE); justDupped = FALSE; moveMode = saved_move_mode; stretchableText = saved_stretchable_text; horiAlign = saved_h_align; vertAlign = saved_v_align; printMag = saved_print_mag; if (UpdPageStyle(pageStyle)) { UpdDrawWinBBox(); AdjSplineVs(); } } void SizeAllSelObj(AbsW, AbsH) int AbsW, AbsH; { int saved_h_align=horiAlign, saved_v_align=vertAlign, num_to_resize=0; char **ppsz_names_to_resize=NULL; struct BBRec obbox; if (topSel == NULL) { MsgBox(TgLoadCachedString(CSTID_NO_OBJ_SELECTED), TOOL_NAME, INFO_MB); return; } if (AbsW == selObjRbX-selObjLtX && AbsH == selObjRbY-selObjLtY) return; obbox.ltx = selObjLtX; obbox.lty = selObjLtY; obbox.rbx = selObjRbX; obbox.rby = selObjRbY; SetPivot(CORNER_RB, &obbox); horiAlign = ALIGN_L; vertAlign = ALIGN_T; multX = (selObjRbX==selObjLtX ? ((double)1.0) : ((double)AbsW) / ((double)selObjRbX-selObjLtX)); multY = (selObjRbY==selObjLtY ? ((double)1.0) : ((double)AbsH) / ((double)selObjRbY-selObjLtY)); changeX = (fabs(multX-1.0) > 1.0e-6); changeY = (fabs(multY-1.0) > 1.0e-6); ppsz_names_to_resize = NeedToProcessOnResize(&num_to_resize); if (ppsz_names_to_resize == NULL) { ScaleAllSel(CORNER_RB, (double)(multX*1000.0), (double)(multY*1000.0), TRUE); } else { StartCompositeCmd(); ScaleAllSel(CORNER_RB, (double)(multX*1000.0), (double)(multY*1000.0), TRUE); DoOnResize(ppsz_names_to_resize, num_to_resize); EndCompositeCmd(); } horiAlign = saved_h_align; vertAlign = saved_v_align; UpdSelBBox(); SetFileModified(TRUE); justDupped = FALSE; } void SizeAnObj(ObjPtr, TopOwner, AbsW, AbsH) struct ObjRec *ObjPtr, *TopOwner; int AbsW, AbsH; /* This function is meant to be called from within an internal command */ { int obj_w=ObjPtr->obbox.rbx-ObjPtr->obbox.ltx; int obj_h=ObjPtr->obbox.rby-ObjPtr->obbox.lty; if (execCurDepth <= 0) { #ifdef _TGIF_DBG /* debug, do not translate */ TgAssert(FALSE, "SizeAnObj() called not from an internal command!", NULL); return; #endif /* _TGIF_DBG */ } if (obj_w == AbsW && obj_h == AbsH) { return; } if (ObjPtr == TopOwner) { struct SelRec *saved_top_sel=topSel, *saved_bot_sel=botSel; topSel = botSel = NULL; AddObjIntoSel(ObjPtr, NULL, topSel, &topSel, &botSel); UpdSelBBox(); SizeAllSelObj(AbsW, AbsH); RemoveAllSel(); topSel = saved_top_sel; botSel = saved_bot_sel; UpdSelBBox(); } else { int saved_h_align=horiAlign, saved_v_align=vertAlign; int ltx=TopOwner->bbox.ltx, lty=TopOwner->bbox.lty; int rbx=TopOwner->bbox.rbx, rby=TopOwner->bbox.rby; struct SelRec *saved_top_sel=topSel, *saved_bot_sel=botSel; SetPivot(CORNER_RB, &ObjPtr->obbox); multX = (obj_w == 0) ? ((double)1.0) : ((double)AbsW) / ((double)obj_w); multY = (obj_h == 0) ? ((double)1.0) : ((double)AbsH) / ((double)obj_h); changeX = (fabs(multX-1.0) > 1.0e-6); changeY = (fabs(multY-1.0) > 1.0e-6); if (!changeX && !changeY) { return; } horiAlign = ALIGN_L; vertAlign = ALIGN_T; topSel = botSel = NULL; UpdSelBBox(); PrepareToReplaceAnObj(TopOwner); StretchObj(ObjPtr, CORNER_RB, (double)(multX*1000.0), (double)(multY*1000.0), FALSE); while (ObjPtr != TopOwner) { ObjPtr = ObjPtr->tmp_parent; AdjObjBBox(ObjPtr); } RecordReplaceAnObj(TopOwner); RedrawAreas(botObj, ltx-GRID_ABS_SIZE(1), lty-GRID_ABS_SIZE(1), rbx+GRID_ABS_SIZE(1), rby+GRID_ABS_SIZE(1), TopOwner->bbox.ltx-GRID_ABS_SIZE(1), TopOwner->bbox.lty-GRID_ABS_SIZE(1), TopOwner->bbox.rbx+GRID_ABS_SIZE(1), TopOwner->bbox.rby+GRID_ABS_SIZE(1)); RemoveAllSel(); topSel = saved_top_sel; botSel = saved_bot_sel; UpdSelBBox(); SetFileModified(TRUE); justDupped = FALSE; horiAlign = saved_h_align; vertAlign = saved_v_align; } } static void DoSizeAllSelToGivenWidthHeight(abs_w, abs_h, do_width, do_height) int abs_h, do_width, do_height; { struct SelRec *saved_top_sel=topSel, *saved_bot_sel=botSel, *sel_ptr=NULL; int saved_h_align=horiAlign, saved_v_align=vertAlign, num_to_resize=0; char **ppsz_names_to_resize=NULL; if (topSel == NULL || (!do_width && !do_height)) { return; } horiAlign = ALIGN_L; vertAlign = ALIGN_T; ppsz_names_to_resize = NeedToProcessOnResize(&num_to_resize); HighLightReverse(); StartCompositeCmd(); for (sel_ptr=saved_top_sel; sel_ptr != NULL; sel_ptr=sel_ptr->next) { struct ObjRec *obj_ptr=sel_ptr->obj; int w=(obj_ptr->obbox.rbx-obj_ptr->obbox.ltx); int h=(obj_ptr->obbox.rby-obj_ptr->obbox.lty); topSel = botSel = SelectThisObject(obj_ptr); UpdSelBBox(); if (do_width && do_height) { SetPivot(CORNER_RB, &obj_ptr->obbox); multX = (w == 0 ? ((double)1.0) : ((double)abs_w) / ((double)w)); multY = (h == 0 ? ((double)1.0) : ((double)abs_h) / ((double)h)); changeX = (fabs(multX-1.0) > 1.0e-6); changeY = (fabs(multY-1.0) > 1.0e-6); ScaleAllSel(CORNER_RB, (double)(multX*1000.0), (double)(multY*1000.0), TRUE); } else if (do_width) { SetPivot(CORNER_RIGHT, &obj_ptr->obbox); multX = (w == 0 ? ((double)1.0) : ((double)abs_w) / ((double)w)); changeX = (fabs(multX-1.0) > 1.0e-6); ScaleAllSel(CORNER_RIGHT, (double)(multX*1000.0), (double)1000, TRUE); } else { SetPivot(CORNER_BOTTOM, &obj_ptr->obbox); multY = (h == 0 ? ((double)1.0) : ((double)abs_h) / ((double)h)); changeY = (fabs(multY-1.0) > 1.0e-6); ScaleAllSel(CORNER_BOTTOM, (double)1000, (double)(multY*1000.0), TRUE); } free(topSel); } if (ppsz_names_to_resize != NULL) { DoOnResize(ppsz_names_to_resize, num_to_resize); } EndCompositeCmd(); horiAlign = saved_h_align; vertAlign = saved_v_align; topSel = saved_top_sel; botSel = saved_bot_sel; UpdSelBBox(); HighLightForward(); SetFileModified(TRUE); justDupped = FALSE; } void SizeAllSelToGivenWidthHeight(AbsW, AbsH) int AbsW, AbsH; { DoSizeAllSelToGivenWidthHeight(AbsW, AbsH, TRUE, TRUE); } void SizeAllSelToGivenWidth(AbsW) int AbsW; { DoSizeAllSelToGivenWidthHeight(AbsW, INVALID, TRUE, FALSE); } void SizeAllSelToGivenHeight(AbsH) int AbsH; { DoSizeAllSelToGivenWidthHeight(INVALID, AbsH, FALSE, TRUE); } void FlipObjHorizontal(ObjPtr) struct ObjRec *ObjPtr; { int two_x_pivot=selNoLockObjLtX+selNoLockObjRbX; int new_obj_ltx=two_x_pivot-ObjPtr->obbox.rbx; int new_obj_rbx=two_x_pivot-ObjPtr->obbox.ltx; int new_obj_lty=ObjPtr->obbox.lty; if (ObjPtr->ctm == NULL && ObjPtr->type != OBJ_XBM && ObjPtr->type != OBJ_XPM) { register IntPoint *v; register int i; int num_pts; struct ObjRec *obj_ptr; struct AttrRec *attr_ptr; struct ArcRec *arc_ptr; switch (ObjPtr->type) { case OBJ_TEXT: if (ObjPtr->detail.t->minilines.just != JUST_C) { ObjPtr->detail.t->minilines.just = MAXJUSTS-1-ObjPtr->detail.t->minilines.just; if (ObjPtr->detail.t->cached_bitmap != None) { XFreePixmap(mainDisplay, ObjPtr->detail.t->cached_bitmap); } ObjPtr->detail.t->cached_bitmap = None; if (zoomScale != 0) { ObjPtr->detail.t->cached_zoom = 0; } } MoveObj(ObjPtr, two_x_pivot-((ObjPtr->x)<<1), 0); UpdTextBBox(ObjPtr); break; default: switch (ObjPtr->type) { case OBJ_XBM: ObjPtr->detail.xbm->flip ^= HORI_EVEN; if (ObjPtr->detail.xbm->cached_bitmap != None) { XFreePixmap(mainDisplay, ObjPtr->detail.xbm->cached_bitmap); } ObjPtr->detail.xbm->cached_bitmap = None; if (zoomScale != 0) { ObjPtr->detail.xbm->cached_zoom = 0; } break; case OBJ_XPM: ObjPtr->detail.xpm->flip ^= HORI_EVEN; if (ObjPtr->detail.xpm->cached_pixmap != None) { XFreePixmap(mainDisplay, ObjPtr->detail.xpm->cached_pixmap); } ObjPtr->detail.xpm->cached_pixmap = None; if (ObjPtr->detail.xpm->cached_bitmap != None) { XFreePixmap(mainDisplay, ObjPtr->detail.xpm->cached_bitmap); } ObjPtr->detail.xpm->cached_bitmap = None; ObjPtr->detail.xpm->cached_color = (-1); if (zoomScale != 0) { ObjPtr->detail.xpm->cached_zoom = 0; } break; case OBJ_ICON: case OBJ_PIN: ObjPtr->detail.r->flip ^= HORI_EVEN; break; } ObjPtr->obbox.ltx = ObjPtr->x = new_obj_ltx; ObjPtr->obbox.rbx = new_obj_rbx; break; } switch (ObjPtr->type) { case OBJ_POLY: num_pts = ObjPtr->detail.p->n; v = ObjPtr->detail.p->vlist; for (i = 0; i < num_pts; i++, v++) (*v).x = two_x_pivot - (*v).x; AdjObjSplineVs(ObjPtr); attr_ptr = ObjPtr->fattr; for ( ; attr_ptr != NULL; attr_ptr = attr_ptr->next) { FlipObjHorizontal(attr_ptr->obj); } break; case OBJ_POLYGON: num_pts = ObjPtr->detail.g->n; v = ObjPtr->detail.g->vlist; for (i = 0; i < num_pts; i++, v++) (*v).x = two_x_pivot - (*v).x; AdjObjSplineVs(ObjPtr); attr_ptr = ObjPtr->fattr; for ( ; attr_ptr != NULL; attr_ptr = attr_ptr->next) { FlipObjHorizontal(attr_ptr->obj); } break; case OBJ_BOX: case OBJ_OVAL: case OBJ_RCBOX: case OBJ_XBM: case OBJ_XPM: attr_ptr = ObjPtr->fattr; for ( ; attr_ptr != NULL; attr_ptr = attr_ptr->next) { FlipObjHorizontal(attr_ptr->obj); } AdjObjSplineVs(ObjPtr); break; case OBJ_TEXT: AdjObjSplineVs(ObjPtr); break; case OBJ_ARC: arc_ptr = ObjPtr->detail.a; arc_ptr->xc = two_x_pivot - arc_ptr->xc; arc_ptr->x1 = two_x_pivot - arc_ptr->x1; arc_ptr->x2 = two_x_pivot - arc_ptr->x2; arc_ptr->dir = !(arc_ptr->dir); arc_ptr->ltx = two_x_pivot - arc_ptr->ltx - arc_ptr->w; if (arc_ptr->angle1 > 0) { arc_ptr->angle1 = (180*64) - arc_ptr->angle1; } else { arc_ptr->angle1 = (-180)*64 - arc_ptr->angle1; } arc_ptr->angle2 = -(arc_ptr->angle2); AdjObjBBox(ObjPtr); attr_ptr = ObjPtr->fattr; for ( ; attr_ptr != NULL; attr_ptr = attr_ptr->next) { FlipObjHorizontal(attr_ptr->obj); } AdjObjSplineVs(ObjPtr); break; case OBJ_GROUP: case OBJ_ICON: case OBJ_SYM: case OBJ_PIN: obj_ptr = ObjPtr->detail.r->first; for ( ; obj_ptr != NULL; obj_ptr = obj_ptr->next) { FlipObjHorizontal(obj_ptr); } attr_ptr = ObjPtr->fattr; for ( ; attr_ptr != NULL; attr_ptr = attr_ptr->next) { FlipObjHorizontal(attr_ptr->obj); } AdjObjSplineVs(ObjPtr); break; } AdjObjBBox(ObjPtr); } else { double dz=(double)0, d1=(double)1000, dm1=(double)-1000; ShearObj(ObjPtr, CORNER_LEFT, dz, dz, dm1, d1, NULL, NULL); MoveObj(ObjPtr, new_obj_ltx-ObjPtr->obbox.ltx, new_obj_lty-ObjPtr->obbox.lty); } SetFileModified(TRUE); } void FlipIconHorizontal(ObjPtr) struct ObjRec *ObjPtr; { register int two_x_pivot; int new_obj_ltx, new_obj_rbx; struct ObjRec *obj_ptr; struct AttrRec *attr_ptr; two_x_pivot = selNoLockObjLtX + selNoLockObjRbX; new_obj_ltx = two_x_pivot - ObjPtr->obbox.rbx; new_obj_rbx = two_x_pivot - ObjPtr->obbox.ltx; ObjPtr->detail.r->flip ^= HORI_EVEN; ObjPtr->obbox.ltx = ObjPtr->x = new_obj_ltx; ObjPtr->obbox.rbx = new_obj_rbx; obj_ptr = ObjPtr->detail.r->first; for ( ; obj_ptr != NULL; obj_ptr = obj_ptr->next) { FlipObjHorizontal(obj_ptr); } attr_ptr = ObjPtr->fattr; for ( ; attr_ptr != NULL; attr_ptr = attr_ptr->next) { FlipObjHorizontal(attr_ptr->obj); } AdjObjBBox(ObjPtr); } void FlipObjVertical(ObjPtr) struct ObjRec *ObjPtr; { int two_x_pivot=selNoLockObjLtY+selNoLockObjRbY; int new_obj_lty=two_x_pivot-ObjPtr->obbox.rby; int new_obj_rby=two_x_pivot-ObjPtr->obbox.lty; int new_obj_ltx=ObjPtr->obbox.ltx; if (ObjPtr->ctm == NULL && ObjPtr->type != OBJ_XBM && ObjPtr->type != OBJ_XPM) { register IntPoint *v; register int i; int num_pts; struct ObjRec *obj_ptr; struct AttrRec *attr_ptr; struct ArcRec *arc_ptr; switch (ObjPtr->type) { case OBJ_TEXT: MoveObj(ObjPtr, 0, new_obj_lty-ObjPtr->y); UpdTextBBox(ObjPtr); break; default: switch (ObjPtr->type) { case OBJ_XBM: ObjPtr->detail.xbm->flip ^= VERT_EVEN; if (ObjPtr->detail.xbm->cached_bitmap != None) { XFreePixmap(mainDisplay, ObjPtr->detail.xbm->cached_bitmap); } ObjPtr->detail.xbm->cached_bitmap = None; if (zoomScale != 0) { ObjPtr->detail.xbm->cached_zoom = 0; } break; case OBJ_XPM: ObjPtr->detail.xpm->flip ^= VERT_EVEN; if (ObjPtr->detail.xpm->cached_pixmap != None) { XFreePixmap(mainDisplay, ObjPtr->detail.xpm->cached_pixmap); } ObjPtr->detail.xpm->cached_pixmap = None; if (ObjPtr->detail.xpm->cached_bitmap != None) { XFreePixmap(mainDisplay, ObjPtr->detail.xpm->cached_bitmap); } ObjPtr->detail.xpm->cached_bitmap = None; ObjPtr->detail.xpm->cached_color = (-1); if (zoomScale != 0) { ObjPtr->detail.xpm->cached_zoom = 0; } break; case OBJ_ICON: case OBJ_PIN: ObjPtr->detail.r->flip ^= VERT_EVEN; break; } ObjPtr->obbox.lty = ObjPtr->y = new_obj_lty; ObjPtr->obbox.rby = new_obj_rby; break; } switch (ObjPtr->type) { case OBJ_POLY: num_pts = ObjPtr->detail.p->n; v = ObjPtr->detail.p->vlist; for (i = 0; i < num_pts; i++, v++) (*v).y = two_x_pivot - (*v).y; AdjObjSplineVs(ObjPtr); attr_ptr = ObjPtr->fattr; for ( ; attr_ptr != NULL; attr_ptr = attr_ptr->next) { FlipObjVertical(attr_ptr->obj); } break; case OBJ_POLYGON: num_pts = ObjPtr->detail.g->n; v = ObjPtr->detail.g->vlist; for (i = 0; i < num_pts; i++, v++) (*v).y = two_x_pivot - (*v).y; AdjObjSplineVs(ObjPtr); attr_ptr = ObjPtr->fattr; for ( ; attr_ptr != NULL; attr_ptr = attr_ptr->next) { FlipObjVertical(attr_ptr->obj); } break; case OBJ_BOX: case OBJ_OVAL: case OBJ_RCBOX: case OBJ_XBM: case OBJ_XPM: attr_ptr = ObjPtr->fattr; for ( ; attr_ptr != NULL; attr_ptr = attr_ptr->next) { FlipObjVertical(attr_ptr->obj); } AdjObjSplineVs(ObjPtr); break; case OBJ_TEXT: AdjObjSplineVs(ObjPtr); break; case OBJ_ARC: arc_ptr = ObjPtr->detail.a; arc_ptr->yc = two_x_pivot - arc_ptr->yc; arc_ptr->y1 = two_x_pivot - arc_ptr->y1; arc_ptr->y2 = two_x_pivot - arc_ptr->y2; arc_ptr->dir = !(arc_ptr->dir); arc_ptr->lty = two_x_pivot - arc_ptr->lty - arc_ptr->h; arc_ptr->angle1 = -(arc_ptr->angle1); arc_ptr->angle2 = -(arc_ptr->angle2); AdjObjBBox(ObjPtr); attr_ptr = ObjPtr->fattr; for ( ; attr_ptr != NULL; attr_ptr = attr_ptr->next) { FlipObjVertical(attr_ptr->obj); } AdjObjSplineVs(ObjPtr); break; case OBJ_GROUP: case OBJ_ICON: case OBJ_SYM: case OBJ_PIN: obj_ptr = ObjPtr->detail.r->first; for ( ; obj_ptr != NULL; obj_ptr = obj_ptr->next) { FlipObjVertical(obj_ptr); } attr_ptr = ObjPtr->fattr; for ( ; attr_ptr != NULL; attr_ptr = attr_ptr->next) { FlipObjVertical(attr_ptr->obj); } AdjObjSplineVs(ObjPtr); break; } AdjObjBBox(ObjPtr); } else { double dz=(double)0, d1=(double)1000, dm1=(double)-1000; ShearObj(ObjPtr, CORNER_TOP, dz, dz, d1, dm1, NULL, NULL); MoveObj(ObjPtr, new_obj_ltx-ObjPtr->obbox.ltx, new_obj_lty-ObjPtr->obbox.lty); } SetFileModified(TRUE); } void FlipIconVertical(ObjPtr) struct ObjRec *ObjPtr; { register int two_x_pivot; int new_obj_lty, new_obj_rby; struct ObjRec *obj_ptr; struct AttrRec *attr_ptr; two_x_pivot = selNoLockObjLtY + selNoLockObjRbY; new_obj_lty = two_x_pivot - ObjPtr->obbox.rby; new_obj_rby = two_x_pivot - ObjPtr->obbox.lty; ObjPtr->detail.r->flip ^= VERT_EVEN; ObjPtr->obbox.lty = ObjPtr->y = new_obj_lty; ObjPtr->obbox.rby = new_obj_rby; obj_ptr = ObjPtr->detail.r->first; for ( ; obj_ptr != NULL; obj_ptr = obj_ptr->next) { FlipObjVertical(obj_ptr); } attr_ptr = ObjPtr->fattr; for ( ; attr_ptr != NULL; attr_ptr = attr_ptr->next) { FlipObjVertical(attr_ptr->obj); } AdjObjBBox(ObjPtr); } /* --------------------- Rotation --------------------- */ static int rotatePivotX=0; static int rotatePivotY=0; static int OkToTransform(obj_ptr, stid) struct ObjRec *obj_ptr; int stid; { char obj_name[MAXSTRING]; struct AttrRec *name_attr=NULL; if (obj_ptr->locked) return FALSE; *obj_name = '\0'; if (HasOnResize(obj_ptr, &name_attr) && name_attr != NULL) { UtilStrCpyN(obj_name, sizeof(obj_name), name_attr->attr_value.s); sprintf(gszMsgBox, TgLoadString(stid), obj_name); if (MsgBox(gszMsgBox, TOOL_NAME, YN_MB) != MB_ID_YES) { return FALSE; } } return TRUE; } void SetRotatePivot() { rotatePivotX = ((selNoLockObjLtX + selNoLockObjRbX)>>1); rotatePivotY = ((selNoLockObjLtY + selNoLockObjRbY)>>1); } void SetRotatePivotByObject(ObjPtr) struct ObjRec *ObjPtr; { rotatePivotX = ((ObjPtr->obbox.ltx + ObjPtr->obbox.rbx)>>1); rotatePivotY = ((ObjPtr->obbox.lty + ObjPtr->obbox.rby)>>1); } static void RotatePtClockWise(X, Y, NewX, NewY) int X, Y, *NewX, *NewY; { *NewX = rotatePivotX + rotatePivotY - Y; *NewY = rotatePivotY - rotatePivotX + X; } static void RotatedXY(X, Y, AngleDelta, NewX, NewY) int X, Y, AngleDelta, *NewX, *NewY; /* AngleDelta is degree*64 */ { register double radian, sin_val, cos_val; int dx=X-pivotX, dy=Y-pivotY; if (dx == 0 && dy == 0) { *NewX = pivotX; *NewY = pivotY; } else { radian = (((double)AngleDelta)*M_PI/180.0/64.0); sin_val = sin(radian); cos_val = cos(radian); *NewX = pivotX + round(dx*cos_val - dy*sin_val); *NewY = pivotY + round(dx*sin_val + dy*cos_val); } } static void RotatedAbsXY(X, Y, AngleDelta, NewX, NewY) int X, Y, AngleDelta, *NewX, *NewY; /* AngleDelta is degree*64 */ { register double radian, sin_val, cos_val; int dx=X-absPivotX, dy=Y-absPivotY; if (dx == 0 && dy == 0) { *NewX = absPivotX; *NewY = absPivotY; } else { radian = (((double)AngleDelta)*M_PI/180.0/64.0); sin_val = sin(radian); cos_val = cos(radian); *NewX = absPivotX + round(dx*cos_val - dy*sin_val); *NewY = absPivotY + round(dx*sin_val + dy*cos_val); } } void RotateObj(ObjPtr, Corner, AngleDelta, RealLtX, RealLtY) struct ObjRec *ObjPtr; int Corner, AngleDelta; /* AngleDelta is degree*64 */ int *RealLtX, *RealLtY; { IntPoint abs_obj_obbox_vs[5]; int x, y, new_ltx, new_lty, new_rbx, new_rby; double radian=(((double)AngleDelta)*M_PI/180.0/64.0); double sin_val=sin(radian), cos_val=cos(radian); struct XfrmMtrxRec ctm, new_ctm; struct ObjRec *obj_ptr; struct AttrRec *attr_ptr; switch (ObjPtr->type) { case OBJ_GROUP: case OBJ_ICON: case OBJ_SYM: case OBJ_PIN: for (obj_ptr=ObjPtr->detail.r->first; obj_ptr != NULL; obj_ptr=obj_ptr->next) { RotateObj(obj_ptr, Corner, AngleDelta, RealLtX, RealLtY); } break; default: if (ObjPtr->ctm == NULL) { memcpy(&ObjPtr->orig_obbox, &ObjPtr->obbox, sizeof(struct BBRec)); if (ObjPtr->type == OBJ_TEXT) { memcpy(&ObjPtr->detail.t->orig_bbox, &ObjPtr->bbox, sizeof(struct BBRec)); } ObjPtr->ctm = (struct XfrmMtrxRec *)malloc(sizeof(struct XfrmMtrxRec)); if (ObjPtr->ctm == NULL) FailAllocMessage(); ObjPtr->ctm->m[CTM_SX] = ObjPtr->ctm->m[CTM_SY] = (double)1000; ObjPtr->ctm->m[CTM_SIN] = ObjPtr->ctm->m[CTM_MSIN] = (double)0; ObjPtr->ctm->t[CTM_TX] = ObjPtr->ctm->t[CTM_TY] = 0; } RotatedAbsXY(ObjPtr->x+ObjPtr->ctm->t[CTM_TX], ObjPtr->y+ObjPtr->ctm->t[CTM_TY], AngleDelta, &x, &y); ctm.m[CTM_SX] = ctm.m[CTM_SY] = ((double)1000.0)*cos_val; ctm.m[CTM_SIN] = ((double)1000.0)*sin_val; ctm.m[CTM_MSIN] = (-ctm.m[CTM_SIN]); ctm.t[CTM_TX] = 0; ctm.t[CTM_TY] = 0; ConcatCTM(ObjPtr->ctm, &ctm, &new_ctm); new_ctm.t[CTM_TX] = x-ObjPtr->x; new_ctm.t[CTM_TY] = y-ObjPtr->y; memcpy(ObjPtr->ctm, &new_ctm, sizeof(struct XfrmMtrxRec)); GetTransformedOBBoxAbsVs(ObjPtr, abs_obj_obbox_vs); new_ltx = min(min(abs_obj_obbox_vs[0].x,abs_obj_obbox_vs[1].x), min(abs_obj_obbox_vs[2].x,abs_obj_obbox_vs[3].x)); new_rbx = max(max(abs_obj_obbox_vs[0].x,abs_obj_obbox_vs[1].x), max(abs_obj_obbox_vs[2].x,abs_obj_obbox_vs[3].x)); new_lty = min(min(abs_obj_obbox_vs[0].y,abs_obj_obbox_vs[1].y), min(abs_obj_obbox_vs[2].y,abs_obj_obbox_vs[3].y)); new_rby = max(max(abs_obj_obbox_vs[0].y,abs_obj_obbox_vs[1].y), max(abs_obj_obbox_vs[2].y,abs_obj_obbox_vs[3].y)); ObjPtr->obbox.ltx = new_ltx; ObjPtr->obbox.lty = new_lty; ObjPtr->obbox.rbx = new_rbx; ObjPtr->obbox.rby = new_rby; if (RealLtX != NULL && RealLtY != NULL) { int dx=(*RealLtX)-new_ltx, dy=(*RealLtY)-new_lty; ObjPtr->x += dx; ObjPtr->y += dy; ObjPtr->bbox.ltx += dx; ObjPtr->bbox.lty += dy; ObjPtr->bbox.rbx += dx; ObjPtr->bbox.rby += dy; ObjPtr->obbox.ltx += dx; ObjPtr->obbox.lty += dy; ObjPtr->obbox.rbx += dx; ObjPtr->obbox.rby += dy; MoveRotatedObjCache(ObjPtr, dx, dy); } if (ObjPtr->ctm->m[CTM_SX] >= 999.0 && ObjPtr->ctm->m[CTM_SX] <= 1001.0 && ObjPtr->ctm->m[CTM_SY] >= 999.0 && ObjPtr->ctm->m[CTM_SY] <= 1001.0 && ObjPtr->ctm->m[CTM_SIN] >= (-1.0) && ObjPtr->ctm->m[CTM_SIN] <= 1.0 && ObjPtr->ctm->m[CTM_MSIN] >= (-1.0) && ObjPtr->ctm->m[CTM_MSIN] <= 1.0) { int dx=ObjPtr->ctm->t[CTM_TX], dy=ObjPtr->ctm->t[CTM_TY]; struct AttrRec *saved_fattr=NULL, *saved_lattr=NULL; free(ObjPtr->ctm); ObjPtr->ctm = NULL; memcpy(&ObjPtr->obbox, &ObjPtr->orig_obbox, sizeof(struct BBRec)); if (ObjPtr->type == OBJ_TEXT) { memcpy(&ObjPtr->bbox, &ObjPtr->detail.t->orig_bbox, sizeof(struct BBRec)); } saved_fattr = ObjPtr->fattr; saved_lattr = ObjPtr->lattr; ObjPtr->fattr = ObjPtr->lattr = NULL; MoveObj(ObjPtr, dx, dy); ObjPtr->fattr = saved_fattr; ObjPtr->lattr = saved_lattr; } break; } for (attr_ptr=ObjPtr->fattr; attr_ptr != NULL; attr_ptr=attr_ptr->next) { RotateObj(attr_ptr->obj, Corner, AngleDelta, RealLtX, RealLtY); } AdjObjCache(ObjPtr); AdjObjBBox(ObjPtr); } void RotateObjForLayout(ObjPtr, AngleInRadian, Corner) struct ObjRec *ObjPtr; double AngleInRadian; int Corner; { double angle=AngleInRadian*64.0*180.0/M_PI; SetPivot(Corner, &ObjPtr->obbox); RotateObj(ObjPtr, Corner, round(angle), NULL, NULL); } void RotateObjClockWise(ObjPtr) struct ObjRec *ObjPtr; { double angle_in_radian=((double)(rotationIncrement))*M_PI/180.0/64.0; double sin_val=sin(angle_in_radian); double cos_val=cos(angle_in_radian); int orig_x=((ObjPtr->obbox.ltx+ObjPtr->obbox.rbx)>>1); int orig_y=ObjPtr->obbox.lty; int x=0, y=0, dx=orig_x-rotatePivotX, dy=orig_y-rotatePivotY; if (dx != 0 || dy != 0) { x = (int)round(dx*cos_val - dy*sin_val); y = (int)round(dx*sin_val + dy*cos_val); } x += rotatePivotX; y += rotatePivotY; /* RotateObjForLayout() rotates about center-top */ RotateObjForLayout(ObjPtr, angle_in_radian, CORNER_BOTTOM); MoveObj(ObjPtr, x-orig_x, y-orig_y); SetFileModified(TRUE); } void RotateIconClockWise(ObjPtr) struct ObjRec *ObjPtr; { int ltx, lty, rbx, rby; struct ObjRec *obj_ptr; struct AttrRec *attr_ptr; SetRotatePivot(); RotatePtClockWise(ObjPtr->obbox.ltx, ObjPtr->obbox.rby, <x, <y); RotatePtClockWise(ObjPtr->obbox.rbx, ObjPtr->obbox.lty, &rbx, &rby); ObjPtr->obbox.ltx = ObjPtr->x = ltx; ObjPtr->obbox.lty = ObjPtr->y = lty; ObjPtr->obbox.rbx = rbx; ObjPtr->obbox.rby = rby; obj_ptr = ObjPtr->detail.r->first; for ( ; obj_ptr != NULL; obj_ptr = obj_ptr->next) { RotateObjClockWise(obj_ptr); } attr_ptr = ObjPtr->fattr; for ( ; attr_ptr != NULL; attr_ptr = attr_ptr->next) { RotateObjClockWise(attr_ptr->obj); } AdjObjBBox(ObjPtr); } static void RotatePtCounter(X, Y, NewX, NewY) int X, Y, *NewX, *NewY; { *NewX = rotatePivotX - rotatePivotY + Y; *NewY = rotatePivotY + rotatePivotX - X; } void RotateObjCounter(ObjPtr) struct ObjRec *ObjPtr; { double angle_in_radian=((double)(-rotationIncrement))*M_PI/180.0/64.0; double sin_val=sin(angle_in_radian); double cos_val=cos(angle_in_radian); int orig_x=((ObjPtr->obbox.ltx+ObjPtr->obbox.rbx)>>1); int orig_y=ObjPtr->obbox.lty; int x=0, y=0, dx=orig_x-rotatePivotX, dy=orig_y-rotatePivotY; if (dx != 0 || dy != 0) { x = (int)round(dx*cos_val - dy*sin_val); y = (int)round(dx*sin_val + dy*cos_val); } x += rotatePivotX; y += rotatePivotY; /* RotateObjForLayout() rotates about center-top */ RotateObjForLayout(ObjPtr, angle_in_radian, CORNER_BOTTOM); MoveObj(ObjPtr, x-orig_x, y-orig_y); SetFileModified(TRUE); } void RotateIconCounter(ObjPtr) struct ObjRec *ObjPtr; { int ltx, lty, rbx, rby; struct ObjRec *obj_ptr; struct AttrRec *attr_ptr; SetRotatePivot(); /* ObjPtr->detail.r->rotate = (ObjPtr->detail.r->rotate+4-1) % 4; */ RotatePtCounter(ObjPtr->obbox.rbx, ObjPtr->obbox.lty, <x, <y); RotatePtCounter(ObjPtr->obbox.ltx, ObjPtr->obbox.rby, &rbx, &rby); ObjPtr->obbox.ltx = ObjPtr->x = ltx; ObjPtr->obbox.lty = ObjPtr->y = lty; ObjPtr->obbox.rbx = rbx; ObjPtr->obbox.rby = rby; obj_ptr = ObjPtr->detail.r->first; for ( ; obj_ptr != NULL; obj_ptr = obj_ptr->next) { RotateObjCounter(obj_ptr); } attr_ptr = ObjPtr->fattr; for ( ; attr_ptr != NULL; attr_ptr = attr_ptr->next) { RotateObjCounter(attr_ptr->obj); } AdjObjBBox(ObjPtr); } static void FlipAllSelHorizontal(saved_ltx, saved_lty, saved_rbx, saved_rby) int saved_ltx, saved_lty, saved_rbx, saved_rby; { struct SelRec *sel_ptr; PrepareToRecord(CMD_REPLACE, topSel, botSel, numObjSelected); JustRemoveAllVSel(); for (sel_ptr = topSel; sel_ptr != NULL; sel_ptr = sel_ptr->next) { if (!sel_ptr->obj->locked) { FlipObjHorizontal(sel_ptr->obj); } } UpdSelBBox(); RecordCmd(CMD_REPLACE, NULL, topSel, botSel, numObjSelected); RedrawAreas(botObj, saved_ltx-GRID_ABS_SIZE(1), saved_lty-GRID_ABS_SIZE(1), saved_rbx+GRID_ABS_SIZE(1), saved_rby+GRID_ABS_SIZE(1), selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1), selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1)); } void FlipHorizontal() { int saved_ltx, saved_lty, saved_rbx, saved_rby, num_to_resize=0; struct BBRec sel_obbox; char **ppsz_names_to_resize=NULL; if (topSel == NULL) { MsgBox(TgLoadCachedString(CSTID_NO_OBJ_SELECTED), TOOL_NAME, INFO_MB); return; } if (numObjSelected == numObjLocked) { Msg(TgLoadString(STID_LOCKED_OBJS_CANT_BE_FLIPPED)); return; } sel_obbox.ltx = selNoLockObjLtX; sel_obbox.lty = selNoLockObjLtY; sel_obbox.rbx = selNoLockObjRbX; sel_obbox.rby = selNoLockObjRbY; SetPivot(CORNER_LEFT, &sel_obbox); saved_ltx = selLtX; saved_lty = selLtY; saved_rbx = selRbX; saved_rby = selRbY; HighLightReverse(); ppsz_names_to_resize = NeedToProcessOnResize(&num_to_resize); if (ppsz_names_to_resize == NULL) { FlipAllSelHorizontal(saved_ltx, saved_lty, saved_rbx, saved_rby); } else { StartCompositeCmd(); FlipAllSelHorizontal(saved_ltx, saved_lty, saved_rbx, saved_rby); DoOnResize(ppsz_names_to_resize, num_to_resize); EndCompositeCmd(); } HighLightForward(); justDupped = FALSE; if (numObjLocked != 0) { Msg(TgLoadString(STID_LOCKED_OBJS_ARE_NOT_FLIPPED)); } else { Msg(TgLoadString(STID_FLIPPED_HORIZONTALLY)); } } static void FlipAllSelVertical(saved_ltx, saved_lty, saved_rbx, saved_rby) int saved_ltx, saved_lty, saved_rbx, saved_rby; { struct SelRec *sel_ptr; PrepareToRecord(CMD_REPLACE, topSel, botSel, numObjSelected); JustRemoveAllVSel(); for (sel_ptr = topSel; sel_ptr != NULL; sel_ptr = sel_ptr->next) { if (!sel_ptr->obj->locked) { FlipObjVertical(sel_ptr->obj); } } UpdSelBBox(); RecordCmd(CMD_REPLACE, NULL, topSel, botSel, numObjSelected); RedrawAreas(botObj, saved_ltx-GRID_ABS_SIZE(1), saved_lty-GRID_ABS_SIZE(1), saved_rbx+GRID_ABS_SIZE(1), saved_rby+GRID_ABS_SIZE(1), selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1), selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1)); } void FlipVertical() { int saved_ltx, saved_lty, saved_rbx, saved_rby, num_to_resize=0; struct BBRec sel_obbox; char **ppsz_names_to_resize=NULL; if (topSel == NULL) { MsgBox(TgLoadCachedString(CSTID_NO_OBJ_SELECTED), TOOL_NAME, INFO_MB); return; } if (numObjSelected == numObjLocked) { Msg(TgLoadString(STID_LOCKED_OBJS_CANT_BE_FLIPPED)); return; } sel_obbox.ltx = selNoLockObjLtX; sel_obbox.lty = selNoLockObjLtY; sel_obbox.rbx = selNoLockObjRbX; sel_obbox.rby = selNoLockObjRbY; SetPivot(CORNER_TOP, &sel_obbox); saved_ltx = selLtX; saved_lty = selLtY; saved_rbx = selRbX; saved_rby = selRbY; HighLightReverse(); ppsz_names_to_resize = NeedToProcessOnResize(&num_to_resize); if (ppsz_names_to_resize == NULL) { FlipAllSelVertical(saved_ltx, saved_lty, saved_rbx, saved_rby); } else { StartCompositeCmd(); FlipAllSelVertical(saved_ltx, saved_lty, saved_rbx, saved_rby); DoOnResize(ppsz_names_to_resize, num_to_resize); EndCompositeCmd(); } HighLightForward(); justDupped = FALSE; if (numObjLocked != 0) { Msg(TgLoadString(STID_LOCKED_OBJS_ARE_NOT_FLIPPED)); } else { Msg(TgLoadString(STID_FLIPPED_VERTICALLY)); } } /* --------------------- Rotate --------------------- */ void RotateClockWise() { register struct SelRec *sel_ptr; int saved_ltx, saved_lty, saved_rbx, saved_rby; int text_obj_created, text_cursor_shown; if (topSel == NULL) { text_cursor_shown = textCursorShown; text_obj_created = TieLooseEnds(); textRotation += rotationIncrement; while (textRotation < 0) textRotation += (360<<6); while (textRotation >= (360<<6)) textRotation -= (360<<6); ShowRotate(); if (!text_obj_created && curChoice == DRAWTEXT && text_cursor_shown) { NewCurText(); RedrawCurText(); } else { textCursorShown = FALSE; } return; } if (numObjSelected == numObjLocked) { MsgBox(TgLoadString(STID_LOCKED_OBJS_CANT_BE_ROTATED), TOOL_NAME, INFO_MB); return; } saved_ltx = selLtX; saved_lty = selLtY; saved_rbx = selRbX; saved_rby = selRbY; HighLightReverse(); PrepareToRecord(CMD_REPLACE, topSel, botSel, numObjSelected); JustRemoveAllVSel(); SetRotatePivot(); for (sel_ptr=topSel; sel_ptr != NULL; sel_ptr=sel_ptr->next) { if (OkToTransform(sel_ptr->obj, STID_DISABLE_ON_RESIZE_ROTATE)) { RotateObjClockWise(sel_ptr->obj); } } UpdSelBBox(); RecordCmd(CMD_REPLACE, NULL, topSel, botSel, numObjSelected); RedrawAreas(botObj, saved_ltx-GRID_ABS_SIZE(1), saved_lty-GRID_ABS_SIZE(1), saved_rbx+GRID_ABS_SIZE(1), saved_rby+GRID_ABS_SIZE(1), selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1), selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1)); HighLightForward(); justDupped = FALSE; if (numObjLocked != 0) { Msg(TgLoadString(STID_LOCKED_OBJS_ARE_NOT_ROTATED)); } else { Msg(TgLoadString(STID_ROTATED_CLOCKWISE)); } } void RotateCounter() { register struct SelRec *sel_ptr; int saved_ltx, saved_lty, saved_rbx, saved_rby; int text_obj_created, text_cursor_shown; if (topSel == NULL) { text_cursor_shown = textCursorShown; text_obj_created = TieLooseEnds(); textRotation -= rotationIncrement; while (textRotation < 0) textRotation += (360<<6); while (textRotation >= (360<<6)) textRotation -= (360<<6); ShowRotate(); if (!text_obj_created && curChoice == DRAWTEXT && text_cursor_shown) { NewCurText(); RedrawCurText(); } else { textCursorShown = FALSE; } return; } if (numObjSelected == numObjLocked) { MsgBox(TgLoadString(STID_LOCKED_OBJS_CANT_BE_ROTATED), TOOL_NAME, INFO_MB); return; } saved_ltx = selLtX; saved_lty = selLtY; saved_rbx = selRbX; saved_rby = selRbY; HighLightReverse(); PrepareToRecord(CMD_REPLACE, topSel, botSel, numObjSelected); JustRemoveAllVSel(); SetRotatePivot(); for (sel_ptr = topSel; sel_ptr != NULL; sel_ptr = sel_ptr->next) { if (OkToTransform(sel_ptr->obj, STID_DISABLE_ON_RESIZE_ROTATE)) { RotateObjCounter(sel_ptr->obj); } } UpdSelBBox(); RecordCmd(CMD_REPLACE, NULL, topSel, botSel, numObjSelected); RedrawAreas(botObj, saved_ltx-GRID_ABS_SIZE(1), saved_lty-GRID_ABS_SIZE(1), saved_rbx+GRID_ABS_SIZE(1), saved_rby+GRID_ABS_SIZE(1), selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1), selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1)); HighLightForward(); justDupped = FALSE; if (numObjLocked != 0) { Msg(TgLoadString(STID_LOCKED_OBJS_ARE_NOT_ROTATED)); } else { Msg(TgLoadString(STID_ROTATED_COUNTER_CLOCKWISE)); } } void SetTextRotation(pszBuf) char *pszBuf; { char spec[80], buf[80]; float fval; int ival; *spec = '\0'; if (pszBuf != NULL) { strcpy(spec, pszBuf); } else { FormatAngle(textRotation, buf); sprintf(gszMsgBox, TgLoadString(STID_ENTER_TEXT_ROT_IN_DEGREE_CUR), buf); if (Dialog(gszMsgBox, NULL, spec) == INVALID) return; } UtilTrimBlanks(spec); if (*spec == '\0') return; if (sscanf(spec, "%f", &fval) != 1) { sprintf(gszMsgBox, TgLoadString(STID_CANT_PARSE_ENTER_ONE_NUM_VAL), spec); MsgBox(gszMsgBox, TOOL_NAME, INFO_MB); return; } fval *= (float)64.0; ival = round(fval); if (ival < 0 || ival >= (360<<6)) { sprintf(gszMsgBox, TgLoadString(STID_INVALID_VAL_ENTERED_RNG_INC), spec, 0, 360); MsgBox(gszMsgBox, TOOL_NAME, INFO_MB); return; } textRotation = ival; ShowRotate(); FormatAngle(textRotation, buf); sprintf(gszMsgBox, TgLoadString(STID_TEXT_ROTATION_SET_TO_GIVEN), buf); Msg(gszMsgBox); } void SetRotationIncrement(pszBuf) char *pszBuf; { char spec[80], buf[80]; float fval; int ival; *spec = '\0'; if (pszBuf != NULL) { strcpy(spec, pszBuf); } else { FormatAngle(rotationIncrement, buf); sprintf(gszMsgBox, TgLoadString(STID_ENTER_ROT_INC_IN_DEGREE_CUR), buf); if (Dialog(gszMsgBox, NULL, spec) == INVALID) return; } UtilTrimBlanks(spec); if (*spec == '\0') return; if (sscanf(spec, "%f", &fval) != 1) { sprintf(gszMsgBox, TgLoadString(STID_CANT_PARSE_ENTER_ONE_NUM_VAL), spec); MsgBox(gszMsgBox, TOOL_NAME, INFO_MB); return; } fval *= (float)64.0; ival = round(fval); if (ival <= 0 || ival >= (360<<6)) { sprintf(gszMsgBox, TgLoadString(STID_INVALID_VAL_ENTERED_RNG_EXC), spec, 0, 360); MsgBox(gszMsgBox, TOOL_NAME, INFO_MB); return; } rotationIncrement = ival; FormatAngle(rotationIncrement, buf); sprintf(gszMsgBox, TgLoadString(STID_TEXT_ROT_INC_SET_TO_GIVEN), buf); Msg(gszMsgBox); } static int IdentCTM(ctm1, ctm2) struct XfrmMtrxRec *ctm1, *ctm2; { return ((fabs(ctm1->m[CTM_SX]-ctm2->m[CTM_SX]) < EQ_TOL) && (fabs(ctm1->m[CTM_SY]-ctm2->m[CTM_SY]) < EQ_TOL) && (fabs(ctm1->m[CTM_SIN]-ctm2->m[CTM_SIN]) < EQ_TOL) && (fabs(ctm1->m[CTM_MSIN]-ctm2->m[CTM_MSIN]) < EQ_TOL)); } static int SetObjCTM(ObjPtr, nTransformed, ctm) struct ObjRec *ObjPtr; int nTransformed; struct XfrmMtrxRec *ctm; { int nReturn=FALSE, cx=0, cy=0; switch (ObjPtr->type) { case OBJ_GROUP: case OBJ_ICON: case OBJ_SYM: case OBJ_PIN: break; default: cx = ((ObjPtr->obbox.ltx+ObjPtr->obbox.rbx)>>1); cy = ((ObjPtr->obbox.lty+ObjPtr->obbox.rby)>>1); if (nTransformed) { struct XfrmMtrxRec *saved_ctm=NULL; if (ObjPtr->ctm == NULL) { SetCTM(ObjPtr, ctm); nReturn = TRUE; } else { if (!IdentCTM(ObjPtr->ctm, ctm)) { if (ObjPtr->type == OBJ_TEXT) { saved_ctm = ObjPtr->ctm; ObjPtr->ctm = NULL; if (!UpdTextBBox(ObjPtr)) { /* read-only text */ ObjPtr->ctm = saved_ctm; } else { free(saved_ctm); SetCTM(ObjPtr, ctm); UpdTextBBox(ObjPtr); nReturn = TRUE; } } else { free(ObjPtr->ctm); ObjPtr->ctm = NULL; SetCTM(ObjPtr, ctm); nReturn = TRUE; } } } } else { if (ObjPtr->ctm != NULL) { free(ObjPtr->ctm); ObjPtr->ctm = NULL; nReturn = TRUE; } } if (nReturn) { int new_cx=0, new_cy=0; new_cx = ((ObjPtr->obbox.ltx+ObjPtr->obbox.rbx)>>1); new_cy = ((ObjPtr->obbox.lty+ObjPtr->obbox.rby)>>1); MoveObj(ObjPtr, cx-new_cx, cy-new_cy); AdjObjCache(ObjPtr); AdjObjSplineVs(ObjPtr); AdjObjBBox(ObjPtr); } break; } return nReturn; } void SetSelCTM(nTransformed, ctm) int nTransformed; struct XfrmMtrxRec *ctm; { struct SelRec *sel_ptr=NULL; int ltx=selLtX, lty=selLtY, rbx=selRbX, rby=selRbY, changed=FALSE; if (topSel == NULL) { MsgBox(TgLoadCachedString(CSTID_NO_OBJ_SELECTED), TOOL_NAME, INFO_MB); return; } if (numObjSelected == numObjLocked) { MsgBox(TgLoadString(STID_LOCKED_OBJS_CANT_BE_XFORMED), TOOL_NAME, INFO_MB); return; } HighLightReverse(); StartCompositeCmd(); for (sel_ptr=botSel; sel_ptr != NULL; sel_ptr=sel_ptr->prev) { if (OkToTransform(sel_ptr->obj, STID_DISABLE_ON_RESIZE_TRANSFORM)) { PrepareToReplaceAnObj(sel_ptr->obj); if (SetObjCTM(sel_ptr->obj, nTransformed, ctm)) { changed = TRUE; RecordReplaceAnObj(sel_ptr->obj); } else { AbortPrepareCmd(CMD_REPLACE); } } } EndCompositeCmd(); if (changed) { SetFileModified(TRUE); UpdSelBBox(); RedrawAreas(botObj, ltx-GRID_ABS_SIZE(1), lty-GRID_ABS_SIZE(1), rbx+GRID_ABS_SIZE(1), rby+GRID_ABS_SIZE(1), selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1), selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1)); justDupped = FALSE; if (numObjLocked != 0) { Msg(TgLoadString(STID_LOCKED_OBJS_ARE_NOT_XFORMED)); } } HighLightForward(); } /* --------------------- Rotate Any Angle --------------------- */ static void RotateBBoxByAnAngle(bbox, d_angle, vs) struct BBRec *bbox; /* the original bounding box */ int d_angle; /* d_angle is degree*64 */ XPoint *vs; /* array of 5 points */ { int x, y; RotatedXY(bbox->ltx, bbox->lty, d_angle, &x, &y); vs[0].x = vs[4].x = x; vs[0].y = vs[4].y = y; RotatedXY(bbox->rbx, bbox->lty, d_angle, &x, &y); vs[1].x = x; vs[1].y = y; RotatedXY(bbox->rbx, bbox->rby, d_angle, &x, &y); vs[2].x = x; vs[2].y = y; RotatedXY(bbox->ltx, bbox->rby, d_angle, &x, &y); vs[3].x = x; vs[3].y = y; } static void RotateVsByAnAngle(InVs, NumPts, d_angle, OutVs) XPoint *InVs, *OutVs; int NumPts, d_angle; { register int i; for (i=0; i < NumPts; i++) { int x, y; RotatedXY(InVs[i].x, InVs[i].y, d_angle, &x, &y); OutVs[i].x = x; OutVs[i].y = y; } } static void RotateAllSelObjects(Corner, AngleDelta) int Corner, AngleDelta; /* AngleDelta is degree*64 */ { register struct SelRec *sel_ptr; for (sel_ptr = topSel; sel_ptr != NULL; sel_ptr = sel_ptr->next) { if (OkToTransform(sel_ptr->obj, STID_DISABLE_ON_RESIZE_ROTATE)) { RotateObj(sel_ptr->obj, Corner, AngleDelta, NULL, NULL); } } if (numObjLocked != 0) { Msg(TgLoadString(STID_LOCKED_OBJS_ARE_NOT_ROTATED)); } } static int ConstrainedRotateAllSel(Corner, AngleDelta, ltx, lty, rbx, rby) int Corner, AngleDelta, *ltx, *lty, *rbx, *rby; { register struct ObjRec *obj_ptr; int something_stretched=FALSE, num_pts; int x_off, y_off, move_first, move_last, x, y; IntPoint *v; for (obj_ptr=botObj; obj_ptr != NULL; obj_ptr=obj_ptr->prev) { if (!obj_ptr->marked && obj_ptr->type==OBJ_POLY && !obj_ptr->locked) { num_pts = obj_ptr->detail.p->n; v = obj_ptr->detail.p->vlist; if (obj_ptr->ctm == NULL) { x_off = OFFSET_X(v[0].x); y_off = OFFSET_Y(v[0].y); move_first = EndPtInSelected(x_off, y_off); x_off = OFFSET_X(v[num_pts-1].x); y_off = OFFSET_Y(v[num_pts-1].y); move_last = EndPtInSelected(x_off, y_off); } else { int tmp_x, tmp_y; TransformPointThroughCTM(v[0].x-obj_ptr->x, v[0].y-obj_ptr->y, obj_ptr->ctm, &tmp_x, &tmp_y); tmp_x += obj_ptr->x; tmp_y += obj_ptr->y; x_off = OFFSET_X(tmp_x); y_off = OFFSET_Y(tmp_y); move_first = EndPtInSelected(x_off, y_off); TransformPointThroughCTM(v[num_pts-1].x-obj_ptr->x, v[num_pts-1].y-obj_ptr->y, obj_ptr->ctm, &tmp_x, &tmp_y); tmp_x += obj_ptr->x; tmp_y += obj_ptr->y; x_off = OFFSET_X(tmp_x); y_off = OFFSET_Y(tmp_y); move_last = EndPtInSelected(x_off, y_off); } if (move_first || move_last) { int index=INVALID, seg_dx, seg_dy, dx, dy, cur_seg_dx, cur_seg_dy; PrepareToReplaceAnObj(obj_ptr); if (obj_ptr->ctm != NULL) { /* Remove the transformations! */ int i; for (i=0; i < num_pts; i++) { int tmp_x, tmp_y; TransformPointThroughCTM(v[i].x-obj_ptr->x, v[i].y-obj_ptr->y, obj_ptr->ctm, &tmp_x, &tmp_y); v[i].x = tmp_x+obj_ptr->x; v[i].y = tmp_y+obj_ptr->y; } free(obj_ptr->ctm); obj_ptr->ctm = NULL; UpdPolyBBox(obj_ptr, num_pts, v); } if (something_stretched) { if (obj_ptr->bbox.ltx < *ltx) *ltx = obj_ptr->bbox.ltx; if (obj_ptr->bbox.lty < *lty) *lty = obj_ptr->bbox.lty; if (obj_ptr->bbox.rbx > *rbx) *rbx = obj_ptr->bbox.rbx; if (obj_ptr->bbox.rby > *rby) *rby = obj_ptr->bbox.rby; } else { *ltx = obj_ptr->bbox.ltx; *lty = obj_ptr->bbox.lty; *rbx = obj_ptr->bbox.rbx; *rby = obj_ptr->bbox.rby; } something_stretched = TRUE; if (move_first && move_last && num_pts==3) { RotatedAbsXY(v[0].x, v[0].y, AngleDelta, &x, &y); dx = x-v[0].x; dy = y-v[0].y; index = 1; cur_seg_dx = v[index-1].x - v[index].x; cur_seg_dy = v[index-1].y - v[index].y; seg_dx = v[index].x - v[index+1].x; seg_dy = v[index].y - v[index+1].y; if (cur_seg_dy==0 && seg_dx==0 && (seg_dy!=0 || (seg_dy==0 && dx==0))) { v[index].y += dy; } else if (cur_seg_dx==0 && seg_dy==0 && (seg_dx!=0 || (seg_dx==0 && dy==0))) { v[index].x += dx; } } else { if (move_first && num_pts>2) { RotatedAbsXY(v[0].x, v[0].y, AngleDelta, &x, &y); dx = x-v[0].x; dy = y-v[0].y; index = 1; cur_seg_dx = v[index-1].x - v[index].x; cur_seg_dy = v[index-1].y - v[index].y; seg_dx = v[index].x - v[index+1].x; seg_dy = v[index].y - v[index+1].y; if (cur_seg_dy==0 && cur_seg_dx!=0 && (seg_dy!=0 || (seg_dy==0 && dx==0))) { v[index].y += dy; } else if (cur_seg_dx==0 && cur_seg_dy!=0 && (seg_dx!=0 || (seg_dx==0 && dy==0))) { v[index].x += dx; } } if (move_last && num_pts>2) { RotatedAbsXY(v[num_pts-1].x, v[num_pts-1].y, AngleDelta, &x, &y); dx = x-v[num_pts-1].x; dy = y-v[num_pts-1].y; index = num_pts-2; cur_seg_dx = v[index+1].x - v[index].x; cur_seg_dy = v[index+1].y - v[index].y; seg_dx = v[index].x - v[index-1].x; seg_dy = v[index].y - v[index-1].y; if (cur_seg_dy==0 && cur_seg_dx!=0 && (seg_dy!=0 || (seg_dy==0 && dx==0))) { v[index].y += dy; } else if (cur_seg_dx==0 && cur_seg_dy!=0 && (seg_dx!=0 || (seg_dx==0 && dy==0))) { v[index].x += dx; } } } if (move_first) { RotatedAbsXY(v[0].x, v[0].y, AngleDelta, &x, &y); v[0].x = x; v[0].y = y; } if (move_last) { RotatedAbsXY(v[num_pts-1].x, v[num_pts-1].y, AngleDelta, &x, &y); v[num_pts-1].x = x; v[num_pts-1].y = y; } AdjObjSplineVs(obj_ptr); switch (obj_ptr->type) { case OBJ_POLY: if (obj_ptr->detail.p->curved != LT_INTSPLINE) { UpdPolyBBox(obj_ptr, num_pts, v); } else { UpdPolyBBox(obj_ptr, obj_ptr->detail.p->intn, obj_ptr->detail.p->intvlist); } break; case OBJ_POLYGON: if (obj_ptr->detail.g->curved != LT_INTSPLINE) { UpdPolyBBox(obj_ptr, num_pts, v); } else { UpdPolyBBox(obj_ptr, obj_ptr->detail.g->intn, obj_ptr->detail.g->intvlist); } break; } AdjObjBBox(obj_ptr); if (AutoCenterAttr(obj_ptr)) { struct AttrRec *attr_ptr=obj_ptr->fattr; int modified=FALSE; for ( ; attr_ptr != NULL; attr_ptr = attr_ptr->next) { if (attr_ptr->shown) { struct BBRec bbox; CenterObjInOBBox(attr_ptr->obj, obj_ptr->obbox, &bbox); if (bbox.ltx < *ltx) *ltx = bbox.ltx; if (bbox.lty < *lty) *lty = bbox.lty; if (bbox.rbx > *rbx) *rbx = bbox.rbx; if (bbox.rby > *rby) *rby = bbox.rby; modified = TRUE; } } if (modified) AdjObjBBox(obj_ptr); } if (obj_ptr->bbox.ltx < *ltx) *ltx = obj_ptr->bbox.ltx; if (obj_ptr->bbox.lty < *lty) *lty = obj_ptr->bbox.lty; if (obj_ptr->bbox.rbx > *rbx) *rbx = obj_ptr->bbox.rbx; if (obj_ptr->bbox.rby > *rby) *rby = obj_ptr->bbox.rby; RecordReplaceAnObj(obj_ptr); } } } return something_stretched; } static void RotateAllSel(Corner, AngleDelta) int Corner, AngleDelta; /* AngleDelta is degree*64 */ { int ltx, lty, rbx, rby, saved_ltx, saved_lty, saved_rbx, saved_rby; int poly_stretched; saved_ltx = selLtX; saved_lty = selLtY; saved_rbx = selRbX; saved_rby = selRbY; if (moveMode==CONST_MOVE) { MarkObjectsForStretch(); StartCompositeCmd(); PrepareToRecord(CMD_STRETCH, topSel, botSel, numObjSelected); RecordCmd(CMD_STRETCH, NULL, topSel, botSel, numObjSelected); poly_stretched = ConstrainedRotateAllSel(Corner, AngleDelta, <x, <y, &rbx, &rby); RotateAllSelObjects(Corner, AngleDelta); UpdSelBBox(); if (poly_stretched) { ltx = min(ltx,min(selLtX,saved_ltx)); lty = min(lty,min(selLtY,saved_lty)); rbx = max(rbx,max(selRbX,saved_rbx)); rby = max(rby,max(selRbY,saved_rby)); RedrawAnArea(botObj, ltx-GRID_ABS_SIZE(1), lty-GRID_ABS_SIZE(1), rbx+GRID_ABS_SIZE(1), rby+GRID_ABS_SIZE(1)); } else { RedrawAreas(botObj, saved_ltx-GRID_ABS_SIZE(1), saved_lty-GRID_ABS_SIZE(1), saved_rbx+GRID_ABS_SIZE(1), saved_rby+GRID_ABS_SIZE(1), selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1), selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1)); } EndCompositeCmd(); } else { PrepareToRecord(CMD_REPLACE, topSel, botSel, numObjSelected); RotateAllSelObjects(Corner, AngleDelta); RecordCmd(CMD_REPLACE, NULL, topSel, botSel, numObjSelected); UpdSelBBox(); RedrawAreas(botObj, saved_ltx-GRID_ABS_SIZE(1), saved_lty-GRID_ABS_SIZE(1), saved_rbx+GRID_ABS_SIZE(1), saved_rby+GRID_ABS_SIZE(1), selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1), selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1)); } } static void FormatAngleForRotate(buf, angle) char *buf; int angle; { float fval=(float)(((float)angle)/((float)64.0)); sprintf(buf, "degree=%.2f", fval); } static void RotateSel(XGridOff, YGridOff, ObjPtr, Corner) int XGridOff, YGridOff, Corner; struct ObjRec *ObjPtr; { register int i; XEvent ev; XPoint all_bbox_vs[5], obj_obbox_vs[5], *vs=NULL, *orig_vs=NULL; int grid_x=XGridOff, grid_y=YGridOff, dx, dy, d_angle=0; int saved_x=XGridOff, saved_y=YGridOff; int rotating=TRUE, deg360=(360<<6), n=0; char buf[80]; struct BBRec orig_all_bbox, orig_obj_obbox; if (numObjSelected == numObjLocked || ObjPtr->locked) { MsgBox(TgLoadString(STID_LOCKED_OBJS_CANT_BE_ROTATED), TOOL_NAME, INFO_MB); return; } XFlush(mainDisplay); XSync(mainDisplay, False); if (XCheckMaskEvent(mainDisplay, ExposureMask, &ev) || XCheckMaskEvent(mainDisplay, VisibilityChangeMask, &ev)) { ExposeEventHandler(&ev, TRUE); } if (ObjPtr->type==OBJ_POLY || ObjPtr->type==OBJ_POLYGON) { IntPoint *pv; int px, py; if (ObjPtr->ctm == NULL) { pv = (ObjPtr->type==OBJ_POLY ? &ObjPtr->detail.p->vlist[Corner] : &ObjPtr->detail.g->vlist[Corner]); px = pv->x; py = pv->y; } else { pv = (ObjPtr->type==OBJ_POLY ? &ObjPtr->detail.p->vlist[Corner] : &ObjPtr->detail.g->vlist[Corner]); TransformPointThroughCTM(pv->x-ObjPtr->x, pv->y-ObjPtr->y, ObjPtr->ctm, &px, &py); px += ObjPtr->x; py += ObjPtr->y; } absPivotX = (ObjPtr->obbox.ltx+ObjPtr->obbox.rbx)>>1; absPivotY = (ObjPtr->obbox.lty+ObjPtr->obbox.rby)>>1; moveX = OFFSET_X(px); moveY = OFFSET_Y(py); changeX = changeY = TRUE; multX = multY = 1.0; pivotX = OFFSET_X(absPivotX); pivotY = OFFSET_Y(absPivotY); } else { SetPivot(Corner, &ObjPtr->obbox); } SetBBRec(&orig_all_bbox, OFFSET_X(selNoLockLtX)-2, OFFSET_Y(selNoLockLtY)-2, OFFSET_X(selNoLockRbX)+2, OFFSET_Y(selNoLockRbY)+2); SetRotateVs(all_bbox_vs, orig_all_bbox.ltx, orig_all_bbox.lty, orig_all_bbox.rbx, orig_all_bbox.rby); XDrawLines(mainDisplay, drawWindow, revDefaultGC, all_bbox_vs, 5, CoordModeOrigin); if (ObjPtr->type==OBJ_POLY || ObjPtr->type==OBJ_POLYGON) { if (ObjPtr->type == OBJ_POLY) { if (ObjPtr->ctm == NULL) { n = ObjPtr->detail.p->sn; orig_vs = (XPoint*)malloc(n*sizeof(XPoint)); vs = (XPoint*)malloc(n*sizeof(XPoint)); if (orig_vs == NULL || vs == NULL) FailAllocMessage(); for (i=0; i < n; i++) { vs[i].x = orig_vs[i].x = ObjPtr->detail.p->svlist[i].x; vs[i].y = orig_vs[i].y = ObjPtr->detail.p->svlist[i].y; } } else { n = ObjPtr->detail.p->rotated_n; orig_vs = (XPoint*)malloc(n*sizeof(XPoint)); vs = (XPoint*)malloc(n*sizeof(XPoint)); if (orig_vs == NULL || vs == NULL) FailAllocMessage(); for (i=0; i < n; i++) { vs[i].x = orig_vs[i].x = ObjPtr->detail.p->rotated_vlist[i].x; vs[i].y = orig_vs[i].y = ObjPtr->detail.p->rotated_vlist[i].y; } } } else { if (ObjPtr->ctm == NULL) { n = ObjPtr->detail.g->sn; orig_vs = (XPoint*)malloc(n*sizeof(XPoint)); vs = (XPoint*)malloc(n*sizeof(XPoint)); if (orig_vs == NULL || vs == NULL) FailAllocMessage(); for (i=0; i < n; i++) { vs[i].x = orig_vs[i].x = ObjPtr->detail.g->svlist[i].x; vs[i].y = orig_vs[i].y = ObjPtr->detail.g->svlist[i].y; } } else { n = ObjPtr->detail.g->rotated_n; orig_vs = (XPoint*)malloc(n*sizeof(XPoint)); vs = (XPoint*)malloc(n*sizeof(XPoint)); if (orig_vs == NULL || vs == NULL) FailAllocMessage(); for (i=0; i < n; i++) { vs[i].x = orig_vs[i].x = ObjPtr->detail.g->rotated_vlist[i].x; vs[i].y = orig_vs[i].y = ObjPtr->detail.g->rotated_vlist[i].y; } } } XDrawLines(mainDisplay, drawWindow, revDefaultGC, vs, n, CoordModeOrigin); } else { if (ObjPtr->ctm == NULL) { SetBBRec(&orig_obj_obbox, OFFSET_X(ObjPtr->obbox.ltx), OFFSET_Y(ObjPtr->obbox.lty), OFFSET_X(ObjPtr->obbox.rbx), OFFSET_Y(ObjPtr->obbox.rby)); SetRotateVs(obj_obbox_vs, orig_obj_obbox.ltx, orig_obj_obbox.lty, orig_obj_obbox.rbx, orig_obj_obbox.rby); XDrawLines(mainDisplay, drawWindow, revDefaultGC, obj_obbox_vs, 5, CoordModeOrigin); } else { memcpy(obj_obbox_vs, ObjPtr->rotated_obbox, 5*sizeof(XPoint)); XDrawLines(mainDisplay, drawWindow, revDefaultGC, obj_obbox_vs, 5, CoordModeOrigin); } } dx = OFFSET_X(ObjPtr->obbox.rbx) - OFFSET_X(ObjPtr->obbox.ltx); dy = OFFSET_Y(ObjPtr->obbox.rby) - OFFSET_Y(ObjPtr->obbox.lty); if (dx == 0 && dy == 0) { MsgBox(TgLoadString(STID_SEL_OBJ_TOO_SMALL_ROT_ANOTHER), TOOL_NAME, INFO_MB); return; } grid_x = moveX; grid_y = moveY; FormatAngleForRotate(buf, 0); StartShowMeasureCursor(grid_x, grid_y, buf, TRUE); if (!debugNoPointerGrab) { XGrabPointer(mainDisplay, drawWindow, False, PointerMotionMask | ButtonReleaseMask, GrabModeAsync, GrabModeAsync, None, rotatingCursor, CurrentTime); } while (rotating) { XEvent input; XNextEvent(mainDisplay, &input); if (input.type == Expose || input.type == VisibilityNotify) { ExposeEventHandler(&input, TRUE); } else if (input.type == ButtonRelease) { XUngrabPointer(mainDisplay, CurrentTime); XSync(mainDisplay, False); rotating = FALSE; FormatAngleForRotate(buf, d_angle); EndShowMeasureCursor(grid_x, grid_y, buf, TRUE); if (ObjPtr->type==OBJ_POLY || ObjPtr->type==OBJ_POLYGON) { XDrawLines(mainDisplay, drawWindow, revDefaultGC, vs, n, CoordModeOrigin); } else { XDrawLines(mainDisplay, drawWindow, revDefaultGC, obj_obbox_vs, 5, CoordModeOrigin); } XDrawLines(mainDisplay, drawWindow, revDefaultGC, all_bbox_vs, 5, CoordModeOrigin); } else if (input.type == MotionNotify || input.type == KeyPress || input.type == KeyRelease) { int end_x=0, end_y=0; FormatAngleForRotate(buf, d_angle); ShowMeasureCursor(grid_x, grid_y, buf, TRUE); if (ObjPtr->type==OBJ_POLY || ObjPtr->type==OBJ_POLYGON) { XDrawLines(mainDisplay, drawWindow, revDefaultGC, vs, n, CoordModeOrigin); } else { XDrawLines(mainDisplay, drawWindow, revDefaultGC, obj_obbox_vs, 5, CoordModeOrigin); } XDrawLines(mainDisplay, drawWindow, revDefaultGC, all_bbox_vs, 5, CoordModeOrigin); if (input.type == KeyPress || input.type == KeyRelease) { end_x = grid_x; end_y = grid_y; } else { end_x = input.xmotion.x; end_y = input.xmotion.y; } GridXY(end_x, end_y, &grid_x, &grid_y); dx = grid_x - saved_x; dy = grid_y - saved_y; grid_x = moveX + dx; grid_y = moveY + dy; MarkRulers(grid_x, grid_y); PointsToArc(pivotX, pivotY, moveX, moveY, grid_x, grid_y, ARC_CW, FALSE, NULL, NULL, NULL, NULL, NULL, &d_angle); if (shiftForDiagMouseMove && DiagEventCheck(&input)) { int tmp_angle=(int)(((double)d_angle) / ((double)(45<<5))); if (tmp_angle & 0x1) { if (tmp_angle > 0) { tmp_angle = ((tmp_angle+1)>>1); } else { tmp_angle = ((tmp_angle-1)>>1); } } else { tmp_angle >>= 1; } d_angle = tmp_angle * (45<<6); } if (d_angle == deg360) d_angle = 0; d_angle = (-d_angle); while (d_angle >= (deg360)) d_angle -= (deg360); RotateBBoxByAnAngle(&orig_all_bbox, d_angle, all_bbox_vs); XDrawLines(mainDisplay, drawWindow, revDefaultGC, all_bbox_vs, 5, CoordModeOrigin); if (ObjPtr->type==OBJ_POLY || ObjPtr->type==OBJ_POLYGON) { RotateVsByAnAngle(orig_vs, n, d_angle, vs); XDrawLines(mainDisplay, drawWindow, revDefaultGC, vs, n, CoordModeOrigin); } else { if (ObjPtr->ctm == NULL) { RotateBBoxByAnAngle(&orig_obj_obbox, d_angle, obj_obbox_vs); } else { RotateVsByAnAngle(ObjPtr->rotated_obbox, 5, d_angle, obj_obbox_vs); } XDrawLines(mainDisplay, drawWindow, revDefaultGC, obj_obbox_vs, 5, CoordModeOrigin); } FormatAngleForRotate(buf, d_angle); ShowMeasureCursor(grid_x, grid_y, buf, TRUE); while (XCheckMaskEvent(mainDisplay, PointerMotionMask, &ev)) ; } } if (d_angle != 0) { HighLightReverse(); RotateAllSel(Corner, d_angle); HighLightForward(); SetFileModified(TRUE); justDupped = FALSE; } if (vs != NULL) free(vs); if (orig_vs != NULL) free(orig_vs); } /* --------------------- Shearing --------------------- */ static void ShearBBox(Corner, bbox, dx_shear, dy_shear, dx_scale, dy_scale, vs) int Corner; double dx_shear, dy_shear, dx_scale, dy_scale; struct BBRec *bbox; /* the original bounding box */ XPoint *vs; /* array of 5 points */ { int x, y; switch (Corner) { case CORNER_TOP: case CORNER_BOTTOM: if (bbox->lty == pivotY) { vs[0].x = vs[4].x = bbox->ltx; vs[0].y = vs[4].y = bbox->lty; vs[1].x = bbox->rbx; vs[1].y = bbox->lty; } else { ShearedXY(Corner, bbox->ltx, bbox->lty, dx_shear, dy_shear, dx_scale, dy_scale, &x, &y); vs[0].x = vs[4].x = x; vs[0].y = vs[4].y = y; ShearedXY(Corner, bbox->rbx, bbox->lty, dx_shear, dy_shear, dx_scale, dy_scale, &x, &y); vs[1].x = x; vs[1].y = y; } if (bbox->rby == pivotY) { vs[2].x = bbox->rbx; vs[2].y = bbox->rby; vs[3].x = bbox->ltx; vs[3].y = bbox->rby; } else { ShearedXY(Corner, bbox->rbx, bbox->rby, dx_shear, dy_shear, dx_scale, dy_scale, &x, &y); vs[2].x = x; vs[2].y = y; ShearedXY(Corner, bbox->ltx, bbox->rby, dx_shear, dy_shear, dx_scale, dy_scale, &x, &y); vs[3].x = x; vs[3].y = y; } break; case CORNER_RIGHT: case CORNER_LEFT: if (bbox->ltx == pivotX) { vs[0].x = vs[4].x = bbox->ltx; vs[0].y = vs[4].y = bbox->lty; vs[3].x = bbox->ltx; vs[3].y = bbox->rby; } else { ShearedXY(Corner, bbox->ltx, bbox->lty, dx_shear, dy_shear, dx_scale, dy_scale, &x, &y); vs[0].x = vs[4].x = x; vs[0].y = vs[4].y = y; ShearedXY(Corner, bbox->ltx, bbox->rby, dx_shear, dy_shear, dx_scale, dy_scale, &x, &y); vs[3].x = x; vs[3].y = y; } if (bbox->rbx == pivotX) { vs[1].x = bbox->rbx; vs[1].y = bbox->lty; vs[2].x = bbox->rbx; vs[2].y = bbox->rby; } else { ShearedXY(Corner, bbox->rbx, bbox->lty, dx_shear, dy_shear, dx_scale, dy_scale, &x, &y); vs[1].x = x; vs[1].y = y; ShearedXY(Corner, bbox->rbx, bbox->rby, dx_shear, dy_shear, dx_scale, dy_scale, &x, &y); vs[2].x = x; vs[2].y = y; } break; } } static void ShearVs(Corner, InVs, NumPts, dx_shear, dy_shear, dx_scale, dy_scale, OutVs) int Corner, NumPts; double dx_shear, dy_shear, dx_scale, dy_scale; XPoint *InVs, *OutVs; /* array of 5 points */ { register int i; int x, y; switch (Corner) { case CORNER_TOP: case CORNER_BOTTOM: for (i=0; i < NumPts; i++) { if (InVs[i].y == pivotY) { OutVs[i].x = InVs[i].x; OutVs[i].y = InVs[i].y; } else { ShearedXY(Corner, InVs[i].x, InVs[i].y, dx_shear, dy_shear, dx_scale, dy_scale, &x, &y); OutVs[i].x = x; OutVs[i].y = y; } } break; case CORNER_RIGHT: case CORNER_LEFT: for (i=0; i < NumPts; i++) { if (InVs[i].x == pivotX) { OutVs[i].x = InVs[i].x; OutVs[i].y = InVs[i].y; } else { ShearedXY(Corner, InVs[i].x, InVs[i].y, dx_shear, dy_shear, dx_scale, dy_scale, &x, &y); OutVs[i].x = x; OutVs[i].y = y; } } break; } } static void ShearAllSelObjects(Corner, dxShear, dyShear, dxScale, dyScale) int Corner; double dxShear, dyShear, dxScale, dyScale; /* everything scaled by 1000 */ { register struct SelRec *sel_ptr; for (sel_ptr = topSel; sel_ptr != NULL; sel_ptr = sel_ptr->next) { if (OkToTransform(sel_ptr->obj, STID_DISABLE_ON_RESIZE_SHEAR)) { ShearObj(sel_ptr->obj, Corner, dxShear, dyShear, dxScale, dyScale, NULL, NULL); } } if (numObjLocked != 0) { Msg(TgLoadString(STID_LOCKED_OBJS_ARE_NOT_SHEARED)); } } static int ConstrainedShearAllSel(Corner, dxShear, dyShear, dxScale, dyScale, ltx, lty, rbx, rby) int Corner, *ltx, *lty, *rbx, *rby; double dxShear, dyShear, dxScale, dyScale; { register struct ObjRec *obj_ptr; int something_stretched=FALSE, num_pts; int x_off, y_off, move_first, move_last, x, y; IntPoint *v; for (obj_ptr=botObj; obj_ptr != NULL; obj_ptr=obj_ptr->prev) { if (!obj_ptr->marked && obj_ptr->type==OBJ_POLY && !obj_ptr->locked) { num_pts = obj_ptr->detail.p->n; v = obj_ptr->detail.p->vlist; if (obj_ptr->ctm == NULL) { x_off = OFFSET_X(v[0].x); y_off = OFFSET_Y(v[0].y); move_first = EndPtInSelected(x_off, y_off); x_off = OFFSET_X(v[num_pts-1].x); y_off = OFFSET_Y(v[num_pts-1].y); move_last = EndPtInSelected(x_off, y_off); } else { int tmp_x, tmp_y; TransformPointThroughCTM(v[0].x-obj_ptr->x, v[0].y-obj_ptr->y, obj_ptr->ctm, &tmp_x, &tmp_y); tmp_x += obj_ptr->x; tmp_y += obj_ptr->y; x_off = OFFSET_X(tmp_x); y_off = OFFSET_Y(tmp_y); move_first = EndPtInSelected(x_off, y_off); TransformPointThroughCTM(v[num_pts-1].x-obj_ptr->x, v[num_pts-1].y-obj_ptr->y, obj_ptr->ctm, &tmp_x, &tmp_y); tmp_x += obj_ptr->x; tmp_y += obj_ptr->y; x_off = OFFSET_X(tmp_x); y_off = OFFSET_Y(tmp_y); move_last = EndPtInSelected(x_off, y_off); } if (move_first || move_last) { int index=INVALID, seg_dx, seg_dy, dx, dy, cur_seg_dx, cur_seg_dy; PrepareToReplaceAnObj(obj_ptr); if (obj_ptr->ctm != NULL) { /* Remove the transformations! */ int i; for (i=0; i < num_pts; i++) { int tmp_x, tmp_y; TransformPointThroughCTM(v[i].x-obj_ptr->x, v[i].y-obj_ptr->y, obj_ptr->ctm, &tmp_x, &tmp_y); v[i].x = tmp_x+obj_ptr->x; v[i].y = tmp_y+obj_ptr->y; } free(obj_ptr->ctm); obj_ptr->ctm = NULL; UpdPolyBBox(obj_ptr, num_pts, v); } if (something_stretched) { if (obj_ptr->bbox.ltx < *ltx) *ltx = obj_ptr->bbox.ltx; if (obj_ptr->bbox.lty < *lty) *lty = obj_ptr->bbox.lty; if (obj_ptr->bbox.rbx > *rbx) *rbx = obj_ptr->bbox.rbx; if (obj_ptr->bbox.rby > *rby) *rby = obj_ptr->bbox.rby; } else { *ltx = obj_ptr->bbox.ltx; *lty = obj_ptr->bbox.lty; *rbx = obj_ptr->bbox.rbx; *rby = obj_ptr->bbox.rby; } something_stretched = TRUE; if (move_first && move_last && num_pts==3) { ShearedAbsXY(Corner, v[0].x, v[0].y, dxShear, dyShear, dxScale, dyScale, &x, &y); dx = x-v[0].x; dy = y-v[0].y; index = 1; cur_seg_dx = v[index-1].x - v[index].x; cur_seg_dy = v[index-1].y - v[index].y; seg_dx = v[index].x - v[index+1].x; seg_dy = v[index].y - v[index+1].y; if (cur_seg_dy==0 && seg_dx==0 && (seg_dy!=0 || (seg_dy==0 && dx==0))) { v[index].y += dy; } else if (cur_seg_dx==0 && seg_dy==0 && (seg_dx!=0 || (seg_dx==0 && dy==0))) { v[index].x += dx; } } else { if (move_first && num_pts>2) { ShearedAbsXY(Corner, v[0].x, v[0].y, dxShear, dyShear, dxScale, dyScale, &x, &y); dx = x-v[0].x; dy = y-v[0].y; index = 1; cur_seg_dx = v[index-1].x - v[index].x; cur_seg_dy = v[index-1].y - v[index].y; seg_dx = v[index].x - v[index+1].x; seg_dy = v[index].y - v[index+1].y; if (cur_seg_dy==0 && cur_seg_dx!=0 && (seg_dy!=0 || (seg_dy==0 && dx==0))) { v[index].y += dy; } else if (cur_seg_dx==0 && cur_seg_dy!=0 && (seg_dx!=0 || (seg_dx==0 && dy==0))) { v[index].x += dx; } } if (move_last && num_pts>2) { ShearedAbsXY(Corner, v[num_pts-1].x, v[num_pts-1].y, dxShear, dyShear, dxScale, dyScale, &x, &y); dx = x-v[num_pts-1].x; dy = y-v[num_pts-1].y; index = num_pts-2; cur_seg_dx = v[index+1].x - v[index].x; cur_seg_dy = v[index+1].y - v[index].y; seg_dx = v[index].x - v[index-1].x; seg_dy = v[index].y - v[index-1].y; if (cur_seg_dy==0 && cur_seg_dx!=0 && (seg_dy!=0 || (seg_dy==0 && dx==0))) { v[index].y += dy; } else if (cur_seg_dx==0 && cur_seg_dy!=0 && (seg_dx!=0 || (seg_dx==0 && dy==0))) { v[index].x += dx; } } } if (move_first) { ShearedAbsXY(Corner, v[0].x, v[0].y, dxShear, dyShear, dxScale, dyScale, &x, &y); v[0].x = x; v[0].y = y; } if (move_last) { ShearedAbsXY(Corner, v[num_pts-1].x, v[num_pts-1].y, dxShear, dyShear, dxScale, dyScale, &x, &y); v[num_pts-1].x = x; v[num_pts-1].y = y; } AdjObjSplineVs(obj_ptr); switch (obj_ptr->type) { case OBJ_POLY: if (obj_ptr->detail.p->curved != LT_INTSPLINE) { UpdPolyBBox(obj_ptr, num_pts, v); } else { UpdPolyBBox(obj_ptr, obj_ptr->detail.p->intn, obj_ptr->detail.p->intvlist); } break; case OBJ_POLYGON: if (obj_ptr->detail.g->curved != LT_INTSPLINE) { UpdPolyBBox(obj_ptr, num_pts, v); } else { UpdPolyBBox(obj_ptr, obj_ptr->detail.g->intn, obj_ptr->detail.g->intvlist); } break; } AdjObjBBox(obj_ptr); if (AutoCenterAttr(obj_ptr)) { struct AttrRec *attr_ptr=obj_ptr->fattr; int modified=FALSE; for ( ; attr_ptr != NULL; attr_ptr = attr_ptr->next) { if (attr_ptr->shown) { struct BBRec bbox; CenterObjInOBBox(attr_ptr->obj, obj_ptr->obbox, &bbox); if (bbox.ltx < *ltx) *ltx = bbox.ltx; if (bbox.lty < *lty) *lty = bbox.lty; if (bbox.rbx > *rbx) *rbx = bbox.rbx; if (bbox.rby > *rby) *rby = bbox.rby; modified = TRUE; } } if (modified) AdjObjBBox(obj_ptr); } if (obj_ptr->bbox.ltx < *ltx) *ltx = obj_ptr->bbox.ltx; if (obj_ptr->bbox.lty < *lty) *lty = obj_ptr->bbox.lty; if (obj_ptr->bbox.rbx > *rbx) *rbx = obj_ptr->bbox.rbx; if (obj_ptr->bbox.rby > *rby) *rby = obj_ptr->bbox.rby; RecordReplaceAnObj(obj_ptr); } } } return something_stretched; } static void ShearAllSel(Corner, dxShear, dyShear, dxScale, dyScale) int Corner; double dxShear, dyShear, dxScale, dyScale; /* everything scaled by 1000 */ { int ltx, lty, rbx, rby, saved_ltx, saved_lty, saved_rbx, saved_rby; int poly_stretched; saved_ltx = selLtX; saved_lty = selLtY; saved_rbx = selRbX; saved_rby = selRbY; if (moveMode==CONST_MOVE) { MarkObjectsForStretch(); StartCompositeCmd(); PrepareToRecord(CMD_STRETCH, topSel, botSel, numObjSelected); RecordCmd(CMD_STRETCH, NULL, topSel, botSel, numObjSelected); poly_stretched = ConstrainedShearAllSel(Corner, dxShear, dyShear, dxScale, dyScale, <x, <y, &rbx, &rby); ShearAllSelObjects(Corner, dxShear, dyShear, dxScale, dyScale); UpdSelBBox(); if (poly_stretched) { ltx = min(ltx,min(selLtX,saved_ltx)); lty = min(lty,min(selLtY,saved_lty)); rbx = max(rbx,max(selRbX,saved_rbx)); rby = max(rby,max(selRbY,saved_rby)); RedrawAnArea(botObj, ltx-GRID_ABS_SIZE(1), lty-GRID_ABS_SIZE(1), rbx+GRID_ABS_SIZE(1), rby+GRID_ABS_SIZE(1)); } else { RedrawAreas(botObj, saved_ltx-GRID_ABS_SIZE(1), saved_lty-GRID_ABS_SIZE(1), saved_rbx+GRID_ABS_SIZE(1), saved_rby+GRID_ABS_SIZE(1), selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1), selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1)); } EndCompositeCmd(); } else { PrepareToRecord(CMD_REPLACE, topSel, botSel, numObjSelected); ShearAllSelObjects(Corner, dxShear, dyShear, dxScale, dyScale); RecordCmd(CMD_REPLACE, NULL, topSel, botSel, numObjSelected); UpdSelBBox(); RedrawAreas(botObj, saved_ltx-GRID_ABS_SIZE(1), saved_lty-GRID_ABS_SIZE(1), saved_rbx+GRID_ABS_SIZE(1), saved_rby+GRID_ABS_SIZE(1), selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1), selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1)); } } static void ShearSel(XGridOff, YGridOff, ObjPtr, Corner) int XGridOff, YGridOff, Corner; struct ObjRec *ObjPtr; { XEvent ev; XPoint all_bbox_vs[5], obj_obbox_vs[5]; int grid_x=XGridOff, grid_y=YGridOff, dx, dy; int saved_x=XGridOff, saved_y=YGridOff; int shearing=TRUE, shear_hori=FALSE; double dx_scale=(double)1000, dy_scale=(double)1000; double dx_shear=(double)0, dy_shear=(double)0; char buf[80]; struct BBRec orig_all_bbox, orig_obj_obbox; if (numObjSelected == numObjLocked || ObjPtr->locked) { MsgBox(TgLoadString(STID_LOCKED_OBJS_CANT_BE_ROTATED), TOOL_NAME, INFO_MB); return; } XFlush(mainDisplay); XSync(mainDisplay, False); if (XCheckMaskEvent(mainDisplay, ExposureMask, &ev) || XCheckMaskEvent(mainDisplay, VisibilityChangeMask, &ev)) { ExposeEventHandler(&ev, TRUE); } SetPivot(Corner, &ObjPtr->obbox); SetBBRec(&orig_all_bbox, OFFSET_X(selNoLockLtX)-2, OFFSET_Y(selNoLockLtY)-2, OFFSET_X(selNoLockRbX)+2, OFFSET_Y(selNoLockRbY)+2); SetRotateVs(all_bbox_vs, orig_all_bbox.ltx, orig_all_bbox.lty, orig_all_bbox.rbx, orig_all_bbox.rby); XDrawLines(mainDisplay, drawWindow, revDefaultGC, all_bbox_vs, 5, CoordModeOrigin); if (ObjPtr->ctm == NULL) { SetBBRec(&orig_obj_obbox, OFFSET_X(ObjPtr->obbox.ltx), OFFSET_Y(ObjPtr->obbox.lty), OFFSET_X(ObjPtr->obbox.rbx), OFFSET_Y(ObjPtr->obbox.rby)); SetRotateVs(obj_obbox_vs, orig_obj_obbox.ltx, orig_obj_obbox.lty, orig_obj_obbox.rbx, orig_obj_obbox.rby); XDrawLines(mainDisplay, drawWindow, revDefaultGC, obj_obbox_vs, 5, CoordModeOrigin); } else { memcpy(obj_obbox_vs, ObjPtr->rotated_obbox, 5*sizeof(XPoint)); XDrawLines(mainDisplay, drawWindow, revDefaultGC, obj_obbox_vs, 5, CoordModeOrigin); } dx = OFFSET_X(ObjPtr->obbox.rbx) - OFFSET_X(ObjPtr->obbox.ltx); dy = OFFSET_Y(ObjPtr->obbox.rby) - OFFSET_Y(ObjPtr->obbox.lty); if (dx == 0 || dy == 0) { MsgBox(TgLoadString(STID_SEL_OBJ_TOO_SMALL_SHEAR_ANO), TOOL_NAME, INFO_MB); return; } if (Corner == CORNER_TOP || Corner == CORNER_BOTTOM) { shear_hori = TRUE; multX = 0.0; multY = (Corner == CORNER_BOTTOM ? 1.0 : (-1.0)); } else { shear_hori = FALSE; multX = (Corner == CORNER_RIGHT ? 1.0 : (-1.0)); multY = 0.0; } dx = dy = 0; grid_x = moveX; grid_y = moveY; sprintf(buf, "dx=0\ndy=0"); StartShowMeasureCursor(grid_x, grid_y, buf, TRUE); if (!debugNoPointerGrab) { XGrabPointer(mainDisplay, drawWindow, False, PointerMotionMask | ButtonReleaseMask, GrabModeAsync, GrabModeAsync, None, ((Corner==CORNER_TOP || Corner==CORNER_BOTTOM) ? horiShearCursor : vertShearCursor), CurrentTime); } while (shearing) { XEvent input; XNextEvent(mainDisplay, &input); if (input.type == Expose || input.type == VisibilityNotify) { ExposeEventHandler(&input, TRUE); } else if (input.type == ButtonRelease) { XUngrabPointer(mainDisplay, CurrentTime); XSync(mainDisplay, False); shearing = FALSE; sprintf(buf, "dx=%1d\ndy=%1d", dx, dy); EndShowMeasureCursor(grid_x, grid_y, buf, TRUE); XDrawLines(mainDisplay, drawWindow, revDefaultGC, obj_obbox_vs, 5, CoordModeOrigin); XDrawLines(mainDisplay, drawWindow, revDefaultGC, all_bbox_vs, 5, CoordModeOrigin); } else if (input.type == MotionNotify) { sprintf(buf, "dx=%1d\ndy=%1d", dx, dy); ShowMeasureCursor(grid_x, grid_y, buf, TRUE); XDrawLines(mainDisplay, drawWindow, revDefaultGC, obj_obbox_vs, 5, CoordModeOrigin); XDrawLines(mainDisplay, drawWindow, revDefaultGC, all_bbox_vs, 5, CoordModeOrigin); GridXY(input.xmotion.x, input.xmotion.y, &grid_x, &grid_y); dx = grid_x - saved_x; dy = grid_y - saved_y; grid_x = moveX + dx; grid_y = moveY + dy; MarkRulers(grid_x, grid_y); PointsToShearScale(Corner, pivotX, pivotY, moveX, moveY, grid_x, grid_y, &dx_shear, &dy_shear, &dx_scale, &dy_scale); ShearBBox(Corner, &orig_all_bbox, dx_shear, dy_shear, dx_scale, dy_scale, all_bbox_vs); XDrawLines(mainDisplay, drawWindow, revDefaultGC, all_bbox_vs, 5, CoordModeOrigin); if (ObjPtr->ctm == NULL) { ShearBBox(Corner, &orig_obj_obbox, dx_shear, dy_shear, dx_scale, dy_scale, obj_obbox_vs); } else { ShearVs(Corner, ObjPtr->rotated_obbox, 5, dx_shear, dy_shear, dx_scale, dy_scale, obj_obbox_vs); } XDrawLines(mainDisplay, drawWindow, revDefaultGC, obj_obbox_vs, 5, CoordModeOrigin); sprintf(buf, "dx=%1d\ndy=%1d", dx, dy); ShowMeasureCursor(grid_x, grid_y, buf, TRUE); while (XCheckMaskEvent(mainDisplay, PointerMotionMask, &ev)) ; } } ShowCursor(); if (dx != 0 || dy != 0) { PointsToShearScale(Corner, pivotX, pivotY, moveX, moveY, moveX+dx, moveY+dy, &dx_shear, &dy_shear, &dx_scale, &dy_scale); HighLightReverse(); ShearAllSel(Corner, dx_shear, dy_shear, dx_scale, dy_scale); HighLightForward(); SetFileModified(TRUE); justDupped = FALSE; } } void RotateShearSel(XGridOff, YGridOff, ObjPtr, Corner) int XGridOff, YGridOff, Corner; struct ObjRec *ObjPtr; /* 1 2 3 */ /* 8 4 */ /* 7 6 5 */ { if (ObjPtr->type==OBJ_POLY || ObjPtr->type==OBJ_POLYGON || (Corner & 0x1)) { RotateSel(XGridOff, YGridOff, ObjPtr, Corner); } else { ShearSel(XGridOff, YGridOff, ObjPtr, Corner); } }