OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [tags/] [start/] [insight/] [tk/] [generic/] [tk3d.c] - Blame information for rev 1780

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.