Annotation of micropolis/src/tk/tk3d.c, revision 1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.