/[dtapublic]/projs/ets/trunk/src/c_tk_base_7_5_w_mods/tkcanvutil.c
ViewVC logotype

Diff of /projs/ets/trunk/src/c_tk_base_7_5_w_mods/tkcanvutil.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

sf_code/esrgpcpj/shared/tk_base/tkcanvutil.c revision 25 by dashley, Sat Oct 8 06:43:03 2016 UTC projs/trunk/shared_source/c_tk_base_7_5_w_mods/tkcanvutil.c revision 71 by dashley, Sat Nov 5 11:07:06 2016 UTC
# Line 1  Line 1 
 /* $Header: /cvsroot/esrg/sfesrg/esrgpcpj/shared/tk_base/tkcanvutil.c,v 1.1.1.1 2001/06/13 04:57:52 dtashley Exp $ */  
   
 /*  
  * tkCanvUtil.c --  
  *  
  *      This procedure contains a collection of utility procedures  
  *      used by the implementations of various canvas item types.  
  *  
  * Copyright (c) 1994 Sun Microsystems, Inc.  
  * Copyright (c) 1994 Sun Microsystems, Inc.  
  *  
  * See the file "license.terms" for information on usage and redistribution  
  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.  
  *  
  * RCS: @(#) $Id: tkcanvutil.c,v 1.1.1.1 2001/06/13 04:57:52 dtashley Exp $  
  */  
   
 #include "tkInt.h"  
 #include "tkCanvas.h"  
 #include "tkPort.h"  
   
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * Tk_CanvasTkwin --  
  *  
  *      Given a token for a canvas, this procedure returns the  
  *      widget that represents the canvas.  
  *  
  * Results:  
  *      The return value is a handle for the widget.  
  *  
  * Side effects:  
  *      None.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 Tk_Window  
 Tk_CanvasTkwin(canvas)  
     Tk_Canvas canvas;                   /* Token for the canvas. */  
 {  
     TkCanvas *canvasPtr = (TkCanvas *) canvas;  
     return canvasPtr->tkwin;  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * Tk_CanvasDrawableCoords --  
  *  
  *      Given an (x,y) coordinate pair within a canvas, this procedure  
  *      returns the corresponding coordinates at which the point should  
  *      be drawn in the drawable used for display.  
  *  
  * Results:  
  *      There is no return value.  The values at *drawableXPtr and  
  *      *drawableYPtr are filled in with the coordinates at which  
  *      x and y should be drawn.  These coordinates are clipped  
  *      to fit within a "short", since this is what X uses in  
  *      most cases for drawing.  
  *  
  * Side effects:  
  *      None.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 void  
 Tk_CanvasDrawableCoords(canvas, x, y, drawableXPtr, drawableYPtr)  
     Tk_Canvas canvas;                   /* Token for the canvas. */  
     double x, y;                        /* Coordinates in canvas space. */  
     short *drawableXPtr, *drawableYPtr; /* Screen coordinates are stored  
                                          * here. */  
 {  
     TkCanvas *canvasPtr = (TkCanvas *) canvas;  
     double tmp;  
   
     tmp = x - canvasPtr->drawableXOrigin;  
     if (tmp > 0) {  
         tmp += 0.5;  
     } else {  
         tmp -= 0.5;  
     }  
     if (tmp > 32767) {  
         *drawableXPtr = 32767;  
     } else if (tmp < -32768) {  
         *drawableXPtr = -32768;  
     } else {  
         *drawableXPtr = (short) tmp;  
     }  
   
     tmp = y  - canvasPtr->drawableYOrigin;  
     if (tmp > 0) {  
         tmp += 0.5;  
     } else {  
         tmp -= 0.5;  
     }  
     if (tmp > 32767) {  
         *drawableYPtr = 32767;  
     } else if (tmp < -32768) {  
         *drawableYPtr = -32768;  
     } else {  
         *drawableYPtr = (short) tmp;  
     }  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * Tk_CanvasWindowCoords --  
  *  
  *      Given an (x,y) coordinate pair within a canvas, this procedure  
  *      returns the corresponding coordinates in the canvas's window.  
  *  
  * Results:  
  *      There is no return value.  The values at *screenXPtr and  
  *      *screenYPtr are filled in with the coordinates at which  
  *      (x,y) appears in the canvas's window.  These coordinates  
  *      are clipped to fit within a "short", since this is what X  
  *      uses in most cases for drawing.  
  *  
  * Side effects:  
  *      None.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 void  
 Tk_CanvasWindowCoords(canvas, x, y, screenXPtr, screenYPtr)  
     Tk_Canvas canvas;                   /* Token for the canvas. */  
     double x, y;                        /* Coordinates in canvas space. */  
     short *screenXPtr, *screenYPtr;     /* Screen coordinates are stored  
                                          * here. */  
 {  
     TkCanvas *canvasPtr = (TkCanvas *) canvas;  
     double tmp;  
   
     tmp = x - canvasPtr->xOrigin;  
     if (tmp > 0) {  
         tmp += 0.5;  
     } else {  
         tmp -= 0.5;  
     }  
     if (tmp > 32767) {  
         *screenXPtr = 32767;  
     } else if (tmp < -32768) {  
         *screenXPtr = -32768;  
     } else {  
         *screenXPtr = (short) tmp;  
     }  
   
     tmp = y  - canvasPtr->yOrigin;  
     if (tmp > 0) {  
         tmp += 0.5;  
     } else {  
         tmp -= 0.5;  
     }  
     if (tmp > 32767) {  
         *screenYPtr = 32767;  
     } else if (tmp < -32768) {  
         *screenYPtr = -32768;  
     } else {  
         *screenYPtr = (short) tmp;  
     }  
 }  
   
 /*  
  *--------------------------------------------------------------  
  *  
  * Tk_CanvasGetCoord --  
  *  
  *      Given a string, returns a floating-point canvas coordinate  
  *      corresponding to that string.  
  *  
  * Results:  
  *      The return value is a standard Tcl return result.  If  
  *      TCL_OK is returned, then everything went well and the  
  *      canvas coordinate is stored at *doublePtr;  otherwise  
  *      TCL_ERROR is returned and an error message is left in  
  *      the interp's result.  
  *  
  * Side effects:  
  *      None.  
  *  
  *--------------------------------------------------------------  
  */  
   
 int  
 Tk_CanvasGetCoord(interp, canvas, string, doublePtr)  
     Tcl_Interp *interp;         /* Interpreter for error reporting. */  
     Tk_Canvas canvas;           /* Canvas to which coordinate applies. */  
     char *string;               /* Describes coordinate (any screen  
                                  * coordinate form may be used here). */  
     double *doublePtr;          /* Place to store converted coordinate. */  
 {  
     TkCanvas *canvasPtr = (TkCanvas *) canvas;  
     if (Tk_GetScreenMM(canvasPtr->interp, canvasPtr->tkwin, string,  
             doublePtr) != TCL_OK) {  
         return TCL_ERROR;  
     }  
     *doublePtr *= canvasPtr->pixelsPerMM;  
     return TCL_OK;  
 }  
   
 /*  
  *--------------------------------------------------------------  
  *  
  * Tk_CanvasGetCoordFromObj --  
  *  
  *      Given a string, returns a floating-point canvas coordinate  
  *      corresponding to that string.  
  *  
  * Results:  
  *      The return value is a standard Tcl return result.  If  
  *      TCL_OK is returned, then everything went well and the  
  *      canvas coordinate is stored at *doublePtr;  otherwise  
  *      TCL_ERROR is returned and an error message is left in  
  *      interp->result.  
  *  
  * Side effects:  
  *      None.  
  *  
  *--------------------------------------------------------------  
  */  
   
 int  
 Tk_CanvasGetCoordFromObj(interp, canvas, obj, doublePtr)  
     Tcl_Interp *interp;         /* Interpreter for error reporting. */  
     Tk_Canvas canvas;           /* Canvas to which coordinate applies. */  
     Tcl_Obj *obj;               /* Describes coordinate (any screen  
                                  * coordinate form may be used here). */  
     double *doublePtr;          /* Place to store converted coordinate. */  
 {  
     TkCanvas *canvasPtr = (TkCanvas *) canvas;  
     if (Tk_GetMMFromObj(canvasPtr->interp, canvasPtr->tkwin, obj,  
             doublePtr) != TCL_OK) {  
         return TCL_ERROR;  
     }  
     *doublePtr *= canvasPtr->pixelsPerMM;  
     return TCL_OK;  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * Tk_CanvasSetStippleOrigin --  
  *  
  *      This procedure sets the stipple origin in a graphics context  
  *      so that stipples drawn with the GC will line up with other  
  *      stipples previously drawn in the canvas.  
  *  
  * Results:  
  *      None.  
  *  
  * Side effects:  
  *      The graphics context is modified.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 void  
 Tk_CanvasSetStippleOrigin(canvas, gc)  
     Tk_Canvas canvas;           /* Token for a canvas. */  
     GC gc;                      /* Graphics context that is about to be  
                                  * used to draw a stippled pattern as  
                                  * part of redisplaying the canvas. */  
   
 {  
     TkCanvas *canvasPtr = (TkCanvas *) canvas;  
   
     XSetTSOrigin(canvasPtr->display, gc, -canvasPtr->drawableXOrigin,  
             -canvasPtr->drawableYOrigin);  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * Tk_CanvasSetOffset--  
  *  
  *      This procedure sets the stipple offset in a graphics  
  *      context so that stipples drawn with the GC will  
  *      line up with other stipples with the same offset.  
  *  
  * Results:  
  *      None.  
  *  
  * Side effects:  
  *      The graphics context is modified.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 void  
 Tk_CanvasSetOffset(canvas, gc, offset)  
     Tk_Canvas canvas;           /* Token for a canvas. */  
     GC gc;                      /* Graphics context that is about to be  
                                  * used to draw a stippled pattern as  
                                  * part of redisplaying the canvas. */  
     Tk_TSOffset *offset;        /* offset (may be NULL pointer)*/  
 {  
     TkCanvas *canvasPtr = (TkCanvas *) canvas;  
     int flags = 0;  
     int x = - canvasPtr->drawableXOrigin;  
     int y = - canvasPtr->drawableYOrigin;  
   
     if (offset != NULL) {  
         flags = offset->flags;  
         x += offset->xoffset;  
         y += offset->yoffset;  
     }  
     if ((flags & TK_OFFSET_RELATIVE) && !(flags & TK_OFFSET_INDEX)) {  
         Tk_SetTSOrigin(canvasPtr->tkwin, gc, x - canvasPtr->xOrigin,  
                 y - canvasPtr->yOrigin);  
     } else {  
         XSetTSOrigin(canvasPtr->display, gc, x, y);  
     }  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * Tk_CanvasGetTextInfo --  
  *  
  *      This procedure returns a pointer to a structure containing  
  *      information about the selection and insertion cursor for  
  *      a canvas widget.  Items such as text items save the pointer  
  *      and use it to share access to the information with the generic  
  *      canvas code.  
  *  
  * Results:  
  *      The return value is a pointer to the structure holding text  
  *      information for the canvas.  Most of the fields should not  
  *      be modified outside the generic canvas code;  see the user  
  *      documentation for details.  
  *  
  * Side effects:  
  *      None.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 Tk_CanvasTextInfo *  
 Tk_CanvasGetTextInfo(canvas)  
     Tk_Canvas canvas;                   /* Token for the canvas widget. */  
 {  
     return &((TkCanvas *) canvas)->textInfo;  
 }  
   
 /*  
  *--------------------------------------------------------------  
  *  
  * Tk_CanvasTagsParseProc --  
  *  
  *      This procedure is invoked during option processing to handle  
  *      "-tags" options for canvas items.  
  *  
  * Results:  
  *      A standard Tcl return value.  
  *  
  * Side effects:  
  *      The tags for a given item get replaced by those indicated  
  *      in the value argument.  
  *  
  *--------------------------------------------------------------  
  */  
   
 int  
 Tk_CanvasTagsParseProc(clientData, interp, tkwin, value, widgRec, offset)  
     ClientData clientData;              /* Not used.*/  
     Tcl_Interp *interp;                 /* Used for reporting errors. */  
     Tk_Window tkwin;                    /* Window containing canvas widget. */  
     char *value;                        /* Value of option (list of tag  
                                          * names). */  
     char *widgRec;                      /* Pointer to record for item. */  
     int offset;                         /* Offset into item (ignored). */  
 {  
     register Tk_Item *itemPtr = (Tk_Item *) widgRec;  
     int argc, i;  
     char **argv;  
     Tk_Uid *newPtr;  
   
     /*  
      * Break the value up into the individual tag names.  
      */  
   
     if (Tcl_SplitList(interp, value, &argc, &argv) != TCL_OK) {  
         return TCL_ERROR;  
     }  
   
     /*  
      * Make sure that there's enough space in the item to hold the  
      * tag names.  
      */  
   
     if (itemPtr->tagSpace < argc) {  
         newPtr = (Tk_Uid *) ckalloc((unsigned) (argc * sizeof(Tk_Uid)));  
         for (i = itemPtr->numTags-1; i >= 0; i--) {  
             newPtr[i] = itemPtr->tagPtr[i];  
         }  
         if (itemPtr->tagPtr != itemPtr->staticTagSpace) {  
             ckfree((char *) itemPtr->tagPtr);  
         }  
         itemPtr->tagPtr = newPtr;  
         itemPtr->tagSpace = argc;  
     }  
     itemPtr->numTags = argc;  
     for (i = 0; i < argc; i++) {  
         itemPtr->tagPtr[i] = Tk_GetUid(argv[i]);  
     }  
     ckfree((char *) argv);  
     return TCL_OK;  
 }  
   
 /*  
  *--------------------------------------------------------------  
  *  
  * Tk_CanvasTagsPrintProc --  
  *  
  *      This procedure is invoked by the Tk configuration code  
  *      to produce a printable string for the "-tags" configuration  
  *      option for canvas items.  
  *  
  * Results:  
  *      The return value is a string describing all the tags for  
  *      the item referred to by "widgRec".  In addition, *freeProcPtr  
  *      is filled in with the address of a procedure to call to free  
  *      the result string when it's no longer needed (or NULL to  
  *      indicate that the string doesn't need to be freed).  
  *  
  * Side effects:  
  *      None.  
  *  
  *--------------------------------------------------------------  
  */  
   
 char *  
 Tk_CanvasTagsPrintProc(clientData, tkwin, widgRec, offset, freeProcPtr)  
     ClientData clientData;              /* Ignored. */  
     Tk_Window tkwin;                    /* Window containing canvas widget. */  
     char *widgRec;                      /* Pointer to record for item. */  
     int offset;                         /* Ignored. */  
     Tcl_FreeProc **freeProcPtr;         /* Pointer to variable to fill in with  
                                          * information about how to reclaim  
                                          * storage for return string. */  
 {  
     register Tk_Item *itemPtr = (Tk_Item *) widgRec;  
   
     if (itemPtr->numTags == 0) {  
         *freeProcPtr = (Tcl_FreeProc *) NULL;  
         return "";  
     }  
     if (itemPtr->numTags == 1) {  
         *freeProcPtr = (Tcl_FreeProc *) NULL;  
         return (char *) itemPtr->tagPtr[0];  
     }  
     *freeProcPtr = TCL_DYNAMIC;  
     return Tcl_Merge(itemPtr->numTags, (char **) itemPtr->tagPtr);  
 }  
   
   
 static int      DashConvert _ANSI_ARGS_((char *l, CONST char *p,  
                         int n, double width));  
 #define ABS(a) ((a>=0)?(a):(-(a)))  
   
 /*  
  *--------------------------------------------------------------  
  *  
  * TkCanvasDashParseProc --  
  *  
  *      This procedure is invoked during option processing to handle  
  *      "-dash", "-activedash" and "-disableddash" options for canvas  
  *      objects.  
  *  
  * Results:  
  *      A standard Tcl return value.  
  *  
  * Side effects:  
  *      The dash list for a given canvas object gets replaced by  
  *      those indicated in the value argument.  
  *  
  *--------------------------------------------------------------  
  */  
   
 int  
 TkCanvasDashParseProc(clientData, interp, tkwin, value, widgRec, offset)  
     ClientData clientData;              /* Not used.*/  
     Tcl_Interp *interp;                 /* Used for reporting errors. */  
     Tk_Window tkwin;                    /* Window containing canvas widget. */  
     CONST char *value;                  /* Value of option. */  
     char *widgRec;                      /* Pointer to record for item. */  
     int offset;                         /* Offset into item. */  
 {  
     return Tk_GetDash(interp, value, (Tk_Dash *)(widgRec+offset));  
 }  
   
 /*  
  *--------------------------------------------------------------  
  *  
  * TkCanvasDashPrintProc --  
  *  
  *      This procedure is invoked by the Tk configuration code  
  *      to produce a printable string for the "-dash", "-activedash"  
  *      and "-disableddash" configuration options for canvas items.  
  *  
  * Results:  
  *      The return value is a string describing all the dash list for  
  *      the item referred to by "widgRec"and "offset".  In addition,  
  *      *freeProcPtr is filled in with the address of a procedure to  
  *      call to free the result string when it's no longer needed (or  
  *      NULL to indicate that the string doesn't need to be freed).  
  *  
  * Side effects:  
  *      None.  
  *  
  *--------------------------------------------------------------  
  */  
   
 char *  
 TkCanvasDashPrintProc(clientData, tkwin, widgRec, offset, freeProcPtr)  
     ClientData clientData;              /* Ignored. */  
     Tk_Window tkwin;                    /* Window containing canvas widget. */  
     char *widgRec;                      /* Pointer to record for item. */  
     int offset;                         /* Offset in record for item. */  
     Tcl_FreeProc **freeProcPtr;         /* Pointer to variable to fill in with  
                                          * information about how to reclaim  
                                          * storage for return string. */  
 {  
     Tk_Dash *dash = (Tk_Dash *) (widgRec+offset);  
     char *buffer;  
     char *p;  
     int i = dash->number;  
   
     if (i < 0) {  
         i = -i;  
         *freeProcPtr = TCL_DYNAMIC;  
         buffer = (char *) ckalloc((unsigned int) (i+1));  
         p = (i > sizeof(char *)) ? dash->pattern.pt : dash->pattern.array;  
         memcpy(buffer, p, (unsigned int) i);  
         buffer[i] = 0;  
         return buffer;  
     } else if (!i) {  
         *freeProcPtr = (Tcl_FreeProc *) NULL;  
         return "";  
     }  
     buffer = (char *)ckalloc((unsigned int) (4*i));  
     *freeProcPtr = TCL_DYNAMIC;  
   
     p = (i > sizeof(char *)) ? dash->pattern.pt : dash->pattern.array;  
     sprintf(buffer, "%d", *p++ & 0xff);  
     while(--i) {  
         sprintf(buffer+strlen(buffer), " %d", *p++ & 0xff);  
     }  
     return buffer;  
 }  
   
 /*  
  *--------------------------------------------------------------  
  *  
  * Tk_CreateSmoothMethod --  
  *  
  *      This procedure is invoked to add additional values  
  *      for the "-smooth" option to the list.  
  *  
  * Results:  
  *      A standard Tcl return value.  
  *  
  * Side effects:  
  *      In the future "-smooth <name>" will be accepted as  
  *      smooth method for the line and polygon.  
  *  
  *--------------------------------------------------------------  
  */  
   
 Tk_SmoothMethod tkBezierSmoothMethod = {  
     "bezier",  
     TkMakeBezierCurve,  
     (void (*) _ANSI_ARGS_((Tcl_Interp *interp, Tk_Canvas canvas,  
             double *coordPtr, int numPoints, int numSteps)))  
                 TkMakeBezierPostscript,  
 };  
   
 static void SmoothMethodCleanupProc _ANSI_ARGS_((ClientData clientData,  
                 Tcl_Interp *interp));  
   
 typedef struct SmoothAssocData {  
     struct SmoothAssocData *nextPtr;    /* pointer to next SmoothAssocData */  
     Tk_SmoothMethod smooth;             /* name and functions associated with this  
                                          * option */  
 } SmoothAssocData;  
   
 void  
 Tk_CreateSmoothMethod(interp, smooth)  
     Tcl_Interp *interp;  
     Tk_SmoothMethod *smooth;  
 {  
     SmoothAssocData *methods, *typePtr2, *prevPtr, *ptr;  
     methods = (SmoothAssocData *) Tcl_GetAssocData(interp, "smoothMethod",  
             (Tcl_InterpDeleteProc **) NULL);  
   
     /*  
      * If there's already a smooth method with the given name, remove it.  
      */  
   
     for (typePtr2 = methods, prevPtr = NULL; typePtr2 != NULL;  
             prevPtr = typePtr2, typePtr2 = typePtr2->nextPtr) {  
         if (!strcmp(typePtr2->smooth.name, smooth->name)) {  
             if (prevPtr == NULL) {  
                 methods = typePtr2->nextPtr;  
             } else {  
                 prevPtr->nextPtr = typePtr2->nextPtr;  
             }  
             ckfree((char *) typePtr2);  
             break;  
         }  
     }  
     ptr = (SmoothAssocData *) ckalloc(sizeof(SmoothAssocData));  
     ptr->smooth.name = smooth->name;  
     ptr->smooth.coordProc = smooth->coordProc;  
     ptr->smooth.postscriptProc = smooth->postscriptProc;  
     ptr->nextPtr = methods;  
     Tcl_SetAssocData(interp, "smoothMethod", SmoothMethodCleanupProc,  
                 (ClientData) ptr);  
 }  
 /*  
  *----------------------------------------------------------------------  
  *  
  * SmoothMethodCleanupProc --  
  *  
  *      This procedure is invoked whenever an interpreter is deleted  
  *      to cleanup the smooth methods.  
  *  
  * Results:  
  *      None.  
  *  
  * Side effects:  
  *      Smooth methods are removed.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 static void  
 SmoothMethodCleanupProc(clientData, interp)  
     ClientData clientData;      /* Points to "smoothMethod" AssocData  
                                  * for the interpreter. */  
     Tcl_Interp *interp;         /* Interpreter that is being deleted. */  
 {  
     SmoothAssocData *ptr, *methods = (SmoothAssocData *) clientData;  
   
     while (methods != NULL) {  
         methods = (ptr = methods)->nextPtr;  
         ckfree((char *) ptr);  
     }  
 }  
 /*  
  *--------------------------------------------------------------  
  *  
  * TkSmoothParseProc --  
  *  
  *      This procedure is invoked during option processing to handle  
  *      the "-smooth" option.  
  *  
  * Results:  
  *      A standard Tcl return value.  
  *  
  * Side effects:  
  *      The smooth option for a given item gets replaced by the value  
  *      indicated in the value argument.  
  *  
  *--------------------------------------------------------------  
  */  
   
 int  
 TkSmoothParseProc(clientData, interp, tkwin, value, widgRec, offset)  
     ClientData clientData;              /* some flags.*/  
     Tcl_Interp *interp;                 /* Used for reporting errors. */  
     Tk_Window tkwin;                    /* Window containing canvas widget. */  
     CONST char *value;                  /* Value of option. */  
     char *widgRec;                      /* Pointer to record for item. */  
     int offset;                         /* Offset into item. */  
 {  
     register Tk_SmoothMethod **smoothPtr =  
         (Tk_SmoothMethod **) (widgRec + offset);  
     Tk_SmoothMethod *smooth = NULL;  
     int b;  
     size_t length;  
     SmoothAssocData *methods;  
   
     if (value == NULL || *value == 0) {  
         *smoothPtr = (Tk_SmoothMethod *) NULL;  
         return TCL_OK;  
     }  
     length = strlen(value);  
     methods = (SmoothAssocData *) Tcl_GetAssocData(interp, "smoothMethod",  
             (Tcl_InterpDeleteProc **) NULL);  
     while (methods != (SmoothAssocData *) NULL) {  
         if (strncmp(value, methods->smooth.name, length) == 0) {  
             if (smooth != (Tk_SmoothMethod *) NULL) {  
                 Tcl_AppendResult(interp, "ambigeous smooth method \"", value,  
                         "\"", (char *) NULL);  
                 return TCL_ERROR;  
             }  
             smooth = &methods->smooth;  
         }  
         methods = methods->nextPtr;  
     }  
     if (smooth) {  
         *smoothPtr = smooth;  
         return TCL_OK;  
     }  
   
     if (Tcl_GetBoolean(interp, (char *) value, &b) != TCL_OK) {  
         return TCL_ERROR;  
     }  
     *smoothPtr = b ? &tkBezierSmoothMethod : (Tk_SmoothMethod*) NULL;  
     return TCL_OK;  
 }  
 /*  
  *--------------------------------------------------------------  
  *  
  * TkSmoothPrintProc --  
  *  
  *      This procedure is invoked by the Tk configuration code  
  *      to produce a printable string for the "-smooth"  
  *      configuration option.  
  *  
  * Results:  
  *      The return value is a string describing the smooth option for  
  *      the item referred to by "widgRec".  In addition, *freeProcPtr  
  *      is filled in with the address of a procedure to call to free  
  *      the result string when it's no longer needed (or NULL to  
  *      indicate that the string doesn't need to be freed).  
  *  
  * Side effects:  
  *      None.  
  *  
  *--------------------------------------------------------------  
  */  
   
 char *  
 TkSmoothPrintProc(clientData, tkwin, widgRec, offset, freeProcPtr)  
     ClientData clientData;              /* Ignored. */  
     Tk_Window tkwin;                    /* Window containing canvas widget. */  
     char *widgRec;                      /* Pointer to record for item. */  
     int offset;                         /* Offset into item. */  
     Tcl_FreeProc **freeProcPtr;         /* Pointer to variable to fill in with  
                                          * information about how to reclaim  
                                          * storage for return string. */  
 {  
     register Tk_SmoothMethod **smoothPtr = (Tk_SmoothMethod **) (widgRec + offset);  
   
     return (*smoothPtr) ? (*smoothPtr)->name : "0";  
 }  
 /*  
  *--------------------------------------------------------------  
  *  
  * Tk_GetDash  
  *  
  *      This procedure is used to parse a string, assuming  
  *      it is dash information.  
  *  
  * Results:  
  *      The return value is a standard Tcl result:  TCL_OK means  
  *      that the dash information was parsed ok, and  
  *      TCL_ERROR means it couldn't be parsed.  
  *  
  * Side effects:  
  *      Dash information in the dash structure is updated.  
  *  
  *--------------------------------------------------------------  
  */  
   
 int  
 Tk_GetDash(interp, value, dash)  
     Tcl_Interp *interp;         /* Used for error reporting. */  
     CONST char *value;          /* Textual specification of dash list. */  
     Tk_Dash *dash;              /* Pointer to record in which to  
                                  * store dash information. */  
 {  
     int argc, i;  
     char **largv, **argv = NULL;  
     char *pt;  
   
     if ((value==(char *) NULL) || (*value==0) ) {  
         dash->number = 0;  
         return TCL_OK;  
     }  
     if ((*value == '.') || (*value == ',') ||  
             (*value == '-') || (*value == '_')) {  
         i = DashConvert((char *) NULL, value, -1, 0.0);  
         if (i>0) {  
             i = strlen(value);  
         } else {  
             goto badDashList;  
         }  
         if (i > sizeof(char *)) {  
             dash->pattern.pt = pt = (char *) ckalloc(strlen(value));  
         } else {  
             pt = dash->pattern.array;  
         }  
         memcpy(pt,value, (unsigned int) i);  
         dash->number = -i;  
         return TCL_OK;  
     }  
     if (Tcl_SplitList(interp, (char *) value, &argc, &argv) != TCL_OK) {  
         Tcl_ResetResult(interp);  
     badDashList:  
         Tcl_AppendResult(interp, "bad dash list \"", value,  
                 "\": must be a list of integers or a format like \"-..\"",  
                 (char *) NULL);  
     syntaxError:  
         if (argv != NULL) {  
             ckfree((char *) argv);  
         }  
         if (ABS(dash->number) > sizeof(char *))  
             ckfree((char *) dash->pattern.pt);  
         dash->number = 0;  
         return TCL_ERROR;  
     }  
   
     if (ABS(dash->number) > sizeof(char *)) {  
         ckfree((char *) dash->pattern.pt);  
     }  
     if (argc > sizeof(char *)) {  
         dash->pattern.pt = pt = (char *) ckalloc((unsigned int) argc);  
     } else {  
         pt = dash->pattern.array;  
     }  
     dash->number = argc;  
   
     largv = argv;  
     while(argc>0) {  
         if (Tcl_GetInt(interp, *largv, &i) != TCL_OK ||  
             i < 1 || i>255) {  
             Tcl_ResetResult(interp);  
             Tcl_AppendResult(interp, "expected integer in the range 1..255 but got \"",  
                          *largv, "\"", (char *) NULL);  
             goto syntaxError;  
         }  
         *pt++ = i;  
         argc--; largv++;  
     }  
     
     if (argv != NULL) {  
         ckfree((char *) argv);  
     }  
   
     return TCL_OK;  
 }  
   
 /*  
  *--------------------------------------------------------------  
  *  
  * Tk_CreateOutline  
  *  
  *      This procedure initializes the Tk_Outline structure  
  *      with default values.  
  *  
  * Results:  
  *      None  
  *  
  * Side effects:  
  *      None  
  *  
  *--------------------------------------------------------------  
  */  
   
 void Tk_CreateOutline(outline)  
     Tk_Outline *outline;  
 {  
     outline->gc = None;  
     outline->width = 1.0;  
     outline->activeWidth = 0.0;  
     outline->disabledWidth = 0.0;  
     outline->offset = 0;  
     outline->dash.number = 0;  
     outline->activeDash.number = 0;  
     outline->disabledDash.number = 0;  
     outline->tsoffset.flags = 0;  
     outline->tsoffset.xoffset = 0;  
     outline->tsoffset.yoffset = 0;  
     outline->color = NULL;  
     outline->activeColor = NULL;  
     outline->disabledColor = NULL;  
     outline->stipple = None;  
     outline->activeStipple = None;  
     outline->disabledStipple = None;  
 }  
   
 /*  
  *--------------------------------------------------------------  
  *  
  * Tk_DeleteOutline  
  *  
  *      This procedure frees all memory that might be  
  *      allocated and referenced in the Tk_Outline structure.  
  *  
  * Results:  
  *      None  
  *  
  * Side effects:  
  *      None  
  *  
  *--------------------------------------------------------------  
  */  
   
 void Tk_DeleteOutline(display, outline)  
     Display *display;                   /* Display containing window */  
     Tk_Outline *outline;  
 {  
     if (outline->gc != None) {  
         Tk_FreeGC(display, outline->gc);  
     }  
     if (ABS(outline->dash.number) > sizeof(char *)) {  
         ckfree((char *) outline->dash.pattern.pt);  
     }  
     if (ABS(outline->activeDash.number) > sizeof(char *)) {  
         ckfree((char *) outline->activeDash.pattern.pt);  
     }  
     if (ABS(outline->disabledDash.number) > sizeof(char *)) {  
         ckfree((char *) outline->disabledDash.pattern.pt);  
     }  
     if (outline->color != NULL) {  
         Tk_FreeColor(outline->color);  
     }  
     if (outline->activeColor != NULL) {  
         Tk_FreeColor(outline->activeColor);  
     }  
     if (outline->disabledColor != NULL) {  
         Tk_FreeColor(outline->disabledColor);  
     }  
     if (outline->stipple != None) {  
         Tk_FreeBitmap(display, outline->stipple);  
     }  
     if (outline->activeStipple != None) {  
         Tk_FreeBitmap(display, outline->activeStipple);  
     }  
     if (outline->disabledStipple != None) {  
         Tk_FreeBitmap(display, outline->disabledStipple);  
     }  
 }  
   
 /*  
  *--------------------------------------------------------------  
  *  
  * Tk_ConfigOutlineGC  
  *  
  *      This procedure should be called in the canvas object  
  *      during the configure command. The graphics context  
  *      description in gcValues is updated according to the  
  *      information in the dash structure, as far as possible.  
  *  
  * Results:  
  *      The return-value is a mask, indicating which  
  *      elements of gcValues have been updated.  
  *      0 means there is no outline.  
  *  
  * Side effects:  
  *      GC information in gcValues is updated.  
  *  
  *--------------------------------------------------------------  
  */  
   
 int Tk_ConfigOutlineGC(gcValues, canvas, item, outline)  
     XGCValues *gcValues;  
     Tk_Canvas canvas;  
     Tk_Item *item;  
     Tk_Outline *outline;  
 {  
     int mask = 0;  
     double width;  
     Tk_Dash *dash;  
     XColor *color;  
     Pixmap stipple;  
     Tk_State state = item->state;  
   
     if (outline->width < 0.0) {  
         outline->width = 0.0;  
     }  
     if (outline->activeWidth < 0.0) {  
         outline->activeWidth = 0.0;  
     }  
     if (outline->disabledWidth < 0) {  
         outline->disabledWidth = 0.0;  
     }  
     if (state==TK_STATE_HIDDEN) {  
         return 0;  
     }  
   
     width = outline->width;  
     if (width < 1.0) {  
         width = 1.0;  
     }  
     dash = &(outline->dash);  
     color = outline->color;  
     stipple = outline->stipple;  
     if (state == TK_STATE_NULL) {  
         state = ((TkCanvas *)canvas)->canvas_state;  
     }  
     if (((TkCanvas *)canvas)->currentItemPtr == item) {  
         if (outline->activeWidth>width) {  
             width = outline->activeWidth;  
         }  
         if (outline->activeDash.number != 0) {  
             dash = &(outline->activeDash);  
         }  
         if (outline->activeColor!=NULL) {  
             color = outline->activeColor;  
         }  
         if (outline->activeStipple!=None) {  
             stipple = outline->activeStipple;  
         }  
     } else if (state==TK_STATE_DISABLED) {  
         if (outline->disabledWidth>0) {  
             width = outline->disabledWidth;  
         }  
         if (outline->disabledDash.number != 0) {  
             dash = &(outline->disabledDash);  
         }  
         if (outline->disabledColor!=NULL) {  
             color = outline->disabledColor;  
         }  
         if (outline->disabledStipple!=None) {  
             stipple = outline->disabledStipple;  
         }  
     }  
   
     if (color==NULL) {  
         return 0;  
     }  
   
     gcValues->line_width = (int) (width + 0.5);  
     if (color != NULL) {  
         gcValues->foreground = color->pixel;  
         mask = GCForeground|GCLineWidth;  
         if (stipple != None) {  
             gcValues->stipple = stipple;  
             gcValues->fill_style = FillStippled;  
             mask |= GCStipple|GCFillStyle;  
         }  
     }  
     if (mask && (dash->number != 0)) {  
         gcValues->line_style = LineOnOffDash;  
         gcValues->dash_offset = outline->offset;  
         if (dash->number >= 2) {  
             gcValues->dashes = 4;  
         } else if (dash->number > 0) {  
             gcValues->dashes = dash->pattern.array[0];  
         } else {  
             gcValues->dashes = (char) (4 * width);  
         }  
         mask |= GCLineStyle|GCDashList|GCDashOffset;  
     }  
     return mask;  
 }  
   
 /*  
  *--------------------------------------------------------------  
  *  
  * Tk_ChangeOutlineGC  
  *  
  *      Updates the GC to represent the full information of  
  *      the dash structure. Partly this is already done in  
  *      Tk_ConfigOutlineGC().  
  *      This function should be called just before drawing  
  *      the dashed item.  
  *  
  * Results:  
  *      1 if there is a stipple pattern.  
  *      0 otherwise.  
  *  
  * Side effects:  
  *      GC is updated.  
  *  
  *--------------------------------------------------------------  
  */  
   
 int  
 Tk_ChangeOutlineGC(canvas, item, outline)  
     Tk_Canvas canvas;  
     Tk_Item *item;  
     Tk_Outline *outline;  
 {  
     CONST char *p;  
     double width;  
     Tk_Dash *dash;  
     XColor *color;  
     Pixmap stipple;  
     Tk_State state = item->state;  
   
     width = outline->width;  
     if (width < 1.0) {  
         width = 1.0;  
     }  
     dash = &(outline->dash);  
     color = outline->color;  
     stipple = outline->stipple;  
     if (state == TK_STATE_NULL) {  
         state = ((TkCanvas *)canvas)->canvas_state;  
     }  
     if (((TkCanvas *)canvas)->currentItemPtr == item) {  
         if (outline->activeWidth > width) {  
             width = outline->activeWidth;  
         }  
         if (outline->activeDash.number != 0) {  
             dash = &(outline->activeDash);  
         }  
         if (outline->activeColor != NULL) {  
             color = outline->activeColor;  
         }  
         if (outline->activeStipple != None) {  
             stipple = outline->activeStipple;  
         }  
     } else if (state == TK_STATE_DISABLED) {  
         if (outline->disabledWidth > width) {  
             width = outline->disabledWidth;  
         }  
         if (outline->disabledDash.number != 0) {  
             dash = &(outline->disabledDash);  
         }  
         if (outline->disabledColor != NULL) {  
             color = outline->disabledColor;  
         }  
         if (outline->disabledStipple != None) {  
             stipple = outline->disabledStipple;  
         }  
     }  
     if (color==NULL) {  
         return 0;  
     }  
   
     if ((dash->number<-1) || ((dash->number == -1) && (dash->pattern.array[1]!=','))) {  
         char *q;  
         int i = -dash->number;  
   
         p = (i > sizeof(char *)) ? dash->pattern.pt : dash->pattern.array;  
         q = (char *) ckalloc(2*(unsigned int)i);  
         i = DashConvert(q, p, i, width);  
         XSetDashes(((TkCanvas *)canvas)->display, outline->gc, outline->offset, q, i);  
         ckfree(q);  
     } else if ( dash->number>2 || (dash->number==2 &&  
                 (dash->pattern.array[0]!=dash->pattern.array[1]))) {  
         p = (char *) (dash->number > sizeof(char *)) ? dash->pattern.pt : dash->pattern.array;  
         XSetDashes(((TkCanvas *)canvas)->display, outline->gc, outline->offset, p, dash->number);  
     }  
     if (stipple!=None) {  
         int w=0; int h=0;  
         Tk_TSOffset *tsoffset = &outline->tsoffset;  
         int flags = tsoffset->flags;  
         if (!(flags & TK_OFFSET_INDEX) && (flags & (TK_OFFSET_CENTER|TK_OFFSET_MIDDLE))) {  
             Tk_SizeOfBitmap(((TkCanvas *)canvas)->display, stipple, &w, &h);  
             if (flags & TK_OFFSET_CENTER) {  
                 w /= 2;  
             } else {  
                 w = 0;  
             }  
             if (flags & TK_OFFSET_MIDDLE) {  
                 h /= 2;  
             } else {  
                 h = 0;  
             }  
         }  
         tsoffset->xoffset -= w;  
         tsoffset->yoffset -= h;  
         Tk_CanvasSetOffset(canvas, outline->gc, tsoffset);  
         tsoffset->xoffset += w;  
         tsoffset->yoffset += h;  
         return 1;  
     }  
     return 0;  
 }  
   
   
 /*  
  *--------------------------------------------------------------  
  *  
  * Tk_ResetOutlineGC  
  *  
  *      Restores the GC to the situation before  
  *      Tk_ChangeDashGC() was called.  
  *      This function should be called just after the dashed  
  *      item is drawn, because the GC is supposed to be  
  *      read-only.  
  *  
  * Results:  
  *      1 if there is a stipple pattern.  
  *      0 otherwise.  
  *  
  * Side effects:  
  *      GC is updated.  
  *  
  *--------------------------------------------------------------  
  */  
 int  
 Tk_ResetOutlineGC(canvas, item, outline)  
     Tk_Canvas canvas;  
     Tk_Item *item;  
     Tk_Outline *outline;  
 {  
     char dashList;  
     double width;  
     Tk_Dash *dash;  
     XColor *color;  
     Pixmap stipple;  
     Tk_State state = item->state;  
   
     width = outline->width;  
     if (width < 1.0) {  
         width = 1.0;  
     }  
     dash = &(outline->dash);  
     color = outline->color;  
     stipple = outline->stipple;  
     if (state == TK_STATE_NULL) {  
         state = ((TkCanvas *)canvas)->canvas_state;  
     }  
     if (((TkCanvas *)canvas)->currentItemPtr == item) {  
         if (outline->activeWidth>width) {  
             width = outline->activeWidth;  
         }  
         if (outline->activeDash.number != 0) {  
             dash = &(outline->activeDash);  
         }  
         if (outline->activeColor!=NULL) {  
             color = outline->activeColor;  
         }  
         if (outline->activeStipple!=None) {  
             stipple = outline->activeStipple;  
         }  
     } else if (state==TK_STATE_DISABLED) {  
         if (outline->disabledWidth>width) {  
             width = outline->disabledWidth;  
         }  
         if (outline->disabledDash.number != 0) {  
             dash = &(outline->disabledDash);  
         }  
         if (outline->disabledColor!=NULL) {  
             color = outline->disabledColor;  
         }  
         if (outline->disabledStipple!=None) {  
             stipple = outline->disabledStipple;  
         }  
     }  
     if (color==NULL) {  
         return 0;  
     }  
   
     if ((dash->number > 2) || (dash->number < -1) || (dash->number==2 &&  
                 (dash->pattern.array[0] != dash->pattern.array[1])) ||  
                 ((dash->number == -1) && (dash->pattern.array[1] != ','))) {  
         if (dash->number < 0) {  
             dashList = (int) (4 * width + 0.5);  
         } else if (dash->number<3) {  
             dashList = dash->pattern.array[0];  
         } else {  
             dashList = 4;  
         }  
         XSetDashes(((TkCanvas *)canvas)->display, outline->gc,  
                 outline->offset, &dashList , 1);  
     }  
     if (stipple != None) {  
         XSetTSOrigin(((TkCanvas *)canvas)->display, outline->gc, 0, 0);  
         return 1;  
     }  
     return 0;  
 }  
   
   
 /*  
  *--------------------------------------------------------------  
  *  
  * Tk_CanvasPsOutline  
  *  
  *      Creates the postscript command for the correct  
  *      Outline-information (width, dash, color and stipple).  
  *  
  * Results:  
  *      TCL_OK if succeeded, otherwise TCL_ERROR.  
  *  
  * Side effects:  
  *      canvas->interp->result contains the postscript string,  
  *      or an error message if the result was TCL_ERROR.  
  *  
  *--------------------------------------------------------------  
  */  
 int  
 Tk_CanvasPsOutline(canvas, item, outline)  
     Tk_Canvas canvas;  
     Tk_Item *item;  
     Tk_Outline *outline;  
 {  
     char string[41];  
     char pattern[11];  
     int i;  
     char *ptr;  
     char *str = string;  
     char *lptr = pattern;  
     Tcl_Interp *interp = ((TkCanvas *)canvas)->interp;  
     double width;  
     Tk_Dash *dash;  
     XColor *color;  
     Pixmap stipple;  
     Tk_State state = item->state;  
   
     width = outline->width;  
     dash = &(outline->dash);  
     color = outline->color;  
     stipple = outline->stipple;  
     if (state == TK_STATE_NULL) {  
         state = ((TkCanvas *)canvas)->canvas_state;  
     }  
     if (((TkCanvas *)canvas)->currentItemPtr == item) {  
         if (outline->activeWidth > width) {  
             width = outline->activeWidth;  
         }  
         if (outline->activeDash.number > 0) {  
             dash = &(outline->activeDash);  
         }  
         if (outline->activeColor != NULL) {  
             color = outline->activeColor;  
         }  
         if (outline->activeStipple != None) {  
             stipple = outline->activeStipple;  
         }  
     } else if (state == TK_STATE_DISABLED) {  
         if (outline->disabledWidth > 0) {  
             width = outline->disabledWidth;  
         }  
         if (outline->disabledDash.number > 0) {  
             dash = &(outline->disabledDash);  
         }  
         if (outline->disabledColor != NULL) {  
             color = outline->disabledColor;  
         }  
         if (outline->disabledStipple != None) {  
             stipple = outline->disabledStipple;  
         }  
     }  
     sprintf(string, "%.15g setlinewidth\n", width);  
     Tcl_AppendResult(interp, string, (char *) NULL);  
   
     if (dash->number > 10) {  
         str = (char *)ckalloc((unsigned int) (1 + 4*dash->number));  
     } else if (dash->number < -5) {  
         str = (char *)ckalloc((unsigned int) (1 - 8*dash->number));  
         lptr = (char *)ckalloc((unsigned int) (1 - 2*dash->number));  
     }  
     ptr = (char *) ((ABS(dash->number) > sizeof(char *)) ) ?  
         dash->pattern.pt : dash->pattern.array;  
     if (dash->number > 0) {  
         char *ptr0 = ptr;  
         sprintf(str, "[%d", *ptr++ & 0xff);  
         i = dash->number-1;  
         while (i--) {  
             sprintf(str+strlen(str), " %d", *ptr++ & 0xff);  
         }  
         Tcl_AppendResult(interp, str, (char *)NULL);  
         if (dash->number&1) {  
             Tcl_AppendResult(interp, " ", str+1, (char *)NULL);  
         }  
         sprintf(str, "] %d setdash\n", outline->offset);  
         Tcl_AppendResult(interp, str, (char *)NULL);  
         ptr = ptr0;  
     } else if (dash->number < 0) {  
         if ((i = DashConvert(lptr, ptr, -dash->number, width)) != 0) {  
             char *lptr0 = lptr;  
             sprintf(str, "[%d", *lptr++ & 0xff);  
             while (--i) {  
                 sprintf(str+strlen(str), " %d", *lptr++ & 0xff);  
             }  
             Tcl_AppendResult(interp, str, (char *)NULL);  
             sprintf(str, "] %d setdash\n", outline->offset);  
             Tcl_AppendResult(interp, str, (char *)NULL);  
             lptr = lptr0;  
         } else {  
             Tcl_AppendResult(interp, "[] 0 setdash\n", (char *)NULL);  
         }  
     } else {  
         Tcl_AppendResult(interp, "[] 0 setdash\n", (char *)NULL);  
     }  
     if (str != string) {  
         ckfree(str);  
     }  
     if (lptr != pattern) {  
         ckfree(lptr);  
     }  
     if (Tk_CanvasPsColor(interp, canvas, color) != TCL_OK) {  
         return TCL_ERROR;  
     }  
     if (stipple != None) {  
         Tcl_AppendResult(interp, "StrokeClip ", (char *) NULL);  
         if (Tk_CanvasPsStipple(interp, canvas, stipple) != TCL_OK) {  
             return TCL_ERROR;  
         }  
     } else {  
         Tcl_AppendResult(interp, "stroke\n", (char *) NULL);  
     }  
   
     return TCL_OK;  
 }  
   
   
 /*  
  *--------------------------------------------------------------  
  *  
  * DashConvert  
  *  
  *      Converts a character-like dash-list (e.g. "-..")  
  *      into an X11-style. l must point to a string that  
  *      holds room to at least 2*n characters. if  
  *      l == NULL, this function can be used for  
  *      syntax checking only.  
  *  
  * Results:  
  *      The length of the resulting X11 compatible  
  *      dash-list. -1 if failed.  
  *  
  * Side effects:  
  *      None  
  *  
  *--------------------------------------------------------------  
  */  
   
 static int  
 DashConvert (l, p, n, width)  
     char *l;  
     CONST char *p;  
     int n;  
     double width;  
 {  
     int result = 0;  
     int size, intWidth;  
   
     if (n<0) {  
         n = strlen(p);  
     }  
     intWidth = (int) (width + 0.5);  
     if (intWidth < 1) {  
         intWidth = 1;  
     }  
     while (n-- && *p) {  
         switch (*p++) {  
             case ' ':  
                 if (result) {  
                     if (l) {  
                         l[-1] += intWidth + 1;  
                     }  
                     continue;  
                 } else {  
                     return 0;  
                 }  
                 break;  
             case '_':  
                 size = 8;  
                 break;  
             case '-':  
                 size = 6;  
                 break;  
             case ',':  
                 size = 4;  
                 break;  
             case '.':  
                 size = 2;  
                 break;  
             default:  
                 return -1;  
         }  
         if (l) {  
             *l++ = size * intWidth;  
             *l++ = 4 * intWidth;  
         }  
         result += 2;  
     }  
     return result;  
 }  
   
   
 /* $History: tkCanvUtil.c $  
  *  
  * *****************  Version 1  *****************  
  * User: Dtashley     Date: 1/02/01    Time: 2:42a  
  * Created in $/IjuScripter, IjuConsole/Source/Tk Base  
  * Initial check-in.  
  */  
   
 /* End of TKCANVUTIL.C */  
1    /* $Header$ */
2    
3    /*
4     * tkCanvUtil.c --
5     *
6     *      This procedure contains a collection of utility procedures
7     *      used by the implementations of various canvas item types.
8     *
9     * Copyright (c) 1994 Sun Microsystems, Inc.
10     * Copyright (c) 1994 Sun Microsystems, Inc.
11     *
12     * See the file "license.terms" for information on usage and redistribution
13     * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
14     *
15     * RCS: @(#) $Id: tkcanvutil.c,v 1.1.1.1 2001/06/13 04:57:52 dtashley Exp $
16     */
17    
18    #include "tkInt.h"
19    #include "tkCanvas.h"
20    #include "tkPort.h"
21    
22    
23    /*
24     *----------------------------------------------------------------------
25     *
26     * Tk_CanvasTkwin --
27     *
28     *      Given a token for a canvas, this procedure returns the
29     *      widget that represents the canvas.
30     *
31     * Results:
32     *      The return value is a handle for the widget.
33     *
34     * Side effects:
35     *      None.
36     *
37     *----------------------------------------------------------------------
38     */
39    
40    Tk_Window
41    Tk_CanvasTkwin(canvas)
42        Tk_Canvas canvas;                   /* Token for the canvas. */
43    {
44        TkCanvas *canvasPtr = (TkCanvas *) canvas;
45        return canvasPtr->tkwin;
46    }
47    
48    /*
49     *----------------------------------------------------------------------
50     *
51     * Tk_CanvasDrawableCoords --
52     *
53     *      Given an (x,y) coordinate pair within a canvas, this procedure
54     *      returns the corresponding coordinates at which the point should
55     *      be drawn in the drawable used for display.
56     *
57     * Results:
58     *      There is no return value.  The values at *drawableXPtr and
59     *      *drawableYPtr are filled in with the coordinates at which
60     *      x and y should be drawn.  These coordinates are clipped
61     *      to fit within a "short", since this is what X uses in
62     *      most cases for drawing.
63     *
64     * Side effects:
65     *      None.
66     *
67     *----------------------------------------------------------------------
68     */
69    
70    void
71    Tk_CanvasDrawableCoords(canvas, x, y, drawableXPtr, drawableYPtr)
72        Tk_Canvas canvas;                   /* Token for the canvas. */
73        double x, y;                        /* Coordinates in canvas space. */
74        short *drawableXPtr, *drawableYPtr; /* Screen coordinates are stored
75                                             * here. */
76    {
77        TkCanvas *canvasPtr = (TkCanvas *) canvas;
78        double tmp;
79    
80        tmp = x - canvasPtr->drawableXOrigin;
81        if (tmp > 0) {
82            tmp += 0.5;
83        } else {
84            tmp -= 0.5;
85        }
86        if (tmp > 32767) {
87            *drawableXPtr = 32767;
88        } else if (tmp < -32768) {
89            *drawableXPtr = -32768;
90        } else {
91            *drawableXPtr = (short) tmp;
92        }
93    
94        tmp = y  - canvasPtr->drawableYOrigin;
95        if (tmp > 0) {
96            tmp += 0.5;
97        } else {
98            tmp -= 0.5;
99        }
100        if (tmp > 32767) {
101            *drawableYPtr = 32767;
102        } else if (tmp < -32768) {
103            *drawableYPtr = -32768;
104        } else {
105            *drawableYPtr = (short) tmp;
106        }
107    }
108    
109    /*
110     *----------------------------------------------------------------------
111     *
112     * Tk_CanvasWindowCoords --
113     *
114     *      Given an (x,y) coordinate pair within a canvas, this procedure
115     *      returns the corresponding coordinates in the canvas's window.
116     *
117     * Results:
118     *      There is no return value.  The values at *screenXPtr and
119     *      *screenYPtr are filled in with the coordinates at which
120     *      (x,y) appears in the canvas's window.  These coordinates
121     *      are clipped to fit within a "short", since this is what X
122     *      uses in most cases for drawing.
123     *
124     * Side effects:
125     *      None.
126     *
127     *----------------------------------------------------------------------
128     */
129    
130    void
131    Tk_CanvasWindowCoords(canvas, x, y, screenXPtr, screenYPtr)
132        Tk_Canvas canvas;                   /* Token for the canvas. */
133        double x, y;                        /* Coordinates in canvas space. */
134        short *screenXPtr, *screenYPtr;     /* Screen coordinates are stored
135                                             * here. */
136    {
137        TkCanvas *canvasPtr = (TkCanvas *) canvas;
138        double tmp;
139    
140        tmp = x - canvasPtr->xOrigin;
141        if (tmp > 0) {
142            tmp += 0.5;
143        } else {
144            tmp -= 0.5;
145        }
146        if (tmp > 32767) {
147            *screenXPtr = 32767;
148        } else if (tmp < -32768) {
149            *screenXPtr = -32768;
150        } else {
151            *screenXPtr = (short) tmp;
152        }
153    
154        tmp = y  - canvasPtr->yOrigin;
155        if (tmp > 0) {
156            tmp += 0.5;
157        } else {
158            tmp -= 0.5;
159        }
160        if (tmp > 32767) {
161            *screenYPtr = 32767;
162        } else if (tmp < -32768) {
163            *screenYPtr = -32768;
164        } else {
165            *screenYPtr = (short) tmp;
166        }
167    }
168    
169    /*
170     *--------------------------------------------------------------
171     *
172     * Tk_CanvasGetCoord --
173     *
174     *      Given a string, returns a floating-point canvas coordinate
175     *      corresponding to that string.
176     *
177     * Results:
178     *      The return value is a standard Tcl return result.  If
179     *      TCL_OK is returned, then everything went well and the
180     *      canvas coordinate is stored at *doublePtr;  otherwise
181     *      TCL_ERROR is returned and an error message is left in
182     *      the interp's result.
183     *
184     * Side effects:
185     *      None.
186     *
187     *--------------------------------------------------------------
188     */
189    
190    int
191    Tk_CanvasGetCoord(interp, canvas, string, doublePtr)
192        Tcl_Interp *interp;         /* Interpreter for error reporting. */
193        Tk_Canvas canvas;           /* Canvas to which coordinate applies. */
194        char *string;               /* Describes coordinate (any screen
195                                     * coordinate form may be used here). */
196        double *doublePtr;          /* Place to store converted coordinate. */
197    {
198        TkCanvas *canvasPtr = (TkCanvas *) canvas;
199        if (Tk_GetScreenMM(canvasPtr->interp, canvasPtr->tkwin, string,
200                doublePtr) != TCL_OK) {
201            return TCL_ERROR;
202        }
203        *doublePtr *= canvasPtr->pixelsPerMM;
204        return TCL_OK;
205    }
206    
207    /*
208     *--------------------------------------------------------------
209     *
210     * Tk_CanvasGetCoordFromObj --
211     *
212     *      Given a string, returns a floating-point canvas coordinate
213     *      corresponding to that string.
214     *
215     * Results:
216     *      The return value is a standard Tcl return result.  If
217     *      TCL_OK is returned, then everything went well and the
218     *      canvas coordinate is stored at *doublePtr;  otherwise
219     *      TCL_ERROR is returned and an error message is left in
220     *      interp->result.
221     *
222     * Side effects:
223     *      None.
224     *
225     *--------------------------------------------------------------
226     */
227    
228    int
229    Tk_CanvasGetCoordFromObj(interp, canvas, obj, doublePtr)
230        Tcl_Interp *interp;         /* Interpreter for error reporting. */
231        Tk_Canvas canvas;           /* Canvas to which coordinate applies. */
232        Tcl_Obj *obj;               /* Describes coordinate (any screen
233                                     * coordinate form may be used here). */
234        double *doublePtr;          /* Place to store converted coordinate. */
235    {
236        TkCanvas *canvasPtr = (TkCanvas *) canvas;
237        if (Tk_GetMMFromObj(canvasPtr->interp, canvasPtr->tkwin, obj,
238                doublePtr) != TCL_OK) {
239            return TCL_ERROR;
240        }
241        *doublePtr *= canvasPtr->pixelsPerMM;
242        return TCL_OK;
243    }
244    
245    /*
246     *----------------------------------------------------------------------
247     *
248     * Tk_CanvasSetStippleOrigin --
249     *
250     *      This procedure sets the stipple origin in a graphics context
251     *      so that stipples drawn with the GC will line up with other
252     *      stipples previously drawn in the canvas.
253     *
254     * Results:
255     *      None.
256     *
257     * Side effects:
258     *      The graphics context is modified.
259     *
260     *----------------------------------------------------------------------
261     */
262    
263    void
264    Tk_CanvasSetStippleOrigin(canvas, gc)
265        Tk_Canvas canvas;           /* Token for a canvas. */
266        GC gc;                      /* Graphics context that is about to be
267                                     * used to draw a stippled pattern as
268                                     * part of redisplaying the canvas. */
269    
270    {
271        TkCanvas *canvasPtr = (TkCanvas *) canvas;
272    
273        XSetTSOrigin(canvasPtr->display, gc, -canvasPtr->drawableXOrigin,
274                -canvasPtr->drawableYOrigin);
275    }
276    
277    /*
278     *----------------------------------------------------------------------
279     *
280     * Tk_CanvasSetOffset--
281     *
282     *      This procedure sets the stipple offset in a graphics
283     *      context so that stipples drawn with the GC will
284     *      line up with other stipples with the same offset.
285     *
286     * Results:
287     *      None.
288     *
289     * Side effects:
290     *      The graphics context is modified.
291     *
292     *----------------------------------------------------------------------
293     */
294    
295    void
296    Tk_CanvasSetOffset(canvas, gc, offset)
297        Tk_Canvas canvas;           /* Token for a canvas. */
298        GC gc;                      /* Graphics context that is about to be
299                                     * used to draw a stippled pattern as
300                                     * part of redisplaying the canvas. */
301        Tk_TSOffset *offset;        /* offset (may be NULL pointer)*/
302    {
303        TkCanvas *canvasPtr = (TkCanvas *) canvas;
304        int flags = 0;
305        int x = - canvasPtr->drawableXOrigin;
306        int y = - canvasPtr->drawableYOrigin;
307    
308        if (offset != NULL) {
309            flags = offset->flags;
310            x += offset->xoffset;
311            y += offset->yoffset;
312        }
313        if ((flags & TK_OFFSET_RELATIVE) && !(flags & TK_OFFSET_INDEX)) {
314            Tk_SetTSOrigin(canvasPtr->tkwin, gc, x - canvasPtr->xOrigin,
315                    y - canvasPtr->yOrigin);
316        } else {
317            XSetTSOrigin(canvasPtr->display, gc, x, y);
318        }
319    }
320    
321    /*
322     *----------------------------------------------------------------------
323     *
324     * Tk_CanvasGetTextInfo --
325     *
326     *      This procedure returns a pointer to a structure containing
327     *      information about the selection and insertion cursor for
328     *      a canvas widget.  Items such as text items save the pointer
329     *      and use it to share access to the information with the generic
330     *      canvas code.
331     *
332     * Results:
333     *      The return value is a pointer to the structure holding text
334     *      information for the canvas.  Most of the fields should not
335     *      be modified outside the generic canvas code;  see the user
336     *      documentation for details.
337     *
338     * Side effects:
339     *      None.
340     *
341     *----------------------------------------------------------------------
342     */
343    
344    Tk_CanvasTextInfo *
345    Tk_CanvasGetTextInfo(canvas)
346        Tk_Canvas canvas;                   /* Token for the canvas widget. */
347    {
348        return &((TkCanvas *) canvas)->textInfo;
349    }
350    
351    /*
352     *--------------------------------------------------------------
353     *
354     * Tk_CanvasTagsParseProc --
355     *
356     *      This procedure is invoked during option processing to handle
357     *      "-tags" options for canvas items.
358     *
359     * Results:
360     *      A standard Tcl return value.
361     *
362     * Side effects:
363     *      The tags for a given item get replaced by those indicated
364     *      in the value argument.
365     *
366     *--------------------------------------------------------------
367     */
368    
369    int
370    Tk_CanvasTagsParseProc(clientData, interp, tkwin, value, widgRec, offset)
371        ClientData clientData;              /* Not used.*/
372        Tcl_Interp *interp;                 /* Used for reporting errors. */
373        Tk_Window tkwin;                    /* Window containing canvas widget. */
374        char *value;                        /* Value of option (list of tag
375                                             * names). */
376        char *widgRec;                      /* Pointer to record for item. */
377        int offset;                         /* Offset into item (ignored). */
378    {
379        register Tk_Item *itemPtr = (Tk_Item *) widgRec;
380        int argc, i;
381        char **argv;
382        Tk_Uid *newPtr;
383    
384        /*
385         * Break the value up into the individual tag names.
386         */
387    
388        if (Tcl_SplitList(interp, value, &argc, &argv) != TCL_OK) {
389            return TCL_ERROR;
390        }
391    
392        /*
393         * Make sure that there's enough space in the item to hold the
394         * tag names.
395         */
396    
397        if (itemPtr->tagSpace < argc) {
398            newPtr = (Tk_Uid *) ckalloc((unsigned) (argc * sizeof(Tk_Uid)));
399            for (i = itemPtr->numTags-1; i >= 0; i--) {
400                newPtr[i] = itemPtr->tagPtr[i];
401            }
402            if (itemPtr->tagPtr != itemPtr->staticTagSpace) {
403                ckfree((char *) itemPtr->tagPtr);
404            }
405            itemPtr->tagPtr = newPtr;
406            itemPtr->tagSpace = argc;
407        }
408        itemPtr->numTags = argc;
409        for (i = 0; i < argc; i++) {
410            itemPtr->tagPtr[i] = Tk_GetUid(argv[i]);
411        }
412        ckfree((char *) argv);
413        return TCL_OK;
414    }
415    
416    /*
417     *--------------------------------------------------------------
418     *
419     * Tk_CanvasTagsPrintProc --
420     *
421     *      This procedure is invoked by the Tk configuration code
422     *      to produce a printable string for the "-tags" configuration
423     *      option for canvas items.
424     *
425     * Results:
426     *      The return value is a string describing all the tags for
427     *      the item referred to by "widgRec".  In addition, *freeProcPtr
428     *      is filled in with the address of a procedure to call to free
429     *      the result string when it's no longer needed (or NULL to
430     *      indicate that the string doesn't need to be freed).
431     *
432     * Side effects:
433     *      None.
434     *
435     *--------------------------------------------------------------
436     */
437    
438    char *
439    Tk_CanvasTagsPrintProc(clientData, tkwin, widgRec, offset, freeProcPtr)
440        ClientData clientData;              /* Ignored. */
441        Tk_Window tkwin;                    /* Window containing canvas widget. */
442        char *widgRec;                      /* Pointer to record for item. */
443        int offset;                         /* Ignored. */
444        Tcl_FreeProc **freeProcPtr;         /* Pointer to variable to fill in with
445                                             * information about how to reclaim
446                                             * storage for return string. */
447    {
448        register Tk_Item *itemPtr = (Tk_Item *) widgRec;
449    
450        if (itemPtr->numTags == 0) {
451            *freeProcPtr = (Tcl_FreeProc *) NULL;
452            return "";
453        }
454        if (itemPtr->numTags == 1) {
455            *freeProcPtr = (Tcl_FreeProc *) NULL;
456            return (char *) itemPtr->tagPtr[0];
457        }
458        *freeProcPtr = TCL_DYNAMIC;
459        return Tcl_Merge(itemPtr->numTags, (char **) itemPtr->tagPtr);
460    }
461    
462    
463    static int      DashConvert _ANSI_ARGS_((char *l, CONST char *p,
464                            int n, double width));
465    #define ABS(a) ((a>=0)?(a):(-(a)))
466    
467    /*
468     *--------------------------------------------------------------
469     *
470     * TkCanvasDashParseProc --
471     *
472     *      This procedure is invoked during option processing to handle
473     *      "-dash", "-activedash" and "-disableddash" options for canvas
474     *      objects.
475     *
476     * Results:
477     *      A standard Tcl return value.
478     *
479     * Side effects:
480     *      The dash list for a given canvas object gets replaced by
481     *      those indicated in the value argument.
482     *
483     *--------------------------------------------------------------
484     */
485    
486    int
487    TkCanvasDashParseProc(clientData, interp, tkwin, value, widgRec, offset)
488        ClientData clientData;              /* Not used.*/
489        Tcl_Interp *interp;                 /* Used for reporting errors. */
490        Tk_Window tkwin;                    /* Window containing canvas widget. */
491        CONST char *value;                  /* Value of option. */
492        char *widgRec;                      /* Pointer to record for item. */
493        int offset;                         /* Offset into item. */
494    {
495        return Tk_GetDash(interp, value, (Tk_Dash *)(widgRec+offset));
496    }
497    
498    /*
499     *--------------------------------------------------------------
500     *
501     * TkCanvasDashPrintProc --
502     *
503     *      This procedure is invoked by the Tk configuration code
504     *      to produce a printable string for the "-dash", "-activedash"
505     *      and "-disableddash" configuration options for canvas items.
506     *
507     * Results:
508     *      The return value is a string describing all the dash list for
509     *      the item referred to by "widgRec"and "offset".  In addition,
510     *      *freeProcPtr is filled in with the address of a procedure to
511     *      call to free the result string when it's no longer needed (or
512     *      NULL to indicate that the string doesn't need to be freed).
513     *
514     * Side effects:
515     *      None.
516     *
517     *--------------------------------------------------------------
518     */
519    
520    char *
521    TkCanvasDashPrintProc(clientData, tkwin, widgRec, offset, freeProcPtr)
522        ClientData clientData;              /* Ignored. */
523        Tk_Window tkwin;                    /* Window containing canvas widget. */
524        char *widgRec;                      /* Pointer to record for item. */
525        int offset;                         /* Offset in record for item. */
526        Tcl_FreeProc **freeProcPtr;         /* Pointer to variable to fill in with
527                                             * information about how to reclaim
528                                             * storage for return string. */
529    {
530        Tk_Dash *dash = (Tk_Dash *) (widgRec+offset);
531        char *buffer;
532        char *p;
533        int i = dash->number;
534    
535        if (i < 0) {
536            i = -i;
537            *freeProcPtr = TCL_DYNAMIC;
538            buffer = (char *) ckalloc((unsigned int) (i+1));
539            p = (i > sizeof(char *)) ? dash->pattern.pt : dash->pattern.array;
540            memcpy(buffer, p, (unsigned int) i);
541            buffer[i] = 0;
542            return buffer;
543        } else if (!i) {
544            *freeProcPtr = (Tcl_FreeProc *) NULL;
545            return "";
546        }
547        buffer = (char *)ckalloc((unsigned int) (4*i));
548        *freeProcPtr = TCL_DYNAMIC;
549    
550        p = (i > sizeof(char *)) ? dash->pattern.pt : dash->pattern.array;
551        sprintf(buffer, "%d", *p++ & 0xff);
552        while(--i) {
553            sprintf(buffer+strlen(buffer), " %d", *p++ & 0xff);
554        }
555        return buffer;
556    }
557    
558    /*
559     *--------------------------------------------------------------
560     *
561     * Tk_CreateSmoothMethod --
562     *
563     *      This procedure is invoked to add additional values
564     *      for the "-smooth" option to the list.
565     *
566     * Results:
567     *      A standard Tcl return value.
568     *
569     * Side effects:
570     *      In the future "-smooth <name>" will be accepted as
571     *      smooth method for the line and polygon.
572     *
573     *--------------------------------------------------------------
574     */
575    
576    Tk_SmoothMethod tkBezierSmoothMethod = {
577        "bezier",
578        TkMakeBezierCurve,
579        (void (*) _ANSI_ARGS_((Tcl_Interp *interp, Tk_Canvas canvas,
580                double *coordPtr, int numPoints, int numSteps)))
581                    TkMakeBezierPostscript,
582    };
583    
584    static void SmoothMethodCleanupProc _ANSI_ARGS_((ClientData clientData,
585                    Tcl_Interp *interp));
586    
587    typedef struct SmoothAssocData {
588        struct SmoothAssocData *nextPtr;    /* pointer to next SmoothAssocData */
589        Tk_SmoothMethod smooth;             /* name and functions associated with this
590                                             * option */
591    } SmoothAssocData;
592    
593    void
594    Tk_CreateSmoothMethod(interp, smooth)
595        Tcl_Interp *interp;
596        Tk_SmoothMethod *smooth;
597    {
598        SmoothAssocData *methods, *typePtr2, *prevPtr, *ptr;
599        methods = (SmoothAssocData *) Tcl_GetAssocData(interp, "smoothMethod",
600                (Tcl_InterpDeleteProc **) NULL);
601    
602        /*
603         * If there's already a smooth method with the given name, remove it.
604         */
605    
606        for (typePtr2 = methods, prevPtr = NULL; typePtr2 != NULL;
607                prevPtr = typePtr2, typePtr2 = typePtr2->nextPtr) {
608            if (!strcmp(typePtr2->smooth.name, smooth->name)) {
609                if (prevPtr == NULL) {
610                    methods = typePtr2->nextPtr;
611                } else {
612                    prevPtr->nextPtr = typePtr2->nextPtr;
613                }
614                ckfree((char *) typePtr2);
615                break;
616            }
617        }
618        ptr = (SmoothAssocData *) ckalloc(sizeof(SmoothAssocData));
619        ptr->smooth.name = smooth->name;
620        ptr->smooth.coordProc = smooth->coordProc;
621        ptr->smooth.postscriptProc = smooth->postscriptProc;
622        ptr->nextPtr = methods;
623        Tcl_SetAssocData(interp, "smoothMethod", SmoothMethodCleanupProc,
624                    (ClientData) ptr);
625    }
626    /*
627     *----------------------------------------------------------------------
628     *
629     * SmoothMethodCleanupProc --
630     *
631     *      This procedure is invoked whenever an interpreter is deleted
632     *      to cleanup the smooth methods.
633     *
634     * Results:
635     *      None.
636     *
637     * Side effects:
638     *      Smooth methods are removed.
639     *
640     *----------------------------------------------------------------------
641     */
642    
643    static void
644    SmoothMethodCleanupProc(clientData, interp)
645        ClientData clientData;      /* Points to "smoothMethod" AssocData
646                                     * for the interpreter. */
647        Tcl_Interp *interp;         /* Interpreter that is being deleted. */
648    {
649        SmoothAssocData *ptr, *methods = (SmoothAssocData *) clientData;
650    
651        while (methods != NULL) {
652            methods = (ptr = methods)->nextPtr;
653            ckfree((char *) ptr);
654        }
655    }
656    /*
657     *--------------------------------------------------------------
658     *
659     * TkSmoothParseProc --
660     *
661     *      This procedure is invoked during option processing to handle
662     *      the "-smooth" option.
663     *
664     * Results:
665     *      A standard Tcl return value.
666     *
667     * Side effects:
668     *      The smooth option for a given item gets replaced by the value
669     *      indicated in the value argument.
670     *
671     *--------------------------------------------------------------
672     */
673    
674    int
675    TkSmoothParseProc(clientData, interp, tkwin, value, widgRec, offset)
676        ClientData clientData;              /* some flags.*/
677        Tcl_Interp *interp;                 /* Used for reporting errors. */
678        Tk_Window tkwin;                    /* Window containing canvas widget. */
679        CONST char *value;                  /* Value of option. */
680        char *widgRec;                      /* Pointer to record for item. */
681        int offset;                         /* Offset into item. */
682    {
683        register Tk_SmoothMethod **smoothPtr =
684            (Tk_SmoothMethod **) (widgRec + offset);
685        Tk_SmoothMethod *smooth = NULL;
686        int b;
687        size_t length;
688        SmoothAssocData *methods;
689    
690        if (value == NULL || *value == 0) {
691            *smoothPtr = (Tk_SmoothMethod *) NULL;
692            return TCL_OK;
693        }
694        length = strlen(value);
695        methods = (SmoothAssocData *) Tcl_GetAssocData(interp, "smoothMethod",
696                (Tcl_InterpDeleteProc **) NULL);
697        while (methods != (SmoothAssocData *) NULL) {
698            if (strncmp(value, methods->smooth.name, length) == 0) {
699                if (smooth != (Tk_SmoothMethod *) NULL) {
700                    Tcl_AppendResult(interp, "ambigeous smooth method \"", value,
701                            "\"", (char *) NULL);
702                    return TCL_ERROR;
703                }
704                smooth = &methods->smooth;
705            }
706            methods = methods->nextPtr;
707        }
708        if (smooth) {
709            *smoothPtr = smooth;
710            return TCL_OK;
711        }
712    
713        if (Tcl_GetBoolean(interp, (char *) value, &b) != TCL_OK) {
714            return TCL_ERROR;
715        }
716        *smoothPtr = b ? &tkBezierSmoothMethod : (Tk_SmoothMethod*) NULL;
717        return TCL_OK;
718    }
719    /*
720     *--------------------------------------------------------------
721     *
722     * TkSmoothPrintProc --
723     *
724     *      This procedure is invoked by the Tk configuration code
725     *      to produce a printable string for the "-smooth"
726     *      configuration option.
727     *
728     * Results:
729     *      The return value is a string describing the smooth option for
730     *      the item referred to by "widgRec".  In addition, *freeProcPtr
731     *      is filled in with the address of a procedure to call to free
732     *      the result string when it's no longer needed (or NULL to
733     *      indicate that the string doesn't need to be freed).
734     *
735     * Side effects:
736     *      None.
737     *
738     *--------------------------------------------------------------
739     */
740    
741    char *
742    TkSmoothPrintProc(clientData, tkwin, widgRec, offset, freeProcPtr)
743        ClientData clientData;              /* Ignored. */
744        Tk_Window tkwin;                    /* Window containing canvas widget. */
745        char *widgRec;                      /* Pointer to record for item. */
746        int offset;                         /* Offset into item. */
747        Tcl_FreeProc **freeProcPtr;         /* Pointer to variable to fill in with
748                                             * information about how to reclaim
749                                             * storage for return string. */
750    {
751        register Tk_SmoothMethod **smoothPtr = (Tk_SmoothMethod **) (widgRec + offset);
752    
753        return (*smoothPtr) ? (*smoothPtr)->name : "0";
754    }
755    /*
756     *--------------------------------------------------------------
757     *
758     * Tk_GetDash
759     *
760     *      This procedure is used to parse a string, assuming
761     *      it is dash information.
762     *
763     * Results:
764     *      The return value is a standard Tcl result:  TCL_OK means
765     *      that the dash information was parsed ok, and
766     *      TCL_ERROR means it couldn't be parsed.
767     *
768     * Side effects:
769     *      Dash information in the dash structure is updated.
770     *
771     *--------------------------------------------------------------
772     */
773    
774    int
775    Tk_GetDash(interp, value, dash)
776        Tcl_Interp *interp;         /* Used for error reporting. */
777        CONST char *value;          /* Textual specification of dash list. */
778        Tk_Dash *dash;              /* Pointer to record in which to
779                                     * store dash information. */
780    {
781        int argc, i;
782        char **largv, **argv = NULL;
783        char *pt;
784    
785        if ((value==(char *) NULL) || (*value==0) ) {
786            dash->number = 0;
787            return TCL_OK;
788        }
789        if ((*value == '.') || (*value == ',') ||
790                (*value == '-') || (*value == '_')) {
791            i = DashConvert((char *) NULL, value, -1, 0.0);
792            if (i>0) {
793                i = strlen(value);
794            } else {
795                goto badDashList;
796            }
797            if (i > sizeof(char *)) {
798                dash->pattern.pt = pt = (char *) ckalloc(strlen(value));
799            } else {
800                pt = dash->pattern.array;
801            }
802            memcpy(pt,value, (unsigned int) i);
803            dash->number = -i;
804            return TCL_OK;
805        }
806        if (Tcl_SplitList(interp, (char *) value, &argc, &argv) != TCL_OK) {
807            Tcl_ResetResult(interp);
808        badDashList:
809            Tcl_AppendResult(interp, "bad dash list \"", value,
810                    "\": must be a list of integers or a format like \"-..\"",
811                    (char *) NULL);
812        syntaxError:
813            if (argv != NULL) {
814                ckfree((char *) argv);
815            }
816            if (ABS(dash->number) > sizeof(char *))
817                ckfree((char *) dash->pattern.pt);
818            dash->number = 0;
819            return TCL_ERROR;
820        }
821    
822        if (ABS(dash->number) > sizeof(char *)) {
823            ckfree((char *) dash->pattern.pt);
824        }
825        if (argc > sizeof(char *)) {
826            dash->pattern.pt = pt = (char *) ckalloc((unsigned int) argc);
827        } else {
828            pt = dash->pattern.array;
829        }
830        dash->number = argc;
831    
832        largv = argv;
833        while(argc>0) {
834            if (Tcl_GetInt(interp, *largv, &i) != TCL_OK ||
835                i < 1 || i>255) {
836                Tcl_ResetResult(interp);
837                Tcl_AppendResult(interp, "expected integer in the range 1..255 but got \"",
838                             *largv, "\"", (char *) NULL);
839                goto syntaxError;
840            }
841            *pt++ = i;
842            argc--; largv++;
843        }
844      
845        if (argv != NULL) {
846            ckfree((char *) argv);
847        }
848    
849        return TCL_OK;
850    }
851    
852    /*
853     *--------------------------------------------------------------
854     *
855     * Tk_CreateOutline
856     *
857     *      This procedure initializes the Tk_Outline structure
858     *      with default values.
859     *
860     * Results:
861     *      None
862     *
863     * Side effects:
864     *      None
865     *
866     *--------------------------------------------------------------
867     */
868    
869    void Tk_CreateOutline(outline)
870        Tk_Outline *outline;
871    {
872        outline->gc = None;
873        outline->width = 1.0;
874        outline->activeWidth = 0.0;
875        outline->disabledWidth = 0.0;
876        outline->offset = 0;
877        outline->dash.number = 0;
878        outline->activeDash.number = 0;
879        outline->disabledDash.number = 0;
880        outline->tsoffset.flags = 0;
881        outline->tsoffset.xoffset = 0;
882        outline->tsoffset.yoffset = 0;
883        outline->color = NULL;
884        outline->activeColor = NULL;
885        outline->disabledColor = NULL;
886        outline->stipple = None;
887        outline->activeStipple = None;
888        outline->disabledStipple = None;
889    }
890    
891    /*
892     *--------------------------------------------------------------
893     *
894     * Tk_DeleteOutline
895     *
896     *      This procedure frees all memory that might be
897     *      allocated and referenced in the Tk_Outline structure.
898     *
899     * Results:
900     *      None
901     *
902     * Side effects:
903     *      None
904     *
905     *--------------------------------------------------------------
906     */
907    
908    void Tk_DeleteOutline(display, outline)
909        Display *display;                   /* Display containing window */
910        Tk_Outline *outline;
911    {
912        if (outline->gc != None) {
913            Tk_FreeGC(display, outline->gc);
914        }
915        if (ABS(outline->dash.number) > sizeof(char *)) {
916            ckfree((char *) outline->dash.pattern.pt);
917        }
918        if (ABS(outline->activeDash.number) > sizeof(char *)) {
919            ckfree((char *) outline->activeDash.pattern.pt);
920        }
921        if (ABS(outline->disabledDash.number) > sizeof(char *)) {
922            ckfree((char *) outline->disabledDash.pattern.pt);
923        }
924        if (outline->color != NULL) {
925            Tk_FreeColor(outline->color);
926        }
927        if (outline->activeColor != NULL) {
928            Tk_FreeColor(outline->activeColor);
929        }
930        if (outline->disabledColor != NULL) {
931            Tk_FreeColor(outline->disabledColor);
932        }
933        if (outline->stipple != None) {
934            Tk_FreeBitmap(display, outline->stipple);
935        }
936        if (outline->activeStipple != None) {
937            Tk_FreeBitmap(display, outline->activeStipple);
938        }
939        if (outline->disabledStipple != None) {
940            Tk_FreeBitmap(display, outline->disabledStipple);
941        }
942    }
943    
944    /*
945     *--------------------------------------------------------------
946     *
947     * Tk_ConfigOutlineGC
948     *
949     *      This procedure should be called in the canvas object
950     *      during the configure command. The graphics context
951     *      description in gcValues is updated according to the
952     *      information in the dash structure, as far as possible.
953     *
954     * Results:
955     *      The return-value is a mask, indicating which
956     *      elements of gcValues have been updated.
957     *      0 means there is no outline.
958     *
959     * Side effects:
960     *      GC information in gcValues is updated.
961     *
962     *--------------------------------------------------------------
963     */
964    
965    int Tk_ConfigOutlineGC(gcValues, canvas, item, outline)
966        XGCValues *gcValues;
967        Tk_Canvas canvas;
968        Tk_Item *item;
969        Tk_Outline *outline;
970    {
971        int mask = 0;
972        double width;
973        Tk_Dash *dash;
974        XColor *color;
975        Pixmap stipple;
976        Tk_State state = item->state;
977    
978        if (outline->width < 0.0) {
979            outline->width = 0.0;
980        }
981        if (outline->activeWidth < 0.0) {
982            outline->activeWidth = 0.0;
983        }
984        if (outline->disabledWidth < 0) {
985            outline->disabledWidth = 0.0;
986        }
987        if (state==TK_STATE_HIDDEN) {
988            return 0;
989        }
990    
991        width = outline->width;
992        if (width < 1.0) {
993            width = 1.0;
994        }
995        dash = &(outline->dash);
996        color = outline->color;
997        stipple = outline->stipple;
998        if (state == TK_STATE_NULL) {
999            state = ((TkCanvas *)canvas)->canvas_state;
1000        }
1001        if (((TkCanvas *)canvas)->currentItemPtr == item) {
1002            if (outline->activeWidth>width) {
1003                width = outline->activeWidth;
1004            }
1005            if (outline->activeDash.number != 0) {
1006                dash = &(outline->activeDash);
1007            }
1008            if (outline->activeColor!=NULL) {
1009                color = outline->activeColor;
1010            }
1011            if (outline->activeStipple!=None) {
1012                stipple = outline->activeStipple;
1013            }
1014        } else if (state==TK_STATE_DISABLED) {
1015            if (outline->disabledWidth>0) {
1016                width = outline->disabledWidth;
1017            }
1018            if (outline->disabledDash.number != 0) {
1019                dash = &(outline->disabledDash);
1020            }
1021            if (outline->disabledColor!=NULL) {
1022                color = outline->disabledColor;
1023            }
1024            if (outline->disabledStipple!=None) {
1025                stipple = outline->disabledStipple;
1026            }
1027        }
1028    
1029        if (color==NULL) {
1030            return 0;
1031        }
1032    
1033        gcValues->line_width = (int) (width + 0.5);
1034        if (color != NULL) {
1035            gcValues->foreground = color->pixel;
1036            mask = GCForeground|GCLineWidth;
1037            if (stipple != None) {
1038                gcValues->stipple = stipple;
1039                gcValues->fill_style = FillStippled;
1040                mask |= GCStipple|GCFillStyle;
1041            }
1042        }
1043        if (mask && (dash->number != 0)) {
1044            gcValues->line_style = LineOnOffDash;
1045            gcValues->dash_offset = outline->offset;
1046            if (dash->number >= 2) {
1047                gcValues->dashes = 4;
1048            } else if (dash->number > 0) {
1049                gcValues->dashes = dash->pattern.array[0];
1050            } else {
1051                gcValues->dashes = (char) (4 * width);
1052            }
1053            mask |= GCLineStyle|GCDashList|GCDashOffset;
1054        }
1055        return mask;
1056    }
1057    
1058    /*
1059     *--------------------------------------------------------------
1060     *
1061     * Tk_ChangeOutlineGC
1062     *
1063     *      Updates the GC to represent the full information of
1064     *      the dash structure. Partly this is already done in
1065     *      Tk_ConfigOutlineGC().
1066     *      This function should be called just before drawing
1067     *      the dashed item.
1068     *
1069     * Results:
1070     *      1 if there is a stipple pattern.
1071     *      0 otherwise.
1072     *
1073     * Side effects:
1074     *      GC is updated.
1075     *
1076     *--------------------------------------------------------------
1077     */
1078    
1079    int
1080    Tk_ChangeOutlineGC(canvas, item, outline)
1081        Tk_Canvas canvas;
1082        Tk_Item *item;
1083        Tk_Outline *outline;
1084    {
1085        CONST char *p;
1086        double width;
1087        Tk_Dash *dash;
1088        XColor *color;
1089        Pixmap stipple;
1090        Tk_State state = item->state;
1091    
1092        width = outline->width;
1093        if (width < 1.0) {
1094            width = 1.0;
1095        }
1096        dash = &(outline->dash);
1097        color = outline->color;
1098        stipple = outline->stipple;
1099        if (state == TK_STATE_NULL) {
1100            state = ((TkCanvas *)canvas)->canvas_state;
1101        }
1102        if (((TkCanvas *)canvas)->currentItemPtr == item) {
1103            if (outline->activeWidth > width) {
1104                width = outline->activeWidth;
1105            }
1106            if (outline->activeDash.number != 0) {
1107                dash = &(outline->activeDash);
1108            }
1109            if (outline->activeColor != NULL) {
1110                color = outline->activeColor;
1111            }
1112            if (outline->activeStipple != None) {
1113                stipple = outline->activeStipple;
1114            }
1115        } else if (state == TK_STATE_DISABLED) {
1116            if (outline->disabledWidth > width) {
1117                width = outline->disabledWidth;
1118            }
1119            if (outline->disabledDash.number != 0) {
1120                dash = &(outline->disabledDash);
1121            }
1122            if (outline->disabledColor != NULL) {
1123                color = outline->disabledColor;
1124            }
1125            if (outline->disabledStipple != None) {
1126                stipple = outline->disabledStipple;
1127            }
1128        }
1129        if (color==NULL) {
1130            return 0;
1131        }
1132    
1133        if ((dash->number<-1) || ((dash->number == -1) && (dash->pattern.array[1]!=','))) {
1134            char *q;
1135            int i = -dash->number;
1136    
1137            p = (i > sizeof(char *)) ? dash->pattern.pt : dash->pattern.array;
1138            q = (char *) ckalloc(2*(unsigned int)i);
1139            i = DashConvert(q, p, i, width);
1140            XSetDashes(((TkCanvas *)canvas)->display, outline->gc, outline->offset, q, i);
1141            ckfree(q);
1142        } else if ( dash->number>2 || (dash->number==2 &&
1143                    (dash->pattern.array[0]!=dash->pattern.array[1]))) {
1144            p = (char *) (dash->number > sizeof(char *)) ? dash->pattern.pt : dash->pattern.array;
1145            XSetDashes(((TkCanvas *)canvas)->display, outline->gc, outline->offset, p, dash->number);
1146        }
1147        if (stipple!=None) {
1148            int w=0; int h=0;
1149            Tk_TSOffset *tsoffset = &outline->tsoffset;
1150            int flags = tsoffset->flags;
1151            if (!(flags & TK_OFFSET_INDEX) && (flags & (TK_OFFSET_CENTER|TK_OFFSET_MIDDLE))) {
1152                Tk_SizeOfBitmap(((TkCanvas *)canvas)->display, stipple, &w, &h);
1153                if (flags & TK_OFFSET_CENTER) {
1154                    w /= 2;
1155                } else {
1156                    w = 0;
1157                }
1158                if (flags & TK_OFFSET_MIDDLE) {
1159                    h /= 2;
1160                } else {
1161                    h = 0;
1162                }
1163            }
1164            tsoffset->xoffset -= w;
1165            tsoffset->yoffset -= h;
1166            Tk_CanvasSetOffset(canvas, outline->gc, tsoffset);
1167            tsoffset->xoffset += w;
1168            tsoffset->yoffset += h;
1169            return 1;
1170        }
1171        return 0;
1172    }
1173    
1174    
1175    /*
1176     *--------------------------------------------------------------
1177     *
1178     * Tk_ResetOutlineGC
1179     *
1180     *      Restores the GC to the situation before
1181     *      Tk_ChangeDashGC() was called.
1182     *      This function should be called just after the dashed
1183     *      item is drawn, because the GC is supposed to be
1184     *      read-only.
1185     *
1186     * Results:
1187     *      1 if there is a stipple pattern.
1188     *      0 otherwise.
1189     *
1190     * Side effects:
1191     *      GC is updated.
1192     *
1193     *--------------------------------------------------------------
1194     */
1195    int
1196    Tk_ResetOutlineGC(canvas, item, outline)
1197        Tk_Canvas canvas;
1198        Tk_Item *item;
1199        Tk_Outline *outline;
1200    {
1201        char dashList;
1202        double width;
1203        Tk_Dash *dash;
1204        XColor *color;
1205        Pixmap stipple;
1206        Tk_State state = item->state;
1207    
1208        width = outline->width;
1209        if (width < 1.0) {
1210            width = 1.0;
1211        }
1212        dash = &(outline->dash);
1213        color = outline->color;
1214        stipple = outline->stipple;
1215        if (state == TK_STATE_NULL) {
1216            state = ((TkCanvas *)canvas)->canvas_state;
1217        }
1218        if (((TkCanvas *)canvas)->currentItemPtr == item) {
1219            if (outline->activeWidth>width) {
1220                width = outline->activeWidth;
1221            }
1222            if (outline->activeDash.number != 0) {
1223                dash = &(outline->activeDash);
1224            }
1225            if (outline->activeColor!=NULL) {
1226                color = outline->activeColor;
1227            }
1228            if (outline->activeStipple!=None) {
1229                stipple = outline->activeStipple;
1230            }
1231        } else if (state==TK_STATE_DISABLED) {
1232            if (outline->disabledWidth>width) {
1233                width = outline->disabledWidth;
1234            }
1235            if (outline->disabledDash.number != 0) {
1236                dash = &(outline->disabledDash);
1237            }
1238            if (outline->disabledColor!=NULL) {
1239                color = outline->disabledColor;
1240            }
1241            if (outline->disabledStipple!=None) {
1242                stipple = outline->disabledStipple;
1243            }
1244        }
1245        if (color==NULL) {
1246            return 0;
1247        }
1248    
1249        if ((dash->number > 2) || (dash->number < -1) || (dash->number==2 &&
1250                    (dash->pattern.array[0] != dash->pattern.array[1])) ||
1251                    ((dash->number == -1) && (dash->pattern.array[1] != ','))) {
1252            if (dash->number < 0) {
1253                dashList = (int) (4 * width + 0.5);
1254            } else if (dash->number<3) {
1255                dashList = dash->pattern.array[0];
1256            } else {
1257                dashList = 4;
1258            }
1259            XSetDashes(((TkCanvas *)canvas)->display, outline->gc,
1260                    outline->offset, &dashList , 1);
1261        }
1262        if (stipple != None) {
1263            XSetTSOrigin(((TkCanvas *)canvas)->display, outline->gc, 0, 0);
1264            return 1;
1265        }
1266        return 0;
1267    }
1268    
1269    
1270    /*
1271     *--------------------------------------------------------------
1272     *
1273     * Tk_CanvasPsOutline
1274     *
1275     *      Creates the postscript command for the correct
1276     *      Outline-information (width, dash, color and stipple).
1277     *
1278     * Results:
1279     *      TCL_OK if succeeded, otherwise TCL_ERROR.
1280     *
1281     * Side effects:
1282     *      canvas->interp->result contains the postscript string,
1283     *      or an error message if the result was TCL_ERROR.
1284     *
1285     *--------------------------------------------------------------
1286     */
1287    int
1288    Tk_CanvasPsOutline(canvas, item, outline)
1289        Tk_Canvas canvas;
1290        Tk_Item *item;
1291        Tk_Outline *outline;
1292    {
1293        char string[41];
1294        char pattern[11];
1295        int i;
1296        char *ptr;
1297        char *str = string;
1298        char *lptr = pattern;
1299        Tcl_Interp *interp = ((TkCanvas *)canvas)->interp;
1300        double width;
1301        Tk_Dash *dash;
1302        XColor *color;
1303        Pixmap stipple;
1304        Tk_State state = item->state;
1305    
1306        width = outline->width;
1307        dash = &(outline->dash);
1308        color = outline->color;
1309        stipple = outline->stipple;
1310        if (state == TK_STATE_NULL) {
1311            state = ((TkCanvas *)canvas)->canvas_state;
1312        }
1313        if (((TkCanvas *)canvas)->currentItemPtr == item) {
1314            if (outline->activeWidth > width) {
1315                width = outline->activeWidth;
1316            }
1317            if (outline->activeDash.number > 0) {
1318                dash = &(outline->activeDash);
1319            }
1320            if (outline->activeColor != NULL) {
1321                color = outline->activeColor;
1322            }
1323            if (outline->activeStipple != None) {
1324                stipple = outline->activeStipple;
1325            }
1326        } else if (state == TK_STATE_DISABLED) {
1327            if (outline->disabledWidth > 0) {
1328                width = outline->disabledWidth;
1329            }
1330            if (outline->disabledDash.number > 0) {
1331                dash = &(outline->disabledDash);
1332            }
1333            if (outline->disabledColor != NULL) {
1334                color = outline->disabledColor;
1335            }
1336            if (outline->disabledStipple != None) {
1337                stipple = outline->disabledStipple;
1338            }
1339        }
1340        sprintf(string, "%.15g setlinewidth\n", width);
1341        Tcl_AppendResult(interp, string, (char *) NULL);
1342    
1343        if (dash->number > 10) {
1344            str = (char *)ckalloc((unsigned int) (1 + 4*dash->number));
1345        } else if (dash->number < -5) {
1346            str = (char *)ckalloc((unsigned int) (1 - 8*dash->number));
1347            lptr = (char *)ckalloc((unsigned int) (1 - 2*dash->number));
1348        }
1349        ptr = (char *) ((ABS(dash->number) > sizeof(char *)) ) ?
1350            dash->pattern.pt : dash->pattern.array;
1351        if (dash->number > 0) {
1352            char *ptr0 = ptr;
1353            sprintf(str, "[%d", *ptr++ & 0xff);
1354            i = dash->number-1;
1355            while (i--) {
1356                sprintf(str+strlen(str), " %d", *ptr++ & 0xff);
1357            }
1358            Tcl_AppendResult(interp, str, (char *)NULL);
1359            if (dash->number&1) {
1360                Tcl_AppendResult(interp, " ", str+1, (char *)NULL);
1361            }
1362            sprintf(str, "] %d setdash\n", outline->offset);
1363            Tcl_AppendResult(interp, str, (char *)NULL);
1364            ptr = ptr0;
1365        } else if (dash->number < 0) {
1366            if ((i = DashConvert(lptr, ptr, -dash->number, width)) != 0) {
1367                char *lptr0 = lptr;
1368                sprintf(str, "[%d", *lptr++ & 0xff);
1369                while (--i) {
1370                    sprintf(str+strlen(str), " %d", *lptr++ & 0xff);
1371                }
1372                Tcl_AppendResult(interp, str, (char *)NULL);
1373                sprintf(str, "] %d setdash\n", outline->offset);
1374                Tcl_AppendResult(interp, str, (char *)NULL);
1375                lptr = lptr0;
1376            } else {
1377                Tcl_AppendResult(interp, "[] 0 setdash\n", (char *)NULL);
1378            }
1379        } else {
1380            Tcl_AppendResult(interp, "[] 0 setdash\n", (char *)NULL);
1381        }
1382        if (str != string) {
1383            ckfree(str);
1384        }
1385        if (lptr != pattern) {
1386            ckfree(lptr);
1387        }
1388        if (Tk_CanvasPsColor(interp, canvas, color) != TCL_OK) {
1389            return TCL_ERROR;
1390        }
1391        if (stipple != None) {
1392            Tcl_AppendResult(interp, "StrokeClip ", (char *) NULL);
1393            if (Tk_CanvasPsStipple(interp, canvas, stipple) != TCL_OK) {
1394                return TCL_ERROR;
1395            }
1396        } else {
1397            Tcl_AppendResult(interp, "stroke\n", (char *) NULL);
1398        }
1399    
1400        return TCL_OK;
1401    }
1402    
1403    
1404    /*
1405     *--------------------------------------------------------------
1406     *
1407     * DashConvert
1408     *
1409     *      Converts a character-like dash-list (e.g. "-..")
1410     *      into an X11-style. l must point to a string that
1411     *      holds room to at least 2*n characters. if
1412     *      l == NULL, this function can be used for
1413     *      syntax checking only.
1414     *
1415     * Results:
1416     *      The length of the resulting X11 compatible
1417     *      dash-list. -1 if failed.
1418     *
1419     * Side effects:
1420     *      None
1421     *
1422     *--------------------------------------------------------------
1423     */
1424    
1425    static int
1426    DashConvert (l, p, n, width)
1427        char *l;
1428        CONST char *p;
1429        int n;
1430        double width;
1431    {
1432        int result = 0;
1433        int size, intWidth;
1434    
1435        if (n<0) {
1436            n = strlen(p);
1437        }
1438        intWidth = (int) (width + 0.5);
1439        if (intWidth < 1) {
1440            intWidth = 1;
1441        }
1442        while (n-- && *p) {
1443            switch (*p++) {
1444                case ' ':
1445                    if (result) {
1446                        if (l) {
1447                            l[-1] += intWidth + 1;
1448                        }
1449                        continue;
1450                    } else {
1451                        return 0;
1452                    }
1453                    break;
1454                case '_':
1455                    size = 8;
1456                    break;
1457                case '-':
1458                    size = 6;
1459                    break;
1460                case ',':
1461                    size = 4;
1462                    break;
1463                case '.':
1464                    size = 2;
1465                    break;
1466                default:
1467                    return -1;
1468            }
1469            if (l) {
1470                *l++ = size * intWidth;
1471                *l++ = 4 * intWidth;
1472            }
1473            result += 2;
1474        }
1475        return result;
1476    }
1477    /* $Header$ */
1478    
1479    /* End of tkcanvutil.c */

Legend:
Removed from v.25  
changed lines
  Added in v.71

dashley@gmail.com
ViewVC Help
Powered by ViewVC 1.1.25