]> git.zerfleddert.de Git - micropolis/blob - src/tk/tk3d.c
Import Micropolis from http://www.donhopkins.com/home/micropolis/
[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(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 \f
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 \f
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 \f
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 \f
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 \f
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 \f
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 \f
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 \f
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 \f
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 \f
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 \f
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 \f
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 \f
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 }
Impressum, Datenschutz