|
|
1.1 ! root 1: /* ! 2: * tkRectOval.c -- ! 3: * ! 4: * This file implements rectangle and oval items for canvas ! 5: * widgets. ! 6: * ! 7: * Copyright 1991-1992 Regents of the University of California. ! 8: * Permission to use, copy, modify, and distribute this ! 9: * software and its documentation for any purpose and without ! 10: * fee is hereby granted, provided that the above copyright ! 11: * notice appear in all copies. The University of California ! 12: * makes no representations about the suitability of this ! 13: * software for any purpose. It is provided "as is" without ! 14: * express or implied warranty. ! 15: */ ! 16: ! 17: #ifndef lint ! 18: static char rcsid[] = "$Header: /user6/ouster/wish/RCS/tkRectOval.c,v 1.15 92/08/24 09:23:58 ouster Exp $ SPRITE (Berkeley)"; ! 19: #endif ! 20: ! 21: #include <stdio.h> ! 22: #include <math.h> ! 23: #include "tkconfig.h" ! 24: #include "tkint.h" ! 25: #include "tkcanvas.h" ! 26: ! 27: /* ! 28: * The structure below defines the record for each rectangle/oval item. ! 29: */ ! 30: ! 31: typedef struct RectOvalItem { ! 32: Tk_Item header; /* Generic stuff that's the same for all ! 33: * types. MUST BE FIRST IN STRUCTURE. */ ! 34: double bbox[4]; /* Coordinates of bounding box for rectangle ! 35: * or oval (x1, y1, x2, y2). Item includes ! 36: * x1 and x2 but not y1 and y2. */ ! 37: int width; /* Width of outline. */ ! 38: XColor *outlineColor; /* Color for outline. */ ! 39: XColor *fillColor; /* Color for filling rectangle/oval. */ ! 40: Pixmap fillStipple; /* Stipple bitmap for filling item. */ ! 41: GC outlineGC; /* Graphics context for outline. */ ! 42: GC fillGC; /* Graphics context for filling item. */ ! 43: } RectOvalItem; ! 44: ! 45: /* ! 46: * Information used for parsing configuration specs: ! 47: */ ! 48: ! 49: static Tk_ConfigSpec configSpecs[] = { ! 50: {TK_CONFIG_COLOR, "-fill", (char *) NULL, (char *) NULL, ! 51: (char *) NULL, Tk_Offset(RectOvalItem, fillColor), TK_CONFIG_NULL_OK}, ! 52: {TK_CONFIG_COLOR, "-outline", (char *) NULL, (char *) NULL, ! 53: "black", Tk_Offset(RectOvalItem, outlineColor), TK_CONFIG_NULL_OK}, ! 54: {TK_CONFIG_BITMAP, "-stipple", (char *) NULL, (char *) NULL, ! 55: (char *) NULL, Tk_Offset(RectOvalItem, fillStipple), TK_CONFIG_NULL_OK}, ! 56: {TK_CONFIG_CUSTOM, "-tags", (char *) NULL, (char *) NULL, ! 57: (char *) NULL, 0, TK_CONFIG_NULL_OK, &tkCanvasTagsOption}, ! 58: {TK_CONFIG_PIXELS, "-width", (char *) NULL, (char *) NULL, ! 59: "1", Tk_Offset(RectOvalItem, width), TK_CONFIG_DONT_SET_DEFAULT}, ! 60: {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, ! 61: (char *) NULL, 0, 0} ! 62: }; ! 63: ! 64: /* ! 65: * Prototypes for procedures defined in this file: ! 66: */ ! 67: ! 68: static void ComputeRectOvalBbox _ANSI_ARGS_((Tk_Canvas *canvasPtr, ! 69: RectOvalItem *rectOvalPtr)); ! 70: static int ConfigureRectOval _ANSI_ARGS_(( ! 71: Tk_Canvas *canvasPtr, Tk_Item *itemPtr, int argc, ! 72: char **argv, int flags)); ! 73: static int CreateRectOval _ANSI_ARGS_((Tk_Canvas *canvasPtr, ! 74: struct Tk_Item *itemPtr, int argc, char **argv)); ! 75: static void DeleteRectOval _ANSI_ARGS_((Tk_Item *itemPtr)); ! 76: static void DisplayRectOval _ANSI_ARGS_((Tk_Canvas *canvasPtr, ! 77: Tk_Item *itemPtr, Drawable dst)); ! 78: static int OvalToArea _ANSI_ARGS_((Tk_Canvas *canvasPtr, ! 79: Tk_Item *itemPtr, double *areaPtr)); ! 80: static double OvalToPoint _ANSI_ARGS_((Tk_Canvas *canvasPtr, ! 81: Tk_Item *itemPtr, double *pointPtr)); ! 82: static int RectOvalCoords _ANSI_ARGS_((Tk_Canvas *canvasPtr, ! 83: Tk_Item *itemPtr, int argc, char **argv)); ! 84: static int RectToArea _ANSI_ARGS_((Tk_Canvas *canvasPtr, ! 85: Tk_Item *itemPtr, double *areaPtr)); ! 86: static double RectToPoint _ANSI_ARGS_((Tk_Canvas *canvasPtr, ! 87: Tk_Item *itemPtr, double *pointPtr)); ! 88: static void ScaleRectOval _ANSI_ARGS_((Tk_Canvas *canvasPtr, ! 89: Tk_Item *itemPtr, double originX, double originY, ! 90: double scaleX, double scaleY)); ! 91: static void TranslateRectOval _ANSI_ARGS_((Tk_Canvas *canvasPtr, ! 92: Tk_Item *itemPtr, double deltaX, double deltaY)); ! 93: ! 94: /* ! 95: * The structures below defines the rectangle and oval item types ! 96: * by means of procedures that can be invoked by generic item code. ! 97: */ ! 98: ! 99: Tk_ItemType TkRectangleType = { ! 100: "rectangle", /* name */ ! 101: sizeof(RectOvalItem), /* itemSize */ ! 102: CreateRectOval, /* createProc */ ! 103: configSpecs, /* configSpecs */ ! 104: ConfigureRectOval, /* configureProc */ ! 105: RectOvalCoords, /* coordProc */ ! 106: DeleteRectOval, /* deleteProc */ ! 107: DisplayRectOval, /* displayProc */ ! 108: 0, /* alwaysRedraw */ ! 109: RectToPoint, /* pointProc */ ! 110: RectToArea, /* areaProc */ ! 111: (Tk_ItemPostscriptProc *) NULL, /* postscriptProc */ ! 112: ScaleRectOval, /* scaleProc */ ! 113: TranslateRectOval, /* translateProc */ ! 114: (Tk_ItemIndexProc *) NULL, /* indexProc */ ! 115: (Tk_ItemCursorProc *) NULL, /* cursorProc */ ! 116: (Tk_ItemSelectionProc *) NULL, /* selectionProc */ ! 117: (Tk_ItemInsertProc *) NULL, /* insertProc */ ! 118: (Tk_ItemDCharsProc *) NULL, /* dTextProc */ ! 119: (Tk_ItemType *) NULL /* nextPtr */ ! 120: }; ! 121: ! 122: Tk_ItemType TkOvalType = { ! 123: "oval", /* name */ ! 124: sizeof(RectOvalItem), /* itemSize */ ! 125: CreateRectOval, /* createProc */ ! 126: configSpecs, /* configSpecs */ ! 127: ConfigureRectOval, /* configureProc */ ! 128: RectOvalCoords, /* coordProc */ ! 129: DeleteRectOval, /* deleteProc */ ! 130: DisplayRectOval, /* displayProc */ ! 131: 0, /* alwaysRedraw */ ! 132: OvalToPoint, /* pointProc */ ! 133: OvalToArea, /* areaProc */ ! 134: (Tk_ItemPostscriptProc *) NULL, /* postscriptProc */ ! 135: ScaleRectOval, /* scaleProc */ ! 136: TranslateRectOval, /* translateProc */ ! 137: (Tk_ItemIndexProc *) NULL, /* indexProc */ ! 138: (Tk_ItemCursorProc *) NULL, /* cursorProc */ ! 139: (Tk_ItemSelectionProc *) NULL, /* selectionProc */ ! 140: (Tk_ItemInsertProc *) NULL, /* insertProc */ ! 141: (Tk_ItemDCharsProc *) NULL, /* dTextProc */ ! 142: (Tk_ItemType *) NULL /* nextPtr */ ! 143: }; ! 144: ! 145: /* ! 146: *-------------------------------------------------------------- ! 147: * ! 148: * CreateRectOval -- ! 149: * ! 150: * This procedure is invoked to create a new rectangle ! 151: * or oval item in a canvas. ! 152: * ! 153: * Results: ! 154: * A standard Tcl return value. If an error occurred in ! 155: * creating the item, then an error message is left in ! 156: * canvasPtr->interp->result; in this case itemPtr is ! 157: * left uninitialized, so it can be safely freed by the ! 158: * caller. ! 159: * ! 160: * Side effects: ! 161: * A new rectangle or oval item is created. ! 162: * ! 163: *-------------------------------------------------------------- ! 164: */ ! 165: ! 166: static int ! 167: CreateRectOval(canvasPtr, itemPtr, argc, argv) ! 168: register Tk_Canvas *canvasPtr; /* Canvas to hold new item. */ ! 169: Tk_Item *itemPtr; /* Record to hold new item; header ! 170: * has been initialized by caller. */ ! 171: int argc; /* Number of arguments in argv. */ ! 172: char **argv; /* Arguments describing rectangle. */ ! 173: { ! 174: register RectOvalItem *rectOvalPtr = (RectOvalItem *) itemPtr; ! 175: ! 176: if (argc < 4) { ! 177: Tcl_AppendResult(canvasPtr->interp, "wrong # args: should be \"", ! 178: Tk_PathName(canvasPtr->tkwin), "\" create ", ! 179: itemPtr->typePtr->name, " x1 y1 x2 y2 ?options?", ! 180: (char *) NULL); ! 181: return TCL_ERROR; ! 182: } ! 183: ! 184: /* ! 185: * Carry out initialization that is needed in order to clean ! 186: * up after errors during the the remainder of this procedure. ! 187: */ ! 188: ! 189: rectOvalPtr->width = 1; ! 190: rectOvalPtr->outlineColor = NULL; ! 191: rectOvalPtr->fillColor = NULL; ! 192: rectOvalPtr->fillStipple = None; ! 193: rectOvalPtr->outlineGC = None; ! 194: rectOvalPtr->fillGC = None; ! 195: ! 196: /* ! 197: * Process the arguments to fill in the item record. ! 198: */ ! 199: ! 200: if ((TkGetCanvasCoord(canvasPtr, argv[0], &rectOvalPtr->bbox[0]) != TCL_OK) ! 201: || (TkGetCanvasCoord(canvasPtr, argv[1], ! 202: &rectOvalPtr->bbox[1]) != TCL_OK) ! 203: || (TkGetCanvasCoord(canvasPtr, argv[2], ! 204: &rectOvalPtr->bbox[2]) != TCL_OK) ! 205: || (TkGetCanvasCoord(canvasPtr, argv[3], ! 206: &rectOvalPtr->bbox[3]) != TCL_OK)) { ! 207: return TCL_ERROR; ! 208: } ! 209: ! 210: if (ConfigureRectOval(canvasPtr, itemPtr, argc-4, argv+4, 0) != TCL_OK) { ! 211: DeleteRectOval(itemPtr); ! 212: return TCL_ERROR; ! 213: } ! 214: return TCL_OK; ! 215: } ! 216: ! 217: /* ! 218: *-------------------------------------------------------------- ! 219: * ! 220: * RectOvalCoords -- ! 221: * ! 222: * This procedure is invoked to process the "coords" widget ! 223: * command on rectangles and ovals. See the user documentation ! 224: * for details on what it does. ! 225: * ! 226: * Results: ! 227: * Returns TCL_OK or TCL_ERROR, and sets canvasPtr->interp->result. ! 228: * ! 229: * Side effects: ! 230: * The coordinates for the given item may be changed. ! 231: * ! 232: *-------------------------------------------------------------- ! 233: */ ! 234: ! 235: static int ! 236: RectOvalCoords(canvasPtr, itemPtr, argc, argv) ! 237: register Tk_Canvas *canvasPtr; /* Canvas containing item. */ ! 238: Tk_Item *itemPtr; /* Item whose coordinates are to be ! 239: * read or modified. */ ! 240: int argc; /* Number of coordinates supplied in ! 241: * argv. */ ! 242: char **argv; /* Array of coordinates: x1, y1, ! 243: * x2, y2, ... */ ! 244: { ! 245: register RectOvalItem *rectOvalPtr = (RectOvalItem *) itemPtr; ! 246: char buffer[500]; ! 247: ! 248: if (argc == 0) { ! 249: sprintf(buffer, "%g %g %g %g", rectOvalPtr->bbox[0], ! 250: rectOvalPtr->bbox[1], rectOvalPtr->bbox[2], ! 251: rectOvalPtr->bbox[3]); ! 252: Tcl_SetResult(canvasPtr->interp, buffer, TCL_VOLATILE); ! 253: } else if (argc == 4) { ! 254: if ((TkGetCanvasCoord(canvasPtr, argv[0], ! 255: &rectOvalPtr->bbox[0]) != TCL_OK) ! 256: || (TkGetCanvasCoord(canvasPtr, argv[1], ! 257: &rectOvalPtr->bbox[1]) != TCL_OK) ! 258: || (TkGetCanvasCoord(canvasPtr, argv[2], ! 259: &rectOvalPtr->bbox[2]) != TCL_OK) ! 260: || (TkGetCanvasCoord(canvasPtr, argv[3], ! 261: &rectOvalPtr->bbox[3]) != TCL_OK)) { ! 262: return TCL_ERROR; ! 263: } ! 264: ComputeRectOvalBbox(canvasPtr, rectOvalPtr); ! 265: } else { ! 266: sprintf(canvasPtr->interp->result, ! 267: "wrong # coordinates: expected 0 or 4, got %d", ! 268: argc); ! 269: return TCL_ERROR; ! 270: } ! 271: return TCL_OK; ! 272: } ! 273: ! 274: /* ! 275: *-------------------------------------------------------------- ! 276: * ! 277: * ConfigureRectOval -- ! 278: * ! 279: * This procedure is invoked to configure various aspects ! 280: * of a rectangle or oval item, such as its border and ! 281: * background colors. ! 282: * ! 283: * Results: ! 284: * A standard Tcl result code. If an error occurs, then ! 285: * an error message is left in canvasPtr->interp->result. ! 286: * ! 287: * Side effects: ! 288: * Configuration information, such as colors and stipple ! 289: * patterns, may be set for itemPtr. ! 290: * ! 291: *-------------------------------------------------------------- ! 292: */ ! 293: ! 294: static int ! 295: ConfigureRectOval(canvasPtr, itemPtr, argc, argv, flags) ! 296: Tk_Canvas *canvasPtr; /* Canvas containing itemPtr. */ ! 297: Tk_Item *itemPtr; /* Rectangle item to reconfigure. */ ! 298: int argc; /* Number of elements in argv. */ ! 299: char **argv; /* Arguments describing things to configure. */ ! 300: int flags; /* Flags to pass to Tk_ConfigureWidget. */ ! 301: { ! 302: register RectOvalItem *rectOvalPtr = (RectOvalItem *) itemPtr; ! 303: XGCValues gcValues; ! 304: GC newGC; ! 305: unsigned long mask; ! 306: ! 307: if (Tk_ConfigureWidget(canvasPtr->interp, canvasPtr->tkwin, ! 308: configSpecs, argc, argv, (char *) rectOvalPtr, flags) != TCL_OK) { ! 309: return TCL_ERROR; ! 310: } ! 311: ! 312: /* ! 313: * A few of the options require additional processing, such as ! 314: * graphics contexts. ! 315: */ ! 316: ! 317: if (rectOvalPtr->outlineColor == NULL) { ! 318: newGC = None; ! 319: } else { ! 320: gcValues.foreground = rectOvalPtr->outlineColor->pixel; ! 321: gcValues.cap_style = CapProjecting; ! 322: if (rectOvalPtr->width < 0) { ! 323: rectOvalPtr->width = 1; ! 324: } ! 325: gcValues.line_width = rectOvalPtr->width; ! 326: mask = GCForeground|GCCapStyle|GCLineWidth; ! 327: newGC = Tk_GetGC(canvasPtr->tkwin, mask, &gcValues); ! 328: } ! 329: if (rectOvalPtr->outlineGC != None) { ! 330: Tk_FreeGC(rectOvalPtr->outlineGC); ! 331: } ! 332: rectOvalPtr->outlineGC = newGC; ! 333: ! 334: if (rectOvalPtr->fillColor == NULL) { ! 335: newGC = None; ! 336: } else { ! 337: gcValues.foreground = rectOvalPtr->fillColor->pixel; ! 338: if (rectOvalPtr->fillStipple != None) { ! 339: gcValues.stipple = rectOvalPtr->fillStipple; ! 340: gcValues.fill_style = FillStippled; ! 341: mask = GCForeground|GCStipple|GCFillStyle; ! 342: } else { ! 343: mask = GCForeground; ! 344: } ! 345: newGC = Tk_GetGC(canvasPtr->tkwin, mask, &gcValues); ! 346: } ! 347: if (rectOvalPtr->fillGC != None) { ! 348: Tk_FreeGC(rectOvalPtr->fillGC); ! 349: } ! 350: rectOvalPtr->fillGC = newGC; ! 351: ComputeRectOvalBbox(canvasPtr, rectOvalPtr); ! 352: ! 353: return TCL_OK; ! 354: } ! 355: ! 356: /* ! 357: *-------------------------------------------------------------- ! 358: * ! 359: * DeleteRectOval -- ! 360: * ! 361: * This procedure is called to clean up the data structure ! 362: * associated with a rectangle or oval item. ! 363: * ! 364: * Results: ! 365: * None. ! 366: * ! 367: * Side effects: ! 368: * Resources associated with itemPtr are released. ! 369: * ! 370: *-------------------------------------------------------------- ! 371: */ ! 372: ! 373: static void ! 374: DeleteRectOval(itemPtr) ! 375: Tk_Item *itemPtr; /* Item that is being deleted. */ ! 376: { ! 377: register RectOvalItem *rectOvalPtr = (RectOvalItem *) itemPtr; ! 378: ! 379: if (rectOvalPtr->outlineColor != NULL) { ! 380: Tk_FreeColor(rectOvalPtr->outlineColor); ! 381: } ! 382: if (rectOvalPtr->fillColor != NULL) { ! 383: Tk_FreeColor(rectOvalPtr->fillColor); ! 384: } ! 385: if (rectOvalPtr->fillStipple != None) { ! 386: Tk_FreeBitmap(rectOvalPtr->fillStipple); ! 387: } ! 388: if (rectOvalPtr->outlineGC != None) { ! 389: Tk_FreeGC(rectOvalPtr->outlineGC); ! 390: } ! 391: if (rectOvalPtr->fillGC != None) { ! 392: Tk_FreeGC(rectOvalPtr->fillGC); ! 393: } ! 394: } ! 395: ! 396: /* ! 397: *-------------------------------------------------------------- ! 398: * ! 399: * ComputeRectOvalBbox -- ! 400: * ! 401: * This procedure is invoked to compute the bounding box of ! 402: * all the pixels that may be drawn as part of a rectangle ! 403: * or oval. ! 404: * ! 405: * Results: ! 406: * None. ! 407: * ! 408: * Side effects: ! 409: * The fields x1, y1, x2, and y2 are updated in the header ! 410: * for itemPtr. ! 411: * ! 412: *-------------------------------------------------------------- ! 413: */ ! 414: ! 415: /* ARGSUSED */ ! 416: static void ! 417: ComputeRectOvalBbox(canvasPtr, rectOvalPtr) ! 418: Tk_Canvas *canvasPtr; /* Canvas that contains item. */ ! 419: register RectOvalItem *rectOvalPtr; /* Item whose bbox is to be ! 420: * recomputed. */ ! 421: { ! 422: int bloat; ! 423: ! 424: /* ! 425: * Make sure that the first coordinates are the lowest ones. ! 426: */ ! 427: ! 428: if (rectOvalPtr->bbox[1] > rectOvalPtr->bbox[3]) { ! 429: double tmp; ! 430: tmp = rectOvalPtr->bbox[3]; ! 431: rectOvalPtr->bbox[3] = rectOvalPtr->bbox[1]; ! 432: rectOvalPtr->bbox[1] = tmp; ! 433: } ! 434: if (rectOvalPtr->bbox[0] > rectOvalPtr->bbox[2]) { ! 435: double tmp; ! 436: tmp = rectOvalPtr->bbox[2]; ! 437: rectOvalPtr->bbox[2] = rectOvalPtr->bbox[0]; ! 438: rectOvalPtr->bbox[0] = tmp; ! 439: } ! 440: ! 441: bloat = (rectOvalPtr->width+1)/2 + 1; ! 442: rectOvalPtr->header.x1 = rectOvalPtr->bbox[0] - bloat; ! 443: rectOvalPtr->header.y1 = rectOvalPtr->bbox[1] - bloat; ! 444: rectOvalPtr->header.x2 = rectOvalPtr->bbox[2] + bloat; ! 445: rectOvalPtr->header.y2 = rectOvalPtr->bbox[3] + bloat; ! 446: } ! 447: ! 448: /* ! 449: *-------------------------------------------------------------- ! 450: * ! 451: * DisplayRectOval -- ! 452: * ! 453: * This procedure is invoked to draw a rectangle or oval ! 454: * item in a given drawable. ! 455: * ! 456: * Results: ! 457: * None. ! 458: * ! 459: * Side effects: ! 460: * ItemPtr is drawn in drawable using the transformation ! 461: * information in canvasPtr. ! 462: * ! 463: *-------------------------------------------------------------- ! 464: */ ! 465: ! 466: static void ! 467: DisplayRectOval(canvasPtr, itemPtr, drawable) ! 468: register Tk_Canvas *canvasPtr; /* Canvas that contains item. */ ! 469: Tk_Item *itemPtr; /* Item to be displayed. */ ! 470: Drawable drawable; /* Pixmap or window in which to draw ! 471: * item. */ ! 472: { ! 473: register RectOvalItem *rectOvalPtr = (RectOvalItem *) itemPtr; ! 474: Display *display = Tk_Display(canvasPtr->tkwin); ! 475: int x1, y1, x2, y2; ! 476: ! 477: /* ! 478: * Compute the screen coordinates of the bounding box for the item. ! 479: * Make sure that the bbox is at least one pixel large, since some ! 480: * X servers will die if it isn't. ! 481: */ ! 482: ! 483: x1 = SCREEN_X(canvasPtr, rectOvalPtr->bbox[0]); ! 484: y1 = SCREEN_Y(canvasPtr, rectOvalPtr->bbox[1]); ! 485: x2 = SCREEN_X(canvasPtr, rectOvalPtr->bbox[2]); ! 486: y2 = SCREEN_Y(canvasPtr, rectOvalPtr->bbox[3]); ! 487: if (x2 <= x1) { ! 488: x2 = x1+1; ! 489: } ! 490: if (y2 <= y1) { ! 491: y2 = y1+1; ! 492: } ! 493: ! 494: /* ! 495: * Display filled box first (if wanted), then outline. ! 496: */ ! 497: ! 498: if (rectOvalPtr->fillGC != None) { ! 499: if (rectOvalPtr->header.typePtr == &TkRectangleType) { ! 500: XFillRectangle(display, drawable, rectOvalPtr->fillGC, ! 501: x1, y1, (unsigned int) (x2-x1), (unsigned int) (y2-y1)); ! 502: } else { ! 503: XFillArc(display, drawable, rectOvalPtr->fillGC, ! 504: x1, y1, (x2-x1), (y2-y1), 0, 360*64); ! 505: } ! 506: } ! 507: if (rectOvalPtr->outlineGC != None) { ! 508: if (rectOvalPtr->header.typePtr == &TkRectangleType) { ! 509: XDrawRectangle(display, drawable, rectOvalPtr->outlineGC, ! 510: x1, y1, (x2-x1-1), (y2-y1-1)); ! 511: } else { ! 512: XDrawArc(display, drawable, rectOvalPtr->outlineGC, ! 513: x1, y1, (x2-x1-1), (y2-y1-1), 0, 360*64); ! 514: } ! 515: } ! 516: } ! 517: ! 518: /* ! 519: *-------------------------------------------------------------- ! 520: * ! 521: * RectToPoint -- ! 522: * ! 523: * Computes the distance from a given point to a given ! 524: * rectangle, in canvas units. ! 525: * ! 526: * Results: ! 527: * The return value is 0 if the point whose x and y coordinates ! 528: * are coordPtr[0] and coordPtr[1] is inside the rectangle. If the ! 529: * point isn't inside the rectangle then the return value is the ! 530: * distance from the point to the rectangle. If itemPtr is filled, ! 531: * then anywhere in the interior is considered "inside"; if ! 532: * itemPtr isn't filled, then "inside" means only the area ! 533: * occupied by the outline. ! 534: * ! 535: * Side effects: ! 536: * None. ! 537: * ! 538: *-------------------------------------------------------------- ! 539: */ ! 540: ! 541: /* ARGSUSED */ ! 542: static double ! 543: RectToPoint(canvasPtr, itemPtr, pointPtr) ! 544: Tk_Canvas *canvasPtr; /* Canvas containing item. */ ! 545: Tk_Item *itemPtr; /* Item to check against point. */ ! 546: double *pointPtr; /* Pointer to x and y coordinates. */ ! 547: { ! 548: register RectOvalItem *rectPtr = (RectOvalItem *) itemPtr; ! 549: double xDiff, yDiff, x1, y1, x2, y2, inc, tmp; ! 550: ! 551: /* ! 552: * Generate a new larger rectangle that includes the border ! 553: * width, if there is one. ! 554: */ ! 555: ! 556: x1 = rectPtr->bbox[0]; ! 557: y1 = rectPtr->bbox[1]; ! 558: x2 = rectPtr->bbox[2]; ! 559: y2 = rectPtr->bbox[3]; ! 560: if (rectPtr->outlineGC != None) { ! 561: inc = rectPtr->width/2.0; ! 562: x1 -= inc; ! 563: y1 -= inc; ! 564: x2 += inc; ! 565: y2 += inc; ! 566: } ! 567: ! 568: /* ! 569: * If the point is inside the rectangle, handle specially: ! 570: * distance is 0 if rectangle is filled, otherwise compute ! 571: * distance to nearest edge of rectangle and subtract width ! 572: * of edge. ! 573: */ ! 574: ! 575: if ((pointPtr[0] >= x1) && (pointPtr[0] < x2) ! 576: && (pointPtr[1] >= y1) && (pointPtr[1] < y2)) { ! 577: if ((rectPtr->fillGC != None) || (rectPtr->outlineGC == None)) { ! 578: return 0.0; ! 579: } ! 580: xDiff = pointPtr[0] - x1; ! 581: tmp = x2 - pointPtr[0]; ! 582: if (tmp < xDiff) { ! 583: xDiff = tmp; ! 584: } ! 585: yDiff = pointPtr[1] - y1; ! 586: tmp = y2 - pointPtr[1]; ! 587: if (tmp < yDiff) { ! 588: yDiff = tmp; ! 589: } ! 590: if (yDiff < xDiff) { ! 591: xDiff = yDiff; ! 592: } ! 593: xDiff -= rectPtr->width; ! 594: if (xDiff < 0.0) { ! 595: return 0.0; ! 596: } ! 597: return xDiff; ! 598: } ! 599: ! 600: /* ! 601: * Point is outside rectangle. ! 602: */ ! 603: ! 604: if (pointPtr[0] < x1) { ! 605: xDiff = x1 - pointPtr[0]; ! 606: } else if (pointPtr[0] > x2) { ! 607: xDiff = pointPtr[0] - x2; ! 608: } else { ! 609: xDiff = 0; ! 610: } ! 611: ! 612: if (pointPtr[1] < y1) { ! 613: yDiff = y1 - pointPtr[1]; ! 614: } else if (pointPtr[1] > y2) { ! 615: yDiff = pointPtr[1] - y2; ! 616: } else { ! 617: yDiff = 0; ! 618: } ! 619: ! 620: return hypot(xDiff, yDiff); ! 621: } ! 622: ! 623: /* ! 624: *-------------------------------------------------------------- ! 625: * ! 626: * OvalToPoint -- ! 627: * ! 628: * Computes the distance from a given point to a given ! 629: * oval, in canvas units. ! 630: * ! 631: * Results: ! 632: * The return value is 0 if the point whose x and y coordinates ! 633: * are coordPtr[0] and coordPtr[1] is inside the oval. If the ! 634: * point isn't inside the oval then the return value is the ! 635: * distance from the point to the oval. If itemPtr is filled, ! 636: * then anywhere in the interior is considered "inside"; if ! 637: * itemPtr isn't filled, then "inside" means only the area ! 638: * occupied by the outline. ! 639: * ! 640: * Side effects: ! 641: * None. ! 642: * ! 643: *-------------------------------------------------------------- ! 644: */ ! 645: ! 646: /* ARGSUSED */ ! 647: static double ! 648: OvalToPoint(canvasPtr, itemPtr, pointPtr) ! 649: Tk_Canvas *canvasPtr; /* Canvas containing item. */ ! 650: Tk_Item *itemPtr; /* Item to check against point. */ ! 651: double *pointPtr; /* Pointer to x and y coordinates. */ ! 652: { ! 653: register RectOvalItem *ovalPtr = (RectOvalItem *) itemPtr; ! 654: double width; ! 655: int filled; ! 656: ! 657: width = ovalPtr->width; ! 658: filled = ovalPtr->fillGC != None; ! 659: if (ovalPtr->outlineGC == None) { ! 660: width = 0.0; ! 661: filled = 1; ! 662: } ! 663: return TkOvalToPoint(ovalPtr->bbox, width, filled, pointPtr); ! 664: } ! 665: ! 666: /* ! 667: *-------------------------------------------------------------- ! 668: * ! 669: * RectToArea -- ! 670: * ! 671: * This procedure is called to determine whether an item ! 672: * lies entirely inside, entirely outside, or overlapping ! 673: * a given rectangle. ! 674: * ! 675: * Results: ! 676: * -1 is returned if the item is entirely outside the area ! 677: * given by rectPtr, 0 if it overlaps, and 1 if it is entirely ! 678: * inside the given area. ! 679: * ! 680: * Side effects: ! 681: * None. ! 682: * ! 683: *-------------------------------------------------------------- ! 684: */ ! 685: ! 686: /* ARGSUSED */ ! 687: static int ! 688: RectToArea(canvasPtr, itemPtr, areaPtr) ! 689: Tk_Canvas *canvasPtr; /* Canvas containing item. */ ! 690: Tk_Item *itemPtr; /* Item to check against rectangle. */ ! 691: double *areaPtr; /* Pointer to array of four coordinates ! 692: * (x1, y1, x2, y2) describing rectangular ! 693: * area. */ ! 694: { ! 695: register RectOvalItem *rectPtr = (RectOvalItem *) itemPtr; ! 696: double halfWidth; ! 697: ! 698: halfWidth = rectPtr->width/2.0; ! 699: if (rectPtr->outlineGC == None) { ! 700: halfWidth = 0.0; ! 701: } ! 702: ! 703: if ((areaPtr[2] <= (rectPtr->bbox[0] - halfWidth)) ! 704: || (areaPtr[0] >= (rectPtr->bbox[2] + halfWidth)) ! 705: || (areaPtr[3] <= (rectPtr->bbox[1] - halfWidth)) ! 706: || (areaPtr[1] >= (rectPtr->bbox[3] + halfWidth))) { ! 707: return -1; ! 708: } ! 709: if ((rectPtr->fillGC == None) && (rectPtr->outlineGC != None) ! 710: && (areaPtr[0] >= (rectPtr->bbox[0] + halfWidth)) ! 711: && (areaPtr[1] >= (rectPtr->bbox[1] + halfWidth)) ! 712: && (areaPtr[2] <= (rectPtr->bbox[2] - halfWidth)) ! 713: && (areaPtr[3] <= (rectPtr->bbox[3] - halfWidth))) { ! 714: return -1; ! 715: } ! 716: if ((areaPtr[0] <= (rectPtr->bbox[0] - halfWidth)) ! 717: && (areaPtr[1] <= (rectPtr->bbox[1] - halfWidth)) ! 718: && (areaPtr[2] >= (rectPtr->bbox[2] + halfWidth)) ! 719: && (areaPtr[3] >= (rectPtr->bbox[3] + halfWidth))) { ! 720: return 1; ! 721: } ! 722: return 0; ! 723: } ! 724: ! 725: /* ! 726: *-------------------------------------------------------------- ! 727: * ! 728: * OvalToArea -- ! 729: * ! 730: * This procedure is called to determine whether an item ! 731: * lies entirely inside, entirely outside, or overlapping ! 732: * a given rectangular area. ! 733: * ! 734: * Results: ! 735: * -1 is returned if the item is entirely outside the area ! 736: * given by rectPtr, 0 if it overlaps, and 1 if it is entirely ! 737: * inside the given area. ! 738: * ! 739: * Side effects: ! 740: * None. ! 741: * ! 742: *-------------------------------------------------------------- ! 743: */ ! 744: ! 745: /* ARGSUSED */ ! 746: static int ! 747: OvalToArea(canvasPtr, itemPtr, areaPtr) ! 748: Tk_Canvas *canvasPtr; /* Canvas containing item. */ ! 749: Tk_Item *itemPtr; /* Item to check against oval. */ ! 750: double *areaPtr; /* Pointer to array of four coordinates ! 751: * (x1, y1, x2, y2) describing rectangular ! 752: * area. */ ! 753: { ! 754: register RectOvalItem *ovalPtr = (RectOvalItem *) itemPtr; ! 755: double oval[4], halfWidth; ! 756: int result; ! 757: ! 758: /* ! 759: * Expand the oval to include the width of the outline, if any. ! 760: */ ! 761: ! 762: halfWidth = ovalPtr->width/2.0; ! 763: if (ovalPtr->outlineGC == None) { ! 764: halfWidth = 0.0; ! 765: } ! 766: oval[0] = ovalPtr->bbox[0] - halfWidth; ! 767: oval[1] = ovalPtr->bbox[1] - halfWidth; ! 768: oval[2] = ovalPtr->bbox[2] + halfWidth; ! 769: oval[3] = ovalPtr->bbox[3] + halfWidth; ! 770: ! 771: result = TkOvalToArea(oval, areaPtr); ! 772: ! 773: /* ! 774: * If the rectangle appears to overlap the oval and the oval ! 775: * isn't filled, do one more check to see if perhaps all four ! 776: * of the rectangle's corners are totally inside the oval's ! 777: * unfilled center, in which case we should return "outside". ! 778: */ ! 779: ! 780: if ((result == 0) && (ovalPtr->outlineGC != NULL) ! 781: && (ovalPtr->fillGC == NULL)) { ! 782: double centerX, centerY, width, height; ! 783: double xDelta1, yDelta1, xDelta2, yDelta2; ! 784: ! 785: centerX = (ovalPtr->bbox[0] + ovalPtr->bbox[2])/2.0; ! 786: centerY = (ovalPtr->bbox[1] + ovalPtr->bbox[3])/2.0; ! 787: width = (ovalPtr->bbox[2] - ovalPtr->bbox[0])/2.0 - halfWidth; ! 788: height = (ovalPtr->bbox[3] - ovalPtr->bbox[1])/2.0 - halfWidth; ! 789: xDelta1 = (areaPtr[0] - centerX)/width; ! 790: xDelta1 *= xDelta1; ! 791: yDelta1 = (areaPtr[1] - centerY)/height; ! 792: yDelta1 *= yDelta1; ! 793: xDelta2 = (areaPtr[2] - centerX)/width; ! 794: xDelta2 *= xDelta2; ! 795: yDelta2 = (areaPtr[3] - centerY)/height; ! 796: yDelta2 *= yDelta2; ! 797: if (((xDelta1 + yDelta1) < 1.0) ! 798: && ((xDelta1 + yDelta2) < 1.0) ! 799: && ((xDelta2 + yDelta1) < 1.0) ! 800: && ((xDelta2 + yDelta2) < 1.0)) { ! 801: return -1; ! 802: } ! 803: } ! 804: return result; ! 805: } ! 806: ! 807: /* ! 808: *-------------------------------------------------------------- ! 809: * ! 810: * ScaleRectOval -- ! 811: * ! 812: * This procedure is invoked to rescale a rectangle or oval ! 813: * item. ! 814: * ! 815: * Results: ! 816: * None. ! 817: * ! 818: * Side effects: ! 819: * The rectangle or oval referred to by itemPtr is rescaled ! 820: * so that the following transformation is applied to all ! 821: * point coordinates: ! 822: * x' = originX + scaleX*(x-originX) ! 823: * y' = originY + scaleY*(y-originY) ! 824: * ! 825: *-------------------------------------------------------------- ! 826: */ ! 827: ! 828: static void ! 829: ScaleRectOval(canvasPtr, itemPtr, originX, originY, scaleX, scaleY) ! 830: Tk_Canvas *canvasPtr; /* Canvas containing rectangle. */ ! 831: Tk_Item *itemPtr; /* Rectangle to be scaled. */ ! 832: double originX, originY; /* Origin about which to scale rect. */ ! 833: double scaleX; /* Amount to scale in X direction. */ ! 834: double scaleY; /* Amount to scale in Y direction. */ ! 835: { ! 836: register RectOvalItem *rectOvalPtr = (RectOvalItem *) itemPtr; ! 837: ! 838: rectOvalPtr->bbox[0] = originX + scaleX*(rectOvalPtr->bbox[0] - originX); ! 839: rectOvalPtr->bbox[1] = originY + scaleY*(rectOvalPtr->bbox[1] - originY); ! 840: rectOvalPtr->bbox[2] = originX + scaleX*(rectOvalPtr->bbox[2] - originX); ! 841: rectOvalPtr->bbox[3] = originY + scaleY*(rectOvalPtr->bbox[3] - originY); ! 842: ComputeRectOvalBbox(canvasPtr, rectOvalPtr); ! 843: } ! 844: ! 845: /* ! 846: *-------------------------------------------------------------- ! 847: * ! 848: * TranslateRectOval -- ! 849: * ! 850: * This procedure is called to move a rectangle or oval by a ! 851: * given amount. ! 852: * ! 853: * Results: ! 854: * None. ! 855: * ! 856: * Side effects: ! 857: * The position of the rectangle or oval is offset by ! 858: * (xDelta, yDelta), and the bounding box is updated in the ! 859: * generic part of the item structure. ! 860: * ! 861: *-------------------------------------------------------------- ! 862: */ ! 863: ! 864: static void ! 865: TranslateRectOval(canvasPtr, itemPtr, deltaX, deltaY) ! 866: Tk_Canvas *canvasPtr; /* Canvas containing item. */ ! 867: Tk_Item *itemPtr; /* Item that is being moved. */ ! 868: double deltaX, deltaY; /* Amount by which item is to be ! 869: * moved. */ ! 870: { ! 871: register RectOvalItem *rectOvalPtr = (RectOvalItem *) itemPtr; ! 872: ! 873: rectOvalPtr->bbox[0] += deltaX; ! 874: rectOvalPtr->bbox[1] += deltaY; ! 875: rectOvalPtr->bbox[2] += deltaX; ! 876: rectOvalPtr->bbox[3] += deltaY; ! 877: ComputeRectOvalBbox(canvasPtr, rectOvalPtr); ! 878: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.