tkCanvText.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:45k
源码类别:

通讯编程

开发平台:

Visual C++

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