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