1/* 2 * tkTreeElem.c -- 3 * 4 * This module implements elements for treectrl widgets. 5 * 6 * Copyright (c) 2002-2009 Tim Baker 7 * 8 * RCS: @(#) $Id: tkTreeElem.c,v 1.71 2010/03/08 17:04:58 treectrl Exp $ 9 */ 10 11#include "tkTreeCtrl.h" 12#include "tkTreeElem.h" 13 14/* 15 *---------------------------------------------------------------------- 16 * 17 * DO_BooleanForState -- 18 * DO_ColorForState -- 19 * DO_FontForState -- 20 * 21 * Returns the value of a per-state option for an element. 22 * 23 * Results: 24 * If the element has the dynamic option allocated, then the 25 * per-state info is checked for a match. If an exact match for 26 * the given state is not found, and if the element is an instance 27 * (not a master), then the master element is checked. 28 * 29 * Side effects: 30 * None. 31 * 32 *---------------------------------------------------------------------- 33 */ 34 35static int 36DO_BooleanForState( 37 TreeCtrl *tree, /* Widget info. */ 38 TreeElement elem, /* Element to examine. */ 39 int id, /* Unique id of dynamic option. */ 40 int state /* STATE_xxx flags. */ 41 ) 42{ 43 int result = -1; 44 PerStateInfo *psi; 45 int match = MATCH_NONE; 46 47 psi = DynamicOption_FindData(elem->options, id); 48 if (psi != NULL) 49 result = PerStateBoolean_ForState(tree, psi, state, &match); 50 if ((match != MATCH_EXACT) && (elem->master != NULL)) { 51 PerStateInfo *psi = DynamicOption_FindData(elem->master->options, id); 52 if (psi != NULL) { 53 int matchM; 54 int resultM = PerStateBoolean_ForState(tree, psi, state, &matchM); 55 if (matchM > match) 56 result = resultM; 57 } 58 } 59 return result; 60} 61 62static XColor * 63DO_ColorForState( 64 TreeCtrl *tree, 65 TreeElement elem, 66 int id, 67 int state 68 ) 69{ 70 XColor *result = NULL; 71 PerStateInfo *psi; 72 int match = MATCH_NONE; 73 74 psi = DynamicOption_FindData(elem->options, id); 75 if (psi != NULL) 76 result = PerStateColor_ForState(tree, psi, state, &match); 77 if ((match != MATCH_EXACT) && (elem->master != NULL)) { 78 PerStateInfo *psi = DynamicOption_FindData(elem->master->options, id); 79 if (psi != NULL) { 80 int matchM; 81 XColor *resultM = PerStateColor_ForState(tree, psi, state, &matchM); 82 if (matchM > match) 83 result = resultM; 84 } 85 } 86 return result; 87} 88 89static Tk_Font 90DO_FontForState( 91 TreeCtrl *tree, 92 TreeElement elem, 93 int id, 94 int state 95 ) 96{ 97 Tk_Font result = NULL; 98 PerStateInfo *psi; 99 int match = MATCH_NONE; 100 101 psi = DynamicOption_FindData(elem->options, id); 102 if (psi != NULL) 103 result = PerStateFont_ForState(tree, psi, state, &match); 104 if ((match != MATCH_EXACT) && (elem->master != NULL)) { 105 PerStateInfo *psi = DynamicOption_FindData(elem->master->options, id); 106 if (psi != NULL) { 107 int matchM; 108 Tk_Font resultM = PerStateFont_ForState(tree, psi, state, &matchM); 109 if (matchM > match) 110 result = resultM; 111 } 112 } 113 return result; 114} 115 116/* 117 *---------------------------------------------------------------------- 118 * 119 * DO_ObjectForState -- 120 * 121 * Returns the object representation of a per-state option 122 * for an element. 123 * 124 * Results: 125 * If the element has the dynamic option allocated, then the 126 * per-state info is checked for a match. If an exact match for 127 * the given state is not found, and if the element is an instance 128 * (not a master), then the master element is checked. 129 * 130 * Side effects: 131 * None. 132 * 133 *---------------------------------------------------------------------- 134 */ 135 136static Tcl_Obj * 137DO_ObjectForState( 138 TreeCtrl *tree, /* Widget info. */ 139 PerStateType *typePtr, /* Type-specific functions and values. */ 140 TreeElement elem, /* Element to examine. */ 141 int id, /* Unique id of dynamic option. */ 142 int state /* STATE_xxx flags. */ 143 ) 144{ 145 Tcl_Obj *result = NULL; 146 PerStateInfo *psi; 147 int match = MATCH_NONE; 148 149 psi = DynamicOption_FindData(elem->options, id); 150 if (psi != NULL) 151 result = PerStateInfo_ObjForState(tree, typePtr, psi, state, &match); 152 if ((match != MATCH_EXACT) && (elem->master != NULL)) { 153 PerStateInfo *psi = DynamicOption_FindData(elem->master->options, id); 154 if (psi != NULL) { 155 int matchM; 156 Tcl_Obj *resultM = PerStateInfo_ObjForState(tree, typePtr, psi, state, &matchM); 157 if (matchM > match) 158 result = resultM; 159 } 160 } 161 return result; 162} 163 164/* BEGIN custom "boolean" option */ 165 166/* Just like TK_OPTION_BOOLEAN but supports TK_OPTION_NULL_OK */ 167/* Internal value is -1 for no-such-value */ 168 169static int BooleanSet( 170 ClientData clientData, 171 Tcl_Interp *interp, 172 Tk_Window tkwin, 173 Tcl_Obj **value, 174 char *recordPtr, 175 int internalOffset, 176 char *saveInternalPtr, 177 int flags) 178{ 179 int objEmpty; 180 int new, *internalPtr; 181 182 if (internalOffset >= 0) 183 internalPtr = (int *) (recordPtr + internalOffset); 184 else 185 internalPtr = NULL; 186 187 objEmpty = ObjectIsEmpty((*value)); 188 189 if ((flags & TK_OPTION_NULL_OK) && objEmpty) 190 (*value) = NULL; 191 else { 192 if (Tcl_GetBooleanFromObj(interp, (*value), &new) != TCL_OK) 193 return TCL_ERROR; 194 } 195 if (internalPtr != NULL) { 196 if ((*value) == NULL) 197 new = -1; 198 *((int *) saveInternalPtr) = *internalPtr; 199 *internalPtr = new; 200 } 201 202 return TCL_OK; 203} 204 205static Tcl_Obj *BooleanGet( 206 ClientData clientData, 207 Tk_Window tkwin, 208 char *recordPtr, 209 int internalOffset) 210{ 211 int value = *(int *) (recordPtr + internalOffset); 212 if (value == -1) 213 return NULL; 214 return Tcl_NewBooleanObj(value); 215} 216 217static void BooleanRestore( 218 ClientData clientData, 219 Tk_Window tkwin, 220 char *internalPtr, 221 char *saveInternalPtr) 222{ 223 *(int *) internalPtr = *(int *) saveInternalPtr; 224} 225 226static Tk_ObjCustomOption booleanCO = 227{ 228 "boolean", 229 BooleanSet, 230 BooleanGet, 231 BooleanRestore, 232 NULL, 233 (ClientData) NULL 234}; 235 236static void 237DynamicOptionInitBoolean( 238 void *data 239 ) 240{ 241 *((int *) data) = -1; 242} 243 244/* END custom "boolean" option */ 245 246/* BEGIN custom "integer" option */ 247 248/* Just like TK_OPTION_INT but supports TK_OPTION_NULL_OK and bounds checking */ 249 250typedef struct IntegerClientData 251{ 252 int min; 253 int max; 254 int empty; /* internal form if empty */ 255 int flags; /* 0x01 - use min, 0x02 - use max */ 256} IntegerClientData; 257 258static int IntegerSet( 259 ClientData clientData, 260 Tcl_Interp *interp, 261 Tk_Window tkwin, 262 Tcl_Obj **value, 263 char *recordPtr, 264 int internalOffset, 265 char *saveInternalPtr, 266 int flags) 267{ 268 IntegerClientData *cd = clientData; 269 int objEmpty; 270 int new, *internalPtr; 271 272 if (internalOffset >= 0) 273 internalPtr = (int *) (recordPtr + internalOffset); 274 else 275 internalPtr = NULL; 276 277 objEmpty = ObjectIsEmpty((*value)); 278 279 if ((flags & TK_OPTION_NULL_OK) && objEmpty) 280 (*value) = NULL; 281 else { 282 if (Tcl_GetIntFromObj(interp, (*value), &new) != TCL_OK) 283 return TCL_ERROR; 284 if ((cd->flags & 0x01) && (new < cd->min)) { 285 FormatResult(interp, 286 "bad integer value \"%d\": must be >= %d", 287 new, cd->min); 288 return TCL_ERROR; 289 } 290 if ((cd->flags & 0x02) && (new > cd->max)) { 291 FormatResult(interp, 292 "bad integer value \"%d\": must be <= %d", 293 new, cd->max); 294 return TCL_ERROR; 295 } 296 } 297 if (internalPtr != NULL) { 298 if ((*value) == NULL) 299 new = cd->empty; 300 *((int *) saveInternalPtr) = *internalPtr; 301 *internalPtr = new; 302 } 303 304 return TCL_OK; 305} 306 307static Tcl_Obj *IntegerGet( 308 ClientData clientData, 309 Tk_Window tkwin, 310 char *recordPtr, 311 int internalOffset) 312{ 313 IntegerClientData *cd = clientData; 314 int value = *(int *) (recordPtr + internalOffset); 315 if (value == cd->empty) 316 return NULL; 317 return Tcl_NewIntObj(value); 318} 319 320static void IntegerRestore( 321 ClientData clientData, 322 Tk_Window tkwin, 323 char *internalPtr, 324 char *saveInternalPtr) 325{ 326 *(int *) internalPtr = *(int *) saveInternalPtr; 327} 328 329/* END custom "integer" option */ 330 331/*****/ 332 333/* BEGIN custom "stringtable" option */ 334 335/* Just like TK_OPTION_STRING_TABLE but supports TK_OPTION_NULL_OK */ 336/* The integer rep is -1 if empty string specified */ 337 338typedef struct StringTableClientData 339{ 340 CONST char **tablePtr; /* NULL-termintated list of strings */ 341 CONST char *msg; /* Tcl_GetIndexFromObj() message */ 342} StringTableClientData; 343 344static int StringTableSet( 345 ClientData clientData, 346 Tcl_Interp *interp, 347 Tk_Window tkwin, 348 Tcl_Obj **value, 349 char *recordPtr, 350 int internalOffset, 351 char *saveInternalPtr, 352 int flags) 353{ 354 StringTableClientData *cd = clientData; 355 int objEmpty; 356 int new, *internalPtr; 357 358 if (internalOffset >= 0) 359 internalPtr = (int *) (recordPtr + internalOffset); 360 else 361 internalPtr = NULL; 362 363 objEmpty = ObjectIsEmpty((*value)); 364 365 if ((flags & TK_OPTION_NULL_OK) && objEmpty) 366 (*value) = NULL; 367 else { 368 if (Tcl_GetIndexFromObj(interp, (*value), cd->tablePtr, 369 cd->msg, 0, &new) != TCL_OK) 370 return TCL_ERROR; 371 } 372 if (internalPtr != NULL) { 373 if ((*value) == NULL) 374 new = -1; 375 *((int *) saveInternalPtr) = *internalPtr; 376 *internalPtr = new; 377 } 378 379 return TCL_OK; 380} 381 382static Tcl_Obj *StringTableGet( 383 ClientData clientData, 384 Tk_Window tkwin, 385 char *recordPtr, 386 int internalOffset) 387{ 388 StringTableClientData *cd = clientData; 389 int index = *(int *) (recordPtr + internalOffset); 390 391 if (index == -1) 392 return NULL; 393 return Tcl_NewStringObj(cd->tablePtr[index], -1); 394} 395 396static void StringTableRestore( 397 ClientData clientData, 398 Tk_Window tkwin, 399 char *internalPtr, 400 char *saveInternalPtr) 401{ 402 *(int *) internalPtr = *(int *) saveInternalPtr; 403} 404 405/* END custom "stringtable" option */ 406 407static int 408BooleanCO_Init( 409 Tk_OptionSpec *optionTable, 410 CONST char *optionName) 411{ 412 Tk_OptionSpec *specPtr; 413 414 specPtr = Tree_FindOptionSpec(optionTable, optionName); 415 specPtr->clientData = &booleanCO; 416 return TCL_OK; 417} 418 419static Tk_ObjCustomOption * 420IntegerCO_Alloc( 421 CONST char *optionName, 422 int min, 423 int max, 424 int empty, 425 int flags 426 ) 427{ 428 IntegerClientData *cd; 429 Tk_ObjCustomOption *co; 430 431 /* ClientData for the Tk custom option record */ 432 cd = (IntegerClientData *) ckalloc(sizeof(IntegerClientData)); 433 cd->min = min; 434 cd->max = max; 435 cd->empty = empty; 436 cd->flags = flags; 437 438 /* The Tk custom option record */ 439 co = (Tk_ObjCustomOption *) ckalloc(sizeof(Tk_ObjCustomOption)); 440 co->name = (char *) optionName + 1; 441 co->setProc = IntegerSet; 442 co->getProc = IntegerGet; 443 co->restoreProc = IntegerRestore; 444 co->freeProc = NULL; 445 co->clientData = (ClientData) cd; 446 447 return co; 448} 449 450static int 451IntegerCO_Init( 452 Tk_OptionSpec *optionTable, 453 CONST char *optionName, 454 int min, 455 int max, 456 int empty, 457 int flags 458 ) 459{ 460 Tk_OptionSpec *specPtr; 461 462 specPtr = Tree_FindOptionSpec(optionTable, optionName); 463 if (specPtr->type != TK_OPTION_CUSTOM) 464 panic("IntegerCO_Init: %s is not TK_OPTION_CUSTOM", optionName); 465 if (specPtr->clientData != NULL) 466 return TCL_OK; 467 468 specPtr->clientData = IntegerCO_Alloc(optionName, min, max, empty, flags); 469 470 return TCL_OK; 471} 472 473static Tk_ObjCustomOption * 474StringTableCO_Alloc( 475 CONST char *optionName, 476 CONST char **tablePtr 477 ) 478{ 479 StringTableClientData *cd; 480 Tk_ObjCustomOption *co; 481 482 /* ClientData for the Tk custom option record */ 483 cd = (StringTableClientData *) ckalloc(sizeof(StringTableClientData)); 484 cd->tablePtr = tablePtr; 485 cd->msg = optionName + 1; 486 487 /* The Tk custom option record */ 488 co = (Tk_ObjCustomOption *) ckalloc(sizeof(Tk_ObjCustomOption)); 489 co->name = (char *) optionName + 1; 490 co->setProc = StringTableSet; 491 co->getProc = StringTableGet; 492 co->restoreProc = StringTableRestore; 493 co->freeProc = NULL; 494 co->clientData = (ClientData) cd; 495 496 return co; 497} 498 499int StringTableCO_Init(Tk_OptionSpec *optionTable, CONST char *optionName, CONST char **tablePtr) 500{ 501 Tk_OptionSpec *specPtr; 502 503 specPtr = Tree_FindOptionSpec(optionTable, optionName); 504 if (specPtr->type != TK_OPTION_CUSTOM) 505 panic("StringTableCO_Init: %s is not TK_OPTION_CUSTOM", optionName); 506 if (specPtr->clientData != NULL) 507 return TCL_OK; 508 509 specPtr->clientData = StringTableCO_Alloc(optionName, tablePtr); 510 511 return TCL_OK; 512} 513 514/*****/ 515 516int TreeStateFromObj(TreeCtrl *tree, Tcl_Obj *obj, int *stateOff, int *stateOn) 517{ 518 int states[3]; 519 520 states[STATE_OP_ON] = states[STATE_OP_OFF] = states[STATE_OP_TOGGLE] = 0; 521 if (Tree_StateFromObj(tree, obj, states, NULL, SFO_NOT_TOGGLE) != TCL_OK) 522 return TCL_ERROR; 523 524 (*stateOn) |= states[STATE_OP_ON]; 525 (*stateOff) |= states[STATE_OP_OFF]; 526 return TCL_OK; 527} 528 529static void AdjustForSticky(int sticky, int cavityWidth, int cavityHeight, 530 int expandX, int expandY, 531 int *xPtr, int *yPtr, int *widthPtr, int *heightPtr) 532{ 533 int dx = 0; 534 int dy = 0; 535 536 if (cavityWidth > *widthPtr) { 537 dx = cavityWidth - *widthPtr; 538 } 539 540 if (cavityHeight > *heightPtr) { 541 dy = cavityHeight - *heightPtr; 542 } 543 544 if ((sticky & STICKY_W) && (sticky & STICKY_E)) { 545 if (expandX) 546 *widthPtr += dx; 547 else 548 sticky &= ~(STICKY_W | STICKY_E); 549 } 550 if ((sticky & STICKY_N) && (sticky & STICKY_S)) { 551 if (expandY) 552 *heightPtr += dy; 553 else 554 sticky &= ~(STICKY_N | STICKY_S); 555 } 556 if (!(sticky & STICKY_W)) { 557 *xPtr += (sticky & STICKY_E) ? dx : dx / 2; 558 } 559 if (!(sticky & STICKY_N)) { 560 *yPtr += (sticky & STICKY_S) ? dy : dy / 2; 561 } 562} 563 564/* This macro gets the value of a per-state option for an element, then 565 * looks for a better match from the master element if it exists */ 566#define OPTION_FOR_STATE(xFUNC,xTYPE,xVAR,xFIELD,xSTATE) \ 567 xVAR = xFUNC(tree, &elemX->xFIELD, xSTATE, &match); \ 568 if ((match != MATCH_EXACT) && (masterX != NULL)) { \ 569 xTYPE varM = xFUNC(tree, &masterX->xFIELD, xSTATE, &match2); \ 570 if (match2 > match) \ 571 xVAR = varM; \ 572 } 573#define BITMAP_FOR_STATE(xVAR,xFIELD,xSTATE) \ 574 OPTION_FOR_STATE(PerStateBitmap_ForState,Pixmap,xVAR,xFIELD,xSTATE) 575#define BOOLEAN_FOR_STATE(xVAR,xFIELD,xSTATE) \ 576 OPTION_FOR_STATE(PerStateBoolean_ForState,int,xVAR,xFIELD,xSTATE) 577#define BORDER_FOR_STATE(xVAR,xFIELD,xSTATE) \ 578 OPTION_FOR_STATE(PerStateBorder_ForState,Tk_3DBorder,xVAR,xFIELD,xSTATE) 579#define COLOR_FOR_STATE(xVAR,xFIELD,xSTATE) \ 580 OPTION_FOR_STATE(PerStateColor_ForState,XColor*,xVAR,xFIELD,xSTATE) 581#define FONT_FOR_STATE(xVAR,xFIELD,xSTATE) \ 582 OPTION_FOR_STATE(PerStateFont_ForState,Tk_Font,xVAR,xFIELD,xSTATE) 583#define IMAGE_FOR_STATE(xVAR,xFIELD,xSTATE) \ 584 OPTION_FOR_STATE(PerStateImage_ForState,Tk_Image,xVAR,xFIELD,xSTATE) 585#define RELIEF_FOR_STATE(xVAR,xFIELD,xSTATE) \ 586 OPTION_FOR_STATE(PerStateRelief_ForState,int,xVAR,xFIELD,xSTATE) 587 588/* This macro gets the object for a per-state option for an element, then 589 * looks for a better match from the master element if it exists */ 590#define OBJECT_FOR_STATE(xVAR,xTYPE,xFIELD,xSTATE) \ 591 xVAR = PerStateInfo_ObjForState(tree, &xTYPE, &elemX->xFIELD, xSTATE, &match); \ 592 if ((match != MATCH_EXACT) && (masterX != NULL)) { \ 593 Tcl_Obj *objM = PerStateInfo_ObjForState(tree, &xTYPE, &masterX->xFIELD, xSTATE, &matchM); \ 594 if (matchM > match) \ 595 xVAR = objM; \ 596 } 597 598/*****/ 599 600typedef struct ElementBitmap ElementBitmap; 601 602struct ElementBitmap 603{ 604 TreeElement_ header; 605#ifdef DEPRECATED 606 PerStateInfo draw; 607#endif 608 PerStateInfo bitmap; 609 PerStateInfo fg; 610 PerStateInfo bg; 611}; 612 613#define BITMAP_CONF_BITMAP 0x0001 614#define BITMAP_CONF_FG 0x0002 615#define BITMAP_CONF_BG 0x0004 616#ifdef DEPRECATED 617#define BITMAP_CONF_DRAW 0x0008 618#endif 619 620static Tk_OptionSpec bitmapOptionSpecs[] = { 621 {TK_OPTION_CUSTOM, "-background", (char *) NULL, (char *) NULL, 622 (char *) NULL, 623 Tk_Offset(ElementBitmap, bg.obj), Tk_Offset(ElementBitmap, bg), 624 TK_OPTION_NULL_OK, (ClientData) NULL, BITMAP_CONF_BG}, 625 {TK_OPTION_CUSTOM, "-bitmap", (char *) NULL, (char *) NULL, 626 (char *) NULL, 627 Tk_Offset(ElementBitmap, bitmap.obj), Tk_Offset(ElementBitmap, bitmap), 628 TK_OPTION_NULL_OK, (ClientData) NULL, BITMAP_CONF_BITMAP}, 629#ifdef DEPRECATED 630 {TK_OPTION_CUSTOM, "-draw", (char *) NULL, (char *) NULL, 631 (char *) NULL, 632 Tk_Offset(ElementBitmap, draw.obj), Tk_Offset(ElementBitmap, draw), 633 TK_OPTION_NULL_OK, (ClientData) NULL, BITMAP_CONF_DRAW}, 634#endif 635 {TK_OPTION_CUSTOM, "-foreground", (char *) NULL, (char *) NULL, 636 (char *) NULL, 637 Tk_Offset(ElementBitmap, fg.obj), Tk_Offset(ElementBitmap, fg), 638 TK_OPTION_NULL_OK, (ClientData) NULL, BITMAP_CONF_FG}, 639 {TK_OPTION_END, (char *) NULL, (char *) NULL, (char *) NULL, 640 (char *) NULL, 0, -1, 0, (ClientData) NULL, 0} 641}; 642 643static void DeleteProcBitmap(TreeElementArgs *args) 644{ 645/* TreeCtrl *tree = args->tree; 646 TreeElement elem = args->elem; 647 ElementBitmap *elemX = (ElementBitmap *) elem;*/ 648} 649 650static int WorldChangedProcBitmap(TreeElementArgs *args) 651{ 652 int flagM = args->change.flagMaster; 653 int flagS = args->change.flagSelf; 654 int mask = 0; 655 656 if ((flagS | flagM) & BITMAP_CONF_BITMAP) 657 mask |= CS_DISPLAY | CS_LAYOUT; 658 659 if ((flagS | flagM) & ( 660#ifdef DEPRECATED 661 BITMAP_CONF_DRAW | 662#endif 663 BITMAP_CONF_FG | BITMAP_CONF_BG)) 664 mask |= CS_DISPLAY; 665 666 return mask; 667} 668 669static int ConfigProcBitmap(TreeElementArgs *args) 670{ 671 TreeCtrl *tree = args->tree; 672 TreeElement elem = args->elem; 673 ElementBitmap *elemX = (ElementBitmap *) elem; 674 Tk_SavedOptions savedOptions; 675 int error; 676 Tcl_Obj *errorResult = NULL; 677 678 for (error = 0; error <= 1; error++) { 679 if (error == 0) { 680 if (Tk_SetOptions(tree->interp, (char *) elemX, 681 elem->typePtr->optionTable, 682 args->config.objc, args->config.objv, tree->tkwin, 683 &savedOptions, &args->config.flagSelf) != TCL_OK) { 684 args->config.flagSelf = 0; 685 continue; 686 } 687 688 Tk_FreeSavedOptions(&savedOptions); 689 break; 690 } else { 691 errorResult = Tcl_GetObjResult(tree->interp); 692 Tcl_IncrRefCount(errorResult); 693 Tk_RestoreSavedOptions(&savedOptions); 694 695 Tcl_SetObjResult(tree->interp, errorResult); 696 Tcl_DecrRefCount(errorResult); 697 return TCL_ERROR; 698 } 699 } 700 701 return TCL_OK; 702} 703 704static int CreateProcBitmap(TreeElementArgs *args) 705{ 706 return TCL_OK; 707} 708 709static void DisplayProcBitmap(TreeElementArgs *args) 710{ 711 TreeCtrl *tree = args->tree; 712 TreeElement elem = args->elem; 713 ElementBitmap *elemX = (ElementBitmap *) elem; 714 ElementBitmap *masterX = (ElementBitmap *) elem->master; 715 int state = args->state; 716 int x = args->display.x, y = args->display.y; 717 int width, height; 718 int match, match2; 719#ifdef DEPRECATED 720 int draw; 721#endif 722 Pixmap bitmap; 723 XColor *fg, *bg; 724 int imgW, imgH; 725 726#ifdef DEPRECATED 727 BOOLEAN_FOR_STATE(draw, draw, state) 728 if (!draw) 729 return; 730#endif 731 732 BITMAP_FOR_STATE(bitmap, bitmap, state) 733 if (bitmap == None) 734 return; 735 736 COLOR_FOR_STATE(fg, fg, state) 737 COLOR_FOR_STATE(bg, bg, state) 738 739 Tk_SizeOfBitmap(tree->display, bitmap, &imgW, &imgH); 740 width = imgW, height = imgH; 741 AdjustForSticky(args->display.sticky, 742 args->display.width, args->display.height, 743 FALSE, FALSE, 744 &x, &y, &width, &height); 745 if (imgW > args->display.width) 746 imgW = args->display.width; 747 if (imgH > args->display.height) 748 imgH = args->display.height; 749 Tree_DrawBitmap(tree, bitmap, args->display.drawable, fg, bg, 750 0, 0, (unsigned int) imgW, (unsigned int) imgH, 751 x, y); 752} 753 754static void NeededProcBitmap(TreeElementArgs *args) 755{ 756 TreeCtrl *tree = args->tree; 757 TreeElement elem = args->elem; 758 ElementBitmap *elemX = (ElementBitmap *) elem; 759 ElementBitmap *masterX = (ElementBitmap *) elem->master; 760 int state = args->state; 761 int width = 0, height = 0; 762 int match, match2; 763 Pixmap bitmap; 764 765 BITMAP_FOR_STATE(bitmap, bitmap, state) 766 767 if (bitmap != None) 768 Tk_SizeOfBitmap(tree->display, bitmap, &width, &height); 769 770 args->needed.width = width; 771 args->needed.height = height; 772} 773 774static int StateProcBitmap(TreeElementArgs *args) 775{ 776 TreeCtrl *tree = args->tree; 777 TreeElement elem = args->elem; 778 ElementBitmap *elemX = (ElementBitmap *) elem; 779 ElementBitmap *masterX = (ElementBitmap *) elem->master; 780 int match, match2; 781#ifdef DEPRECATED 782 int draw1, draw2; 783#endif 784 Pixmap bitmap1, bitmap2; 785 XColor *fg1, *fg2; 786 XColor *bg1, *bg2; 787 788 if (!args->states.visible2) 789 return 0; 790 791 BITMAP_FOR_STATE(bitmap1, bitmap, args->states.state1) 792 BITMAP_FOR_STATE(bitmap2, bitmap, args->states.state2) 793 if (bitmap1 != bitmap2) { 794 if ((bitmap1 != None) && (bitmap2 != None)) { 795 int w1, h1, w2, h2; 796 Tk_SizeOfBitmap(tree->display, bitmap1, &w1, &h1); 797 Tk_SizeOfBitmap(tree->display, bitmap2, &w2, &h2); 798 if ((w1 != w2) || (h1 != h2)) 799 return CS_DISPLAY | CS_LAYOUT; 800 return CS_DISPLAY; 801 } 802 return CS_DISPLAY | CS_LAYOUT; 803 } 804 805 /* Layout hasn't changed, and -draw layout option is false. */ 806 if (!args->states.draw2) 807 return 0; 808#ifdef DEPRECATED 809 BOOLEAN_FOR_STATE(draw1, draw, args->states.state1) 810 BOOLEAN_FOR_STATE(draw2, draw, args->states.state2) 811 if ((draw1 != 0) != (draw2 != 0)) 812 return CS_DISPLAY; 813 if (draw2 == 0) 814 return 0; 815#endif 816 817 COLOR_FOR_STATE(fg1, fg, args->states.state1) 818 COLOR_FOR_STATE(fg2, fg, args->states.state2) 819 if (fg1 != fg2) 820 return CS_DISPLAY; 821 822 COLOR_FOR_STATE(bg1, bg, args->states.state1) 823 COLOR_FOR_STATE(bg2, bg, args->states.state2) 824 if (bg1 != bg2) 825 return CS_DISPLAY; 826 827 return 0; 828} 829 830static int UndefProcBitmap(TreeElementArgs *args) 831{ 832 TreeCtrl *tree = args->tree; 833 ElementBitmap *elemX = (ElementBitmap *) args->elem; 834 int modified = 0; 835 836#ifdef DEPRECATED 837 modified |= PerStateInfo_Undefine(tree, &pstBoolean, &elemX->draw, args->state); 838#endif 839 modified |= PerStateInfo_Undefine(tree, &pstColor, &elemX->fg, args->state); 840 modified |= PerStateInfo_Undefine(tree, &pstColor, &elemX->bg, args->state); 841 modified |= PerStateInfo_Undefine(tree, &pstBitmap, &elemX->bitmap, args->state); 842 return modified; 843} 844 845static int ActualProcBitmap(TreeElementArgs *args) 846{ 847 TreeCtrl *tree = args->tree; 848 ElementBitmap *elemX = (ElementBitmap *) args->elem; 849 ElementBitmap *masterX = (ElementBitmap *) args->elem->master; 850 static CONST char *optionName[] = { 851 "-background", "-bitmap", 852#ifdef DEPRECATED 853 "-draw", 854#endif 855 "-foreground", 856 (char *) NULL }; 857 int index, match, matchM; 858 Tcl_Obj *obj = NULL; 859 860 if (Tcl_GetIndexFromObj(tree->interp, args->actual.obj, optionName, 861 "option", 0, &index) != TCL_OK) 862 return TCL_ERROR; 863 864 switch (index) { 865 case 0: { 866 OBJECT_FOR_STATE(obj, pstColor, bg, args->state) 867 break; 868 } 869 case 1: { 870 OBJECT_FOR_STATE(obj, pstBitmap, bitmap, args->state) 871 break; 872 } 873#ifdef DEPRECATED 874 case 2: { 875 OBJECT_FOR_STATE(obj, pstBoolean, draw, args->state) 876 break; 877 } 878 case 3: { 879 OBJECT_FOR_STATE(obj, pstColor, fg, args->state) 880 break; 881 } 882#else 883 case 2: { 884 OBJECT_FOR_STATE(obj, pstColor, fg, args->state) 885 break; 886 } 887#endif 888 } 889 if (obj != NULL) 890 Tcl_SetObjResult(tree->interp, obj); 891 return TCL_OK; 892} 893 894TreeElementType treeElemTypeBitmap = { 895 "bitmap", 896 sizeof(ElementBitmap), 897 bitmapOptionSpecs, 898 NULL, 899 CreateProcBitmap, 900 DeleteProcBitmap, 901 ConfigProcBitmap, 902 DisplayProcBitmap, 903 NeededProcBitmap, 904 NULL, /* heightProc */ 905 WorldChangedProcBitmap, 906 StateProcBitmap, 907 UndefProcBitmap, 908 ActualProcBitmap, 909 NULL /* onScreenProc */ 910}; 911 912/*****/ 913 914typedef struct ElementBorder ElementBorder; 915 916struct ElementBorder 917{ 918 TreeElement_ header; /* Must be first */ 919#ifdef DEPRECATED 920 PerStateInfo draw; 921#endif 922 PerStateInfo border; 923 PerStateInfo relief; 924 int thickness; 925 Tcl_Obj *thicknessObj; 926 int width; 927 Tcl_Obj *widthObj; 928 int height; 929 Tcl_Obj *heightObj; 930 int filled; 931}; 932 933#define BORDER_CONF_BG 0x0001 934#define BORDER_CONF_RELIEF 0x0002 935#define BORDER_CONF_SIZE 0x0004 936#define BORDER_CONF_THICKNESS 0x0008 937#define BORDER_CONF_FILLED 0x0010 938#ifdef DEPRECATED 939#define BORDER_CONF_DRAW 0x0020 940#endif 941 942static Tk_OptionSpec borderOptionSpecs[] = { 943 {TK_OPTION_CUSTOM, "-background", (char *) NULL, (char *) NULL, 944 (char *) NULL, 945 Tk_Offset(ElementBorder, border.obj), Tk_Offset(ElementBorder, border), 946 TK_OPTION_NULL_OK, (ClientData) NULL, BORDER_CONF_BG}, 947#ifdef DEPRECATED 948 {TK_OPTION_CUSTOM, "-draw", (char *) NULL, (char *) NULL, 949 (char *) NULL, 950 Tk_Offset(ElementBorder, draw.obj), Tk_Offset(ElementBorder, draw), 951 TK_OPTION_NULL_OK, (ClientData) NULL, BORDER_CONF_DRAW}, 952#endif 953 {TK_OPTION_CUSTOM, "-filled", (char *) NULL, (char *) NULL, 954 (char *) NULL, -1, Tk_Offset(ElementBorder, filled), 955 TK_OPTION_NULL_OK, (ClientData) &booleanCO, BORDER_CONF_FILLED}, 956 {TK_OPTION_PIXELS, "-height", (char *) NULL, (char *) NULL, 957 (char *) NULL, Tk_Offset(ElementBorder, heightObj), 958 Tk_Offset(ElementBorder, height), 959 TK_OPTION_NULL_OK, (ClientData) NULL, BORDER_CONF_SIZE}, 960 {TK_OPTION_CUSTOM, "-relief", (char *) NULL, (char *) NULL, 961 (char *) NULL, 962 Tk_Offset(ElementBorder, relief.obj), Tk_Offset(ElementBorder, relief), 963 TK_OPTION_NULL_OK, (ClientData) NULL, BORDER_CONF_RELIEF}, 964 {TK_OPTION_PIXELS, "-thickness", (char *) NULL, (char *) NULL, 965 (char *) NULL, Tk_Offset(ElementBorder, thicknessObj), 966 Tk_Offset(ElementBorder, thickness), 967 TK_OPTION_NULL_OK, (ClientData) NULL, BORDER_CONF_THICKNESS}, 968 {TK_OPTION_PIXELS, "-width", (char *) NULL, (char *) NULL, 969 (char *) NULL, Tk_Offset(ElementBorder, widthObj), 970 Tk_Offset(ElementBorder, width), 971 TK_OPTION_NULL_OK, (ClientData) NULL, BORDER_CONF_SIZE}, 972 {TK_OPTION_END, (char *) NULL, (char *) NULL, (char *) NULL, 973 (char *) NULL, 0, -1, 0, (ClientData) NULL, 0} 974}; 975 976static void DeleteProcBorder(TreeElementArgs *args) 977{ 978/* TreeCtrl *tree = args->tree; 979 TreeElement elem = args->elem; 980 ElementBorder *elemX = (ElementBorder *) elem;*/ 981} 982 983static int WorldChangedProcBorder(TreeElementArgs *args) 984{ 985 int flagM = args->change.flagMaster; 986 int flagS = args->change.flagSelf; 987 int mask = 0; 988 989 if ((flagS | flagM) & BORDER_CONF_SIZE) 990 mask |= CS_DISPLAY | CS_LAYOUT; 991 992 if ((flagS | flagM) & ( 993#ifdef DEPRECATED 994 BORDER_CONF_DRAW | 995#endif 996 BORDER_CONF_BG | BORDER_CONF_RELIEF | BORDER_CONF_THICKNESS | 997 BORDER_CONF_FILLED)) 998 mask |= CS_DISPLAY; 999 1000 return mask; 1001} 1002 1003static int ConfigProcBorder(TreeElementArgs *args) 1004{ 1005 TreeCtrl *tree = args->tree; 1006 TreeElement elem = args->elem; 1007 ElementBorder *elemX = (ElementBorder *) elem; 1008 Tk_SavedOptions savedOptions; 1009 int error; 1010 Tcl_Obj *errorResult = NULL; 1011 1012 for (error = 0; error <= 1; error++) { 1013 if (error == 0) { 1014 if (Tk_SetOptions(tree->interp, (char *) elemX, 1015 elem->typePtr->optionTable, 1016 args->config.objc, args->config.objv, tree->tkwin, 1017 &savedOptions, &args->config.flagSelf) != TCL_OK) { 1018 args->config.flagSelf = 0; 1019 continue; 1020 } 1021 1022 Tk_FreeSavedOptions(&savedOptions); 1023 break; 1024 } else { 1025 errorResult = Tcl_GetObjResult(tree->interp); 1026 Tcl_IncrRefCount(errorResult); 1027 Tk_RestoreSavedOptions(&savedOptions); 1028 1029 Tcl_SetObjResult(tree->interp, errorResult); 1030 Tcl_DecrRefCount(errorResult); 1031 return TCL_ERROR; 1032 } 1033 } 1034 1035 return TCL_OK; 1036} 1037 1038static int CreateProcBorder(TreeElementArgs *args) 1039{ 1040 TreeElement elem = args->elem; 1041 ElementBorder *elemX = (ElementBorder *) elem; 1042 1043 elemX->filled = -1; 1044 return TCL_OK; 1045} 1046 1047static void DisplayProcBorder(TreeElementArgs *args) 1048{ 1049 TreeCtrl *tree = args->tree; 1050 TreeElement elem = args->elem; 1051 ElementBorder *elemX = (ElementBorder *) elem; 1052 ElementBorder *masterX = (ElementBorder *) elem->master; 1053 int state = args->state; 1054 int x = args->display.x, y = args->display.y; 1055 int width = args->display.width, height = args->display.height; 1056 int match, match2; 1057#ifdef DEPRECATED 1058 int draw; 1059#endif 1060 Tk_3DBorder border; 1061 int relief, filled = FALSE; 1062 int thickness = 0; 1063 1064#ifdef DEPRECATED 1065 BOOLEAN_FOR_STATE(draw, draw, state) 1066 if (!draw) 1067 return; 1068#endif 1069 1070 BORDER_FOR_STATE(border, border, state) 1071 if (border == NULL) 1072 return; 1073 1074 RELIEF_FOR_STATE(relief, relief, state) 1075 if (relief == TK_RELIEF_NULL) 1076 relief = TK_RELIEF_FLAT; 1077 1078 if (elemX->thicknessObj) 1079 thickness = elemX->thickness; 1080 else if ((masterX != NULL) && (masterX->thicknessObj != NULL)) 1081 thickness = masterX->thickness; 1082 1083 if (elemX->filled != -1) 1084 filled = elemX->filled; 1085 else if ((masterX != NULL) && (masterX->filled != -1)) 1086 filled = masterX->filled; 1087 1088 if (elemX->widthObj != NULL) 1089 width = elemX->width; 1090 else if ((masterX != NULL) && (masterX->widthObj != NULL)) 1091 width = masterX->width; 1092 1093 if (elemX->heightObj != NULL) 1094 height = elemX->height; 1095 else if ((masterX != NULL) && (masterX->heightObj != NULL)) 1096 height = masterX->height; 1097 1098 AdjustForSticky(args->display.sticky, 1099 args->display.width, args->display.height, 1100 TRUE, TRUE, 1101 &x, &y, &width, &height); 1102 1103 if (filled) { 1104 Tk_Fill3DRectangle(tree->tkwin, args->display.drawable, border, 1105 x, y, width, height, thickness, relief); 1106 } else if (thickness > 0) { 1107 Tk_Draw3DRectangle(tree->tkwin, args->display.drawable, border, 1108 x, y, width, height, thickness, relief); 1109 } 1110} 1111 1112static void NeededProcBorder(TreeElementArgs *args) 1113{ 1114 TreeElement elem = args->elem; 1115 ElementBorder *elemX = (ElementBorder *) elem; 1116 ElementBorder *masterX = (ElementBorder *) elem->master; 1117 int width = 0, height = 0; 1118 1119 if (elemX->widthObj != NULL) 1120 width = elemX->width; 1121 else if ((masterX != NULL) && (masterX->widthObj != NULL)) 1122 width = masterX->width; 1123 1124 if (elemX->heightObj != NULL) 1125 height = elemX->height; 1126 else if ((masterX != NULL) && (masterX->heightObj != NULL)) 1127 height = masterX->height; 1128 1129 args->needed.width = width; 1130 args->needed.height = height; 1131} 1132 1133static int StateProcBorder(TreeElementArgs *args) 1134{ 1135 TreeCtrl *tree = args->tree; 1136 TreeElement elem = args->elem; 1137 ElementBorder *elemX = (ElementBorder *) elem; 1138 ElementBorder *masterX = (ElementBorder *) elem->master; 1139 int match, match2; 1140#ifdef DEPRECATED 1141 int draw1, draw2; 1142#endif 1143 Tk_3DBorder border1, border2; 1144 int relief1, relief2; 1145 1146 if (!args->states.visible2 || !args->states.draw2) 1147 return 0; 1148 1149#ifdef DEPRECATED 1150 BOOLEAN_FOR_STATE(draw1, draw, args->states.state1) 1151 BOOLEAN_FOR_STATE(draw2, draw, args->states.state2) 1152 if ((draw1 != 0) != (draw2 != 0)) 1153 return CS_DISPLAY; 1154 if (draw2 == 0) 1155 return 0; 1156#endif 1157 1158 BORDER_FOR_STATE(border1, border, args->states.state1) 1159 BORDER_FOR_STATE(border2, border, args->states.state2) 1160 if (border1 != border2) 1161 return CS_DISPLAY; 1162 1163 RELIEF_FOR_STATE(relief1, relief, args->states.state1) 1164 RELIEF_FOR_STATE(relief2, relief, args->states.state2) 1165 if (relief1 != relief2) 1166 return CS_DISPLAY; 1167 1168 return 0; 1169} 1170 1171static int UndefProcBorder(TreeElementArgs *args) 1172{ 1173 TreeCtrl *tree = args->tree; 1174 ElementBorder *elemX = (ElementBorder *) args->elem; 1175 int modified = 0; 1176 1177#ifdef DEPRECATED 1178 modified |= PerStateInfo_Undefine(tree, &pstBoolean, &elemX->draw, args->state); 1179#endif 1180 modified |= PerStateInfo_Undefine(tree, &pstBorder, &elemX->border, args->state); 1181 modified |= PerStateInfo_Undefine(tree, &pstRelief, &elemX->relief, args->state); 1182 return modified; 1183} 1184 1185static int ActualProcBorder(TreeElementArgs *args) 1186{ 1187 TreeCtrl *tree = args->tree; 1188 ElementBorder *elemX = (ElementBorder *) args->elem; 1189 ElementBorder *masterX = (ElementBorder *) args->elem->master; 1190 static CONST char *optionName[] = { 1191 "-background", 1192#ifdef DEPRECATED 1193 "-draw", 1194#endif 1195 "-relief", 1196 (char *) NULL }; 1197 int index, match, matchM; 1198 Tcl_Obj *obj = NULL; 1199 1200 if (Tcl_GetIndexFromObj(tree->interp, args->actual.obj, optionName, 1201 "option", 0, &index) != TCL_OK) 1202 return TCL_ERROR; 1203 1204 switch (index) { 1205 case 0: { 1206 OBJECT_FOR_STATE(obj, pstBorder, border, args->state) 1207 break; 1208 } 1209#ifdef DEPRECATED 1210 case 1: { 1211 OBJECT_FOR_STATE(obj, pstBoolean, draw, args->state) 1212 break; 1213 } 1214 case 2: { 1215 OBJECT_FOR_STATE(obj, pstRelief, relief, args->state) 1216 break; 1217 } 1218#else 1219 case 1: { 1220 OBJECT_FOR_STATE(obj, pstRelief, relief, args->state) 1221 break; 1222 } 1223#endif 1224 } 1225 if (obj != NULL) 1226 Tcl_SetObjResult(tree->interp, obj); 1227 return TCL_OK; 1228} 1229 1230TreeElementType treeElemTypeBorder = { 1231 "border", 1232 sizeof(ElementBorder), 1233 borderOptionSpecs, 1234 NULL, 1235 CreateProcBorder, 1236 DeleteProcBorder, 1237 ConfigProcBorder, 1238 DisplayProcBorder, 1239 NeededProcBorder, 1240 NULL, /* heightProc */ 1241 WorldChangedProcBorder, 1242 StateProcBorder, 1243 UndefProcBorder, 1244 ActualProcBorder, 1245 NULL /* onScreenProc */ 1246}; 1247 1248/*****/ 1249#if 0 1250 1251static CONST char *chkbutStateST[] = { 1252 "checked", "mixed", "normal", "active", "pressed", "disabled", (char *) NULL 1253}; 1254 1255typedef struct ElementCheckButton ElementCheckButton; 1256 1257struct ElementCheckButton 1258{ 1259 TreeElement_ header; 1260 PerStateInfo image; 1261 int state; 1262}; 1263 1264#define CHKBUT_CONF_IMAGE 0x0001 1265#define CHKBUT_CONF_STATE 0x0002 1266 1267static Tk_OptionSpec chkbutOptionSpecs[] = { 1268 {TK_OPTION_STRING, "-image", (char *) NULL, (char *) NULL, 1269 (char *) NULL, Tk_Offset(ElementCheckButton, image.obj), -1, 1270 TK_OPTION_NULL_OK, (ClientData) NULL, CHKBUT_CONF_IMAGE}, 1271 {TK_OPTION_STRING_TABLE, "-state", (char *) NULL, (char *) NULL, 1272 "normal", -1, Tk_Offset(ElementCheckButton, state), 1273 0, (ClientData) chkbutStateST, CHKBUT_CONF_STATE}, 1274 {TK_OPTION_END, (char *) NULL, (char *) NULL, (char *) NULL, 1275 (char *) NULL, 0, -1, 0, (ClientData) NULL, 0} 1276}; 1277 1278static void DeleteProcCheckButton(TreeElementArgs *args) 1279{ 1280 TreeCtrl *tree = args->tree; 1281 TreeElement elem = args->elem; 1282 ElementCheckButton *elemX = (ElementCheckButton *) elem; 1283 1284 PerStateInfo_Free(tree, &pstImage, &elemX->image); 1285} 1286 1287static int WorldChangedProcCheckButton(TreeElementArgs *args) 1288{ 1289 int flagM = args->change.flagMaster; 1290 int flagS = args->change.flagSelf; 1291 int mask = 0; 1292 1293 if ((flagS | flagM) & (CHKBUT_CONF_IMAGE | CHKBUT_CONF_STATE)) 1294 mask |= CS_DISPLAY | CS_LAYOUT; 1295 1296 return mask; 1297} 1298 1299static int ChkButStateFromObj(TreeCtrl *tree, Tcl_Obj *obj, int *stateOff, int *stateOn) 1300{ 1301 Tcl_Interp *interp = tree->interp; 1302 int i, op = STATE_OP_ON, op2, op3, length, state = 0; 1303 char ch0, *string; 1304 int states[3]; 1305 1306 states[STATE_OP_ON] = 0; 1307 states[STATE_OP_OFF] = 0; 1308 states[STATE_OP_TOGGLE] = 0; 1309 1310 string = Tcl_GetStringFromObj(obj, &length); 1311 if (length == 0) 1312 goto unknown; 1313 ch0 = string[0]; 1314 if (ch0 == '!') { 1315 op = STATE_OP_OFF; 1316 ++string; 1317 ch0 = string[0]; 1318 } else if (ch0 == '~') { 1319 if (1) { 1320 FormatResult(interp, "can't specify '~' for this command"); 1321 return TCL_ERROR; 1322 } 1323 op = STATE_OP_TOGGLE; 1324 ++string; 1325 ch0 = string[0]; 1326 } 1327 for (i = 0; chkbutStateST[i] != NULL; i++) { 1328 if ((ch0 == chkbutStateST[i][0]) && !strcmp(string, chkbutStateST[i])) { 1329 state = 1L << i; 1330 break; 1331 } 1332 } 1333 if (state == 0) 1334 goto unknown; 1335 1336 if (op == STATE_OP_ON) { 1337 op2 = STATE_OP_OFF; 1338 op3 = STATE_OP_TOGGLE; 1339 } 1340 else if (op == STATE_OP_OFF) { 1341 op2 = STATE_OP_ON; 1342 op3 = STATE_OP_TOGGLE; 1343 } else { 1344 op2 = STATE_OP_ON; 1345 op3 = STATE_OP_OFF; 1346 } 1347 states[op2] &= ~state; 1348 states[op3] &= ~state; 1349 states[op] |= state; 1350 1351 *stateOn |= states[STATE_OP_ON]; 1352 *stateOff |= states[STATE_OP_OFF]; 1353 1354 return TCL_OK; 1355 1356unknown: 1357 FormatResult(interp, "unknown state \"%s\"", string); 1358 return TCL_ERROR; 1359} 1360 1361static int ConfigProcCheckButton(TreeElementArgs *args) 1362{ 1363 TreeCtrl *tree = args->tree; 1364 TreeElement elem = args->elem; 1365 ElementCheckButton *elemX = (ElementCheckButton *) elem; 1366 ElementCheckButton savedX; 1367 Tk_SavedOptions savedOptions; 1368 int error; 1369 Tcl_Obj *errorResult = NULL; 1370 1371 for (error = 0; error <= 1; error++) { 1372 if (error == 0) { 1373 if (Tk_SetOptions(tree->interp, (char *) elemX, 1374 elem->typePtr->optionTable, 1375 args->config.objc, args->config.objv, tree->tkwin, 1376 &savedOptions, &args->config.flagSelf) != TCL_OK) { 1377 args->config.flagSelf = 0; 1378 continue; 1379 } 1380 1381 if (args->config.flagSelf & CHKBUT_CONF_IMAGE) 1382 PSTSave(&elemX->image, &savedX.image); 1383 1384 if (args->config.flagSelf & CHKBUT_CONF_IMAGE) { 1385 if (PerStateInfo_FromObj(tree, ChkButStateFromObj, &pstImage, &elemX->image) != TCL_OK) 1386 continue; 1387 } 1388 1389 if (args->config.flagSelf & CHKBUT_CONF_IMAGE) 1390 PerStateInfo_Free(tree, &pstImage, &savedX.image); 1391 Tk_FreeSavedOptions(&savedOptions); 1392 break; 1393 } else { 1394 errorResult = Tcl_GetObjResult(tree->interp); 1395 Tcl_IncrRefCount(errorResult); 1396 Tk_RestoreSavedOptions(&savedOptions); 1397 1398 if (args->config.flagSelf & CHKBUT_CONF_IMAGE) 1399 PSTRestore(tree, &pstImage, &elemX->image, &savedX.image); 1400 1401 Tcl_SetObjResult(tree->interp, errorResult); 1402 Tcl_DecrRefCount(errorResult); 1403 return TCL_ERROR; 1404 } 1405 } 1406 1407 return TCL_OK; 1408} 1409 1410static int CreateProcCheckButton(TreeElementArgs *args) 1411{ 1412 return TCL_OK; 1413} 1414 1415static void DisplayProcCheckButton(TreeElementArgs *args) 1416{ 1417 TreeCtrl *tree = args->tree; 1418 TreeElement elem = args->elem; 1419 ElementCheckButton *elemX = (ElementCheckButton *) elem; 1420 ElementCheckButton *masterX = (ElementCheckButton *) elem->master; 1421 int state = args->state; 1422 int match, matchM; 1423 Tk_Image image; 1424 int imgW, imgH; 1425 int dx = 0, dy = 0; 1426 1427 image = PerStateImage_ForState(tree, &elemX->image, state, &match); 1428 if ((match != MATCH_EXACT) && (masterX != NULL)) { 1429 Tk_Image imageM = PerStateImage_ForState(tree, &masterX->image, 1430 state, &matchM); 1431 if (matchM > match) 1432 image = imageM; 1433 } 1434 1435 if (image != NULL) { 1436 Tk_SizeOfImage(image, &imgW, &imgH); 1437 if (imgW < args->display.width) 1438 dx = (args->display.width - imgW) / 2; 1439 else if (imgW > args->display.width) 1440 imgW = args->display.width; 1441 if (imgH < args->display.height) 1442 dy = (args->display.height - imgH) / 2; 1443 else if (imgH > args->display.height) 1444 imgH = args->display.height; 1445 Tk_RedrawImage(image, 0, 0, imgW, imgH, args->display.drawable, 1446 args->display.x + dx, 1447 args->display.y + dy); 1448 } 1449} 1450 1451static void NeededProcCheckButton(TreeElementArgs *args) 1452{ 1453 TreeCtrl *tree = args->tree; 1454 TreeElement elem = args->elem; 1455 ElementCheckButton *elemX = (ElementCheckButton *) elem; 1456 ElementCheckButton *masterX = (ElementCheckButton *) elem->master; 1457 int state = args->state; 1458 int match, match2; 1459 Tk_Image image; 1460 int width = 0, height = 0; 1461 1462 image = PerStateImage_ForState(tree, &elemX->image, state, &match); 1463 if ((match != MATCH_EXACT) && (masterX != NULL)) { 1464 Tk_Image image2 = PerStateImage_ForState(tree, &masterX->image, 1465 state, &match2); 1466 if (match2 > match) 1467 image = image2; 1468 } 1469 1470 if (image != NULL) 1471 Tk_SizeOfImage(image, &width, &height); 1472 1473 args->layout.width = width; 1474 args->layout.height = height; 1475} 1476 1477static int StateProcCheckButton(TreeElementArgs *args) 1478{ 1479 TreeCtrl *tree = args->tree; 1480 TreeElement elem = args->elem; 1481 ElementCheckButton *elemX = (ElementCheckButton *) elem; 1482 ElementCheckButton *masterX = (ElementCheckButton *) elem->master; 1483 int match, match2; 1484 Tk_Image image1, image2; 1485 int mask = 0; 1486 1487 image1 = PerStateImage_ForState(tree, &elemX->image, 1488 args->states.state1, &match); 1489 if ((match != MATCH_EXACT) && (masterX != NULL)) { 1490 Tk_Image image = PerStateImage_ForState(tree, &masterX->image, args->states.state1, &match2); 1491 if (match2 > match) 1492 image1 = image; 1493 } 1494 1495 image2 = PerStateImage_ForState(tree, &elemX->image, 1496 args->states.state2, &match); 1497 if ((match != MATCH_EXACT) && (masterX != NULL)) { 1498 Tk_Image image = PerStateImage_ForState(tree, &masterX->image, 1499 args->states.state2, &match2); 1500 if (match2 > match) 1501 image2 = image; 1502 } 1503 1504 if (image1 != image2) { 1505 mask |= CS_DISPLAY; 1506 if ((image1 != NULL) && (image2 != NULL)) { 1507 int w1, h1, w2, h2; 1508 Tk_SizeOfImage(image1, &w1, &h1); 1509 Tk_SizeOfImage(image2, &w2, &h2); 1510 if ((w1 != w2) || (h1 != h2)) 1511 mask |= CS_LAYOUT; 1512 } else 1513 mask |= CS_LAYOUT; 1514 } 1515 1516 return mask; 1517} 1518 1519static int UndefProcCheckButton(TreeElementArgs *args) 1520{ 1521 TreeCtrl *tree = args->tree; 1522 ElementCheckButton *elemX = (ElementCheckButton *) args->elem; 1523 1524 return PerStateInfo_Undefine(tree, &pstImage, &elemX->image, args->state); 1525} 1526 1527static int ActualProcCheckButton(TreeElementArgs *args) 1528{ 1529 TreeCtrl *tree = args->tree; 1530 ElementCheckButton *elemX = (ElementCheckButton *) args->elem; 1531 ElementCheckButton *masterX = (ElementCheckButton *) args->elem->master; 1532 static CONST char *optionName[] = { 1533 "-image", 1534 (char *) NULL }; 1535 int index, match, matchM; 1536 Tcl_Obj *obj = NULL; 1537 1538 if (Tcl_GetIndexFromObj(tree->interp, args->actual.obj, optionName, 1539 "option", 0, &index) != TCL_OK) 1540 return TCL_ERROR; 1541 1542 switch (index) { 1543 case 0: { 1544 obj = PerStateInfo_ObjForState(tree, &pstImage, 1545 &elemX->image, args->state, &match); 1546 if ((match != MATCH_EXACT) && (masterX != NULL)) { 1547 objM = PerStateInfo_ObjForState(tree, &pstImage, 1548 &masterX->image, args->state, &matchM); 1549 if (matchM > match) 1550 obj = objM; 1551 } 1552 break; 1553 } 1554 } 1555 if (obj != NULL) 1556 Tcl_SetObjResult(tree->interp, obj); 1557 return TCL_OK; 1558} 1559 1560TreeElementType treeElemTypeCheckButton = { 1561 "checkbutton", 1562 sizeof(ElementCheckButton), 1563 chkbutOptionSpecs, 1564 NULL, 1565 CreateProcCheckButton, 1566 DeleteProcCheckButton, 1567 ConfigProcCheckButton, 1568 DisplayProcCheckButton, 1569 NeededProcCheckButton, 1570 NULL, /* heightProc */ 1571 WorldChangedProcCheckButton, 1572 StateProcCheckButton, 1573 UndefProcCheckButton, 1574 ActualProcCheckButton, 1575 NULL /* onScreenProc */ 1576}; 1577 1578#endif 1579 1580/*****/ 1581 1582typedef struct ElementImage ElementImage; 1583 1584struct ElementImage 1585{ 1586 TreeElement_ header; 1587 PerStateInfo image; 1588}; 1589 1590typedef struct ElementImageSize 1591{ 1592 int width; 1593 Tcl_Obj *widthObj; 1594 int height; 1595 Tcl_Obj *heightObj; 1596} ElementImageSize; 1597 1598#define IMAGE_CONF_IMAGE 0x0001 1599#define IMAGE_CONF_SIZE 0x0002 1600#define IMAGE_CONF_DISPLAY 0x0004 1601#ifdef DEPRECATED 1602#define IMAGE_CONF_DRAW 0x0008 1603#endif 1604 1605static Tk_OptionSpec imageOptionSpecs[] = { 1606#ifdef DEPRECATED 1607 {TK_OPTION_CUSTOM, "-draw", (char *) NULL, (char *) NULL, 1608 (char *) NULL, -1, Tk_Offset(TreeElement_, options), 1609 TK_OPTION_NULL_OK, (ClientData) NULL, IMAGE_CONF_DRAW}, 1610#endif 1611 {TK_OPTION_CUSTOM, "-height", (char *) NULL, (char *) NULL, 1612 (char *) NULL, -1, Tk_Offset(TreeElement_, options), 1613 TK_OPTION_NULL_OK, (ClientData) NULL, IMAGE_CONF_SIZE}, 1614 {TK_OPTION_CUSTOM, "-image", (char *) NULL, (char *) NULL, 1615 (char *) NULL, 1616 Tk_Offset(ElementImage, image.obj), Tk_Offset(ElementImage, image), 1617 TK_OPTION_NULL_OK, (ClientData) NULL, IMAGE_CONF_IMAGE}, 1618 {TK_OPTION_CUSTOM, "-tiled", (char *) NULL, (char *) NULL, 1619 (char *) NULL, -1, Tk_Offset(TreeElement_, options), 1620 TK_OPTION_NULL_OK, (ClientData) NULL, IMAGE_CONF_DISPLAY}, 1621 {TK_OPTION_CUSTOM, "-width", (char *) NULL, (char *) NULL, 1622 (char *) NULL, -1, Tk_Offset(TreeElement_, options), 1623 TK_OPTION_NULL_OK, (ClientData) NULL, IMAGE_CONF_SIZE}, 1624 {TK_OPTION_END, (char *) NULL, (char *) NULL, (char *) NULL, 1625 (char *) NULL, 0, -1, 0, (ClientData) NULL, 0} 1626}; 1627 1628static void DeleteProcImage(TreeElementArgs *args) 1629{ 1630/* TreeCtrl *tree = args->tree; 1631 TreeElement elem = args->elem; 1632 ElementImage *elemX = (ElementImage *) elem;*/ 1633} 1634 1635static int WorldChangedProcImage(TreeElementArgs *args) 1636{ 1637 int flagM = args->change.flagMaster; 1638 int flagS = args->change.flagSelf; 1639 int mask = 0; 1640 1641 if ((flagS | flagM) & ( 1642#ifdef DEPRECATED 1643 IMAGE_CONF_DRAW | 1644#endif 1645 IMAGE_CONF_IMAGE | IMAGE_CONF_SIZE)) 1646 mask |= CS_DISPLAY | CS_LAYOUT; 1647 if ((flagS | flagM) & IMAGE_CONF_DISPLAY) 1648 mask |= CS_DISPLAY; 1649 1650 return mask; 1651} 1652 1653static int ConfigProcImage(TreeElementArgs *args) 1654{ 1655 TreeCtrl *tree = args->tree; 1656 TreeElement elem = args->elem; 1657 ElementImage *elemX = (ElementImage *) elem; 1658 Tk_SavedOptions savedOptions; 1659 int error; 1660 Tcl_Obj *errorResult = NULL; 1661 1662 for (error = 0; error <= 1; error++) { 1663 if (error == 0) { 1664 if (Tk_SetOptions(tree->interp, (char *) elemX, 1665 elem->typePtr->optionTable, 1666 args->config.objc, args->config.objv, tree->tkwin, 1667 &savedOptions, &args->config.flagSelf) != TCL_OK) { 1668 args->config.flagSelf = 0; 1669 continue; 1670 } 1671 1672 Tk_FreeSavedOptions(&savedOptions); 1673 break; 1674 } else { 1675 errorResult = Tcl_GetObjResult(tree->interp); 1676 Tcl_IncrRefCount(errorResult); 1677 Tk_RestoreSavedOptions(&savedOptions); 1678 1679 Tcl_SetObjResult(tree->interp, errorResult); 1680 Tcl_DecrRefCount(errorResult); 1681 return TCL_ERROR; 1682 } 1683 } 1684 1685 return TCL_OK; 1686} 1687 1688static int CreateProcImage(TreeElementArgs *args) 1689{ 1690/* ElementImage *elemX = (ElementImage *) args->elem;*/ 1691 1692 return TCL_OK; 1693} 1694 1695static void DisplayProcImage(TreeElementArgs *args) 1696{ 1697 TreeCtrl *tree = args->tree; 1698 TreeElement elem = args->elem; 1699 ElementImage *elemX = (ElementImage *) elem; 1700 ElementImage *masterX = (ElementImage *) elem->master; 1701 int state = args->state; 1702 int x = args->display.x, y = args->display.y; 1703 int width, height; 1704 int match, match2; 1705#ifdef DEPRECATED 1706 int draw; 1707#endif 1708 Tk_Image image; 1709 int imgW, imgH; 1710 int tiled = 0, *eit, *eitM = NULL; 1711 1712#ifdef DEPRECATED 1713 draw = DO_BooleanForState(tree, elem, 1002, state); 1714 if (!draw) 1715 return; 1716#endif 1717 1718 IMAGE_FOR_STATE(image, image, state) 1719 if (image == NULL) 1720 return; 1721 1722 eit = DynamicOption_FindData(elem->options, 1003); 1723 if (masterX != NULL) 1724 eitM = DynamicOption_FindData(elem->master->options, 1003); 1725 1726 if (eit != NULL && *eit != -1) 1727 tiled = *eit; 1728 else if ((eitM != NULL) && (*eitM != -1)) 1729 tiled = *eitM; 1730 if (tiled) { 1731 Tree_DrawTiledImage(tree, args->display.drawable, image, x, y, 1732 x + args->display.width, y + args->display.height, -x, -y); 1733 return; 1734 } 1735 1736 Tk_SizeOfImage(image, &imgW, &imgH); 1737 width = imgW, height = imgH; 1738 AdjustForSticky(args->display.sticky, 1739 args->display.width, args->display.height, 1740 FALSE, FALSE, 1741 &x, &y, &width, &height); 1742 if (imgW > args->display.width) 1743 imgW = args->display.width; 1744 if (imgH > args->display.height) 1745 imgH = args->display.height; 1746 Tree_RedrawImage(image, 0, 0, imgW, imgH, args->display.td, x, y); 1747} 1748 1749static void NeededProcImage(TreeElementArgs *args) 1750{ 1751 TreeCtrl *tree = args->tree; 1752 TreeElement elem = args->elem; 1753 ElementImage *elemX = (ElementImage *) elem; 1754 ElementImage *masterX = (ElementImage *) elem->master; 1755 int state = args->state; 1756 int width = 0, height = 0; 1757 int match, match2; 1758 Tk_Image image; 1759 ElementImageSize *eis, *eisM = NULL; 1760 1761 IMAGE_FOR_STATE(image, image, state) 1762 1763 if (image != NULL) 1764 Tk_SizeOfImage(image, &width, &height); 1765 1766 eis = DynamicOption_FindData(elem->options, 1001); 1767 if (masterX != NULL) 1768 eisM = DynamicOption_FindData(elem->master->options, 1001); 1769 1770 if (eis != NULL && eis->widthObj != NULL) 1771 width = eis->width; 1772 else if ((eisM != NULL) && (eisM->widthObj != NULL)) 1773 width = eisM->width; 1774 1775 if (eis != NULL && eis->heightObj != NULL) 1776 height = eis->height; 1777 else if ((eisM != NULL) && (eisM->heightObj != NULL)) 1778 height = eisM->height; 1779 1780 args->needed.width = width; 1781 args->needed.height = height; 1782} 1783 1784static int StateProcImage(TreeElementArgs *args) 1785{ 1786 TreeCtrl *tree = args->tree; 1787 TreeElement elem = args->elem; 1788 ElementImage *elemX = (ElementImage *) elem; 1789 ElementImage *masterX = (ElementImage *) elem->master; 1790 int match, match2; 1791#ifdef DEPRECATED 1792 int draw1, draw2; 1793#endif 1794 Tk_Image image1, image2; 1795 1796 if (!args->states.visible2) 1797 return 0; 1798 1799 IMAGE_FOR_STATE(image1, image, args->states.state1) 1800 IMAGE_FOR_STATE(image2, image, args->states.state2) 1801 1802 if (image1 != image2) { 1803 if ((image1 != NULL) && (image2 != NULL)) { 1804 int w1, h1, w2, h2; 1805 Tk_SizeOfImage(image1, &w1, &h1); 1806 Tk_SizeOfImage(image2, &w2, &h2); 1807 if ((w1 != w2) || (h1 != h2)) 1808 return CS_DISPLAY | CS_LAYOUT; 1809 return CS_DISPLAY; 1810 } 1811 return CS_DISPLAY | CS_LAYOUT; 1812 } 1813 1814 if (!args->states.draw2) 1815 return 0; 1816#ifdef DEPRECATED 1817 draw1 = DO_BooleanForState(tree, elem, 1002, args->states.state1); 1818 draw2 = DO_BooleanForState(tree, elem, 1002, args->states.state2); 1819 if ((draw1 != 0) != (draw2 != 0)) 1820 return CS_DISPLAY; 1821#endif 1822 1823 return 0; 1824} 1825 1826static int UndefProcImage(TreeElementArgs *args) 1827{ 1828 TreeCtrl *tree = args->tree; 1829 TreeElement elem = args->elem; 1830 ElementImage *elemX = (ElementImage *) elem; 1831 int modified = 0; 1832#ifdef DEPRECATED 1833 PerStateInfo *psi; 1834#endif 1835 1836#ifdef DEPRECATED 1837 if ((psi = DynamicOption_FindData(elem->options, 1002)) != NULL) 1838 modified |= PerStateInfo_Undefine(tree, &pstBoolean, psi, args->state); 1839#endif 1840 modified |= PerStateInfo_Undefine(tree, &pstImage, &elemX->image, args->state); 1841 return modified; 1842} 1843 1844static int ActualProcImage(TreeElementArgs *args) 1845{ 1846 TreeCtrl *tree = args->tree; 1847 ElementImage *elemX = (ElementImage *) args->elem; 1848 ElementImage *masterX = (ElementImage *) args->elem->master; 1849 static CONST char *optionName[] = { 1850#ifdef DEPRECATED 1851 "-draw", 1852#endif 1853 "-image", 1854 (char *) NULL }; 1855 int index, match, matchM; 1856 Tcl_Obj *obj = NULL; 1857 1858 if (Tcl_GetIndexFromObj(tree->interp, args->actual.obj, optionName, 1859 "option", 0, &index) != TCL_OK) 1860 return TCL_ERROR; 1861 1862 switch (index) { 1863#ifdef DEPRECATED 1864 case 0: { 1865 obj = DO_ObjectForState(tree, &pstBoolean, args->elem, 1002, args->state); 1866 break; 1867 } 1868 case 1: { 1869 OBJECT_FOR_STATE(obj, pstImage, image, args->state) 1870 break; 1871 } 1872#else 1873 case 0: { 1874 OBJECT_FOR_STATE(obj, pstImage, image, args->state) 1875 break; 1876 } 1877#endif 1878 } 1879 if (obj != NULL) 1880 Tcl_SetObjResult(tree->interp, obj); 1881 return TCL_OK; 1882} 1883 1884TreeElementType treeElemTypeImage = { 1885 "image", 1886 sizeof(ElementImage), 1887 imageOptionSpecs, 1888 NULL, 1889 CreateProcImage, 1890 DeleteProcImage, 1891 ConfigProcImage, 1892 DisplayProcImage, 1893 NeededProcImage, 1894 NULL, /* heightProc */ 1895 WorldChangedProcImage, 1896 StateProcImage, 1897 UndefProcImage, 1898 ActualProcImage, 1899 NULL /* onScreenProc */ 1900}; 1901 1902/*****/ 1903 1904typedef struct ElementRect ElementRect; 1905 1906struct ElementRect 1907{ 1908 TreeElement_ header; 1909#ifdef DEPRECATED 1910 PerStateInfo draw; 1911#endif 1912 int width; 1913 Tcl_Obj *widthObj; 1914 int height; 1915 Tcl_Obj *heightObj; 1916 PerStateInfo fill; 1917 PerStateInfo outline; 1918 int outlineWidth; 1919 Tcl_Obj *outlineWidthObj; 1920 int open; 1921 char *openString; 1922 int showFocus; 1923}; 1924 1925#define RECT_CONF_FILL 0x0001 1926#define RECT_CONF_OUTLINE 0x0002 1927#define RECT_CONF_OUTWIDTH 0x0004 1928#define RECT_CONF_OPEN 0x0008 1929#define RECT_CONF_SIZE 0x0010 1930#define RECT_CONF_FOCUS 0x0020 1931#ifdef DEPRECATED 1932#define RECT_CONF_DRAW 0x0040 1933#endif 1934 1935static Tk_OptionSpec rectOptionSpecs[] = { 1936#ifdef DEPRECATED 1937 {TK_OPTION_CUSTOM, "-draw", (char *) NULL, (char *) NULL, 1938 (char *) NULL, 1939 Tk_Offset(ElementRect, draw.obj), Tk_Offset(ElementRect, draw), 1940 TK_OPTION_NULL_OK, (ClientData) NULL, RECT_CONF_DRAW}, 1941#endif 1942 {TK_OPTION_CUSTOM, "-fill", (char *) NULL, (char *) NULL, 1943 (char *) NULL, 1944 Tk_Offset(ElementRect, fill.obj), Tk_Offset(ElementRect, fill), 1945 TK_OPTION_NULL_OK, (ClientData) NULL, RECT_CONF_FILL}, 1946 {TK_OPTION_PIXELS, "-height", (char *) NULL, (char *) NULL, 1947 (char *) NULL, Tk_Offset(ElementRect, heightObj), 1948 Tk_Offset(ElementRect, height), 1949 TK_OPTION_NULL_OK, (ClientData) NULL, RECT_CONF_SIZE}, 1950 {TK_OPTION_STRING, "-open", (char *) NULL, (char *) NULL, 1951 (char *) NULL, -1, Tk_Offset(ElementRect, openString), 1952 TK_OPTION_NULL_OK, (ClientData) NULL, RECT_CONF_OPEN}, 1953 {TK_OPTION_CUSTOM, "-outline", (char *) NULL, (char *) NULL, 1954 (char *) NULL, 1955 Tk_Offset(ElementRect, outline.obj), Tk_Offset(ElementRect, outline), 1956 TK_OPTION_NULL_OK, (ClientData) NULL, RECT_CONF_OUTLINE}, 1957 {TK_OPTION_PIXELS, "-outlinewidth", (char *) NULL, (char *) NULL, 1958 (char *) NULL, Tk_Offset(ElementRect, outlineWidthObj), 1959 Tk_Offset(ElementRect, outlineWidth), 1960 TK_OPTION_NULL_OK, (ClientData) NULL, RECT_CONF_OUTWIDTH}, 1961 {TK_OPTION_CUSTOM, "-showfocus", (char *) NULL, (char *) NULL, 1962 (char *) NULL, -1, Tk_Offset(ElementRect, showFocus), 1963 TK_OPTION_NULL_OK, (ClientData) &booleanCO, RECT_CONF_FOCUS}, 1964 {TK_OPTION_PIXELS, "-width", (char *) NULL, (char *) NULL, 1965 (char *) NULL, Tk_Offset(ElementRect, widthObj), 1966 Tk_Offset(ElementRect, width), 1967 TK_OPTION_NULL_OK, (ClientData) NULL, RECT_CONF_SIZE}, 1968 {TK_OPTION_END, (char *) NULL, (char *) NULL, (char *) NULL, 1969 (char *) NULL, 0, -1, 0, (ClientData) NULL, 0} 1970}; 1971 1972static void DeleteProcRect(TreeElementArgs *args) 1973{ 1974/* TreeCtrl *tree = args->tree; 1975 ElementRect *elemX = (ElementRect *) args->elem;*/ 1976} 1977 1978static int WorldChangedProcRect(TreeElementArgs *args) 1979{ 1980 int flagM = args->change.flagMaster; 1981 int flagS = args->change.flagSelf; 1982 int mask = 0; 1983 1984 if ((flagS | flagM) & (RECT_CONF_SIZE | RECT_CONF_OUTWIDTH)) 1985 mask |= CS_DISPLAY | CS_LAYOUT; 1986 1987 if ((flagS | flagM) & ( 1988#ifdef DEPRECATED 1989 RECT_CONF_DRAW | 1990#endif 1991 RECT_CONF_FILL | RECT_CONF_OUTLINE | RECT_CONF_OPEN | 1992 RECT_CONF_FOCUS)) 1993 mask |= CS_DISPLAY; 1994 1995 return mask; 1996} 1997 1998static int ConfigProcRect(TreeElementArgs *args) 1999{ 2000 TreeCtrl *tree = args->tree; 2001 TreeElement elem = args->elem; 2002 ElementRect *elemX = (ElementRect *) elem; 2003 ElementRect savedX; 2004 Tk_SavedOptions savedOptions; 2005 int error; 2006 Tcl_Obj *errorResult = NULL; 2007 int i; 2008 2009 savedX.open = 0; /* Prevent compiler warning */ 2010 2011 for (error = 0; error <= 1; error++) { 2012 if (error == 0) { 2013 if (Tk_SetOptions(tree->interp, (char *) elemX, 2014 elem->typePtr->optionTable, 2015 args->config.objc, args->config.objv, tree->tkwin, 2016 &savedOptions, &args->config.flagSelf) != TCL_OK) { 2017 args->config.flagSelf = 0; 2018 continue; 2019 } 2020 2021 if (args->config.flagSelf & RECT_CONF_OPEN) 2022 savedX.open = elemX->open; 2023 2024 if (args->config.flagSelf & RECT_CONF_OPEN) { 2025 elemX->open = 0; 2026 if (elemX->openString != NULL) { 2027 int badChar = 0; 2028 2029 for (i = 0; elemX->openString[i]; i++) { 2030 switch (elemX->openString[i]) { 2031 case 'w': case 'W': elemX->open |= 0x01; break; 2032 case 'n': case 'N': elemX->open |= 0x02; break; 2033 case 'e': case 'E': elemX->open |= 0x04; break; 2034 case 's': case 'S': elemX->open |= 0x08; break; 2035 default: { 2036 Tcl_ResetResult(tree->interp); 2037 Tcl_AppendResult(tree->interp, "bad open value \"", 2038 elemX->openString, "\": must be a string ", 2039 "containing zero or more of n, e, s, and w", 2040 (char *) NULL); 2041 badChar = 1; 2042 break; 2043 } 2044 } 2045 if (badChar) 2046 break; 2047 } 2048 if (badChar) 2049 continue; 2050 } 2051 } 2052 2053 Tk_FreeSavedOptions(&savedOptions); 2054 break; 2055 } else { 2056 errorResult = Tcl_GetObjResult(tree->interp); 2057 Tcl_IncrRefCount(errorResult); 2058 Tk_RestoreSavedOptions(&savedOptions); 2059 2060 if (args->config.flagSelf & RECT_CONF_OPEN) 2061 elemX->open = savedX.open; 2062 2063 Tcl_SetObjResult(tree->interp, errorResult); 2064 Tcl_DecrRefCount(errorResult); 2065 return TCL_ERROR; 2066 } 2067 } 2068 2069 return TCL_OK; 2070} 2071 2072static int CreateProcRect(TreeElementArgs *args) 2073{ 2074 ElementRect *elemX = (ElementRect *) args->elem; 2075 2076 elemX->showFocus = -1; 2077 return TCL_OK; 2078} 2079 2080static void DisplayProcRect(TreeElementArgs *args) 2081{ 2082 TreeCtrl *tree = args->tree; 2083 TreeElement elem = args->elem; 2084 ElementRect *elemX = (ElementRect *) elem; 2085 ElementRect *masterX = (ElementRect *) elem->master; 2086 int state = args->state; 2087 int x = args->display.x, y = args->display.y; 2088 int width = args->display.width, height = args->display.height; 2089 int match, match2; 2090#ifdef DEPRECATED 2091 int draw; 2092#endif 2093 XColor *color; 2094 int open = 0; 2095 int outlineWidth = 0; 2096 int showFocus = 0; 2097 2098#ifdef DEPRECATED 2099 BOOLEAN_FOR_STATE(draw, draw, state) 2100 if (!draw) 2101 return; 2102#endif 2103 2104 if (elemX->outlineWidthObj != NULL) 2105 outlineWidth = elemX->outlineWidth; 2106 else if ((masterX != NULL) && (masterX->outlineWidthObj != NULL)) 2107 outlineWidth = masterX->outlineWidth; 2108 2109 if (elemX->openString != NULL) 2110 open = elemX->open; 2111 else if ((masterX != NULL) && (masterX->openString != NULL)) 2112 open = masterX->open; 2113 2114 if (elemX->showFocus != -1) 2115 showFocus = elemX->showFocus; 2116 else if ((masterX != NULL) && (masterX->showFocus != -1)) 2117 showFocus = masterX->showFocus; 2118 2119 if (elemX->widthObj != NULL) 2120 width = elemX->width; 2121 else if ((masterX != NULL) && (masterX->widthObj != NULL)) 2122 width = masterX->width; 2123 2124 if (elemX->heightObj != NULL) 2125 height = elemX->height; 2126 else if ((masterX != NULL) && (masterX->heightObj != NULL)) 2127 height = masterX->height; 2128 2129 AdjustForSticky(args->display.sticky, 2130 args->display.width, args->display.height, 2131 TRUE, TRUE, 2132 &x, &y, &width, &height); 2133 2134 COLOR_FOR_STATE(color, fill, state) 2135 if (color != NULL) { 2136 GC gc = Tk_GCForColor(color, Tk_WindowId(tree->tkwin)); 2137 XFillRectangle(tree->display, args->display.drawable, gc, 2138 x, y, width, height); 2139 } 2140 2141 COLOR_FOR_STATE(color, outline, state) 2142 if ((color != NULL) && (outlineWidth > 0)) { 2143 GC gc = Tk_GCForColor(color, Tk_WindowId(tree->tkwin)); 2144 if (!(open & 0x01)) 2145 XFillRectangle(tree->display, args->display.drawable, gc, 2146 x, y, outlineWidth, height); 2147 if (!(open & 0x02)) 2148 XFillRectangle(tree->display, args->display.drawable, gc, 2149 x, y, width, outlineWidth); 2150 if (!(open & 0x04)) 2151 XFillRectangle(tree->display, args->display.drawable, gc, 2152 x + width - outlineWidth, y, outlineWidth, height); 2153 if (!(open & 0x08)) 2154 XFillRectangle(tree->display, args->display.drawable, gc, 2155 x, y + height - outlineWidth, width, outlineWidth); 2156 } 2157 2158 if (showFocus && (state & STATE_FOCUS) && (state & STATE_ACTIVE)) { 2159 Tree_DrawActiveOutline(tree, args->display.drawable, 2160 args->display.x, args->display.y, 2161 args->display.width, args->display.height, 2162 open); 2163 } 2164} 2165 2166static void NeededProcRect(TreeElementArgs *args) 2167{ 2168 TreeElement elem = args->elem; 2169 ElementRect *elemX = (ElementRect *) elem; 2170 ElementRect *masterX = (ElementRect *) elem->master; 2171 int width = 0, height = 0; 2172 int outlineWidth = 0; 2173 2174 if (elemX->outlineWidthObj != NULL) 2175 outlineWidth = elemX->outlineWidth; 2176 else if ((masterX != NULL) && (masterX->outlineWidthObj != NULL)) 2177 outlineWidth = masterX->outlineWidth; 2178 2179 if (elemX->widthObj != NULL) 2180 width = elemX->width; 2181 else if ((masterX != NULL) && (masterX->widthObj != NULL)) 2182 width = masterX->width; 2183 2184 if (elemX->heightObj != NULL) 2185 height = elemX->height; 2186 else if ((masterX != NULL) && (masterX->heightObj != NULL)) 2187 height = masterX->height; 2188 2189 args->needed.width = MAX(width, outlineWidth * 2); 2190 args->needed.height = MAX(height, outlineWidth * 2); 2191} 2192 2193static int StateProcRect(TreeElementArgs *args) 2194{ 2195 TreeCtrl *tree = args->tree; 2196 TreeElement elem = args->elem; 2197 ElementRect *elemX = (ElementRect *) elem; 2198 ElementRect *masterX = (ElementRect *) elem->master; 2199 int match, match2; 2200#ifdef DEPRECATED 2201 int draw1, draw2; 2202#endif 2203 XColor *f1, *f2; 2204 XColor *o1, *o2; 2205 int s1, s2; 2206 int showFocus = 0; 2207 2208 /* If either the -draw or -visible layout option is false for the 2209 * current state, then changes to colors etc don't warrant a redisplay. */ 2210 if (!args->states.visible2 || !args->states.draw2) 2211 return 0; 2212 2213#ifdef DEPRECATED 2214 BOOLEAN_FOR_STATE(draw1, draw, args->states.state1) 2215 BOOLEAN_FOR_STATE(draw2, draw, args->states.state2) 2216 if ((draw1 != 0) != (draw2 != 0)) 2217 return CS_DISPLAY; 2218 /* If the element isn't drawn, then changes to colors etc don't 2219 * warrant a redisplay. */ 2220 if (draw2 == 0) 2221 return 0; 2222#endif 2223 2224 if (elemX->showFocus != -1) 2225 showFocus = elemX->showFocus; 2226 else if ((masterX != NULL) && (masterX->showFocus != -1)) 2227 showFocus = masterX->showFocus; 2228 2229 s1 = showFocus && 2230 (args->states.state1 & STATE_FOCUS) && 2231 (args->states.state1 & STATE_ACTIVE); 2232 s2 = showFocus && 2233 (args->states.state2 & STATE_FOCUS) && 2234 (args->states.state2 & STATE_ACTIVE); 2235 if (s1 != s2) 2236 return CS_DISPLAY; 2237 2238 COLOR_FOR_STATE(f1, fill, args->states.state1) 2239 COLOR_FOR_STATE(f2, fill, args->states.state2) 2240 if (f1 != f2) 2241 return CS_DISPLAY; 2242 2243 COLOR_FOR_STATE(o1, outline, args->states.state1) 2244 COLOR_FOR_STATE(o2, outline, args->states.state2) 2245 if (o1 != o2) 2246 return CS_DISPLAY; 2247 2248 return 0; 2249} 2250 2251static int UndefProcRect(TreeElementArgs *args) 2252{ 2253 TreeCtrl *tree = args->tree; 2254 ElementRect *elemX = (ElementRect *) args->elem; 2255 int modified = 0; 2256 2257#ifdef DEPRECATED 2258 modified |= PerStateInfo_Undefine(tree, &pstBoolean, &elemX->draw, args->state); 2259#endif 2260 modified |= PerStateInfo_Undefine(tree, &pstColor, &elemX->fill, args->state); 2261 modified |= PerStateInfo_Undefine(tree, &pstColor, &elemX->outline, args->state); 2262 return modified; 2263} 2264 2265static int ActualProcRect(TreeElementArgs *args) 2266{ 2267 TreeCtrl *tree = args->tree; 2268 ElementRect *elemX = (ElementRect *) args->elem; 2269 ElementRect *masterX = (ElementRect *) args->elem->master; 2270 static CONST char *optionName[] = { 2271#ifdef DEPRECATED 2272 "-draw", 2273#endif 2274 "-fill", "-outline", 2275 (char *) NULL }; 2276 int index, match, matchM; 2277 Tcl_Obj *obj = NULL; 2278 2279 if (Tcl_GetIndexFromObj(tree->interp, args->actual.obj, optionName, 2280 "option", 0, &index) != TCL_OK) 2281 return TCL_ERROR; 2282 2283 switch (index) { 2284#ifdef DEPRECATED 2285 case 0: { 2286 OBJECT_FOR_STATE(obj, pstBoolean, draw, args->state) 2287 break; 2288 } 2289 case 1: { 2290 OBJECT_FOR_STATE(obj, pstColor, fill, args->state) 2291 break; 2292 } 2293 case 2: { 2294 OBJECT_FOR_STATE(obj, pstColor, outline, args->state) 2295 break; 2296 } 2297#else 2298 case 0: { 2299 OBJECT_FOR_STATE(obj, pstColor, fill, args->state) 2300 break; 2301 } 2302 case 1: { 2303 OBJECT_FOR_STATE(obj, pstColor, outline, args->state) 2304 break; 2305 } 2306#endif 2307 } 2308 if (obj != NULL) 2309 Tcl_SetObjResult(tree->interp, obj); 2310 return TCL_OK; 2311} 2312 2313TreeElementType treeElemTypeRect = { 2314 "rect", 2315 sizeof(ElementRect), 2316 rectOptionSpecs, 2317 NULL, 2318 CreateProcRect, 2319 DeleteProcRect, 2320 ConfigProcRect, 2321 DisplayProcRect, 2322 NeededProcRect, 2323 NULL, /* heightProc */ 2324 WorldChangedProcRect, 2325 StateProcRect, 2326 UndefProcRect, 2327 ActualProcRect, 2328 NULL /* onScreenProc */ 2329}; 2330 2331/*****/ 2332 2333typedef struct ElementText ElementText; 2334 2335struct ElementText 2336{ 2337 TreeElement_ header; 2338 char *textCfg; /* -text */ 2339 char *text; /* This will be the same as textCfg, or it 2340 * will be a dynamically allocated string 2341 * from any -data or -textvariable. */ 2342#define STRINGREP_INVALID -1 2343 int textLen; /* Number of bytes (not characters) in the 2344 * UTF-8 string. If -1, it means the string 2345 * representation is invalid. */ 2346}; 2347#define TEXTVAR 2348 2349/* for Tk_SetOptions() */ 2350#define TEXT_CONF_LAYOUT 0x0001 2351#define TEXT_CONF_DISPLAY 0x0002 2352#define TEXT_CONF_STRINGREP 0x0040 2353#ifdef TEXTVAR 2354#define TEXT_CONF_TEXTVAR 0x0080 2355#endif 2356 2357/* 2358 * Dynamic option ids for the text element. 2359 */ 2360#define DOID_TEXT_VAR 1001 2361#define DOID_TEXT_DRAW 1002 2362#define DOID_TEXT_FILL 1003 2363#define DOID_TEXT_FONT 1004 2364#define DOID_TEXT_LAYOUT 1005 2365#define DOID_TEXT_DATA 1006 2366#define DOID_TEXT_LAYOUT2 1007 2367#define DOID_TEXT_STYLE 1008 2368#define DOID_TEXT_LAYOUT3 1009 2369 2370typedef struct ElementTextData { 2371 Tcl_Obj *dataObj; /* -data */ 2372#define TDT_NULL -1 2373#define TDT_DOUBLE 0 2374#define TDT_INTEGER 1 2375#define TDT_LONG 2 2376#define TDT_STRING 3 2377#define TDT_TIME 4 2378 int dataType; /* -datatype */ 2379 Tcl_Obj *formatObj; /* -format */ 2380} ElementTextData; 2381 2382typedef struct ElementTextLayout { 2383#define TK_JUSTIFY_NULL -1 2384 int justify; /* -justify */ 2385 int lines; /* -lines */ 2386 Tcl_Obj *widthObj; /* -width */ 2387 int width; /* -width */ 2388#define TEXT_WRAP_NULL -1 2389#define TEXT_WRAP_CHAR 0 2390#define TEXT_WRAP_NONE 1 2391#define TEXT_WRAP_WORD 2 2392 int wrap; /* -wrap */ 2393} ElementTextLayout; 2394 2395/* This structure doesn't hold any option values, but it is managed by 2396 * the dynamic-option code. */ 2397typedef struct ElementTextLayout2 { 2398 TextLayout layout; 2399 int layoutWidth; 2400 int neededWidth; 2401 int totalWidth; 2402} ElementTextLayout2; 2403 2404typedef struct ElementTextLayout3 { 2405 Tcl_Obj *lMargin1Obj; /* -lmargin1 */ 2406 int lMargin1; /* -lmargin2 */ 2407 Tcl_Obj *lMargin2Obj; /* -lmargin1 */ 2408 int lMargin2; /* -lmargin2 */ 2409} ElementTextLayout3; 2410 2411#define TEXT_STYLE 2412#ifdef TEXT_STYLE 2413typedef struct ElementTextStyle { 2414 int underline; /* -underline */ 2415} ElementTextStyle; 2416 2417/* Called by the dynamic-option code when an ElementTextData is allocated. */ 2418static void 2419ElementTextStyleInit( 2420 void *data 2421 ) 2422{ 2423 ElementTextStyle *ets = data; 2424 2425#define TEXT_UNDERLINE_EMPTYVAL -100000 2426 ets->underline = TEXT_UNDERLINE_EMPTYVAL; 2427} 2428#endif 2429 2430#ifdef TEXTVAR 2431typedef struct ElementTextVar { 2432 Tcl_Obj *varNameObj; /* -textvariable */ 2433 TreeCtrl *tree; /* needed to redisplay */ 2434 TreeItem item; /* needed to redisplay */ 2435 TreeItemColumn column; /* needed to redisplay */ 2436} ElementTextVar; 2437#endif 2438 2439/* Called by the dynamic-option code when an ElementTextData is allocated. */ 2440static void 2441ElementTextDataInit( 2442 void *data 2443 ) 2444{ 2445 ElementTextData *etd = data; 2446 2447 etd->dataType = TDT_NULL; 2448} 2449 2450/* Called by the dynamic-option code when an ElementTextLayout is allocated. */ 2451static void 2452ElementTextLayoutInit( 2453 void *data 2454 ) 2455{ 2456 ElementTextLayout *etl = data; 2457 2458 etl->justify = TK_JUSTIFY_NULL; 2459 etl->lines = -1; 2460 etl->wrap = TEXT_WRAP_NULL; 2461} 2462 2463static CONST char *textDataTypeST[] = { "double", "integer", "long", "string", 2464 "time", (char *) NULL }; 2465static CONST char *textJustifyST[] = { "left", "right", "center", (char *) NULL }; 2466static CONST char *textWrapST[] = { "char", "none", "word", (char *) NULL }; 2467 2468static Tk_OptionSpec textOptionSpecs[] = { 2469 {TK_OPTION_CUSTOM, "-data", (char *) NULL, (char *) NULL, 2470 (char *) NULL, -1, Tk_Offset(TreeElement_, options), 2471 TK_OPTION_NULL_OK, (ClientData) NULL, TEXT_CONF_STRINGREP}, 2472 {TK_OPTION_CUSTOM, "-datatype", (char *) NULL, (char *) NULL, 2473 (char *) NULL, -1, Tk_Offset(TreeElement_, options), 2474 TK_OPTION_NULL_OK, (ClientData) NULL, TEXT_CONF_STRINGREP}, 2475#ifdef DEPRECATED 2476 {TK_OPTION_CUSTOM, "-draw", (char *) NULL, (char *) NULL, 2477 (char *) NULL, -1, Tk_Offset(TreeElement_, options), 2478 TK_OPTION_NULL_OK, (ClientData) NULL, TEXT_CONF_DISPLAY}, 2479#endif 2480 {TK_OPTION_CUSTOM, "-fill", (char *) NULL, (char *) NULL, 2481 (char *) NULL, -1, Tk_Offset(TreeElement_, options), 2482 TK_OPTION_NULL_OK, (ClientData) NULL, TEXT_CONF_DISPLAY}, 2483 {TK_OPTION_CUSTOM, "-font", (char *) NULL, (char *) NULL, 2484 (char *) NULL, -1, Tk_Offset(TreeElement_, options), 2485 TK_OPTION_NULL_OK, (ClientData) NULL, TEXT_CONF_LAYOUT}, 2486 {TK_OPTION_CUSTOM, "-format", (char *) NULL, (char *) NULL, 2487 (char *) NULL, -1, Tk_Offset(TreeElement_, options), 2488 TK_OPTION_NULL_OK, (ClientData) NULL, TEXT_CONF_STRINGREP}, 2489 {TK_OPTION_CUSTOM, "-justify", (char *) NULL, (char *) NULL, 2490 (char *) NULL, -1, Tk_Offset(TreeElement_, options), 2491 TK_OPTION_NULL_OK, (ClientData) NULL, TEXT_CONF_LAYOUT}, 2492 {TK_OPTION_CUSTOM, "-lines", (char *) NULL, (char *) NULL, 2493 (char *) NULL, -1, Tk_Offset(TreeElement_, options), 2494 TK_OPTION_NULL_OK, (ClientData) NULL, TEXT_CONF_LAYOUT}, 2495 {TK_OPTION_CUSTOM, "-lmargin1", (char *) NULL, (char *) NULL, 2496 (char *) NULL, -1, Tk_Offset(TreeElement_, options), 2497 TK_OPTION_NULL_OK, (ClientData) NULL, TEXT_CONF_LAYOUT}, 2498 {TK_OPTION_CUSTOM, "-lmargin2", (char *) NULL, (char *) NULL, 2499 (char *) NULL, -1, Tk_Offset(TreeElement_, options), 2500 TK_OPTION_NULL_OK, (ClientData) NULL, TEXT_CONF_LAYOUT}, 2501 {TK_OPTION_STRING, "-text", (char *) NULL, (char *) NULL, 2502 (char *) NULL, -1, Tk_Offset(ElementText, textCfg), 2503 TK_OPTION_NULL_OK, (ClientData) NULL, TEXT_CONF_STRINGREP}, 2504#ifdef TEXTVAR 2505 {TK_OPTION_CUSTOM, "-textvariable", (char *) NULL, (char *) NULL, 2506 (char *) NULL, -1, Tk_Offset(TreeElement_, options), 2507 TK_OPTION_NULL_OK, (ClientData) NULL, TEXT_CONF_STRINGREP | TEXT_CONF_TEXTVAR}, 2508#endif 2509#ifdef TEXT_STYLE 2510 {TK_OPTION_CUSTOM, "-underline", (char *) NULL, (char *) NULL, 2511 (char *) NULL, -1, Tk_Offset(TreeElement_, options), 2512 TK_OPTION_NULL_OK, (ClientData) NULL, TEXT_CONF_DISPLAY}, 2513#endif 2514 {TK_OPTION_CUSTOM, "-width", (char *) NULL, (char *) NULL, 2515 (char *) NULL, -1, Tk_Offset(TreeElement_, options), 2516 TK_OPTION_NULL_OK, (ClientData) NULL, TEXT_CONF_LAYOUT}, 2517 {TK_OPTION_CUSTOM, "-wrap", (char *) NULL, (char *) NULL, 2518 (char *) NULL, -1, Tk_Offset(TreeElement_, options), 2519 TK_OPTION_NULL_OK, (ClientData) NULL, TEXT_CONF_LAYOUT}, 2520 {TK_OPTION_END, (char *) NULL, (char *) NULL, (char *) NULL, 2521 (char *) NULL, 0, -1, 0, 0, 0} 2522}; 2523 2524static int WorldChangedProcText(TreeElementArgs *args) 2525{ 2526/* TreeCtrl *tree = args->tree;*/ 2527 TreeElement elem = args->elem; 2528 ElementText *elemX = (ElementText *) elem; 2529/* ElementText *masterX = (ElementText *) elem->master;*/ 2530 int flagT = args->change.flagTree; 2531 int flagM = args->change.flagMaster; 2532 int flagS = args->change.flagSelf; 2533 int mask = 0; 2534 2535 if ((flagS | flagM) & TEXT_CONF_STRINGREP) { 2536 elemX->textLen = STRINGREP_INVALID; 2537 } 2538 2539 if ((elemX->textLen == STRINGREP_INVALID) || 2540 ((flagS | flagM) & TEXT_CONF_LAYOUT) || 2541 /* Not needed if this element has its own font. */ 2542 (flagT & TREE_CONF_FONT)) { 2543 mask |= CS_DISPLAY | CS_LAYOUT; 2544 } 2545 2546 if ((flagS | flagM) & TEXT_CONF_DISPLAY) 2547 mask |= CS_DISPLAY; 2548 2549 return mask; 2550} 2551 2552static void TextUpdateStringRep(TreeElementArgs *args) 2553{ 2554 TreeCtrl *tree = args->tree; 2555 TreeElement elem = args->elem; 2556 ElementText *elemX = (ElementText *) elem; 2557 ElementText *masterX = (ElementText *) elem->master; 2558 Tcl_Obj *dataObj, *formatObj; 2559 char *text; 2560 ElementTextData *etd, *etdM = NULL; 2561#ifdef TEXTVAR 2562 ElementTextVar *etv; 2563 Tcl_Obj *varNameObj; 2564#endif 2565 int dataType; 2566 2567 /* Free any string allocated as a result of -data or -textvariable. */ 2568 if ((elemX->text != NULL) && (elemX->text != elemX->textCfg)) { 2569 ckfree(elemX->text); 2570 } 2571 2572 /* Forget any string, and mark the string rep as no-longer invalid. */ 2573 elemX->text = NULL; 2574 elemX->textLen = 0; 2575 2576 /* If -text is specified, then -data and -textvariable are ignored. */ 2577 if (elemX->textCfg != NULL) { 2578 elemX->text = elemX->textCfg; 2579 elemX->textLen = strlen(elemX->textCfg); 2580 return; 2581 } 2582 2583#ifdef TEXTVAR 2584 etv = DynamicOption_FindData(elem->options, DOID_TEXT_VAR); 2585 varNameObj = etv ? etv->varNameObj : NULL; 2586 2587 if (varNameObj != NULL) { 2588 Tcl_Obj *valueObj = Tcl_ObjGetVar2(tree->interp, varNameObj, NULL, 2589 TCL_GLOBAL_ONLY); 2590 2591 if (valueObj == NULL) { 2592 /* not possible I think */ 2593 } else { 2594 /* FIXME: do I need to allocate a copy, or can I just point 2595 * to the internal rep of the string object? */ 2596 text = Tcl_GetStringFromObj(valueObj, &elemX->textLen); 2597 if (elemX->textLen > 0) { 2598 elemX->text = ckalloc(elemX->textLen); 2599 memcpy(elemX->text, text, elemX->textLen); 2600 } 2601 } 2602 return; 2603 } 2604#endif 2605 2606 etd = DynamicOption_FindData(elem->options, DOID_TEXT_DATA); 2607 if (masterX != NULL) 2608 etdM = DynamicOption_FindData(elem->master->options, DOID_TEXT_DATA); 2609 2610 dataObj = etd ? etd->dataObj : NULL; 2611 if ((dataObj == NULL) && (etdM != NULL)) 2612 dataObj = etdM->dataObj; 2613 2614 dataType = etd ? etd->dataType : TDT_NULL; 2615 if ((dataType == TDT_NULL) && (etdM != NULL)) 2616 dataType = etdM->dataType; 2617 2618 formatObj = etd ? etd->formatObj : NULL; 2619 if ((formatObj == NULL) && (etdM != NULL)) 2620 formatObj = etdM->formatObj; 2621 2622 /* Only create a string rep if elemX (not masterX) has dataObj, 2623 dataType or formatObj. */ 2624 if ((dataObj != NULL) && (dataType != TDT_NULL) && 2625 ((etd != NULL) && ((etd->dataObj != NULL) || 2626 (etd->dataType != TDT_NULL) || 2627 (etd->formatObj != NULL)))) { 2628 int i, objc = 0; 2629 Tcl_Obj *objv[5], *resultObj = NULL; 2630 static Tcl_Obj *staticObj[3] = { NULL }; 2631 static Tcl_Obj *staticFormat[4] = { NULL }; 2632 Tcl_ObjCmdProc *clockObjCmd = NULL, *formatObjCmd = NULL; 2633 ClientData clockClientData = NULL, formatClientData = NULL; 2634 Tcl_CmdInfo cmdInfo; 2635 2636 if (staticFormat[0] == NULL) { 2637 staticFormat[0] = Tcl_NewStringObj("%g", -1); 2638 staticFormat[1] = Tcl_NewStringObj("%d", -1); 2639 staticFormat[2] = Tcl_NewStringObj("%ld", -1); 2640 staticFormat[3] = Tcl_NewStringObj("%s", -1); 2641 for (i = 0; i < 4; i++) 2642 Tcl_IncrRefCount(staticFormat[i]); 2643 } 2644 if (staticObj[0] == NULL) { 2645 staticObj[0] = Tcl_NewStringObj("clock", -1); 2646 staticObj[1] = Tcl_NewStringObj("format", -1); 2647 staticObj[2] = Tcl_NewStringObj("-format", -1); 2648 for (i = 0; i < 3; i++) 2649 Tcl_IncrRefCount(staticObj[i]); 2650 } 2651 if (Tcl_GetCommandInfo(tree->interp, "::clock", &cmdInfo) == 1) { 2652 clockObjCmd = cmdInfo.objProc; 2653 clockClientData = cmdInfo.objClientData; 2654 } 2655 if (Tcl_GetCommandInfo(tree->interp, "::format", &cmdInfo) == 1) { 2656 formatObjCmd = cmdInfo.objProc; 2657 formatClientData = cmdInfo.objClientData; 2658 } 2659 2660 /* Important to remove any shared result object, otherwise 2661 * calls like Tcl_SetStringObj(Tcl_GetObjResult()) fail. */ 2662 Tcl_ResetResult(tree->interp); 2663 2664 switch (dataType) { 2665 case TDT_DOUBLE: 2666 if (formatObjCmd == NULL) 2667 break; 2668 if (formatObj == NULL) formatObj = staticFormat[0]; 2669 objv[objc++] = staticObj[1]; /* format */ 2670 objv[objc++] = formatObj; 2671 objv[objc++] = dataObj; 2672 if (formatObjCmd(formatClientData, tree->interp, objc, objv) 2673 == TCL_OK) 2674 resultObj = Tcl_GetObjResult(tree->interp); 2675 break; 2676 case TDT_INTEGER: 2677 if (formatObjCmd == NULL) 2678 break; 2679 if (formatObj == NULL) formatObj = staticFormat[1]; 2680 objv[objc++] = staticObj[1]; /* format */ 2681 objv[objc++] = formatObj; 2682 objv[objc++] = dataObj; 2683 if (formatObjCmd(formatClientData, tree->interp, objc, objv) 2684 == TCL_OK) 2685 resultObj = Tcl_GetObjResult(tree->interp); 2686 break; 2687 case TDT_LONG: 2688 if (formatObjCmd == NULL) 2689 break; 2690 if (formatObj == NULL) formatObj = staticFormat[2]; 2691 objv[objc++] = staticObj[1]; /* format */ 2692 objv[objc++] = formatObj; 2693 objv[objc++] = dataObj; 2694 if (formatObjCmd(formatClientData, tree->interp, objc, objv) 2695 == TCL_OK) 2696 resultObj = Tcl_GetObjResult(tree->interp); 2697 break; 2698 case TDT_STRING: 2699 if (formatObjCmd == NULL) 2700 break; 2701 if (formatObj == NULL) formatObj = staticFormat[3]; 2702 objv[objc++] = staticObj[1]; /* format */ 2703 objv[objc++] = formatObj; 2704 objv[objc++] = dataObj; 2705 if (formatObjCmd(formatClientData, tree->interp, objc, objv) 2706 == TCL_OK) 2707 resultObj = Tcl_GetObjResult(tree->interp); 2708 break; 2709 case TDT_TIME: 2710 if (clockObjCmd == NULL) 2711 break; 2712 objv[objc++] = staticObj[0]; 2713 objv[objc++] = staticObj[1]; 2714 objv[objc++] = dataObj; 2715 if (formatObj != NULL) { 2716 objv[objc++] = staticObj[2]; 2717 objv[objc++] = formatObj; 2718 } 2719 if (clockObjCmd(clockClientData, tree->interp, objc, objv) 2720 == TCL_OK) 2721 resultObj = Tcl_GetObjResult(tree->interp); 2722 break; 2723 default: 2724 panic("unknown ElementText dataType"); 2725 break; 2726 } 2727 2728 if (resultObj != NULL) { 2729 text = Tcl_GetStringFromObj(resultObj, &elemX->textLen); 2730 if (elemX->textLen > 0) { 2731 elemX->text = ckalloc(elemX->textLen); 2732 memcpy(elemX->text, text, elemX->textLen); 2733 } 2734 } 2735 } 2736} 2737 2738static ElementTextLayout2 * 2739TextUpdateLayout( 2740 char *func, 2741 TreeElementArgs *args, 2742 int fixedWidth, 2743 int maxWidth 2744 ) 2745{ 2746 TreeCtrl *tree = args->tree; 2747 TreeElement elem = args->elem; 2748 ElementText *elemX = (ElementText *) elem; 2749 ElementText *masterX = (ElementText *) elem->master; 2750 int state = args->state; 2751 Tk_Font tkfont; 2752 char *text = NULL; 2753 int textLen = 0; 2754 int justify = TK_JUSTIFY_LEFT; 2755 int lines = 0; 2756 int wrap = TEXT_WRAP_WORD; 2757 int width = 0; 2758 int flags = 0; 2759 int i, multiLine = FALSE; 2760 int textWidth; 2761 ElementTextLayout *etl, *etlM = NULL; 2762 ElementTextLayout2 *etl2; 2763 ElementTextLayout3 *etl3, *etl3M = NULL; 2764 DynamicOption *opt; 2765 int lMargin1 = 0, lMargin2 = 0; 2766 2767 if (tree->debug.enable && tree->debug.textLayout) 2768 dbwin("TextUpdateLayout: %s %p (%s) %s\n fixedWidth %d maxWidth %d\n", 2769 Tk_PathName(tree->tkwin), elemX, masterX ? "instance" : "master", 2770 func, fixedWidth, maxWidth); 2771 2772 etl2 = DynamicOption_FindData(elem->options, DOID_TEXT_LAYOUT2); 2773 if (etl2 != NULL && etl2->layout != NULL) { 2774 if (tree->debug.enable && tree->debug.textLayout) 2775 dbwin(" FREE\n"); 2776 TextLayout_Free(etl2->layout); 2777 etl2->layout = NULL; 2778 } 2779 2780 if (elemX->text != NULL) { 2781 text = elemX->text; 2782 textLen = elemX->textLen; 2783 } else if ((masterX != NULL) && (masterX->text != NULL)) { 2784 text = masterX->text; 2785 textLen = masterX->textLen; 2786 } 2787 if ((text == NULL) || (textLen == 0)) 2788 return etl2; 2789 2790 etl = DynamicOption_FindData(elem->options, DOID_TEXT_LAYOUT); 2791 if (masterX != NULL) 2792 etlM = DynamicOption_FindData(elem->master->options, DOID_TEXT_LAYOUT); 2793 2794 if (etl != NULL && etl->lines != -1) 2795 lines = etl->lines; 2796 else if (etlM != NULL && etlM->lines != -1) 2797 lines = etlM->lines; 2798 if (lines == 1) 2799 return etl2; 2800 2801 tkfont = DO_FontForState(tree, elem, DOID_TEXT_FONT, state); 2802 if (tkfont == NULL) 2803 tkfont = tree->tkfont; 2804 2805 if (etl != NULL && etl->wrap != TEXT_WRAP_NULL) 2806 wrap = etl->wrap; 2807 else if (etlM != NULL && etlM->wrap != TEXT_WRAP_NULL) 2808 wrap = etlM->wrap; 2809 2810 if (wrap != TEXT_WRAP_NONE) { 2811 if (fixedWidth >= 0) 2812 width = fixedWidth; 2813 else if (maxWidth >= 0) 2814 width = maxWidth; 2815 if (etl != NULL && etl->widthObj != NULL) { 2816 if (!width || (etl->width < width)) 2817 width = etl->width; 2818 } else if ((etlM != NULL) && (etlM->widthObj != NULL)) { 2819 if (!width || (etlM->width < width)) 2820 width = etlM->width; 2821 } 2822 } 2823 2824 for (i = 0; i < textLen; i++) { 2825 if ((text[i] == '\n') || (text[i] == '\r')) { 2826 multiLine = TRUE; 2827 break; 2828 } 2829 } 2830 if (tree->debug.enable && tree->debug.textLayout) 2831 dbwin(" lines %d multiLine %d width %d wrap %s\n", 2832 lines, multiLine, width, textWrapST[wrap]); 2833 if (!multiLine) { 2834 if (width == 0) 2835 return etl2; 2836 textWidth = Tk_TextWidth(tkfont, text, textLen); 2837if (tree->debug.enable && tree->debug.textLayout) dbwin(" available width %d textWidth %d\n", width, textWidth); 2838 if (width >= textWidth) 2839 return etl2; 2840 } 2841 2842 if (etl != NULL && etl->justify != TK_JUSTIFY_NULL) 2843 justify = etl->justify; 2844 else if (etlM != NULL && etlM->justify != TK_JUSTIFY_NULL) 2845 justify = etlM->justify; 2846 2847 if (wrap == TEXT_WRAP_WORD) 2848 flags |= TK_WHOLE_WORDS; 2849 2850 if (etl2 == NULL) { 2851 opt = (DynamicOption *) DynamicOption_AllocIfNeeded(tree, 2852 &elem->options, DOID_TEXT_LAYOUT2, sizeof(ElementTextLayout2), NULL); 2853 etl2 = (ElementTextLayout2 *) opt->data; 2854 /* It is possible that the needed size of this element does not 2855 * require a TextLayout, in which case neededWidth never gets 2856 * set. */ 2857 etl2->neededWidth = -1; 2858 } 2859 2860 etl3 = DynamicOption_FindData(elem->options, DOID_TEXT_LAYOUT3); 2861 if (masterX != NULL) 2862 etl3M = DynamicOption_FindData(elem->master->options, DOID_TEXT_LAYOUT3); 2863 if (etl3 != NULL && etl3->lMargin1Obj != NULL) 2864 lMargin1 = etl3->lMargin1; 2865 else if (etl3M != NULL && etl3M->lMargin1Obj != NULL) 2866 lMargin1 = etl3M->lMargin1; 2867 if (etl3 != NULL && etl3->lMargin2Obj != NULL) 2868 lMargin2 = etl3->lMargin2; 2869 else if (etl3M != NULL && etl3M->lMargin2Obj != NULL) 2870 lMargin2 = etl3M->lMargin2; 2871 2872 etl2->layout = TextLayout_Compute(tkfont, text, 2873 Tcl_NumUtfChars(text, textLen), width, justify, lines, 2874 lMargin1, lMargin2, flags); 2875 2876 if (tree->debug.enable && tree->debug.textLayout) 2877 dbwin(" ALLOC\n"); 2878 return etl2; 2879} 2880 2881#ifdef TEXTVAR 2882static Tcl_VarTraceProc VarTraceProc_Text; 2883 2884static void TextTraceSet(Tcl_Interp *interp, ElementText *elemX) 2885{ 2886 ElementTextVar *etv = DynamicOption_FindData(elemX->header.options, 2887 DOID_TEXT_VAR); 2888 Tcl_Obj *varNameObj = etv ? etv->varNameObj : NULL; 2889 2890 if (varNameObj != NULL) { 2891 Tcl_TraceVar2(interp, Tcl_GetString(varNameObj), 2892 NULL, 2893 TCL_GLOBAL_ONLY | TCL_TRACE_WRITES | TCL_TRACE_UNSETS, 2894 VarTraceProc_Text, (ClientData) elemX); 2895 } 2896} 2897 2898static void TextTraceUnset(Tcl_Interp *interp, ElementText *elemX) 2899{ 2900 ElementTextVar *etv = DynamicOption_FindData(elemX->header.options, 2901 DOID_TEXT_VAR); 2902 Tcl_Obj *varNameObj = etv ? etv->varNameObj : NULL; 2903 2904 if (varNameObj != NULL) { 2905 Tcl_UntraceVar2(interp, Tcl_GetString(varNameObj), 2906 NULL, 2907 TCL_GLOBAL_ONLY | TCL_TRACE_WRITES | TCL_TRACE_UNSETS, 2908 VarTraceProc_Text, (ClientData) elemX); 2909 } 2910} 2911 2912static char *VarTraceProc_Text(ClientData clientData, Tcl_Interp *interp, 2913 CONST char *name1, CONST char *name2, int flags) 2914{ 2915 ElementText *elemX = (ElementText *) clientData; 2916 ElementTextVar *etv = DynamicOption_FindData(elemX->header.options, 2917 DOID_TEXT_VAR); 2918 Tcl_Obj *varNameObj = etv ? etv->varNameObj : NULL; 2919 Tcl_Obj *valueObj; 2920 2921 /* 2922 * If the variable is unset, then immediately recreate it unless 2923 * the whole interpreter is going away. 2924 */ 2925 2926 if (flags & TCL_TRACE_UNSETS) { 2927 if ((flags & TCL_TRACE_DESTROYED) && !(flags & TCL_INTERP_DESTROYED)) { 2928 /* Use the current string if it is valid. */ 2929 if (elemX->textLen > 0) { 2930 valueObj = Tcl_NewStringObj(elemX->text, elemX->textLen); 2931 } else { 2932 valueObj = Tcl_NewStringObj("", 0); 2933 } 2934 Tcl_IncrRefCount(valueObj); 2935 Tcl_ObjSetVar2(interp, varNameObj, NULL, valueObj, 2936 TCL_GLOBAL_ONLY); 2937 Tcl_DecrRefCount(valueObj); 2938 TextTraceSet(interp, elemX); 2939 } 2940 return (char *) NULL; 2941 } 2942 2943 elemX->textLen = STRINGREP_INVALID; 2944 Tree_ElementChangedItself(etv->tree, etv->item, etv->column, 2945 (TreeElement) elemX, TEXT_CONF_TEXTVAR, CS_LAYOUT | CS_DISPLAY); 2946 return (char *) NULL; 2947} 2948#endif /* TEXTVAR */ 2949 2950static void DeleteProcText(TreeElementArgs *args) 2951{ 2952 TreeCtrl *tree = args->tree; 2953 TreeElement elem = args->elem; 2954 ElementText *elemX = (ElementText *) elem; 2955 ElementTextLayout2 *etl2; 2956 2957 if ((elemX->textCfg == NULL) && (elemX->text != NULL)) { 2958 ckfree(elemX->text); 2959 elemX->text = NULL; 2960 } 2961 etl2 = DynamicOption_FindData(elem->options, DOID_TEXT_LAYOUT2); 2962 if (etl2 != NULL && etl2->layout != NULL) 2963 TextLayout_Free(etl2->layout); 2964 DynamicOption_Free1(tree, &elem->options, DOID_TEXT_LAYOUT2, 2965 sizeof(ElementTextLayout2)); 2966#ifdef TEXTVAR 2967 TextTraceUnset(tree->interp, elemX); 2968#endif 2969} 2970 2971static int ConfigProcText(TreeElementArgs *args) 2972{ 2973 TreeCtrl *tree = args->tree; 2974 Tcl_Interp *interp = tree->interp; 2975 TreeElement elem = args->elem; 2976 ElementText *elemX = (ElementText *) elem; 2977 Tk_SavedOptions savedOptions; 2978 int error; 2979 Tcl_Obj *errorResult = NULL; 2980 char *textCfg = elemX->textCfg; 2981#ifdef TEXTVAR 2982 ElementTextVar *etv; 2983 Tcl_Obj *varNameObj; 2984#endif 2985 2986#ifdef TEXTVAR 2987 TextTraceUnset(interp, elemX); 2988#endif 2989 2990 for (error = 0; error <= 1; error++) { 2991 if (error == 0) { 2992 if (Tk_SetOptions(interp, (char *) elemX, 2993 elem->typePtr->optionTable, 2994 args->config.objc, args->config.objv, tree->tkwin, 2995 &savedOptions, &args->config.flagSelf) != TCL_OK) { 2996 args->config.flagSelf = 0; 2997 continue; 2998 } 2999 3000#ifdef TEXTVAR 3001 etv = DynamicOption_FindData(elem->options, DOID_TEXT_VAR); 3002 if (etv != NULL) { 3003 etv->tree = tree; 3004 etv->item = args->config.item; 3005 etv->column = args->config.column; 3006 varNameObj = etv->varNameObj; 3007 } else 3008 varNameObj = NULL; 3009 if (varNameObj != NULL) { 3010 Tcl_Obj *valueObj; 3011 valueObj = Tcl_ObjGetVar2(interp, varNameObj, 3012 NULL, TCL_GLOBAL_ONLY); 3013 if (valueObj == NULL) { 3014 valueObj = Tcl_NewStringObj("", 0); 3015 Tcl_IncrRefCount(valueObj); 3016 /* This validates the variable name. We get an error 3017 * if it is the name of an array */ 3018 if (Tcl_ObjSetVar2(interp, varNameObj, NULL, 3019 valueObj, TCL_GLOBAL_ONLY | TCL_LEAVE_ERR_MSG) 3020 == NULL) { 3021 Tcl_DecrRefCount(valueObj); 3022 continue; 3023 } 3024 Tcl_DecrRefCount(valueObj); 3025 } 3026 } 3027#endif 3028 3029 Tk_FreeSavedOptions(&savedOptions); 3030 break; 3031 } else { 3032 errorResult = Tcl_GetObjResult(interp); 3033 Tcl_IncrRefCount(errorResult); 3034 Tk_RestoreSavedOptions(&savedOptions); 3035 } 3036 } 3037 3038 /* If -text was specified, then do not try to free the old value in 3039 * TextUpdateStringRep. */ 3040 if (textCfg != elemX->textCfg && elemX->text == textCfg) 3041 elemX->text = NULL; 3042 3043#ifdef TEXTVAR 3044 TextTraceSet(interp, elemX); 3045#endif 3046 3047 if (error) { 3048 Tcl_SetObjResult(interp, errorResult); 3049 Tcl_DecrRefCount(errorResult); 3050 return TCL_ERROR; 3051 } 3052 3053 return TCL_OK; 3054} 3055 3056static int CreateProcText(TreeElementArgs *args) 3057{ 3058/* ElementText *elemX = (ElementText *) args->elem;*/ 3059 3060 return TCL_OK; 3061} 3062 3063static ElementTextLayout2 * 3064TextRedoLayoutIfNeeded( 3065 char *func, 3066 TreeElementArgs *args, 3067 int fixedWidth 3068 ) 3069{ 3070 TreeElement elem = args->elem; 3071/* ElementText *elemX = (ElementText *) elem;*/ 3072 ElementText *masterX = (ElementText *) elem->master; 3073 int doLayout = 0; 3074 int wrap = TEXT_WRAP_WORD; 3075 ElementTextLayout *etl, *etlM = NULL; 3076 ElementTextLayout2 *etl2; 3077 3078 etl = DynamicOption_FindData(elem->options, DOID_TEXT_LAYOUT); 3079 if (masterX != NULL) 3080 etlM = DynamicOption_FindData(elem->master->options, DOID_TEXT_LAYOUT); 3081 3082 etl2 = DynamicOption_FindData(elem->options, DOID_TEXT_LAYOUT2); 3083 3084 /* If text wrapping is disabled, the layout doesn't change */ 3085 if (etl != NULL && etl->wrap != TEXT_WRAP_NULL) 3086 wrap = etl->wrap; 3087 else if ((etlM != NULL) && (etlM->wrap != TEXT_WRAP_NULL)) 3088 wrap = etlM->wrap; 3089 if (wrap == TEXT_WRAP_NONE) 3090 return etl2; 3091 3092 if (etl2 != NULL && etl2->layout != NULL) { 3093 3094 /* See comment in NeededProc about totalWidth */ 3095 if ((etl2->neededWidth != -1) && (fixedWidth >= etl2->neededWidth)) 3096 fixedWidth = etl2->totalWidth; 3097 3098 /* Already layed out at this width */ 3099 if (fixedWidth == etl2->layoutWidth) 3100 return etl2; 3101 } 3102 3103 /* May switch from layout -> no layout or vice versa */ 3104 if (etl2 == NULL || etl2->layout == NULL) 3105 doLayout = 1; 3106 3107 /* Width was constrained and we have more space now */ 3108 else if ((etl2->layoutWidth != -1) && (fixedWidth > etl2->layoutWidth)) 3109 doLayout = 1; 3110 3111 /* Width was unconstrained or we have less space now */ 3112 else { 3113 int width; 3114 TextLayout_Size(etl2->layout, &width, NULL); 3115 /* Redo if we are narrower than the layout */ 3116 if (fixedWidth < width) 3117 doLayout = 1; 3118 } 3119 if (doLayout) 3120 etl2 = TextUpdateLayout(func, args, fixedWidth, -1); 3121 if (etl2 != NULL) 3122 etl2->layoutWidth = (etl2->layout != NULL) ? fixedWidth : -1; 3123 return etl2; 3124} 3125 3126static void DisplayProcText(TreeElementArgs *args) 3127{ 3128 TreeCtrl *tree = args->tree; 3129 TreeElement elem = args->elem; 3130 ElementText *elemX = (ElementText *) elem; 3131 ElementText *masterX = (ElementText *) elem->master; 3132 int state = args->state; 3133 int x = args->display.x, y = args->display.y; 3134 int width, height; 3135#ifdef DEPRECATED 3136 int draw; 3137#endif 3138 XColor *color; 3139 char *text = elemX->text; 3140 int textLen = elemX->textLen; 3141 Tk_Font tkfont; 3142 TextLayout layout = NULL; 3143 Tk_FontMetrics fm; 3144 GC gc; 3145 int bytesThatFit, pixelsForText; 3146 char *ellipsis = "..."; 3147 TkRegion clipRgn = NULL; 3148 ElementTextLayout2 *etl2; 3149#ifdef TEXT_STYLE 3150 ElementTextStyle *ets, *etsM = NULL; 3151 int underline = TEXT_UNDERLINE_EMPTYVAL; 3152#endif 3153 3154#ifdef DEPRECATED 3155 draw = DO_BooleanForState(tree, elem, DOID_TEXT_DRAW, state); 3156 if (!draw) 3157 return; 3158#endif 3159 3160 if ((text == NULL) && (masterX != NULL)) { 3161 text = masterX->text; 3162 textLen = masterX->textLen; 3163 } 3164 3165 if (text == NULL) /* always false (or layout sets height/width to zero) */ 3166 return; 3167 3168 color = DO_ColorForState(tree, elem, DOID_TEXT_FILL, state); 3169 tkfont = DO_FontForState(tree, elem, DOID_TEXT_FONT, state); 3170 3171 /* FIXME: -font {"" {state...}}*/ 3172 if ((color != NULL) || (tkfont != NULL)) { 3173 XGCValues gcValues; 3174 unsigned long gcMask = 0; 3175 if (color == NULL) 3176 color = tree->fgColorPtr; 3177 gcValues.foreground = color->pixel; 3178 gcMask |= GCForeground; 3179 if (tkfont == NULL) 3180 tkfont = tree->tkfont; 3181 gcValues.font = Tk_FontId(tkfont); 3182 gcMask |= GCFont; 3183 gcValues.graphics_exposures = False; 3184 gcMask |= GCGraphicsExposures; 3185 gc = Tree_GetGC(tree, gcMask, &gcValues); 3186 } else { 3187 tkfont = tree->tkfont; 3188 gc = tree->textGC; 3189 } 3190 3191#ifdef TEXT_STYLE 3192 ets = DynamicOption_FindData(elem->options, DOID_TEXT_STYLE); 3193 if (ets != NULL && ets->underline != TEXT_UNDERLINE_EMPTYVAL) 3194 underline = ets->underline; 3195 else if (masterX != NULL) { 3196 etsM = DynamicOption_FindData(elem->master->options, DOID_TEXT_STYLE); 3197 if (etsM != NULL && etsM->underline != TEXT_UNDERLINE_EMPTYVAL) 3198 underline = etsM->underline; 3199 } 3200#endif 3201 3202 etl2 = TextRedoLayoutIfNeeded("DisplayProcText", args, args->display.width); 3203 if (etl2 != NULL && etl2->layout != NULL) 3204 layout = etl2->layout; 3205 3206 if (layout != NULL) { 3207 TextLayout_Size(layout, &width, &height); 3208 pixelsForText = width; 3209 /* Hack -- The actual size of the text may be slightly smaller than 3210 * the available space when squeezed. If so we don't want to center 3211 * the text horizontally */ 3212 if ((etl2->neededWidth == -1) || (etl2->neededWidth > width)) 3213 width = args->display.width; 3214 AdjustForSticky(args->display.sticky, 3215 args->display.width, args->display.height, 3216 FALSE, FALSE, 3217 &x, &y, &width, &height); 3218 /* Use clipping if text is larger than the display area. */ 3219 if (pixelsForText > args->display.width || height > args->display.height) { 3220 XRectangle rect; 3221 clipRgn = Tree_GetRegion(tree); 3222 rect.x = x; 3223 rect.y = y; 3224 rect.width = args->display.width; 3225 rect.height = args->display.height; 3226 TkUnionRectWithRegion(&rect, clipRgn, clipRgn); 3227 TkSetRegion(tree->display, gc, clipRgn); 3228 } 3229 TextLayout_Draw(tree->display, args->display.drawable, gc, 3230 layout, x, y, 0, -1, underline); 3231 if (clipRgn != NULL) { 3232 Tree_UnsetClipMask(tree, args->display.drawable, gc); 3233 Tree_FreeRegion(tree, clipRgn); 3234 } 3235 return; 3236 } 3237 3238 Tk_GetFontMetrics(tkfont, &fm); 3239 3240 pixelsForText = args->display.width; 3241 bytesThatFit = Tree_Ellipsis(tkfont, text, textLen, &pixelsForText, 3242 ellipsis, FALSE); 3243 width = pixelsForText, height = fm.linespace; 3244 /* Hack -- The actual size of the text may be slightly smaller than 3245 * the available space when squeezed. If so we don't want to center 3246 * the text horizontally */ 3247 if (bytesThatFit != textLen) 3248 width = args->display.width; 3249 AdjustForSticky(args->display.sticky, 3250 args->display.width, args->display.height, 3251 FALSE, FALSE, 3252 &x, &y, &width, &height); 3253 /* Use clipping if text is larger than the display area. */ 3254 if (pixelsForText > args->display.width || height > args->display.height) { 3255 XRectangle rect; 3256 clipRgn = Tree_GetRegion(tree); 3257 rect.x = x; 3258 rect.y = y; 3259 rect.width = args->display.width; 3260 rect.height = args->display.height; 3261 TkUnionRectWithRegion(&rect, clipRgn, clipRgn); 3262 TkSetRegion(tree->display, gc, clipRgn); 3263 } 3264 if (bytesThatFit != textLen) { 3265 char staticStr[256], *buf = staticStr; 3266 int bufLen = abs(bytesThatFit); 3267 int ellipsisLen = strlen(ellipsis); 3268 3269 if (bufLen + ellipsisLen > sizeof(staticStr)) 3270 buf = ckalloc(bufLen + ellipsisLen); 3271 memcpy(buf, text, bufLen); 3272 if (bytesThatFit > 0) { 3273 memcpy(buf + bufLen, ellipsis, ellipsisLen); 3274 bufLen += ellipsisLen; 3275 } 3276 Tk_DrawChars(tree->display, args->display.drawable, gc, 3277 tkfont, buf, bufLen, x, y + fm.ascent); 3278#ifdef TEXT_STYLE 3279 if (underline >= 0 && underline < Tcl_NumUtfChars(buf, abs(bytesThatFit))) { 3280 CONST char *fstBytePtr = Tcl_UtfAtIndex(buf, underline); 3281 CONST char *sndBytePtr = Tcl_UtfNext(fstBytePtr); 3282 Tk_UnderlineChars(tree->display, args->display.drawable, gc, 3283 tkfont, buf, x, y + fm.ascent, 3284 fstBytePtr - buf, sndBytePtr - buf); 3285 } 3286#endif 3287 if (buf != staticStr) 3288 ckfree(buf); 3289 } else { 3290 Tk_DrawChars(tree->display, args->display.drawable, gc, 3291 tkfont, text, textLen, x, y + fm.ascent); 3292#ifdef TEXT_STYLE 3293 if (underline >= 0 && underline < Tcl_NumUtfChars(text, textLen)) { 3294 CONST char *fstBytePtr = Tcl_UtfAtIndex(text, underline); 3295 CONST char *sndBytePtr = Tcl_UtfNext(fstBytePtr); 3296 Tk_UnderlineChars(tree->display, args->display.drawable, gc, 3297 tkfont, text, x, y + fm.ascent, 3298 fstBytePtr - text, sndBytePtr - text); 3299 } 3300#endif 3301 } 3302 if (clipRgn != NULL) { 3303 Tree_UnsetClipMask(tree, args->display.drawable, gc); 3304 Tree_FreeRegion(tree, clipRgn); 3305 } 3306} 3307 3308static void NeededProcText(TreeElementArgs *args) 3309{ 3310 TreeCtrl *tree = args->tree; 3311 TreeElement elem = args->elem; 3312 ElementText *elemX = (ElementText *) elem; 3313 ElementText *masterX = (ElementText *) elem->master; 3314 int state = args->state; 3315 char *text = NULL; 3316 int textLen = 0; 3317 Tk_Font tkfont; 3318 Tk_FontMetrics fm; 3319 int width = 0, height = 0; 3320 ElementTextLayout *etl, *etlM = NULL; 3321 ElementTextLayout2 *etl2; 3322 3323 etl = DynamicOption_FindData(args->elem->options, DOID_TEXT_LAYOUT); 3324 if (masterX != NULL) 3325 etlM = DynamicOption_FindData(args->elem->master->options, DOID_TEXT_LAYOUT); 3326 3327 if ((masterX != NULL) && (masterX->textLen == STRINGREP_INVALID)) { 3328 args->elem = (TreeElement) masterX; 3329 TextUpdateStringRep(args); 3330 args->elem = elem; 3331 } 3332 if (elemX->textLen == STRINGREP_INVALID) { 3333 TextUpdateStringRep(args); 3334 } 3335 3336 etl2 = TextUpdateLayout("NeededProcText", args, args->needed.fixedWidth, 3337 args->needed.maxWidth); 3338 if (etl2 != NULL) { 3339 etl2->layoutWidth = -1; 3340 etl2->neededWidth = -1; 3341 } 3342 3343 if (etl2 != NULL && etl2->layout != NULL) { 3344 TextLayout_Size(etl2->layout, &width, &height); 3345 if (args->needed.fixedWidth >= 0) 3346 etl2->layoutWidth = args->needed.fixedWidth; 3347 else if (args->needed.maxWidth >= 0) 3348 etl2->layoutWidth = args->needed.maxWidth; 3349 etl2->neededWidth = width; 3350 3351 /* 3352 * Hack -- If we call TextLayout_Compute() with the same width 3353 * returned by TextLayout_Size(), we may get a different layout. 3354 * I think this has to do with whitespace at the end of lines. 3355 * So if HeightProc or DisplayProc is given neededWidth, I do the 3356 * layout at totalWidth, not neededWidth. 3357 */ 3358 etl2->totalWidth = TextLayout_TotalWidth(etl2->layout); 3359 } else { 3360 if (elemX->text != NULL) { 3361 text = elemX->text; 3362 textLen = elemX->textLen; 3363 } else if ((masterX != NULL) && (masterX->text != NULL)) { 3364 text = masterX->text; 3365 textLen = masterX->textLen; 3366 } 3367 if (textLen > 0) { 3368 int maxWidth = -1; 3369 3370 tkfont = DO_FontForState(tree, elem, DOID_TEXT_FONT, state); 3371 if (tkfont == NULL) 3372 tkfont = tree->tkfont; 3373 3374 width = Tk_TextWidth(tkfont, text, textLen); 3375 if (etl != NULL && etl->widthObj != NULL) 3376 maxWidth = etl->width; 3377 else if ((etlM != NULL) && (etlM->widthObj != NULL)) 3378 maxWidth = etlM->width; 3379 if ((maxWidth >= 0) && (maxWidth < width)) 3380 width = maxWidth; 3381 3382 Tk_GetFontMetrics(tkfont, &fm); 3383 height = fm.linespace; 3384 } 3385 } 3386 3387 args->needed.width = width; 3388 args->needed.height = height; 3389} 3390 3391static void HeightProcText(TreeElementArgs *args) 3392{ 3393 TreeCtrl *tree = args->tree; 3394 TreeElement elem = args->elem; 3395 ElementText *elemX = (ElementText *) elem; 3396 ElementText *masterX = (ElementText *) elem->master; 3397 int state = args->state; 3398 int height = 0; 3399 char *text = NULL; 3400 int textLen = 0; 3401 Tk_Font tkfont; 3402 Tk_FontMetrics fm; 3403 ElementTextLayout2 *etl2; 3404 3405 etl2 = TextRedoLayoutIfNeeded("HeightProcText", args, args->height.fixedWidth); 3406 3407 if (etl2 != NULL && etl2->layout != NULL) { 3408 TextLayout_Size(etl2->layout, NULL, &height); 3409 } else { 3410 if (elemX->text != NULL) { 3411 text = elemX->text; 3412 textLen = elemX->textLen; 3413 } else if ((masterX != NULL) && (masterX->text != NULL)) { 3414 text = masterX->text; 3415 textLen = masterX->textLen; 3416 } 3417 if (textLen > 0) { 3418 tkfont = DO_FontForState(tree, elem, DOID_TEXT_FONT, state); 3419 if (tkfont == NULL) 3420 tkfont = tree->tkfont; 3421 Tk_GetFontMetrics(tkfont, &fm); 3422 height = fm.linespace; 3423 } 3424 } 3425 3426 args->height.height = height; 3427} 3428 3429int 3430TreeElement_GetSortData( 3431 TreeCtrl *tree, 3432 TreeElement elem, 3433 int type, 3434 long *lv, 3435 double *dv, 3436 char **sv) 3437{ 3438 ElementText *elemX = (ElementText *) elem; 3439 ElementText *masterX = (ElementText *) elem->master; 3440 ElementTextData *etd, *etdM = NULL; 3441 Tcl_Obj *dataObj = NULL; 3442 int dataType = TDT_NULL; 3443 3444 etd = DynamicOption_FindData(elem->options, DOID_TEXT_DATA); 3445 if (etd != NULL) { 3446 dataObj = etd->dataObj; 3447 dataType = etd->dataType; 3448 } 3449 if (dataType == TDT_NULL && masterX != NULL) { 3450 etdM = DynamicOption_FindData(elem->master->options, DOID_TEXT_DATA); 3451 /* FIXME: get dataObj from master? */ 3452 if (etdM != NULL) 3453 dataType = etdM->dataType; 3454 } 3455 3456 switch (type) { 3457 case SORT_ASCII: 3458 case SORT_DICT: 3459 if (dataObj != NULL && dataType != TDT_NULL) 3460 (*sv) = Tcl_GetString(dataObj); 3461 else 3462 (*sv) = elemX->textCfg; 3463 break; 3464 case SORT_DOUBLE: 3465 if (dataObj != NULL && dataType == TDT_DOUBLE) { 3466 if (Tcl_GetDoubleFromObj(tree->interp, dataObj, dv) != TCL_OK) 3467 return TCL_ERROR; 3468 break; 3469 } 3470 if (elemX->textCfg != NULL) { 3471 if (Tcl_GetDouble(tree->interp, elemX->textCfg, dv) != TCL_OK) 3472 return TCL_ERROR; 3473 break; 3474 } 3475 FormatResult(tree->interp, "can't get a double from an empty -text value"); 3476 return TCL_ERROR; 3477 case SORT_LONG: 3478 if (dataObj != NULL && dataType != TDT_NULL) { 3479 if (dataType == TDT_LONG || dataType == TDT_TIME) { 3480 if (Tcl_GetLongFromObj(tree->interp, dataObj, lv) != TCL_OK) 3481 return TCL_ERROR; 3482 break; 3483 } 3484 if (dataType == TDT_INTEGER) { 3485 int iv; 3486 if (Tcl_GetIntFromObj(tree->interp, dataObj, &iv) != TCL_OK) 3487 return TCL_ERROR; 3488 (*lv) = iv; 3489 break; 3490 } 3491 } 3492 if (elemX->textCfg != NULL) { 3493 Tcl_Obj obj; 3494 3495 obj.refCount = 1; 3496 obj.bytes = (char *) elemX->textCfg; 3497 obj.length = strlen(elemX->textCfg); 3498 obj.typePtr = NULL; 3499 3500 if (Tcl_GetLongFromObj(tree->interp, &obj, lv) != TCL_OK) 3501 return TCL_ERROR; 3502 break; 3503 } 3504 FormatResult(tree->interp, "can't get a long from an empty -text value"); 3505 return TCL_ERROR; 3506 } 3507 return TCL_OK; 3508} 3509 3510static int StateProcText(TreeElementArgs *args) 3511{ 3512 TreeCtrl *tree = args->tree; 3513 TreeElement elem = args->elem; 3514/* ElementText *elemX = (ElementText *) elem; 3515 ElementText *masterX = (ElementText *) elem->master;*/ 3516#ifdef DEPRECATED 3517 int draw1, draw2; 3518#endif 3519 XColor *f1, *f2; 3520 Tk_Font tkfont1, tkfont2; 3521 3522 if (!args->states.visible2) 3523 return 0; 3524 3525 tkfont1 = DO_FontForState(tree, elem, DOID_TEXT_FONT, args->states.state1); 3526 tkfont2 = DO_FontForState(tree, elem, DOID_TEXT_FONT, args->states.state2); 3527 if (tkfont1 != tkfont2) 3528 return CS_DISPLAY | CS_LAYOUT; 3529 3530 if (!args->states.draw2) 3531 return 0; 3532#ifdef DEPRECATED 3533 draw1 = DO_BooleanForState(tree, elem, DOID_TEXT_DRAW, args->states.state1); 3534 draw2 = DO_BooleanForState(tree, elem, DOID_TEXT_DRAW, args->states.state2); 3535 if ((draw1 != 0) != (draw2 != 0)) 3536 return CS_DISPLAY; 3537 if (draw2 == 0) 3538 return 0; 3539#endif 3540 3541 f1 = DO_ColorForState(tree, elem, DOID_TEXT_FILL, args->states.state1); 3542 f2 = DO_ColorForState(tree, elem, DOID_TEXT_FILL, args->states.state2); 3543 if (f1 != f2) 3544 return CS_DISPLAY; 3545 3546 return 0; 3547} 3548 3549static int UndefProcText(TreeElementArgs *args) 3550{ 3551 TreeCtrl *tree = args->tree; 3552/* ElementText *elemX = (ElementText *) args->elem;*/ 3553 int modified = 0; 3554 PerStateInfo *psi; 3555 3556 if ((psi = DynamicOption_FindData(args->elem->options, DOID_TEXT_DRAW)) != NULL) 3557 modified |= PerStateInfo_Undefine(tree, &pstBoolean, psi, args->state); 3558 if ((psi = DynamicOption_FindData(args->elem->options, DOID_TEXT_FILL)) != NULL) 3559 modified |= PerStateInfo_Undefine(tree, &pstColor, psi, args->state); 3560 if ((psi = DynamicOption_FindData(args->elem->options, DOID_TEXT_FONT)) != NULL) 3561 modified |= PerStateInfo_Undefine(tree, &pstFont, psi, args->state); 3562 3563 return modified; 3564} 3565 3566static int ActualProcText(TreeElementArgs *args) 3567{ 3568 TreeCtrl *tree = args->tree; 3569/* ElementText *elemX = (ElementText *) args->elem; 3570 ElementText *masterX = (ElementText *) args->elem->master;*/ 3571 static CONST char *optionName[] = { 3572#ifdef DEPRECATED 3573 "-draw", 3574#endif 3575 "-fill", "-font", 3576 (char *) NULL }; 3577 int index; 3578 Tcl_Obj *obj = NULL; 3579 3580 if (Tcl_GetIndexFromObj(tree->interp, args->actual.obj, optionName, 3581 "option", 0, &index) != TCL_OK) 3582 return TCL_ERROR; 3583 3584 switch (index) { 3585#ifdef DEPRECATED 3586 case 0: { 3587 obj = DO_ObjectForState(tree, &pstBoolean, args->elem, DOID_TEXT_DRAW, args->state); 3588 break; 3589 } 3590 case 1: { 3591 obj = DO_ObjectForState(tree, &pstColor, args->elem, DOID_TEXT_FILL, args->state); 3592 break; 3593 } 3594 case 2: { 3595 obj = DO_ObjectForState(tree, &pstFont, args->elem, DOID_TEXT_FONT, args->state); 3596 break; 3597 } 3598#else 3599 case 0: { 3600 obj = DO_ObjectForState(tree, &pstColor, args->elem, DOID_TEXT_FILL, args->state); 3601 break; 3602 } 3603 case 1: { 3604 obj = DO_ObjectForState(tree, &pstFont, args->elem, DOID_TEXT_FONT, args->state); 3605 break; 3606 } 3607#endif 3608 } 3609 if (obj != NULL) 3610 Tcl_SetObjResult(tree->interp, obj); 3611 return TCL_OK; 3612} 3613 3614TreeElementType treeElemTypeText = { 3615 "text", 3616 sizeof(ElementText), 3617 textOptionSpecs, 3618 NULL, 3619 CreateProcText, 3620 DeleteProcText, 3621 ConfigProcText, 3622 DisplayProcText, 3623 NeededProcText, 3624 HeightProcText, 3625 WorldChangedProcText, 3626 StateProcText, 3627 UndefProcText, 3628 ActualProcText, 3629 NULL /* onScreenProc */ 3630}; 3631 3632/*****/ 3633 3634typedef struct ElementWindow ElementWindow; 3635 3636struct ElementWindow 3637{ 3638 TreeElement_ header; 3639#ifdef DEPRECATED 3640 PerStateInfo draw; /* -draw */ 3641#endif 3642 TreeCtrl *tree; 3643 TreeItem item; /* Needed if window changes size */ 3644 TreeItemColumn column; /* Needed if window changes size */ 3645 Tk_Window tkwin; /* Window associated with item. NULL means 3646 * window has been destroyed. */ 3647 int destroy; /* Destroy window when element 3648 * is deleted */ 3649#define CLIP_WINDOW 1 3650#ifdef CLIP_WINDOW 3651 int clip; /* TRUE if tkwin is a borderless frame 3652 * widget whose first child is the actual 3653 * window we want displayed. */ 3654 Tk_Window child; /* The first child of tkwin. tkwin is resized 3655 * so that it is never out-of-bounds, and 3656 * the child is positioned within tkwin to 3657 * provide clipping of the child. */ 3658#endif 3659}; 3660 3661#define EWIN_CONF_WINDOW 0x0001 3662#ifdef DEPRECATED 3663#define EWIN_CONF_DRAW 0x0002 3664#endif 3665 3666static Tk_OptionSpec windowOptionSpecs[] = { 3667#ifdef CLIP_WINDOW 3668 {TK_OPTION_CUSTOM, "-clip", (char *) NULL, (char *) NULL, 3669 (char *) NULL, -1, Tk_Offset(ElementWindow, clip), 3670 TK_OPTION_NULL_OK, (ClientData) &booleanCO, 0}, 3671#endif 3672 {TK_OPTION_CUSTOM, "-destroy", (char *) NULL, (char *) NULL, 3673 (char *) NULL, -1, Tk_Offset(ElementWindow, destroy), 3674 TK_OPTION_NULL_OK, (ClientData) &booleanCO, 0}, 3675#ifdef DEPRECATED 3676 {TK_OPTION_CUSTOM, "-draw", (char *) NULL, (char *) NULL, 3677 (char *) NULL, 3678 Tk_Offset(ElementWindow, draw.obj), Tk_Offset(ElementWindow, draw), 3679 TK_OPTION_NULL_OK, (ClientData) NULL, EWIN_CONF_DRAW}, 3680#endif 3681 {TK_OPTION_WINDOW, "-window", (char *) NULL, (char *) NULL, 3682 (char *) NULL, -1, Tk_Offset(ElementWindow, tkwin), 3683 TK_OPTION_NULL_OK, (ClientData) NULL, EWIN_CONF_WINDOW}, 3684 {TK_OPTION_END, (char *) NULL, (char *) NULL, (char *) NULL, 3685 (char *) NULL, 0, -1, 0, (ClientData) NULL, 0} 3686}; 3687 3688static void 3689WinItemStructureProc( 3690 ClientData clientData, /* Pointer to record describing window elem. */ 3691 XEvent *eventPtr) /* Describes what just happened. */ 3692{ 3693 ElementWindow *elemX = clientData; 3694 3695 if (eventPtr->type == DestroyNotify) { 3696 elemX->tkwin = elemX->child = NULL; 3697 Tree_ElementChangedItself(elemX->tree, elemX->item, elemX->column, 3698 (TreeElement) elemX, EWIN_CONF_WINDOW, CS_LAYOUT | CS_DISPLAY); 3699 } 3700} 3701 3702static void 3703WinItemRequestProc( 3704 ClientData clientData, /* Pointer to record for window item. */ 3705 Tk_Window tkwin) /* Window that changed its desired 3706 * size. */ 3707{ 3708 ElementWindow *elemX = clientData; 3709 3710#ifdef CLIP_WINDOW 3711 /* We don't care about size changes for the clip window. */ 3712 if (elemX->child != NULL && tkwin != elemX->child) 3713 return; 3714#endif 3715 Tree_ElementChangedItself(elemX->tree, elemX->item, elemX->column, 3716 (TreeElement) elemX, EWIN_CONF_WINDOW, CS_LAYOUT | CS_DISPLAY); 3717} 3718 3719static void 3720WinItemLostSlaveProc( 3721 ClientData clientData, /* WindowItem structure for slave window that 3722 * was stolen away. */ 3723 Tk_Window tkwin) /* Tk's handle for the slave window. */ 3724{ 3725 ElementWindow *elemX = clientData; 3726 TreeCtrl *tree = elemX->tree; 3727 3728#ifdef CLIP_WINDOW 3729 /* If either window is lost to another geometry manager, forget 3730 * about both windows. */ 3731 if (elemX->child != NULL) { 3732 Tk_DeleteEventHandler(elemX->child, StructureNotifyMask, 3733 WinItemStructureProc, (ClientData) elemX); 3734 if (tkwin != elemX->child) { 3735 Tk_ManageGeometry(elemX->child, (Tk_GeomMgr *) NULL, 3736 (ClientData) NULL); 3737 Tk_UnmapWindow(elemX->child); 3738 } 3739 elemX->child = NULL; 3740 } 3741 if (elemX->tkwin != NULL) { 3742 Tk_DeleteEventHandler(elemX->tkwin, StructureNotifyMask, 3743 WinItemStructureProc, (ClientData) elemX); 3744 if (tkwin != elemX->tkwin) { 3745 Tk_ManageGeometry(elemX->tkwin, (Tk_GeomMgr *) NULL, 3746 (ClientData) NULL); 3747 if (tree->tkwin != Tk_Parent(elemX->tkwin)) { 3748 Tk_UnmaintainGeometry(elemX->tkwin, tree->tkwin); 3749 } 3750 Tk_UnmapWindow(elemX->tkwin); 3751 } 3752 elemX->tkwin = NULL; 3753 } 3754#else 3755 Tk_DeleteEventHandler(elemX->tkwin, StructureNotifyMask, 3756 WinItemStructureProc, (ClientData) elemX); 3757 if (tree->tkwin != Tk_Parent(elemX->tkwin)) { 3758 Tk_UnmaintainGeometry(elemX->tkwin, tree->tkwin); 3759 } 3760 Tk_UnmapWindow(elemX->tkwin); 3761 elemX->tkwin = NULL; 3762#endif 3763 Tree_ElementChangedItself(elemX->tree, elemX->item, elemX->column, 3764 (TreeElement) elemX, EWIN_CONF_WINDOW, CS_LAYOUT | CS_DISPLAY); 3765} 3766 3767static Tk_GeomMgr winElemGeomType = { 3768 "treectrl", /* name */ 3769 WinItemRequestProc, /* requestProc */ 3770 WinItemLostSlaveProc, /* lostSlaveProc */ 3771}; 3772 3773static void DeleteProcWindow(TreeElementArgs *args) 3774{ 3775 TreeCtrl *tree = args->tree; 3776 TreeElement elem = args->elem; 3777 ElementWindow *elemX = (ElementWindow *) elem; 3778 ElementWindow *masterX = (ElementWindow *) elem->master; 3779 3780 if (elemX->tkwin != NULL) { 3781#ifdef CLIP_WINDOW 3782 if (elemX->child != NULL) { 3783 Tk_DeleteEventHandler(elemX->child, StructureNotifyMask, 3784 WinItemStructureProc, (ClientData) elemX); 3785 Tk_ManageGeometry(elemX->child, (Tk_GeomMgr *) NULL, 3786 (ClientData) NULL); 3787 Tk_UnmapWindow(elemX->child); 3788 elemX->child = NULL; 3789 } 3790#endif 3791 Tk_DeleteEventHandler(elemX->tkwin, StructureNotifyMask, 3792 WinItemStructureProc, (ClientData) elemX); 3793 Tk_ManageGeometry(elemX->tkwin, (Tk_GeomMgr *) NULL, 3794 (ClientData) NULL); 3795 if (tree->tkwin != Tk_Parent(elemX->tkwin)) { 3796 Tk_UnmaintainGeometry(elemX->tkwin, tree->tkwin); 3797 } 3798 Tk_UnmapWindow(elemX->tkwin); 3799 3800 if ((elemX->destroy == 1) || 3801 ((masterX != NULL) && (masterX->destroy == 1))) { 3802 Tk_DestroyWindow(elemX->tkwin); 3803 } 3804 3805 elemX->tkwin = NULL; 3806 } 3807} 3808 3809static int WorldChangedProcWindow(TreeElementArgs *args) 3810{ 3811 int flagM = args->change.flagMaster; 3812 int flagS = args->change.flagSelf; 3813 int mask = 0; 3814 3815#ifdef DEPRECATED 3816 if ((flagS | flagM) & (EWIN_CONF_DRAW)) 3817 mask |= CS_DISPLAY; 3818#endif 3819 3820 if ((flagS | flagM) & (EWIN_CONF_WINDOW)) 3821 mask |= CS_DISPLAY | CS_LAYOUT; 3822 3823 return mask; 3824} 3825 3826static int ConfigProcWindow(TreeElementArgs *args) 3827{ 3828 TreeCtrl *tree = args->tree; 3829 TreeElement elem = args->elem; 3830 ElementWindow *elemX = (ElementWindow *) elem; 3831 ElementWindow *masterX = (ElementWindow *) elem->master; 3832 ElementWindow savedX; 3833 Tk_SavedOptions savedOptions; 3834 int error; 3835 Tcl_Obj *errorResult = NULL; 3836 3837 savedX.tkwin = elemX->tkwin; 3838 3839 for (error = 0; error <= 1; error++) { 3840 if (error == 0) { 3841 if (Tk_SetOptions(tree->interp, (char *) elemX, 3842 elem->typePtr->optionTable, 3843 args->config.objc, args->config.objv, tree->tkwin, 3844 &savedOptions, &args->config.flagSelf) != TCL_OK) { 3845 args->config.flagSelf = 0; 3846 continue; 3847 } 3848 3849 if (args->config.flagSelf & EWIN_CONF_WINDOW) { 3850 if ((elem->master == NULL) && (elemX->tkwin != NULL)){ 3851 FormatResult(tree->interp, "can't specify -window for a master element"); 3852 continue; 3853 } 3854 } 3855 3856 Tk_FreeSavedOptions(&savedOptions); 3857 break; 3858 } else { 3859 errorResult = Tcl_GetObjResult(tree->interp); 3860 Tcl_IncrRefCount(errorResult); 3861 Tk_RestoreSavedOptions(&savedOptions); 3862 3863 Tcl_SetObjResult(tree->interp, errorResult); 3864 Tcl_DecrRefCount(errorResult); 3865 return TCL_ERROR; 3866 } 3867 } 3868 3869 if (savedX.tkwin != elemX->tkwin) { 3870 if (savedX.tkwin != NULL) { 3871#ifdef CLIP_WINDOW 3872 if (elemX->child != NULL) { 3873 Tk_DeleteEventHandler(elemX->child, StructureNotifyMask, 3874 WinItemStructureProc, (ClientData) elemX); 3875 Tk_ManageGeometry(elemX->child, (Tk_GeomMgr *) NULL, 3876 (ClientData) NULL); 3877 Tk_UnmapWindow(elemX->child); 3878 elemX->child = NULL; 3879 } 3880#endif 3881 Tk_DeleteEventHandler(savedX.tkwin, StructureNotifyMask, 3882 WinItemStructureProc, (ClientData) elemX); 3883 Tk_ManageGeometry(savedX.tkwin, (Tk_GeomMgr *) NULL, 3884 (ClientData) NULL); 3885 Tk_UnmaintainGeometry(savedX.tkwin, tree->tkwin); 3886 Tk_UnmapWindow(savedX.tkwin); 3887 } 3888 if (elemX->tkwin != NULL) { 3889 Tk_Window ancestor, parent; 3890 3891 /* 3892 * Make sure that the treectrl is either the parent of the 3893 * window associated with the element or a descendant of that 3894 * parent. Also, don't allow a top-of-hierarchy window to be 3895 * managed inside a treectrl. 3896 */ 3897 3898 parent = Tk_Parent(elemX->tkwin); 3899 for (ancestor = tree->tkwin; ; 3900 ancestor = Tk_Parent(ancestor)) { 3901 if (ancestor == parent) { 3902 break; 3903 } 3904 if (((Tk_FakeWin *) (ancestor))->flags & TK_TOP_HIERARCHY) { 3905 badWindow: 3906 FormatResult(tree->interp, 3907 "can't use %s in a window element of %s", 3908 Tk_PathName(elemX->tkwin), 3909 Tk_PathName(tree->tkwin)); 3910 elemX->tkwin = NULL; 3911 return TCL_ERROR; 3912 } 3913 } 3914 if (((Tk_FakeWin *) (elemX->tkwin))->flags & TK_TOP_HIERARCHY) { 3915 goto badWindow; 3916 } 3917 if (elemX->tkwin == tree->tkwin) { 3918 goto badWindow; 3919 } 3920#ifdef CLIP_WINDOW 3921 if ((elemX->clip == 1) || ((masterX != NULL) && (masterX->clip == 1))) { 3922 elemX->child = (Tk_Window) ((TkWindow *) elemX->tkwin)->childList; 3923 if (elemX->child != NULL) { 3924 Tk_CreateEventHandler(elemX->child, StructureNotifyMask, 3925 WinItemStructureProc, (ClientData) elemX); 3926 Tk_ManageGeometry(elemX->child, &winElemGeomType, 3927 (ClientData) elemX); 3928 } 3929 } 3930#endif 3931 Tk_CreateEventHandler(elemX->tkwin, StructureNotifyMask, 3932 WinItemStructureProc, (ClientData) elemX); 3933 Tk_ManageGeometry(elemX->tkwin, &winElemGeomType, 3934 (ClientData) elemX); 3935 } 3936 } 3937#if 0 3938 if ((elemX->tkwin != NULL) 3939 && (itemPtr->state == TK_STATE_HIDDEN)) { 3940 if (tree->tkwin == Tk_Parent(elemX->tkwin)) { 3941 Tk_UnmapWindow(elemX->tkwin); 3942 } else { 3943 Tk_UnmaintainGeometry(elemX->tkwin, tree->tkwin); 3944 } 3945 } 3946#endif 3947 return TCL_OK; 3948} 3949 3950static int CreateProcWindow(TreeElementArgs *args) 3951{ 3952 TreeCtrl *tree = args->tree; 3953 TreeElement elem = args->elem; 3954 ElementWindow *elemX = (ElementWindow *) elem; 3955 3956 elemX->tree = tree; 3957 elemX->item = args->create.item; 3958 elemX->column = args->create.column; 3959 elemX->destroy = -1; 3960#ifdef CLIP_WINDOW 3961 elemX->clip = -1; 3962#endif 3963 return TCL_OK; 3964} 3965 3966static void DisplayProcWindow(TreeElementArgs *args) 3967{ 3968 TreeCtrl *tree = args->tree; 3969 TreeElement elem = args->elem; 3970 ElementWindow *elemX = (ElementWindow *) elem; 3971 ElementWindow *masterX = (ElementWindow *) elem->master; 3972 int state = args->state; 3973 int x = args->display.x, y = args->display.y; 3974 int minX, maxX, minY, maxY; 3975 int width, height; 3976 int match, match2; 3977#ifdef DEPRECATED 3978 int draw; 3979#endif 3980 int requests; 3981 3982#ifdef DEPRECATED 3983 BOOLEAN_FOR_STATE(draw, draw, state); 3984 if (!draw) 3985 goto hideIt; 3986#endif 3987 3988 if (elemX->tkwin == NULL) 3989 return; 3990 3991#ifdef CLIP_WINDOW 3992 if (elemX->child != NULL) { 3993 width = Tk_ReqWidth(elemX->child); 3994 height = Tk_ReqHeight(elemX->child); 3995 } else { 3996 width = Tk_ReqWidth(elemX->tkwin); 3997 height = Tk_ReqHeight(elemX->tkwin); 3998 } 3999 if (width < 1 || height < 1) 4000 goto hideIt; 4001#else 4002 width = Tk_ReqWidth(elemX->tkwin); 4003 height = Tk_ReqHeight(elemX->tkwin); 4004#endif 4005 AdjustForSticky(args->display.sticky, 4006 args->display.width, args->display.height, 4007 TRUE, TRUE, 4008 &x, &y, &width, &height); 4009 4010 x += tree->drawableXOrigin - tree->xOrigin; 4011 y += tree->drawableYOrigin - tree->yOrigin; 4012 4013 /* -squeeze layout may give the element less space than requested. */ 4014 if (width > args->display.width) 4015 width = args->display.width; 4016 if (height > args->display.height) 4017 height = args->display.height; 4018 4019 minX = args->display.bounds[0]; 4020 minY = args->display.bounds[1]; 4021 maxX = args->display.bounds[2]; 4022 maxY = args->display.bounds[3]; 4023 4024 /* 4025 * If the window is completely out of the visible area of the treectrl 4026 * then unmap it. The window could suddenly reappear if the treectrl 4027 * window gets resized. 4028 */ 4029 4030 if (((x + width) <= minX) || ((y + height) <= minY) 4031 || (x >= maxX) || (y >= maxY)) { 4032hideIt: 4033 if (tree->tkwin == Tk_Parent(elemX->tkwin)) { 4034 Tk_UnmapWindow(elemX->tkwin); 4035 } else { 4036 Tk_UnmaintainGeometry(elemX->tkwin, tree->tkwin); 4037 } 4038 return; 4039 } 4040 4041 TreeDisplay_GetReadyForTrouble(tree, &requests); 4042 4043#ifdef CLIP_WINDOW 4044 if (elemX->child != NULL) { 4045 int cx = x, cy = y, cw = width, ch = height; /* clip win coords */ 4046 4047 if (cx < minX) { 4048 cw -= minX - cx; 4049 cx = minX; 4050 } 4051 if (cy < minY) { 4052 ch -= minY - cy; 4053 cy = minY; 4054 } 4055 if (cx + cw > maxX) 4056 cw = maxX - cx; 4057 if (cy + ch > maxY) 4058 ch = maxY - cy; 4059 4060 /* 4061 * Reposition and map the window (but in different ways depending 4062 * on whether the treectrl is the window's parent). 4063 */ 4064 4065 if (tree->tkwin == Tk_Parent(elemX->tkwin)) { 4066 if ((cx != Tk_X(elemX->tkwin)) || (cy != Tk_Y(elemX->tkwin)) 4067 || (cw != Tk_Width(elemX->tkwin)) 4068 || (ch != Tk_Height(elemX->tkwin))) { 4069 Tk_MoveResizeWindow(elemX->tkwin, cx, cy, cw, ch); 4070 if (TreeDisplay_WasThereTrouble(tree, requests)) 4071 return; 4072 } 4073 Tk_MapWindow(elemX->tkwin); 4074 } else { 4075 Tk_MaintainGeometry(elemX->tkwin, tree->tkwin, cx, cy, cw, ch); 4076 } 4077 if (TreeDisplay_WasThereTrouble(tree, requests)) 4078 return; 4079 4080 /* 4081 * Position the child window within the clip window. 4082 */ 4083 x -= cx; 4084 y -= cy; 4085 if ((x != Tk_X(elemX->child)) || (y != Tk_Y(elemX->child)) 4086 || (width != Tk_Width(elemX->child)) 4087 || (height != Tk_Height(elemX->child))) { 4088 Tk_MoveResizeWindow(elemX->child, x, y, width, height); 4089 if (TreeDisplay_WasThereTrouble(tree, requests)) 4090 return; 4091 } 4092 Tk_MapWindow(elemX->child); 4093 return; 4094 } 4095#endif /* CLIP_WINDOW */ 4096 4097 /* 4098 * Reposition and map the window (but in different ways depending 4099 * on whether the treectrl is the window's parent). 4100 */ 4101 4102 if (tree->tkwin == Tk_Parent(elemX->tkwin)) { 4103 if ((x != Tk_X(elemX->tkwin)) || (y != Tk_Y(elemX->tkwin)) 4104 || (width != Tk_Width(elemX->tkwin)) 4105 || (height != Tk_Height(elemX->tkwin))) { 4106 Tk_MoveResizeWindow(elemX->tkwin, x, y, width, height); 4107 if (TreeDisplay_WasThereTrouble(tree, requests)) 4108 return; 4109 } 4110 Tk_MapWindow(elemX->tkwin); 4111 } else { 4112 Tk_MaintainGeometry(elemX->tkwin, tree->tkwin, x, y, 4113 width, height); 4114 } 4115} 4116 4117static void NeededProcWindow(TreeElementArgs *args) 4118{ 4119/* TreeCtrl *tree = args->tree;*/ 4120 TreeElement elem = args->elem; 4121 ElementWindow *elemX = (ElementWindow *) elem; 4122/* ElementWindow *masterX = (ElementWindow *) elem->master; 4123 int state = args->state;*/ 4124 int width = 0, height = 0; 4125 4126#ifdef CLIP_WINDOW 4127 if (elemX->child != NULL) { 4128 width = Tk_ReqWidth(elemX->child); 4129 if (width <= 0) { 4130 width = 1; 4131 } 4132 height = Tk_ReqHeight(elemX->child); 4133 if (height <= 0) { 4134 height = 1; 4135 } 4136 } else 4137#endif 4138 if (elemX->tkwin) { 4139 width = Tk_ReqWidth(elemX->tkwin); 4140 if (width <= 0) { 4141 width = 1; 4142 } 4143 height = Tk_ReqHeight(elemX->tkwin); 4144 if (height <= 0) { 4145 height = 1; 4146 } 4147 } 4148 args->needed.width = width; 4149 args->needed.height = height; 4150} 4151 4152static int StateProcWindow(TreeElementArgs *args) 4153{ 4154#ifdef DEPRECATED 4155 TreeCtrl *tree = args->tree; 4156 TreeElement elem = args->elem; 4157 ElementBitmap *elemX = (ElementBitmap *) elem; 4158 ElementBitmap *masterX = (ElementBitmap *) elem->master; 4159 int match, match2; 4160 int draw1, draw2; 4161 4162 if (!args->states.visible2 || !args->states.draw2) 4163 return 0; 4164 4165 BOOLEAN_FOR_STATE(draw1, draw, args->states.state1) 4166 BOOLEAN_FOR_STATE(draw2, draw, args->states.state2) 4167 if ((draw1 != 0) != (draw2 != 0)) 4168 return CS_DISPLAY; 4169#endif 4170 4171 return 0; 4172} 4173 4174static int UndefProcWindow(TreeElementArgs *args) 4175{ 4176 TreeCtrl *tree = args->tree; 4177 TreeElement elem = args->elem; 4178 ElementWindow *elemX = (ElementWindow *) elem; 4179 int modified = 0; 4180 4181#ifdef DEPRECATED 4182 modified |= PerStateInfo_Undefine(tree, &pstBoolean, &elemX->draw, args->state); 4183#endif 4184 return modified; 4185} 4186 4187static int ActualProcWindow(TreeElementArgs *args) 4188{ 4189#ifdef DEPRECATED 4190 TreeCtrl *tree = args->tree; 4191 ElementWindow *elemX = (ElementWindow *) args->elem; 4192 ElementWindow *masterX = (ElementWindow *) args->elem->master; 4193 static CONST char *optionName[] = { 4194 "-draw", 4195 (char *) NULL }; 4196 int index, match, matchM; 4197 Tcl_Obj *obj = NULL; 4198 4199 if (Tcl_GetIndexFromObj(tree->interp, args->actual.obj, optionName, 4200 "option", 0, &index) != TCL_OK) 4201 return TCL_ERROR; 4202 4203 switch (index) { 4204 case 0: { 4205 OBJECT_FOR_STATE(obj, pstBoolean, draw, args->state) 4206 break; 4207 } 4208 } 4209 if (obj != NULL) 4210 Tcl_SetObjResult(tree->interp, obj); 4211#endif 4212 return TCL_OK; 4213} 4214 4215static void OnScreenProcWindow(TreeElementArgs *args) 4216{ 4217 TreeCtrl *tree = args->tree; 4218 TreeElement elem = args->elem; 4219 ElementWindow *elemX = (ElementWindow *) elem; 4220 4221 if (!args->screen.visible && (elemX->tkwin != NULL)) { 4222 if (tree->tkwin == Tk_Parent(elemX->tkwin)) { 4223 Tk_UnmapWindow(elemX->tkwin); 4224 } else { 4225 Tk_UnmaintainGeometry(elemX->tkwin, tree->tkwin); 4226 } 4227 } 4228} 4229 4230TreeElementType treeElemTypeWindow = { 4231 "window", 4232 sizeof(ElementWindow), 4233 windowOptionSpecs, 4234 NULL, 4235 CreateProcWindow, 4236 DeleteProcWindow, 4237 ConfigProcWindow, 4238 DisplayProcWindow, 4239 NeededProcWindow, 4240 NULL, /* heightProc */ 4241 WorldChangedProcWindow, 4242 StateProcWindow, 4243 UndefProcWindow, 4244 ActualProcWindow, 4245 OnScreenProcWindow 4246}; 4247 4248/*****/ 4249 4250typedef struct ElementAssocData ElementAssocData; 4251 4252struct ElementAssocData 4253{ 4254 TreeElementType *typeList; 4255}; 4256 4257int TreeElement_TypeFromObj(TreeCtrl *tree, Tcl_Obj *objPtr, TreeElementType **typePtrPtr) 4258{ 4259 Tcl_Interp *interp = tree->interp; 4260 ElementAssocData *assocData; 4261 char *typeStr; 4262 int length; 4263 TreeElementType *typeList; 4264 TreeElementType *typePtr, *matchPtr = NULL; 4265 4266 assocData = Tcl_GetAssocData(interp, "TreeCtrlElementTypes", NULL); 4267 typeList = assocData->typeList; 4268 4269 typeStr = Tcl_GetStringFromObj(objPtr, &length); 4270 if (!length) { 4271 FormatResult(interp, "invalid element type \"\""); 4272 return TCL_ERROR; 4273 } 4274 for (typePtr = typeList; 4275 typePtr != NULL; 4276 typePtr = typePtr->next) { 4277 if ((typeStr[0] == typePtr->name[0]) && 4278 !strncmp(typeStr, typePtr->name, length)) { 4279 if (matchPtr != NULL) { 4280 FormatResult(interp, 4281 "ambiguous element type \"%s\"", 4282 typeStr); 4283 return TCL_ERROR; 4284 } 4285 matchPtr = typePtr; 4286 } 4287 } 4288 if (matchPtr == NULL) { 4289 FormatResult(interp, "unknown element type \"%s\"", typeStr); 4290 return TCL_ERROR; 4291 } 4292 *typePtrPtr = matchPtr; 4293 4294 return TCL_OK; 4295} 4296 4297int TreeCtrl_RegisterElementType(Tcl_Interp *interp, TreeElementType *newTypePtr) 4298{ 4299 ElementAssocData *assocData; 4300 TreeElementType *typeList; 4301 TreeElementType *prevPtr, *typePtr, *nextPtr; 4302 4303 assocData = Tcl_GetAssocData(interp, "TreeCtrlElementTypes", NULL); 4304 typeList = assocData->typeList; 4305 4306 for (typePtr = typeList, prevPtr = NULL; 4307 typePtr != NULL; 4308 prevPtr = typePtr, typePtr = nextPtr) { 4309 nextPtr = typePtr->next; 4310 /* Remove duplicate type */ 4311 if (!strcmp(typePtr->name, newTypePtr->name)) { 4312 if (prevPtr == NULL) 4313 typeList = typePtr->next; 4314 else 4315 prevPtr->next = typePtr->next; 4316 ckfree((char *) typePtr); 4317 } 4318 } 4319 typePtr = (TreeElementType *) ckalloc(sizeof(TreeElementType)); 4320 memcpy(typePtr, newTypePtr, sizeof(TreeElementType)); 4321 4322 typePtr->next = typeList; 4323 typeList = typePtr; 4324 4325 typePtr->optionTable = Tk_CreateOptionTable(interp, 4326 newTypePtr->optionSpecs); 4327 4328 assocData->typeList = typeList; 4329 4330 return TCL_OK; 4331} 4332 4333static TreeCtrlStubs stubs = { 4334 TreeCtrl_RegisterElementType, 4335 Tree_RedrawElement, 4336 Tree_ElementIterateBegin, 4337 Tree_ElementIterateNext, 4338 Tree_ElementIterateGet, 4339 Tree_ElementIterateChanged, 4340 PerStateInfo_Free, 4341 PerStateInfo_FromObj, 4342 PerStateInfo_ForState, 4343 PerStateInfo_ObjForState, 4344 PerStateInfo_Undefine, 4345 &pstBoolean, 4346 PerStateBoolean_ForState, 4347 PSTSave, 4348 PSTRestore, 4349 TreeStateFromObj, 4350 BooleanCO_Init, 4351 StringTableCO_Init, 4352 PerStateCO_Init 4353}; 4354 4355static void FreeAssocData(ClientData clientData, Tcl_Interp *interp) 4356{ 4357 ElementAssocData *assocData = clientData; 4358 TreeElementType *typeList = assocData->typeList; 4359 TreeElementType *next; 4360 4361 while (typeList != NULL) { 4362 next = typeList->next; 4363 /* The ElementType.optionTables are freed when the interp is deleted */ 4364 ckfree((char *) typeList); 4365 typeList = next; 4366 } 4367 ckfree((char *) assocData); 4368} 4369 4370int TreeElement_Init(Tcl_Interp *interp) 4371{ 4372 ElementAssocData *assocData; 4373 4374 /* FIXME: memory leak with dynamically-allocated ClientData. */ 4375 4376 /* 4377 * bitmap 4378 */ 4379 PerStateCO_Init(treeElemTypeBitmap.optionSpecs, "-background", 4380 &pstColor, TreeStateFromObj); 4381 PerStateCO_Init(treeElemTypeBitmap.optionSpecs, "-bitmap", 4382 &pstBitmap, TreeStateFromObj); 4383#ifdef DEPRECATED 4384 PerStateCO_Init(treeElemTypeBitmap.optionSpecs, "-draw", 4385 &pstBoolean, TreeStateFromObj); 4386#endif 4387 PerStateCO_Init(treeElemTypeBitmap.optionSpecs, "-foreground", 4388 &pstColor, TreeStateFromObj); 4389 4390 /* 4391 * border 4392 */ 4393#ifdef DEPRECATED 4394 PerStateCO_Init(treeElemTypeBorder.optionSpecs, "-draw", 4395 &pstBoolean, TreeStateFromObj); 4396#endif 4397 PerStateCO_Init(treeElemTypeBorder.optionSpecs, "-background", 4398 &pstBorder, TreeStateFromObj); 4399 PerStateCO_Init(treeElemTypeBorder.optionSpecs, "-relief", 4400 &pstRelief, TreeStateFromObj); 4401 4402 /* 4403 * image 4404 */ 4405#ifdef DEPRECATED 4406 DynamicCO_Init(treeElemTypeImage.optionSpecs, "-draw", 4407 1002, sizeof(PerStateInfo), 4408 Tk_Offset(PerStateInfo, obj), 4409 0, PerStateCO_Alloc("-draw", &pstBoolean, TreeStateFromObj), 4410 (DynamicOptionInitProc *) NULL); 4411#endif 4412 PerStateCO_Init(treeElemTypeImage.optionSpecs, "-image", 4413 &pstImage, TreeStateFromObj); 4414 4415 /* 2 options in the same structure. */ 4416 DynamicCO_Init(treeElemTypeImage.optionSpecs, "-height", 4417 1001, sizeof(ElementImageSize), 4418 Tk_Offset(ElementImageSize, heightObj), 4419 Tk_Offset(ElementImageSize, height), &TreeCtrlCO_pixels, 4420 (DynamicOptionInitProc *) NULL); 4421 DynamicCO_Init(treeElemTypeImage.optionSpecs, "-width", 4422 1001, sizeof(ElementImageSize), 4423 Tk_Offset(ElementImageSize, widthObj), 4424 Tk_Offset(ElementImageSize, width), &TreeCtrlCO_pixels, 4425 (DynamicOptionInitProc *) NULL); 4426 4427 DynamicCO_Init(treeElemTypeImage.optionSpecs, "-tiled", 4428 1003, sizeof(int), 4429 -1, 4430 0, &booleanCO, 4431 DynamicOptionInitBoolean); 4432 4433 /* 4434 * rect 4435 */ 4436#ifdef DEPRECATED 4437 PerStateCO_Init(treeElemTypeRect.optionSpecs, "-draw", 4438 &pstBoolean, TreeStateFromObj); 4439#endif 4440 PerStateCO_Init(treeElemTypeRect.optionSpecs, "-fill", 4441 &pstColor, TreeStateFromObj); 4442 PerStateCO_Init(treeElemTypeRect.optionSpecs, "-outline", 4443 &pstColor, TreeStateFromObj); 4444 4445 /* 4446 * text 4447 */ 4448 /* 3 options in the same structure. */ 4449 DynamicCO_Init(treeElemTypeText.optionSpecs, "-data", 4450 DOID_TEXT_DATA, sizeof(ElementTextData), 4451 Tk_Offset(ElementTextData, dataObj), 4452 -1, &TreeCtrlCO_string, 4453 ElementTextDataInit); 4454 DynamicCO_Init(treeElemTypeText.optionSpecs, "-datatype", 4455 DOID_TEXT_DATA, sizeof(ElementTextData), 4456 -1, 4457 Tk_Offset(ElementTextData, dataType), 4458 StringTableCO_Alloc("-datatype", textDataTypeST), 4459 ElementTextDataInit); 4460 DynamicCO_Init(treeElemTypeText.optionSpecs, "-format", 4461 DOID_TEXT_DATA, sizeof(ElementTextData), 4462 Tk_Offset(ElementTextData, formatObj), 4463 -1, &TreeCtrlCO_string, 4464 ElementTextDataInit); 4465 4466 /* 4 options in the same structure. */ 4467 DynamicCO_Init(treeElemTypeText.optionSpecs, "-justify", 4468 DOID_TEXT_LAYOUT, sizeof(ElementTextLayout), 4469 -1, 4470 Tk_Offset(ElementTextLayout, justify), 4471 StringTableCO_Alloc("-justify", textJustifyST), 4472 ElementTextLayoutInit); 4473 DynamicCO_Init(treeElemTypeText.optionSpecs, "-lines", 4474 DOID_TEXT_LAYOUT, sizeof(ElementTextLayout), 4475 -1, 4476 Tk_Offset(ElementTextLayout, lines), 4477 IntegerCO_Alloc("-lines", 4478 0, /* min */ 4479 0, /* max (ignored) */ 4480 -1, /* empty */ 4481 0x01), /* flags: min */ 4482 ElementTextLayoutInit); 4483 DynamicCO_Init(treeElemTypeText.optionSpecs, "-width", 4484 DOID_TEXT_LAYOUT, sizeof(ElementTextLayout), 4485 Tk_Offset(ElementTextLayout, widthObj), 4486 Tk_Offset(ElementTextLayout, width), &TreeCtrlCO_pixels, 4487 ElementTextLayoutInit); 4488 DynamicCO_Init(treeElemTypeText.optionSpecs, "-wrap", 4489 DOID_TEXT_LAYOUT, sizeof(ElementTextLayout), 4490 -1, 4491 Tk_Offset(ElementTextLayout, wrap), 4492 StringTableCO_Alloc("-wrap", textWrapST), 4493 ElementTextLayoutInit); 4494 4495#ifdef DEPRECATED 4496 DynamicCO_Init(treeElemTypeText.optionSpecs, "-draw", 4497 DOID_TEXT_DRAW, sizeof(PerStateInfo), 4498 Tk_Offset(PerStateInfo, obj), 4499 0, PerStateCO_Alloc("-draw", &pstBoolean, TreeStateFromObj), 4500 (DynamicOptionInitProc *) NULL); 4501#endif 4502 DynamicCO_Init(treeElemTypeText.optionSpecs, "-fill", 4503 DOID_TEXT_FILL, sizeof(PerStateInfo), 4504 Tk_Offset(PerStateInfo, obj), 4505 0, PerStateCO_Alloc("-fill", &pstColor, TreeStateFromObj), 4506 (DynamicOptionInitProc *) NULL); 4507 DynamicCO_Init(treeElemTypeText.optionSpecs, "-font", 4508 DOID_TEXT_FONT, sizeof(PerStateInfo), 4509 Tk_Offset(PerStateInfo, obj), 4510 0, PerStateCO_Alloc("-font", &pstFont, TreeStateFromObj), 4511 (DynamicOptionInitProc *) NULL); 4512 DynamicCO_Init(treeElemTypeText.optionSpecs, "-textvariable", 4513 DOID_TEXT_VAR, sizeof(ElementTextVar), 4514 Tk_Offset(struct ElementTextVar, varNameObj), 4515 -1, &TreeCtrlCO_string, 4516 (DynamicOptionInitProc *) NULL); 4517 4518#ifdef TEXT_STYLE 4519 DynamicCO_Init(treeElemTypeText.optionSpecs, "-underline", 4520 DOID_TEXT_STYLE, sizeof(ElementTextStyle), 4521 -1, 4522 Tk_Offset(ElementTextStyle, underline), 4523 IntegerCO_Alloc("-underline", 4524 0, /* min (ignored) */ 4525 0, /* max (ignored) */ 4526 TEXT_UNDERLINE_EMPTYVAL, /* empty */ 4527 0x00), /* flags */ 4528 ElementTextStyleInit); 4529#endif 4530 4531 /* 2 options in the same structure */ 4532 DynamicCO_Init(treeElemTypeText.optionSpecs, "-lmargin1", 4533 DOID_TEXT_LAYOUT3, sizeof(ElementTextLayout3), 4534 Tk_Offset(ElementTextLayout3, lMargin1Obj), 4535 Tk_Offset(ElementTextLayout3, lMargin1), &TreeCtrlCO_pixels, 4536 (DynamicOptionInitProc *) NULL); 4537 DynamicCO_Init(treeElemTypeText.optionSpecs, "-lmargin2", 4538 DOID_TEXT_LAYOUT3, sizeof(ElementTextLayout3), 4539 Tk_Offset(ElementTextLayout3, lMargin2Obj), 4540 Tk_Offset(ElementTextLayout3, lMargin2), &TreeCtrlCO_pixels, 4541 (DynamicOptionInitProc *) NULL); 4542 4543 /* 4544 * window 4545 */ 4546#ifdef DEPRECATED 4547 PerStateCO_Init(treeElemTypeWindow.optionSpecs, "-draw", 4548 &pstBoolean, TreeStateFromObj); 4549#endif 4550 4551 assocData = (ElementAssocData *) ckalloc(sizeof(ElementAssocData)); 4552 assocData->typeList = NULL; 4553 Tcl_SetAssocData(interp, "TreeCtrlElementTypes", FreeAssocData, assocData); 4554 4555 TreeCtrl_RegisterElementType(interp, &treeElemTypeBitmap); 4556 TreeCtrl_RegisterElementType(interp, &treeElemTypeBorder); 4557/* TreeCtrl_RegisterElementType(interp, &treeElemTypeCheckButton);*/ 4558 TreeCtrl_RegisterElementType(interp, &treeElemTypeImage); 4559 TreeCtrl_RegisterElementType(interp, &treeElemTypeRect); 4560 TreeCtrl_RegisterElementType(interp, &treeElemTypeText); 4561 TreeCtrl_RegisterElementType(interp, &treeElemTypeWindow); 4562 4563 Tcl_SetAssocData(interp, "TreeCtrlStubs", NULL, &stubs); 4564 4565 return TCL_OK; 4566} 4567