Annotation of micropolis/src/tk/tkcvtext.c, revision 1.1.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.