|
|
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.