/* * 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/edit.c,v 1.14 2006/06/13 19:55:08 william Exp $ */ #define _INCLUDE_FROM_EDIT_C_ #include "tgifdefs.h" #include "cmdids.h" #include "align.e" #include "arc.e" #include "attr.e" #include "auxtext.e" #include "button.e" #include "choice.e" #include "cmd.e" #include "color.e" #include "cutpaste.e" #include "cursor.e" #include "dialog.e" #include "drawing.e" #include "dup.e" #include "edit.e" #include "eps.e" #include "file.e" #include "font.e" #include "grid.e" #include "group.e" #include "mainloop.e" #include "mainmenu.e" #include "mark.e" #include "menu.e" #include "menuinfo.e" #include "miniline.e" #include "move.e" #include "msg.e" #include "names.e" #include "navigate.e" #include "obj.e" #include "page.e" #include "pattern.e" #include "pin.e" #include "poly.e" #include "polygon.e" #include "raster.e" #include "rect.e" #include "ruler.e" #include "select.e" #include "setup.e" #include "shape.e" #include "special.e" #include "spline.e" #include "stretch.e" #include "strtbl.e" #include "text.e" #include "util.e" #include "xbitmap.e" #include "xpixmap.e" struct SelRec *outerSelForFind=NULL; struct SelRec *innerSelForFind=NULL; int ignoreObjectShadowInfoInFile=TRUE; int objShadowXOffset=2, objShadowYOffset=2; char objShadowColorStr[MAXSTRING]; static struct ObjRec *tmpTopObj=NULL, *tmpBotObj=NULL; static struct SelRec *tmpTopSel=NULL, *tmpBotSel=NULL; static char *gpszSearch=NULL; static int gnSearchLen=0; static int gnSearchCaseSensitive=TRUE; static int gnFoundStartCharIndex=0, gnFoundEndCharIndex=0; static StrBlockInfo *gpFoundStartStrBlock=NULL, *gpFoundEndStrBlock=NULL; static int convertToBezierNumSegs=50; void CleanOuterInnerSelForFind() { struct SelRec *sel_ptr=NULL, *next_sel=NULL; if (outerSelForFind != NULL) { for (sel_ptr=outerSelForFind; sel_ptr != NULL; sel_ptr=next_sel) { next_sel = sel_ptr->next; free(sel_ptr); } outerSelForFind = innerSelForFind = NULL; } } static void CopyOuterSelToOuterSelForFind() { struct SelRec *sel_ptr=NULL; CleanOuterInnerSelForFind(); for (sel_ptr=outerSel; sel_ptr != NULL; sel_ptr=sel_ptr->next) { AddObjIntoSel(sel_ptr->obj, NULL, outerSelForFind, &outerSelForFind, &innerSelForFind); } } void CleanUpEdit() { CleanOuterInnerSelForFind(); if (gpszSearch != NULL) free(gpszSearch); gpszSearch = NULL; } void InitEdit() { char *c_ptr=NULL, spec[MAXSTRING]; if (PRTGIF && !cmdLineOpenDisplay) return; convertToBezierNumSegs = 50; if ((c_ptr=XGetDefault(mainDisplay,TOOL_NAME, "ConvertToBezierSegments")) != NULL) { SetBezierConvertNumSegsValue(c_ptr); } objShadowXOffset = objShadowYOffset = 2; if ((c_ptr=XGetDefault(mainDisplay,TOOL_NAME, "ObjectShadowOffsets")) != NULL) { UtilStrCpyN(spec, sizeof(spec), c_ptr); UtilTrimBlanks(spec); if (!ParseXYSpec(spec, &objShadowXOffset, &objShadowYOffset)) { fprintf(stderr, TgLoadString(STID_INVALID_XDEF_USE_ALT_STR), TOOL_NAME, "ObjectShadowOffsets", spec, "2,2"); fprintf(stderr, "\n"); } } strcpy(objShadowColorStr, "#c0c0c0"); if ((c_ptr=XGetDefault(mainDisplay,TOOL_NAME,"ObjectShadowColor")) != NULL) { int new_alloc=0; UtilStrCpyN(spec, sizeof(spec), c_ptr); UtilTrimBlanks(spec); if (QuickFindColorIndex(NULL, spec, &new_alloc, FALSE) == INVALID) { fprintf(stderr, TgLoadString(STID_INVALID_XDEF_COLORXPM_GET), TOOL_NAME, "ObjectShadowColor", spec); fprintf(stderr, "\n"); return; } UtilStrCpyN(objShadowColorStr, sizeof(objShadowColorStr), spec); } ignoreObjectShadowInfoInFile = TRUE; if ((c_ptr=XGetDefault(mainDisplay,TOOL_NAME, "IgnoreObjectShadowInfoInFile")) != NULL && UtilStrICmp(c_ptr, "false") == 0) { ignoreObjectShadowInfoInFile = FALSE; } } int CanPerformImageProc() { if (topSel != NULL && topSel == botSel && topSel->obj->type == OBJ_XPM) { return !IsLinkedJpegObj(topSel->obj); } return FALSE; } /* --------------------- ConvertIntSpline() --------------------- */ static int ConvertObjIntSpline(ObjPtr) struct ObjRec *ObjPtr; { register struct ObjRec *obj_ptr; register int i, changed=FALSE; switch (ObjPtr->type) { case OBJ_POLY: if (ObjPtr->detail.p->curved == LT_INTSPLINE) { struct PolyRec *poly_ptr=ObjPtr->detail.p; int new_n, n, index=0; char *smooth=poly_ptr->smooth; IntPoint *vs; changed = TRUE; if (smooth != NULL) free(smooth); n = poly_ptr->n; new_n = (n == 2 ? n : ((n-2)<<1)+n); vs = (IntPoint*)malloc((new_n+1)*sizeof(IntPoint)); if (vs == NULL) FailAllocMessage(); smooth = (char*)malloc((new_n+1)*sizeof(char)); if (smooth == NULL) FailAllocMessage(); smooth[0] = smooth[new_n-1] = FALSE; vs[0] = poly_ptr->vlist[0]; vs[new_n-1] = poly_ptr->vlist[n-1]; for (i=1; i < n-1; i++) { index++; smooth[index] = TRUE; vs[index] = poly_ptr->intvlist[(i<<1)-1]; index++; smooth[index] = FALSE; vs[index] = poly_ptr->vlist[i]; index++; smooth[index] = TRUE; vs[index] = poly_ptr->intvlist[i<<1]; } poly_ptr->curved = LT_SPLINE; free(poly_ptr->vlist); free(poly_ptr->intvlist); poly_ptr->vlist = vs; poly_ptr->n = new_n; poly_ptr->smooth = smooth; poly_ptr->intvlist = NULL; poly_ptr->intn = 0; AdjObjSplineVs(ObjPtr); UpdPolyBBox(ObjPtr, poly_ptr->n, poly_ptr->vlist); } break; case OBJ_POLYGON: if (ObjPtr->detail.g->curved == LT_INTSPLINE) { struct PolygonRec *polygon_ptr=ObjPtr->detail.g; int new_n, n, index=0; char *smooth=polygon_ptr->smooth; IntPoint *vs; changed = TRUE; if (smooth != NULL) free(smooth); n = polygon_ptr->n; new_n = ((n-1)<<1)+n; vs = (IntPoint*)malloc((new_n+1)*sizeof(IntPoint)); if (vs == NULL) FailAllocMessage(); smooth = (char*)malloc((new_n+1)*sizeof(char)); if (smooth == NULL) FailAllocMessage(); smooth[0] = FALSE; vs[0] = polygon_ptr->vlist[0]; for (i=0; i < n-1; i++) { index++; smooth[index] = TRUE; vs[index] = polygon_ptr->intvlist[i<<1]; index++; smooth[index] = TRUE; vs[index] = polygon_ptr->intvlist[(i<<1)+1]; index++; smooth[index] = FALSE; vs[index] = polygon_ptr->vlist[i+1]; } polygon_ptr->curved = LT_SPLINE; free(polygon_ptr->vlist); free(polygon_ptr->intvlist); polygon_ptr->vlist = vs; polygon_ptr->n = new_n; polygon_ptr->smooth = smooth; polygon_ptr->intvlist = NULL; polygon_ptr->intn = 0; AdjObjSplineVs(ObjPtr); UpdPolyBBox(ObjPtr, polygon_ptr->n, polygon_ptr->vlist); } break; case OBJ_GROUP: case OBJ_SYM: for (obj_ptr=ObjPtr->detail.r->last; obj_ptr!=NULL; obj_ptr=obj_ptr->prev) { if (ConvertObjIntSpline(obj_ptr)) { changed = TRUE; } } break; } if (changed) AdjObjBBox(ObjPtr); return changed; } void ConvertIntSpline() { struct SelRec *sel_ptr=NULL; int changed=FALSE; if (topSel == NULL) { MsgBox(TgLoadString(STID_NO_INTSPLINE_SELECTED), TOOL_NAME, INFO_MB); return; } HighLightReverse(); StartCompositeCmd(); for (sel_ptr=botSel; sel_ptr != NULL; sel_ptr=sel_ptr->prev) { PrepareToReplaceAnObj(sel_ptr->obj); if (ConvertObjIntSpline(sel_ptr->obj)) { changed = TRUE; RecordReplaceAnObj(sel_ptr->obj); } else { AbortPrepareCmd(CMD_REPLACE); } } EndCompositeCmd(); if (changed) { SetFileModified(TRUE); RedrawAnArea(botObj, selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1), selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1)); UpdSelBBox(); justDupped = FALSE; Msg(TgLoadString(STID_INTSPLINE_CONVERTED_TO_SPLINE)); } else { HighLightForward(); MsgBox(TgLoadString(STID_NO_INTSPLINE_SELECTED), TOOL_NAME, INFO_MB); return; } HighLightForward(); } /* --------------------- ConvertToBezier() --------------------- */ static void SetBezierPoints(n, vs, new_n, bezier_vs) int n, new_n; IntPoint *vs, *bezier_vs; { int i=0, *n_choose_i=(int*)malloc((n+1)*sizeof(int)), index=0; double t=(double)0, dt=(((double)1.0)/((double)(new_n-1))); double final_t=((double)1)+(dt/((double)2)); if (n_choose_i == NULL) FailAllocMessage(); memset(n_choose_i, 0, (n+1)*sizeof(int)); n--; n_choose_i[0] = 1; for (i=1; i <= n; i++) { n_choose_i[i] = n_choose_i[i-1] * (n-i+1) / i; } for (t=(double)0; t <= final_t; t+=dt, index++) { double s=((double)1)-t, xt=(double)0, yt=(double)0; for (i=0; i <= n; i++) { /* Bi = B_{i,n}(t) */ double Bi=((double)(n_choose_i[i])); int j=0; for (j=1; j <= (n-i); j++) Bi *= s; for (j=1; j <= i; j++) Bi *= t; xt += Bi * ((double)(vs[i].x)); yt += Bi * ((double)(vs[i].y)); } bezier_vs[index].x = round(xt); bezier_vs[index].y = round(yt); } free(n_choose_i); } static int ConvertObjToBezier(ObjPtr) struct ObjRec *ObjPtr; { register struct ObjRec *obj_ptr; register int i, changed=FALSE; switch (ObjPtr->type) { case OBJ_POLY: if (ObjPtr->detail.p->curved != LT_INTSPLINE) { struct PolyRec *poly_ptr=ObjPtr->detail.p; int n=poly_ptr->n; char *smooth=poly_ptr->smooth; if (n == 3) { if (!smooth[1]) { smooth[1] = TRUE; changed = TRUE; poly_ptr->curved = LT_SPLINE; AdjObjSplineVs(ObjPtr); UpdPolyBBox(ObjPtr, poly_ptr->n, poly_ptr->vlist); } } else if (n > 3) { int new_n=convertToBezierNumSegs+1; IntPoint *vs=NULL; changed = TRUE; if (smooth != NULL) free(smooth); vs = (IntPoint*)malloc((new_n+1)*sizeof(IntPoint)); if (vs == NULL) FailAllocMessage(); memset(vs, 0, (new_n+1)*sizeof(IntPoint)); smooth = (char*)malloc((new_n+1)*sizeof(char)); if (smooth == NULL) FailAllocMessage(); memset(smooth, 0, (new_n+1)*sizeof(char)); SetBezierPoints(n, poly_ptr->vlist, new_n, vs); smooth[0] = smooth[new_n-1] = FALSE; for (i=1; i < new_n-1; i++) smooth[i] = TRUE; poly_ptr->curved = LT_SPLINE; free(poly_ptr->vlist); poly_ptr->vlist = vs; poly_ptr->n = new_n; poly_ptr->smooth = smooth; AdjObjSplineVs(ObjPtr); UpdPolyBBox(ObjPtr, poly_ptr->n, poly_ptr->vlist); } } break; case OBJ_GROUP: case OBJ_SYM: for (obj_ptr=ObjPtr->detail.r->last; obj_ptr!=NULL; obj_ptr=obj_ptr->prev) { if (ConvertObjToBezier(obj_ptr)) { changed = TRUE; } } break; } if (changed) AdjObjBBox(ObjPtr); return changed; } void ConvertToBezier() { struct SelRec *sel_ptr=NULL; int changed=FALSE; if (topSel == NULL) { MsgBox(TgLoadString(STID_NO_SPLINE_SELECTED), TOOL_NAME, INFO_MB); return; } HighLightReverse(); StartCompositeCmd(); for (sel_ptr=botSel; sel_ptr != NULL; sel_ptr=sel_ptr->prev) { PrepareToReplaceAnObj(sel_ptr->obj); if (ConvertObjToBezier(sel_ptr->obj)) { changed = TRUE; RecordReplaceAnObj(sel_ptr->obj); } else { AbortPrepareCmd(CMD_REPLACE); } } EndCompositeCmd(); if (changed) { SetFileModified(TRUE); RedrawAnArea(botObj, selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1), selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1)); UpdSelBBox(); justDupped = FALSE; Msg(TgLoadString(STID_SPLINE_CONVERTED_TO_BEZIER)); } else { HighLightForward(); MsgBox(TgLoadString(STID_NO_SPLINE_SELECTED), TOOL_NAME, INFO_MB); return; } HighLightForward(); } int SetBezierConvertNumSegsValue(spec) char *spec; { int ival=0; if (sscanf(spec, "%d", &ival) != 1) { sprintf(gszMsgBox, TgLoadCachedString(CSTID_MALFORMED_INPUT_STR), spec); MsgBox(gszMsgBox, TOOL_NAME, INFO_MB); return FALSE; } else if (ival < 2) { sprintf(gszMsgBox, TgLoadString(STID_ENT_VAL_RANGE_ENTER_GE_INT), spec, 3); MsgBox(gszMsgBox, TOOL_NAME, INFO_MB); return FALSE; } convertToBezierNumSegs = ival; return TRUE; } void SetBezierConvertNumSegs(psz_num_segs) char *psz_num_segs; { char spec[MAXSTRING+1]; *spec = '\0'; if (psz_num_segs != NULL && strcmp(psz_num_segs, "-1") != 0) { UtilStrCpyN(spec, sizeof(spec), psz_num_segs); } else { sprintf(gszMsgBox, TgLoadString(STID_ENTER_BEZIER_NUM_SEGS_CUR_IS), convertToBezierNumSegs); if (Dialog(gszMsgBox, NULL, spec) == INVALID) return; } UtilTrimBlanks(spec); if (*spec == '\0') return; if (SetBezierConvertNumSegsValue(spec)) { sprintf(gszMsgBox, TgLoadString(STID_BEZIER_NUM_SEGS_SET_TO_INT), convertToBezierNumSegs); Msg(gszMsgBox); } } static void SelectModeToggleSmoothHinge() { register struct ObjRec *obj_ptr; struct PolyRec *poly_ptr=NULL; struct PolygonRec *polygon_ptr=NULL; int index, n, pt_toggled=FALSE, toggling=TRUE; int root_x, root_y, old_x, old_y, curved=(-1); unsigned int status; Window root_win, child_win; XEvent input, ev; char *smooth=NULL; if (!(topSel != NULL && topSel == botSel && (topSel->obj->type == OBJ_POLY || topSel->obj->type == OBJ_POLYGON))) { MsgBox(TgLoadString(STID_SELECT_ONLY_ONE_POLY_POLYGON), TOOL_NAME, INFO_MB); return; } obj_ptr = topSel->obj; switch (obj_ptr->type) { case OBJ_POLY: poly_ptr = obj_ptr->detail.p; smooth = poly_ptr->smooth; curved = poly_ptr->curved; break; case OBJ_POLYGON: polygon_ptr = obj_ptr->detail.g; smooth = polygon_ptr->smooth; curved = polygon_ptr->curved; break; } if (curved == LT_INTSPLINE) { MsgBox(TgLoadString(STID_CANNOT_TOGGLE_FOR_INTSPLINE), TOOL_NAME, INFO_MB); return; } if (smooth == NULL) { FatalUnexpectedError(TgLoadString(STID_BAD_POLY_IN_TOGGLE_SMOOTH), NULL); return; } PrepareToRecord(CMD_REPLACE, topSel, botSel, numObjSelected); SaveStatusStrings(); SetMouseStatus(TgLoadCachedString(CSTID_TOGGLE_SMOOTH_HINGE), TgLoadCachedString(CSTID_FINISH), TgLoadCachedString(CSTID_FINISH)); TwoLineMsg(TgLoadString(STID_CLICK_LEFT_BUTTON_TO_TOGGLE), TgLoadString(STID_CLICK_OTHER_BUTTON_TO_QUIT)); if (!debugNoPointerGrab) { XGrabPointer(mainDisplay, drawWindow, False, PointerMotionMask | ButtonPressMask, GrabModeAsync, GrabModeAsync, None, defaultCursor, CurrentTime); } XQueryPointer(mainDisplay, drawWindow, &root_win, &child_win, &root_x, &root_y, &old_x, &old_y, &status); XSetFont(mainDisplay, revDefaultGC, defaultFontPtr->fid); /* do not translate -- program constants */ XDrawString(mainDisplay, drawWindow, revDefaultGC, old_x+4, old_y+defaultFontAsc, "S/H", 3); MarkRulers(old_x, old_y); while (toggling) { XNextEvent(mainDisplay, &input); if (input.type == Expose || input.type == VisibilityNotify) { ExposeEventHandler(&input, TRUE); } else if (input.type == ButtonPress) { if (input.xbutton.button == Button1) { if ((obj_ptr->type == OBJ_POLY && PtInPolyMark(obj_ptr, input.xbutton.x, input.xbutton.y, poly_ptr->n, poly_ptr->vlist, &index) && index != 0 && index != poly_ptr->n-1) || (obj_ptr->type == OBJ_POLYGON && PtInPolyMark(obj_ptr, input.xbutton.x, input.xbutton.y, polygon_ptr->n-1, polygon_ptr->vlist, &index))) { int sel_ltx=selLtX, sel_lty=selLtY; int sel_rbx=selRbX, sel_rby=selRbY; pt_toggled = TRUE; HighLightReverse(); switch (obj_ptr->type) { case OBJ_POLY: n = poly_ptr->n; if (smooth[index]) { smooth[index] = FALSE; } else { smooth[index] = TRUE; } AdjObjSplineVs(obj_ptr); UpdPolyBBox(obj_ptr, poly_ptr->n, poly_ptr->vlist); break; case OBJ_POLYGON: n = polygon_ptr->n; if (smooth[index]) { smooth[index] = FALSE; } else { smooth[index] = TRUE; } if (index == 0) smooth[n-1] = smooth[0]; AdjObjSplineVs(obj_ptr); UpdPolyBBox(obj_ptr, polygon_ptr->n, polygon_ptr->vlist); break; } AdjObjBBox(obj_ptr); XDrawString(mainDisplay, drawWindow, revDefaultGC, old_x+4, old_y+defaultFontAsc, "S/H", 3); old_x = input.xbutton.x; old_y = input.xbutton.y; UpdSelBBox(); RedrawAreas(botObj, sel_ltx-GRID_ABS_SIZE(1), sel_lty-GRID_ABS_SIZE(1), sel_rbx+GRID_ABS_SIZE(1), sel_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(); if (obj_ptr != NULL) { XDrawString(mainDisplay, drawWindow, revDefaultGC, old_x+4, old_y+defaultFontAsc, "S/H", 3); } SetFileModified(TRUE); justDupped = FALSE; } } else { XUngrabPointer(mainDisplay, CurrentTime); Msg(""); toggling = FALSE; XDrawString(mainDisplay, drawWindow, revDefaultGC, old_x+4, old_y+defaultFontAsc, "S/H", 3); } } else if (input.type == MotionNotify) { XDrawString(mainDisplay, drawWindow, revDefaultGC, old_x+4, old_y+defaultFontAsc, "S/H", 3); old_x = input.xmotion.x; old_y = input.xmotion.y; XDrawString(mainDisplay, drawWindow, revDefaultGC, old_x+4, old_y+defaultFontAsc, "S/H", 3); MarkRulers(old_x, old_y); while (XCheckMaskEvent(mainDisplay, PointerMotionMask, &ev)) ; } } RestoreStatusStrings(); if (pt_toggled) { RecordCmd(CMD_REPLACE, NULL, topSel, botSel, numObjSelected); } else { AbortPrepareCmd(CMD_REPLACE); } } void ToggleSmoothHinge() { register int i; int changed=FALSE, ltx=selLtX, lty=selLtY, rbx=selRbX, rby=selRbY; struct VSelRec *vsel_ptr; struct ObjRec *obj_ptr; if (curChoice == NOTHING) { SelectModeToggleSmoothHinge(); return; } if (curChoice != VERTEXMODE) { MsgBox(TgLoadString(STID_ONLY_TOGGLE_SMOOTH_IN_MODES), TOOL_NAME, INFO_MB); return; } if (topVSel == NULL) { if (topSel == NULL) return; HighLightReverse(); JustRemoveAllVSel(); HighLightForward(); SelectModeToggleSmoothHinge(); return; } for (vsel_ptr=topVSel; vsel_ptr != NULL; vsel_ptr=vsel_ptr->next) { if ((vsel_ptr->obj->type == OBJ_POLY && vsel_ptr->obj->detail.p->curved == LT_INTSPLINE) || (vsel_ptr->obj->type == OBJ_POLYGON && vsel_ptr->obj->detail.g->curved == LT_INTSPLINE)) { MsgBox(TgLoadString(STID_CANNOT_TOGGLE_FOR_INTSPLINE), TOOL_NAME, INFO_MB); return; } } HighLightReverse(); StartCompositeCmd(); for (vsel_ptr=botVSel; vsel_ptr != NULL; vsel_ptr=vsel_ptr->prev) { int obj_changed=FALSE, n; IntPoint *v; char *smooth=NULL; obj_ptr = vsel_ptr->obj; switch (obj_ptr->type) { case OBJ_POLY: v = obj_ptr->detail.p->vlist; n = obj_ptr->detail.p->n; smooth = obj_ptr->detail.p->smooth; for (i=0; i < vsel_ptr->n; i++) { if (vsel_ptr->v_index[i] != 0 || vsel_ptr->v_index[i] != n-1) { break; } } if (i == vsel_ptr->n) continue; break; case OBJ_POLYGON: v = obj_ptr->detail.g->vlist; n = obj_ptr->detail.g->n; smooth = obj_ptr->detail.g->smooth; break; default: continue; } PrepareToReplaceAnObj(obj_ptr); for (i=0; i < vsel_ptr->n; i++) { int index=vsel_ptr->v_index[i]; if (!(obj_ptr->type == OBJ_POLY && (index == 0 || index == n-1))) { smooth[index] = (smooth[index] ? FALSE : TRUE); obj_changed = TRUE; } } AdjObjSplineVs(obj_ptr); UpdPolyBBox(obj_ptr, n, v); if (obj_changed) { RecordReplaceAnObj(obj_ptr); changed = TRUE; } else { AbortPrepareCmd(CMD_REPLACE); } } EndCompositeCmd(); if (changed) { Msg(TgLoadString(STID_SMOOTHNESS_TOGGLED)); 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)); SetFileModified(TRUE); justDupped = FALSE; } HighLightForward(); } static void BreakATextObj(ObjPtr, how, poli) struct ObjRec *ObjPtr; int how; ObjListInfo *poli; { struct ObjRec *prototype=NULL; struct TextRec *text_ptr=NULL; struct SelRec *sel_ptr=NULL; MiniLinesInfo *minilines=NULL; int tx_to_move=0, ty_to_move=0; prototype = DupObj(ObjPtr); text_ptr = prototype->detail.t; InvalidateTextCache(text_ptr); minilines = (&text_ptr->minilines); FreeMiniLines(minilines, FALSE); /* do not translate -- program constants */ CreateMiniLineFromString("XX", &minilines->first, &minilines->last); minilines->first->owner_minilines = minilines; text_ptr->lines = 1; text_ptr = ObjPtr->detail.t; minilines = (&text_ptr->minilines); PushCurFont(); ObjFontInfoToCurFontInfo(text_ptr); SetCanvasFont(); if (ObjPtr->ctm != NULL) { TransformPointThroughCTM(0, 0, prototype->ctm, &tx_to_move, &ty_to_move); } BreakMiniLines(minilines, how, ObjPtr->x, text_ptr->baseline_y, prototype, tx_to_move, ty_to_move, poli); PopCurFont(); FreeTextObj(prototype); for (sel_ptr=poli->top_sel; sel_ptr != NULL; sel_ptr=sel_ptr->next) { struct ObjRec *obj_ptr=sel_ptr->obj; UpdTextBBox(obj_ptr); AdjObjSplineVs(obj_ptr); AdjObjBBox(obj_ptr); } } static int GetBreakSpec() /* return TRUE if breaking into words */ { int how=INVALID, can_do_lines=FALSE, can_do_words=FALSE; char spec[MAXSTRING+1]; struct SelRec *sel_ptr=NULL; for (sel_ptr=topSel; sel_ptr != NULL; sel_ptr=sel_ptr->next) { struct ObjRec *obj_ptr=sel_ptr->obj; if (obj_ptr->type == OBJ_TEXT && !obj_ptr->locked) { struct TextRec *text_ptr=obj_ptr->detail.t; MiniLinesInfo *minilines=(&text_ptr->minilines); if (text_ptr->read_only) continue; if (CanBreakMiniLinesIntoWords(&text_ptr->minilines)) { can_do_words = TRUE; } if (minilines->first->next != NULL) can_do_lines = TRUE; } if (can_do_lines && can_do_words) break; } if (can_do_lines) { if (can_do_words) { strcpy(gszMsgBox, TgLoadString(STID_BREAK_TEXT_CWL)); } else { strcpy(gszMsgBox, TgLoadString(STID_BREAK_TEXT_CL)); } } else if (can_do_words) { strcpy(gszMsgBox, TgLoadString(STID_BREAK_TEXT_CW)); } else { return BREAK_CHAR; } *spec = '\0'; if (Dialog(gszMsgBox, NULL, spec) == INVALID) { return INVALID; } UtilTrimBlanks(spec); if (*spec == '\0') strcpy(spec, "c"); strcpy(gszMsgBox, spec); gszMsgBox[1] = '\0'; UtilStrLower(gszMsgBox); if (can_do_lines) { if (can_do_words) { switch (*gszMsgBox) { case 'c': how = BREAK_CHAR; break; case 'w': how = BREAK_WORD; break; case 'l': how = BREAK_LINE; break; } } else { switch (*gszMsgBox) { case 'c': how = BREAK_CHAR; break; case 'l': how = BREAK_LINE; break; } } } else if (can_do_words) { switch (*gszMsgBox) { case 'c': how = BREAK_CHAR; break; case 'w': how = BREAK_WORD; break; } } if (how == INVALID) { sprintf(gszMsgBox, TgLoadString(STID_INVALID_SPEC_ON_BREAK_TEXT), spec); MsgBox(gszMsgBox, TOOL_NAME, INFO_MB); } return how; } static int GetBreakSpecFromCh(spec) char *spec; { char buf[2]; int how=INVALID; buf[0] = *spec; buf[1] = '\0'; UtilStrLower(buf); switch (*buf) { case 'c': how = BREAK_CHAR; break; case 'w': how = BREAK_WORD; break; case 'l': how = BREAK_LINE; break; } if (how == INVALID) { sprintf(gszMsgBox, TgLoadString(STID_INVALID_SPEC_ON_BREAK_TEXT), spec); MsgBox(gszMsgBox, TOOL_NAME, INFO_MB); } return how; } void DoBreakUpText(spec, forced_justify) char *spec; int forced_justify; { struct ObjRec *obj_ptr=NULL; struct SelRec *sel_ptr=NULL, *next_sel=NULL; int sel_ltx=selLtX, sel_lty=selLtY, sel_rbx=selRbX, sel_rby=selRbY; int how=INVALID, changed=FALSE, read_only_text_exists=FALSE; if (topSel == NULL) { MsgBox(TgLoadString(STID_NO_TEXT_OBJ_TO_BREAK_UP), TOOL_NAME, INFO_MB); return; } if (spec == NULL || *spec == '\0' || strcmp(spec, "-1") == 0) { if ((how=GetBreakSpec()) == INVALID) return; } else { if ((how=GetBreakSpecFromCh(spec)) == INVALID) return; } HighLightReverse(); StartCompositeCmd(); for (sel_ptr=topSel; sel_ptr != NULL; sel_ptr=next_sel) { next_sel = sel_ptr->next; obj_ptr = sel_ptr->obj; if (obj_ptr->type == OBJ_TEXT && !obj_ptr->locked) { ObjListInfo oli; if (obj_ptr->detail.t->read_only) { read_only_text_exists = TRUE; continue; } memset(&oli, 0, sizeof(ObjListInfo)); changed = TRUE; PrepareToReplaceAnObj(obj_ptr); BreakATextObj(obj_ptr, how, &oli); oli.top_sel->obj->prev = obj_ptr->prev; if (obj_ptr->prev == NULL) { curPage->top = topObj = oli.top_sel->obj; } else { obj_ptr->prev->next = oli.top_sel->obj; } oli.bot_sel->obj->next = obj_ptr->next; if (obj_ptr->next == NULL) { curPage->bot = botObj = oli.bot_sel->obj; } else { obj_ptr->next->prev = oli.bot_sel->obj; } RecordCmd(CMD_ONE_TO_MANY, NULL, oli.top_sel, oli.bot_sel, oli.count); oli.top_sel->prev = sel_ptr->prev; if (sel_ptr->prev == NULL) { topSel = oli.top_sel; } else { sel_ptr->prev->next = oli.top_sel; } oli.bot_sel->next = sel_ptr->next; if (sel_ptr->next == NULL) { botSel = oli.bot_sel; } else { sel_ptr->next->prev = oli.bot_sel; } FreeObj(obj_ptr); free(sel_ptr); } } EndCompositeCmd(); if (read_only_text_exists) { MsgBox(TgLoadString(STID_SOME_TEXT_NOT_BROKEN_UP_SIZE), TOOL_NAME, INFO_MB); } if (changed) { UpdSelBBox(); RedrawAreas(botObj, selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1), selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1), sel_ltx-GRID_ABS_SIZE(1), sel_lty-GRID_ABS_SIZE(1), sel_rbx+GRID_ABS_SIZE(1), sel_rby+GRID_ABS_SIZE(1)); SetFileModified(TRUE); justDupped = FALSE; Msg(TgLoadString(STID_TEXT_BROKEN_INTO_CHARS)); } else if (!read_only_text_exists) { MsgBox(TgLoadString(STID_NO_TEXT_OBJ_TO_BREAK_UP), TOOL_NAME, INFO_MB); } HighLightForward(); } void BreakUpText(spec) char *spec; { DoBreakUpText(spec, '\0'); } static int DoSetTextFillPatternColor(ObjPtr) struct ObjRec *ObjPtr; { struct ObjRec *obj_ptr=NULL; int changed=FALSE; switch (ObjPtr->type) { case OBJ_TEXT: if (ObjPtr->color != colorIndex) { ObjPtr->color = colorIndex; changed = TRUE; } break; case OBJ_SYM: case OBJ_GROUP: case OBJ_ICON: for (obj_ptr=ObjPtr->detail.r->last; obj_ptr != NULL; obj_ptr=obj_ptr->prev) { if (DoSetTextFillPatternColor(obj_ptr)) { changed = TRUE; } } break; case OBJ_PIN: obj_ptr = GetPinObj(ObjPtr); if (DoSetTextFillPatternColor(obj_ptr)) { changed = TRUE; } break; } return changed; } void SetTextFillPatternColor() { struct SelRec *sel_ptr=NULL; int changed=FALSE; if (curChoice == DRAWTEXT) { if (curTextObj->color != colorIndex) { curTextObj->color = colorIndex; SetFileModified(TRUE); sprintf(gszMsgBox, TgLoadString(STID_CUR_TEXT_BG_SET_TO_NAMED), colorMenuItems[colorIndex]); Msg(gszMsgBox); } return; } if (topSel == NULL) { MsgBox(TgLoadCachedString(CSTID_NO_OBJ_SELECTED), TOOL_NAME, INFO_MB); return; } HighLightReverse(); StartCompositeCmd(); for (sel_ptr=topSel; sel_ptr != NULL; sel_ptr=sel_ptr->next) { struct ObjRec *obj_ptr=sel_ptr->obj; PrepareToReplaceAnObj(obj_ptr); if (DoSetTextFillPatternColor(obj_ptr)) { changed = TRUE; RecordReplaceAnObj(obj_ptr); } else { AbortPrepareCmd(CMD_REPLACE); } } EndCompositeCmd(); if (changed) { RedrawAnArea(botObj, selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1), selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1)); HighLightForward(); SetFileModified(TRUE); justDupped = FALSE; sprintf(gszMsgBox, TgLoadString(STID_SOME_TEXT_BG_SET_TO_NAMED), colorMenuItems[colorIndex]); Msg(gszMsgBox); } } void MakeRegularPolygon() { register int i; int vertex_at_right, xc, yc; int sel_ltx, sel_lty, sel_rbx, sel_rby, sides, radius; int ltx, lty, rbx, rby; double inc, angle, r; struct ObjRec *obj_ptr, *new_obj_ptr; struct PolygonRec *polygon_ptr; if (topSel == NULL) { MsgBox(TgLoadCachedString(CSTID_NO_OBJ_SELECTED), TOOL_NAME, INFO_MB); return; } else if (topSel != botSel || topSel->obj->type != OBJ_POLYGON) { MsgBox(TgLoadString(STID_SEL_ONE_POLYGON_TO_MAKE_REG), TOOL_NAME, INFO_MB); return; } else if (topSel->obj->locked) { MsgBox(TgLoadString(STID_POLYGON_LOCKED), TOOL_NAME, INFO_MB); return; } PrepareToRecord(CMD_REPLACE, topSel, botSel, numObjSelected); sel_ltx = selLtX; sel_lty = selLtY; sel_rbx = selRbX; sel_rby = selRbY; obj_ptr = topSel->obj; radius = (min(obj_ptr->obbox.rbx-obj_ptr->obbox.ltx, obj_ptr->obbox.rby-obj_ptr->obbox.lty))>>1; if (radius < 1) { MsgBox(TgLoadString(STID_POLYGON_TOO_SMALL_FOR_REGULAR), TOOL_NAME, INFO_MB); return; } sprintf(gszMsgBox, TgLoadString(STID_VERTEX_AT_3_OCLOCK_YNC)); if ((vertex_at_right=MsgBox(gszMsgBox, TOOL_NAME, YNC_MB)) == MB_ID_CANCEL) { return; } tmpTopObj = tmpBotObj = NULL; tmpTopSel = tmpBotSel = NULL; HighLightReverse(); new_obj_ptr = DupObj(obj_ptr); UnlinkObj(obj_ptr); polygon_ptr = new_obj_ptr->detail.g; sides = polygon_ptr->n-1; inc = 2*M_PI/sides; angle = (vertex_at_right==MB_ID_YES) ? 0 : inc/2; xc = obj_ptr->obbox.ltx+radius; yc = obj_ptr->obbox.lty+radius; if ((sides%4)==0 && vertex_at_right==MB_ID_NO) { r = ((double)(min(obj_ptr->obbox.rbx-obj_ptr->obbox.ltx, obj_ptr->obbox.rby-obj_ptr->obbox.lty)) / cos(angle)) / 2; } else { r = radius; } ltx = obj_ptr->obbox.rbx; lty = obj_ptr->obbox.rby; rbx = obj_ptr->obbox.ltx; rby = obj_ptr->obbox.lty; for (i=0; i < sides; i++, angle+=inc) { polygon_ptr->vlist[i].x = xc + round(r*cos(angle)); polygon_ptr->vlist[i].y = yc - round(r*sin(angle)); if (polygon_ptr->vlist[i].x < ltx) ltx = polygon_ptr->vlist[i].x; if (polygon_ptr->vlist[i].y < lty) lty = polygon_ptr->vlist[i].y; if (polygon_ptr->vlist[i].x > rbx) rbx = polygon_ptr->vlist[i].x; if (polygon_ptr->vlist[i].y > rby) rby = polygon_ptr->vlist[i].y; } polygon_ptr->vlist[sides].x = polygon_ptr->vlist[0].x; polygon_ptr->vlist[sides].y = polygon_ptr->vlist[0].y; new_obj_ptr->obbox.ltx = ltx; new_obj_ptr->obbox.lty = lty; new_obj_ptr->obbox.rbx = rbx; new_obj_ptr->obbox.rby = rby; AdjObjSplineVs(new_obj_ptr); AdjObjBBox(new_obj_ptr); topSel->obj = botSel->obj = new_obj_ptr; AddObj(NULL, topObj, new_obj_ptr); RecordCmd(CMD_REPLACE, NULL, topSel, botSel, numObjSelected); FreeObj(obj_ptr); UpdSelBBox(); RedrawAnArea(botObj, sel_ltx-GRID_ABS_SIZE(1), sel_lty-GRID_ABS_SIZE(1), sel_rbx+GRID_ABS_SIZE(1), sel_rby+GRID_ABS_SIZE(1)); SetFileModified(TRUE); justDupped = FALSE; HighLightForward(); } void DeletePoint() { int i, n, pt_deleted=FALSE, deleting=TRUE, root_x, root_y, old_x, old_y; struct ObjRec *obj_ptr; struct PolyRec *poly_ptr=NULL; struct PolygonRec *polygon_ptr=NULL; unsigned int status; Window root_win, child_win; if (!(topSel != NULL && topSel == botSel && (topSel->obj->type == OBJ_POLY || topSel->obj->type == OBJ_POLYGON))) { MsgBox(TgLoadString(STID_SELECT_ONLY_ONE_POLY_POLYGON), TOOL_NAME, INFO_MB); return; } else if (topSel->obj->locked) { MsgBox(TgLoadString(STID_CANNOT_DEL_PT_FOR_LOCKED), TOOL_NAME, INFO_MB); return; } if (curChoice == VERTEXMODE) { HighLightReverse(); JustRemoveAllVSel(); HighLightForward(); } PrepareToRecord(CMD_REPLACE, topSel, botSel, numObjSelected); obj_ptr = topSel->obj; switch (obj_ptr->type) { case OBJ_POLY: poly_ptr = obj_ptr->detail.p; break; case OBJ_POLYGON: polygon_ptr = obj_ptr->detail.g; break; } SaveStatusStrings(); SetMouseStatus(TgLoadCachedString(CSTID_DEL_A_VERTEX), TgLoadCachedString(CSTID_FINISH), TgLoadCachedString(CSTID_FINISH)); TwoLineMsg(TgLoadString(STID_LEFT_BTN_TO_DEL_PTS), TgLoadString(STID_CLICK_OTHER_BUTTON_TO_QUIT)); if (!debugNoPointerGrab) { XGrabPointer(mainDisplay, drawWindow, False, PointerMotionMask | ButtonPressMask, GrabModeAsync, GrabModeAsync, None, defaultCursor, CurrentTime); } XQueryPointer(mainDisplay, drawWindow, &root_win, &child_win, &root_x, &root_y, &old_x, &old_y, &status); XSetFont(mainDisplay, revDefaultGC, defaultFontPtr->fid); /* do not translate -- program constants */ XDrawString(mainDisplay, drawWindow, revDefaultGC, old_x+4, old_y+defaultFontAsc, "DEL", 3); MarkRulers(old_x, old_y); while (deleting) { XEvent input; XNextEvent(mainDisplay, &input); if (input.type == Expose || input.type == VisibilityNotify) { ExposeEventHandler(&input, TRUE); } else if (input.type == ButtonPress) { if (input.xbutton.button == Button1) { int index; if ((obj_ptr->type == OBJ_POLY && PtInPolyMark(obj_ptr, input.xbutton.x, input.xbutton.y, poly_ptr->n, poly_ptr->vlist, &index)) || (obj_ptr->type == OBJ_POLYGON && PtInPolyMark(obj_ptr, input.xbutton.x, input.xbutton.y, polygon_ptr->n-1, polygon_ptr->vlist, &index))) { pt_deleted = TRUE; HighLightReverse(); if ((obj_ptr->type == OBJ_POLY && poly_ptr->n == 2) || (obj_ptr->type == OBJ_POLYGON && polygon_ptr->n == 4)) { XUngrabPointer(mainDisplay, CurrentTime); Msg(""); DelObj(obj_ptr); deleting = FALSE; obj_ptr = NULL; free(topSel); topSel = botSel = NULL; XDrawString(mainDisplay, drawWindow, revDefaultGC, old_x+4, old_y+defaultFontAsc, "DEL", 3); old_x = input.xbutton.x; old_y = input.xbutton.y; RedrawAnArea(botObj, selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1), selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1)); HighLightForward(); UpdSelBBox(); } else { int sel_ltx=selLtX, sel_lty=selLtY; int sel_rbx=selRbX, sel_rby=selRbY; char *smooth=NULL; switch (obj_ptr->type) { case OBJ_POLY: n = poly_ptr->n; smooth = poly_ptr->smooth; for (i = index+1; i < n; i++) { poly_ptr->vlist[i-1] = poly_ptr->vlist[i]; if (smooth != NULL) smooth[i-1] = smooth[i]; } if (smooth != NULL) { if (index == 0) { smooth[0] = FALSE; } else if (index == n-1) { smooth[n-2] = FALSE; } } poly_ptr->n--; AdjObjSplineVs(obj_ptr); if (poly_ptr->curved != LT_INTSPLINE) { UpdPolyBBox(obj_ptr, poly_ptr->n, poly_ptr->vlist); } else { UpdPolyBBox(obj_ptr, poly_ptr->intn, poly_ptr->intvlist); } break; case OBJ_POLYGON: n = polygon_ptr->n; smooth = polygon_ptr->smooth; for (i = index+1; i < n; i++) { polygon_ptr->vlist[i-1] = polygon_ptr->vlist[i]; if (smooth != NULL) smooth[i-1] = smooth[i]; } polygon_ptr->n--; n--; if (index == 0) { polygon_ptr->vlist[n-1] = polygon_ptr->vlist[0]; if (smooth != NULL) smooth[n-1] = smooth[0]; } AdjObjSplineVs(obj_ptr); if (polygon_ptr->curved != LT_INTSPLINE) { UpdPolyBBox(obj_ptr, polygon_ptr->n, polygon_ptr->vlist); } else { UpdPolyBBox(obj_ptr, polygon_ptr->intn, polygon_ptr->intvlist); } break; } AdjObjBBox(obj_ptr); XDrawString(mainDisplay, drawWindow, revDefaultGC, old_x+4, old_y+defaultFontAsc, "DEL", 3); old_x = input.xbutton.x; old_y = input.xbutton.y; UpdSelBBox(); RedrawAreas(botObj, sel_ltx-GRID_ABS_SIZE(1), sel_lty-GRID_ABS_SIZE(1), sel_rbx+GRID_ABS_SIZE(1), sel_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(); if (obj_ptr != NULL) { XDrawString(mainDisplay, drawWindow, revDefaultGC, old_x+4, old_y+defaultFontAsc, "DEL", 3); } } SetFileModified(TRUE); justDupped = FALSE; } } else { XUngrabPointer(mainDisplay, CurrentTime); Msg(""); deleting = FALSE; XDrawString(mainDisplay, drawWindow, revDefaultGC, old_x+4, old_y+defaultFontAsc, "DEL", 3); } } else if (input.type == MotionNotify) { XEvent ev; XDrawString(mainDisplay, drawWindow, revDefaultGC, old_x+4, old_y+defaultFontAsc, "DEL", 3); old_x = input.xmotion.x; old_y = input.xmotion.y; XDrawString(mainDisplay, drawWindow, revDefaultGC, old_x+4, old_y+defaultFontAsc, "DEL", 3); MarkRulers(old_x, old_y); while (XCheckMaskEvent(mainDisplay, PointerMotionMask, &ev)) ; } } RestoreStatusStrings(); if (pt_deleted) { if (topSel == NULL) { ChangeReplaceOneCmdToDeleteCmd(); } else { RecordCmd(CMD_REPLACE, NULL, topSel, botSel, numObjSelected); } } else { AbortPrepareCmd(CMD_REPLACE); } } static int ContinueAddPolyPoint(ObjPtr, MouseX, MouseY, Index, PolyPtr, LastMouseX, LastMouseY) struct ObjRec *ObjPtr; int MouseX, MouseY, Index; struct PolyRec *PolyPtr; int *LastMouseX, *LastMouseY; /* (MouseX,MouseY) is the mouse's origin in screen offsets */ { int n=PolyPtr->n, sn=0, curved=PolyPtr->curved; int already_moved=FALSE, done=FALSE, before=FALSE; XPoint v[3], *sv=NULL; IntPoint *vs=PolyPtr->vlist, *pv=NULL, *cntrlv=NULL; int prev_x, prev_y, prev_tx, prev_ty, x, y, tx, ty, tmp_x, tmp_y; int next_x, next_y, next_tx, next_ty; int orig_x, orig_y, grid_x, grid_y, new_mouse_x, new_mouse_y; int sel_ltx, sel_lty, sel_rbx, sel_rby, num=0, i, intn=0; char *smooth=PolyPtr->smooth, *tmp_smooth=NULL; char buf[80], w_buf[80], h_buf[80], x_buf[80], y_buf[80]; double prev_angle, next_angle; sel_ltx = selLtX; sel_lty = selLtY; sel_rbx = selRbX; sel_rby = selRbY; x = tx = vs[Index].x; y = ty = vs[Index].y; if (ObjPtr->ctm != NULL) { TransformPointThroughCTM(x-ObjPtr->x, y-ObjPtr->y, ObjPtr->ctm, &tmp_x, &tmp_y); tx = ObjPtr->x+tmp_x; ty = ObjPtr->y+tmp_y; } if (curved == LT_INTSPLINE || smooth == NULL || !smooth[Index]) { MARK(drawWindow, revDefaultGC, OFFSET_X(tx), OFFSET_Y(ty)); } else { MARKO(drawWindow, revDefaultGC, OFFSET_X(tx), OFFSET_Y(ty)); } if (Index == 0) { next_x = next_tx = vs[1].x; next_y = next_ty = vs[1].y; prev_x = prev_tx = 2*x-next_x; prev_y = prev_ty = 2*y-next_y; } else if (Index == n-1) { prev_x = next_tx = vs[n-2].x; prev_y = next_ty = vs[n-2].y; next_x = prev_tx = 2*x-prev_x; next_y = prev_ty = 2*y-prev_y; } else { prev_x = prev_tx = vs[Index-1].x; prev_y = prev_ty = vs[Index-1].y; next_x = next_tx = vs[Index+1].x; next_y = next_ty = vs[Index+1].y; } if (ObjPtr->ctm != NULL) { TransformPointThroughCTM(next_x-ObjPtr->x, next_y-ObjPtr->y, ObjPtr->ctm, &tmp_x, &tmp_y); next_tx = ObjPtr->x+tmp_x; next_ty = ObjPtr->y+tmp_y; TransformPointThroughCTM(prev_x-ObjPtr->x, prev_y-ObjPtr->y, ObjPtr->ctm, &tmp_x, &tmp_y); prev_tx = ObjPtr->x+tmp_x; prev_ty = ObjPtr->y+tmp_y; } prev_angle = (prev_tx==tx) ? ((prev_ty>=ty) ? M_PI/2.0 : -M_PI/2.0) : atan2((double)(prev_ty-ty), (double)(prev_tx-tx)); next_angle = (next_tx==tx) ? ((next_ty>=ty) ? M_PI/2.0 : -M_PI/2.0) : atan2((double)(next_ty-ty), (double)(next_tx-tx)); if (splineRubberband) { pv = (IntPoint*)malloc((n+2)*sizeof(IntPoint)); if (pv == NULL) FailAllocMessage(); if (curved != LT_INTSPLINE && smooth != NULL) { tmp_smooth = (char*)malloc((n+2)*sizeof(char)); if (tmp_smooth == NULL) FailAllocMessage(); } if (ObjPtr->ctm == NULL) { for (i = 0; i <= Index; i++) { pv[i].x = vs[i].x; pv[i].y = vs[i].y; if (tmp_smooth != NULL) tmp_smooth[i] = smooth[i]; } for (i = Index; i < n; i++) { pv[i+1].x = vs[i].x; pv[i+1].y = vs[i].y; if (tmp_smooth != NULL) tmp_smooth[i+1] = smooth[i]; } } else { for (i = 0; i <= Index; i++) { TransformPointThroughCTM(vs[i].x-ObjPtr->x, vs[i].y-ObjPtr->y, ObjPtr->ctm, &tmp_x, &tmp_y); pv[i].x = ObjPtr->x+tmp_x; pv[i].y = ObjPtr->y+tmp_y; if (tmp_smooth != NULL) tmp_smooth[i] = smooth[i]; } for (i = Index; i < n; i++) { TransformPointThroughCTM(vs[i].x-ObjPtr->x, vs[i].y-ObjPtr->y, ObjPtr->ctm, &tmp_x, &tmp_y); pv[i+1].x = ObjPtr->x+tmp_x; pv[i+1].y = ObjPtr->y+tmp_y; if (tmp_smooth != NULL) tmp_smooth[i+1] = smooth[i]; } } } GridXY(MouseX, MouseY, &orig_x, &orig_y); grid_x = orig_x; grid_y = orig_y; new_mouse_x = MouseX; new_mouse_y = MouseY; PixelToMeasurementUnit(w_buf, 0); PixelToMeasurementUnit(h_buf, 0); PixelToMeasurementUnit(x_buf, tx); PixelToMeasurementUnit(y_buf, ty); /* do not translate -- program constants */ sprintf(buf, "ADD: dx=%s\n dy=%s\n x=%s\n y=%s", w_buf, h_buf, x_buf, y_buf); StartShowMeasureCursor(OFFSET_X(tx), OFFSET_Y(ty), buf, FALSE); while (!done) { double new_angle, theta_1, theta_2; XEvent input, ev; XNextEvent(mainDisplay, &input); if (input.type == Expose || input.type == VisibilityNotify) { ExposeEventHandler(&input, TRUE); } else if (input.type == MotionNotify || input.type == KeyPress || input.type == KeyRelease) { int new_x, new_y; if (input.type == KeyPress || input.type == KeyRelease) { new_mouse_x = grid_x; new_mouse_y = grid_y; } else { new_mouse_x = input.xmotion.x; new_mouse_y = input.xmotion.y; } if (shiftForDiagMouseMove && DiagEventCheck(&input)) { if (input.type == KeyRelease) { new_mouse_x = input.xkey.x; new_mouse_y = input.xkey.y; } else { DiagGridXY(orig_x, orig_y, &new_mouse_x, &new_mouse_y); } } GridXY(new_mouse_x, new_mouse_y, &grid_x, &grid_y); new_x = ABS_SIZE(new_mouse_x-MouseX) + tx; new_y = ABS_SIZE(new_mouse_y-MouseY) + ty; if (!already_moved) { already_moved = TRUE; new_angle = (new_x==tx) ? ((new_y>=ty) ? M_PI/2.0 : -M_PI/2.0) : atan2((double)(new_y-ty), (double)(new_x-tx)); theta_1 = fabs(prev_angle - new_angle); theta_2 = fabs(next_angle - new_angle); if (theta_1 > M_PI) theta_1 = 2*M_PI-theta_1; if (theta_2 > M_PI) theta_2 = 2*M_PI-theta_2; before = (theta_1 <= theta_2); if (before) { /* Add a point between the current and the previous point */ if (Index == 0) { num = 2; v[0].x = OFFSET_X(tx); v[0].y = OFFSET_Y(ty); v[1].x = OFFSET_X(tx); v[1].y = OFFSET_Y(ty); } else { num = 3; v[0].x = OFFSET_X(prev_tx); v[0].y = OFFSET_Y(prev_ty); v[1].x = OFFSET_X(tx); v[1].y = OFFSET_Y(ty); v[2].x = OFFSET_X(tx); v[2].y = OFFSET_Y(ty); } } else { /* Add a point between the current and the next point */ if (Index == n-1) { num = 2; v[0].x = OFFSET_X(tx); v[0].y = OFFSET_Y(ty); v[1].x = OFFSET_X(tx); v[1].y = OFFSET_Y(ty); } else { num = 3; v[0].x = OFFSET_X(tx); v[0].y = OFFSET_Y(ty); v[1].x = OFFSET_X(tx); v[1].y = OFFSET_Y(ty); v[2].x = OFFSET_X(next_tx); v[2].y = OFFSET_Y(next_ty); } } if (splineRubberband) { switch (curved) { case LT_STRAIGHT: case LT_SPLINE: sv = MakeMultiSplinePolyVertex(&sn, tmp_smooth, drawOrigX, drawOrigY, n+1, pv); break; case LT_INTSPLINE: sv = MakeIntSplinePolyVertex(&sn, &intn, &cntrlv, drawOrigX, drawOrigY, n+1, pv); break; } XDrawLines(mainDisplay, drawWindow, revDefaultGC, sv, sn, CoordModeOrigin); } } else { PixelToMeasurementUnit(w_buf, abs(ABS_X(v[1].x)-tx)); PixelToMeasurementUnit(h_buf, abs(ABS_Y(v[1].y)-ty)); PixelToMeasurementUnit(x_buf, ABS_X(v[1].x)); PixelToMeasurementUnit(y_buf, ABS_Y(v[1].y)); sprintf(buf, "ADD: dx=%s\n dy=%s\n x=%s\n y=%s", w_buf, h_buf, x_buf, y_buf); ShowMeasureCursor(v[1].x, v[1].y, buf, FALSE); if (splineRubberband) { XDrawLines(mainDisplay, drawWindow, revDefaultGC, sv, sn, CoordModeOrigin); } else { MyDashedLine(drawWindow, revDefaultGC, v, num); } v[1].x = OFFSET_X(tx) + grid_x - orig_x; v[1].y = OFFSET_Y(ty) + grid_y - orig_y; if (splineRubberband) { free(sv); if (before) { pv[Index].x = tx + ABS_SIZE(grid_x-orig_x); pv[Index].y = ty + ABS_SIZE(grid_y-orig_y); } else { pv[Index+1].x = tx + ABS_SIZE(grid_x-orig_x); pv[Index+1].y = ty + ABS_SIZE(grid_y-orig_y); } switch (curved) { case LT_STRAIGHT: case LT_SPLINE: sv = MakeMultiSplinePolyVertex(&sn, tmp_smooth, drawOrigX, drawOrigY, n+1, pv); break; case LT_INTSPLINE: free(cntrlv); sv = MakeIntSplinePolyVertex(&sn, &intn, &cntrlv, drawOrigX, drawOrigY, n+1, pv); break; } XDrawLines(mainDisplay, drawWindow, revDefaultGC, sv, sn, CoordModeOrigin); } else { MyDashedLine(drawWindow, revDefaultGC, v, num); } MarkRulers(v[1].x, v[1].y); PixelToMeasurementUnit(w_buf, abs(ABS_X(v[1].x)-tx)); PixelToMeasurementUnit(h_buf, abs(ABS_Y(v[1].y)-ty)); PixelToMeasurementUnit(x_buf, ABS_X(v[1].x)); PixelToMeasurementUnit(y_buf, ABS_Y(v[1].y)); sprintf(buf, "ADD: dx=%s\n dy=%s\n x=%s\n y=%s", w_buf, h_buf, x_buf, y_buf); ShowMeasureCursor(v[1].x, v[1].y, buf, FALSE); } while (XCheckMaskEvent(mainDisplay, PointerMotionMask, &ev)) ; } else if (input.type == ButtonRelease) { done = TRUE; *LastMouseX = new_mouse_x; *LastMouseY = new_mouse_y; if (curved == LT_INTSPLINE || smooth == NULL || !smooth[Index]) { MARK(drawWindow, revDefaultGC, OFFSET_X(tx), OFFSET_Y(ty)); } else { MARKO(drawWindow, revDefaultGC, OFFSET_X(tx), OFFSET_Y(ty)); } if (already_moved) { PixelToMeasurementUnit(w_buf, abs(ABS_X(v[1].x)-tx)); PixelToMeasurementUnit(h_buf, abs(ABS_Y(v[1].y)-ty)); PixelToMeasurementUnit(x_buf, ABS_X(v[1].x)); PixelToMeasurementUnit(y_buf, ABS_Y(v[1].y)); sprintf(buf, "ADD: dx=%s\n dy=%s\n x=%s\n y=%s", w_buf, h_buf, x_buf, y_buf); EndShowMeasureCursor(v[1].x, v[1].y, buf, FALSE); } else { PixelToMeasurementUnit(w_buf, 0); PixelToMeasurementUnit(h_buf, 0); PixelToMeasurementUnit(x_buf, tx); PixelToMeasurementUnit(y_buf, ty); sprintf(buf, "ADD: dx=%s\n dy=%s\n x=%s\n y=%s", w_buf, h_buf, x_buf, y_buf); StartShowMeasureCursor(OFFSET_X(tx), OFFSET_Y(ty), buf, FALSE); } if (!already_moved) { return FALSE; } else { if (splineRubberband) { XDrawLines(mainDisplay, drawWindow, revDefaultGC, sv, sn, CoordModeOrigin); } if (grid_x == orig_x && grid_y == orig_y) { return FALSE; } } HighLightReverse(); vs = (IntPoint*)realloc(vs, (n+2)*sizeof(IntPoint)); if (vs == NULL) return FailAllocMessage(); if (smooth != NULL) { smooth = (char*)realloc(smooth, (n+2)*sizeof(char)); if (smooth == NULL) return FailAllocMessage(); } PolyPtr->vlist = vs; PolyPtr->smooth = smooth; if (before) { for (i = n-1; i >= Index; i--) { vs[i+1] = vs[i]; if (smooth != NULL) smooth[i+1] = smooth[i]; } if (ObjPtr->ctm == NULL) { vs[Index].x = x + ABS_SIZE(grid_x-orig_x); vs[Index].y = y + ABS_SIZE(grid_y-orig_y); } else { vs[Index].x = tx + ABS_SIZE(grid_x-orig_x); vs[Index].y = ty + ABS_SIZE(grid_y-orig_y); ReverseTransformPointThroughCTM(vs[Index].x-ObjPtr->x, vs[Index].y-ObjPtr->y, ObjPtr->ctm, &tmp_x, &tmp_y); vs[Index].x = ObjPtr->x+tmp_x; vs[Index].y = ObjPtr->y+tmp_y; } if (smooth != NULL) smooth[Index] = smooth[Index+1]; } else { for (i = n-1; i > Index; i--) { vs[i+1] = vs[i]; if (smooth != NULL) smooth[i+1] = smooth[i]; } if (ObjPtr->ctm == NULL) { vs[Index+1].x = x + ABS_SIZE(grid_x-orig_x); vs[Index+1].y = y + ABS_SIZE(grid_y-orig_y); } else { vs[Index+1].x = tx + ABS_SIZE(grid_x-orig_x); vs[Index+1].y = ty + ABS_SIZE(grid_y-orig_y); ReverseTransformPointThroughCTM(vs[Index+1].x-ObjPtr->x, vs[Index+1].y-ObjPtr->y, ObjPtr->ctm, &tmp_x, &tmp_y); vs[Index+1].x = ObjPtr->x+tmp_x; vs[Index+1].y = ObjPtr->y+tmp_y; } if (smooth != NULL) smooth[Index+1] = smooth[Index]; } if (splineRubberband) { free(sv); free(pv); if (tmp_smooth != NULL) free(tmp_smooth); if (curved == LT_INTSPLINE && cntrlv != NULL) free(cntrlv); } PolyPtr->n++; n++; AdjObjSplineVs(ObjPtr); if (curved != LT_INTSPLINE) { UpdPolyBBox(ObjPtr, PolyPtr->n, PolyPtr->vlist); } else { UpdPolyBBox(ObjPtr, PolyPtr->intn, PolyPtr->intvlist); } AdjObjBBox(ObjPtr); UpdSelBBox(); RedrawAreas(botObj, sel_ltx-GRID_ABS_SIZE(1), sel_lty-GRID_ABS_SIZE(1), sel_rbx+GRID_ABS_SIZE(1), sel_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(); SetFileModified(TRUE); justDupped = FALSE; } else if (input.type == KeyPress) { if (KeyPressEventIsEscape(&input.xkey)) { done = TRUE; *LastMouseX = new_mouse_x; *LastMouseY = new_mouse_y; if (curved == LT_INTSPLINE || smooth == NULL || !smooth[Index]) { MARK(drawWindow, revDefaultGC, OFFSET_X(tx), OFFSET_Y(ty)); } else { MARKO(drawWindow, revDefaultGC, OFFSET_X(tx), OFFSET_Y(ty)); } if (already_moved) { PixelToMeasurementUnit(w_buf, abs(ABS_X(v[1].x)-tx)); PixelToMeasurementUnit(h_buf, abs(ABS_Y(v[1].y)-ty)); PixelToMeasurementUnit(x_buf, ABS_X(v[1].x)); PixelToMeasurementUnit(y_buf, ABS_Y(v[1].y)); sprintf(buf, "ADD: dx=%s\n dy=%s\n x=%s\n y=%s", w_buf, h_buf, x_buf, y_buf); EndShowMeasureCursor(v[1].x, v[1].y, buf, FALSE); } else { PixelToMeasurementUnit(w_buf, 0); PixelToMeasurementUnit(h_buf, 0); PixelToMeasurementUnit(x_buf, tx); PixelToMeasurementUnit(y_buf, ty); sprintf(buf, "ADD: dx=%s\n dy=%s\n x=%s\n y=%s", w_buf, h_buf, x_buf, y_buf); StartShowMeasureCursor(OFFSET_X(tx), OFFSET_Y(ty), buf, FALSE); } if (already_moved) { if (splineRubberband) { XDrawLines(mainDisplay, drawWindow, revDefaultGC, sv, sn, CoordModeOrigin); } else { MyDashedLine(drawWindow, revDefaultGC, v, 3); } if (grid_x == orig_x && grid_y == orig_y) { return FALSE; } } return FALSE; } } } return TRUE; } static int ContinueAddPolygonPoint(ObjPtr, MouseX, MouseY, Index, PolygonPtr, LastMouseX, LastMouseY) struct ObjRec *ObjPtr; int MouseX, MouseY, Index; struct PolygonRec *PolygonPtr; int *LastMouseX, *LastMouseY; /* (MouseX,MouseY) is the mouse's origin in screen offsets */ { int n=PolygonPtr->n, sn=0, curved=PolygonPtr->curved; int already_moved=FALSE, done=FALSE, before=FALSE; XPoint v[3], *sv=NULL; IntPoint *vs=PolygonPtr->vlist, *pv=NULL, *cntrlv=NULL; int prev_x, prev_y, prev_tx, prev_ty, x, y, tx, ty, tmp_x, tmp_y; int next_x, next_y, next_tx, next_ty; int orig_x, orig_y, grid_x, grid_y, new_mouse_x, new_mouse_y; int sel_ltx, sel_lty, sel_rbx, sel_rby, i, intn=0; char *smooth=PolygonPtr->smooth, *tmp_smooth=NULL; char buf[80], w_buf[80], h_buf[80], x_buf[80], y_buf[80]; double prev_angle, next_angle; sel_ltx = selLtX; sel_lty = selLtY; sel_rbx = selRbX; sel_rby = selRbY; x = tx = vs[Index].x; y = ty = vs[Index].y; if (ObjPtr->ctm != NULL) { TransformPointThroughCTM(x-ObjPtr->x, y-ObjPtr->y, ObjPtr->ctm, &tmp_x, &tmp_y); tx = ObjPtr->x+tmp_x; ty = ObjPtr->y+tmp_y; } if (curved == LT_INTSPLINE || smooth == NULL || !smooth[Index]) { MARK(drawWindow, revDefaultGC, OFFSET_X(tx), OFFSET_Y(ty)); } else { MARKO(drawWindow, revDefaultGC, OFFSET_X(tx), OFFSET_Y(ty)); } if (Index == 0 || Index == n-1) { next_x = next_tx = vs[1].x; next_y = next_ty = vs[1].y; prev_x = prev_tx = vs[n-2].x; prev_y = prev_ty = vs[n-2].y; } else { prev_x = prev_tx = vs[Index-1].x; prev_y = prev_ty = vs[Index-1].y; next_x = next_tx = vs[Index+1].x; next_y = next_ty = vs[Index+1].y; } if (ObjPtr->ctm != NULL) { TransformPointThroughCTM(next_x-ObjPtr->x, next_y-ObjPtr->y, ObjPtr->ctm, &tmp_x, &tmp_y); next_tx = ObjPtr->x+tmp_x; next_ty = ObjPtr->y+tmp_y; TransformPointThroughCTM(prev_x-ObjPtr->x, prev_y-ObjPtr->y, ObjPtr->ctm, &tmp_x, &tmp_y); prev_tx = ObjPtr->x+tmp_x; prev_ty = ObjPtr->y+tmp_y; } prev_angle = (prev_tx==tx) ? ((prev_ty>=ty) ? M_PI/2.0 : -M_PI/2.0) : atan2((double)(prev_ty-ty), (double)(prev_tx-tx)); next_angle = (next_tx==tx) ? ((next_ty>=ty) ? M_PI/2.0 : -M_PI/2.0) : atan2((double)(next_ty-ty), (double)(next_tx-tx)); if (splineRubberband) { pv = (IntPoint *)malloc((n+2)*sizeof(IntPoint)); if (pv == NULL) FailAllocMessage(); if (curved != LT_INTSPLINE && smooth != NULL) { tmp_smooth = (char*)malloc((n+2)*sizeof(char)); if (tmp_smooth == NULL) FailAllocMessage(); } if (ObjPtr->ctm == NULL) { for (i = 0; i <= Index; i++) { pv[i].x = vs[i].x; pv[i].y = vs[i].y; if (tmp_smooth != NULL) tmp_smooth[i] = smooth[i]; } for (i = Index; i < n; i++) { pv[i+1].x = vs[i].x; pv[i+1].y = vs[i].y; if (tmp_smooth != NULL) tmp_smooth[i+1] = smooth[i]; } } else { for (i = 0; i <= Index; i++) { TransformPointThroughCTM(vs[i].x-ObjPtr->x, vs[i].y-ObjPtr->y, ObjPtr->ctm, &tmp_x, &tmp_y); pv[i].x = ObjPtr->x+tmp_x; pv[i].y = ObjPtr->y+tmp_y; if (tmp_smooth != NULL) tmp_smooth[i] = smooth[i]; } for (i = Index; i < n; i++) { TransformPointThroughCTM(vs[i].x-ObjPtr->x, vs[i].y-ObjPtr->y, ObjPtr->ctm, &tmp_x, &tmp_y); pv[i+1].x = ObjPtr->x+tmp_x; pv[i+1].y = ObjPtr->y+tmp_y; if (tmp_smooth != NULL) tmp_smooth[i+1] = smooth[i]; } } } GridXY(MouseX, MouseY, &orig_x, &orig_y); grid_x = orig_x; grid_y = orig_y; new_mouse_x = MouseX; new_mouse_y = MouseY; PixelToMeasurementUnit(w_buf, 0); PixelToMeasurementUnit(h_buf, 0); PixelToMeasurementUnit(x_buf, tx); PixelToMeasurementUnit(y_buf, ty); /* do not translate -- program constants */ sprintf(buf, "ADD: dx=%s\n dy=%s\n x=%s\n y=%s", w_buf, h_buf, x_buf, y_buf); StartShowMeasureCursor(OFFSET_X(tx), OFFSET_Y(ty), buf, FALSE); while (!done) { double new_angle, theta_1, theta_2; XEvent input, ev; XNextEvent(mainDisplay, &input); if (input.type == Expose || input.type == VisibilityNotify) { ExposeEventHandler(&input, TRUE); } else if (input.type == MotionNotify || input.type == KeyPress || input.type == KeyRelease) { int new_x, new_y; if (input.type == KeyPress || input.type == KeyRelease) { new_mouse_x = grid_x; new_mouse_y = grid_y; } else { new_mouse_x = input.xmotion.x; new_mouse_y = input.xmotion.y; } if (shiftForDiagMouseMove && DiagEventCheck(&input)) { if (input.type == KeyRelease) { new_mouse_x = input.xkey.x; new_mouse_y = input.xkey.y; } else { DiagGridXY(orig_x, orig_y, &new_mouse_x, &new_mouse_y); } } GridXY(new_mouse_x, new_mouse_y, &grid_x, &grid_y); new_x = ABS_SIZE(new_mouse_x-MouseX) + tx; new_y = ABS_SIZE(new_mouse_y-MouseY) + ty; if (!already_moved) { already_moved = TRUE; new_angle = (new_x==tx) ? ((new_y>=ty) ? M_PI/2.0 : -M_PI/2.0) : atan2((double)(new_y-ty), (double)(new_x-tx)); theta_1 = fabs(prev_angle - new_angle); theta_2 = fabs(next_angle - new_angle); if (theta_1 > M_PI) theta_1 = 2*M_PI-theta_1; if (theta_2 > M_PI) theta_2 = 2*M_PI-theta_2; before = (theta_1 <= theta_2); if (before) { /* Add a point between the current and the previous point */ v[0].x = OFFSET_X(prev_tx); v[0].y = OFFSET_Y(prev_ty); v[1].x = OFFSET_X(tx); v[1].y = OFFSET_Y(ty); v[2].x = OFFSET_X(tx); v[2].y = OFFSET_Y(ty); } else { /* Add a point between the current and the next point */ v[0].x = OFFSET_X(tx); v[0].y = OFFSET_Y(ty); v[1].x = OFFSET_X(tx); v[1].y = OFFSET_Y(ty); v[2].x = OFFSET_X(next_tx); v[2].y = OFFSET_Y(next_ty); } if (splineRubberband) { switch (curved) { case LT_STRAIGHT: case LT_SPLINE: sv = MakeMultiSplinePolygonVertex(&sn, tmp_smooth, drawOrigX, drawOrigY, n+1, pv); break; case LT_INTSPLINE: sv = MakeIntSplinePolygonVertex(&sn, &intn, &cntrlv, drawOrigX, drawOrigY, n+1, pv); break; } XDrawLines(mainDisplay, drawWindow, revDefaultGC, sv, sn, CoordModeOrigin); } } else { PixelToMeasurementUnit(w_buf, abs(ABS_X(v[1].x)-tx)); PixelToMeasurementUnit(h_buf, abs(ABS_Y(v[1].y)-ty)); PixelToMeasurementUnit(x_buf, ABS_X(v[1].x)); PixelToMeasurementUnit(y_buf, ABS_Y(v[1].y)); sprintf(buf, "ADD: dx=%s\n dy=%s\n x=%s\n y=%s", w_buf, h_buf, x_buf, y_buf); ShowMeasureCursor (v[1].x, v[1].y, buf, FALSE); if (splineRubberband) { XDrawLines(mainDisplay, drawWindow, revDefaultGC, sv, sn, CoordModeOrigin); } else { MyDashedLine(drawWindow, revDefaultGC, v, 3); } v[1].x = OFFSET_X(tx) + grid_x - orig_x; v[1].y = OFFSET_Y(ty) + grid_y - orig_y; if (splineRubberband) { free(sv); if (before) { pv[Index].x = tx + ABS_SIZE(grid_x-orig_x); pv[Index].y = ty + ABS_SIZE(grid_y-orig_y); if (Index == 0) { pv[n].x = tx + ABS_SIZE(grid_x-orig_x); pv[n].y = ty + ABS_SIZE(grid_y-orig_y); } } else { pv[Index+1].x = tx + ABS_SIZE(grid_x-orig_x); pv[Index+1].y = ty + ABS_SIZE(grid_y-orig_y); if (Index == n-1) { pv[0].x = tx + ABS_SIZE(grid_x-orig_x); pv[0].y = ty + ABS_SIZE(grid_y-orig_y); } } switch (curved) { case LT_STRAIGHT: case LT_SPLINE: sv = MakeMultiSplinePolygonVertex(&sn, tmp_smooth, drawOrigX, drawOrigY, n+1, pv); break; case LT_INTSPLINE: free(cntrlv); sv = MakeIntSplinePolygonVertex(&sn, &intn, &cntrlv, drawOrigX, drawOrigY, n+1, pv); break; } XDrawLines(mainDisplay, drawWindow, revDefaultGC, sv, sn, CoordModeOrigin); } else { MyDashedLine(drawWindow, revDefaultGC, v, 3); } MarkRulers(v[1].x, v[1].y); PixelToMeasurementUnit(w_buf, abs(ABS_X(v[1].x)-tx)); PixelToMeasurementUnit(h_buf, abs(ABS_Y(v[1].y)-ty)); PixelToMeasurementUnit(x_buf, ABS_X(v[1].x)); PixelToMeasurementUnit(y_buf, ABS_Y(v[1].y)); sprintf(buf, "ADD: dx=%s\n dy=%s\n x=%s\n y=%s", w_buf, h_buf, x_buf, y_buf); ShowMeasureCursor(v[1].x, v[1].y, buf, FALSE); } while (XCheckMaskEvent(mainDisplay, PointerMotionMask, &ev)) ; } else if (input.type == ButtonRelease) { done = TRUE; *LastMouseX = new_mouse_x; *LastMouseY = new_mouse_y; if (curved == LT_INTSPLINE || smooth == NULL || !smooth[Index]) { MARK(drawWindow, revDefaultGC, OFFSET_X(tx), OFFSET_Y(ty)); } else { MARKO(drawWindow, revDefaultGC, OFFSET_X(tx), OFFSET_Y(ty)); } if (already_moved) { PixelToMeasurementUnit(w_buf, abs(ABS_X(v[1].x)-tx)); PixelToMeasurementUnit(h_buf, abs(ABS_Y(v[1].y)-ty)); PixelToMeasurementUnit(x_buf, ABS_X(v[1].x)); PixelToMeasurementUnit(y_buf, ABS_Y(v[1].y)); sprintf(buf, "ADD: dx=%s\n dy=%s\n x=%s\n y=%s", w_buf, h_buf, x_buf, y_buf); EndShowMeasureCursor(v[1].x, v[1].y, buf, FALSE); } else { PixelToMeasurementUnit(w_buf, 0); PixelToMeasurementUnit(h_buf, 0); PixelToMeasurementUnit(x_buf, tx); PixelToMeasurementUnit(y_buf, ty); sprintf(buf, "ADD: dx=%s\n dy=%s\n x=%s\n y=%s", w_buf, h_buf, x_buf, y_buf); StartShowMeasureCursor(OFFSET_X(tx), OFFSET_Y(ty), buf, FALSE); } if (!already_moved) { return FALSE; } else { if (splineRubberband) { XDrawLines(mainDisplay, drawWindow, revDefaultGC, sv, sn, CoordModeOrigin); } if (grid_x == orig_x && grid_y == orig_y) { return FALSE; } } HighLightReverse(); vs = (IntPoint*)realloc(vs, (n+2)*sizeof(IntPoint)); if (vs == NULL) return FailAllocMessage(); if (smooth != NULL) { smooth = (char*)realloc(smooth, (n+2)*sizeof(char)); if (smooth == NULL) return FailAllocMessage(); } PolygonPtr->vlist = vs; PolygonPtr->smooth = smooth; if (Index == 0 || Index == n-1) { if (before) { vs[n].x = vs[n-1].x; vs[n].y = vs[n-1].y; if (ObjPtr->ctm == NULL) { vs[n-1].x = x + ABS_SIZE(grid_x-orig_x); vs[n-1].y = y + ABS_SIZE(grid_y-orig_y); } else { vs[n-1].x = tx + ABS_SIZE(grid_x-orig_x); vs[n-1].y = ty + ABS_SIZE(grid_y-orig_y); ReverseTransformPointThroughCTM(vs[n-1].x-ObjPtr->x, vs[n-1].y-ObjPtr->y, ObjPtr->ctm, &tmp_x, &tmp_y); vs[n-1].x = ObjPtr->x+tmp_x; vs[n-1].y = ObjPtr->y+tmp_y; } if (smooth != NULL) smooth[n] = smooth[n-1]; } else { for (i = n-1; i > 0; i--) { vs[i+1].x = vs[i].x; vs[i+1].y = vs[i].y; if (smooth != NULL) smooth[i+1] = smooth[i]; } if (ObjPtr->ctm == NULL) { vs[1].x = x + ABS_SIZE(grid_x-orig_x); vs[1].y = y + ABS_SIZE(grid_y-orig_y); } else { vs[1].x = tx + ABS_SIZE(grid_x-orig_x); vs[1].y = ty + ABS_SIZE(grid_y-orig_y); ReverseTransformPointThroughCTM(vs[1].x-ObjPtr->x, vs[1].y-ObjPtr->y, ObjPtr->ctm, &tmp_x, &tmp_y); vs[1].x = ObjPtr->x+tmp_x; vs[1].y = ObjPtr->y+tmp_y; } if (smooth != NULL) smooth[1] = smooth[0]; } } else { if (before) { for (i = n-1; i >= Index; i--) { vs[i+1].x = vs[i].x; vs[i+1].y = vs[i].y; if (smooth != NULL) smooth[i+1] = smooth[i]; } if (ObjPtr->ctm == NULL) { vs[Index].x = x + ABS_SIZE(grid_x-orig_x); vs[Index].y = y + ABS_SIZE(grid_y-orig_y); } else { vs[Index].x = tx + ABS_SIZE(grid_x-orig_x); vs[Index].y = ty + ABS_SIZE(grid_y-orig_y); ReverseTransformPointThroughCTM(vs[Index].x-ObjPtr->x, vs[Index].y-ObjPtr->y, ObjPtr->ctm, &tmp_x, &tmp_y); vs[Index].x = ObjPtr->x+tmp_x; vs[Index].y = ObjPtr->y+tmp_y; } if (smooth != NULL) smooth[Index] = smooth[Index+1]; } else { for (i = n-1; i > Index; i--) { vs[i+1].x = vs[i].x; vs[i+1].y = vs[i].y; if (smooth != NULL) smooth[i+1] = smooth[i]; } if (ObjPtr->ctm == NULL) { vs[Index+1].x = x + ABS_SIZE(grid_x-orig_x); vs[Index+1].y = y + ABS_SIZE(grid_y-orig_y); } else { vs[Index+1].x = tx + ABS_SIZE(grid_x-orig_x); vs[Index+1].y = ty + ABS_SIZE(grid_y-orig_y); ReverseTransformPointThroughCTM(vs[Index+1].x-ObjPtr->x, vs[Index+1].y-ObjPtr->y, ObjPtr->ctm, &tmp_x, &tmp_y); vs[Index+1].x = ObjPtr->x+tmp_x; vs[Index+1].y = ObjPtr->y+tmp_y; } if (smooth != NULL) smooth[Index+1] = smooth[Index]; } } if (splineRubberband) { free(sv); free(pv); if (tmp_smooth != NULL) free(tmp_smooth); if (curved == LT_INTSPLINE && cntrlv != NULL) free(cntrlv); } PolygonPtr->n++; n++; AdjObjSplineVs(ObjPtr); if (curved != LT_INTSPLINE) { UpdPolyBBox(ObjPtr, PolygonPtr->n, PolygonPtr->vlist); } else { UpdPolyBBox(ObjPtr, PolygonPtr->intn, PolygonPtr->intvlist); } AdjObjBBox(ObjPtr); UpdSelBBox(); RedrawAreas(botObj, sel_ltx-GRID_ABS_SIZE(1), sel_lty-GRID_ABS_SIZE(1), sel_rbx+GRID_ABS_SIZE(1), sel_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(); SetFileModified(TRUE); justDupped = FALSE; } else if (input.type == KeyPress) { if (KeyPressEventIsEscape(&input.xkey)) { done = TRUE; *LastMouseX = new_mouse_x; *LastMouseY = new_mouse_y; if (curved == LT_INTSPLINE || smooth == NULL || !smooth[Index]) { MARK(drawWindow, revDefaultGC, OFFSET_X(tx), OFFSET_Y(ty)); } else { MARKO(drawWindow, revDefaultGC, OFFSET_X(tx), OFFSET_Y(ty)); } if (already_moved) { PixelToMeasurementUnit(w_buf, abs(ABS_X(v[1].x)-tx)); PixelToMeasurementUnit(h_buf, abs(ABS_Y(v[1].y)-ty)); PixelToMeasurementUnit(x_buf, ABS_X(v[1].x)); PixelToMeasurementUnit(y_buf, ABS_Y(v[1].y)); sprintf(buf, "ADD: dx=%s\n dy=%s\n x=%s\n y=%s", w_buf, h_buf, x_buf, y_buf); EndShowMeasureCursor(v[1].x, v[1].y, buf, FALSE); } else { PixelToMeasurementUnit(w_buf, 0); PixelToMeasurementUnit(h_buf, 0); PixelToMeasurementUnit(x_buf, tx); PixelToMeasurementUnit(y_buf, ty); sprintf(buf, "ADD: dx=%s\n dy=%s\n x=%s\n y=%s", w_buf, h_buf, x_buf, y_buf); StartShowMeasureCursor(OFFSET_X(x), OFFSET_Y(y), buf, FALSE); } if (already_moved) { if (splineRubberband) { XDrawLines(mainDisplay, drawWindow, revDefaultGC, sv, sn, CoordModeOrigin); } else { MyDashedLine(drawWindow, revDefaultGC, v, 3); } if (grid_x == orig_x && grid_y == orig_y) { return FALSE; } } return FALSE; } } } return TRUE; } void AddPoint() { int adding=TRUE, pt_added=FALSE, root_x, root_y, old_x, old_y; struct ObjRec *obj_ptr; struct PolyRec *poly_ptr=NULL; struct PolygonRec *polygon_ptr=NULL; unsigned int status; Window root_win, child_win; if (!(topSel != NULL && topSel == botSel && (topSel->obj->type == OBJ_POLY || topSel->obj->type == OBJ_POLYGON))) { MsgBox(TgLoadString(STID_SELECT_ONLY_ONE_POLY_POLYGON), TOOL_NAME, INFO_MB); return; } else if (topSel->obj->locked) { MsgBox(TgLoadString(STID_CANNOT_ADD_PT_FOR_LOCKED), TOOL_NAME, INFO_MB); return; } else if (AutoRetractedArrowAttr(topSel->obj, TRUE)) { MsgBox(TgLoadString(STID_CANNOT_ADD_PT_FOR_AUTO_ARROW), TOOL_NAME, INFO_MB); return; } if (curChoice == VERTEXMODE) { HighLightReverse(); JustRemoveAllVSel(); HighLightForward(); } PrepareToRecord(CMD_REPLACE, topSel, botSel, numObjSelected); obj_ptr = topSel->obj; switch (obj_ptr->type) { case OBJ_POLY: poly_ptr = obj_ptr->detail.p; break; case OBJ_POLYGON: polygon_ptr = obj_ptr->detail.g; break; } SaveStatusStrings(); SetMouseStatus(TgLoadCachedString(CSTID_ADD_A_VERTEX), TgLoadCachedString(CSTID_FINISH), TgLoadCachedString(CSTID_FINISH)); TwoLineMsg(TgLoadString(STID_LEFT_BTN_TO_ADD_PTS), TgLoadString(STID_CLICK_OTHER_BUTTON_TO_QUIT)); if (!debugNoPointerGrab) { XGrabPointer(mainDisplay, drawWindow, False, PointerMotionMask | ButtonPressMask | ButtonReleaseMask, GrabModeAsync, GrabModeAsync, None, defaultCursor, CurrentTime); } XQueryPointer(mainDisplay, drawWindow, &root_win, &child_win, &root_x, &root_y, &old_x, &old_y, &status); XSetFont(mainDisplay, revDefaultGC, defaultFontPtr->fid); /* do not translate -- program constants */ XDrawString(mainDisplay, drawWindow, revDefaultGC, old_x+4, old_y+defaultFontAsc, "ADD", 3); MarkRulers(old_x, old_y); while (adding) { XEvent input; XNextEvent(mainDisplay, &input); if (input.type == Expose || input.type == VisibilityNotify) { ExposeEventHandler(&input, TRUE); } else if (input.type == ButtonPress) { if (input.xbutton.button == Button1) { int index; XDrawString(mainDisplay, drawWindow, revDefaultGC, old_x+4, old_y+defaultFontAsc, "ADD", 3); if (obj_ptr->type == OBJ_POLY && PtInPolyMark(obj_ptr, input.xbutton.x, input.xbutton.y, poly_ptr->n, poly_ptr->vlist, &index)) { if (ContinueAddPolyPoint(obj_ptr, input.xbutton.x, input.xbutton.y, index, poly_ptr, &old_x, &old_y)) { pt_added = TRUE; } } else if (obj_ptr->type == OBJ_POLYGON && PtInPolyMark(obj_ptr, input.xbutton.x, input.xbutton.y, polygon_ptr->n-1, polygon_ptr->vlist, &index)) { if (ContinueAddPolygonPoint(obj_ptr, input.xbutton.x, input.xbutton.y, index, polygon_ptr, &old_x, &old_y)) { pt_added = TRUE; } } XDrawString(mainDisplay, drawWindow, revDefaultGC, old_x+4, old_y+defaultFontAsc, "ADD", 3); } else { XUngrabPointer(mainDisplay, CurrentTime); Msg(""); adding = FALSE; XDrawString(mainDisplay, drawWindow, revDefaultGC, old_x+4, old_y+defaultFontAsc, "ADD", 3); } } else if (input.type == MotionNotify) { XEvent ev; XDrawString(mainDisplay, drawWindow, revDefaultGC, old_x+4, old_y+defaultFontAsc, "ADD", 3); old_x = input.xmotion.x; old_y = input.xmotion.y; XDrawString(mainDisplay, drawWindow, revDefaultGC, old_x+4, old_y+defaultFontAsc, "ADD", 3); MarkRulers(old_x, old_y); while (XCheckMaskEvent(mainDisplay, PointerMotionMask, &ev)) ; } } RestoreStatusStrings(); if (pt_added) { RecordCmd(CMD_REPLACE, NULL, topSel, botSel, numObjSelected); } else { AbortPrepareCmd(CMD_REPLACE); } } void FlushUndoBuffer() { CleanUpMsg(); CleanUpCmds(); if (FlushColormap()) { Msg(TgLoadString(STID_UNDO_BUF_AND_CMAP_FLUSHED)); sprintf(gszMsgBox, TgLoadString(STID_NUM_COLORS_ALLOCATED), maxColors); Msg(gszMsgBox); } else { Msg(TgLoadString(STID_UNDO_BUF_FLUSHED)); } } void RestoreImageWH() { struct XBmRec *xbm_ptr=NULL; struct XPmRec *xpm_ptr=NULL; int w, h, image_w=0, image_h=0; int ltx, lty, rbx, rby; if (topSel == NULL) { MsgBox(TgLoadCachedString(CSTID_NO_OBJ_SELECTED), TOOL_NAME, INFO_MB); return; } else if (topSel != botSel || (!(topSel->obj->type==OBJ_XBM || topSel->obj->type==OBJ_XPM))) { MsgBox(TgLoadString(STID_SEL_ONE_XBM_OR_XPM_TO_RESTORE), TOOL_NAME, INFO_MB); return; } else if (topSel->obj->locked) { MsgBox(TgLoadString(STID_CANNOT_RESTORE_LOCKED), TOOL_NAME, INFO_MB); return; } w = topSel->obj->obbox.rbx - topSel->obj->obbox.ltx; h = topSel->obj->obbox.rby - topSel->obj->obbox.lty; switch (topSel->obj->type) { case OBJ_XBM: xbm_ptr = topSel->obj->detail.xbm; if (xbm_ptr->real_type==XBM_EPS && xbm_ptr->bitmap==None) { image_w = xbm_ptr->eps_w; image_h = xbm_ptr->eps_h; } else { image_w = xbm_ptr->image_w; image_h = xbm_ptr->image_h; } if (w == image_w && h == image_h) return; break; case OBJ_XPM: xpm_ptr = topSel->obj->detail.xpm; image_w = xpm_ptr->image_w; image_h = xpm_ptr->image_h; if (w == image_w && h == image_h) return; break; } ltx = selLtX; lty = selLtY; rbx = selRbX; rby = selRbY; HighLightReverse(); PrepareToReplaceAnObj(topSel->obj); if (topSel->obj->ctm == NULL) { topSel->obj->obbox.rbx = topSel->obj->obbox.ltx+image_w; topSel->obj->obbox.rby = topSel->obj->obbox.lty+image_h; } else { topSel->obj->obbox.rbx = topSel->obj->obbox.ltx+image_w; topSel->obj->obbox.rby = topSel->obj->obbox.lty+image_h; free(topSel->obj->ctm); topSel->obj->ctm = NULL; } topSel->obj->x = topSel->obj->obbox.ltx; topSel->obj->y = topSel->obj->obbox.lty; switch (topSel->obj->type) { case OBJ_XBM: if (xbm_ptr->cached_bitmap != None) { XFreePixmap(mainDisplay, xbm_ptr->cached_bitmap); } xbm_ptr->cached_bitmap = None; xbm_ptr->cached_zoom = 0; break; case OBJ_XPM: if (xpm_ptr->cached_pixmap != None) { XFreePixmap(mainDisplay, xpm_ptr->cached_pixmap); } xpm_ptr->cached_pixmap = None; if (xpm_ptr->cached_bitmap != None) { XFreePixmap(mainDisplay, xpm_ptr->cached_bitmap); } xpm_ptr->cached_bitmap = None; if (xpm_ptr->clip_mask != None) { XFreePixmap(mainDisplay, xpm_ptr->clip_mask); } xpm_ptr->clip_mask = None; xpm_ptr->cached_zoom = 0; xpm_ptr->cached_color = (-1); break; } AdjObjBBox(topSel->obj); RecordReplaceAnObj(topSel->obj); 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)); HighLightForward(); SetFileModified(TRUE); justDupped = FALSE; } void CutMaps() { if (topSel == NULL || topSel != botSel) { MsgBox(TgLoadString(STID_SEL_ONE_XBM_OR_XPM_TO_CUT), TOOL_NAME, INFO_MB); return; } else if (topSel->obj->locked) { MsgBox(TgLoadString(STID_CANNOT_CUT_LOCKED), TOOL_NAME, INFO_MB); return; } else if (topSel->obj->ctm != NULL) { MsgBox(TgLoadString(STID_CANNOT_CUT_TRANSFORMED_X_OBJ), TOOL_NAME, INFO_MB); return; } switch (topSel->obj->type) { case OBJ_XBM: CutXBitmap(); break; case OBJ_XPM: CutXPixmap(NULL, NULL, NULL, NULL); break; default: MsgBox(TgLoadString(STID_SEL_ONE_XBM_OR_XPM_TO_CUT), TOOL_NAME, INFO_MB); break; } } void BreakUpMaps() { int cols=0, rows=0, cols_and_rows=TRUE, ok=TRUE, image_w=0, image_h=0; char spec[MAXSTRING+1], *dup_spec=NULL, *part1=NULL, *part2=NULL; struct ObjRec *obj_ptr=NULL; if (topSel == NULL || topSel != botSel || (topSel->obj->type != OBJ_XBM && topSel->obj->type != OBJ_XPM)) { MsgBox(TgLoadString(STID_SEL_ONE_XBM_OR_XPM_TO_BREAKUP), TOOL_NAME, INFO_MB); return; } else if (topSel->obj->ctm != NULL) { MsgBox(TgLoadString(STID_CANNOT_BREAK_XFORMED_X_OBJ), TOOL_NAME, INFO_MB); return; } else if (topSel->obj->locked) { MsgBox(TgLoadString(STID_CANNOT_BREAKUP_LOCKED), TOOL_NAME, INFO_MB); return; } obj_ptr = topSel->obj; switch (obj_ptr->type) { case OBJ_XBM: image_w=obj_ptr->detail.xbm->image_w; image_h=obj_ptr->detail.xbm->image_h; break; case OBJ_XPM: image_w=obj_ptr->detail.xpm->image_w; image_h=obj_ptr->detail.xpm->image_h; break; default: return; } sprintf(gszMsgBox, TgLoadString(STID_ENTER_NUM_ROWCOL_TO_BREAK), image_w, image_h); *spec = '\0'; if (Dialog(gszMsgBox, TgLoadCachedString(CSTID_DLG_ACCEPT_CANCEL), spec) == INVALID) { return; } UtilTrimBlanks(spec); if (*spec == '\0') return; if ((dup_spec=UtilStrDup(spec)) == NULL) { FailAllocMessage(); return; } if (*dup_spec == '=') cols_and_rows = FALSE; /* do not translate -- program constants */ if ((part1=strtok(dup_spec, " ,xX=[]")) != NULL && (part2=strtok(NULL, " ,xX=[]")) != NULL) { cols = atoi(part1); rows = atoi(part2); if (cols > 0 && rows > 0) { switch (obj_ptr->type) { case OBJ_XBM: BreakUpXBitmap(obj_ptr, cols_and_rows, cols, rows); break; case OBJ_XPM: BreakUpXPixmap(obj_ptr, cols_and_rows, cols, rows); break; } } else { ok = FALSE; } } else { ok = FALSE; } if (!ok) { sprintf(gszMsgBox, TgLoadString(STID_INVALID_ROWCOL_SPEC_REENTER), dup_spec); MsgBox(gszMsgBox, TOOL_NAME, INFO_MB); } free(dup_spec); } /* ----------------------- LayoutOnArc ----------------------- */ typedef struct BoxInfoRec { struct ObjRec *obj; int w, h; int valid_v; double half_w, angle_in_radian, angle_to_rotate; XPoint v[5]; } *BoxInfoPtr; #define LAYOUT_DIR_NONE 0 #define LAYOUT_DIR_S 1 /* convex */ #define LAYOUT_DIR_N 2 /* concave */ int gnLayoutDirection=LAYOUT_DIR_NONE; static void RotateXY(x, y, angle_in_radian, new_x, new_y) int x, y; double angle_in_radian; short *new_x, *new_y; { if (x == 0 && y == 0) { *new_x = 0; *new_y = 0; } else { double sin_val = sin(angle_in_radian); double cos_val = cos(angle_in_radian); *new_x = (short)round(x*cos_val - y*sin_val); *new_y = (short)round(x*sin_val + y*cos_val); } } static void RotateBBoxByRadian(bbox, angle_in_radian, v) struct BBRec *bbox; double angle_in_radian; XPoint *v; /* array of 5 points */ { RotateXY(bbox->ltx, bbox->lty, angle_in_radian, &(v[0].x), &(v[0].y)); RotateXY(bbox->rbx, bbox->lty, angle_in_radian, &(v[1].x), &(v[1].y)); RotateXY(bbox->rbx, bbox->rby, angle_in_radian, &(v[2].x), &(v[2].y)); RotateXY(bbox->ltx, bbox->rby, angle_in_radian, &(v[3].x), &(v[3].y)); v[4].x = v[0].x; v[4].y = v[0].y; } #define SET_LAYOUT_VS (FALSE) #define FINALIZE_LAYOUT (TRUE) static int HighLightOrFinalLayout(arc_ptr, box_info_ptr, grid_x, grid_y, finalize) struct ArcRec *arc_ptr; struct BoxInfoRec *box_info_ptr; int grid_x, grid_y, finalize; { int i, num_objects=numObjSelected-1, circular=FALSE; int abs_cx, abs_cy, abs_x=ABS_X(grid_x), abs_y=ABS_Y(grid_y), dx, dy; double abs_radius, total_arc_radian, total_radian=0, inc_radian=0, angle; if (abs(arc_ptr->angle2) == (360<<6)) { circular = TRUE; } abs_cx = arc_ptr->xc; abs_cy = arc_ptr->yc; dx = abs_x - abs_cx; dy = abs_y - abs_cy; if (dx == 0 && dy == 0) { box_info_ptr[0].valid_v = FALSE; return FALSE; } box_info_ptr[0].valid_v = TRUE; total_arc_radian = ((double)arc_ptr->angle2)*M_PI/((double)180.0*64.0); abs_radius = (double)sqrt((double)(dx*dx+dy*dy)); for (i=0; i < num_objects; i++) { if (!finalize) { box_info_ptr[i].angle_in_radian = atan2(box_info_ptr[i].half_w, abs_radius) * ((double)2.0); } total_radian += fabs(box_info_ptr[i].angle_in_radian); } switch (gnLayoutDirection) { case LAYOUT_DIR_S: if (circular) { inc_radian = (total_arc_radian-total_radian)/((double)num_objects); } else { inc_radian = (total_arc_radian-total_radian)/((double)(num_objects-1)); } break; case LAYOUT_DIR_N: if (circular) { inc_radian = (total_arc_radian+total_radian)/((double)num_objects); } else { inc_radian = (total_arc_radian+total_radian)/((double)(num_objects-1)); } break; } angle = arc_ptr->angle1*M_PI/((double)180.0*64.0); for (i=0; i < num_objects; i++, angle+=inc_radian) { struct ObjRec *obj_ptr=box_info_ptr[i].obj; int x=0, y=0, w=0, h=0, orig_x=0, orig_y=0; XPoint v[5]; struct BBRec bbox; double half_way_angle=(double)0.0; w = box_info_ptr[i].w; h = box_info_ptr[i].h; if (finalize) { if (obj_ptr->type == OBJ_TEXT && obj_ptr->detail.t->minilines.just != JUST_C) { ChangeObjTextJust(obj_ptr, JUST_C); } } /* * half_way_angle measures angle in the arc sense (see the beginning * of "arc.c"). * the RoateaBBoxByRadian() rotates things in the drawing sense * (the one that's vertically flipped w.r.t. PostScript) */ switch (gnLayoutDirection) { case LAYOUT_DIR_S: half_way_angle = angle+(box_info_ptr[i].angle_in_radian/2.0); if (finalize) { orig_x = ((obj_ptr->obbox.rbx+obj_ptr->obbox.ltx)>>1); orig_y = obj_ptr->obbox.lty; RotateObjForLayout(obj_ptr, box_info_ptr[i].angle_to_rotate, CORNER_BOTTOM); x = abs_cx + (int)((abs_radius-h)*cos(half_way_angle)); y = abs_cy - (int)((abs_radius-h)*sin(half_way_angle)); } else { SetBBRec(&bbox, -(w>>1), -h, w-(w>>1), 0); box_info_ptr[i].angle_to_rotate = (-half_way_angle-(M_PI/2.0)); RotateBBoxByRadian(&bbox, box_info_ptr[i].angle_to_rotate, v); x = abs_cx + (int)(abs_radius*cos(half_way_angle)); y = abs_cy - (int)(abs_radius*sin(half_way_angle)); } break; case LAYOUT_DIR_N: half_way_angle = angle-(box_info_ptr[i].angle_in_radian/2.0); if (finalize) { orig_x = ((obj_ptr->obbox.rbx+obj_ptr->obbox.ltx)>>1); orig_y = obj_ptr->obbox.rby; RotateObjForLayout(obj_ptr, box_info_ptr[i].angle_to_rotate, CORNER_TOP); x = abs_cx + (int)((abs_radius-h)*cos(half_way_angle)); y = abs_cy - (int)((abs_radius-h)*sin(half_way_angle)); } else { SetBBRec(&bbox, -(w>>1), 0, w-(w>>1), h); box_info_ptr[i].angle_to_rotate = (-half_way_angle+(M_PI/2.0)); RotateBBoxByRadian(&bbox, box_info_ptr[i].angle_to_rotate, v); x = abs_cx + (int)(abs_radius*cos(half_way_angle)); y = abs_cy - (int)(abs_radius*sin(half_way_angle)); } break; } if (finalize) { MoveObj(obj_ptr, x-orig_x, y-orig_y); } else { box_info_ptr[i].v[0].x = OFFSET_X(x + v[0].x); box_info_ptr[i].v[0].y = OFFSET_Y(y + v[0].y); box_info_ptr[i].v[1].x = OFFSET_X(x + v[1].x); box_info_ptr[i].v[1].y = OFFSET_Y(y + v[1].y); box_info_ptr[i].v[2].x = OFFSET_X(x + v[2].x); box_info_ptr[i].v[2].y = OFFSET_Y(y + v[2].y); box_info_ptr[i].v[3].x = OFFSET_X(x + v[3].x); box_info_ptr[i].v[3].y = OFFSET_Y(y + v[3].y); box_info_ptr[i].v[4].x = box_info_ptr[i].v[0].x; box_info_ptr[i].v[4].y = box_info_ptr[i].v[0].y; } switch (gnLayoutDirection) { case LAYOUT_DIR_S: angle += box_info_ptr[i].angle_in_radian; break; case LAYOUT_DIR_N: angle -= box_info_ptr[i].angle_in_radian; break; } } return TRUE; } #define NO_GENERATE 0 #define GENERATE 1 static void HighLightLayout(arc_ptr, box_info_ptr, grid_x, grid_y, generate) struct ArcRec *arc_ptr; struct BoxInfoRec *box_info_ptr; int grid_x, grid_y, generate; { int i, num_objects=numObjSelected-1; if (generate) { HighLightOrFinalLayout(arc_ptr, box_info_ptr, grid_x, grid_y, SET_LAYOUT_VS); } if (box_info_ptr[0].valid_v) { for (i=0; i < num_objects; i++) { XDrawLines(mainDisplay, drawWindow, revDefaultGC, box_info_ptr[i].v, 5, CoordModeOrigin); } } } static void DoLayoutOnArc(arc_obj, box_info_ptr) struct ObjRec *arc_obj; struct BoxInfoRec *box_info_ptr; { struct ArcRec *arc_ptr=arc_obj->detail.a; int done=FALSE, something_changed=FALSE, grid_x=0, grid_y=0; SetMouseStatus(TgLoadCachedString(CSTID_START_LAYOUT_ON_ARC), TgLoadCachedString(CSTID_FINISH), TgLoadCachedString(CSTID_FINISH)); if (!debugNoPointerGrab) { XGrabPointer(mainDisplay, drawWindow, FALSE, PointerMotionMask | ButtonPressMask | ButtonReleaseMask, GrabModeAsync, GrabModeAsync, None, handCursor, CurrentTime); } while (!done) { XEvent input; XNextEvent(mainDisplay, &input); switch (input.type) { case Expose: ExposeEventHandler(&input, TRUE); break; case VisibilityNotify: ExposeEventHandler(&input, TRUE); break; case ButtonPress: if (input.xbutton.button == Button1) { SetMouseStatus(TgLoadCachedString(CSTID_END_LAYOUT_ON_ARC), "", ""); GridXY(input.xbutton.x, input.xbutton.y, &grid_x, &grid_y); HighLightLayout(arc_ptr, box_info_ptr, grid_x, grid_y, GENERATE); something_changed = TRUE; } else { XUngrabPointer(mainDisplay, CurrentTime); XSync(mainDisplay, False); done = TRUE; } break; case MotionNotify: if (something_changed) { HighLightLayout(arc_ptr, box_info_ptr, grid_x, grid_y, NO_GENERATE); GridXY(input.xmotion.x, input.xmotion.y, &grid_x, &grid_y); HighLightLayout(arc_ptr, box_info_ptr, grid_x, grid_y, GENERATE); } break; case ButtonRelease: XUngrabPointer(mainDisplay, CurrentTime); XSync(mainDisplay, False); done = TRUE; HighLightLayout(arc_ptr, box_info_ptr, grid_x, grid_y, NO_GENERATE); } } if (something_changed && box_info_ptr[0].valid_v) { int ltx=selLtX, lty=selLtY, rbx=selRbX, rby=selRbY; HighLightReverse(); PrepareToRecord(CMD_REPLACE, topSel, botSel, numObjSelected); if (HighLightOrFinalLayout(arc_ptr, box_info_ptr, grid_x, grid_y, FINALIZE_LAYOUT)) { RecordCmd(CMD_REPLACE, NULL, topSel, botSel, numObjSelected); 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)); SetFileModified(TRUE); justDupped = FALSE; } else { AbortPrepareCmd(CMD_REPLACE); } HighLightForward(); } } static int ObjsAlreadySorted(box_info_ptr, min_index, max_index) struct BoxInfoRec *box_info_ptr; int min_index, max_index; { int i; for (i=min_index; i < max_index; i++) { int d=box_info_ptr[i].obj->obbox.ltx-box_info_ptr[i+1].obj->obbox.ltx; if (d > 0) { return FALSE; } else if (d == 0 && box_info_ptr[i].obj->obbox.lty > box_info_ptr[i+1].obj->obbox.lty) { return FALSE; } } return TRUE; } static void QuickSortObjs(box_info_ptr, min_index, max_index, level) struct BoxInfoRec *box_info_ptr; int min_index, max_index, level; { int i, j, pivot_index, pivot_x_value, pivot_y_value, something_swapped; struct ObjRec *tmp_obj; if (min_index > max_index) return; if (ObjsAlreadySorted(box_info_ptr, min_index, max_index)) return; pivot_index = max_index; pivot_x_value = box_info_ptr[pivot_index].obj->obbox.ltx; pivot_y_value = box_info_ptr[pivot_index].obj->obbox.lty; i = min_index; j = max_index-1; something_swapped = FALSE; do { int d; while (TRUE) { d = box_info_ptr[i].obj->obbox.ltx-pivot_x_value; if (d < 0 || (d == 0 && box_info_ptr[i].obj->obbox.lty < pivot_y_value)) { i++; } else { break; } } while (j > i) { d = box_info_ptr[j].obj->obbox.ltx-pivot_x_value; if (d > 0 || (d == 0 && box_info_ptr[j].obj->obbox.lty > pivot_y_value)) { j--; } else { break; } } if (j > i) { tmp_obj = box_info_ptr[j].obj; box_info_ptr[j].obj = box_info_ptr[i].obj; box_info_ptr[i].obj = tmp_obj; something_swapped = TRUE; if (j == i+1) break; i++; j--; } else { break; } } while (TRUE); if (i == max_index) { /* pivot corresponds to the largest */ if (something_swapped) { #ifdef _TGIF_DBG /* debug, do not translate */ fprintf(stderr, "Huh? min_index=%1d, max_index=%1d, level=%1d\n", min_index, max_index, level); #endif /* _TGIF_DBG */ } else { QuickSortObjs(box_info_ptr, min_index, j, level+1); } } else if (j > i) { tmp_obj = box_info_ptr[max_index].obj; box_info_ptr[max_index].obj = box_info_ptr[j].obj; box_info_ptr[j].obj = tmp_obj; QuickSortObjs(box_info_ptr, min_index, j-1, level+1); QuickSortObjs(box_info_ptr, j+1, max_index, level+1); } else { tmp_obj = box_info_ptr[max_index].obj; box_info_ptr[max_index].obj = box_info_ptr[i].obj; box_info_ptr[i].obj = tmp_obj; QuickSortObjs(box_info_ptr, min_index, i-1, level+1); QuickSortObjs(box_info_ptr, i+1, max_index, level+1); } } static int DecideLayoutDirection(obj_ptr) struct ObjRec *obj_ptr; { struct ArcRec *arc_ptr=obj_ptr->detail.a; struct BBRec *p_obbox=(&obj_ptr->obbox); int cx=arc_ptr->xc, cy=arc_ptr->yc, h_slack, v_slack; char spec[MAXSTRING+1]; h_slack = ((p_obbox->ltx+p_obbox->rbx)>>1) - cx; v_slack = ((p_obbox->lty+p_obbox->rby)>>1) - cy; if (h_slack == 0) { if (v_slack == 0) { return LAYOUT_DIR_S; } else if (v_slack > 0) { return LAYOUT_DIR_S; } else { return LAYOUT_DIR_N; } } *spec = '\0'; if (Dialog(TgLoadString(STID_ENTER_CONCAVE_OR_CONVEX), NULL, spec) == INVALID) { return LAYOUT_DIR_NONE; } UtilTrimBlanks(spec); /* do not translate -- program constants */ if (UtilStrICmp(spec, "concave") == 0) { return LAYOUT_DIR_N; } else if (UtilStrICmp(spec, "convex") == 0) { return LAYOUT_DIR_S; } else { switch (*spec) { case 'c': case 'C': return LAYOUT_DIR_N; case 'v': case 'V': return LAYOUT_DIR_S; } } sprintf(gszMsgBox, TgLoadString(STID_INVALID_SPEC), spec); MsgBox(gszMsgBox, TOOL_NAME, INFO_MB); return LAYOUT_DIR_NONE; } void LayoutOnArc() { struct SelRec *sel_ptr; struct ObjRec *arc_obj=NULL; int arc_obj_count=0, i, something_locked=FALSE; struct BoxInfoRec *box_info_ptr; if (curChoice != NOTHING) { MsgBox(TgLoadString(STID_SEL_AN_ARC_OBJ), TOOL_NAME, INFO_MB); return; } for (sel_ptr=topSel; sel_ptr != NULL; sel_ptr=sel_ptr->next) { struct ObjRec *obj_ptr=sel_ptr->obj; if (obj_ptr->type == OBJ_ARC) { arc_obj_count++; arc_obj = obj_ptr; } else if (obj_ptr->locked) { something_locked = TRUE; } } if (arc_obj_count == 0) { MsgBox(TgLoadString(STID_NO_ARC_OBJ_SELECTED), TOOL_NAME, INFO_MB); return; } else if (arc_obj_count > 1) { MsgBox(TgLoadString(STID_TOO_MANY_ARC_SEL_ONLY_ONE_ARC), TOOL_NAME, INFO_MB); return; } else if (numObjSelected == 1) { MsgBox(TgLoadString(STID_NO_OTHER_OBJ_FOR_LAYOUTONARC), TOOL_NAME, INFO_MB); return; } else if (something_locked) { MsgBox(TgLoadString(STID_CANNOT_LAYOUTONARC_LOCKED), TOOL_NAME, INFO_MB); return; } if (arc_obj->ctm != NULL || arc_obj->detail.a->w != arc_obj->detail.a->h) { MsgBox(TgLoadString(STID_ARC_XFORMED_FOR_LAYOUTONARC), TOOL_NAME, INFO_MB); return; } gnLayoutDirection = DecideLayoutDirection(arc_obj); if (gnLayoutDirection == LAYOUT_DIR_NONE) { return; } box_info_ptr = (struct BoxInfoRec *)malloc( (numObjSelected-1)*sizeof(struct BoxInfoRec)); if (box_info_ptr == NULL) { FailAllocMessage(); return; } for (i=0, sel_ptr=topSel; sel_ptr != NULL; sel_ptr=sel_ptr->next) { struct ObjRec *obj_ptr=sel_ptr->obj; if (obj_ptr->type != OBJ_ARC) { box_info_ptr[i].obj = obj_ptr; i++; } } QuickSortObjs(box_info_ptr, 0, numObjSelected-2, 0); for (i=0; i < numObjSelected-1; i++) { struct ObjRec *obj_ptr=box_info_ptr[i].obj; box_info_ptr[i].w = obj_ptr->obbox.rbx-obj_ptr->obbox.ltx; box_info_ptr[i].h = obj_ptr->obbox.rby-obj_ptr->obbox.lty; box_info_ptr[i].half_w = (double)(box_info_ptr[i].w>>1); box_info_ptr[i].valid_v = FALSE; } SaveStatusStrings(); DoLayoutOnArc(arc_obj, box_info_ptr); RestoreStatusStrings(); free(box_info_ptr); } /* ----------------------- PreciseRotate ----------------------- */ static int FinishPreciseRotate(angle_spec, pivot_x, pivot_y) double angle_spec; int pivot_x, pivot_y; { struct SelRec *sel_ptr; double angle_in_radian=angle_spec*M_PI/180.0; double sin_val=sin(angle_in_radian); double cos_val=cos(angle_in_radian); for (sel_ptr=topSel; sel_ptr != NULL; sel_ptr=sel_ptr->next) { struct ObjRec *obj_ptr=sel_ptr->obj; int orig_x=((obj_ptr->obbox.ltx+obj_ptr->obbox.rbx)>>1); int orig_y=obj_ptr->obbox.lty; int x=0, y=0, dx=orig_x-pivot_x, dy=orig_y-pivot_y; if (dx != 0 || dy != 0) { x = (short)round(dx*cos_val - dy*sin_val); y = (short)round(dx*sin_val + dy*cos_val); } x += pivot_x; y += pivot_y; /* RotateObjForLayout() rotates about center-top */ RotateObjForLayout(obj_ptr, angle_in_radian, CORNER_BOTTOM); MoveObj(obj_ptr, x-orig_x, y-orig_y); } return TRUE; } void PreciseRotate() { char spec[MAXSTRING+1]; double angle_spec; int arc_count=0, pivot_x=0, pivot_y=0, ltx, lty, rbx, rby; struct SelRec *sel_ptr; struct ObjRec *arc_obj=NULL; if (curChoice == VERTEXMODE) { MsgBox(TgLoadString(STID_ROT_NOT_AVAIL_ON_VERTEX_MODE), TOOL_NAME, INFO_MB); return; } else if (curChoice != NOTHING || topSel == NULL) { MsgBox(TgLoadCachedString(CSTID_NO_OBJ_SELECTED), TOOL_NAME, INFO_MB); return; } for (sel_ptr=topSel; sel_ptr != NULL; sel_ptr=sel_ptr->next) { if (sel_ptr->obj->type == OBJ_ARC) { arc_obj = sel_ptr->obj; arc_count++; } } if (arc_count == 1) { if (arc_obj->ctm == NULL) { pivot_x = arc_obj->detail.a->xc; pivot_y = arc_obj->detail.a->yc; } else { struct ArcRec *arc_ptr=arc_obj->detail.a; int x, y; TransformPointThroughCTM(arc_ptr->xc-arc_obj->x, arc_ptr->yc-arc_obj->y, arc_obj->ctm, &x, &y); pivot_x = x + arc_obj->x; pivot_y = y + arc_obj->y; } } else { pivot_x = (selObjLtX+selObjRbX)>>1; pivot_y = (selObjLtY+selObjRbY)>>1; } *spec = '\0'; Dialog(TgLoadString(STID_ENTER_AN_ANGLE_IN_DEGREES), NULL, spec); UtilTrimBlanks(spec); if (*spec == '\0') return; if (sscanf(spec, "%lf", &angle_spec) != 1) { sprintf(gszMsgBox, TgLoadString(STID_INVALID_SPEC_NUM_EXPECTED), spec); MsgBox(gszMsgBox, TOOL_NAME, INFO_MB); return; } if (fabs(angle_spec) < (1.0e-5)) return; ltx = selLtX; lty = selLtY; rbx = selRbX; rby = selRbY; HighLightReverse(); PrepareToRecord(CMD_REPLACE, topSel, botSel, numObjSelected); if (FinishPreciseRotate(angle_spec, pivot_x, pivot_y)) { RecordCmd(CMD_REPLACE, NULL, topSel, botSel, numObjSelected); 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)); SetFileModified(TRUE); justDupped = FALSE; } else { AbortPrepareCmd(CMD_REPLACE); } HighLightForward(); } void RotateAllSelObj(angle_spec) double angle_spec; { int arc_count=0, pivot_x=0, pivot_y=0, ltx, lty, rbx, rby; struct SelRec *sel_ptr; struct ObjRec *arc_obj=NULL; if (curChoice != NOTHING || topSel == NULL) { MsgBox(TgLoadCachedString(CSTID_NO_OBJ_SELECTED), TOOL_NAME, INFO_MB); return; } for (sel_ptr=topSel; sel_ptr != NULL; sel_ptr=sel_ptr->next) { if (sel_ptr->obj->type == OBJ_ARC) { arc_obj = sel_ptr->obj; arc_count++; } } if (arc_count == 1) { if (arc_obj->ctm == NULL) { pivot_x = arc_obj->detail.a->xc; pivot_y = arc_obj->detail.a->yc; } else { struct ArcRec *arc_ptr=arc_obj->detail.a; int x, y; TransformPointThroughCTM(arc_ptr->xc-arc_obj->x, arc_ptr->yc-arc_obj->y, arc_obj->ctm, &x, &y); pivot_x = x + arc_obj->x; pivot_y = y + arc_obj->y; } } else { pivot_x = (selObjLtX+selObjRbX)>>1; pivot_y = (selObjLtY+selObjRbY)>>1; } if (fabs(angle_spec) < (1.0e-5)) return; ltx = selLtX; lty = selLtY; rbx = selRbX; rby = selRbY; HighLightReverse(); PrepareToRecord(CMD_REPLACE, topSel, botSel, numObjSelected); FinishPreciseRotate(angle_spec, pivot_x, pivot_y); RecordCmd(CMD_REPLACE, NULL, topSel, botSel, numObjSelected); 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)); HighLightForward(); SetFileModified(TRUE); justDupped = FALSE; } void NoTransform() { struct SelRec *sel_ptr; int changed=FALSE, grouped=FALSE; int ltx=selLtX, lty=selLtY, rbx=selRbX, rby=selRbY; if (topSel == NULL) { MsgBox(TgLoadCachedString(CSTID_NO_OBJ_SELECTED), TOOL_NAME, INFO_MB); return; } HighLightReverse(); StartCompositeCmd(); for (sel_ptr=topSel; sel_ptr != NULL; sel_ptr=sel_ptr->next) { struct ObjRec *obj_ptr=sel_ptr->obj; if (obj_ptr->ctm != NULL) { int cx=0, cy=0; switch (obj_ptr->type) { case OBJ_GROUP: case OBJ_SYM: case OBJ_ICON: case OBJ_PIN: grouped = TRUE; break; default: cx = ((obj_ptr->obbox.ltx+obj_ptr->obbox.rbx)>>1); cy = ((obj_ptr->obbox.lty+obj_ptr->obbox.rby)>>1); changed = TRUE; PrepareToReplaceAnObj(obj_ptr); free(obj_ptr->ctm); obj_ptr->ctm = NULL; memcpy(&obj_ptr->obbox, &obj_ptr->orig_obbox, sizeof(struct BBRec)); if (obj_ptr->type == OBJ_TEXT) { memcpy(&obj_ptr->bbox, &obj_ptr->detail.t->orig_bbox, sizeof(struct BBRec)); } AdjObjSplineVs(obj_ptr); AdjObjCache(obj_ptr); AdjObjBBox(obj_ptr); MoveObj(obj_ptr, cx-((obj_ptr->obbox.ltx+obj_ptr->obbox.rbx)>>1), cy-((obj_ptr->obbox.lty+obj_ptr->obbox.rby)>>1)); RecordReplaceAnObj(obj_ptr); break; } } else { switch (obj_ptr->type) { case OBJ_GROUP: case OBJ_SYM: case OBJ_ICON: case OBJ_PIN: grouped = TRUE; break; default: break; } } } EndCompositeCmd(); if (changed) { 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)); HighLightForward(); SetFileModified(TRUE); justDupped = FALSE; if (grouped) { Msg(TgLoadString(STID_SOME_GROUP_OBJ_NOT_MODIFIED)); } } else { if (grouped) { MsgBox(TgLoadString(STID_CANNOT_REM_XFORM_FOR_GROUPED), TOOL_NAME, INFO_MB); } HighLightForward(); } } void SetEditTextSize() { char spec[MAXSTRING+1]; int size=0; MakeQuiescent(); *spec = '\0'; sprintf(gszMsgBox, TgLoadString(STID_ENTER_EDIT_TEXT_SIZE), editTextSize); *spec = '\0'; Dialog(gszMsgBox, NULL, spec); UtilTrimBlanks(spec); if (*spec == '\0') return; size = atoi(spec); if (size != 0 && (size < 4 || size > 34)) { sprintf(gszMsgBox, TgLoadString(STID_EDIT_TEXT_SIZE_OUT_OF_RANGE), spec); MsgBox(gszMsgBox, TOOL_NAME, INFO_MB); } else { SetEditTextSizeValue(size); if (editTextSize == 0) { Msg(TgLoadString(STID_ACTUAL_EDIT_TEXT_SIZE)); } else { sprintf(gszMsgBox, TgLoadString(STID_USE_SPECIFIED_EDIT_TEXT_SIZE), editTextSize); Msg(gszMsgBox); } } } static void UpdateOuterInnerSelForFind(obj_ptr) struct ObjRec *obj_ptr; /* outerSel is at the top of the chain and innerSel is at the bottom */ { AddObjIntoSel(obj_ptr, NULL, outerSelForFind, &outerSelForFind, &innerSelForFind); } static struct ObjRec *DoFind(obj_ptr) struct ObjRec *obj_ptr; { int found_starting_point=TRUE; MiniLinesInfo *minilines=NULL; struct ObjRec *ptr=NULL; struct ObjRec *return_obj=NULL; if (obj_ptr->type != OBJ_TEXT) { struct AttrRec *attr_ptr; for (attr_ptr=obj_ptr->fattr; attr_ptr != NULL; attr_ptr=attr_ptr->next) { if (attr_ptr->shown) { return_obj = DoFind(attr_ptr->obj); if (return_obj != NULL) { return return_obj; } } } } switch (obj_ptr->type) { case OBJ_SYM: case OBJ_GROUP: case OBJ_ICON: for (ptr=obj_ptr->detail.r->last; ptr != NULL; ptr=ptr->prev) { ptr->tmp_parent = obj_ptr; return_obj = DoFind(ptr); if (return_obj != NULL) { UpdateOuterInnerSelForFind(obj_ptr); return return_obj; } } break; case OBJ_PIN: ptr = GetPinObj(obj_ptr); ptr->tmp_parent = obj_ptr; return_obj = DoFind(ptr); if (return_obj != NULL) { return return_obj; } break; case OBJ_TEXT: found_starting_point = TRUE; minilines = (&obj_ptr->detail.t->minilines); SaveCursorPositionInCurText(); curStrBlock = minilines->first->first_block; textCurIndex = 0; ResetOnCursorKey(FALSE); SetTextHighlight(); UpdatePinnedMenu(MENU_EDIT); if (FindStringInMiniLines(minilines, &found_starting_point, gpszSearch, gnSearchLen, gnSearchCaseSensitive, &gpFoundStartStrBlock, &gnFoundStartCharIndex, &gpFoundEndStrBlock, &gnFoundEndCharIndex)) { return obj_ptr; } RestoreCursorPositionInCurText(); break; default: break; } return NULL; } static int gnFoundStartingPoint=FALSE; static struct ObjRec *DoFindAlready(obj_ptr, bottom_half, pn_give_up) struct ObjRec *obj_ptr; int bottom_half; /* TRUE if searching from curTextObj to topObj */ int *pn_give_up; { struct ObjRec *ptr=NULL; struct ObjRec *return_obj=NULL; if (obj_ptr->type != OBJ_TEXT) { struct AttrRec *attr_ptr; for (attr_ptr=obj_ptr->fattr; attr_ptr != NULL; attr_ptr=attr_ptr->next) { if (attr_ptr->shown) { return_obj = DoFindAlready(attr_ptr->obj, bottom_half, pn_give_up); if (return_obj != NULL) { return return_obj; } if (pn_give_up != NULL && *pn_give_up) { return NULL; } } } } switch (obj_ptr->type) { case OBJ_SYM: case OBJ_GROUP: case OBJ_ICON: for (ptr=obj_ptr->detail.r->last; ptr != NULL; ptr=ptr->prev) { ptr->tmp_parent = obj_ptr; return_obj = DoFindAlready(ptr, bottom_half, pn_give_up); if (return_obj != NULL) { UpdateOuterInnerSelForFind(obj_ptr); return return_obj; } if (pn_give_up != NULL && *pn_give_up) { return NULL; } } break; case OBJ_PIN: ptr = GetPinObj(obj_ptr); ptr->tmp_parent = obj_ptr; return_obj = DoFindAlready(ptr, bottom_half, pn_give_up); if (return_obj != NULL) { return return_obj; } if (pn_give_up != NULL && *pn_give_up) { return NULL; } break; case OBJ_TEXT: if ((bottom_half && gnFoundStartingPoint) || (!bottom_half && obj_ptr != curTextObj)) { int found_starting_point=TRUE; MiniLinesInfo *minilines=(&obj_ptr->detail.t->minilines); SaveCursorPositionInCurText(); curStrBlock = minilines->first->first_block; textCurIndex = 0; ResetOnCursorKey(FALSE); SetTextHighlight(); UpdatePinnedMenu(MENU_EDIT); if (FindStringInMiniLines(minilines, &found_starting_point, gpszSearch, gnSearchLen, gnSearchCaseSensitive, &gpFoundStartStrBlock, &gnFoundStartCharIndex, &gpFoundEndStrBlock, &gnFoundEndCharIndex)) { return obj_ptr; } RestoreCursorPositionInCurText(); } else if (bottom_half) { if (obj_ptr == curTextObj) { gnFoundStartingPoint = TRUE; } } else { if (obj_ptr == curTextObj) { if (pn_give_up != NULL) *pn_give_up = TRUE; } } break; default: break; } return NULL; } static void Find() { int wrapped=FALSE; struct ObjRec *obj_ptr=NULL; struct ObjRec *found_obj=NULL; CleanOuterInnerSelForFind(); UpdatePinnedMenu(MENU_EDIT); if (gpszSearch == NULL) return; gnSearchLen = strlen(gpszSearch); gnFoundStartCharIndex = 0; gpFoundStartStrBlock = NULL; SetWatchCursor(drawWindow); SetWatchCursor(mainWindow); if (curChoice == DRAWTEXT) { if (curTextObj != NULL && FindTextInCurTextObj(gpszSearch, gnSearchLen, gnSearchCaseSensitive, &gpFoundStartStrBlock, &gnFoundStartCharIndex, &gpFoundEndStrBlock, &gnFoundEndCharIndex)) { found_obj = curTextObj; CopyOuterSelToOuterSelForFind(); } if (found_obj == NULL) { gnFoundStartingPoint = FALSE; for (obj_ptr=botObj; obj_ptr != NULL; obj_ptr=obj_ptr->prev) { obj_ptr->tmp_parent = NULL; if (!ObjInVisibleLayer(obj_ptr)) { continue; } found_obj = DoFindAlready(obj_ptr, TRUE, NULL); if (found_obj != NULL) { break; } } if (found_obj == NULL && gnFoundStartingPoint) { wrapped = TRUE; for (obj_ptr=botObj; obj_ptr != NULL; obj_ptr=obj_ptr->prev) { int give_up=FALSE; obj_ptr->tmp_parent = NULL; if (!ObjInVisibleLayer(obj_ptr)) { continue; } found_obj = DoFindAlready(obj_ptr, FALSE, &give_up); if (found_obj != NULL) { break; } if (give_up) { break; } } } } } if (found_obj == NULL) { if (curChoice == DRAWTEXT) { wrapped = TRUE; } for (obj_ptr=botObj; obj_ptr != NULL; obj_ptr=obj_ptr->prev) { obj_ptr->tmp_parent = NULL; if (!ObjInVisibleLayer(obj_ptr)) { continue; } found_obj = DoFind(obj_ptr); if (found_obj != NULL) { break; } } if (found_obj != NULL) { if (curChoice != DRAWTEXT) { SetCurChoice(DRAWTEXT); } } } SetDefaultCursor(mainWindow); ShowCursor(); if (found_obj == NULL) { sprintf(gszMsgBox, TgLoadString(STID_CANNOT_FIND_NAMED_STRING), gpszSearch); MsgBox(gszMsgBox, TOOL_NAME, INFO_MB); } else { HighLightText(found_obj, gpFoundStartStrBlock, gnFoundStartCharIndex, gpFoundEndStrBlock, gnFoundEndCharIndex); if (wrapped) { Msg(TgLoadString(STID_FIND_CMD_WRAPPED)); } } } void FindCaseSensitive() { char spec[MAXSTRING]; *spec = '\0'; Dialog(TgLoadString(STID_ENTER_CASE_STR_TO_FIND), NULL, spec); if (*spec == '\0') { return; } if (gpszSearch != NULL) free(gpszSearch); if ((gpszSearch=UtilStrDup(spec)) == NULL) FailAllocMessage(); gnSearchCaseSensitive = TRUE; if (curChoice != DRAWTEXT) { MakeQuiescent(); } Find(); } void FindNoCase() { char spec[MAXSTRING]; *spec = '\0'; Dialog(TgLoadString(STID_ENTER_NOCASE_STR_TO_FIND), NULL, spec); if (*spec == '\0') { return; } if (gpszSearch != NULL) free(gpszSearch); if ((gpszSearch=UtilStrDup(spec)) == NULL) FailAllocMessage(); gnSearchCaseSensitive = FALSE; if (curChoice != DRAWTEXT) { MakeQuiescent(); } Find(); } void FindAgain() { if (gpszSearch == NULL) { MsgBox(TgLoadString(STID_NO_PREVIOUS_FIND), TOOL_NAME, INFO_MB); } else { Find(); } } /* ----------------------- EditMenu ----------------------- */ int RefreshEditMenu(menu) TgMenu *menu; { int ok=TRUE; /* CopyPlainTextAsObject */ ok &= TgEnableMenuItemById(menu, CMDID_COPYPLAINTEXTASOBJECT, (curChoice == DRAWTEXT && textHighlight && CanCopyHighLightedTextAsStrings())); /* ImageProc submenu */ ok &= TgEnableMenuItemById(menu, MENU_IMAGEPROC, CanPerformImageProc()); /* FindAgain */ ok &= TgEnableMenuItemById(menu, CMDID_FINDAGAIN, (gpszSearch != NULL)); return ok; } TgMenu *CreateEditMenu(parent_menu, x, y, menu_info, status_str_xlated) TgMenu *parent_menu; int x, y; TgMenuInfo *menu_info; int status_str_xlated; /* ignored, always 0 */ { TgMenu *menu=TgCreateMenuFromMenuInfo(parent_menu, x, y, menu_info, FALSE); if (menu != NULL) { if (!RefreshEditMenu(menu)) { return TgDestroyMenu(menu, TRUE); } menu->refresh_proc = ((RefreshMenuFunc*)RefreshEditMenu); } return menu; } int EditMenu(X, Y, TrackMenubar) int X, Y, TrackMenubar; { int rc=INVALID; TgMenu *menu=(editMenuInfo.create_proc)(NULL, X, Y, &editMenuInfo, INVALID); activeMenu = MENU_EDIT; if (menu != NULL) { menu->track_menubar = TrackMenubar; rc = TgMenuLoop(menu); TgDestroyMenu(menu, TRUE); } return rc; } /* ======================= ArrangeMenu Related ======================= */ void FrontProc() { if (topSel != NULL) { HighLightReverse(); MoveSelToTop(); RedrawAnArea(botObj, selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1), selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1)); HighLightForward(); SetFileModified(TRUE); } } void BackProc() { if (topSel != NULL) { HighLightReverse(); MoveSelToBot(); RedrawAnArea(botObj, selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1), selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1)); HighLightForward(); SetFileModified(TRUE); } } void AlignObjsTop() { register int saved_h_align = horiAlign, saved_v_align = vertAlign; horiAlign = ALIGN_N; vertAlign = ALIGN_T; AlignSelObjs(); horiAlign = saved_h_align; vertAlign = saved_v_align; } void AlignObjsMiddle() { register int saved_h_align = horiAlign, saved_v_align = vertAlign; horiAlign = ALIGN_N; vertAlign = ALIGN_M; AlignSelObjs(); horiAlign = saved_h_align; vertAlign = saved_v_align; } void AlignObjsBottom() { register int saved_h_align = horiAlign, saved_v_align = vertAlign; horiAlign = ALIGN_N; vertAlign = ALIGN_B; AlignSelObjs(); horiAlign = saved_h_align; vertAlign = saved_v_align; } void AlignObjsLeft() { register int saved_h_align = horiAlign, saved_v_align = vertAlign; horiAlign = ALIGN_L; vertAlign = ALIGN_N; AlignSelObjs(); horiAlign = saved_h_align; vertAlign = saved_v_align; } void AlignObjsCenter() { register int saved_h_align = horiAlign, saved_v_align = vertAlign; horiAlign = ALIGN_C; vertAlign = ALIGN_N; AlignSelObjs(); horiAlign = saved_h_align; vertAlign = saved_v_align; } void AlignObjsRight() { register int saved_h_align = horiAlign, saved_v_align = vertAlign; horiAlign = ALIGN_R; vertAlign = ALIGN_N; AlignSelObjs(); horiAlign = saved_h_align; vertAlign = saved_v_align; } static void Abut(Dir) int Dir; { struct ObjRec *obj_ptr=NULL; struct SelRec *sel_ptr=NULL; struct SelRec *top_sort=NULL, *bot_sort=NULL, *sort_ptr=NULL; struct SelRec *new_sort_ptr=NULL, *tmp_sel_ptr=NULL, *next_sort=NULL; struct ObjRec *sorted_obj=NULL, *locked_obj=NULL; struct SubCmdRec *sub_cmd=NULL; int sel_ltx=0, sel_lty=0, sel_rbx=0, sel_rby=0, rbx=0, rby=0; int found=FALSE, delta=0, dx=0, dy=0; if (topSel == NULL) { MsgBox(TgLoadCachedString(CSTID_NO_OBJ_SELECTED), TOOL_NAME, INFO_MB); return; } else if (curChoice == VERTEXMODE) { MsgBox(TgLoadString(STID_CANNOT_ABUT_IN_VERTEX_MODE), TOOL_NAME, INFO_MB); return; } else if (numObjLocked > 1) { MsgBox(TgLoadString(STID_CANNOT_ABUT_LOCKED), TOOL_NAME, INFO_MB); return; } HighLightReverse(); StartCompositeCmd(); sel_ltx = selLtX; sel_lty = selLtY; sel_rbx = selRbX; sel_rby = selRbY; top_sort = (struct SelRec *)malloc(sizeof(struct SelRec)); if (top_sort == NULL) FailAllocMessage(); top_sort->next = top_sort->prev = NULL; top_sort->obj = sorted_obj = botSel->obj; if (botSel->obj->locked) locked_obj = botSel->obj; for (sel_ptr=botSel->prev; sel_ptr != NULL; sel_ptr=sel_ptr->prev) { obj_ptr = sel_ptr->obj; if (obj_ptr->locked) locked_obj = obj_ptr; switch (Dir) { case ABUT_HORIZONTAL: if (obj_ptr->obbox.ltx < sorted_obj->obbox.ltx || (obj_ptr->obbox.ltx == sorted_obj->obbox.ltx && obj_ptr->obbox.lty < sorted_obj->obbox.lty)) { top_sort->obj = sorted_obj = sel_ptr->obj; } break; case ABUT_VERTICAL: if (obj_ptr->obbox.lty < sorted_obj->obbox.lty || (obj_ptr->obbox.lty == sorted_obj->obbox.lty && obj_ptr->obbox.ltx < sorted_obj->obbox.ltx)) { top_sort->obj = sorted_obj = sel_ptr->obj; } break; } } bot_sort = top_sort; for (sel_ptr=botSel; sel_ptr != NULL; sel_ptr=sel_ptr->prev) { if (sel_ptr->obj == top_sort->obj) continue; obj_ptr = sel_ptr->obj; new_sort_ptr = (struct SelRec *)malloc(sizeof(struct SelRec)); if (new_sort_ptr == NULL) FailAllocMessage(); new_sort_ptr->obj = obj_ptr; found = FALSE; for (sort_ptr=top_sort->next; sort_ptr!=NULL; sort_ptr=sort_ptr->next) { switch (Dir) { case ABUT_HORIZONTAL: if (sort_ptr->obj->obbox.ltx > obj_ptr->obbox.ltx || (sort_ptr->obj->obbox.ltx == obj_ptr->obbox.ltx && sort_ptr->obj->obbox.lty > obj_ptr->obbox.lty)) { found = TRUE; } break; case ABUT_VERTICAL: if (sort_ptr->obj->obbox.lty > obj_ptr->obbox.lty || (sort_ptr->obj->obbox.lty == obj_ptr->obbox.lty && sort_ptr->obj->obbox.ltx > obj_ptr->obbox.ltx)) { found = TRUE; } break; } if (found) break; } new_sort_ptr->next = sort_ptr; if (sort_ptr == NULL) { new_sort_ptr->prev = bot_sort; bot_sort->next = new_sort_ptr; bot_sort = new_sort_ptr; } else { new_sort_ptr->prev = sort_ptr->prev; sort_ptr->prev->next = new_sort_ptr; sort_ptr->prev = new_sort_ptr; } } tmp_sel_ptr = (struct SelRec *)malloc(sizeof(struct SelRec)); if (tmp_sel_ptr == NULL) FailAllocMessage(); tmp_sel_ptr->next = tmp_sel_ptr->prev = NULL; if (locked_obj != NULL) { switch (Dir) { case ABUT_HORIZONTAL: rbx = top_sort->obj->obbox.rbx; for (sort_ptr=top_sort; sort_ptr->obj!=locked_obj && sort_ptr->next!=NULL; sort_ptr=next_sort) { next_sort = sort_ptr->next; delta = rbx-next_sort->obj->obbox.ltx; dx = (-delta); rbx = next_sort->obj->obbox.rbx+delta; } break; case ABUT_VERTICAL: rby = top_sort->obj->obbox.rby; for (sort_ptr=top_sort; sort_ptr->obj!=locked_obj && sort_ptr->next!=NULL; sort_ptr=next_sort) { next_sort = sort_ptr->next; delta = rby-next_sort->obj->obbox.lty; dy = (-delta); rby = next_sort->obj->obbox.rby+delta; } break; } } sub_cmd = (struct SubCmdRec *)malloc(sizeof(struct SubCmdRec)); if (sub_cmd == NULL) FailAllocMessage(); memset(sub_cmd, 0, sizeof(struct SubCmdRec)); rbx = top_sort->obj->obbox.rbx; rby = top_sort->obj->obbox.rby; found = (locked_obj == NULL); if (!found && locked_obj != top_sort->obj) { tmp_sel_ptr->obj = top_sort->obj; switch (Dir) { case ABUT_HORIZONTAL: sub_cmd->detail.move.dx = dx; sub_cmd->detail.move.dy = 0; PrepareToRecord(CMD_MOVE, tmp_sel_ptr, tmp_sel_ptr, 1); RecordCmd(CMD_MOVE, sub_cmd, NULL, NULL, 0); MoveObj(top_sort->obj, dx, 0); break; case ABUT_VERTICAL: sub_cmd->detail.move.dx = 0; sub_cmd->detail.move.dy = dy; PrepareToRecord(CMD_MOVE, tmp_sel_ptr, tmp_sel_ptr, 1); RecordCmd(CMD_MOVE, sub_cmd, NULL, NULL, 0); MoveObj(top_sort->obj, 0, dy); break; } } for (sort_ptr=top_sort; sort_ptr->next!=NULL; sort_ptr=next_sort) { next_sort = sort_ptr->next; tmp_sel_ptr->obj = next_sort->obj; switch (Dir) { case ABUT_HORIZONTAL: delta = rbx-next_sort->obj->obbox.ltx; rbx = next_sort->obj->obbox.rbx+delta; if (!found) delta += dx; sub_cmd->detail.move.dx = delta; sub_cmd->detail.move.dy = 0; PrepareToRecord(CMD_MOVE, tmp_sel_ptr, tmp_sel_ptr, 1); RecordCmd(CMD_MOVE, sub_cmd, NULL, NULL, 0); MoveObj(next_sort->obj, delta, 0); break; case ABUT_VERTICAL: delta = rby-next_sort->obj->obbox.lty; rby = next_sort->obj->obbox.rby+delta; if (!found) delta += dy; sub_cmd->detail.move.dx = 0; sub_cmd->detail.move.dy = delta; PrepareToRecord(CMD_MOVE, tmp_sel_ptr, tmp_sel_ptr, 1); RecordCmd(CMD_MOVE, sub_cmd, NULL, NULL, 0); MoveObj(next_sort->obj, 0, delta); break; } free(sort_ptr); } EndCompositeCmd(); free(sort_ptr); free(sub_cmd); free(tmp_sel_ptr); UpdSelBBox(); RedrawAreas(botObj, selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1), selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1), sel_ltx-GRID_ABS_SIZE(1), sel_lty-GRID_ABS_SIZE(1), sel_rbx+GRID_ABS_SIZE(1), sel_rby+GRID_ABS_SIZE(1)); HighLightForward(); justDupped = FALSE; switch (Dir) { case ABUT_HORIZONTAL: Msg(TgLoadString(STID_ABUTTED_HORI)); break; case ABUT_VERTICAL: Msg(TgLoadString(STID_ABUTTED_VERT)); break; } SetFileModified(TRUE); } void AbutHorizontal() { Abut(ABUT_HORIZONTAL); } void AbutVertical() { Abut(ABUT_VERTICAL); } void RefreshArrangeMenu(menu) TgMenu *menu; { } int ArrangeMenu(X, Y, TrackMenubar) int X, Y, TrackMenubar; { int rc=INVALID; TgMenu *menu=(arrangeMenuInfo.create_proc)(NULL, X, Y, &arrangeMenuInfo, FALSE); activeMenu = MENU_ARRANGE; if (menu != NULL) { menu->track_menubar = TrackMenubar; rc = TgMenuLoop(menu); TgDestroyMenu(menu, TRUE); } return rc; } int RefreshPropertiesMenu(menu) TgMenu *menu; { int ok=TRUE; /* UseAltEditTextBgColor */ ok &= TgSetMenuItemCheckById(menu, CMDID_TOGGLEALTEDITTEXTBGCOLOR, useAltEditTextBgColor); /* AddColor */ ok &= TgEnableMenuItemById(menu, CMDID_ADDCOLOR, colorDisplay); return ok; } TgMenu *CreatePropertiesMenu(parent_menu, x, y, menu_info, status_str_xlated) TgMenu *parent_menu; int x, y; TgMenuInfo *menu_info; int status_str_xlated; /* ignored, always 0 */ { TgMenu *menu=TgCreateMenuFromMenuInfo(parent_menu, x, y, menu_info, FALSE); if (menu != NULL) { if (!RefreshPropertiesMenu(menu)) { return TgDestroyMenu(menu, TRUE); } menu->refresh_proc = ((RefreshMenuFunc*)RefreshPropertiesMenu); } return menu; } int PropertiesMenu(X, Y, TrackMenubar) int X, Y, TrackMenubar; { int rc=INVALID; TgMenu *menu=(propertiesMenuInfo.create_proc)(NULL, X, Y, &propertiesMenuInfo, INVALID); activeMenu = MENU_PROPERTIES; if (menu != NULL) { menu->track_menubar = TrackMenubar; rc = TgMenuLoop(menu); TgDestroyMenu(menu, TRUE); } return rc; } void UpdateSymbols() { int dx=0, dy=0, changed=FALSE; int sel_ltx, sel_lty, sel_rbx, sel_rby, file_type=INVALID; char path_name[MAXPATHLENGTH], sym_name[MAXPATHLENGTH]; struct ObjRec *obj_ptr, *new_obj_ptr; struct SelRec *sel_ptr; struct GroupRec *icon_ptr; if (topSel == NULL) { MsgBox(TgLoadCachedString(CSTID_NO_OBJ_SELECTED), TOOL_NAME, INFO_MB); return; } tmpTopObj = tmpBotObj = NULL; tmpTopSel = tmpBotSel = NULL; sel_ltx = selLtX; sel_lty = selLtY; sel_rbx = selRbX; sel_rby = selRbY; HighLightReverse(); StartCompositeCmd(); for (sel_ptr=botSel; sel_ptr != NULL; sel_ptr=sel_ptr->prev) { obj_ptr = sel_ptr->obj; if (obj_ptr->type != OBJ_ICON && obj_ptr->type != OBJ_PIN) { continue; } icon_ptr = obj_ptr->detail.r; strcpy(sym_name, icon_ptr->s); if (obj_ptr->type == OBJ_ICON) { file_type = SYM_FILE_TYPE; } else { file_type = PIN_FILE_TYPE; } if (GetSymbolPath(icon_ptr->s, obj_ptr->type==OBJ_PIN, path_name)) { if ((new_obj_ptr=GetObjRepresentation(path_name, sym_name, file_type)) != NULL) { PrepareToReplaceAnObj(obj_ptr); if (icon_ptr->flip != NO_FLIP) { if (icon_ptr->flip & HORI_EVEN) FlipIconHorizontal(new_obj_ptr); if (icon_ptr->flip & VERT_EVEN) FlipIconVertical(new_obj_ptr); if (icon_ptr->flip & (HORI_ODD | VERT_ODD)) { RotateIconClockWise(new_obj_ptr); if (icon_ptr->flip & HORI_ODD) { FlipIconHorizontal(new_obj_ptr); } if (icon_ptr->flip & VERT_ODD) { FlipIconVertical(new_obj_ptr); } RotateIconCounter(new_obj_ptr); } } switch (horiAlign) { case ALIGN_L: dx = obj_ptr->obbox.ltx - new_obj_ptr->obbox.ltx; break; case ALIGN_N: case ALIGN_S: case ALIGN_C: dx = (int)(((obj_ptr->obbox.ltx+obj_ptr->obbox.rbx) - (new_obj_ptr->obbox.ltx+new_obj_ptr->obbox.rbx))/2); break; case ALIGN_R: dx = obj_ptr->obbox.rbx - new_obj_ptr->obbox.rbx; break; } switch (vertAlign) { case ALIGN_T: dy = obj_ptr->obbox.lty - new_obj_ptr->obbox.lty; break; case ALIGN_N: case ALIGN_S: case ALIGN_M: dy = (int)(((obj_ptr->obbox.lty+obj_ptr->obbox.rby) - (new_obj_ptr->obbox.lty+new_obj_ptr->obbox.rby))/2); break; case ALIGN_B: dy = obj_ptr->obbox.rby - new_obj_ptr->obbox.rby; break; } MoveObj(new_obj_ptr, dx, dy); changed = TRUE; UnlinkObj(obj_ptr); CopyAndUpdateAttrs(new_obj_ptr, obj_ptr); ExpandCurSelBBoxes(new_obj_ptr); sel_ptr->obj = new_obj_ptr; AssignNewObjIds(new_obj_ptr); AddObj(NULL, topObj, new_obj_ptr); RecordReplaceAnObj(new_obj_ptr); FreeObj(obj_ptr); } } } EndCompositeCmd(); if (changed) { UpdSelBBox(); RedrawAreas(botObj, sel_ltx-GRID_ABS_SIZE(1), sel_lty-GRID_ABS_SIZE(1), sel_rbx+GRID_ABS_SIZE(1), sel_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)); SetFileModified(TRUE); justDupped = FALSE; Msg(TgLoadString(STID_ICONS_BROUGHT_UP_TO_DATE)); } HighLightForward(); } void SizeToWidest() { struct SelRec *sel_ptr=NULL; int abs_w=0; if (topSel == NULL || topSel == botSel) { MsgBox(TgLoadString(STID_SEL_AT_LEAST_TWO_OBJS), TOOL_NAME, INFO_MB); return; } for (sel_ptr=topSel; 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; if (w > abs_w) abs_w = w; } if (abs_w <= 1) { sprintf(gszMsgBox, TgLoadString(STID_CANNOT_SIZE_OF_GIVEN_WIDTH), abs_w); MsgBox(gszMsgBox, TOOL_NAME, INFO_MB); return; } SizeAllSelToGivenWidth(abs_w); } void SizeToNarrowest() { struct SelRec *sel_ptr=NULL; int abs_w=0; if (topSel == NULL || topSel == botSel) { MsgBox(TgLoadString(STID_SEL_AT_LEAST_TWO_OBJS), TOOL_NAME, INFO_MB); return; } abs_w = topSel->obj->obbox.rbx-topSel->obj->obbox.ltx; for (sel_ptr=topSel; 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; if (w < abs_w) abs_w = w; } if (abs_w <= 1) { sprintf(gszMsgBox, TgLoadString(STID_CANNOT_SIZE_OF_GIVEN_WIDTH), abs_w); MsgBox(gszMsgBox, TOOL_NAME, INFO_MB); return; } SizeAllSelToGivenWidth(abs_w); } void SizeToTallest() { struct SelRec *sel_ptr=NULL; int abs_h=0; if (topSel == NULL || topSel == botSel) { MsgBox(TgLoadString(STID_SEL_AT_LEAST_TWO_OBJS), TOOL_NAME, INFO_MB); return; } for (sel_ptr=topSel; sel_ptr != NULL; sel_ptr=sel_ptr->next) { struct ObjRec *obj_ptr=sel_ptr->obj; int h=obj_ptr->obbox.rby-obj_ptr->obbox.lty; if (h > abs_h) abs_h = h; } if (abs_h <= 1) { sprintf(gszMsgBox, TgLoadString(STID_CANNOT_SIZE_OF_GIVEN_HEIGHT), abs_h); MsgBox(gszMsgBox, TOOL_NAME, INFO_MB); return; } SizeAllSelToGivenHeight(abs_h); } void SizeToShortest() { struct SelRec *sel_ptr=NULL; int abs_h=0; if (topSel == NULL || topSel == botSel) { MsgBox(TgLoadString(STID_SEL_AT_LEAST_TWO_OBJS), TOOL_NAME, INFO_MB); return; } abs_h = topSel->obj->obbox.rby-topSel->obj->obbox.lty; for (sel_ptr=topSel; sel_ptr != NULL; sel_ptr=sel_ptr->next) { struct ObjRec *obj_ptr=sel_ptr->obj; int h=obj_ptr->obbox.rby-obj_ptr->obbox.lty; if (h < abs_h) abs_h = h; } if (abs_h <= 1) { sprintf(gszMsgBox, TgLoadString(STID_CANNOT_SIZE_OF_GIVEN_HEIGHT), abs_h); MsgBox(gszMsgBox, TOOL_NAME, INFO_MB); return; } SizeAllSelToGivenHeight(abs_h); } void SizeToGivenWidthHeight() { int abs_w=0, abs_h=0; char spec[MAXSTRING]; if (topSel == NULL) { MsgBox(TgLoadCachedString(CSTID_NO_OBJ_SELECTED), TOOL_NAME, INFO_MB); return; } *spec = '\0'; if (Dialog(TgLoadString(STID_SPECIFY_WIDTH_HEIGHT), NULL, spec) == INVALID) { return; } UtilTrimBlanks(spec); if (*spec == '\0') return; if (!ParseWHSpec(spec, &abs_w, &abs_h)) { sprintf(gszMsgBox, TgLoadString(STID_INVALID_SPEC), spec); MsgBox(gszMsgBox, TOOL_NAME, INFO_MB); return; } if (abs_w <= 1) { sprintf(gszMsgBox, TgLoadString(STID_CANNOT_SIZE_OF_GIVEN_WIDTH), abs_w); MsgBox(gszMsgBox, TOOL_NAME, INFO_MB); return; } if (abs_h <= 1) { sprintf(gszMsgBox, TgLoadString(STID_CANNOT_SIZE_OF_GIVEN_HEIGHT), abs_h); MsgBox(gszMsgBox, TOOL_NAME, INFO_MB); return; } SizeAllSelToGivenWidthHeight(abs_w, abs_h); } void SizeToGivenWidth() { int abs_w=0; char spec[MAXSTRING]; if (topSel == NULL) { MsgBox(TgLoadCachedString(CSTID_NO_OBJ_SELECTED), TOOL_NAME, INFO_MB); return; } *spec = '\0'; if (Dialog(TgLoadString(STID_SPECIFY_WIDTH), NULL, spec) == INVALID) return; UtilTrimBlanks(spec); if (*spec == '\0') return; if (!GetDimension(spec, FALSE, &abs_w)) { sprintf(gszMsgBox, TgLoadString(STID_INVALID_SPEC), spec); MsgBox(gszMsgBox, TOOL_NAME, INFO_MB); return; } if (abs_w <= 1) { sprintf(gszMsgBox, TgLoadString(STID_CANNOT_SIZE_OF_GIVEN_WIDTH), abs_w); MsgBox(gszMsgBox, TOOL_NAME, INFO_MB); return; } SizeAllSelToGivenWidth(abs_w); } void SizeToGivenHeight() { int abs_h=0; char spec[MAXSTRING]; if (topSel == NULL) { MsgBox(TgLoadCachedString(CSTID_NO_OBJ_SELECTED), TOOL_NAME, INFO_MB); return; } *spec = '\0'; if (Dialog(TgLoadString(STID_SPECIFY_HEIGHT), NULL, spec) == INVALID) return; UtilTrimBlanks(spec); if (*spec == '\0') return; if (!GetDimension(spec, FALSE, &abs_h)) { sprintf(gszMsgBox, TgLoadString(STID_INVALID_SPEC), spec); MsgBox(gszMsgBox, TOOL_NAME, INFO_MB); return; } if (abs_h <= 1) { sprintf(gszMsgBox, TgLoadString(STID_CANNOT_SIZE_OF_GIVEN_HEIGHT), abs_h); MsgBox(gszMsgBox, TOOL_NAME, INFO_MB); return; } SizeAllSelToGivenHeight(abs_h); } /* ----------------------- Generic Object Shadow ----------------------- */ void SetObjectShadowColor() { char spec[MAXSTRING], buf[MAXSTRING]; int new_alloc=0; *spec = '\0'; sprintf(buf, TgLoadString(STID_ENTER_A_COLOR_FOR_OBJ_SHADOW), objShadowColorStr); UtilStrCpyN(spec, sizeof(spec), objShadowColorStr); if (Dialog(buf, TgLoadString(STID_PRESS_ENTER_FOR_DEF_COLOR), spec) == INVALID) { return; } UtilTrimBlanks(spec); if (*spec == '\0') { strcpy(objShadowColorStr, "#c0c0c0"); sprintf(gszMsgBox, TgLoadString(STID_OBJ_SHADOW_COLOR_SET_TO_NAMED), objShadowColorStr); Msg(gszMsgBox); return; } if (QuickFindColorIndex(NULL, spec, &new_alloc, FALSE) == INVALID) { sprintf(gszMsgBox, TgLoadString(STID_FAIL_ALLOC_NAMED_COLOR), spec); MsgBox(gszMsgBox, TOOL_NAME, INFO_MB); return; } UtilStrCpyN(objShadowColorStr, sizeof(objShadowColorStr), spec); sprintf(gszMsgBox, TgLoadString(STID_OBJ_SHADOW_COLOR_SET_TO_NAMED), objShadowColorStr); Msg(gszMsgBox); } void SetObjectShadowOffsets() { char spec[MAXSTRING]; *spec = '\0'; sprintf(gszMsgBox, TgLoadString(STID_ENTER_XY_OFFSET_OBJ_SHADOW), objShadowXOffset, objShadowYOffset); if (Dialog(gszMsgBox, NULL, spec) == INVALID) return; UtilTrimBlanks(spec); if (*spec == '\0') return; if (ParseXYSpec(spec, &objShadowXOffset, &objShadowYOffset)) { sprintf(gszMsgBox, TgLoadString(STID_OBJ_SHADOW_XY_OFFSETS_SET_TO), objShadowXOffset, objShadowYOffset); Msg(gszMsgBox); } } static void DoAddObjectShadow() { struct SelRec *sel_ptr=NULL; int new_alloc=0, color_index=QuickFindColorIndex(NULL, objShadowColorStr, &new_alloc, FALSE); for (sel_ptr=botSel; sel_ptr != NULL; sel_ptr=sel_ptr->prev) { struct ObjRec *obj_ptr=sel_ptr->obj, *dup_obj_ptr=NULL, *group_obj=NULL; struct GroupRec *group_ptr=NULL; struct BBRec obbox, bbox; int locked=obj_ptr->locked; dup_obj_ptr = DupObj(obj_ptr); AdjObjSplineVs(dup_obj_ptr); MoveObj(dup_obj_ptr, objShadowXOffset, objShadowYOffset); ChangeObjColor(dup_obj_ptr, color_index); UnionRect(&(obj_ptr->obbox), &(dup_obj_ptr->obbox), &obbox); UnionRect(&(obj_ptr->bbox), &(dup_obj_ptr->bbox), &bbox); group_obj = JustCreateGroupObj(); group_ptr = group_obj->detail.r; group_obj->prev = obj_ptr->prev; group_obj->next = obj_ptr->next; if (obj_ptr == topObj) { curPage->top = topObj = group_obj; } else { obj_ptr->prev->next = group_obj; } if (obj_ptr == botObj) { curPage->bot = botObj = group_obj; } else { obj_ptr->next->prev = group_obj; } obj_ptr->prev = NULL; obj_ptr->next = dup_obj_ptr; dup_obj_ptr->prev = obj_ptr; dup_obj_ptr->next = NULL; group_ptr->first = obj_ptr; group_ptr->last = dup_obj_ptr; obj_ptr->x = min(obj_ptr->x, dup_obj_ptr->x); obj_ptr->y = min(obj_ptr->y, dup_obj_ptr->y); memcpy(&group_obj->obbox, &obbox, sizeof(struct BBRec)); memcpy(&group_obj->bbox, &bbox, sizeof(struct BBRec)); group_obj->locked = locked; sel_ptr->obj = group_obj; } UpdSelBBox(); } void AddObjectShadow() { if (curChoice != NOTHING || topSel == NULL) { MsgBox(TgLoadCachedString(CSTID_NO_OBJ_SELECTED), TOOL_NAME, INFO_MB); return; } HighLightReverse(); PrepareToRecord(CMD_REPLACE, topSel, botSel, numObjSelected); DoAddObjectShadow(); RecordCmd(CMD_REPLACE, NULL, topSel, botSel, numObjSelected); RedrawAnArea(botObj, selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1), selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1)); HighLightForward(); SetFileModified(TRUE); justDupped = FALSE; } static void DoRemoveObjectShadow() { struct SelRec *sel_ptr=NULL; for (sel_ptr=botSel; sel_ptr != NULL; sel_ptr=sel_ptr->prev) { struct ObjRec *obj_ptr=sel_ptr->obj; if (obj_ptr->type == OBJ_GROUP) { struct GroupRec *group_ptr=obj_ptr->detail.r; struct ObjRec *first_obj=group_ptr->first; if (first_obj != NULL) { struct ObjRec *second_obj=first_obj->next; if (second_obj->next == NULL) { int first_w=(first_obj->obbox.rbx-first_obj->obbox.ltx); int first_h=(first_obj->obbox.rby-first_obj->obbox.lty); int second_w=(second_obj->obbox.rbx-second_obj->obbox.ltx); int second_h=(second_obj->obbox.rby-second_obj->obbox.lty); if (first_w == second_w && first_h == second_h) { group_ptr->first = group_ptr->last = NULL; first_obj->prev = obj_ptr->prev; first_obj->next = obj_ptr->next; if (obj_ptr == topObj) { curPage->top = topObj = first_obj; } else { obj_ptr->prev->next = first_obj; } if (obj_ptr == botObj) { curPage->bot = botObj = first_obj; } else { obj_ptr->next->prev = first_obj; } obj_ptr->prev = NULL; obj_ptr->next = NULL; FreeObj(second_obj); FreeObj(obj_ptr); sel_ptr->obj = first_obj; } } } } } } static int CountObjectWithShadow() { struct SelRec *sel_ptr=NULL; int count=0; for (sel_ptr=botSel; sel_ptr != NULL; sel_ptr=sel_ptr->prev) { struct ObjRec *obj_ptr=sel_ptr->obj; if (obj_ptr->type == OBJ_GROUP) { struct GroupRec *group_ptr=obj_ptr->detail.r; struct ObjRec *first_obj=group_ptr->first; if (first_obj != NULL) { struct ObjRec *second_obj=first_obj->next; if (second_obj->next == NULL) { int first_w=(first_obj->obbox.rbx-first_obj->obbox.ltx); int first_h=(first_obj->obbox.rby-first_obj->obbox.lty); int second_w=(second_obj->obbox.rbx-second_obj->obbox.ltx); int second_h=(second_obj->obbox.rby-second_obj->obbox.lty); if (first_w == second_w && first_h == second_h) { count++; } } } } } return count; } void RemoveObjectShadow() { if (curChoice != NOTHING || topSel == NULL) { MsgBox(TgLoadCachedString(CSTID_NO_OBJ_SELECTED), TOOL_NAME, INFO_MB); return; } if (CountObjectWithShadow() == 0) { sprintf(gszMsgBox, TgLoadString(STID_NO_OBJ_SHADOW_FOUND)); MsgBox(gszMsgBox, TOOL_NAME, INFO_MB); return; } HighLightReverse(); PrepareToRecord(CMD_REPLACE, topSel, botSel, numObjSelected); DoRemoveObjectShadow(); RecordCmd(CMD_REPLACE, NULL, topSel, botSel, numObjSelected); RedrawAnArea(botObj, selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1), selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1)); HighLightForward(); SetFileModified(TRUE); justDupped = FALSE; } int ReadObjectShadowInfo(buf) char *buf; { int x=0, y=0; char color_str[40], *psz=NULL; if (importingFile) return TRUE; psz = FindChar((int)'(', buf); *color_str = '\0'; psz = ParseStr(psz, (int)',', color_str, sizeof(color_str)); InitScan(psz, "\t\n, []"); if (GETINT("objshadow_info", x, "x offset") == INVALID || GETINT("objshadow_info", y, "y offset") == INVALID) { return FALSE; } UtilTrimBlanks(color_str); if (!ignoreObjectShadowInfoInFile) { UtilStrCpyN(objShadowColorStr, sizeof(objShadowColorStr), color_str); objShadowXOffset = x; objShadowYOffset = y; } return TRUE; }