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