|
|
1.1 ! root 1: /* ! 2: * tk3D.c -- ! 3: * ! 4: * This module provides procedures to draw borders in ! 5: * the three-dimensional Motif style. ! 6: * ! 7: * Copyright 1990 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/tk3d.c,v 1.30 92/06/15 14:28:18 ouster Exp $ SPRITE (Berkeley)"; ! 19: #endif ! 20: ! 21: #include "tkconfig.h" ! 22: #include "tk.h" ! 23: ! 24: /* ! 25: * One of the following data structures is allocated for ! 26: * each 3-D border currently in use. Structures of this ! 27: * type are indexed by borderTable, so that a single ! 28: * structure can be shared for several uses. ! 29: */ ! 30: ! 31: typedef struct { ! 32: Display *display; /* Display for which the resources ! 33: * below are allocated. */ ! 34: int refCount; /* Number of different users of ! 35: * this border. */ ! 36: XColor *bgColorPtr; /* Background color (intensity ! 37: * between lightColorPtr and ! 38: * darkColorPtr). */ ! 39: XColor *lightColorPtr; /* Color used for lighter areas of ! 40: * border (must free this when ! 41: * deleting structure). */ ! 42: XColor *darkColorPtr; /* Color for darker areas (must ! 43: * free when deleting structure). */ ! 44: Pixmap shadow; /* Stipple pattern to use for drawing ! 45: * lighter-shadow-ed areas. Only used on ! 46: * monochrome displays; on color displays ! 47: * this is None. */ ! 48: GC lightGC; /* Used to draw lighter parts of ! 49: * the border. */ ! 50: GC darkGC; /* Used to draw darker parts of the ! 51: * border. */ ! 52: GC bgGC; /* Used (if necessary) to draw areas in ! 53: * the background color. */ ! 54: Tcl_HashEntry *hashPtr; /* Entry in borderTable (needed in ! 55: * order to delete structure). */ ! 56: } Border; ! 57: ! 58: /* ! 59: * Hash table to map from a border's values (color, etc.) to a ! 60: * Border structure for those values. ! 61: */ ! 62: ! 63: static Tcl_HashTable borderTable; ! 64: typedef struct { ! 65: Tk_Uid colorName; /* Color for border. */ ! 66: Colormap colormap; /* Colormap used for allocating border ! 67: * colors. */ ! 68: Screen *screen; /* Screen on which border will be drawn. */ ! 69: } BorderKey; ! 70: ! 71: /* ! 72: * Maximum intensity for a color: ! 73: */ ! 74: ! 75: #define MAX_INTENSITY 65535 ! 76: ! 77: ! 78: static int initialized = 0; /* 0 means static structures haven't ! 79: * been initialized yet. */ ! 80: ! 81: /* ! 82: * Forward declarations for procedures defined in this file: ! 83: */ ! 84: ! 85: static void BorderInit _ANSI_ARGS_((void)); ! 86: static int Intersect _ANSI_ARGS_((XPoint *a1Ptr, XPoint *a2Ptr, ! 87: XPoint *b1Ptr, XPoint *b2Ptr, XPoint *iPtr)); ! 88: static void ShiftLine _ANSI_ARGS_((XPoint *p1Ptr, XPoint *p2Ptr, ! 89: int distance, XPoint *p3Ptr)); ! 90: ! 91: /* ! 92: *-------------------------------------------------------------- ! 93: * ! 94: * Tk_Get3DBorder -- ! 95: * ! 96: * Create a data structure for displaying a 3-D border. ! 97: * ! 98: * Results: ! 99: * The return value is a token for a data structure ! 100: * describing a 3-D border. This token may be passed ! 101: * to Tk_Draw3DRectangle and Tk_Free3DBorder. If an ! 102: * error prevented the border from being created then ! 103: * NULL is returned and an error message will be left ! 104: * in interp->result. ! 105: * ! 106: * Side effects: ! 107: * Data structures, graphics contexts, etc. are allocated. ! 108: * It is the caller's responsibility to eventually call ! 109: * Tk_Free3DBorder to release the resources. ! 110: * ! 111: *-------------------------------------------------------------- ! 112: */ ! 113: ! 114: Tk_3DBorder ! 115: Tk_Get3DBorder(interp, tkwin, colormap, colorName) ! 116: Tcl_Interp *interp; /* Place to store an error message. */ ! 117: Tk_Window tkwin; /* Token for window in which ! 118: * border will be drawn. */ ! 119: Colormap colormap; /* Colormap to use for allocating border ! 120: * colors. None means use default colormap ! 121: * for screen. */ ! 122: Tk_Uid colorName; /* String giving name of color ! 123: * for window background. */ ! 124: { ! 125: BorderKey key; ! 126: Tcl_HashEntry *hashPtr; ! 127: register Border *borderPtr; ! 128: int new; ! 129: unsigned long light, dark; ! 130: XGCValues gcValues; ! 131: unsigned long mask; ! 132: ! 133: if (!initialized) { ! 134: BorderInit(); ! 135: } ! 136: ! 137: /* ! 138: * First, check to see if there's already a border that will work ! 139: * for this request. ! 140: */ ! 141: ! 142: key.colorName = colorName; ! 143: if (colormap == None) { ! 144: colormap = Tk_DefaultColormap(Tk_Screen(tkwin)); ! 145: } ! 146: key.colormap = colormap; ! 147: key.screen = Tk_Screen(tkwin); ! 148: ! 149: hashPtr = Tcl_CreateHashEntry(&borderTable, (char *) &key, &new); ! 150: if (!new) { ! 151: borderPtr = (Border *) Tcl_GetHashValue(hashPtr); ! 152: borderPtr->refCount++; ! 153: } else { ! 154: ! 155: /* ! 156: * No satisfactory border exists yet. Initialize a new one. ! 157: */ ! 158: ! 159: borderPtr = (Border *) ckalloc(sizeof(Border)); ! 160: borderPtr->display = Tk_Display(tkwin); ! 161: borderPtr->refCount = 1; ! 162: borderPtr->bgColorPtr = NULL; ! 163: borderPtr->lightColorPtr = NULL; ! 164: borderPtr->darkColorPtr = NULL; ! 165: borderPtr->shadow = None; ! 166: borderPtr->lightGC = None; ! 167: borderPtr->darkGC = None; ! 168: borderPtr->bgGC = None; ! 169: borderPtr->hashPtr = hashPtr; ! 170: Tcl_SetHashValue(hashPtr, borderPtr); ! 171: ! 172: /* ! 173: * Figure out what colors and GC's to use for the light ! 174: * and dark areas and set up the graphics contexts. ! 175: * Monochrome displays get handled differently than ! 176: * color displays. ! 177: */ ! 178: ! 179: borderPtr->bgColorPtr = Tk_GetColor(interp, tkwin, ! 180: key.colormap, colorName); ! 181: if (borderPtr->bgColorPtr == NULL) { ! 182: goto error; ! 183: } ! 184: if (Tk_DefaultDepth(Tk_Screen(tkwin)) == 1) { ! 185: /* ! 186: * Monochrome display. ! 187: */ ! 188: ! 189: light = borderPtr->bgColorPtr->pixel; ! 190: if (light == WhitePixelOfScreen(Tk_Screen(tkwin))) { ! 191: dark = BlackPixelOfScreen(Tk_Screen(tkwin)); ! 192: } else { ! 193: dark = WhitePixelOfScreen(Tk_Screen(tkwin)); ! 194: } ! 195: borderPtr->shadow = Tk_GetBitmap(interp, tkwin, ! 196: Tk_GetUid("gray50")); ! 197: if (borderPtr->shadow == None) { ! 198: goto error; ! 199: } ! 200: } else { ! 201: XColor lightColor, darkColor; ! 202: int tmp; ! 203: ! 204: /* ! 205: * Color display. Compute the colors for the illuminated ! 206: * and shaded portions of the border. ! 207: */ ! 208: ! 209: tmp = (14*(int)borderPtr->bgColorPtr->red)/10; ! 210: if (tmp > MAX_INTENSITY) { ! 211: tmp = MAX_INTENSITY; ! 212: } ! 213: lightColor.red = tmp; ! 214: tmp = (14*(int)borderPtr->bgColorPtr->green)/10; ! 215: if (tmp > MAX_INTENSITY) { ! 216: tmp = MAX_INTENSITY; ! 217: } ! 218: lightColor.green = tmp; ! 219: tmp = (14*(int)borderPtr->bgColorPtr->blue)/10; ! 220: if (tmp > MAX_INTENSITY) { ! 221: tmp = MAX_INTENSITY; ! 222: } ! 223: lightColor.blue = tmp; ! 224: darkColor.red = (60*(int)borderPtr->bgColorPtr->red)/100; ! 225: darkColor.green = (60*(int)borderPtr->bgColorPtr->green)/100; ! 226: darkColor.blue = (60*(int)borderPtr->bgColorPtr->blue)/100; ! 227: borderPtr->lightColorPtr = Tk_GetColorByValue(interp, tkwin, ! 228: key.colormap, &lightColor); ! 229: if (borderPtr->lightColorPtr == NULL) { ! 230: goto error; ! 231: } ! 232: borderPtr->darkColorPtr = Tk_GetColorByValue(interp, tkwin, ! 233: key.colormap, &darkColor); ! 234: if (borderPtr->darkColorPtr == NULL) { ! 235: goto error; ! 236: } ! 237: light = borderPtr->lightColorPtr->pixel; ! 238: dark = borderPtr->darkColorPtr->pixel; ! 239: } ! 240: gcValues.foreground = light; ! 241: gcValues.background = dark; ! 242: mask = GCForeground|GCBackground; ! 243: if (borderPtr->shadow != None) { ! 244: gcValues.stipple = borderPtr->shadow; ! 245: gcValues.fill_style = FillOpaqueStippled; ! 246: mask |= GCStipple|GCFillStyle; ! 247: } ! 248: borderPtr->lightGC = Tk_GetGC(tkwin, mask, &gcValues); ! 249: gcValues.foreground = dark; ! 250: gcValues.background = light; ! 251: borderPtr->darkGC = Tk_GetGC(tkwin, GCForeground|GCBackground, ! 252: &gcValues); ! 253: gcValues.foreground = borderPtr->bgColorPtr->pixel; ! 254: borderPtr->bgGC = Tk_GetGC(tkwin, GCForeground, &gcValues); ! 255: } ! 256: return (Tk_3DBorder) borderPtr; ! 257: ! 258: error: ! 259: Tk_Free3DBorder((Tk_3DBorder) borderPtr); ! 260: return NULL; ! 261: } ! 262: ! 263: /* ! 264: *-------------------------------------------------------------- ! 265: * ! 266: * Tk_Draw3DRectangle -- ! 267: * ! 268: * Draw a 3-D border at a given place in a given window. ! 269: * ! 270: * Results: ! 271: * None. ! 272: * ! 273: * Side effects: ! 274: * A 3-D border will be drawn in the indicated drawable. ! 275: * The outside edges of the border will be determined by x, ! 276: * y, width, and height. The inside edges of the border ! 277: * will be determined by the borderWidth argument. ! 278: * ! 279: *-------------------------------------------------------------- ! 280: */ ! 281: ! 282: void ! 283: Tk_Draw3DRectangle(display, drawable, border, x, y, width, height, ! 284: borderWidth, relief) ! 285: Display *display; /* X display in which to draw. */ ! 286: Drawable drawable; /* X window or pixmap in which to draw. */ ! 287: Tk_3DBorder border; /* Token for border to draw. */ ! 288: int x, y, width, height; /* Outside area of region in ! 289: * which border will be drawn. */ ! 290: int borderWidth; /* Desired width for border, in ! 291: * pixels. */ ! 292: int relief; /* Should be either TK_RELIEF_RAISED ! 293: * or TK_RELIEF_SUNKEN; indicates ! 294: * position of interior of window relative ! 295: * to exterior. */ ! 296: { ! 297: register Border *borderPtr = (Border *) border; ! 298: GC top, bottom; ! 299: XPoint points[7]; ! 300: ! 301: if ((width < 2*borderWidth) || (height < 2*borderWidth)) { ! 302: return; ! 303: } ! 304: ! 305: if (relief == TK_RELIEF_RAISED) { ! 306: top = borderPtr->lightGC; ! 307: bottom = borderPtr->darkGC; ! 308: } else if (relief == TK_RELIEF_SUNKEN) { ! 309: top = borderPtr->darkGC; ! 310: bottom = borderPtr->lightGC; ! 311: } else { ! 312: top = bottom = borderPtr->bgGC; ! 313: } ! 314: XFillRectangle(display, drawable, bottom, x, y+height-borderWidth, ! 315: ! 316: (unsigned int) width, (unsigned int) borderWidth); ! 317: XFillRectangle(display, drawable, bottom, x+width-borderWidth, y, ! 318: (unsigned int) borderWidth, (unsigned int) height); ! 319: points[0].x = points[1].x = points[6].x = x; ! 320: points[0].y = points[6].y = y + height; ! 321: points[1].y = points[2].y = y; ! 322: points[2].x = x + width; ! 323: points[3].x = x + width - borderWidth; ! 324: points[3].y = points[4].y = y + borderWidth; ! 325: points[4].x = points[5].x = x + borderWidth; ! 326: points[5].y = y + height - borderWidth; ! 327: XFillPolygon(display, drawable, top, points, 7, Nonconvex, ! 328: CoordModeOrigin); ! 329: } ! 330: ! 331: /* ! 332: *-------------------------------------------------------------- ! 333: * ! 334: * Tk_NameOf3DBorder -- ! 335: * ! 336: * Given a border, return a textual string identifying the ! 337: * border's color. ! 338: * ! 339: * Results: ! 340: * The return value is the string that was used to create ! 341: * the border. ! 342: * ! 343: * Side effects: ! 344: * None. ! 345: * ! 346: *-------------------------------------------------------------- ! 347: */ ! 348: ! 349: char * ! 350: Tk_NameOf3DBorder(border) ! 351: Tk_3DBorder border; /* Token for border. */ ! 352: { ! 353: Border *borderPtr = (Border *) border; ! 354: ! 355: return ((BorderKey *) borderPtr->hashPtr->key.words)->colorName; ! 356: } ! 357: ! 358: /* ! 359: *-------------------------------------------------------------------- ! 360: * ! 361: * Tk_3DBorderColor -- ! 362: * ! 363: * Given a 3D border, return the X color used for the "flat" ! 364: * surfaces. ! 365: * ! 366: * Results: ! 367: * Returns the color used drawing flat surfaces with the border. ! 368: * ! 369: * Side effects: ! 370: * None. ! 371: * ! 372: *-------------------------------------------------------------------- ! 373: */ ! 374: XColor * ! 375: Tk_3DBorderColor(border) ! 376: Tk_3DBorder border; ! 377: { ! 378: return(((Border *) border)->bgColorPtr); ! 379: } ! 380: ! 381: /* ! 382: *-------------------------------------------------------------- ! 383: * ! 384: * Tk_Free3DBorder -- ! 385: * ! 386: * This procedure is called when a 3D border is no longer ! 387: * needed. It frees the resources associated with the ! 388: * border. After this call, the caller should never again ! 389: * use the "border" token. ! 390: * ! 391: * Results: ! 392: * None. ! 393: * ! 394: * Side effects: ! 395: * Resources are freed. ! 396: * ! 397: *-------------------------------------------------------------- ! 398: */ ! 399: ! 400: void ! 401: Tk_Free3DBorder(border) ! 402: Tk_3DBorder border; /* Token for border to be released. */ ! 403: { ! 404: register Border *borderPtr = (Border *) border; ! 405: ! 406: borderPtr->refCount--; ! 407: if (borderPtr->refCount == 0) { ! 408: if (borderPtr->bgColorPtr != NULL) { ! 409: Tk_FreeColor(borderPtr->bgColorPtr); ! 410: } ! 411: if (borderPtr->lightColorPtr != NULL) { ! 412: Tk_FreeColor(borderPtr->lightColorPtr); ! 413: } ! 414: if (borderPtr->darkColorPtr != NULL) { ! 415: Tk_FreeColor(borderPtr->darkColorPtr); ! 416: } ! 417: if (borderPtr->shadow != None) { ! 418: Tk_FreeBitmap(borderPtr->shadow); ! 419: } ! 420: if (borderPtr->lightGC != None) { ! 421: Tk_FreeGC(borderPtr->lightGC); ! 422: } ! 423: if (borderPtr->darkGC != None) { ! 424: Tk_FreeGC(borderPtr->darkGC); ! 425: } ! 426: if (borderPtr->bgGC != None) { ! 427: Tk_FreeGC(borderPtr->bgGC); ! 428: } ! 429: Tcl_DeleteHashEntry(borderPtr->hashPtr); ! 430: ckfree((char *) borderPtr); ! 431: } ! 432: } ! 433: ! 434: /* ! 435: *---------------------------------------------------------------------- ! 436: * ! 437: * Tk_SetBackgroundFromBorder -- ! 438: * ! 439: * Change the background of a window to one appropriate for a given ! 440: * 3-D border. ! 441: * ! 442: * Results: ! 443: * None. ! 444: * ! 445: * Side effects: ! 446: * Tkwin's background gets modified. ! 447: * ! 448: *---------------------------------------------------------------------- ! 449: */ ! 450: ! 451: void ! 452: Tk_SetBackgroundFromBorder(tkwin, border) ! 453: Tk_Window tkwin; /* Window whose background is to be set. */ ! 454: Tk_3DBorder border; /* Token for border. */ ! 455: { ! 456: register Border *borderPtr = (Border *) border; ! 457: ! 458: Tk_SetWindowBackground(tkwin, borderPtr->bgColorPtr->pixel); ! 459: } ! 460: ! 461: /* ! 462: *---------------------------------------------------------------------- ! 463: * ! 464: * Tk_GetRelief -- ! 465: * ! 466: * Parse a relief description and return the corresponding ! 467: * relief value, or an error. ! 468: * ! 469: * Results: ! 470: * A standard Tcl return value. If all goes well then ! 471: * *reliefPtr is filled in with one of the values ! 472: * TK_RELIEF_RAISED, TK_RELIEF_FLAT, or TK_RELIEF_SUNKEN. ! 473: * ! 474: * Side effects: ! 475: * None. ! 476: * ! 477: *---------------------------------------------------------------------- ! 478: */ ! 479: ! 480: int ! 481: Tk_GetRelief(interp, name, reliefPtr) ! 482: Tcl_Interp *interp; /* For error messages. */ ! 483: char *name; /* Name of a relief type. */ ! 484: int *reliefPtr; /* Where to store converted relief. */ ! 485: { ! 486: char c; ! 487: int length; ! 488: ! 489: c = name[0]; ! 490: length = strlen(name); ! 491: if ((c == 'f') && (strncmp(name, "flat", length) == 0)) { ! 492: *reliefPtr = TK_RELIEF_FLAT; ! 493: } else if ((c == 'r') && (strncmp(name, "raised", length) == 0)) { ! 494: *reliefPtr = TK_RELIEF_RAISED; ! 495: } else if ((c == 's') && (strncmp(name, "sunken", length) == 0)) { ! 496: *reliefPtr = TK_RELIEF_SUNKEN; ! 497: } else { ! 498: sprintf(interp->result, "bad relief type \"%.50s\": must be %s", ! 499: name, "flat, raised, or sunken"); ! 500: return TCL_ERROR; ! 501: } ! 502: return TCL_OK; ! 503: } ! 504: ! 505: /* ! 506: *-------------------------------------------------------------- ! 507: * ! 508: * Tk_NameOfRelief -- ! 509: * ! 510: * Given a relief value, produce a string describing that ! 511: * relief value. ! 512: * ! 513: * Results: ! 514: * The return value is a static string that is equivalent ! 515: * to relief. ! 516: * ! 517: * Side effects: ! 518: * None. ! 519: * ! 520: *-------------------------------------------------------------- ! 521: */ ! 522: ! 523: char * ! 524: Tk_NameOfRelief(relief) ! 525: int relief; /* One of TK_RELIEF_FLAT, TK_RELIEF_RAISED, ! 526: * or TK_RELIEF_SUNKEN. */ ! 527: { ! 528: if (relief == TK_RELIEF_FLAT) { ! 529: return "flat"; ! 530: } else if (relief == TK_RELIEF_SUNKEN) { ! 531: return "sunken"; ! 532: } else if (relief == TK_RELIEF_RAISED) { ! 533: return "raised"; ! 534: } else { ! 535: return "unknown relief"; ! 536: } ! 537: } ! 538: ! 539: /* ! 540: *-------------------------------------------------------------- ! 541: * ! 542: * Tk_Draw3DPolygon -- ! 543: * ! 544: * Draw a border with 3-D appearance around the edge of a ! 545: * given polygon. ! 546: * ! 547: * Results: ! 548: * None. ! 549: * ! 550: * Side effects: ! 551: * Information is drawn in "drawable" in the form of a ! 552: * 3-D border borderWidth units width wide on the left ! 553: * of the trajectory given by pointPtr and numPoints (or ! 554: * -borderWidth units wide on the right side, if borderWidth ! 555: * is negative. ! 556: * ! 557: *-------------------------------------------------------------- ! 558: */ ! 559: ! 560: void ! 561: Tk_Draw3DPolygon(display, drawable, border, pointPtr, numPoints, ! 562: borderWidth, leftRelief) ! 563: Display *display; /* X display in which to draw polygon. */ ! 564: Drawable drawable; /* X window or pixmap in which to draw. */ ! 565: Tk_3DBorder border; /* Token for border to draw. */ ! 566: XPoint *pointPtr; /* Array of points describing ! 567: * polygon. All points must be ! 568: * absolute (CoordModeOrigin). */ ! 569: int numPoints; /* Number of points at *pointPtr. */ ! 570: int borderWidth; /* Width of border, measured in ! 571: * pixels to the left of the polygon's ! 572: * trajectory. May be negative. */ ! 573: int leftRelief; /* TK_RELIEF_RAISED or ! 574: * TK_RELIEF_SUNKEN: indicates how ! 575: * stuff to left of trajectory looks ! 576: * relative to stuff on right. */ ! 577: { ! 578: XPoint poly[4], b1, b2, newB1, newB2; ! 579: XPoint perp, c, shift1, shift2; /* Used for handling parallel lines. */ ! 580: register XPoint *p1Ptr, *p2Ptr; ! 581: Border *borderPtr = (Border *) border; ! 582: GC gc; ! 583: int i, lightOnLeft, dx, dy, parallel, pointsSeen; ! 584: ! 585: /* ! 586: * If the polygon is already closed, drop the last point from it ! 587: * (we'll close it automatically). ! 588: */ ! 589: ! 590: p1Ptr = &pointPtr[numPoints-1]; ! 591: p2Ptr = &pointPtr[0]; ! 592: if ((p1Ptr->x == p2Ptr->x) && (p1Ptr->y == p2Ptr->y)) { ! 593: numPoints--; ! 594: } ! 595: ! 596: /* ! 597: * The loop below is executed once for each vertex in the polgon. ! 598: * At the beginning of each iteration things look like this: ! 599: * ! 600: * poly[1] / ! 601: * * / ! 602: * | / ! 603: * b1 * poly[0] (pointPtr[i-1]) ! 604: * | | ! 605: * | | ! 606: * | | ! 607: * | | ! 608: * | | ! 609: * | | *p1Ptr *p2Ptr ! 610: * b2 *--------------------* ! 611: * | ! 612: * | ! 613: * x------------------------- ! 614: * ! 615: * The job of this iteration is to do the following: ! 616: * (a) Compute x (the border corner corresponding to ! 617: * pointPtr[i]) and put it in poly[2]. As part of ! 618: * this, compute a new b1 and b2 value for the next ! 619: * side of the polygon. ! 620: * (b) Put pointPtr[i] into poly[3]. ! 621: * (c) Draw the polygon given by poly[0..3]. ! 622: * (d) Advance poly[0], poly[1], b1, and b2 for the ! 623: * next side of the polygon. ! 624: */ ! 625: ! 626: /* ! 627: * The above situation doesn't first come into existence until ! 628: * two points have been processed; the first two points are ! 629: * used to "prime the pump", so some parts of the processing ! 630: * are ommitted for these points. The variable "pointsSeen" ! 631: * keeps track of the priming process; it has to be separate ! 632: * from i in order to be able to ignore duplicate points in the ! 633: * polygon. ! 634: */ ! 635: ! 636: pointsSeen = 0; ! 637: for (i = -2, p1Ptr = &pointPtr[numPoints-2], p2Ptr = p1Ptr+1; ! 638: i < numPoints; i++, p1Ptr = p2Ptr, p2Ptr++) { ! 639: if ((i == -1) || (i == numPoints-1)) { ! 640: p2Ptr = pointPtr; ! 641: } ! 642: if ((p2Ptr->x == p1Ptr->x) && (p2Ptr->y == p1Ptr->y)) { ! 643: /* ! 644: * Ignore duplicate points (they'd cause core dumps in ! 645: * ShiftLine calls below). ! 646: */ ! 647: continue; ! 648: } ! 649: ShiftLine(p1Ptr, p2Ptr, borderWidth, &newB1); ! 650: newB2.x = newB1.x + (p2Ptr->x - p1Ptr->x); ! 651: newB2.y = newB1.y + (p2Ptr->y - p1Ptr->y); ! 652: poly[3] = *p1Ptr; ! 653: parallel = 0; ! 654: if (pointsSeen >= 1) { ! 655: parallel = Intersect(&newB1, &newB2, &b1, &b2, &poly[2]); ! 656: ! 657: /* ! 658: * If two consecutive segments of the polygon are parallel, ! 659: * then things get more complex. Consider the following ! 660: * diagram: ! 661: * ! 662: * poly[1] ! 663: * *----b1-----------b2------a ! 664: * \ ! 665: * \ ! 666: * *---------*----------* b ! 667: * poly[0] *p2Ptr *p1Ptr / ! 668: * / ! 669: * --*--------*----c ! 670: * newB1 newB2 ! 671: * ! 672: * Instead of using x and *p1Ptr for poly[2] and poly[3], as ! 673: * in the original diagram, use a and b as above. Then instead ! 674: * of using x and *p1Ptr for the new poly[0] and poly[1], use ! 675: * b and c as above. ! 676: * ! 677: * Do the computation in three stages: ! 678: * 1. Compute a point "perp" such that the line p1Ptr-perp ! 679: * is perpendicular to p1Ptr-p2Ptr. ! 680: * 2. Compute the points a and c by intersecting the lines ! 681: * b1-b2 and newB1-newB2 with p1Ptr-perp. ! 682: * 3. Compute b by shifting p1Ptr-perp to the right and ! 683: * intersecting it with p1Ptr-p2Ptr. ! 684: */ ! 685: ! 686: if (parallel) { ! 687: perp.x = p1Ptr->x + (p2Ptr->y - p1Ptr->y); ! 688: perp.y = p1Ptr->y - (p2Ptr->x - p1Ptr->x); ! 689: (void) Intersect(p1Ptr, &perp, &b1, &b2, &poly[2]); ! 690: (void) Intersect(p1Ptr, &perp, &newB1, &newB2, &c); ! 691: ShiftLine(p1Ptr, &perp, borderWidth, &shift1); ! 692: shift2.x = shift1.x + (perp.x - p1Ptr->x); ! 693: shift2.y = shift1.y + (perp.y - p1Ptr->y); ! 694: (void) Intersect(p1Ptr, p2Ptr, &shift1, &shift2, &poly[3]); ! 695: } ! 696: } ! 697: if (pointsSeen >= 2) { ! 698: dx = poly[3].x - poly[0].x; ! 699: dy = poly[3].y - poly[0].y; ! 700: if (dx > 0) { ! 701: lightOnLeft = (dy <= dx); ! 702: } else { ! 703: lightOnLeft = (dy < dx); ! 704: } ! 705: if (lightOnLeft ^ (leftRelief == TK_RELIEF_RAISED)) { ! 706: gc = borderPtr->lightGC; ! 707: } else { ! 708: gc = borderPtr->darkGC; ! 709: } ! 710: XFillPolygon(display, drawable, gc, poly, 4, Convex, ! 711: CoordModeOrigin); ! 712: } ! 713: b1.x = newB1.x; ! 714: b1.y = newB1.y; ! 715: b2.x = newB2.x; ! 716: b2.y = newB2.y; ! 717: poly[0].x = poly[3].x; ! 718: poly[0].y = poly[3].y; ! 719: if (parallel) { ! 720: poly[1].x = c.x; ! 721: poly[1].y = c.y; ! 722: } else if (pointsSeen >= 1) { ! 723: poly[1].x = poly[2].x; ! 724: poly[1].y = poly[2].y; ! 725: } ! 726: pointsSeen++; ! 727: } ! 728: } ! 729: ! 730: /* ! 731: *---------------------------------------------------------------------- ! 732: * ! 733: * Tk_Fill3DRectangle -- ! 734: * ! 735: * Fill a rectangular area, supplying a 3D border if desired. ! 736: * ! 737: * Results: ! 738: * None. ! 739: * ! 740: * Side effects: ! 741: * Information gets drawn on the screen. ! 742: * ! 743: *---------------------------------------------------------------------- ! 744: */ ! 745: ! 746: void ! 747: Tk_Fill3DRectangle(display, drawable, border, x, y, width, ! 748: height, borderWidth, relief) ! 749: Display *display; /* X display in which to draw rectangle. */ ! 750: Drawable drawable; /* X window or pixmap in which to draw. */ ! 751: Tk_3DBorder border; /* Token for border to draw. */ ! 752: int x, y, width, height; /* Outside area of rectangular region. */ ! 753: int borderWidth; /* Desired width for border, in ! 754: * pixels. Border will be *inside* region. */ ! 755: int relief; /* Indicates 3D effect: TK_RELIEF_FLAT, ! 756: * TK_RELIEF_RAISED, or TK_RELIEF_SUNKEN. */ ! 757: { ! 758: register Border *borderPtr = (Border *) border; ! 759: ! 760: XFillRectangle(display, drawable, borderPtr->bgGC, ! 761: x, y, (unsigned int) width, (unsigned int) height); ! 762: if (relief != TK_RELIEF_FLAT) { ! 763: Tk_Draw3DRectangle(display, drawable, border, x, y, width, ! 764: height, borderWidth, relief); ! 765: } ! 766: } ! 767: ! 768: /* ! 769: *---------------------------------------------------------------------- ! 770: * ! 771: * Tk_Fill3DPolygon -- ! 772: * ! 773: * Fill a polygonal area, supplying a 3D border if desired. ! 774: * ! 775: * Results: ! 776: * None. ! 777: * ! 778: * Side effects: ! 779: * Information gets drawn on the screen. ! 780: * ! 781: *---------------------------------------------------------------------- ! 782: */ ! 783: ! 784: void ! 785: Tk_Fill3DPolygon(display, drawable, border, pointPtr, numPoints, ! 786: borderWidth, leftRelief) ! 787: Display *display; /* X display in which to draw polygon. */ ! 788: Drawable drawable; /* X window or pixmap in which to draw. */ ! 789: Tk_3DBorder border; /* Token for border to draw. */ ! 790: XPoint *pointPtr; /* Array of points describing ! 791: * polygon. All points must be ! 792: * absolute (CoordModeOrigin). */ ! 793: int numPoints; /* Number of points at *pointPtr. */ ! 794: int borderWidth; /* Width of border, measured in ! 795: * pixels to the left of the polygon's ! 796: * trajectory. May be negative. */ ! 797: int leftRelief; /* Indicates 3D effect of left side of ! 798: * trajectory relative to right: ! 799: * TK_RELIEF_FLAT, TK_RELIEF_RAISED, ! 800: * or TK_RELIEF_SUNKEN. */ ! 801: { ! 802: register Border *borderPtr = (Border *) border; ! 803: ! 804: XFillPolygon(display, drawable, borderPtr->bgGC, ! 805: pointPtr, numPoints, Complex, CoordModeOrigin); ! 806: if (leftRelief != TK_RELIEF_FLAT) { ! 807: Tk_Draw3DPolygon(display, drawable, border, pointPtr, numPoints, ! 808: borderWidth, leftRelief); ! 809: } ! 810: } ! 811: ! 812: /* ! 813: *-------------------------------------------------------------- ! 814: * ! 815: * BorderInit -- ! 816: * ! 817: * Initialize the structures used for border management. ! 818: * ! 819: * Results: ! 820: * None. ! 821: * ! 822: * Side effects: ! 823: * Read the code. ! 824: * ! 825: *------------------------------------------------------------- ! 826: */ ! 827: ! 828: static void ! 829: BorderInit() ! 830: { ! 831: initialized = 1; ! 832: Tcl_InitHashTable(&borderTable, sizeof(BorderKey)/sizeof(int)); ! 833: } ! 834: ! 835: /* ! 836: *-------------------------------------------------------------- ! 837: * ! 838: * ShiftLine -- ! 839: * ! 840: * Given two points on a line, compute a point on a ! 841: * new line that is parallel to the given line and ! 842: * a given distance away from it. ! 843: * ! 844: * Results: ! 845: * None. ! 846: * ! 847: * Side effects: ! 848: * None. ! 849: * ! 850: *-------------------------------------------------------------- ! 851: */ ! 852: ! 853: static void ! 854: ShiftLine(p1Ptr, p2Ptr, distance, p3Ptr) ! 855: XPoint *p1Ptr; /* First point on line. */ ! 856: XPoint *p2Ptr; /* Second point on line. */ ! 857: int distance; /* New line is to be this many ! 858: * units to the left of original ! 859: * line, when looking from p1 to ! 860: * p2. May be negative. */ ! 861: XPoint *p3Ptr; /* Store coords of point on new ! 862: * line here. */ ! 863: { ! 864: int dx, dy, dxNeg, dyNeg; ! 865: ! 866: /* ! 867: * The table below is used for a quick approximation in ! 868: * computing the new point. An index into the table ! 869: * is 128 times the slope of the original line (the slope ! 870: * must always be between 0 and 1). The value of the table ! 871: * entry is 128 times the amount to displace the new line ! 872: * in y for each unit of perpendicular distance. In other ! 873: * words, the table maps from the tangent of an angle to ! 874: * the inverse of its cosine. If the slope of the original ! 875: * line is greater than 1, then the displacement is done in ! 876: * x rather than in y. ! 877: */ ! 878: ! 879: static int shiftTable[129]; ! 880: ! 881: /* ! 882: * Initialize the table if this is the first time it is ! 883: * used. ! 884: */ ! 885: ! 886: if (shiftTable[0] == 0) { ! 887: int i; ! 888: double tangent, cosine; ! 889: ! 890: for (i = 0; i <= 128; i++) { ! 891: tangent = i/128.0; ! 892: cosine = 128/cos(atan(tangent)) + .5; ! 893: shiftTable[i] = cosine; ! 894: } ! 895: } ! 896: ! 897: *p3Ptr = *p1Ptr; ! 898: dx = p2Ptr->x - p1Ptr->x; ! 899: dy = p2Ptr->y - p1Ptr->y; ! 900: if (dy < 0) { ! 901: dyNeg = 1; ! 902: dy = -dy; ! 903: } else { ! 904: dyNeg = 0; ! 905: } ! 906: if (dx < 0) { ! 907: dxNeg = 1; ! 908: dx = -dx; ! 909: } else { ! 910: dxNeg = 0; ! 911: } ! 912: if (dy <= dx) { ! 913: dy = ((distance * shiftTable[(dy<<7)/dx]) + 64) >> 7; ! 914: if (!dxNeg) { ! 915: dy = -dy; ! 916: } ! 917: p3Ptr->y += dy; ! 918: } else { ! 919: dx = ((distance * shiftTable[(dx<<7)/dy]) + 64) >> 7; ! 920: if (dyNeg) { ! 921: dx = -dx; ! 922: } ! 923: p3Ptr->x += dx; ! 924: } ! 925: } ! 926: ! 927: /* ! 928: *-------------------------------------------------------------- ! 929: * ! 930: * Intersect -- ! 931: * ! 932: * Find the intersection point between two lines. ! 933: * ! 934: * Results: ! 935: * Under normal conditions 0 is returned and the point ! 936: * at *iPtr is filled in with the intersection between ! 937: * the two lines. If the two lines are parallel, then ! 938: * -1 is returned and *iPtr isn't modified. ! 939: * ! 940: * Side effects: ! 941: * None. ! 942: * ! 943: *-------------------------------------------------------------- ! 944: */ ! 945: ! 946: static int ! 947: Intersect(a1Ptr, a2Ptr, b1Ptr, b2Ptr, iPtr) ! 948: XPoint *a1Ptr; /* First point of first line. */ ! 949: XPoint *a2Ptr; /* Second point of first line. */ ! 950: XPoint *b1Ptr; /* First point of second line. */ ! 951: XPoint *b2Ptr; /* Second point of second line. */ ! 952: XPoint *iPtr; /* Filled in with intersection point. */ ! 953: { ! 954: int dxadyb, dxbdya, dxadxb, dyadyb, p, q; ! 955: ! 956: /* ! 957: * The code below is just a straightforward manipulation of two ! 958: * equations of the form y = (x-x1)*(y2-y1)/(x2-x1) + y1 to solve ! 959: * for the x-coordinate of intersection, then the y-coordinate. ! 960: */ ! 961: ! 962: dxadyb = (a2Ptr->x - a1Ptr->x)*(b2Ptr->y - b1Ptr->y); ! 963: dxbdya = (b2Ptr->x - b1Ptr->x)*(a2Ptr->y - a1Ptr->y); ! 964: dxadxb = (a2Ptr->x - a1Ptr->x)*(b2Ptr->x - b1Ptr->x); ! 965: dyadyb = (a2Ptr->y - a1Ptr->y)*(b2Ptr->y - b1Ptr->y); ! 966: ! 967: if (dxadyb == dxbdya) { ! 968: return -1; ! 969: } ! 970: p = (a1Ptr->x*dxbdya - b1Ptr->x*dxadyb + (b1Ptr->y - a1Ptr->y)*dxadxb); ! 971: q = dxbdya - dxadyb; ! 972: if (q < 0) { ! 973: p = -p; ! 974: q = -q; ! 975: } ! 976: if (p < 0) { ! 977: iPtr->x = - ((-p + q/2)/q); ! 978: } else { ! 979: iPtr->x = (p + q/2)/q; ! 980: } ! 981: p = (a1Ptr->y*dxadyb - b1Ptr->y*dxbdya + (b1Ptr->x - a1Ptr->x)*dyadyb); ! 982: q = dxadyb - dxbdya; ! 983: if (q < 0) { ! 984: p = -p; ! 985: q = -q; ! 986: } ! 987: if (p < 0) { ! 988: iPtr->y = - ((-p + q/2)/q); ! 989: } else { ! 990: iPtr->y = (p + q/2)/q; ! 991: } ! 992: return 0; ! 993: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.