1/* 2 * tkTreeStyle.c -- 3 * 4 * This module implements styles for treectrl widgets. 5 * 6 * Copyright (c) 2002-2009 Tim Baker 7 * 8 * RCS: @(#) $Id: tkTreeStyle.c,v 1.80 2010/03/21 20:47:06 treectrl Exp $ 9 */ 10 11#include "tkTreeCtrl.h" 12#include "tkTreeElem.h" 13 14/* This is the roundUp argument to TreeAlloc_CAlloc. */ 15#define ELEMENT_LINK_ROUND 1 16 17/* Define this for performance gain and increased memory usage. */ 18/* When undefined, there is quite a performance hit when elements are 19 * squeezable and a style has less than its needed width. The memory 20 * savings are not too great when undefined. */ 21#define CACHE_STYLE_SIZE 22 23/* Define this for performance gain and increased memory usage. */ 24#define CACHE_ELEM_SIZE 25 26typedef struct MStyle MStyle; 27typedef struct IStyle IStyle; 28typedef struct MElementLink MElementLink; 29typedef struct IElementLink IElementLink; 30 31/* 32 * A data structure of the following type is kept for each master style. 33 * Master styles are created by the [style create] widget command. 34 */ 35struct MStyle 36{ 37 MStyle *master; /* Always NULL. Needed to distinguish between 38 * an MStyle and IStyle. */ 39 Tk_Uid name; /* Unique identifier. */ 40 int numElements; /* Size of elements[]. */ 41 MElementLink *elements; /* Array of master elements. */ 42 int vertical; /* -orient */ 43}; 44 45/* 46 * A data structure of the following type is kept for each instance style. 47 * Instance styles are created when a style is assigned to an item-column. 48 */ 49struct IStyle 50{ 51 MStyle *master; /* Always non-NULL. */ 52 IElementLink *elements; /* Array of master or instance elements. */ 53 int neededWidth; /* Requested size of this style based on */ 54 int neededHeight; /* layout of the elements. */ 55#ifdef TREECTRL_DEBUG 56 int neededState; 57#endif 58#ifdef CACHE_STYLE_SIZE 59 int minWidth; 60 int minHeight; 61 int layoutWidth; 62 int layoutHeight; 63#endif 64}; 65 66#define ELF_eEXPAND_W 0x0001 /* expand Layout.ePadX[0] */ 67#define ELF_eEXPAND_N 0x0002 68#define ELF_eEXPAND_E 0x0004 69#define ELF_eEXPAND_S 0x0008 70#define ELF_iEXPAND_W 0x0010 /* expand Layout.iPadX[0] */ 71#define ELF_iEXPAND_N 0x0020 72#define ELF_iEXPAND_E 0x0040 73#define ELF_iEXPAND_S 0x0080 74#define ELF_SQUEEZE_X 0x0100 /* shrink Layout.useWidth if needed */ 75#define ELF_SQUEEZE_Y 0x0200 76#define ELF_DETACH 0x0400 77#define ELF_INDENT 0x0800 /* don't layout under button&line area */ 78#define ELF_STICKY_W 0x1000 79#define ELF_STICKY_N 0x2000 80#define ELF_STICKY_E 0x4000 81#define ELF_STICKY_S 0x8000 82#define ELF_iEXPAND_X 0x00010000 /* expand Layout.useWidth */ 83#define ELF_iEXPAND_Y 0x00020000 84 85#define ELF_eEXPAND_WE (ELF_eEXPAND_W | ELF_eEXPAND_E) 86#define ELF_eEXPAND_NS (ELF_eEXPAND_N | ELF_eEXPAND_S) 87#define ELF_eEXPAND (ELF_eEXPAND_WE | ELF_eEXPAND_NS) 88#define ELF_iEXPAND_WE (ELF_iEXPAND_W | ELF_iEXPAND_E) 89#define ELF_iEXPAND_NS (ELF_iEXPAND_N | ELF_iEXPAND_S) 90#define ELF_iEXPAND (ELF_iEXPAND_WE | ELF_iEXPAND_NS) 91#define ELF_EXPAND_WE (ELF_eEXPAND_WE | ELF_iEXPAND_WE) 92#define ELF_EXPAND_NS (ELF_eEXPAND_NS | ELF_iEXPAND_NS) 93#define ELF_EXPAND_W (ELF_eEXPAND_W | ELF_iEXPAND_W) 94#define ELF_EXPAND_N (ELF_eEXPAND_N | ELF_iEXPAND_N) 95#define ELF_EXPAND_E (ELF_eEXPAND_E | ELF_iEXPAND_E) 96#define ELF_EXPAND_S (ELF_eEXPAND_S | ELF_iEXPAND_S) 97#define ELF_STICKY (ELF_STICKY_W | ELF_STICKY_N | ELF_STICKY_E | ELF_STICKY_S) 98 99#define DETACH_OR_UNION(e) (((e)->onion != NULL) || ((e)->flags & ELF_DETACH)) 100 101/* 102 * An array of these is kept for each master style, one per element. 103 * Most of the fields are set by the [style layout] widget command. 104 */ 105struct MElementLink 106{ 107 TreeElement elem; /* Master element. */ 108 int ePadX[2]; /* external horizontal padding */ 109 int ePadY[2]; /* external vertical padding */ 110 int iPadX[2]; /* internal horizontal padding */ 111 int iPadY[2]; /* internal vertical padding */ 112 int flags; /* ELF_xxx */ 113 int *onion, onionCount; /* -union option info */ 114 int minWidth, fixedWidth, maxWidth; 115 int minHeight, fixedHeight, maxHeight; 116 PerStateInfo draw; /* -draw */ 117 PerStateInfo visible; /* -visible */ 118}; 119 120/* 121 * An array of these is kept for each instance style, one per element. 122 */ 123struct IElementLink 124{ 125 TreeElement elem; /* Master or instance element. */ 126#ifdef CACHE_ELEM_SIZE 127 int neededWidth; 128 int neededHeight; 129 int layoutWidth; 130 int layoutHeight; 131#endif 132}; 133 134static CONST char *MStyleUid = "MStyle", *IStyleUid = "IStyle", 135 *MElementLinkUid = "MElementLink", *IElementLinkUid = "IElementLink"; 136 137static char *orientStringTable[] = { "horizontal", "vertical", (char *) NULL }; 138 139static Tk_OptionSpec styleOptionSpecs[] = { 140 {TK_OPTION_STRING_TABLE, "-orient", (char *) NULL, (char *) NULL, 141 "horizontal", -1, Tk_Offset(MStyle, vertical), 142 0, (ClientData) orientStringTable, 0}, 143 {TK_OPTION_END, (char *) NULL, (char *) NULL, (char *) NULL, 144 (char *) NULL, 0, -1, 0, (ClientData) NULL, 0} 145}; 146 147/* 148 * The following structure is used to hold layout information about a 149 * single element. This information is not cached anywhere. 150 */ 151struct Layout 152{ 153 MElementLink *master; 154 IElementLink *eLink; 155 int useWidth; 156 int useHeight; 157#ifndef CACHE_ELEM_SIZE 158 int neededWidth; 159 int neededHeight; 160#endif 161 int x; /* left of ePad */ 162 int y; /* above ePad */ 163 int eWidth; /* ePad + iPad + useWidth + iPad + ePad */ 164 int eHeight; /* ePad + iPad + useHeight + iPad + ePad */ 165 int iWidth; /* iPad + useWidth + iPad */ 166 int iHeight; /* iPad + useHeight + iPad */ 167 int ePadX[2]; /* external horizontal padding */ 168 int ePadY[2]; /* external vertical padding */ 169 int iPadX[2]; /* internal horizontal padding */ 170 int iPadY[2]; /* internal vertical padding */ 171 int uPadX[2]; /* padding due to -union */ 172 int uPadY[2]; /* padding due to -union */ 173 int temp; 174 int visible; /* TRUE if the element should be displayed. */ 175}; 176 177#define IS_HIDDEN(L) ((L)->visible == 0) 178 179/* 180 *---------------------------------------------------------------------- 181 * 182 * Style_DoExpandH -- 183 * 184 * Add extra horizontal space to an element. The space is 185 * distributed from right to left until all available space 186 * is used or expansion is not possible. 187 * 188 * Results: 189 * Layout.ePadX, Layout.iPadX, and Layout.useWidth may be 190 * updated. The amount of available space that was used is 191 * returned. 192 * 193 * Side effects: 194 * None. 195 * 196 *---------------------------------------------------------------------- 197 */ 198 199static int 200Style_DoExpandH( 201 struct Layout *layout, /* Layout to be adjusted. */ 202 int right /* Limit of expansion. */ 203 ) 204{ 205 MElementLink *eLink1 = layout->master; 206 int flags = eLink1->flags; 207 int numExpand = 0, spaceRemaining, spaceUsed = 0; 208 int *ePadX, *iPadX, *uPadX; 209 210 if (!(flags & (ELF_EXPAND_WE | ELF_iEXPAND_X))) 211 return 0; 212 213 ePadX = layout->ePadX; 214 iPadX = layout->iPadX; 215 uPadX = layout->uPadX; 216 217 spaceRemaining = right - (layout->x + ePadX[PAD_TOP_LEFT] + 218 layout->iWidth + MAX(ePadX[PAD_BOTTOM_RIGHT], uPadX[PAD_BOTTOM_RIGHT])); 219 if (spaceRemaining <= 0) 220 return 0; 221 222 if (layout->temp) 223 numExpand = layout->temp; 224 /* For -detach or vertical layout, just set layout->temp to zero */ 225 else { 226 if (flags & ELF_eEXPAND_W) numExpand++; 227 if (flags & ELF_iEXPAND_W) numExpand++; 228 if (flags & ELF_iEXPAND_X) { 229 if ((eLink1->maxWidth < 0) || 230 (eLink1->maxWidth > layout->useWidth)) 231 numExpand++; 232 } 233 if (flags & ELF_iEXPAND_E) numExpand++; 234 if (flags & ELF_eEXPAND_E) numExpand++; 235 } 236 237 while ((spaceRemaining > 0) && (numExpand > 0)) { 238 int each = (spaceRemaining >= numExpand) ? (spaceRemaining / numExpand) : 1; 239 240 numExpand = 0; 241 242 /* Allocate extra space to the *right* padding first so that any 243 * extra single pixel is given to the right. */ 244 245 if (flags & ELF_eEXPAND_E) { 246 int add = each; 247 ePadX[PAD_BOTTOM_RIGHT] += add; 248 layout->eWidth += add; 249 spaceRemaining -= add; 250 spaceUsed += add; 251 if (!spaceRemaining) 252 break; 253 numExpand++; 254 } 255 256 if (flags & ELF_iEXPAND_E) { 257 int add = each; 258 iPadX[PAD_BOTTOM_RIGHT] += add; 259 layout->iWidth += add; 260 layout->eWidth += add; 261 spaceRemaining -= add; 262 spaceUsed += add; 263 if (!spaceRemaining) 264 break; 265 numExpand++; 266 } 267 268 if (flags & ELF_iEXPAND_X) { 269 int max = eLink1->maxWidth; 270 if ((max < 0) || (layout->useWidth < max)) { 271 int add = (max < 0) ? each : MIN(each, max - layout->useWidth); 272 layout->useWidth += add; 273 layout->iWidth += add; 274 layout->eWidth += add; 275 spaceRemaining -= add; 276 spaceUsed += add; 277 if ((max >= 0) && (max == layout->useWidth)) 278 layout->temp--; 279 if (!spaceRemaining) 280 break; 281 if ((max < 0) || (max > layout->useWidth)) 282 numExpand++; 283 } 284 } 285 286 if (flags & ELF_iEXPAND_W) { 287 int add = each; 288 iPadX[PAD_TOP_LEFT] += add; 289 layout->iWidth += add; 290 layout->eWidth += add; 291 spaceRemaining -= add; 292 spaceUsed += add; 293 if (!spaceRemaining) 294 break; 295 numExpand++; 296 } 297 298 if (flags & ELF_eEXPAND_W) { 299 int add = each; 300 ePadX[PAD_TOP_LEFT] += add; 301 layout->eWidth += add; 302 spaceRemaining -= add; 303 spaceUsed += add; 304 if (!spaceRemaining) 305 break; 306 numExpand++; 307 } 308 } 309 310 return spaceUsed; 311} 312 313/* 314 *---------------------------------------------------------------------- 315 * 316 * Style_DoExpandV -- 317 * 318 * Add extra vertical space to an element. The space is 319 * distributed from bottom to top until all available space 320 * is used or expansion is not possible. 321 * 322 * Results: 323 * Layout.ePadY, Layout.iPadY, and Layout.useHeight may be 324 * updated. The amount of available space that was used is 325 * returned. 326 * 327 * Side effects: 328 * None. 329 * 330 *---------------------------------------------------------------------- 331 */ 332 333static int 334Style_DoExpandV( 335 struct Layout *layout, /* Layout to be adjusted. */ 336 int bottom /* Limit of expansion. */ 337 ) 338{ 339 MElementLink *eLink1 = layout->master; 340 int flags = eLink1->flags; 341 int numExpand = 0, spaceRemaining, spaceUsed = 0; 342 int *ePadY, *iPadY, *uPadY; 343 344 if (!(flags & (ELF_EXPAND_NS | ELF_iEXPAND_Y))) 345 return 0; 346 347 ePadY = layout->ePadY; 348 iPadY = layout->iPadY; 349 uPadY = layout->uPadY; 350 351 spaceRemaining = bottom - (layout->y + ePadY[PAD_TOP_LEFT] + 352 layout->iHeight + MAX(ePadY[PAD_BOTTOM_RIGHT], uPadY[PAD_BOTTOM_RIGHT])); 353 if (spaceRemaining <= 0) 354 return 0; 355 356 if (layout->temp) 357 numExpand = layout->temp; 358 /* For -detach or vertical layout, just set layout->temp to zero */ 359 else { 360 if (flags & ELF_eEXPAND_N) numExpand++; 361 if (flags & ELF_iEXPAND_N) numExpand++; 362 if (flags & ELF_iEXPAND_Y) { 363 if ((eLink1->maxHeight < 0) || 364 (eLink1->maxHeight > layout->useHeight)) 365 numExpand++; 366 } 367 if (flags & ELF_iEXPAND_S) numExpand++; 368 if (flags & ELF_eEXPAND_S) numExpand++; 369 } 370 371 while ((spaceRemaining > 0) && (numExpand > 0)) { 372 int each = (spaceRemaining >= numExpand) ? (spaceRemaining / numExpand) : 1; 373 374 numExpand = 0; 375 376 /* Allocate extra space to the *bottom* padding first so that any 377 * extra single pixel is given to the bottom. */ 378 379 if (flags & ELF_eEXPAND_S) { 380 int add = each; 381 ePadY[PAD_BOTTOM_RIGHT] += add; 382 layout->eHeight += add; 383 spaceRemaining -= add; 384 spaceUsed += add; 385 if (!spaceRemaining) 386 break; 387 numExpand++; 388 } 389 390 if (flags & ELF_iEXPAND_S) { 391 int add = each; 392 iPadY[PAD_BOTTOM_RIGHT] += add; 393 layout->iHeight += add; 394 layout->eHeight += add; 395 spaceRemaining -= add; 396 spaceUsed += add; 397 if (!spaceRemaining) 398 break; 399 numExpand++; 400 } 401 402 if (flags & ELF_iEXPAND_Y) { 403 int max = eLink1->maxHeight; 404 if ((max < 0) || (layout->useHeight < max)) { 405 int add = (max < 0) ? each : MIN(each, max - layout->useHeight); 406 layout->useHeight += add; 407 layout->iHeight += add; 408 layout->eHeight += add; 409 spaceRemaining -= add; 410 spaceUsed += add; 411 if ((max >= 0) && (max == layout->useHeight)) 412 layout->temp--; 413 if (!spaceRemaining) 414 break; 415 if ((max < 0) || (max > layout->useHeight)) 416 numExpand++; 417 } 418 } 419 420 if (flags & ELF_iEXPAND_N) { 421 int add = each; 422 iPadY[PAD_TOP_LEFT] += add; 423 layout->iHeight += add; 424 layout->eHeight += add; 425 spaceRemaining -= add; 426 spaceUsed += add; 427 if (!spaceRemaining) 428 break; 429 numExpand++; 430 } 431 432 if (flags & ELF_eEXPAND_N) { 433 int add = each; 434 ePadY[PAD_TOP_LEFT] += add; 435 layout->eHeight += add; 436 spaceRemaining -= add; 437 spaceUsed += add; 438 if (!spaceRemaining) 439 break; 440 numExpand++; 441 } 442 } 443 444 return spaceUsed; 445} 446 447/* 448 *---------------------------------------------------------------------- 449 * 450 * ElementLink_NeededSize -- 451 * 452 * Calculate the needed width and height of an element. 453 * 454 * Results: 455 * None. 456 * 457 * Side effects: 458 * None. 459 * 460 *---------------------------------------------------------------------- 461 */ 462 463static void 464Element_NeededSize( 465 TreeCtrl *tree, /* Widget info. */ 466 MElementLink *eLink1, /* Master style layout info. */ 467 TreeElement elem, /* Master/Instance element. */ 468 int state, /* STATE_xxx flags. */ 469 int *widthPtr, /* Out: width */ 470 int *heightPtr /* Out: height */ 471 ) 472{ 473 TreeElementArgs args; 474 int width, height; 475 476 if ((eLink1->fixedWidth >= 0) && (eLink1->fixedHeight >= 0)) { 477 width = eLink1->fixedWidth; 478 height = eLink1->fixedHeight; 479 } else { 480 args.tree = tree; 481 args.state = state; 482 args.elem = elem; 483 args.needed.fixedWidth = eLink1->fixedWidth; 484 args.needed.fixedHeight = eLink1->fixedHeight; 485 if (eLink1->maxWidth > eLink1->minWidth) 486 args.needed.maxWidth = eLink1->maxWidth; 487 else 488 args.needed.maxWidth = -1; 489 if (eLink1->maxHeight > eLink1->minHeight) 490 args.needed.maxHeight = eLink1->maxHeight; 491 else 492 args.needed.maxHeight = -1; 493 (*args.elem->typePtr->neededProc)(&args); 494 width = args.needed.width; 495 height = args.needed.height; 496 497 if (eLink1->fixedWidth >= 0) 498 width = eLink1->fixedWidth; 499 else if ((eLink1->minWidth >= 0) && 500 (width < eLink1->minWidth)) 501 width = eLink1->minWidth; 502 else if ((eLink1->maxWidth >= 0) && 503 (width > eLink1->maxWidth)) 504 width = eLink1->maxWidth; 505 506 if (eLink1->fixedHeight >= 0) 507 height = eLink1->fixedHeight; 508 else if ((eLink1->minHeight >= 0) && 509 (height < eLink1->minHeight)) 510 height = eLink1->minHeight; 511 else if ((eLink1->maxHeight >= 0) && 512 (height > eLink1->maxHeight)) 513 height = eLink1->maxHeight; 514 } 515 516 *widthPtr = width; 517 *heightPtr = height; 518} 519 520/* 521 *---------------------------------------------------------------------- 522 * 523 * Style_DoLayoutH -- 524 * 525 * Calculate the horizontal size and position of each element. 526 * This gets called if the style -orient option is horizontal or 527 * vertical. 528 * 529 * Results: 530 * layouts[] is updated. 531 * 532 * Side effects: 533 * None. 534 * 535 *---------------------------------------------------------------------- 536 */ 537 538static void 539Style_DoLayoutH( 540 StyleDrawArgs *drawArgs, /* Various args. */ 541 struct Layout layouts[] /* Array of layout records to be 542 * filled in, one per element. Should be 543 * uninitialized. */ 544 ) 545{ 546 IStyle *style = (IStyle *) drawArgs->style; 547 MStyle *masterStyle = style->master; 548 MElementLink *eLinks1, *eLink1; 549 IElementLink *eLinks2, *eLink2; 550 int x = drawArgs->indent; 551 int w, e; 552 int *ePadX, *iPadX, *uPadX, *ePadY, *iPadY, *uPadY; 553 int numExpandWE = 0; 554 int numSqueezeX = 0; 555 int i, j, eLinkCount = 0; 556 int rightEdge = 0; 557 558 eLinks1 = masterStyle->elements; 559 eLinks2 = style->elements; 560 eLinkCount = masterStyle->numElements; 561 562 for (i = 0; i < eLinkCount; i++) { 563 struct Layout *layout = &layouts[i]; 564 565 eLink1 = &eLinks1[i]; 566 eLink2 = &eLinks2[i]; 567 568 layout->visible = PerStateBoolean_ForState(drawArgs->tree, 569 &eLink1->visible, drawArgs->state, NULL) != 0; 570 if (IS_HIDDEN(layout)) 571 continue; 572 573 layout->eLink = eLink2; 574 layout->master = eLink1; 575 576 /* Width before squeezing/expanding */ 577 if (eLink1->onion != NULL) { 578 layout->useWidth = 0; 579 } else { 580#ifdef CACHE_ELEM_SIZE 581 layout->useWidth = eLink2->neededWidth; 582#else 583 Element_NeededSize(drawArgs->tree, eLink1, eLink2->elem, 584 drawArgs->state, &layout->neededWidth, &layout->neededHeight); 585 layout->useWidth = layout->neededWidth; 586#endif 587 } 588 589 for (j = 0; j < 2; j++) { 590 /* Pad values before expansion */ 591 layout->ePadX[j] = eLink1->ePadX[j]; 592 layout->ePadY[j] = eLink1->ePadY[j]; 593 layout->iPadX[j] = eLink1->iPadX[j]; 594 layout->iPadY[j] = eLink1->iPadY[j]; 595 596 /* No -union padding yet */ 597 layout->uPadX[j] = 0; 598 layout->uPadY[j] = 0; 599 } 600 601 /* Count all non-union, non-detach squeezeable elements */ 602 if (DETACH_OR_UNION(eLink1)) 603 continue; 604 if (eLink1->flags & ELF_SQUEEZE_X) 605 numSqueezeX++; 606 } 607 608 /* Calculate the padding around elements surrounded by -union elements */ 609 for (i = 0; i < eLinkCount; i++) { 610 struct Layout *layout = &layouts[i]; 611 int first = -1, last = -1; 612 613 if (IS_HIDDEN(layout)) 614 continue; 615 616 eLink1 = &eLinks1[i]; 617 618 if (eLink1->onion == NULL) 619 continue; 620 621 for (j = 0; j < eLink1->onionCount; j++) { 622 struct Layout *layout = &layouts[eLink1->onion[j]]; 623 624 if (IS_HIDDEN(layout)) 625 continue; 626 627 /* Remember the first and last visible elements surrounded by 628 * this -union element. */ 629 if (first == -1) 630 first = j; 631 last = j; 632 } 633 634 /* If there are no visible elements surrounded by this -union 635 * element, then hide it. */ 636 if (first == -1) { 637 layout->visible = 0; 638 continue; 639 } 640 641 ePadX = eLink1->ePadX; 642 ePadY = eLink1->ePadY; 643 iPadX = eLink1->iPadX; 644 iPadY = eLink1->iPadY; 645 646 for (j = 0; j < eLink1->onionCount; j++) { 647 struct Layout *layout = &layouts[eLink1->onion[j]]; 648 649 if (IS_HIDDEN(layout)) 650 continue; 651 652 uPadX = layout->uPadX; 653 uPadY = layout->uPadY; 654 655 if (masterStyle->vertical) { 656 uPadX[PAD_TOP_LEFT] = MAX(uPadX[PAD_TOP_LEFT], iPadX[PAD_TOP_LEFT] + ePadX[PAD_TOP_LEFT]); 657 uPadX[PAD_BOTTOM_RIGHT] = MAX(uPadX[PAD_BOTTOM_RIGHT], iPadX[PAD_BOTTOM_RIGHT] + ePadX[PAD_BOTTOM_RIGHT]); 658 if (j == first) /* topmost */ 659 uPadY[PAD_TOP_LEFT] = MAX(uPadY[PAD_TOP_LEFT], iPadY[PAD_TOP_LEFT] + ePadY[PAD_TOP_LEFT]); 660 if (j == last) /* bottommost */ 661 uPadY[PAD_BOTTOM_RIGHT] = MAX(uPadY[PAD_BOTTOM_RIGHT], iPadY[PAD_BOTTOM_RIGHT] + ePadY[PAD_BOTTOM_RIGHT]); 662 } else { 663 if (j == first) /* leftmost */ 664 uPadX[PAD_TOP_LEFT] = MAX(uPadX[PAD_TOP_LEFT], iPadX[PAD_TOP_LEFT] + ePadX[PAD_TOP_LEFT]); 665 if (j == last) /* rightmost */ 666 uPadX[PAD_BOTTOM_RIGHT] = MAX(uPadX[PAD_BOTTOM_RIGHT], iPadX[PAD_BOTTOM_RIGHT] + ePadX[PAD_BOTTOM_RIGHT]); 667 uPadY[PAD_TOP_LEFT] = MAX(uPadY[PAD_TOP_LEFT], iPadY[PAD_TOP_LEFT] + ePadY[PAD_TOP_LEFT]); 668 uPadY[PAD_BOTTOM_RIGHT] = MAX(uPadY[PAD_BOTTOM_RIGHT], iPadY[PAD_BOTTOM_RIGHT] + ePadY[PAD_BOTTOM_RIGHT]); 669 } 670 } 671 } 672 673 /* Left-to-right layout. Make the width of some elements less than they 674 * need */ 675 if (!masterStyle->vertical && 676 (drawArgs->width < style->neededWidth + drawArgs->indent) && 677 (numSqueezeX > 0)) { 678 int numSqueeze = numSqueezeX; 679 int spaceRemaining = (style->neededWidth + drawArgs->indent) - drawArgs->width; 680 681 while ((spaceRemaining > 0) && (numSqueeze > 0)) { 682 int each = (spaceRemaining >= numSqueeze) ? (spaceRemaining / numSqueeze) : 1; 683 684 numSqueeze = 0; 685 for (i = 0; i < eLinkCount; i++) { 686 struct Layout *layout = &layouts[i]; 687 int min = 0; 688 689 if (IS_HIDDEN(layout)) 690 continue; 691 692 eLink1 = &eLinks1[i]; 693 694 if (DETACH_OR_UNION(eLink1)) 695 continue; 696 697 if (!(eLink1->flags & ELF_SQUEEZE_X)) 698 continue; 699 700 if (eLink1->minWidth >= 0) 701 min = eLink1->minWidth; 702 if (layout->useWidth > min) { 703 int sub = MIN(each, layout->useWidth - min); 704 layout->useWidth -= sub; 705 spaceRemaining -= sub; 706 if (!spaceRemaining) break; 707 if (layout->useWidth > min) 708 numSqueeze++; 709 } 710 } 711 } 712 } 713 714 /* Reduce the width of all non-union elements, except for the 715 * cases handled above. */ 716 for (i = 0; i < eLinkCount; i++) { 717 struct Layout *layout = &layouts[i]; 718 int width, subtract; 719 720 if (IS_HIDDEN(layout)) 721 continue; 722 723 eLink1 = &eLinks1[i]; 724 725 if (eLink1->onion != NULL) 726 continue; 727 728 if (!(eLink1->flags & ELF_SQUEEZE_X)) 729 continue; 730 731 if (!(eLink1->flags & ELF_DETACH) && !masterStyle->vertical) 732 continue; 733 734 ePadX = eLink1->ePadX; 735 iPadX = eLink1->iPadX; 736 uPadX = layout->uPadX; 737 738 width = 739 MAX(ePadX[PAD_TOP_LEFT], uPadX[PAD_TOP_LEFT]) + 740 iPadX[PAD_TOP_LEFT] + layout->useWidth + iPadX[PAD_BOTTOM_RIGHT] + 741 MAX(ePadX[PAD_BOTTOM_RIGHT], uPadX[PAD_BOTTOM_RIGHT]); 742 subtract = width - drawArgs->width; 743 744 if (!(eLink1->flags & ELF_DETACH) || (eLink1->flags & ELF_INDENT)) 745 subtract += drawArgs->indent; 746 747 if (subtract > 0) { 748 if ((eLink1->minWidth >= 0) && 749 (eLink1->minWidth <= layout->useWidth) && 750 (layout->useWidth - subtract < eLink1->minWidth)) 751 layout->useWidth = eLink1->minWidth; 752 else 753 layout->useWidth -= subtract; 754 } 755 } 756 757 /* Layout elements left-to-right */ 758 for (i = 0; i < eLinkCount; i++) { 759 struct Layout *layout = &layouts[i]; 760 int right; 761 762 if (IS_HIDDEN(layout)) 763 continue; 764 765 eLink1 = &eLinks1[i]; 766 eLink2 = &eLinks2[i]; 767 768 if (DETACH_OR_UNION(eLink1)) 769 continue; 770 771 ePadX = eLink1->ePadX; 772 iPadX = eLink1->iPadX; 773 uPadX = layout->uPadX; 774 775 layout->x = x + abs(ePadX[PAD_TOP_LEFT] - MAX(ePadX[PAD_TOP_LEFT], uPadX[PAD_TOP_LEFT])); 776 layout->iWidth = iPadX[PAD_TOP_LEFT] + layout->useWidth + iPadX[PAD_BOTTOM_RIGHT]; 777 layout->eWidth = ePadX[PAD_TOP_LEFT] + layout->iWidth + ePadX[PAD_BOTTOM_RIGHT]; 778 779 right = layout->x + layout->ePadX[PAD_TOP_LEFT] + 780 layout->iWidth + 781 MAX(ePadX[PAD_BOTTOM_RIGHT], uPadX[PAD_BOTTOM_RIGHT]); 782 783 if (masterStyle->vertical) 784 rightEdge = MAX(rightEdge, right); 785 else { 786 rightEdge = right; 787 x = layout->x + layout->eWidth; 788 } 789 790 /* Count number that want to expand */ 791 if (eLink1->flags & (ELF_EXPAND_WE | ELF_iEXPAND_X)) 792 numExpandWE++; 793 } 794 795 /* Left-to-right layout. Expand some elements horizontally if we have 796 * more space available horizontally than is needed by the Style. */ 797 if (!masterStyle->vertical && 798 (drawArgs->width > rightEdge) && 799 (numExpandWE > 0)) { 800 int numExpand = 0; 801 int spaceRemaining = drawArgs->width - rightEdge; 802 803 /* Each element has 5 areas that can optionally expand. */ 804 for (i = 0; i < eLinkCount; i++) { 805 struct Layout *layout = &layouts[i]; 806 807 if (IS_HIDDEN(layout)) 808 continue; 809 810 eLink1 = &eLinks1[i]; 811 812 layout->temp = 0; 813 814 if (DETACH_OR_UNION(eLink1)) 815 continue; 816 817 if (eLink1->flags & ELF_eEXPAND_W) layout->temp++; 818 if (eLink1->flags & ELF_iEXPAND_W) layout->temp++; 819 if (eLink1->flags & ELF_iEXPAND_X) { 820 if ((eLink1->maxWidth < 0) || 821 (eLink1->maxWidth > layout->useWidth)) 822 layout->temp++; 823 } 824 if (eLink1->flags & ELF_iEXPAND_E) layout->temp++; 825 if (eLink1->flags & ELF_eEXPAND_E) layout->temp++; 826 827 numExpand += layout->temp; 828 } 829 830 while ((spaceRemaining > 0) && (numExpand > 0)) { 831 int each = (spaceRemaining >= numExpand) ? spaceRemaining / numExpand : 1; 832 833 numExpand = 0; 834 for (i = 0; i < eLinkCount; i++) { 835 struct Layout *layout = &layouts[i]; 836 int spaceUsed; 837 838 if (IS_HIDDEN(layout)) 839 continue; 840 841 if (!layout->temp) 842 continue; 843 844 eLink1 = &eLinks1[i]; 845 846 spaceUsed = Style_DoExpandH(layout, 847 layout->x + layout->ePadX[PAD_TOP_LEFT] + layout->iWidth + 848 MAX(layout->ePadX[PAD_BOTTOM_RIGHT], layout->uPadX[PAD_BOTTOM_RIGHT]) + 849 MIN(each * layout->temp, spaceRemaining)); 850 851 if (spaceUsed) { 852 /* Shift following elements to the right */ 853 for (j = i + 1; j < eLinkCount; j++) 854 if (!DETACH_OR_UNION(&eLinks1[j])) 855 layouts[j].x += spaceUsed; 856 857 rightEdge += spaceUsed; 858 859 spaceRemaining -= spaceUsed; 860 if (!spaceRemaining) 861 break; 862 863 numExpand += layout->temp; 864 } else 865 layout->temp = 0; 866 } 867 } 868 } 869 870 /* Top-to-bottom layout. Expand some elements horizontally */ 871 if (masterStyle->vertical && (numExpandWE > 0)) { 872 for (i = 0; i < eLinkCount; i++) { 873 struct Layout *layout = &layouts[i]; 874 int right; 875 876 if (IS_HIDDEN(layout)) 877 continue; 878 879 eLink1 = &eLinks1[i]; 880 881 if (DETACH_OR_UNION(eLink1)) 882 continue; 883 884 layout->temp = 0; 885 Style_DoExpandH(layout, drawArgs->width); 886 887 right = layout->x + layout->ePadX[PAD_TOP_LEFT] + 888 layout->iWidth + 889 MAX(layout->ePadX[PAD_BOTTOM_RIGHT], layout->uPadX[PAD_BOTTOM_RIGHT]); 890 rightEdge = MAX(rightEdge, right); 891 } 892 } 893 894 /* Now handle column justification */ 895 /* All the non-union, non-detach elements are moved as a group */ 896 if (drawArgs->width > rightEdge) { 897 int dx = drawArgs->width - rightEdge; 898 899 for (i = 0; i < eLinkCount; i++) { 900 struct Layout *layout = &layouts[i]; 901 902 if (IS_HIDDEN(layout)) 903 continue; 904 905 eLink1 = &eLinks1[i]; 906 907 if (DETACH_OR_UNION(eLink1)) 908 continue; 909 910 switch (drawArgs->justify) { 911 case TK_JUSTIFY_LEFT: 912 break; 913 case TK_JUSTIFY_RIGHT: 914 layout->x += dx; 915 break; 916 case TK_JUSTIFY_CENTER: 917 layout->x += dx / 2; 918 break; 919 } 920 } 921 } 922 923 /* Position and expand -detach elements */ 924 for (i = 0; i < eLinkCount; i++) { 925 struct Layout *layout = &layouts[i]; 926 927 if (IS_HIDDEN(layout)) 928 continue; 929 930 eLink1 = &eLinks1[i]; 931 eLink2 = &eLinks2[i]; 932 933 if (!(eLink1->flags & ELF_DETACH) || (eLink1->onion != NULL)) 934 continue; 935 936 ePadX = eLink1->ePadX; 937 iPadX = eLink1->iPadX; 938 uPadX = layout->uPadX; 939 940 layout->x = abs(ePadX[PAD_TOP_LEFT] - MAX(ePadX[PAD_TOP_LEFT], uPadX[PAD_TOP_LEFT])); 941 if (eLink1->flags & ELF_INDENT) 942 layout->x += drawArgs->indent; 943 layout->iWidth = iPadX[PAD_TOP_LEFT] + layout->useWidth + iPadX[PAD_BOTTOM_RIGHT]; 944 layout->eWidth = ePadX[PAD_TOP_LEFT] + layout->iWidth + ePadX[PAD_BOTTOM_RIGHT]; 945 946 layout->temp = 0; 947 Style_DoExpandH(layout, drawArgs->width); 948 } 949 950 /* Now calculate layout of -union elements. */ 951 for (i = 0; i < eLinkCount; i++) { 952 struct Layout *layout = &layouts[i]; 953 954 eLink1 = &eLinks1[i]; 955 eLink2 = &eLinks2[i]; 956 957 if (IS_HIDDEN(layout)) 958 continue; 959 960 if (eLink1->onion == NULL) 961 continue; 962 963 ePadX = eLink1->ePadX; 964 iPadX = eLink1->iPadX; 965 966 w = 1000000, e = -1000000; 967 968 for (j = 0; j < eLink1->onionCount; j++) { 969 struct Layout *layout2 = &layouts[eLink1->onion[j]]; 970 971 if (IS_HIDDEN(layout2)) 972 continue; 973 974 w = MIN(w, layout2->x + layout2->ePadX[PAD_TOP_LEFT]); 975 e = MAX(e, layout2->x + layout2->ePadX[PAD_TOP_LEFT] + layout2->iWidth); 976 } 977 978 layout->x = w - iPadX[PAD_TOP_LEFT] - ePadX[PAD_TOP_LEFT]; 979 layout->useWidth = (e - w); 980 layout->iWidth = iPadX[PAD_TOP_LEFT] + layout->useWidth + iPadX[PAD_BOTTOM_RIGHT]; 981 layout->eWidth = ePadX[PAD_TOP_LEFT] + layout->iWidth + ePadX[PAD_BOTTOM_RIGHT]; 982 } 983 984 /* Expand -union elements if needed: horizontal */ 985 /* Expansion of "-union" elements is different than non-"-union" elements */ 986 for (i = 0; i < eLinkCount; i++) { 987 struct Layout *layout = &layouts[i]; 988 int extraWidth; 989 990 if (IS_HIDDEN(layout)) 991 continue; 992 993 eLink1 = &eLinks1[i]; 994 995 if ((eLink1->onion == NULL) || !(eLink1->flags & ELF_EXPAND_WE)) 996 continue; 997 998 if (drawArgs->width - (layout->eWidth + drawArgs->indent) <= 0) 999 continue; 1000 1001 /* External and internal expansion: W */ 1002 extraWidth = layout->x - drawArgs->indent; 1003 if ((extraWidth > 0) && (eLink1->flags & ELF_EXPAND_W)) { 1004 if ((eLink1->flags & ELF_EXPAND_W) == ELF_EXPAND_W) { 1005 int eExtra = extraWidth / 2; 1006 int iExtra = extraWidth - extraWidth / 2; 1007 1008 layout->x = drawArgs->indent; 1009 1010 /* External expansion */ 1011 layout->ePadX[PAD_TOP_LEFT] += eExtra; 1012 layout->eWidth += extraWidth; 1013 1014 /* Internal expansion */ 1015 layout->iPadX[PAD_TOP_LEFT] += iExtra; 1016 layout->iWidth += iExtra; 1017 } 1018 1019 /* External expansion only: W */ 1020 else if (eLink1->flags & ELF_eEXPAND_W) { 1021 layout->ePadX[PAD_TOP_LEFT] += extraWidth; 1022 layout->x = drawArgs->indent; 1023 layout->eWidth += extraWidth; 1024 } 1025 1026 /* Internal expansion only: W */ 1027 else { 1028 layout->iPadX[PAD_TOP_LEFT] += extraWidth; 1029 layout->x = drawArgs->indent; 1030 layout->iWidth += extraWidth; 1031 layout->eWidth += extraWidth; 1032 } 1033 } 1034 1035 /* External and internal expansion: E */ 1036 extraWidth = drawArgs->width - (layout->x + layout->eWidth); 1037 if ((extraWidth > 0) && (eLink1->flags & ELF_EXPAND_E)) { 1038 if ((eLink1->flags & ELF_EXPAND_E) == ELF_EXPAND_E) { 1039 int eExtra = extraWidth / 2; 1040 int iExtra = extraWidth - extraWidth / 2; 1041 1042 /* External expansion */ 1043 layout->ePadX[PAD_BOTTOM_RIGHT] += eExtra; 1044 layout->eWidth += extraWidth; /* all the space */ 1045 1046 /* Internal expansion */ 1047 layout->iPadX[PAD_BOTTOM_RIGHT] += iExtra; 1048 layout->iWidth += iExtra; 1049 } 1050 1051 /* External expansion only: E */ 1052 else if (eLink1->flags & ELF_eEXPAND_E) { 1053 layout->ePadX[PAD_BOTTOM_RIGHT] += extraWidth; 1054 layout->eWidth += extraWidth; 1055 } 1056 1057 /* Internal expansion only: E */ 1058 else { 1059 layout->iPadX[PAD_BOTTOM_RIGHT] += extraWidth; 1060 layout->iWidth += extraWidth; 1061 layout->eWidth += extraWidth; 1062 } 1063 } 1064 } 1065 1066 /* Add internal padding to display area for -union elements */ 1067 for (i = 0; i < eLinkCount; i++) { 1068 struct Layout *layout = &layouts[i]; 1069 1070 if (IS_HIDDEN(layout)) 1071 continue; 1072 1073 eLink1 = &eLinks1[i]; 1074 1075 if (eLink1->onion == NULL) 1076 continue; 1077 1078 iPadX = layout->iPadX; 1079 1080 layout->useWidth += iPadX[PAD_TOP_LEFT] + iPadX[PAD_BOTTOM_RIGHT]; 1081 iPadX[PAD_TOP_LEFT] = iPadX[PAD_BOTTOM_RIGHT] = 0; 1082 } 1083} 1084 1085/* 1086 *---------------------------------------------------------------------- 1087 * 1088 * Style_DoLayoutV -- 1089 * 1090 * Calculate the vertical size and position of each element. 1091 * This gets called if the style -orient option is horizontal or 1092 * vertical. 1093 * 1094 * Results: 1095 * layouts[] is updated. 1096 * 1097 * Side effects: 1098 * None. 1099 * 1100 *---------------------------------------------------------------------- 1101 */ 1102 1103static void 1104Style_DoLayoutV( 1105 StyleDrawArgs *drawArgs, /* Various args. */ 1106 struct Layout layouts[] /* Array of layout records to be updated, 1107 * one per element. Should be initialized 1108 * by Style_DoLayoutH(). */ 1109 ) 1110{ 1111 IStyle *style = (IStyle *) drawArgs->style; 1112 MStyle *masterStyle = style->master; 1113 MElementLink *eLinks1, *eLink1; 1114 IElementLink *eLinks2, *eLink2; 1115 int y = 0; 1116 int n, s; 1117 int *ePadY, *iPadY, *uPadY; 1118 int numExpandNS = 0; 1119 int numSqueezeY = 0; 1120 int i, j, eLinkCount = 0; 1121 int bottomEdge = 0; 1122 1123 eLinks1 = masterStyle->elements; 1124 eLinks2 = style->elements; 1125 eLinkCount = masterStyle->numElements; 1126 1127 for (i = 0; i < eLinkCount; i++) { 1128 if (IS_HIDDEN(&layouts[i])) 1129 continue; 1130 1131 eLink1 = &eLinks1[i]; 1132 1133 /* Count all non-union, non-detach squeezeable elements */ 1134 if (DETACH_OR_UNION(eLink1)) 1135 continue; 1136 if (eLink1->flags & ELF_SQUEEZE_Y) 1137 numSqueezeY++; 1138 } 1139 1140 /* Top-top-bottom layout. Make the height of some elements less than they 1141 * need */ 1142 if (masterStyle->vertical && 1143 (drawArgs->height < style->neededHeight) && 1144 (numSqueezeY > 0)) { 1145 int numSqueeze = numSqueezeY; 1146 int spaceRemaining = style->neededHeight - drawArgs->height; 1147 1148 while ((spaceRemaining > 0) && (numSqueeze > 0)) { 1149 int each = (spaceRemaining >= numSqueeze) ? (spaceRemaining / numSqueeze) : 1; 1150 1151 numSqueeze = 0; 1152 for (i = 0; i < eLinkCount; i++) { 1153 struct Layout *layout = &layouts[i]; 1154 int min = 0; 1155 1156 if (IS_HIDDEN(layout)) 1157 continue; 1158 1159 eLink1 = &eLinks1[i]; 1160 1161 if (DETACH_OR_UNION(eLink1)) 1162 continue; 1163 1164 if (!(eLink1->flags & ELF_SQUEEZE_Y)) 1165 continue; 1166 1167 if (eLink1->minHeight >= 0) 1168 min = eLink1->minHeight; 1169 if (layout->useHeight > min) { 1170 int sub = MIN(each, layout->useHeight - min); 1171 layout->useHeight -= sub; 1172 spaceRemaining -= sub; 1173 if (!spaceRemaining) break; 1174 if (layout->useHeight > min) 1175 numSqueeze++; 1176 } 1177 } 1178 } 1179 } 1180 1181 /* Reduce the height of all non-union elements, except for the 1182 * cases handled above. */ 1183 if (drawArgs->height < style->neededHeight) { 1184 for (i = 0; i < eLinkCount; i++) { 1185 struct Layout *layout = &layouts[i]; 1186 int height, subtract; 1187 1188 if (IS_HIDDEN(layout)) 1189 continue; 1190 1191 eLink1 = &eLinks1[i]; 1192 1193 if (eLink1->onion != NULL) 1194 continue; 1195 1196 if (!(eLink1->flags & ELF_SQUEEZE_Y)) 1197 continue; 1198 1199 if (!(eLink1->flags & ELF_DETACH) && masterStyle->vertical) 1200 continue; 1201 1202 ePadY = eLink1->ePadY; 1203 iPadY = eLink1->iPadY; 1204 uPadY = layout->uPadY; 1205 1206 height = 1207 MAX(ePadY[PAD_TOP_LEFT], uPadY[PAD_TOP_LEFT]) + 1208 iPadY[PAD_TOP_LEFT] + layout->useHeight + iPadY[PAD_BOTTOM_RIGHT] + 1209 MAX(ePadY[PAD_BOTTOM_RIGHT], uPadY[PAD_BOTTOM_RIGHT]); 1210 subtract = height - drawArgs->height; 1211 1212 if (subtract > 0) { 1213 if ((eLink1->minHeight >= 0) && 1214 (eLink1->minHeight <= layout->useHeight) && 1215 (layout->useHeight - subtract < eLink1->minHeight)) 1216 layout->useHeight = eLink1->minHeight; 1217 else 1218 layout->useHeight -= subtract; 1219 } 1220 } 1221 } 1222 1223 /* Layout elements top-to-bottom */ 1224 for (i = 0; i < eLinkCount; i++) { 1225 struct Layout *layout = &layouts[i]; 1226 1227 if (IS_HIDDEN(layout)) 1228 continue; 1229 1230 eLink1 = &eLinks1[i]; 1231 eLink2 = &eLinks2[i]; 1232 1233 if (DETACH_OR_UNION(eLink1)) 1234 continue; 1235 1236 ePadY = eLink1->ePadY; 1237 iPadY = eLink1->iPadY; 1238 uPadY = layout->uPadY; 1239 1240 layout->y = y + abs(ePadY[PAD_TOP_LEFT] - MAX(ePadY[PAD_TOP_LEFT], uPadY[PAD_TOP_LEFT])); 1241 layout->iHeight = iPadY[PAD_TOP_LEFT] + layout->useHeight + iPadY[PAD_BOTTOM_RIGHT]; 1242 layout->eHeight = ePadY[PAD_TOP_LEFT] + layout->iHeight + ePadY[PAD_BOTTOM_RIGHT]; 1243 1244 if (masterStyle->vertical) 1245 y = layout->y + layout->eHeight; 1246 1247 if (masterStyle->vertical) { 1248 bottomEdge = layout->y + layout->ePadY[PAD_TOP_LEFT] + 1249 layout->iHeight + 1250 MAX(ePadY[PAD_BOTTOM_RIGHT], uPadY[PAD_BOTTOM_RIGHT]); 1251 } 1252 1253 /* Count number that want to expand */ 1254 if (eLink1->flags & (ELF_EXPAND_NS | ELF_iEXPAND_Y)) 1255 numExpandNS++; 1256 } 1257 1258 /* Top-to-bottom layout. Expand some elements vertically if we have 1259 * more space available vertically than is needed by the Style. */ 1260 if (masterStyle->vertical && 1261 (drawArgs->height > bottomEdge) && 1262 (numExpandNS > 0)) { 1263 int numExpand = 0; 1264 int spaceRemaining = drawArgs->height - bottomEdge; 1265 1266 for (i = 0; i < eLinkCount; i++) { 1267 struct Layout *layout = &layouts[i]; 1268 1269 if (IS_HIDDEN(layout)) 1270 continue; 1271 1272 eLink1 = &eLinks1[i]; 1273 1274 layout->temp = 0; 1275 1276 if (DETACH_OR_UNION(eLink1)) 1277 continue; 1278 1279 if (eLink1->flags & ELF_eEXPAND_N) layout->temp++; 1280 if (eLink1->flags & ELF_iEXPAND_N) layout->temp++; 1281 if (eLink1->flags & ELF_iEXPAND_Y) { 1282 if ((eLink1->maxHeight < 0) || 1283 (eLink1->maxHeight > layout->useHeight)) 1284 layout->temp++; 1285 } 1286 if (eLink1->flags & ELF_iEXPAND_S) layout->temp++; 1287 if (eLink1->flags & ELF_eEXPAND_S) layout->temp++; 1288 1289 numExpand += layout->temp; 1290 } 1291 1292 while ((spaceRemaining > 0) && (numExpand > 0)) { 1293 int each = (spaceRemaining >= numExpand) ? spaceRemaining / numExpand : 1; 1294 1295 numExpand = 0; 1296 for (i = 0; i < eLinkCount; i++) { 1297 struct Layout *layout = &layouts[i]; 1298 int spaceUsed; 1299 1300 if (IS_HIDDEN(layout)) 1301 continue; 1302 1303 if (!layout->temp) 1304 continue; 1305 1306 eLink1 = &eLinks1[i]; 1307 1308 spaceUsed = Style_DoExpandV(layout, 1309 layout->y + layout->ePadY[PAD_TOP_LEFT] + layout->iHeight + 1310 MAX(layout->ePadY[PAD_BOTTOM_RIGHT], layout->uPadY[PAD_BOTTOM_RIGHT]) + 1311 MIN(each * layout->temp, spaceRemaining)); 1312 1313 if (spaceUsed) { 1314 /* Shift following elements down */ 1315 for (j = i + 1; j < eLinkCount; j++) 1316 if (!DETACH_OR_UNION(&eLinks1[j])) 1317 layouts[j].y += spaceUsed; 1318 1319 spaceRemaining -= spaceUsed; 1320 if (!spaceRemaining) 1321 break; 1322 1323 numExpand += layout->temp; 1324 } else 1325 layout->temp = 0; 1326 } 1327 } 1328 } 1329 1330 /* Left-to-right layout. Expand some elements vertically */ 1331 if (!masterStyle->vertical && (numExpandNS > 0)) { 1332 for (i = 0; i < eLinkCount; i++) { 1333 struct Layout *layout = &layouts[i]; 1334 1335 if (IS_HIDDEN(layout)) 1336 continue; 1337 1338 eLink1 = &eLinks1[i]; 1339 1340 if (DETACH_OR_UNION(eLink1)) 1341 continue; 1342 1343 layout->temp = 0; 1344 Style_DoExpandV(layout, drawArgs->height); 1345 } 1346 } 1347 1348 /* Position and expand -detach elements */ 1349 for (i = 0; i < eLinkCount; i++) { 1350 struct Layout *layout = &layouts[i]; 1351 1352 if (IS_HIDDEN(layout)) 1353 continue; 1354 1355 eLink1 = &eLinks1[i]; 1356 eLink2 = &eLinks2[i]; 1357 1358 if (!(eLink1->flags & ELF_DETACH) || (eLink1->onion != NULL)) 1359 continue; 1360 1361 ePadY = eLink1->ePadY; 1362 iPadY = eLink1->iPadY; 1363 uPadY = layout->uPadY; 1364 1365 layout->y = abs(ePadY[PAD_TOP_LEFT] - MAX(ePadY[PAD_TOP_LEFT], uPadY[PAD_TOP_LEFT])); 1366 layout->iHeight = iPadY[PAD_TOP_LEFT] + layout->useHeight + iPadY[PAD_BOTTOM_RIGHT]; 1367 layout->eHeight = ePadY[PAD_TOP_LEFT] + layout->iHeight + ePadY[PAD_BOTTOM_RIGHT]; 1368 1369 layout->temp = 0; 1370 Style_DoExpandV(layout, drawArgs->height); 1371 } 1372 1373 /* Now calculate layout of -union elements. */ 1374 for (i = 0; i < eLinkCount; i++) { 1375 struct Layout *layout = &layouts[i]; 1376 1377 if (IS_HIDDEN(layout)) 1378 continue; 1379 1380 eLink1 = &eLinks1[i]; 1381 eLink2 = &eLinks2[i]; 1382 1383 if (eLink1->onion == NULL) 1384 continue; 1385 1386 ePadY = eLink1->ePadY; 1387 iPadY = eLink1->iPadY; 1388 1389 n = 1000000, s = -1000000; 1390 1391 for (j = 0; j < eLink1->onionCount; j++) { 1392 struct Layout *layout2 = &layouts[eLink1->onion[j]]; 1393 1394 if (IS_HIDDEN(layout2)) 1395 continue; 1396 1397 n = MIN(n, layout2->y + layout2->ePadY[PAD_TOP_LEFT]); 1398 s = MAX(s, layout2->y + layout2->ePadY[PAD_TOP_LEFT] + layout2->iHeight); 1399 } 1400 1401 layout->y = n - iPadY[PAD_TOP_LEFT] - ePadY[PAD_TOP_LEFT]; 1402 layout->useHeight = (s - n); 1403 layout->iHeight = iPadY[PAD_TOP_LEFT] + layout->useHeight + iPadY[PAD_BOTTOM_RIGHT]; 1404 layout->eHeight = ePadY[PAD_TOP_LEFT] + layout->iHeight + ePadY[PAD_BOTTOM_RIGHT]; 1405 } 1406 1407 /* Expand -union elements if needed: vertical */ 1408 for (i = 0; i < eLinkCount; i++) { 1409 struct Layout *layout = &layouts[i]; 1410 int extraHeight; 1411 1412 if (IS_HIDDEN(layout)) 1413 continue; 1414 1415 eLink1 = &eLinks1[i]; 1416 1417 if ((eLink1->onion == NULL) || !(eLink1->flags & ELF_EXPAND_NS)) 1418 continue; 1419 1420 if (drawArgs->height - layout->eHeight <= 0) 1421 continue; 1422 1423 /* External and internal expansion: N */ 1424 extraHeight = layout->y; 1425 if ((extraHeight > 0) && (eLink1->flags & ELF_EXPAND_N)) { 1426 if ((eLink1->flags & ELF_EXPAND_N) == ELF_EXPAND_N) { 1427 int eExtra = extraHeight / 2; 1428 int iExtra = extraHeight - extraHeight / 2; 1429 1430 /* External expansion */ 1431 layout->ePadY[PAD_TOP_LEFT] += eExtra; 1432 layout->y = 0; 1433 layout->eHeight += extraHeight; 1434 1435 /* Internal expansion */ 1436 layout->iPadY[PAD_TOP_LEFT] += iExtra; 1437 layout->iHeight += iExtra; 1438 } 1439 1440 /* External expansion only: N */ 1441 else if (eLink1->flags & ELF_eEXPAND_N) { 1442 layout->ePadY[PAD_TOP_LEFT] += extraHeight; 1443 layout->y = 0; 1444 layout->eHeight += extraHeight; 1445 } 1446 1447 /* Internal expansion only: N */ 1448 else { 1449 layout->iPadY[PAD_TOP_LEFT] += extraHeight; 1450 layout->y = 0; 1451 layout->iHeight += extraHeight; 1452 layout->eHeight += extraHeight; 1453 } 1454 } 1455 1456 /* External and internal expansion: S */ 1457 extraHeight = drawArgs->height - (layout->y + layout->eHeight); 1458 if ((extraHeight > 0) && (eLink1->flags & ELF_EXPAND_S)) { 1459 if ((eLink1->flags & ELF_EXPAND_S) == ELF_EXPAND_S) { 1460 int eExtra = extraHeight / 2; 1461 int iExtra = extraHeight - extraHeight / 2; 1462 1463 /* External expansion */ 1464 layout->ePadY[PAD_BOTTOM_RIGHT] += eExtra; 1465 layout->eHeight += extraHeight; /* all the space */ 1466 1467 /* Internal expansion */ 1468 layout->iPadY[PAD_BOTTOM_RIGHT] += iExtra; 1469 layout->iHeight += iExtra; 1470 } 1471 1472 /* External expansion only: S */ 1473 else if (eLink1->flags & ELF_eEXPAND_S) { 1474 layout->ePadY[PAD_BOTTOM_RIGHT] += extraHeight; 1475 layout->eHeight += extraHeight; 1476 } 1477 1478 /* Internal expansion only */ 1479 else { 1480 layout->iPadY[PAD_BOTTOM_RIGHT] += extraHeight; 1481 layout->iHeight += extraHeight; 1482 layout->eHeight += extraHeight; 1483 } 1484 } 1485 } 1486 1487 /* Add internal padding to display area for -union elements */ 1488 for (i = 0; i < eLinkCount; i++) { 1489 struct Layout *layout = &layouts[i]; 1490 1491 if (IS_HIDDEN(layout)) 1492 continue; 1493 1494 eLink1 = &eLinks1[i]; 1495 1496 if (eLink1->onion == NULL) 1497 continue; 1498 1499 iPadY = layout->iPadY; 1500 1501 layout->useHeight += iPadY[PAD_TOP_LEFT] + iPadY[PAD_BOTTOM_RIGHT]; 1502 iPadY[PAD_TOP_LEFT] = iPadY[PAD_BOTTOM_RIGHT] = 0; 1503 } 1504} 1505 1506/* 1507 *---------------------------------------------------------------------- 1508 * 1509 * Layout_Size -- 1510 * 1511 * Calculate the height and width of a style after all the 1512 * elements have been arranged. 1513 * 1514 * Results: 1515 * The height and width of the style. 1516 * 1517 * Side effects: 1518 * None. 1519 * 1520 *---------------------------------------------------------------------- 1521 */ 1522 1523static void 1524Layout_Size( 1525 int vertical, /* TRUE if elements are arranged from top 1526 * to bottom. */ 1527 int numLayouts, /* Number of layout records. */ 1528 struct Layout layouts[], /* Initialized layout records. */ 1529 int *widthPtr, /* Returned width. */ 1530 int *heightPtr /* Returned height. */ 1531 ) 1532{ 1533 int i, W, N, E, S; 1534 int width = 0, height = 0; 1535 1536 W = 1000000, N = 1000000, E = -1000000, S = -1000000; 1537 1538 for (i = 0; i < numLayouts; i++) { 1539 struct Layout *layout = &layouts[i]; 1540 int w, n, e, s; 1541 int *ePadX, *iPadX, *uPadX, *ePadY, *iPadY, *uPadY; 1542 1543 if (IS_HIDDEN(layout)) 1544 continue; 1545 1546 ePadX = layout->ePadX, iPadX = layout->iPadX, uPadX = layout->uPadX; 1547 ePadY = layout->ePadY, iPadY = layout->iPadY, uPadY = layout->uPadY; 1548 1549 w = layout->x + ePadX[PAD_TOP_LEFT] - MAX(ePadX[PAD_TOP_LEFT], uPadX[PAD_TOP_LEFT]); 1550 n = layout->y + ePadY[PAD_TOP_LEFT] - MAX(ePadY[PAD_TOP_LEFT], uPadY[PAD_TOP_LEFT]); 1551 e = layout->x + layout->eWidth - ePadX[PAD_BOTTOM_RIGHT] + MAX(ePadX[PAD_BOTTOM_RIGHT], uPadX[PAD_BOTTOM_RIGHT]); 1552 s = layout->y + layout->eHeight - ePadY[PAD_BOTTOM_RIGHT] + MAX(ePadY[PAD_BOTTOM_RIGHT], uPadY[PAD_BOTTOM_RIGHT]); 1553 1554 if (vertical) { 1555 N = MIN(N, n); 1556 S = MAX(S, s); 1557 width = MAX(width, e - w); 1558 } else { 1559 W = MIN(W, w); 1560 E = MAX(E, e); 1561 height = MAX(height, s - n); 1562 } 1563 } 1564 1565 if (vertical) 1566 height = MAX(height, S - N); 1567 else 1568 width = MAX(width, E - W); 1569 1570 (*widthPtr) = width; 1571 (*heightPtr) = height; 1572} 1573 1574/* 1575 *---------------------------------------------------------------------- 1576 * 1577 * Style_DoLayoutNeededV -- 1578 * 1579 * Calculate the vertical size and position of each element. 1580 * This is similar to Style_DoLayoutV but without expansion or 1581 * squeezing. Also, the size and position of -union elements 1582 * is not calculated. 1583 * 1584 * Results: 1585 * layouts[] is updated. 1586 * 1587 * Side effects: 1588 * None. 1589 * 1590 *---------------------------------------------------------------------- 1591 */ 1592 1593static void 1594Style_DoLayoutNeededV( 1595 StyleDrawArgs *drawArgs, /* Various args. */ 1596 struct Layout layouts[] /* Array of layout records to be updated, 1597 * one per element. Should be initialized 1598 * by Style_DoLayoutH(). */ 1599 ) 1600{ 1601 IStyle *style = (IStyle *) drawArgs->style; 1602 MStyle *masterStyle = style->master; 1603 MElementLink *eLinks1, *eLink1; 1604 IElementLink *eLinks2, *eLink2; 1605 int *ePadY, *iPadY, *uPadY; 1606 int i; 1607 int y = 0; 1608 1609 eLinks1 = masterStyle->elements; 1610 eLinks2 = style->elements; 1611 1612 /* Layout elements left-to-right, or top-to-bottom */ 1613 for (i = 0; i < masterStyle->numElements; i++) { 1614 struct Layout *layout = &layouts[i]; 1615 1616 if (IS_HIDDEN(layout)) 1617 continue; 1618 1619 eLink1 = &eLinks1[i]; 1620 eLink2 = &eLinks2[i]; 1621 1622 /* The size of a -union element is determined by the elements 1623 * it surrounds */ 1624 if (eLink1->onion != NULL) { 1625 /* I don't need good values because I'm only calculating the 1626 * needed height */ 1627 layout->y = layout->iHeight = layout->eHeight = 0; 1628 continue; 1629 } 1630 1631 /* -detach elements are positioned by themselves */ 1632 if (eLink1->flags & ELF_DETACH) 1633 continue; 1634 1635 ePadY = eLink1->ePadY; 1636 iPadY = eLink1->iPadY; 1637 uPadY = layout->uPadY; 1638 1639 layout->y = y + abs(ePadY[PAD_TOP_LEFT] - MAX(ePadY[PAD_TOP_LEFT], uPadY[PAD_TOP_LEFT])); 1640 layout->iHeight = iPadY[PAD_TOP_LEFT] + layout->useHeight + iPadY[PAD_BOTTOM_RIGHT]; 1641 layout->eHeight = ePadY[PAD_TOP_LEFT] + layout->iHeight + ePadY[PAD_BOTTOM_RIGHT]; 1642 1643 if (masterStyle->vertical) 1644 y = layout->y + layout->eHeight; 1645 } 1646 1647 /* -detach elements */ 1648 for (i = 0; i < masterStyle->numElements; i++) { 1649 struct Layout *layout = &layouts[i]; 1650 1651 if (IS_HIDDEN(layout)) 1652 continue; 1653 1654 eLink1 = &eLinks1[i]; 1655 eLink2 = &eLinks2[i]; 1656 1657 if (!(eLink1->flags & ELF_DETACH) || (eLink1->onion != NULL)) 1658 continue; 1659 1660 ePadY = eLink1->ePadY; 1661 iPadY = eLink1->iPadY; 1662 uPadY = layout->uPadY; 1663 1664 layout->y = abs(ePadY[PAD_TOP_LEFT] - MAX(ePadY[PAD_TOP_LEFT], uPadY[PAD_TOP_LEFT])); 1665 layout->iHeight = iPadY[PAD_TOP_LEFT] + layout->useHeight + iPadY[PAD_BOTTOM_RIGHT]; 1666 layout->eHeight = ePadY[PAD_TOP_LEFT] + layout->iHeight + ePadY[PAD_BOTTOM_RIGHT]; 1667 } 1668} 1669 1670/* 1671 *---------------------------------------------------------------------- 1672 * 1673 * Style_DoLayout -- 1674 * 1675 * Calculate the size and position of each element. 1676 * 1677 * Results: 1678 * layouts[] is updated. 1679 * 1680 * Side effects: 1681 * None. 1682 * 1683 *---------------------------------------------------------------------- 1684 */ 1685 1686/* Arrange all the Elements considering drawArgs.width and maybe drawArgs.height */ 1687static void 1688Style_DoLayout( 1689 StyleDrawArgs *drawArgs, /* Various args. */ 1690 struct Layout layouts[], /* Uninitialized records to be filled in. */ 1691 int neededV, /* TRUE if drawArgs.height should be ignored. */ 1692 char *file, /* debug */ 1693 int line /* debug */ 1694 ) 1695{ 1696 TreeCtrl *tree = drawArgs->tree; 1697 IStyle *style = (IStyle *) drawArgs->style; 1698 MStyle *masterStyle = style->master; 1699 int state = drawArgs->state; 1700 int i; 1701 1702 if (style->neededWidth == -1) 1703 panic("Style_DoLayout(file %s line %d): style.neededWidth == -1", 1704 file, line); 1705#ifdef CACHE_STYLE_STYLE 1706 if (style->minWidth + drawArgs->indent > drawArgs->width) 1707 panic("Style_DoLayout(file %s line %d): style.minWidth + drawArgs->indent %d > drawArgs.width %d", 1708 file, line, style->minWidth + drawArgs->indent, drawArgs->width); 1709#endif 1710 Style_DoLayoutH(drawArgs, layouts); 1711 1712 for (i = 0; i < masterStyle->numElements; i++) { 1713 struct Layout *layout = &layouts[i]; 1714 MElementLink *eLink1 = layout->master; 1715 IElementLink *eLink2 = layout->eLink; 1716 TreeElementArgs args; 1717 1718 if (IS_HIDDEN(layout)) 1719 continue; 1720 1721 /* The size of a -union element is determined by the elements 1722 * it surrounds */ 1723 if (eLink1->onion != NULL) { 1724 layout->useHeight = 0; 1725 continue; 1726 } 1727 1728#ifdef CACHE_ELEM_SIZE 1729 layout->useHeight = eLink2->neededHeight; 1730#else 1731 layout->useHeight = layout->neededHeight; 1732#endif 1733 1734 /* If a Text Element is given less width than it needs (due to 1735 * -squeeze x layout), then it may wrap lines. This means 1736 * the height can vary depending on the width. */ 1737 if (eLink2->elem->typePtr->heightProc == NULL) 1738 continue; 1739 1740 if (eLink1->fixedHeight >= 0) 1741 continue; 1742 1743#ifdef CACHE_ELEM_SIZE 1744 /* Not squeezed */ 1745 if (layout->useWidth >= eLink2->neededWidth) 1746 continue; 1747 1748 /* Already calculated the height at this width */ 1749 if (layout->useWidth == eLink2->layoutWidth) { 1750 layout->useHeight = eLink2->layoutHeight; 1751 continue; 1752 } 1753#if 0 1754 /* */ 1755 if ((eLink2->layoutWidth == -1) && 1756 (layout->useWidth >= eLink2->neededWidth)) 1757 continue; 1758#endif 1759#else 1760 /* Not squeezed */ 1761 if (layout->useWidth >= layout->neededWidth) 1762 continue; 1763#endif 1764 args.tree = tree; 1765 args.state = state; 1766 args.elem = eLink2->elem; 1767 args.height.fixedWidth = layout->useWidth; 1768 (*args.elem->typePtr->heightProc)(&args); 1769 1770 if (eLink1->fixedHeight >= 0) 1771 layout->useHeight = eLink1->fixedHeight; 1772 else if ((eLink1->minHeight >= 0) && 1773 (args.height.height < eLink1->minHeight)) 1774 layout->useHeight = eLink1->minHeight; 1775 else if ((eLink1->maxHeight >= 0) && 1776 (args.height.height > eLink1->maxHeight)) 1777 layout->useHeight = eLink1->maxHeight; 1778 else 1779 layout->useHeight = args.height.height; 1780 1781#ifdef CACHE_ELEM_SIZE 1782 eLink2->layoutWidth = layout->useWidth; 1783 eLink2->layoutHeight = layout->useHeight; 1784#endif 1785 } 1786 1787 if (neededV) { 1788 Style_DoLayoutNeededV(drawArgs, layouts); 1789 } else { 1790 Style_DoLayoutV(drawArgs, layouts); 1791 } 1792} 1793 1794/* 1795 *---------------------------------------------------------------------- 1796 * 1797 * Style_NeededSize -- 1798 * 1799 * Calculate the width and height of a style based only on 1800 * the requested size of each element. 1801 * 1802 * Results: 1803 * The width and height. The minimum width and height is equal to 1804 * the requested width and height minus any squeezing. 1805 * 1806 * Side effects: 1807 * None. 1808 * 1809 *---------------------------------------------------------------------- 1810 */ 1811 1812static void 1813Style_NeededSize( 1814 TreeCtrl *tree, /* Widget info. */ 1815 IStyle *style, /* Style to calculate size of. */ 1816 int state, /* STATE_xxx flags. */ 1817 int *widthPtr, /* Returned width. */ 1818 int *heightPtr, /* Returned height. */ 1819 int *minWidthPtr, /* Returned minimum width. */ 1820 int *minHeightPtr /* Returned minimum height. */ 1821 ) 1822{ 1823 MStyle *masterStyle = style->master; 1824 MElementLink *eLinks1, *eLink1; 1825 IElementLink *eLinks2, *eLink2; 1826 struct Layout staticLayouts[STATIC_SIZE], *layouts = staticLayouts; 1827 int *ePadX, *iPadX, *uPadX, *ePadY, *iPadY, *uPadY; 1828 int i, j; 1829 int x = 0, y = 0; 1830 int squeezeX = 0, squeezeY = 0; 1831 1832 STATIC_ALLOC(layouts, struct Layout, masterStyle->numElements); 1833 1834 eLinks1 = masterStyle->elements; 1835 eLinks2 = style->elements; 1836 1837 for (i = 0; i < masterStyle->numElements; i++) { 1838 struct Layout *layout = &layouts[i]; 1839 1840 eLink1 = &eLinks1[i]; 1841 eLink2 = &eLinks2[i]; 1842 1843 layout->visible = PerStateBoolean_ForState(tree, 1844 &eLink1->visible, state, NULL) != 0; 1845 if (IS_HIDDEN(layout)) 1846 continue; 1847 1848 layout->master = eLink1; 1849 layout->eLink = eLink2; 1850 1851 if (eLink1->onion == NULL) { 1852#ifdef CACHE_ELEM_SIZE 1853 if ((eLink2->neededWidth == -1) || (eLink2->neededHeight == -1)) { 1854 Element_NeededSize(tree, eLink1, eLink2->elem, state, 1855 &eLink2->neededWidth, &eLink2->neededHeight); 1856 eLink2->layoutWidth = -1; 1857 } 1858 layout->useWidth = eLink2->neededWidth; 1859 layout->useHeight = eLink2->neededHeight; 1860#else 1861 Element_NeededSize(tree, eLink1, eLink2->elem, state, 1862 &layout->neededWidth, &layout->neededHeight); 1863 layout->useWidth = layout->neededWidth; 1864#endif 1865 } 1866 1867 /* No -union padding yet */ 1868 layout->uPadX[PAD_TOP_LEFT] = 0; 1869 layout->uPadX[PAD_BOTTOM_RIGHT] = 0; 1870 layout->uPadY[PAD_TOP_LEFT] = 0; 1871 layout->uPadY[PAD_BOTTOM_RIGHT] = 0; 1872 } 1873 1874 /* Figure out the padding around elements surrounded by -union elements */ 1875 for (i = 0; i < masterStyle->numElements; i++) { 1876 struct Layout *layout = &layouts[i]; 1877 int first = -1, last = -1; 1878 1879 if (IS_HIDDEN(layout)) 1880 continue; 1881 1882 eLink1 = &eLinks1[i]; 1883 1884 if (eLink1->onion == NULL) 1885 continue; 1886 1887 for (j = 0; j < eLink1->onionCount; j++) { 1888 struct Layout *layout = &layouts[eLink1->onion[j]]; 1889 1890 if (IS_HIDDEN(layout)) 1891 continue; 1892 1893 /* Remember the first and last visible elements surrounded by 1894 * this -union element. */ 1895 if (first == -1) 1896 first = j; 1897 last = j; 1898 } 1899 1900 /* If there are no visible elements surrounded by this -union 1901 * element, then hide it. */ 1902 if (first == -1) { 1903 layout->visible = 0; 1904 continue; 1905 } 1906 1907 ePadX = eLink1->ePadX; 1908 ePadY = eLink1->ePadY; 1909 iPadX = eLink1->iPadX; 1910 iPadY = eLink1->iPadY; 1911 1912 for (j = 0; j < eLink1->onionCount; j++) { 1913 struct Layout *layout = &layouts[eLink1->onion[j]]; 1914 1915 if (IS_HIDDEN(layout)) 1916 continue; 1917 1918 uPadX = layout->uPadX; 1919 uPadY = layout->uPadY; 1920 1921 if (masterStyle->vertical) { 1922 uPadX[PAD_TOP_LEFT] = MAX(uPadX[PAD_TOP_LEFT], iPadX[PAD_TOP_LEFT] + ePadX[PAD_TOP_LEFT]); 1923 uPadX[PAD_BOTTOM_RIGHT] = MAX(uPadX[PAD_BOTTOM_RIGHT], iPadX[PAD_BOTTOM_RIGHT] + ePadX[PAD_BOTTOM_RIGHT]); 1924 if (j == first) /* topmost */ 1925 uPadY[PAD_TOP_LEFT] = MAX(uPadY[PAD_TOP_LEFT], iPadY[PAD_TOP_LEFT] + ePadY[PAD_TOP_LEFT]); 1926 if (j == last) /* bottommost */ 1927 uPadY[PAD_BOTTOM_RIGHT] = MAX(uPadY[PAD_BOTTOM_RIGHT], iPadY[PAD_BOTTOM_RIGHT] + ePadY[PAD_BOTTOM_RIGHT]); 1928 } else { 1929 if (j == first) /* leftmost */ 1930 uPadX[PAD_TOP_LEFT] = MAX(uPadX[PAD_TOP_LEFT], iPadX[PAD_TOP_LEFT] + ePadX[PAD_TOP_LEFT]); 1931 if (j == last) /* rightmost */ 1932 uPadX[PAD_BOTTOM_RIGHT] = MAX(uPadX[PAD_BOTTOM_RIGHT], iPadX[PAD_BOTTOM_RIGHT] + ePadX[PAD_BOTTOM_RIGHT]); 1933 uPadY[PAD_TOP_LEFT] = MAX(uPadY[PAD_TOP_LEFT], iPadY[PAD_TOP_LEFT] + ePadY[PAD_TOP_LEFT]); 1934 uPadY[PAD_BOTTOM_RIGHT] = MAX(uPadY[PAD_BOTTOM_RIGHT], iPadY[PAD_BOTTOM_RIGHT] + ePadY[PAD_BOTTOM_RIGHT]); 1935 } 1936 } 1937 } 1938 1939 /* Layout elements left-to-right, or top-to-bottom */ 1940 for (i = 0; i < masterStyle->numElements; i++) { 1941 struct Layout *layout = &layouts[i]; 1942 1943 if (IS_HIDDEN(layout)) 1944 continue; 1945 1946 eLink1 = &eLinks1[i]; 1947 eLink2 = &eLinks2[i]; 1948 1949 ePadX = eLink1->ePadX; 1950 ePadY = eLink1->ePadY; 1951 iPadX = eLink1->iPadX; 1952 iPadY = eLink1->iPadY; 1953 uPadX = layout->uPadX; 1954 uPadY = layout->uPadY; 1955 1956 /* The size of a -union element is determined by the elements 1957 * it surrounds */ 1958 if (eLink1->onion != NULL) { 1959 layout->x = layout->y = layout->eWidth = layout->eHeight = 0; 1960 layout->ePadX[PAD_TOP_LEFT] = 0; 1961 layout->ePadX[PAD_BOTTOM_RIGHT] = 0; 1962 layout->ePadY[PAD_TOP_LEFT] = 0; 1963 layout->ePadY[PAD_BOTTOM_RIGHT] = 0; 1964 layout->iPadX[PAD_TOP_LEFT] = 0; 1965 layout->iPadX[PAD_BOTTOM_RIGHT] = 0; 1966 layout->iPadY[PAD_TOP_LEFT] = 0; 1967 layout->iPadY[PAD_BOTTOM_RIGHT] = 0; 1968 continue; 1969 } 1970 1971 if (eLink1->flags & ELF_SQUEEZE_X) { 1972 if ((eLink1->minWidth >= 0) && 1973 (eLink1->minWidth <= layout->useWidth)) { 1974 squeezeX += layout->useWidth - eLink1->minWidth; 1975 } else { 1976 squeezeX += layout->useWidth; 1977 } 1978 } 1979 if (eLink1->flags & ELF_SQUEEZE_Y) { 1980 if ((eLink1->minHeight >= 0) && 1981 (eLink1->minHeight <= layout->useHeight)) { 1982 squeezeY += layout->useHeight - eLink1->minHeight; 1983 } else { 1984 squeezeY += layout->useHeight; 1985 } 1986 } 1987 1988 /* -detach elements are positioned by themselves */ 1989 if (eLink1->flags & ELF_DETACH) 1990 continue; 1991 1992 layout->eLink = eLink2; 1993 layout->x = x + abs(ePadX[PAD_TOP_LEFT] - MAX(ePadX[PAD_TOP_LEFT], uPadX[PAD_TOP_LEFT])); 1994 layout->y = y + abs(ePadY[PAD_TOP_LEFT] - MAX(ePadY[PAD_TOP_LEFT], uPadY[PAD_TOP_LEFT])); 1995 layout->iWidth = iPadX[PAD_TOP_LEFT] + layout->useWidth + iPadX[PAD_BOTTOM_RIGHT]; 1996 layout->iHeight = iPadY[PAD_TOP_LEFT] + layout->useHeight + iPadY[PAD_BOTTOM_RIGHT]; 1997 layout->eWidth = ePadX[PAD_TOP_LEFT] + layout->iWidth + ePadX[PAD_BOTTOM_RIGHT]; 1998 layout->eHeight = ePadY[PAD_TOP_LEFT] + layout->iHeight + ePadY[PAD_BOTTOM_RIGHT]; 1999 2000 for (j = 0; j < 2; j++) { 2001 layout->ePadX[j] = eLink1->ePadX[j]; 2002 layout->ePadY[j] = eLink1->ePadY[j]; 2003 layout->iPadX[j] = eLink1->iPadX[j]; 2004 layout->iPadY[j] = eLink1->iPadY[j]; 2005 } 2006 2007 if (masterStyle->vertical) 2008 y = layout->y + layout->eHeight; 2009 else 2010 x = layout->x + layout->eWidth; 2011 } 2012 2013 /* -detach elements */ 2014 for (i = 0; i < masterStyle->numElements; i++) { 2015 struct Layout *layout = &layouts[i]; 2016 2017 if (IS_HIDDEN(layout)) 2018 continue; 2019 2020 eLink1 = &eLinks1[i]; 2021 eLink2 = &eLinks2[i]; 2022 2023 if (!(eLink1->flags & ELF_DETACH) || (eLink1->onion != NULL)) 2024 continue; 2025 2026 ePadX = eLink1->ePadX; 2027 ePadY = eLink1->ePadY; 2028 iPadX = eLink1->iPadX; 2029 iPadY = eLink1->iPadY; 2030 uPadX = layout->uPadX; 2031 uPadY = layout->uPadY; 2032 2033 layout->eLink = eLink2; 2034 layout->master = eLink1; 2035 layout->x = abs(ePadX[PAD_TOP_LEFT] - MAX(ePadX[PAD_TOP_LEFT], uPadX[PAD_TOP_LEFT])); 2036 layout->y = abs(ePadY[PAD_TOP_LEFT] - MAX(ePadY[PAD_TOP_LEFT], uPadY[PAD_TOP_LEFT])); 2037 layout->iWidth = iPadX[PAD_TOP_LEFT] + layout->useWidth + iPadX[PAD_BOTTOM_RIGHT]; 2038 layout->iHeight = iPadY[PAD_TOP_LEFT] + layout->useHeight + iPadY[PAD_BOTTOM_RIGHT]; 2039 layout->eWidth = ePadX[PAD_TOP_LEFT] + layout->iWidth + ePadX[PAD_BOTTOM_RIGHT]; 2040 layout->eHeight = ePadY[PAD_TOP_LEFT] + layout->iHeight + ePadY[PAD_BOTTOM_RIGHT]; 2041 2042 for (j = 0; j < 2; j++) { 2043 layout->ePadX[j] = eLink1->ePadX[j]; 2044 layout->ePadY[j] = eLink1->ePadY[j]; 2045 layout->iPadX[j] = eLink1->iPadX[j]; 2046 layout->iPadY[j] = eLink1->iPadY[j]; 2047 } 2048 } 2049 2050 Layout_Size(masterStyle->vertical, masterStyle->numElements, layouts, 2051 widthPtr, heightPtr); 2052 2053 *minWidthPtr = *widthPtr - squeezeX; 2054 *minHeightPtr = *heightPtr - squeezeY; 2055 2056 STATIC_FREE(layouts, struct Layout, masterStyle->numElements); 2057} 2058 2059/* 2060 *---------------------------------------------------------------------- 2061 * 2062 * Style_CheckNeededSize -- 2063 * 2064 * If the style's requested size is out-of-date then recalculate 2065 * Style.neededWidth, Style.neededHeight, Style.minWidth, and 2066 * Style.minHeight. 2067 * 2068 * Results: 2069 * None. 2070 * 2071 * Side effects: 2072 * None. 2073 * 2074 *---------------------------------------------------------------------- 2075 */ 2076 2077static void 2078Style_CheckNeededSize( 2079 TreeCtrl *tree, /* Widget info. */ 2080 IStyle *style, /* Style info. */ 2081 int state /* STATE_xxx flags. */ 2082 ) 2083{ 2084 if (style->neededWidth == -1) { 2085 int minWidth, minHeight; 2086 2087 Style_NeededSize(tree, style, state, 2088 &style->neededWidth, &style->neededHeight, &minWidth, &minHeight); 2089#ifdef CACHE_STYLE_SIZE 2090 style->minWidth = minWidth; 2091 style->minHeight = minHeight; 2092 style->layoutWidth = -1; 2093#endif /* CACHE_STYLE_SIZE */ 2094#ifdef TREECTRL_DEBUG 2095 style->neededState = state; 2096#endif 2097 } 2098#ifdef TREECTRL_DEBUG 2099 if (style->neededState != state) 2100 panic("Style_CheckNeededSize: neededState %d != state %d\n", 2101 style->neededState, state); 2102#endif 2103} 2104 2105#ifndef CACHE_STYLE_SIZE 2106 2107static void 2108Style_MinSize( 2109 TreeCtrl *tree, /* Widget info. */ 2110 IStyle *style, /* Style info. */ 2111 int state, /* STATE_xxx flags. */ 2112 int *minWidthPtr, 2113 int *minHeightPtr 2114 ) 2115{ 2116 int i, hasSqueeze = FALSE; 2117 2118 for (i = 0; i < style->master->numElements; i++) { 2119 MElementLink *eLink1 = &style->master->elements[i]; 2120 if ((eLink1->onion == NULL) && 2121 (eLink1->flags & (ELF_SQUEEZE_X | ELF_SQUEEZE_Y))) { 2122 hasSqueeze = TRUE; 2123 break; 2124 } 2125 } 2126 if (hasSqueeze) { 2127 int width, height; 2128 Style_NeededSize(tree, style, state, &width, &height, 2129 minWidthPtr, minHeightPtr); 2130 } else { 2131 *minWidthPtr = style->neededWidth; 2132 *minHeightPtr = style->neededHeight; 2133 } 2134} 2135 2136#endif /* !CACHE_STYLE_SIZE */ 2137 2138/* 2139 *---------------------------------------------------------------------- 2140 * 2141 * TreeStyle_NeededWidth -- 2142 * 2143 * Return the requested width of a style. 2144 * 2145 * Results: 2146 * The requested width. If the requested size is out-of-date 2147 * then it is recalculated. 2148 * 2149 * Side effects: 2150 * None. 2151 * 2152 *---------------------------------------------------------------------- 2153 */ 2154 2155int 2156TreeStyle_NeededWidth( 2157 TreeCtrl *tree, /* Widget info. */ 2158 TreeStyle style_, /* Style token. */ 2159 int state /* STATE_xxx flags. */ 2160 ) 2161{ 2162 IStyle *style = (IStyle *) style_; 2163 2164 Style_CheckNeededSize(tree, style, state); 2165 return style->neededWidth; 2166} 2167 2168/* 2169 *---------------------------------------------------------------------- 2170 * 2171 * TreeStyle_NeededHeight -- 2172 * 2173 * Return the requested height of a style. 2174 * 2175 * Results: 2176 * The requested height. If the requested size is out-of-date 2177 * then it is recalculated. 2178 * 2179 * Side effects: 2180 * None. 2181 * 2182 *---------------------------------------------------------------------- 2183 */ 2184 2185int 2186TreeStyle_NeededHeight( 2187 TreeCtrl *tree, /* Widget info. */ 2188 TreeStyle style_, /* Style token. */ 2189 int state /* STATE_xxx flags. */ 2190 ) 2191{ 2192 IStyle *style = (IStyle *) style_; 2193 2194 Style_CheckNeededSize(tree, style, state); 2195 return style->neededHeight; 2196} 2197 2198/* 2199 *---------------------------------------------------------------------- 2200 * 2201 * TreeStyle_UseHeight -- 2202 * 2203 * Return the height of a style for a given state and width. 2204 * 2205 * Results: 2206 * The height of the style. 2207 * 2208 * Side effects: 2209 * None. 2210 * 2211 *---------------------------------------------------------------------- 2212 */ 2213 2214/* Calculate height of Style considering drawArgs.width */ 2215int 2216TreeStyle_UseHeight( 2217 StyleDrawArgs *drawArgs /* Various args. */ 2218 ) 2219{ 2220 TreeCtrl *tree = drawArgs->tree; 2221 IStyle *style = (IStyle *) drawArgs->style; 2222 MStyle *masterStyle = style->master; 2223 int state = drawArgs->state; 2224 struct Layout staticLayouts[STATIC_SIZE], *layouts = staticLayouts; 2225 int width, height, minWidth; 2226#ifndef CACHE_STYLE_SIZE 2227 int minHeight; 2228#endif 2229 2230 Style_CheckNeededSize(tree, style, state); 2231#ifdef CACHE_STYLE_SIZE 2232 minWidth = style->minWidth; 2233#else 2234 if (drawArgs->width < style->neededWidth + drawArgs->indent) 2235 Style_MinSize(tree, style, state, &minWidth, &minHeight); 2236 else 2237 minWidth = style->neededWidth; 2238#endif 2239 2240 /* 2241 * If we have: 2242 * a) infinite space available, or 2243 * b) more width than the style needs, or 2244 * c) less width than the style needs, but it has no -squeeze x elements 2245 * then return the needed height of the style. This is safe since no 2246 * text elements will be growing vertically when lines wrap. 2247 */ 2248 if ((drawArgs->width == -1) || 2249 (drawArgs->width >= style->neededWidth + drawArgs->indent) || 2250 (style->neededWidth == minWidth)) { 2251 return style->neededHeight; 2252 } 2253 2254 /* We never lay out the style at less than the minimum width */ 2255 if (drawArgs->width < minWidth + drawArgs->indent) 2256 drawArgs->width = minWidth + drawArgs->indent; 2257 2258#ifdef CACHE_STYLE_SIZE 2259 /* We have less space than the style needs, and have already calculated 2260 * the height of the style at this width. (The height may change because 2261 * of text elements wrapping lines). */ 2262 if (drawArgs->width == style->layoutWidth) 2263 return style->layoutHeight; 2264#endif 2265 2266 STATIC_ALLOC(layouts, struct Layout, masterStyle->numElements); 2267 2268 Style_DoLayout(drawArgs, layouts, TRUE, __FILE__, __LINE__); 2269 2270 Layout_Size(style->master->vertical, masterStyle->numElements, layouts, 2271 &width, &height); 2272 2273 STATIC_FREE(layouts, struct Layout, masterStyle->numElements); 2274 2275#ifdef CACHE_STYLE_SIZE 2276 style->layoutWidth = drawArgs->width; 2277 style->layoutHeight = height; 2278#endif 2279 2280 return height; 2281} 2282 2283/* 2284 *---------------------------------------------------------------------- 2285 * 2286 * TreeStyle_Draw -- 2287 * 2288 * Draw all the elements in a style. 2289 * 2290 * Results: 2291 * None. 2292 * 2293 * Side effects: 2294 * Stuff is drawn. 2295 * 2296 *---------------------------------------------------------------------- 2297 */ 2298 2299void TreeStyle_Draw( 2300 StyleDrawArgs *drawArgs /* Various args. */ 2301 ) 2302{ 2303 IStyle *style = (IStyle *) drawArgs->style; 2304 MStyle *masterStyle = style->master; 2305 TreeCtrl *tree = drawArgs->tree; 2306 int *bounds = drawArgs->bounds; 2307 TreeElementArgs args; 2308 int i, x, y, minWidth, minHeight; 2309 struct Layout staticLayouts[STATIC_SIZE], *layouts = staticLayouts; 2310#undef DEBUG_DRAW 2311#ifdef DEBUG_DRAW 2312 int debugDraw = FALSE; 2313#endif 2314 2315 Style_CheckNeededSize(tree, style, drawArgs->state); 2316#ifdef CACHE_STYLE_SIZE 2317 minWidth = style->minWidth; 2318 minHeight = style->minHeight; 2319#else 2320 if ((drawArgs->width < style->neededWidth + drawArgs->indent) || 2321 (drawArgs->height < style->neededHeight)) { 2322 Style_MinSize(tree, style, drawArgs->state, &minWidth, &minHeight); 2323 } else { 2324 minWidth = style->neededWidth; 2325 minHeight = style->neededHeight; 2326 } 2327#endif 2328 2329 /* Get the bounds allowed for drawing (in window coordinates), inside 2330 * the item-column(s) and inside the header/borders. */ 2331 x = drawArgs->x + tree->drawableXOrigin - tree->xOrigin; 2332 y = drawArgs->y + tree->drawableYOrigin - tree->yOrigin; 2333 args.display.bounds[0] = MAX(bounds[0], x); 2334 args.display.bounds[1] = MAX(bounds[1], y); 2335 args.display.bounds[2] = MIN(bounds[2], x + drawArgs->width); 2336 args.display.bounds[3] = MIN(bounds[3], y + drawArgs->height); 2337 2338 /* We never lay out the style at less than the minimum size */ 2339 if (drawArgs->width < minWidth + drawArgs->indent) 2340 drawArgs->width = minWidth + drawArgs->indent; 2341 if (drawArgs->height < minHeight) 2342 drawArgs->height = minHeight; 2343 2344 STATIC_ALLOC(layouts, struct Layout, masterStyle->numElements); 2345 2346 Style_DoLayout(drawArgs, layouts, FALSE, __FILE__, __LINE__); 2347 2348 args.tree = tree; 2349 args.state = drawArgs->state; 2350 args.display.td = drawArgs->td; 2351 args.display.drawable = drawArgs->td.drawable; 2352 2353 for (i = 0; i < masterStyle->numElements; i++) { 2354 struct Layout *layout = &layouts[i]; 2355 2356 if (IS_HIDDEN(layout)) 2357 continue; 2358 2359 /* Don't "draw" window elements. TreeStyle_UpdateWindowPositions() 2360 * does that for us. */ 2361 if (ELEMENT_TYPE_MATCHES(layout->eLink->elem->typePtr, &treeElemTypeWindow)) 2362 continue; 2363 2364 if (PerStateBoolean_ForState(tree, &layout->master->draw, 2365 drawArgs->state, NULL) == 0) 2366 continue; 2367 2368#ifdef DEBUG_DRAW 2369 if (debugDraw && layout->master->onion != NULL) 2370 continue; 2371#endif 2372 2373 if ((layout->useWidth > 0) && (layout->useHeight > 0)) { 2374 args.elem = layout->eLink->elem; 2375 args.display.x = drawArgs->x + layout->x + layout->ePadX[PAD_TOP_LEFT]; 2376 args.display.y = drawArgs->y + layout->y + layout->ePadY[PAD_TOP_LEFT]; 2377 args.display.x += layout->iPadX[PAD_TOP_LEFT]; 2378 args.display.y += layout->iPadY[PAD_TOP_LEFT]; 2379 args.display.width = layout->useWidth; 2380 args.display.height = layout->useHeight; 2381 args.display.sticky = layout->master->flags & ELF_STICKY; 2382#ifdef DEBUG_DRAW 2383 if (debugDraw) { 2384 XColor *color[3]; 2385 GC gc[3]; 2386 2387 if (layout->master->onion != NULL) { 2388 color[0] = Tk_GetColor(tree->interp, tree->tkwin, "blue2"); 2389 gc[0] = Tk_GCForColor(color[0], Tk_WindowId(tree->tkwin)); 2390 color[1] = Tk_GetColor(tree->interp, tree->tkwin, "blue3"); 2391 gc[1] = Tk_GCForColor(color[1], Tk_WindowId(tree->tkwin)); 2392 } else { 2393 color[0] = Tk_GetColor(tree->interp, tree->tkwin, "gray50"); 2394 gc[0] = Tk_GCForColor(color[0], Tk_WindowId(tree->tkwin)); 2395 color[1] = Tk_GetColor(tree->interp, tree->tkwin, "gray60"); 2396 gc[1] = Tk_GCForColor(color[1], Tk_WindowId(tree->tkwin)); 2397 color[2] = Tk_GetColor(tree->interp, tree->tkwin, "gray70"); 2398 gc[2] = Tk_GCForColor(color[2], Tk_WindowId(args.tree->tkwin)); 2399 } 2400 2401 /* external */ 2402 XFillRectangle(tree->display, args.display.drawable, 2403 gc[2], 2404 args.display.x - layout->ePadX[PAD_TOP_LEFT], 2405 args.display.y - layout->ePadY[PAD_TOP_LEFT], 2406 layout->eWidth, layout->eHeight); 2407 /* internal */ 2408 XFillRectangle(tree->display, args.display.drawable, 2409 gc[1], 2410 args.display.x, args.display.y, 2411 args.display.width, args.display.height); 2412 /* needed */ 2413 if (!layout->master->onion && !(layout->master->flags & ELF_DETACH)) 2414 XFillRectangle(tree->display, args.display.drawable, 2415 gc[0], 2416 args.display.x + layout->iPadX[PAD_TOP_LEFT], 2417 args.display.y + layout->iPadY[PAD_TOP_LEFT], 2418 layout->eLink->neededWidth, layout->eLink->neededHeight); 2419 } else 2420#endif /* DEBUG_DRAW */ 2421 (*args.elem->typePtr->displayProc)(&args); 2422 } 2423 } 2424 2425#ifdef DEBUG_DRAW 2426 if (debugDraw) 2427 for (i = 0; i < masterStyle->numElements; i++) { 2428 struct Layout *layout = &layouts[i]; 2429 2430 if (IS_HIDDEN(layout)) 2431 continue; 2432 2433 if (layout->master->onion == NULL) 2434 continue; 2435 if (layout->useWidth > 0 && layout->useHeight > 0) { 2436 args.elem = layout->eLink->elem; 2437 args.display.x = drawArgs->x + layout->x + layout->ePadX[PAD_TOP_LEFT]; 2438 args.display.y = drawArgs->y + layout->y + layout->ePadY[PAD_TOP_LEFT]; 2439 args.display.width = layout->iWidth; 2440 args.display.height = layout->iHeight; 2441 { 2442 XColor *color[3]; 2443 GC gc[3]; 2444 2445 color[0] = Tk_GetColor(tree->interp, tree->tkwin, "blue2"); 2446 gc[0] = Tk_GCForColor(color[0], Tk_WindowId(tree->tkwin)); 2447 color[1] = Tk_GetColor(tree->interp, tree->tkwin, "blue3"); 2448 gc[1] = Tk_GCForColor(color[1], Tk_WindowId(tree->tkwin)); 2449 2450 /* external */ 2451 XDrawRectangle(tree->display, args.display.drawable, 2452 gc[0], 2453 args.display.x - layout->ePadX[PAD_TOP_LEFT], 2454 args.display.y - layout->ePadY[PAD_TOP_LEFT], 2455 layout->eWidth - 1, layout->eHeight - 1); 2456 /* internal */ 2457 XDrawRectangle(tree->display, args.display.drawable, 2458 gc[1], 2459 args.display.x, args.display.y, 2460 args.display.width - 1, args.display.height - 1); 2461 } 2462 } 2463 } 2464#endif /* DEBUG_DRAW */ 2465 2466 STATIC_FREE(layouts, struct Layout, masterStyle->numElements); 2467} 2468 2469/* 2470 *---------------------------------------------------------------------- 2471 * 2472 * TreeStyle_UpdateWindowPositions -- 2473 * 2474 * Call the displayProc on each window element so it can update 2475 * its geometry. This is needed if an item was scrolled and its 2476 * displayProc wasn't otherwise called. 2477 * 2478 * Results: 2479 * None. 2480 * 2481 * Side effects: 2482 * Possible window geometry changes. 2483 * 2484 *---------------------------------------------------------------------- 2485 */ 2486 2487void 2488TreeStyle_UpdateWindowPositions( 2489 StyleDrawArgs *drawArgs /* Various args. */ 2490 ) 2491{ 2492 IStyle *style = (IStyle *) drawArgs->style; 2493 MStyle *masterStyle = style->master; 2494 TreeCtrl *tree = drawArgs->tree; 2495 int *bounds = drawArgs->bounds; 2496 TreeElementArgs args; 2497 int i, x, y, minWidth, minHeight; 2498 struct Layout staticLayouts[STATIC_SIZE], *layouts = staticLayouts; 2499 int numElements = masterStyle->numElements; 2500 2501 /* FIXME: Perhaps remember whether this style has any window 2502 * elements */ 2503 for (i = 0; i < numElements; i++) { 2504 if (ELEMENT_TYPE_MATCHES(masterStyle->elements[i].elem->typePtr, &treeElemTypeWindow)) 2505 break; 2506 } 2507 if (i == numElements) 2508 return; 2509 2510 Style_CheckNeededSize(tree, style, drawArgs->state); 2511#ifdef CACHE_STYLE_SIZE 2512 minWidth = style->minWidth; 2513 minHeight = style->minHeight; 2514#else 2515 if ((drawArgs->width < style->neededWidth + drawArgs->indent) || 2516 (drawArgs->height < style->neededHeight)) { 2517 Style_MinSize(tree, style, drawArgs->state, &minWidth, &minHeight); 2518 } else { 2519 minWidth = style->neededWidth; 2520 minHeight = style->neededHeight; 2521 } 2522#endif 2523 2524 /* Get the bounds allowed for drawing (in window coordinates), inside 2525 * the item-column(s) and inside the header/borders. */ 2526 x = drawArgs->x + tree->drawableXOrigin - tree->xOrigin; 2527 y = drawArgs->y + tree->drawableYOrigin - tree->yOrigin; 2528 args.display.bounds[0] = MAX(bounds[0], x); 2529 args.display.bounds[1] = MAX(bounds[1], y); 2530 args.display.bounds[2] = MIN(bounds[2], x + drawArgs->width); 2531 args.display.bounds[3] = MIN(bounds[3], y + drawArgs->height); 2532 2533 /* We never lay out the style at less than the minimum size */ 2534 if (drawArgs->width < minWidth + drawArgs->indent) 2535 drawArgs->width = minWidth + drawArgs->indent; 2536 if (drawArgs->height < minHeight) 2537 drawArgs->height = minHeight; 2538 2539 STATIC_ALLOC(layouts, struct Layout, numElements); 2540 2541 Style_DoLayout(drawArgs, layouts, FALSE, __FILE__, __LINE__); 2542 2543 args.tree = tree; 2544 args.state = drawArgs->state; 2545 args.display.td = drawArgs->td; 2546 args.display.drawable = drawArgs->td.drawable; 2547 2548 for (i = 0; i < numElements; i++) { 2549 struct Layout *layout = &layouts[i]; 2550 2551 if (IS_HIDDEN(layout)) 2552 continue; 2553 2554 if (!ELEMENT_TYPE_MATCHES(layout->eLink->elem->typePtr, &treeElemTypeWindow)) 2555 continue; 2556 2557 if (PerStateBoolean_ForState(tree, &layout->master->draw, 2558 drawArgs->state, NULL) == 0) 2559 continue; 2560 2561 if ((layout->useWidth > 0) && (layout->useHeight > 0)) { 2562 int requests; 2563 2564 TreeDisplay_GetReadyForTrouble(tree, &requests); 2565 2566 args.elem = layout->eLink->elem; 2567 args.display.x = drawArgs->x + layout->x + layout->ePadX[PAD_TOP_LEFT]; 2568 args.display.y = drawArgs->y + layout->y + layout->ePadY[PAD_TOP_LEFT]; 2569 args.display.x += layout->iPadX[PAD_TOP_LEFT]; 2570 args.display.y += layout->iPadY[PAD_TOP_LEFT]; 2571 args.display.width = layout->useWidth; 2572 args.display.height = layout->useHeight; 2573 args.display.sticky = layout->master->flags & ELF_STICKY; 2574 (*args.elem->typePtr->displayProc)(&args); 2575 2576 /* Updating the position of a window may generate a <Configure> 2577 * or <Map> event on that window. Binding scripts on those 2578 * events could do anything, including deleting items and 2579 * thus the style we are drawing. In other cases (such as when 2580 * using Tile widgets I notice), the Tk_GeomMgr.requestProc 2581 * may get called which calls Tree_ElementChangedItself which 2582 * calls FreeDItemInfo which frees a DItem we are in the middle 2583 * of displaying. So if anything was done that caused a display 2584 * request, then abort abort abort. */ 2585 if (TreeDisplay_WasThereTrouble(tree, requests)) 2586 break; 2587 } 2588 } 2589 2590 STATIC_FREE(layouts, struct Layout, numElements); 2591} 2592 2593/* 2594 *---------------------------------------------------------------------- 2595 * 2596 * TreeStyle_OnScreen -- 2597 * 2598 * Call the onScreenProc (if non-NULL) on each element so it can 2599 * update its visibility when an item's visibility changes. 2600 * 2601 * Results: 2602 * None. 2603 * 2604 * Side effects: 2605 * Possible window visibility changes. 2606 * 2607 *---------------------------------------------------------------------- 2608 */ 2609 2610void 2611TreeStyle_OnScreen( 2612 TreeCtrl *tree, /* Widget info. */ 2613 TreeStyle style_, /* Style token. */ 2614 int onScreen /* Boolean indicating whether the item 2615 * using the style is on screen anymore. */ 2616 ) 2617{ 2618 IStyle *style = (IStyle *) style_; 2619 TreeElementArgs args; 2620 int i; 2621 2622 args.tree = tree; 2623 args.screen.visible = onScreen; 2624 2625 for (i = 0; i < style->master->numElements; i++) { 2626 IElementLink *eLink = &style->elements[i]; 2627 2628 if (eLink->elem->typePtr->onScreenProc == NULL) 2629 continue; 2630 2631 args.elem = eLink->elem; 2632 (*args.elem->typePtr->onScreenProc)(&args); 2633 } 2634} 2635 2636/* 2637 *---------------------------------------------------------------------- 2638 * 2639 * Element_FreeResources -- 2640 * 2641 * Free memory etc associated with an Element. 2642 * 2643 * Results: 2644 * None. 2645 * 2646 * Side effects: 2647 * Memory is deallocated. 2648 * 2649 *---------------------------------------------------------------------- 2650 */ 2651 2652static void 2653Element_FreeResources( 2654 TreeCtrl *tree, /* Widget info. */ 2655 TreeElement elem /* Record to free. */ 2656 ) 2657{ 2658 TreeElementType *typePtr = elem->typePtr; 2659 TreeElementArgs args; 2660 Tcl_HashEntry *hPtr; 2661 2662 if (elem->master == NULL) { 2663 hPtr = Tcl_FindHashEntry(&tree->elementHash, elem->name); 2664 Tcl_DeleteHashEntry(hPtr); 2665 } 2666 args.tree = tree; 2667 args.elem = elem; 2668 (*typePtr->deleteProc)(&args); 2669 Tk_FreeConfigOptions((char *) elem, 2670 typePtr->optionTable, 2671 tree->tkwin); 2672 DynamicOption_Free(tree, elem->options, typePtr->optionSpecs); 2673#ifdef ALLOC_HAX 2674 TreeAlloc_Free(tree->allocData, typePtr->name, (char *) elem, typePtr->size); 2675#else 2676 WFREE(elem, TreeElement_); 2677#endif 2678} 2679 2680/* 2681 *---------------------------------------------------------------------- 2682 * 2683 * MElementLink_Init -- 2684 * 2685 * Initialize (don't allocate) a MElementLink. 2686 * 2687 * Results: 2688 * eLink is filled with default values. 2689 * 2690 * Side effects: 2691 * None. 2692 * 2693 *---------------------------------------------------------------------- 2694 */ 2695 2696static MElementLink * 2697MElementLink_Init( 2698 MElementLink *eLink, /* Existing record to initialize. */ 2699 TreeElement elem /* Existing element to point to. */ 2700 ) 2701{ 2702 memset(eLink, '\0', sizeof(MElementLink)); 2703 eLink->elem = elem; 2704 eLink->flags |= ELF_INDENT; 2705 eLink->minWidth = eLink->fixedWidth = eLink->maxWidth = -1; 2706 eLink->minHeight = eLink->fixedHeight = eLink->maxHeight = -1; 2707 eLink->flags |= ELF_STICKY; 2708 return eLink; 2709} 2710 2711/* 2712 *---------------------------------------------------------------------- 2713 * 2714 * MElementLink_FreeResources -- 2715 * 2716 * Free memory etc associated with an MElementLink. 2717 * 2718 * Results: 2719 * None. 2720 * 2721 * Side effects: 2722 * Memory is deallocated. 2723 * 2724 *---------------------------------------------------------------------- 2725 */ 2726 2727static void 2728MElementLink_FreeResources( 2729 TreeCtrl *tree, /* Widget info. */ 2730 MElementLink *eLink /* Record to free. */ 2731 ) 2732{ 2733 if (eLink->onion != NULL) 2734 WCFREE(eLink->onion, int, eLink->onionCount); 2735 PerStateInfo_Free(tree, &pstBoolean, &eLink->draw); 2736 if (eLink->draw.obj != NULL) { 2737 Tcl_DecrRefCount(eLink->draw.obj); 2738 } 2739 PerStateInfo_Free(tree, &pstBoolean, &eLink->visible); 2740 if (eLink->visible.obj != NULL) { 2741 Tcl_DecrRefCount(eLink->visible.obj); 2742 } 2743} 2744 2745/* 2746 *---------------------------------------------------------------------- 2747 * 2748 * IElementLink_FreeResources -- 2749 * 2750 * Free memory etc associated with an ElementLink. 2751 * 2752 * Results: 2753 * None. 2754 * 2755 * Side effects: 2756 * Memory is deallocated. 2757 * 2758 *---------------------------------------------------------------------- 2759 */ 2760 2761static void 2762IElementLink_FreeResources( 2763 TreeCtrl *tree, /* Widget info. */ 2764 IElementLink *eLink /* Record to free. */ 2765 ) 2766{ 2767 if (eLink->elem->master != NULL) 2768 Element_FreeResources(tree, eLink->elem); 2769} 2770 2771/* 2772 *---------------------------------------------------------------------- 2773 * 2774 * MStyle_FreeResources -- 2775 * 2776 * Free memory etc associated with a Style. 2777 * 2778 * Results: 2779 * None. 2780 * 2781 * Side effects: 2782 * Memory is deallocated. 2783 * 2784 *---------------------------------------------------------------------- 2785 */ 2786 2787static void 2788MStyle_FreeResources( 2789 TreeCtrl *tree, /* Widget info. */ 2790 MStyle *style /* Style to free. */ 2791 ) 2792{ 2793 Tcl_HashEntry *hPtr; 2794 int i; 2795 2796 hPtr = Tcl_FindHashEntry(&tree->styleHash, style->name); 2797 Tcl_DeleteHashEntry(hPtr); 2798 2799 if (style->numElements > 0) { 2800 for (i = 0; i < style->numElements; i++) 2801 MElementLink_FreeResources(tree, &style->elements[i]); 2802#ifdef ALLOC_HAX 2803 TreeAlloc_CFree(tree->allocData, MElementLinkUid, (char *) style->elements, 2804 sizeof(MElementLink), style->numElements, ELEMENT_LINK_ROUND); 2805#else 2806 WCFREE(style->elements, MElementLink, style->numElements); 2807#endif 2808 } 2809#ifdef ALLOC_HAX 2810 TreeAlloc_Free(tree->allocData, MStyleUid, (char *) style, sizeof(MStyle)); 2811#else 2812 WFREE(style, MStyle); 2813#endif 2814} 2815 2816/* 2817 *---------------------------------------------------------------------- 2818 * 2819 * IStyle_FreeResources -- 2820 * 2821 * Free memory etc associated with a Style. 2822 * 2823 * Results: 2824 * None. 2825 * 2826 * Side effects: 2827 * Memory is deallocated. 2828 * 2829 *---------------------------------------------------------------------- 2830 */ 2831 2832static void 2833IStyle_FreeResources( 2834 TreeCtrl *tree, /* Widget info. */ 2835 IStyle *style /* Style to free. */ 2836 ) 2837{ 2838 MStyle *masterStyle = style->master; 2839 int i; 2840 2841 if (masterStyle->numElements > 0) { 2842 for (i = 0; i < masterStyle->numElements; i++) 2843 IElementLink_FreeResources(tree, &style->elements[i]); 2844#ifdef ALLOC_HAX 2845 TreeAlloc_CFree(tree->allocData, IElementLinkUid, 2846 (char *) style->elements, sizeof(IElementLink), 2847 masterStyle->numElements, ELEMENT_LINK_ROUND); 2848#else 2849 WCFREE(style->elements, IElementLink, masterStyle->numElements); 2850#endif 2851 } 2852#ifdef ALLOC_HAX 2853 TreeAlloc_Free(tree->allocData, IStyleUid, (char *) style, sizeof(IStyle)); 2854#else 2855 WFREE(style, IStyle); 2856#endif 2857} 2858/* 2859 *---------------------------------------------------------------------- 2860 * 2861 * TreeStyle_FreeResources -- 2862 * 2863 * Free memory etc associated with a Style. 2864 * 2865 * Results: 2866 * None. 2867 * 2868 * Side effects: 2869 * Memory is deallocated. 2870 * 2871 *---------------------------------------------------------------------- 2872 */ 2873 2874void 2875TreeStyle_FreeResources( 2876 TreeCtrl *tree, /* Widget info. */ 2877 TreeStyle style_ /* Token of style to free. */ 2878 ) 2879{ 2880 MStyle *masterStyle = (MStyle *) style_; 2881 IStyle *style = (IStyle *) style_; 2882 2883 if (style->master == NULL) 2884 MStyle_FreeResources(tree, masterStyle); 2885 else 2886 IStyle_FreeResources(tree, style); 2887} 2888 2889/* 2890 *---------------------------------------------------------------------- 2891 * 2892 * MStyle_FindElem -- 2893 * 2894 * Find an ElementLink in a style. 2895 * 2896 * Results: 2897 * If found, a pointer to the ElementLink and index in the 2898 * style's array of ElementLinks is returned; otherwise NULL 2899 * is returned. 2900 * 2901 * Side effects: 2902 * World peace. 2903 * 2904 *---------------------------------------------------------------------- 2905 */ 2906 2907static MElementLink * 2908MStyle_FindElem( 2909 TreeCtrl *tree, /* Widget info. */ 2910 MStyle *style, /* Style to search. */ 2911 TreeElement master, /* Master element to find. */ 2912 int *index /* Returned index, may be NULL. */ 2913 ) 2914{ 2915 int i; 2916 2917 for (i = 0; i < style->numElements; i++) { 2918 MElementLink *eLink = &style->elements[i]; 2919 if (eLink->elem->name == master->name) { 2920 if (index != NULL) (*index) = i; 2921 return eLink; 2922 } 2923 } 2924 return NULL; 2925} 2926 2927/* 2928 *---------------------------------------------------------------------- 2929 * 2930 * IStyle_FindElem -- 2931 * 2932 * Find an ElementLink in a style. 2933 * 2934 * Results: 2935 * If found, a pointer to the ElementLink and index in the 2936 * style's array of ElementLinks is returned; otherwise NULL 2937 * is returned. 2938 * 2939 * Side effects: 2940 * World peace. 2941 * 2942 *---------------------------------------------------------------------- 2943 */ 2944 2945static IElementLink * 2946IStyle_FindElem( 2947 TreeCtrl *tree, /* Widget info. */ 2948 IStyle *style, /* Style to search. */ 2949 TreeElement master, /* Master element to find. */ 2950 int *index /* Returned index, may be NULL. */ 2951 ) 2952{ 2953 MStyle *masterStyle = style->master; 2954 int i; 2955 2956 for (i = 0; i < masterStyle->numElements; i++) { 2957 IElementLink *eLink = &style->elements[i]; 2958 if (eLink->elem->name == master->name) { 2959 if (index != NULL) (*index) = i; 2960 return eLink; 2961 } 2962 } 2963 return NULL; 2964} 2965 2966/* 2967 *---------------------------------------------------------------------- 2968 * 2969 * TreeStyle_FindElement -- 2970 * 2971 * Find an ElementLink in a style. 2972 * 2973 * Results: 2974 * If found, the index in the style's array of ElementLinks is 2975 * returned with TCL_OK. Otherwise TCL_ERROR is returned and an 2976 * error message is placed in the interpreter result. 2977 * 2978 * Side effects: 2979 * None. 2980 * 2981 *---------------------------------------------------------------------- 2982 */ 2983 2984int 2985TreeStyle_FindElement( 2986 TreeCtrl *tree, /* Widget info. */ 2987 TreeStyle style_, /* Token of style to search. */ 2988 TreeElement elem, /* Master element to find. */ 2989 int *index /* Returned index, may be NULL. */ 2990 ) 2991{ 2992 MStyle *masterStyle = (MStyle *) style_; 2993 IStyle *style = (IStyle *) style_; 2994 2995 if (((style->master == NULL) && 2996 (MStyle_FindElem(tree, masterStyle, elem, index) == NULL)) || 2997 ((style->master != NULL) && 2998 (IStyle_FindElem(tree, style, elem, index) == NULL))) { 2999 FormatResult(tree->interp, "style %s does not use element %s", 3000 style->master ? style->master->name : masterStyle->name, 3001 elem->name); 3002 return TCL_ERROR; 3003 } 3004 return TCL_OK; 3005} 3006 3007/* 3008 *---------------------------------------------------------------------- 3009 * 3010 * Element_CreateAndConfig -- 3011 * 3012 * Allocate and initialize a new Element (master or instance). 3013 * 3014 * Results: 3015 * An Element is allocated, its createProc is called, default 3016 * configuration options are set, then the configProc and changeProc 3017 * are called to handle any given configurations options. If an 3018 * error occurs NULL is returned. 3019 * 3020 * Side effects: 3021 * Memory is allocated. 3022 * 3023 *---------------------------------------------------------------------- 3024 */ 3025 3026static TreeElement 3027Element_CreateAndConfig( 3028 TreeCtrl *tree, /* Widget info. */ 3029 TreeItem item, /* Item containing the element. Should 3030 * be NULL for a master element. */ 3031 TreeItemColumn column, /* Item-column containing the element. 3032 * Should be NULL for a master element. */ 3033 TreeElement masterElem, /* Master element if creating an instance. */ 3034 TreeElementType *type, /* Element type. Should be NULL when 3035 * creating an instance. */ 3036 CONST char *name, /* Name of master element, NULL for an 3037 * instance. */ 3038 int objc, /* Array of intialial configuration. */ 3039 Tcl_Obj *CONST objv[] /* options. */ 3040 ) 3041{ 3042 TreeElement elem; 3043 TreeElementArgs args; 3044 3045 if (masterElem != NULL) { 3046 type = masterElem->typePtr; 3047 name = masterElem->name; 3048 } 3049 3050#ifdef ALLOC_HAX 3051 elem = (TreeElement) TreeAlloc_Alloc(tree->allocData, type->name, 3052 type->size); 3053#else 3054 elem = (TreeElement) ckalloc(type->size); 3055#endif 3056 memset(elem, '\0', type->size); 3057 elem->name = Tk_GetUid(name); 3058 elem->typePtr = type; 3059 elem->master = masterElem; 3060 3061 args.tree = tree; 3062 args.elem = elem; 3063 args.create.item = item; 3064 args.create.column = column; 3065 if ((*type->createProc)(&args) != TCL_OK) { 3066#ifdef ALLOC_HAX 3067 TreeAlloc_Free(tree->allocData, type->name, (char *) elem, type->size); 3068#else 3069 WFREE(elem, TreeElement_); 3070#endif 3071 return NULL; 3072 } 3073 3074 if (Tk_InitOptions(tree->interp, (char *) elem, 3075 type->optionTable, tree->tkwin) != TCL_OK) { 3076#ifdef ALLOC_HAX 3077 TreeAlloc_Free(tree->allocData, type->name, (char *) elem, type->size); 3078#else 3079 WFREE(elem, TreeElement_); 3080#endif 3081 return NULL; 3082 } 3083 args.config.objc = objc; 3084 args.config.objv = objv; 3085 args.config.flagSelf = 0; 3086 args.config.item = item; 3087 args.config.column = column; 3088 if ((*type->configProc)(&args) != TCL_OK) { 3089 (*type->deleteProc)(&args); 3090 Tk_FreeConfigOptions((char *) elem, 3091 type->optionTable, 3092 tree->tkwin); 3093 DynamicOption_Free(tree, elem->options, type->optionSpecs); 3094#ifdef ALLOC_HAX 3095 TreeAlloc_Free(tree->allocData, type->name, (char *) elem, type->size); 3096#else 3097 WFREE(elem, TreeElement_); 3098#endif 3099 return NULL; 3100 } 3101 3102 args.change.flagSelf = args.config.flagSelf; 3103 args.change.flagTree = 0; 3104 args.change.flagMaster = 0; 3105 (*type->changeProc)(&args); 3106 3107 return elem; 3108} 3109 3110/* 3111 *---------------------------------------------------------------------- 3112 * 3113 * Style_CreateElem -- 3114 * 3115 * Allocate and initialize a new instance Element in a IStyle 3116 * (if it doesn't already exist) and return its associated 3117 * IElementLink. 3118 * 3119 * Results: 3120 * If the style already has a matching instance element, then a 3121 * pointer to an existing IElementLink is returned. 3122 * If the style does not already have a matching instance element, 3123 * then a new one is created and a pointer to an existing 3124 * IElementLink is returned. 3125 * If an error occurs creating the new element the result is 3126 * NULL. 3127 * 3128 * Side effects: 3129 * Memory is allocated. 3130 * 3131 *---------------------------------------------------------------------- 3132 */ 3133 3134static IElementLink * 3135Style_CreateElem( 3136 TreeCtrl *tree, /* Widget info. */ 3137 TreeItem item, /* Item containing the element. */ 3138 TreeItemColumn column, /* Item-column containing the element. */ 3139 IStyle *style, /* Style to search/add the element to. */ 3140 TreeElement masterElem, /* Element to find or create and instance of. */ 3141 int *isNew) /* If non-NULL, set to TRUE if a new instance 3142 * element was created. */ 3143{ 3144 MStyle *masterStyle = style->master; 3145 IElementLink *eLink = NULL; 3146 TreeElement elem; 3147 int i; 3148 3149 if (masterElem->master != NULL) 3150 panic("Style_CreateElem called with instance Element"); 3151 3152 if (isNew != NULL) (*isNew) = FALSE; 3153 3154 for (i = 0; i < masterStyle->numElements; i++) { 3155 eLink = &style->elements[i]; 3156 if (eLink->elem == masterElem) { 3157 /* Allocate instance Element here */ 3158 break; 3159 } 3160 3161 /* Instance Style already has instance Element */ 3162 if (eLink->elem->name == masterElem->name) 3163 return eLink; 3164 } 3165 3166 /* Error: Element isn't in the master Style */ 3167 if (i == masterStyle->numElements) 3168 return NULL; 3169 3170 elem = Element_CreateAndConfig(tree, item, column, masterElem, NULL, NULL, 0, NULL); 3171 if (elem == NULL) 3172 return NULL; 3173 3174 eLink->elem = elem; 3175 if (isNew != NULL) (*isNew) = TRUE; 3176 return eLink; 3177} 3178 3179/* 3180 *---------------------------------------------------------------------- 3181 * 3182 * TreeStyle_NewInstance -- 3183 * 3184 * Create and initialize a new instance of a master style. 3185 * 3186 * Results: 3187 * A new instance Style. The new array of ElementLinks is 3188 * initialized to contain pointers to master elements; instance 3189 * elements are created the first time they are configured. 3190 * 3191 * Side effects: 3192 * Memory is allocated. 3193 * 3194 *---------------------------------------------------------------------- 3195 */ 3196 3197TreeStyle 3198TreeStyle_NewInstance( 3199 TreeCtrl *tree, /* Widget info. */ 3200 TreeStyle style_ /* Master style to create instance of. */ 3201 ) 3202{ 3203 MStyle *style = (MStyle *) style_; 3204 IStyle *copy; 3205 IElementLink *eLink; 3206 int i; 3207 3208#ifdef ALLOC_HAX 3209 copy = (IStyle *) TreeAlloc_Alloc(tree->allocData, IStyleUid, sizeof(IStyle)); 3210#else 3211 copy = (IStyle *) ckalloc(sizeof(IStyle)); 3212#endif 3213 memset(copy, '\0', sizeof(IStyle)); 3214 copy->master = style; 3215 copy->neededWidth = -1; 3216 copy->neededHeight = -1; 3217 if (style->numElements > 0) { 3218#ifdef ALLOC_HAX 3219 copy->elements = (IElementLink *) TreeAlloc_CAlloc(tree->allocData, 3220 IElementLinkUid, sizeof(IElementLink), style->numElements, 3221 ELEMENT_LINK_ROUND); 3222#else 3223 copy->elements = (IElementLink *) ckalloc(sizeof(IElementLink) * 3224 style->numElements); 3225#endif 3226 memset(copy->elements, '\0', sizeof(IElementLink) * style->numElements); 3227 for (i = 0; i < style->numElements; i++) { 3228 eLink = ©->elements[i]; 3229 eLink->elem = style->elements[i].elem; 3230#ifdef CACHE_ELEM_SIZE 3231 eLink->neededWidth = -1; 3232 eLink->neededHeight = -1; 3233#endif 3234 } 3235 } 3236 3237 return (TreeStyle) copy; 3238} 3239 3240/* 3241 *---------------------------------------------------------------------- 3242 * 3243 * Element_FromObj -- 3244 * 3245 * Convert a Tcl_Obj to a master element. 3246 * 3247 * Results: 3248 * A standard Tcl result. 3249 * 3250 * Side effects: 3251 * None. 3252 * 3253 *---------------------------------------------------------------------- 3254 */ 3255 3256static int 3257Element_FromObj( 3258 TreeCtrl *tree, /* Widget info. */ 3259 Tcl_Obj *obj, /* Object to convert from. */ 3260 TreeElement *elemPtr /* Returned record. */ 3261 ) 3262{ 3263 char *name; 3264 Tcl_HashEntry *hPtr; 3265 3266 name = Tcl_GetString(obj); 3267 hPtr = Tcl_FindHashEntry(&tree->elementHash, name); 3268 if (hPtr == NULL) { 3269 Tcl_AppendResult(tree->interp, "element \"", name, "\" doesn't exist", 3270 NULL); 3271 return TCL_ERROR; 3272 } 3273 (*elemPtr) = (TreeElement) Tcl_GetHashValue(hPtr); 3274 return TCL_OK; 3275} 3276 3277/* 3278 *---------------------------------------------------------------------- 3279 * 3280 * TreeElement_FromObj -- 3281 * 3282 * Convert a Tcl_Obj to a master element. 3283 * 3284 * Results: 3285 * A standard Tcl result. 3286 * 3287 * Side effects: 3288 * None. 3289 * 3290 *---------------------------------------------------------------------- 3291 */ 3292 3293int 3294TreeElement_FromObj( 3295 TreeCtrl *tree, /* Widget info. */ 3296 Tcl_Obj *obj, /* Object to convert from. */ 3297 TreeElement *elemPtr /* Returned master element token. */ 3298 ) 3299{ 3300 return Element_FromObj(tree, obj, elemPtr); 3301} 3302 3303 3304/* 3305 *---------------------------------------------------------------------- 3306 * 3307 * TreeElement_IsType -- 3308 * 3309 * Determine if an element is of a certain type. 3310 * 3311 * Results: 3312 * TRUE if the type matches, otherwise FALSE. 3313 * 3314 * Side effects: 3315 * None. 3316 * 3317 *---------------------------------------------------------------------- 3318 */ 3319 3320int 3321TreeElement_IsType( 3322 TreeCtrl *tree, /* Widget info. */ 3323 TreeElement elem, /* Element to check. */ 3324 CONST char *type /* NULL-terminated element type name. */ 3325 ) 3326{ 3327 return strcmp(elem->typePtr->name, type) == 0; 3328} 3329 3330/* 3331 *---------------------------------------------------------------------- 3332 * 3333 * TreeStyle_FromObj -- 3334 * 3335 * Convert a Tcl_Obj to a master style. 3336 * 3337 * Results: 3338 * A standard Tcl result. 3339 * 3340 * Side effects: 3341 * None. 3342 * 3343 *---------------------------------------------------------------------- 3344 */ 3345 3346int 3347TreeStyle_FromObj( 3348 TreeCtrl *tree, /* Widget info. */ 3349 Tcl_Obj *obj, /* Object to convert from. */ 3350 TreeStyle *stylePtr) /* Returned master style token. */ 3351{ 3352 char *name; 3353 Tcl_HashEntry *hPtr; 3354 3355 name = Tcl_GetString(obj); 3356 hPtr = Tcl_FindHashEntry(&tree->styleHash, name); 3357 if (hPtr == NULL) { 3358 Tcl_AppendResult(tree->interp, "style \"", name, "\" doesn't exist", 3359 NULL); 3360 return TCL_ERROR; 3361 } 3362 (*stylePtr) = (TreeStyle) Tcl_GetHashValue(hPtr); 3363 return TCL_OK; 3364} 3365 3366/* 3367 *---------------------------------------------------------------------- 3368 * 3369 * Element_ToObj -- 3370 * 3371 * Create a new Tcl_Obj representing an element. 3372 * 3373 * Results: 3374 * A Tcl_Obj. 3375 * 3376 * Side effects: 3377 * Memory is allocated. 3378 * 3379 *---------------------------------------------------------------------- 3380 */ 3381 3382static Tcl_Obj * 3383Element_ToObj( 3384 TreeElement elem /* Element to create Tcl_Obj from. */ 3385 ) 3386{ 3387 return Tcl_NewStringObj(elem->name, -1); 3388} 3389 3390/* 3391 *---------------------------------------------------------------------- 3392 * 3393 * TreeStyle_ToObj -- 3394 * 3395 * Create a new Tcl_Obj representing a style. 3396 * 3397 * Results: 3398 * A Tcl_Obj. 3399 * 3400 * Side effects: 3401 * Memory is allocated. 3402 * 3403 *---------------------------------------------------------------------- 3404 */ 3405 3406Tcl_Obj * 3407TreeStyle_ToObj( 3408 TreeStyle style_ /* Style token to create Tcl_Obj from. */ 3409 ) 3410{ 3411 MStyle *masterStyle = (MStyle *) style_; 3412 IStyle *style = (IStyle *) style_; 3413 3414 if (style->master != NULL) 3415 masterStyle = style->master; 3416 return Tcl_NewStringObj(masterStyle->name, -1); 3417} 3418 3419/* 3420 *---------------------------------------------------------------------- 3421 * 3422 * Style_Changed -- 3423 * 3424 * Called when a master style is configured or the layout of one 3425 * of its elements changes. 3426 * 3427 * Results: 3428 * For each item-column using an instance of the given master 3429 * style, size and display info is marked out-of-date. 3430 * 3431 * Side effects: 3432 * Display changes. 3433 * 3434 *---------------------------------------------------------------------- 3435 */ 3436 3437static void 3438Style_Changed( 3439 TreeCtrl *tree, /* Widget info. */ 3440 MStyle *masterStyle /* Style that changed. */ 3441 ) 3442{ 3443 TreeItem item; 3444 TreeItemColumn column; 3445 TreeColumn treeColumn; 3446 Tcl_HashEntry *hPtr; 3447 Tcl_HashSearch search; 3448 int columnIndex, layout; 3449 int updateDInfo = FALSE; 3450 IStyle *style; 3451 3452 hPtr = Tcl_FirstHashEntry(&tree->itemHash, &search); 3453 while (hPtr != NULL) { 3454 item = (TreeItem) Tcl_GetHashValue(hPtr); 3455 treeColumn = tree->columns; 3456 column = TreeItem_GetFirstColumn(tree, item); 3457 columnIndex = 0; 3458 layout = FALSE; 3459 while (column != NULL) { 3460 style = (IStyle *) TreeItemColumn_GetStyle(tree, column); 3461 if ((style != NULL) && (style->master == masterStyle)) { 3462#ifdef CACHE_ELEM_SIZE 3463 int i; 3464 for (i = 0; i < masterStyle->numElements; i++) { 3465 IElementLink *eLink = &style->elements[i]; 3466 /* This is needed if the -width/-height layout options change */ 3467 eLink->neededWidth = eLink->neededHeight = -1; 3468 } 3469#endif 3470 style->neededWidth = style->neededHeight = -1; 3471 Tree_InvalidateColumnWidth(tree, treeColumn); 3472 TreeItemColumn_InvalidateSize(tree, column); 3473 layout = TRUE; 3474 } 3475 columnIndex++; 3476 column = TreeItemColumn_GetNext(tree, column); 3477 treeColumn = TreeColumn_Next(treeColumn); 3478 } 3479 if (layout) { 3480 TreeItem_InvalidateHeight(tree, item); 3481 Tree_FreeItemDInfo(tree, item, NULL); 3482 updateDInfo = TRUE; 3483 } 3484 hPtr = Tcl_NextHashEntry(&search); 3485 } 3486 if (updateDInfo) 3487 Tree_DInfoChanged(tree, DINFO_REDO_RANGES); 3488} 3489 3490/* 3491 *---------------------------------------------------------------------- 3492 * 3493 * MStyle_ChangeElementsAux -- 3494 * 3495 * Update the list of elements used by a style. Elements 3496 * may be inserted or deleted. 3497 * 3498 * Results: 3499 * The list of elements in the style is updated. 3500 * 3501 * Side effects: 3502 * Memory may be allocated/deallocated. 3503 * 3504 *---------------------------------------------------------------------- 3505 */ 3506 3507static void 3508MStyle_ChangeElementsAux( 3509 TreeCtrl *tree, /* Widget info. */ 3510 MStyle *style, /* Master style to be updated. */ 3511 int count, /* The number of elements in the style after 3512 * this routine finishes. */ 3513 TreeElement *elemList, /* List of master elements the style uses. */ 3514 int *map /* Array of indexes into the list of elements 3515 * currently used by the style. */ 3516 ) 3517{ 3518 MElementLink *eLink, *eLinks = NULL; 3519 int i, staticKeep[STATIC_SIZE], *keep = staticKeep; 3520 3521 STATIC_ALLOC(keep, int, style->numElements); 3522 3523 if (count > 0) { 3524#ifdef ALLOC_HAX 3525 eLinks = (MElementLink *) TreeAlloc_CAlloc(tree->allocData, 3526 MElementLinkUid, sizeof(MElementLink), count, 3527 ELEMENT_LINK_ROUND); 3528#else 3529 eLinks = (MElementLink *) ckalloc(sizeof(MElementLink) * count); 3530#endif 3531 } 3532 3533 /* Assume we are discarding all the old ElementLinks */ 3534 for (i = 0; i < style->numElements; i++) 3535 keep[i] = 0; 3536 3537 for (i = 0; i < count; i++) { 3538 if (map[i] != -1) { 3539 eLinks[i] = style->elements[map[i]]; 3540 keep[map[i]] = 1; 3541 } else { 3542 eLink = MElementLink_Init(&eLinks[i], elemList[i]); 3543 } 3544 } 3545 3546 if (style->numElements > 0) { 3547 /* Free unused ElementLinks */ 3548 for (i = 0; i < style->numElements; i++) { 3549 if (!keep[i]) { 3550 MElementLink_FreeResources(tree, &style->elements[i]); 3551 } 3552 } 3553#ifdef ALLOC_HAX 3554 TreeAlloc_CFree(tree->allocData, MElementLinkUid, 3555 (char *) style->elements, sizeof(MElementLink), 3556 style->numElements, ELEMENT_LINK_ROUND); 3557#else 3558 WCFREE(style->elements, MElementLink, style->numElements); 3559#endif 3560 } 3561 3562 STATIC_FREE(keep, int, style->numElements); 3563 3564 style->elements = eLinks; 3565 style->numElements = count; 3566} 3567 3568/* 3569 *---------------------------------------------------------------------- 3570 * 3571 * IStyle_ChangeElementsAux -- 3572 * 3573 * Update the list of elements used by a style. Elements 3574 * may be inserted or deleted. 3575 * 3576 * Results: 3577 * The list of elements in the style is updated. 3578 * 3579 * Side effects: 3580 * Memory may be allocated/deallocated. 3581 * 3582 *---------------------------------------------------------------------- 3583 */ 3584 3585static void 3586IStyle_ChangeElementsAux( 3587 TreeCtrl *tree, /* Widget info. */ 3588 IStyle *style, /* Instance style to be updated. */ 3589 int oldCount, /* The previous number of elements. */ 3590 int count, /* The number of elements in the style after 3591 * this routine finishes. */ 3592 TreeElement *elemList, /* List of master elements the style uses. */ 3593 int *map /* Array of indexes into the list of elements 3594 * currently used by the style. */ 3595 ) 3596{ 3597 IElementLink *eLink, *eLinks = NULL; 3598 int i, staticKeep[STATIC_SIZE], *keep = staticKeep; 3599 3600 STATIC_ALLOC(keep, int, oldCount); 3601 3602 if (count > 0) { 3603#ifdef ALLOC_HAX 3604 eLinks = (IElementLink *) TreeAlloc_CAlloc(tree->allocData, 3605 IElementLinkUid, sizeof(IElementLink), count, 3606 ELEMENT_LINK_ROUND); 3607#else 3608 eLinks = (IElementLink *) ckalloc(sizeof(IElementLink) * count); 3609#endif 3610 } 3611 3612 /* Assume we are discarding all the old ElementLinks */ 3613 for (i = 0; i < oldCount; i++) 3614 keep[i] = 0; 3615 3616 for (i = 0; i < count; i++) { 3617 if (map[i] != -1) { 3618 eLinks[i] = style->elements[map[i]]; 3619 keep[map[i]] = 1; 3620 } else { 3621 eLink = &eLinks[i]; 3622 eLink->elem = elemList[i]; 3623#ifdef CACHE_ELEM_SIZE 3624 eLink->neededWidth = eLink->neededHeight = -1; 3625#endif 3626 } 3627 } 3628 3629 if (oldCount > 0) { 3630 /* Free unused ElementLinks */ 3631 for (i = 0; i < oldCount; i++) { 3632 if (!keep[i]) { 3633 IElementLink_FreeResources(tree, &style->elements[i]); 3634 } 3635 } 3636#ifdef ALLOC_HAX 3637 TreeAlloc_CFree(tree->allocData, IElementLinkUid, 3638 (char *) style->elements, sizeof(IElementLink), 3639 oldCount, ELEMENT_LINK_ROUND); 3640#else 3641 WCFREE(style->elements, IElementLink, oldCount); 3642#endif 3643 } 3644 3645 STATIC_FREE(keep, int, oldCount); 3646 3647 style->elements = eLinks; 3648} 3649 3650/* 3651 *---------------------------------------------------------------------- 3652 * 3653 * Style_ChangeElements -- 3654 * 3655 * Update the list of elements used by a style. Elements 3656 * may be inserted or deleted. 3657 * 3658 * Results: 3659 * The list of elements in the master style is updated. For 3660 * each item-column using an instance of the master style, 3661 * the list of elements is updated. 3662 * 3663 * Side effects: 3664 * Display changes. 3665 * 3666 *---------------------------------------------------------------------- 3667 */ 3668 3669static void 3670Style_ChangeElements( 3671 TreeCtrl *tree, /* Widget info. */ 3672 MStyle *masterStyle, /* Master style to be updated. */ 3673 int count, /* The number of elements in the style after 3674 * this routine finishes. */ 3675 TreeElement *elemList, /* List of master elements the style uses. */ 3676 int *map /* Array of indexes into the list of elements 3677 * currently used by the style. */ 3678 ) 3679{ 3680 TreeItem item; 3681 TreeItemColumn column; 3682 TreeColumn treeColumn; 3683 Tcl_HashEntry *hPtr; 3684 Tcl_HashSearch search; 3685 int columnIndex, layout; 3686 int updateDInfo = FALSE; 3687 IStyle *style; 3688 int i, j, k, oldCount; 3689 3690 /* Update -union lists */ 3691 for (i = 0; i < masterStyle->numElements; i++) { 3692 MElementLink *eLink = &masterStyle->elements[i]; 3693 int staticKeep[STATIC_SIZE], *keep = staticKeep; 3694 int onionCnt = 0, *onion = NULL; 3695 3696 if (eLink->onion == NULL) 3697 continue; 3698 3699 STATIC_ALLOC(keep, int, eLink->onionCount); 3700 3701 /* Check every Element in this -union */ 3702 for (j = 0; j < eLink->onionCount; j++) { 3703 MElementLink *eLink2 = &masterStyle->elements[eLink->onion[j]]; 3704 3705 /* Check the new list of Elements */ 3706 keep[j] = -1; 3707 for (k = 0; k < count; k++) { 3708 /* This new Element is in the -union */ 3709 if (elemList[k] == eLink2->elem) { 3710 keep[j] = k; 3711 onionCnt++; 3712 break; 3713 } 3714 } 3715 } 3716 3717 if (onionCnt > 0) { 3718 if (onionCnt != eLink->onionCount) 3719 onion = (int *) ckalloc(sizeof(int) * onionCnt); 3720 else 3721 onion = eLink->onion; 3722 k = 0; 3723 for (j = 0; j < eLink->onionCount; j++) { 3724 if (keep[j] != -1) 3725 onion[k++] = keep[j]; 3726 } 3727 } 3728 3729 STATIC_FREE(keep, int, eLink->onionCount); 3730 3731 if (onionCnt != eLink->onionCount) { 3732 WCFREE(eLink->onion, int, eLink->onionCount); 3733 eLink->onion = onion; 3734 eLink->onionCount = onionCnt; 3735 } 3736 } 3737 3738 oldCount = masterStyle->numElements; 3739 MStyle_ChangeElementsAux(tree, masterStyle, count, elemList, map); 3740 3741 hPtr = Tcl_FirstHashEntry(&tree->itemHash, &search); 3742 while (hPtr != NULL) { 3743 item = (TreeItem) Tcl_GetHashValue(hPtr); 3744 treeColumn = tree->columns; 3745 column = TreeItem_GetFirstColumn(tree, item); 3746 columnIndex = 0; 3747 layout = FALSE; 3748 while (column != NULL) { 3749 style = (IStyle *) TreeItemColumn_GetStyle(tree, column); 3750 if ((style != NULL) && (style->master == masterStyle)) { 3751 IStyle_ChangeElementsAux(tree, style, oldCount, count, elemList, map); 3752 style->neededWidth = style->neededHeight = -1; 3753 Tree_InvalidateColumnWidth(tree, treeColumn); 3754 TreeItemColumn_InvalidateSize(tree, column); 3755 layout = TRUE; 3756 } 3757 columnIndex++; 3758 column = TreeItemColumn_GetNext(tree, column); 3759 treeColumn = TreeColumn_Next(treeColumn); 3760 } 3761 if (layout) { 3762 TreeItem_InvalidateHeight(tree, item); 3763 Tree_FreeItemDInfo(tree, item, NULL); 3764 updateDInfo = TRUE; 3765 } 3766 hPtr = Tcl_NextHashEntry(&search); 3767 } 3768 if (updateDInfo) 3769 Tree_DInfoChanged(tree, DINFO_REDO_RANGES); 3770} 3771 3772/* 3773 *---------------------------------------------------------------------- 3774 * 3775 * Style_ElemChanged -- 3776 * 3777 * Called when a master element or TreeCtrl is configured. 3778 * 3779 * Results: 3780 * A check is made on each item-column to see if it is using 3781 * the element. The size of any element/column/item affected 3782 * is marked out-of-date. 3783 * 3784 * Side effects: 3785 * Display changes. 3786 * 3787 *---------------------------------------------------------------------- 3788 */ 3789 3790static void 3791Style_ElemChanged( 3792 TreeCtrl *tree, /* Widget info. */ 3793 MStyle *masterStyle, /* Master style that uses the element. */ 3794 TreeElement masterElem, /* Master element affected by the change. */ 3795 int masterElemIndex, /* Index of masterElem in masterStyle. */ 3796 int flagM, /* Flags returned by TreeElementType.configProc() 3797 * if the master element was configured, 3798 * zero if the TreeCtrl was configured. */ 3799 int flagT, /* TREE_CONF_xxx flags if the TreeCtrl was 3800 * configured, zero if the master element 3801 * was configured. */ 3802 int csM /* CS_xxx flags returned by 3803 * TreeElementType.changeProc(). */ 3804 ) 3805{ 3806 TreeItem item; 3807 TreeItemColumn column; 3808 TreeColumn treeColumn; 3809 Tcl_HashEntry *hPtr; 3810 Tcl_HashSearch search; 3811 IElementLink *eLink; 3812 int columnIndex; 3813 TreeElementArgs args; 3814 IStyle *style; 3815 int eMask, cMask, iMask; 3816 int updateDInfo = FALSE; 3817 3818 args.tree = tree; 3819 args.change.flagTree = flagT; 3820 args.change.flagMaster = flagM; 3821 args.change.flagSelf = 0; 3822 3823 hPtr = Tcl_FirstHashEntry(&tree->itemHash, &search); 3824 while (hPtr != NULL) { 3825 item = (TreeItem) Tcl_GetHashValue(hPtr); 3826 treeColumn = tree->columns; 3827 column = TreeItem_GetFirstColumn(tree, item); 3828 columnIndex = 0; 3829 iMask = 0; 3830 while (column != NULL) { 3831 cMask = 0; 3832 style = (IStyle *) TreeItemColumn_GetStyle(tree, column); 3833 if ((style != NULL) && (style->master == masterStyle)) { 3834 eLink = &style->elements[masterElemIndex]; 3835 if (eLink->elem == masterElem) { 3836#ifdef CACHE_ELEM_SIZE 3837 if (csM & CS_LAYOUT) 3838 eLink->neededWidth = eLink->neededHeight = -1; 3839#endif 3840 cMask |= csM; 3841 } 3842 /* Instance element */ 3843 else { 3844 args.elem = eLink->elem; 3845 eMask = (*masterElem->typePtr->changeProc)(&args); 3846#ifdef CACHE_ELEM_SIZE 3847 if (eMask & CS_LAYOUT) 3848 eLink->neededWidth = eLink->neededHeight = -1; 3849#endif 3850 cMask |= eMask; 3851 } 3852 iMask |= cMask; 3853 if (cMask & CS_LAYOUT) { 3854 style->neededWidth = style->neededHeight = -1; 3855 Tree_InvalidateColumnWidth(tree, treeColumn); 3856 TreeItemColumn_InvalidateSize(tree, column); 3857 } 3858 else if (cMask & CS_DISPLAY) { 3859 Tree_InvalidateItemDInfo(tree, treeColumn, item, NULL); 3860 } 3861 } 3862 columnIndex++; 3863 column = TreeItemColumn_GetNext(tree, column); 3864 treeColumn = TreeColumn_Next(treeColumn); 3865 } 3866 if (iMask & CS_LAYOUT) { 3867 TreeItem_InvalidateHeight(tree, item); 3868 Tree_FreeItemDInfo(tree, item, NULL); 3869 updateDInfo = TRUE; 3870 } 3871 else if (iMask & CS_DISPLAY) { 3872 } 3873 hPtr = Tcl_NextHashEntry(&search); 3874 } 3875 if (updateDInfo) 3876 Tree_DInfoChanged(tree, DINFO_REDO_RANGES); 3877} 3878 3879/* 3880 *---------------------------------------------------------------------- 3881 * 3882 * TreeStyle_GetMaster -- 3883 * 3884 * Return the master style for an instance style. 3885 * 3886 * Results: 3887 * Token for the master style. 3888 * 3889 * Side effects: 3890 * None. 3891 * 3892 *---------------------------------------------------------------------- 3893 */ 3894 3895TreeStyle 3896TreeStyle_GetMaster( 3897 TreeCtrl *tree, /* Widget info. */ 3898 TreeStyle style_ /* Instance style token. */ 3899 ) 3900{ 3901 return (TreeStyle) ((IStyle *) style_)->master; 3902} 3903 3904static Tcl_Obj *confImageObj = NULL; 3905static Tcl_Obj *confTextObj = NULL; 3906 3907/* 3908 *---------------------------------------------------------------------- 3909 * 3910 * Style_GetImageOrText -- 3911 * 3912 * Return the value of a configuration option for an element. 3913 * 3914 * Results: 3915 * The result of Tk_GetOptionValue for an option of the first 3916 * element of the proper type (if any), otherwise NULL. 3917 * 3918 * Side effects: 3919 * A Tcl_Obj may be allocated. 3920 * 3921 *---------------------------------------------------------------------- 3922 */ 3923 3924static Tcl_Obj * 3925Style_GetImageOrText( 3926 TreeCtrl *tree, /* Widget info. */ 3927 IStyle *style, /* Style. */ 3928 TreeElementType *typePtr, /* Type of element to look for. */ 3929 CONST char *optionName, /* Name of config option to query. */ 3930 Tcl_Obj **optionNameObj /* Pointer to a Tcl_Obj to hold the 3931 * option name. Initialized 3932 * on the first call. */ 3933 ) 3934{ 3935 IElementLink *eLink; 3936 int i; 3937 3938 if (*optionNameObj == NULL) { 3939 *optionNameObj = Tcl_NewStringObj(optionName, -1); 3940 Tcl_IncrRefCount(*optionNameObj); 3941 } 3942 3943 for (i = 0; i < style->master->numElements; i++) { 3944 eLink = &style->elements[i]; 3945 if (ELEMENT_TYPE_MATCHES(eLink->elem->typePtr, typePtr)) { 3946 Tcl_Obj *resultObjPtr; 3947 resultObjPtr = Tk_GetOptionValue(tree->interp, 3948 (char *) eLink->elem, eLink->elem->typePtr->optionTable, 3949 *optionNameObj, tree->tkwin); 3950 return resultObjPtr; 3951 } 3952 } 3953 3954 return NULL; 3955} 3956 3957/* 3958 *---------------------------------------------------------------------- 3959 * 3960 * TreeStyle_GetImage -- 3961 * 3962 * Return the value of the -image option for the first 3963 * image element in a style (if any). 3964 * 3965 * Results: 3966 * The result of Tk_GetOptionValue if the element was found, 3967 * otherwise NULL. 3968 * 3969 * Side effects: 3970 * A Tcl_Obj may be allocated. 3971 * 3972 *---------------------------------------------------------------------- 3973 */ 3974 3975Tcl_Obj * 3976TreeStyle_GetImage( 3977 TreeCtrl *tree, /* Widget info. */ 3978 TreeStyle style_ /* Token for style to examine. */ 3979 ) 3980{ 3981 return Style_GetImageOrText(tree, (IStyle *) style_, &treeElemTypeImage, 3982 "-image", &confImageObj); 3983} 3984 3985/* 3986 *---------------------------------------------------------------------- 3987 * 3988 * TreeStyle_GetText -- 3989 * 3990 * Return the value of the -text option for the first 3991 * text element in a style (if any). 3992 * 3993 * Results: 3994 * The result of Tk_GetOptionValue if the element was found, 3995 * otherwise NULL. 3996 * 3997 * Side effects: 3998 * A Tcl_Obj may be allocated. 3999 * 4000 *---------------------------------------------------------------------- 4001 */ 4002 4003Tcl_Obj * 4004TreeStyle_GetText( 4005 TreeCtrl *tree, /* Widget info. */ 4006 TreeStyle style_ /* Token for style to examine. */ 4007 ) 4008{ 4009 return Style_GetImageOrText(tree, (IStyle *) style_, &treeElemTypeText, 4010 "-text", &confTextObj); 4011} 4012 4013/* 4014 *---------------------------------------------------------------------- 4015 * 4016 * Style_SetImageOrText -- 4017 * 4018 * Set the value of a configuration option for the first 4019 * element of the proper type in a style (if any). 4020 * 4021 * Results: 4022 * A standard Tcl result. 4023 * 4024 * Side effects: 4025 * Size of the element and style will be marked out-of-date. 4026 * A Tcl_Obj may be allocated. 4027 * 4028 *---------------------------------------------------------------------- 4029 */ 4030 4031static int 4032Style_SetImageOrText( 4033 TreeCtrl *tree, /* Widget info. */ 4034 TreeItem item, /* Item containing the style. Needed if 4035 * a new instance Element is created. */ 4036 TreeItemColumn column, /* Item-column containing the style */ 4037 IStyle *style, /* The style */ 4038 TreeElementType *typePtr, /* Element type to look for. */ 4039 CONST char *optionName, /* NULL-terminated config option name. */ 4040 Tcl_Obj **optionNameObj, /* Pointer to Tcl_Obj to hold the option 4041 * name; initialized on the first call. */ 4042 Tcl_Obj *valueObj /* New value for the config option. */ 4043 ) 4044{ 4045 MStyle *masterStyle = style->master; 4046 IElementLink *eLink; 4047 int i; 4048 4049 if (*optionNameObj == NULL) { 4050 *optionNameObj = Tcl_NewStringObj(optionName, -1); 4051 Tcl_IncrRefCount(*optionNameObj); 4052 } 4053 4054 for (i = 0; i < masterStyle->numElements; i++) { 4055 TreeElement masterElem = masterStyle->elements[i].elem; 4056 if (ELEMENT_TYPE_MATCHES(masterElem->typePtr, typePtr)) { 4057 Tcl_Obj *objv[2]; 4058 TreeElementArgs args; 4059 4060 eLink = Style_CreateElem(tree, item, column, style, masterElem, NULL); 4061 4062 objv[0] = *optionNameObj; 4063 objv[1] = valueObj; 4064 args.tree = tree; 4065 args.elem = eLink->elem; 4066 args.config.objc = 2; 4067 args.config.objv = objv; 4068 args.config.flagSelf = 0; 4069 args.config.item = item; 4070 args.config.column = column; 4071 if ((*eLink->elem->typePtr->configProc)(&args) != TCL_OK) 4072 return TCL_ERROR; 4073 4074 args.change.flagSelf = args.config.flagSelf; 4075 args.change.flagTree = 0; 4076 args.change.flagMaster = 0; 4077 (void) (*eLink->elem->typePtr->changeProc)(&args); 4078 4079#ifdef CACHE_ELEM_SIZE 4080 eLink->neededWidth = eLink->neededHeight = -1; 4081#endif 4082 style->neededWidth = style->neededHeight = -1; 4083 break; 4084 } 4085 } 4086 return TCL_OK; 4087} 4088 4089/* 4090 *---------------------------------------------------------------------- 4091 * 4092 * TreeStyle_SetImage -- 4093 * 4094 * Set the value of the -image option for the first image 4095 * element in a style (if any). 4096 * 4097 * Results: 4098 * A standard Tcl result. 4099 * 4100 * Side effects: 4101 * Size of the element and style will be marked out-of-date. 4102 * A Tcl_Obj may be allocated. 4103 * 4104 *---------------------------------------------------------------------- 4105 */ 4106 4107int 4108TreeStyle_SetImage( 4109 TreeCtrl *tree, /* Widget info. */ 4110 TreeItem item, /* Item containing the style. */ 4111 TreeItemColumn column, /* Item-column containing the style. */ 4112 TreeStyle style_, /* The instance style. */ 4113 Tcl_Obj *valueObj /* New value for -image option. */ 4114 ) 4115{ 4116 return Style_SetImageOrText(tree, item, column, (IStyle *) style_, 4117 &treeElemTypeImage, "-image", &confImageObj, valueObj); 4118} 4119 4120/* 4121 *---------------------------------------------------------------------- 4122 * 4123 * TreeStyle_SetText -- 4124 * 4125 * Set the value of the -text option for the first text 4126 * element in a style (if any). 4127 * 4128 * Results: 4129 * A standard Tcl result. 4130 * 4131 * Side effects: 4132 * Size of the element and style will be marked out-of-date. 4133 * A Tcl_Obj may be allocated. 4134 * 4135 *---------------------------------------------------------------------- 4136 */ 4137 4138int 4139TreeStyle_SetText( 4140 TreeCtrl *tree, /* Widget info. */ 4141 TreeItem item, /* Item containing the style. */ 4142 TreeItemColumn column, /* Item-column containing the style. */ 4143 TreeStyle style_, /* The instance style. */ 4144 Tcl_Obj *valueObj /* New value for -text option. */ 4145 ) 4146{ 4147 return Style_SetImageOrText(tree, item, column, (IStyle *) style_, 4148 &treeElemTypeText, "-text", &confTextObj, valueObj); 4149} 4150 4151/* 4152 *---------------------------------------------------------------------- 4153 * 4154 * Style_Deleted -- 4155 * 4156 * Called when a master style is about to be deleted. Any 4157 * item-columns using an instance of the style have their style 4158 * freed. 4159 * 4160 * Results: 4161 * The TreeCtrl -defaultstyle option is updated if the deleted 4162 * style was specified in the value of the option. 4163 * 4164 * Side effects: 4165 * Display changes. Memory is deallocated. 4166 * 4167 *---------------------------------------------------------------------- 4168 */ 4169 4170static void 4171Style_Deleted( 4172 TreeCtrl *tree, /* Widget info. */ 4173 MStyle *masterStyle /* The master style being deleted. */ 4174 ) 4175{ 4176 TreeItem item; 4177 TreeItemColumn column; 4178 TreeColumn treeColumn; 4179 Tcl_HashEntry *hPtr; 4180 Tcl_HashSearch search; 4181 IStyle *style; 4182 int columnIndex; 4183 4184 hPtr = Tcl_FirstHashEntry(&tree->itemHash, &search); 4185 while (hPtr != NULL) { 4186 item = (TreeItem) Tcl_GetHashValue(hPtr); 4187 treeColumn = tree->columns; 4188 column = TreeItem_GetFirstColumn(tree, item); 4189 columnIndex = 0; 4190 while (column != NULL) { 4191 style = (IStyle *) TreeItemColumn_GetStyle(tree, column); 4192 if ((style != NULL) && (style->master == masterStyle)) { 4193 Tree_InvalidateColumnWidth(tree, treeColumn); 4194 TreeItemColumn_ForgetStyle(tree, column); 4195 TreeItem_InvalidateHeight(tree, item); 4196 Tree_FreeItemDInfo(tree, item, NULL); 4197 } 4198 columnIndex++; 4199 column = TreeItemColumn_GetNext(tree, column); 4200 treeColumn = TreeColumn_Next(treeColumn); 4201 } 4202 hPtr = Tcl_NextHashEntry(&search); 4203 } 4204 4205 /* Update each column's -itemstyle option */ 4206 treeColumn = tree->columns; 4207 while (treeColumn != NULL) { 4208 TreeColumn_StyleDeleted(treeColumn, (TreeStyle) masterStyle); 4209 treeColumn = TreeColumn_Next(treeColumn); 4210 } 4211 4212#ifdef DEPRECATED 4213 /* Update -defaultstyle option */ 4214 if (tree->defaultStyle.stylesObj != NULL) { 4215 Tcl_Obj *stylesObj = tree->defaultStyle.stylesObj; 4216 if (Tcl_IsShared(stylesObj)) { 4217 stylesObj = Tcl_DuplicateObj(stylesObj); 4218 Tcl_DecrRefCount(tree->defaultStyle.stylesObj); 4219 Tcl_IncrRefCount(stylesObj); 4220 tree->defaultStyle.stylesObj = stylesObj; 4221 } 4222 for (columnIndex = 0; columnIndex < tree->defaultStyle.numStyles; columnIndex++) { 4223 Tcl_Obj *emptyObj; 4224 if (tree->defaultStyle.styles[columnIndex] != (TreeStyle) masterStyle) 4225 continue; 4226 tree->defaultStyle.styles[columnIndex] = NULL; 4227 emptyObj = Tcl_NewObj(); 4228 Tcl_ListObjReplace(tree->interp, stylesObj, columnIndex, 1, 1, &emptyObj); 4229 } 4230 } 4231#endif /* DEPRECATED */ 4232 4233#ifdef DRAGIMAGE_STYLE 4234 TreeDragImage_StyleDeleted(tree->dragImage, (TreeStyle) masterStyle); 4235#endif 4236} 4237 4238/* 4239 *---------------------------------------------------------------------- 4240 * 4241 * Element_Changed -- 4242 * 4243 * Called when a master element or TreeCtrl has been configured. 4244 * 4245 * Results: 4246 * Every master and instance style using the element is updated. 4247 * 4248 * Side effects: 4249 * Display changes. 4250 * 4251 *---------------------------------------------------------------------- 4252 */ 4253 4254static void 4255Element_Changed( 4256 TreeCtrl *tree, /* Widget info. */ 4257 TreeElement masterElem, /* Master element that may have changed. */ 4258 int flagM, /* Flags returned by TreeElementType.configProc() 4259 * if the master element was configured, 4260 * zero if the TreeCtrl was configured. */ 4261 int flagT, /* TREE_CONF_xxx flags if the TreeCtrl was 4262 * configured, zero if the master element 4263 * was configured. */ 4264 int csM /* CS_xxx flags returned by 4265 * TreeElementType.changeProc(). */ 4266 ) 4267{ 4268 Tcl_HashEntry *hPtr; 4269 Tcl_HashSearch search; 4270 MStyle *masterStyle; 4271 MElementLink *eLink; 4272 int i; 4273 4274 hPtr = Tcl_FirstHashEntry(&tree->styleHash, &search); 4275 while (hPtr != NULL) { 4276 masterStyle = (MStyle *) Tcl_GetHashValue(hPtr); 4277 for (i = 0; i < masterStyle->numElements; i++) { 4278 eLink = &masterStyle->elements[i]; 4279 if (eLink->elem == masterElem) { 4280 Style_ElemChanged(tree, masterStyle, masterElem, i, flagM, flagT, csM); 4281 break; 4282 } 4283 } 4284 hPtr = Tcl_NextHashEntry(&search); 4285 } 4286} 4287 4288/* 4289 *---------------------------------------------------------------------- 4290 * 4291 * Element_Deleted -- 4292 * 4293 * Called when a master element is about to be deleted. 4294 * 4295 * Results: 4296 * The list of elements in any master styles using the element is 4297 * updated. Ditto for instance styles. 4298 * 4299 * Side effects: 4300 * Display changes. 4301 * 4302 *---------------------------------------------------------------------- 4303 */ 4304 4305static void 4306Element_Deleted( 4307 TreeCtrl *tree, /* Widget info. */ 4308 TreeElement masterElem /* Master element being deleted. */ 4309 ) 4310{ 4311 Tcl_HashEntry *hPtr; 4312 Tcl_HashSearch search; 4313 MStyle *masterStyle; 4314 MElementLink *eLink; 4315 int i, j; 4316 4317 hPtr = Tcl_FirstHashEntry(&tree->styleHash, &search); 4318 while (hPtr != NULL) { 4319 masterStyle = (MStyle *) Tcl_GetHashValue(hPtr); 4320 for (i = 0; i < masterStyle->numElements; i++) { 4321 eLink = &masterStyle->elements[i]; 4322 if (eLink->elem == masterElem) { 4323 TreeElement staticElemList[STATIC_SIZE], 4324 *elemList = staticElemList; 4325 int staticElemMap[STATIC_SIZE], *elemMap = staticElemMap; 4326 4327 STATIC_ALLOC(elemList, TreeElement, masterStyle->numElements); 4328 STATIC_ALLOC(elemMap, int, masterStyle->numElements); 4329 4330 for (j = 0; j < masterStyle->numElements; j++) { 4331 if (j == i) 4332 continue; 4333 elemList[(j < i) ? j : (j - 1)] = 4334 masterStyle->elements[j].elem; 4335 elemMap[(j < i) ? j : (j - 1)] = j; 4336 } 4337 Style_ChangeElements(tree, masterStyle, 4338 masterStyle->numElements - 1, elemList, elemMap); 4339 STATIC_FREE(elemList, TreeElement, masterStyle->numElements + 1); 4340 STATIC_FREE(elemMap, int, masterStyle->numElements + 1); 4341 break; 4342 } 4343 } 4344 hPtr = Tcl_NextHashEntry(&search); 4345 } 4346} 4347 4348/* 4349 *---------------------------------------------------------------------- 4350 * 4351 * Tree_RedrawElement -- 4352 * 4353 * A STUB export. Schedules a redraw of the given item. 4354 * 4355 * Results: 4356 * None. 4357 * 4358 * Side effects: 4359 * Display changes. 4360 * 4361 *---------------------------------------------------------------------- 4362 */ 4363 4364void 4365Tree_RedrawElement( 4366 TreeCtrl *tree, /* Widget info. */ 4367 TreeItem item, /* Item containing the element. */ 4368 TreeElement elem /* The element that changed. */ 4369 ) 4370{ 4371 /* Master element */ 4372 if (elem->master == NULL) { 4373 } 4374 4375 /* Instance element */ 4376 else { 4377 Tree_InvalidateItemDInfo(tree, NULL, item, NULL); 4378 } 4379} 4380 4381typedef struct Iterate 4382{ 4383 TreeCtrl *tree; 4384 TreeItem item; 4385 TreeItemColumn column; 4386 int columnIndex; 4387 IStyle *style; 4388 TreeElementType *elemTypePtr; 4389 IElementLink *eLink; 4390 Tcl_HashSearch search; 4391 Tcl_HashEntry *hPtr; 4392} Iterate; 4393 4394static int IterateItem(Iterate *iter) 4395{ 4396 int i; 4397 4398 while (iter->column != NULL) { 4399 iter->style = (IStyle *) TreeItemColumn_GetStyle(iter->tree, iter->column); 4400 if (iter->style != NULL) { 4401 for (i = 0; i < iter->style->master->numElements; i++) { 4402 iter->eLink = &iter->style->elements[i]; 4403 if (ELEMENT_TYPE_MATCHES(iter->eLink->elem->typePtr, iter->elemTypePtr)) 4404 return 1; 4405 } 4406 } 4407 iter->column = TreeItemColumn_GetNext(iter->tree, iter->column); 4408 iter->columnIndex++; 4409 } 4410 return 0; 4411} 4412 4413TreeIterate 4414Tree_ElementIterateBegin( 4415 TreeCtrl *tree, 4416 TreeElementType *elemTypePtr) 4417{ 4418 Iterate *iter; 4419 4420 iter = (Iterate *) ckalloc(sizeof(Iterate)); 4421 iter->tree = tree; 4422 iter->elemTypePtr = elemTypePtr; 4423 iter->hPtr = Tcl_FirstHashEntry(&tree->itemHash, &iter->search); 4424 while (iter->hPtr != NULL) { 4425 iter->item = (TreeItem) Tcl_GetHashValue(iter->hPtr); 4426 iter->column = TreeItem_GetFirstColumn(tree, iter->item); 4427 iter->columnIndex = 0; 4428 if (IterateItem(iter)) 4429 return (TreeIterate) iter; 4430 iter->hPtr = Tcl_NextHashEntry(&iter->search); 4431 } 4432 ckfree((char *) iter); 4433 return NULL; 4434} 4435 4436TreeIterate 4437Tree_ElementIterateNext( 4438 TreeIterate iter_) 4439{ 4440 Iterate *iter = (Iterate *) iter_; 4441 4442 iter->column = TreeItemColumn_GetNext(iter->tree, iter->column); 4443 iter->columnIndex++; 4444 if (IterateItem(iter)) 4445 return iter_; 4446 iter->hPtr = Tcl_NextHashEntry(&iter->search); 4447 while (iter->hPtr != NULL) { 4448 iter->item = (TreeItem) Tcl_GetHashValue(iter->hPtr); 4449 iter->column = TreeItem_GetFirstColumn(iter->tree, iter->item); 4450 iter->columnIndex = 0; 4451 if (IterateItem(iter)) 4452 return iter_; 4453 iter->hPtr = Tcl_NextHashEntry(&iter->search); 4454 } 4455 ckfree((char *) iter); 4456 return NULL; 4457} 4458 4459/* 4460 *---------------------------------------------------------------------- 4461 * 4462 * Tree_ElementChangedItself -- 4463 * 4464 * Called when an element has reconfigured itself outside of 4465 * any API calls. For example, when a window associated with a 4466 * window element is resized, or a text element's -textvariable 4467 * is set. 4468 * 4469 * Results: 4470 * None. 4471 * 4472 * Side effects: 4473 * Display changes. 4474 * 4475 *---------------------------------------------------------------------- 4476 */ 4477 4478void 4479Tree_ElementChangedItself( 4480 TreeCtrl *tree, /* Widget info. */ 4481 TreeItem item, /* Item containing the element. */ 4482 TreeItemColumn column, /* Item-column containing the element. */ 4483 TreeElement elem, /* The element that changed. */ 4484 int flags, /* Element-specific configuration flags. */ 4485 int csM /* CS_xxx flags detailing the effects of 4486 * the change. */ 4487 ) 4488{ 4489 /* Master element. */ 4490 if (item == NULL) { 4491 Element_Changed(tree, elem, flags, 0, csM); 4492 return; 4493 } 4494 if (csM & CS_LAYOUT) { 4495 IStyle *style = (IStyle *) TreeItemColumn_GetStyle(tree, column); 4496 int i; 4497 IElementLink *eLink = NULL; 4498 int columnIndex; 4499 4500 if (style == NULL) 4501 panic("Tree_ElementChangedItself but style is NULL\n"); 4502 4503 for (i = 0; i < style->master->numElements; i++) { 4504 eLink = &style->elements[i]; 4505 if (eLink->elem == elem) 4506 break; 4507 } 4508 4509 if (eLink == NULL) 4510 panic("Tree_ElementChangedItself but eLink is NULL\n"); 4511 4512 columnIndex = TreeItemColumn_Index(tree, item, column); 4513 4514#ifdef CACHE_ELEM_SIZE 4515 eLink->neededWidth = eLink->neededHeight = -1; 4516#endif 4517 style->neededWidth = style->neededHeight = -1; 4518 4519 Tree_InvalidateColumnWidth(tree, Tree_FindColumn(tree, columnIndex)); 4520 TreeItemColumn_InvalidateSize(tree, column); 4521 TreeItem_InvalidateHeight(tree, item); 4522 Tree_FreeItemDInfo(tree, item, NULL); 4523 Tree_DInfoChanged(tree, DINFO_REDO_RANGES); 4524 } 4525 else if (csM & CS_DISPLAY) { 4526 int columnIndex; 4527 4528 columnIndex = TreeItemColumn_Index(tree, item, column); 4529 Tree_InvalidateItemDInfo(tree, Tree_FindColumn(tree, columnIndex), 4530 item, NULL); 4531 } 4532} 4533 4534void Tree_ElementIterateChanged(TreeIterate iter_, int mask) 4535{ 4536 Iterate *iter = (Iterate *) iter_; 4537 4538 if (mask & CS_LAYOUT) { 4539#ifdef CACHE_ELEM_SIZE 4540 iter->eLink->neededWidth = iter->eLink->neededHeight = -1; 4541#endif 4542 iter->style->neededWidth = iter->style->neededHeight = -1; 4543 Tree_InvalidateColumnWidth(iter->tree, 4544 Tree_FindColumn(iter->tree, iter->columnIndex)); 4545 TreeItemColumn_InvalidateSize(iter->tree, iter->column); 4546 TreeItem_InvalidateHeight(iter->tree, iter->item); 4547 Tree_FreeItemDInfo(iter->tree, iter->item, NULL); 4548 Tree_DInfoChanged(iter->tree, DINFO_REDO_RANGES); 4549 } 4550 if (mask & CS_DISPLAY) 4551 Tree_InvalidateItemDInfo(iter->tree, NULL, iter->item, NULL); 4552} 4553 4554TreeElement Tree_ElementIterateGet(TreeIterate iter_) 4555{ 4556 Iterate *iter = (Iterate *) iter_; 4557 4558 return iter->eLink->elem; 4559} 4560 4561/* 4562 *---------------------------------------------------------------------- 4563 * 4564 * TreeStyle_TreeChanged -- 4565 * 4566 * Called when a TreeCtrl is configured. This handles changes to 4567 * the -font option affecting text elements for example. 4568 * 4569 * Results: 4570 * Calls the changeProc on every master element. Any elements 4571 * affected by the change are eventually redisplayed. 4572 * 4573 * Side effects: 4574 * Display changes. 4575 * 4576 *---------------------------------------------------------------------- 4577 */ 4578 4579void 4580TreeStyle_TreeChanged( 4581 TreeCtrl *tree, /* Widget info. */ 4582 int flagT /* TREE_CONF_xxx flags. */ 4583 ) 4584{ 4585 Tcl_HashEntry *hPtr; 4586 Tcl_HashSearch search; 4587 TreeElement masterElem; 4588 TreeElementArgs args; 4589 int eMask; 4590 4591 if (flagT == 0) 4592 return; 4593 4594 args.tree = tree; 4595 args.change.flagTree = flagT; 4596 args.change.flagMaster = 0; 4597 args.change.flagSelf = 0; 4598 4599 hPtr = Tcl_FirstHashEntry(&tree->elementHash, &search); 4600 while (hPtr != NULL) { 4601 masterElem = (TreeElement) Tcl_GetHashValue(hPtr); 4602 args.elem = masterElem; 4603 eMask = (*masterElem->typePtr->changeProc)(&args); 4604 Element_Changed(tree, masterElem, 0, flagT, eMask); 4605 hPtr = Tcl_NextHashEntry(&search); 4606 } 4607} 4608 4609/* 4610 *---------------------------------------------------------------------- 4611 * 4612 * TreeStyle_ElementCget -- 4613 * 4614 * This procedure is invoked to process the [item element cget] 4615 * widget command. See the user documentation for details on what 4616 * it does. 4617 * 4618 * Results: 4619 * A standard Tcl result. 4620 * 4621 * Side effects: 4622 * See the user documentation. 4623 * 4624 *---------------------------------------------------------------------- 4625 */ 4626 4627int 4628TreeStyle_ElementCget( 4629 TreeCtrl *tree, /* Widget info. */ 4630 TreeItem item, /* Item containing the element. */ 4631 TreeItemColumn column, /* Item-column containing the element. */ 4632 TreeStyle style_, /* Style containing the element. */ 4633 Tcl_Obj *elemObj, /* Name of the element. */ 4634 Tcl_Obj *optionNameObj /* Name of the config option. */ 4635 ) 4636{ 4637 IStyle *style = (IStyle *) style_; 4638 Tcl_Obj *resultObjPtr = NULL; 4639 TreeElement elem; 4640 IElementLink *eLink; 4641 4642 if (Element_FromObj(tree, elemObj, &elem) != TCL_OK) 4643 return TCL_ERROR; 4644 4645 eLink = IStyle_FindElem(tree, style, elem, NULL); 4646 if ((eLink != NULL) && (eLink->elem == elem)) { 4647 int index = TreeItemColumn_Index(tree, item, column); 4648 TreeColumn treeColumn = Tree_FindColumn(tree, index); 4649 4650 FormatResult(tree->interp, 4651 "element %s is not configured in item %s%d column %s%d", 4652 elem->name, tree->itemPrefix, TreeItem_GetID(tree, item), 4653 tree->columnPrefix, TreeColumn_GetID(treeColumn)); 4654 return TCL_ERROR; 4655 } 4656 if (eLink == NULL) { 4657 FormatResult(tree->interp, "style %s does not use element %s", 4658 style->master->name, elem->name); 4659 return TCL_ERROR; 4660 } 4661 4662 resultObjPtr = Tk_GetOptionValue(tree->interp, (char *) eLink->elem, 4663 eLink->elem->typePtr->optionTable, optionNameObj, tree->tkwin); 4664 if (resultObjPtr == NULL) 4665 return TCL_ERROR; 4666 Tcl_SetObjResult(tree->interp, resultObjPtr); 4667 return TCL_OK; 4668} 4669 4670/* 4671 *---------------------------------------------------------------------- 4672 * 4673 * TreeStyle_ElementConfigure -- 4674 * 4675 * This procedure is invoked to process the [item element configure] 4676 * widget command. See the user documentation for details on what 4677 * it does. 4678 * 4679 * Results: 4680 * A standard Tcl result. 4681 * 4682 * Side effects: 4683 * See the user documentation. 4684 * 4685 *---------------------------------------------------------------------- 4686 */ 4687 4688int 4689TreeStyle_ElementConfigure( 4690 TreeCtrl *tree, /* Widget info. */ 4691 TreeItem item, /* Item containing the element. */ 4692 TreeItemColumn column, /* Item-column containing the element. */ 4693 TreeStyle style_, /* Style containing the element. */ 4694 Tcl_Obj *elemObj, /* Name of the element. */ 4695 int objc, /* Number of arguments. */ 4696 Tcl_Obj **objv, /* Argument values. */ 4697 int *eMask /* Returned CS_xxx flags. */ 4698 ) 4699{ 4700 IStyle *style = (IStyle *) style_; 4701 TreeElement elem; 4702 IElementLink *eLink; 4703 TreeElementArgs args; 4704 4705 (*eMask) = 0; 4706 4707 if (Element_FromObj(tree, elemObj, &elem) != TCL_OK) 4708 return TCL_ERROR; 4709 4710 if (objc <= 1) { 4711 Tcl_Obj *resultObjPtr; 4712 4713 eLink = IStyle_FindElem(tree, style, elem, NULL); 4714 if ((eLink != NULL) && (eLink->elem == elem)) { 4715 int index = TreeItemColumn_Index(tree, item, column); 4716 TreeColumn treeColumn = Tree_FindColumn(tree, index); 4717 4718 FormatResult(tree->interp, 4719 "element %s is not configured in item %s%d column %s%d", 4720 elem->name, tree->itemPrefix, TreeItem_GetID(tree, item), 4721 tree->columnPrefix, TreeColumn_GetID(treeColumn)); 4722 return TCL_ERROR; 4723 } 4724 if (eLink == NULL) { 4725 FormatResult(tree->interp, "style %s does not use element %s", 4726 style->master->name, elem->name); 4727 return TCL_ERROR; 4728 } 4729 4730 resultObjPtr = Tk_GetOptionInfo(tree->interp, (char *) eLink->elem, 4731 eLink->elem->typePtr->optionTable, 4732 (objc == 0) ? (Tcl_Obj *) NULL : objv[0], 4733 tree->tkwin); 4734 if (resultObjPtr == NULL) 4735 return TCL_ERROR; 4736 Tcl_SetObjResult(tree->interp, resultObjPtr); 4737 } else { 4738 int isNew; 4739 4740 eLink = Style_CreateElem(tree, item, column, style, elem, &isNew); 4741 if (eLink == NULL) { 4742 FormatResult(tree->interp, "style %s does not use element %s", 4743 style->master->name, elem->name); 4744 return TCL_ERROR; 4745 } 4746 4747 /* Do this before configProc(). If eLink was just allocated and an 4748 * error occurs in configProc() it won't be done */ 4749 (*eMask) = 0; 4750 if (isNew) { 4751#ifdef CACHE_ELEM_SIZE 4752 eLink->neededWidth = eLink->neededHeight = -1; 4753#endif 4754 style->neededWidth = style->neededHeight = -1; 4755 (*eMask) = CS_DISPLAY | CS_LAYOUT; 4756 } 4757 4758 args.tree = tree; 4759 args.elem = eLink->elem; 4760 args.config.objc = objc; 4761 args.config.objv = objv; 4762 args.config.flagSelf = 0; 4763 args.config.item = item; 4764 args.config.column = column; 4765 if ((*args.elem->typePtr->configProc)(&args) != TCL_OK) 4766 return TCL_ERROR; 4767 4768 args.change.flagSelf = args.config.flagSelf; 4769 args.change.flagTree = 0; 4770 args.change.flagMaster = 0; 4771 (*eMask) |= (*elem->typePtr->changeProc)(&args); 4772 4773 if (!isNew && ((*eMask) & CS_LAYOUT)) { 4774#ifdef CACHE_ELEM_SIZE 4775 eLink->neededWidth = eLink->neededHeight = -1; 4776#endif 4777 style->neededWidth = style->neededHeight = -1; 4778 } 4779 } 4780 return TCL_OK; 4781} 4782 4783/* 4784 *---------------------------------------------------------------------- 4785 * 4786 * TreeStyle_ElementActual -- 4787 * 4788 * This procedure is invoked to process the [item element perstate] 4789 * widget command. See the user documentation for details on what 4790 * it does. 4791 * 4792 * Results: 4793 * A standard Tcl result. 4794 * 4795 * Side effects: 4796 * See the user documentation. 4797 * 4798 *---------------------------------------------------------------------- 4799 */ 4800 4801int 4802TreeStyle_ElementActual( 4803 TreeCtrl *tree, /* Widget info. */ 4804 TreeStyle style_, /* The style. */ 4805 int state, /* STATE_xxx flags. */ 4806 Tcl_Obj *elemObj, /* Name of the element. */ 4807 Tcl_Obj *optionNameObj /* Name of the config option. */ 4808 ) 4809{ 4810 IStyle *style = (IStyle *) style_; 4811 TreeElement masterElem; 4812 IElementLink *eLink; 4813 TreeElementArgs args; 4814 4815 if (Element_FromObj(tree, elemObj, &masterElem) != TCL_OK) 4816 return TCL_ERROR; 4817 4818 eLink = IStyle_FindElem(tree, style, masterElem, NULL); 4819 if (eLink == NULL) { 4820 FormatResult(tree->interp, "style %s does not use element %s", 4821 style->master->name, masterElem->name); 4822 return TCL_ERROR; 4823 } 4824 4825 args.tree = tree; 4826 args.elem = eLink->elem; 4827 args.state = state; 4828 args.actual.obj = optionNameObj; 4829 return (*masterElem->typePtr->actualProc)(&args); 4830} 4831 4832/* 4833 *---------------------------------------------------------------------- 4834 * 4835 * TreeElementCmd -- 4836 * 4837 * This procedure is invoked to process the [element] 4838 * widget command. See the user documentation for details on what 4839 * it does. 4840 * 4841 * Results: 4842 * A standard Tcl result. 4843 * 4844 * Side effects: 4845 * See the user documentation. 4846 * 4847 *---------------------------------------------------------------------- 4848 */ 4849 4850int 4851TreeElementCmd( 4852 ClientData clientData, /* Widget info. */ 4853 Tcl_Interp *interp, /* Current interpreter. */ 4854 int objc, /* Number of arguments. */ 4855 Tcl_Obj *CONST objv[] /* Argument values. */ 4856 ) 4857{ 4858 TreeCtrl *tree = clientData; 4859 static CONST char *commandNames[] = { 4860 "cget", "configure", "create", "delete", "names", "perstate", "type", 4861 (char *) NULL 4862 }; 4863 enum { 4864 COMMAND_CGET, COMMAND_CONFIGURE, COMMAND_CREATE, COMMAND_DELETE, 4865 COMMAND_NAMES, COMMAND_PERSTATE, COMMAND_TYPE 4866 }; 4867 int index; 4868 4869 if (objc < 3) { 4870 Tcl_WrongNumArgs(interp, 2, objv, "command ?arg arg ...?"); 4871 return TCL_ERROR; 4872 } 4873 4874 if (Tcl_GetIndexFromObj(interp, objv[2], commandNames, "command", 0, 4875 &index) != TCL_OK) { 4876 return TCL_ERROR; 4877 } 4878 4879 switch (index) { 4880 case COMMAND_CGET: { 4881 Tcl_Obj *resultObjPtr = NULL; 4882 TreeElement elem; 4883 4884 if (objc != 5) { 4885 Tcl_WrongNumArgs(interp, 3, objv, "name option"); 4886 return TCL_ERROR; 4887 } 4888 if (Element_FromObj(tree, objv[3], &elem) != TCL_OK) 4889 return TCL_ERROR; 4890 resultObjPtr = Tk_GetOptionValue(interp, (char *) elem, 4891 elem->typePtr->optionTable, objv[4], tree->tkwin); 4892 if (resultObjPtr == NULL) 4893 return TCL_ERROR; 4894 Tcl_SetObjResult(interp, resultObjPtr); 4895 break; 4896 } 4897 4898 case COMMAND_CONFIGURE: { 4899 Tcl_Obj *resultObjPtr = NULL; 4900 TreeElement elem; 4901 int eMask; 4902 4903 if (objc < 4) { 4904 Tcl_WrongNumArgs(interp, 3, objv, "name ?option? ?value option value ...?"); 4905 return TCL_ERROR; 4906 } 4907 if (Element_FromObj(tree, objv[3], &elem) != TCL_OK) 4908 return TCL_ERROR; 4909 if (objc <= 5) { 4910 resultObjPtr = Tk_GetOptionInfo(interp, (char *) elem, 4911 elem->typePtr->optionTable, 4912 (objc == 4) ? (Tcl_Obj *) NULL : objv[4], 4913 tree->tkwin); 4914 if (resultObjPtr == NULL) 4915 return TCL_ERROR; 4916 Tcl_SetObjResult(interp, resultObjPtr); 4917 } else { 4918 TreeElementArgs args; 4919 4920 args.tree = tree; 4921 args.elem = elem; 4922 args.config.objc = objc - 4; 4923 args.config.objv = objv + 4; 4924 args.config.flagSelf = 0; 4925 args.config.item = NULL; 4926 args.config.column = NULL; 4927 if ((*elem->typePtr->configProc)(&args) != TCL_OK) 4928 return TCL_ERROR; 4929 4930 args.change.flagSelf = args.config.flagSelf; 4931 args.change.flagTree = 0; 4932 args.change.flagMaster = 0; 4933 eMask = (*elem->typePtr->changeProc)(&args); 4934 4935 Element_Changed(tree, elem, args.change.flagSelf, 0, eMask); 4936 } 4937 break; 4938 } 4939 4940 case COMMAND_CREATE: { 4941 char *name; 4942 int length; 4943 int isNew; 4944 TreeElement elem; 4945 TreeElementType *typePtr; 4946 Tcl_HashEntry *hPtr; 4947 4948 if (objc < 5) { 4949 Tcl_WrongNumArgs(interp, 3, objv, "name type ?option value ...?"); 4950 return TCL_ERROR; 4951 } 4952 name = Tcl_GetStringFromObj(objv[3], &length); 4953 if (!length) 4954 return TCL_ERROR; 4955 hPtr = Tcl_FindHashEntry(&tree->elementHash, name); 4956 if (hPtr != NULL) { 4957 FormatResult(interp, "element \"%s\" already exists", name); 4958 return TCL_ERROR; 4959 } 4960 if (TreeElement_TypeFromObj(tree, objv[4], &typePtr) != TCL_OK) 4961 return TCL_ERROR; 4962 elem = Element_CreateAndConfig(tree, NULL, NULL, NULL, typePtr, name, objc - 5, objv + 5); 4963 if (elem == NULL) 4964 return TCL_ERROR; 4965 hPtr = Tcl_CreateHashEntry(&tree->elementHash, name, &isNew); 4966 Tcl_SetHashValue(hPtr, elem); 4967 Tcl_SetObjResult(interp, Element_ToObj(elem)); 4968 break; 4969 } 4970 4971 case COMMAND_DELETE: { 4972 TreeElement elem; 4973 int i; 4974 4975 for (i = 3; i < objc; i++) { 4976 if (Element_FromObj(tree, objv[i], &elem) != TCL_OK) 4977 return TCL_ERROR; 4978 Element_Deleted(tree, elem); 4979 Element_FreeResources(tree, elem); 4980 } 4981 break; 4982 } 4983 4984 case COMMAND_NAMES: { 4985 Tcl_Obj *listObj; 4986 Tcl_HashSearch search; 4987 Tcl_HashEntry *hPtr; 4988 TreeElement elem; 4989 4990 if (objc != 3) { 4991 Tcl_WrongNumArgs(interp, 3, objv, NULL); 4992 return TCL_ERROR; 4993 } 4994 listObj = Tcl_NewListObj(0, NULL); 4995 hPtr = Tcl_FirstHashEntry(&tree->elementHash, &search); 4996 while (hPtr != NULL) { 4997 elem = (TreeElement) Tcl_GetHashValue(hPtr); 4998 Tcl_ListObjAppendElement(interp, listObj, Element_ToObj(elem)); 4999 hPtr = Tcl_NextHashEntry(&search); 5000 } 5001 Tcl_SetObjResult(interp, listObj); 5002 break; 5003 } 5004 5005 /* T element perstate E option stateList */ 5006 case COMMAND_PERSTATE: { 5007 TreeElement elem; 5008 int states[3]; 5009 TreeElementArgs args; 5010 5011 if (objc != 6) { 5012 Tcl_WrongNumArgs(tree->interp, 3, objv, 5013 "element option stateList"); 5014 return TCL_ERROR; 5015 } 5016 5017 if (Element_FromObj(tree, objv[3], &elem) != TCL_OK) 5018 return TCL_ERROR; 5019 5020 if (Tree_StateFromListObj(tree, objv[5], states, 5021 SFO_NOT_OFF | SFO_NOT_TOGGLE) != TCL_OK) 5022 return TCL_ERROR; 5023 5024 args.tree = tree; 5025 args.elem = elem; 5026 args.state = states[STATE_OP_ON]; 5027 args.actual.obj = objv[4]; 5028 return (*elem->typePtr->actualProc)(&args); 5029 } 5030 5031 case COMMAND_TYPE: { 5032 TreeElement elem; 5033 5034 if (objc != 4) { 5035 Tcl_WrongNumArgs(interp, 3, objv, "name"); 5036 return TCL_ERROR; 5037 } 5038 if (Element_FromObj(tree, objv[3], &elem) != TCL_OK) 5039 return TCL_ERROR; 5040 Tcl_SetResult(interp, elem->typePtr->name, TCL_STATIC); /* Tk_Uid */ 5041 break; 5042 } 5043 } 5044 return TCL_OK; 5045} 5046 5047/* 5048 *---------------------------------------------------------------------- 5049 * 5050 * Style_CreateAndConfig -- 5051 * 5052 * Allocate and initialize a master style. 5053 * 5054 * Results: 5055 * Pointer to the new Style, or NULL if an error occurs. 5056 * 5057 * Side effects: 5058 * Memory is allocated. 5059 * 5060 *---------------------------------------------------------------------- 5061 */ 5062 5063static MStyle * 5064Style_CreateAndConfig( 5065 TreeCtrl *tree, /* Widget info. */ 5066 char *name, /* Name of new style. */ 5067 int objc, /* Number of config-option arg-value pairs. */ 5068 Tcl_Obj *CONST objv[] /* Config-option arg-value pairs. */ 5069 ) 5070{ 5071 MStyle *style; 5072 5073#ifdef ALLOC_HAX 5074 style = (MStyle *) TreeAlloc_Alloc(tree->allocData, MStyleUid, 5075 sizeof(MStyle)); 5076#else 5077 style = (MStyle *) ckalloc(sizeof(MStyle)); 5078#endif 5079 memset(style, '\0', sizeof(MStyle)); 5080 style->name = Tk_GetUid(name); 5081 5082 if (Tk_InitOptions(tree->interp, (char *) style, 5083 tree->styleOptionTable, tree->tkwin) != TCL_OK) { 5084#ifdef ALLOC_HAX 5085 TreeAlloc_Free(tree->allocData, MStyleUid, (char *) style, sizeof(MStyle)); 5086#else 5087 WFREE(style, MStyle); 5088#endif 5089 return NULL; 5090 } 5091 5092 if (Tk_SetOptions(tree->interp, (char *) style, 5093 tree->styleOptionTable, objc, objv, tree->tkwin, 5094 NULL, NULL) != TCL_OK) { 5095 Tk_FreeConfigOptions((char *) style, tree->styleOptionTable, tree->tkwin); 5096#ifdef ALLOC_HAX 5097 TreeAlloc_Free(tree->allocData, MStyleUid, (char *) style, sizeof(MStyle)); 5098#else 5099 WFREE(style, MStyle); 5100#endif 5101 return NULL; 5102 } 5103 5104 return style; 5105} 5106 5107/* 5108 *---------------------------------------------------------------------- 5109 * 5110 * TreeStyle_ListElements -- 5111 * 5112 * Creates a Tcl list with the names of elements in a style. 5113 * 5114 * Results: 5115 * If the style is a master style, the interpreter result holds 5116 * a list of each element in the style. If the style is an 5117 * instance style, the interpreter result holds a list of those 5118 * elements configured for the style (i.e., instance elements). 5119 * 5120 * Side effects: 5121 * Memory is allocated, interpreter result changed. 5122 * 5123 *---------------------------------------------------------------------- 5124 */ 5125 5126void 5127TreeStyle_ListElements( 5128 TreeCtrl *tree, /* Widget info. */ 5129 TreeStyle style_ /* The style. */ 5130 ) 5131{ 5132 MStyle *masterStyle = (MStyle *) style_; 5133 IStyle *style = (IStyle *) style_; 5134 Tcl_Obj *listObj; 5135 TreeElement elem; 5136 int i, numElements = TreeStyle_NumElements(tree, style_); 5137 5138 if (numElements <= 0) 5139 return; 5140 5141 listObj = Tcl_NewListObj(0, NULL); 5142 for (i = 0; i < numElements; i++) { 5143 if (style->master != NULL) { 5144 elem = style->elements[i].elem; 5145 if (elem->master == NULL) 5146 continue; 5147 } else { 5148 elem = masterStyle->elements[i].elem; 5149 } 5150 Tcl_ListObjAppendElement(tree->interp, listObj, Element_ToObj(elem)); 5151 } 5152 Tcl_SetObjResult(tree->interp, listObj); 5153} 5154 5155enum { 5156 OPTION_DETACH, OPTION_DRAW, OPTION_EXPAND, OPTION_HEIGHT, OPTION_iEXPAND, 5157 OPTION_INDENT, OPTION_iPADX, OPTION_iPADY, OPTION_MAXHEIGHT, 5158 OPTION_MAXWIDTH, OPTION_MINHEIGHT, OPTION_MINWIDTH, OPTION_PADX, 5159 OPTION_PADY, OPTION_SQUEEZE, OPTION_STICKY, OPTION_UNION, 5160 OPTION_WIDTH, OPTION_VISIBLE 5161}; 5162 5163/* 5164 *---------------------------------------------------------------------- 5165 * 5166 * LayoutOptionToObj -- 5167 * 5168 * Return a Tcl_Obj holding the value of a style layout option 5169 * for an element. 5170 * 5171 * Results: 5172 * Pointer to a new Tcl_Obj or NULL if the option has no value. 5173 * 5174 * Side effects: 5175 * A Tcl_Obj may be allocated. 5176 * 5177 *---------------------------------------------------------------------- 5178 */ 5179 5180static Tcl_Obj * 5181LayoutOptionToObj( 5182 TreeCtrl *tree, /* Widget info. */ 5183 MStyle *style, /* Master style using the element. */ 5184 MElementLink *eLink, /* Layout info for the element. */ 5185 int option /* OPTION_xxx constant. */ 5186 ) 5187{ 5188 Tcl_Interp *interp = tree->interp; 5189 5190 switch (option) { 5191 case OPTION_PADX: 5192 return TreeCtrl_NewPadAmountObj(eLink->ePadX); 5193 case OPTION_PADY: 5194 return TreeCtrl_NewPadAmountObj(eLink->ePadY); 5195 case OPTION_iPADX: 5196 return TreeCtrl_NewPadAmountObj(eLink->iPadX); 5197 case OPTION_iPADY: 5198 return TreeCtrl_NewPadAmountObj(eLink->iPadY); 5199 case OPTION_DETACH: 5200 return Tcl_NewStringObj((eLink->flags & ELF_DETACH) ? "yes" : "no", -1); 5201 case OPTION_EXPAND: { 5202 char flags[4]; 5203 int n = 0; 5204 5205 if (eLink->flags & ELF_eEXPAND_W) flags[n++] = 'w'; 5206 if (eLink->flags & ELF_eEXPAND_N) flags[n++] = 'n'; 5207 if (eLink->flags & ELF_eEXPAND_E) flags[n++] = 'e'; 5208 if (eLink->flags & ELF_eEXPAND_S) flags[n++] = 's'; 5209 if (n) 5210 return Tcl_NewStringObj(flags, n); 5211 break; 5212 } 5213 case OPTION_iEXPAND: { 5214 char flags[6]; 5215 int n = 0; 5216 5217 if (eLink->flags & ELF_iEXPAND_X) flags[n++] = 'x'; 5218 if (eLink->flags & ELF_iEXPAND_Y) flags[n++] = 'y'; 5219 if (eLink->flags & ELF_iEXPAND_W) flags[n++] = 'w'; 5220 if (eLink->flags & ELF_iEXPAND_N) flags[n++] = 'n'; 5221 if (eLink->flags & ELF_iEXPAND_E) flags[n++] = 'e'; 5222 if (eLink->flags & ELF_iEXPAND_S) flags[n++] = 's'; 5223 if (n) 5224 return Tcl_NewStringObj(flags, n); 5225 break; 5226 } 5227 case OPTION_INDENT: 5228 return Tcl_NewStringObj((eLink->flags & ELF_INDENT) ? "yes" : "no", -1); 5229 case OPTION_SQUEEZE: { 5230 char flags[2]; 5231 int n = 0; 5232 5233 if (eLink->flags & ELF_SQUEEZE_X) flags[n++] = 'x'; 5234 if (eLink->flags & ELF_SQUEEZE_Y) flags[n++] = 'y'; 5235 if (n) 5236 return Tcl_NewStringObj(flags, n); 5237 break; 5238 } 5239 case OPTION_UNION: { 5240 int i; 5241 Tcl_Obj *objPtr; 5242 5243 if (eLink->onionCount == 0) 5244 break; 5245 objPtr = Tcl_NewListObj(0, NULL); 5246 for (i = 0; i < eLink->onionCount; i++) 5247 Tcl_ListObjAppendElement(interp, objPtr, 5248 Element_ToObj(style->elements[eLink->onion[i]].elem)); 5249 return objPtr; 5250 } 5251 case OPTION_MAXHEIGHT: { 5252 if (eLink->maxHeight >= 0) 5253 return Tcl_NewIntObj(eLink->maxHeight); 5254 break; 5255 } 5256 case OPTION_MINHEIGHT: { 5257 if (eLink->minHeight >= 0) 5258 return Tcl_NewIntObj(eLink->minHeight); 5259 break; 5260 } 5261 case OPTION_HEIGHT: { 5262 if (eLink->fixedHeight >= 0) 5263 return Tcl_NewIntObj(eLink->fixedHeight); 5264 break; 5265 } 5266 case OPTION_MAXWIDTH: { 5267 if (eLink->maxWidth >= 0) 5268 return Tcl_NewIntObj(eLink->maxWidth); 5269 break; 5270 } 5271 case OPTION_MINWIDTH: { 5272 if (eLink->minWidth >= 0) 5273 return Tcl_NewIntObj(eLink->minWidth); 5274 break; 5275 } 5276 case OPTION_WIDTH: { 5277 if (eLink->fixedWidth >= 0) 5278 return Tcl_NewIntObj(eLink->fixedWidth); 5279 break; 5280 } 5281 case OPTION_STICKY: { 5282 char flags[4]; 5283 int n = 0; 5284 5285 if (eLink->flags & ELF_STICKY_W) flags[n++] = 'w'; 5286 if (eLink->flags & ELF_STICKY_N) flags[n++] = 'n'; 5287 if (eLink->flags & ELF_STICKY_E) flags[n++] = 'e'; 5288 if (eLink->flags & ELF_STICKY_S) flags[n++] = 's'; 5289 if (n) 5290 return Tcl_NewStringObj(flags, n); 5291 break; 5292 } 5293 case OPTION_DRAW: { 5294 return eLink->draw.obj; 5295 } 5296 case OPTION_VISIBLE: { 5297 return eLink->visible.obj; 5298 } 5299 } 5300 return NULL; 5301} 5302 5303/* 5304 *---------------------------------------------------------------------- 5305 * 5306 * StyleLayoutCmd -- 5307 * 5308 * This procedure is invoked to process the [style layout] 5309 * widget command. See the user documentation for details on what 5310 * it does. 5311 * 5312 * Results: 5313 * A standard Tcl result. 5314 * 5315 * Side effects: 5316 * See the user documentation. 5317 * 5318 *---------------------------------------------------------------------- 5319 */ 5320 5321static int 5322StyleLayoutCmd( 5323 ClientData clientData, /* Widget info. */ 5324 Tcl_Interp *interp, /* The current interpreter. */ 5325 int objc, /* Number of arguments. */ 5326 Tcl_Obj *CONST objv[] /* Argument values. */ 5327 ) 5328{ 5329 TreeCtrl *tree = clientData; 5330 TreeStyle _style; 5331 MStyle *style; 5332 TreeElement elem; 5333 MElementLink saved, *eLink; 5334 int i, index; 5335 static CONST char *optionNames[] = { 5336 "-detach", "-draw", "-expand", "-height", "-iexpand", 5337 "-indent", "-ipadx", "-ipady", "-maxheight", "-maxwidth", "-minheight", 5338 "-minwidth", "-padx", "-pady", "-squeeze", "-sticky", "-union", 5339 "-width", "-visible", 5340 (char *) NULL 5341 }; 5342 if (objc < 5) { 5343 Tcl_WrongNumArgs(interp, 3, objv, "name element ?option? ?value? ?option value ...?"); 5344 return TCL_ERROR; 5345 } 5346 5347 if (TreeStyle_FromObj(tree, objv[3], &_style) != TCL_OK) 5348 return TCL_ERROR; 5349 style = (MStyle *) _style; 5350 5351 if (Element_FromObj(tree, objv[4], &elem) != TCL_OK) 5352 return TCL_ERROR; 5353 5354 eLink = MStyle_FindElem(tree, style, elem, NULL); 5355 if (eLink == NULL) { 5356 FormatResult(interp, "style %s does not use element %s", 5357 style->name, elem->name); 5358 return TCL_ERROR; 5359 } 5360 5361 /* T style layout S E */ 5362 if (objc == 5) { 5363 Tcl_Obj *listObj = Tcl_NewListObj(0, NULL); 5364 Tcl_Obj *objPtr; 5365 5366 for (i = 0; optionNames[i] != NULL; i++) { 5367 Tcl_ListObjAppendElement(interp, listObj, 5368 Tcl_NewStringObj(optionNames[i], -1)); 5369 objPtr = LayoutOptionToObj(tree, style, eLink, i); 5370 Tcl_ListObjAppendElement(interp, listObj, 5371 objPtr ? objPtr : Tcl_NewObj()); 5372 } 5373 Tcl_SetObjResult(interp, listObj); 5374 return TCL_OK; 5375 } 5376 5377 /* T style layout S E option */ 5378 if (objc == 6) { 5379 Tcl_Obj *objPtr; 5380 5381 if (Tcl_GetIndexFromObj(interp, objv[5], optionNames, "option", 5382 0, &index) != TCL_OK) 5383 return TCL_ERROR; 5384 objPtr = LayoutOptionToObj(tree, style, eLink, index); 5385 if (objPtr != NULL) 5386 Tcl_SetObjResult(interp, objPtr); 5387 return TCL_OK; 5388 } 5389 5390 saved = *eLink; 5391 5392 for (i = 5; i < objc; i += 2) { 5393 if (i + 2 > objc) { 5394 FormatResult(interp, "value for \"%s\" missing", 5395 Tcl_GetString(objv[i])); 5396 goto badConfig; 5397 } 5398 if (Tcl_GetIndexFromObj(interp, objv[i], optionNames, "option", 5399 0, &index) != TCL_OK) { 5400 goto badConfig; 5401 } 5402 switch (index) { 5403 case OPTION_PADX: { 5404 if (TreeCtrl_GetPadAmountFromObj(interp, 5405 tree->tkwin, objv[i + 1], 5406 &eLink->ePadX[PAD_TOP_LEFT], 5407 &eLink->ePadX[PAD_BOTTOM_RIGHT]) != TCL_OK) 5408 goto badConfig; 5409 break; 5410 } 5411 case OPTION_PADY: { 5412 if (TreeCtrl_GetPadAmountFromObj(interp, 5413 tree->tkwin, objv[i + 1], 5414 &eLink->ePadY[PAD_TOP_LEFT], 5415 &eLink->ePadY[PAD_BOTTOM_RIGHT]) != TCL_OK) 5416 goto badConfig; 5417 break; 5418 } 5419 case OPTION_iPADX: { 5420 if (TreeCtrl_GetPadAmountFromObj(interp, 5421 tree->tkwin, objv[i + 1], 5422 &eLink->iPadX[PAD_TOP_LEFT], 5423 &eLink->iPadX[PAD_BOTTOM_RIGHT]) != TCL_OK) 5424 goto badConfig; 5425 break; 5426 } 5427 case OPTION_iPADY: { 5428 if (TreeCtrl_GetPadAmountFromObj(interp, 5429 tree->tkwin, objv[i + 1], 5430 &eLink->iPadY[PAD_TOP_LEFT], 5431 &eLink->iPadY[PAD_BOTTOM_RIGHT]) != TCL_OK) 5432 goto badConfig; 5433 break; 5434 } 5435 case OPTION_DETACH: { 5436 int detach; 5437 if (Tcl_GetBooleanFromObj(interp, objv[i + 1], &detach) != TCL_OK) 5438 goto badConfig; 5439 if (detach) 5440 eLink->flags |= ELF_DETACH; 5441 else 5442 eLink->flags &= ~ELF_DETACH; 5443 break; 5444 } 5445 case OPTION_EXPAND: { 5446 char *expand; 5447 int len, k; 5448 expand = Tcl_GetStringFromObj(objv[i + 1], &len); 5449 eLink->flags &= ~ELF_eEXPAND; 5450 for (k = 0; k < len; k++) { 5451 switch (expand[k]) { 5452 case 'w': case 'W': eLink->flags |= ELF_eEXPAND_W; break; 5453 case 'n': case 'N': eLink->flags |= ELF_eEXPAND_N; break; 5454 case 'e': case 'E': eLink->flags |= ELF_eEXPAND_E; break; 5455 case 's': case 'S': eLink->flags |= ELF_eEXPAND_S; break; 5456 default: { 5457 Tcl_ResetResult(tree->interp); 5458 Tcl_AppendResult(tree->interp, "bad expand value \"", 5459 expand, "\": must be a string ", 5460 "containing zero or more of n, e, s, and w", 5461 (char *) NULL); 5462 goto badConfig; 5463 } 5464 } 5465 } 5466 break; 5467 } 5468 case OPTION_iEXPAND: { 5469 char *expand; 5470 int len, k; 5471 expand = Tcl_GetStringFromObj(objv[i + 1], &len); 5472 eLink->flags &= ~(ELF_iEXPAND | ELF_iEXPAND_X | ELF_iEXPAND_Y); 5473 for (k = 0; k < len; k++) { 5474 switch (expand[k]) { 5475 case 'x': case 'X': eLink->flags |= ELF_iEXPAND_X; break; 5476 case 'y': case 'Y': eLink->flags |= ELF_iEXPAND_Y; break; 5477 case 'w': case 'W': eLink->flags |= ELF_iEXPAND_W; break; 5478 case 'n': case 'N': eLink->flags |= ELF_iEXPAND_N; break; 5479 case 'e': case 'E': eLink->flags |= ELF_iEXPAND_E; break; 5480 case 's': case 'S': eLink->flags |= ELF_iEXPAND_S; break; 5481 default: { 5482 Tcl_ResetResult(tree->interp); 5483 Tcl_AppendResult(tree->interp, "bad iexpand value \"", 5484 expand, "\": must be a string ", 5485 "containing zero or more of x, y, n, e, s, and w", 5486 (char *) NULL); 5487 goto badConfig; 5488 } 5489 } 5490 } 5491 break; 5492 } 5493 case OPTION_INDENT: { 5494 int indent; 5495 if (Tcl_GetBooleanFromObj(interp, objv[i + 1], &indent) != TCL_OK) 5496 goto badConfig; 5497 if (indent) 5498 eLink->flags |= ELF_INDENT; 5499 else 5500 eLink->flags &= ~ELF_INDENT; 5501 break; 5502 } 5503 case OPTION_SQUEEZE: { 5504 char *string; 5505 int len, k; 5506 string = Tcl_GetStringFromObj(objv[i + 1], &len); 5507 eLink->flags &= ~(ELF_SQUEEZE_X | ELF_SQUEEZE_Y); 5508 for (k = 0; k < len; k++) { 5509 switch (string[k]) { 5510 case 'x': case 'X': eLink->flags |= ELF_SQUEEZE_X; break; 5511 case 'y': case 'Y': eLink->flags |= ELF_SQUEEZE_Y; break; 5512 default: { 5513 Tcl_ResetResult(tree->interp); 5514 Tcl_AppendResult(tree->interp, "bad squeeze value \"", 5515 string, "\": must be a string ", 5516 "containing zero or more of x and y", 5517 (char *) NULL); 5518 goto badConfig; 5519 } 5520 } 5521 } 5522 break; 5523 } 5524 case OPTION_UNION: { 5525 int objc1; 5526 Tcl_Obj **objv1; 5527 int j, k, n, *onion, count = 0; 5528 5529 if (Tcl_ListObjGetElements(interp, objv[i + 1], 5530 &objc1, &objv1) != TCL_OK) 5531 goto badConfig; 5532 if (objc1 == 0) { 5533 if (eLink->onion != NULL) { 5534 if (eLink->onion != saved.onion) 5535 WCFREE(eLink->onion, int, eLink->onionCount); 5536 eLink->onionCount = 0; 5537 eLink->onion = NULL; 5538 } 5539 break; 5540 } 5541 onion = (int *) ckalloc(sizeof(int) * objc1); 5542 for (j = 0; j < objc1; j++) { 5543 TreeElement elem2; 5544 MElementLink *eLink2; 5545 5546 if (Element_FromObj(tree, objv1[j], &elem2) != TCL_OK) { 5547 ckfree((char *) onion); 5548 goto badConfig; 5549 } 5550 5551 eLink2 = MStyle_FindElem(tree, style, elem2, &n); 5552 if (eLink2 == NULL) { 5553 ckfree((char *) onion); 5554 FormatResult(interp, 5555 "style %s does not use element %s", 5556 style->name, elem2->name); 5557 goto badConfig; 5558 } 5559 if (eLink == eLink2) { 5560 ckfree((char *) onion); 5561 FormatResult(interp, 5562 "element %s can't form union with itself", 5563 elem2->name); 5564 goto badConfig; 5565 } 5566 /* Silently ignore duplicates */ 5567 for (k = 0; k < count; k++) { 5568 if (onion[k] == n) 5569 break; 5570 } 5571 if (k < count) 5572 continue; 5573 onion[count++] = n; 5574 } 5575 if ((eLink->onion != NULL) && (eLink->onion != saved.onion)) 5576 WCFREE(eLink->onion, int, eLink->onionCount); 5577 if (count == objc1) 5578 eLink->onion = onion; 5579 else { 5580 eLink->onion = (int *) ckalloc(sizeof(int) * count); 5581 for (k = 0; k < count; k++) 5582 eLink->onion[k] = onion[k]; 5583 ckfree((char *) onion); 5584 } 5585 eLink->onionCount = count; 5586 break; 5587 } 5588 case OPTION_MAXHEIGHT: { 5589 int height; 5590 if (ObjectIsEmpty(objv[i + 1])) { 5591 eLink->maxHeight = -1; 5592 break; 5593 } 5594 if ((Tk_GetPixelsFromObj(interp, tree->tkwin, objv[i + 1], 5595 &height) != TCL_OK) || (height < 0)) { 5596 FormatResult(interp, "bad screen distance \"%s\"", 5597 Tcl_GetString(objv[i + 1])); 5598 goto badConfig; 5599 } 5600 eLink->maxHeight = height; 5601 break; 5602 } 5603 case OPTION_MINHEIGHT: { 5604 int height; 5605 if (ObjectIsEmpty(objv[i + 1])) { 5606 eLink->minHeight = -1; 5607 break; 5608 } 5609 if ((Tk_GetPixelsFromObj(interp, tree->tkwin, objv[i + 1], 5610 &height) != TCL_OK) || (height < 0)) { 5611 FormatResult(interp, "bad screen distance \"%s\"", 5612 Tcl_GetString(objv[i + 1])); 5613 goto badConfig; 5614 } 5615 eLink->minHeight = height; 5616 break; 5617 } 5618 case OPTION_HEIGHT: { 5619 int height; 5620 if (ObjectIsEmpty(objv[i + 1])) { 5621 eLink->fixedHeight = -1; 5622 break; 5623 } 5624 if ((Tk_GetPixelsFromObj(interp, tree->tkwin, objv[i + 1], 5625 &height) != TCL_OK) || (height < 0)) { 5626 FormatResult(interp, "bad screen distance \"%s\"", 5627 Tcl_GetString(objv[i + 1])); 5628 goto badConfig; 5629 } 5630 eLink->fixedHeight = height; 5631 break; 5632 } 5633 case OPTION_MAXWIDTH: { 5634 int width; 5635 if (ObjectIsEmpty(objv[i + 1])) { 5636 eLink->maxWidth = -1; 5637 break; 5638 } 5639 if ((Tk_GetPixelsFromObj(interp, tree->tkwin, objv[i + 1], 5640 &width) != TCL_OK) || (width < 0)) { 5641 FormatResult(interp, "bad screen distance \"%s\"", 5642 Tcl_GetString(objv[i + 1])); 5643 goto badConfig; 5644 } 5645 eLink->maxWidth = width; 5646 break; 5647 } 5648 case OPTION_MINWIDTH: { 5649 int width; 5650 if (ObjectIsEmpty(objv[i + 1])) { 5651 eLink->minWidth = -1; 5652 break; 5653 } 5654 if ((Tk_GetPixelsFromObj(interp, tree->tkwin, objv[i + 1], 5655 &width) != TCL_OK) || (width < 0)) { 5656 FormatResult(interp, "bad screen distance \"%s\"", 5657 Tcl_GetString(objv[i + 1])); 5658 goto badConfig; 5659 } 5660 eLink->minWidth = width; 5661 break; 5662 } 5663 case OPTION_WIDTH: { 5664 int width; 5665 if (ObjectIsEmpty(objv[i + 1])) { 5666 eLink->fixedWidth = -1; 5667 break; 5668 } 5669 if ((Tk_GetPixelsFromObj(interp, tree->tkwin, objv[i + 1], 5670 &width) != TCL_OK) || (width < 0)) { 5671 FormatResult(interp, "bad screen distance \"%s\"", 5672 Tcl_GetString(objv[i + 1])); 5673 goto badConfig; 5674 } 5675 eLink->fixedWidth = width; 5676 break; 5677 } 5678 case OPTION_STICKY: { 5679 char *sticky; 5680 int len, k; 5681 sticky = Tcl_GetStringFromObj(objv[i + 1], &len); 5682 eLink->flags &= ~ELF_STICKY; 5683 for (k = 0; k < len; k++) { 5684 switch (sticky[k]) { 5685 case 'w': case 'W': eLink->flags |= ELF_STICKY_W; break; 5686 case 'n': case 'N': eLink->flags |= ELF_STICKY_N; break; 5687 case 'e': case 'E': eLink->flags |= ELF_STICKY_E; break; 5688 case 's': case 'S': eLink->flags |= ELF_STICKY_S; break; 5689 default: { 5690 Tcl_ResetResult(tree->interp); 5691 Tcl_AppendResult(tree->interp, "bad sticky value \"", 5692 sticky, "\": must be a string ", 5693 "containing zero or more of n, e, s, and w", 5694 (char *) NULL); 5695 goto badConfig; 5696 } 5697 } 5698 } 5699 break; 5700 } 5701 case OPTION_DRAW: 5702 case OPTION_VISIBLE: { 5703 PerStateInfo *psi, *psiSaved; 5704 5705 if (index == OPTION_DRAW) { 5706 psi = &eLink->draw; 5707 psiSaved = &saved.draw; 5708 } else { 5709 psi = &eLink->visible; 5710 psiSaved = &saved.visible; 5711 } 5712 5713 /* Already configured this once. */ 5714 if (psi->obj != NULL && psi->obj != psiSaved->obj) { 5715 PerStateInfo_Free(tree, &pstBoolean, psi); 5716 Tcl_DecrRefCount(psi->obj); 5717 5718 /* First configure. Don't free the saved data. */ 5719 } else { 5720 psi->data = NULL; 5721 psi->count = 0; 5722 } 5723 psi->obj = objv[i + 1]; 5724 Tcl_IncrRefCount(psi->obj); 5725 if (PerStateInfo_FromObj(tree, TreeStateFromObj, &pstBoolean, 5726 psi) != TCL_OK) { 5727 goto badConfig; 5728 } 5729 break; 5730 } 5731 } 5732 } 5733 if (saved.onion && (eLink->onion != saved.onion)) 5734 WCFREE(saved.onion, int, saved.onionCount); 5735 if (saved.draw.obj != NULL && 5736 saved.draw.obj != eLink->draw.obj) { 5737 PerStateInfo_Free(tree, &pstBoolean, &saved.draw); 5738 Tcl_DecrRefCount(saved.draw.obj); 5739 } 5740 if (saved.visible.obj != NULL && 5741 saved.visible.obj != eLink->visible.obj) { 5742 PerStateInfo_Free(tree, &pstBoolean, &saved.visible); 5743 Tcl_DecrRefCount(saved.visible.obj); 5744 } 5745 Style_Changed(tree, style); 5746 return TCL_OK; 5747 5748badConfig: 5749 if (eLink->onion && (eLink->onion != saved.onion)) 5750 WCFREE(eLink->onion, int, eLink->onionCount); 5751 if (eLink->draw.obj != NULL && 5752 eLink->draw.obj != saved.draw.obj) { 5753 PerStateInfo_Free(tree, &pstBoolean, &eLink->draw); 5754 Tcl_DecrRefCount(eLink->draw.obj); 5755 } 5756 if (eLink->visible.obj != NULL && 5757 eLink->visible.obj != saved.visible.obj) { 5758 PerStateInfo_Free(tree, &pstBoolean, &eLink->visible); 5759 Tcl_DecrRefCount(eLink->visible.obj); 5760 } 5761 *eLink = saved; 5762 return TCL_ERROR; 5763} 5764 5765/* 5766 *---------------------------------------------------------------------- 5767 * 5768 * TreeStyleCmd -- 5769 * 5770 * This procedure is invoked to process the [style] widget 5771 * command. See the user documentation for details on what it 5772 * does. 5773 * 5774 * Results: 5775 * A standard Tcl result. 5776 * 5777 * Side effects: 5778 * See the user documentation. 5779 * 5780 *---------------------------------------------------------------------- 5781 */ 5782 5783int 5784TreeStyleCmd( 5785 ClientData clientData, /* Widget info. */ 5786 Tcl_Interp *interp, /* Current interpreter. */ 5787 int objc, /* Number of arguments. */ 5788 Tcl_Obj *CONST objv[] /* Argument values. */ 5789 ) 5790{ 5791 TreeCtrl *tree = clientData; 5792 static CONST char *commandNames[] = { 5793 "cget", "configure", "create", "delete", "elements", "layout", 5794 "names", (char *) NULL }; 5795 enum { 5796 COMMAND_CGET, COMMAND_CONFIGURE, COMMAND_CREATE, COMMAND_DELETE, 5797 COMMAND_ELEMENTS, COMMAND_LAYOUT, COMMAND_NAMES }; 5798 int index; 5799 TreeStyle _style; 5800 MStyle *style; 5801 5802 if (objc < 3) { 5803 Tcl_WrongNumArgs(interp, 2, objv, "command ?arg arg ...?"); 5804 return TCL_ERROR; 5805 } 5806 5807 if (Tcl_GetIndexFromObj(interp, objv[2], commandNames, "command", 0, 5808 &index) != TCL_OK) { 5809 return TCL_ERROR; 5810 } 5811 5812 switch (index) { 5813 case COMMAND_CGET: { 5814 Tcl_Obj *resultObjPtr; 5815 5816 if (objc != 5) { 5817 Tcl_WrongNumArgs(interp, 3, objv, "name option"); 5818 return TCL_ERROR; 5819 } 5820 if (TreeStyle_FromObj(tree, objv[3], &_style) != TCL_OK) 5821 return TCL_ERROR; 5822 style = (MStyle *) _style; 5823 resultObjPtr = Tk_GetOptionValue(interp, (char *) style, 5824 tree->styleOptionTable, objv[4], tree->tkwin); 5825 if (resultObjPtr == NULL) 5826 return TCL_ERROR; 5827 Tcl_SetObjResult(interp, resultObjPtr); 5828 break; 5829 } 5830 5831 case COMMAND_CONFIGURE: { 5832 Tcl_Obj *resultObjPtr = NULL; 5833 5834 if (objc < 4) { 5835 Tcl_WrongNumArgs(interp, 3, objv, "name ?option? ?value option value ...?"); 5836 return TCL_ERROR; 5837 } 5838 if (TreeStyle_FromObj(tree, objv[3], &_style) != TCL_OK) 5839 return TCL_ERROR; 5840 style = (MStyle *) _style; 5841 if (objc <= 5) { 5842 resultObjPtr = Tk_GetOptionInfo(interp, (char *) style, 5843 tree->styleOptionTable, 5844 (objc == 4) ? (Tcl_Obj *) NULL : objv[4], 5845 tree->tkwin); 5846 if (resultObjPtr == NULL) 5847 return TCL_ERROR; 5848 Tcl_SetObjResult(interp, resultObjPtr); 5849 } else { 5850 if (Tk_SetOptions(tree->interp, (char *) style, 5851 tree->styleOptionTable, objc - 4, objv + 4, tree->tkwin, 5852 NULL, NULL) != TCL_OK) 5853 return TCL_ERROR; 5854 Style_Changed(tree, style); 5855 } 5856 break; 5857 } 5858 5859 case COMMAND_CREATE: { 5860 char *name; 5861 int len; 5862 Tcl_HashEntry *hPtr; 5863 int isNew; 5864 5865 if (objc < 4) { 5866 Tcl_WrongNumArgs(interp, 3, objv, "name ?option value ...?"); 5867 return TCL_ERROR; 5868 } 5869 name = Tcl_GetStringFromObj(objv[3], &len); 5870 if (!len) { 5871 FormatResult(interp, "invalid style name \"\""); 5872 return TCL_ERROR; 5873 } 5874 hPtr = Tcl_FindHashEntry(&tree->styleHash, name); 5875 if (hPtr != NULL) { 5876 FormatResult(interp, "style \"%s\" already exists", name); 5877 return TCL_ERROR; 5878 } 5879 style = Style_CreateAndConfig(tree, name, objc - 4, objv + 4); 5880 if (style == NULL) 5881 return TCL_ERROR; 5882 hPtr = Tcl_CreateHashEntry(&tree->styleHash, name, &isNew); 5883 Tcl_SetHashValue(hPtr, style); 5884 Tcl_SetObjResult(interp, TreeStyle_ToObj((TreeStyle) style)); 5885 break; 5886 } 5887 5888 case COMMAND_DELETE: { 5889 int i; 5890 5891 if (objc < 3) { 5892 Tcl_WrongNumArgs(interp, 3, objv, "?name ...?"); 5893 return TCL_ERROR; 5894 } 5895 for (i = 3; i < objc; i++) { 5896 if (TreeStyle_FromObj(tree, objv[i], &_style) != TCL_OK) 5897 return TCL_ERROR; 5898 Style_Deleted(tree, (MStyle *) _style); 5899 TreeStyle_FreeResources(tree, _style); 5900 } 5901 break; 5902 } 5903 5904 /* T style elements S ?{E ...}? */ 5905 case COMMAND_ELEMENTS: { 5906 TreeElement elem, *elemList = NULL; 5907 int i, j, count = 0; 5908 int staticMap[STATIC_SIZE], *map = staticMap; 5909 int listObjc; 5910 Tcl_Obj **listObjv; 5911 5912 if (objc < 4 || objc > 5) { 5913 Tcl_WrongNumArgs(interp, 3, objv, "name ?elementList?"); 5914 return TCL_ERROR; 5915 } 5916 if (TreeStyle_FromObj(tree, objv[3], &_style) != TCL_OK) 5917 return TCL_ERROR; 5918 style = (MStyle *) _style; 5919 if (objc == 5) { 5920 if (Tcl_ListObjGetElements(interp, objv[4], &listObjc, &listObjv) != TCL_OK) 5921 return TCL_ERROR; 5922 if (listObjc > 0) 5923 elemList = (TreeElement *) ckalloc(sizeof(TreeElement_) * listObjc); 5924 for (i = 0; i < listObjc; i++) { 5925 if (Element_FromObj(tree, listObjv[i], &elem) != TCL_OK) { 5926 ckfree((char *) elemList); 5927 return TCL_ERROR; 5928 } 5929 5930 /* Ignore duplicate elements */ 5931 for (j = 0; j < count; j++) { 5932 if (elemList[j] == elem) 5933 break; 5934 } 5935 if (j < count) 5936 continue; 5937 5938 elemList[count++] = elem; 5939 } 5940 5941 STATIC_ALLOC(map, int, count); 5942 5943 for (i = 0; i < count; i++) 5944 map[i] = -1; 5945 5946 /* Reassigning Elements to a Style */ 5947 if (style->numElements > 0) { 5948 /* Check each Element */ 5949 for (i = 0; i < count; i++) { 5950 /* See if this Element is already used by the Style */ 5951 for (j = 0; j < style->numElements; j++) { 5952 if (elemList[i] == style->elements[j].elem) { 5953 /* Preserve it */ 5954 map[i] = j; 5955 break; 5956 } 5957 } 5958 } 5959 } 5960 Style_ChangeElements(tree, style, count, elemList, map); 5961 if (elemList != NULL) 5962 ckfree((char *) elemList); 5963 STATIC_FREE(map, int, count); 5964 break; 5965 } 5966 TreeStyle_ListElements(tree, (TreeStyle) style); 5967 break; 5968 } 5969 5970 /* T style layout S E ?option? ?value? ?option value ...? */ 5971 case COMMAND_LAYOUT: { 5972 return StyleLayoutCmd(clientData, interp, objc, objv); 5973 } 5974 5975 case COMMAND_NAMES: { 5976 Tcl_Obj *listObj; 5977 Tcl_HashSearch search; 5978 Tcl_HashEntry *hPtr; 5979 5980 listObj = Tcl_NewListObj(0, NULL); 5981 hPtr = Tcl_FirstHashEntry(&tree->styleHash, &search); 5982 while (hPtr != NULL) { 5983 _style = (TreeStyle) Tcl_GetHashValue(hPtr); 5984 Tcl_ListObjAppendElement(interp, listObj, 5985 TreeStyle_ToObj(_style)); 5986 hPtr = Tcl_NextHashEntry(&search); 5987 } 5988 Tcl_SetObjResult(interp, listObj); 5989 break; 5990 } 5991 } 5992 return TCL_OK; 5993} 5994 5995/* 5996 *---------------------------------------------------------------------- 5997 * 5998 * Tree_ButtonMaxWidth -- 5999 * 6000 * Return the maximum possible size of a button in any state. This 6001 * includes the size of the -buttonimage and -buttonbitmap options, 6002 * as well as the theme button and default +/- button. 6003 * 6004 * Results: 6005 * Pixel size >= 0. 6006 * 6007 * Side effects: 6008 * None. 6009 * 6010 *---------------------------------------------------------------------- 6011 */ 6012 6013int 6014Tree_ButtonMaxWidth( 6015 TreeCtrl *tree /* Widget info. */ 6016 ) 6017{ 6018 int w, h, width = 0; 6019 6020 PerStateImage_MaxSize(tree, &tree->buttonImage, &w, &h); 6021 width = MAX(width, w); 6022 6023 PerStateBitmap_MaxSize(tree, &tree->buttonBitmap, &w, &h); 6024 width = MAX(width, w); 6025 6026 if (tree->useTheme) { 6027 if (TreeTheme_GetButtonSize(tree, Tk_WindowId(tree->tkwin), 6028 TRUE, &w, &h) == TCL_OK) 6029 width = MAX(width, w); 6030 if (TreeTheme_GetButtonSize(tree, Tk_WindowId(tree->tkwin), 6031 FALSE, &w, &h) == TCL_OK) 6032 width = MAX(width, w); 6033 } 6034 6035 return MAX(width, tree->buttonSize); 6036} 6037 6038/* 6039 *---------------------------------------------------------------------- 6040 * 6041 * Tree_ButtonHeight -- 6042 * 6043 * Return the size of a button for a certain state. 6044 * 6045 * Results: 6046 * Pixel size >= 0. 6047 * 6048 * Side effects: 6049 * None. 6050 * 6051 *---------------------------------------------------------------------- 6052 */ 6053 6054int 6055Tree_ButtonHeight( 6056 TreeCtrl *tree, /* Widget info. */ 6057 int state /* STATE_xxx flags. */ 6058 ) 6059{ 6060 Tk_Image image; 6061 Pixmap bitmap; 6062 int w, h; 6063 6064 image = PerStateImage_ForState(tree, &tree->buttonImage, state, NULL); 6065 if (image != NULL) { 6066 Tk_SizeOfImage(image, &w, &h); 6067 return h; 6068 } 6069 6070 bitmap = PerStateBitmap_ForState(tree, &tree->buttonBitmap, state, NULL); 6071 if (bitmap != None) { 6072 Tk_SizeOfBitmap(tree->display, bitmap, &w, &h); 6073 return h; 6074 } 6075 6076 if (tree->useTheme && 6077 TreeTheme_GetButtonSize(tree, Tk_WindowId(tree->tkwin), 6078 (state & STATE_OPEN) != 0, &w, &h) == TCL_OK) 6079 return h; 6080 6081 return tree->buttonSize; 6082} 6083 6084/* 6085 *---------------------------------------------------------------------- 6086 * 6087 * TreeStyle_Identify -- 6088 * 6089 * Perform hit-testing on a style. 6090 * 6091 * Results: 6092 * The name of the element containing the given point, or NULL. 6093 * 6094 * Side effects: 6095 * None. 6096 * 6097 *---------------------------------------------------------------------- 6098 */ 6099 6100char * 6101TreeStyle_Identify( 6102 StyleDrawArgs *drawArgs, /* Various args. */ 6103 int x, /* Window x-coord to hit-test against. */ 6104 int y /* Window y-coord to hit-test against. */ 6105 ) 6106{ 6107 TreeCtrl *tree = drawArgs->tree; 6108 IStyle *style = (IStyle *) drawArgs->style; 6109 MStyle *masterStyle = style->master; 6110 int state = drawArgs->state; 6111 IElementLink *eLink = NULL; 6112 int i, minWidth, minHeight; 6113 struct Layout staticLayouts[STATIC_SIZE], *layouts = staticLayouts; 6114 6115 Style_CheckNeededSize(tree, style, state); 6116#ifdef CACHE_STYLE_SIZE 6117 minWidth = style->minWidth; 6118 minHeight = style->minHeight; 6119#else 6120 Style_MinSize(tree, style, state, &minWidth, &minHeight); 6121#endif 6122 6123 if (drawArgs->width < minWidth + drawArgs->indent) 6124 drawArgs->width = minWidth + drawArgs->indent; 6125 if (drawArgs->height < minHeight) 6126 drawArgs->height = minHeight; 6127 6128 x -= drawArgs->x; 6129 6130 STATIC_ALLOC(layouts, struct Layout, masterStyle->numElements); 6131 6132 Style_DoLayout(drawArgs, layouts, FALSE, __FILE__, __LINE__); 6133 6134 for (i = style->master->numElements - 1; i >= 0; i--) { 6135 struct Layout *layout = &layouts[i]; 6136 6137 if (IS_HIDDEN(layout)) 6138 continue; 6139 6140 eLink = layout->eLink; 6141 if ((x >= layout->x + layout->ePadX[PAD_TOP_LEFT]) && (x < layout->x + layout->ePadX[PAD_TOP_LEFT] + layout->iWidth) && 6142 (y >= layout->y + layout->ePadY[PAD_TOP_LEFT]) && (y < layout->y + layout->ePadY[PAD_TOP_LEFT] + layout->iHeight)) { 6143 goto done; 6144 } 6145 } 6146 eLink = NULL; 6147done: 6148 STATIC_FREE(layouts, struct Layout, masterStyle->numElements); 6149 if (eLink != NULL) 6150 return (char *) eLink->elem->name; 6151 return NULL; 6152} 6153 6154/* 6155 *---------------------------------------------------------------------- 6156 * 6157 * TreeStyle_Identify2 -- 6158 * 6159 * Return a list of elements overlapping the given area. 6160 * 6161 * Results: 6162 * The names of any elements overlapping the given area are 6163 * appended to the supplied list. 6164 * 6165 * Side effects: 6166 * Memory is allocated. 6167 * 6168 *---------------------------------------------------------------------- 6169 */ 6170 6171void 6172TreeStyle_Identify2( 6173 StyleDrawArgs *drawArgs, /* Various args. */ 6174 int x1, int y1, /* Top-left of area to hit-test. */ 6175 int x2, int y2, /* Bottom-right of area to hit-test. */ 6176 Tcl_Obj *listObj /* Initialized list object to hold 6177 * the result. */ 6178 ) 6179{ 6180 TreeCtrl *tree = drawArgs->tree; 6181 IStyle *style = (IStyle *) drawArgs->style; 6182 MStyle *masterStyle = style->master; 6183 int state = drawArgs->state; 6184 IElementLink *eLink; 6185 int i, minWidth, minHeight; 6186 struct Layout staticLayouts[STATIC_SIZE], *layouts = staticLayouts; 6187 6188 Style_CheckNeededSize(tree, style, state); 6189#ifdef CACHE_STYLE_SIZE 6190 minWidth = style->minWidth; 6191 minHeight = style->minHeight; 6192#else 6193 Style_MinSize(tree, style, state, &minWidth, &minHeight); 6194#endif 6195 6196 if (drawArgs->width < minWidth + drawArgs->indent) 6197 drawArgs->width = minWidth + drawArgs->indent; 6198 if (drawArgs->height < minHeight) 6199 drawArgs->height = minHeight; 6200 6201 STATIC_ALLOC(layouts, struct Layout, masterStyle->numElements); 6202 6203 Style_DoLayout(drawArgs, layouts, FALSE, __FILE__, __LINE__); 6204 6205 for (i = style->master->numElements - 1; i >= 0; i--) { 6206 struct Layout *layout = &layouts[i]; 6207 6208 if (IS_HIDDEN(layout)) 6209 continue; 6210 6211 eLink = layout->eLink; 6212 if ((drawArgs->x + layout->x + layout->ePadX[PAD_TOP_LEFT] < x2) && 6213 (drawArgs->x + layout->x + layout->ePadX[PAD_TOP_LEFT] + layout->iWidth > x1) && 6214 (drawArgs->y + layout->y + layout->ePadY[PAD_TOP_LEFT] < y2) && 6215 (drawArgs->y + layout->y + layout->ePadY[PAD_TOP_LEFT] + layout->iHeight > y1)) { 6216 Tcl_ListObjAppendElement(drawArgs->tree->interp, listObj, 6217 Tcl_NewStringObj(eLink->elem->name, -1)); 6218 } 6219 } 6220 6221 STATIC_FREE(layouts, struct Layout, masterStyle->numElements); 6222} 6223 6224/* 6225 *---------------------------------------------------------------------- 6226 * 6227 * TreeStyle_Remap -- 6228 * 6229 * The guts of the [item style map] command. See the user 6230 * documentation for details on what it does. 6231 * 6232 * Results: 6233 * A standard Tcl result. 6234 * 6235 * Side effects: 6236 * See the user documentation. 6237 * 6238 *---------------------------------------------------------------------- 6239 */ 6240 6241int 6242TreeStyle_Remap( 6243 TreeCtrl *tree, /* Widget info. */ 6244 TreeStyle styleFrom_, /* Current instance style. */ 6245 TreeStyle styleTo_, /* Master style to "convert" the current 6246 * style to. */ 6247 int objc, /* Must be even number. */ 6248 Tcl_Obj *CONST objv[] /* Array of old-new element names. */ 6249 ) 6250{ 6251 IStyle *styleFrom = (IStyle *) styleFrom_; 6252 MStyle *styleTo = (MStyle *) styleTo_; 6253 int i, indexFrom, indexTo; 6254 int staticMap[STATIC_SIZE], *map = staticMap; 6255 IElementLink *eLink; 6256 TreeElement elemFrom, elemTo; 6257 TreeElement staticElemMap[STATIC_SIZE], *elemMap = staticElemMap; 6258 int styleFromNumElements = styleFrom->master->numElements; 6259 int result = TCL_OK; 6260 6261 /* Must be instance */ 6262 if ((styleFrom == NULL) || (styleFrom->master == NULL)) 6263 return TCL_ERROR; 6264 6265 /* Must be master */ 6266 if ((styleTo == NULL) || (styleTo->master != NULL)) 6267 return TCL_ERROR; 6268 6269 /* Nothing to do */ 6270 if (styleFrom->master == styleTo) 6271 return TCL_OK; 6272 6273 if (objc & 1) 6274 return TCL_ERROR; 6275 6276 STATIC_ALLOC(map, int, styleFromNumElements); 6277 STATIC_ALLOC(elemMap, TreeElement, styleFromNumElements); 6278 6279 for (i = 0; i < styleFromNumElements; i++) 6280 map[i] = -1; 6281 6282 for (i = 0; i < objc; i += 2) { 6283 /* Get the old-style element */ 6284 if (Element_FromObj(tree, objv[i], &elemFrom) != TCL_OK) { 6285 result = TCL_ERROR; 6286 goto done; 6287 } 6288 6289 /* Verify the old style uses the element */ 6290 if (MStyle_FindElem(tree, styleFrom->master, elemFrom, &indexFrom) == NULL) { 6291 FormatResult(tree->interp, "style %s does not use element %s", 6292 styleFrom->master->name, elemFrom->name); 6293 result = TCL_ERROR; 6294 goto done; 6295 } 6296 6297 /* Get the new-style element */ 6298 if (Element_FromObj(tree, objv[i + 1], &elemTo) != TCL_OK) { 6299 result = TCL_ERROR; 6300 goto done; 6301 } 6302 6303 /* Verify the new style uses the element */ 6304 if (MStyle_FindElem(tree, styleTo, elemTo, &indexTo) == NULL) { 6305 FormatResult(tree->interp, "style %s does not use element %s", 6306 styleTo->name, elemTo->name); 6307 result = TCL_ERROR; 6308 goto done; 6309 } 6310 6311 /* Must be the same type */ 6312 if (elemFrom->typePtr != elemTo->typePtr) { 6313 FormatResult(tree->interp, "can't map element type %s to %s", 6314 elemFrom->typePtr->name, elemTo->typePtr->name); 6315 result = TCL_ERROR; 6316 goto done; 6317 } 6318 6319 /* See if the instance style has any info for this element */ 6320 eLink = &styleFrom->elements[indexFrom]; 6321 if (eLink->elem->master != NULL) { 6322 map[indexFrom] = indexTo; 6323 elemMap[indexFrom] = eLink->elem; 6324 } 6325 } 6326 6327 for (i = 0; i < styleFromNumElements; i++) { 6328 eLink = &styleFrom->elements[i]; 6329 indexTo = map[i]; 6330 6331 /* Free info for any Elements not being remapped */ 6332 if ((indexTo == -1) && (eLink->elem->master != NULL)) { 6333 elemFrom = eLink->elem->master; 6334 Element_FreeResources(tree, eLink->elem); 6335 eLink->elem = elemFrom; 6336 } 6337 6338 /* Remap this Element */ 6339 if (indexTo != -1) { 6340 elemMap[i]->master = styleTo->elements[indexTo].elem; 6341 elemMap[i]->name = styleTo->elements[indexTo].elem->name; 6342 } 6343 } 6344 6345 if (styleFromNumElements != styleTo->numElements) { 6346#ifdef ALLOC_HAX 6347 if (styleFromNumElements > 0) 6348 TreeAlloc_CFree(tree->allocData, IElementLinkUid, 6349 (char *) styleFrom->elements, sizeof(IElementLink), 6350 styleFromNumElements, ELEMENT_LINK_ROUND); 6351 styleFrom->elements = (IElementLink *) TreeAlloc_CAlloc(tree->allocData, 6352 IElementLinkUid, sizeof(IElementLink), styleTo->numElements, 6353 ELEMENT_LINK_ROUND); 6354#else 6355 if (styleFromNumElements > 0) 6356 WCFREE(styleFrom->elements, IElementLink, styleFromNumElements); 6357 styleFrom->elements = (IElementLink *) ckalloc(sizeof(IElementLink) * 6358 styleTo->numElements); 6359#endif 6360 memset(styleFrom->elements, '\0', sizeof(IElementLink) * styleTo->numElements); 6361 } 6362 for (i = 0; i < styleTo->numElements; i++) { 6363 styleFrom->elements[i].elem = styleTo->elements[i].elem; 6364#ifdef CACHE_ELEM_SIZE 6365 styleFrom->elements[i].neededWidth = -1; 6366 styleFrom->elements[i].neededHeight = -1; 6367#endif 6368 } 6369 for (i = 0; i < styleFromNumElements; i++) { 6370 indexTo = map[i]; 6371 if (indexTo != -1) 6372 styleFrom->elements[indexTo].elem = elemMap[i]; 6373 } 6374 styleFrom->master = styleTo; 6375 styleFrom->neededWidth = styleFrom->neededHeight = -1; 6376 6377done: 6378 STATIC_FREE(map, int, styleFromNumElements); 6379 STATIC_FREE(elemMap, TreeElement, styleFromNumElements); 6380 return result; 6381} 6382 6383/* 6384 *---------------------------------------------------------------------- 6385 * 6386 * TreeStyle_GetSortData -- 6387 * 6388 * Called by the [item sort] code. Returns a long, double or 6389 * string value from a text element. 6390 * 6391 * Results: 6392 * A standard Tcl result. 6393 * 6394 * Side effects: 6395 * None. 6396 * 6397 *---------------------------------------------------------------------- 6398 */ 6399 6400int 6401TreeStyle_GetSortData( 6402 TreeCtrl *tree, /* Widget info. */ 6403 TreeStyle style_, /* The style. */ 6404 int elemIndex, /* Index of a text element, or -1 to use 6405 * the first text element. */ 6406 int type, /* SORT_xxx constant. */ 6407 long *lv, /* Returned for SORT_LONG. */ 6408 double *dv, /* Returned for SORT_DOUBLE. */ 6409 char **sv /* Returned for SORT_ASCII or SORT_DICT. */ 6410 ) 6411{ 6412 IStyle *style = (IStyle *) style_; 6413 IElementLink *eLink = style->elements; 6414 int i; 6415 6416 if (elemIndex == -1) { 6417 for (i = 0; i < style->master->numElements; i++) { 6418 if (ELEMENT_TYPE_MATCHES(eLink->elem->typePtr, &treeElemTypeText)) 6419 return TreeElement_GetSortData(tree, eLink->elem, type, lv, dv, sv); 6420 eLink++; 6421 } 6422 } else { 6423 if ((elemIndex < 0) || (elemIndex >= style->master->numElements)) 6424 panic("bad elemIndex %d to TreeStyle_GetSortData", elemIndex); 6425 eLink = &style->elements[elemIndex]; 6426 if (ELEMENT_TYPE_MATCHES(eLink->elem->typePtr, &treeElemTypeText)) 6427 return TreeElement_GetSortData(tree, eLink->elem, type, lv, dv, sv); 6428 } 6429 6430 FormatResult(tree->interp, "can't find text element in style %s", 6431 style->master->name); 6432 return TCL_ERROR; 6433} 6434 6435#if 0 6436 6437/* 6438 *---------------------------------------------------------------------- 6439 * 6440 * TreeStyle_ValidateElements -- 6441 * 6442 * Verify that each object in an objv[] array refers to a 6443 * master element. 6444 * 6445 * Results: 6446 * A standard Tcl result. 6447 * 6448 * Side effects: 6449 * None. 6450 * 6451 *---------------------------------------------------------------------- 6452 */ 6453 6454int 6455TreeStyle_ValidateElements( 6456 TreeCtrl *tree, /* Widget info. */ 6457 TreeStyle style_, /* Instance style. */ 6458 int objc, /* Number of element names. */ 6459 Tcl_Obj *CONST objv[] /* Array of element names. */ 6460 ) 6461{ 6462 IStyle *style = (IStyle *) style_; 6463 MStyle *master = style->master; 6464 TreeElement elem; 6465 MElementLink *eLink; 6466 int i; 6467 6468 for (i = 0; i < objc; i++) { 6469 if (Element_FromObj(tree, objv[i], &elem) != TCL_OK) 6470 return TCL_ERROR; 6471 6472 eLink = MStyle_FindElem(tree, master, elem, NULL); 6473 if (eLink == NULL) { 6474 FormatResult(tree->interp, 6475 "style %s does not use element %s", 6476 master->name, elem->name); 6477 return TCL_ERROR; 6478 } 6479 } 6480 return TCL_OK; 6481} 6482 6483#endif /* 0 */ 6484 6485/* 6486 *---------------------------------------------------------------------- 6487 * 6488 * TreeStyle_GetElemRects -- 6489 * 6490 * Return a list of rectangles for specified elements in a style. 6491 * 6492 * Results: 6493 * The number of rects[] written. 6494 * 6495 * Side effects: 6496 * None. 6497 * 6498 *---------------------------------------------------------------------- 6499 */ 6500 6501int 6502TreeStyle_GetElemRects( 6503 StyleDrawArgs *drawArgs, /* Various args. */ 6504 int objc, /* Number of element names. */ 6505 Tcl_Obj *CONST objv[], /* Array of element names. */ 6506 TreeRectangle rects[] /* Returned rectangles. */ 6507 ) 6508 6509{ 6510 IStyle *style = (IStyle *) drawArgs->style; 6511 MStyle *master = style->master; 6512 int i, j, count = 0, minWidth, minHeight; 6513 struct Layout staticLayouts[STATIC_SIZE], *layouts = staticLayouts; 6514 TreeElement staticElems[STATIC_SIZE], *elems = staticElems; 6515 MElementLink *eLink; 6516 6517 STATIC_ALLOC(elems, TreeElement, objc); 6518 6519 for (j = 0; j < objc; j++) { 6520 if (Element_FromObj(drawArgs->tree, objv[j], &elems[j]) != TCL_OK) { 6521 count = -1; 6522 goto done; 6523 } 6524 6525 eLink = MStyle_FindElem(drawArgs->tree, master, elems[j], NULL); 6526 if (eLink == NULL) { 6527 FormatResult(drawArgs->tree->interp, 6528 "style %s does not use element %s", 6529 master->name, elems[j]->name); 6530 count = -1; 6531 goto done; 6532 } 6533 } 6534 6535#ifdef CACHE_STYLE_SIZE 6536 minWidth = style->minWidth; 6537 minHeight = style->minHeight; 6538#else 6539 Style_MinSize(drawArgs->tree, style, drawArgs->state, &minWidth, &minHeight); 6540#endif 6541 6542 if (drawArgs->width < minWidth + drawArgs->indent) 6543 drawArgs->width = minWidth + drawArgs->indent; 6544 if (drawArgs->height < minHeight) 6545 drawArgs->height = minHeight; 6546 6547 STATIC_ALLOC(layouts, struct Layout, master->numElements); 6548 6549 Style_DoLayout(drawArgs, layouts, FALSE, __FILE__, __LINE__); 6550 6551 for (i = master->numElements - 1; i >= 0; i--) { 6552 struct Layout *layout = &layouts[i]; 6553 6554 if (IS_HIDDEN(layout)) 6555 continue; 6556 6557 if (objc > 0) { 6558 for (j = 0; j < objc; j++) 6559 if (elems[j] == layout->eLink->elem || 6560 elems[j] == layout->master->elem) 6561 break; 6562 if (j == objc) 6563 continue; 6564 } 6565 rects[count].x = drawArgs->x + layout->x + layout->ePadX[PAD_TOP_LEFT]; 6566 rects[count].y = drawArgs->y + layout->y + layout->ePadY[PAD_TOP_LEFT]; 6567 if (layout->master->onion == NULL) { 6568 rects[count].x += layout->iPadX[PAD_TOP_LEFT]; 6569 rects[count].y += layout->iPadY[PAD_TOP_LEFT]; 6570 rects[count].width = layout->useWidth; 6571 rects[count].height = layout->useHeight; 6572 } else { 6573 rects[count].width = layout->iWidth; 6574 rects[count].height = layout->iHeight; 6575 } 6576 count++; 6577 } 6578 6579 STATIC_FREE(layouts, struct Layout, master->numElements); 6580 6581done: 6582 STATIC_FREE(elems, TreeElement, objc); 6583 return count; 6584} 6585 6586/* 6587 *---------------------------------------------------------------------- 6588 * 6589 * TreeStyle_ChangeState -- 6590 * 6591 * Called when the state of an item or item-column changes. 6592 * 6593 * Results: 6594 * A bitmask of CS_DISPLAY and CS_LAYOUT values. 6595 * 6596 * Side effects: 6597 * None. 6598 * 6599 *---------------------------------------------------------------------- 6600 */ 6601 6602int 6603TreeStyle_ChangeState( 6604 TreeCtrl *tree, /* Widget info. */ 6605 TreeStyle style_, /* The instance style. */ 6606 int state1, /* The previous state. */ 6607 int state2 /* The current state. */ 6608 ) 6609{ 6610 IStyle *style = (IStyle *) style_; 6611 MStyle *masterStyle = style->master; 6612 MElementLink *eLink1; 6613 IElementLink *eLink2; 6614 TreeElementArgs args; 6615 int i, eMask, mask = 0; 6616 int undisplay; 6617 6618 if (state1 == state2) 6619 return 0; 6620 6621 args.tree = tree; 6622 6623 for (i = 0; i < masterStyle->numElements; i++) { 6624 eLink2 = &style->elements[i]; 6625 args.elem = eLink2->elem; 6626 args.states.state1 = state1; 6627 args.states.state2 = state2; 6628 args.states.draw1 = args.states.draw2 = TRUE; 6629 args.states.visible1 = args.states.visible2 = TRUE; 6630 6631 eLink1 = &masterStyle->elements[i]; 6632 undisplay = FALSE; 6633 eMask = 0; 6634 6635 /* Check for the style layout option -draw changing. */ 6636 if (eLink1->draw.count > 0) { 6637 args.states.draw1 = PerStateBoolean_ForState(tree, 6638 &eLink1->draw, state1, NULL) != 0; 6639 args.states.draw2 = PerStateBoolean_ForState(tree, 6640 &eLink1->draw, state2, NULL) != 0; 6641 if (args.states.draw1 != args.states.draw2) { 6642 eMask |= CS_DISPLAY; 6643 if (!args.states.draw2) 6644 undisplay = TRUE; 6645 } 6646 } 6647 6648 /* Check for the style layout option -visible changing. */ 6649 if (eLink1->visible.count > 0) { 6650 args.states.visible1 = PerStateBoolean_ForState(tree, 6651 &eLink1->visible, state1, NULL) != 0; 6652 args.states.visible2 = PerStateBoolean_ForState(tree, 6653 &eLink1->visible, state2, NULL) != 0; 6654 /* FIXME: Changing visibility might not change the layout. */ 6655 if (args.states.visible1 != args.states.visible2) { 6656 eMask |= CS_DISPLAY | CS_LAYOUT; 6657 if (!args.states.visible2) 6658 undisplay = TRUE; 6659 } 6660 } 6661 6662 /* Tell the element about the state change. */ 6663 eMask |= (*args.elem->typePtr->stateProc)(&args); 6664 6665 /* Hack: If a window element becomes hidden, then tell it it is 6666 * not onscreen, otherwise it will never be "drawn" in the 6667 * hidden state. */ 6668 if (undisplay && ELEMENT_TYPE_MATCHES(args.elem->typePtr, 6669 &treeElemTypeWindow)) { 6670 args.screen.visible = FALSE; 6671 (*args.elem->typePtr->onScreenProc)(&args); 6672 } 6673 6674 if (eMask) { 6675#ifdef CACHE_ELEM_SIZE 6676 if (eMask & CS_LAYOUT) 6677 eLink2->neededWidth = eLink2->neededHeight = -1; 6678#endif 6679 mask |= eMask; 6680 } 6681 } 6682 6683 if (mask & CS_LAYOUT) 6684 style->neededWidth = style->neededHeight = -1; 6685 6686#ifdef TREECTRL_DEBUG 6687 if (style->neededWidth != -1) 6688 style->neededState = state2; 6689#endif 6690 6691 return mask; 6692} 6693 6694/* 6695 *---------------------------------------------------------------------- 6696 * 6697 * Tree_UndefineState -- 6698 * 6699 * The guts of the [state undefine] widget command. 6700 * 6701 * Results: 6702 * The undefProc of every element is called to respond to the 6703 * undefined state flag. The size of every element/column/item is 6704 * marked out-of-date regardless of whether the state change 6705 * affected the element. 6706 * 6707 * Side effects: 6708 * Display changes. 6709 * 6710 *---------------------------------------------------------------------- 6711 */ 6712 6713void 6714Tree_UndefineState( 6715 TreeCtrl *tree, /* Widget info. */ 6716 int state /* STATE_xxx flag. */ 6717 ) 6718{ 6719 TreeItem item; 6720 TreeItemColumn column; 6721 Tcl_HashEntry *hPtr; 6722 Tcl_HashSearch search; 6723 IElementLink *eLink; 6724 int i, columnIndex; 6725 TreeElementArgs args; 6726 6727 /* Undefine the state for the -draw and -visible style layout 6728 * options for each element of this style. */ 6729 hPtr = Tcl_FirstHashEntry(&tree->styleHash, &search); 6730 while (hPtr != NULL) { 6731 MStyle *masterStyle = (MStyle *) Tcl_GetHashValue(hPtr); 6732 for (i = 0; i < masterStyle->numElements; i++) { 6733 MElementLink *eLink1 = &masterStyle->elements[i]; 6734 PerStateInfo_Undefine(tree, &pstBoolean, &eLink1->draw, state); 6735 PerStateInfo_Undefine(tree, &pstBoolean, &eLink1->visible, state); 6736 } 6737 hPtr = Tcl_NextHashEntry(&search); 6738 } 6739 6740 args.tree = tree; 6741 args.state = state; 6742 6743 hPtr = Tcl_FirstHashEntry(&tree->itemHash, &search); 6744 while (hPtr != NULL) { 6745 item = (TreeItem) Tcl_GetHashValue(hPtr); 6746 column = TreeItem_GetFirstColumn(tree, item); 6747 columnIndex = 0; 6748 while (column != NULL) { 6749 IStyle *style = (IStyle *) TreeItemColumn_GetStyle(tree, column); 6750 if (style != NULL) { 6751 for (i = 0; i < style->master->numElements; i++) { 6752 eLink = &style->elements[i]; 6753 /* Instance element */ 6754 if (eLink->elem->master != NULL) { 6755 args.elem = eLink->elem; 6756 (*args.elem->typePtr->undefProc)(&args); 6757 } 6758#ifdef CACHE_ELEM_SIZE 6759 eLink->neededWidth = eLink->neededHeight = -1; 6760#endif 6761 } 6762 style->neededWidth = style->neededHeight = -1; 6763 TreeItemColumn_InvalidateSize(tree, column); 6764 } 6765 columnIndex++; 6766 column = TreeItemColumn_GetNext(tree, column); 6767 } 6768 TreeItem_InvalidateHeight(tree, item); 6769 Tree_FreeItemDInfo(tree, item, NULL); 6770 TreeItem_UndefineState(tree, item, state); 6771 hPtr = Tcl_NextHashEntry(&search); 6772 } 6773 Tree_InvalidateColumnWidth(tree, NULL); 6774 Tree_DInfoChanged(tree, DINFO_REDO_RANGES); 6775 6776 hPtr = Tcl_FirstHashEntry(&tree->elementHash, &search); 6777 while (hPtr != NULL) { 6778 args.elem = (TreeElement) Tcl_GetHashValue(hPtr); 6779 (*args.elem->typePtr->undefProc)(&args); 6780 hPtr = Tcl_NextHashEntry(&search); 6781 } 6782} 6783 6784/* 6785 *---------------------------------------------------------------------- 6786 * 6787 * TreeStyle_NumElements -- 6788 * 6789 * Return the number of elements in a style. 6790 * 6791 * Results: 6792 * The number of... oh nevermind. 6793 * 6794 * Side effects: 6795 * None. 6796 * 6797 *---------------------------------------------------------------------- 6798 */ 6799 6800int 6801TreeStyle_NumElements( 6802 TreeCtrl *tree, /* Widget info. */ 6803 TreeStyle style_ /* The style. */ 6804 ) 6805{ 6806 MStyle *masterStyle = ((MStyle *) style_); 6807 IStyle *style = ((IStyle *) style_); 6808 return (style->master == NULL) ? 6809 masterStyle->numElements : 6810 style->master->numElements; 6811} 6812 6813/* 6814 *---------------------------------------------------------------------- 6815 * 6816 * TreeStyle_Init -- 6817 * 6818 * Style-related package initialization. 6819 * 6820 * Results: 6821 * A standard Tcl result. 6822 * 6823 * Side effects: 6824 * None. 6825 * 6826 *---------------------------------------------------------------------- 6827 */ 6828 6829int 6830TreeStyle_Init( 6831 TreeCtrl *tree /* Widget info. */ 6832 ) 6833{ 6834 tree->styleOptionTable = Tk_CreateOptionTable(tree->interp, 6835 styleOptionSpecs); 6836 return TCL_OK; 6837} 6838 6839/* 6840 *---------------------------------------------------------------------- 6841 * 6842 * TreeStyle_Free -- 6843 * 6844 * Free style-related resources for a deleted TreeCtrl. 6845 * 6846 * Results: 6847 * None. 6848 * 6849 * Side effects: 6850 * Memory is freed. 6851 * 6852 *---------------------------------------------------------------------- 6853 */ 6854 6855void 6856TreeStyle_Free( 6857 TreeCtrl *tree /* Widget info. */ 6858 ) 6859{ 6860 Tcl_HashEntry *hPtr; 6861 Tcl_HashSearch search; 6862 TreeElement elem; 6863 TreeStyle style; 6864 6865 while (1) { 6866 hPtr = Tcl_FirstHashEntry(&tree->styleHash, &search); 6867 if (hPtr == NULL) 6868 break; 6869 style = (TreeStyle) Tcl_GetHashValue(hPtr); 6870 TreeStyle_FreeResources(tree, style); 6871 } 6872 6873 while (1) { 6874 hPtr = Tcl_FirstHashEntry(&tree->elementHash, &search); 6875 if (hPtr == NULL) 6876 break; 6877 elem = (TreeElement) Tcl_GetHashValue(hPtr); 6878 Element_FreeResources(tree, elem); 6879 } 6880 6881 Tcl_DeleteHashTable(&tree->elementHash); 6882 Tcl_DeleteHashTable(&tree->styleHash); 6883} 6884 6885