1/* 2 * tkCanvImg.c -- 3 * 4 * This file implements image items for canvas widgets. 5 * 6 * Copyright (c) 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 19/* 20 * The structure below defines the record for each image item. 21 */ 22 23typedef struct ImageItem { 24 Tk_Item header; /* Generic stuff that's the same for all 25 * types. MUST BE FIRST IN STRUCTURE. */ 26 Tk_Canvas canvas; /* Canvas containing the image. */ 27 double x, y; /* Coordinates of positioning point for 28 * image. */ 29 Tk_Anchor anchor; /* Where to anchor image relative to (x,y). */ 30 char *imageString; /* String describing -image option 31 * (malloc-ed). NULL means no image right 32 * now. */ 33 char *activeImageString; /* String describing -activeimage option. 34 * NULL means no image right now. */ 35 char *disabledImageString; /* String describing -disabledimage option. 36 * NULL means no image right now. */ 37 Tk_Image image; /* Image to display in window, or NULL if no 38 * image at present. */ 39 Tk_Image activeImage; /* Image to display in window, or NULL if no 40 * image at present. */ 41 Tk_Image disabledImage; /* Image to display in window, or NULL if no 42 * image at present. */ 43} ImageItem; 44 45/* 46 * Information used for parsing configuration specs: 47 */ 48 49static Tk_CustomOption stateOption = { 50 (Tk_OptionParseProc *) TkStateParseProc, 51 TkStatePrintProc, (ClientData) 2 52}; 53static Tk_CustomOption tagsOption = { 54 (Tk_OptionParseProc *) Tk_CanvasTagsParseProc, 55 Tk_CanvasTagsPrintProc, (ClientData) NULL 56}; 57 58static Tk_ConfigSpec configSpecs[] = { 59 {TK_CONFIG_STRING, "-activeimage", NULL, NULL, 60 NULL, Tk_Offset(ImageItem, activeImageString), TK_CONFIG_NULL_OK}, 61 {TK_CONFIG_ANCHOR, "-anchor", NULL, NULL, 62 "center", Tk_Offset(ImageItem, anchor), TK_CONFIG_DONT_SET_DEFAULT}, 63 {TK_CONFIG_STRING, "-disabledimage", NULL, NULL, 64 NULL, Tk_Offset(ImageItem, disabledImageString), TK_CONFIG_NULL_OK}, 65 {TK_CONFIG_STRING, "-image", NULL, NULL, 66 NULL, Tk_Offset(ImageItem, imageString), TK_CONFIG_NULL_OK}, 67 {TK_CONFIG_CUSTOM, "-state", NULL, NULL, 68 NULL, Tk_Offset(Tk_Item, state), TK_CONFIG_NULL_OK, &stateOption}, 69 {TK_CONFIG_CUSTOM, "-tags", NULL, NULL, 70 NULL, 0, TK_CONFIG_NULL_OK, &tagsOption}, 71 {TK_CONFIG_END, NULL, NULL, NULL, NULL, 0, 0} 72}; 73 74/* 75 * Prototypes for functions defined in this file: 76 */ 77 78static void ImageChangedProc(ClientData clientData, 79 int x, int y, int width, int height, int imgWidth, 80 int imgHeight); 81static int ImageCoords(Tcl_Interp *interp, 82 Tk_Canvas canvas, Tk_Item *itemPtr, int argc, 83 Tcl_Obj *CONST argv[]); 84static int ImageToArea(Tk_Canvas canvas, 85 Tk_Item *itemPtr, double *rectPtr); 86static double ImageToPoint(Tk_Canvas canvas, 87 Tk_Item *itemPtr, double *coordPtr); 88static int ImageToPostscript(Tcl_Interp *interp, 89 Tk_Canvas canvas, Tk_Item *itemPtr, int prepass); 90static void ComputeImageBbox(Tk_Canvas canvas, ImageItem *imgPtr); 91static int ConfigureImage(Tcl_Interp *interp, 92 Tk_Canvas canvas, Tk_Item *itemPtr, int argc, 93 Tcl_Obj *CONST argv[], int flags); 94static int CreateImage(Tcl_Interp *interp, 95 Tk_Canvas canvas, struct Tk_Item *itemPtr, 96 int argc, Tcl_Obj *CONST argv[]); 97static void DeleteImage(Tk_Canvas canvas, 98 Tk_Item *itemPtr, Display *display); 99static void DisplayImage(Tk_Canvas canvas, 100 Tk_Item *itemPtr, Display *display, Drawable dst, 101 int x, int y, int width, int height); 102static void ScaleImage(Tk_Canvas canvas, 103 Tk_Item *itemPtr, double originX, double originY, 104 double scaleX, double scaleY); 105static void TranslateImage(Tk_Canvas canvas, 106 Tk_Item *itemPtr, double deltaX, double deltaY); 107 108/* 109 * The structures below defines the image item type in terms of functions that 110 * can be invoked by generic item code. 111 */ 112 113Tk_ItemType tkImageType = { 114 "image", /* name */ 115 sizeof(ImageItem), /* itemSize */ 116 CreateImage, /* createProc */ 117 configSpecs, /* configSpecs */ 118 ConfigureImage, /* configureProc */ 119 ImageCoords, /* coordProc */ 120 DeleteImage, /* deleteProc */ 121 DisplayImage, /* displayProc */ 122 TK_CONFIG_OBJS, /* flags */ 123 ImageToPoint, /* pointProc */ 124 ImageToArea, /* areaProc */ 125 ImageToPostscript, /* postscriptProc */ 126 ScaleImage, /* scaleProc */ 127 TranslateImage, /* translateProc */ 128 NULL, /* indexProc */ 129 NULL, /* icursorProc */ 130 NULL, /* selectionProc */ 131 NULL, /* insertProc */ 132 NULL, /* dTextProc */ 133 NULL, /* nextPtr */ 134}; 135 136/* 137 *-------------------------------------------------------------- 138 * 139 * CreateImage -- 140 * 141 * This function is invoked to create a new image item in a canvas. 142 * 143 * Results: 144 * A standard Tcl return value. If an error occurred in creating the 145 * item, then an error message is left in the interp's result; in this 146 * case itemPtr is left uninitialized, so it can be safely freed by the 147 * caller. 148 * 149 * Side effects: 150 * A new image item is created. 151 * 152 *-------------------------------------------------------------- 153 */ 154 155static int 156CreateImage( 157 Tcl_Interp *interp, /* Interpreter for error reporting. */ 158 Tk_Canvas canvas, /* Canvas to hold new item. */ 159 Tk_Item *itemPtr, /* Record to hold new item; header has been 160 * initialized by caller. */ 161 int objc, /* Number of arguments in objv. */ 162 Tcl_Obj *CONST objv[]) /* Arguments describing rectangle. */ 163{ 164 ImageItem *imgPtr = (ImageItem *) itemPtr; 165 int i; 166 167 if (objc == 0) { 168 Tcl_Panic("canvas did not pass any coords\n"); 169 } 170 171 /* 172 * Initialize item's record. 173 */ 174 175 imgPtr->canvas = canvas; 176 imgPtr->anchor = TK_ANCHOR_CENTER; 177 imgPtr->imageString = NULL; 178 imgPtr->activeImageString = NULL; 179 imgPtr->disabledImageString = NULL; 180 imgPtr->image = NULL; 181 imgPtr->activeImage = NULL; 182 imgPtr->disabledImage = NULL; 183 184 /* 185 * Process the arguments to fill in the item record. Only 1 (list) or 2 (x 186 * y) coords are allowed. 187 */ 188 189 if (objc == 1) { 190 i = 1; 191 } else { 192 char *arg = Tcl_GetString(objv[1]); 193 i = 2; 194 if ((arg[0] == '-') && (arg[1] >= 'a') && (arg[1] <= 'z')) { 195 i = 1; 196 } 197 } 198 if ((ImageCoords(interp, canvas, itemPtr, i, objv) != TCL_OK)) { 199 goto error; 200 } 201 if (ConfigureImage(interp, canvas, itemPtr, objc-i, objv+i, 0) == TCL_OK) { 202 return TCL_OK; 203 } 204 205 error: 206 DeleteImage(canvas, itemPtr, Tk_Display(Tk_CanvasTkwin(canvas))); 207 return TCL_ERROR; 208} 209 210/* 211 *-------------------------------------------------------------- 212 * 213 * ImageCoords -- 214 * 215 * This function is invoked to process the "coords" widget command on 216 * image items. See the user documentation for details on what it does. 217 * 218 * Results: 219 * Returns TCL_OK or TCL_ERROR, and sets the interp's result. 220 * 221 * Side effects: 222 * The coordinates for the given item may be changed. 223 * 224 *-------------------------------------------------------------- 225 */ 226 227static int 228ImageCoords( 229 Tcl_Interp *interp, /* Used for error reporting. */ 230 Tk_Canvas canvas, /* Canvas containing item. */ 231 Tk_Item *itemPtr, /* Item whose coordinates are to be read or 232 * modified. */ 233 int objc, /* Number of coordinates supplied in objv. */ 234 Tcl_Obj *CONST objv[]) /* Array of coordinates: x1, y1, x2, y2, ... */ 235{ 236 ImageItem *imgPtr = (ImageItem *) itemPtr; 237 238 if (objc == 0) { 239 Tcl_Obj *obj = Tcl_NewObj(); 240 241 Tcl_Obj *subobj = Tcl_NewDoubleObj(imgPtr->x); 242 Tcl_ListObjAppendElement(interp, obj, subobj); 243 subobj = Tcl_NewDoubleObj(imgPtr->y); 244 Tcl_ListObjAppendElement(interp, obj, subobj); 245 Tcl_SetObjResult(interp, obj); 246 } else if (objc < 3) { 247 if (objc==1) { 248 if (Tcl_ListObjGetElements(interp, objv[0], &objc, 249 (Tcl_Obj ***) &objv) != TCL_OK) { 250 return TCL_ERROR; 251 } else if (objc != 2) { 252 char buf[64]; 253 254 sprintf(buf, "wrong # coordinates: expected 2, got %d", objc); 255 Tcl_SetResult(interp, buf, TCL_VOLATILE); 256 return TCL_ERROR; 257 } 258 } 259 if ((Tk_CanvasGetCoordFromObj(interp, canvas, objv[0], &imgPtr->x) != TCL_OK) 260 || (Tk_CanvasGetCoordFromObj(interp, canvas, objv[1], 261 &imgPtr->y) != TCL_OK)) { 262 return TCL_ERROR; 263 } 264 ComputeImageBbox(canvas, imgPtr); 265 } else { 266 char buf[64]; 267 268 sprintf(buf, "wrong # coordinates: expected 0 or 2, got %d", objc); 269 Tcl_SetResult(interp, buf, TCL_VOLATILE); 270 return TCL_ERROR; 271 } 272 return TCL_OK; 273} 274 275/* 276 *-------------------------------------------------------------- 277 * 278 * ConfigureImage -- 279 * 280 * This function is invoked to configure various aspects of an image 281 * item, such as its anchor position. 282 * 283 * Results: 284 * A standard Tcl result code. If an error occurs, then an error message 285 * is left in the interp's result. 286 * 287 * Side effects: 288 * Configuration information may be set for itemPtr. 289 * 290 *-------------------------------------------------------------- 291 */ 292 293static int 294ConfigureImage( 295 Tcl_Interp *interp, /* Used for error reporting. */ 296 Tk_Canvas canvas, /* Canvas containing itemPtr. */ 297 Tk_Item *itemPtr, /* Image item to reconfigure. */ 298 int objc, /* Number of elements in objv. */ 299 Tcl_Obj *CONST objv[], /* Arguments describing things to configure. */ 300 int flags) /* Flags to pass to Tk_ConfigureWidget. */ 301{ 302 ImageItem *imgPtr = (ImageItem *) itemPtr; 303 Tk_Window tkwin; 304 Tk_Image image; 305 306 tkwin = Tk_CanvasTkwin(canvas); 307 if (TCL_OK != Tk_ConfigureWidget(interp, tkwin, configSpecs, objc, 308 (CONST char **) objv, (char *) imgPtr, flags|TK_CONFIG_OBJS)) { 309 return TCL_ERROR; 310 } 311 312 /* 313 * Create the image. Save the old image around and don't free it until 314 * after the new one is allocated. This keeps the reference count from 315 * going to zero so the image doesn't have to be recreated if it hasn't 316 * changed. 317 */ 318 319 if (imgPtr->activeImageString != NULL) { 320 itemPtr->redraw_flags |= TK_ITEM_STATE_DEPENDANT; 321 } else { 322 itemPtr->redraw_flags &= ~TK_ITEM_STATE_DEPENDANT; 323 } 324 if (imgPtr->imageString != NULL) { 325 image = Tk_GetImage(interp, tkwin, imgPtr->imageString, 326 ImageChangedProc, (ClientData) imgPtr); 327 if (image == NULL) { 328 return TCL_ERROR; 329 } 330 } else { 331 image = NULL; 332 } 333 if (imgPtr->image != NULL) { 334 Tk_FreeImage(imgPtr->image); 335 } 336 imgPtr->image = image; 337 if (imgPtr->activeImageString != NULL) { 338 image = Tk_GetImage(interp, tkwin, imgPtr->activeImageString, 339 ImageChangedProc, (ClientData) imgPtr); 340 if (image == NULL) { 341 return TCL_ERROR; 342 } 343 } else { 344 image = NULL; 345 } 346 if (imgPtr->activeImage != NULL) { 347 Tk_FreeImage(imgPtr->activeImage); 348 } 349 imgPtr->activeImage = image; 350 if (imgPtr->disabledImageString != NULL) { 351 image = Tk_GetImage(interp, tkwin, imgPtr->disabledImageString, 352 ImageChangedProc, (ClientData) imgPtr); 353 if (image == NULL) { 354 return TCL_ERROR; 355 } 356 } else { 357 image = NULL; 358 } 359 if (imgPtr->disabledImage != NULL) { 360 Tk_FreeImage(imgPtr->disabledImage); 361 } 362 imgPtr->disabledImage = image; 363 ComputeImageBbox(canvas, imgPtr); 364 return TCL_OK; 365} 366 367/* 368 *-------------------------------------------------------------- 369 * 370 * DeleteImage -- 371 * 372 * This function is called to clean up the data structure associated with 373 * a image item. 374 * 375 * Results: 376 * None. 377 * 378 * Side effects: 379 * Resources associated with itemPtr are released. 380 * 381 *-------------------------------------------------------------- 382 */ 383 384static void 385DeleteImage( 386 Tk_Canvas canvas, /* Info about overall canvas widget. */ 387 Tk_Item *itemPtr, /* Item that is being deleted. */ 388 Display *display) /* Display containing window for canvas. */ 389{ 390 ImageItem *imgPtr = (ImageItem *) itemPtr; 391 392 if (imgPtr->imageString != NULL) { 393 ckfree(imgPtr->imageString); 394 } 395 if (imgPtr->activeImageString != NULL) { 396 ckfree(imgPtr->activeImageString); 397 } 398 if (imgPtr->disabledImageString != NULL) { 399 ckfree(imgPtr->disabledImageString); 400 } 401 if (imgPtr->image != NULL) { 402 Tk_FreeImage(imgPtr->image); 403 } 404 if (imgPtr->activeImage != NULL) { 405 Tk_FreeImage(imgPtr->activeImage); 406 } 407 if (imgPtr->disabledImage != NULL) { 408 Tk_FreeImage(imgPtr->disabledImage); 409 } 410} 411 412/* 413 *-------------------------------------------------------------- 414 * 415 * ComputeImageBbox -- 416 * 417 * This function is invoked to compute the bounding box of all the pixels 418 * that may be drawn as part of a image item. This function is where the 419 * child image's placement is computed. 420 * 421 * Results: 422 * None. 423 * 424 * Side effects: 425 * The fields x1, y1, x2, and y2 are updated in the header for itemPtr. 426 * 427 *-------------------------------------------------------------- 428 */ 429 430 /* ARGSUSED */ 431static void 432ComputeImageBbox( 433 Tk_Canvas canvas, /* Canvas that contains item. */ 434 ImageItem *imgPtr) /* Item whose bbox is to be recomputed. */ 435{ 436 int width, height; 437 int x, y; 438 Tk_Image image; 439 Tk_State state = imgPtr->header.state; 440 441 if(state == TK_STATE_NULL) { 442 state = ((TkCanvas *)canvas)->canvas_state; 443 } 444 image = imgPtr->image; 445 if (((TkCanvas *)canvas)->currentItemPtr == (Tk_Item *)imgPtr) { 446 if (imgPtr->activeImage != NULL) { 447 image = imgPtr->activeImage; 448 } 449 } else if (state == TK_STATE_DISABLED) { 450 if (imgPtr->disabledImage != NULL) { 451 image = imgPtr->disabledImage; 452 } 453 } 454 455 x = (int) (imgPtr->x + ((imgPtr->x >= 0) ? 0.5 : - 0.5)); 456 y = (int) (imgPtr->y + ((imgPtr->y >= 0) ? 0.5 : - 0.5)); 457 458 if ((state == TK_STATE_HIDDEN) || (image == None)) { 459 imgPtr->header.x1 = imgPtr->header.x2 = x; 460 imgPtr->header.y1 = imgPtr->header.y2 = y; 461 return; 462 } 463 464 /* 465 * Compute location and size of image, using anchor information. 466 */ 467 468 Tk_SizeOfImage(image, &width, &height); 469 switch (imgPtr->anchor) { 470 case TK_ANCHOR_N: 471 x -= width/2; 472 break; 473 case TK_ANCHOR_NE: 474 x -= width; 475 break; 476 case TK_ANCHOR_E: 477 x -= width; 478 y -= height/2; 479 break; 480 case TK_ANCHOR_SE: 481 x -= width; 482 y -= height; 483 break; 484 case TK_ANCHOR_S: 485 x -= width/2; 486 y -= height; 487 break; 488 case TK_ANCHOR_SW: 489 y -= height; 490 break; 491 case TK_ANCHOR_W: 492 y -= height/2; 493 break; 494 case TK_ANCHOR_NW: 495 break; 496 case TK_ANCHOR_CENTER: 497 x -= width/2; 498 y -= height/2; 499 break; 500 } 501 502 /* 503 * Store the information in the item header. 504 */ 505 506 imgPtr->header.x1 = x; 507 imgPtr->header.y1 = y; 508 imgPtr->header.x2 = x + width; 509 imgPtr->header.y2 = y + height; 510} 511 512/* 513 *-------------------------------------------------------------- 514 * 515 * DisplayImage -- 516 * 517 * This function is invoked to draw a image item in a given drawable. 518 * 519 * Results: 520 * None. 521 * 522 * Side effects: 523 * ItemPtr is drawn in drawable using the transformation information in 524 * canvas. 525 * 526 *-------------------------------------------------------------- 527 */ 528 529static void 530DisplayImage( 531 Tk_Canvas canvas, /* Canvas that contains item. */ 532 Tk_Item *itemPtr, /* Item to be displayed. */ 533 Display *display, /* Display on which to draw item. */ 534 Drawable drawable, /* Pixmap or window in which to draw item. */ 535 int x, int y, int width, int height) 536 /* Describes region of canvas that must be 537 * redisplayed (not used). */ 538{ 539 ImageItem *imgPtr = (ImageItem *) itemPtr; 540 short drawableX, drawableY; 541 Tk_Image image; 542 Tk_State state = itemPtr->state; 543 544 if (state == TK_STATE_NULL) { 545 state = ((TkCanvas *)canvas)->canvas_state; 546 } 547 548 image = imgPtr->image; 549 if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) { 550 if (imgPtr->activeImage != NULL) { 551 image = imgPtr->activeImage; 552 } 553 } else if (state == TK_STATE_DISABLED) { 554 if (imgPtr->disabledImage != NULL) { 555 image = imgPtr->disabledImage; 556 } 557 } 558 559 if (image == NULL) { 560 return; 561 } 562 563 /* 564 * Translate the coordinates to those of the image, then redisplay it. 565 */ 566 567 Tk_CanvasDrawableCoords(canvas, (double) x, (double) y, 568 &drawableX, &drawableY); 569 Tk_RedrawImage(image, x - imgPtr->header.x1, y - imgPtr->header.y1, 570 width, height, drawable, drawableX, drawableY); 571} 572 573/* 574 *-------------------------------------------------------------- 575 * 576 * ImageToPoint -- 577 * 578 * Computes the distance from a given point to a given rectangle, in 579 * canvas units. 580 * 581 * Results: 582 * The return value is 0 if the point whose x and y coordinates are 583 * coordPtr[0] and coordPtr[1] is inside the image. If the point isn't 584 * inside the image then the return value is the distance from the point 585 * to the image. 586 * 587 * Side effects: 588 * None. 589 * 590 *-------------------------------------------------------------- 591 */ 592 593static double 594ImageToPoint( 595 Tk_Canvas canvas, /* Canvas containing item. */ 596 Tk_Item *itemPtr, /* Item to check against point. */ 597 double *coordPtr) /* Pointer to x and y coordinates. */ 598{ 599 ImageItem *imgPtr = (ImageItem *) itemPtr; 600 double x1, x2, y1, y2, xDiff, yDiff; 601 602 x1 = imgPtr->header.x1; 603 y1 = imgPtr->header.y1; 604 x2 = imgPtr->header.x2; 605 y2 = imgPtr->header.y2; 606 607 /* 608 * Point is outside rectangle. 609 */ 610 611 if (coordPtr[0] < x1) { 612 xDiff = x1 - coordPtr[0]; 613 } else if (coordPtr[0] > x2) { 614 xDiff = coordPtr[0] - x2; 615 } else { 616 xDiff = 0; 617 } 618 619 if (coordPtr[1] < y1) { 620 yDiff = y1 - coordPtr[1]; 621 } else if (coordPtr[1] > y2) { 622 yDiff = coordPtr[1] - y2; 623 } else { 624 yDiff = 0; 625 } 626 627 return hypot(xDiff, yDiff); 628} 629 630/* 631 *-------------------------------------------------------------- 632 * 633 * ImageToArea -- 634 * 635 * This function is called to determine whether an item lies entirely 636 * inside, entirely outside, or overlapping a given rectangle. 637 * 638 * Results: 639 * -1 is returned if the item is entirely outside the area given by 640 * rectPtr, 0 if it overlaps, and 1 if it is entirely inside the given 641 * area. 642 * 643 * Side effects: 644 * None. 645 * 646 *-------------------------------------------------------------- 647 */ 648 649static int 650ImageToArea( 651 Tk_Canvas canvas, /* Canvas containing item. */ 652 Tk_Item *itemPtr, /* Item to check against rectangle. */ 653 double *rectPtr) /* Pointer to array of four coordinates 654 * (x1,y1,x2,y2) describing rectangular 655 * area. */ 656{ 657 ImageItem *imgPtr = (ImageItem *) itemPtr; 658 659 if ((rectPtr[2] <= imgPtr->header.x1) 660 || (rectPtr[0] >= imgPtr->header.x2) 661 || (rectPtr[3] <= imgPtr->header.y1) 662 || (rectPtr[1] >= imgPtr->header.y2)) { 663 return -1; 664 } 665 if ((rectPtr[0] <= imgPtr->header.x1) 666 && (rectPtr[1] <= imgPtr->header.y1) 667 && (rectPtr[2] >= imgPtr->header.x2) 668 && (rectPtr[3] >= imgPtr->header.y2)) { 669 return 1; 670 } 671 return 0; 672} 673 674/* 675 *-------------------------------------------------------------- 676 * 677 * ImageToPostscript -- 678 * 679 * This function is called to generate Postscript for image items. 680 * 681 * Results: 682 * The return value is a standard Tcl result. If an error occurs in 683 * generating Postscript then an error message is left in interp->result, 684 * replacing whatever used to be there. If no error occurs, then 685 * Postscript for the item is appended to the result. 686 * 687 * Side effects: 688 * None. 689 * 690 *-------------------------------------------------------------- 691 */ 692 693static int 694ImageToPostscript( 695 Tcl_Interp *interp, /* Leave Postscript or error message here. */ 696 Tk_Canvas canvas, /* Information about overall canvas. */ 697 Tk_Item *itemPtr, /* Item for which Postscript is wanted. */ 698 int prepass) /* 1 means this is a prepass to collect font 699 * information; 0 means final Postscript is 700 * being created.*/ 701{ 702 ImageItem *imgPtr = (ImageItem *)itemPtr; 703 Tk_Window canvasWin = Tk_CanvasTkwin(canvas); 704 705 char buffer[256]; 706 double x, y; 707 int width, height; 708 Tk_Image image; 709 Tk_State state = itemPtr->state; 710 711 if(state == TK_STATE_NULL) { 712 state = ((TkCanvas *)canvas)->canvas_state; 713 } 714 715 image = imgPtr->image; 716 if (((TkCanvas *)canvas)->currentItemPtr == itemPtr) { 717 if (imgPtr->activeImage != NULL) { 718 image = imgPtr->activeImage; 719 } 720 } else if (state == TK_STATE_DISABLED) { 721 if (imgPtr->disabledImage != NULL) { 722 image = imgPtr->disabledImage; 723 } 724 } 725 if (image == NULL) { 726 /* 727 * Image item without actual image specified. 728 */ 729 730 return TCL_OK; 731 } 732 Tk_SizeOfImage(image, &width, &height); 733 734 /* 735 * Compute the coordinates of the lower-left corner of the image, taking 736 * into account the anchor position for the image. 737 */ 738 739 x = imgPtr->x; 740 y = Tk_CanvasPsY(canvas, imgPtr->y); 741 742 switch (imgPtr->anchor) { 743 case TK_ANCHOR_NW: y -= height; break; 744 case TK_ANCHOR_N: x -= width/2.0; y -= height; break; 745 case TK_ANCHOR_NE: x -= width; y -= height; break; 746 case TK_ANCHOR_E: x -= width; y -= height/2.0; break; 747 case TK_ANCHOR_SE: x -= width; break; 748 case TK_ANCHOR_S: x -= width/2.0; break; 749 case TK_ANCHOR_SW: break; 750 case TK_ANCHOR_W: y -= height/2.0; break; 751 case TK_ANCHOR_CENTER: x -= width/2.0; y -= height/2.0; break; 752 } 753 754 if (!prepass) { 755 sprintf(buffer, "%.15g %.15g", x, y); 756 Tcl_AppendResult(interp, buffer, " translate\n", NULL); 757 } 758 759 return Tk_PostscriptImage(image, interp, canvasWin, 760 ((TkCanvas *) canvas)->psInfo, 0, 0, width, height, prepass); 761} 762 763/* 764 *-------------------------------------------------------------- 765 * 766 * ScaleImage -- 767 * 768 * This function is invoked to rescale an item. 769 * 770 * Results: 771 * None. 772 * 773 * Side effects: 774 * The item referred to by itemPtr is rescaled so that the following 775 * transformation is applied to all point coordinates: 776 * x' = originX + scaleX*(x-originX) 777 * y' = originY + scaleY*(y-originY) 778 * 779 *-------------------------------------------------------------- 780 */ 781 782static void 783ScaleImage( 784 Tk_Canvas canvas, /* Canvas containing rectangle. */ 785 Tk_Item *itemPtr, /* Rectangle to be scaled. */ 786 double originX, double originY, 787 /* Origin about which to scale rect. */ 788 double scaleX, /* Amount to scale in X direction. */ 789 double scaleY) /* Amount to scale in Y direction. */ 790{ 791 ImageItem *imgPtr = (ImageItem *) itemPtr; 792 793 imgPtr->x = originX + scaleX*(imgPtr->x - originX); 794 imgPtr->y = originY + scaleY*(imgPtr->y - originY); 795 ComputeImageBbox(canvas, imgPtr); 796} 797 798/* 799 *-------------------------------------------------------------- 800 * 801 * TranslateImage -- 802 * 803 * This function is called to move an item by a given amount. 804 * 805 * Results: 806 * None. 807 * 808 * Side effects: 809 * The position of the item is offset by (xDelta, yDelta), and the 810 * bounding box is updated in the generic part of the item structure. 811 * 812 *-------------------------------------------------------------- 813 */ 814 815static void 816TranslateImage( 817 Tk_Canvas canvas, /* Canvas containing item. */ 818 Tk_Item *itemPtr, /* Item that is being moved. */ 819 double deltaX, double deltaY) 820 /* Amount by which item is to be moved. */ 821{ 822 ImageItem *imgPtr = (ImageItem *) itemPtr; 823 824 imgPtr->x += deltaX; 825 imgPtr->y += deltaY; 826 ComputeImageBbox(canvas, imgPtr); 827} 828 829/* 830 *---------------------------------------------------------------------- 831 * 832 * ImageChangedProc -- 833 * 834 * This function is invoked by the image code whenever the manager for an 835 * image does something that affects the image's size or how it is 836 * displayed. 837 * 838 * Results: 839 * None. 840 * 841 * Side effects: 842 * Arranges for the canvas to get redisplayed. 843 * 844 *---------------------------------------------------------------------- 845 */ 846 847static void 848ImageChangedProc( 849 ClientData clientData, /* Pointer to canvas item for image. */ 850 int x, int y, /* Upper left pixel (within image) that must 851 * be redisplayed. */ 852 int width, int height, /* Dimensions of area to redisplay (may be <= 853 * 0). */ 854 int imgWidth, int imgHeight)/* New dimensions of image. */ 855{ 856 ImageItem *imgPtr = (ImageItem *) clientData; 857 858 /* 859 * If the image's size changed and it's not anchored at its northwest 860 * corner then just redisplay the entire area of the image. This is a bit 861 * over-conservative, but we need to do something because a size change 862 * also means a position change. 863 */ 864 865 if (((imgPtr->header.x2 - imgPtr->header.x1) != imgWidth) 866 || ((imgPtr->header.y2 - imgPtr->header.y1) != imgHeight)) { 867 x = y = 0; 868 width = imgWidth; 869 height = imgHeight; 870 Tk_CanvasEventuallyRedraw(imgPtr->canvas, imgPtr->header.x1, 871 imgPtr->header.y1, imgPtr->header.x2, imgPtr->header.y2); 872 } 873 ComputeImageBbox(imgPtr->canvas, imgPtr); 874 Tk_CanvasEventuallyRedraw(imgPtr->canvas, imgPtr->header.x1 + x, 875 imgPtr->header.y1 + y, (int) (imgPtr->header.x1 + x + width), 876 (int) (imgPtr->header.y1 + y + height)); 877} 878 879/* 880 * Local Variables: 881 * mode: c 882 * c-basic-offset: 4 883 * fill-column: 78 884 * End: 885 */ 886