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