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