1/* 2 * tkTableCmds.c -- 3 * 4 * This module implements general commands of a table widget, 5 * based on the major/minor command structure. 6 * 7 * Copyright (c) 1998-2002 Jeffrey Hobbs 8 * 9 * See the file "license.txt" for information on usage and redistribution 10 * of this file, and for a DISCLAIMER OF ALL WARRANTIES. 11 * 12 */ 13 14#include "tkTable.h" 15 16/* 17 *-------------------------------------------------------------- 18 * 19 * Table_ActivateCmd -- 20 * This procedure is invoked to process the activate method 21 * that corresponds to a table widget managed by this module. 22 * See the user documentation for details on what it does. 23 * 24 * Results: 25 * A standard Tcl result. 26 * 27 * Side effects: 28 * See the user documentation. 29 * 30 *-------------------------------------------------------------- 31 */ 32int 33Table_ActivateCmd(ClientData clientData, register Tcl_Interp *interp, 34 int objc, Tcl_Obj *CONST objv[]) 35{ 36 register Table *tablePtr = (Table *) clientData; 37 int result = TCL_OK; 38 int row, col, templen; 39 40 if (objc != 3) { 41 Tcl_WrongNumArgs(interp, 2, objv, "index"); 42 return TCL_ERROR; 43 } else if (Tcl_GetStringFromObj(objv[2], &templen), templen == 0) { 44 /* 45 * Test implementation to clear active cell (becroft) 46 */ 47 tablePtr->flags &= ~HAS_ACTIVE; 48 tablePtr->flags |= ACTIVE_DISABLED; 49 tablePtr->activeRow = -1; 50 tablePtr->activeCol = -1; 51 TableAdjustActive(tablePtr); 52 TableConfigCursor(tablePtr); 53 } else if (TableGetIndexObj(tablePtr, objv[2], &row, &col) != TCL_OK) { 54 return TCL_ERROR; 55 } else { 56 int x, y, w, dummy; 57 char buf1[INDEX_BUFSIZE], buf2[INDEX_BUFSIZE]; 58 59 /* convert to valid active index in real coords */ 60 row -= tablePtr->rowOffset; 61 col -= tablePtr->colOffset; 62 /* we do this regardless, to avoid cell commit problems */ 63 if ((tablePtr->flags & HAS_ACTIVE) && 64 (tablePtr->flags & TEXT_CHANGED)) { 65 tablePtr->flags &= ~TEXT_CHANGED; 66 TableSetCellValue(tablePtr, 67 tablePtr->activeRow+tablePtr->rowOffset, 68 tablePtr->activeCol+tablePtr->colOffset, 69 tablePtr->activeBuf); 70 } 71 if (row != tablePtr->activeRow || col != tablePtr->activeCol) { 72 if (tablePtr->flags & HAS_ACTIVE) { 73 TableMakeArrayIndex(tablePtr->activeRow+tablePtr->rowOffset, 74 tablePtr->activeCol+tablePtr->colOffset, 75 buf1); 76 } else { 77 buf1[0] = '\0'; 78 } 79 tablePtr->flags |= HAS_ACTIVE; 80 tablePtr->flags &= ~ACTIVE_DISABLED; 81 tablePtr->activeRow = row; 82 tablePtr->activeCol = col; 83 if (tablePtr->activeTagPtr != NULL) { 84 ckfree((char *) (tablePtr->activeTagPtr)); 85 tablePtr->activeTagPtr = NULL; 86 } 87 TableAdjustActive(tablePtr); 88 TableConfigCursor(tablePtr); 89 if (!(tablePtr->flags & BROWSE_CMD) && 90 tablePtr->browseCmd != NULL) { 91 Tcl_DString script; 92 tablePtr->flags |= BROWSE_CMD; 93 row = tablePtr->activeRow+tablePtr->rowOffset; 94 col = tablePtr->activeCol+tablePtr->colOffset; 95 TableMakeArrayIndex(row, col, buf2); 96 Tcl_DStringInit(&script); 97 ExpandPercents(tablePtr, tablePtr->browseCmd, row, col, 98 buf1, buf2, tablePtr->icursor, &script, 0); 99 result = Tcl_GlobalEval(interp, Tcl_DStringValue(&script)); 100 if (result == TCL_OK || result == TCL_RETURN) { 101 Tcl_ResetResult(interp); 102 } 103 Tcl_DStringFree(&script); 104 tablePtr->flags &= ~BROWSE_CMD; 105 } 106 } else { 107 char *p = Tcl_GetString(objv[2]); 108 109 if ((tablePtr->activeTagPtr != NULL) && *p == '@' && 110 !(tablePtr->flags & ACTIVE_DISABLED) && 111 TableCellVCoords(tablePtr, row, col, &x, &y, &w, &dummy, 0)) { 112 /* we are clicking into the same cell 113 * If it was activated with @x,y indexing, 114 * find the closest char */ 115 Tk_TextLayout textLayout; 116 TableTag *tagPtr = tablePtr->activeTagPtr; 117 118 /* no error checking because GetIndex did it for us */ 119 p++; 120 x = strtol(p, &p, 0) - x - tablePtr->activeX; 121 p++; 122 y = strtol(p, &p, 0) - y - tablePtr->activeY; 123 124 textLayout = Tk_ComputeTextLayout(tagPtr->tkfont, 125 tablePtr->activeBuf, -1, 126 (tagPtr->wrap) ? w : 0, 127 tagPtr->justify, 0, &dummy, &dummy); 128 129 tablePtr->icursor = Tk_PointToChar(textLayout, x, y); 130 Tk_FreeTextLayout(textLayout); 131 TableRefresh(tablePtr, row, col, CELL|INV_FORCE); 132 } 133 } 134 tablePtr->flags |= HAS_ACTIVE; 135 } 136 return result; 137} 138 139/* 140 *-------------------------------------------------------------- 141 * 142 * Table_AdjustCmd -- 143 * This procedure is invoked to process the width/height method 144 * that corresponds to a table widget managed by this module. 145 * See the user documentation for details on what it does. 146 * 147 * Results: 148 * A standard Tcl result. 149 * 150 * Side effects: 151 * See the user documentation. 152 * 153 *-------------------------------------------------------------- 154 */ 155int 156Table_AdjustCmd(ClientData clientData, register Tcl_Interp *interp, 157 int objc, Tcl_Obj *CONST objv[]) 158{ 159 register Table *tablePtr = (Table *) clientData; 160 Tcl_HashEntry *entryPtr; 161 Tcl_HashSearch search; 162 Tcl_HashTable *hashTablePtr; 163 int i, widthType, dummy, value, posn, offset; 164 char buf1[INDEX_BUFSIZE]; 165 166 widthType = (*(Tcl_GetString(objv[1])) == 'w'); 167 /* changes the width/height of certain selected columns */ 168 if (objc != 3 && (objc & 1)) { 169 Tcl_WrongNumArgs(interp, 2, objv, widthType ? 170 "?col? ?width col width ...?" : 171 "?row? ?height row height ...?"); 172 return TCL_ERROR; 173 } 174 if (widthType) { 175 hashTablePtr = tablePtr->colWidths; 176 offset = tablePtr->colOffset; 177 } else { 178 hashTablePtr = tablePtr->rowHeights; 179 offset = tablePtr->rowOffset; 180 } 181 182 if (objc == 2) { 183 /* print out all the preset column widths or row heights */ 184 entryPtr = Tcl_FirstHashEntry(hashTablePtr, &search); 185 while (entryPtr != NULL) { 186 posn = ((int) Tcl_GetHashKey(hashTablePtr, entryPtr)) + offset; 187 value = (int) Tcl_GetHashValue(entryPtr); 188 sprintf(buf1, "%d %d", posn, value); 189 /* OBJECTIFY */ 190 Tcl_AppendElement(interp, buf1); 191 entryPtr = Tcl_NextHashEntry(&search); 192 } 193 } else if (objc == 3) { 194 /* get the width/height of a particular row/col */ 195 if (Tcl_GetIntFromObj(interp, objv[2], &posn) != TCL_OK) { 196 return TCL_ERROR; 197 } 198 /* no range check is done, why bother? */ 199 posn -= offset; 200 entryPtr = Tcl_FindHashEntry(hashTablePtr, (char *) posn); 201 if (entryPtr != NULL) { 202 Tcl_SetIntObj(Tcl_GetObjResult(interp), 203 (int) Tcl_GetHashValue(entryPtr)); 204 } else { 205 Tcl_SetIntObj(Tcl_GetObjResult(interp), widthType ? 206 tablePtr->defColWidth : tablePtr->defRowHeight); 207 } 208 } else { 209 for (i=2; i<objc; i++) { 210 /* set new width|height here */ 211 value = -999999; 212 if (Tcl_GetIntFromObj(interp, objv[i++], &posn) != TCL_OK || 213 (strcmp(Tcl_GetString(objv[i]), "default") && 214 Tcl_GetIntFromObj(interp, objv[i], &value) != TCL_OK)) { 215 return TCL_ERROR; 216 } 217 posn -= offset; 218 if (value == -999999) { 219 /* reset that field */ 220 entryPtr = Tcl_FindHashEntry(hashTablePtr, (char *) posn); 221 if (entryPtr != NULL) { 222 Tcl_DeleteHashEntry(entryPtr); 223 } 224 } else { 225 entryPtr = Tcl_CreateHashEntry(hashTablePtr, 226 (char *) posn, &dummy); 227 Tcl_SetHashValue(entryPtr, (ClientData) value); 228 } 229 } 230 TableAdjustParams(tablePtr); 231 /* rerequest geometry */ 232 TableGeometryRequest(tablePtr); 233 /* 234 * Invalidate the whole window as TableAdjustParams 235 * will only check to see if the top left cell has moved 236 * FIX: should just move from lowest order visible cell 237 * to edge of window 238 */ 239 TableInvalidateAll(tablePtr, 0); 240 } 241 return TCL_OK; 242} 243 244/* 245 *-------------------------------------------------------------- 246 * 247 * Table_BboxCmd -- 248 * This procedure is invoked to process the bbox method 249 * that corresponds to a table widget managed by this module. 250 * See the user documentation for details on what it does. 251 * 252 * Results: 253 * A standard Tcl result. 254 * 255 * Side effects: 256 * See the user documentation. 257 * 258 *-------------------------------------------------------------- 259 */ 260int 261Table_BboxCmd(ClientData clientData, register Tcl_Interp *interp, 262 int objc, Tcl_Obj *CONST objv[]) 263{ 264 register Table *tablePtr = (Table *) clientData; 265 int x, y, w, h, row, col, key; 266 Tcl_Obj *resultPtr; 267 268 /* Returns bounding box of cell(s) */ 269 if (objc < 3 || objc > 4) { 270 Tcl_WrongNumArgs(interp, 2, objv, "first ?last?"); 271 return TCL_ERROR; 272 } else if (TableGetIndexObj(tablePtr, objv[2], &row, &col) == TCL_ERROR || 273 (objc == 4 && 274 TableGetIndexObj(tablePtr, objv[3], &x, &y) == TCL_ERROR)) { 275 return TCL_ERROR; 276 } 277 278 resultPtr = Tcl_GetObjResult(interp); 279 if (objc == 3) { 280 row -= tablePtr->rowOffset; col -= tablePtr->colOffset; 281 if (TableCellVCoords(tablePtr, row, col, &x, &y, &w, &h, 0)) { 282 Tcl_ListObjAppendElement(NULL, resultPtr, Tcl_NewIntObj(x)); 283 Tcl_ListObjAppendElement(NULL, resultPtr, Tcl_NewIntObj(y)); 284 Tcl_ListObjAppendElement(NULL, resultPtr, Tcl_NewIntObj(w)); 285 Tcl_ListObjAppendElement(NULL, resultPtr, Tcl_NewIntObj(h)); 286 } 287 return TCL_OK; 288 } else { 289 int r1, c1, r2, c2, minX = 99999, minY = 99999, maxX = 0, maxY = 0; 290 291 row -= tablePtr->rowOffset; col -= tablePtr->colOffset; 292 x -= tablePtr->rowOffset; y -= tablePtr->colOffset; 293 r1 = MIN(row,x); r2 = MAX(row,x); 294 c1 = MIN(col,y); c2 = MAX(col,y); 295 key = 0; 296 for (row = r1; row <= r2; row++) { 297 for (col = c1; col <= c2; col++) { 298 if (TableCellVCoords(tablePtr, row, col, &x, &y, &w, &h, 0)) { 299 /* Get max bounding box */ 300 if (x < minX) minX = x; 301 if (y < minY) minY = y; 302 if (x+w > maxX) maxX = x+w; 303 if (y+h > maxY) maxY = y+h; 304 key++; 305 } 306 } 307 } 308 if (key) { 309 Tcl_ListObjAppendElement(NULL, resultPtr, Tcl_NewIntObj(minX)); 310 Tcl_ListObjAppendElement(NULL, resultPtr, Tcl_NewIntObj(minY)); 311 Tcl_ListObjAppendElement(NULL, resultPtr, 312 Tcl_NewIntObj(maxX-minX)); 313 Tcl_ListObjAppendElement(NULL, resultPtr, 314 Tcl_NewIntObj(maxY-minY)); 315 } 316 } 317 return TCL_OK; 318} 319 320static CONST84 char *bdCmdNames[] = { 321 "mark", "dragto", (char *)NULL 322}; 323enum bdCmd { 324 BD_MARK, BD_DRAGTO 325}; 326 327/* 328 *-------------------------------------------------------------- 329 * 330 * Table_BorderCmd -- 331 * This procedure is invoked to process the bbox method 332 * that corresponds to a table widget managed by this module. 333 * See the user documentation for details on what it does. 334 * 335 * Results: 336 * A standard Tcl result. 337 * 338 * Side effects: 339 * See the user documentation. 340 * 341 *-------------------------------------------------------------- 342 */ 343int 344Table_BorderCmd(ClientData clientData, register Tcl_Interp *interp, 345 int objc, Tcl_Obj *CONST objv[]) 346{ 347 register Table *tablePtr = (Table *) clientData; 348 Tcl_HashEntry *entryPtr; 349 int x, y, w, h, row, col, key, dummy, value, cmdIndex; 350 char *rc = NULL; 351 Tcl_Obj *objPtr, *resultPtr; 352 353 if (objc < 5 || objc > 6) { 354 Tcl_WrongNumArgs(interp, 2, objv, "mark|dragto x y ?row|col?"); 355 return TCL_ERROR; 356 } 357 if (Tcl_GetIndexFromObj(interp, objv[2], bdCmdNames, 358 "option", 0, &cmdIndex) != TCL_OK || 359 Tcl_GetIntFromObj(interp, objv[3], &x) != TCL_OK || 360 Tcl_GetIntFromObj(interp, objv[4], &y) != TCL_OK) { 361 return TCL_ERROR; 362 } 363 if (objc == 6) { 364 rc = Tcl_GetStringFromObj(objv[5], &w); 365 if ((w < 1) || (strncmp(rc, "row", w) && strncmp(rc, "col", w))) { 366 Tcl_WrongNumArgs(interp, 2, objv, "mark|dragto x y ?row|col?"); 367 return TCL_ERROR; 368 } 369 } 370 371 resultPtr = Tcl_GetObjResult(interp); 372 switch ((enum bdCmd) cmdIndex) { 373 case BD_MARK: 374 /* Use x && y to determine if we are over a border */ 375 value = TableAtBorder(tablePtr, x, y, &row, &col); 376 /* Cache the row && col for use in DRAGTO */ 377 tablePtr->scanMarkRow = row; 378 tablePtr->scanMarkCol = col; 379 if (!value) { 380 return TCL_OK; 381 } 382 TableCellCoords(tablePtr, row, col, &x, &y, &dummy, &dummy); 383 tablePtr->scanMarkX = x; 384 tablePtr->scanMarkY = y; 385 if (objc == 5 || *rc == 'r') { 386 if (row < 0) { 387 objPtr = Tcl_NewStringObj("", 0); 388 } else { 389 objPtr = Tcl_NewIntObj(row+tablePtr->rowOffset); 390 } 391 Tcl_ListObjAppendElement(NULL, resultPtr, objPtr); 392 } 393 if (objc == 5 || *rc == 'c') { 394 if (col < 0) { 395 objPtr = Tcl_NewStringObj("", 0); 396 } else { 397 objPtr = Tcl_NewIntObj(col+tablePtr->colOffset); 398 } 399 Tcl_ListObjAppendElement(NULL, resultPtr, objPtr); 400 } 401 return TCL_OK; /* BORDER MARK */ 402 403 case BD_DRAGTO: 404 /* check to see if we want to resize any borders */ 405 if (tablePtr->resize == SEL_NONE) { return TCL_OK; } 406 row = tablePtr->scanMarkRow; 407 col = tablePtr->scanMarkCol; 408 TableCellCoords(tablePtr, row, col, &w, &h, &dummy, &dummy); 409 key = 0; 410 if (row >= 0 && (tablePtr->resize & SEL_ROW)) { 411 /* row border was active, move it */ 412 value = y-h; 413 if (value < -1) value = -1; 414 if (value != tablePtr->scanMarkY) { 415 entryPtr = Tcl_CreateHashEntry(tablePtr->rowHeights, 416 (char *) row, &dummy); 417 /* -value means rowHeight will be interp'd as pixels, not 418 lines */ 419 Tcl_SetHashValue(entryPtr, (ClientData) MIN(0,-value)); 420 tablePtr->scanMarkY = value; 421 key++; 422 } 423 } 424 if (col >= 0 && (tablePtr->resize & SEL_COL)) { 425 /* col border was active, move it */ 426 value = x-w; 427 if (value < -1) value = -1; 428 if (value != tablePtr->scanMarkX) { 429 entryPtr = Tcl_CreateHashEntry(tablePtr->colWidths, 430 (char *) col, &dummy); 431 /* -value means colWidth will be interp'd as pixels, not 432 chars */ 433 Tcl_SetHashValue(entryPtr, (ClientData) MIN(0,-value)); 434 tablePtr->scanMarkX = value; 435 key++; 436 } 437 } 438 /* Only if something changed do we want to update */ 439 if (key) { 440 TableAdjustParams(tablePtr); 441 /* Only rerequest geometry if the basis is the #rows &| #cols */ 442 if (tablePtr->maxReqCols || tablePtr->maxReqRows) 443 TableGeometryRequest(tablePtr); 444 TableInvalidateAll(tablePtr, 0); 445 } 446 return TCL_OK; /* BORDER DRAGTO */ 447 } 448 return TCL_OK; 449} 450 451/* clear subcommands */ 452static CONST84 char *clearNames[] = { 453 "all", "cache", "sizes", "tags", (char *)NULL 454}; 455enum clearCommand { 456 CLEAR_ALL, CLEAR_CACHE, CLEAR_SIZES, CLEAR_TAGS 457}; 458 459/* 460 *-------------------------------------------------------------- 461 * 462 * Table_ClearCmd -- 463 * This procedure is invoked to process the clear method 464 * that corresponds to a table widget managed by this module. 465 * See the user documentation for details on what it does. 466 * 467 * Results: 468 * Cached info can be lost. Returns valid Tcl result. 469 * 470 * Side effects: 471 * Can cause redraw. 472 * See the user documentation. 473 * 474 *-------------------------------------------------------------- 475 */ 476int 477Table_ClearCmd(ClientData clientData, register Tcl_Interp *interp, 478 int objc, Tcl_Obj *CONST objv[]) 479{ 480 register Table *tablePtr = (Table *) clientData; 481 int cmdIndex, redraw = 0; 482 483 if (objc < 3 || objc > 5) { 484 Tcl_WrongNumArgs(interp, 2, objv, "option ?first? ?last?"); 485 return TCL_ERROR; 486 } 487 488 if (Tcl_GetIndexFromObj(interp, objv[2], clearNames, 489 "clear option", 0, &cmdIndex) != TCL_OK) { 490 return TCL_ERROR; 491 } 492 493 if (objc == 3) { 494 if (cmdIndex == CLEAR_TAGS || cmdIndex == CLEAR_ALL) { 495 Tcl_DeleteHashTable(tablePtr->rowStyles); 496 Tcl_DeleteHashTable(tablePtr->colStyles); 497 Tcl_DeleteHashTable(tablePtr->cellStyles); 498 Tcl_DeleteHashTable(tablePtr->flashCells); 499 Tcl_DeleteHashTable(tablePtr->selCells); 500 501 /* style hash tables */ 502 Tcl_InitHashTable(tablePtr->rowStyles, TCL_ONE_WORD_KEYS); 503 Tcl_InitHashTable(tablePtr->colStyles, TCL_ONE_WORD_KEYS); 504 Tcl_InitHashTable(tablePtr->cellStyles, TCL_STRING_KEYS); 505 506 /* special style hash tables */ 507 Tcl_InitHashTable(tablePtr->flashCells, TCL_STRING_KEYS); 508 Tcl_InitHashTable(tablePtr->selCells, TCL_STRING_KEYS); 509 } 510 511 if (cmdIndex == CLEAR_SIZES || cmdIndex == CLEAR_ALL) { 512 Tcl_DeleteHashTable(tablePtr->colWidths); 513 Tcl_DeleteHashTable(tablePtr->rowHeights); 514 515 /* style hash tables */ 516 Tcl_InitHashTable(tablePtr->colWidths, TCL_ONE_WORD_KEYS); 517 Tcl_InitHashTable(tablePtr->rowHeights, TCL_ONE_WORD_KEYS); 518 } 519 520 if (cmdIndex == CLEAR_CACHE || cmdIndex == CLEAR_ALL) { 521 Table_ClearHashTable(tablePtr->cache); 522 Tcl_InitHashTable(tablePtr->cache, TCL_STRING_KEYS); 523 /* If we were caching and we have no other data source, 524 * invalidate all the cells */ 525 if (tablePtr->dataSource == DATA_CACHE) { 526 TableGetActiveBuf(tablePtr); 527 } 528 } 529 redraw = 1; 530 } else { 531 int row, col, r1, r2, c1, c2; 532 Tcl_HashEntry *entryPtr; 533 char buf[INDEX_BUFSIZE], *value; 534 535 if (TableGetIndexObj(tablePtr, objv[3], &row, &col) != TCL_OK || 536 ((objc == 5) && 537 TableGetIndexObj(tablePtr, objv[4], &r2, &c2) != TCL_OK)) { 538 return TCL_ERROR; 539 } 540 if (objc == 4) { 541 r1 = r2 = row; 542 c1 = c2 = col; 543 } else { 544 r1 = MIN(row,r2); r2 = MAX(row,r2); 545 c1 = MIN(col,c2); c2 = MAX(col,c2); 546 } 547 for (row = r1; row <= r2; row++) { 548 /* Note that *Styles entries are user based (no offset) 549 * while size entries are 0-based (real) */ 550 if ((cmdIndex == CLEAR_TAGS || cmdIndex == CLEAR_ALL) && 551 (entryPtr = Tcl_FindHashEntry(tablePtr->rowStyles, 552 (char *) row))) { 553 Tcl_DeleteHashEntry(entryPtr); 554 redraw = 1; 555 } 556 557 if ((cmdIndex == CLEAR_SIZES || cmdIndex == CLEAR_ALL) && 558 (entryPtr = Tcl_FindHashEntry(tablePtr->rowHeights, 559 (char *) row-tablePtr->rowOffset))) { 560 Tcl_DeleteHashEntry(entryPtr); 561 redraw = 1; 562 } 563 564 for (col = c1; col <= c2; col++) { 565 TableMakeArrayIndex(row, col, buf); 566 567 if (cmdIndex == CLEAR_TAGS || cmdIndex == CLEAR_ALL) { 568 if ((row == r1) && 569 (entryPtr = Tcl_FindHashEntry(tablePtr->colStyles, 570 (char *) col))) { 571 Tcl_DeleteHashEntry(entryPtr); 572 redraw = 1; 573 } 574 if ((entryPtr = Tcl_FindHashEntry(tablePtr->cellStyles, 575 buf))) { 576 Tcl_DeleteHashEntry(entryPtr); 577 redraw = 1; 578 } 579 if ((entryPtr = Tcl_FindHashEntry(tablePtr->flashCells, 580 buf))) { 581 Tcl_DeleteHashEntry(entryPtr); 582 redraw = 1; 583 } 584 if ((entryPtr = Tcl_FindHashEntry(tablePtr->selCells, 585 buf))) { 586 Tcl_DeleteHashEntry(entryPtr); 587 redraw = 1; 588 } 589 } 590 591 if ((cmdIndex == CLEAR_SIZES || cmdIndex == CLEAR_ALL) && 592 row == r1 && 593 (entryPtr = Tcl_FindHashEntry(tablePtr->colWidths, (char *) 594 col-tablePtr->colOffset))) { 595 Tcl_DeleteHashEntry(entryPtr); 596 redraw = 1; 597 } 598 599 if ((cmdIndex == CLEAR_CACHE || cmdIndex == CLEAR_ALL) && 600 (entryPtr = Tcl_FindHashEntry(tablePtr->cache, buf))) { 601 value = (char *) Tcl_GetHashValue(entryPtr); 602 if (value) { ckfree(value); } 603 Tcl_DeleteHashEntry(entryPtr); 604 /* if the cache is our data source, 605 * we need to invalidate the cells changed */ 606 if ((tablePtr->dataSource == DATA_CACHE) && 607 (row-tablePtr->rowOffset == tablePtr->activeRow && 608 col-tablePtr->colOffset == tablePtr->activeCol)) 609 TableGetActiveBuf(tablePtr); 610 redraw = 1; 611 } 612 } 613 } 614 } 615 /* This could be more sensitive about what it updates, 616 * but that can actually be a lot more costly in some cases */ 617 if (redraw) { 618 if (cmdIndex == CLEAR_SIZES || cmdIndex == CLEAR_ALL) { 619 TableAdjustParams(tablePtr); 620 /* rerequest geometry */ 621 TableGeometryRequest(tablePtr); 622 } 623 TableInvalidateAll(tablePtr, 0); 624 } 625 return TCL_OK; 626} 627 628/* 629 *-------------------------------------------------------------- 630 * 631 * Table_CurselectionCmd -- 632 * This procedure is invoked to process the bbox method 633 * that corresponds to a table widget managed by this module. 634 * See the user documentation for details on what it does. 635 * 636 * Results: 637 * A standard Tcl result. 638 * 639 * Side effects: 640 * See the user documentation. 641 * 642 *-------------------------------------------------------------- 643 */ 644int 645Table_CurselectionCmd(ClientData clientData, register Tcl_Interp *interp, 646 int objc, Tcl_Obj *CONST objv[]) 647{ 648 register Table *tablePtr = (Table *) clientData; 649 Tcl_HashEntry *entryPtr; 650 Tcl_HashSearch search; 651 char *value = NULL; 652 int row, col; 653 654 if (objc > 3) { 655 Tcl_WrongNumArgs(interp, 2, objv, "?value?"); 656 return TCL_ERROR; 657 } 658 if (objc == 3) { 659 /* make sure there is a data source to accept a set value */ 660 if ((tablePtr->state == STATE_DISABLED) || 661 (tablePtr->dataSource == DATA_NONE)) { 662 return TCL_OK; 663 } 664 value = Tcl_GetString(objv[2]); 665 for (entryPtr = Tcl_FirstHashEntry(tablePtr->selCells, &search); 666 entryPtr != NULL; entryPtr = Tcl_NextHashEntry(&search)) { 667 TableParseArrayIndex(&row, &col, 668 Tcl_GetHashKey(tablePtr->selCells, entryPtr)); 669 TableSetCellValue(tablePtr, row, col, value); 670 row -= tablePtr->rowOffset; 671 col -= tablePtr->colOffset; 672 if (row == tablePtr->activeRow && col == tablePtr->activeCol) { 673 TableGetActiveBuf(tablePtr); 674 } 675 TableRefresh(tablePtr, row, col, CELL); 676 } 677 } else { 678 Tcl_Obj *objPtr = Tcl_NewObj(); 679 680 for (entryPtr = Tcl_FirstHashEntry(tablePtr->selCells, &search); 681 entryPtr != NULL; entryPtr = Tcl_NextHashEntry(&search)) { 682 value = Tcl_GetHashKey(tablePtr->selCells, entryPtr); 683 Tcl_ListObjAppendElement(NULL, objPtr, 684 Tcl_NewStringObj(value, -1)); 685 } 686 Tcl_SetObjResult(interp, TableCellSortObj(interp, objPtr)); 687 } 688 return TCL_OK; 689} 690 691/* 692 *-------------------------------------------------------------- 693 * 694 * Table_CurvalueCmd -- 695 * This procedure is invoked to process the curvalue method 696 * that corresponds to a table widget managed by this module. 697 * See the user documentation for details on what it does. 698 * 699 * Results: 700 * A standard Tcl result. 701 * 702 * Side effects: 703 * See the user documentation. 704 * 705 *-------------------------------------------------------------- 706 */ 707int 708Table_CurvalueCmd(ClientData clientData, register Tcl_Interp *interp, 709 int objc, Tcl_Obj *CONST objv[]) 710{ 711 register Table *tablePtr = (Table *) clientData; 712 713 if (objc > 3) { 714 Tcl_WrongNumArgs(interp, 2, objv, "?<value>?"); 715 return TCL_ERROR; 716 } else if (!(tablePtr->flags & HAS_ACTIVE)) { 717 return TCL_OK; 718 } 719 720 if (objc == 3) { 721 char *value; 722 int len; 723 724 value = Tcl_GetStringFromObj(objv[2], &len); 725 if (STREQ(value, tablePtr->activeBuf)) { 726 Tcl_SetObjResult(interp, objv[2]); 727 return TCL_OK; 728 } 729 /* validate potential new active buffer contents 730 * only accept if validation returns acceptance. */ 731 if (tablePtr->validate && 732 TableValidateChange(tablePtr, 733 tablePtr->activeRow+tablePtr->rowOffset, 734 tablePtr->activeCol+tablePtr->colOffset, 735 tablePtr->activeBuf, 736 value, tablePtr->icursor) != TCL_OK) { 737 return TCL_OK; 738 } 739 tablePtr->activeBuf = (char *)ckrealloc(tablePtr->activeBuf, len+1); 740 strcpy(tablePtr->activeBuf, value); 741 /* mark the text as changed */ 742 tablePtr->flags |= TEXT_CHANGED; 743 TableSetActiveIndex(tablePtr); 744 /* check for possible adjustment of icursor */ 745 TableGetIcursor(tablePtr, "insert", (int *)0); 746 TableRefresh(tablePtr, tablePtr->activeRow, tablePtr->activeCol, CELL); 747 } 748 749 Tcl_SetObjResult(interp, Tcl_NewStringObj(tablePtr->activeBuf, -1)); 750 return TCL_OK; 751} 752 753/* 754 *-------------------------------------------------------------- 755 * 756 * Table_GetCmd -- 757 * This procedure is invoked to process the bbox method 758 * that corresponds to a table widget managed by this module. 759 * See the user documentation for details on what it does. 760 * 761 * Results: 762 * A standard Tcl result. 763 * 764 * Side effects: 765 * See the user documentation. 766 * 767 *-------------------------------------------------------------- 768 */ 769int 770Table_GetCmd(ClientData clientData, register Tcl_Interp *interp, 771 int objc, Tcl_Obj *CONST objv[]) 772{ 773 register Table *tablePtr = (Table *) clientData; 774 int result = TCL_OK; 775 int r1, c1, r2, c2, row, col; 776 777 if (objc < 3 || objc > 4) { 778 Tcl_WrongNumArgs(interp, 2, objv, "first ?last?"); 779 result = TCL_ERROR; 780 } else if (TableGetIndexObj(tablePtr, objv[2], &row, &col) == TCL_ERROR) { 781 result = TCL_ERROR; 782 } else if (objc == 3) { 783 Tcl_SetObjResult(interp, 784 Tcl_NewStringObj(TableGetCellValue(tablePtr, row, col), -1)); 785 } else if (TableGetIndexObj(tablePtr, objv[3], &r2, &c2) == TCL_ERROR) { 786 result = TCL_ERROR; 787 } else { 788 Tcl_Obj *objPtr = Tcl_NewObj(); 789 790 r1 = MIN(row,r2); r2 = MAX(row,r2); 791 c1 = MIN(col,c2); c2 = MAX(col,c2); 792 for ( row = r1; row <= r2; row++ ) { 793 for ( col = c1; col <= c2; col++ ) { 794 Tcl_ListObjAppendElement(NULL, objPtr, 795 Tcl_NewStringObj(TableGetCellValue(tablePtr, 796 row, col), -1)); 797 } 798 } 799 Tcl_SetObjResult(interp, objPtr); 800 } 801 return result; 802} 803 804/* 805 *-------------------------------------------------------------- 806 * 807 * Table_ScanCmd -- 808 * This procedure is invoked to process the scan method 809 * that corresponds to a table widget managed by this module. 810 * See the user documentation for details on what it does. 811 * 812 * Results: 813 * A standard Tcl result. 814 * 815 * Side effects: 816 * See the user documentation. 817 * 818 *-------------------------------------------------------------- 819 */ 820int 821Table_ScanCmd(ClientData clientData, register Tcl_Interp *interp, 822 int objc, Tcl_Obj *CONST objv[]) 823{ 824 register Table *tablePtr = (Table *) clientData; 825 int x, y, row, col, cmdIndex; 826 827 if (objc != 5) { 828 Tcl_WrongNumArgs(interp, 2, objv, "mark|dragto x y"); 829 return TCL_ERROR; 830 } else if (Tcl_GetIndexFromObj(interp, objv[2], bdCmdNames, 831 "option", 0, &cmdIndex) != TCL_OK || 832 Tcl_GetIntFromObj(interp, objv[3], &x) == TCL_ERROR || 833 Tcl_GetIntFromObj(interp, objv[4], &y) == TCL_ERROR) { 834 return TCL_ERROR; 835 } 836 switch ((enum bdCmd) cmdIndex) { 837 case BD_MARK: 838 TableWhatCell(tablePtr, x, y, &row, &col); 839 tablePtr->scanMarkRow = row-tablePtr->topRow; 840 tablePtr->scanMarkCol = col-tablePtr->leftCol; 841 tablePtr->scanMarkX = x; 842 tablePtr->scanMarkY = y; 843 break; 844 845 case BD_DRAGTO: { 846 int oldTop = tablePtr->topRow, oldLeft = tablePtr->leftCol; 847 y += (5*(y-tablePtr->scanMarkY)); 848 x += (5*(x-tablePtr->scanMarkX)); 849 850 TableWhatCell(tablePtr, x, y, &row, &col); 851 852 /* maintain appropriate real index */ 853 tablePtr->topRow = BETWEEN(row-tablePtr->scanMarkRow, 854 tablePtr->titleRows, tablePtr->rows-1); 855 tablePtr->leftCol = BETWEEN(col-tablePtr->scanMarkCol, 856 tablePtr->titleCols, tablePtr->cols-1); 857 858 /* Adjust the table if new top left */ 859 if (oldTop != tablePtr->topRow || oldLeft != tablePtr->leftCol) { 860 TableAdjustParams(tablePtr); 861 } 862 break; 863 } 864 } 865 return TCL_OK; 866} 867 868/* 869 *-------------------------------------------------------------- 870 * 871 * Table_SelAnchorCmd -- 872 * This procedure is invoked to process the selection anchor method 873 * that corresponds to a table widget managed by this module. 874 * See the user documentation for details on what it does. 875 * 876 * Results: 877 * A standard Tcl result. 878 * 879 * Side effects: 880 * See the user documentation. 881 * 882 *-------------------------------------------------------------- 883 */ 884int 885Table_SelAnchorCmd(ClientData clientData, register Tcl_Interp *interp, 886 int objc, Tcl_Obj *CONST objv[]) 887{ 888 register Table *tablePtr = (Table *) clientData; 889 int row, col; 890 891 if (objc != 4) { 892 Tcl_WrongNumArgs(interp, 3, objv, "index"); 893 return TCL_ERROR; 894 } else if (TableGetIndexObj(tablePtr, objv[3], &row, &col) != TCL_OK) { 895 return TCL_ERROR; 896 } 897 tablePtr->flags |= HAS_ANCHOR; 898 /* maintain appropriate real index */ 899 if (tablePtr->selectTitles) { 900 tablePtr->anchorRow = BETWEEN(row-tablePtr->rowOffset, 901 0, tablePtr->rows-1); 902 tablePtr->anchorCol = BETWEEN(col-tablePtr->colOffset, 903 0, tablePtr->cols-1); 904 } else { 905 tablePtr->anchorRow = BETWEEN(row-tablePtr->rowOffset, 906 tablePtr->titleRows, tablePtr->rows-1); 907 tablePtr->anchorCol = BETWEEN(col-tablePtr->colOffset, 908 tablePtr->titleCols, tablePtr->cols-1); 909 } 910 return TCL_OK; 911} 912 913/* 914 *-------------------------------------------------------------- 915 * 916 * Table_SelClearCmd -- 917 * This procedure is invoked to process the selection clear method 918 * that corresponds to a table widget managed by this module. 919 * See the user documentation for details on what it does. 920 * 921 * Results: 922 * A standard Tcl result. 923 * 924 * Side effects: 925 * See the user documentation. 926 * 927 *-------------------------------------------------------------- 928 */ 929int 930Table_SelClearCmd(ClientData clientData, register Tcl_Interp *interp, 931 int objc, Tcl_Obj *CONST objv[]) 932{ 933 register Table *tablePtr = (Table *) clientData; 934 int result = TCL_OK; 935 char buf1[INDEX_BUFSIZE]; 936 int row, col, key, clo=0,chi=0,r1,c1,r2,c2; 937 Tcl_HashEntry *entryPtr; 938 939 if (objc < 4 || objc > 5) { 940 Tcl_WrongNumArgs(interp, 3, objv, "all|<first> ?<last>?"); 941 return TCL_ERROR; 942 } 943 if (STREQ(Tcl_GetString(objv[3]), "all")) { 944 Tcl_HashSearch search; 945 for(entryPtr = Tcl_FirstHashEntry(tablePtr->selCells, &search); 946 entryPtr != NULL; entryPtr = Tcl_NextHashEntry(&search)) { 947 TableParseArrayIndex(&row, &col, 948 Tcl_GetHashKey(tablePtr->selCells,entryPtr)); 949 Tcl_DeleteHashEntry(entryPtr); 950 TableRefresh(tablePtr, row-tablePtr->rowOffset, 951 col-tablePtr->colOffset, CELL); 952 } 953 return TCL_OK; 954 } 955 if (TableGetIndexObj(tablePtr, objv[3], &row, &col) == TCL_ERROR || 956 (objc==5 && 957 TableGetIndexObj(tablePtr, objv[4], &r2, &c2) == TCL_ERROR)) { 958 return TCL_ERROR; 959 } 960 key = 0; 961 if (objc == 4) { 962 r1 = r2 = row; 963 c1 = c2 = col; 964 } else { 965 r1 = MIN(row,r2); r2 = MAX(row,r2); 966 c1 = MIN(col,c2); c2 = MAX(col,c2); 967 } 968 switch (tablePtr->selectType) { 969 case SEL_BOTH: 970 clo = c1; chi = c2; 971 c1 = tablePtr->colOffset; 972 c2 = tablePtr->cols-1+c1; 973 key = 1; 974 goto CLEAR_CELLS; 975 CLEAR_BOTH: 976 key = 0; 977 c1 = clo; c2 = chi; 978 case SEL_COL: 979 r1 = tablePtr->rowOffset; 980 r2 = tablePtr->rows-1+r1; 981 break; 982 case SEL_ROW: 983 c1 = tablePtr->colOffset; 984 c2 = tablePtr->cols-1+c1; 985 break; 986 } 987 /* row/col are in user index coords */ 988CLEAR_CELLS: 989 for ( row = r1; row <= r2; row++ ) { 990 for ( col = c1; col <= c2; col++ ) { 991 TableMakeArrayIndex(row, col, buf1); 992 entryPtr = Tcl_FindHashEntry(tablePtr->selCells, buf1); 993 if (entryPtr != NULL) { 994 Tcl_DeleteHashEntry(entryPtr); 995 TableRefresh(tablePtr, row-tablePtr->rowOffset, 996 col-tablePtr->colOffset, CELL); 997 } 998 } 999 } 1000 if (key) goto CLEAR_BOTH; 1001 return result; 1002} 1003 1004/* 1005 *-------------------------------------------------------------- 1006 * 1007 * Table_SelIncludesCmd -- 1008 * This procedure is invoked to process the selection includes method 1009 * that corresponds to a table widget managed by this module. 1010 * See the user documentation for details on what it does. 1011 * 1012 * Results: 1013 * A standard Tcl result. 1014 * 1015 * Side effects: 1016 * See the user documentation. 1017 * 1018 *-------------------------------------------------------------- 1019 */ 1020int 1021Table_SelIncludesCmd(ClientData clientData, register Tcl_Interp *interp, 1022 int objc, Tcl_Obj *CONST objv[]) 1023{ 1024 register Table *tablePtr = (Table *) clientData; 1025 int row, col; 1026 1027 if (objc != 4) { 1028 Tcl_WrongNumArgs(interp, 3, objv, "index"); 1029 return TCL_ERROR; 1030 } else if (TableGetIndexObj(tablePtr, objv[3], &row, &col) == TCL_ERROR) { 1031 return TCL_ERROR; 1032 } else { 1033 char buf[INDEX_BUFSIZE]; 1034 TableMakeArrayIndex(row, col, buf); 1035 Tcl_SetBooleanObj(Tcl_GetObjResult(interp), 1036 (Tcl_FindHashEntry(tablePtr->selCells, buf)!=NULL)); 1037 } 1038 return TCL_OK; 1039} 1040 1041/* 1042 *-------------------------------------------------------------- 1043 * 1044 * Table_SelSetCmd -- 1045 * This procedure is invoked to process the selection set method 1046 * that corresponds to a table widget managed by this module. 1047 * See the user documentation for details on what it does. 1048 * 1049 * Results: 1050 * A standard Tcl result. 1051 * 1052 * Side effects: 1053 * See the user documentation. 1054 * 1055 *-------------------------------------------------------------- 1056 */ 1057int 1058Table_SelSetCmd(ClientData clientData, register Tcl_Interp *interp, 1059 int objc, Tcl_Obj *CONST objv[]) 1060{ 1061 register Table *tablePtr = (Table *) clientData; 1062 int row, col, dummy, key; 1063 char buf1[INDEX_BUFSIZE]; 1064 Tcl_HashSearch search; 1065 Tcl_HashEntry *entryPtr; 1066 1067 int clo=0, chi=0, r1, c1, r2, c2, firstRow, firstCol, lastRow, lastCol; 1068 if (objc < 4 || objc > 5) { 1069 Tcl_WrongNumArgs(interp, 3, objv, "first ?last?"); 1070 return TCL_ERROR; 1071 } 1072 if (TableGetIndexObj(tablePtr, objv[3], &row, &col) == TCL_ERROR || 1073 (objc==5 && 1074 TableGetIndexObj(tablePtr, objv[4], &r2, &c2) == TCL_ERROR)) { 1075 return TCL_ERROR; 1076 } 1077 key = 0; 1078 lastRow = tablePtr->rows-1+tablePtr->rowOffset; 1079 lastCol = tablePtr->cols-1+tablePtr->colOffset; 1080 if (tablePtr->selectTitles) { 1081 firstRow = tablePtr->rowOffset; 1082 firstCol = tablePtr->colOffset; 1083 } else { 1084 firstRow = tablePtr->titleRows+tablePtr->rowOffset; 1085 firstCol = tablePtr->titleCols+tablePtr->colOffset; 1086 } 1087 /* maintain appropriate user index */ 1088 CONSTRAIN(row, firstRow, lastRow); 1089 CONSTRAIN(col, firstCol, lastCol); 1090 if (objc == 4) { 1091 r1 = r2 = row; 1092 c1 = c2 = col; 1093 } else { 1094 CONSTRAIN(r2, firstRow, lastRow); 1095 CONSTRAIN(c2, firstCol, lastCol); 1096 r1 = MIN(row,r2); r2 = MAX(row,r2); 1097 c1 = MIN(col,c2); c2 = MAX(col,c2); 1098 } 1099 switch (tablePtr->selectType) { 1100 case SEL_BOTH: 1101 if (firstCol > lastCol) c2--; /* No selectable columns in table */ 1102 if (firstRow > lastRow) r2--; /* No selectable rows in table */ 1103 clo = c1; chi = c2; 1104 c1 = firstCol; 1105 c2 = lastCol; 1106 key = 1; 1107 goto SET_CELLS; 1108 SET_BOTH: 1109 key = 0; 1110 c1 = clo; c2 = chi; 1111 case SEL_COL: 1112 r1 = firstRow; 1113 r2 = lastRow; 1114 if (firstCol > lastCol) c2--; /* No selectable columns in table */ 1115 break; 1116 case SEL_ROW: 1117 c1 = firstCol; 1118 c2 = lastCol; 1119 if (firstRow>lastRow) r2--; /* No selectable rows in table */ 1120 break; 1121 } 1122SET_CELLS: 1123 entryPtr = Tcl_FirstHashEntry(tablePtr->selCells, &search); 1124 for ( row = r1; row <= r2; row++ ) { 1125 for ( col = c1; col <= c2; col++ ) { 1126 TableMakeArrayIndex(row, col, buf1); 1127 if (Tcl_FindHashEntry(tablePtr->selCells, buf1) == NULL) { 1128 Tcl_CreateHashEntry(tablePtr->selCells, buf1, &dummy); 1129 TableRefresh(tablePtr, row-tablePtr->rowOffset, 1130 col-tablePtr->colOffset, CELL); 1131 } 1132 } 1133 } 1134 if (key) goto SET_BOTH; 1135 1136 /* Adjust the table for top left, selection on screen etc */ 1137 TableAdjustParams(tablePtr); 1138 1139 /* If the table was previously empty and we want to export the 1140 * selection, we should grab it now */ 1141 if (entryPtr == NULL && tablePtr->exportSelection) { 1142 Tk_OwnSelection(tablePtr->tkwin, XA_PRIMARY, TableLostSelection, 1143 (ClientData) tablePtr); 1144 } 1145 return TCL_OK; 1146} 1147 1148/* 1149 *-------------------------------------------------------------- 1150 * 1151 * Table_ViewCmd -- 1152 * This procedure is invoked to process the x|yview method 1153 * that corresponds to a table widget managed by this module. 1154 * See the user documentation for details on what it does. 1155 * 1156 * Results: 1157 * A standard Tcl result. 1158 * 1159 * Side effects: 1160 * See the user documentation. 1161 * 1162 *-------------------------------------------------------------- 1163 */ 1164int 1165Table_ViewCmd(ClientData clientData, register Tcl_Interp *interp, 1166 int objc, Tcl_Obj *CONST objv[]) 1167{ 1168 register Table *tablePtr = (Table *) clientData; 1169 int row, col, value; 1170 char *xy; 1171 1172 /* Check xview or yview */ 1173 if (objc > 5) { 1174 Tcl_WrongNumArgs(interp, 2, objv, "?args?"); 1175 return TCL_ERROR; 1176 } 1177 xy = Tcl_GetString(objv[1]); 1178 1179 if (objc == 2) { 1180 Tcl_Obj *resultPtr; 1181 int diff, x, y, w, h; 1182 double first, last; 1183 1184 resultPtr = Tcl_GetObjResult(interp); 1185 TableGetLastCell(tablePtr, &row, &col); 1186 TableCellVCoords(tablePtr, row, col, &x, &y, &w, &h, 0); 1187 if (*xy == 'y') { 1188 if (row < tablePtr->titleRows) { 1189 first = 0; 1190 last = 1; 1191 } else { 1192 diff = tablePtr->rowStarts[tablePtr->titleRows]; 1193 last = (double) (tablePtr->rowStarts[tablePtr->rows]-diff); 1194 first = (tablePtr->rowStarts[tablePtr->topRow]-diff) / last; 1195 last = (h+tablePtr->rowStarts[row]-diff) / last; 1196 } 1197 } else { 1198 if (col < tablePtr->titleCols) { 1199 first = 0; 1200 last = 1; 1201 } else { 1202 diff = tablePtr->colStarts[tablePtr->titleCols]; 1203 last = (double) (tablePtr->colStarts[tablePtr->cols]-diff); 1204 first = (tablePtr->colStarts[tablePtr->leftCol]-diff) / last; 1205 last = (w+tablePtr->colStarts[col]-diff) / last; 1206 } 1207 } 1208 Tcl_ListObjAppendElement(NULL, resultPtr, Tcl_NewDoubleObj(first)); 1209 Tcl_ListObjAppendElement(NULL, resultPtr, Tcl_NewDoubleObj(last)); 1210 } else { 1211 /* cache old topleft to see if it changes */ 1212 int oldTop = tablePtr->topRow, oldLeft = tablePtr->leftCol; 1213 1214 if (objc == 3) { 1215 if (Tcl_GetIntFromObj(interp, objv[2], &value) != TCL_OK) { 1216 return TCL_ERROR; 1217 } 1218 if (*xy == 'y') { 1219 tablePtr->topRow = value + tablePtr->titleRows; 1220 } else { 1221 tablePtr->leftCol = value + tablePtr->titleCols; 1222 } 1223 } else { 1224 int result; 1225 double frac; 1226#if (TK_MINOR_VERSION > 0) /* 8.1+ */ 1227 result = Tk_GetScrollInfoObj(interp, objc, objv, &frac, &value); 1228#else 1229 int i; 1230 char **argv = (char **) ckalloc((objc + 1) * sizeof(char *)); 1231 for (i = 0; i < objc; i++) { 1232 argv[i] = Tcl_GetString(objv[i]); 1233 } 1234 argv[i] = NULL; 1235 result = Tk_GetScrollInfo(interp, objc, argv, &frac, &value); 1236 ckfree ((char *) argv); 1237#endif 1238 switch (result) { 1239 case TK_SCROLL_ERROR: 1240 return TCL_ERROR; 1241 case TK_SCROLL_MOVETO: 1242 if (frac < 0) frac = 0; 1243 if (*xy == 'y') { 1244 tablePtr->topRow = (int)(frac*tablePtr->rows) 1245 +tablePtr->titleRows; 1246 } else { 1247 tablePtr->leftCol = (int)(frac*tablePtr->cols) 1248 +tablePtr->titleCols; 1249 } 1250 break; 1251 case TK_SCROLL_PAGES: 1252 TableGetLastCell(tablePtr, &row, &col); 1253 if (*xy == 'y') { 1254 tablePtr->topRow += value * (row-tablePtr->topRow+1); 1255 } else { 1256 tablePtr->leftCol += value * (col-tablePtr->leftCol+1); 1257 } 1258 break; 1259 case TK_SCROLL_UNITS: 1260 if (*xy == 'y') { 1261 tablePtr->topRow += value; 1262 } else { 1263 tablePtr->leftCol += value; 1264 } 1265 break; 1266 } 1267 } 1268 /* maintain appropriate real index */ 1269 CONSTRAIN(tablePtr->topRow, tablePtr->titleRows, tablePtr->rows-1); 1270 CONSTRAIN(tablePtr->leftCol, tablePtr->titleCols, tablePtr->cols-1); 1271 /* Do the table adjustment if topRow || leftCol changed */ 1272 if (oldTop != tablePtr->topRow || oldLeft != tablePtr->leftCol) { 1273 TableAdjustParams(tablePtr); 1274 } 1275 } 1276 1277 return TCL_OK; 1278} 1279 1280#if 0 1281/* 1282 *-------------------------------------------------------------- 1283 * 1284 * Table_Cmd -- 1285 * This procedure is invoked to process the CMD method 1286 * that corresponds to a table widget managed by this module. 1287 * See the user documentation for details on what it does. 1288 * 1289 * Results: 1290 * A standard Tcl result. 1291 * 1292 * Side effects: 1293 * See the user documentation. 1294 * 1295 *-------------------------------------------------------------- 1296 */ 1297int 1298Table_Cmd(ClientData clientData, register Tcl_Interp *interp, 1299 int objc, Tcl_Obj *CONST objv[]) 1300{ 1301 register Table *tablePtr = (Table *) clientData; 1302 int result = TCL_OK; 1303 1304 return result; 1305} 1306#endif 1307