From 70119230076c08f6bae58a17b9ab93a5fccee8a2 Mon Sep 17 00:00:00 2001 From: treectrl Date: Sun, 3 Dec 2006 00:22:52 +0000 Subject: Changed how the display code tracks column headers to better detect changes to column size, position or visibility. Don't mark display info OUT_OF_DATE in some cases where only INVALIDATE is needed to redraw the items. --- generic/tkTreeColumn.c | 77 ++++++++++++++++++------ generic/tkTreeCtrl.h | 5 +- generic/tkTreeDisplay.c | 157 +++++++++++++++++++++++++----------------------- 3 files changed, 144 insertions(+), 95 deletions(-) diff --git a/generic/tkTreeColumn.c b/generic/tkTreeColumn.c index f95e96e..1bc051e 100644 --- a/generic/tkTreeColumn.c +++ b/generic/tkTreeColumn.c @@ -7,7 +7,7 @@ * Copyright (c) 2002-2003 Christian Krone * Copyright (c) 2003 ActiveState Corporation * - * RCS: @(#) $Id: tkTreeColumn.c,v 1.70 2006/12/02 21:18:40 treectrl Exp $ + * RCS: @(#) $Id: tkTreeColumn.c,v 1.71 2006/12/03 00:22:52 treectrl Exp $ */ #include "tkTreeCtrl.h" @@ -121,6 +121,7 @@ struct TreeColumn_ UniformGroup *uniform; /* -uniform */ int weight; /* -weight */ #endif + TreeColumnDInfo dInfo; /* Display info. */ }; #ifdef UNIFORM_GROUP @@ -1971,10 +1972,7 @@ renumber: /* Also update columnTreeLeft. */ tree->widthOfColumns = -1; tree->widthOfColumnsLeft = tree->widthOfColumnsRight = -1; - Tree_DInfoChanged(tree, DINFO_CHECK_COLUMN_WIDTH | - DINFO_INVALIDATE | DINFO_OUT_OF_DATE); - /* BUG 784245 */ - Tree_DInfoChanged(tree, DINFO_DRAW_HEADER); + Tree_DInfoChanged(tree, DINFO_CHECK_COLUMN_WIDTH); } } @@ -2205,7 +2203,7 @@ Column_Config( walk = walk->next; } } - Tree_DInfoChanged(tree, DINFO_INVALIDATE | DINFO_OUT_OF_DATE); + Tree_DInfoChanged(tree, DINFO_INVALIDATE); } if (!createFlag && (column->lock != lock)) { @@ -2249,18 +2247,12 @@ Column_Config( /* FIXME: only this column needs to be redisplayed. */ if (mask & COLU_CONF_JUSTIFY) - Tree_DInfoChanged(tree, DINFO_INVALIDATE | DINFO_OUT_OF_DATE); + Tree_DInfoChanged(tree, DINFO_INVALIDATE); /* -stepwidth and -widthhack */ if (mask & COLU_CONF_RANGES) Tree_DInfoChanged(tree, DINFO_REDO_RANGES); - /* If one column becomes visible and another of equal width becomes - * hidden, and the two columns swap places with each other, then - * display ranges are unaffected but items must be redrawn. */ - if (visible != column->visible) - Tree_DInfoChanged(tree, DINFO_INVALIDATE | DINFO_OUT_OF_DATE); - /* Redraw everything */ if (mask & (COLU_CONF_TWIDTH | COLU_CONF_NWIDTH | COLU_CONF_NHEIGHT)) { tree->widthOfColumns = -1; @@ -2369,6 +2361,57 @@ Column_Free( /* *---------------------------------------------------------------------- * + * TreeColumn_SetDInfo -- + * + * Store a display-info token in a column. Called by the display + * code. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +void +TreeColumn_SetDInfo( + TreeColumn column, /* Column record. */ + TreeColumnDInfo dInfo /* Display info token. */ + ) +{ + column->dInfo = dInfo; +} + +/* + *---------------------------------------------------------------------- + * + * TreeColumn_GetDInfo -- + * + * Return the display-info token of a column. Called by the display + * code. + * + * Results: + * The display-info token or NULL. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +TreeColumnDInfo +TreeColumn_GetDInfo( + TreeColumn column /* Column record. */ + ) +{ + return column->dInfo; +} + +/* + *---------------------------------------------------------------------- + * * TreeColumn_FixedWidth -- * * Return the value of the -width option. @@ -4963,7 +5006,7 @@ Tree_InvalidateColumnWidth( } tree->widthOfColumns = -1; tree->widthOfColumnsLeft = tree->widthOfColumnsRight = -1; - Tree_DInfoChanged(tree, DINFO_CHECK_COLUMN_WIDTH | DINFO_DRAW_HEADER); + Tree_DInfoChanged(tree, DINFO_CHECK_COLUMN_WIDTH); } /* @@ -5445,10 +5488,8 @@ doOffsets: totalWidth = 0; column = first; while (column != NULL && column->lock == first->lock) { - if (column->visible) { - column->offset = totalWidth; - totalWidth += column->useWidth; - } + column->offset = totalWidth; + totalWidth += column->useWidth; column = column->next; } return totalWidth; diff --git a/generic/tkTreeCtrl.h b/generic/tkTreeCtrl.h index 1ed2b51..941df69 100644 --- a/generic/tkTreeCtrl.h +++ b/generic/tkTreeCtrl.h @@ -7,7 +7,7 @@ * Copyright (c) 2002-2003 Christian Krone * Copyright (c) 2003 ActiveState Corporation * - * RCS: @(#) $Id: tkTreeCtrl.h,v 1.78 2006/12/02 21:42:19 treectrl Exp $ + * RCS: @(#) $Id: tkTreeCtrl.h,v 1.79 2006/12/03 00:22:52 treectrl Exp $ */ #include "tkPort.h" @@ -39,6 +39,7 @@ typedef struct TreeCtrl TreeCtrl; typedef struct TreeColumn_ *TreeColumn; +typedef struct TreeColumnDInfo_ *TreeColumnDInfo; typedef struct TreeDInfo_ *TreeDInfo; typedef struct TreeDragImage_ *TreeDragImage; typedef struct TreeItem_ *TreeItem; @@ -702,6 +703,8 @@ extern int Tree_WidthOfColumns(TreeCtrl *tree); extern int Tree_WidthOfLeftColumns(TreeCtrl *tree); extern int Tree_WidthOfRightColumns(TreeCtrl *tree); extern void TreeColumn_TreeChanged(TreeCtrl *tree, int flagT); +extern void TreeColumn_SetDInfo(TreeColumn column, TreeColumnDInfo dInfo); +extern TreeColumnDInfo TreeColumn_GetDInfo(TreeColumn column); /* tkTreeDrag.c */ extern int TreeDragImage_Init(TreeCtrl *tree); diff --git a/generic/tkTreeDisplay.c b/generic/tkTreeDisplay.c index 3674949..4fa8a0b 100644 --- a/generic/tkTreeDisplay.c +++ b/generic/tkTreeDisplay.c @@ -5,7 +5,7 @@ * * Copyright (c) 2002-2006 Tim Baker * - * RCS: @(#) $Id: tkTreeDisplay.c,v 1.68 2006/12/02 21:22:51 treectrl Exp $ + * RCS: @(#) $Id: tkTreeDisplay.c,v 1.69 2006/12/03 00:22:52 treectrl Exp $ */ #include "tkTreeCtrl.h" @@ -16,6 +16,7 @@ #define COMPLEX_WHITESPACE +typedef struct TreeColumnDInfo_ TreeColumnDInfo_; typedef struct TreeDInfo_ TreeDInfo_; typedef struct RItem RItem; typedef struct Range Range; @@ -81,11 +82,11 @@ struct DItem DItem *next; }; -typedef struct ColumnInfo { - TreeColumn column; +/* Display information for a TreeColumn. */ +struct TreeColumnDInfo_ { int offset; /* Last seen x-offset */ int width; /* Last seen column width */ -} ColumnInfo; +}; /* Display information for a TreeCtrl. */ struct TreeDInfo_ @@ -95,8 +96,6 @@ struct TreeDInfo_ int yOrigin; /* Last seen TreeCtrl.yOrigin */ int totalWidth; /* Last seen Tree_TotalWidth() */ int totalHeight; /* Last seen Tree_TotalHeight() */ - ColumnInfo *columns; /* Last seen offset & width of each column */ - int columnsSize; /* Num elements in columns[] */ int headerHeight; /* Last seen TreeCtrl.headerHeight */ DItem *dItem; /* Head of list for each displayed item */ DItem *dItemLast; /* Temp for UpdateDInfo() */ @@ -2665,9 +2664,8 @@ GetOnScreenColumnsForItemAux( TreeColumnList *columns /* Initialized list to append to. */ ) { - TreeDInfo dInfo = tree->dInfo; int minX, maxX, columnIndex = 0, x = 0, i, width; - TreeColumn column; + TreeColumn column = NULL, column2; minX = MAX(area->x, bounds[0]); maxX = MIN(area->x + area->width, bounds[2]); @@ -2677,30 +2675,33 @@ GetOnScreenColumnsForItemAux( switch (lock) { case COLUMN_LOCK_LEFT: - columnIndex = TreeColumn_Index(tree->columnLockLeft); + column = tree->columnLockLeft; break; case COLUMN_LOCK_NONE: - columnIndex = TreeColumn_Index(tree->columnLockNone); + column = tree->columnLockNone; break; case COLUMN_LOCK_RIGHT: - columnIndex = TreeColumn_Index(tree->columnLockRight); + column = tree->columnLockRight; break; } - for (/* nothing */; columnIndex < tree->columnCount; columnIndex++) { - column = dInfo->columns[columnIndex].column; + for (columnIndex = TreeColumn_Index(column); + columnIndex < tree->columnCount; columnIndex++) { if (TreeColumn_Lock(column) != lock) break; - if (!TreeColumn_Visible(column)) - continue; - width = dInfo->columns[columnIndex].width; + width = TreeColumn_GetDInfo(column)->width; + if (width == 0) /* also handles hidden columns */ + goto next; if (dItem->spans != NULL) { + /* FIXME: not possible since I skip over the entire span. */ if (dItem->spans[columnIndex] != columnIndex) goto next; - /* Start of a span */ + /* Calculate the width of the span. */ + column2 = TreeColumn_Next(column); for (i = columnIndex + 1; columnIndex < tree->columnCount && dItem->spans[i] == columnIndex; i++) { - width += dInfo->columns[i].width; + width += TreeColumn_GetDInfo(column2)->width; + column2 = TreeColumn_Next(column2); } columnIndex = i - 1; } @@ -2711,6 +2712,7 @@ next: x += width; if (x >= maxX) break; + column = TreeColumn_Next(column); } } @@ -4714,20 +4716,19 @@ DrawWhitespaceBelowItem( int index /* Used for alternating background colors. */ ) { - TreeDInfo dInfo = tree->dInfo; - int i = 0; - TreeColumn treeColumn; + int i = 0, width; + TreeColumn treeColumn = NULL; XRectangle boundsBox, columnBox; switch (lock) { case COLUMN_LOCK_LEFT: - i = TreeColumn_Index(tree->columnLockLeft); + treeColumn = tree->columnLockLeft; break; case COLUMN_LOCK_NONE: - i = TreeColumn_Index(tree->columnLockNone); + treeColumn = tree->columnLockNone; break; case COLUMN_LOCK_RIGHT: - i = TreeColumn_Index(tree->columnLockRight); + treeColumn = tree->columnLockRight; break; } @@ -4736,15 +4737,15 @@ DrawWhitespaceBelowItem( boundsBox.width = bounds[2] - bounds[0]; boundsBox.height = bounds[3] - bounds[1]; - for (/*nothing*/; i < tree->columnCount; i++) { - treeColumn = dInfo->columns[i].column; + for (i = TreeColumn_Index(treeColumn); i < tree->columnCount; i++) { if (TreeColumn_Lock(treeColumn) != lock) break; - if (dInfo->columns[i].width == 0) - continue; + width = TreeColumn_GetDInfo(treeColumn)->width; + if (width == 0) /* also handles hidden columns */ + goto next; columnBox.x = left; columnBox.y = top; - columnBox.width = dInfo->columns[i].width; + columnBox.width = width; columnBox.height = bounds[3] - top; if (Tree_IntersectRect(&columnBox, &boundsBox, &columnBox)) { TkSubtractRegion(columnRgn, columnRgn, columnRgn); @@ -4753,7 +4754,9 @@ DrawWhitespaceBelowItem( DrawColumnBackground(tree, drawable, treeColumn, columnRgn, &columnBox, (RItem *) NULL, height, index); } - left += dInfo->columns[i].width; + left += width; +next: + treeColumn = TreeColumn_Next(treeColumn); } } @@ -5262,46 +5265,49 @@ displayRetry: } /* DINFO_REDO_COLUMN_WIDTH - A column was created or deleted. */ - /* DINFO_CHECK_COLUMN_WIDTH - The width of one or more columns - * *might* have changed. Column visibility - might have changed. */ + /* DINFO_CHECK_COLUMN_WIDTH - The width, offset or visibility of one or + * more columns *might* have changed. */ if (dInfo->flags & (DINFO_REDO_COLUMN_WIDTH | DINFO_CHECK_COLUMN_WIDTH)) { TreeColumn treeColumn = tree->columns; - ColumnInfo *cinfo; + TreeColumnDInfo dColumn; int force = (dInfo->flags & DINFO_REDO_COLUMN_WIDTH) != 0; - int changed = force; - - if (dInfo->columnsSize < tree->columnCount) { - dInfo->columnsSize = tree->columnCount + 10; - dInfo->columns = (ColumnInfo *) ckrealloc((char *) dInfo->columns, - sizeof(ColumnInfo) * dInfo->columnsSize); - } + int redoRanges = force, drawItems = force, drawHeader = force; + int offset, width; /* Set max -itembackground as well. */ tree->columnBgCnt = 0; - cinfo = dInfo->columns; while (treeColumn != NULL) { - cinfo->column = treeColumn; - cinfo->offset = TreeColumn_Offset(treeColumn); - if (force || (cinfo->width != TreeColumn_UseWidth(treeColumn))) { - cinfo->width = TreeColumn_UseWidth(treeColumn); - changed = TRUE; + offset = TreeColumn_Offset(treeColumn); + width = TreeColumn_UseWidth(treeColumn); + dColumn = TreeColumn_GetDInfo(treeColumn); + + /* Haven't seen this column before. */ + if (dColumn == NULL) { + dColumn = (TreeColumnDInfo) ckalloc(sizeof(TreeColumnDInfo_)); + TreeColumn_SetDInfo(treeColumn, dColumn); + if (width > 0) + redoRanges = drawItems = drawHeader = TRUE; + } else { + /* Changes to observed width also detects column visibililty + * changing. */ + if (dColumn->width != width) { + redoRanges = drawItems = drawHeader = TRUE; + } else if ((dColumn->offset != offset) && (width > 0)) { + drawItems = drawHeader = TRUE; + } } + dColumn->offset = offset; + dColumn->width = width; if (TreeColumn_Visible(treeColumn) && (TreeColumn_BackgroundCount(treeColumn) > tree->columnBgCnt)) tree->columnBgCnt = TreeColumn_BackgroundCount(treeColumn); - ++cinfo; treeColumn = TreeColumn_Next(treeColumn); } + if (redoRanges) dInfo->flags |= DINFO_REDO_RANGES | DINFO_OUT_OF_DATE; + if (drawHeader) dInfo->flags |= DINFO_DRAW_HEADER; + if (drawItems) dInfo->flags |= DINFO_INVALIDATE; dInfo->flags &= ~(DINFO_REDO_COLUMN_WIDTH | DINFO_CHECK_COLUMN_WIDTH); - if (changed) { - dInfo->flags |= - DINFO_INVALIDATE | - DINFO_OUT_OF_DATE | - DINFO_REDO_RANGES | - DINFO_DRAW_HEADER; - } } if (dInfo->headerHeight != Tree_HeaderHeight(tree)) { dInfo->headerHeight = Tree_HeaderHeight(tree); @@ -5406,6 +5412,14 @@ displayRetry: Tree_UpdateDInfo(tree); dInfo->flags &= ~DINFO_OUT_OF_DATE; } + if (dInfo->flags & DINFO_INVALIDATE) { + for (dItem = dInfo->dItem; dItem != NULL; dItem = dItem->next) { + dItem->area.flags |= DITEM_DIRTY | DITEM_ALL_DIRTY; + dItem->left.flags |= DITEM_DIRTY | DITEM_ALL_DIRTY; + dItem->right.flags |= DITEM_DIRTY | DITEM_ALL_DIRTY; + } + dInfo->flags &= ~DINFO_INVALIDATE; + } /* * When an item goes from visible to hidden, "window" elements in the @@ -6613,6 +6627,7 @@ Tree_InvalidateItemDInfo( ) { TreeDInfo dInfo = tree->dInfo; + TreeColumn column2; DItem *dItem; TreeItem item = item1; int changed = 0; @@ -6631,6 +6646,7 @@ Tree_InvalidateItemDInfo( dItem->right.flags |= (DITEM_DIRTY | DITEM_ALL_DIRTY); changed = 1; } else { + TreeColumnDInfo dColumn = TreeColumn_GetDInfo(column); int columnIndex, left, width, i; DItemArea *area = NULL; @@ -6649,22 +6665,8 @@ Tree_InvalidateItemDInfo( if (area->flags & DITEM_ALL_DIRTY) goto next; - /* If a hidden column was moved we can't rely on - * dInfo->columns[] being in the right order. */ - if (dInfo->flags & DINFO_CHECK_COLUMN_WIDTH) { - for (columnIndex = 0; columnIndex < tree->columnCount; - columnIndex++) { - if (dInfo->columns[columnIndex].column == column) - break; - } - if (columnIndex == tree->columnCount) { - panic("Tree_InvalidateItemDInfo: can't find a column"); - } - } else { - columnIndex = TreeColumn_Index(column); - } - - left = dInfo->columns[columnIndex].offset; + columnIndex = TreeColumn_Index(column); + left = dColumn->offset; /* Calculate the width of the entire span. */ /* Do NOT call TreeColumn_UseWidth() or another routine @@ -6672,14 +6674,16 @@ Tree_InvalidateItemDInfo( * up recalculating the size of items whose display info * is currently being invalidated. */ if (dItem->spans == NULL) { - width = dInfo->columns[columnIndex].width; + width = dColumn->width; } else { width = 0; + column2 = column; i = dItem->spans[columnIndex]; while (dItem->spans[i] == dItem->spans[columnIndex]) { - width += dInfo->columns[i].width; + width += TreeColumn_GetDInfo(column2)->width; if (++i == tree->columnCount) break; + column2 = TreeColumn_Next(column2); } } @@ -6763,6 +6767,7 @@ TreeDisplay_ColumnDeleted( TreeColumn column /* Column to remove. */ ) { + TreeColumnDInfo dColumn = TreeColumn_GetDInfo(column); #ifdef DCOLUMN TreeDInfo dInfo = tree->dInfo; Tcl_HashSearch search; @@ -6789,6 +6794,9 @@ if (tree->debug.enable && tree->debug.display) hPtr = Tcl_NextHashEntry(&search); } #endif + + if (dColumn != NULL) + ckfree((char *) dColumn); } /* @@ -7138,8 +7146,6 @@ TreeDInfo_Init( gcValues.graphics_exposures = True; dInfo->scrollGC = Tk_GetGC(tree->tkwin, GCGraphicsExposures, &gcValues); dInfo->flags = DINFO_OUT_OF_DATE; - dInfo->columnsSize = 10; - dInfo->columns = (ColumnInfo *) ckalloc(sizeof(ColumnInfo) * dInfo->columnsSize); dInfo->wsRgn = TkCreateRegion(); Tcl_InitHashTable(&dInfo->itemVisHash, TCL_ONE_WORD_KEYS); tree->dInfo = dInfo; @@ -7205,7 +7211,6 @@ TreeDInfo_Free( } #endif Tcl_DeleteHashTable(&dInfo->itemVisHash); - ckfree((char *) dInfo->columns); WFREE(dInfo, TreeDInfo_); } -- cgit v0.12