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

1.1     ! root        1: /* 
        !             2:  * tkCanvText.c --
        !             3:  *
        !             4:  *     This file implements text items for canvas widgets.
        !             5:  *
        !             6:  * Copyright 1991-1992 Regents of the University of California.
        !             7:  * Permission to use, copy, modify, and distribute this
        !             8:  * software and its documentation for any purpose and without
        !             9:  * fee is hereby granted, provided that the above copyright
        !            10:  * notice appear in all copies.  The University of California
        !            11:  * makes no representations about the suitability of this
        !            12:  * software for any purpose.  It is provided "as is" without
        !            13:  * express or implied warranty.
        !            14:  */
        !            15: 
        !            16: #ifndef lint
        !            17: static char rcsid[] = "$Header: /user6/ouster/wish/RCS/tkCanvText.c,v 1.12 92/08/19 08:34:12 ouster Exp $ SPRITE (Berkeley)";
        !            18: #endif
        !            19: 
        !            20: #include <stdio.h>
        !            21: #include "tkint.h"
        !            22: #include "tkcanvas.h"
        !            23: #include "tkconfig.h"
        !            24: 
        !            25: /*
        !            26:  * One of the following structures is kept for each line of text
        !            27:  * in a text item.  It contains geometry and display information
        !            28:  * for that line.
        !            29:  */
        !            30: 
        !            31: typedef struct TextLine {
        !            32:     char *firstChar;           /* Pointer to the first character in this
        !            33:                                 * line (in the "text" field of enclosing
        !            34:                                 * text item). */
        !            35:     int numChars;              /* Number of characters displayed in this
        !            36:                                 * line. */
        !            37:     int totalChars;            /* Total number of characters included as
        !            38:                                 * part of this line (may include an extra
        !            39:                                 * space character at the end that isn't
        !            40:                                 * displayed). */
        !            41:     int x, y;                  /* Origin at which to draw line on screen
        !            42:                                 * (in integer pixel units, but in canvas
        !            43:                                 * coordinates, not screen coordinates). */
        !            44:     int x1, y1;                        /* Upper-left pixel that is part of text
        !            45:                                 * line on screen (again, in integer canvas
        !            46:                                 * pixel units). */
        !            47:     int x2, y2;                        /* Lower-left pixel that is part of text
        !            48:                                 * line on screen (again, in integer canvas
        !            49:                                 * pixel units). */
        !            50: } TextLine;
        !            51: 
        !            52: /*
        !            53:  * The structure below defines the record for each text item.
        !            54:  */
        !            55: 
        !            56: typedef struct TextItem  {
        !            57:     Tk_Item header;            /* Generic stuff that's the same for all
        !            58:                                 * types.  MUST BE FIRST IN STRUCTURE. */
        !            59:     char *text;                        /* Text for item (malloc-ed). */
        !            60:     int numChars;              /* Number of non-NULL characters in text. */
        !            61:     double x, y;               /* Positioning point for text. */
        !            62:     Tk_Anchor anchor;          /* Where to anchor text relative to (x,y). */
        !            63:     int width;                 /* Width of lines for word-wrap, pixels.
        !            64:                                 * Zero means no word-wrap. */
        !            65:     Tk_Justify justify;                /* Justification mode for text. */
        !            66:     int rightEdge;             /* Pixel just to right of right edge of
        !            67:                                 * area of text item.  Used for selecting
        !            68:                                 * up to end of line. */
        !            69:     XFontStruct *fontPtr;      /* Font for drawing text. */
        !            70:     XColor *color;             /* Color for text. */
        !            71:     Pixmap stipple;            /* Stipple bitmap for text, or None. */
        !            72:     GC gc;                     /* Graphics context for drawing text. */
        !            73:     TextLine *linePtr;         /* Pointer to array of structures describing
        !            74:                                 * individual lines of text item (malloc-ed). */
        !            75:     int numLines;              /* Number of structs at *linePtr. */
        !            76:     int cursorPos;             /* Insertion cursor is displayed just to left
        !            77:                                 * of character with this index. */
        !            78:     GC selTextGC;              /* Graphics context for selected text. */
        !            79: } TextItem;
        !            80: 
        !            81: /*
        !            82:  * Information used for parsing configuration specs:
        !            83:  */
        !            84: 
        !            85: static Tk_ConfigSpec configSpecs[] = {
        !            86:     {TK_CONFIG_ANCHOR, "-anchor", (char *) NULL, (char *) NULL,
        !            87:        "center", Tk_Offset(TextItem, anchor),
        !            88:        TK_CONFIG_DONT_SET_DEFAULT},
        !            89:     {TK_CONFIG_COLOR, "-fill", (char *) NULL, (char *) NULL,
        !            90:        "black", Tk_Offset(TextItem, color), 0},
        !            91:     {TK_CONFIG_FONT, "-font", (char *) NULL, (char *) NULL,
        !            92:        "-Adobe-Helvetica-Bold-R-Normal-*-120-*",
        !            93:        Tk_Offset(TextItem, fontPtr), 0},
        !            94:     {TK_CONFIG_JUSTIFY, "-justify", (char *) NULL, (char *) NULL,
        !            95:        "left", Tk_Offset(TextItem, justify),
        !            96:        TK_CONFIG_DONT_SET_DEFAULT},
        !            97:     {TK_CONFIG_BITMAP, "-stipple", (char *) NULL, (char *) NULL,
        !            98:        (char *) NULL, Tk_Offset(TextItem, stipple), TK_CONFIG_NULL_OK},
        !            99:     {TK_CONFIG_CUSTOM, "-tags", (char *) NULL, (char *) NULL,
        !           100:        (char *) NULL, 0, TK_CONFIG_NULL_OK, &tkCanvasTagsOption},
        !           101:     {TK_CONFIG_STRING, "-text", (char *) NULL, (char *) NULL,
        !           102:        "", Tk_Offset(TextItem, text), 0},
        !           103:     {TK_CONFIG_PIXELS, "-width", (char *) NULL, (char *) NULL,
        !           104:        "0", Tk_Offset(TextItem, width), TK_CONFIG_DONT_SET_DEFAULT},
        !           105:     {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
        !           106:        (char *) NULL, 0, 0}
        !           107: };
        !           108: 
        !           109: /*
        !           110:  * Prototypes for procedures defined in this file:
        !           111:  */
        !           112: 
        !           113: static void            ComputeTextBbox _ANSI_ARGS_((Tk_Canvas *canvasPtr,
        !           114:                            TextItem *textPtr));
        !           115: static int             ConfigureText _ANSI_ARGS_((
        !           116:                            Tk_Canvas *canvasPtr, Tk_Item *itemPtr, int argc,
        !           117:                            char **argv, int flags));
        !           118: static int             CreateText _ANSI_ARGS_((Tk_Canvas *canvasPtr,
        !           119:                            struct Tk_Item *itemPtr, int argc, char **argv));
        !           120: static void            DeleteText _ANSI_ARGS_((Tk_Item *itemPtr));
        !           121: static void            DisplayText _ANSI_ARGS_((Tk_Canvas *canvasPtr,
        !           122:                            Tk_Item *itemPtr, Drawable dst));
        !           123: static int             GetSelText _ANSI_ARGS_((Tk_Canvas *canvasPtr,
        !           124:                            Tk_Item *itemPtr, int offset, char *buffer,
        !           125:                            int maxBytes));
        !           126: static int             GetTextIndex _ANSI_ARGS_((Tk_Canvas *canvasPtr,
        !           127:                            Tk_Item *itemPtr, char *indexString,
        !           128:                            int *indexPtr));
        !           129: static void            ScaleText _ANSI_ARGS_((Tk_Canvas *canvasPtr,
        !           130:                            Tk_Item *itemPtr, double originX, double originY,
        !           131:                            double scaleX, double scaleY));
        !           132: static void            SetTextCursor _ANSI_ARGS_((Tk_Canvas *canvasPtr,
        !           133:                            Tk_Item *itemPtr, int index));
        !           134: static int             TextCoords _ANSI_ARGS_((Tk_Canvas *canvasPtr,
        !           135:                            Tk_Item *itemPtr, int argc, char **argv));
        !           136: static int             TextDeleteChars _ANSI_ARGS_((Tk_Canvas *canvasPtr,
        !           137:                            Tk_Item *itemPtr, int first, int last));
        !           138: static int             TextInsert _ANSI_ARGS_((Tk_Canvas *canvasPtr,
        !           139:                            Tk_Item *itemPtr, int beforeThis, char *string));
        !           140: static int             TextToArea _ANSI_ARGS_((Tk_Canvas *canvasPtr,
        !           141:                            Tk_Item *itemPtr, double *rectPtr));
        !           142: static double          TextToPoint _ANSI_ARGS_((Tk_Canvas *canvasPtr,
        !           143:                            Tk_Item *itemPtr, double *pointPtr));
        !           144: static void            TranslateText _ANSI_ARGS_((Tk_Canvas *canvasPtr,
        !           145:                            Tk_Item *itemPtr, double deltaX, double deltaY));
        !           146: 
        !           147: /*
        !           148:  * The structures below defines the rectangle and oval item types
        !           149:  * by means of procedures that can be invoked by generic item code.
        !           150:  */
        !           151: 
        !           152: Tk_ItemType TkTextType = {
        !           153:     "text",                            /* name */
        !           154:     sizeof(TextItem),                  /* itemSize */
        !           155:     CreateText,                                /* createProc */
        !           156:     configSpecs,                       /* configSpecs */
        !           157:     ConfigureText,                     /* configureProc */
        !           158:     TextCoords,                                /* coordProc */
        !           159:     DeleteText,                                /* deleteProc */
        !           160:     DisplayText,                       /* displayProc */
        !           161:     0,                                 /* alwaysRedraw */
        !           162:     TextToPoint,                       /* pointProc */
        !           163:     TextToArea,                                /* areaProc */
        !           164:     (Tk_ItemPostscriptProc *) NULL,    /* postscriptProc */
        !           165:     ScaleText,                         /* scaleProc */
        !           166:     TranslateText,                     /* translateProc */
        !           167:     GetTextIndex,                      /* indexProc */
        !           168:     SetTextCursor,                     /* cursorProc */
        !           169:     GetSelText,                                /* selectionProc */
        !           170:     TextInsert,                                /* insertProc */
        !           171:     TextDeleteChars,                   /* dTextProc */
        !           172:     (Tk_ItemType *) NULL               /* nextPtr */
        !           173: };
        !           174: 
        !           175: /*
        !           176:  *--------------------------------------------------------------
        !           177:  *
        !           178:  * CreateText --
        !           179:  *
        !           180:  *     This procedure is invoked to create a new text item
        !           181:  *     in a canvas.
        !           182:  *
        !           183:  * Results:
        !           184:  *     A standard Tcl return value.  If an error occurred in
        !           185:  *     creating the item then an error message is left in
        !           186:  *     canvasPtr->interp->result;  in this case itemPtr is
        !           187:  *     left uninitialized so it can be safely freed by the
        !           188:  *     caller.
        !           189:  *
        !           190:  * Side effects:
        !           191:  *     A new text item is created.
        !           192:  *
        !           193:  *--------------------------------------------------------------
        !           194:  */
        !           195: 
        !           196: static int
        !           197: CreateText(canvasPtr, itemPtr, argc, argv)
        !           198:     register Tk_Canvas *canvasPtr;     /* Canvas to hold new item. */
        !           199:     Tk_Item *itemPtr;                  /* Record to hold new item;  header
        !           200:                                         * has been initialized by caller. */
        !           201:     int argc;                          /* Number of arguments in argv. */
        !           202:     char **argv;                       /* Arguments describing rectangle. */
        !           203: {
        !           204:     register TextItem *textPtr = (TextItem *) itemPtr;
        !           205: 
        !           206:     if (argc < 2) {
        !           207:        Tcl_AppendResult(canvasPtr->interp, "wrong # args:  should be \"",
        !           208:                Tk_PathName(canvasPtr->tkwin),
        !           209:                "\" create text x y [options]", (char *) NULL);
        !           210:        return TCL_ERROR;
        !           211:     }
        !           212: 
        !           213:     /*
        !           214:      * Carry out initialization that is needed in order to clean
        !           215:      * up after errors during the the remainder of this procedure.
        !           216:      */
        !           217: 
        !           218:     textPtr->text = NULL;
        !           219:     textPtr->anchor = TK_ANCHOR_CENTER;
        !           220:     textPtr->width = 0;
        !           221:     textPtr->justify = TK_JUSTIFY_LEFT;
        !           222:     textPtr->fontPtr = NULL;
        !           223:     textPtr->color = NULL;
        !           224:     textPtr->stipple = None;
        !           225:     textPtr->gc = None;
        !           226:     textPtr->linePtr = NULL;
        !           227:     textPtr->numLines = 0;
        !           228:     textPtr->cursorPos = 0;
        !           229:     textPtr->selTextGC = None;
        !           230: 
        !           231:     /*
        !           232:      * Process the arguments to fill in the item record.
        !           233:      */
        !           234: 
        !           235:     if ((TkGetCanvasCoord(canvasPtr, argv[0], &textPtr->x) != TCL_OK)
        !           236:            || (TkGetCanvasCoord(canvasPtr, argv[1], &textPtr->y) != TCL_OK)) {
        !           237:        return TCL_ERROR;
        !           238:     }
        !           239: 
        !           240:     if (ConfigureText(canvasPtr, itemPtr, argc-2, argv+2, 0) != TCL_OK) {
        !           241:        DeleteText(itemPtr);
        !           242:        return TCL_ERROR;
        !           243:     }
        !           244:     return TCL_OK;
        !           245: }
        !           246: 
        !           247: /*
        !           248:  *--------------------------------------------------------------
        !           249:  *
        !           250:  * TextCoords --
        !           251:  *
        !           252:  *     This procedure is invoked to process the "coords" widget
        !           253:  *     command on text items.  See the user documentation for
        !           254:  *     details on what it does.
        !           255:  *
        !           256:  * Results:
        !           257:  *     Returns TCL_OK or TCL_ERROR, and sets canvasPtr->interp->result.
        !           258:  *
        !           259:  * Side effects:
        !           260:  *     The coordinates for the given item may be changed.
        !           261:  *
        !           262:  *--------------------------------------------------------------
        !           263:  */
        !           264: 
        !           265: static int
        !           266: TextCoords(canvasPtr, itemPtr, argc, argv)
        !           267:     register Tk_Canvas *canvasPtr;     /* Canvas containing item. */
        !           268:     Tk_Item *itemPtr;                  /* Item whose coordinates are to be
        !           269:                                         * read or modified. */
        !           270:     int argc;                          /* Number of coordinates supplied in
        !           271:                                         * argv. */
        !           272:     char **argv;                       /* Array of coordinates: x1, y1,
        !           273:                                         * x2, y2, ... */
        !           274: {
        !           275:     register TextItem *textPtr = (TextItem *) itemPtr;
        !           276: 
        !           277:     if (argc == 0) {
        !           278:        sprintf(canvasPtr->interp->result, "%g %g", textPtr->x, textPtr->y);
        !           279:     } else if (argc == 2) {
        !           280:        if ((TkGetCanvasCoord(canvasPtr, argv[0], &textPtr->x) != TCL_OK)
        !           281:                || (TkGetCanvasCoord(canvasPtr, argv[1],
        !           282:                    &textPtr->y) != TCL_OK)) {
        !           283:            return TCL_ERROR;
        !           284:        }
        !           285:        ComputeTextBbox(canvasPtr, textPtr);
        !           286:     } else {
        !           287:        sprintf(canvasPtr->interp->result,
        !           288:                "wrong # coordinates:  expected 0 or 2, got %d",
        !           289:                argc);
        !           290:        return TCL_ERROR;
        !           291:     }
        !           292:     return TCL_OK;
        !           293: }
        !           294: 
        !           295: /*
        !           296:  *--------------------------------------------------------------
        !           297:  *
        !           298:  * ConfigureText --
        !           299:  *
        !           300:  *     This procedure is invoked to configure various aspects
        !           301:  *     of a text item, such as its border and background colors.
        !           302:  *
        !           303:  * Results:
        !           304:  *     A standard Tcl result code.  If an error occurs, then
        !           305:  *     an error message is left in canvasPtr->interp->result.
        !           306:  *
        !           307:  * Side effects:
        !           308:  *     Configuration information, such as colors and stipple
        !           309:  *     patterns, may be set for itemPtr.
        !           310:  *
        !           311:  *--------------------------------------------------------------
        !           312:  */
        !           313: 
        !           314: static int
        !           315: ConfigureText(canvasPtr, itemPtr, argc, argv, flags)
        !           316:     Tk_Canvas *canvasPtr;      /* Canvas containing itemPtr. */
        !           317:     Tk_Item *itemPtr;          /* Rectangle item to reconfigure. */
        !           318:     int argc;                  /* Number of elements in argv.  */
        !           319:     char **argv;               /* Arguments describing things to configure. */
        !           320:     int flags;                 /* Flags to pass to Tk_ConfigureWidget. */
        !           321: {
        !           322:     register TextItem *textPtr = (TextItem *) itemPtr;
        !           323:     XGCValues gcValues;
        !           324:     GC newGC, newSelGC;
        !           325:     unsigned long mask;
        !           326: 
        !           327:     if (Tk_ConfigureWidget(canvasPtr->interp, canvasPtr->tkwin,
        !           328:            configSpecs, argc, argv, (char *) textPtr, flags) != TCL_OK) {
        !           329:        return TCL_ERROR;
        !           330:     }
        !           331: 
        !           332:     /*
        !           333:      * A few of the options require additional processing, such as
        !           334:      * graphics contexts.
        !           335:      */
        !           336: 
        !           337:     textPtr->numChars = strlen(textPtr->text);
        !           338:     newGC = newSelGC = None;
        !           339:     if ((textPtr->color != NULL) && (textPtr->fontPtr != NULL)) {
        !           340:        gcValues.foreground = textPtr->color->pixel;
        !           341:        gcValues.font = textPtr->fontPtr->fid;
        !           342:        mask = GCForeground|GCFont;
        !           343:        if (textPtr->stipple != None) {
        !           344:            gcValues.stipple = textPtr->stipple;
        !           345:            gcValues.fill_style = FillStippled;
        !           346:            mask |= GCForeground|GCStipple|GCFillStyle;
        !           347:        }
        !           348:        newGC = Tk_GetGC(canvasPtr->tkwin, mask, &gcValues);
        !           349:        gcValues.foreground = canvasPtr->selFgColorPtr->pixel;
        !           350:        newSelGC = Tk_GetGC(canvasPtr->tkwin, mask, &gcValues);
        !           351:     }
        !           352:     if (textPtr->gc != None) {
        !           353:        Tk_FreeGC(textPtr->gc);
        !           354:     }
        !           355:     textPtr->gc = newGC;
        !           356:     if (textPtr->selTextGC != None) {
        !           357:        Tk_FreeGC(textPtr->selTextGC);
        !           358:     }
        !           359:     textPtr->selTextGC = newSelGC;
        !           360: 
        !           361:     /*
        !           362:      * If the text was changed, move the selection and insertion indices
        !           363:      * to keep them inside the item.
        !           364:      */
        !           365: 
        !           366:     if (canvasPtr->selItemPtr == itemPtr) {
        !           367:        if (canvasPtr->selectFirst >= textPtr->numChars) {
        !           368:            canvasPtr->selItemPtr = NULL;
        !           369:        } else {
        !           370:            if (canvasPtr->selectLast >= textPtr->numChars) {
        !           371:                canvasPtr->selectLast = textPtr->numChars-1;
        !           372:            }
        !           373:            if ((canvasPtr->anchorItemPtr == itemPtr)
        !           374:                    && (canvasPtr->selectAnchor >= textPtr->numChars)) {
        !           375:                canvasPtr->selectAnchor = textPtr->numChars-1;
        !           376:            }
        !           377:        }
        !           378:     }
        !           379:     if (textPtr->cursorPos >= textPtr->numChars) {
        !           380:        textPtr->cursorPos = textPtr->numChars;
        !           381:     }
        !           382: 
        !           383:     ComputeTextBbox(canvasPtr, textPtr);
        !           384:     return TCL_OK;
        !           385: }
        !           386: 
        !           387: /*
        !           388:  *--------------------------------------------------------------
        !           389:  *
        !           390:  * DeleteText --
        !           391:  *
        !           392:  *     This procedure is called to clean up the data structure
        !           393:  *     associated with a text item.
        !           394:  *
        !           395:  * Results:
        !           396:  *     None.
        !           397:  *
        !           398:  * Side effects:
        !           399:  *     Resources associated with itemPtr are released.
        !           400:  *
        !           401:  *--------------------------------------------------------------
        !           402:  */
        !           403: 
        !           404: static void
        !           405: DeleteText(itemPtr)
        !           406:     Tk_Item *itemPtr;                  /* Item that is being deleted. */
        !           407: {
        !           408:     register TextItem *textPtr = (TextItem *) itemPtr;
        !           409: 
        !           410:     if (textPtr->text != NULL) {
        !           411:        ckfree(textPtr->text);
        !           412:     }
        !           413:     if (textPtr->fontPtr != NULL) {
        !           414:        Tk_FreeFontStruct(textPtr->fontPtr);
        !           415:     }
        !           416:     if (textPtr->color != NULL) {
        !           417:        Tk_FreeColor(textPtr->color);
        !           418:     }
        !           419:     if (textPtr->stipple != None) {
        !           420:        Tk_FreeBitmap(textPtr->stipple);
        !           421:     }
        !           422:     if (textPtr->gc != None) {
        !           423:        Tk_FreeGC(textPtr->gc);
        !           424:     }
        !           425:     if (textPtr->linePtr != NULL) {
        !           426:        ckfree((char *) textPtr->linePtr);
        !           427:     }
        !           428:     if (textPtr->selTextGC != None) {
        !           429:        Tk_FreeGC(textPtr->selTextGC);
        !           430:     }
        !           431: }
        !           432: 
        !           433: /*
        !           434:  *--------------------------------------------------------------
        !           435:  *
        !           436:  * ComputeTextBbox --
        !           437:  *
        !           438:  *     This procedure is invoked to compute the bounding box of
        !           439:  *     all the pixels that may be drawn as part of a text item.
        !           440:  *     In addition, it recomputes all of the geometry information
        !           441:  *     used to display a text item or check for mouse hits.
        !           442:  *
        !           443:  * Results:
        !           444:  *     None.
        !           445:  *
        !           446:  * Side effects:
        !           447:  *     The fields x1, y1, x2, and y2 are updated in the header
        !           448:  *     for itemPtr, and the linePtr structure is regenerated
        !           449:  *     for itemPtr.
        !           450:  *
        !           451:  *--------------------------------------------------------------
        !           452:  */
        !           453: 
        !           454: static void
        !           455: ComputeTextBbox(canvasPtr, textPtr)
        !           456:     register Tk_Canvas *canvasPtr;     /* Canvas that contains item. */
        !           457:     register TextItem *textPtr;                /* Item whose bbos is to be
        !           458:                                         * recomputed. */
        !           459: {
        !           460:     register TextLine *linePtr;
        !           461: #define MAX_LINES 100
        !           462:     char *lineStart[MAX_LINES];
        !           463:     int lineChars[MAX_LINES];
        !           464:     int linePixels[MAX_LINES];
        !           465:     int numLines, wrapPixels, maxLinePixels, leftX, topY, y;
        !           466:     int lineHeight, i, fudge;
        !           467:     char *p;
        !           468:     XCharStruct *maxBoundsPtr = &textPtr->fontPtr->max_bounds;
        !           469: 
        !           470:     if (textPtr->linePtr != NULL) {
        !           471:        ckfree((char *) textPtr->linePtr);
        !           472:        textPtr->linePtr = NULL;
        !           473:     }
        !           474: 
        !           475:     /*
        !           476:      * Work through the text computing the starting point, number of
        !           477:      * characters, and number of pixels in each line.
        !           478:      */
        !           479: 
        !           480:     p = textPtr->text;
        !           481:     if (textPtr->width > 0) {
        !           482:        wrapPixels = maxLinePixels = textPtr->width;
        !           483:     } else {
        !           484:        wrapPixels = 10000000;
        !           485:        maxLinePixels = 0;
        !           486:     }
        !           487:     for (numLines = 0; (numLines < MAX_LINES) && (*p != 0);
        !           488:            numLines++) {
        !           489:        int numChars, numPixels;
        !           490:        numChars = TkMeasureChars(textPtr->fontPtr, p,
        !           491:                (textPtr->text + textPtr->numChars) - p, 0,
        !           492:                wrapPixels, TK_WHOLE_WORDS|TK_AT_LEAST_ONE, &numPixels);
        !           493:        if (numPixels > maxLinePixels) {
        !           494:            maxLinePixels = numPixels;
        !           495:        }
        !           496:        lineStart[numLines] = p;
        !           497:        lineChars[numLines] = numChars;
        !           498:        linePixels[numLines] = numPixels;
        !           499:        p += numChars;
        !           500: 
        !           501:        /*
        !           502:         * Skip space character that terminates a line, if there is one.
        !           503:         * In the case of multiple spaces, all but one will be displayed.
        !           504:         * This is important to make sure the insertion cursor gets
        !           505:         * displayed when it is in the middle of a multi-space.
        !           506:         */
        !           507: 
        !           508:        if (isspace(*p)) {
        !           509:            p++;
        !           510:        }
        !           511:     }
        !           512: 
        !           513:     /*
        !           514:      * Use overall geometry information to compute the top-left corner
        !           515:      * of the bounding box for the text item.
        !           516:      */
        !           517: 
        !           518:     leftX = textPtr->x + 0.5;
        !           519:     topY = textPtr->y + 0.5;
        !           520:     lineHeight = textPtr->fontPtr->ascent + textPtr->fontPtr->descent;
        !           521:     switch (textPtr->anchor) {
        !           522:        case TK_ANCHOR_NW:
        !           523:        case TK_ANCHOR_N:
        !           524:        case TK_ANCHOR_NE:
        !           525:            break;
        !           526: 
        !           527:        case TK_ANCHOR_W:
        !           528:        case TK_ANCHOR_CENTER:
        !           529:        case TK_ANCHOR_E:
        !           530:            topY -= (lineHeight * numLines)/2;
        !           531:            break;
        !           532: 
        !           533:        case TK_ANCHOR_SW:
        !           534:        case TK_ANCHOR_S:
        !           535:        case TK_ANCHOR_SE:
        !           536:            topY -= lineHeight * numLines;
        !           537:            break;
        !           538:     }
        !           539:     switch (textPtr->anchor) {
        !           540:        case TK_ANCHOR_NW:
        !           541:        case TK_ANCHOR_W:
        !           542:        case TK_ANCHOR_SW:
        !           543:            break;
        !           544: 
        !           545:        case TK_ANCHOR_N:
        !           546:        case TK_ANCHOR_CENTER:
        !           547:        case TK_ANCHOR_S:
        !           548:            leftX -= maxLinePixels/2;
        !           549:            break;
        !           550: 
        !           551:        case TK_ANCHOR_NE:
        !           552:        case TK_ANCHOR_E:
        !           553:        case TK_ANCHOR_SE:
        !           554:            leftX -= maxLinePixels;
        !           555:            break;
        !           556:     }
        !           557:     textPtr->rightEdge = leftX + maxLinePixels;
        !           558: 
        !           559:     /*
        !           560:      * Create the new TextLine array and fill it in using the geometry
        !           561:      * information gathered already.
        !           562:      */
        !           563: 
        !           564:     if (numLines > 0) {
        !           565:        textPtr->linePtr = (TextLine *) ckalloc((unsigned)
        !           566:                (numLines * sizeof(TextLine)));
        !           567:     } else {
        !           568:        textPtr->linePtr = NULL;
        !           569:     }
        !           570:     textPtr->numLines = numLines;
        !           571:     for (i = 0, linePtr = textPtr->linePtr, y = topY;
        !           572:            i < numLines; i++, linePtr++, y += lineHeight) {
        !           573:        linePtr->firstChar = lineStart[i];
        !           574:        linePtr->numChars = lineChars[i];
        !           575:        if (i == (numLines-1)) {
        !           576:            linePtr->totalChars = linePtr->numChars;
        !           577:        } else {
        !           578:            linePtr->totalChars = lineStart[i+1] - lineStart[i];
        !           579:        }
        !           580:        switch (textPtr->justify) {
        !           581:            case TK_JUSTIFY_LEFT:
        !           582:            case TK_JUSTIFY_FILL:
        !           583:                linePtr->x = leftX;
        !           584:                break;
        !           585:            case TK_JUSTIFY_CENTER:
        !           586:                linePtr->x = leftX + maxLinePixels/2 - linePixels[i]/2;
        !           587:                break;
        !           588:            case TK_JUSTIFY_RIGHT:
        !           589:                linePtr->x = leftX + maxLinePixels - linePixels[i];
        !           590:                break;
        !           591:        }
        !           592:        linePtr->y = y + textPtr->fontPtr->ascent;
        !           593:        linePtr->x1 = linePtr->x - maxBoundsPtr->lbearing;
        !           594:        linePtr->y1 = y;
        !           595:        linePtr->x2 = linePtr->x + linePixels[i] + maxBoundsPtr->rbearing
        !           596:                - textPtr->fontPtr->min_bounds.rbearing;
        !           597:        linePtr->y2 = linePtr->y + textPtr->fontPtr->descent - 1;
        !           598:     }
        !           599: 
        !           600:     /*
        !           601:      * Last of all, update the bounding box for the item.  The item's
        !           602:      * bounding box includes the bounding box of all its lines, plus
        !           603:      * an extra fudge factor for the cursor border (which could
        !           604:      * potentially be quite large).
        !           605:      */
        !           606: 
        !           607:     linePtr = textPtr->linePtr;
        !           608:     textPtr->header.x1 = textPtr->header.x2 = leftX;
        !           609:     textPtr->header.y1 = topY;
        !           610:     textPtr->header.y2 = topY + numLines*lineHeight;
        !           611:     for (linePtr = textPtr->linePtr, i = textPtr->numLines; i > 0;
        !           612:            i--, linePtr++) {
        !           613:        if (linePtr->x1 < textPtr->header.x1) {
        !           614:            textPtr->header.x1 = linePtr->x1;
        !           615:        }
        !           616:        if (linePtr->x2 >= textPtr->header.x2) {
        !           617:            textPtr->header.x2 = linePtr->x2 + 1;
        !           618:        }
        !           619:     }
        !           620: 
        !           621:     fudge = canvasPtr->cursorWidth/2;
        !           622:     if (canvasPtr->selBorderWidth > fudge) {
        !           623:        fudge = canvasPtr->selBorderWidth;
        !           624:     }
        !           625:     textPtr->header.x1 -= fudge;
        !           626:     textPtr->header.x2 += fudge;
        !           627: }
        !           628: 
        !           629: /*
        !           630:  *--------------------------------------------------------------
        !           631:  *
        !           632:  * DisplayText --
        !           633:  *
        !           634:  *     This procedure is invoked to draw a text item in a given
        !           635:  *     drawable.
        !           636:  *
        !           637:  * Results:
        !           638:  *     None.
        !           639:  *
        !           640:  * Side effects:
        !           641:  *     ItemPtr is drawn in drawable using the transformation
        !           642:  *     information in canvasPtr.
        !           643:  *
        !           644:  *--------------------------------------------------------------
        !           645:  */
        !           646: 
        !           647: static void
        !           648: DisplayText(canvasPtr, itemPtr, drawable)
        !           649:     register Tk_Canvas *canvasPtr;     /* Canvas that contains item. */
        !           650:     Tk_Item *itemPtr;                  /* Item to be displayed. */
        !           651:     Drawable drawable;                 /* Pixmap or window in which to draw
        !           652:                                         * item. */
        !           653: {
        !           654:     register TextItem *textPtr = (TextItem *) itemPtr;
        !           655:     Display *display = Tk_Display(canvasPtr->tkwin);
        !           656:     register TextLine *linePtr;
        !           657:     int i, focusHere, cursorX, cursorIndex, lineIndex;
        !           658:     int beforeSelect, inSelect, afterSelect, selStartX, selEndX;
        !           659: 
        !           660:     if (textPtr->gc == None) {
        !           661:        return;
        !           662:     }
        !           663:     focusHere = (canvasPtr->focusItemPtr == itemPtr) &&
        !           664:            (canvasPtr->flags & GOT_FOCUS);
        !           665:     for (linePtr = textPtr->linePtr, i = textPtr->numLines;
        !           666:            i > 0; linePtr++, i--) {
        !           667: 
        !           668:        /*
        !           669:         * If part or all of this line is selected, then draw a special
        !           670:         * background under the selected part of the line.
        !           671:         */
        !           672: 
        !           673:        lineIndex = linePtr->firstChar - textPtr->text;
        !           674:        if ((canvasPtr->selItemPtr != itemPtr)
        !           675:                || (canvasPtr->selectLast < lineIndex)
        !           676:                || (canvasPtr->selectFirst >= (lineIndex
        !           677:                        + linePtr->totalChars))) {
        !           678:            beforeSelect = linePtr->numChars;
        !           679:            inSelect = 0;
        !           680:        } else {
        !           681:            beforeSelect = canvasPtr->selectFirst - lineIndex;
        !           682:            if (beforeSelect <= 0) {
        !           683:                beforeSelect = 0;
        !           684:                selStartX = linePtr->x;
        !           685:            } else {
        !           686:                (void) TkMeasureChars(textPtr->fontPtr,
        !           687:                        linePtr->firstChar, beforeSelect, 0,
        !           688:                        (int) 1000000, TK_PARTIAL_OK, &selStartX);
        !           689:                selStartX += linePtr->x;
        !           690:            }
        !           691:            inSelect = canvasPtr->selectLast + 1 - (lineIndex + beforeSelect);
        !           692: 
        !           693:            /*
        !           694:             * If the selection spans the end of this line, then display
        !           695:             * selection background all the way to the end of the line.
        !           696:             * However, for the last line we only want to display up to
        !           697:             * the last character, not the end of the line, hence the
        !           698:             * "i != 1" check.
        !           699:             */
        !           700: 
        !           701:            if (inSelect >= (linePtr->totalChars - beforeSelect)) {
        !           702:                inSelect = linePtr->numChars - beforeSelect;
        !           703:                if (i != 1) {
        !           704:                    selEndX = textPtr->rightEdge;
        !           705:                    goto fillSelectBackground;
        !           706:                }
        !           707:            }
        !           708:            (void) TkMeasureChars(textPtr->fontPtr,
        !           709:                    linePtr->firstChar + beforeSelect, inSelect,
        !           710:                    selStartX-linePtr->x, (int) 1000000, TK_PARTIAL_OK,
        !           711:                    &selEndX);
        !           712:            selEndX += linePtr->x;
        !           713:            fillSelectBackground:
        !           714:            Tk_Fill3DRectangle(display, drawable, canvasPtr->selBorder,
        !           715:                    selStartX - canvasPtr->drawableXOrigin
        !           716:                        - canvasPtr->selBorderWidth,
        !           717:                    linePtr->y - canvasPtr->drawableYOrigin
        !           718:                        - textPtr->fontPtr->ascent,
        !           719:                    selEndX - selStartX + 2*canvasPtr->selBorderWidth,
        !           720:                    textPtr->fontPtr->ascent + textPtr->fontPtr->descent,
        !           721:                    canvasPtr->selBorderWidth, TK_RELIEF_RAISED);
        !           722:        }
        !           723: 
        !           724:        /*
        !           725:         * If the insertion cursor is in this line, then draw a special
        !           726:         * background for the cursor before drawing the text.  Note:
        !           727:         * if we're the cursor item but the cursor is turned off, then
        !           728:         * redraw background over the area of the cursor.  This guarantees
        !           729:         * that the selection won't make the cursor invisible on mono
        !           730:         * displays, where both are drawn in the same color.
        !           731:         */
        !           732: 
        !           733:        if (focusHere) {
        !           734:            cursorIndex = textPtr->cursorPos
        !           735:                    - (linePtr->firstChar - textPtr->text);
        !           736:            if ((cursorIndex >= 0) && (cursorIndex <= linePtr->numChars)) {
        !           737:                (void) TkMeasureChars(textPtr->fontPtr, linePtr->firstChar,
        !           738:                    cursorIndex, 0, (int) 1000000, TK_PARTIAL_OK, &cursorX);
        !           739:                if (canvasPtr->flags & CURSOR_ON) {
        !           740:                    Tk_Fill3DRectangle(display, drawable,
        !           741:                            canvasPtr->cursorBorder,
        !           742:                            linePtr->x - canvasPtr->drawableXOrigin
        !           743:                                + cursorX  - (canvasPtr->cursorWidth)/2,
        !           744:                            linePtr->y - canvasPtr->drawableYOrigin
        !           745:                                - textPtr->fontPtr->ascent,
        !           746:                            canvasPtr->cursorWidth,
        !           747:                            textPtr->fontPtr->ascent
        !           748:                                + textPtr->fontPtr->descent,
        !           749:                            canvasPtr->cursorBorderWidth, TK_RELIEF_RAISED);
        !           750:                } else if (Tk_DefaultDepth(
        !           751:                        Tk_Screen(canvasPtr->tkwin)) == 1){
        !           752:                    Tk_Fill3DRectangle(display, drawable,
        !           753:                            canvasPtr->bgBorder,
        !           754:                            linePtr->x - canvasPtr->drawableXOrigin
        !           755:                                + cursorX  - (canvasPtr->cursorWidth)/2,
        !           756:                            linePtr->y - canvasPtr->drawableYOrigin
        !           757:                                - textPtr->fontPtr->ascent,
        !           758:                            canvasPtr->cursorWidth,
        !           759:                            textPtr->fontPtr->ascent
        !           760:                                + textPtr->fontPtr->descent,
        !           761:                            0, TK_RELIEF_FLAT);
        !           762:                }
        !           763:            }
        !           764:        }
        !           765: 
        !           766:        /*
        !           767:         * Display the text in three pieces:  the part before the
        !           768:         * selection, the selected part (which needs a different graphics
        !           769:         * context), and the part after the selection.
        !           770:         */
        !           771: 
        !           772:        if (beforeSelect != 0) {
        !           773:            TkDisplayChars(display, drawable, textPtr->gc, textPtr->fontPtr,
        !           774:                    linePtr->firstChar, beforeSelect,
        !           775:                    linePtr->x - canvasPtr->drawableXOrigin,
        !           776:                    linePtr->y - canvasPtr->drawableYOrigin, 0);
        !           777:        }
        !           778:        if (inSelect != 0) {
        !           779:            TkDisplayChars(display, drawable, textPtr->selTextGC,
        !           780:                    textPtr->fontPtr, linePtr->firstChar + beforeSelect,
        !           781:                    inSelect, selStartX - canvasPtr->drawableXOrigin,
        !           782:                    linePtr->y - canvasPtr->drawableYOrigin, 0);
        !           783:        }
        !           784:        afterSelect = linePtr->numChars - beforeSelect - inSelect;
        !           785:        if (afterSelect > 0) {
        !           786:            TkDisplayChars(display, drawable, textPtr->gc, textPtr->fontPtr,
        !           787:                    linePtr->firstChar + beforeSelect + inSelect,
        !           788:                    afterSelect, selEndX - canvasPtr->drawableXOrigin,
        !           789:                    linePtr->y - canvasPtr->drawableYOrigin, 0);
        !           790:        }
        !           791:     }
        !           792: }
        !           793: 
        !           794: /*
        !           795:  *--------------------------------------------------------------
        !           796:  *
        !           797:  * TextInsert --
        !           798:  *
        !           799:  *     Insert characters into a text item at a given position.
        !           800:  *
        !           801:  * Results:
        !           802:  *     Always returns TCL_OK.
        !           803:  *
        !           804:  * Side effects:
        !           805:  *     The text in the given item is modified.  The cursor and
        !           806:  *     selection positions are also modified to reflect the
        !           807:  *     insertion.
        !           808:  *
        !           809:  *--------------------------------------------------------------
        !           810:  */
        !           811: 
        !           812: static int
        !           813: TextInsert(canvasPtr, itemPtr, beforeThis, string)
        !           814:     Tk_Canvas *canvasPtr;      /* Canvas containing text item. */
        !           815:     Tk_Item *itemPtr;          /* Text item to be modified. */
        !           816:     int beforeThis;            /* Index of character before which text is
        !           817:                                 * to be inserted. */
        !           818:     char *string;              /* New characters to be inserted. */
        !           819: {
        !           820:     register TextItem *textPtr = (TextItem *) itemPtr;
        !           821:     int length;
        !           822:     char *new;
        !           823: 
        !           824:     length = strlen(string);
        !           825:     if (length == 0) {
        !           826:        return TCL_OK;
        !           827:     }
        !           828:     if (beforeThis < 0) {
        !           829:        beforeThis = 0;
        !           830:     }
        !           831:     if (beforeThis > textPtr->numChars) {
        !           832:        beforeThis = textPtr->numChars;
        !           833:     }
        !           834: 
        !           835:     new = (char *) ckalloc((unsigned) (textPtr->numChars + length + 1));
        !           836:     strncpy(new, textPtr->text, beforeThis);
        !           837:     strcpy(new+beforeThis, string);
        !           838:     strcpy(new+beforeThis+length, textPtr->text+beforeThis);
        !           839:     ckfree(textPtr->text);
        !           840:     textPtr->text = new;
        !           841:     textPtr->numChars += length;
        !           842: 
        !           843:     /*
        !           844:      * Inserting characters invalidates indices such as those for the
        !           845:      * selection and cursor.  Update the indices appropriately.
        !           846:      */
        !           847: 
        !           848:     if (canvasPtr->selItemPtr == itemPtr) {
        !           849:        if (canvasPtr->selectFirst >= beforeThis) {
        !           850:            canvasPtr->selectFirst += length;
        !           851:        }
        !           852:        if (canvasPtr->selectLast >= beforeThis) {
        !           853:            canvasPtr->selectLast += length;
        !           854:        }
        !           855:        if ((canvasPtr->anchorItemPtr == itemPtr)
        !           856:                && (canvasPtr->selectAnchor >= beforeThis)) {
        !           857:            canvasPtr->selectAnchor += length;
        !           858:        }
        !           859:     }
        !           860:     if (textPtr->cursorPos >= beforeThis) {
        !           861:        textPtr->cursorPos += length;
        !           862:     }
        !           863:     ComputeTextBbox(canvasPtr, textPtr);
        !           864:     return TCL_OK;
        !           865: }
        !           866: 
        !           867: /*
        !           868:  *--------------------------------------------------------------
        !           869:  *
        !           870:  * TextDeleteChars --
        !           871:  *
        !           872:  *     Delete one or more characters from a text item.
        !           873:  *
        !           874:  * Results:
        !           875:  *     Always returns TCL_OK.
        !           876:  *
        !           877:  * Side effects:
        !           878:  *     Characters between "first" and "last", inclusive, get
        !           879:  *     deleted from itemPtr, and things like the selection
        !           880:  *     position get updated.
        !           881:  *
        !           882:  *--------------------------------------------------------------
        !           883:  */
        !           884: 
        !           885: static int
        !           886: TextDeleteChars(canvasPtr, itemPtr, first, last)
        !           887:     Tk_Canvas *canvasPtr;      /* Canvas containing itemPtr. */
        !           888:     Tk_Item *itemPtr;          /* Item in which to delete characters. */
        !           889:     int first;                 /* Index of first character to delete. */
        !           890:     int last;                  /* Index of last character to delete. */
        !           891: {
        !           892:     register TextItem *textPtr = (TextItem *) itemPtr;
        !           893:     int count;
        !           894:     char *new;
        !           895: 
        !           896:     if (first < 0) {
        !           897:        first = 0;
        !           898:     }
        !           899:     if (last >= textPtr->numChars) {
        !           900:        last = textPtr->numChars-1;
        !           901:     }
        !           902:     if (first > last) {
        !           903:        return TCL_OK;
        !           904:     }
        !           905:     count = last + 1 - first;
        !           906: 
        !           907:     new = ckalloc((unsigned) (textPtr->numChars + 1 - count));
        !           908:     strncpy(new, textPtr->text, first);
        !           909:     strcpy(new+first, textPtr->text+last+1);
        !           910:     ckfree(textPtr->text);
        !           911:     textPtr->text = new;
        !           912:     textPtr->numChars -= count;
        !           913: 
        !           914:     /*
        !           915:      * Update indexes for the selection and cursor to reflect the
        !           916:      * renumbering of the remaining characters.
        !           917:      */
        !           918: 
        !           919:     if (canvasPtr->selItemPtr == itemPtr) {
        !           920:        if (canvasPtr->selectFirst > first) {
        !           921:            canvasPtr->selectFirst -= count;
        !           922:            if (canvasPtr->selectFirst < first) {
        !           923:                canvasPtr->selectFirst = first;
        !           924:            }
        !           925:        }
        !           926:        if (canvasPtr->selectLast >= first) {
        !           927:            canvasPtr->selectLast -= count;
        !           928:            if (canvasPtr->selectLast < (first-1)) {
        !           929:                canvasPtr->selectLast = (first-1);
        !           930:            }
        !           931:        }
        !           932:        if (canvasPtr->selectFirst > canvasPtr->selectLast) {
        !           933:            canvasPtr->selItemPtr = NULL;
        !           934:        }
        !           935:        if ((canvasPtr->anchorItemPtr == itemPtr)
        !           936:                && (canvasPtr->selectAnchor > first)) {
        !           937:            canvasPtr->selectAnchor -= count;
        !           938:            if (canvasPtr->selectAnchor < first) {
        !           939:                canvasPtr->selectAnchor = first;
        !           940:            }
        !           941:        }
        !           942:     }
        !           943:     if (textPtr->cursorPos > first) {
        !           944:        textPtr->cursorPos -= count;
        !           945:        if (textPtr->cursorPos < first) {
        !           946:            textPtr->cursorPos = first;
        !           947:        }
        !           948:     }
        !           949:     ComputeTextBbox(canvasPtr, textPtr);
        !           950:     return TCL_OK;
        !           951: }
        !           952: 
        !           953: /*
        !           954:  *--------------------------------------------------------------
        !           955:  *
        !           956:  * TextToPoint --
        !           957:  *
        !           958:  *     Computes the distance from a given point to a given
        !           959:  *     text item, in canvas units.
        !           960:  *
        !           961:  * Results:
        !           962:  *     The return value is 0 if the point whose x and y coordinates
        !           963:  *     are pointPtr[0] and pointPtr[1] is inside the arc.  If the
        !           964:  *     point isn't inside the arc then the return value is the
        !           965:  *     distance from the point to the arc.
        !           966:  *
        !           967:  * Side effects:
        !           968:  *     None.
        !           969:  *
        !           970:  *--------------------------------------------------------------
        !           971:  */
        !           972: 
        !           973:        /* ARGSUSED */
        !           974: static double
        !           975: TextToPoint(canvasPtr, itemPtr, pointPtr)
        !           976:     Tk_Canvas *canvasPtr;      /* Canvas containing itemPtr. */
        !           977:     Tk_Item *itemPtr;          /* Item to check against point. */
        !           978:     double *pointPtr;          /* Pointer to x and y coordinates. */
        !           979: {
        !           980:     TextItem *textPtr = (TextItem *) itemPtr;
        !           981:     register TextLine *linePtr;
        !           982:     int i;
        !           983:     double xDiff, yDiff, dist, minDist;
        !           984: 
        !           985:     /*
        !           986:      * Treat each line in the text item as a rectangle, compute the
        !           987:      * distance to that rectangle, and take the minimum of these
        !           988:      * distances.  Perform most of the calculations in integer pixel
        !           989:      * units, since that's how the dimensions of the text are defined.
        !           990:      */
        !           991: 
        !           992:     minDist = -1.0;
        !           993:     for (linePtr = textPtr->linePtr, i = textPtr->numLines;
        !           994:            i > 0; linePtr++, i--) {
        !           995: 
        !           996:        /*
        !           997:         * If the point is inside the line's rectangle, then can
        !           998:         * return immediately.
        !           999:         */
        !          1000:     
        !          1001:        if ((pointPtr[0] >= linePtr->x1)
        !          1002:                && (pointPtr[0] <= linePtr->x2)
        !          1003:                && (pointPtr[1] >= linePtr->y1)
        !          1004:                && (pointPtr[1] <= linePtr->y2)) {
        !          1005:            return 0.0;
        !          1006:        }
        !          1007:     
        !          1008:        /*
        !          1009:         * Point is outside line's rectangle; compute distance to nearest
        !          1010:         * side.
        !          1011:         */
        !          1012:     
        !          1013:        if (pointPtr[0] < linePtr->x1) {
        !          1014:            xDiff = linePtr->x1 - pointPtr[0];
        !          1015:        } else if (pointPtr[0] > linePtr->x2)  {
        !          1016:            xDiff = pointPtr[0] - linePtr->x2;
        !          1017:        } else {
        !          1018:            xDiff = 0;
        !          1019:        }
        !          1020:     
        !          1021:        if (pointPtr[1] < linePtr->y1) {
        !          1022:            yDiff = linePtr->y1 - pointPtr[1];
        !          1023:        } else if (pointPtr[1] > linePtr->y2)  {
        !          1024:            yDiff = pointPtr[1] - linePtr->y2;
        !          1025:        } else {
        !          1026:            yDiff = 0;
        !          1027:        }
        !          1028: 
        !          1029:        dist = hypot((float) xDiff, (float) yDiff);
        !          1030:        if ((dist < minDist) || (minDist < 0.0)) {
        !          1031:            minDist = dist;
        !          1032:        }
        !          1033:     }
        !          1034:     return minDist;
        !          1035: }
        !          1036: 
        !          1037: /*
        !          1038:  *--------------------------------------------------------------
        !          1039:  *
        !          1040:  * TextToArea --
        !          1041:  *
        !          1042:  *     This procedure is called to determine whether an item
        !          1043:  *     lies entirely inside, entirely outside, or overlapping
        !          1044:  *     a given rectangle.
        !          1045:  *
        !          1046:  * Results:
        !          1047:  *     -1 is returned if the item is entirely outside the area
        !          1048:  *     given by rectPtr, 0 if it overlaps, and 1 if it is entirely
        !          1049:  *     inside the given area.
        !          1050:  *
        !          1051:  * Side effects:
        !          1052:  *     None.
        !          1053:  *
        !          1054:  *--------------------------------------------------------------
        !          1055:  */
        !          1056: 
        !          1057:        /* ARGSUSED */
        !          1058: static int
        !          1059: TextToArea(canvasPtr, itemPtr, rectPtr)
        !          1060:     Tk_Canvas *canvasPtr;      /* Canvas containing itemPtr. */
        !          1061:     Tk_Item *itemPtr;          /* Item to check against rectangle. */
        !          1062:     double *rectPtr;           /* Pointer to array of four coordinates
        !          1063:                                 * (x1, y1, x2, y2) describing rectangular
        !          1064:                                 * area.  */
        !          1065: {
        !          1066:     TextItem *textPtr = (TextItem *) itemPtr;
        !          1067:     register TextLine *linePtr;
        !          1068:     int i, result;
        !          1069: 
        !          1070:     /*
        !          1071:      * Scan the lines one at a time, seeing whether each line is
        !          1072:      * entirely in, entirely out, or overlapping the rectangle.  If
        !          1073:      * an overlap is detected, return immediately;  otherwise wait
        !          1074:      * until all lines have been processed and see if they were all
        !          1075:      * inside or all outside.
        !          1076:      */
        !          1077: 
        !          1078:     result = 0;
        !          1079:     for (linePtr = textPtr->linePtr, i = textPtr->numLines;
        !          1080:            i > 0; linePtr++, i--) {
        !          1081:        if ((rectPtr[2] < linePtr->x1) || (rectPtr[0] > linePtr->x2)
        !          1082:                || (rectPtr[3] < linePtr->y1) || (rectPtr[1] > linePtr->y2)) {
        !          1083:            if (result == 1) {
        !          1084:                return 0;
        !          1085:            }
        !          1086:            result = -1;
        !          1087:            continue;
        !          1088:        }
        !          1089:        if ((linePtr->x1 < rectPtr[0]) || (linePtr->x2 > rectPtr[2])
        !          1090:                || (linePtr->y1 < rectPtr[1]) || (linePtr->y2 > rectPtr[3])) {
        !          1091:            return 0;
        !          1092:        }
        !          1093:        if (result == -1) {
        !          1094:            return 0;
        !          1095:        }
        !          1096:        result = 1;
        !          1097:     }
        !          1098:     return result;
        !          1099: }
        !          1100: 
        !          1101: /*
        !          1102:  *--------------------------------------------------------------
        !          1103:  *
        !          1104:  * ScaleText --
        !          1105:  *
        !          1106:  *     This procedure is invoked to rescale a text item.
        !          1107:  *
        !          1108:  * Results:
        !          1109:  *     None.
        !          1110:  *
        !          1111:  * Side effects:
        !          1112:  *     Scales the position of the text, but not the size
        !          1113:  *     of the font for the text.
        !          1114:  *
        !          1115:  *--------------------------------------------------------------
        !          1116:  */
        !          1117: 
        !          1118:        /* ARGSUSED */
        !          1119: static void
        !          1120: ScaleText(canvasPtr, itemPtr, originX, originY, scaleX, scaleY)
        !          1121:     Tk_Canvas *canvasPtr;              /* Canvas containing rectangle. */
        !          1122:     Tk_Item *itemPtr;                  /* Rectangle to be scaled. */
        !          1123:     double originX, originY;           /* Origin about which to scale rect. */
        !          1124:     double scaleX;                     /* Amount to scale in X direction. */
        !          1125:     double scaleY;                     /* Amount to scale in Y direction. */
        !          1126: {
        !          1127:     register TextItem *textPtr = (TextItem *) itemPtr;
        !          1128: 
        !          1129:     textPtr->x = originX + scaleX*(textPtr->x - originX);
        !          1130:     textPtr->y = originY + scaleY*(textPtr->y - originY);
        !          1131:     ComputeTextBbox(canvasPtr, textPtr);
        !          1132:     return;
        !          1133: }
        !          1134: 
        !          1135: /*
        !          1136:  *--------------------------------------------------------------
        !          1137:  *
        !          1138:  * TranslateText --
        !          1139:  *
        !          1140:  *     This procedure is called to move a text item by a
        !          1141:  *     given amount.
        !          1142:  *
        !          1143:  * Results:
        !          1144:  *     None.
        !          1145:  *
        !          1146:  * Side effects:
        !          1147:  *     The position of the text item is offset by (xDelta, yDelta),
        !          1148:  *     and the bounding box is updated in the generic part of the
        !          1149:  *     item structure.
        !          1150:  *
        !          1151:  *--------------------------------------------------------------
        !          1152:  */
        !          1153: 
        !          1154: static void
        !          1155: TranslateText(canvasPtr, itemPtr, deltaX, deltaY)
        !          1156:     Tk_Canvas *canvasPtr;              /* Canvas containing item. */
        !          1157:     Tk_Item *itemPtr;                  /* Item that is being moved. */
        !          1158:     double deltaX, deltaY;             /* Amount by which item is to be
        !          1159:                                         * moved. */
        !          1160: {
        !          1161:     register TextItem *textPtr = (TextItem *) itemPtr;
        !          1162: 
        !          1163:     textPtr->x += deltaX;
        !          1164:     textPtr->y += deltaY;
        !          1165:     ComputeTextBbox(canvasPtr, textPtr);
        !          1166: }
        !          1167: 
        !          1168: /*
        !          1169:  *--------------------------------------------------------------
        !          1170:  *
        !          1171:  * GetTextIndex --
        !          1172:  *
        !          1173:  *     Parse an index into a text item and return either its value
        !          1174:  *     or an error.
        !          1175:  *
        !          1176:  * Results:
        !          1177:  *     A standard Tcl result.  If all went well, then *indexPtr is
        !          1178:  *     filled in with the index (into itemPtr) corresponding to
        !          1179:  *     string.  Otherwise an error message is left in
        !          1180:  *     canvasPtr->interp->result.
        !          1181:  *
        !          1182:  * Side effects:
        !          1183:  *     None.
        !          1184:  *
        !          1185:  *--------------------------------------------------------------
        !          1186:  */
        !          1187: 
        !          1188: static int
        !          1189: GetTextIndex(canvasPtr, itemPtr, string, indexPtr)
        !          1190:     Tk_Canvas *canvasPtr;      /* Canvas containing item. */
        !          1191:     Tk_Item *itemPtr;          /* Item for which the index is being
        !          1192:                                 * specified. */
        !          1193:     char *string;              /* Specification of a particular character
        !          1194:                                 * in itemPtr's text. */
        !          1195:     int *indexPtr;             /* Where to store converted index. */
        !          1196: {
        !          1197:     register TextItem *textPtr = (TextItem *) itemPtr;
        !          1198:     int length;
        !          1199: 
        !          1200:     length = strlen(string);
        !          1201: 
        !          1202:     if (string[0] == 'e') {
        !          1203:        if (strncmp(string, "end", length) == 0) {
        !          1204:            *indexPtr = textPtr->numChars;
        !          1205:        } else {
        !          1206:            badIndex:
        !          1207: 
        !          1208:            /*
        !          1209:             * Some of the paths here leave messages in
        !          1210:             * canvasPtr->interp->result, so we have to clear it out
        !          1211:             * before storing our own message.
        !          1212:             */
        !          1213: 
        !          1214:            Tcl_SetResult(canvasPtr->interp, (char *) NULL, TCL_STATIC);
        !          1215:            Tcl_AppendResult(canvasPtr->interp, "bad index \"", string,
        !          1216:                    "\"", (char *) NULL);
        !          1217:            return TCL_ERROR;
        !          1218:        }
        !          1219:     } else if (string[0] == 'c') {
        !          1220:        if (strncmp(string, "cursor", length) == 0) {
        !          1221:            *indexPtr = textPtr->cursorPos;
        !          1222:        } else {
        !          1223:            goto badIndex;
        !          1224:        }
        !          1225:     } else if (string[0] == 's') {
        !          1226:        if (canvasPtr->selItemPtr != itemPtr) {
        !          1227:            canvasPtr->interp->result = "selection isn't in item";
        !          1228:            return TCL_ERROR;
        !          1229:        }
        !          1230:        if (length < 5) {
        !          1231:            goto badIndex;
        !          1232:        }
        !          1233:        if (strncmp(string, "sel.first", length) == 0) {
        !          1234:            *indexPtr = canvasPtr->selectFirst;
        !          1235:        } else if (strncmp(string, "sel.last", length) == 0) {
        !          1236:            *indexPtr = canvasPtr->selectLast;
        !          1237:        } else {
        !          1238:            goto badIndex;
        !          1239:        }
        !          1240:     } else if (string[0] == '@') {
        !          1241:        int x, y, dummy, i;
        !          1242:        char *end, *p;
        !          1243:        register TextLine *linePtr;
        !          1244: 
        !          1245:        p = string+1;
        !          1246:        x = strtol(p, &end, 0);
        !          1247:        if ((end == p) || (*end != ',')) {
        !          1248:            goto badIndex;
        !          1249:        }
        !          1250:        p = end+1;
        !          1251:        y = strtol(p, &end, 0);
        !          1252:        if ((end == p) || (*end != 0)) {
        !          1253:            goto badIndex;
        !          1254:        }
        !          1255:        if ((textPtr->numChars == 0) || (y < textPtr->linePtr[0].y1)) {
        !          1256:            *indexPtr = 0;
        !          1257:            return TCL_OK;
        !          1258:        }
        !          1259:        for (i = 0, linePtr = textPtr->linePtr; ; i++, linePtr++) {
        !          1260:            if (i >= textPtr->numLines) {
        !          1261:                *indexPtr = textPtr->numChars;
        !          1262:                return TCL_OK;
        !          1263:            }
        !          1264:            if (y <= linePtr->y2) {
        !          1265:                break;
        !          1266:            }
        !          1267:        }
        !          1268:        *indexPtr = TkMeasureChars(textPtr->fontPtr, linePtr->firstChar,
        !          1269:                linePtr->numChars, linePtr->x, x, 0, &dummy);
        !          1270:        *indexPtr += linePtr->firstChar - textPtr->text;
        !          1271:     } else {
        !          1272:        if (Tcl_GetInt(canvasPtr->interp, string, indexPtr) != TCL_OK) {
        !          1273:            goto badIndex;
        !          1274:        }
        !          1275:        if (*indexPtr < 0){
        !          1276:            *indexPtr = 0;
        !          1277:        } else if (*indexPtr > textPtr->numChars) {
        !          1278:            *indexPtr = textPtr->numChars;
        !          1279:        }
        !          1280:     }
        !          1281:     return TCL_OK;
        !          1282: }
        !          1283: 
        !          1284: /*
        !          1285:  *--------------------------------------------------------------
        !          1286:  *
        !          1287:  * SetTextCursor --
        !          1288:  *
        !          1289:  *     Set the position of the insertion cursor in this item.
        !          1290:  *
        !          1291:  * Results:
        !          1292:  *     None.
        !          1293:  *
        !          1294:  * Side effects:
        !          1295:  *     The cursor position will change.
        !          1296:  *
        !          1297:  *--------------------------------------------------------------
        !          1298:  */
        !          1299: 
        !          1300:        /* ARGSUSED */
        !          1301: static void
        !          1302: SetTextCursor(canvasPtr, itemPtr, index)
        !          1303:     Tk_Canvas *canvasPtr;              /* Record describing canvas widget. */
        !          1304:     Tk_Item *itemPtr;                  /* Text item in which cursor position
        !          1305:                                         * is to be set. */
        !          1306:     int index;                         /* Index of character just before which
        !          1307:                                         * cursor is to be positioned. */
        !          1308: {
        !          1309:     register TextItem *textPtr = (TextItem *) itemPtr;
        !          1310: 
        !          1311:     if (index < 0) {
        !          1312:        textPtr->cursorPos = 0;
        !          1313:     } else  if (index > textPtr->numChars) {
        !          1314:        textPtr->cursorPos = textPtr->numChars;
        !          1315:     } else {
        !          1316:        textPtr->cursorPos = index;
        !          1317:     }
        !          1318: }
        !          1319: 
        !          1320: /*
        !          1321:  *--------------------------------------------------------------
        !          1322:  *
        !          1323:  * GetSelText --
        !          1324:  *
        !          1325:  *     This procedure is invoked to return the selected portion
        !          1326:  *     of a text item.  It is only called when this item has
        !          1327:  *     the selection.
        !          1328:  *
        !          1329:  * Results:
        !          1330:  *     The return value is the number of non-NULL bytes stored
        !          1331:  *     at buffer.  Buffer is filled (or partially filled) with a
        !          1332:  *     NULL-terminated string containing part or all of the selection,
        !          1333:  *     as given by offset and maxBytes.
        !          1334:  *
        !          1335:  * Side effects:
        !          1336:  *     None.
        !          1337:  *
        !          1338:  *--------------------------------------------------------------
        !          1339:  */
        !          1340: 
        !          1341: static int
        !          1342: GetSelText(canvasPtr, itemPtr, offset, buffer, maxBytes)
        !          1343:     Tk_Canvas *canvasPtr;              /* Canvas containing selection. */
        !          1344:     Tk_Item *itemPtr;                  /* Text item containing selection. */
        !          1345:     int offset;                                /* Offset within selection of first
        !          1346:                                         * character to be returned. */
        !          1347:     char *buffer;                      /* Location in which to place
        !          1348:                                         * selection. */
        !          1349:     int maxBytes;                      /* Maximum number of bytes to place
        !          1350:                                         * at buffer, not including terminating
        !          1351:                                         * NULL character. */
        !          1352: {
        !          1353:     TextItem *textPtr = (TextItem *) itemPtr;
        !          1354:     int count;
        !          1355: 
        !          1356:     count = canvasPtr->selectLast + 1 - canvasPtr->selectFirst - offset;
        !          1357:     if (canvasPtr->selectLast == textPtr->numChars) {
        !          1358:        count -= 1;
        !          1359:     }
        !          1360:     if (count > maxBytes) {
        !          1361:        count = maxBytes;
        !          1362:     }
        !          1363:     if (count <= 0) {
        !          1364:        return 0;
        !          1365:     }
        !          1366:     strncpy(buffer, textPtr->text + canvasPtr->selectFirst + offset, count);
        !          1367:     buffer[count] = '\0';
        !          1368:     return count;
        !          1369: }

unix.superglobalmegacorp.com

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