/[dtapublic]/projs/trunk/shared_source/c_tk_base_7_5_w_mods/tktextimage.c
ViewVC logotype

Diff of /projs/trunk/shared_source/c_tk_base_7_5_w_mods/tktextimage.c

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

sf_code/esrgpcpj/shared/tk_base/tktextimage.c revision 25 by dashley, Sat Oct 8 06:43:03 2016 UTC projs/trunk/shared_source/c_tk_base_7_5_w_mods/tktextimage.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/tktextimage.c,v 1.1.1.1 2001/06/13 05:10:24 dtashley Exp $ */  
   
 /*  
  * tkImage.c --  
  *  
  *      This file contains code that allows images to be  
  *      nested inside text widgets.  It also implements the "image"  
  *      widget command for texts.  
  *  
  * Copyright (c) 1997 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: tktextimage.c,v 1.1.1.1 2001/06/13 05:10:24 dtashley Exp $  
  */  
   
 #include "tk.h"  
 #include "tkText.h"  
 #include "tkPort.h"  
   
 /*  
  * Definitions for alignment values:  
  */  
   
 #define ALIGN_BOTTOM            0  
 #define ALIGN_CENTER            1  
 #define ALIGN_TOP               2  
 #define ALIGN_BASELINE          3  
   
 /*  
  * Macro that determines the size of an embedded image segment:  
  */  
   
 #define EI_SEG_SIZE ((unsigned) (Tk_Offset(TkTextSegment, body) \  
         + sizeof(TkTextEmbImage)))  
   
 /*  
  * Prototypes for procedures defined in this file:  
  */  
   
 static int              AlignParseProc _ANSI_ARGS_((ClientData clientData,  
                             Tcl_Interp *interp, Tk_Window tkwin, char *value,  
                             char *widgRec, int offset));  
 static char *           AlignPrintProc _ANSI_ARGS_((ClientData clientData,  
                             Tk_Window tkwin, char *widgRec, int offset,  
                             Tcl_FreeProc **freeProcPtr));  
 static TkTextSegment *  EmbImageCleanupProc _ANSI_ARGS_((TkTextSegment *segPtr,  
                             TkTextLine *linePtr));  
 static void             EmbImageCheckProc _ANSI_ARGS_((TkTextSegment *segPtr,  
                             TkTextLine *linePtr));  
 static void             EmbImageBboxProc _ANSI_ARGS_((TkTextDispChunk *chunkPtr,  
                             int index, int y, int lineHeight, int baseline,  
                             int *xPtr, int *yPtr, int *widthPtr,  
                             int *heightPtr));  
 static int              EmbImageConfigure _ANSI_ARGS_((TkText *textPtr,  
                             TkTextSegment *eiPtr, int argc, char **argv));  
 static int              EmbImageDeleteProc _ANSI_ARGS_((TkTextSegment *segPtr,  
                             TkTextLine *linePtr, int treeGone));  
 static void             EmbImageDisplayProc _ANSI_ARGS_((  
                             TkTextDispChunk *chunkPtr, int x, int y,  
                             int lineHeight, int baseline, Display *display,  
                             Drawable dst, int screenY));  
 static int              EmbImageLayoutProc _ANSI_ARGS_((TkText *textPtr,  
                             TkTextIndex *indexPtr, TkTextSegment *segPtr,  
                             int offset, int maxX, int maxChars,  
                             int noCharsYet, TkWrapMode wrapMode,  
                             TkTextDispChunk *chunkPtr));  
 static void             EmbImageProc _ANSI_ARGS_((ClientData clientData,  
                             int x, int y, int width, int height,  
                             int imageWidth, int imageHeight));  
   
 /*  
  * The following structure declares the "embedded image" segment type.  
  */  
   
 static Tk_SegType tkTextEmbImageType = {  
     "image",                                    /* name */  
     0,                                          /* leftGravity */  
     (Tk_SegSplitProc *) NULL,                   /* splitProc */  
     EmbImageDeleteProc,                         /* deleteProc */  
     EmbImageCleanupProc,                        /* cleanupProc */  
     (Tk_SegLineChangeProc *) NULL,              /* lineChangeProc */  
     EmbImageLayoutProc,                         /* layoutProc */  
     EmbImageCheckProc                           /* checkProc */  
 };  
   
 /*  
  * Information used for parsing image configuration options:  
  */  
   
 static Tk_CustomOption alignOption = {AlignParseProc, AlignPrintProc,  
         (ClientData) NULL};  
   
 static Tk_ConfigSpec configSpecs[] = {  
     {TK_CONFIG_CUSTOM, "-align", (char *) NULL, (char *) NULL,  
         "center", 0, TK_CONFIG_DONT_SET_DEFAULT, &alignOption},  
     {TK_CONFIG_PIXELS, "-padx", (char *) NULL, (char *) NULL,  
         "0", Tk_Offset(TkTextEmbImage, padX),  
         TK_CONFIG_DONT_SET_DEFAULT},  
     {TK_CONFIG_PIXELS, "-pady", (char *) NULL, (char *) NULL,  
         "0", Tk_Offset(TkTextEmbImage, padY),  
         TK_CONFIG_DONT_SET_DEFAULT},  
     {TK_CONFIG_STRING, "-image", (char *) NULL, (char *) NULL,  
         (char *) NULL, Tk_Offset(TkTextEmbImage, imageString),  
         TK_CONFIG_DONT_SET_DEFAULT|TK_CONFIG_NULL_OK},  
     {TK_CONFIG_STRING, "-name", (char *) NULL, (char *) NULL,  
         (char *) NULL, Tk_Offset(TkTextEmbImage, imageName),  
         TK_CONFIG_DONT_SET_DEFAULT|TK_CONFIG_NULL_OK},  
     {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,  
         (char *) NULL, 0, 0}  
 };  
   
 /*  
  *--------------------------------------------------------------  
  *  
  * TkTextImageCmd --  
  *  
  *      This procedure implements the "image" widget command  
  *      for text widgets.  See the user documentation for details  
  *      on what it does.  
  *  
  * Results:  
  *      A standard Tcl result or error.  
  *  
  * Side effects:  
  *      See the user documentation.  
  *  
  *--------------------------------------------------------------  
  */  
   
 int  
 TkTextImageCmd(textPtr, interp, argc, argv)  
     register TkText *textPtr;   /* Information about text widget. */  
     Tcl_Interp *interp;         /* Current interpreter. */  
     int argc;                   /* Number of arguments. */  
     char **argv;                /* Argument strings.  Someone else has already  
                                  * parsed this command enough to know that  
                                  * argv[1] is "image". */  
 {  
     size_t length;  
     register TkTextSegment *eiPtr;  
   
     if (argc < 3) {  
         Tcl_AppendResult(interp, "wrong # args: should be \"",  
                 argv[0], " image option ?arg arg ...?\"", (char *) NULL);  
         return TCL_ERROR;  
     }  
     length = strlen(argv[2]);  
     if ((strncmp(argv[2], "cget", length) == 0) && (length >= 2)) {  
         TkTextIndex index;  
         TkTextSegment *eiPtr;  
   
         if (argc != 5) {  
             Tcl_AppendResult(interp, "wrong # args: should be \"",  
                     argv[0], " image cget index option\"",  
                     (char *) NULL);  
             return TCL_ERROR;  
         }  
         if (TkTextGetIndex(interp, textPtr, argv[3], &index) != TCL_OK) {  
             return TCL_ERROR;  
         }  
         eiPtr = TkTextIndexToSeg(&index, (int *) NULL);  
         if (eiPtr->typePtr != &tkTextEmbImageType) {  
             Tcl_AppendResult(interp, "no embedded image at index \"",  
                     argv[3], "\"", (char *) NULL);  
             return TCL_ERROR;  
         }  
         return Tk_ConfigureValue(interp, textPtr->tkwin, configSpecs,  
                 (char *) &eiPtr->body.ei, argv[4], 0);  
     } else if ((strncmp(argv[2], "configure", length) == 0) && (length >= 2)) {  
         TkTextIndex index;  
         TkTextSegment *eiPtr;  
   
         if (argc < 4) {  
             Tcl_AppendResult(interp, "wrong # args: should be \"",  
                     argv[0], " image configure index ?option value ...?\"",  
                     (char *) NULL);  
             return TCL_ERROR;  
         }  
         if (TkTextGetIndex(interp, textPtr, argv[3], &index) != TCL_OK) {  
             return TCL_ERROR;  
         }  
         eiPtr = TkTextIndexToSeg(&index, (int *) NULL);  
         if (eiPtr->typePtr != &tkTextEmbImageType) {  
             Tcl_AppendResult(interp, "no embedded image at index \"",  
                     argv[3], "\"", (char *) NULL);  
             return TCL_ERROR;  
         }  
         if (argc == 4) {  
             return Tk_ConfigureInfo(interp, textPtr->tkwin, configSpecs,  
                     (char *) &eiPtr->body.ei, (char *) NULL, 0);  
         } else if (argc == 5) {  
             return Tk_ConfigureInfo(interp, textPtr->tkwin, configSpecs,  
                     (char *) &eiPtr->body.ei, argv[4], 0);  
         } else {  
             TkTextChanged(textPtr, &index, &index);  
             return EmbImageConfigure(textPtr, eiPtr, argc-4, argv+4);  
         }  
     } else if ((strncmp(argv[2], "create", length) == 0) && (length >= 2)) {  
         TkTextIndex index;  
         int lineIndex;  
   
         /*  
          * Add a new image.  Find where to put the new image, and  
          * mark that position for redisplay.  
          */  
   
         if (argc < 4) {  
             Tcl_AppendResult(interp, "wrong # args: should be \"",  
                     argv[0], " image create index ?option value ...?\"",  
                     (char *) NULL);  
             return TCL_ERROR;  
         }  
         if (TkTextGetIndex(interp, textPtr, argv[3], &index) != TCL_OK) {  
             return TCL_ERROR;  
         }  
   
         /*  
          * Don't allow insertions on the last (dummy) line of the text.  
          */  
       
         lineIndex = TkBTreeLineIndex(index.linePtr);  
         if (lineIndex == TkBTreeNumLines(textPtr->tree)) {  
             lineIndex--;  
             TkTextMakeByteIndex(textPtr->tree, lineIndex, 1000000, &index);  
         }  
   
         /*  
          * Create the new image segment and initialize it.  
          */  
   
         eiPtr = (TkTextSegment *) ckalloc(EI_SEG_SIZE);  
         eiPtr->typePtr = &tkTextEmbImageType;  
         eiPtr->size = 1;  
         eiPtr->body.ei.textPtr = textPtr;  
         eiPtr->body.ei.linePtr = NULL;  
         eiPtr->body.ei.imageName = NULL;  
         eiPtr->body.ei.imageString = NULL;  
         eiPtr->body.ei.name = NULL;  
         eiPtr->body.ei.image = NULL;  
         eiPtr->body.ei.align = ALIGN_CENTER;  
         eiPtr->body.ei.padX = eiPtr->body.ei.padY = 0;  
         eiPtr->body.ei.chunkCount = 0;  
   
         /*  
          * Link the segment into the text widget, then configure it (delete  
          * it again if the configuration fails).  
          */  
   
         TkTextChanged(textPtr, &index, &index);  
         TkBTreeLinkSegment(eiPtr, &index);  
         if (EmbImageConfigure(textPtr, eiPtr, argc-4, argv+4) != TCL_OK) {  
             TkTextIndex index2;  
   
             TkTextIndexForwChars(&index, 1, &index2);  
             TkBTreeDeleteChars(&index, &index2);  
             return TCL_ERROR;  
         }  
     } else if (strncmp(argv[2], "names", length) == 0) {  
         Tcl_HashSearch search;  
         Tcl_HashEntry *hPtr;  
   
         if (argc != 3) {  
             Tcl_AppendResult(interp, "wrong # args: should be \"",  
                     argv[0], " image names\"", (char *) NULL);  
             return TCL_ERROR;  
         }  
         for (hPtr = Tcl_FirstHashEntry(&textPtr->imageTable, &search);  
                 hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) {  
             Tcl_AppendElement(interp,  
                     Tcl_GetHashKey(&textPtr->markTable, hPtr));  
         }  
     } else {  
         Tcl_AppendResult(interp, "bad image option \"", argv[2],  
                 "\": must be cget, configure, create, or names",  
                 (char *) NULL);  
         return TCL_ERROR;  
     }  
     return TCL_OK;  
 }  
   
 /*  
  *--------------------------------------------------------------  
  *  
  * EmbImageConfigure --  
  *  
  *      This procedure is called to handle configuration options  
  *      for an embedded image, using an argc/argv list.  
  *  
  * Results:  
  *      The return value is a standard Tcl result.  If TCL_ERROR is  
  *      returned, then the interp's result contains an error message..  
  *  
  * Side effects:  
  *      Configuration information for the embedded image changes,  
  *      such as alignment, or name of the image.  
  *  
  *--------------------------------------------------------------  
  */  
   
 static int  
 EmbImageConfigure(textPtr, eiPtr, argc, argv)  
     TkText *textPtr;            /* Information about text widget that  
                                  * contains embedded image. */  
     TkTextSegment *eiPtr;       /* Embedded image to be configured. */  
     int argc;                   /* Number of strings in argv. */  
     char **argv;                /* Array of strings describing configuration  
                                  * options. */  
 {  
     Tk_Image image;  
     Tcl_DString newName;  
     Tcl_HashEntry *hPtr;  
     Tcl_HashSearch search;  
     int new;  
     char *name;  
     int count = 0;              /* The counter for picking a unique name */  
     int conflict = 0;           /* True if we have a name conflict */  
     unsigned int len;           /* length of image name */  
   
     if (Tk_ConfigureWidget(textPtr->interp, textPtr->tkwin, configSpecs,  
             argc, argv, (char *) &eiPtr->body.ei,TK_CONFIG_ARGV_ONLY)  
             != TCL_OK) {  
         return TCL_ERROR;  
     }  
   
     /*  
      * Create the image.  Save the old image around and don't free it  
      * until after the new one is allocated.  This keeps the reference  
      * count from going to zero so the image doesn't have to be recreated  
      * if it hasn't changed.  
      */  
   
     if (eiPtr->body.ei.imageString != NULL) {  
         image = Tk_GetImage(textPtr->interp, textPtr->tkwin, eiPtr->body.ei.imageString,  
                 EmbImageProc, (ClientData) eiPtr);  
         if (image == NULL) {  
             return TCL_ERROR;  
         }  
     } else {  
         image = NULL;  
     }  
     if (eiPtr->body.ei.image != NULL) {  
         Tk_FreeImage(eiPtr->body.ei.image);  
     }  
     eiPtr->body.ei.image = image;  
   
     if (eiPtr->body.ei.name != NULL) {  
         return TCL_OK;  
     }  
   
     /*  
      * Find a unique name for this image.  Use imageName (or imageString)  
      * if available, otherwise tack on a #nn and use it.  If a name is already  
      * associated with this image, delete the name.  
      */  
   
     name = eiPtr->body.ei.imageName;  
     if (name == NULL) {  
         name = eiPtr->body.ei.imageString;  
     }  
     if (name == NULL) {  
         Tcl_AppendResult(textPtr->interp,"Either a \"-name\" ",  
                 "or a \"-image\" argument must be provided ",  
                 "to the \"image create\" subcommand.",  
                 (char *) NULL);  
         return TCL_ERROR;  
     }  
     len = strlen(name);  
     for (hPtr = Tcl_FirstHashEntry(&textPtr->imageTable, &search);  
             hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) {  
         char *haveName = Tcl_GetHashKey(&textPtr->imageTable, hPtr);  
         if (strncmp(name, haveName, len) == 0) {  
             new = 0;  
             sscanf(haveName+len,"#%d",&new);  
             if (new > count) {  
                 count = new;  
             }  
             if (len == (int) strlen(haveName)) {  
                 conflict = 1;  
             }  
         }  
     }  
   
     Tcl_DStringInit(&newName);  
     Tcl_DStringAppend(&newName,name, -1);  
   
     if (conflict) {  
         char buf[4 + TCL_INTEGER_SPACE];  
         sprintf(buf, "#%d",count+1);  
         Tcl_DStringAppend(&newName,buf, -1);  
     }  
     name = Tcl_DStringValue(&newName);  
     hPtr = Tcl_CreateHashEntry(&textPtr->imageTable, name, &new);  
     Tcl_SetHashValue(hPtr, eiPtr);  
     Tcl_AppendResult(textPtr->interp, name , (char *) NULL);  
     eiPtr->body.ei.name = ckalloc((unsigned) Tcl_DStringLength(&newName)+1);  
     strcpy(eiPtr->body.ei.name,name);  
     Tcl_DStringFree(&newName);  
   
     return TCL_OK;  
 }  
   
 /*  
  *--------------------------------------------------------------  
  *  
  * AlignParseProc --  
  *  
  *      This procedure is invoked by Tk_ConfigureWidget during  
  *      option processing to handle "-align" options for embedded  
  *      images.  
  *  
  * Results:  
  *      A standard Tcl return value.  
  *  
  * Side effects:  
  *      The alignment for the embedded image may change.  
  *  
  *--------------------------------------------------------------  
  */  
   
         /* ARGSUSED */  
 static int  
 AlignParseProc(clientData, interp, tkwin, value, widgRec, offset)  
     ClientData clientData;              /* Not used.*/  
     Tcl_Interp *interp;                 /* Used for reporting errors. */  
     Tk_Window tkwin;                    /* Window for text widget. */  
     char *value;                        /* Value of option. */  
     char *widgRec;                      /* Pointer to TkTextEmbWindow  
                                          * structure. */  
     int offset;                         /* Offset into item (ignored). */  
 {  
     register TkTextEmbImage *embPtr = (TkTextEmbImage *) widgRec;  
   
     if (strcmp(value, "baseline") == 0) {  
         embPtr->align = ALIGN_BASELINE;  
     } else if (strcmp(value, "bottom") == 0) {  
         embPtr->align = ALIGN_BOTTOM;  
     } else if (strcmp(value, "center") == 0) {  
         embPtr->align = ALIGN_CENTER;  
     } else if (strcmp(value, "top") == 0) {  
         embPtr->align = ALIGN_TOP;  
     } else {  
         Tcl_AppendResult(interp, "bad alignment \"", value,  
                 "\": must be baseline, bottom, center, or top",  
                 (char *) NULL);  
         return TCL_ERROR;  
     }  
     return TCL_OK;  
 }  
   
 /*  
  *--------------------------------------------------------------  
  *  
  * AlignPrintProc --  
  *  
  *      This procedure is invoked by the Tk configuration code  
  *      to produce a printable string for the "-align" configuration  
  *      option for embedded images.  
  *  
  * Results:  
  *      The return value is a string describing the embedded  
  *      images's current alignment.  
  *  
  * Side effects:  
  *      None.  
  *  
  *--------------------------------------------------------------  
  */  
   
         /* ARGSUSED */  
 static char *  
 AlignPrintProc(clientData, tkwin, widgRec, offset, freeProcPtr)  
     ClientData clientData;              /* Ignored. */  
     Tk_Window tkwin;                    /* Window for text widget. */  
     char *widgRec;                      /* Pointer to TkTextEmbImage  
                                          * structure. */  
     int offset;                         /* Ignored. */  
     Tcl_FreeProc **freeProcPtr;         /* Pointer to variable to fill in with  
                                          * information about how to reclaim  
                                          * storage for return string. */  
 {  
     switch (((TkTextEmbImage *) widgRec)->align) {  
         case ALIGN_BASELINE:  
             return "baseline";  
         case ALIGN_BOTTOM:  
             return "bottom";  
         case ALIGN_CENTER:  
             return "center";  
         case ALIGN_TOP:  
             return "top";  
         default:  
             return "??";  
     }  
 }  
   
 /*  
  *--------------------------------------------------------------  
  *  
  * EmbImageDeleteProc --  
  *  
  *      This procedure is invoked by the text B-tree code whenever  
  *      an embedded image lies in a range of characters being deleted.  
  *  
  * Results:  
  *      Returns 0 to indicate that the deletion has been accepted.  
  *  
  * Side effects:  
  *      The embedded image is deleted, if it exists, and any resources  
  *      associated with it are released.  
  *  
  *--------------------------------------------------------------  
  */  
   
         /* ARGSUSED */  
 static int  
 EmbImageDeleteProc(eiPtr, linePtr, treeGone)  
     TkTextSegment *eiPtr;               /* Segment being deleted. */  
     TkTextLine *linePtr;                /* Line containing segment. */  
     int treeGone;                       /* Non-zero means the entire tree is  
                                          * being deleted, so everything must  
                                          * get cleaned up. */  
 {  
     Tcl_HashEntry *hPtr;  
   
     if (eiPtr->body.ei.image != NULL) {  
         hPtr = Tcl_FindHashEntry(&eiPtr->body.ei.textPtr->imageTable,  
                 eiPtr->body.ei.name);  
         if (hPtr != NULL) {  
             /*  
              * (It's possible for there to be no hash table entry for this  
              * image, if an error occurred while creating the image segment  
              * but before the image got added to the table)  
              */  
   
             Tcl_DeleteHashEntry(hPtr);  
         }  
         Tk_FreeImage(eiPtr->body.ei.image);  
     }  
     Tk_FreeOptions(configSpecs, (char *) &eiPtr->body.ei,  
             eiPtr->body.ei.textPtr->display, 0);  
     if (eiPtr->body.ei.name != NULL) {  
         ckfree(eiPtr->body.ei.name);  
     }  
     ckfree((char *) eiPtr);  
     return 0;  
 }  
   
 /*  
  *--------------------------------------------------------------  
  *  
  * EmbImageCleanupProc --  
  *  
  *      This procedure is invoked by the B-tree code whenever a  
  *      segment containing an embedded image is moved from one  
  *      line to another.  
  *  
  * Results:  
  *      None.  
  *  
  * Side effects:  
  *      The linePtr field of the segment gets updated.  
  *  
  *--------------------------------------------------------------  
  */  
   
 static TkTextSegment *  
 EmbImageCleanupProc(eiPtr, linePtr)  
     TkTextSegment *eiPtr;               /* Mark segment that's being moved. */  
     TkTextLine *linePtr;                /* Line that now contains segment. */  
 {  
     eiPtr->body.ei.linePtr = linePtr;  
     return eiPtr;  
 }  
   
 /*  
  *--------------------------------------------------------------  
  *  
  * EmbImageLayoutProc --  
  *  
  *      This procedure is the "layoutProc" for embedded image  
  *      segments.  
  *  
  * Results:  
  *      1 is returned to indicate that the segment should be  
  *      displayed.  The chunkPtr structure is filled in.  
  *  
  * Side effects:  
  *      None, except for filling in chunkPtr.  
  *  
  *--------------------------------------------------------------  
  */  
   
         /*ARGSUSED*/  
 static int  
 EmbImageLayoutProc(textPtr, indexPtr, eiPtr, offset, maxX, maxChars,  
         noCharsYet, wrapMode, chunkPtr)  
     TkText *textPtr;            /* Text widget being layed out. */  
     TkTextIndex *indexPtr;      /* Identifies first character in chunk. */  
     TkTextSegment *eiPtr;       /* Segment corresponding to indexPtr. */  
     int offset;                 /* Offset within segPtr corresponding to  
                                  * indexPtr (always 0). */  
     int maxX;                   /* Chunk must not occupy pixels at this  
                                  * position or higher. */  
     int maxChars;               /* Chunk must not include more than this  
                                  * many characters. */  
     int noCharsYet;             /* Non-zero means no characters have been  
                                  * assigned to this line yet. */  
     TkWrapMode wrapMode;        /* Wrap mode to use for line: TEXT_WRAPMODE_CHAR,  
                                  * TEXT_WRAPMODE_NONE, or TEXT_WRAPMODE_WORD. */  
     register TkTextDispChunk *chunkPtr;  
                                 /* Structure to fill in with information  
                                  * about this chunk.  The x field has already  
                                  * been set by the caller. */  
 {  
     int width, height;  
   
     if (offset != 0) {  
         panic("Non-zero offset in EmbImageLayoutProc");  
     }  
   
     /*  
      * See if there's room for this image on this line.  
      */  
   
     if (eiPtr->body.ei.image == NULL) {  
         width = 0;  
         height = 0;  
     } else {  
         Tk_SizeOfImage(eiPtr->body.ei.image, &width, &height);  
         width += 2*eiPtr->body.ei.padX;  
         height += 2*eiPtr->body.ei.padY;  
     }  
     if ((width > (maxX - chunkPtr->x))  
             && !noCharsYet && (textPtr->wrapMode != TEXT_WRAPMODE_NONE)) {  
         return 0;  
     }  
   
     /*  
      * Fill in the chunk structure.  
      */  
   
     chunkPtr->displayProc = EmbImageDisplayProc;  
     chunkPtr->undisplayProc = (Tk_ChunkUndisplayProc *) NULL;  
     chunkPtr->measureProc = (Tk_ChunkMeasureProc *) NULL;  
     chunkPtr->bboxProc = EmbImageBboxProc;  
     chunkPtr->numBytes = 1;  
     if (eiPtr->body.ei.align == ALIGN_BASELINE) {  
         chunkPtr->minAscent = height - eiPtr->body.ei.padY;  
         chunkPtr->minDescent = eiPtr->body.ei.padY;  
         chunkPtr->minHeight = 0;  
     } else {  
         chunkPtr->minAscent = 0;  
         chunkPtr->minDescent = 0;  
         chunkPtr->minHeight = height;  
     }  
     chunkPtr->width = width;  
     chunkPtr->breakIndex = -1;  
     chunkPtr->breakIndex = 1;  
     chunkPtr->clientData = (ClientData) eiPtr;  
     eiPtr->body.ei.chunkCount += 1;  
     return 1;  
 }  
   
 /*  
  *--------------------------------------------------------------  
  *  
  * EmbImageCheckProc --  
  *  
  *      This procedure is invoked by the B-tree code to perform  
  *      consistency checks on embedded images.  
  *  
  * Results:  
  *      None.  
  *  
  * Side effects:  
  *      The procedure panics if it detects anything wrong with  
  *      the embedded image.  
  *  
  *--------------------------------------------------------------  
  */  
   
 static void  
 EmbImageCheckProc(eiPtr, linePtr)  
     TkTextSegment *eiPtr;               /* Segment to check. */  
     TkTextLine *linePtr;                /* Line containing segment. */  
 {  
     if (eiPtr->nextPtr == NULL) {  
         panic("EmbImageCheckProc: embedded image is last segment in line");  
     }  
     if (eiPtr->size != 1) {  
         panic("EmbImageCheckProc: embedded image has size %d", eiPtr->size);  
     }  
 }  
   
 /*  
  *--------------------------------------------------------------  
  *  
  * EmbImageDisplayProc --  
  *  
  *      This procedure is invoked by the text displaying code  
  *      when it is time to actually draw an embedded image  
  *      chunk on the screen.  
  *  
  * Results:  
  *      None.  
  *  
  * Side effects:  
  *      The embedded image gets moved to the correct location  
  *      and drawn onto the display.  
  *  
  *--------------------------------------------------------------  
  */  
   
 static void  
 EmbImageDisplayProc(chunkPtr, x, y, lineHeight, baseline, display, dst, screenY)  
     TkTextDispChunk *chunkPtr;          /* Chunk that is to be drawn. */  
     int x;                              /* X-position in dst at which to  
                                          * draw this chunk (differs from  
                                          * the x-position in the chunk because  
                                          * of scrolling). */  
     int y;                              /* Top of rectangular bounding box  
                                          * for line: tells where to draw this  
                                          * chunk in dst (x-position is in  
                                          * the chunk itself). */  
     int lineHeight;                     /* Total height of line. */  
     int baseline;                       /* Offset of baseline from y. */  
     Display *display;                   /* Display to use for drawing. */  
     Drawable dst;                       /* Pixmap or window in which to draw */  
     int screenY;                        /* Y-coordinate in text window that  
                                          * corresponds to y. */  
 {  
     TkTextSegment *eiPtr = (TkTextSegment *) chunkPtr->clientData;  
     int lineX, imageX, imageY, width, height;  
     Tk_Image image;  
   
     image = eiPtr->body.ei.image;  
     if (image == NULL) {  
         return;  
     }  
     if ((x + chunkPtr->width) <= 0) {  
         return;  
     }  
   
     /*  
      * Compute the image's location and size in the text widget, taking  
      * into account the align value for the image.  
      */  
   
     EmbImageBboxProc(chunkPtr, 0, y, lineHeight, baseline, &lineX,  
             &imageY, &width, &height);  
     imageX = lineX - chunkPtr->x + x;  
   
     Tk_RedrawImage(image, 0, 0, width, height, dst,  
             imageX, imageY);  
 }  
   
 /*  
  *--------------------------------------------------------------  
  *  
  * EmbImageBboxProc --  
  *  
  *      This procedure is called to compute the bounding box of  
  *      the area occupied by an embedded image.  
  *  
  * Results:  
  *      There is no return value.  *xPtr and *yPtr are filled in  
  *      with the coordinates of the upper left corner of the  
  *      image, and *widthPtr and *heightPtr are filled in with  
  *      the dimensions of the image in pixels.  Note:  not all  
  *      of the returned bbox is necessarily visible on the screen  
  *      (the rightmost part might be off-screen to the right,  
  *      and the bottommost part might be off-screen to the bottom).  
  *  
  * Side effects:  
  *      None.  
  *  
  *--------------------------------------------------------------  
  */  
   
 static void  
 EmbImageBboxProc(chunkPtr, index, y, lineHeight, baseline, xPtr, yPtr,  
         widthPtr, heightPtr)  
     TkTextDispChunk *chunkPtr;          /* Chunk containing desired char. */  
     int index;                          /* Index of desired character within  
                                          * the chunk. */  
     int y;                              /* Topmost pixel in area allocated  
                                          * for this line. */  
     int lineHeight;                     /* Total height of line. */  
     int baseline;                       /* Location of line's baseline, in  
                                          * pixels measured down from y. */  
     int *xPtr, *yPtr;                   /* Gets filled in with coords of  
                                          * character's upper-left pixel. */  
     int *widthPtr;                      /* Gets filled in with width of  
                                          * character, in pixels. */  
     int *heightPtr;                     /* Gets filled in with height of  
                                          * character, in pixels. */  
 {  
     TkTextSegment *eiPtr = (TkTextSegment *) chunkPtr->clientData;  
     Tk_Image image;  
   
     image = eiPtr->body.ei.image;  
     if (image != NULL) {  
         Tk_SizeOfImage(image, widthPtr, heightPtr);  
     } else {  
         *widthPtr = 0;  
         *heightPtr = 0;  
     }  
     *xPtr = chunkPtr->x + eiPtr->body.ei.padX;  
     switch (eiPtr->body.ei.align) {  
         case ALIGN_BOTTOM:  
             *yPtr = y + (lineHeight - *heightPtr - eiPtr->body.ei.padY);  
             break;  
         case ALIGN_CENTER:  
             *yPtr = y + (lineHeight - *heightPtr)/2;  
             break;  
         case ALIGN_TOP:  
             *yPtr = y + eiPtr->body.ei.padY;  
             break;  
         case ALIGN_BASELINE:  
             *yPtr = y + (baseline - *heightPtr);  
             break;  
     }  
 }  
   
 /*  
  *--------------------------------------------------------------  
  *  
  * TkTextImageIndex --  
  *  
  *      Given the name of an embedded image within a text widget,  
  *      returns an index corresponding to the image's position  
  *      in the text.  
  *  
  * Results:  
  *      The return value is 1 if there is an embedded image by  
  *      the given name in the text widget, 0 otherwise.  If the  
  *      image exists, *indexPtr is filled in with its index.  
  *  
  * Side effects:  
  *      None.  
  *  
  *--------------------------------------------------------------  
  */  
   
 int  
 TkTextImageIndex(textPtr, name, indexPtr)  
     TkText *textPtr;            /* Text widget containing image. */  
     char *name;                 /* Name of image. */  
     TkTextIndex *indexPtr;      /* Index information gets stored here. */  
 {  
     Tcl_HashEntry *hPtr;  
     TkTextSegment *eiPtr;  
   
     hPtr = Tcl_FindHashEntry(&textPtr->imageTable, name);  
     if (hPtr == NULL) {  
         return 0;  
     }  
     eiPtr = (TkTextSegment *) Tcl_GetHashValue(hPtr);  
     indexPtr->tree = textPtr->tree;  
     indexPtr->linePtr = eiPtr->body.ei.linePtr;  
     indexPtr->byteIndex = TkTextSegToOffset(eiPtr, indexPtr->linePtr);  
     return 1;  
 }  
   
 /*  
  *--------------------------------------------------------------  
  *  
  * EmbImageProc --  
  *  
  *      This procedure is called by the image code whenever an  
  *      image or its contents changes.  
  *  
  * Results:  
  *      None.  
  *  
  * Side effects:  
  *      The image will be redisplayed.  
  *  
  *--------------------------------------------------------------  
  */  
   
 static void  
 EmbImageProc(clientData, x, y, width, height, imgWidth, imgHeight)  
     ClientData clientData;              /* Pointer to widget record. */  
     int x, y;                           /* Upper left pixel (within image)  
                                          * that must be redisplayed. */  
     int width, height;                  /* Dimensions of area to redisplay  
                                          * (may be <= 0). */  
     int imgWidth, imgHeight;            /* New dimensions of image. */  
   
 {  
     TkTextSegment *eiPtr = (TkTextSegment *) clientData;  
     TkTextIndex index;  
   
     index.tree = eiPtr->body.ei.textPtr->tree;  
     index.linePtr = eiPtr->body.ei.linePtr;  
     index.byteIndex = TkTextSegToOffset(eiPtr, eiPtr->body.ei.linePtr);  
     TkTextChanged(eiPtr->body.ei.textPtr, &index, &index);  
 }  
   
   
 /* $History: tkTextImage.c $  
  *  
  * *****************  Version 1  *****************  
  * User: Dtashley     Date: 1/02/01    Time: 3:07a  
  * Created in $/IjuScripter, IjuConsole/Source/Tk Base  
  * Initial check-in.  
  */  
   
 /* End of TKTEXTIMAGE.C */  
1    /* $Header$ */
2    
3    /*
4     * tkImage.c --
5     *
6     *      This file contains code that allows images to be
7     *      nested inside text widgets.  It also implements the "image"
8     *      widget command for texts.
9     *
10     * Copyright (c) 1997 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: tktextimage.c,v 1.1.1.1 2001/06/13 05:10:24 dtashley Exp $
16     */
17    
18    #include "tk.h"
19    #include "tkText.h"
20    #include "tkPort.h"
21    
22    /*
23     * Definitions for alignment values:
24     */
25    
26    #define ALIGN_BOTTOM            0
27    #define ALIGN_CENTER            1
28    #define ALIGN_TOP               2
29    #define ALIGN_BASELINE          3
30    
31    /*
32     * Macro that determines the size of an embedded image segment:
33     */
34    
35    #define EI_SEG_SIZE ((unsigned) (Tk_Offset(TkTextSegment, body) \
36            + sizeof(TkTextEmbImage)))
37    
38    /*
39     * Prototypes for procedures defined in this file:
40     */
41    
42    static int              AlignParseProc _ANSI_ARGS_((ClientData clientData,
43                                Tcl_Interp *interp, Tk_Window tkwin, char *value,
44                                char *widgRec, int offset));
45    static char *           AlignPrintProc _ANSI_ARGS_((ClientData clientData,
46                                Tk_Window tkwin, char *widgRec, int offset,
47                                Tcl_FreeProc **freeProcPtr));
48    static TkTextSegment *  EmbImageCleanupProc _ANSI_ARGS_((TkTextSegment *segPtr,
49                                TkTextLine *linePtr));
50    static void             EmbImageCheckProc _ANSI_ARGS_((TkTextSegment *segPtr,
51                                TkTextLine *linePtr));
52    static void             EmbImageBboxProc _ANSI_ARGS_((TkTextDispChunk *chunkPtr,
53                                int index, int y, int lineHeight, int baseline,
54                                int *xPtr, int *yPtr, int *widthPtr,
55                                int *heightPtr));
56    static int              EmbImageConfigure _ANSI_ARGS_((TkText *textPtr,
57                                TkTextSegment *eiPtr, int argc, char **argv));
58    static int              EmbImageDeleteProc _ANSI_ARGS_((TkTextSegment *segPtr,
59                                TkTextLine *linePtr, int treeGone));
60    static void             EmbImageDisplayProc _ANSI_ARGS_((
61                                TkTextDispChunk *chunkPtr, int x, int y,
62                                int lineHeight, int baseline, Display *display,
63                                Drawable dst, int screenY));
64    static int              EmbImageLayoutProc _ANSI_ARGS_((TkText *textPtr,
65                                TkTextIndex *indexPtr, TkTextSegment *segPtr,
66                                int offset, int maxX, int maxChars,
67                                int noCharsYet, TkWrapMode wrapMode,
68                                TkTextDispChunk *chunkPtr));
69    static void             EmbImageProc _ANSI_ARGS_((ClientData clientData,
70                                int x, int y, int width, int height,
71                                int imageWidth, int imageHeight));
72    
73    /*
74     * The following structure declares the "embedded image" segment type.
75     */
76    
77    static Tk_SegType tkTextEmbImageType = {
78        "image",                                    /* name */
79        0,                                          /* leftGravity */
80        (Tk_SegSplitProc *) NULL,                   /* splitProc */
81        EmbImageDeleteProc,                         /* deleteProc */
82        EmbImageCleanupProc,                        /* cleanupProc */
83        (Tk_SegLineChangeProc *) NULL,              /* lineChangeProc */
84        EmbImageLayoutProc,                         /* layoutProc */
85        EmbImageCheckProc                           /* checkProc */
86    };
87    
88    /*
89     * Information used for parsing image configuration options:
90     */
91    
92    static Tk_CustomOption alignOption = {AlignParseProc, AlignPrintProc,
93            (ClientData) NULL};
94    
95    static Tk_ConfigSpec configSpecs[] = {
96        {TK_CONFIG_CUSTOM, "-align", (char *) NULL, (char *) NULL,
97            "center", 0, TK_CONFIG_DONT_SET_DEFAULT, &alignOption},
98        {TK_CONFIG_PIXELS, "-padx", (char *) NULL, (char *) NULL,
99            "0", Tk_Offset(TkTextEmbImage, padX),
100            TK_CONFIG_DONT_SET_DEFAULT},
101        {TK_CONFIG_PIXELS, "-pady", (char *) NULL, (char *) NULL,
102            "0", Tk_Offset(TkTextEmbImage, padY),
103            TK_CONFIG_DONT_SET_DEFAULT},
104        {TK_CONFIG_STRING, "-image", (char *) NULL, (char *) NULL,
105            (char *) NULL, Tk_Offset(TkTextEmbImage, imageString),
106            TK_CONFIG_DONT_SET_DEFAULT|TK_CONFIG_NULL_OK},
107        {TK_CONFIG_STRING, "-name", (char *) NULL, (char *) NULL,
108            (char *) NULL, Tk_Offset(TkTextEmbImage, imageName),
109            TK_CONFIG_DONT_SET_DEFAULT|TK_CONFIG_NULL_OK},
110        {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
111            (char *) NULL, 0, 0}
112    };
113    
114    /*
115     *--------------------------------------------------------------
116     *
117     * TkTextImageCmd --
118     *
119     *      This procedure implements the "image" widget command
120     *      for text widgets.  See the user documentation for details
121     *      on what it does.
122     *
123     * Results:
124     *      A standard Tcl result or error.
125     *
126     * Side effects:
127     *      See the user documentation.
128     *
129     *--------------------------------------------------------------
130     */
131    
132    int
133    TkTextImageCmd(textPtr, interp, argc, argv)
134        register TkText *textPtr;   /* Information about text widget. */
135        Tcl_Interp *interp;         /* Current interpreter. */
136        int argc;                   /* Number of arguments. */
137        char **argv;                /* Argument strings.  Someone else has already
138                                     * parsed this command enough to know that
139                                     * argv[1] is "image". */
140    {
141        size_t length;
142        register TkTextSegment *eiPtr;
143    
144        if (argc < 3) {
145            Tcl_AppendResult(interp, "wrong # args: should be \"",
146                    argv[0], " image option ?arg arg ...?\"", (char *) NULL);
147            return TCL_ERROR;
148        }
149        length = strlen(argv[2]);
150        if ((strncmp(argv[2], "cget", length) == 0) && (length >= 2)) {
151            TkTextIndex index;
152            TkTextSegment *eiPtr;
153    
154            if (argc != 5) {
155                Tcl_AppendResult(interp, "wrong # args: should be \"",
156                        argv[0], " image cget index option\"",
157                        (char *) NULL);
158                return TCL_ERROR;
159            }
160            if (TkTextGetIndex(interp, textPtr, argv[3], &index) != TCL_OK) {
161                return TCL_ERROR;
162            }
163            eiPtr = TkTextIndexToSeg(&index, (int *) NULL);
164            if (eiPtr->typePtr != &tkTextEmbImageType) {
165                Tcl_AppendResult(interp, "no embedded image at index \"",
166                        argv[3], "\"", (char *) NULL);
167                return TCL_ERROR;
168            }
169            return Tk_ConfigureValue(interp, textPtr->tkwin, configSpecs,
170                    (char *) &eiPtr->body.ei, argv[4], 0);
171        } else if ((strncmp(argv[2], "configure", length) == 0) && (length >= 2)) {
172            TkTextIndex index;
173            TkTextSegment *eiPtr;
174    
175            if (argc < 4) {
176                Tcl_AppendResult(interp, "wrong # args: should be \"",
177                        argv[0], " image configure index ?option value ...?\"",
178                        (char *) NULL);
179                return TCL_ERROR;
180            }
181            if (TkTextGetIndex(interp, textPtr, argv[3], &index) != TCL_OK) {
182                return TCL_ERROR;
183            }
184            eiPtr = TkTextIndexToSeg(&index, (int *) NULL);
185            if (eiPtr->typePtr != &tkTextEmbImageType) {
186                Tcl_AppendResult(interp, "no embedded image at index \"",
187                        argv[3], "\"", (char *) NULL);
188                return TCL_ERROR;
189            }
190            if (argc == 4) {
191                return Tk_ConfigureInfo(interp, textPtr->tkwin, configSpecs,
192                        (char *) &eiPtr->body.ei, (char *) NULL, 0);
193            } else if (argc == 5) {
194                return Tk_ConfigureInfo(interp, textPtr->tkwin, configSpecs,
195                        (char *) &eiPtr->body.ei, argv[4], 0);
196            } else {
197                TkTextChanged(textPtr, &index, &index);
198                return EmbImageConfigure(textPtr, eiPtr, argc-4, argv+4);
199            }
200        } else if ((strncmp(argv[2], "create", length) == 0) && (length >= 2)) {
201            TkTextIndex index;
202            int lineIndex;
203    
204            /*
205             * Add a new image.  Find where to put the new image, and
206             * mark that position for redisplay.
207             */
208    
209            if (argc < 4) {
210                Tcl_AppendResult(interp, "wrong # args: should be \"",
211                        argv[0], " image create index ?option value ...?\"",
212                        (char *) NULL);
213                return TCL_ERROR;
214            }
215            if (TkTextGetIndex(interp, textPtr, argv[3], &index) != TCL_OK) {
216                return TCL_ERROR;
217            }
218    
219            /*
220             * Don't allow insertions on the last (dummy) line of the text.
221             */
222        
223            lineIndex = TkBTreeLineIndex(index.linePtr);
224            if (lineIndex == TkBTreeNumLines(textPtr->tree)) {
225                lineIndex--;
226                TkTextMakeByteIndex(textPtr->tree, lineIndex, 1000000, &index);
227            }
228    
229            /*
230             * Create the new image segment and initialize it.
231             */
232    
233            eiPtr = (TkTextSegment *) ckalloc(EI_SEG_SIZE);
234            eiPtr->typePtr = &tkTextEmbImageType;
235            eiPtr->size = 1;
236            eiPtr->body.ei.textPtr = textPtr;
237            eiPtr->body.ei.linePtr = NULL;
238            eiPtr->body.ei.imageName = NULL;
239            eiPtr->body.ei.imageString = NULL;
240            eiPtr->body.ei.name = NULL;
241            eiPtr->body.ei.image = NULL;
242            eiPtr->body.ei.align = ALIGN_CENTER;
243            eiPtr->body.ei.padX = eiPtr->body.ei.padY = 0;
244            eiPtr->body.ei.chunkCount = 0;
245    
246            /*
247             * Link the segment into the text widget, then configure it (delete
248             * it again if the configuration fails).
249             */
250    
251            TkTextChanged(textPtr, &index, &index);
252            TkBTreeLinkSegment(eiPtr, &index);
253            if (EmbImageConfigure(textPtr, eiPtr, argc-4, argv+4) != TCL_OK) {
254                TkTextIndex index2;
255    
256                TkTextIndexForwChars(&index, 1, &index2);
257                TkBTreeDeleteChars(&index, &index2);
258                return TCL_ERROR;
259            }
260        } else if (strncmp(argv[2], "names", length) == 0) {
261            Tcl_HashSearch search;
262            Tcl_HashEntry *hPtr;
263    
264            if (argc != 3) {
265                Tcl_AppendResult(interp, "wrong # args: should be \"",
266                        argv[0], " image names\"", (char *) NULL);
267                return TCL_ERROR;
268            }
269            for (hPtr = Tcl_FirstHashEntry(&textPtr->imageTable, &search);
270                    hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) {
271                Tcl_AppendElement(interp,
272                        Tcl_GetHashKey(&textPtr->markTable, hPtr));
273            }
274        } else {
275            Tcl_AppendResult(interp, "bad image option \"", argv[2],
276                    "\": must be cget, configure, create, or names",
277                    (char *) NULL);
278            return TCL_ERROR;
279        }
280        return TCL_OK;
281    }
282    
283    /*
284     *--------------------------------------------------------------
285     *
286     * EmbImageConfigure --
287     *
288     *      This procedure is called to handle configuration options
289     *      for an embedded image, using an argc/argv list.
290     *
291     * Results:
292     *      The return value is a standard Tcl result.  If TCL_ERROR is
293     *      returned, then the interp's result contains an error message..
294     *
295     * Side effects:
296     *      Configuration information for the embedded image changes,
297     *      such as alignment, or name of the image.
298     *
299     *--------------------------------------------------------------
300     */
301    
302    static int
303    EmbImageConfigure(textPtr, eiPtr, argc, argv)
304        TkText *textPtr;            /* Information about text widget that
305                                     * contains embedded image. */
306        TkTextSegment *eiPtr;       /* Embedded image to be configured. */
307        int argc;                   /* Number of strings in argv. */
308        char **argv;                /* Array of strings describing configuration
309                                     * options. */
310    {
311        Tk_Image image;
312        Tcl_DString newName;
313        Tcl_HashEntry *hPtr;
314        Tcl_HashSearch search;
315        int new;
316        char *name;
317        int count = 0;              /* The counter for picking a unique name */
318        int conflict = 0;           /* True if we have a name conflict */
319        unsigned int len;           /* length of image name */
320    
321        if (Tk_ConfigureWidget(textPtr->interp, textPtr->tkwin, configSpecs,
322                argc, argv, (char *) &eiPtr->body.ei,TK_CONFIG_ARGV_ONLY)
323                != TCL_OK) {
324            return TCL_ERROR;
325        }
326    
327        /*
328         * Create the image.  Save the old image around and don't free it
329         * until after the new one is allocated.  This keeps the reference
330         * count from going to zero so the image doesn't have to be recreated
331         * if it hasn't changed.
332         */
333    
334        if (eiPtr->body.ei.imageString != NULL) {
335            image = Tk_GetImage(textPtr->interp, textPtr->tkwin, eiPtr->body.ei.imageString,
336                    EmbImageProc, (ClientData) eiPtr);
337            if (image == NULL) {
338                return TCL_ERROR;
339            }
340        } else {
341            image = NULL;
342        }
343        if (eiPtr->body.ei.image != NULL) {
344            Tk_FreeImage(eiPtr->body.ei.image);
345        }
346        eiPtr->body.ei.image = image;
347    
348        if (eiPtr->body.ei.name != NULL) {
349            return TCL_OK;
350        }
351    
352        /*
353         * Find a unique name for this image.  Use imageName (or imageString)
354         * if available, otherwise tack on a #nn and use it.  If a name is already
355         * associated with this image, delete the name.
356         */
357    
358        name = eiPtr->body.ei.imageName;
359        if (name == NULL) {
360            name = eiPtr->body.ei.imageString;
361        }
362        if (name == NULL) {
363            Tcl_AppendResult(textPtr->interp,"Either a \"-name\" ",
364                    "or a \"-image\" argument must be provided ",
365                    "to the \"image create\" subcommand.",
366                    (char *) NULL);
367            return TCL_ERROR;
368        }
369        len = strlen(name);
370        for (hPtr = Tcl_FirstHashEntry(&textPtr->imageTable, &search);
371                hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) {
372            char *haveName = Tcl_GetHashKey(&textPtr->imageTable, hPtr);
373            if (strncmp(name, haveName, len) == 0) {
374                new = 0;
375                sscanf(haveName+len,"#%d",&new);
376                if (new > count) {
377                    count = new;
378                }
379                if (len == (int) strlen(haveName)) {
380                    conflict = 1;
381                }
382            }
383        }
384    
385        Tcl_DStringInit(&newName);
386        Tcl_DStringAppend(&newName,name, -1);
387    
388        if (conflict) {
389            char buf[4 + TCL_INTEGER_SPACE];
390            sprintf(buf, "#%d",count+1);
391            Tcl_DStringAppend(&newName,buf, -1);
392        }
393        name = Tcl_DStringValue(&newName);
394        hPtr = Tcl_CreateHashEntry(&textPtr->imageTable, name, &new);
395        Tcl_SetHashValue(hPtr, eiPtr);
396        Tcl_AppendResult(textPtr->interp, name , (char *) NULL);
397        eiPtr->body.ei.name = ckalloc((unsigned) Tcl_DStringLength(&newName)+1);
398        strcpy(eiPtr->body.ei.name,name);
399        Tcl_DStringFree(&newName);
400    
401        return TCL_OK;
402    }
403    
404    /*
405     *--------------------------------------------------------------
406     *
407     * AlignParseProc --
408     *
409     *      This procedure is invoked by Tk_ConfigureWidget during
410     *      option processing to handle "-align" options for embedded
411     *      images.
412     *
413     * Results:
414     *      A standard Tcl return value.
415     *
416     * Side effects:
417     *      The alignment for the embedded image may change.
418     *
419     *--------------------------------------------------------------
420     */
421    
422            /* ARGSUSED */
423    static int
424    AlignParseProc(clientData, interp, tkwin, value, widgRec, offset)
425        ClientData clientData;              /* Not used.*/
426        Tcl_Interp *interp;                 /* Used for reporting errors. */
427        Tk_Window tkwin;                    /* Window for text widget. */
428        char *value;                        /* Value of option. */
429        char *widgRec;                      /* Pointer to TkTextEmbWindow
430                                             * structure. */
431        int offset;                         /* Offset into item (ignored). */
432    {
433        register TkTextEmbImage *embPtr = (TkTextEmbImage *) widgRec;
434    
435        if (strcmp(value, "baseline") == 0) {
436            embPtr->align = ALIGN_BASELINE;
437        } else if (strcmp(value, "bottom") == 0) {
438            embPtr->align = ALIGN_BOTTOM;
439        } else if (strcmp(value, "center") == 0) {
440            embPtr->align = ALIGN_CENTER;
441        } else if (strcmp(value, "top") == 0) {
442            embPtr->align = ALIGN_TOP;
443        } else {
444            Tcl_AppendResult(interp, "bad alignment \"", value,
445                    "\": must be baseline, bottom, center, or top",
446                    (char *) NULL);
447            return TCL_ERROR;
448        }
449        return TCL_OK;
450    }
451    
452    /*
453     *--------------------------------------------------------------
454     *
455     * AlignPrintProc --
456     *
457     *      This procedure is invoked by the Tk configuration code
458     *      to produce a printable string for the "-align" configuration
459     *      option for embedded images.
460     *
461     * Results:
462     *      The return value is a string describing the embedded
463     *      images's current alignment.
464     *
465     * Side effects:
466     *      None.
467     *
468     *--------------------------------------------------------------
469     */
470    
471            /* ARGSUSED */
472    static char *
473    AlignPrintProc(clientData, tkwin, widgRec, offset, freeProcPtr)
474        ClientData clientData;              /* Ignored. */
475        Tk_Window tkwin;                    /* Window for text widget. */
476        char *widgRec;                      /* Pointer to TkTextEmbImage
477                                             * structure. */
478        int offset;                         /* Ignored. */
479        Tcl_FreeProc **freeProcPtr;         /* Pointer to variable to fill in with
480                                             * information about how to reclaim
481                                             * storage for return string. */
482    {
483        switch (((TkTextEmbImage *) widgRec)->align) {
484            case ALIGN_BASELINE:
485                return "baseline";
486            case ALIGN_BOTTOM:
487                return "bottom";
488            case ALIGN_CENTER:
489                return "center";
490            case ALIGN_TOP:
491                return "top";
492            default:
493                return "??";
494        }
495    }
496    
497    /*
498     *--------------------------------------------------------------
499     *
500     * EmbImageDeleteProc --
501     *
502     *      This procedure is invoked by the text B-tree code whenever
503     *      an embedded image lies in a range of characters being deleted.
504     *
505     * Results:
506     *      Returns 0 to indicate that the deletion has been accepted.
507     *
508     * Side effects:
509     *      The embedded image is deleted, if it exists, and any resources
510     *      associated with it are released.
511     *
512     *--------------------------------------------------------------
513     */
514    
515            /* ARGSUSED */
516    static int
517    EmbImageDeleteProc(eiPtr, linePtr, treeGone)
518        TkTextSegment *eiPtr;               /* Segment being deleted. */
519        TkTextLine *linePtr;                /* Line containing segment. */
520        int treeGone;                       /* Non-zero means the entire tree is
521                                             * being deleted, so everything must
522                                             * get cleaned up. */
523    {
524        Tcl_HashEntry *hPtr;
525    
526        if (eiPtr->body.ei.image != NULL) {
527            hPtr = Tcl_FindHashEntry(&eiPtr->body.ei.textPtr->imageTable,
528                    eiPtr->body.ei.name);
529            if (hPtr != NULL) {
530                /*
531                 * (It's possible for there to be no hash table entry for this
532                 * image, if an error occurred while creating the image segment
533                 * but before the image got added to the table)
534                 */
535    
536                Tcl_DeleteHashEntry(hPtr);
537            }
538            Tk_FreeImage(eiPtr->body.ei.image);
539        }
540        Tk_FreeOptions(configSpecs, (char *) &eiPtr->body.ei,
541                eiPtr->body.ei.textPtr->display, 0);
542        if (eiPtr->body.ei.name != NULL) {
543            ckfree(eiPtr->body.ei.name);
544        }
545        ckfree((char *) eiPtr);
546        return 0;
547    }
548    
549    /*
550     *--------------------------------------------------------------
551     *
552     * EmbImageCleanupProc --
553     *
554     *      This procedure is invoked by the B-tree code whenever a
555     *      segment containing an embedded image is moved from one
556     *      line to another.
557     *
558     * Results:
559     *      None.
560     *
561     * Side effects:
562     *      The linePtr field of the segment gets updated.
563     *
564     *--------------------------------------------------------------
565     */
566    
567    static TkTextSegment *
568    EmbImageCleanupProc(eiPtr, linePtr)
569        TkTextSegment *eiPtr;               /* Mark segment that's being moved. */
570        TkTextLine *linePtr;                /* Line that now contains segment. */
571    {
572        eiPtr->body.ei.linePtr = linePtr;
573        return eiPtr;
574    }
575    
576    /*
577     *--------------------------------------------------------------
578     *
579     * EmbImageLayoutProc --
580     *
581     *      This procedure is the "layoutProc" for embedded image
582     *      segments.
583     *
584     * Results:
585     *      1 is returned to indicate that the segment should be
586     *      displayed.  The chunkPtr structure is filled in.
587     *
588     * Side effects:
589     *      None, except for filling in chunkPtr.
590     *
591     *--------------------------------------------------------------
592     */
593    
594            /*ARGSUSED*/
595    static int
596    EmbImageLayoutProc(textPtr, indexPtr, eiPtr, offset, maxX, maxChars,
597            noCharsYet, wrapMode, chunkPtr)
598        TkText *textPtr;            /* Text widget being layed out. */
599        TkTextIndex *indexPtr;      /* Identifies first character in chunk. */
600        TkTextSegment *eiPtr;       /* Segment corresponding to indexPtr. */
601        int offset;                 /* Offset within segPtr corresponding to
602                                     * indexPtr (always 0). */
603        int maxX;                   /* Chunk must not occupy pixels at this
604                                     * position or higher. */
605        int maxChars;               /* Chunk must not include more than this
606                                     * many characters. */
607        int noCharsYet;             /* Non-zero means no characters have been
608                                     * assigned to this line yet. */
609        TkWrapMode wrapMode;        /* Wrap mode to use for line: TEXT_WRAPMODE_CHAR,
610                                     * TEXT_WRAPMODE_NONE, or TEXT_WRAPMODE_WORD. */
611        register TkTextDispChunk *chunkPtr;
612                                    /* Structure to fill in with information
613                                     * about this chunk.  The x field has already
614                                     * been set by the caller. */
615    {
616        int width, height;
617    
618        if (offset != 0) {
619            panic("Non-zero offset in EmbImageLayoutProc");
620        }
621    
622        /*
623         * See if there's room for this image on this line.
624         */
625    
626        if (eiPtr->body.ei.image == NULL) {
627            width = 0;
628            height = 0;
629        } else {
630            Tk_SizeOfImage(eiPtr->body.ei.image, &width, &height);
631            width += 2*eiPtr->body.ei.padX;
632            height += 2*eiPtr->body.ei.padY;
633        }
634        if ((width > (maxX - chunkPtr->x))
635                && !noCharsYet && (textPtr->wrapMode != TEXT_WRAPMODE_NONE)) {
636            return 0;
637        }
638    
639        /*
640         * Fill in the chunk structure.
641         */
642    
643        chunkPtr->displayProc = EmbImageDisplayProc;
644        chunkPtr->undisplayProc = (Tk_ChunkUndisplayProc *) NULL;
645        chunkPtr->measureProc = (Tk_ChunkMeasureProc *) NULL;
646        chunkPtr->bboxProc = EmbImageBboxProc;
647        chunkPtr->numBytes = 1;
648        if (eiPtr->body.ei.align == ALIGN_BASELINE) {
649            chunkPtr->minAscent = height - eiPtr->body.ei.padY;
650            chunkPtr->minDescent = eiPtr->body.ei.padY;
651            chunkPtr->minHeight = 0;
652        } else {
653            chunkPtr->minAscent = 0;
654            chunkPtr->minDescent = 0;
655            chunkPtr->minHeight = height;
656        }
657        chunkPtr->width = width;
658        chunkPtr->breakIndex = -1;
659        chunkPtr->breakIndex = 1;
660        chunkPtr->clientData = (ClientData) eiPtr;
661        eiPtr->body.ei.chunkCount += 1;
662        return 1;
663    }
664    
665    /*
666     *--------------------------------------------------------------
667     *
668     * EmbImageCheckProc --
669     *
670     *      This procedure is invoked by the B-tree code to perform
671     *      consistency checks on embedded images.
672     *
673     * Results:
674     *      None.
675     *
676     * Side effects:
677     *      The procedure panics if it detects anything wrong with
678     *      the embedded image.
679     *
680     *--------------------------------------------------------------
681     */
682    
683    static void
684    EmbImageCheckProc(eiPtr, linePtr)
685        TkTextSegment *eiPtr;               /* Segment to check. */
686        TkTextLine *linePtr;                /* Line containing segment. */
687    {
688        if (eiPtr->nextPtr == NULL) {
689            panic("EmbImageCheckProc: embedded image is last segment in line");
690        }
691        if (eiPtr->size != 1) {
692            panic("EmbImageCheckProc: embedded image has size %d", eiPtr->size);
693        }
694    }
695    
696    /*
697     *--------------------------------------------------------------
698     *
699     * EmbImageDisplayProc --
700     *
701     *      This procedure is invoked by the text displaying code
702     *      when it is time to actually draw an embedded image
703     *      chunk on the screen.
704     *
705     * Results:
706     *      None.
707     *
708     * Side effects:
709     *      The embedded image gets moved to the correct location
710     *      and drawn onto the display.
711     *
712     *--------------------------------------------------------------
713     */
714    
715    static void
716    EmbImageDisplayProc(chunkPtr, x, y, lineHeight, baseline, display, dst, screenY)
717        TkTextDispChunk *chunkPtr;          /* Chunk that is to be drawn. */
718        int x;                              /* X-position in dst at which to
719                                             * draw this chunk (differs from
720                                             * the x-position in the chunk because
721                                             * of scrolling). */
722        int y;                              /* Top of rectangular bounding box
723                                             * for line: tells where to draw this
724                                             * chunk in dst (x-position is in
725                                             * the chunk itself). */
726        int lineHeight;                     /* Total height of line. */
727        int baseline;                       /* Offset of baseline from y. */
728        Display *display;                   /* Display to use for drawing. */
729        Drawable dst;                       /* Pixmap or window in which to draw */
730        int screenY;                        /* Y-coordinate in text window that
731                                             * corresponds to y. */
732    {
733        TkTextSegment *eiPtr = (TkTextSegment *) chunkPtr->clientData;
734        int lineX, imageX, imageY, width, height;
735        Tk_Image image;
736    
737        image = eiPtr->body.ei.image;
738        if (image == NULL) {
739            return;
740        }
741        if ((x + chunkPtr->width) <= 0) {
742            return;
743        }
744    
745        /*
746         * Compute the image's location and size in the text widget, taking
747         * into account the align value for the image.
748         */
749    
750        EmbImageBboxProc(chunkPtr, 0, y, lineHeight, baseline, &lineX,
751                &imageY, &width, &height);
752        imageX = lineX - chunkPtr->x + x;
753    
754        Tk_RedrawImage(image, 0, 0, width, height, dst,
755                imageX, imageY);
756    }
757    
758    /*
759     *--------------------------------------------------------------
760     *
761     * EmbImageBboxProc --
762     *
763     *      This procedure is called to compute the bounding box of
764     *      the area occupied by an embedded image.
765     *
766     * Results:
767     *      There is no return value.  *xPtr and *yPtr are filled in
768     *      with the coordinates of the upper left corner of the
769     *      image, and *widthPtr and *heightPtr are filled in with
770     *      the dimensions of the image in pixels.  Note:  not all
771     *      of the returned bbox is necessarily visible on the screen
772     *      (the rightmost part might be off-screen to the right,
773     *      and the bottommost part might be off-screen to the bottom).
774     *
775     * Side effects:
776     *      None.
777     *
778     *--------------------------------------------------------------
779     */
780    
781    static void
782    EmbImageBboxProc(chunkPtr, index, y, lineHeight, baseline, xPtr, yPtr,
783            widthPtr, heightPtr)
784        TkTextDispChunk *chunkPtr;          /* Chunk containing desired char. */
785        int index;                          /* Index of desired character within
786                                             * the chunk. */
787        int y;                              /* Topmost pixel in area allocated
788                                             * for this line. */
789        int lineHeight;                     /* Total height of line. */
790        int baseline;                       /* Location of line's baseline, in
791                                             * pixels measured down from y. */
792        int *xPtr, *yPtr;                   /* Gets filled in with coords of
793                                             * character's upper-left pixel. */
794        int *widthPtr;                      /* Gets filled in with width of
795                                             * character, in pixels. */
796        int *heightPtr;                     /* Gets filled in with height of
797                                             * character, in pixels. */
798    {
799        TkTextSegment *eiPtr = (TkTextSegment *) chunkPtr->clientData;
800        Tk_Image image;
801    
802        image = eiPtr->body.ei.image;
803        if (image != NULL) {
804            Tk_SizeOfImage(image, widthPtr, heightPtr);
805        } else {
806            *widthPtr = 0;
807            *heightPtr = 0;
808        }
809        *xPtr = chunkPtr->x + eiPtr->body.ei.padX;
810        switch (eiPtr->body.ei.align) {
811            case ALIGN_BOTTOM:
812                *yPtr = y + (lineHeight - *heightPtr - eiPtr->body.ei.padY);
813                break;
814            case ALIGN_CENTER:
815                *yPtr = y + (lineHeight - *heightPtr)/2;
816                break;
817            case ALIGN_TOP:
818                *yPtr = y + eiPtr->body.ei.padY;
819                break;
820            case ALIGN_BASELINE:
821                *yPtr = y + (baseline - *heightPtr);
822                break;
823        }
824    }
825    
826    /*
827     *--------------------------------------------------------------
828     *
829     * TkTextImageIndex --
830     *
831     *      Given the name of an embedded image within a text widget,
832     *      returns an index corresponding to the image's position
833     *      in the text.
834     *
835     * Results:
836     *      The return value is 1 if there is an embedded image by
837     *      the given name in the text widget, 0 otherwise.  If the
838     *      image exists, *indexPtr is filled in with its index.
839     *
840     * Side effects:
841     *      None.
842     *
843     *--------------------------------------------------------------
844     */
845    
846    int
847    TkTextImageIndex(textPtr, name, indexPtr)
848        TkText *textPtr;            /* Text widget containing image. */
849        char *name;                 /* Name of image. */
850        TkTextIndex *indexPtr;      /* Index information gets stored here. */
851    {
852        Tcl_HashEntry *hPtr;
853        TkTextSegment *eiPtr;
854    
855        hPtr = Tcl_FindHashEntry(&textPtr->imageTable, name);
856        if (hPtr == NULL) {
857            return 0;
858        }
859        eiPtr = (TkTextSegment *) Tcl_GetHashValue(hPtr);
860        indexPtr->tree = textPtr->tree;
861        indexPtr->linePtr = eiPtr->body.ei.linePtr;
862        indexPtr->byteIndex = TkTextSegToOffset(eiPtr, indexPtr->linePtr);
863        return 1;
864    }
865    
866    /*
867     *--------------------------------------------------------------
868     *
869     * EmbImageProc --
870     *
871     *      This procedure is called by the image code whenever an
872     *      image or its contents changes.
873     *
874     * Results:
875     *      None.
876     *
877     * Side effects:
878     *      The image will be redisplayed.
879     *
880     *--------------------------------------------------------------
881     */
882    
883    static void
884    EmbImageProc(clientData, x, y, width, height, imgWidth, imgHeight)
885        ClientData clientData;              /* Pointer to widget record. */
886        int x, y;                           /* Upper left pixel (within image)
887                                             * that must be redisplayed. */
888        int width, height;                  /* Dimensions of area to redisplay
889                                             * (may be <= 0). */
890        int imgWidth, imgHeight;            /* New dimensions of image. */
891    
892    {
893        TkTextSegment *eiPtr = (TkTextSegment *) clientData;
894        TkTextIndex index;
895    
896        index.tree = eiPtr->body.ei.textPtr->tree;
897        index.linePtr = eiPtr->body.ei.linePtr;
898        index.byteIndex = TkTextSegToOffset(eiPtr, eiPtr->body.ei.linePtr);
899        TkTextChanged(eiPtr->body.ei.textPtr, &index, &index);
900    }
901    
902    /* End of tktextimage.c */

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

dashley@gmail.com
ViewVC Help
Powered by ViewVC 1.1.25