4 * This module implements tags for table widgets.
6 * Copyright (c) 1998-2001 Jeffrey Hobbs
8 * See the file "license.terms" for information on usage and redistribution
9 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
16 static TableTag *TableTagGetEntry _ANSI_ARGS_((Table *tablePtr, char *name,
17 int objc, char **argv));
18 static unsigned int TableTagGetPriority _ANSI_ARGS_((Table *tablePtr,
20 static void TableImageProc _ANSI_ARGS_((ClientData clientData, int x,
21 int y, int width, int height, int imageWidth, int imageHeight));
23 static char *tagCmdNames[] = {
24 "celltag", "cget", "coltag", "configure", "delete", "exists",
25 "includes", "lower", "names", "raise", "rowtag", (char *) NULL
29 TAG_CELLTAG, TAG_CGET, TAG_COLTAG, TAG_CONFIGURE, TAG_DELETE, TAG_EXISTS,
30 TAG_INCLUDES, TAG_LOWER, TAG_NAMES, TAG_RAISE, TAG_ROWTAG
33 static Cmd_Struct tagState_vals[]= {
34 {"unknown", STATE_UNKNOWN},
35 {"normal", STATE_NORMAL},
36 {"disabled", STATE_DISABLED},
40 static Tk_CustomOption tagStateOpt = { Cmd_OptionSet, Cmd_OptionGet,
41 (ClientData)(&tagState_vals) };
42 static Tk_CustomOption tagBdOpt = { TableOptionBdSet, TableOptionBdGet,
43 (ClientData) BD_TABLE_TAG };
46 * The default specification for configuring tags
47 * Done like this to make the command line parsing easy
50 static Tk_ConfigSpec tagConfig[] = {
51 {TK_CONFIG_ANCHOR, "-anchor", "anchor", "Anchor", "center",
52 Tk_Offset(TableTag, anchor), TK_CONFIG_DONT_SET_DEFAULT|TK_CONFIG_NULL_OK },
53 {TK_CONFIG_BORDER, "-background", "background", "Background", NULL,
54 Tk_Offset(TableTag, bg), TK_CONFIG_DONT_SET_DEFAULT|TK_CONFIG_NULL_OK },
55 {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *)NULL, (char *)NULL, 0, 0},
56 {TK_CONFIG_SYNONYM, "-bg", "background", (char *)NULL, (char *)NULL, 0, 0},
57 {TK_CONFIG_CUSTOM, "-borderwidth", "borderWidth", "BorderWidth", "",
59 TK_CONFIG_DONT_SET_DEFAULT|TK_CONFIG_NULL_OK, &tagBdOpt },
60 {TK_CONFIG_BORDER, "-foreground", "foreground", "Foreground", NULL,
61 Tk_Offset(TableTag, fg), TK_CONFIG_DONT_SET_DEFAULT|TK_CONFIG_NULL_OK },
62 {TK_CONFIG_SYNONYM, "-fg", "foreground", (char *)NULL, (char *)NULL, 0, 0},
63 {TK_CONFIG_FONT, "-font", "font", "Font", NULL,
64 Tk_Offset(TableTag, tkfont), TK_CONFIG_DONT_SET_DEFAULT|TK_CONFIG_NULL_OK },
65 {TK_CONFIG_STRING, "-image", "image", "Image", NULL,
66 Tk_Offset(TableTag, imageStr),
67 TK_CONFIG_DONT_SET_DEFAULT|TK_CONFIG_NULL_OK },
68 {TK_CONFIG_JUSTIFY, "-justify", "justify", "Justify", "left",
69 Tk_Offset(TableTag, justify), TK_CONFIG_DONT_SET_DEFAULT|TK_CONFIG_NULL_OK },
70 {TK_CONFIG_INT, "-multiline", "multiline", "Multiline", "-1",
71 Tk_Offset(TableTag, multiline), TK_CONFIG_DONT_SET_DEFAULT },
72 {TK_CONFIG_RELIEF, "-relief", "relief", "Relief", "flat",
73 Tk_Offset(TableTag, relief), TK_CONFIG_DONT_SET_DEFAULT|TK_CONFIG_NULL_OK },
74 {TK_CONFIG_INT, "-showtext", "showText", "ShowText", "-1",
75 Tk_Offset(TableTag, showtext), TK_CONFIG_DONT_SET_DEFAULT },
76 {TK_CONFIG_CUSTOM, "-state", "state", "State", "unknown",
77 Tk_Offset(TableTag, state), TK_CONFIG_DONT_SET_DEFAULT, &tagStateOpt },
78 {TK_CONFIG_INT, "-wrap", "wrap", "Wrap", "-1",
79 Tk_Offset(TableTag, wrap), TK_CONFIG_DONT_SET_DEFAULT },
80 {TK_CONFIG_END, (char *)NULL, (char *)NULL, (char *)NULL, (char *)NULL, 0, 0}
84 * The join tag structure is used to create a combined tag, so it
85 * keeps priority info.
88 TableTag tag; /* must be first */
90 unsigned int pbg, pfg, pborders, prelief, ptkfont, panchor, pimage;
91 unsigned int pstate, pjustify, pmultiline, pwrap, pshowtext;
95 *----------------------------------------------------------------------
98 * Called when an image associated with a tag is changed.
104 * Invalidates the whole table.
105 * This should only invalidate affected cells, but that info
108 *----------------------------------------------------------------------
111 TableImageProc(ClientData clientData, int x, int y, int width, int height,
112 int imageWidth, int imageHeight)
114 TableInvalidateAll((Table *)clientData, 0);
118 *----------------------------------------------------------------------
121 * ckallocs space for a new tag structure and inits the structure.
124 * Returns a pointer to the new structure. Must be freed later.
129 *----------------------------------------------------------------------
132 TableNewTag(Table *tablePtr)
137 * If tablePtr is NULL, make a regular tag, otherwise make a join tag.
139 if (tablePtr == NULL) {
140 tagPtr = (TableTag *) ckalloc(sizeof(TableTag));
141 memset((VOID *) tagPtr, 0, sizeof(TableTag));
144 * Set the values that aren't 0/NULL by default
146 tagPtr->anchor = (Tk_Anchor)-1;
147 tagPtr->justify = (Tk_Justify)-1;
148 tagPtr->multiline = -1;
150 tagPtr->showtext = -1;
151 tagPtr->state = STATE_UNKNOWN;
154 TableJoinTag *jtagPtr = (TableJoinTag *) ckalloc(sizeof(TableJoinTag));
155 memset((VOID *) jtagPtr, 0, sizeof(TableJoinTag));
156 tagPtr = (TableTag *) jtagPtr;
158 tagPtr->anchor = (Tk_Anchor)-1;
159 tagPtr->justify = (Tk_Justify)-1;
160 tagPtr->multiline = -1;
162 tagPtr->showtext = -1;
163 tagPtr->state = STATE_UNKNOWN;
165 jtagPtr->magic = 0x99ABCDEF;
168 jtagPtr->pborders = -1;
169 jtagPtr->prelief = -1;
170 jtagPtr->ptkfont = -1;
171 jtagPtr->panchor = -1;
172 jtagPtr->pimage = -1;
173 jtagPtr->pstate = -1;
174 jtagPtr->pjustify = -1;
175 jtagPtr->pmultiline = -1;
177 jtagPtr->pshowtext = -1;
180 return (TableTag *) tagPtr;
184 *----------------------------------------------------------------------
187 * This routine resets a given tag to the table defaults.
190 * Tag will have values changed.
195 *----------------------------------------------------------------------
198 TableResetTag(Table *tablePtr, TableTag *tagPtr)
200 TableJoinTag *jtagPtr = (TableJoinTag *) tagPtr;
202 if (jtagPtr->magic != 0x99ABCDEF) {
203 panic("bad mojo in TableResetTag");
206 memset((VOID *) jtagPtr, 0, sizeof(TableJoinTag));
208 tagPtr->anchor = (Tk_Anchor)-1;
209 tagPtr->justify = (Tk_Justify)-1;
210 tagPtr->multiline = -1;
212 tagPtr->showtext = -1;
213 tagPtr->state = STATE_UNKNOWN;
215 jtagPtr->magic = 0x99ABCDEF;
218 jtagPtr->pborders = -1;
219 jtagPtr->prelief = -1;
220 jtagPtr->ptkfont = -1;
221 jtagPtr->panchor = -1;
222 jtagPtr->pimage = -1;
223 jtagPtr->pstate = -1;
224 jtagPtr->pjustify = -1;
225 jtagPtr->pmultiline = -1;
227 jtagPtr->pshowtext = -1;
230 * Merge in the default tag.
232 memcpy((VOID *) jtagPtr, (VOID *) &(tablePtr->defaultTag),
237 *----------------------------------------------------------------------
240 * This routine merges two tags by adding any fields from the addTag
241 * that are set to the baseTag.
244 * baseTag will inherit all set characteristics of addTag
245 * (addTag thus has the priority).
250 *----------------------------------------------------------------------
253 TableMergeTag(Table *tablePtr, TableTag *baseTag, TableTag *addTag)
255 TableJoinTag *jtagPtr = (TableJoinTag *) baseTag;
258 if (jtagPtr->magic != 0x99ABCDEF) {
259 panic("bad mojo in TableMergeTag");
262 #ifndef NO_TAG_PRIORITIES
264 * Find priority for the tag to merge
266 prio = TableTagGetPriority(tablePtr, addTag);
268 if ((addTag->anchor != -1) && (prio < jtagPtr->panchor)) {
269 baseTag->anchor = addTag->anchor;
270 jtagPtr->panchor = prio;
272 if ((addTag->bg != NULL) && (prio < jtagPtr->pbg)) {
273 baseTag->bg = addTag->bg;
276 if ((addTag->fg != NULL) && (prio < jtagPtr->pfg)) {
277 baseTag->fg = addTag->fg;
280 if ((addTag->tkfont != NULL) && (prio < jtagPtr->ptkfont)) {
281 baseTag->tkfont = addTag->tkfont;
282 jtagPtr->ptkfont = prio;
284 if ((addTag->imageStr != NULL) && (prio < jtagPtr->pimage)) {
285 baseTag->imageStr = addTag->imageStr;
286 baseTag->image = addTag->image;
287 jtagPtr->pimage = prio;
289 if ((addTag->multiline >= 0) && (prio < jtagPtr->pmultiline)) {
290 baseTag->multiline = addTag->multiline;
291 jtagPtr->pmultiline = prio;
293 if ((addTag->relief != -1) && (prio < jtagPtr->prelief)) {
294 baseTag->relief = addTag->relief;
295 jtagPtr->prelief = prio;
297 if ((addTag->showtext >= 0) && (prio < jtagPtr->pshowtext)) {
298 baseTag->showtext = addTag->showtext;
299 jtagPtr->pshowtext = prio;
301 if ((addTag->state != STATE_UNKNOWN) && (prio < jtagPtr->pstate)) {
302 baseTag->state = addTag->state;
303 jtagPtr->pstate = prio;
305 if ((addTag->justify != -1) && (prio < jtagPtr->pjustify)) {
306 baseTag->justify = addTag->justify;
307 jtagPtr->pjustify = prio;
309 if ((addTag->wrap >= 0) && (prio < jtagPtr->pwrap)) {
310 baseTag->wrap = addTag->wrap;
311 jtagPtr->pwrap = prio;
313 if ((addTag->borders) && (prio < jtagPtr->pborders)) {
314 baseTag->borderStr = addTag->borderStr;
315 baseTag->borders = addTag->borders;
316 baseTag->bd[0] = addTag->bd[0];
317 baseTag->bd[1] = addTag->bd[1];
318 baseTag->bd[2] = addTag->bd[2];
319 baseTag->bd[3] = addTag->bd[3];
320 jtagPtr->pborders = prio;
323 if (addTag->anchor != -1) baseTag->anchor = addTag->anchor;
324 if (addTag->bg != NULL) baseTag->bg = addTag->bg;
325 if (addTag->fg != NULL) baseTag->fg = addTag->fg;
326 if (addTag->tkfont != NULL) baseTag->tkfont = addTag->tkfont;
327 if (addTag->imageStr != NULL) {
328 baseTag->imageStr = addTag->imageStr;
329 baseTag->image = addTag->image;
331 if (addTag->multiline >= 0) baseTag->multiline = addTag->multiline;
332 if (addTag->relief != -1) baseTag->relief = addTag->relief;
333 if (addTag->showtext >= 0) baseTag->showtext = addTag->showtext;
334 if (addTag->state != STATE_UNKNOWN) baseTag->state = addTag->state;
335 if (addTag->justify != -1) baseTag->justify = addTag->justify;
336 if (addTag->wrap >= 0) baseTag->wrap = addTag->wrap;
337 if (addTag->borders) {
338 baseTag->borderStr = addTag->borderStr;
339 baseTag->borders = addTag->borders;
340 baseTag->bd[0] = addTag->bd[0];
341 baseTag->bd[1] = addTag->bd[1];
342 baseTag->bd[2] = addTag->bd[2];
343 baseTag->bd[3] = addTag->bd[3];
349 *----------------------------------------------------------------------
352 * This routine swaps background and foreground for the selected tag.
355 * Inverts fg and bg of tag.
360 *----------------------------------------------------------------------
363 TableInvertTag(TableTag *baseTag)
368 baseTag->fg = baseTag->bg;
373 *----------------------------------------------------------------------
375 * TableGetTagBorders --
376 * This routine gets the border values based on a tag.
379 * It returns the values in the int*'s (if not NULL), and the
380 * total number of defined borders as a result.
385 *----------------------------------------------------------------------
388 TableGetTagBorders(TableTag *tagPtr,
389 int *left, int *right, int *top, int *bottom)
391 switch (tagPtr->borders) {
393 if (left) { *left = 0; }
394 if (right) { *right = 0; }
395 if (top) { *top = 0; }
396 if (bottom) { *bottom = 0; }
399 if (left) { *left = tagPtr->bd[0]; }
400 if (right) { *right = tagPtr->bd[0]; }
401 if (top) { *top = tagPtr->bd[0]; }
402 if (bottom) { *bottom = tagPtr->bd[0]; }
405 if (left) { *left = tagPtr->bd[0]; }
406 if (right) { *right = tagPtr->bd[1]; }
407 if (top) { *top = 0; }
408 if (bottom) { *bottom = 0; }
411 if (left) { *left = tagPtr->bd[0]; }
412 if (right) { *right = tagPtr->bd[1]; }
413 if (top) { *top = tagPtr->bd[2]; }
414 if (bottom) { *bottom = tagPtr->bd[3]; }
417 panic("invalid border value '%d'\n", tagPtr->borders);
420 return tagPtr->borders;
424 *----------------------------------------------------------------------
426 * TableTagGetEntry --
427 * Takes a name and optional args and creates a tag entry in the
431 * A new tag entry will be created and returned.
436 *----------------------------------------------------------------------
439 TableTagGetEntry(Table *tablePtr, char *name, int objc, char **argv)
441 Tcl_HashEntry *entryPtr;
442 TableTag *tagPtr = NULL;
445 entryPtr = Tcl_CreateHashEntry(tablePtr->tagTable, name, &new);
447 tagPtr = TableNewTag(NULL);
448 Tcl_SetHashValue(entryPtr, (ClientData) tagPtr);
449 if (tablePtr->tagPrioSize >= tablePtr->tagPrioMax) {
452 * Increase the priority list size in blocks of 10
454 tablePtr->tagPrioMax += 10;
455 tablePtr->tagPrioNames = (char **) ckrealloc(
456 (char *) tablePtr->tagPrioNames,
457 sizeof(TableTag *) * tablePtr->tagPrioMax);
458 tablePtr->tagPrios = (TableTag **) ckrealloc(
459 (char *) tablePtr->tagPrios,
460 sizeof(TableTag *) * tablePtr->tagPrioMax);
461 for (i = tablePtr->tagPrioSize; i < tablePtr->tagPrioMax; i++) {
462 tablePtr->tagPrioNames[i] = (char *) NULL;
463 tablePtr->tagPrios[i] = (TableTag *) NULL;
466 tablePtr->tagPrioNames[tablePtr->tagPrioSize] =
467 (char *) Tcl_GetHashKey(tablePtr->tagTable, entryPtr);
468 tablePtr->tagPrios[tablePtr->tagPrioSize] = tagPtr;
469 tablePtr->tagPrioSize++;
471 tagPtr = (TableTag *) Tcl_GetHashValue(entryPtr);
474 Tk_ConfigureWidget(tablePtr->interp, tablePtr->tkwin, tagConfig,
475 objc, argv, (char *)tagPtr, TK_CONFIG_ARGV_ONLY);
481 *----------------------------------------------------------------------
483 * TableTagGetPriority --
484 * Get the priority value for a tag.
487 * returns the priority.
492 *----------------------------------------------------------------------
495 TableTagGetPriority(Table *tablePtr, TableTag *tagPtr)
497 unsigned int prio = 0;
498 while (tagPtr != tablePtr->tagPrios[prio]) { prio++; }
503 *----------------------------------------------------------------------
506 * Creates the static table tags.
509 * active, sel, title and flash are created as tags.
514 *----------------------------------------------------------------------
517 TableInitTags(Table *tablePtr)
519 static char *activeArgs[] = {"-bg", ACTIVE_BG, "-relief", "flat" };
520 static char *selArgs[] = {"-bg", SELECT_BG, "-fg", SELECT_FG,
521 "-relief", "sunken" };
522 static char *titleArgs[] = {"-bg", DISABLED, "-fg", "white",
523 "-relief", "flat", "-state", "disabled" };
524 static char *flashArgs[] = {"-bg", "red" };
526 * The order of creation is important to priority.
528 TableTagGetEntry(tablePtr, "flash", ARSIZE(flashArgs), flashArgs);
529 TableTagGetEntry(tablePtr, "active", ARSIZE(activeArgs), activeArgs);
530 TableTagGetEntry(tablePtr, "sel", ARSIZE(selArgs), selArgs);
531 TableTagGetEntry(tablePtr, "title", ARSIZE(titleArgs), titleArgs);
535 *----------------------------------------------------------------------
538 * Finds a row/col tag based on the row/col styles and tagCommand.
541 * Returns tag associated with row/col cell, if any.
544 * Possible side effects from eval of tagCommand.
545 * IMPORTANT: This plays with the interp result object,
546 * so use of resultPtr in prior command may be invalid after
547 * calling this function.
549 *----------------------------------------------------------------------
552 FindRowColTag(Table *tablePtr, int cell, int mode)
554 Tcl_HashEntry *entryPtr;
555 TableTag *tagPtr = NULL;
557 entryPtr = Tcl_FindHashEntry((mode == ROW) ? tablePtr->rowStyles
558 : tablePtr->colStyles, (char *) cell);
559 if (entryPtr == NULL) {
560 char *cmd = (mode == ROW) ? tablePtr->rowTagCmd : tablePtr->colTagCmd;
562 register Tcl_Interp *interp = tablePtr->interp;
563 char buf[INDEX_BUFSIZE];
565 * Since no specific row/col tag exists, eval the given command
566 * with row/col appended
568 sprintf(buf, " %d", cell);
569 Tcl_Preserve((ClientData) interp);
570 if (Tcl_VarEval(interp, cmd, buf, (char *)NULL) == TCL_OK) {
571 char *name = Tcl_GetStringResult(interp);
574 * If a result was returned, check to see if it is
577 entryPtr = Tcl_FindHashEntry(tablePtr->tagTable, name);
580 Tcl_Release((ClientData) interp);
581 Tcl_ResetResult(interp);
584 if (entryPtr != NULL) {
586 * This can be either the one in row|colStyles,
587 * or that returned by eval'ing the row|colTagCmd
589 tagPtr = (TableTag *) Tcl_GetHashValue(entryPtr);
595 *----------------------------------------------------------------------
598 * Releases the resources used by a tag before it is freed up.
604 * The tag is no longer valid.
606 *----------------------------------------------------------------------
609 TableCleanupTag(Table *tablePtr, TableTag *tagPtr)
612 * Free resources that the optionSpec doesn't specifically know about
615 Tk_FreeImage(tagPtr->image);
618 Tk_FreeOptions(tagConfig, (char *) tagPtr, tablePtr->display, 0);
622 *--------------------------------------------------------------
625 * This procedure is invoked to process the tag method
626 * that corresponds to a widget managed by this module.
627 * See the user documentation for details on what it does.
630 * A standard Tcl result.
633 * See the user documentation.
635 *--------------------------------------------------------------
638 Table_TagCmd(ClientData clientData, register Tcl_Interp *interp,
639 int objc, Tcl_Obj *CONST objv[])
641 register Table *tablePtr = (Table *)clientData;
642 int result = TCL_OK, cmdIndex, i, newEntry, value, len;
643 int row, col, tagPrio, refresh = 0;
644 TableTag *tagPtr, *tag2Ptr;
645 Tcl_HashEntry *entryPtr, *scanPtr;
646 Tcl_HashTable *hashTblPtr;
647 Tcl_HashSearch search;
649 Tcl_Obj *objPtr, *resultPtr;
650 char buf[INDEX_BUFSIZE], *keybuf, *tagname;
653 Tcl_WrongNumArgs(interp, 2, objv, "option ?arg arg ...?");
657 result = Tcl_GetIndexFromObj(interp, objv[2], tagCmdNames,
658 "tag option", 0, &cmdIndex);
659 if (result != TCL_OK) {
663 * Before using this object, make sure there aren't any calls that
664 * could have changed the interp result, thus freeing the object.
666 resultPtr = Tcl_GetObjResult(interp);
668 switch ((enum tagCmd) cmdIndex) {
669 case TAG_CELLTAG: /* add named tag to a (group of) cell(s) */
671 Tcl_WrongNumArgs(interp, 3, objv, "tag ?arg arg ...?");
674 tagname = Tcl_GetStringFromObj(objv[3], &len);
677 * An empty string was specified, so just delete the tag.
682 * Get the pointer to the tag structure. If it doesn't
683 * exist, it will be created.
685 tagPtr = TableTagGetEntry(tablePtr, tagname, 0, NULL);
690 * The user just wants the cells with this tag returned.
691 * Handle specially tags named: active, flash, sel, title
694 if ((tablePtr->flags & HAS_ACTIVE) &&
695 STREQ(tagname, "active")) {
697 tablePtr->activeRow+tablePtr->rowOffset,
698 tablePtr->activeCol+tablePtr->colOffset, buf);
699 Tcl_SetStringObj(resultPtr, buf, -1);
700 } else if ((tablePtr->flashMode && STREQ(tagname, "flash"))
701 || STREQ(tagname, "sel")) {
702 hashTblPtr = (*tagname == 's') ?
703 tablePtr->selCells : tablePtr->flashCells;
704 for (scanPtr = Tcl_FirstHashEntry(hashTblPtr, &search);
706 scanPtr = Tcl_NextHashEntry(&search)) {
707 keybuf = (char *) Tcl_GetHashKey(hashTblPtr, scanPtr);
708 Tcl_ListObjAppendElement(NULL, resultPtr,
709 Tcl_NewStringObj(keybuf, -1));
711 } else if (STREQ(tagname, "title") &&
712 (tablePtr->titleRows || tablePtr->titleCols)) {
713 for (row = tablePtr->rowOffset;
714 row < tablePtr->rowOffset+tablePtr->rows; row++) {
715 for (col = tablePtr->colOffset;
716 col < tablePtr->colOffset+tablePtr->titleCols;
718 TableMakeArrayIndex(row, col, buf);
719 Tcl_ListObjAppendElement(NULL, resultPtr,
720 Tcl_NewStringObj(buf, -1));
723 for (row = tablePtr->rowOffset;
724 row < tablePtr->rowOffset+tablePtr->titleRows;
726 for (col = tablePtr->colOffset+tablePtr->titleCols;
727 col < tablePtr->colOffset+tablePtr->cols; col++) {
728 TableMakeArrayIndex(row, col, buf);
729 Tcl_ListObjAppendElement(NULL, resultPtr,
730 Tcl_NewStringObj(buf, -1));
735 * Check this tag pointer amongst all tagged cells
737 for (scanPtr = Tcl_FirstHashEntry(tablePtr->cellStyles,
740 scanPtr = Tcl_NextHashEntry(&search)) {
741 if ((TableTag *) Tcl_GetHashValue(scanPtr) == tagPtr) {
742 keybuf = (char *) Tcl_GetHashKey(
743 tablePtr->cellStyles, scanPtr);
744 Tcl_ListObjAppendElement(NULL, resultPtr,
745 Tcl_NewStringObj(keybuf, -1));
753 * Loop through the arguments and fill in the hash table
755 for (i = 4; i < objc; i++) {
757 * Try and parse the index
759 if (TableGetIndexObj(tablePtr, objv[i], &row, &col)
764 * Get the hash key ready
766 TableMakeArrayIndex(row, col, buf);
768 if (tagPtr == NULL) {
772 entryPtr = Tcl_FindHashEntry(tablePtr->cellStyles, buf);
773 if (entryPtr != NULL) {
774 Tcl_DeleteHashEntry(entryPtr);
779 * Add a key to the hash table and set it to point to the
780 * Tag structure if it wasn't the same as an existing one
782 entryPtr = Tcl_CreateHashEntry(tablePtr->cellStyles,
784 if (newEntry || (tagPtr !=
785 (TableTag *) Tcl_GetHashValue(entryPtr))) {
786 Tcl_SetHashValue(entryPtr, (ClientData) tagPtr);
791 * Now invalidate this cell for redraw
794 TableRefresh(tablePtr, row-tablePtr->rowOffset,
795 col-tablePtr->colOffset, CELL);
801 case TAG_ROWTAG: { /* tag a row or a column */
802 int forRows = (cmdIndex == TAG_ROWTAG);
805 Tcl_WrongNumArgs(interp, 3, objv, "tag ?arg arg ..?");
808 tagname = Tcl_GetStringFromObj(objv[3], &len);
811 * Empty string, so we want to delete this element
816 * Get the pointer to the tag structure. If it doesn't
817 * exist, it will be created.
819 tagPtr = TableTagGetEntry(tablePtr, tagname, 0, NULL);
823 * Choose the correct hash table based on args
825 hashTblPtr = forRows ? tablePtr->rowStyles : tablePtr->colStyles;
828 /* the user just wants the tagged cells to be returned */
829 /* Special handling for tags: active, flash, sel, title */
831 if ((tablePtr->flags & HAS_ACTIVE) &&
832 strcmp(tagname, "active") == 0) {
833 Tcl_SetIntObj(resultPtr,
835 tablePtr->activeRow+tablePtr->rowOffset :
836 tablePtr->activeCol+tablePtr->colOffset));
837 } else if ((tablePtr->flashMode && STREQ(tagname, "flash"))
838 || STREQ(tagname, "sel")) {
839 Tcl_HashTable *cacheTblPtr;
841 cacheTblPtr = (Tcl_HashTable *)
842 ckalloc(sizeof(Tcl_HashTable));
843 Tcl_InitHashTable(cacheTblPtr, TCL_ONE_WORD_KEYS);
845 hashTblPtr = (*tagname == 's') ?
846 tablePtr->selCells : tablePtr->flashCells;
847 for (scanPtr = Tcl_FirstHashEntry(hashTblPtr, &search);
849 scanPtr = Tcl_NextHashEntry(&search)) {
850 TableParseArrayIndex(&row, &col,
851 Tcl_GetHashKey(hashTblPtr, scanPtr));
852 value = forRows ? row : col;
853 entryPtr = Tcl_CreateHashEntry(cacheTblPtr,
854 (char *)value, &newEntry);
856 Tcl_ListObjAppendElement(NULL, resultPtr,
857 Tcl_NewIntObj(value));
861 Tcl_DeleteHashTable(cacheTblPtr);
862 ckfree((char *) (cacheTblPtr));
863 } else if (STREQ(tagname, "title") &&
864 (forRows?tablePtr->titleRows:tablePtr->titleCols)) {
866 for (row = tablePtr->rowOffset;
867 row < tablePtr->rowOffset+tablePtr->titleRows;
869 Tcl_ListObjAppendElement(NULL, resultPtr,
873 for (col = tablePtr->colOffset;
874 col < tablePtr->colOffset+tablePtr->titleCols;
876 Tcl_ListObjAppendElement(NULL, resultPtr,
881 for (scanPtr = Tcl_FirstHashEntry(hashTblPtr, &search);
883 scanPtr = Tcl_NextHashEntry(&search)) {
884 /* is this the tag pointer on this row */
885 if ((TableTag *) Tcl_GetHashValue(scanPtr) == tagPtr) {
886 objPtr = Tcl_NewIntObj(
887 (int) Tcl_GetHashKey(hashTblPtr, scanPtr));
888 Tcl_ListObjAppendElement(NULL, resultPtr, objPtr);
896 * Loop through the arguments and fill in the hash table
898 for (i = 4; i < objc; i++) {
900 * Try and parse the index
902 if (Tcl_GetIntFromObj(interp, objv[i], &value) != TCL_OK) {
905 if (tagPtr == NULL) {
909 entryPtr = Tcl_FindHashEntry(hashTblPtr, (char *)value);
910 if (entryPtr != NULL) {
911 Tcl_DeleteHashEntry(entryPtr);
916 * Add a key to the hash table and set it to point to the
917 * Tag structure if it wasn't the same as an existing one
919 entryPtr = Tcl_CreateHashEntry(hashTblPtr,
920 (char *) value, &newEntry);
921 if (newEntry || (tagPtr !=
922 (TableTag *) Tcl_GetHashValue(entryPtr))) {
923 Tcl_SetHashValue(entryPtr, (ClientData) tagPtr);
927 /* and invalidate the row or column affected */
929 if (cmdIndex == TAG_ROWTAG) {
930 TableRefresh(tablePtr, value-tablePtr->rowOffset, 0,
933 TableRefresh(tablePtr, 0, value-tablePtr->colOffset,
938 return TCL_OK; /* COLTAG && ROWTAG */
943 Tcl_WrongNumArgs(interp, 3, objv, "tagName option");
946 tagname = Tcl_GetString(objv[3]);
947 entryPtr = Tcl_FindHashEntry(tablePtr->tagTable, tagname);
948 if (entryPtr == NULL) {
951 tagPtr = (TableTag *) Tcl_GetHashValue (entryPtr);
952 result = Tk_ConfigureValue(interp, tablePtr->tkwin, tagConfig,
953 (char *) tagPtr, Tcl_GetString(objv[4]), 0);
955 return result; /* CGET */
959 Tcl_WrongNumArgs(interp, 3, objv, "tagName ?arg arg ...?");
964 * Get the pointer to the tag structure. If it doesn't
965 * exist, it will be created.
967 tagPtr = TableTagGetEntry(tablePtr, Tcl_GetString(objv[3]),
971 * If there were less than 6 args, we return the configuration
972 * (for all or just one option), even for new tags
975 result = Tk_ConfigureInfo(interp, tablePtr->tkwin, tagConfig,
976 (char *) tagPtr, (objc == 5) ?
977 Tcl_GetString(objv[4]) : NULL, 0);
982 argv = (char **) ckalloc((objc + 1) * sizeof(char *));
983 for (i = 0; i < objc; i++)
984 argv[i] = Tcl_GetString(objv[i]);
987 result = Tk_ConfigureWidget(interp, tablePtr->tkwin,
988 tagConfig, objc-4, argv+4, (char *) tagPtr,
989 TK_CONFIG_ARGV_ONLY);
990 ckfree((char *) argv);
991 if (result == TCL_ERROR) {
996 * Handle change of image name
998 if (tagPtr->imageStr) {
999 image = Tk_GetImage(interp, tablePtr->tkwin,
1001 TableImageProc, (ClientData)tablePtr);
1002 if (image == NULL) {
1008 if (tagPtr->image) {
1009 Tk_FreeImage(tagPtr->image);
1011 tagPtr->image = image;
1014 * We reconfigured, so invalidate the table to redraw
1016 TableInvalidateAll(tablePtr, 0);
1023 Tcl_WrongNumArgs(interp, 3, objv, "tagName ?tagName ...?");
1026 /* run through the remaining arguments */
1027 for (i = 3; i < objc; i++) {
1028 tagname = Tcl_GetString(objv[i]);
1029 /* cannot delete the title tag */
1030 if (STREQ(tagname, "title") ||
1031 STREQ(tagname, "sel") ||
1032 STREQ(tagname, "flash") ||
1033 STREQ(tagname, "active")) {
1034 Tcl_AppendStringsToObj(resultPtr, "cannot delete ",
1035 tagname, " tag", (char *) NULL);
1038 entryPtr = Tcl_FindHashEntry(tablePtr->tagTable, tagname);
1039 if (entryPtr != NULL) {
1040 /* get the tag pointer */
1041 tagPtr = (TableTag *) Tcl_GetHashValue(entryPtr);
1043 /* delete all references to this tag in rows */
1044 scanPtr = Tcl_FirstHashEntry(tablePtr->rowStyles, &search);
1045 for (; scanPtr != NULL;
1046 scanPtr = Tcl_NextHashEntry(&search)) {
1047 if ((TableTag *)Tcl_GetHashValue(scanPtr) == tagPtr) {
1048 Tcl_DeleteHashEntry(scanPtr);
1053 /* delete all references to this tag in cols */
1054 scanPtr = Tcl_FirstHashEntry(tablePtr->colStyles, &search);
1055 for (; scanPtr != NULL;
1056 scanPtr = Tcl_NextHashEntry(&search)) {
1057 if ((TableTag *)Tcl_GetHashValue(scanPtr) == tagPtr) {
1058 Tcl_DeleteHashEntry(scanPtr);
1063 /* delete all references to this tag in cells */
1064 scanPtr = Tcl_FirstHashEntry(tablePtr->cellStyles,
1066 for (; scanPtr != NULL;
1067 scanPtr = Tcl_NextHashEntry(&search)) {
1068 if ((TableTag *)Tcl_GetHashValue(scanPtr) == tagPtr) {
1069 Tcl_DeleteHashEntry(scanPtr);
1075 * Remove the tag from the prio list and collapse
1076 * the rest of the tags. We could check for shrinking
1077 * the prio list as well.
1079 for (i = 0; i < tablePtr->tagPrioSize; i++) {
1080 if (tablePtr->tagPrios[i] == tagPtr) break;
1082 for ( ; i < tablePtr->tagPrioSize; i++) {
1083 tablePtr->tagPrioNames[i] =
1084 tablePtr->tagPrioNames[i+1];
1085 tablePtr->tagPrios[i] = tablePtr->tagPrios[i+1];
1087 tablePtr->tagPrioSize--;
1089 /* Release the tag structure */
1090 TableCleanupTag(tablePtr, tagPtr);
1091 ckfree((char *) tagPtr);
1093 /* And free the hash table entry */
1094 Tcl_DeleteHashEntry(entryPtr);
1097 /* since we deleted a tag, redraw the screen */
1099 TableInvalidateAll(tablePtr, 0);
1105 Tcl_WrongNumArgs(interp, 3, objv, "tagName");
1108 Tcl_SetBooleanObj(resultPtr,
1109 (Tcl_FindHashEntry(tablePtr->tagTable,
1110 Tcl_GetString(objv[3])) != NULL));
1114 /* does a tag contain a index ? */
1116 Tcl_WrongNumArgs(interp, 3, objv, "tag index");
1119 tagname = Tcl_GetString(objv[3]);
1120 /* check to see if the tag actually exists */
1121 entryPtr = Tcl_FindHashEntry(tablePtr->tagTable, tagname);
1122 if (entryPtr == NULL) {
1123 /* Unknown tag, just return 0 */
1124 Tcl_SetBooleanObj(resultPtr, 0);
1128 if (TableGetIndexObj(tablePtr, objv[4], &row, &col) != TCL_OK) {
1131 /* create hash key */
1132 TableMakeArrayIndex(row, col, buf);
1134 if (STREQ(tagname, "active")) {
1135 result = (tablePtr->activeRow+tablePtr->rowOffset==row &&
1136 tablePtr->activeCol+tablePtr->colOffset==col);
1137 } else if (STREQ(tagname, "flash")) {
1138 result = (tablePtr->flashMode &&
1139 (Tcl_FindHashEntry(tablePtr->flashCells, buf)
1141 } else if (STREQ(tagname, "sel")) {
1142 result = (Tcl_FindHashEntry(tablePtr->selCells, buf) != NULL);
1143 } else if (STREQ(tagname, "title")) {
1144 result = (row < tablePtr->titleRows+tablePtr->rowOffset ||
1145 col < tablePtr->titleCols+tablePtr->colOffset);
1147 /* get the pointer to the tag structure */
1148 tagPtr = (TableTag *) Tcl_GetHashValue(entryPtr);
1149 scanPtr = Tcl_FindHashEntry(tablePtr->cellStyles, buf);
1151 * Look to see if there is a cell, row, or col tag
1154 result = ((scanPtr &&
1155 (tagPtr == (TableTag *) Tcl_GetHashValue(scanPtr))) ||
1156 (tagPtr == FindRowColTag(tablePtr, row, ROW)) ||
1157 (tagPtr == FindRowColTag(tablePtr, col, COL)));
1160 * Because we may call FindRowColTag above, we can't use
1161 * the resultPtr, but this is almost equivalent, and is SAFE
1163 Tcl_SetObjResult(interp, Tcl_NewBooleanObj(result));
1168 * Print out the tag names in priority order
1170 if (objc < 3 || objc > 4) {
1171 Tcl_WrongNumArgs(interp, 3, objv, "?pattern?");
1174 tagname = (objc == 4) ? Tcl_GetString(objv[3]) : NULL;
1175 for (i = 0; i < tablePtr->tagPrioSize; i++) {
1176 keybuf = tablePtr->tagPrioNames[i];
1177 if (objc == 3 || Tcl_StringMatch(keybuf, tagname)) {
1178 objPtr = Tcl_NewStringObj(keybuf, -1);
1179 Tcl_ListObjAppendElement(NULL, resultPtr, objPtr);
1187 * Change priority of the named tag
1189 if (objc != 4 && objc != 5) {
1190 Tcl_WrongNumArgs(interp, 3, objv, (cmdIndex == TAG_LOWER) ?
1191 "tagName ?belowThis?" : "tagName ?aboveThis?");
1194 tagname = Tcl_GetString(objv[3]);
1195 /* check to see if the tag actually exists */
1196 entryPtr = Tcl_FindHashEntry(tablePtr->tagTable, tagname);
1197 if (entryPtr == NULL) {
1200 tagPtr = (TableTag *) Tcl_GetHashValue(entryPtr);
1201 tagPrio = TableTagGetPriority(tablePtr, tagPtr);
1202 keybuf = tablePtr->tagPrioNames[tagPrio];
1204 * In the RAISE case, the priority is one higher (-1) because
1205 * we want the named tag to move above the other in priority.
1208 tagname = Tcl_GetString(objv[4]);
1209 entryPtr = Tcl_FindHashEntry(tablePtr->tagTable, tagname);
1210 if (entryPtr == NULL) {
1213 tag2Ptr = (TableTag *) Tcl_GetHashValue(entryPtr);
1214 if (cmdIndex == TAG_LOWER) {
1215 value = TableTagGetPriority(tablePtr, tag2Ptr);
1217 value = TableTagGetPriority(tablePtr, tag2Ptr) - 1;
1220 if (cmdIndex == TAG_LOWER) {
1222 * Lower this tag's priority to the bottom.
1224 value = tablePtr->tagPrioSize - 1;
1227 * Raise this tag's priority to the top.
1232 if (value < tagPrio) {
1234 * Move tag up in priority.
1236 for (i = tagPrio; i > value; i--) {
1237 tablePtr->tagPrioNames[i] = tablePtr->tagPrioNames[i-1];
1238 tablePtr->tagPrios[i] = tablePtr->tagPrios[i-1];
1241 tablePtr->tagPrioNames[i] = keybuf;
1242 tablePtr->tagPrios[i] = tagPtr;
1244 } else if (value > tagPrio) {
1246 * Move tag down in priority.
1248 for (i = tagPrio; i < value; i++) {
1249 tablePtr->tagPrioNames[i] = tablePtr->tagPrioNames[i+1];
1250 tablePtr->tagPrios[i] = tablePtr->tagPrios[i+1];
1252 tablePtr->tagPrioNames[i] = keybuf;
1253 tablePtr->tagPrios[i] = tagPtr;
1256 /* since we deleted a tag, redraw the screen */
1258 TableInvalidateAll(tablePtr, 0);
1267 * When jumping here, ensure the invalid 'tagname' is set already.
1269 Tcl_AppendStringsToObj(resultPtr, "invalid tag name \"",
1270 tagname, "\"", (char *) NULL);