diff options
author | treectrl <treectrl> | 2002-12-17 05:04:00 (GMT) |
---|---|---|
committer | treectrl <treectrl> | 2002-12-17 05:04:00 (GMT) |
commit | 51219bf94e57870b142db498f63180828d6990d9 (patch) | |
tree | 2aaef21ae17c7dc8591f1fdf095fb4fbeeef8197 /generic/tkTreeColumn.c | |
download | tktreectrl-51219bf94e57870b142db498f63180828d6990d9.zip tktreectrl-51219bf94e57870b142db498f63180828d6990d9.tar.gz tktreectrl-51219bf94e57870b142db498f63180828d6990d9.tar.bz2 |
Initial revision
Diffstat (limited to 'generic/tkTreeColumn.c')
-rw-r--r-- | generic/tkTreeColumn.c | 1547 |
1 files changed, 1547 insertions, 0 deletions
diff --git a/generic/tkTreeColumn.c b/generic/tkTreeColumn.c new file mode 100644 index 0000000..6d43e1f --- /dev/null +++ b/generic/tkTreeColumn.c @@ -0,0 +1,1547 @@ +#include "tkTreeCtrl.h" + +typedef struct Column Column; + +struct Column +{ + char *text; /* -text */ + int width; /* -width */ + Tcl_Obj *widthObj; /* -width */ + int minWidth; /* -minwidth */ + Tcl_Obj *minWidthObj; /* -minwidth */ + int stepWidth; /* -stepwidth */ + Tcl_Obj *stepWidthObj; /* -stepwidth */ + int widthHack; /* -widthhack */ + Tk_Font tkfont; /* -font */ + Tk_Justify justify; /* -justify */ + Tk_3DBorder border; /* -border */ + int borderWidth; /* -borderwidth */ + int relief; /* -relief */ + XColor *textColor; /* -textcolor */ + int expand; /* -expand */ + int visible; /* -visible */ + char *tag; /* -tag */ + char *imageString; /* -image */ + Pixmap bitmap; /* -bitmap */ + int sunken; /* -sunken */ + Tcl_Obj *itemBgObj; /* -itembackground */ + int button; /* -button */ + + TreeCtrl *tree; + int index; /* column number */ + int textLen; + int textWidth; + Tk_Image image; + int neededWidth; /* calculated from borders + text + arrow */ + int neededHeight; /* calculated from borders + text */ + int useWidth; /* -width, -minwidth, or required+expansion */ + int widthOfItems; /* width of all TreeItemColumns */ + int textPad[2]; /* padding for text */ + int imagePad[2]; /* padding for image */ + int itemBgCount; + XColor **itemBgColor; + GC bitmapGC; + +#define ARROW_NONE 0 +#define ARROW_UP 1 +#define ARROW_DOWN 2 + int arrow; + +#define SIDE_LEFT 0 +#define SIDE_RIGHT 1 + int arrowSide; + int arrowGravity; + + int arrowPad[2]; + Column *next; +}; + +static char *arrowST[] = { "none", "up", "down", (char *) NULL }; +static char *arrowSideST[] = { "left", "right", (char *) NULL }; + +#define COLU_CONF_IMAGE 0x0001 +#define COLU_CONF_NWIDTH 0x0002 /* neededWidth */ +#define COLU_CONF_NHEIGHT 0x0004 /* neededHeight */ +#define COLU_CONF_TWIDTH 0x0008 /* totalWidth */ +#define COLU_CONF_ITEMBG 0x0010 +#define COLU_CONF_DISPLAY 0x0040 +#define COLU_CONF_JUSTIFY 0x0080 +#define COLU_CONF_TAG 0x0100 +#define COLU_CONF_TEXT 0x0200 +#define COLU_CONF_BITMAP 0x0400 +#define COLU_CONF_RANGES 0x0800 + +static Tk_OptionSpec columnSpecs[] = { + {TK_OPTION_STRING_TABLE, "-arrow", (char *) NULL, (char *) NULL, + "none", -1, Tk_Offset(Column, arrow), + 0, (ClientData) arrowST, COLU_CONF_NWIDTH | COLU_CONF_DISPLAY}, + {TK_OPTION_STRING_TABLE, "-arrowside", (char *) NULL, (char *) NULL, + "right", -1, Tk_Offset(Column, arrowSide), + 0, (ClientData) arrowSideST, COLU_CONF_NWIDTH | COLU_CONF_DISPLAY}, + {TK_OPTION_STRING_TABLE, "-arrowgravity", (char *) NULL, (char *) NULL, + "left", -1, Tk_Offset(Column, arrowGravity), + 0, (ClientData) arrowSideST, COLU_CONF_DISPLAY}, + {TK_OPTION_PIXELS, "-arrowpadw", (char *) NULL, (char *) NULL, + "6", -1, Tk_Offset(Column, arrowPad[SIDE_LEFT]), + 0, (ClientData) NULL, COLU_CONF_NWIDTH | COLU_CONF_DISPLAY}, + {TK_OPTION_PIXELS, "-arrowpade", (char *) NULL, (char *) NULL, + "6", -1, Tk_Offset(Column, arrowPad[SIDE_RIGHT]), + 0, (ClientData) NULL, COLU_CONF_NWIDTH | COLU_CONF_DISPLAY}, + {TK_OPTION_BITMAP, "-bitmap", (char *) NULL, (char *) NULL, + (char *) NULL, -1, Tk_Offset(Column, bitmap), + TK_OPTION_NULL_OK, (ClientData) NULL, + COLU_CONF_BITMAP | COLU_CONF_NWIDTH | COLU_CONF_NHEIGHT | COLU_CONF_DISPLAY}, + {TK_OPTION_BORDER, "-background", (char *) NULL, (char *) NULL, + DEF_BUTTON_BG_COLOR, -1, Tk_Offset(Column, border), + 0, (ClientData) DEF_BUTTON_BG_MONO, COLU_CONF_DISPLAY}, + {TK_OPTION_PIXELS, "-borderwidth", (char *) NULL, (char *) NULL, + "2", -1, Tk_Offset(Column, borderWidth), + 0, (ClientData) NULL, COLU_CONF_TWIDTH | COLU_CONF_NWIDTH | COLU_CONF_NHEIGHT | COLU_CONF_DISPLAY}, + {TK_OPTION_BOOLEAN, "-button", (char *) NULL, (char *) NULL, + "1", -1, Tk_Offset(Column, button), + 0, (ClientData) NULL, 0}, + {TK_OPTION_BOOLEAN, "-expand", (char *) NULL, (char *) NULL, + "0", -1, Tk_Offset(Column, expand), + 0, (ClientData) NULL, COLU_CONF_TWIDTH}, + {TK_OPTION_FONT, "-font", (char *) NULL, (char *) NULL, + (char *) NULL, -1, Tk_Offset(Column, tkfont), + TK_OPTION_NULL_OK, (ClientData) NULL, COLU_CONF_NWIDTH | COLU_CONF_NHEIGHT | COLU_CONF_DISPLAY}, + {TK_OPTION_STRING, "-image", (char *) NULL, (char *) NULL, + (char *) NULL, -1, Tk_Offset(Column, imageString), + TK_OPTION_NULL_OK, (ClientData) NULL, + COLU_CONF_IMAGE | COLU_CONF_NWIDTH | COLU_CONF_NHEIGHT | COLU_CONF_DISPLAY}, + {TK_OPTION_PIXELS, "-imagepade", (char *) NULL, (char *) NULL, + "6", -1, Tk_Offset(Column, imagePad[SIDE_RIGHT]), + 0, (ClientData) NULL, COLU_CONF_NWIDTH | COLU_CONF_DISPLAY}, + {TK_OPTION_PIXELS, "-imagepadw", (char *) NULL, (char *) NULL, + "6", -1, Tk_Offset(Column, imagePad[SIDE_LEFT]), + 0, (ClientData) NULL, COLU_CONF_NWIDTH | COLU_CONF_DISPLAY}, + {TK_OPTION_STRING, "-itembackground", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(Column, itemBgObj), -1, + TK_OPTION_NULL_OK, (ClientData) NULL, COLU_CONF_ITEMBG}, + {TK_OPTION_JUSTIFY, "-justify", (char *) NULL, (char *) NULL, + "left", -1, Tk_Offset(Column, justify), + 0, (ClientData) NULL, COLU_CONF_DISPLAY | COLU_CONF_JUSTIFY}, + {TK_OPTION_PIXELS, "-minwidth", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(Column, minWidthObj), + Tk_Offset(Column, minWidth), + TK_OPTION_NULL_OK, (ClientData) NULL, COLU_CONF_TWIDTH}, + {TK_OPTION_RELIEF, "-relief", (char *) NULL, (char *) NULL, + "raised", -1, Tk_Offset(Column, relief), + 0, (ClientData) NULL, COLU_CONF_DISPLAY}, + {TK_OPTION_PIXELS, "-stepwidth", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(Column, stepWidthObj), + Tk_Offset(Column, stepWidth), + TK_OPTION_NULL_OK, (ClientData) NULL, COLU_CONF_RANGES}, + {TK_OPTION_BOOLEAN, "-sunken", (char *) NULL, (char *) NULL, + "0", -1, Tk_Offset(Column, sunken), + 0, (ClientData) NULL, COLU_CONF_DISPLAY}, + {TK_OPTION_STRING, "-tag", (char *) NULL, (char *) NULL, + (char *) NULL, -1, Tk_Offset(Column, tag), + TK_OPTION_NULL_OK, (ClientData) NULL, COLU_CONF_TAG}, + {TK_OPTION_STRING, "-text", (char *) NULL, (char *) NULL, + (char *) NULL, -1, Tk_Offset(Column, text), + TK_OPTION_NULL_OK, (ClientData) NULL, + COLU_CONF_TEXT | COLU_CONF_NWIDTH | COLU_CONF_NHEIGHT | COLU_CONF_DISPLAY}, + {TK_OPTION_COLOR, "-textcolor", (char *) NULL, (char *) NULL, + DEF_BUTTON_FG, -1, Tk_Offset(Column, textColor), + 0, (ClientData) NULL, COLU_CONF_DISPLAY}, + {TK_OPTION_PIXELS, "-textpade", (char *) NULL, (char *) NULL, + "6", -1, Tk_Offset(Column, textPad[SIDE_RIGHT]), + 0, (ClientData) NULL, COLU_CONF_NWIDTH | COLU_CONF_DISPLAY}, + {TK_OPTION_PIXELS, "-textpadw", (char *) NULL, (char *) NULL, + "6", -1, Tk_Offset(Column, textPad[SIDE_LEFT]), + 0, (ClientData) NULL, COLU_CONF_NWIDTH | COLU_CONF_DISPLAY}, + {TK_OPTION_PIXELS, "-width", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(Column, widthObj), Tk_Offset(Column, width), + TK_OPTION_NULL_OK, (ClientData) NULL, COLU_CONF_TWIDTH}, + {TK_OPTION_BOOLEAN, "-visible", (char *) NULL, (char *) NULL, + "1", -1, Tk_Offset(Column, visible), + 0, (ClientData) NULL, COLU_CONF_TWIDTH | COLU_CONF_DISPLAY}, + {TK_OPTION_BOOLEAN, "-widthhack", (char *) NULL, (char *) NULL, + "0", -1, Tk_Offset(Column, widthHack), + 0, (ClientData) NULL, COLU_CONF_RANGES}, + {TK_OPTION_END, (char *) NULL, (char *) NULL, (char *) NULL, + (char *) NULL, 0, -1, 0, 0, 0} +}; + +static Tk_OptionTable columnOptionTable = NULL; + +/* Called when Tk_Image is deleted or modified */ +static void ImageChangedProc( + ClientData clientData, + int x, int y, + int width, int height, + int imageWidth, int imageHeight) +{ + /* I would like to know the image was deleted... */ +} + +int Tree_FindColumnByTag(TreeCtrl *tree, Tcl_Obj *obj, TreeColumn *columnPtr, int flags) +{ + Column *walk = (Column *) tree->columns; + char *string = Tcl_GetString(obj); + + if (!strcmp(string, "tail")) + { + if (!(flags & CFO_NOT_TAIL)) + { + (*columnPtr) = tree->columnTail; + return TCL_OK; + } + FormatResult(tree->interp, "can't specify \"tail\" for this command"); + return TCL_ERROR; + } + + while (walk != NULL) + { + if ((walk->tag != NULL) && !strcmp(walk->tag, string)) + { + (*columnPtr) = (TreeColumn) walk; + return TCL_OK; + } + walk = walk->next; + } + FormatResult(tree->interp, "column with tag \"%s\" doesn't exist", + string); + return TCL_ERROR; +} + +int TreeColumn_FromObj(TreeCtrl *tree, Tcl_Obj *obj, TreeColumn *columnPtr, int flags) +{ + int columnIndex; + + if (Tcl_GetIntFromObj(NULL, obj, &columnIndex) == TCL_OK) + { + if (columnIndex < 0 || columnIndex >= tree->columnCount) + { + FormatResult(tree->interp, + "bad column index \"%d\": must be from 0 to %d", + columnIndex, tree->columnCount - 1); + return TCL_ERROR; + } + (*columnPtr) = Tree_FindColumn(tree, columnIndex); + return TCL_OK; + } + + return Tree_FindColumnByTag(tree, obj, columnPtr, flags); +} + +TreeColumn Tree_FindColumn(TreeCtrl *tree, int columnIndex) +{ + Column *column = (Column *) tree->columns; + + while (column != NULL) + { + if (column->index == columnIndex) + break; + column = column->next; + } + return (TreeColumn) column; +} + +TreeColumn TreeColumn_Next(TreeColumn column_) +{ + return (TreeColumn) ((Column *) column_)->next; +} + +static void Column_FreeColors(XColor **colors, int count) +{ + int i; + + if (colors == NULL) + return; + for (i = 0; i < count; i++) + if (colors[i] != NULL) + Tk_FreeColor(colors[i]); + wipefree((char *) colors, sizeof(XColor *) * count); +} + +static int Column_Config(Column *column, int objc, Tcl_Obj *CONST objv[]) +{ + TreeCtrl *tree = column->tree; + Column saved, *walk; + Tk_SavedOptions savedOptions; + int error; + Tcl_Obj *errorResult = NULL; + int mask; + XGCValues gcValues; + unsigned long gcMask; + + for (error = 0; error <= 1; error++) + { + if (error == 0) + { + if (Tk_SetOptions(tree->interp, (char *) column, columnOptionTable, + objc, objv, tree->tkwin, &savedOptions, &mask) != TCL_OK) + { + mask = 0; + continue; + } + + /* Verify -tag is unique */ + if ((mask & COLU_CONF_TAG) && (column->tag != NULL)) + { + walk = (Column *) tree->columns; + if (!strcmp(column->tag, "tail")) + { + FormatResult(tree->interp, "column tag \"%s\" is not unique", + column->tag); + continue; + } + while (walk != NULL) + { + if ((walk != column) && (walk->tag != NULL) && !strcmp(walk->tag, column->tag)) + { + FormatResult(tree->interp, "column tag \"%s\" is not unique", + column->tag); + break; + } + walk = walk->next; + } + if (walk != NULL) + continue; + } + + if (mask & COLU_CONF_IMAGE) + { + saved.image = column->image; + column->image = NULL; + if (column->imageString != NULL) + { + column->image = Tk_GetImage(tree->interp, tree->tkwin, + column->imageString, ImageChangedProc, + (ClientData) column); + if (column->image == NULL) + continue; + } + } + + if (mask & COLU_CONF_ITEMBG) + { + saved.itemBgColor = column->itemBgColor; + saved.itemBgCount = column->itemBgCount; + column->itemBgColor = NULL; + column->itemBgCount = 0; + if (column->itemBgObj != NULL) + { + int i, length, listObjc; + Tcl_Obj **listObjv; + XColor **colors; + + if (Tcl_ListObjGetElements(tree->interp, column->itemBgObj, + &listObjc, &listObjv) != TCL_OK) + continue; + colors = (XColor **) ckalloc(sizeof(XColor *) * listObjc); + for (i = 0; i < listObjc; i++) + colors[i] = NULL; + for (i = 0; i < listObjc; i++) + { + /* Can specify "" for tree background */ + (void) Tcl_GetStringFromObj(listObjv[i], &length); + if (length != 0) + { + colors[i] = Tk_AllocColorFromObj(tree->interp, + tree->tkwin, listObjv[i]); + if (colors[i] == NULL) + break; + } + } + if (i < listObjc) + { + Column_FreeColors(colors, listObjc); + continue; + } + column->itemBgColor = colors; + column->itemBgCount = listObjc; + } + } + + if (mask & COLU_CONF_IMAGE) + { + if (saved.image != NULL) + Tk_FreeImage(saved.image); + } + if (mask & COLU_CONF_ITEMBG) + { + Column_FreeColors(saved.itemBgColor, saved.itemBgCount); + + /* Set max -itembackground */ + tree->columnBgCnt = 0; + walk = (Column *) tree->columns; + while (walk != NULL) + { + if (walk->itemBgCount > tree->columnBgCnt) + tree->columnBgCnt = walk->itemBgCount; + walk = walk->next; + } + } + Tk_FreeSavedOptions(&savedOptions); + break; + } + else + { + errorResult = Tcl_GetObjResult(tree->interp); + Tcl_IncrRefCount(errorResult); + Tk_RestoreSavedOptions(&savedOptions); + + if (mask & COLU_CONF_IMAGE) + { + if (column->image != NULL) + Tk_FreeImage(column->image); + column->image = saved.image; + } + if (mask & COLU_CONF_ITEMBG) + { + Column_FreeColors(column->itemBgColor, column->itemBgCount); + column->itemBgColor = saved.itemBgColor; + column->itemBgCount = saved.itemBgCount; + } + + Tcl_SetObjResult(tree->interp, errorResult); + Tcl_DecrRefCount(errorResult); + return TCL_ERROR; + } + } + + if (mask & COLU_CONF_TEXT) + { + column->textLen = column->text ? strlen(column->text) : 0; + if (column->textLen) + { + Tk_Font tkfont = column->tkfont ? column->tkfont : tree->tkfont; + column->textWidth = Tk_TextWidth(tkfont, column->text, column->textLen); + } + else + column->textWidth = 0; + } + + if (mask & COLU_CONF_BITMAP) + { + if (column->bitmapGC != None) + { + Tk_FreeGC(tree->display, column->bitmapGC); + column->bitmapGC = None; + } + if (column->bitmap != None) + { + gcValues.clip_mask = column->bitmap; + gcValues.graphics_exposures = False; + gcMask = GCClipMask | GCGraphicsExposures; + column->bitmapGC = Tk_GetGC(tree->tkwin, gcMask, &gcValues); + } + } + + if (mask & COLU_CONF_ITEMBG) + Tree_DInfoChanged(tree, DINFO_INVALIDATE | DINFO_OUT_OF_DATE); + + if (mask & COLU_CONF_NWIDTH) + column->neededWidth = -1; + if (mask & COLU_CONF_NHEIGHT) + { + column->neededHeight = -1; + tree->headerHeight = -1; + } + + if (mask & COLU_CONF_JUSTIFY) + Tree_DInfoChanged(tree, DINFO_INVALIDATE | DINFO_OUT_OF_DATE); + + /* -stepwidth and -widthHack */ + if (mask & COLU_CONF_RANGES) + Tree_DInfoChanged(tree, DINFO_REDO_RANGES); + + /* Redraw everything */ + if (mask & (COLU_CONF_TWIDTH | COLU_CONF_NWIDTH | COLU_CONF_NHEIGHT)) + { + tree->widthOfColumns = -1; + Tree_DInfoChanged(tree, DINFO_CHECK_COLUMN_WIDTH | DINFO_DRAW_HEADER); + } + + /* Redraw header only */ + else if (mask & COLU_CONF_DISPLAY) + { + Tree_DInfoChanged(tree, DINFO_DRAW_HEADER); + } + + return TCL_OK; +} + +static Column *Column_Alloc(TreeCtrl *tree) +{ + Column *column; + + if (columnOptionTable == NULL) + columnOptionTable = Tk_CreateOptionTable(tree->interp, columnSpecs); + + column = (Column *) ckalloc(sizeof(Column)); + memset(column, '\0', sizeof(Column)); + column->tree = tree; + if (Tk_InitOptions(tree->interp, (char *) column, columnOptionTable, + tree->tkwin) != TCL_OK) + { + WFREE(column, Column); + return NULL; + } +#if 0 + if (Tk_SetOptions(header->tree->interp, (char *) column, + columnOptionTable, 0, + NULL, header->tree->tkwin, &savedOptions, + (int *) NULL) != TCL_OK) + { + WFREE(column, Column); + return NULL; + } +#endif + column->neededWidth = column->neededHeight = -1; + tree->headerHeight = tree->widthOfColumns = -1; + tree->columnCount++; + return column; +} + +TreeColumn Tree_CreateColumn(TreeCtrl *tree, int columnIndex, int *isNew) +{ + Column *column = (Column *) tree->columns; + int i; + + if (isNew != NULL) + (*isNew) = FALSE; + if (column == NULL) + { + column = Column_Alloc(tree); + column->index = 0; + tree->columns = (TreeColumn) column; + if (isNew != NULL) + (*isNew) = TRUE; + } + for (i = 0; i < columnIndex; i++) + { + if (column->next == NULL) + { + column->next = Column_Alloc(tree); + column->next->index = i + 1; + if (isNew != NULL) + (*isNew) = TRUE; + } + column = column->next; + } + return (TreeColumn) column; +} + +static Column *Column_Free(Column *column) +{ + TreeCtrl *tree = column->tree; + Column *next = column->next; + + Column_FreeColors(column->itemBgColor, column->itemBgCount); + if (column->bitmapGC != None) + Tk_FreeGC(tree->display, column->bitmapGC); + if (column->image != NULL) + Tk_FreeImage(column->image); + Tk_FreeConfigOptions((char *) column, columnOptionTable, tree->tkwin); + WFREE(column, Column); + tree->columnCount--; + return next; +} + +int TreeColumn_FixedWidth(TreeColumn column_) +{ + return ((Column *) column_)->widthObj ? ((Column *) column_)->width : -1; +} + +int TreeColumn_MinWidth(TreeColumn column_) +{ + return ((Column *) column_)->minWidthObj ? ((Column *) column_)->minWidth : -1; +} + +int TreeColumn_StepWidth(TreeColumn column_) +{ + return ((Column *) column_)->stepWidthObj ? ((Column *) column_)->stepWidth : -1; +} + +int TreeColumn_NeededWidth(TreeColumn column_) +{ + Column *column = (Column *) column_; + int i, widthList[3], padList[4], n = 0; + int arrowWidth = 0; + + if (column->neededWidth >= 0) + return column->neededWidth; + + for (i = 0; i < 3; i++) widthList[i] = 0; + for (i = 0; i < 4; i++) padList[i] = 0; + + if (column->arrow != ARROW_NONE) + { + arrowWidth = Tree_HeaderHeight(column->tree) / 2; + if (!(arrowWidth & 1)) + arrowWidth--; + } + if ((column->arrow != ARROW_NONE) && (column->arrowSide == SIDE_LEFT)) + { + widthList[n] = arrowWidth; + padList[n] = column->arrowPad[SIDE_LEFT]; + padList[n + 1] = column->arrowPad[SIDE_RIGHT]; + n++; + } + if ((column->image != NULL) || (column->bitmap != None)) + { + int imgWidth, imgHeight; + if (column->image != NULL) + Tk_SizeOfImage(column->image, &imgWidth, &imgHeight); + else + Tk_SizeOfBitmap(column->tree->display, column->bitmap, &imgWidth, &imgHeight); + padList[n] = MAX(column->imagePad[SIDE_LEFT], padList[n]); + padList[n + 1] = column->imagePad[SIDE_RIGHT]; + widthList[n] = imgWidth; + n++; + } + if (column->textLen > 0) + { + padList[n] = MAX(column->textPad[SIDE_LEFT], padList[n]); + padList[n + 1] = column->textPad[SIDE_RIGHT]; + widthList[n] = column->textWidth; + n++; + } + if ((column->arrow != ARROW_NONE) && (column->arrowSide == SIDE_RIGHT)) + { + widthList[n] = arrowWidth; + padList[n] = column->arrowPad[SIDE_LEFT]; + padList[n + 1] = column->arrowPad[SIDE_RIGHT]; + n++; + } + + column->neededWidth = 0; + for (i = 0; i < n; i++) + column->neededWidth += widthList[i] + padList[i]; + column->neededWidth += padList[n]; + + return column->neededWidth; +} + +int TreeColumn_NeededHeight(TreeColumn column_) +{ + Column *column = (Column *) column_; + + if (column->neededHeight >= 0) + return column->neededHeight; + + column->neededHeight = 0; + if ((column->image != NULL) || (column->bitmap != None)) + { + int imgWidth, imgHeight; + if (column->image != NULL) + Tk_SizeOfImage(column->image, &imgWidth, &imgHeight); + else + Tk_SizeOfBitmap(column->tree->display, column->bitmap, &imgWidth, &imgHeight); + column->neededHeight = MAX(column->neededHeight, imgHeight); + } + if (column->text != NULL) + { + Tk_Font tkfont = column->tkfont ? column->tkfont : column->tree->tkfont; + Tk_FontMetrics fm; + Tk_GetFontMetrics(tkfont, &fm); + column->neededHeight = MAX(column->neededHeight, fm.linespace); + } + column->neededHeight += column->borderWidth * 2; + + return column->neededHeight; +} + +int TreeColumn_UseWidth(TreeColumn column_) +{ + /* Update layout if needed */ + (void) Tree_WidthOfColumns(((Column *) column_)->tree); + + return ((Column *) column_)->useWidth; +} + +void TreeColumn_SetUseWidth(TreeColumn column_, int width) +{ + ((Column *) column_)->useWidth = width; +} + +Tk_Justify TreeColumn_Justify(TreeColumn column_) +{ + return ((Column *) column_)->justify; +} + +int TreeColumn_WidthHack(TreeColumn column_) +{ + return ((Column *) column_)->widthHack; +} + +GC TreeColumn_BackgroundGC(TreeColumn column_, int index) +{ + Column *column = (Column *) column_; + XColor *color; + + if ((index < 0) || (column->itemBgCount == 0)) + return None; + color = column->itemBgColor[index % column->itemBgCount]; + if (color == NULL) + return None; + return Tk_GCForColor(color, Tk_WindowId(column->tree->tkwin)); +} + +int TreeColumn_Visible(TreeColumn column_) +{ + return ((Column *) column_)->visible; +} + +int TreeColumn_Index(TreeColumn column_) +{ + return ((Column *) column_)->index; +} + +int TreeColumnCmd(ClientData clientData, Tcl_Interp *interp, int objc, + Tcl_Obj *CONST objv[]) +{ + TreeCtrl *tree = (TreeCtrl *) clientData; + static CONST char *commandNames[] = { "bbox", "cget", "configure", "delete", + "neededwidth", "width", (char *) NULL }; + enum { COMMAND_BBOX, COMMAND_CGET, COMMAND_CONFIGURE, COMMAND_DELETE, + COMMAND_NEEDEDWIDTH, COMMAND_WIDTH }; + int index; + + if (objc < 3) + { + Tcl_WrongNumArgs(interp, 3, objv, "command ?arg arg...?"); + return TCL_ERROR; + } + + if (Tcl_GetIndexFromObj(interp, objv[2], commandNames, "command", 0, + &index) != TCL_OK) + { + return TCL_ERROR; + } + + switch (index) + { + case COMMAND_BBOX: + { + int x = 0; + Column *column, *walk; + + if (objc != 4) + { + Tcl_WrongNumArgs(interp, 3, objv, "columnIndex"); + return TCL_ERROR; + } + if (TreeColumn_FromObj(tree, objv[3], (TreeColumn *) &column, 0) != TCL_OK) + return TCL_ERROR; + if (!tree->showHeader || !column->visible) + break; + /* Update layout */ + Tree_WidthOfColumns(tree); + walk = (Column *) tree->columns; + while (walk != column) + { + if (column->visible) + x += walk->useWidth; + walk = walk->next; + } + FormatResult(interp, "%d %d %d %d", + x - tree->xOrigin, + tree->inset, + x - tree->xOrigin + column->useWidth, + tree->inset + Tree_HeaderHeight(tree)); + break; + } + case COMMAND_CGET: + { + TreeColumn column; + Tcl_Obj *resultObjPtr; + + if (objc != 5) + { + Tcl_WrongNumArgs(interp, 3, objv, "columnIndex option"); + return TCL_ERROR; + } + if (TreeColumn_FromObj(tree, objv[3], &column, 0) != TCL_OK) + return TCL_ERROR; + resultObjPtr = Tk_GetOptionValue(interp, (char *) column, + columnOptionTable, objv[4], tree->tkwin); + if (resultObjPtr == NULL) + return TCL_ERROR; + Tcl_SetObjResult(interp, resultObjPtr); + break; + } + + case COMMAND_CONFIGURE: + { + int columnIndex; + Column *column; + + if (objc < 4) + { + Tcl_WrongNumArgs(interp, 3, objv, "columnIndex ?option? ?value?"); + return TCL_ERROR; + } + if (Tcl_GetIntFromObj(NULL, objv[3], &columnIndex) == TCL_OK) + { + if (columnIndex < 0) + return TCL_ERROR; + column = (Column *) Tree_CreateColumn(tree, columnIndex, NULL); + if (column == NULL) + return TCL_ERROR; + } + else if (Tree_FindColumnByTag(tree, objv[3], (TreeColumn *) &column, 0) != TCL_OK) + return TCL_ERROR; + if (objc <= 5) + { + Tcl_Obj *resultObjPtr; + resultObjPtr = Tk_GetOptionInfo(interp, (char *) column, + columnOptionTable, + (objc == 4) ? (Tcl_Obj *) NULL : objv[4], + tree->tkwin); + if (resultObjPtr == NULL) + return TCL_ERROR; + Tcl_SetObjResult(interp, resultObjPtr); + break; + } + return Column_Config(column, objc - 4, objv + 4); + } + + case COMMAND_DELETE: + { + int columnIndex; + Column *column, *prev; + TreeItem item; + TreeItemColumn itemColumn; + Tcl_HashEntry *hPtr; + Tcl_HashSearch search; + + if (objc != 4) + { + Tcl_WrongNumArgs(interp, 3, objv, "columnIndex"); + return TCL_ERROR; + } + if (TreeColumn_FromObj(tree, objv[3], (TreeColumn *) &column, + CFO_NOT_TAIL) != TCL_OK) + return TCL_ERROR; + columnIndex = column->index; + if (columnIndex > 0) + { + prev = (Column *) Tree_FindColumn(tree, columnIndex - 1); + prev->next = column->next; + } + else + { + tree->columns = (TreeColumn) column->next; + } + Column_Free(column); + + if (columnIndex == tree->columnTree) + tree->columnTree = 0; + + /* Delete all TreeItemColumns */ + hPtr = Tcl_FirstHashEntry(&tree->itemHash, &search); + while (hPtr != NULL) + { + item = (TreeItem) Tcl_GetHashValue(hPtr); + itemColumn = TreeItem_FindColumn(tree, item, columnIndex); + if (itemColumn != NULL) + TreeItem_RemoveColumn(tree, item, itemColumn); + hPtr = Tcl_NextHashEntry(&search); + } + + /* Renumber columns */ + column = (Column *) tree->columns; + columnIndex = 0; + while (column != NULL) + { + column->index = columnIndex++; + column = column->next; + } + + tree->widthOfColumns = tree->headerHeight = -1; + Tree_DInfoChanged(tree, DINFO_CHECK_COLUMN_WIDTH); + break; + } + + case COMMAND_WIDTH: + { + Column *column; + + if (objc != 4) + { + Tcl_WrongNumArgs(interp, 3, objv, "columnIndex"); + return TCL_ERROR; + } + if (TreeColumn_FromObj(tree, objv[3], (TreeColumn *) &column, 0) != TCL_OK) + return TCL_ERROR; + /* Update layout if needed */ + (void) Tree_TotalWidth(tree); + Tcl_SetObjResult(interp, Tcl_NewIntObj(column->useWidth)); + break; + } + + case COMMAND_NEEDEDWIDTH: + { + Column *column; + int width; + + if (objc != 4) + { + Tcl_WrongNumArgs(interp, 3, objv, "columnIndex"); + return TCL_ERROR; + } + if (TreeColumn_FromObj(tree, objv[3], (TreeColumn *) &column, 0) != TCL_OK) + return TCL_ERROR; + /* Update layout if needed */ + (void) Tree_TotalWidth(tree); + width = TreeColumn_WidthOfItems((TreeColumn) column); + width = MAX(width, TreeColumn_NeededWidth((TreeColumn) column)); + Tcl_SetObjResult(interp, Tcl_NewIntObj(width)); + break; + } + } + + return TCL_OK; +} + +struct Layout +{ + Tk_Font tkfont; + Tk_FontMetrics fm; + int width; /* Provided by caller */ + int height; /* Provided by caller */ + int textLeft; + int textWidth; + int bytesThatFit; + int imageLeft; + int imageWidth; + int arrowLeft; + int arrowWidth; + int arrowHeight; +}; + +static void Column_Layout(Column *column, struct Layout *layout) +{ + int i, leftList[3], widthList[3], padList[4], n = 0; + int iArrow = -1, iImage = -1, iText = -1; + int left, right; + + for (i = 0; i < 3; i++) leftList[i] = 0; + for (i = 0; i < 3; i++) widthList[i] = 0; + for (i = 0; i < 4; i++) padList[i] = 0; + + if (column->arrow != ARROW_NONE) + { + layout->arrowWidth = Tree_HeaderHeight(column->tree) / 2; + if (!(layout->arrowWidth & 1)) + layout->arrowWidth--; + layout->arrowHeight = layout->arrowWidth; + } + if ((column->arrow != ARROW_NONE) && (column->arrowSide == SIDE_LEFT)) + { + widthList[n] = layout->arrowWidth; + padList[n] = column->arrowPad[SIDE_LEFT]; + padList[n + 1] = column->arrowPad[SIDE_RIGHT]; + iArrow = n++; + } + if ((column->image != NULL) || (column->bitmap != None)) + { + int imgWidth, imgHeight; + if (column->image != NULL) + Tk_SizeOfImage(column->image, &imgWidth, &imgHeight); + else + Tk_SizeOfBitmap(column->tree->display, column->bitmap, &imgWidth, &imgHeight); + padList[n] = MAX(column->imagePad[SIDE_LEFT], padList[n]); + padList[n + 1] = column->imagePad[SIDE_RIGHT]; + widthList[n] = imgWidth; + layout->imageWidth = imgWidth; + iImage = n++; + } + if (column->textLen > 0) + { + layout->tkfont = column->tkfont ? column->tkfont : column->tree->tkfont; + Tk_GetFontMetrics(layout->tkfont, &layout->fm); + layout->bytesThatFit = 0; + if (layout->width >= TreeColumn_NeededWidth((TreeColumn) column)) + { + padList[n] = MAX(column->textPad[SIDE_LEFT], padList[n]); + padList[n + 1] = column->textPad[SIDE_RIGHT]; + widthList[n] = column->textWidth; + iText = n++; + layout->bytesThatFit = column->textLen; + layout->textWidth = column->textWidth; + } + else + { + int width = column->neededWidth - layout->width; + if (width < column->textWidth) + { + width = column->textWidth - width; + layout->bytesThatFit = Ellipsis(layout->tkfont, column->text, + column->textLen, &width, "..."); + padList[n] = MAX(column->textPad[SIDE_LEFT], padList[n]); + padList[n + 1] = column->textPad[SIDE_RIGHT]; + widthList[n] = width; + iText = n++; + layout->textWidth = width; + } + } + } + if ((column->arrow != ARROW_NONE) && (column->arrowSide == SIDE_RIGHT)) + { + widthList[n] = layout->arrowWidth; + padList[n] = column->arrowPad[SIDE_LEFT]; + padList[n + 1] = column->arrowPad[SIDE_RIGHT]; + iArrow = n++; + } + + if (n == 0) + return; + + if (iText != -1) + { + switch (column->justify) + { + case TK_JUSTIFY_LEFT: + leftList[iText] = 0; + break; + case TK_JUSTIFY_RIGHT: + leftList[iText] = layout->width; + break; + case TK_JUSTIFY_CENTER: + if (iImage == -1) + leftList[iText] = (layout->width - widthList[iText]) / 2; + else + leftList[iText] = (layout->width - widthList[iImage] - + padList[iText] - widthList[iText]) / 2 + widthList[iImage] + + padList[iText]; + break; + } + } + + if (iImage != -1) + { + switch (column->justify) + { + case TK_JUSTIFY_LEFT: + leftList[iImage] = 0; + break; + case TK_JUSTIFY_RIGHT: + leftList[iImage] = layout->width; + break; + case TK_JUSTIFY_CENTER: + if (iText == -1) + leftList[iImage] = (layout->width - widthList[iImage]) / 2; + else + leftList[iImage] = (layout->width - widthList[iImage] - + padList[iText] - widthList[iText]) / 2; + break; + } + } + + if (iArrow == -1) + goto finish; + + switch (column->justify) + { + case TK_JUSTIFY_LEFT: + switch (column->arrowSide) + { + case SIDE_LEFT: + leftList[iArrow] = 0; + break; + case SIDE_RIGHT: + switch (column->arrowGravity) + { + case SIDE_LEFT: + leftList[iArrow] = 0; + break; + case SIDE_RIGHT: + leftList[iArrow] = layout->width; + break; + } + break; + } + break; + case TK_JUSTIFY_RIGHT: + switch (column->arrowSide) + { + case SIDE_LEFT: + switch (column->arrowGravity) + { + case SIDE_LEFT: + leftList[iArrow] = 0; + break; + case SIDE_RIGHT: + leftList[iArrow] = layout->width; + break; + } + break; + case SIDE_RIGHT: + leftList[iArrow] = layout->width; + break; + } + break; + case TK_JUSTIFY_CENTER: + switch (column->arrowSide) + { + case SIDE_LEFT: + switch (column->arrowGravity) + { + case SIDE_LEFT: + leftList[iArrow] = 0; + break; + case SIDE_RIGHT: + if (n == 3) + leftList[iArrow] = + (layout->width - widthList[1] - padList[2] - + widthList[2]) / 2 - padList[1] - widthList[0]; + else if (n == 2) + leftList[iArrow] = + (layout->width - widthList[1]) / 2 - + padList[1] - widthList[0]; + else + leftList[iArrow] = + (layout->width - widthList[0]) / 2; + break; + } + break; + case SIDE_RIGHT: + switch (column->arrowGravity) + { + case SIDE_LEFT: + if (n == 3) + leftList[iArrow] = + (layout->width - widthList[0] - padList[1] - + widthList[1]) / 2 + widthList[0] + padList[1] + + widthList[1] + padList[2]; + else if (n == 2) + leftList[iArrow] = + (layout->width - widthList[0]) / 2 + + widthList[0] + padList[1]; + else + leftList[iArrow] = + (layout->width - widthList[0]) / 2; + break; + case SIDE_RIGHT: + leftList[iArrow] = layout->width; + break; + } + break; + } + break; + } + +finish: + right = layout->width - padList[n]; + for (i = n - 1; i >= 0; i--) + { + if (leftList[i] + widthList[i] > right) + leftList[i] = right - widthList[i]; + right -= widthList[i] + padList[i]; + } + left = padList[0]; + for (i = 0; i < n; i++) + { + if (leftList[i] < left) + leftList[i] = left; + + if (i == iArrow) + layout->arrowLeft = leftList[i]; + else if (i == iText) + layout->textLeft = leftList[i]; + else if (i == iImage) + layout->imageLeft = leftList[i]; + + left += widthList[i] + padList[i + 1]; + } +} + +void TreeColumn_Draw(TreeColumn column_, Drawable drawable, int x, int y) +{ + Column *column = (Column *) column_; + TreeCtrl *tree = column->tree; + int height = tree->headerHeight; + struct Layout layout; + int width = column->useWidth; + int relief = column->sunken ? TK_RELIEF_SUNKEN : TK_RELIEF_RAISED; + + layout.width = width; + layout.height = height; + Column_Layout(column, &layout); + + Tk_Fill3DRectangle(tree->tkwin, drawable, column->border, + x, y, width, height, 0, TK_RELIEF_FLAT /* column->borderWidth, relief */); + + if (column->image != NULL) + { + int imgW, imgH; + Tk_SizeOfImage(column->image, &imgW, &imgH); + Tk_RedrawImage(column->image, 0, 0, imgW, imgH, + drawable, x + layout.imageLeft + column->sunken, + y + (height - imgH) / 2 + column->sunken); + } + else if (column->bitmap != None) + { + int imgW, imgH, bx, by; + + Tk_SizeOfBitmap(tree->display, column->bitmap, &imgW, &imgH); + bx = x + layout.imageLeft + column->sunken; + by = y + (height - imgH) / 2 + column->sunken; + XSetClipOrigin(tree->display, column->bitmapGC, bx, by); + XCopyPlane(tree->display, column->bitmap, drawable, column->bitmapGC, + 0, 0, (unsigned int) imgW, (unsigned int) imgH, + bx, by, 1); + XSetClipOrigin(tree->display, column->bitmapGC, 0, 0); + } + + if ((column->text != NULL) && (layout.bytesThatFit > 0)) + { + XGCValues gcValues; + GC gc; + unsigned long mask; + char staticStr[256], *text = staticStr; + int textLen = column->textLen; + char *ellipsis = "..."; + int ellipsisLen = strlen(ellipsis); + + if (textLen + ellipsisLen > sizeof(staticStr)) + text = ckalloc(textLen + ellipsisLen); + memcpy(text, column->text, textLen); + if (layout.bytesThatFit != textLen) + { + textLen = abs(layout.bytesThatFit); + if (layout.bytesThatFit > 0) + { + memcpy(text + layout.bytesThatFit, ellipsis, ellipsisLen); + textLen += ellipsisLen; + } + } + + gcValues.font = Tk_FontId(layout.tkfont); + gcValues.foreground = column->textColor->pixel; + gcValues.graphics_exposures = False; + mask = GCFont | GCForeground | GCGraphicsExposures; + gc = Tk_GetGC(tree->tkwin, mask, &gcValues); + Tk_DrawChars(tree->display, drawable, gc, + layout.tkfont, text, textLen, + x + layout.textLeft + column->sunken, + y + (height - layout.fm.linespace) / 2 + layout.fm.ascent + column->sunken); + Tk_FreeGC(tree->display, gc); + if (text != staticStr) + ckfree(text); + } + + if (column->arrow != ARROW_NONE) + { + int arrowWidth = layout.arrowWidth; + int arrowHeight = layout.arrowHeight; + int arrowTop = y + (height - arrowHeight) / 2; + int arrowBottom = arrowTop + arrowHeight; + XPoint points[5]; + int color1 = 0, color2 = 0; + int i; + + switch (column->arrow) + { + case ARROW_UP: + points[0].x = x + layout.arrowLeft; + points[0].y = arrowBottom - 1; + points[1].x = x + layout.arrowLeft + arrowWidth / 2; + points[1].y = arrowTop - 1; + color1 = TK_3D_DARK_GC; + points[4].x = x + layout.arrowLeft + arrowWidth / 2; + points[4].y = arrowTop - 1; + points[3].x = x + layout.arrowLeft + arrowWidth - 1; + points[3].y = arrowBottom - 1; + points[2].x = x + layout.arrowLeft; + points[2].y = arrowBottom - 1; + color2 = TK_3D_LIGHT_GC; + break; + case ARROW_DOWN: + points[0].x = x + layout.arrowLeft + arrowWidth - 1; + points[0].y = arrowTop; + points[1].x = x + layout.arrowLeft + arrowWidth / 2; + points[1].y = arrowBottom; + color1 = TK_3D_LIGHT_GC; + points[2].x = x + layout.arrowLeft + arrowWidth - 1; + points[2].y = arrowTop; + points[3].x = x + layout.arrowLeft; + points[3].y = arrowTop; + points[4].x = x + layout.arrowLeft + arrowWidth / 2; + points[4].y = arrowBottom; + color2 = TK_3D_DARK_GC; + break; + } + for (i = 0; i < 5; i++) + { + points[i].x += column->sunken; + points[i].y += column->sunken; + } + XDrawLines(tree->display, drawable, + Tk_3DBorderGC(tree->tkwin, column->border, color2), + points + 2, 3, CoordModeOrigin); + XDrawLines(tree->display, drawable, + Tk_3DBorderGC(tree->tkwin, column->border, color1), + points, 2, CoordModeOrigin); + } + + Tk_Draw3DRectangle(tree->tkwin, drawable, column->border, + x, y, width, height, column->borderWidth, relief); +} + +void Tree_DrawHeader(TreeCtrl *tree, Drawable drawable, int x, int y) +{ + Column *column = (Column *) tree->columns; + Tk_Window tkwin = tree->tkwin; + int minX, maxX, width, height; + Drawable pixmap; + + /* Update layout if needed */ + (void) Tree_HeaderHeight(tree); + (void) Tree_WidthOfColumns(tree); + + minX = tree->inset; + maxX = Tk_Width(tkwin) - tree->inset; + + if (tree->doubleBuffer == DOUBLEBUFFER_ITEM) + pixmap = Tk_GetPixmap(tree->display, Tk_WindowId(tkwin), + Tk_Width(tkwin), tree->inset + tree->headerHeight, Tk_Depth(tkwin)); + else + pixmap = drawable; + + while (column != NULL) + { + if (column->visible) + { + if ((x < maxX) && (x + column->useWidth > minX)) + TreeColumn_Draw((TreeColumn) column, pixmap, x, y); + x += column->useWidth; + } + column = column->next; + } + + /* Draw "tail" column */ + if (x < maxX) + { + column = (Column *) tree->columnTail; + width = maxX - x + column->borderWidth; + height = tree->headerHeight; + Tk_Fill3DRectangle(tkwin, pixmap, column->border, + x, y, width, height, column->borderWidth, column->relief); + Tk_Draw3DRectangle(tkwin, pixmap, column->border, + x, y, width, height, column->borderWidth, column->relief); + } + + if (tree->doubleBuffer == DOUBLEBUFFER_ITEM) + { + XCopyArea(tree->display, pixmap, drawable, + tree->copyGC, minX, y, + maxX - minX, tree->headerHeight, + tree->inset, y); + + Tk_FreePixmap(tree->display, pixmap); + } +} + +/* Calculate the maximum needed width of all ReallyVisible TreeItemColumns */ +int TreeColumn_WidthOfItems(TreeColumn column_) +{ + Column *column = (Column *) column_; + TreeCtrl *tree = column->tree; + TreeItem item; + TreeItemColumn itemColumn; + int width; + + if (column->widthOfItems >= 0) + return column->widthOfItems; + + column->widthOfItems = 0; + item = tree->root; + if (!TreeItem_ReallyVisible(tree, item)) + item = TreeItem_NextVisible(tree, item); + while (item != NULL) + { + itemColumn = TreeItem_FindColumn(tree, item, column->index); + if (itemColumn != NULL) + { + width = TreeItemColumn_NeededWidth(tree, item, itemColumn); + if (column->index == tree->columnTree) + width += TreeItem_Indent(tree, item); + column->widthOfItems = MAX(column->widthOfItems, width); + } + item = TreeItem_NextVisible(tree, item); + } + + return column->widthOfItems; +} + +/* Set useWidth for all columns */ +void Tree_LayoutColumns(TreeCtrl *tree) +{ + Column *column = (Column *) tree->columns; + int width, visWidth, totalWidth = 0; + int numExpand = 0; + + while (column != NULL) + { + if (column->visible) + { + if (column->widthObj != NULL) + width = column->width; + else + { + width = TreeColumn_WidthOfItems((TreeColumn) column); + width = MAX(width, TreeColumn_NeededWidth((TreeColumn) column)); + width = MAX(width, TreeColumn_MinWidth((TreeColumn) column)); + if (column->expand) + numExpand++; + } + column->useWidth = width; + totalWidth += width; + } + else + column->useWidth = 0; + column = column->next; + } + + visWidth = Tk_Width(tree->tkwin) - tree->inset * 2; + if ((visWidth > totalWidth) && (numExpand > 0)) + { + int extraWidth = (visWidth - totalWidth) / numExpand; + int fudge = (visWidth - totalWidth) - extraWidth * numExpand; + int seen = 0; + + column = (Column *) tree->columns; + while (column != NULL) + { + if (column->visible && column->expand && (column->widthObj == NULL)) + { + column->useWidth += extraWidth; + if (++seen == numExpand) + { + column->useWidth += fudge; + break; + } + } + column = column->next; + } + } +} + +void Tree_InvalidateColumnWidth(TreeCtrl *tree, int columnIndex) +{ + Column *column; + + if (columnIndex == -1) + { + column = (Column *) tree->columns; + while (column != NULL) + { + column->widthOfItems = -1; + column = column->next; + } + } + else + { + column = (Column *) Tree_FindColumn(tree, columnIndex); + if (column != NULL) + column->widthOfItems = -1; + } + tree->widthOfColumns = -1; + Tree_DInfoChanged(tree, DINFO_CHECK_COLUMN_WIDTH); +} + +void TreeColumn_TreeChanged(TreeCtrl *tree, int flagT) +{ + Column *column; + + /* Column widths are invalidated elsewhere */ + if (flagT & TREE_CONF_FONT) + { + column = (Column *) tree->columns; + while (column != NULL) + { + if ((column->tkfont == NULL) && (column->textLen > 0)) + { + column->textWidth = Tk_TextWidth(tree->tkfont, column->text, column->textLen); + column->neededHeight = -1; + } + column = column->next; + } + tree->headerHeight = -1; + } +} + +int Tree_HeaderHeight(TreeCtrl *tree) +{ + Column *column; + int height; + + if (!tree->showHeader) + return 0; + + if (tree->headerHeight >= 0) + return tree->headerHeight; + + height = 0; + column = (Column *) tree->columns; + while (column != NULL) + { + if (column->visible) + height = MAX(height, TreeColumn_NeededHeight((TreeColumn) column)); + column = column->next; + } + return tree->headerHeight = height; +} + +int Tree_WidthOfColumns(TreeCtrl *tree) +{ + Column *column; + int width; + + if (tree->widthOfColumns >= 0) + return tree->widthOfColumns; + + Tree_LayoutColumns(tree); + + tree->columnTreeLeft = 0; + tree->columnTreeVis = FALSE; + tree->columnVis = NULL; + tree->columnCountVis = 0; + width = 0; + column = (Column *) tree->columns; + while (column != NULL) + { + if (column->visible) + { + if (tree->columnVis == NULL) + tree->columnVis = (TreeColumn) column; + tree->columnCountVis++; + if (column->index == tree->columnTree) + { + tree->columnTreeLeft = width; + tree->columnTreeVis = TRUE; + } + width += column->useWidth; + } + column = column->next; + } + + return tree->widthOfColumns = width; +} + +void Tree_InitColumns(TreeCtrl *tree) +{ + tree->columnTail = (TreeColumn) Column_Alloc(tree); + tree->columnCount = 0; + ((Column *) tree->columnTail)->index = -1; +} + +void Tree_FreeColumns(TreeCtrl *tree) +{ + Column *column = (Column *) tree->columns; + + while (column != NULL) + column = Column_Free(column); + + Column_Free((Column *) tree->columnTail); + tree->columnCount = 0; +} + |