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