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