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

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

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

projs/trunk/shared_source/tk_base/tkcanvtext.c revision 42 by dashley, Fri Oct 14 01:50:00 2016 UTC projs/ets/trunk/src/c_tk_base_7_5_w_mods/tkcanvtext.c revision 220 by dashley, Sun Jul 22 15:58:07 2018 UTC
# Line 1  Line 1 
 /* $Header: /cvsroot/esrg/sfesrg/esrgpcpj/shared/tk_base/tkcanvtext.c,v 1.1.1.1 2001/06/13 04:57:44 dtashley Exp $ */  
   
 /*  
  * tkCanvText.c --  
  *  
  *      This file implements text items for canvas widgets.  
  *  
  * Copyright (c) 1991-1994 The Regents of the University of California.  
  * Copyright (c) 1994-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: tkcanvtext.c,v 1.1.1.1 2001/06/13 04:57:44 dtashley Exp $  
  */  
   
 #include <stdio.h>  
 #include "tkInt.h"  
 #include "tkCanvas.h"  
 #include "tkPort.h"  
 #include "default.h"  
   
 /*  
  * The structure below defines the record for each text item.  
  */  
   
 typedef struct TextItem  {  
     Tk_Item header;             /* Generic stuff that's the same for all  
                                  * types.  MUST BE FIRST IN STRUCTURE. */  
     Tk_CanvasTextInfo *textInfoPtr;  
                                 /* Pointer to a structure containing  
                                  * information about the selection and  
                                  * insertion cursor.  The structure is owned  
                                  * by (and shared with) the generic canvas  
                                  * code. */  
     /*  
      * Fields that are set by widget commands other than "configure".  
      */  
       
     double x, y;                /* Positioning point for text. */  
     int insertPos;              /* Character index of character just before  
                                  * which the insertion cursor is displayed. */  
   
     /*  
      * Configuration settings that are updated by Tk_ConfigureWidget.  
      */  
   
     Tk_Anchor anchor;           /* Where to anchor text relative to (x,y). */  
     Tk_TSOffset tsoffset;  
     XColor *color;              /* Color for text. */  
     XColor *activeColor;        /* Color for text. */  
     XColor *disabledColor;      /* Color for text. */  
     Tk_Font tkfont;             /* Font for drawing text. */  
     Tk_Justify justify;         /* Justification mode for text. */  
     Pixmap stipple;             /* Stipple bitmap for text, or None. */  
     Pixmap activeStipple;       /* Stipple bitmap for text, or None. */  
     Pixmap disabledStipple;     /* Stipple bitmap for text, or None. */  
     char *text;                 /* Text for item (malloc-ed). */  
     int width;                  /* Width of lines for word-wrap, pixels.  
                                  * Zero means no word-wrap. */  
   
     /*  
      * Fields whose values are derived from the current values of the  
      * configuration settings above.  
      */  
   
     int numChars;               /* Length of text in characters. */  
     int numBytes;               /* Length of text in bytes. */  
     Tk_TextLayout textLayout;   /* Cached text layout information. */  
     int leftEdge;               /* Pixel location of the left edge of the  
                                  * text item; where the left border of the  
                                  * text layout is drawn. */  
     int rightEdge;              /* Pixel just to right of right edge of  
                                  * area of text item.  Used for selecting up  
                                  * to end of line. */  
     GC gc;                      /* Graphics context for drawing text. */  
     GC selTextGC;               /* Graphics context for selected text. */  
     GC cursorOffGC;             /* If not None, this gives a graphics context  
                                  * to use to draw the insertion cursor when  
                                  * it's off.  Used if the selection and  
                                  * insertion cursor colors are the same.  */  
 } TextItem;  
   
 /*  
  * Information used for parsing configuration specs:  
  */  
   
 static Tk_CustomOption stateOption = {  
     (Tk_OptionParseProc *) TkStateParseProc,  
     TkStatePrintProc, (ClientData) 2  
 };  
 static Tk_CustomOption tagsOption = {  
     (Tk_OptionParseProc *) Tk_CanvasTagsParseProc,  
     Tk_CanvasTagsPrintProc, (ClientData) NULL  
 };  
 static Tk_CustomOption offsetOption = {  
     (Tk_OptionParseProc *) TkOffsetParseProc,  
     TkOffsetPrintProc, (ClientData) (TK_OFFSET_RELATIVE)  
 };  
   
 static Tk_ConfigSpec configSpecs[] = {  
     {TK_CONFIG_COLOR, "-activefill", (char *) NULL, (char *) NULL,  
         (char *) NULL, Tk_Offset(TextItem, activeColor), TK_CONFIG_NULL_OK},  
     {TK_CONFIG_BITMAP, "-activestipple", (char *) NULL, (char *) NULL,  
         (char *) NULL, Tk_Offset(TextItem, activeStipple), TK_CONFIG_NULL_OK},  
     {TK_CONFIG_ANCHOR, "-anchor", (char *) NULL, (char *) NULL,  
         "center", Tk_Offset(TextItem, anchor),  
         TK_CONFIG_DONT_SET_DEFAULT},  
     {TK_CONFIG_COLOR, "-disabledfill", (char *) NULL, (char *) NULL,  
         (char *) NULL, Tk_Offset(TextItem, disabledColor), TK_CONFIG_NULL_OK},  
     {TK_CONFIG_BITMAP, "-disabledstipple", (char *) NULL, (char *) NULL,  
         (char *) NULL, Tk_Offset(TextItem, disabledStipple), TK_CONFIG_NULL_OK},  
     {TK_CONFIG_COLOR, "-fill", (char *) NULL, (char *) NULL,  
         "black", Tk_Offset(TextItem, color), TK_CONFIG_NULL_OK},  
     {TK_CONFIG_FONT, "-font", (char *) NULL, (char *) NULL,  
         DEF_CANVTEXT_FONT, Tk_Offset(TextItem, tkfont), 0},  
     {TK_CONFIG_JUSTIFY, "-justify", (char *) NULL, (char *) NULL,  
         "left", Tk_Offset(TextItem, justify),  
         TK_CONFIG_DONT_SET_DEFAULT},  
     {TK_CONFIG_CUSTOM, "-offset", (char *) NULL, (char *) NULL,  
         "0,0", Tk_Offset(TextItem, tsoffset),  
         TK_CONFIG_DONT_SET_DEFAULT, &offsetOption},  
     {TK_CONFIG_CUSTOM, "-state", (char *) NULL, (char *) NULL,  
         (char *) NULL, Tk_Offset(Tk_Item, state), TK_CONFIG_NULL_OK,  
         &stateOption},  
     {TK_CONFIG_BITMAP, "-stipple", (char *) NULL, (char *) NULL,  
         (char *) NULL, Tk_Offset(TextItem, stipple), TK_CONFIG_NULL_OK},  
     {TK_CONFIG_CUSTOM, "-tags", (char *) NULL, (char *) NULL,  
         (char *) NULL, 0, TK_CONFIG_NULL_OK, &tagsOption},  
     {TK_CONFIG_STRING, "-text", (char *) NULL, (char *) NULL,  
         "", Tk_Offset(TextItem, text), 0},  
     {TK_CONFIG_PIXELS, "-width", (char *) NULL, (char *) NULL,  
         "0", Tk_Offset(TextItem, width), TK_CONFIG_DONT_SET_DEFAULT},  
     {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,  
         (char *) NULL, 0, 0}  
 };  
   
 /*  
  * Prototypes for procedures defined in this file:  
  */  
   
 static void             ComputeTextBbox _ANSI_ARGS_((Tk_Canvas canvas,  
                             TextItem *textPtr));  
 static int              ConfigureText _ANSI_ARGS_((Tcl_Interp *interp,  
                             Tk_Canvas canvas, Tk_Item *itemPtr, int argc,  
                             Tcl_Obj *CONST argv[], int flags));  
 static int              CreateText _ANSI_ARGS_((Tcl_Interp *interp,  
                             Tk_Canvas canvas, struct Tk_Item *itemPtr,  
                             int argc, Tcl_Obj *CONST argv[]));  
 static void             DeleteText _ANSI_ARGS_((Tk_Canvas canvas,  
                             Tk_Item *itemPtr, Display *display));  
 static void             DisplayCanvText _ANSI_ARGS_((Tk_Canvas canvas,  
                             Tk_Item *itemPtr, Display *display, Drawable dst,  
                             int x, int y, int width, int height));  
 static int              GetSelText _ANSI_ARGS_((Tk_Canvas canvas,  
                             Tk_Item *itemPtr, int offset, char *buffer,  
                             int maxBytes));  
 static int              GetTextIndex _ANSI_ARGS_((Tcl_Interp *interp,  
                             Tk_Canvas canvas, Tk_Item *itemPtr,  
                             Tcl_Obj *obj, int *indexPtr));  
 static void             ScaleText _ANSI_ARGS_((Tk_Canvas canvas,  
                             Tk_Item *itemPtr, double originX, double originY,  
                             double scaleX, double scaleY));  
 static void             SetTextCursor _ANSI_ARGS_((Tk_Canvas canvas,  
                             Tk_Item *itemPtr, int index));  
 static int              TextCoords _ANSI_ARGS_((Tcl_Interp *interp,  
                             Tk_Canvas canvas, Tk_Item *itemPtr,  
                             int argc, Tcl_Obj *CONST argv[]));  
 static void             TextDeleteChars _ANSI_ARGS_((Tk_Canvas canvas,  
                             Tk_Item *itemPtr, int first, int last));  
 static void             TextInsert _ANSI_ARGS_((Tk_Canvas canvas,  
                             Tk_Item *itemPtr, int beforeThis, char *string));  
 static int              TextToArea _ANSI_ARGS_((Tk_Canvas canvas,  
                             Tk_Item *itemPtr, double *rectPtr));  
 static double           TextToPoint _ANSI_ARGS_((Tk_Canvas canvas,  
                             Tk_Item *itemPtr, double *pointPtr));  
 static int              TextToPostscript _ANSI_ARGS_((Tcl_Interp *interp,  
                             Tk_Canvas canvas, Tk_Item *itemPtr, int prepass));  
 static void             TranslateText _ANSI_ARGS_((Tk_Canvas canvas,  
                             Tk_Item *itemPtr, double deltaX, double deltaY));  
   
 /*  
  * The structures below defines the rectangle and oval item types  
  * by means of procedures that can be invoked by generic item code.  
  */  
   
 Tk_ItemType tkTextType = {  
     "text",                     /* name */  
     sizeof(TextItem),           /* itemSize */  
     CreateText,                 /* createProc */  
     configSpecs,                /* configSpecs */  
     ConfigureText,              /* configureProc */  
     TextCoords,                 /* coordProc */  
     DeleteText,                 /* deleteProc */  
     DisplayCanvText,            /* displayProc */  
     TK_CONFIG_OBJS,             /* flags */  
     TextToPoint,                /* pointProc */  
     TextToArea,                 /* areaProc */  
     TextToPostscript,           /* postscriptProc */  
     ScaleText,                  /* scaleProc */  
     TranslateText,              /* translateProc */  
     (Tk_ItemIndexProc *) GetTextIndex,/* indexProc */  
     SetTextCursor,              /* icursorProc */  
     GetSelText,                 /* selectionProc */  
     TextInsert,                 /* insertProc */  
     TextDeleteChars,            /* dTextProc */  
     (Tk_ItemType *) NULL,       /* nextPtr */  
 };  
   
 /*  
  *--------------------------------------------------------------  
  *  
  * CreateText --  
  *  
  *      This procedure is invoked to create a new text item  
  *      in a canvas.  
  *  
  * Results:  
  *      A standard Tcl return value.  If an error occurred in  
  *      creating the item then an error message is left in  
  *      the interp's result;  in this case itemPtr is left uninitialized  
  *      so it can be safely freed by the caller.  
  *  
  * Side effects:  
  *      A new text item is created.  
  *  
  *--------------------------------------------------------------  
  */  
   
 static int  
 CreateText(interp, canvas, itemPtr, argc, argv)  
     Tcl_Interp *interp;         /* Interpreter for error reporting. */  
     Tk_Canvas canvas;           /* Canvas to hold new item. */  
     Tk_Item *itemPtr;           /* Record to hold new item; header has been  
                                  * initialized by caller. */  
     int argc;                   /* Number of arguments in argv. */  
     Tcl_Obj *CONST argv[];      /* Arguments describing rectangle. */  
 {  
     TextItem *textPtr = (TextItem *) itemPtr;  
     int i;  
   
     if (argc==1) {  
         i = 1;  
     } else {  
         char *arg = Tcl_GetStringFromObj(argv[1], NULL);  
         if ((argc>1) && (arg[0] == '-')  
                 && (arg[1] >= 'a') && (arg[1] <= 'z')) {  
             i = 1;  
         } else {  
             i = 2;  
         }  
     }  
   
     if (argc < i) {  
         Tcl_AppendResult(interp, "wrong # args: should be \"",  
                 Tk_PathName(Tk_CanvasTkwin(canvas)), " create ",  
                 itemPtr->typePtr->name, " x y ?options?\"", (char *) NULL);  
         return TCL_ERROR;  
     }  
   
     /*  
      * Carry out initialization that is needed in order to clean up after  
      * errors during the the remainder of this procedure.  
      */  
   
     textPtr->textInfoPtr = Tk_CanvasGetTextInfo(canvas);  
   
     textPtr->insertPos  = 0;  
   
     textPtr->anchor     = TK_ANCHOR_CENTER;  
     textPtr->tsoffset.flags = 0;  
     textPtr->tsoffset.xoffset = 0;  
     textPtr->tsoffset.yoffset = 0;  
     textPtr->color      = NULL;  
     textPtr->activeColor = NULL;  
     textPtr->disabledColor = NULL;  
     textPtr->tkfont     = NULL;  
     textPtr->justify    = TK_JUSTIFY_LEFT;  
     textPtr->stipple    = None;  
     textPtr->activeStipple = None;  
     textPtr->disabledStipple = None;  
     textPtr->text       = NULL;  
     textPtr->width      = 0;  
   
     textPtr->numChars   = 0;  
     textPtr->numBytes   = 0;  
     textPtr->textLayout = NULL;  
     textPtr->leftEdge   = 0;  
     textPtr->rightEdge  = 0;  
     textPtr->gc         = None;  
     textPtr->selTextGC  = None;  
     textPtr->cursorOffGC = None;  
   
     /*  
      * Process the arguments to fill in the item record.  
      */  
   
     if ((TextCoords(interp, canvas, itemPtr, i, argv) != TCL_OK)) {  
         goto error;  
     }  
     if (ConfigureText(interp, canvas, itemPtr, argc-i, argv+i, 0) == TCL_OK) {  
         return TCL_OK;  
     }  
   
     error:  
     DeleteText(canvas, itemPtr, Tk_Display(Tk_CanvasTkwin(canvas)));  
     return TCL_ERROR;  
 }  
   
 /*  
  *--------------------------------------------------------------  
  *  
  * TextCoords --  
  *  
  *      This procedure is invoked to process the "coords" widget  
  *      command on text items.  See the user documentation for  
  *      details on what it does.  
  *  
  * Results:  
  *      Returns TCL_OK or TCL_ERROR, and sets the interp's result.  
  *  
  * Side effects:  
  *      The coordinates for the given item may be changed.  
  *  
  *--------------------------------------------------------------  
  */  
   
 static int  
 TextCoords(interp, canvas, itemPtr, argc, argv)  
     Tcl_Interp *interp;         /* Used for error reporting. */  
     Tk_Canvas canvas;           /* Canvas containing item. */  
     Tk_Item *itemPtr;           /* Item whose coordinates are to be read or  
                                  * modified. */  
     int argc;                   /* Number of coordinates supplied in argv. */  
     Tcl_Obj *CONST argv[];      /* Array of coordinates: x1, y1, x2, y2, ... */  
 {  
     TextItem *textPtr = (TextItem *) itemPtr;  
   
     if (argc == 0) {  
         Tcl_Obj *obj = Tcl_NewObj();  
         Tcl_Obj *subobj = Tcl_NewDoubleObj(textPtr->x);  
         Tcl_ListObjAppendElement(interp, obj, subobj);  
         subobj = Tcl_NewDoubleObj(textPtr->y);  
         Tcl_ListObjAppendElement(interp, obj, subobj);  
         Tcl_SetObjResult(interp, obj);  
     } else if (argc < 3) {  
         if (argc==1) {  
             if (Tcl_ListObjGetElements(interp, argv[0], &argc,  
                     (Tcl_Obj ***) &argv) != TCL_OK) {  
                 return TCL_ERROR;  
             } else if (argc != 2) {  
                 char buf[64 + TCL_INTEGER_SPACE];  
   
                 sprintf(buf, "wrong # coordinates: expected 2, got %d", argc);  
                 Tcl_SetResult(interp, buf, TCL_VOLATILE);  
                 return TCL_ERROR;  
             }  
         }  
         if ((Tk_CanvasGetCoordFromObj(interp, canvas, argv[0], &textPtr->x) != TCL_OK)  
                 || (Tk_CanvasGetCoordFromObj(interp, canvas, argv[1],  
                     &textPtr->y) != TCL_OK)) {  
             return TCL_ERROR;  
         }  
         ComputeTextBbox(canvas, textPtr);  
     } else {  
         char buf[64 + TCL_INTEGER_SPACE];  
           
         sprintf(buf, "wrong # coordinates: expected 0 or 2, got %d", argc);  
         Tcl_SetResult(interp, buf, TCL_VOLATILE);  
         return TCL_ERROR;  
     }  
     return TCL_OK;  
 }  
   
 /*  
  *--------------------------------------------------------------  
  *  
  * ConfigureText --  
  *  
  *      This procedure is invoked to configure various aspects  
  *      of a text item, such as its border and background colors.  
  *  
  * Results:  
  *      A standard Tcl result code.  If an error occurs, then  
  *      an error message is left in the interp's result.  
  *  
  * Side effects:  
  *      Configuration information, such as colors and stipple  
  *      patterns, may be set for itemPtr.  
  *  
  *--------------------------------------------------------------  
  */  
   
 static int  
 ConfigureText(interp, canvas, itemPtr, argc, argv, flags)  
     Tcl_Interp *interp;         /* Interpreter for error reporting. */  
     Tk_Canvas canvas;           /* Canvas containing itemPtr. */  
     Tk_Item *itemPtr;           /* Rectangle item to reconfigure. */  
     int argc;                   /* Number of elements in argv.  */  
     Tcl_Obj *CONST argv[];      /* Arguments describing things to configure. */  
     int flags;                  /* Flags to pass to Tk_ConfigureWidget. */  
 {  
     TextItem *textPtr = (TextItem *) itemPtr;  
     XGCValues gcValues;  
     GC newGC, newSelGC;  
     unsigned long mask;  
     Tk_Window tkwin;  
     Tk_CanvasTextInfo *textInfoPtr = textPtr->textInfoPtr;  
     XColor *selBgColorPtr;  
     XColor *color;  
     Pixmap stipple;  
     Tk_State state;  
   
     tkwin = Tk_CanvasTkwin(canvas);  
     if (Tk_ConfigureWidget(interp, tkwin, configSpecs, argc, (char **) argv,  
             (char *) textPtr, flags|TK_CONFIG_OBJS) != TCL_OK) {  
         return TCL_ERROR;  
     }  
   
     /*  
      * A few of the options require additional processing, such as  
      * graphics contexts.  
      */  
   
     state = itemPtr->state;  
   
     if (textPtr->activeColor != NULL ||  
             textPtr->activeStipple != None) {  
         itemPtr->redraw_flags |= TK_ITEM_STATE_DEPENDANT;  
     } else {  
         itemPtr->redraw_flags &= ~TK_ITEM_STATE_DEPENDANT;  
     }  
   
     if(state == TK_STATE_NULL) {  
         state = ((TkCanvas *)canvas)->canvas_state;  
     }  
   
     color = textPtr->color;  
     stipple = textPtr->stipple;  
     if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) {  
         if (textPtr->activeColor!=NULL) {  
             color = textPtr->activeColor;  
         }  
         if (textPtr->activeStipple!=None) {  
             stipple = textPtr->activeStipple;  
         }  
     } else if (state==TK_STATE_DISABLED) {  
         if (textPtr->disabledColor!=NULL) {  
             color = textPtr->disabledColor;  
         }  
         if (textPtr->disabledStipple!=None) {  
             stipple = textPtr->disabledStipple;  
         }  
     }  
   
     newGC = newSelGC = None;  
     if (textPtr->tkfont != NULL) {  
         gcValues.font = Tk_FontId(textPtr->tkfont);  
         mask = GCFont;  
         if (color != NULL) {  
             gcValues.foreground = color->pixel;  
             mask |= GCForeground;  
             if (stipple != None) {  
                 gcValues.stipple = stipple;  
                 gcValues.fill_style = FillStippled;  
                 mask |= GCStipple|GCFillStyle;  
             }  
             newGC = Tk_GetGC(tkwin, mask, &gcValues);  
         }  
         mask &= ~(GCTile|GCFillStyle|GCStipple);  
         if (stipple != None) {  
             gcValues.stipple = stipple;  
             gcValues.fill_style = FillStippled;  
             mask |= GCStipple|GCFillStyle;  
         }  
         gcValues.foreground = textInfoPtr->selFgColorPtr->pixel;  
         newSelGC = Tk_GetGC(tkwin, mask|GCForeground, &gcValues);  
     }  
     if (textPtr->gc != None) {  
         Tk_FreeGC(Tk_Display(tkwin), textPtr->gc);  
     }  
     textPtr->gc = newGC;  
     if (textPtr->selTextGC != None) {  
         Tk_FreeGC(Tk_Display(tkwin), textPtr->selTextGC);  
     }  
     textPtr->selTextGC = newSelGC;  
   
     selBgColorPtr = Tk_3DBorderColor(textInfoPtr->selBorder);  
     if (Tk_3DBorderColor(textInfoPtr->insertBorder)->pixel  
             == selBgColorPtr->pixel) {  
         if (selBgColorPtr->pixel == BlackPixelOfScreen(Tk_Screen(tkwin))) {  
             gcValues.foreground = WhitePixelOfScreen(Tk_Screen(tkwin));  
         } else {  
             gcValues.foreground = BlackPixelOfScreen(Tk_Screen(tkwin));  
         }  
         newGC = Tk_GetGC(tkwin, GCForeground, &gcValues);  
     } else {  
         newGC = None;  
     }  
     if (textPtr->cursorOffGC != None) {  
         Tk_FreeGC(Tk_Display(tkwin), textPtr->cursorOffGC);  
     }  
     textPtr->cursorOffGC = newGC;  
   
   
     /*  
      * If the text was changed, move the selection and insertion indices  
      * to keep them inside the item.  
      */  
   
     textPtr->numBytes = strlen(textPtr->text);  
     textPtr->numChars = Tcl_NumUtfChars(textPtr->text, textPtr->numBytes);  
     if (textInfoPtr->selItemPtr == itemPtr) {  
           
         if (textInfoPtr->selectFirst >= textPtr->numChars) {  
             textInfoPtr->selItemPtr = NULL;  
         } else {  
             if (textInfoPtr->selectLast >= textPtr->numChars) {  
                 textInfoPtr->selectLast = textPtr->numChars - 1;  
             }  
             if ((textInfoPtr->anchorItemPtr == itemPtr)  
                     && (textInfoPtr->selectAnchor >= textPtr->numChars)) {  
                 textInfoPtr->selectAnchor = textPtr->numChars - 1;  
             }  
         }  
     }  
     if (textPtr->insertPos >= textPtr->numChars) {  
         textPtr->insertPos = textPtr->numChars;  
     }  
   
     ComputeTextBbox(canvas, textPtr);  
     return TCL_OK;  
 }  
   
 /*  
  *--------------------------------------------------------------  
  *  
  * DeleteText --  
  *  
  *      This procedure is called to clean up the data structure  
  *      associated with a text item.  
  *  
  * Results:  
  *      None.  
  *  
  * Side effects:  
  *      Resources associated with itemPtr are released.  
  *  
  *--------------------------------------------------------------  
  */  
   
 static void  
 DeleteText(canvas, itemPtr, display)  
     Tk_Canvas canvas;           /* Info about overall canvas widget. */  
     Tk_Item *itemPtr;           /* Item that is being deleted. */  
     Display *display;           /* Display containing window for canvas. */  
 {  
     TextItem *textPtr = (TextItem *) itemPtr;  
   
     if (textPtr->color != NULL) {  
         Tk_FreeColor(textPtr->color);  
     }  
     if (textPtr->activeColor != NULL) {  
         Tk_FreeColor(textPtr->activeColor);  
     }  
     if (textPtr->disabledColor != NULL) {  
         Tk_FreeColor(textPtr->disabledColor);  
     }  
     Tk_FreeFont(textPtr->tkfont);  
     if (textPtr->stipple != None) {  
         Tk_FreeBitmap(display, textPtr->stipple);  
     }  
     if (textPtr->activeStipple != None) {  
         Tk_FreeBitmap(display, textPtr->activeStipple);  
     }  
     if (textPtr->disabledStipple != None) {  
         Tk_FreeBitmap(display, textPtr->disabledStipple);  
     }  
     if (textPtr->text != NULL) {  
         ckfree(textPtr->text);  
     }  
   
     Tk_FreeTextLayout(textPtr->textLayout);  
     if (textPtr->gc != None) {  
         Tk_FreeGC(display, textPtr->gc);  
     }  
     if (textPtr->selTextGC != None) {  
         Tk_FreeGC(display, textPtr->selTextGC);  
     }  
     if (textPtr->cursorOffGC != None) {  
         Tk_FreeGC(display, textPtr->cursorOffGC);  
     }  
 }  
   
 /*  
  *--------------------------------------------------------------  
  *  
  * ComputeTextBbox --  
  *  
  *      This procedure is invoked to compute the bounding box of  
  *      all the pixels that may be drawn as part of a text item.  
  *      In addition, it recomputes all of the geometry information  
  *      used to display a text item or check for mouse hits.  
  *  
  * Results:  
  *      None.  
  *  
  * Side effects:  
  *      The fields x1, y1, x2, and y2 are updated in the header  
  *      for itemPtr, and the linePtr structure is regenerated  
  *      for itemPtr.  
  *  
  *--------------------------------------------------------------  
  */  
   
 static void  
 ComputeTextBbox(canvas, textPtr)  
     Tk_Canvas canvas;           /* Canvas that contains item. */  
     TextItem *textPtr;          /* Item whose bbox is to be recomputed. */  
 {  
     Tk_CanvasTextInfo *textInfoPtr;  
     int leftX, topY, width, height, fudge;  
     Tk_State state = textPtr->header.state;  
   
     if(state == TK_STATE_NULL) {  
         state = ((TkCanvas *)canvas)->canvas_state;  
     }  
   
     Tk_FreeTextLayout(textPtr->textLayout);  
     textPtr->textLayout = Tk_ComputeTextLayout(textPtr->tkfont,  
             textPtr->text, textPtr->numChars, textPtr->width,  
             textPtr->justify, 0, &width, &height);  
   
     if (state == TK_STATE_HIDDEN || textPtr->color == NULL) {  
         width = height = 0;  
     }  
   
     /*  
      * Use overall geometry information to compute the top-left corner  
      * of the bounding box for the text item.  
      */  
   
     leftX = (int) (textPtr->x + 0.5);  
     topY = (int) (textPtr->y + 0.5);  
     switch (textPtr->anchor) {  
         case TK_ANCHOR_NW:  
         case TK_ANCHOR_N:  
         case TK_ANCHOR_NE:  
             break;  
   
         case TK_ANCHOR_W:  
         case TK_ANCHOR_CENTER:  
         case TK_ANCHOR_E:  
             topY -= height / 2;  
             break;  
   
         case TK_ANCHOR_SW:  
         case TK_ANCHOR_S:  
         case TK_ANCHOR_SE:  
             topY -= height;  
             break;  
     }  
     switch (textPtr->anchor) {  
         case TK_ANCHOR_NW:  
         case TK_ANCHOR_W:  
         case TK_ANCHOR_SW:  
             break;  
   
         case TK_ANCHOR_N:  
         case TK_ANCHOR_CENTER:  
         case TK_ANCHOR_S:  
             leftX -= width / 2;  
             break;  
   
         case TK_ANCHOR_NE:  
         case TK_ANCHOR_E:  
         case TK_ANCHOR_SE:  
             leftX -= width;  
             break;  
     }  
   
     textPtr->leftEdge  = leftX;  
     textPtr->rightEdge = leftX + width;  
   
     /*  
      * Last of all, update the bounding box for the item.  The item's  
      * bounding box includes the bounding box of all its lines, plus  
      * an extra fudge factor for the cursor border (which could  
      * potentially be quite large).  
      */  
   
     textInfoPtr = textPtr->textInfoPtr;  
     fudge = (textInfoPtr->insertWidth + 1) / 2;  
     if (textInfoPtr->selBorderWidth > fudge) {  
         fudge = textInfoPtr->selBorderWidth;  
     }  
     textPtr->header.x1 = leftX - fudge;  
     textPtr->header.y1 = topY;  
     textPtr->header.x2 = leftX + width + fudge;  
     textPtr->header.y2 = topY + height;  
 }  
   
 /*  
  *--------------------------------------------------------------  
  *  
  * DisplayCanvText --  
  *  
  *      This procedure is invoked to draw a text item in a given  
  *      drawable.  
  *  
  * Results:  
  *      None.  
  *  
  * Side effects:  
  *      ItemPtr is drawn in drawable using the transformation  
  *      information in canvas.  
  *  
  *--------------------------------------------------------------  
  */  
   
 static void  
 DisplayCanvText(canvas, itemPtr, display, drawable, x, y, width, height)  
     Tk_Canvas canvas;           /* Canvas that contains item. */  
     Tk_Item *itemPtr;           /* Item to be displayed. */  
     Display *display;           /* Display on which to draw item. */  
     Drawable drawable;          /* Pixmap or window in which to draw item. */  
     int x, y, width, height;    /* Describes region of canvas that must be  
                                  * redisplayed (not used). */  
 {  
     TextItem *textPtr;  
     Tk_CanvasTextInfo *textInfoPtr;  
     int selFirstChar, selLastChar;  
     short drawableX, drawableY;  
     Pixmap stipple;  
     Tk_State state = itemPtr->state;  
   
     textPtr = (TextItem *) itemPtr;  
     textInfoPtr = textPtr->textInfoPtr;  
   
     if(state == TK_STATE_NULL) {  
         state = ((TkCanvas *)canvas)->canvas_state;  
     }  
     stipple = textPtr->stipple;  
     if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) {  
         if (textPtr->activeStipple!=None) {  
             stipple = textPtr->activeStipple;  
         }  
     } else if (state==TK_STATE_DISABLED) {  
         if (textPtr->disabledStipple!=None) {  
             stipple = textPtr->disabledStipple;  
         }  
     }  
   
     if (textPtr->gc == None) {  
         return;  
     }  
   
     /*  
      * If we're stippling, then modify the stipple offset in the GC.  Be  
      * sure to reset the offset when done, since the GC is supposed to be  
      * read-only.  
      */  
   
     if (stipple != None) {  
         Tk_CanvasSetOffset(canvas, textPtr->gc, &textPtr->tsoffset);  
     }  
   
     selFirstChar = -1;  
     selLastChar = 0;            /* lint. */  
   
     if (textInfoPtr->selItemPtr == itemPtr) {  
         selFirstChar = textInfoPtr->selectFirst;  
         selLastChar = textInfoPtr->selectLast;  
         if (selLastChar > textPtr->numChars) {  
             selLastChar = textPtr->numChars - 1;  
         }  
         if ((selFirstChar >= 0) && (selFirstChar <= selLastChar)) {  
             int xFirst, yFirst, hFirst;  
             int xLast, yLast;  
   
             /*  
              * Draw a special background under the selection.  
              */  
   
             Tk_CharBbox(textPtr->textLayout, selFirstChar, &xFirst, &yFirst,  
                     NULL, &hFirst);  
             Tk_CharBbox(textPtr->textLayout, selLastChar, &xLast, &yLast,  
                     NULL, NULL);  
   
             /*  
              * If the selection spans the end of this line, then display  
              * selection background all the way to the end of the line.  
              * However, for the last line we only want to display up to the  
              * last character, not the end of the line.  
              */  
   
             x = xFirst;  
             height = hFirst;  
             for (y = yFirst ; y <= yLast; y += height) {  
                 if (y == yLast) {  
                     width = xLast - x;  
                 } else {              
                     width = textPtr->rightEdge - textPtr->leftEdge - x;  
                 }  
                 Tk_CanvasDrawableCoords(canvas,  
                         (double) (textPtr->leftEdge + x  
                                 - textInfoPtr->selBorderWidth),  
                         (double) (textPtr->header.y1 + y),  
                         &drawableX, &drawableY);  
                 Tk_Fill3DRectangle(Tk_CanvasTkwin(canvas), drawable,  
                         textInfoPtr->selBorder, drawableX, drawableY,  
                         width + 2 * textInfoPtr->selBorderWidth,  
                         height, textInfoPtr->selBorderWidth, TK_RELIEF_RAISED);  
                 x = 0;  
             }  
         }  
     }  
   
     /*  
      * If the insertion point should be displayed, then draw a special  
      * background for the cursor before drawing the text.  Note:  if  
      * we're the cursor item but the cursor is turned off, then redraw  
      * background over the area of the cursor.  This guarantees that  
      * the selection won't make the cursor invisible on mono displays,  
      * where both are drawn in the same color.  
      */  
   
     if ((textInfoPtr->focusItemPtr == itemPtr) && (textInfoPtr->gotFocus)) {  
         if (Tk_CharBbox(textPtr->textLayout, textPtr->insertPos,  
                 &x, &y, NULL, &height)) {  
             Tk_CanvasDrawableCoords(canvas,  
                     (double) (textPtr->leftEdge + x  
                             - (textInfoPtr->insertWidth / 2)),  
                     (double) (textPtr->header.y1 + y),  
                     &drawableX, &drawableY);  
             if (textInfoPtr->cursorOn) {  
                 Tk_Fill3DRectangle(Tk_CanvasTkwin(canvas), drawable,  
                         textInfoPtr->insertBorder,  
                         drawableX, drawableY,  
                         textInfoPtr->insertWidth, height,  
                         textInfoPtr->insertBorderWidth, TK_RELIEF_RAISED);  
             } else if (textPtr->cursorOffGC != None) {  
                 /*  
                  * Redraw the background over the area of the cursor,  
                  * even though the cursor is turned off.  This  
                  * guarantees that the selection won't make the cursor  
                  * invisible on mono displays, where both may be drawn  
                  * in the same color.  
                  */  
   
                 XFillRectangle(display, drawable, textPtr->cursorOffGC,  
                         drawableX, drawableY,  
                         (unsigned) textInfoPtr->insertWidth,  
                         (unsigned) height);  
             }  
         }  
     }  
   
   
     /*  
      * Display the text in two pieces: draw the entire text item, then  
      * draw the selected text on top of it.  The selected text then  
      * will only need to be drawn if it has different attributes (such  
      * as foreground color) than regular text.  
      */  
   
     Tk_CanvasDrawableCoords(canvas, (double) textPtr->leftEdge,  
             (double) textPtr->header.y1, &drawableX, &drawableY);  
     Tk_DrawTextLayout(display, drawable, textPtr->gc, textPtr->textLayout,  
             drawableX, drawableY, 0, -1);  
   
     if ((selFirstChar >= 0) && (textPtr->selTextGC != textPtr->gc)) {  
         Tk_DrawTextLayout(display, drawable, textPtr->selTextGC,  
             textPtr->textLayout, drawableX, drawableY, selFirstChar,  
             selLastChar + 1);  
     }  
   
     if (stipple != None) {  
         XSetTSOrigin(display, textPtr->gc, 0, 0);  
     }  
 }  
   
 /*  
  *--------------------------------------------------------------  
  *  
  * TextInsert --  
  *  
  *      Insert characters into a text item at a given position.  
  *  
  * Results:  
  *      None.  
  *  
  * Side effects:  
  *      The text in the given item is modified.  The cursor and  
  *      selection positions are also modified to reflect the  
  *      insertion.  
  *  
  *--------------------------------------------------------------  
  */  
   
 static void  
 TextInsert(canvas, itemPtr, index, string)  
     Tk_Canvas canvas;           /* Canvas containing text item. */  
     Tk_Item *itemPtr;           /* Text item to be modified. */  
     int index;                  /* Character index before which string is  
                                  * to be inserted. */  
     char *string;               /* New characters to be inserted. */  
 {  
     TextItem *textPtr = (TextItem *) itemPtr;  
     int byteIndex, byteCount, charsAdded;  
     char *new, *text;  
     Tk_CanvasTextInfo *textInfoPtr = textPtr->textInfoPtr;  
   
     string = Tcl_GetStringFromObj((Tcl_Obj *) string, &byteCount);  
   
     text = textPtr->text;  
   
     if (index < 0) {  
         index = 0;  
     }  
     if (index > textPtr->numChars) {  
         index = textPtr->numChars;  
     }  
     byteIndex = Tcl_UtfAtIndex(text, index) - text;  
     byteCount = strlen(string);  
     if (byteCount == 0) {  
         return;  
     }  
   
     new = (char *) ckalloc((unsigned) textPtr->numBytes + byteCount + 1);  
     memcpy(new, text, (size_t) byteIndex);  
     strcpy(new + byteIndex, string);  
     strcpy(new + byteIndex + byteCount, text + byteIndex);  
   
     ckfree(text);  
     textPtr->text = new;  
     charsAdded = Tcl_NumUtfChars(string, byteCount);  
     textPtr->numChars += charsAdded;  
     textPtr->numBytes += byteCount;  
   
     /*  
      * Inserting characters invalidates indices such as those for the  
      * selection and cursor.  Update the indices appropriately.  
      */  
   
     if (textInfoPtr->selItemPtr == itemPtr) {  
         if (textInfoPtr->selectFirst >= index) {  
             textInfoPtr->selectFirst += charsAdded;  
         }  
         if (textInfoPtr->selectLast >= index) {  
             textInfoPtr->selectLast += charsAdded;  
         }  
         if ((textInfoPtr->anchorItemPtr == itemPtr)  
                 && (textInfoPtr->selectAnchor >= index)) {  
             textInfoPtr->selectAnchor += charsAdded;  
         }  
     }  
     if (textPtr->insertPos >= index) {  
         textPtr->insertPos += charsAdded;  
     }  
     ComputeTextBbox(canvas, textPtr);  
 }  
   
 /*  
  *--------------------------------------------------------------  
  *  
  * TextDeleteChars --  
  *  
  *      Delete one or more characters from a text item.  
  *  
  * Results:  
  *      None.  
  *  
  * Side effects:  
  *      Characters between "first" and "last", inclusive, get  
  *      deleted from itemPtr, and things like the selection  
  *      position get updated.  
  *  
  *--------------------------------------------------------------  
  */  
   
 static void  
 TextDeleteChars(canvas, itemPtr, first, last)  
     Tk_Canvas canvas;           /* Canvas containing itemPtr. */  
     Tk_Item *itemPtr;           /* Item in which to delete characters. */  
     int first;                  /* Character index of first character to  
                                  * delete. */  
     int last;                   /* Character index of last character to  
                                  * delete (inclusive). */  
 {  
     TextItem *textPtr = (TextItem *) itemPtr;  
     int byteIndex, byteCount, charsRemoved;  
     char *new, *text;  
     Tk_CanvasTextInfo *textInfoPtr = textPtr->textInfoPtr;  
   
     text = textPtr->text;  
     if (first < 0) {  
         first = 0;  
     }  
     if (last >= textPtr->numChars) {  
         last = textPtr->numChars - 1;  
     }  
     if (first > last) {  
         return;  
     }  
     charsRemoved = last + 1 - first;  
   
     byteIndex = Tcl_UtfAtIndex(text, first) - text;  
     byteCount = Tcl_UtfAtIndex(text + byteIndex, charsRemoved)  
         - (text + byteIndex);  
       
     new = (char *) ckalloc((unsigned) (textPtr->numBytes + 1 - byteCount));  
     memcpy(new, text, (size_t) byteIndex);  
     strcpy(new + byteIndex, text + byteIndex + byteCount);  
   
     ckfree(text);  
     textPtr->text = new;  
     textPtr->numChars -= charsRemoved;  
     textPtr->numBytes -= byteCount;  
   
     /*  
      * Update indexes for the selection and cursor to reflect the  
      * renumbering of the remaining characters.  
      */  
   
     if (textInfoPtr->selItemPtr == itemPtr) {  
         if (textInfoPtr->selectFirst > first) {  
             textInfoPtr->selectFirst -= charsRemoved;  
             if (textInfoPtr->selectFirst < first) {  
                 textInfoPtr->selectFirst = first;  
             }  
         }  
         if (textInfoPtr->selectLast >= first) {  
             textInfoPtr->selectLast -= charsRemoved;  
             if (textInfoPtr->selectLast < first - 1) {  
                 textInfoPtr->selectLast = first - 1;  
             }  
         }  
         if (textInfoPtr->selectFirst > textInfoPtr->selectLast) {  
             textInfoPtr->selItemPtr = NULL;  
         }  
         if ((textInfoPtr->anchorItemPtr == itemPtr)  
                 && (textInfoPtr->selectAnchor > first)) {  
             textInfoPtr->selectAnchor -= charsRemoved;  
             if (textInfoPtr->selectAnchor < first) {  
                 textInfoPtr->selectAnchor = first;  
             }  
         }  
     }  
     if (textPtr->insertPos > first) {  
         textPtr->insertPos -= charsRemoved;  
         if (textPtr->insertPos < first) {  
             textPtr->insertPos = first;  
         }  
     }  
     ComputeTextBbox(canvas, textPtr);  
     return;  
 }  
   
 /*  
  *--------------------------------------------------------------  
  *  
  * TextToPoint --  
  *  
  *      Computes the distance from a given point to a given  
  *      text item, in canvas units.  
  *  
  * Results:  
  *      The return value is 0 if the point whose x and y coordinates  
  *      are pointPtr[0] and pointPtr[1] is inside the text item.  If  
  *      the point isn't inside the text item then the return value  
  *      is the distance from the point to the text item.  
  *  
  * Side effects:  
  *      None.  
  *  
  *--------------------------------------------------------------  
  */  
   
 static double  
 TextToPoint(canvas, itemPtr, pointPtr)  
     Tk_Canvas canvas;           /* Canvas containing itemPtr. */  
     Tk_Item *itemPtr;           /* Item to check against point. */  
     double *pointPtr;           /* Pointer to x and y coordinates. */  
 {  
     TextItem *textPtr;  
     Tk_State state = itemPtr->state;  
     double value;  
   
     if (state == TK_STATE_NULL) {  
         state = ((TkCanvas *)canvas)->canvas_state;  
     }  
     textPtr = (TextItem *) itemPtr;  
     value =  (double) Tk_DistanceToTextLayout(textPtr->textLayout,  
             (int) pointPtr[0] - textPtr->leftEdge,  
             (int) pointPtr[1] - textPtr->header.y1);  
   
     if ((state == TK_STATE_HIDDEN) || (textPtr->color == NULL) ||  
             (textPtr->text == NULL) || (*textPtr->text == 0)) {  
         value = 1.0e36;  
     }  
     return value;  
 }  
   
 /*  
  *--------------------------------------------------------------  
  *  
  * TextToArea --  
  *  
  *      This procedure is called to determine whether an item  
  *      lies entirely inside, entirely outside, or overlapping  
  *      a given rectangle.  
  *  
  * Results:  
  *      -1 is returned if the item is entirely outside the area  
  *      given by rectPtr, 0 if it overlaps, and 1 if it is entirely  
  *      inside the given area.  
  *  
  * Side effects:  
  *      None.  
  *  
  *--------------------------------------------------------------  
  */  
   
 static int  
 TextToArea(canvas, itemPtr, rectPtr)  
     Tk_Canvas canvas;           /* Canvas containing itemPtr. */  
     Tk_Item *itemPtr;           /* Item to check against rectangle. */  
     double *rectPtr;            /* Pointer to array of four coordinates  
                                  * (x1, y1, x2, y2) describing rectangular  
                                  * area.  */  
 {  
     TextItem *textPtr;  
     Tk_State state = itemPtr->state;  
   
     if (state == TK_STATE_NULL) {  
         state = ((TkCanvas *)canvas)->canvas_state;  
     }  
   
     textPtr = (TextItem *) itemPtr;  
     return Tk_IntersectTextLayout(textPtr->textLayout,  
             (int) (rectPtr[0] + 0.5) - textPtr->leftEdge,  
             (int) (rectPtr[1] + 0.5) - textPtr->header.y1,  
             (int) (rectPtr[2] - rectPtr[0] + 0.5),  
             (int) (rectPtr[3] - rectPtr[1] + 0.5));  
 }  
   
 /*  
  *--------------------------------------------------------------  
  *  
  * ScaleText --  
  *  
  *      This procedure is invoked to rescale a text item.  
  *  
  * Results:  
  *      None.  
  *  
  * Side effects:  
  *      Scales the position of the text, but not the size  
  *      of the font for the text.  
  *  
  *--------------------------------------------------------------  
  */  
   
         /* ARGSUSED */  
 static void  
 ScaleText(canvas, itemPtr, originX, originY, scaleX, scaleY)  
     Tk_Canvas canvas;           /* Canvas containing rectangle. */  
     Tk_Item *itemPtr;           /* Rectangle to be scaled. */  
     double originX, originY;    /* Origin about which to scale rect. */  
     double scaleX;              /* Amount to scale in X direction. */  
     double scaleY;              /* Amount to scale in Y direction. */  
 {  
     TextItem *textPtr = (TextItem *) itemPtr;  
   
     textPtr->x = originX + scaleX*(textPtr->x - originX);  
     textPtr->y = originY + scaleY*(textPtr->y - originY);  
     ComputeTextBbox(canvas, textPtr);  
     return;  
 }  
   
 /*  
  *--------------------------------------------------------------  
  *  
  * TranslateText --  
  *  
  *      This procedure is called to move a text item by a  
  *      given amount.  
  *  
  * Results:  
  *      None.  
  *  
  * Side effects:  
  *      The position of the text item is offset by (xDelta, yDelta),  
  *      and the bounding box is updated in the generic part of the  
  *      item structure.  
  *  
  *--------------------------------------------------------------  
  */  
   
 static void  
 TranslateText(canvas, itemPtr, deltaX, deltaY)  
     Tk_Canvas canvas;           /* Canvas containing item. */  
     Tk_Item *itemPtr;           /* Item that is being moved. */  
     double deltaX, deltaY;      /* Amount by which item is to be moved. */  
 {  
     TextItem *textPtr = (TextItem *) itemPtr;  
   
     textPtr->x += deltaX;  
     textPtr->y += deltaY;  
     ComputeTextBbox(canvas, textPtr);  
 }  
   
 /*  
  *--------------------------------------------------------------  
  *  
  * GetTextIndex --  
  *  
  *      Parse an index into a text item and return either its value  
  *      or an error.  
  *  
  * Results:  
  *      A standard Tcl result.  If all went well, then *indexPtr is  
  *      filled in with the index (into itemPtr) corresponding to  
  *      string.  Otherwise an error message is left in  
  *      the interp's result.  
  *  
  * Side effects:  
  *      None.  
  *  
  *--------------------------------------------------------------  
  */  
   
 static int  
 GetTextIndex(interp, canvas, itemPtr, obj, indexPtr)  
     Tcl_Interp *interp;         /* Used for error reporting. */  
     Tk_Canvas canvas;           /* Canvas containing item. */  
     Tk_Item *itemPtr;           /* Item for which the index is being  
                                  * specified. */  
     Tcl_Obj *obj;               /* Specification of a particular character  
                                  * in itemPtr's text. */  
     int *indexPtr;              /* Where to store converted character  
                                  * index. */  
 {  
     TextItem *textPtr = (TextItem *) itemPtr;  
     size_t length;  
     int c;  
     TkCanvas *canvasPtr = (TkCanvas *) canvas;  
     Tk_CanvasTextInfo *textInfoPtr = textPtr->textInfoPtr;  
     char *string = Tcl_GetStringFromObj(obj, (int *) &length);  
   
     c = string[0];  
     length = strlen(string);  
   
     if ((c == 'e') && (strncmp(string, "end", length) == 0)) {  
         *indexPtr = textPtr->numChars;  
     } else if ((c == 'i') && (strncmp(string, "insert", length) == 0)) {  
         *indexPtr = textPtr->insertPos;  
     } else if ((c == 's') && (strncmp(string, "sel.first", length) == 0)  
             && (length >= 5)) {  
         if (textInfoPtr->selItemPtr != itemPtr) {  
             Tcl_SetResult(interp, "selection isn't in item", TCL_STATIC);  
             return TCL_ERROR;  
         }  
         *indexPtr = textInfoPtr->selectFirst;  
     } else if ((c == 's') && (strncmp(string, "sel.last", length) == 0)  
             && (length >= 5)) {  
         if (textInfoPtr->selItemPtr != itemPtr) {  
             Tcl_SetResult(interp, "selection isn't in item", TCL_STATIC);  
             return TCL_ERROR;  
         }  
         *indexPtr = textInfoPtr->selectLast;  
     } else if (c == '@') {  
         int x, y;  
         double tmp;  
         char *end, *p;  
   
         p = string+1;  
         tmp = strtod(p, &end);  
         if ((end == p) || (*end != ',')) {  
             goto badIndex;  
         }  
         x = (int) ((tmp < 0) ? tmp - 0.5 : tmp + 0.5);  
         p = end+1;  
         tmp = strtod(p, &end);  
         if ((end == p) || (*end != 0)) {  
             goto badIndex;  
         }  
         y = (int) ((tmp < 0) ? tmp - 0.5 : tmp + 0.5);  
         *indexPtr = Tk_PointToChar(textPtr->textLayout,  
                 x + canvasPtr->scrollX1 - textPtr->leftEdge,  
                 y + canvasPtr->scrollY1 - textPtr->header.y1);  
     } else if (Tcl_GetIntFromObj((Tcl_Interp *)NULL, obj, indexPtr) == TCL_OK) {  
         if (*indexPtr < 0){  
             *indexPtr = 0;  
         } else if (*indexPtr > textPtr->numChars) {  
             *indexPtr = textPtr->numChars;  
         }  
     } else {  
         /*  
          * Some of the paths here leave messages in the interp's result,  
          * so we have to clear it out before storing our own message.  
          */  
   
         badIndex:  
         Tcl_SetResult(interp, (char *) NULL, TCL_STATIC);  
         Tcl_AppendResult(interp, "bad index \"", string, "\"",  
                 (char *) NULL);  
         return TCL_ERROR;  
     }  
     return TCL_OK;  
 }  
   
 /*  
  *--------------------------------------------------------------  
  *  
  * SetTextCursor --  
  *  
  *      Set the position of the insertion cursor in this item.  
  *  
  * Results:  
  *      None.  
  *  
  * Side effects:  
  *      The cursor position will change.  
  *  
  *--------------------------------------------------------------  
  */  
   
         /* ARGSUSED */  
 static void  
 SetTextCursor(canvas, itemPtr, index)  
     Tk_Canvas canvas;           /* Record describing canvas widget. */  
     Tk_Item *itemPtr;           /* Text item in which cursor position is to  
                                  * be set. */  
     int index;                  /* Character index of character just before  
                                  * which cursor is to be positioned. */  
 {  
     TextItem *textPtr = (TextItem *) itemPtr;  
   
     if (index < 0) {  
         textPtr->insertPos = 0;  
     } else  if (index > textPtr->numChars) {  
         textPtr->insertPos = textPtr->numChars;  
     } else {  
         textPtr->insertPos = index;  
     }  
 }  
   
 /*  
  *--------------------------------------------------------------  
  *  
  * GetSelText --  
  *  
  *      This procedure is invoked to return the selected portion  
  *      of a text item.  It is only called when this item has  
  *      the selection.  
  *  
  * Results:  
  *      The return value is the number of non-NULL bytes stored  
  *      at buffer.  Buffer is filled (or partially filled) with a  
  *      NULL-terminated string containing part or all of the selection,  
  *      as given by offset and maxBytes.  
  *  
  * Side effects:  
  *      None.  
  *  
  *--------------------------------------------------------------  
  */  
   
 static int  
 GetSelText(canvas, itemPtr, offset, buffer, maxBytes)  
     Tk_Canvas canvas;           /* Canvas containing selection. */  
     Tk_Item *itemPtr;           /* Text item containing selection. */  
     int offset;                 /* Byte offset within selection of first  
                                  * character to be returned. */  
     char *buffer;               /* Location in which to place selection. */  
     int maxBytes;               /* Maximum number of bytes to place at  
                                  * buffer, not including terminating NULL  
                                  * character. */  
 {  
     TextItem *textPtr = (TextItem *) itemPtr;  
     int byteCount;  
     char *text, *selStart, *selEnd;  
     Tk_CanvasTextInfo *textInfoPtr = textPtr->textInfoPtr;  
   
     if ((textInfoPtr->selectFirst < 0) ||  
             (textInfoPtr->selectFirst > textInfoPtr->selectLast)) {  
         return 0;  
     }  
     text = textPtr->text;  
     selStart = Tcl_UtfAtIndex(text, textInfoPtr->selectFirst);  
     selEnd = Tcl_UtfAtIndex(selStart,  
             textInfoPtr->selectLast + 1 - textInfoPtr->selectFirst);  
     byteCount = selEnd - selStart - offset;  
     if (byteCount > maxBytes) {  
         byteCount = maxBytes;  
     }  
     if (byteCount <= 0) {  
         return 0;  
     }  
     memcpy(buffer, selStart + offset, (size_t) byteCount);  
     buffer[byteCount] = '\0';  
     return byteCount;  
 }  
   
 /*  
  *--------------------------------------------------------------  
  *  
  * TextToPostscript --  
  *  
  *      This procedure is called to generate Postscript for  
  *      text items.  
  *  
  * Results:  
  *      The return value is a standard Tcl result.  If an error  
  *      occurs in generating Postscript then an error message is  
  *      left in the interp's result, replacing whatever used  
  *      to be there.  If no error occurs, then Postscript for the  
  *      item is appended to the result.  
  *  
  * Side effects:  
  *      None.  
  *  
  *--------------------------------------------------------------  
  */  
   
 static int  
 TextToPostscript(interp, canvas, itemPtr, prepass)  
     Tcl_Interp *interp;         /* Leave Postscript or error message here. */  
     Tk_Canvas canvas;           /* Information about overall canvas. */  
     Tk_Item *itemPtr;           /* Item for which Postscript is wanted. */  
     int prepass;                /* 1 means this is a prepass to collect  
                                  * font information; 0 means final Postscript  
                                  * is being created. */  
 {  
     TextItem *textPtr = (TextItem *) itemPtr;  
     int x, y;  
     Tk_FontMetrics fm;  
     char *justify;  
     char buffer[500];  
     XColor *color;  
     Pixmap stipple;  
     Tk_State state = itemPtr->state;  
   
     if(state == TK_STATE_NULL) {  
         state = ((TkCanvas *)canvas)->canvas_state;  
     }  
     color = textPtr->color;  
     stipple = textPtr->stipple;  
     if (state == TK_STATE_HIDDEN || textPtr->color == NULL ||  
             textPtr->text == NULL || *textPtr->text == 0) {  
         return TCL_OK;  
     } else if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) {  
         if (textPtr->activeColor!=NULL) {  
             color = textPtr->activeColor;  
         }  
         if (textPtr->activeStipple!=None) {  
             stipple = textPtr->activeStipple;  
         }  
     } else if (state==TK_STATE_DISABLED) {  
         if (textPtr->disabledColor!=NULL) {  
             color = textPtr->disabledColor;  
         }  
         if (textPtr->disabledStipple!=None) {  
             stipple = textPtr->disabledStipple;  
         }  
     }  
   
     if (Tk_CanvasPsFont(interp, canvas, textPtr->tkfont) != TCL_OK) {  
         return TCL_ERROR;  
     }  
     if (prepass != 0) {  
         return TCL_OK;  
     }  
     if (Tk_CanvasPsColor(interp, canvas, color) != TCL_OK) {  
         return TCL_ERROR;  
     }  
     if (stipple != None) {  
         Tcl_AppendResult(interp, "/StippleText {\n    ",  
                 (char *) NULL);  
         Tk_CanvasPsStipple(interp, canvas, stipple);  
         Tcl_AppendResult(interp, "} bind def\n", (char *) NULL);  
     }  
   
     sprintf(buffer, "%.15g %.15g [\n", textPtr->x,  
             Tk_CanvasPsY(canvas, textPtr->y));  
     Tcl_AppendResult(interp, buffer, (char *) NULL);  
   
     Tk_TextLayoutToPostscript(interp, textPtr->textLayout);  
   
     x = 0;  y = 0;  justify = NULL;     /* lint. */  
     switch (textPtr->anchor) {  
         case TK_ANCHOR_NW:      x = 0; y = 0;   break;  
         case TK_ANCHOR_N:       x = 1; y = 0;   break;  
         case TK_ANCHOR_NE:      x = 2; y = 0;   break;  
         case TK_ANCHOR_E:       x = 2; y = 1;   break;  
         case TK_ANCHOR_SE:      x = 2; y = 2;   break;  
         case TK_ANCHOR_S:       x = 1; y = 2;   break;  
         case TK_ANCHOR_SW:      x = 0; y = 2;   break;  
         case TK_ANCHOR_W:       x = 0; y = 1;   break;  
         case TK_ANCHOR_CENTER:  x = 1; y = 1;   break;  
     }  
     switch (textPtr->justify) {  
         case TK_JUSTIFY_LEFT:   justify = "0";  break;  
         case TK_JUSTIFY_CENTER: justify = "0.5";break;  
         case TK_JUSTIFY_RIGHT:  justify = "1";  break;  
     }  
   
     Tk_GetFontMetrics(textPtr->tkfont, &fm);  
     sprintf(buffer, "] %d %g %g %s %s DrawText\n",  
             fm.linespace, x / -2.0, y / 2.0, justify,  
             ((stipple == None) ? "false" : "true"));  
     Tcl_AppendResult(interp, buffer, (char *) NULL);  
   
     return TCL_OK;  
 }  
   
   
 /* $History: tkCanvText.c $  
  *  
  * *****************  Version 1  *****************  
  * User: Dtashley     Date: 1/02/01    Time: 2:42a  
  * Created in $/IjuScripter, IjuConsole/Source/Tk Base  
  * Initial check-in.  
  */  
   
 /* End of TKCANVTEXT.C */  
1    /* $Header$ */
2    
3    /*
4     * tkCanvText.c --
5     *
6     *      This file implements text items for canvas widgets.
7     *
8     * Copyright (c) 1991-1994 The Regents of the University of California.
9     * Copyright (c) 1994-1997 Sun Microsystems, Inc.
10     *
11     * See the file "license.terms" for information on usage and redistribution
12     * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
13     *
14     * RCS: @(#) $Id: tkcanvtext.c,v 1.1.1.1 2001/06/13 04:57:44 dtashley Exp $
15     */
16    
17    #include <stdio.h>
18    #include "tkInt.h"
19    #include "tkCanvas.h"
20    #include "tkPort.h"
21    #include "default.h"
22    
23    /*
24     * The structure below defines the record for each text item.
25     */
26    
27    typedef struct TextItem  {
28        Tk_Item header;             /* Generic stuff that's the same for all
29                                     * types.  MUST BE FIRST IN STRUCTURE. */
30        Tk_CanvasTextInfo *textInfoPtr;
31                                    /* Pointer to a structure containing
32                                     * information about the selection and
33                                     * insertion cursor.  The structure is owned
34                                     * by (and shared with) the generic canvas
35                                     * code. */
36        /*
37         * Fields that are set by widget commands other than "configure".
38         */
39        
40        double x, y;                /* Positioning point for text. */
41        int insertPos;              /* Character index of character just before
42                                     * which the insertion cursor is displayed. */
43    
44        /*
45         * Configuration settings that are updated by Tk_ConfigureWidget.
46         */
47    
48        Tk_Anchor anchor;           /* Where to anchor text relative to (x,y). */
49        Tk_TSOffset tsoffset;
50        XColor *color;              /* Color for text. */
51        XColor *activeColor;        /* Color for text. */
52        XColor *disabledColor;      /* Color for text. */
53        Tk_Font tkfont;             /* Font for drawing text. */
54        Tk_Justify justify;         /* Justification mode for text. */
55        Pixmap stipple;             /* Stipple bitmap for text, or None. */
56        Pixmap activeStipple;       /* Stipple bitmap for text, or None. */
57        Pixmap disabledStipple;     /* Stipple bitmap for text, or None. */
58        char *text;                 /* Text for item (malloc-ed). */
59        int width;                  /* Width of lines for word-wrap, pixels.
60                                     * Zero means no word-wrap. */
61    
62        /*
63         * Fields whose values are derived from the current values of the
64         * configuration settings above.
65         */
66    
67        int numChars;               /* Length of text in characters. */
68        int numBytes;               /* Length of text in bytes. */
69        Tk_TextLayout textLayout;   /* Cached text layout information. */
70        int leftEdge;               /* Pixel location of the left edge of the
71                                     * text item; where the left border of the
72                                     * text layout is drawn. */
73        int rightEdge;              /* Pixel just to right of right edge of
74                                     * area of text item.  Used for selecting up
75                                     * to end of line. */
76        GC gc;                      /* Graphics context for drawing text. */
77        GC selTextGC;               /* Graphics context for selected text. */
78        GC cursorOffGC;             /* If not None, this gives a graphics context
79                                     * to use to draw the insertion cursor when
80                                     * it's off.  Used if the selection and
81                                     * insertion cursor colors are the same.  */
82    } TextItem;
83    
84    /*
85     * Information used for parsing configuration specs:
86     */
87    
88    static Tk_CustomOption stateOption = {
89        (Tk_OptionParseProc *) TkStateParseProc,
90        TkStatePrintProc, (ClientData) 2
91    };
92    static Tk_CustomOption tagsOption = {
93        (Tk_OptionParseProc *) Tk_CanvasTagsParseProc,
94        Tk_CanvasTagsPrintProc, (ClientData) NULL
95    };
96    static Tk_CustomOption offsetOption = {
97        (Tk_OptionParseProc *) TkOffsetParseProc,
98        TkOffsetPrintProc, (ClientData) (TK_OFFSET_RELATIVE)
99    };
100    
101    static Tk_ConfigSpec configSpecs[] = {
102        {TK_CONFIG_COLOR, "-activefill", (char *) NULL, (char *) NULL,
103            (char *) NULL, Tk_Offset(TextItem, activeColor), TK_CONFIG_NULL_OK},
104        {TK_CONFIG_BITMAP, "-activestipple", (char *) NULL, (char *) NULL,
105            (char *) NULL, Tk_Offset(TextItem, activeStipple), TK_CONFIG_NULL_OK},
106        {TK_CONFIG_ANCHOR, "-anchor", (char *) NULL, (char *) NULL,
107            "center", Tk_Offset(TextItem, anchor),
108            TK_CONFIG_DONT_SET_DEFAULT},
109        {TK_CONFIG_COLOR, "-disabledfill", (char *) NULL, (char *) NULL,
110            (char *) NULL, Tk_Offset(TextItem, disabledColor), TK_CONFIG_NULL_OK},
111        {TK_CONFIG_BITMAP, "-disabledstipple", (char *) NULL, (char *) NULL,
112            (char *) NULL, Tk_Offset(TextItem, disabledStipple), TK_CONFIG_NULL_OK},
113        {TK_CONFIG_COLOR, "-fill", (char *) NULL, (char *) NULL,
114            "black", Tk_Offset(TextItem, color), TK_CONFIG_NULL_OK},
115        {TK_CONFIG_FONT, "-font", (char *) NULL, (char *) NULL,
116            DEF_CANVTEXT_FONT, Tk_Offset(TextItem, tkfont), 0},
117        {TK_CONFIG_JUSTIFY, "-justify", (char *) NULL, (char *) NULL,
118            "left", Tk_Offset(TextItem, justify),
119            TK_CONFIG_DONT_SET_DEFAULT},
120        {TK_CONFIG_CUSTOM, "-offset", (char *) NULL, (char *) NULL,
121            "0,0", Tk_Offset(TextItem, tsoffset),
122            TK_CONFIG_DONT_SET_DEFAULT, &offsetOption},
123        {TK_CONFIG_CUSTOM, "-state", (char *) NULL, (char *) NULL,
124            (char *) NULL, Tk_Offset(Tk_Item, state), TK_CONFIG_NULL_OK,
125            &stateOption},
126        {TK_CONFIG_BITMAP, "-stipple", (char *) NULL, (char *) NULL,
127            (char *) NULL, Tk_Offset(TextItem, stipple), TK_CONFIG_NULL_OK},
128        {TK_CONFIG_CUSTOM, "-tags", (char *) NULL, (char *) NULL,
129            (char *) NULL, 0, TK_CONFIG_NULL_OK, &tagsOption},
130        {TK_CONFIG_STRING, "-text", (char *) NULL, (char *) NULL,
131            "", Tk_Offset(TextItem, text), 0},
132        {TK_CONFIG_PIXELS, "-width", (char *) NULL, (char *) NULL,
133            "0", Tk_Offset(TextItem, width), TK_CONFIG_DONT_SET_DEFAULT},
134        {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
135            (char *) NULL, 0, 0}
136    };
137    
138    /*
139     * Prototypes for procedures defined in this file:
140     */
141    
142    static void             ComputeTextBbox _ANSI_ARGS_((Tk_Canvas canvas,
143                                TextItem *textPtr));
144    static int              ConfigureText _ANSI_ARGS_((Tcl_Interp *interp,
145                                Tk_Canvas canvas, Tk_Item *itemPtr, int argc,
146                                Tcl_Obj *CONST argv[], int flags));
147    static int              CreateText _ANSI_ARGS_((Tcl_Interp *interp,
148                                Tk_Canvas canvas, struct Tk_Item *itemPtr,
149                                int argc, Tcl_Obj *CONST argv[]));
150    static void             DeleteText _ANSI_ARGS_((Tk_Canvas canvas,
151                                Tk_Item *itemPtr, Display *display));
152    static void             DisplayCanvText _ANSI_ARGS_((Tk_Canvas canvas,
153                                Tk_Item *itemPtr, Display *display, Drawable dst,
154                                int x, int y, int width, int height));
155    static int              GetSelText _ANSI_ARGS_((Tk_Canvas canvas,
156                                Tk_Item *itemPtr, int offset, char *buffer,
157                                int maxBytes));
158    static int              GetTextIndex _ANSI_ARGS_((Tcl_Interp *interp,
159                                Tk_Canvas canvas, Tk_Item *itemPtr,
160                                Tcl_Obj *obj, int *indexPtr));
161    static void             ScaleText _ANSI_ARGS_((Tk_Canvas canvas,
162                                Tk_Item *itemPtr, double originX, double originY,
163                                double scaleX, double scaleY));
164    static void             SetTextCursor _ANSI_ARGS_((Tk_Canvas canvas,
165                                Tk_Item *itemPtr, int index));
166    static int              TextCoords _ANSI_ARGS_((Tcl_Interp *interp,
167                                Tk_Canvas canvas, Tk_Item *itemPtr,
168                                int argc, Tcl_Obj *CONST argv[]));
169    static void             TextDeleteChars _ANSI_ARGS_((Tk_Canvas canvas,
170                                Tk_Item *itemPtr, int first, int last));
171    static void             TextInsert _ANSI_ARGS_((Tk_Canvas canvas,
172                                Tk_Item *itemPtr, int beforeThis, char *string));
173    static int              TextToArea _ANSI_ARGS_((Tk_Canvas canvas,
174                                Tk_Item *itemPtr, double *rectPtr));
175    static double           TextToPoint _ANSI_ARGS_((Tk_Canvas canvas,
176                                Tk_Item *itemPtr, double *pointPtr));
177    static int              TextToPostscript _ANSI_ARGS_((Tcl_Interp *interp,
178                                Tk_Canvas canvas, Tk_Item *itemPtr, int prepass));
179    static void             TranslateText _ANSI_ARGS_((Tk_Canvas canvas,
180                                Tk_Item *itemPtr, double deltaX, double deltaY));
181    
182    /*
183     * The structures below defines the rectangle and oval item types
184     * by means of procedures that can be invoked by generic item code.
185     */
186    
187    Tk_ItemType tkTextType = {
188        "text",                     /* name */
189        sizeof(TextItem),           /* itemSize */
190        CreateText,                 /* createProc */
191        configSpecs,                /* configSpecs */
192        ConfigureText,              /* configureProc */
193        TextCoords,                 /* coordProc */
194        DeleteText,                 /* deleteProc */
195        DisplayCanvText,            /* displayProc */
196        TK_CONFIG_OBJS,             /* flags */
197        TextToPoint,                /* pointProc */
198        TextToArea,                 /* areaProc */
199        TextToPostscript,           /* postscriptProc */
200        ScaleText,                  /* scaleProc */
201        TranslateText,              /* translateProc */
202        (Tk_ItemIndexProc *) GetTextIndex,/* indexProc */
203        SetTextCursor,              /* icursorProc */
204        GetSelText,                 /* selectionProc */
205        TextInsert,                 /* insertProc */
206        TextDeleteChars,            /* dTextProc */
207        (Tk_ItemType *) NULL,       /* nextPtr */
208    };
209    
210    /*
211     *--------------------------------------------------------------
212     *
213     * CreateText --
214     *
215     *      This procedure is invoked to create a new text item
216     *      in a canvas.
217     *
218     * Results:
219     *      A standard Tcl return value.  If an error occurred in
220     *      creating the item then an error message is left in
221     *      the interp's result;  in this case itemPtr is left uninitialized
222     *      so it can be safely freed by the caller.
223     *
224     * Side effects:
225     *      A new text item is created.
226     *
227     *--------------------------------------------------------------
228     */
229    
230    static int
231    CreateText(interp, canvas, itemPtr, argc, argv)
232        Tcl_Interp *interp;         /* Interpreter for error reporting. */
233        Tk_Canvas canvas;           /* Canvas to hold new item. */
234        Tk_Item *itemPtr;           /* Record to hold new item; header has been
235                                     * initialized by caller. */
236        int argc;                   /* Number of arguments in argv. */
237        Tcl_Obj *CONST argv[];      /* Arguments describing rectangle. */
238    {
239        TextItem *textPtr = (TextItem *) itemPtr;
240        int i;
241    
242        if (argc==1) {
243            i = 1;
244        } else {
245            char *arg = Tcl_GetStringFromObj(argv[1], NULL);
246            if ((argc>1) && (arg[0] == '-')
247                    && (arg[1] >= 'a') && (arg[1] <= 'z')) {
248                i = 1;
249            } else {
250                i = 2;
251            }
252        }
253    
254        if (argc < i) {
255            Tcl_AppendResult(interp, "wrong # args: should be \"",
256                    Tk_PathName(Tk_CanvasTkwin(canvas)), " create ",
257                    itemPtr->typePtr->name, " x y ?options?\"", (char *) NULL);
258            return TCL_ERROR;
259        }
260    
261        /*
262         * Carry out initialization that is needed in order to clean up after
263         * errors during the the remainder of this procedure.
264         */
265    
266        textPtr->textInfoPtr = Tk_CanvasGetTextInfo(canvas);
267    
268        textPtr->insertPos  = 0;
269    
270        textPtr->anchor     = TK_ANCHOR_CENTER;
271        textPtr->tsoffset.flags = 0;
272        textPtr->tsoffset.xoffset = 0;
273        textPtr->tsoffset.yoffset = 0;
274        textPtr->color      = NULL;
275        textPtr->activeColor = NULL;
276        textPtr->disabledColor = NULL;
277        textPtr->tkfont     = NULL;
278        textPtr->justify    = TK_JUSTIFY_LEFT;
279        textPtr->stipple    = None;
280        textPtr->activeStipple = None;
281        textPtr->disabledStipple = None;
282        textPtr->text       = NULL;
283        textPtr->width      = 0;
284    
285        textPtr->numChars   = 0;
286        textPtr->numBytes   = 0;
287        textPtr->textLayout = NULL;
288        textPtr->leftEdge   = 0;
289        textPtr->rightEdge  = 0;
290        textPtr->gc         = None;
291        textPtr->selTextGC  = None;
292        textPtr->cursorOffGC = None;
293    
294        /*
295         * Process the arguments to fill in the item record.
296         */
297    
298        if ((TextCoords(interp, canvas, itemPtr, i, argv) != TCL_OK)) {
299            goto error;
300        }
301        if (ConfigureText(interp, canvas, itemPtr, argc-i, argv+i, 0) == TCL_OK) {
302            return TCL_OK;
303        }
304    
305        error:
306        DeleteText(canvas, itemPtr, Tk_Display(Tk_CanvasTkwin(canvas)));
307        return TCL_ERROR;
308    }
309    
310    /*
311     *--------------------------------------------------------------
312     *
313     * TextCoords --
314     *
315     *      This procedure is invoked to process the "coords" widget
316     *      command on text items.  See the user documentation for
317     *      details on what it does.
318     *
319     * Results:
320     *      Returns TCL_OK or TCL_ERROR, and sets the interp's result.
321     *
322     * Side effects:
323     *      The coordinates for the given item may be changed.
324     *
325     *--------------------------------------------------------------
326     */
327    
328    static int
329    TextCoords(interp, canvas, itemPtr, argc, argv)
330        Tcl_Interp *interp;         /* Used for error reporting. */
331        Tk_Canvas canvas;           /* Canvas containing item. */
332        Tk_Item *itemPtr;           /* Item whose coordinates are to be read or
333                                     * modified. */
334        int argc;                   /* Number of coordinates supplied in argv. */
335        Tcl_Obj *CONST argv[];      /* Array of coordinates: x1, y1, x2, y2, ... */
336    {
337        TextItem *textPtr = (TextItem *) itemPtr;
338    
339        if (argc == 0) {
340            Tcl_Obj *obj = Tcl_NewObj();
341            Tcl_Obj *subobj = Tcl_NewDoubleObj(textPtr->x);
342            Tcl_ListObjAppendElement(interp, obj, subobj);
343            subobj = Tcl_NewDoubleObj(textPtr->y);
344            Tcl_ListObjAppendElement(interp, obj, subobj);
345            Tcl_SetObjResult(interp, obj);
346        } else if (argc < 3) {
347            if (argc==1) {
348                if (Tcl_ListObjGetElements(interp, argv[0], &argc,
349                        (Tcl_Obj ***) &argv) != TCL_OK) {
350                    return TCL_ERROR;
351                } else if (argc != 2) {
352                    char buf[64 + TCL_INTEGER_SPACE];
353    
354                    sprintf(buf, "wrong # coordinates: expected 2, got %d", argc);
355                    Tcl_SetResult(interp, buf, TCL_VOLATILE);
356                    return TCL_ERROR;
357                }
358            }
359            if ((Tk_CanvasGetCoordFromObj(interp, canvas, argv[0], &textPtr->x) != TCL_OK)
360                    || (Tk_CanvasGetCoordFromObj(interp, canvas, argv[1],
361                        &textPtr->y) != TCL_OK)) {
362                return TCL_ERROR;
363            }
364            ComputeTextBbox(canvas, textPtr);
365        } else {
366            char buf[64 + TCL_INTEGER_SPACE];
367            
368            sprintf(buf, "wrong # coordinates: expected 0 or 2, got %d", argc);
369            Tcl_SetResult(interp, buf, TCL_VOLATILE);
370            return TCL_ERROR;
371        }
372        return TCL_OK;
373    }
374    
375    /*
376     *--------------------------------------------------------------
377     *
378     * ConfigureText --
379     *
380     *      This procedure is invoked to configure various aspects
381     *      of a text item, such as its border and background colors.
382     *
383     * Results:
384     *      A standard Tcl result code.  If an error occurs, then
385     *      an error message is left in the interp's result.
386     *
387     * Side effects:
388     *      Configuration information, such as colors and stipple
389     *      patterns, may be set for itemPtr.
390     *
391     *--------------------------------------------------------------
392     */
393    
394    static int
395    ConfigureText(interp, canvas, itemPtr, argc, argv, flags)
396        Tcl_Interp *interp;         /* Interpreter for error reporting. */
397        Tk_Canvas canvas;           /* Canvas containing itemPtr. */
398        Tk_Item *itemPtr;           /* Rectangle item to reconfigure. */
399        int argc;                   /* Number of elements in argv.  */
400        Tcl_Obj *CONST argv[];      /* Arguments describing things to configure. */
401        int flags;                  /* Flags to pass to Tk_ConfigureWidget. */
402    {
403        TextItem *textPtr = (TextItem *) itemPtr;
404        XGCValues gcValues;
405        GC newGC, newSelGC;
406        unsigned long mask;
407        Tk_Window tkwin;
408        Tk_CanvasTextInfo *textInfoPtr = textPtr->textInfoPtr;
409        XColor *selBgColorPtr;
410        XColor *color;
411        Pixmap stipple;
412        Tk_State state;
413    
414        tkwin = Tk_CanvasTkwin(canvas);
415        if (Tk_ConfigureWidget(interp, tkwin, configSpecs, argc, (char **) argv,
416                (char *) textPtr, flags|TK_CONFIG_OBJS) != TCL_OK) {
417            return TCL_ERROR;
418        }
419    
420        /*
421         * A few of the options require additional processing, such as
422         * graphics contexts.
423         */
424    
425        state = itemPtr->state;
426    
427        if (textPtr->activeColor != NULL ||
428                textPtr->activeStipple != None) {
429            itemPtr->redraw_flags |= TK_ITEM_STATE_DEPENDANT;
430        } else {
431            itemPtr->redraw_flags &= ~TK_ITEM_STATE_DEPENDANT;
432        }
433    
434        if(state == TK_STATE_NULL) {
435            state = ((TkCanvas *)canvas)->canvas_state;
436        }
437    
438        color = textPtr->color;
439        stipple = textPtr->stipple;
440        if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) {
441            if (textPtr->activeColor!=NULL) {
442                color = textPtr->activeColor;
443            }
444            if (textPtr->activeStipple!=None) {
445                stipple = textPtr->activeStipple;
446            }
447        } else if (state==TK_STATE_DISABLED) {
448            if (textPtr->disabledColor!=NULL) {
449                color = textPtr->disabledColor;
450            }
451            if (textPtr->disabledStipple!=None) {
452                stipple = textPtr->disabledStipple;
453            }
454        }
455    
456        newGC = newSelGC = None;
457        if (textPtr->tkfont != NULL) {
458            gcValues.font = Tk_FontId(textPtr->tkfont);
459            mask = GCFont;
460            if (color != NULL) {
461                gcValues.foreground = color->pixel;
462                mask |= GCForeground;
463                if (stipple != None) {
464                    gcValues.stipple = stipple;
465                    gcValues.fill_style = FillStippled;
466                    mask |= GCStipple|GCFillStyle;
467                }
468                newGC = Tk_GetGC(tkwin, mask, &gcValues);
469            }
470            mask &= ~(GCTile|GCFillStyle|GCStipple);
471            if (stipple != None) {
472                gcValues.stipple = stipple;
473                gcValues.fill_style = FillStippled;
474                mask |= GCStipple|GCFillStyle;
475            }
476            gcValues.foreground = textInfoPtr->selFgColorPtr->pixel;
477            newSelGC = Tk_GetGC(tkwin, mask|GCForeground, &gcValues);
478        }
479        if (textPtr->gc != None) {
480            Tk_FreeGC(Tk_Display(tkwin), textPtr->gc);
481        }
482        textPtr->gc = newGC;
483        if (textPtr->selTextGC != None) {
484            Tk_FreeGC(Tk_Display(tkwin), textPtr->selTextGC);
485        }
486        textPtr->selTextGC = newSelGC;
487    
488        selBgColorPtr = Tk_3DBorderColor(textInfoPtr->selBorder);
489        if (Tk_3DBorderColor(textInfoPtr->insertBorder)->pixel
490                == selBgColorPtr->pixel) {
491            if (selBgColorPtr->pixel == BlackPixelOfScreen(Tk_Screen(tkwin))) {
492                gcValues.foreground = WhitePixelOfScreen(Tk_Screen(tkwin));
493            } else {
494                gcValues.foreground = BlackPixelOfScreen(Tk_Screen(tkwin));
495            }
496            newGC = Tk_GetGC(tkwin, GCForeground, &gcValues);
497        } else {
498            newGC = None;
499        }
500        if (textPtr->cursorOffGC != None) {
501            Tk_FreeGC(Tk_Display(tkwin), textPtr->cursorOffGC);
502        }
503        textPtr->cursorOffGC = newGC;
504    
505    
506        /*
507         * If the text was changed, move the selection and insertion indices
508         * to keep them inside the item.
509         */
510    
511        textPtr->numBytes = strlen(textPtr->text);
512        textPtr->numChars = Tcl_NumUtfChars(textPtr->text, textPtr->numBytes);
513        if (textInfoPtr->selItemPtr == itemPtr) {
514            
515            if (textInfoPtr->selectFirst >= textPtr->numChars) {
516                textInfoPtr->selItemPtr = NULL;
517            } else {
518                if (textInfoPtr->selectLast >= textPtr->numChars) {
519                    textInfoPtr->selectLast = textPtr->numChars - 1;
520                }
521                if ((textInfoPtr->anchorItemPtr == itemPtr)
522                        && (textInfoPtr->selectAnchor >= textPtr->numChars)) {
523                    textInfoPtr->selectAnchor = textPtr->numChars - 1;
524                }
525            }
526        }
527        if (textPtr->insertPos >= textPtr->numChars) {
528            textPtr->insertPos = textPtr->numChars;
529        }
530    
531        ComputeTextBbox(canvas, textPtr);
532        return TCL_OK;
533    }
534    
535    /*
536     *--------------------------------------------------------------
537     *
538     * DeleteText --
539     *
540     *      This procedure is called to clean up the data structure
541     *      associated with a text item.
542     *
543     * Results:
544     *      None.
545     *
546     * Side effects:
547     *      Resources associated with itemPtr are released.
548     *
549     *--------------------------------------------------------------
550     */
551    
552    static void
553    DeleteText(canvas, itemPtr, display)
554        Tk_Canvas canvas;           /* Info about overall canvas widget. */
555        Tk_Item *itemPtr;           /* Item that is being deleted. */
556        Display *display;           /* Display containing window for canvas. */
557    {
558        TextItem *textPtr = (TextItem *) itemPtr;
559    
560        if (textPtr->color != NULL) {
561            Tk_FreeColor(textPtr->color);
562        }
563        if (textPtr->activeColor != NULL) {
564            Tk_FreeColor(textPtr->activeColor);
565        }
566        if (textPtr->disabledColor != NULL) {
567            Tk_FreeColor(textPtr->disabledColor);
568        }
569        Tk_FreeFont(textPtr->tkfont);
570        if (textPtr->stipple != None) {
571            Tk_FreeBitmap(display, textPtr->stipple);
572        }
573        if (textPtr->activeStipple != None) {
574            Tk_FreeBitmap(display, textPtr->activeStipple);
575        }
576        if (textPtr->disabledStipple != None) {
577            Tk_FreeBitmap(display, textPtr->disabledStipple);
578        }
579        if (textPtr->text != NULL) {
580            ckfree(textPtr->text);
581        }
582    
583        Tk_FreeTextLayout(textPtr->textLayout);
584        if (textPtr->gc != None) {
585            Tk_FreeGC(display, textPtr->gc);
586        }
587        if (textPtr->selTextGC != None) {
588            Tk_FreeGC(display, textPtr->selTextGC);
589        }
590        if (textPtr->cursorOffGC != None) {
591            Tk_FreeGC(display, textPtr->cursorOffGC);
592        }
593    }
594    
595    /*
596     *--------------------------------------------------------------
597     *
598     * ComputeTextBbox --
599     *
600     *      This procedure is invoked to compute the bounding box of
601     *      all the pixels that may be drawn as part of a text item.
602     *      In addition, it recomputes all of the geometry information
603     *      used to display a text item or check for mouse hits.
604     *
605     * Results:
606     *      None.
607     *
608     * Side effects:
609     *      The fields x1, y1, x2, and y2 are updated in the header
610     *      for itemPtr, and the linePtr structure is regenerated
611     *      for itemPtr.
612     *
613     *--------------------------------------------------------------
614     */
615    
616    static void
617    ComputeTextBbox(canvas, textPtr)
618        Tk_Canvas canvas;           /* Canvas that contains item. */
619        TextItem *textPtr;          /* Item whose bbox is to be recomputed. */
620    {
621        Tk_CanvasTextInfo *textInfoPtr;
622        int leftX, topY, width, height, fudge;
623        Tk_State state = textPtr->header.state;
624    
625        if(state == TK_STATE_NULL) {
626            state = ((TkCanvas *)canvas)->canvas_state;
627        }
628    
629        Tk_FreeTextLayout(textPtr->textLayout);
630        textPtr->textLayout = Tk_ComputeTextLayout(textPtr->tkfont,
631                textPtr->text, textPtr->numChars, textPtr->width,
632                textPtr->justify, 0, &width, &height);
633    
634        if (state == TK_STATE_HIDDEN || textPtr->color == NULL) {
635            width = height = 0;
636        }
637    
638        /*
639         * Use overall geometry information to compute the top-left corner
640         * of the bounding box for the text item.
641         */
642    
643        leftX = (int) (textPtr->x + 0.5);
644        topY = (int) (textPtr->y + 0.5);
645        switch (textPtr->anchor) {
646            case TK_ANCHOR_NW:
647            case TK_ANCHOR_N:
648            case TK_ANCHOR_NE:
649                break;
650    
651            case TK_ANCHOR_W:
652            case TK_ANCHOR_CENTER:
653            case TK_ANCHOR_E:
654                topY -= height / 2;
655                break;
656    
657            case TK_ANCHOR_SW:
658            case TK_ANCHOR_S:
659            case TK_ANCHOR_SE:
660                topY -= height;
661                break;
662        }
663        switch (textPtr->anchor) {
664            case TK_ANCHOR_NW:
665            case TK_ANCHOR_W:
666            case TK_ANCHOR_SW:
667                break;
668    
669            case TK_ANCHOR_N:
670            case TK_ANCHOR_CENTER:
671            case TK_ANCHOR_S:
672                leftX -= width / 2;
673                break;
674    
675            case TK_ANCHOR_NE:
676            case TK_ANCHOR_E:
677            case TK_ANCHOR_SE:
678                leftX -= width;
679                break;
680        }
681    
682        textPtr->leftEdge  = leftX;
683        textPtr->rightEdge = leftX + width;
684    
685        /*
686         * Last of all, update the bounding box for the item.  The item's
687         * bounding box includes the bounding box of all its lines, plus
688         * an extra fudge factor for the cursor border (which could
689         * potentially be quite large).
690         */
691    
692        textInfoPtr = textPtr->textInfoPtr;
693        fudge = (textInfoPtr->insertWidth + 1) / 2;
694        if (textInfoPtr->selBorderWidth > fudge) {
695            fudge = textInfoPtr->selBorderWidth;
696        }
697        textPtr->header.x1 = leftX - fudge;
698        textPtr->header.y1 = topY;
699        textPtr->header.x2 = leftX + width + fudge;
700        textPtr->header.y2 = topY + height;
701    }
702    
703    /*
704     *--------------------------------------------------------------
705     *
706     * DisplayCanvText --
707     *
708     *      This procedure is invoked to draw a text item in a given
709     *      drawable.
710     *
711     * Results:
712     *      None.
713     *
714     * Side effects:
715     *      ItemPtr is drawn in drawable using the transformation
716     *      information in canvas.
717     *
718     *--------------------------------------------------------------
719     */
720    
721    static void
722    DisplayCanvText(canvas, itemPtr, display, drawable, x, y, width, height)
723        Tk_Canvas canvas;           /* Canvas that contains item. */
724        Tk_Item *itemPtr;           /* Item to be displayed. */
725        Display *display;           /* Display on which to draw item. */
726        Drawable drawable;          /* Pixmap or window in which to draw item. */
727        int x, y, width, height;    /* Describes region of canvas that must be
728                                     * redisplayed (not used). */
729    {
730        TextItem *textPtr;
731        Tk_CanvasTextInfo *textInfoPtr;
732        int selFirstChar, selLastChar;
733        short drawableX, drawableY;
734        Pixmap stipple;
735        Tk_State state = itemPtr->state;
736    
737        textPtr = (TextItem *) itemPtr;
738        textInfoPtr = textPtr->textInfoPtr;
739    
740        if(state == TK_STATE_NULL) {
741            state = ((TkCanvas *)canvas)->canvas_state;
742        }
743        stipple = textPtr->stipple;
744        if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) {
745            if (textPtr->activeStipple!=None) {
746                stipple = textPtr->activeStipple;
747            }
748        } else if (state==TK_STATE_DISABLED) {
749            if (textPtr->disabledStipple!=None) {
750                stipple = textPtr->disabledStipple;
751            }
752        }
753    
754        if (textPtr->gc == None) {
755            return;
756        }
757    
758        /*
759         * If we're stippling, then modify the stipple offset in the GC.  Be
760         * sure to reset the offset when done, since the GC is supposed to be
761         * read-only.
762         */
763    
764        if (stipple != None) {
765            Tk_CanvasSetOffset(canvas, textPtr->gc, &textPtr->tsoffset);
766        }
767    
768        selFirstChar = -1;
769        selLastChar = 0;            /* lint. */
770    
771        if (textInfoPtr->selItemPtr == itemPtr) {
772            selFirstChar = textInfoPtr->selectFirst;
773            selLastChar = textInfoPtr->selectLast;
774            if (selLastChar > textPtr->numChars) {
775                selLastChar = textPtr->numChars - 1;
776            }
777            if ((selFirstChar >= 0) && (selFirstChar <= selLastChar)) {
778                int xFirst, yFirst, hFirst;
779                int xLast, yLast;
780    
781                /*
782                 * Draw a special background under the selection.
783                 */
784    
785                Tk_CharBbox(textPtr->textLayout, selFirstChar, &xFirst, &yFirst,
786                        NULL, &hFirst);
787                Tk_CharBbox(textPtr->textLayout, selLastChar, &xLast, &yLast,
788                        NULL, NULL);
789    
790                /*
791                 * If the selection spans the end of this line, then display
792                 * selection background all the way to the end of the line.
793                 * However, for the last line we only want to display up to the
794                 * last character, not the end of the line.
795                 */
796    
797                x = xFirst;
798                height = hFirst;
799                for (y = yFirst ; y <= yLast; y += height) {
800                    if (y == yLast) {
801                        width = xLast - x;
802                    } else {            
803                        width = textPtr->rightEdge - textPtr->leftEdge - x;
804                    }
805                    Tk_CanvasDrawableCoords(canvas,
806                            (double) (textPtr->leftEdge + x
807                                    - textInfoPtr->selBorderWidth),
808                            (double) (textPtr->header.y1 + y),
809                            &drawableX, &drawableY);
810                    Tk_Fill3DRectangle(Tk_CanvasTkwin(canvas), drawable,
811                            textInfoPtr->selBorder, drawableX, drawableY,
812                            width + 2 * textInfoPtr->selBorderWidth,
813                            height, textInfoPtr->selBorderWidth, TK_RELIEF_RAISED);
814                    x = 0;
815                }
816            }
817        }
818    
819        /*
820         * If the insertion point should be displayed, then draw a special
821         * background for the cursor before drawing the text.  Note:  if
822         * we're the cursor item but the cursor is turned off, then redraw
823         * background over the area of the cursor.  This guarantees that
824         * the selection won't make the cursor invisible on mono displays,
825         * where both are drawn in the same color.
826         */
827    
828        if ((textInfoPtr->focusItemPtr == itemPtr) && (textInfoPtr->gotFocus)) {
829            if (Tk_CharBbox(textPtr->textLayout, textPtr->insertPos,
830                    &x, &y, NULL, &height)) {
831                Tk_CanvasDrawableCoords(canvas,
832                        (double) (textPtr->leftEdge + x
833                                - (textInfoPtr->insertWidth / 2)),
834                        (double) (textPtr->header.y1 + y),
835                        &drawableX, &drawableY);
836                if (textInfoPtr->cursorOn) {
837                    Tk_Fill3DRectangle(Tk_CanvasTkwin(canvas), drawable,
838                            textInfoPtr->insertBorder,
839                            drawableX, drawableY,
840                            textInfoPtr->insertWidth, height,
841                            textInfoPtr->insertBorderWidth, TK_RELIEF_RAISED);
842                } else if (textPtr->cursorOffGC != None) {
843                    /*
844                     * Redraw the background over the area of the cursor,
845                     * even though the cursor is turned off.  This
846                     * guarantees that the selection won't make the cursor
847                     * invisible on mono displays, where both may be drawn
848                     * in the same color.
849                     */
850    
851                    XFillRectangle(display, drawable, textPtr->cursorOffGC,
852                            drawableX, drawableY,
853                            (unsigned) textInfoPtr->insertWidth,
854                            (unsigned) height);
855                }
856            }
857        }
858    
859    
860        /*
861         * Display the text in two pieces: draw the entire text item, then
862         * draw the selected text on top of it.  The selected text then
863         * will only need to be drawn if it has different attributes (such
864         * as foreground color) than regular text.
865         */
866    
867        Tk_CanvasDrawableCoords(canvas, (double) textPtr->leftEdge,
868                (double) textPtr->header.y1, &drawableX, &drawableY);
869        Tk_DrawTextLayout(display, drawable, textPtr->gc, textPtr->textLayout,
870                drawableX, drawableY, 0, -1);
871    
872        if ((selFirstChar >= 0) && (textPtr->selTextGC != textPtr->gc)) {
873            Tk_DrawTextLayout(display, drawable, textPtr->selTextGC,
874                textPtr->textLayout, drawableX, drawableY, selFirstChar,
875                selLastChar + 1);
876        }
877    
878        if (stipple != None) {
879            XSetTSOrigin(display, textPtr->gc, 0, 0);
880        }
881    }
882    
883    /*
884     *--------------------------------------------------------------
885     *
886     * TextInsert --
887     *
888     *      Insert characters into a text item at a given position.
889     *
890     * Results:
891     *      None.
892     *
893     * Side effects:
894     *      The text in the given item is modified.  The cursor and
895     *      selection positions are also modified to reflect the
896     *      insertion.
897     *
898     *--------------------------------------------------------------
899     */
900    
901    static void
902    TextInsert(canvas, itemPtr, index, string)
903        Tk_Canvas canvas;           /* Canvas containing text item. */
904        Tk_Item *itemPtr;           /* Text item to be modified. */
905        int index;                  /* Character index before which string is
906                                     * to be inserted. */
907        char *string;               /* New characters to be inserted. */
908    {
909        TextItem *textPtr = (TextItem *) itemPtr;
910        int byteIndex, byteCount, charsAdded;
911        char *new, *text;
912        Tk_CanvasTextInfo *textInfoPtr = textPtr->textInfoPtr;
913    
914        string = Tcl_GetStringFromObj((Tcl_Obj *) string, &byteCount);
915    
916        text = textPtr->text;
917    
918        if (index < 0) {
919            index = 0;
920        }
921        if (index > textPtr->numChars) {
922            index = textPtr->numChars;
923        }
924        byteIndex = Tcl_UtfAtIndex(text, index) - text;
925        byteCount = strlen(string);
926        if (byteCount == 0) {
927            return;
928        }
929    
930        new = (char *) ckalloc((unsigned) textPtr->numBytes + byteCount + 1);
931        memcpy(new, text, (size_t) byteIndex);
932        strcpy(new + byteIndex, string);
933        strcpy(new + byteIndex + byteCount, text + byteIndex);
934    
935        ckfree(text);
936        textPtr->text = new;
937        charsAdded = Tcl_NumUtfChars(string, byteCount);
938        textPtr->numChars += charsAdded;
939        textPtr->numBytes += byteCount;
940    
941        /*
942         * Inserting characters invalidates indices such as those for the
943         * selection and cursor.  Update the indices appropriately.
944         */
945    
946        if (textInfoPtr->selItemPtr == itemPtr) {
947            if (textInfoPtr->selectFirst >= index) {
948                textInfoPtr->selectFirst += charsAdded;
949            }
950            if (textInfoPtr->selectLast >= index) {
951                textInfoPtr->selectLast += charsAdded;
952            }
953            if ((textInfoPtr->anchorItemPtr == itemPtr)
954                    && (textInfoPtr->selectAnchor >= index)) {
955                textInfoPtr->selectAnchor += charsAdded;
956            }
957        }
958        if (textPtr->insertPos >= index) {
959            textPtr->insertPos += charsAdded;
960        }
961        ComputeTextBbox(canvas, textPtr);
962    }
963    
964    /*
965     *--------------------------------------------------------------
966     *
967     * TextDeleteChars --
968     *
969     *      Delete one or more characters from a text item.
970     *
971     * Results:
972     *      None.
973     *
974     * Side effects:
975     *      Characters between "first" and "last", inclusive, get
976     *      deleted from itemPtr, and things like the selection
977     *      position get updated.
978     *
979     *--------------------------------------------------------------
980     */
981    
982    static void
983    TextDeleteChars(canvas, itemPtr, first, last)
984        Tk_Canvas canvas;           /* Canvas containing itemPtr. */
985        Tk_Item *itemPtr;           /* Item in which to delete characters. */
986        int first;                  /* Character index of first character to
987                                     * delete. */
988        int last;                   /* Character index of last character to
989                                     * delete (inclusive). */
990    {
991        TextItem *textPtr = (TextItem *) itemPtr;
992        int byteIndex, byteCount, charsRemoved;
993        char *new, *text;
994        Tk_CanvasTextInfo *textInfoPtr = textPtr->textInfoPtr;
995    
996        text = textPtr->text;
997        if (first < 0) {
998            first = 0;
999        }
1000        if (last >= textPtr->numChars) {
1001            last = textPtr->numChars - 1;
1002        }
1003        if (first > last) {
1004            return;
1005        }
1006        charsRemoved = last + 1 - first;
1007    
1008        byteIndex = Tcl_UtfAtIndex(text, first) - text;
1009        byteCount = Tcl_UtfAtIndex(text + byteIndex, charsRemoved)
1010            - (text + byteIndex);
1011        
1012        new = (char *) ckalloc((unsigned) (textPtr->numBytes + 1 - byteCount));
1013        memcpy(new, text, (size_t) byteIndex);
1014        strcpy(new + byteIndex, text + byteIndex + byteCount);
1015    
1016        ckfree(text);
1017        textPtr->text = new;
1018        textPtr->numChars -= charsRemoved;
1019        textPtr->numBytes -= byteCount;
1020    
1021        /*
1022         * Update indexes for the selection and cursor to reflect the
1023         * renumbering of the remaining characters.
1024         */
1025    
1026        if (textInfoPtr->selItemPtr == itemPtr) {
1027            if (textInfoPtr->selectFirst > first) {
1028                textInfoPtr->selectFirst -= charsRemoved;
1029                if (textInfoPtr->selectFirst < first) {
1030                    textInfoPtr->selectFirst = first;
1031                }
1032            }
1033            if (textInfoPtr->selectLast >= first) {
1034                textInfoPtr->selectLast -= charsRemoved;
1035                if (textInfoPtr->selectLast < first - 1) {
1036                    textInfoPtr->selectLast = first - 1;
1037                }
1038            }
1039            if (textInfoPtr->selectFirst > textInfoPtr->selectLast) {
1040                textInfoPtr->selItemPtr = NULL;
1041            }
1042            if ((textInfoPtr->anchorItemPtr == itemPtr)
1043                    && (textInfoPtr->selectAnchor > first)) {
1044                textInfoPtr->selectAnchor -= charsRemoved;
1045                if (textInfoPtr->selectAnchor < first) {
1046                    textInfoPtr->selectAnchor = first;
1047                }
1048            }
1049        }
1050        if (textPtr->insertPos > first) {
1051            textPtr->insertPos -= charsRemoved;
1052            if (textPtr->insertPos < first) {
1053                textPtr->insertPos = first;
1054            }
1055        }
1056        ComputeTextBbox(canvas, textPtr);
1057        return;
1058    }
1059    
1060    /*
1061     *--------------------------------------------------------------
1062     *
1063     * TextToPoint --
1064     *
1065     *      Computes the distance from a given point to a given
1066     *      text item, in canvas units.
1067     *
1068     * Results:
1069     *      The return value is 0 if the point whose x and y coordinates
1070     *      are pointPtr[0] and pointPtr[1] is inside the text item.  If
1071     *      the point isn't inside the text item then the return value
1072     *      is the distance from the point to the text item.
1073     *
1074     * Side effects:
1075     *      None.
1076     *
1077     *--------------------------------------------------------------
1078     */
1079    
1080    static double
1081    TextToPoint(canvas, itemPtr, pointPtr)
1082        Tk_Canvas canvas;           /* Canvas containing itemPtr. */
1083        Tk_Item *itemPtr;           /* Item to check against point. */
1084        double *pointPtr;           /* Pointer to x and y coordinates. */
1085    {
1086        TextItem *textPtr;
1087        Tk_State state = itemPtr->state;
1088        double value;
1089    
1090        if (state == TK_STATE_NULL) {
1091            state = ((TkCanvas *)canvas)->canvas_state;
1092        }
1093        textPtr = (TextItem *) itemPtr;
1094        value =  (double) Tk_DistanceToTextLayout(textPtr->textLayout,
1095                (int) pointPtr[0] - textPtr->leftEdge,
1096                (int) pointPtr[1] - textPtr->header.y1);
1097    
1098        if ((state == TK_STATE_HIDDEN) || (textPtr->color == NULL) ||
1099                (textPtr->text == NULL) || (*textPtr->text == 0)) {
1100            value = 1.0e36;
1101        }
1102        return value;
1103    }
1104    
1105    /*
1106     *--------------------------------------------------------------
1107     *
1108     * TextToArea --
1109     *
1110     *      This procedure is called to determine whether an item
1111     *      lies entirely inside, entirely outside, or overlapping
1112     *      a given rectangle.
1113     *
1114     * Results:
1115     *      -1 is returned if the item is entirely outside the area
1116     *      given by rectPtr, 0 if it overlaps, and 1 if it is entirely
1117     *      inside the given area.
1118     *
1119     * Side effects:
1120     *      None.
1121     *
1122     *--------------------------------------------------------------
1123     */
1124    
1125    static int
1126    TextToArea(canvas, itemPtr, rectPtr)
1127        Tk_Canvas canvas;           /* Canvas containing itemPtr. */
1128        Tk_Item *itemPtr;           /* Item to check against rectangle. */
1129        double *rectPtr;            /* Pointer to array of four coordinates
1130                                     * (x1, y1, x2, y2) describing rectangular
1131                                     * area.  */
1132    {
1133        TextItem *textPtr;
1134        Tk_State state = itemPtr->state;
1135    
1136        if (state == TK_STATE_NULL) {
1137            state = ((TkCanvas *)canvas)->canvas_state;
1138        }
1139    
1140        textPtr = (TextItem *) itemPtr;
1141        return Tk_IntersectTextLayout(textPtr->textLayout,
1142                (int) (rectPtr[0] + 0.5) - textPtr->leftEdge,
1143                (int) (rectPtr[1] + 0.5) - textPtr->header.y1,
1144                (int) (rectPtr[2] - rectPtr[0] + 0.5),
1145                (int) (rectPtr[3] - rectPtr[1] + 0.5));
1146    }
1147    
1148    /*
1149     *--------------------------------------------------------------
1150     *
1151     * ScaleText --
1152     *
1153     *      This procedure is invoked to rescale a text item.
1154     *
1155     * Results:
1156     *      None.
1157     *
1158     * Side effects:
1159     *      Scales the position of the text, but not the size
1160     *      of the font for the text.
1161     *
1162     *--------------------------------------------------------------
1163     */
1164    
1165            /* ARGSUSED */
1166    static void
1167    ScaleText(canvas, itemPtr, originX, originY, scaleX, scaleY)
1168        Tk_Canvas canvas;           /* Canvas containing rectangle. */
1169        Tk_Item *itemPtr;           /* Rectangle to be scaled. */
1170        double originX, originY;    /* Origin about which to scale rect. */
1171        double scaleX;              /* Amount to scale in X direction. */
1172        double scaleY;              /* Amount to scale in Y direction. */
1173    {
1174        TextItem *textPtr = (TextItem *) itemPtr;
1175    
1176        textPtr->x = originX + scaleX*(textPtr->x - originX);
1177        textPtr->y = originY + scaleY*(textPtr->y - originY);
1178        ComputeTextBbox(canvas, textPtr);
1179        return;
1180    }
1181    
1182    /*
1183     *--------------------------------------------------------------
1184     *
1185     * TranslateText --
1186     *
1187     *      This procedure is called to move a text item by a
1188     *      given amount.
1189     *
1190     * Results:
1191     *      None.
1192     *
1193     * Side effects:
1194     *      The position of the text item is offset by (xDelta, yDelta),
1195     *      and the bounding box is updated in the generic part of the
1196     *      item structure.
1197     *
1198     *--------------------------------------------------------------
1199     */
1200    
1201    static void
1202    TranslateText(canvas, itemPtr, deltaX, deltaY)
1203        Tk_Canvas canvas;           /* Canvas containing item. */
1204        Tk_Item *itemPtr;           /* Item that is being moved. */
1205        double deltaX, deltaY;      /* Amount by which item is to be moved. */
1206    {
1207        TextItem *textPtr = (TextItem *) itemPtr;
1208    
1209        textPtr->x += deltaX;
1210        textPtr->y += deltaY;
1211        ComputeTextBbox(canvas, textPtr);
1212    }
1213    
1214    /*
1215     *--------------------------------------------------------------
1216     *
1217     * GetTextIndex --
1218     *
1219     *      Parse an index into a text item and return either its value
1220     *      or an error.
1221     *
1222     * Results:
1223     *      A standard Tcl result.  If all went well, then *indexPtr is
1224     *      filled in with the index (into itemPtr) corresponding to
1225     *      string.  Otherwise an error message is left in
1226     *      the interp's result.
1227     *
1228     * Side effects:
1229     *      None.
1230     *
1231     *--------------------------------------------------------------
1232     */
1233    
1234    static int
1235    GetTextIndex(interp, canvas, itemPtr, obj, indexPtr)
1236        Tcl_Interp *interp;         /* Used for error reporting. */
1237        Tk_Canvas canvas;           /* Canvas containing item. */
1238        Tk_Item *itemPtr;           /* Item for which the index is being
1239                                     * specified. */
1240        Tcl_Obj *obj;               /* Specification of a particular character
1241                                     * in itemPtr's text. */
1242        int *indexPtr;              /* Where to store converted character
1243                                     * index. */
1244    {
1245        TextItem *textPtr = (TextItem *) itemPtr;
1246        size_t length;
1247        int c;
1248        TkCanvas *canvasPtr = (TkCanvas *) canvas;
1249        Tk_CanvasTextInfo *textInfoPtr = textPtr->textInfoPtr;
1250        char *string = Tcl_GetStringFromObj(obj, (int *) &length);
1251    
1252        c = string[0];
1253        length = strlen(string);
1254    
1255        if ((c == 'e') && (strncmp(string, "end", length) == 0)) {
1256            *indexPtr = textPtr->numChars;
1257        } else if ((c == 'i') && (strncmp(string, "insert", length) == 0)) {
1258            *indexPtr = textPtr->insertPos;
1259        } else if ((c == 's') && (strncmp(string, "sel.first", length) == 0)
1260                && (length >= 5)) {
1261            if (textInfoPtr->selItemPtr != itemPtr) {
1262                Tcl_SetResult(interp, "selection isn't in item", TCL_STATIC);
1263                return TCL_ERROR;
1264            }
1265            *indexPtr = textInfoPtr->selectFirst;
1266        } else if ((c == 's') && (strncmp(string, "sel.last", length) == 0)
1267                && (length >= 5)) {
1268            if (textInfoPtr->selItemPtr != itemPtr) {
1269                Tcl_SetResult(interp, "selection isn't in item", TCL_STATIC);
1270                return TCL_ERROR;
1271            }
1272            *indexPtr = textInfoPtr->selectLast;
1273        } else if (c == '@') {
1274            int x, y;
1275            double tmp;
1276            char *end, *p;
1277    
1278            p = string+1;
1279            tmp = strtod(p, &end);
1280            if ((end == p) || (*end != ',')) {
1281                goto badIndex;
1282            }
1283            x = (int) ((tmp < 0) ? tmp - 0.5 : tmp + 0.5);
1284            p = end+1;
1285            tmp = strtod(p, &end);
1286            if ((end == p) || (*end != 0)) {
1287                goto badIndex;
1288            }
1289            y = (int) ((tmp < 0) ? tmp - 0.5 : tmp + 0.5);
1290            *indexPtr = Tk_PointToChar(textPtr->textLayout,
1291                    x + canvasPtr->scrollX1 - textPtr->leftEdge,
1292                    y + canvasPtr->scrollY1 - textPtr->header.y1);
1293        } else if (Tcl_GetIntFromObj((Tcl_Interp *)NULL, obj, indexPtr) == TCL_OK) {
1294            if (*indexPtr < 0){
1295                *indexPtr = 0;
1296            } else if (*indexPtr > textPtr->numChars) {
1297                *indexPtr = textPtr->numChars;
1298            }
1299        } else {
1300            /*
1301             * Some of the paths here leave messages in the interp's result,
1302             * so we have to clear it out before storing our own message.
1303             */
1304    
1305            badIndex:
1306            Tcl_SetResult(interp, (char *) NULL, TCL_STATIC);
1307            Tcl_AppendResult(interp, "bad index \"", string, "\"",
1308                    (char *) NULL);
1309            return TCL_ERROR;
1310        }
1311        return TCL_OK;
1312    }
1313    
1314    /*
1315     *--------------------------------------------------------------
1316     *
1317     * SetTextCursor --
1318     *
1319     *      Set the position of the insertion cursor in this item.
1320     *
1321     * Results:
1322     *      None.
1323     *
1324     * Side effects:
1325     *      The cursor position will change.
1326     *
1327     *--------------------------------------------------------------
1328     */
1329    
1330            /* ARGSUSED */
1331    static void
1332    SetTextCursor(canvas, itemPtr, index)
1333        Tk_Canvas canvas;           /* Record describing canvas widget. */
1334        Tk_Item *itemPtr;           /* Text item in which cursor position is to
1335                                     * be set. */
1336        int index;                  /* Character index of character just before
1337                                     * which cursor is to be positioned. */
1338    {
1339        TextItem *textPtr = (TextItem *) itemPtr;
1340    
1341        if (index < 0) {
1342            textPtr->insertPos = 0;
1343        } else  if (index > textPtr->numChars) {
1344            textPtr->insertPos = textPtr->numChars;
1345        } else {
1346            textPtr->insertPos = index;
1347        }
1348    }
1349    
1350    /*
1351     *--------------------------------------------------------------
1352     *
1353     * GetSelText --
1354     *
1355     *      This procedure is invoked to return the selected portion
1356     *      of a text item.  It is only called when this item has
1357     *      the selection.
1358     *
1359     * Results:
1360     *      The return value is the number of non-NULL bytes stored
1361     *      at buffer.  Buffer is filled (or partially filled) with a
1362     *      NULL-terminated string containing part or all of the selection,
1363     *      as given by offset and maxBytes.
1364     *
1365     * Side effects:
1366     *      None.
1367     *
1368     *--------------------------------------------------------------
1369     */
1370    
1371    static int
1372    GetSelText(canvas, itemPtr, offset, buffer, maxBytes)
1373        Tk_Canvas canvas;           /* Canvas containing selection. */
1374        Tk_Item *itemPtr;           /* Text item containing selection. */
1375        int offset;                 /* Byte offset within selection of first
1376                                     * character to be returned. */
1377        char *buffer;               /* Location in which to place selection. */
1378        int maxBytes;               /* Maximum number of bytes to place at
1379                                     * buffer, not including terminating NULL
1380                                     * character. */
1381    {
1382        TextItem *textPtr = (TextItem *) itemPtr;
1383        int byteCount;
1384        char *text, *selStart, *selEnd;
1385        Tk_CanvasTextInfo *textInfoPtr = textPtr->textInfoPtr;
1386    
1387        if ((textInfoPtr->selectFirst < 0) ||
1388                (textInfoPtr->selectFirst > textInfoPtr->selectLast)) {
1389            return 0;
1390        }
1391        text = textPtr->text;
1392        selStart = Tcl_UtfAtIndex(text, textInfoPtr->selectFirst);
1393        selEnd = Tcl_UtfAtIndex(selStart,
1394                textInfoPtr->selectLast + 1 - textInfoPtr->selectFirst);
1395        byteCount = selEnd - selStart - offset;
1396        if (byteCount > maxBytes) {
1397            byteCount = maxBytes;
1398        }
1399        if (byteCount <= 0) {
1400            return 0;
1401        }
1402        memcpy(buffer, selStart + offset, (size_t) byteCount);
1403        buffer[byteCount] = '\0';
1404        return byteCount;
1405    }
1406    
1407    /*
1408     *--------------------------------------------------------------
1409     *
1410     * TextToPostscript --
1411     *
1412     *      This procedure is called to generate Postscript for
1413     *      text items.
1414     *
1415     * Results:
1416     *      The return value is a standard Tcl result.  If an error
1417     *      occurs in generating Postscript then an error message is
1418     *      left in the interp's result, replacing whatever used
1419     *      to be there.  If no error occurs, then Postscript for the
1420     *      item is appended to the result.
1421     *
1422     * Side effects:
1423     *      None.
1424     *
1425     *--------------------------------------------------------------
1426     */
1427    
1428    static int
1429    TextToPostscript(interp, canvas, itemPtr, prepass)
1430        Tcl_Interp *interp;         /* Leave Postscript or error message here. */
1431        Tk_Canvas canvas;           /* Information about overall canvas. */
1432        Tk_Item *itemPtr;           /* Item for which Postscript is wanted. */
1433        int prepass;                /* 1 means this is a prepass to collect
1434                                     * font information; 0 means final Postscript
1435                                     * is being created. */
1436    {
1437        TextItem *textPtr = (TextItem *) itemPtr;
1438        int x, y;
1439        Tk_FontMetrics fm;
1440        char *justify;
1441        char buffer[500];
1442        XColor *color;
1443        Pixmap stipple;
1444        Tk_State state = itemPtr->state;
1445    
1446        if(state == TK_STATE_NULL) {
1447            state = ((TkCanvas *)canvas)->canvas_state;
1448        }
1449        color = textPtr->color;
1450        stipple = textPtr->stipple;
1451        if (state == TK_STATE_HIDDEN || textPtr->color == NULL ||
1452                textPtr->text == NULL || *textPtr->text == 0) {
1453            return TCL_OK;
1454        } else if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) {
1455            if (textPtr->activeColor!=NULL) {
1456                color = textPtr->activeColor;
1457            }
1458            if (textPtr->activeStipple!=None) {
1459                stipple = textPtr->activeStipple;
1460            }
1461        } else if (state==TK_STATE_DISABLED) {
1462            if (textPtr->disabledColor!=NULL) {
1463                color = textPtr->disabledColor;
1464            }
1465            if (textPtr->disabledStipple!=None) {
1466                stipple = textPtr->disabledStipple;
1467            }
1468        }
1469    
1470        if (Tk_CanvasPsFont(interp, canvas, textPtr->tkfont) != TCL_OK) {
1471            return TCL_ERROR;
1472        }
1473        if (prepass != 0) {
1474            return TCL_OK;
1475        }
1476        if (Tk_CanvasPsColor(interp, canvas, color) != TCL_OK) {
1477            return TCL_ERROR;
1478        }
1479        if (stipple != None) {
1480            Tcl_AppendResult(interp, "/StippleText {\n    ",
1481                    (char *) NULL);
1482            Tk_CanvasPsStipple(interp, canvas, stipple);
1483            Tcl_AppendResult(interp, "} bind def\n", (char *) NULL);
1484        }
1485    
1486        sprintf(buffer, "%.15g %.15g [\n", textPtr->x,
1487                Tk_CanvasPsY(canvas, textPtr->y));
1488        Tcl_AppendResult(interp, buffer, (char *) NULL);
1489    
1490        Tk_TextLayoutToPostscript(interp, textPtr->textLayout);
1491    
1492        x = 0;  y = 0;  justify = NULL;     /* lint. */
1493        switch (textPtr->anchor) {
1494            case TK_ANCHOR_NW:      x = 0; y = 0;   break;
1495            case TK_ANCHOR_N:       x = 1; y = 0;   break;
1496            case TK_ANCHOR_NE:      x = 2; y = 0;   break;
1497            case TK_ANCHOR_E:       x = 2; y = 1;   break;
1498            case TK_ANCHOR_SE:      x = 2; y = 2;   break;
1499            case TK_ANCHOR_S:       x = 1; y = 2;   break;
1500            case TK_ANCHOR_SW:      x = 0; y = 2;   break;
1501            case TK_ANCHOR_W:       x = 0; y = 1;   break;
1502            case TK_ANCHOR_CENTER:  x = 1; y = 1;   break;
1503        }
1504        switch (textPtr->justify) {
1505            case TK_JUSTIFY_LEFT:   justify = "0";  break;
1506            case TK_JUSTIFY_CENTER: justify = "0.5";break;
1507            case TK_JUSTIFY_RIGHT:  justify = "1";  break;
1508        }
1509    
1510        Tk_GetFontMetrics(textPtr->tkfont, &fm);
1511        sprintf(buffer, "] %d %g %g %s %s DrawText\n",
1512                fm.linespace, x / -2.0, y / 2.0, justify,
1513                ((stipple == None) ? "false" : "true"));
1514        Tcl_AppendResult(interp, buffer, (char *) NULL);
1515    
1516        return TCL_OK;
1517    }
1518    /* $Header$ */
1519    
1520    /* End of tkcanvtext.c */

Legend:
Removed from v.42  
changed lines
  Added in v.220

dashley@gmail.com
ViewVC Help
Powered by ViewVC 1.1.25