1/* 2 * tkTreeDrag.c -- 3 * 4 * This module implements outline dragging for treectrl widgets. 5 * 6 * Copyright (c) 2002-2009 Tim Baker 7 * 8 * RCS: @(#) $Id: tkTreeDrag.c,v 1.34 2010/03/21 20:47:06 treectrl Exp $ 9 */ 10 11#include "tkTreeCtrl.h" 12 13typedef struct TreeDragImage_ TreeDragImage_; 14typedef struct DragElem DragElem; 15 16/* 17 * The following structure holds info about a single element of the drag 18 * image. 19 */ 20struct DragElem 21{ 22 int x, y, width, height; 23 DragElem *next; 24}; 25 26/* 27 * The following structure holds info about the drag image. There is one of 28 * these per TreeCtrl. 29 */ 30struct TreeDragImage_ 31{ 32 TreeCtrl *tree; 33 Tk_OptionTable optionTable; 34 int visible; 35 int x, y; /* offset to draw at in canvas coords */ 36 int bounds[4]; /* bounds of all DragElems */ 37 DragElem *elem; 38 int onScreen; /* TRUE if is displayed */ 39 int sx, sy; /* Window coords where displayed */ 40 int sw, sh; /* Width/height of previously-displayed image */ 41#ifdef DRAG_PIXMAP 42 int pixmapW, pixmapH; 43 Pixmap pixmap; 44 Tk_Image image; 45#endif /* DRAG_PIXMAP */ 46#ifdef DRAGIMAGE_STYLE 47 TreeStyle masterStyle; /* Style to create the drag image from. */ 48 TreeStyle instanceStyle; /* Style to create the drag image from. */ 49 int styleX, styleY; /* Mouse cursor hotspot offset into dragimage. */ 50 int styleW, styleH; /* Width/Height of dragimage style. */ 51 int pixmapW, pixmapH; /* Width/Height of 'pixmap'. */ 52 Pixmap pixmap; /* Pixmap -> Tk_Image. */ 53 Tk_Image tkimage; /* Transparent image that is drawn in the widget. */ 54#endif /* DRAGIMAGE_STYLE */ 55}; 56 57#define DRAG_CONF_VISIBLE 0x0001 58 59static Tk_OptionSpec optionSpecs[] = { 60#ifdef DRAGIMAGE_STYLE 61 {TK_OPTION_CUSTOM, "-style", (char *) NULL, (char *) NULL, 62 (char *) NULL, -1, Tk_Offset(TreeDragImage_, masterStyle), 63 TK_OPTION_NULL_OK, (ClientData) &TreeCtrlCO_style, 0}, 64#endif /* DRAGIMAGE_STYLE */ 65 {TK_OPTION_BOOLEAN, "-visible", (char *) NULL, (char *) NULL, 66 "0", -1, Tk_Offset(TreeDragImage_, visible), 67 0, (ClientData) NULL, DRAG_CONF_VISIBLE}, 68 {TK_OPTION_END, (char *) NULL, (char *) NULL, (char *) NULL, 69 (char *) NULL, 0, -1, 0, 0, 0} 70}; 71 72#ifdef DRAG_PIXMAP 73static void 74UpdateImage( 75 TreeDragImage dragImage /* Drag image record. */ 76 ) 77{ 78 TreeCtrl *tree = dragImage->tree; 79 Tk_PhotoHandle photoH; 80 XImage *ximage; 81 int width = dragImage->bounds[2] - dragImage->bounds[0]; 82 int height = dragImage->bounds[3] - dragImage->bounds[1]; 83 int alpha = 128; 84 XColor *colorPtr; 85 86 if (dragImage->image != NULL) { 87 Tk_FreeImage(dragImage->image); 88 dragImage->image = NULL; 89 } 90 91 photoH = Tk_FindPhoto(tree->interp, "::TreeCtrl::ImageDrag"); 92 if (photoH == NULL) { 93 Tcl_GlobalEval(tree->interp, "image create photo ::TreeCtrl::ImageDrag"); 94 photoH = Tk_FindPhoto(tree->interp, "::TreeCtrl::ImageDrag"); 95 if (photoH == NULL) 96 return; 97 } 98 99 /* Pixmap -> XImage */ 100 ximage = XGetImage(tree->display, dragImage->pixmap, 0, 0, 101 (unsigned int)width, (unsigned int)height, AllPlanes, ZPixmap); 102 if (ximage == NULL) 103 panic("tkTreeDrag.c:UpdateImage() ximage is NULL"); 104 105 /* XImage -> Tk_Image */ 106 colorPtr = Tk_GetColor(tree->interp, tree->tkwin, "pink"); 107 Tree_XImage2Photo(tree->interp, photoH, ximage, colorPtr->pixel, alpha); 108 109 XDestroyImage(ximage); 110 111 dragImage->image = Tk_GetImage(tree->interp, tree->tkwin, 112 "::TreeCtrl::ImageDrag", NULL, (ClientData) NULL); 113} 114 115static void 116UpdatePixmap( 117 TreeDragImage dragImage /* Drag image record. */ 118 ) 119{ 120 TreeCtrl *tree = dragImage->tree; 121 int w, h; 122 XColor *colorPtr; 123 GC gc; 124 DragElem *elem; 125 unsigned long trans; 126 127 w = dragImage->bounds[2] - dragImage->bounds[0]; 128 h = dragImage->bounds[3] - dragImage->bounds[1]; 129 if (w > dragImage->pixmapW || h > dragImage->pixmapH) 130 { 131 132 if (dragImage->pixmap != None) 133 Tk_FreePixmap(tree->display, dragImage->pixmap); 134 dragImage->pixmap = Tk_GetPixmap(tree->display, 135 Tk_WindowId(tree->tkwin), 136 w, h, Tk_Depth(tree->tkwin)); 137 138 dragImage->pixmapW = w; 139 dragImage->pixmapH = h; 140 } 141 142 colorPtr = Tk_GetColor(tree->interp, tree->tkwin, "pink"); 143 gc = Tk_GCForColor(colorPtr, Tk_WindowId(tree->tkwin)); 144 XFillRectangle(tree->display, dragImage->pixmap, gc, 145 0, 0, w, h); 146 147 trans = colorPtr->pixel; 148 149 colorPtr = Tk_GetColor(tree->interp, tree->tkwin, "gray50"); 150 gc = Tk_GCForColor(colorPtr, Tk_WindowId(tree->tkwin)); 151 152 for (elem = dragImage->elem; elem != NULL; elem = elem->next) { 153 XFillRectangle(tree->display, dragImage->pixmap, gc, 154 elem->x - dragImage->bounds[0], 155 elem->y - dragImage->bounds[1], 156 elem->width, elem->height); 157 } 158 159 if (dragImage->image != NULL) { 160 Tk_FreeImage(dragImage->image); 161 dragImage->image = NULL; 162 } 163} 164 165static void 166DrawPixmap( 167 TreeDragImage dragImage, /* Drag image record. */ 168 TreeDrawable td) 169{ 170 TreeCtrl *tree = dragImage->tree; 171 int ix, iy, iw, ih; 172 173 if (!dragImage->visible) 174 return; 175 176 if (dragImage->image == NULL) 177 UpdateImage(dragImage); 178 179 if (dragImage->image == NULL) 180 return; 181 182 ix = iy = 0; 183 iw = dragImage->bounds[2] - dragImage->bounds[0]; 184 ih = dragImage->bounds[3] - dragImage->bounds[1]; 185 186 /* FIXME: clip src image to area to be redrawn */ 187 188 Tree_RedrawImage(dragImage->image, ix, iy, iw, ih, td, 189 dragImage->x + dragImage->bounds[0] - tree->drawableXOrigin, 190 dragImage->y + dragImage->bounds[1] - tree->drawableYOrigin); 191} 192#endif /* DRAG_PIXMAP */ 193 194#ifdef DRAGIMAGE_STYLE 195void 196TreeDragImage_StyleDeleted( 197 TreeDragImage dragImage, /* Drag image record. */ 198 TreeStyle style) /* Style that was deleted. */ 199{ 200 TreeCtrl *tree = dragImage->tree; 201 202 if (dragImage->masterStyle == style) { 203 TreeStyle_FreeResources(tree, dragImage->instanceStyle); 204 dragImage->masterStyle = NULL; 205 dragImage->instanceStyle = NULL; 206 } 207} 208 209static void 210DragImage_UpdateStyleTkImage( 211 TreeDragImage dragImage) /* Drag image record. */ 212{ 213 TreeCtrl *tree = dragImage->tree; 214 Tk_PhotoHandle photoH; 215 XImage *ximage; 216 int width = dragImage->styleW; 217 int height = dragImage->styleH; 218 int alpha = 128; 219 XColor *colorPtr; 220 221 if (dragImage->tkimage != NULL) { 222 Tk_FreeImage(dragImage->tkimage); 223 dragImage->tkimage = NULL; 224 } 225 226 photoH = Tk_FindPhoto(tree->interp, "::TreeCtrl::ImageDrag"); 227 if (photoH == NULL) { 228 Tcl_GlobalEval(tree->interp, "image create photo ::TreeCtrl::ImageDrag"); 229 photoH = Tk_FindPhoto(tree->interp, "::TreeCtrl::ImageDrag"); 230 if (photoH == NULL) 231 return; 232 } 233 234 /* Pixmap -> XImage */ 235 ximage = XGetImage(tree->display, dragImage->pixmap, 0, 0, 236 (unsigned int)width, (unsigned int)height, AllPlanes, ZPixmap); 237 if (ximage == NULL) 238 panic("tkTreeDrag.c:DragImage_UpdateStyleTkImage() ximage is NULL"); 239 240 /* XImage -> Tk_Image */ 241 colorPtr = Tk_GetColor(tree->interp, tree->tkwin, "pink"); 242 Tree_XImage2Photo(tree->interp, photoH, ximage, colorPtr->pixel, alpha); 243 244 XDestroyImage(ximage); 245 246 dragImage->tkimage = Tk_GetImage(tree->interp, tree->tkwin, 247 "::TreeCtrl::ImageDrag", NULL, (ClientData) NULL); 248} 249 250static void 251DragImage_UpdateStylePixmap( 252 TreeDragImage dragImage) /* Drag image record. */ 253{ 254 TreeCtrl *tree = dragImage->tree; 255 int w, h, state = 0; 256 XColor *colorPtr; 257 GC gc; 258 StyleDrawArgs drawArgs; 259 260 w = dragImage->styleW = TreeStyle_NeededWidth(tree, dragImage->instanceStyle, state); 261 h = dragImage->styleH = TreeStyle_NeededHeight(tree, dragImage->instanceStyle, state); 262 if (w > dragImage->pixmapW || h > dragImage->pixmapH) 263 { 264 265 if (dragImage->pixmap != None) 266 Tk_FreePixmap(tree->display, dragImage->pixmap); 267 dragImage->pixmap = Tk_GetPixmap(tree->display, 268 Tk_WindowId(tree->tkwin), 269 w, h, Tk_Depth(tree->tkwin)); 270 271 dragImage->pixmapW = w; 272 dragImage->pixmapH = h; 273 } 274 275 colorPtr = Tk_GetColor(tree->interp, tree->tkwin, "pink"); 276 gc = Tk_GCForColor(colorPtr, Tk_WindowId(tree->tkwin)); 277 XFillRectangle(tree->display, dragImage->pixmap, gc, 278 0, 0, w, h); 279 280 drawArgs.tree = tree; 281 282 drawArgs.td.drawable = dragImage->pixmap; 283 drawArgs.td.width = w; drawArgs.td.height = h; 284 285 drawArgs.bounds[0] = drawArgs.bounds[1] = 0; 286 drawArgs.bounds[2] = w; drawArgs.bounds[3] = h; 287 288 drawArgs.state = state; 289 drawArgs.style = dragImage->instanceStyle; 290 291 drawArgs.indent = 0; 292 293 drawArgs.x = drawArgs.y = 0; 294 drawArgs.width = w; drawArgs.height = h; 295 296 drawArgs.justify = TK_JUSTIFY_LEFT; 297 298 TreeStyle_Draw(&drawArgs); 299 300 if (dragImage->tkimage != NULL) { 301 Tk_FreeImage(dragImage->tkimage); 302 dragImage->tkimage = NULL; 303 } 304} 305 306static void 307DragImage_DrawStyle( 308 TreeDragImage dragImage, /* Drag image record. */ 309 TreeDrawable td) /* Where to draw. */ 310{ 311 TreeCtrl *tree = dragImage->tree; 312 int ix, iy, iw, ih; 313 314 if (dragImage->tkimage == NULL) 315 DragImage_UpdateStyleTkImage(dragImage); 316 317 if (dragImage->tkimage == NULL) 318 return; 319 320 ix = iy = 0; 321 iw = dragImage->styleW; ih = dragImage->styleH; 322 323 Tree_RedrawImage(dragImage->tkimage, ix, iy, iw, ih, td, 324 dragImage->x + -dragImage->styleX - tree->drawableXOrigin, 325 dragImage->y + -dragImage->styleY - tree->drawableYOrigin); 326} 327#endif /* DRAGIMAGE_STYLE */ 328 329/* 330 *---------------------------------------------------------------------- 331 * 332 * TreeDragImage_Draw -- 333 * 334 * Draw the elements that make up the drag image if it is visible. 335 * 336 * Results: 337 * None. 338 * 339 * Side effects: 340 * Stuff is drawn. 341 * 342 *---------------------------------------------------------------------- 343 */ 344 345void 346TreeDragImage_Draw( 347 TreeDragImage dragImage, /* Drag image record. */ 348 TreeDrawable td) /* Where to draw. */ 349{ 350#ifdef DRAG_PIXMAP 351 DrawPixmap(tree->dragImage, tdrawable); 352 353#elif 1 /* Use XOR dotted rectangles where possible. */ 354 TreeCtrl *tree = dragImage->tree; 355 356 if (!dragImage->visible) 357 return; 358 359#ifdef DRAGIMAGE_STYLE 360 if (dragImage->instanceStyle != NULL) { 361 DragImage_DrawStyle(dragImage, td); 362 return; 363 } 364#endif /* DRAGIMAGE_STYLE */ 365 366 /* Yes this is XOR drawing but we aren't erasing the previous 367 * dragimage as when TreeDragImage_IsXOR() returns TRUE. */ 368 TreeDragImage_DrawXOR(dragImage, td.drawable, 369 0 - tree->xOrigin, 0 - tree->yOrigin); 370#else /* */ 371 TreeCtrl *tree = dragImage->tree; 372 GC gc; 373 DragElem *elem; 374#if 1 /* Stippled rectangles: BUG not clipped to contentbox. */ 375 XGCValues gcValues; 376 unsigned long mask; 377 XPoint points[5]; 378 379 if (!dragImage->visible) 380 return; 381 382 gcValues.stipple = Tk_GetBitmap(tree->interp, tree->tkwin, "gray50"); 383 gcValues.fill_style = FillStippled; 384 mask = GCStipple|GCFillStyle; 385 gc = Tk_GetGC(tree->tkwin, mask, &gcValues); 386 387 for (elem = dragImage->elem; elem != NULL; elem = elem->next) { 388 XRectangle rect; 389 rect.x = dragImage->x + elem->x /*- dragImage->bounds[0]*/ - tree->drawableXOrigin; 390 rect.y = dragImage->y + elem->y /*- dragImage->bounds[1]*/ - tree->drawableYOrigin; 391 rect.width = elem->width; 392 rect.height = elem->height; 393 394#ifdef WIN32 395 /* XDrawRectangle ignores the stipple pattern. */ 396 points[0].x = rect.x, points[0].y = rect.y; 397 points[1].x = rect.x + rect.width - 1, points[1].y = rect.y; 398 points[2].x = rect.x + rect.width - 1, points[2].y = rect.y + rect.height - 1; 399 points[3].x = rect.x, points[3].y = rect.y + rect.height - 1; 400 points[4] = points[0]; 401 XDrawLines(tree->display, td.drawable, gc, points, 5, CoordModeOrigin); 402#else /* !WIN32 */ 403 XDrawRectangle(tree->display, td.drawable, gc, rect.x, rect.y, 404 rect.width - 1, rect.height - 1); 405#endif 406 } 407 408 Tk_FreeGC(tree->display, gc); 409#else /* Debug/test: gray rectangles */ 410 XColor *colorPtr; 411 TkRegion rgn; 412 413 if (!dragImage->visible) 414 return; 415 416 colorPtr = Tk_GetColor(tree->interp, tree->tkwin, "gray50"); 417 gc = Tk_GCForColor(colorPtr, Tk_WindowId(tree->tkwin)); 418 419 rgn = Tree_GetRegion(tree); 420 421 for (elem = dragImage->elem; elem != NULL; elem = elem->next) { 422 XRectangle rect; 423 rect.x = dragImage->x + elem->x /*- dragImage->bounds[0]*/ - tree->drawableXOrigin; 424 rect.y = dragImage->y + elem->y /*- dragImage->bounds[1]*/ - tree->drawableYOrigin; 425 rect.width = elem->width; 426 rect.height = elem->height; 427 TkUnionRectWithRegion(&rect, rgn, rgn); 428 } 429 430 Tree_FillRegion(tree->display, td.drawable, gc, rgn); 431 432 Tree_FreeRegion(tree, rgn); 433#endif /* Debug/test: gray rectangles */ 434#endif /* XOR */ 435} 436 437/* 438 *---------------------------------------------------------------------- 439 * 440 * DragElem_Alloc -- 441 * 442 * Allocate and initialize a new DragElem record. Add the record 443 * to the list of records for the drag image. 444 * 445 * Results: 446 * Pointer to allocated DragElem. 447 * 448 * Side effects: 449 * Memory is allocated. 450 * 451 *---------------------------------------------------------------------- 452 */ 453 454static DragElem * 455DragElem_Alloc( 456 TreeDragImage dragImage /* Drag image record. */ 457 ) 458{ 459 DragElem *elem = (DragElem *) ckalloc(sizeof(DragElem)); 460 DragElem *walk = dragImage->elem; 461 memset(elem, '\0', sizeof(DragElem)); 462 if (dragImage->elem == NULL) 463 dragImage->elem = elem; 464 else { 465 while (walk->next != NULL) 466 walk = walk->next; 467 walk->next = elem; 468 } 469 return elem; 470} 471 472/* 473 *---------------------------------------------------------------------- 474 * 475 * DragElem_Free -- 476 * 477 * Free a DragElem. 478 * 479 * Results: 480 * Pointer to the next DragElem. 481 * 482 * Side effects: 483 * Memory is deallocated. 484 * 485 *---------------------------------------------------------------------- 486 */ 487 488static DragElem * 489DragElem_Free( 490 TreeDragImage dragImage, /* Drag image record. */ 491 DragElem *elem /* Drag element to free. */ 492 ) 493{ 494 DragElem *next = elem->next; 495 WFREE(elem, DragElem); 496 return next; 497} 498 499/* 500 *---------------------------------------------------------------------- 501 * 502 * TreeDragImage_Init -- 503 * 504 * Perform drag-image-related initialization when a new TreeCtrl is 505 * created. 506 * 507 * Results: 508 * A standard Tcl result. 509 * 510 * Side effects: 511 * Memory is allocated. 512 * 513 *---------------------------------------------------------------------- 514 */ 515 516int 517TreeDragImage_Init( 518 TreeCtrl *tree /* Widget info. */ 519 ) 520{ 521 TreeDragImage dragImage; 522 523 dragImage = (TreeDragImage) ckalloc(sizeof(TreeDragImage_)); 524 memset(dragImage, '\0', sizeof(TreeDragImage_)); 525 dragImage->tree = tree; 526 dragImage->optionTable = Tk_CreateOptionTable(tree->interp, optionSpecs); 527 if (Tk_InitOptions(tree->interp, (char *) dragImage, dragImage->optionTable, 528 tree->tkwin) != TCL_OK) { 529 WFREE(dragImage, TreeDragImage_); 530 return TCL_ERROR; 531 } 532 tree->dragImage = (TreeDragImage) dragImage; 533 return TCL_OK; 534} 535 536/* 537 *---------------------------------------------------------------------- 538 * 539 * TreeDragImage_Free -- 540 * 541 * Free drag-image-related resources when a TreeCtrl is deleted. 542 * 543 * Results: 544 * None. 545 * 546 * Side effects: 547 * Memory is deallocated. 548 * 549 *---------------------------------------------------------------------- 550 */ 551 552void 553TreeDragImage_Free( 554 TreeDragImage dragImage /* Drag image token. */ 555 ) 556{ 557 DragElem *elem = dragImage->elem; 558 559 while (elem != NULL) 560 elem = DragElem_Free(dragImage, elem); 561#ifdef DRAG_PIXMAP 562 if (dragImage->image != NULL) 563 Tk_FreeImage(dragImage->image); 564 if (dragImage->pixmap != None) 565 Tk_FreePixmap(dragImage->tree->display, dragImage->pixmap); 566#endif /* DRAG_PIXMAP */ 567 Tk_FreeConfigOptions((char *) dragImage, dragImage->optionTable, 568 dragImage->tree->tkwin); 569 WFREE(dragImage, TreeDragImage_); 570} 571 572/* 573 *---------------------------------------------------------------------- 574 * 575 * TreeDragImage_IsXOR -- 576 * 577 * Return true if the dragimage is being drawn with XOR. 578 * 579 * Results: 580 * None. 581 * 582 * Side effects: 583 * None. 584 * 585 *---------------------------------------------------------------------- 586 */ 587 588int TreeDragImage_IsXOR(TreeDragImage dragImage) 589{ 590#if defined(WIN32) 591 return FALSE; /* TRUE on XP, FALSE on Win7 (lots of flickering) */ 592#elif defined(MAC_TK_CARBON) 593 return TRUE; 594#elif defined(MAC_TK_COCOA) 595 return FALSE; /* Cocoa doesn't have XOR */ 596#else /* X11 */ 597 /* With VirtualBox+Ubuntu get extreme lag if TRUE with Compiz. */ 598 /* With VirtualBox+Ubuntu get lots of flickering if TRUE without Compiz. */ 599 return FALSE; 600#endif 601} 602 603/* 604 *---------------------------------------------------------------------- 605 * 606 * TreeDragImage_IsVisible -- 607 * 608 * Return true if the dragimage is being drawn. 609 * 610 * Results: 611 * None. 612 * 613 * Side effects: 614 * None. 615 * 616 *---------------------------------------------------------------------- 617 */ 618 619int TreeDragImage_IsVisible(TreeDragImage dragImage) 620{ 621 return dragImage->visible; 622} 623 624/* 625 *---------------------------------------------------------------------- 626 * 627 * TreeDragImage_Display -- 628 * 629 * Draw the drag image if it is not already displayed and if 630 * it's -visible option is TRUE. 631 * 632 * Results: 633 * None. 634 * 635 * Side effects: 636 * Stuff is drawn. 637 * 638 *---------------------------------------------------------------------- 639 */ 640 641void 642TreeDragImage_Display( 643 TreeDragImage dragImage /* Drag image token. */ 644 ) 645{ 646 TreeCtrl *tree = dragImage->tree; 647 648 if (!dragImage->onScreen && dragImage->visible) { 649 if (TreeDragImage_IsXOR(dragImage) == FALSE) { 650 dragImage->sx = dragImage->x + dragImage->bounds[0] - tree->xOrigin; 651 dragImage->sy = dragImage->y + dragImage->bounds[1] - tree->yOrigin; 652 dragImage->sw = dragImage->bounds[2] - dragImage->bounds[0]; 653 dragImage->sh = dragImage->bounds[3] - dragImage->bounds[1]; 654/* Tree_InvalidateItemArea(tree, dragImage->sx, dragImage->sy, 655 dragImage->sx + dragImage->sw, dragImage->sy + dragImage->sh);*/ 656 Tree_EventuallyRedraw(tree); 657 } else { 658 dragImage->sx = 0 - tree->xOrigin; 659 dragImage->sy = 0 - tree->yOrigin; 660 TreeDragImage_DrawXOR(dragImage, Tk_WindowId(tree->tkwin), dragImage->sx, dragImage->sy); 661 } 662 dragImage->onScreen = TRUE; 663 } 664} 665 666/* 667 *---------------------------------------------------------------------- 668 * 669 * TreeDragImage_Undisplay -- 670 * 671 * Erase the drag image if it is displayed. 672 * 673 * Results: 674 * None. 675 * 676 * Side effects: 677 * Stuff is drawn. 678 * 679 *---------------------------------------------------------------------- 680 */ 681 682void 683TreeDragImage_Undisplay( 684 TreeDragImage dragImage /* Drag image token. */ 685 ) 686{ 687 TreeCtrl *tree = dragImage->tree; 688 689 if (dragImage->onScreen) { 690 if (TreeDragImage_IsXOR(dragImage) == FALSE) { 691/* Tree_InvalidateItemArea(tree, dragImage->sx, dragImage->sy, 692 dragImage->sx + dragImage->sw, dragImage->sy + dragImage->sh);*/ 693 Tree_EventuallyRedraw(tree); 694 } else { 695 TreeDragImage_DrawXOR(dragImage, Tk_WindowId(tree->tkwin), 696 dragImage->sx, dragImage->sy); 697 } 698 dragImage->onScreen = FALSE; 699 } 700} 701 702/* 703 *---------------------------------------------------------------------- 704 * 705 * DragImage_Config -- 706 * 707 * This procedure is called to process an objc/objv list to set 708 * configuration options for a DragImage. 709 * 710 * Results: 711 * The return value is a standard Tcl result. If TCL_ERROR is 712 * returned, then an error message is left in interp's result. 713 * 714 * Side effects: 715 * Configuration information, such as text string, colors, font, 716 * etc. get set for dragImage; old resources get freed, if there 717 * were any. Display changes may occur. 718 * 719 *---------------------------------------------------------------------- 720 */ 721 722static int 723DragImage_Config( 724 TreeDragImage dragImage, /* Drag image record. */ 725 int objc, /* Number of arguments. */ 726 Tcl_Obj *CONST objv[] /* Argument values. */ 727 ) 728{ 729 TreeCtrl *tree = dragImage->tree; 730 Tk_SavedOptions savedOptions; 731 int error; 732 Tcl_Obj *errorResult = NULL; 733 int mask; 734 735 for (error = 0; error <= 1; error++) { 736 if (error == 0) { 737 if (Tk_SetOptions(tree->interp, (char *) dragImage, dragImage->optionTable, 738 objc, objv, tree->tkwin, &savedOptions, &mask) != TCL_OK) { 739 mask = 0; 740 continue; 741 } 742 743 /* xxx */ 744 745 Tk_FreeSavedOptions(&savedOptions); 746 break; 747 } else { 748 errorResult = Tcl_GetObjResult(tree->interp); 749 Tcl_IncrRefCount(errorResult); 750 Tk_RestoreSavedOptions(&savedOptions); 751 752 /* xxx */ 753 754 Tcl_SetObjResult(tree->interp, errorResult); 755 Tcl_DecrRefCount(errorResult); 756 return TCL_ERROR; 757 } 758 } 759 760 if (mask & DRAG_CONF_VISIBLE) { 761 TreeDragImage_Undisplay((TreeDragImage) dragImage); 762 TreeDragImage_Display((TreeDragImage) dragImage); 763 } 764 765#ifdef DRAGIMAGE_STYLE 766 if (dragImage->instanceStyle != NULL) { 767 TreeStyle_FreeResources(tree, dragImage->instanceStyle); 768 dragImage->instanceStyle = NULL; 769 } 770 if (dragImage->masterStyle != NULL) { 771 dragImage->instanceStyle = TreeStyle_NewInstance(tree, dragImage->masterStyle); 772 DragImage_UpdateStylePixmap(dragImage); 773 } 774#endif /* DRAGIMAGE_STYLE */ 775 776 return TCL_OK; 777} 778 779/* 780 *---------------------------------------------------------------------- 781 * 782 * TreeDragImage_DrawXOR -- 783 * 784 * Draw (or erase) the elements that make up the drag image. 785 * 786 * Results: 787 * None. 788 * 789 * Side effects: 790 * Stuff is drawn (or erased, since this is XOR drawing). 791 * 792 *---------------------------------------------------------------------- 793 */ 794 795void TreeDragImage_DrawXOR(TreeDragImage dragImage, Drawable drawable, int x, int y) 796{ 797 TreeCtrl *tree = dragImage->tree; 798 DragElem *elem = dragImage->elem; 799 DotState dotState; 800 801/* if (!dragImage->visible) 802 return; */ 803 if (elem == NULL) 804 return; 805 806 TreeDotRect_Setup(tree, drawable, &dotState); 807 808 while (elem != NULL) { 809 TreeDotRect_Draw(&dotState, 810 x + dragImage->x + elem->x, 811 y + dragImage->y + elem->y, 812 elem->width, elem->height); 813 elem = elem->next; 814 } 815 816 TreeDotRect_Restore(&dotState); 817} 818 819/* 820 *---------------------------------------------------------------------- 821 * 822 * TreeDragImageCmd -- 823 * 824 * This procedure is invoked to process the [dragimage] widget 825 * command. See the user documentation for details on what it 826 * does. 827 * 828 * Results: 829 * A standard Tcl result. 830 * 831 * Side effects: 832 * See the user documentation. 833 * 834 *---------------------------------------------------------------------- 835 */ 836 837int 838TreeDragImageCmd( 839 ClientData clientData, /* Widget info. */ 840 Tcl_Interp *interp, /* Current interpreter. */ 841 int objc, /* Number of arguments. */ 842 Tcl_Obj *CONST objv[] /* Argument values. */ 843 ) 844{ 845 TreeCtrl *tree = clientData; 846 TreeDragImage dragImage = tree->dragImage; 847 static CONST char *commandNames[] = { "add", "cget", "clear", "configure", 848 "offset", 849#ifdef DRAGIMAGE_STYLE 850 "stylehotspot", 851#endif /* DRAGIMAGE_STYLE */ 852 (char *) NULL }; 853 enum { COMMAND_ADD, COMMAND_CGET, COMMAND_CLEAR, COMMAND_CONFIGURE, 854 COMMAND_OFFSET 855#ifdef DRAGIMAGE_STYLE 856 , COMMAND_STYLEHOTSPOT 857#endif /* DRAGIMAGE_STYLE */ 858 }; 859 int index; 860 861 if (objc < 3) { 862 Tcl_WrongNumArgs(interp, 2, objv, "command ?arg arg ...?"); 863 return TCL_ERROR; 864 } 865 866 if (Tcl_GetIndexFromObj(interp, objv[2], commandNames, "command", 0, 867 &index) != TCL_OK) { 868 return TCL_ERROR; 869 } 870 871 switch (index) { 872 /* T dragimage add I ?C? ?E ...? */ 873 case COMMAND_ADD: { 874 TreeItem item; 875 TreeItemColumn itemColumn; 876 TreeColumn treeColumn; 877 TreeRectangle rects[128]; 878 DragElem *elem; 879 int i, count, result = TCL_OK; 880 881 if (objc < 4) { 882 Tcl_WrongNumArgs(interp, 3, objv, "item ?column? ?element ...?"); 883 return TCL_ERROR; 884 } 885 886 if (TreeItem_FromObj(tree, objv[3], &item, IFO_NOT_NULL) != TCL_OK) 887 return TCL_ERROR; 888 889 TreeDragImage_Undisplay(tree->dragImage); 890 891 /* Every element in every column. */ 892 if (objc == 4) { 893 894 treeColumn = tree->columns; 895 itemColumn = TreeItem_GetFirstColumn(tree, item); 896 while (itemColumn != NULL) { 897 if (TreeItemColumn_GetStyle(tree, itemColumn) != NULL) { 898 count = TreeItem_GetRects(tree, item, treeColumn, 899 -1, NULL, rects); 900 if (count == -1) { 901 result = TCL_ERROR; 902 goto doneADD; 903 } 904 for (i = 0; i < count; i++) { 905 elem = DragElem_Alloc(dragImage); 906 elem->x = rects[i].x; 907 elem->y = rects[i].y; 908 elem->width = rects[i].width; 909 elem->height = rects[i].height; 910 } 911 } 912 treeColumn = TreeColumn_Next(treeColumn); 913 itemColumn = TreeItemColumn_GetNext(tree, itemColumn); 914 } 915 916 } else { 917 918 if (TreeColumn_FromObj(tree, objv[4], &treeColumn, 919 CFO_NOT_NULL | CFO_NOT_TAIL) != TCL_OK) { 920 result = TCL_ERROR; 921 goto doneADD; 922 } 923 924 /* Every element in a column. */ 925 if (objc == 5) { 926 objc = -1; 927 objv = NULL; 928 929 /* List of elements in a column. */ 930 } else { 931 objc -= 5; 932 objv += 5; 933 } 934 935 count = TreeItem_GetRects(tree, item, treeColumn, objc, objv, 936 rects); 937 if (count == -1) { 938 result = TCL_ERROR; 939 goto doneADD; 940 } 941 942 for (i = 0; i < count; i++) { 943 elem = DragElem_Alloc(dragImage); 944 elem->x = rects[i].x; 945 elem->y = rects[i].y; 946 elem->width = rects[i].width; 947 elem->height = rects[i].height; 948 } 949 } 950 951doneADD: 952 dragImage->bounds[0] = 100000; 953 dragImage->bounds[1] = 100000; 954 dragImage->bounds[2] = -100000; 955 dragImage->bounds[3] = -100000; 956 for (elem = dragImage->elem; elem != NULL; elem = elem->next) { 957 if (elem->x < dragImage->bounds[0]) 958 dragImage->bounds[0] = elem->x; 959 if (elem->y < dragImage->bounds[1]) 960 dragImage->bounds[1] = elem->y; 961 if (elem->x + elem->width > dragImage->bounds[2]) 962 dragImage->bounds[2] = elem->x + elem->width; 963 if (elem->y + elem->height > dragImage->bounds[3]) 964 dragImage->bounds[3] = elem->y + elem->height; 965 } 966#ifdef DRAG_PIXMAP 967 UpdatePixmap(dragImage); 968#endif /* DRAG_PIXMAP */ 969 TreeDragImage_Display(tree->dragImage); 970 return result; 971 } 972 973 /* T dragimage cget option */ 974 case COMMAND_CGET: { 975 Tcl_Obj *resultObjPtr; 976 977 if (objc != 4) { 978 Tcl_WrongNumArgs(interp, 3, objv, "option"); 979 return TCL_ERROR; 980 } 981 resultObjPtr = Tk_GetOptionValue(interp, (char *) dragImage, 982 dragImage->optionTable, objv[3], tree->tkwin); 983 if (resultObjPtr == NULL) 984 return TCL_ERROR; 985 Tcl_SetObjResult(interp, resultObjPtr); 986 break; 987 } 988 989 /* T dragimage clear */ 990 case COMMAND_CLEAR: { 991 if (objc != 3) { 992 Tcl_WrongNumArgs(interp, 3, objv, (char *) NULL); 993 return TCL_ERROR; 994 } 995 if (dragImage->elem != NULL) { 996 DragElem *elem = dragImage->elem; 997 TreeDragImage_Undisplay(tree->dragImage); 998/* if (dragImage->visible) 999 DragImage_Redraw(dragImage); */ 1000 while (elem != NULL) 1001 elem = DragElem_Free(dragImage, elem); 1002 dragImage->elem = NULL; 1003 } 1004 break; 1005 } 1006 1007 /* T dragimage configure ?option? ?value? ?option value ...? */ 1008 case COMMAND_CONFIGURE: { 1009 Tcl_Obj *resultObjPtr; 1010 1011 if (objc < 3) { 1012 Tcl_WrongNumArgs(interp, 3, objv, "?option? ?value?"); 1013 return TCL_ERROR; 1014 } 1015 if (objc <= 4) { 1016 resultObjPtr = Tk_GetOptionInfo(interp, (char *) dragImage, 1017 dragImage->optionTable, 1018 (objc == 3) ? (Tcl_Obj *) NULL : objv[3], 1019 tree->tkwin); 1020 if (resultObjPtr == NULL) 1021 return TCL_ERROR; 1022 Tcl_SetObjResult(interp, resultObjPtr); 1023 break; 1024 } 1025 return DragImage_Config(dragImage, objc - 3, objv + 3); 1026 } 1027 1028 /* T dragimage offset ?x y? */ 1029 case COMMAND_OFFSET: { 1030 int x, y; 1031 1032 if (objc != 3 && objc != 5) { 1033 Tcl_WrongNumArgs(interp, 3, objv, "?x y?"); 1034 return TCL_ERROR; 1035 } 1036 if (objc == 3) { 1037 FormatResult(interp, "%d %d", dragImage->x, dragImage->y); 1038 break; 1039 } 1040 if (Tcl_GetIntFromObj(interp, objv[3], &x) != TCL_OK) 1041 return TCL_ERROR; 1042 if (Tcl_GetIntFromObj(interp, objv[4], &y) != TCL_OK) 1043 return TCL_ERROR; 1044 TreeDragImage_Undisplay(tree->dragImage); 1045/* if (dragImage->visible) 1046 DragImage_Redraw(dragImage); */ 1047 dragImage->x = x; 1048 dragImage->y = y; 1049 TreeDragImage_Display(tree->dragImage); 1050 break; 1051 } 1052 1053#ifdef DRAGIMAGE_STYLE 1054 /* T dragimage stylehotspot ?x y? */ 1055 case COMMAND_STYLEHOTSPOT: { 1056 int x, y; 1057 1058 if (objc != 3 && objc != 5) { 1059 Tcl_WrongNumArgs(interp, 3, objv, "?x y?"); 1060 return TCL_ERROR; 1061 } 1062 if (objc == 3) { 1063 FormatResult(interp, "%d %d", dragImage->styleX, dragImage->styleY); 1064 break; 1065 } 1066 if (Tcl_GetIntFromObj(interp, objv[3], &x) != TCL_OK) 1067 return TCL_ERROR; 1068 if (Tcl_GetIntFromObj(interp, objv[4], &y) != TCL_OK) 1069 return TCL_ERROR; 1070 TreeDragImage_Undisplay(tree->dragImage); 1071 dragImage->styleX = x; 1072 dragImage->styleY = y; 1073 TreeDragImage_Display(tree->dragImage); 1074 break; 1075 } 1076#endif /* DRAGIMAGE_STYLE */ 1077 } 1078 1079 return TCL_OK; 1080} 1081