summaryrefslogtreecommitdiffstats
path: root/generic/ttk/ttkTreeview.c
diff options
context:
space:
mode:
Diffstat (limited to 'generic/ttk/ttkTreeview.c')
-rw-r--r--generic/ttk/ttkTreeview.c1780
1 files changed, 1427 insertions, 353 deletions
diff --git a/generic/ttk/ttkTreeview.c b/generic/ttk/ttkTreeview.c
index 944115d..884c1f3 100644
--- a/generic/ttk/ttkTreeview.c
+++ b/generic/ttk/ttkTreeview.c
@@ -1,11 +1,11 @@
/*
- * Copyright (c) 2004, Joe English
+ * Copyright © 2004, Joe English
*
* ttk::treeview widget implementation.
*/
#include "tkInt.h"
-#include "ttkTheme.h"
+#include "ttkThemeInt.h"
#include "ttkWidget.h"
#ifdef _WIN32
@@ -13,16 +13,16 @@
#endif
#define DEF_TREE_ROWS "10"
+#define DEF_TITLECOLUMNS "0"
+#define DEF_TITLEITEMS "0"
+#define DEF_STRIPED "0"
#define DEF_COLWIDTH "200"
#define DEF_MINWIDTH "20"
-static const int DEFAULT_ROWHEIGHT = 20;
+static const Tk_Anchor DEFAULT_IMAGEANCHOR = TK_ANCHOR_W;
static const int DEFAULT_INDENT = 20;
static const int HALO = 4; /* heading separator */
-#define TTK_STATE_OPEN TTK_STATE_USER1
-#define TTK_STATE_LEAF TTK_STATE_USER2
-
#define STATE_CHANGED (0x100) /* item state option changed */
#define MAX(a,b) (((a) > (b)) ? (a) : (b))
@@ -54,37 +54,60 @@ struct TreeItemRec {
Tcl_Obj *valuesObj;
Tcl_Obj *openObj;
Tcl_Obj *tagsObj;
+ Tcl_Obj *selObj;
+ Tcl_Obj *imageAnchorObj;
+ int hidden;
+ int height; /* Height is in number of row heights */
+
+ Ttk_TagSet *cellTagSets;
+ Tcl_Size nTagSets;
/*
* Derived resources:
*/
Ttk_TagSet tagset;
Ttk_ImageSpec *imagespec;
+ int itemPos; /* Counting items */
+ int visiblePos; /* Counting visible items */
+ int rowPos; /* Counting rows (visible physical space) */
};
#define ITEM_OPTION_TAGS_CHANGED 0x100
#define ITEM_OPTION_IMAGE_CHANGED 0x200
-static Tk_OptionSpec ItemOptionSpecs[] = {
+static const Tk_OptionSpec ItemOptionSpecs[] = {
{TK_OPTION_STRING, "-text", "text", "Text",
- "", Tk_Offset(TreeItem,textObj), -1,
+ "", offsetof(TreeItem,textObj), TCL_INDEX_NONE,
+ 0,0,0 },
+ {TK_OPTION_INT, "-height", "height", "Height",
+ "1", TCL_INDEX_NONE, offsetof(TreeItem,height),
+ 0,0,0 },
+ {TK_OPTION_BOOLEAN, "-hidden", "hidden", "Hidden",
+ "0", TCL_INDEX_NONE, offsetof(TreeItem,hidden),
0,0,0 },
{TK_OPTION_STRING, "-image", "image", "Image",
- NULL, Tk_Offset(TreeItem,imageObj), -1,
+ NULL, offsetof(TreeItem,imageObj), TCL_INDEX_NONE,
TK_OPTION_NULL_OK,0,ITEM_OPTION_IMAGE_CHANGED },
+ {TK_OPTION_ANCHOR, "-imageanchor", "imageAnchor", "ImageAnchor",
+ NULL, offsetof(TreeItem,imageAnchorObj), TCL_INDEX_NONE,
+ TK_OPTION_NULL_OK,0,0 },
{TK_OPTION_STRING, "-values", "values", "Values",
- NULL, Tk_Offset(TreeItem,valuesObj), -1,
+ NULL, offsetof(TreeItem,valuesObj), TCL_INDEX_NONE,
TK_OPTION_NULL_OK,0,0 },
{TK_OPTION_BOOLEAN, "-open", "open", "Open",
- "0", Tk_Offset(TreeItem,openObj), -1,
+ "0", offsetof(TreeItem,openObj), TCL_INDEX_NONE,
0,0,0 },
{TK_OPTION_STRING, "-tags", "tags", "Tags",
- NULL, Tk_Offset(TreeItem,tagsObj), -1,
+ NULL, offsetof(TreeItem,tagsObj), TCL_INDEX_NONE,
TK_OPTION_NULL_OK,0,ITEM_OPTION_TAGS_CHANGED },
- {TK_OPTION_END, 0,0,0, NULL, -1,-1, 0,0,0}
+ {TK_OPTION_END, 0,0,0, NULL, TCL_INDEX_NONE,TCL_INDEX_NONE, 0,0,0}
};
+/* Forward declarations */
+static void RemoveTag(TreeItem *, Ttk_Tag);
+static void RemoveTagFromCellsAtItem(TreeItem *, Ttk_Tag);
+
/* + NewItem --
* Allocate a new, uninitialized, unlinked item
*/
@@ -101,6 +124,12 @@ static TreeItem *NewItem(void)
item->valuesObj = NULL;
item->openObj = NULL;
item->tagsObj = NULL;
+ item->selObj = NULL;
+ item->imageAnchorObj = NULL;
+ item->hidden = 0;
+ item->height = 1;
+ item->cellTagSets = NULL;
+ item->nTagSets = 0;
item->tagset = NULL;
item->imagespec = NULL;
@@ -113,14 +142,25 @@ static TreeItem *NewItem(void)
*/
static void FreeItem(TreeItem *item)
{
+ Tcl_Size i;
if (item->textObj) { Tcl_DecrRefCount(item->textObj); }
if (item->imageObj) { Tcl_DecrRefCount(item->imageObj); }
if (item->valuesObj) { Tcl_DecrRefCount(item->valuesObj); }
if (item->openObj) { Tcl_DecrRefCount(item->openObj); }
if (item->tagsObj) { Tcl_DecrRefCount(item->tagsObj); }
+ if (item->selObj) { Tcl_DecrRefCount(item->selObj); }
+ if (item->imageAnchorObj) { Tcl_DecrRefCount(item->imageAnchorObj); }
if (item->tagset) { Ttk_FreeTagSet(item->tagset); }
if (item->imagespec) { TtkFreeImageSpec(item->imagespec); }
+ if (item->cellTagSets) {
+ for (i = 0; i < item->nTagSets; ++i) {
+ if (item->cellTagSets[i] != NULL) {
+ Ttk_FreeTagSet(item->cellTagSets[i]);
+ }
+ }
+ ckfree(item->cellTagSets);
+ }
ckfree(item);
}
@@ -186,36 +226,53 @@ static TreeItem *NextPreorder(TreeItem *item)
typedef struct {
Tcl_Obj *textObj; /* taken from item / data cell */
- Tcl_Obj *imageObj; /* taken from item */
+ Tcl_Obj *imageObj; /* taken from item or tag*/
+ Tcl_Obj *imageAnchorObj; /* taken from item or tag */
Tcl_Obj *anchorObj; /* from column <<NOTE-ANCHOR>> */
Tcl_Obj *backgroundObj; /* remainder from tag */
+ Tcl_Obj *stripedBgObj;
Tcl_Obj *foregroundObj;
Tcl_Obj *fontObj;
+ Tcl_Obj *paddingObj;
} DisplayItem;
-static Tk_OptionSpec TagOptionSpecs[] = {
+static const Tk_OptionSpec DisplayOptionSpecs[] = {
{TK_OPTION_STRING, "-text", "text", "Text",
- NULL, Tk_Offset(DisplayItem,textObj), -1,
- TK_OPTION_NULL_OK,0,0 },
- {TK_OPTION_STRING, "-image", "image", "Image",
- NULL, Tk_Offset(DisplayItem,imageObj), -1,
+ NULL, offsetof(DisplayItem,textObj), TCL_INDEX_NONE,
TK_OPTION_NULL_OK,0,0 },
{TK_OPTION_ANCHOR, "-anchor", "anchor", "Anchor",
- "center", Tk_Offset(DisplayItem,anchorObj), -1,
+ "center", offsetof(DisplayItem,anchorObj), TCL_INDEX_NONE,
0, 0, GEOMETRY_CHANGED}, /* <<NOTE-ANCHOR>> */
+ /* From here down are the tags options. The index in TagOptionSpecs
+ * below should be kept in synch with this position.
+ */
+ {TK_OPTION_STRING, "-image", "image", "Image",
+ NULL, offsetof(DisplayItem,imageObj), TCL_INDEX_NONE,
+ TK_OPTION_NULL_OK,0,0 },
+ {TK_OPTION_ANCHOR, "-imageanchor", "imageAnchor", "ImageAnchor",
+ NULL, offsetof(DisplayItem,imageAnchorObj), TCL_INDEX_NONE,
+ TK_OPTION_NULL_OK,0,0 },
{TK_OPTION_COLOR, "-background", "windowColor", "WindowColor",
- NULL, Tk_Offset(DisplayItem,backgroundObj), -1,
+ NULL, offsetof(DisplayItem,backgroundObj), TCL_INDEX_NONE,
+ TK_OPTION_NULL_OK,0,0 },
+ {TK_OPTION_COLOR, "-stripedbackground", "windowColor", "WindowColor",
+ NULL, offsetof(DisplayItem,stripedBgObj), TCL_INDEX_NONE,
TK_OPTION_NULL_OK,0,0 },
{TK_OPTION_COLOR, "-foreground", "textColor", "TextColor",
- NULL, Tk_Offset(DisplayItem,foregroundObj), -1,
+ NULL, offsetof(DisplayItem,foregroundObj), TCL_INDEX_NONE,
TK_OPTION_NULL_OK,0,0 },
{TK_OPTION_FONT, "-font", "font", "Font",
- NULL, Tk_Offset(DisplayItem,fontObj), -1,
+ NULL, offsetof(DisplayItem,fontObj), TCL_INDEX_NONE,
+ TK_OPTION_NULL_OK,0,GEOMETRY_CHANGED },
+ {TK_OPTION_STRING, "-padding", "padding", "Pad",
+ NULL, offsetof(DisplayItem,paddingObj), TCL_INDEX_NONE,
TK_OPTION_NULL_OK,0,GEOMETRY_CHANGED },
- {TK_OPTION_END, 0,0,0, NULL, -1,-1, 0,0,0}
+ {TK_OPTION_END, 0,0,0, NULL, TCL_INDEX_NONE,TCL_INDEX_NONE, 0,0,0}
};
+static const Tk_OptionSpec *TagOptionSpecs = &DisplayOptionSpecs[2];
+
/*------------------------------------------------------------------------
* +++ Columns.
*
@@ -227,6 +284,7 @@ typedef struct {
int width; /* Column width, in pixels */
int minWidth; /* Minimum column width, in pixels */
int stretch; /* Should column stretch while resizing? */
+ int separator; /* Should this column have a separator? */
Tcl_Obj *idObj; /* Column identifier, from -columns option */
Tcl_Obj *anchorObj; /* -anchor for cell data <<NOTE-ANCHOR>> */
@@ -243,6 +301,8 @@ typedef struct {
/* Temporary storage for cell data
*/
Tcl_Obj *data;
+ int selected;
+ Ttk_TagSet tagset;
} TreeColumn;
static void InitColumn(TreeColumn *column)
@@ -250,6 +310,7 @@ static void InitColumn(TreeColumn *column)
column->width = atoi(DEF_COLWIDTH);
column->minWidth = atoi(DEF_MINWIDTH);
column->stretch = 1;
+ column->separator = 0;
column->idObj = 0;
column->anchorObj = 0;
@@ -261,6 +322,7 @@ static void InitColumn(TreeColumn *column)
column->headingCommandObj = 0;
column->data = 0;
+ column->tagset = NULL;
}
static void FreeColumn(TreeColumn *column)
@@ -277,42 +339,45 @@ static void FreeColumn(TreeColumn *column)
/* Don't touch column->data, it's scratch storage */
}
-static Tk_OptionSpec ColumnOptionSpecs[] = {
+static const Tk_OptionSpec ColumnOptionSpecs[] = {
{TK_OPTION_INT, "-width", "width", "Width",
- DEF_COLWIDTH, -1, Tk_Offset(TreeColumn,width),
+ DEF_COLWIDTH, TCL_INDEX_NONE, offsetof(TreeColumn,width),
0,0,GEOMETRY_CHANGED },
{TK_OPTION_INT, "-minwidth", "minWidth", "MinWidth",
- DEF_MINWIDTH, -1, Tk_Offset(TreeColumn,minWidth),
+ DEF_MINWIDTH, TCL_INDEX_NONE, offsetof(TreeColumn,minWidth),
+ 0,0,0 },
+ {TK_OPTION_BOOLEAN, "-separator", "separator", "Separator",
+ "0", TCL_INDEX_NONE, offsetof(TreeColumn,separator),
0,0,0 },
{TK_OPTION_BOOLEAN, "-stretch", "stretch", "Stretch",
- "1", -1, Tk_Offset(TreeColumn,stretch),
+ "1", TCL_INDEX_NONE, offsetof(TreeColumn,stretch),
0,0,GEOMETRY_CHANGED },
{TK_OPTION_ANCHOR, "-anchor", "anchor", "Anchor",
- "w", Tk_Offset(TreeColumn,anchorObj), -1, /* <<NOTE-ANCHOR>> */
+ "w", offsetof(TreeColumn,anchorObj), TCL_INDEX_NONE, /* <<NOTE-ANCHOR>> */
0,0,0 },
{TK_OPTION_STRING, "-id", "id", "ID",
- NULL, Tk_Offset(TreeColumn,idObj), -1,
+ NULL, offsetof(TreeColumn,idObj), TCL_INDEX_NONE,
TK_OPTION_NULL_OK,0,READONLY_OPTION },
- {TK_OPTION_END, 0,0,0, NULL, -1,-1, 0,0,0}
+ {TK_OPTION_END, 0,0,0, NULL, TCL_INDEX_NONE,TCL_INDEX_NONE, 0,0,0}
};
-static Tk_OptionSpec HeadingOptionSpecs[] = {
+static const Tk_OptionSpec HeadingOptionSpecs[] = {
{TK_OPTION_STRING, "-text", "text", "Text",
- "", Tk_Offset(TreeColumn,headingObj), -1,
+ "", offsetof(TreeColumn,headingObj), TCL_INDEX_NONE,
0,0,0 },
{TK_OPTION_STRING, "-image", "image", "Image",
- "", Tk_Offset(TreeColumn,headingImageObj), -1,
+ "", offsetof(TreeColumn,headingImageObj), TCL_INDEX_NONE,
0,0,0 },
{TK_OPTION_ANCHOR, "-anchor", "anchor", "Anchor",
- "center", Tk_Offset(TreeColumn,headingAnchorObj), -1,
+ "center", offsetof(TreeColumn,headingAnchorObj), TCL_INDEX_NONE,
0,0,0 },
{TK_OPTION_STRING, "-command", "", "",
- "", Tk_Offset(TreeColumn,headingCommandObj), -1,
+ "", offsetof(TreeColumn,headingCommandObj), TCL_INDEX_NONE,
TK_OPTION_NULL_OK,0,0 },
{TK_OPTION_STRING, "state", "", "",
- "", Tk_Offset(TreeColumn,headingStateObj), -1,
+ "", offsetof(TreeColumn,headingStateObj), TCL_INDEX_NONE,
0,0,STATE_CHANGED },
- {TK_OPTION_END, 0,0,0, NULL, -1,-1, 0,0,0}
+ {TK_OPTION_END, 0,0,0, NULL, TCL_INDEX_NONE,TCL_INDEX_NONE, 0,0,0}
};
/*------------------------------------------------------------------------
@@ -336,7 +401,7 @@ static int GetEnumSetFromObj(
unsigned *resultPtr)
{
unsigned result = 0;
- int i, objc;
+ Tcl_Size i, objc;
Tcl_Obj **objv;
if (Tcl_ListObjGetElements(interp, objPtr, &objc, &objv) != TCL_OK)
@@ -371,7 +436,7 @@ typedef struct {
Tk_OptionTable itemOptionTable;
Tk_OptionTable columnOptionTable;
Tk_OptionTable headingOptionTable;
- Tk_OptionTable tagOptionTable;
+ Tk_OptionTable displayOptionTable;
Tk_BindingTable bindingTable;
Ttk_TagTable tagTable;
@@ -381,9 +446,11 @@ typedef struct {
Ttk_Layout cellLayout;
Ttk_Layout headingLayout;
Ttk_Layout rowLayout;
+ Ttk_Layout separatorLayout;
int headingHeight; /* Space for headings */
int rowHeight; /* Height of each item */
+ int colSeparatorWidth; /* Width of column separator, if used (screen units) */
int indent; /* Horizontal offset for child items (screen units) */
/* Tree data:
@@ -405,9 +472,13 @@ typedef struct {
Tcl_Obj *heightObj; /* height (rows) */
Tcl_Obj *paddingObj; /* internal padding */
+ Tcl_Size nTitleColumns; /* -titlecolumns */
+ Tcl_Size nTitleItems; /* -titleitems */
+ int striped; /* -striped option */
Tcl_Obj *showObj; /* -show list */
Tcl_Obj *selectModeObj; /* -selectmode option */
+ Tcl_Obj *selectTypeObj; /* -selecttype option */
Scrollable xscroll;
ScrollHandle xscrollHandle;
@@ -417,15 +488,17 @@ typedef struct {
/* Derived resources:
*/
Tcl_HashTable columnNames; /* Map: column name -> column table entry */
- int nColumns; /* #columns */
- unsigned showFlags; /* bitmask of subparts to display */
-
+ Tcl_Size nColumns; /* #columns */
+ Tcl_Size nDisplayColumns; /* #display columns */
TreeColumn **displayColumns; /* List of columns for display (incl tree) */
- int nDisplayColumns; /* #display columns */
+ int titleWidth; /* Width of non-scrolled columns */
+ int titleRows; /* Height of non-scrolled items, in rows */
+ int totalRows; /* Height of non-hidden items, in rows */
+ int rowPosNeedsUpdate; /* Internal rowPos data needs update */
Ttk_Box headingArea; /* Display area for column headings */
Ttk_Box treeArea; /* Display area for tree */
int slack; /* Slack space (see Resizing section) */
-
+ unsigned showFlags; /* bitmask of subparts to display */
} TreePart;
typedef struct {
@@ -440,34 +513,47 @@ typedef struct {
#define SHOW_CHANGED (USER_MASK<<3)
static const char *const SelectModeStrings[] = { "none", "browse", "extended", NULL };
+static const char *const SelectTypeStrings[] = { "item", "cell", NULL };
-static Tk_OptionSpec TreeviewOptionSpecs[] = {
+static const Tk_OptionSpec TreeviewOptionSpecs[] = {
{TK_OPTION_STRING, "-columns", "columns", "Columns",
- "", Tk_Offset(Treeview,tree.columnsObj), -1,
+ "", offsetof(Treeview,tree.columnsObj), TCL_INDEX_NONE,
0, 0, COLUMNS_CHANGED | GEOMETRY_CHANGED /*| READONLY_OPTION*/ },
{TK_OPTION_STRING, "-displaycolumns","displayColumns","DisplayColumns",
- "#all", Tk_Offset(Treeview,tree.displayColumnsObj), -1,
+ "#all", offsetof(Treeview,tree.displayColumnsObj), TCL_INDEX_NONE,
0, 0, DCOLUMNS_CHANGED | GEOMETRY_CHANGED },
{TK_OPTION_STRING, "-show", "show", "Show",
- DEFAULT_SHOW, Tk_Offset(Treeview,tree.showObj), -1,
+ DEFAULT_SHOW, offsetof(Treeview,tree.showObj), TCL_INDEX_NONE,
0, 0, SHOW_CHANGED | GEOMETRY_CHANGED },
{TK_OPTION_STRING_TABLE, "-selectmode", "selectMode", "SelectMode",
- "extended", Tk_Offset(Treeview,tree.selectModeObj), -1,
+ "extended", offsetof(Treeview,tree.selectModeObj), TCL_INDEX_NONE,
0, SelectModeStrings, 0 },
+ {TK_OPTION_STRING_TABLE, "-selecttype", "selectType", "SelectType",
+ "item", offsetof(Treeview,tree.selectTypeObj), TCL_INDEX_NONE,
+ 0, SelectTypeStrings, 0 },
{TK_OPTION_PIXELS, "-height", "height", "Height",
- DEF_TREE_ROWS, Tk_Offset(Treeview,tree.heightObj), -1,
+ DEF_TREE_ROWS, offsetof(Treeview,tree.heightObj), TCL_INDEX_NONE,
0, 0, GEOMETRY_CHANGED},
{TK_OPTION_STRING, "-padding", "padding", "Pad",
- NULL, Tk_Offset(Treeview,tree.paddingObj), -1,
+ NULL, offsetof(Treeview,tree.paddingObj), TCL_INDEX_NONE,
TK_OPTION_NULL_OK, 0, GEOMETRY_CHANGED },
+ {TK_OPTION_INT, "-titlecolumns", "titlecolumns", "Titlecolumns",
+ DEF_TITLECOLUMNS, TCL_INDEX_NONE, offsetof(Treeview,tree.nTitleColumns),
+ TK_OPTION_VAR(Tcl_Size), 0, GEOMETRY_CHANGED},
+ {TK_OPTION_INT, "-titleitems", "titleitems", "Titleitems",
+ DEF_TITLEITEMS, TCL_INDEX_NONE, offsetof(Treeview,tree.nTitleItems),
+ TK_OPTION_VAR(Tcl_Size), 0, GEOMETRY_CHANGED},
+ {TK_OPTION_BOOLEAN, "-striped", "striped", "Striped",
+ DEF_STRIPED, TCL_INDEX_NONE, offsetof(Treeview,tree.striped),
+ 0, 0, GEOMETRY_CHANGED},
{TK_OPTION_STRING, "-xscrollcommand", "xScrollCommand", "ScrollCommand",
- NULL, -1, Tk_Offset(Treeview, tree.xscroll.scrollCmd),
+ NULL, TCL_INDEX_NONE, offsetof(Treeview, tree.xscroll.scrollCmd),
TK_OPTION_NULL_OK, 0, SCROLLCMD_CHANGED},
{TK_OPTION_STRING, "-yscrollcommand", "yScrollCommand", "ScrollCommand",
- NULL, -1, Tk_Offset(Treeview, tree.yscroll.scrollCmd),
+ NULL, TCL_INDEX_NONE, offsetof(Treeview, tree.yscroll.scrollCmd),
TK_OPTION_NULL_OK, 0, SCROLLCMD_CHANGED},
WIDGET_TAKEFOCUS_TRUE,
@@ -489,6 +575,20 @@ static void foreachHashEntry(Tcl_HashTable *ht, HashEntryIterator func)
}
}
+static int CellSelectionClear(Treeview *tv)
+{
+ TreeItem *item;
+ int anyChange = 0;
+ for (item=tv->tree.root; item; item = NextPreorder(item)) {
+ if (item->selObj != NULL) {
+ Tcl_DecrRefCount(item->selObj);
+ item->selObj = NULL;
+ anyChange = 1;
+ }
+ }
+ return anyChange;
+}
+
/* + unshareObj(objPtr) --
* Ensure that a Tcl_Obj * has refcount 1 -- either return objPtr
* itself, or a duplicated copy.
@@ -515,6 +615,33 @@ static void DisplayLayout(
Ttk_DrawLayout(layout, state, d);
}
+/* DisplayLayoutTree --
+ * Like DisplayLayout, but for the tree column.
+ */
+static void DisplayLayoutTree(
+ Tk_Anchor imageAnchor, Tk_Anchor textAnchor,
+ Ttk_Layout layout, void *recordPtr, Ttk_State state, Ttk_Box b, Drawable d)
+{
+ Ttk_Element elem;
+ Ttk_RebindSublayout(layout, recordPtr);
+
+ elem = Ttk_FindElement(layout, "image");
+ if (elem != NULL) {
+ Ttk_AnchorElement(elem, imageAnchor);
+ }
+ elem = Ttk_FindElement(layout, "text");
+ if (elem != NULL) {
+ Ttk_AnchorElement(elem, textAnchor);
+ }
+ elem = Ttk_FindElement(layout, "focus");
+ if (elem != NULL) {
+ Ttk_AnchorElement(elem, textAnchor);
+ }
+
+ Ttk_PlaceLayout(layout, state, b);
+ Ttk_DrawLayout(layout, state, d);
+}
+
/* + GetColumn --
* Look up column by name or number.
* Returns: pointer to column table entry, NULL if not found.
@@ -524,7 +651,7 @@ static TreeColumn *GetColumn(
Tcl_Interp *interp, Treeview *tv, Tcl_Obj *columnIDObj)
{
Tcl_HashEntry *entryPtr;
- int columnIndex;
+ Tcl_Size columnIndex;
/* Check for named column:
*/
@@ -534,12 +661,12 @@ static TreeColumn *GetColumn(
return (TreeColumn *)Tcl_GetHashValue(entryPtr);
}
- /* Check for number:
+ /* Check for index:
*/
- if (Tcl_GetIntFromObj(NULL, columnIDObj, &columnIndex) == TCL_OK) {
+ if (TkGetIntForIndex(columnIDObj, tv->tree.nColumns - 1, 1, &columnIndex) == TCL_OK) {
if (columnIndex < 0 || columnIndex >= tv->tree.nColumns) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "Column index %s out of bounds",
+ "Column index \"%s\" out of bounds",
Tcl_GetString(columnIDObj)));
Tcl_SetErrorCode(interp, "TTK", "TREE", "COLBOUND", NULL);
return NULL;
@@ -548,7 +675,7 @@ static TreeColumn *GetColumn(
return tv->tree.columns + columnIndex;
}
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "Invalid column index %s", Tcl_GetString(columnIDObj)));
+ "Invalid column index \"%s\"", Tcl_GetString(columnIDObj)));
Tcl_SetErrorCode(interp, "TTK", "TREE", "COLUMN", NULL);
return NULL;
}
@@ -559,9 +686,9 @@ static TreeColumn *GetColumn(
static TreeColumn *FindColumn(
Tcl_Interp *interp, Treeview *tv, Tcl_Obj *columnIDObj)
{
- int colno;
+ Tcl_WideInt colno;
- if (sscanf(Tcl_GetString(columnIDObj), "#%d", &colno) == 1)
+ if (sscanf(Tcl_GetString(columnIDObj), "#%" TCL_LL_MODIFIER "d", &colno) == 1)
{ /* Display column specification, #n */
if (colno >= 0 && colno < tv->tree.nDisplayColumns) {
return tv->tree.displayColumns[colno];
@@ -607,7 +734,7 @@ static TreeItem **GetItemListFromObj(
{
TreeItem **items;
Tcl_Obj **elements;
- int i, nElements;
+ Tcl_Size i, nElements;
if (Tcl_ListObjGetElements(interp,objPtr,&nElements,&elements) != TCL_OK) {
return NULL;
@@ -651,7 +778,7 @@ static Tcl_Obj *ItemID(Treeview *tv, TreeItem *item)
*/
static void TreeviewFreeColumns(Treeview *tv)
{
- int i;
+ Tcl_Size i;
Tcl_DeleteHashTable(&tv->tree.columnNames);
Tcl_InitHashTable(&tv->tree.columnNames, TCL_STRING_KEYS);
@@ -671,7 +798,7 @@ static void TreeviewFreeColumns(Treeview *tv)
static int TreeviewInitColumns(Tcl_Interp *interp, Treeview *tv)
{
Tcl_Obj **columns;
- int i, ncols;
+ Tcl_Size i, ncols;
if (Tcl_ListObjGetElements(
interp, tv->tree.columnsObj, &ncols, &columns) != TCL_OK)
@@ -700,10 +827,10 @@ static int TreeviewInitColumns(Tcl_Interp *interp, Treeview *tv)
InitColumn(tv->tree.columns + i);
Tk_InitOptions(
- interp, (void *)(tv->tree.columns + i),
+ interp, tv->tree.columns + i,
tv->tree.columnOptionTable, tv->core.tkwin);
Tk_InitOptions(
- interp, (void *)(tv->tree.columns + i),
+ interp, tv->tree.columns + i,
tv->tree.headingOptionTable, tv->core.tkwin);
Tcl_IncrRefCount(columnName);
tv->tree.columns[i].idObj = columnName;
@@ -723,7 +850,7 @@ static int TreeviewInitColumns(Tcl_Interp *interp, Treeview *tv)
static int TreeviewInitDisplayColumns(Tcl_Interp *interp, Treeview *tv)
{
Tcl_Obj **dcolumns;
- int index, ndcols;
+ Tcl_Size index, ndcols;
TreeColumn **displayColumns = 0;
if (Tcl_ListObjGetElements(interp,
@@ -769,12 +896,19 @@ static int TreeviewInitDisplayColumns(Tcl_Interp *interp, Treeview *tv)
*/
static int TreeWidth(Treeview *tv)
{
- int i = FirstColumn(tv);
+ Tcl_Size i = FirstColumn(tv);
int width = 0;
+ tv->tree.titleWidth = 0;
while (i < tv->tree.nDisplayColumns) {
+ if (i == tv->tree.nTitleColumns) {
+ tv->tree.titleWidth = width;
+ }
width += tv->tree.displayColumns[i++]->width;
}
+ if (tv->tree.nTitleColumns >= tv->tree.nDisplayColumns) {
+ tv->tree.titleWidth = width;
+ }
return width;
}
@@ -830,9 +964,9 @@ static int Stretch(TreeColumn *c, int n)
* Adjust width of (stretchable) columns to the left by N pixels.
* Returns: leftover slack.
*/
-static int ShoveLeft(Treeview *tv, int i, int n)
+static int ShoveLeft(Treeview *tv, Tcl_Size i, int n)
{
- int first = FirstColumn(tv);
+ Tcl_Size first = FirstColumn(tv);
while (n != 0 && i >= first) {
TreeColumn *c = tv->tree.displayColumns[i];
if (c->stretch) {
@@ -847,7 +981,7 @@ static int ShoveLeft(Treeview *tv, int i, int n)
* Adjust width of (stretchable) columns to the right by N pixels.
* Returns: leftover slack.
*/
-static int ShoveRight(Treeview *tv, int i, int n)
+static int ShoveRight(Treeview *tv, Tcl_Size i, int n)
{
while (n != 0 && i < tv->tree.nDisplayColumns) {
TreeColumn *c = tv->tree.displayColumns[i];
@@ -870,7 +1004,7 @@ static int DistributeWidth(Treeview *tv, int n)
{
int w = TreeWidth(tv);
int m = 0;
- int i;
+ Tcl_Size i;
int d, r;
for (i = FirstColumn(tv); i < tv->tree.nDisplayColumns; ++i) {
@@ -913,7 +1047,7 @@ static void ResizeColumns(Treeview *tv, int newWidth)
* Move the separator to the right of specified column,
* adjusting other column widths as necessary.
*/
-static void DragColumn(Treeview *tv, int i, int delta)
+static void DragColumn(Treeview *tv, Tcl_Size i, int delta)
{
TreeColumn *c = tv->tree.displayColumns[i];
int dl = delta - ShoveLeft(tv, i-1, delta - Stretch(c, delta));
@@ -922,10 +1056,119 @@ static void DragColumn(Treeview *tv, int i, int delta)
}
/*------------------------------------------------------------------------
+ * +++ Cells.
+ */
+
+typedef struct {
+ TreeItem *item;
+ TreeColumn *column;
+ Tcl_Obj *colObj;
+} TreeCell;
+
+/* + GetCellFromObj
+ * Get Row and Column from a cell ID.
+ */
+static int GetCellFromObj(
+ Tcl_Interp *interp, Treeview *tv, Tcl_Obj *obj,
+ int displayColumnOnly, int *displayColumn,
+ TreeCell *cell)
+{
+ Tcl_Size nElements;
+ Tcl_Obj **elements;
+
+ if (Tcl_ListObjGetElements(interp, obj, &nElements, &elements) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ if (nElements != 2) {
+ Tcl_SetObjResult(interp, Tcl_NewStringObj(
+ "Cell id must be a list of two elements", -1));
+ Tcl_SetErrorCode(interp, "TTK", "TREE", "CELL", NULL);
+ return TCL_ERROR;
+ }
+ /* Valid item/column in each pair? */
+ cell->item = FindItem(interp, tv, elements[0]);
+ if (!cell->item) {
+ return TCL_ERROR;
+ }
+ cell->column = FindColumn(interp, tv, elements[1]);
+ if (!cell->column) {
+ return TCL_ERROR;
+ }
+ /* colObj is short lived and do not keep a reference counted */
+ cell->colObj = elements[1];
+ if (displayColumnOnly) {
+ Tcl_Size i = FirstColumn(tv);
+ while (i < tv->tree.nDisplayColumns) {
+ if (tv->tree.displayColumns[i] == cell->column) {
+ break;
+ }
+ ++i;
+ }
+ if (i == tv->tree.nDisplayColumns) { /* specified column unviewable */
+ Tcl_SetObjResult(interp, Tcl_NewStringObj(
+ "Cell id must be in a visible column", -1));
+ Tcl_SetErrorCode(interp, "TTK", "TREE", "CELL", NULL);
+ return TCL_ERROR;
+ }
+ if (displayColumn != NULL) {
+ *displayColumn = i;
+ }
+ }
+ return TCL_OK;
+}
+
+/* + GetCellListFromObj --
+ * Parse a Tcl_Obj * as a list of cells.
+ * Returns an array of cells; result must be ckfree()d.
+ * On error, returns NULL and leaves an error
+ * message in interp.
+ */
+
+static TreeCell *GetCellListFromObj(
+ Tcl_Interp *interp, Treeview *tv, Tcl_Obj *objPtr, Tcl_Size *nCells)
+{
+ TreeCell *cells;
+ TreeCell cell;
+ Tcl_Obj **elements;
+ Tcl_Obj *oneCell;
+ Tcl_Size i, n;
+
+ if (Tcl_ListObjGetElements(interp, objPtr, &n, &elements) != TCL_OK) {
+ return NULL;
+ }
+
+ /* A two element list might be a single cell */
+ if (n == 2) {
+ if (GetCellFromObj(interp, tv, objPtr, 0, NULL, &cell)
+ == TCL_OK) {
+ n = 1;
+ oneCell = objPtr;
+ elements = &oneCell;
+ } else {
+ Tcl_ResetResult(interp);
+ }
+ }
+
+ cells = (TreeCell *) ckalloc(n * sizeof(TreeCell));
+ for (i = 0; i < n; ++i) {
+ if (GetCellFromObj(interp, tv, elements[i], 0, NULL, &cells[i]) != TCL_OK) {
+ ckfree(cells);
+ return NULL;
+ }
+ }
+
+ if (nCells) {
+ *nCells = n;
+ }
+ return cells;
+}
+
+/*------------------------------------------------------------------------
* +++ Event handlers.
*/
static TreeItem *IdentifyItem(Treeview *tv, int y); /*forward*/
+static Tcl_Size IdentifyDisplayColumn(Treeview *tv, int x, int *x1); /*forward*/
static const unsigned long TreeviewBindEventMask =
KeyPressMask|KeyReleaseMask
@@ -939,6 +1182,9 @@ static void TreeviewBindEventProc(void *clientData, XEvent *event)
Treeview *tv = (Treeview *)clientData;
TreeItem *item = NULL;
Ttk_TagSet tagset;
+ int unused;
+ Tcl_Size colno = TCL_INDEX_NONE;
+ TreeColumn *column = NULL;
/*
* Figure out where to deliver the event.
@@ -953,9 +1199,11 @@ static void TreeviewBindEventProc(void *clientData, XEvent *event)
case ButtonPress:
case ButtonRelease:
item = IdentifyItem(tv, event->xbutton.y);
+ colno = IdentifyDisplayColumn(tv, event->xbutton.x, &unused);
break;
case MotionNotify:
item = IdentifyItem(tv, event->xmotion.y);
+ colno = IdentifyDisplayColumn(tv, event->xmotion.x, &unused);
break;
default:
break;
@@ -972,6 +1220,23 @@ static void TreeviewBindEventProc(void *clientData, XEvent *event)
tagset = Ttk_GetTagSetFromObj(NULL, tv->tree.tagTable, item->tagsObj);
/*
+ * Pick up any cell tags.
+ */
+ if (colno >= 0) {
+ column = tv->tree.displayColumns[colno];
+ if (column == &tv->tree.column0) {
+ colno = 0;
+ } else {
+ colno = column - tv->tree.columns + 1;
+ }
+ if (colno < item->nTagSets) {
+ if (item->cellTagSets[colno] != NULL) {
+ Ttk_TagSetAddSet(tagset, item->cellTagSets[colno]);
+ }
+ }
+ }
+
+ /*
* Fire binding:
*/
Tcl_Preserve(clientData);
@@ -997,8 +1262,8 @@ static void TreeviewInitialize(Tcl_Interp *interp, void *recordPtr)
Tk_CreateOptionTable(interp, ColumnOptionSpecs);
tv->tree.headingOptionTable =
Tk_CreateOptionTable(interp, HeadingOptionSpecs);
- tv->tree.tagOptionTable =
- Tk_CreateOptionTable(interp, TagOptionSpecs);
+ tv->tree.displayOptionTable =
+ Tk_CreateOptionTable(interp, DisplayOptionSpecs);
tv->tree.tagTable = Ttk_CreateTagTable(
interp, tv->core.tkwin, TagOptionSpecs, sizeof(DisplayItem));
@@ -1010,22 +1275,33 @@ static void TreeviewInitialize(Tcl_Interp *interp, void *recordPtr)
= tv->tree.cellLayout
= tv->tree.headingLayout
= tv->tree.rowLayout
+ = tv->tree.separatorLayout
= 0;
- tv->tree.headingHeight = tv->tree.rowHeight = DEFAULT_ROWHEIGHT;
+ tv->tree.headingHeight = tv->tree.rowHeight = 0;
+ tv->tree.colSeparatorWidth = 1;
tv->tree.indent = DEFAULT_INDENT;
Tcl_InitHashTable(&tv->tree.columnNames, TCL_STRING_KEYS);
tv->tree.nColumns = tv->tree.nDisplayColumns = 0;
+ tv->tree.nTitleColumns = 0;
+ tv->tree.nTitleItems = 0;
+ tv->tree.titleWidth = 0;
+ tv->tree.titleRows = 0;
+ tv->tree.totalRows = 0;
+ tv->tree.rowPosNeedsUpdate = 1;
+ tv->tree.striped = 0;
tv->tree.columns = NULL;
tv->tree.displayColumns = NULL;
tv->tree.showFlags = ~0;
InitColumn(&tv->tree.column0);
+ tv->tree.column0.idObj = Tcl_NewStringObj("#0", 2);
+ Tcl_IncrRefCount(tv->tree.column0.idObj);
Tk_InitOptions(
- interp, (void *)(&tv->tree.column0),
+ interp, &tv->tree.column0,
tv->tree.columnOptionTable, tv->core.tkwin);
Tk_InitOptions(
- interp, (void *)(&tv->tree.column0),
+ interp, &tv->tree.column0,
tv->tree.headingOptionTable, tv->core.tkwin);
Tcl_InitHashTable(&tv->tree.items, TCL_STRING_KEYS);
@@ -1036,7 +1312,7 @@ static void TreeviewInitialize(Tcl_Interp *interp, void *recordPtr)
/* Create root item "":
*/
tv->tree.root = NewItem();
- Tk_InitOptions(interp, (void *)tv->tree.root,
+ Tk_InitOptions(interp, tv->tree.root,
tv->tree.itemOptionTable, tv->core.tkwin);
tv->tree.root->tagset = Ttk_GetTagSetFromObj(NULL, tv->tree.tagTable, NULL);
tv->tree.root->entryPtr = Tcl_CreateHashEntry(&tv->tree.items, "", &unused);
@@ -1066,11 +1342,13 @@ static void TreeviewCleanup(void *recordPtr)
if (tv->tree.cellLayout) Ttk_FreeLayout(tv->tree.cellLayout);
if (tv->tree.headingLayout) Ttk_FreeLayout(tv->tree.headingLayout);
if (tv->tree.rowLayout) Ttk_FreeLayout(tv->tree.rowLayout);
+ if (tv->tree.separatorLayout) Ttk_FreeLayout(tv->tree.separatorLayout);
+ FreeColumn(&tv->tree.column0);
TreeviewFreeColumns(tv);
if (tv->tree.displayColumns)
- ckfree((void *)tv->tree.displayColumns);
+ ckfree(tv->tree.displayColumns);
foreachHashEntry(&tv->tree.items, FreeItemCB);
Tcl_DeleteHashTable(&tv->tree.items);
@@ -1100,6 +1378,23 @@ TreeviewConfigure(Tcl_Interp *interp, void *recordPtr, int mask)
if (TreeviewInitDisplayColumns(interp, tv) != TCL_OK)
return TCL_ERROR;
}
+ if (mask & COLUMNS_CHANGED) {
+ CellSelectionClear(tv);
+ }
+ if (tv->tree.nTitleColumns < 0) {
+ Tcl_SetObjResult(interp, Tcl_ObjPrintf(
+ "\"#%" TCL_SIZE_MODIFIER "d\" is out of range",
+ tv->tree.nTitleColumns));
+ Tcl_SetErrorCode(interp, "TTK", "TREE", "TITLECOLUMNS", NULL);
+ return TCL_ERROR;
+ }
+ if (tv->tree.nTitleItems < 0) {
+ Tcl_SetObjResult(interp, Tcl_ObjPrintf(
+ "\"%" TCL_SIZE_MODIFIER "d\" is out of range",
+ tv->tree.nTitleItems));
+ Tcl_SetErrorCode(interp, "TTK", "TREE", "TITLEITEMS", NULL);
+ return TCL_ERROR;
+ }
if (mask & SCROLLCMD_CHANGED) {
TtkScrollbarUpdateRequired(tv->tree.xscrollHandle);
TtkScrollbarUpdateRequired(tv->tree.yscrollHandle);
@@ -1114,6 +1409,7 @@ TreeviewConfigure(Tcl_Interp *interp, void *recordPtr, int mask)
return TCL_ERROR;
}
+ tv->tree.rowPosNeedsUpdate = 1;
tv->tree.showFlags = showFlags;
if (mask & (SHOW_CHANGED | DCOLUMNS_CHANGED)) {
@@ -1127,14 +1423,14 @@ TreeviewConfigure(Tcl_Interp *interp, void *recordPtr, int mask)
*/
static int ConfigureItem(
Tcl_Interp *interp, Treeview *tv, TreeItem *item,
- int objc, Tcl_Obj *const objv[])
+ Tcl_Size objc, Tcl_Obj *const objv[])
{
Tk_SavedOptions savedOptions;
int mask;
Ttk_ImageSpec *newImageSpec = NULL;
Ttk_TagSet newTagSet = NULL;
- if (Tk_SetOptions(interp, (void *)item, tv->tree.itemOptionTable,
+ if (Tk_SetOptions(interp, item, tv->tree.itemOptionTable,
objc, objv, tv->core.tkwin, &savedOptions, &mask)
!= TCL_OK)
{
@@ -1144,11 +1440,20 @@ static int ConfigureItem(
/* Make sure that -values is a valid list:
*/
if (item->valuesObj) {
- int unused;
+ Tcl_Size unused;
if (Tcl_ListObjLength(interp, item->valuesObj, &unused) != TCL_OK)
goto error;
}
+ /* Check -height
+ */
+ if (item->height < 1) {
+ Tcl_SetObjResult(interp, Tcl_ObjPrintf(
+ "Invalid item height %d", item->height));
+ Tcl_SetErrorCode(interp, "TTK", "TREE", "HEIGHT", NULL);
+ goto error;
+ }
+
/* Check -image.
*/
if ((mask & ITEM_OPTION_IMAGE_CHANGED) && item->imageObj) {
@@ -1194,6 +1499,7 @@ static int ConfigureItem(
if (item->imagespec) { TtkFreeImageSpec(item->imagespec); }
item->imagespec = newImageSpec;
}
+ tv->tree.rowPosNeedsUpdate = 1;
TtkRedisplayWidget(&tv->core);
return TCL_OK;
@@ -1209,12 +1515,12 @@ error:
*/
static int ConfigureColumn(
Tcl_Interp *interp, Treeview *tv, TreeColumn *column,
- int objc, Tcl_Obj *const objv[])
+ Tcl_Size objc, Tcl_Obj *const objv[])
{
Tk_SavedOptions savedOptions;
int mask;
- if (Tk_SetOptions(interp, (void *)column,
+ if (Tk_SetOptions(interp, column,
tv->tree.columnOptionTable, objc, objv, tv->core.tkwin,
&savedOptions,&mask) != TCL_OK)
{
@@ -1235,10 +1541,10 @@ static int ConfigureColumn(
if (mask & GEOMETRY_CHANGED) {
if (!Tk_IsMapped(tv->core.tkwin)) {
TtkResizeWidget(&tv->core);
- } else {
+ } else {
RecomputeSlack(tv);
ResizeColumns(tv, TreeWidth(tv));
- }
+ }
}
TtkRedisplayWidget(&tv->core);
@@ -1255,12 +1561,12 @@ error:
*/
static int ConfigureHeading(
Tcl_Interp *interp, Treeview *tv, TreeColumn *column,
- int objc, Tcl_Obj *const objv[])
+ Tcl_Size objc, Tcl_Obj *const objv[])
{
Tk_SavedOptions savedOptions;
int mask;
- if (Tk_SetOptions(interp, (void *)column,
+ if (Tk_SetOptions(interp, column,
tv->tree.headingOptionTable, objc, objv, tv->core.tkwin,
&savedOptions,&mask) != TCL_OK)
{
@@ -1294,48 +1600,55 @@ error:
* +++ Geometry routines.
*/
-/* + CountRows --
- * Returns the number of viewable rows rooted at item
+/* + UpdatePositionItem --
+ * Update position data for all visible items.
*/
-static int CountRows(TreeItem *item)
+static void UpdatePositionItem(
+ Treeview *tv, TreeItem *item, int hidden,
+ int *rowPos, int *itemPos, int *visiblePos)
{
- int rows = 1;
+ TreeItem *child = item->children;
+ item->itemPos = *itemPos;
+ *itemPos += 1;
- if (item->state & TTK_STATE_OPEN) {
- TreeItem *child = item->children;
- while (child) {
- rows += CountRows(child);
- child = child->next;
+ if (item->hidden) {
+ hidden = 1;
+ }
+
+ if (hidden) {
+ item->rowPos = -1;
+ item->visiblePos = -1;
+ } else {
+ item->rowPos = *rowPos;
+ item->visiblePos = *visiblePos;
+ if (*visiblePos == tv->tree.nTitleItems) {
+ tv->tree.titleRows = *rowPos;
}
+
+ *visiblePos += 1;
+ *rowPos += item->height;
+ }
+
+ if (!(item->state & TTK_STATE_OPEN)) {
+ hidden = 1;
+ }
+ while (child) {
+ UpdatePositionItem(tv, child, hidden, rowPos, itemPos, visiblePos);
+ child = child->next;
}
- return rows;
}
-/* + IdentifyRow --
- * Recursive search for item at specified y position.
- * Main work routine for IdentifyItem()
+/* + UpdatePositionTree --
+ * Update position data for all visible items.
*/
-static TreeItem *IdentifyRow(
- Treeview *tv, /* Widget record */
- TreeItem *item, /* Where to start search */
- int *ypos, /* Scan position */
- int y) /* Target y coordinate */
+static void UpdatePositionTree(Treeview *tv)
{
- while (item) {
- int next_ypos = *ypos + tv->tree.rowHeight;
- if (*ypos <= y && y <= next_ypos) {
- return item;
- }
- *ypos = next_ypos;
- if (item->state & TTK_STATE_OPEN) {
- TreeItem *subitem = IdentifyRow(tv, item->children, ypos, y);
- if (subitem) {
- return subitem;
- }
- }
- item = item->next;
- }
- return 0;
+ /* -1 for the invisible root */
+ int rowPos = -1, itemPos = -1, visiblePos = -1;
+ tv->tree.titleRows = 0;
+ UpdatePositionItem(tv, tv->tree.root, 0, &rowPos, &itemPos, &visiblePos);
+ tv->tree.totalRows = rowPos;
+ tv->tree.rowPosNeedsUpdate = 0;
}
/* + IdentifyItem --
@@ -1343,19 +1656,39 @@ static TreeItem *IdentifyRow(
*/
static TreeItem *IdentifyItem(Treeview *tv, int y)
{
+ TreeItem *item;
int rowHeight = tv->tree.rowHeight;
- int ypos = tv->tree.treeArea.y - rowHeight * tv->tree.yscroll.first;
- return IdentifyRow(tv, tv->tree.root->children, &ypos, y);
+ int ypos = tv->tree.treeArea.y;
+ int nextRow, row;
+ if (y < ypos) {
+ return NULL;
+ }
+ if (tv->tree.rowPosNeedsUpdate) {
+ UpdatePositionTree(tv);
+ }
+ row = (y - ypos) / rowHeight;
+ if (row >= tv->tree.titleRows) {
+ row += tv->tree.yscroll.first;
+ }
+ for (item = tv->tree.root->children; item; item = NextPreorder(item)) {
+ nextRow = item->rowPos + item->height;
+ if (item->rowPos <= row && row < nextRow) break;
+ }
+ return item;
}
/* + IdentifyDisplayColumn --
* Returns the display column number at the specified x position,
* or -1 if x is outside any columns.
*/
-static int IdentifyDisplayColumn(Treeview *tv, int x, int *x1)
+static Tcl_Size IdentifyDisplayColumn(Treeview *tv, int x, int *x1)
{
- int colno = FirstColumn(tv);
- int xpos = tv->tree.treeArea.x - tv->tree.xscroll.first;
+ Tcl_Size colno = FirstColumn(tv);
+ int xpos = tv->tree.treeArea.x;
+
+ if (tv->tree.nTitleColumns <= colno) {
+ xpos -= tv->tree.xscroll.first;
+ }
while (colno < tv->tree.nDisplayColumns) {
TreeColumn *column = tv->tree.displayColumns[colno];
@@ -1366,40 +1699,12 @@ static int IdentifyDisplayColumn(Treeview *tv, int x, int *x1)
}
++colno;
xpos = next_xpos;
- }
-
- return -1;
-}
-
-/* + RowNumber --
- * Calculate which row the specified item appears on;
- * returns -1 if the item is not viewable.
- * Xref: DrawForest, IdentifyItem.
- */
-static int RowNumber(Treeview *tv, TreeItem *item)
-{
- TreeItem *p = tv->tree.root->children;
- int n = 0;
-
- while (p) {
- if (p == item)
- return n;
-
- ++n;
-
- /* Find next viewable item in preorder traversal order
- */
- if (p->children && (p->state & TTK_STATE_OPEN)) {
- p = p->children;
- } else {
- while (!p->next && p && p->parent)
- p = p->parent;
- if (p)
- p = p->next;
+ if (tv->tree.nTitleColumns == colno) {
+ xpos -= tv->tree.xscroll.first;
}
}
- return -1;
+ return TCL_INDEX_NONE;
}
/* + ItemDepth -- return the depth of a tree item.
@@ -1416,31 +1721,23 @@ static int ItemDepth(TreeItem *item)
return depth-1;
}
-/* + ItemRow --
- * Returns row number of specified item relative to root,
- * -1 if item is not viewable.
+/* + DisplayRow --
+ * Returns the position row has on screen, or -1 if off-screen.
*/
-static int ItemRow(Treeview *tv, TreeItem *p)
+static int DisplayRow(int row, Treeview *tv)
{
- TreeItem *root = tv->tree.root;
- int rowNumber = 0;
-
- for (;;) {
- if (p->prev) {
- p = p->prev;
- rowNumber += CountRows(p);
- } else {
- p = p->parent;
- if (!(p && (p->state & TTK_STATE_OPEN))) {
- /* detached or closed ancestor */
- return -1;
- }
- if (p == root) {
- return rowNumber;
- }
- ++rowNumber;
- }
+ int visibleRows = tv->tree.treeArea.height / tv->tree.rowHeight
+ - tv->tree.titleRows;
+ if (row < tv->tree.titleRows) {
+ return row;
+ }
+ row -= tv->tree.titleRows;
+ if (row < tv->tree.yscroll.first
+ || row > tv->tree.yscroll.first + visibleRows) {
+ /* not viewable, or off-screen */
+ return -1;
}
+ return row - tv->tree.yscroll.first + tv->tree.titleRows;
}
/* + BoundingBox --
@@ -1454,23 +1751,27 @@ static int BoundingBox(
TreeColumn *column, /* desired column */
Ttk_Box *bbox_rtn) /* bounding box of item */
{
- int row = ItemRow(tv, item);
+ int dispRow;
Ttk_Box bbox = tv->tree.treeArea;
- if (row < tv->tree.yscroll.first || row > tv->tree.yscroll.last) {
+ if (tv->tree.rowPosNeedsUpdate) {
+ UpdatePositionTree(tv);
+ }
+ dispRow = DisplayRow(item->rowPos, tv);
+ if (dispRow < 0) {
/* not viewable, or off-screen */
return 0;
}
- bbox.y += (row - tv->tree.yscroll.first) * tv->tree.rowHeight;
- bbox.height = tv->tree.rowHeight;
+ bbox.y += dispRow * tv->tree.rowHeight;
+ bbox.height = tv->tree.rowHeight * item->height;
bbox.x -= tv->tree.xscroll.first;
bbox.width = TreeWidth(tv);
if (column) {
int xpos = 0;
- int i = FirstColumn(tv);
+ Tcl_Size i = FirstColumn(tv);
while (i < tv->tree.nDisplayColumns) {
if (tv->tree.displayColumns[i] == column) {
break;
@@ -1484,6 +1785,11 @@ static int BoundingBox(
bbox.x += xpos;
bbox.width = column->width;
+ if (i < tv->tree.nTitleColumns) {
+ /* Unscrollable column, remove scroll shift */
+ bbox.x += tv->tree.xscroll.first;
+ }
+
/* Account for indentation in tree column:
*/
if (column == &tv->tree.column0) {
@@ -1514,7 +1820,7 @@ static const char *const regionStrings[] = {
static TreeRegion IdentifyRegion(Treeview *tv, int x, int y)
{
int x1 = 0;
- int colno = IdentifyDisplayColumn(tv, x, &x1);
+ Tcl_Size colno = IdentifyDisplayColumn(tv, x, &x1);
if (Ttk_BoxContains(tv->tree.headingArea, x, y)) {
if (colno < 0) {
@@ -1570,18 +1876,22 @@ static Ttk_Layout TreeviewGetLayout(
Treeview *tv = (Treeview *)recordPtr;
Ttk_Layout treeLayout = TtkWidgetGetLayout(interp, themePtr, recordPtr);
Tcl_Obj *objPtr;
- int unused;
+ int unused, cellHeight;
+ DisplayItem displayItem;
+ Ttk_Style style;
if (!(
treeLayout
&& GetSublayout(interp, themePtr, treeLayout, ".Item",
- tv->tree.tagOptionTable, &tv->tree.itemLayout)
+ tv->tree.displayOptionTable, &tv->tree.itemLayout)
&& GetSublayout(interp, themePtr, treeLayout, ".Cell",
- tv->tree.tagOptionTable, &tv->tree.cellLayout)
+ tv->tree.displayOptionTable, &tv->tree.cellLayout)
&& GetSublayout(interp, themePtr, treeLayout, ".Heading",
tv->tree.headingOptionTable, &tv->tree.headingLayout)
&& GetSublayout(interp, themePtr, treeLayout, ".Row",
- tv->tree.tagOptionTable, &tv->tree.rowLayout)
+ tv->tree.displayOptionTable, &tv->tree.rowLayout)
+ && GetSublayout(interp, themePtr, treeLayout, ".Separator",
+ tv->tree.displayOptionTable, &tv->tree.separatorLayout)
)) {
return 0;
}
@@ -1591,14 +1901,34 @@ static Ttk_Layout TreeviewGetLayout(
Ttk_RebindSublayout(tv->tree.headingLayout, &tv->tree.column0);
Ttk_LayoutSize(tv->tree.headingLayout, 0, &unused, &tv->tree.headingHeight);
- /* Get item height, indent from style:
+ /* Get row height from style, or compute it to fit Item and Cell.
+ * Pick up default font from the Treeview style.
*/
- tv->tree.rowHeight = DEFAULT_ROWHEIGHT;
- tv->tree.indent = DEFAULT_INDENT;
+ style = Ttk_LayoutStyle(treeLayout);
+ Ttk_TagSetDefaults(tv->tree.tagTable, style, &displayItem);
+
+ Ttk_RebindSublayout(tv->tree.itemLayout, &displayItem);
+ Ttk_LayoutSize(tv->tree.itemLayout, 0, &unused, &tv->tree.rowHeight);
+
+ Ttk_RebindSublayout(tv->tree.cellLayout, &displayItem);
+ Ttk_LayoutSize(tv->tree.cellLayout, 0, &unused, &cellHeight);
+
+ if (cellHeight > tv->tree.rowHeight) {
+ tv->tree.rowHeight = cellHeight;
+ }
+
if ((objPtr = Ttk_QueryOption(treeLayout, "-rowheight", 0))) {
(void)Tk_GetPixelsFromObj(NULL, tv->core.tkwin, objPtr, &tv->tree.rowHeight);
- tv->tree.rowHeight = MAX(tv->tree.rowHeight, 1);
}
+ tv->tree.rowHeight = MAX(tv->tree.rowHeight, 1);
+
+ if ((objPtr = Ttk_QueryOption(treeLayout, "-columnseparatorwidth", 0))) {
+ (void)Tk_GetPixelsFromObj(NULL, tv->core.tkwin, objPtr, &tv->tree.colSeparatorWidth);
+ }
+
+ /* Get item indent from style:
+ */
+ tv->tree.indent = DEFAULT_INDENT;
if ((objPtr = Ttk_QueryOption(treeLayout, "-indent", 0))) {
(void)Tk_GetPixelsFromObj(NULL, tv->core.tkwin, objPtr, &tv->tree.indent);
}
@@ -1617,17 +1947,18 @@ static Ttk_Layout TreeviewGetLayout(
static void TreeviewDoLayout(void *clientData)
{
Treeview *tv = (Treeview *)clientData;
- int totalRows, visibleRows;
+ int visibleRows;
+ int first, last, total;
Ttk_PlaceLayout(tv->core.layout,tv->core.state,Ttk_WinBox(tv->core.tkwin));
tv->tree.treeArea = Ttk_ClientRegion(tv->core.layout, "treearea");
ResizeColumns(tv, tv->tree.treeArea.width);
- TtkScrolled(tv->tree.xscrollHandle,
- tv->tree.xscroll.first,
- tv->tree.xscroll.first + tv->tree.treeArea.width,
- TreeWidth(tv));
+ first = tv->tree.xscroll.first;
+ last = first + tv->tree.treeArea.width - tv->tree.titleWidth;
+ total = TreeWidth(tv) - tv->tree.titleWidth;
+ TtkScrolled(tv->tree.xscrollHandle, first, last, total);
if (tv->tree.showFlags & SHOW_HEADINGS) {
tv->tree.headingArea = Ttk_PackBox(
@@ -1636,22 +1967,22 @@ static void TreeviewDoLayout(void *clientData)
tv->tree.headingArea = Ttk_MakeBox(0,0,0,0);
}
- tv->tree.root->state |= TTK_STATE_OPEN;
- totalRows = CountRows(tv->tree.root) - 1;
visibleRows = tv->tree.treeArea.height / tv->tree.rowHeight;
+ tv->tree.root->state |= TTK_STATE_OPEN;
+ UpdatePositionTree(tv);
+ first = tv->tree.yscroll.first;
+ last = tv->tree.yscroll.first + visibleRows - tv->tree.titleRows;
+ total = tv->tree.totalRows - tv->tree.titleRows;
if (tv->tree.treeArea.height % tv->tree.rowHeight) {
- /* When the treeview height doesn't correspond to an exact number
- * of rows, the visible row count must be incremented to draw a
- * partial row at the bottom. The total row count must also be
- * incremented to be able to scroll all the way to the bottom.
- */
- visibleRows++;
- totalRows++;
+ /* When the treeview height doesn't correspond to an exact number
+ * of rows, the last row count must be incremented to draw a
+ * partial row at the bottom. The total row count must also be
+ * incremented to be able to scroll all the way to the bottom.
+ */
+ last++;
+ total++;
}
- TtkScrolled(tv->tree.yscrollHandle,
- tv->tree.yscroll.first,
- tv->tree.yscroll.first + visibleRows,
- totalRows);
+ TtkScrolled(tv->tree.yscrollHandle, first, last, total);
}
/* + TreeviewSize --
@@ -1695,15 +2026,34 @@ static Ttk_State ItemState(Treeview *tv, TreeItem *item)
*/
static void DrawHeadings(Treeview *tv, Drawable d)
{
- const int x0 = tv->tree.headingArea.x - tv->tree.xscroll.first;
+ int x0 = tv->tree.headingArea.x - tv->tree.xscroll.first;
const int y0 = tv->tree.headingArea.y;
const int h0 = tv->tree.headingArea.height;
- int i = FirstColumn(tv);
+ Tcl_Size i = FirstColumn(tv);
int x = 0;
+ if (tv->tree.nTitleColumns > i) {
+ x = tv->tree.titleWidth;
+ i = tv->tree.nTitleColumns;
+ }
+
while (i < tv->tree.nDisplayColumns) {
TreeColumn *column = tv->tree.displayColumns[i];
Ttk_Box parcel = Ttk_MakeBox(x0+x, y0, column->width, h0);
+ if (x0+x+column->width > tv->tree.titleWidth) {
+ DisplayLayout(tv->tree.headingLayout,
+ column, column->headingState, parcel, d);
+ }
+ x += column->width;
+ ++i;
+ }
+
+ x0 = tv->tree.headingArea.x;
+ i = FirstColumn(tv);
+ x = 0;
+ while ((i < tv->tree.nTitleColumns) && (i < tv->tree.nDisplayColumns)) {
+ TreeColumn *column = tv->tree.displayColumns[i];
+ Ttk_Box parcel = Ttk_MakeBox(x0+x, y0, column->width, h0);
DisplayLayout(tv->tree.headingLayout,
column, column->headingState, parcel, d);
x += column->width;
@@ -1711,53 +2061,200 @@ static void DrawHeadings(Treeview *tv, Drawable d)
}
}
+/* + DrawSeparators --
+ * Draw separators between columns
+ */
+static void DrawSeparators(Treeview *tv, Drawable d)
+{
+ const int y0 = tv->tree.treeArea.y;
+ const int h0 = tv->tree.treeArea.height;
+ DisplayItem displayItem;
+ Ttk_Style style = Ttk_LayoutStyle(tv->tree.separatorLayout);
+ int x = tv->tree.treeArea.x;
+ Tcl_Size i;
+
+ Ttk_TagSetDefaults(tv->tree.tagTable, style, &displayItem);
+
+ for (i = FirstColumn(tv); i < tv->tree.nDisplayColumns; ++i) {
+ TreeColumn *column = tv->tree.displayColumns[i];
+ Ttk_Box parcel;
+ int xDraw = x + column->width;
+ x += column->width;
+
+ if (!column->separator) continue;
+
+ if (i >= tv->tree.nTitleColumns) {
+ xDraw -= tv->tree.xscroll.first;
+ if (xDraw < tv->tree.titleWidth) continue;
+ }
+
+ parcel = Ttk_MakeBox(xDraw - (tv->tree.colSeparatorWidth+1)/2, y0,
+ tv->tree.colSeparatorWidth, h0);
+ DisplayLayout(tv->tree.separatorLayout, &displayItem, 0, parcel, d);
+ }
+}
+
+/* + OverrideStriped --
+ * Each level of settings might add stripedbackground, and it should
+ * override background if this is indeed on a striped item.
+ * By copying it between each level, and NULL-ing stripedBgObj,
+ * it can be detected if the next level overrides it.
+ */
+ static void OverrideStriped(
+ Treeview *tv, TreeItem *item, DisplayItem *displayItem)
+{
+ int striped = item->visiblePos % 2 && tv->tree.striped;
+ if (striped && displayItem->stripedBgObj) {
+ displayItem->backgroundObj = displayItem->stripedBgObj;
+ displayItem->stripedBgObj = NULL;
+ }
+}
+
/* + PrepareItem --
* Fill in a displayItem record.
*/
static void PrepareItem(
- Treeview *tv, TreeItem *item, DisplayItem *displayItem)
+ Treeview *tv, TreeItem *item, DisplayItem *displayItem, Ttk_State state)
{
Ttk_Style style = Ttk_LayoutStyle(tv->core.layout);
- Ttk_State state = ItemState(tv, item);
+ Ttk_TagSetDefaults(tv->tree.tagTable, style, displayItem);
+ OverrideStriped(tv, item, displayItem);
Ttk_TagSetValues(tv->tree.tagTable, item->tagset, displayItem);
+ OverrideStriped(tv, item, displayItem);
Ttk_TagSetApplyStyle(tv->tree.tagTable, style, state, displayItem);
}
+/* Fill in data from item to temporary storage in columns. */
+static void PrepareCells(
+ Treeview *tv, TreeItem *item)
+{
+ Tcl_Size i, nValues = 0;
+ Tcl_Obj **values = NULL;
+ TreeColumn *column;
+
+ if (item->valuesObj) {
+ Tcl_ListObjGetElements(NULL, item->valuesObj, &nValues, &values);
+ }
+ for (i = 0; i < tv->tree.nColumns; ++i) {
+ tv->tree.columns[i].data = (i < nValues) ? values[i] : 0;
+ tv->tree.columns[i].selected = 0;
+ tv->tree.columns[i].tagset = NULL;
+ }
+ tv->tree.column0.data = NULL;
+ tv->tree.column0.selected = 0;
+ tv->tree.column0.tagset = NULL;
+
+ if (item->selObj != NULL) {
+ Tcl_ListObjGetElements(NULL, item->selObj, &nValues, &values);
+ for (i = 0; i < nValues; ++i) {
+ column = FindColumn(NULL, tv, values[i]);
+ /* Just in case. It should not be possible for column to be NULL */
+ if (column != NULL) {
+ column->selected = 1;
+ }
+ }
+ }
+ if (item->nTagSets > 0) {
+ tv->tree.column0.tagset = item->cellTagSets[0];
+ }
+ for (i = 1; i < item->nTagSets && i <= tv->tree.nColumns; ++i) {
+ tv->tree.columns[i-1].tagset = item->cellTagSets[i];
+ }
+}
+
/* + DrawCells --
* Draw data cells for specified item.
*/
static void DrawCells(
- Treeview *tv, TreeItem *item, DisplayItem *displayItem,
- Drawable d, int x, int y)
+ Treeview *tv, TreeItem *item,
+ DisplayItem *displayItem, DisplayItem *displayItemSel,
+ Drawable d, int x, int y, int title)
{
Ttk_Layout layout = tv->tree.cellLayout;
+ Ttk_Style style = Ttk_LayoutStyle(tv->core.layout);
Ttk_State state = ItemState(tv, item);
Ttk_Padding cellPadding = {4, 0, 4, 0};
- int rowHeight = tv->tree.rowHeight;
- int nValues = 0;
- Tcl_Obj **values = 0;
- int i;
+ DisplayItem displayItemLocal;
+ DisplayItem displayItemCell, displayItemCellSel;
+ int rowHeight = tv->tree.rowHeight * item->height;
+ int xPad = 0, defaultPadding = 1;
+ Tcl_Size i;
- if (!item->valuesObj) {
- return;
+ /* Adjust if the tree column has a separator */
+ if (tv->tree.showFlags & SHOW_TREE && tv->tree.column0.separator) {
+ xPad = tv->tree.colSeparatorWidth/2;
}
- Tcl_ListObjGetElements(NULL, item->valuesObj, &nValues, &values);
- for (i = 0; i < tv->tree.nColumns; ++i) {
- tv->tree.columns[i].data = (i < nValues) ? values[i] : 0;
+ /* An Item's image should not propagate to a Cell.
+ A Cell's image can only be set by cell tags. */
+ displayItemCell = *displayItem;
+ displayItemCellSel = *displayItemSel;
+ displayItemCell.imageObj = NULL;
+ displayItemCellSel.imageObj = NULL;
+ displayItemCell.imageAnchorObj = NULL;
+ displayItemCellSel.imageAnchorObj = NULL;
+
+ /* If explicit padding was asked for, skip default. */
+ if (Ttk_QueryStyle(Ttk_LayoutStyle(tv->tree.cellLayout), &displayItemCell,
+ tv->tree.displayOptionTable, "-padding", state) != NULL) {
+ defaultPadding = 0;
}
for (i = 1; i < tv->tree.nDisplayColumns; ++i) {
TreeColumn *column = tv->tree.displayColumns[i];
- Ttk_Box parcel = Ttk_PadBox(
- Ttk_MakeBox(x, y, column->width, rowHeight), cellPadding);
-
- displayItem->textObj = column->data;
- displayItem->anchorObj = column->anchorObj; /* <<NOTE-ANCHOR>> */
+ int parcelX = x + xPad;
+ int parcelWidth = column->separator ?
+ column->width - tv->tree.colSeparatorWidth : column->width;
+ Ttk_Box parcel = Ttk_MakeBox(parcelX, y, parcelWidth, rowHeight);
+ DisplayItem *displayItemUsed = &displayItemCell;
+ Ttk_State stateCell = state;
+ Tk_Anchor textAnchor, imageAnchor;
+ xPad = column->separator ? tv->tree.colSeparatorWidth/2 : 0;
- DisplayLayout(layout, displayItem, state, parcel, d);
x += column->width;
+ if (title && i >= tv->tree.nTitleColumns) break;
+ if (!title && i < tv->tree.nTitleColumns) continue;
+ if (!title && x < tv->tree.titleWidth) continue;
+
+ if (column->selected) {
+ displayItemUsed = &displayItemCellSel;
+ stateCell |= TTK_STATE_SELECTED;
+ }
+
+ if (column->tagset) {
+ displayItemLocal = *displayItemUsed;
+ displayItemUsed = &displayItemLocal;
+ Ttk_TagSetValues(tv->tree.tagTable, column->tagset,
+ displayItemUsed);
+ OverrideStriped(tv, item, displayItemUsed);
+ Ttk_TagSetApplyStyle(tv->tree.tagTable, style, stateCell,
+ displayItemUsed);
+ }
+
+ displayItemUsed->textObj = column->data;
+ displayItemUsed->anchorObj = column->anchorObj;/* <<NOTE-ANCHOR>> */
+ Tk_GetAnchorFromObj(NULL, column->anchorObj, &textAnchor);
+
+ imageAnchor = DEFAULT_IMAGEANCHOR;
+ if (displayItemUsed->imageAnchorObj) {
+ Tk_GetAnchorFromObj(NULL, displayItemUsed->imageAnchorObj,
+ &imageAnchor);
+ }
+ /* displayItem was used to draw the full item backgound.
+ Redraw cell background if needed. */
+ if (displayItemUsed != &displayItemCell) {
+ DisplayLayout(tv->tree.rowLayout, displayItemUsed, stateCell,
+ parcel, d);
+ }
+
+ if (defaultPadding && displayItemUsed->paddingObj == NULL) {
+ /* If no explicit padding was asked for, add some default. */
+ parcel = Ttk_PadBox(parcel, cellPadding);
+ }
+
+ DisplayLayoutTree(imageAnchor, textAnchor,
+ layout, displayItemUsed, state, parcel, d);
}
}
@@ -1765,17 +2262,19 @@ static void DrawCells(
* Draw an item (row background, tree label, and cells).
*/
static void DrawItem(
- Treeview *tv, TreeItem *item, Drawable d, int depth, int row)
+ Treeview *tv, TreeItem *item, Drawable d, int depth)
{
+ Ttk_Style style = Ttk_LayoutStyle(tv->core.layout);
Ttk_State state = ItemState(tv, item);
- DisplayItem displayItem;
- int rowHeight = tv->tree.rowHeight;
+ DisplayItem displayItem, displayItemSel, displayItemLocal;
+ int rowHeight = tv->tree.rowHeight * item->height;
int x = tv->tree.treeArea.x - tv->tree.xscroll.first;
- int y = tv->tree.treeArea.y + rowHeight * (row - tv->tree.yscroll.first);
+ int xTitle = tv->tree.treeArea.x;
+ int dispRow = DisplayRow(item->rowPos, tv);
+ int y = tv->tree.treeArea.y + tv->tree.rowHeight * dispRow;
- if (row % 2) state |= TTK_STATE_ALTERNATE;
-
- PrepareItem(tv, item, &displayItem);
+ PrepareItem(tv, item, &displayItem, state);
+ PrepareItem(tv, item, &displayItemSel, state | TTK_STATE_SELECTED);
/* Draw row background:
*/
@@ -1784,63 +2283,118 @@ static void DrawItem(
DisplayLayout(tv->tree.rowLayout, &displayItem, state, rowBox, d);
}
+ /* Make room for tree label:
+ */
+ if (tv->tree.showFlags & SHOW_TREE) {
+ x += tv->tree.column0.width;
+ }
+
+ /* Draw data cells:
+ */
+ PrepareCells(tv, item);
+ DrawCells(tv, item, &displayItem, &displayItemSel, d, x, y, 0);
+
+ /* Draw row background for non-scrolled area:
+ */
+ if (tv->tree.nTitleColumns >= 1) {
+ Ttk_Box rowBox = Ttk_MakeBox(tv->tree.treeArea.x, y,
+ tv->tree.titleWidth, rowHeight);
+ DisplayLayout(tv->tree.rowLayout, &displayItem, state, rowBox, d);
+ }
+
/* Draw tree label:
*/
+ x = tv->tree.treeArea.x - tv->tree.xscroll.first;
if (tv->tree.showFlags & SHOW_TREE) {
+ TreeColumn *column = &tv->tree.column0;
int indent = depth * tv->tree.indent;
- int colwidth = tv->tree.column0.width;
- Ttk_Box parcel = Ttk_MakeBox(
- x+indent, y, colwidth-indent, rowHeight);
- if (item->textObj) { displayItem.textObj = item->textObj; }
- if (item->imageObj) { displayItem.imageObj = item->imageObj; }
- displayItem.anchorObj = tv->tree.column0.anchorObj;
- DisplayLayout(tv->tree.itemLayout, &displayItem, state, parcel, d);
- x += colwidth;
+ int colwidth = tv->tree.column0.width -
+ (tv->tree.column0.separator ? tv->tree.colSeparatorWidth/2 : 0);
+ int xTree = tv->tree.nTitleColumns >= 1 ? xTitle : x;
+ Ttk_Box parcel = Ttk_MakeBox(xTree, y, colwidth, rowHeight);
+ DisplayItem *displayItemUsed = &displayItem;
+ Ttk_State stateCell = state;
+ Tk_Anchor textAnchor, imageAnchor = DEFAULT_IMAGEANCHOR;
+ Ttk_Padding cellPadding = {(short)indent, 0, 0, 0};
+
+ if (column->selected) {
+ displayItemUsed = &displayItemSel;
+ stateCell |= TTK_STATE_SELECTED;
+ }
+
+ if (column->tagset) {
+ displayItemLocal = *displayItemUsed;
+ displayItemUsed = &displayItemLocal;
+ Ttk_TagSetValues(tv->tree.tagTable, column->tagset,
+ displayItemUsed);
+ OverrideStriped(tv, item, displayItemUsed);
+ Ttk_TagSetApplyStyle(tv->tree.tagTable, style, stateCell,
+ displayItemUsed);
+ }
+
+ displayItem.anchorObj = tv->tree.column0.anchorObj;
+ Tk_GetAnchorFromObj(NULL, column->anchorObj, &textAnchor);
+ displayItemUsed->textObj = item->textObj;
+ /* Item's image can be null, and may come from the tag */
+ if (item->imageObj) {
+ displayItemUsed->imageObj = item->imageObj;
+ }
+ if (item->imageAnchorObj) {
+ displayItemUsed->imageAnchorObj = item->imageAnchorObj;
+ }
+ if (displayItemUsed->imageAnchorObj) {
+ Tk_GetAnchorFromObj(NULL, displayItemUsed->imageAnchorObj,
+ &imageAnchor);
+ }
+
+ if (displayItemUsed != &displayItem) {
+ DisplayLayout(tv->tree.rowLayout, displayItemUsed, stateCell,
+ parcel, d);
+ }
+
+ parcel = Ttk_PadBox(parcel, cellPadding);
+ DisplayLayoutTree(imageAnchor, textAnchor,
+ tv->tree.itemLayout, displayItemUsed, state, parcel, d);
+ xTitle += colwidth;
}
- /* Draw data cells:
+ /* Draw non-scrolled data cells:
*/
- DrawCells(tv, item, &displayItem, d, x, y);
+ if (tv->tree.nTitleColumns > 1) {
+ DrawCells(tv, item, &displayItem, &displayItemSel, d, xTitle, y, 1);
+ }
}
/* + DrawSubtree --
* Draw an item and all of its (viewable) descendants.
- *
- * Returns:
- * Row number of the last item drawn.
*/
-static int DrawForest( /* forward */
- Treeview *tv, TreeItem *item, Drawable d, int depth, int row);
+static void DrawForest( /* forward */
+ Treeview *tv, TreeItem *item, Drawable d, int depth);
-static int DrawSubtree(
- Treeview *tv, TreeItem *item, Drawable d, int depth, int row)
+static void DrawSubtree(
+ Treeview *tv, TreeItem *item, Drawable d, int depth)
{
- if (row >= tv->tree.yscroll.first) {
- DrawItem(tv, item, d, depth, row);
+ int dispRow = DisplayRow(item->rowPos, tv);
+ if (dispRow >= 0) {
+ DrawItem(tv, item, d, depth);
}
if (item->state & TTK_STATE_OPEN) {
- return DrawForest(tv, item->children, d, depth + 1, row + 1);
- } else {
- return row + 1;
+ DrawForest(tv, item->children, d, depth + 1);
}
}
/* + DrawForest --
* Draw a sequence of items and their visible descendants.
- *
- * Returns:
- * Row number of the last item drawn.
*/
-static int DrawForest(
- Treeview *tv, TreeItem *item, Drawable d, int depth, int row)
+static void DrawForest(
+ Treeview *tv, TreeItem *item, Drawable d, int depth)
{
- while (item && row < tv->tree.yscroll.last) {
- row = DrawSubtree(tv, item, d, depth, row);
+ while (item) {
+ DrawSubtree(tv, item, d, depth);
item = item->next;
}
- return row;
}
/* + TreeviewDisplay --
@@ -1854,7 +2408,8 @@ static void TreeviewDisplay(void *clientData, Drawable d)
if (tv->tree.showFlags & SHOW_HEADINGS) {
DrawHeadings(tv, d);
}
- DrawForest(tv, tv->tree.root->children, d, 0, 0);
+ DrawForest(tv, tv->tree.root->children, d, 0);
+ DrawSeparators(tv, d);
}
/*------------------------------------------------------------------------
@@ -1960,7 +2515,7 @@ static TreeItem *DeleteItems(TreeItem *item, TreeItem *delq)
* Return the list of children associated with $item
*/
static int TreeviewChildrenCommand(
- void *recordPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
+ void *recordPtr, Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *const objv[])
{
Treeview *tv = (Treeview *)recordPtr;
TreeItem *item;
@@ -2030,6 +2585,7 @@ static int TreeviewChildrenCommand(
}
ckfree(newChildren);
+ tv->tree.rowPosNeedsUpdate = 1;
TtkRedisplayWidget(&tv->core);
}
@@ -2040,7 +2596,7 @@ static int TreeviewChildrenCommand(
* Return the item ID of $item's parent.
*/
static int TreeviewParentCommand(
- void *recordPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
+ void *recordPtr, Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *const objv[])
{
Treeview *tv = (Treeview *)recordPtr;
TreeItem *item;
@@ -2068,7 +2624,7 @@ static int TreeviewParentCommand(
* Return the ID of $item's next sibling.
*/
static int TreeviewNextCommand(
- void *recordPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
+ void *recordPtr, Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *const objv[])
{
Treeview *tv = (Treeview *)recordPtr;
TreeItem *item;
@@ -2093,7 +2649,7 @@ static int TreeviewNextCommand(
* Return the ID of $item's previous sibling.
*/
static int TreeviewPrevCommand(
- void *recordPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
+ void *recordPtr, Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *const objv[])
{
Treeview *tv = (Treeview *)recordPtr;
TreeItem *item;
@@ -2118,11 +2674,11 @@ static int TreeviewPrevCommand(
* Return the index of $item within its parent.
*/
static int TreeviewIndexCommand(
- void *recordPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
+ void *recordPtr, Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *const objv[])
{
Treeview *tv = (Treeview *)recordPtr;
TreeItem *item;
- int index = 0;
+ Tcl_Size index = 0;
if (objc != 3) {
Tcl_WrongNumArgs(interp, 2, objv, "item");
@@ -2138,7 +2694,7 @@ static int TreeviewIndexCommand(
item = item->prev;
}
- Tcl_SetObjResult(interp, Tcl_NewIntObj(index));
+ Tcl_SetObjResult(interp, TkNewIndexObj(index));
return TCL_OK;
}
@@ -2146,7 +2702,7 @@ static int TreeviewIndexCommand(
* Test if the specified item id is present in the tree.
*/
static int TreeviewExistsCommand(
- void *recordPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
+ void *recordPtr, Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *const objv[])
{
Treeview *tv = (Treeview *)recordPtr;
Tcl_HashEntry *entryPtr;
@@ -2165,7 +2721,7 @@ static int TreeviewExistsCommand(
* Return bounding box [x y width height] of specified item.
*/
static int TreeviewBBoxCommand(
- void *recordPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
+ void *recordPtr, Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *const objv[])
{
Treeview *tv = (Treeview *)recordPtr;
TreeItem *item = 0;
@@ -2203,14 +2759,14 @@ static int TreeviewBBoxCommand(
*/
static int TreeviewHorribleIdentify(
Tcl_Interp *interp,
- TCL_UNUSED(int), /* objc */
+ TCL_UNUSED(Tcl_Size), /* objc */
Tcl_Obj *const objv[],
Treeview *tv)
{
const char *what = "nothing", *detail = NULL;
TreeItem *item = 0;
Tcl_Obj *result;
- int dColumnNumber;
+ Tcl_Size dColumnNumber;
char dcolbuf[32];
int x, y, x1;
@@ -2225,7 +2781,7 @@ static int TreeviewHorribleIdentify(
if (dColumnNumber < 0) {
goto done;
}
- snprintf(dcolbuf, sizeof(dcolbuf), "#%d", dColumnNumber);
+ snprintf(dcolbuf, sizeof(dcolbuf), "#%" TCL_SIZE_MODIFIER "d", dColumnNumber);
if (Ttk_BoxContains(tv->tree.headingArea,x,y)) {
if (-HALO <= x1 - x && x1 - x <= HALO) {
@@ -2244,13 +2800,14 @@ static int TreeviewHorribleIdentify(
Ttk_Box itemBox;
DisplayItem displayItem;
Ttk_Element element;
+ Ttk_State state = ItemState(tv, item);
BoundingBox(tv, item, NULL, &itemBox);
- PrepareItem(tv, item, &displayItem);
- if (item->textObj) { displayItem.textObj = item->textObj; }
- if (item->imageObj) { displayItem.imageObj = item->imageObj; }
+ PrepareItem(tv, item, &displayItem, state);
+ if (item->textObj) { displayItem.textObj = item->textObj; }
+ if (item->imageObj) { displayItem.imageObj = item->imageObj; }
Ttk_RebindSublayout(layout, &displayItem);
- Ttk_PlaceLayout(layout, ItemState(tv,item), itemBox);
+ Ttk_PlaceLayout(layout, state, itemBox);
element = Ttk_IdentifyElement(layout, x, y);
if (element) {
@@ -2279,11 +2836,11 @@ done:
*/
static int TreeviewIdentifyCommand(
- void *recordPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
+ void *recordPtr, Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *const objv[])
{
static const char *const submethodStrings[] =
- { "region", "item", "column", "row", "element", NULL };
- enum { I_REGION, I_ITEM, I_COLUMN, I_ROW, I_ELEMENT };
+ { "region", "item", "column", "row", "element", "cell", NULL };
+ enum { I_REGION, I_ITEM, I_COLUMN, I_ROW, I_ELEMENT, I_CELL };
Treeview *tv = (Treeview *)recordPtr;
int submethod;
@@ -2293,7 +2850,7 @@ static int TreeviewIdentifyCommand(
Ttk_Box bbox;
TreeItem *item;
TreeColumn *column = 0;
- int colno;
+ Tcl_Size colno;
int x1;
if (objc == 4) { /* Old form */
@@ -2305,7 +2862,7 @@ static int TreeviewIdentifyCommand(
if (Tcl_GetIndexFromObjStruct(interp, objv[2], submethodStrings,
sizeof(char *), "command", TCL_EXACT, &submethod) != TCL_OK
- || Tk_GetPixelsFromObj(interp, tv->core.tkwin, objv[3], &x) != TCL_OK
+ || Tk_GetPixelsFromObj(interp, tv->core.tkwin, objv[3], &x) != TCL_OK
|| Tk_GetPixelsFromObj(interp, tv->core.tkwin, objv[4], &y) != TCL_OK
) {
return TCL_ERROR;
@@ -2331,7 +2888,16 @@ static int TreeviewIdentifyCommand(
case I_COLUMN :
if (colno >= 0) {
- Tcl_SetObjResult(interp, Tcl_ObjPrintf("#%d", colno));
+ Tcl_SetObjResult(interp, Tcl_ObjPrintf("#%" TCL_SIZE_MODIFIER "d", colno));
+ }
+ break;
+
+ case I_CELL :
+ if (item && colno >= 0) {
+ Tcl_Obj *elem[2];
+ elem[0] = ItemID(tv, item);
+ elem[1] = Tcl_ObjPrintf("#%" TCL_SIZE_MODIFIER "d", colno);
+ Tcl_SetObjResult(interp, Tcl_NewListObj(2, elem));
}
break;
@@ -2340,6 +2906,7 @@ static int TreeviewIdentifyCommand(
Ttk_Layout layout = 0;
DisplayItem displayItem;
Ttk_Element element;
+ Ttk_State state;
switch (region) {
case REGION_NOTHING:
@@ -2357,15 +2924,18 @@ static int TreeviewIdentifyCommand(
break;
}
+ if (item == NULL) {
+ return TCL_OK;
+ }
if (!BoundingBox(tv, item, column, &bbox)) {
return TCL_OK;
}
-
- PrepareItem(tv, item, &displayItem);
- if (item->textObj) { displayItem.textObj = item->textObj; }
- if (item->imageObj) { displayItem.imageObj = item->imageObj; }
+ state = ItemState(tv, item);
+ PrepareItem(tv, item, &displayItem, state);
+ if (item->textObj) { displayItem.textObj = item->textObj; }
+ if (item->imageObj) { displayItem.imageObj = item->imageObj; }
Ttk_RebindSublayout(layout, &displayItem);
- Ttk_PlaceLayout(layout, ItemState(tv,item), bbox);
+ Ttk_PlaceLayout(layout, state, bbox);
element = Ttk_IdentifyElement(layout, x, y);
if (element) {
@@ -2386,13 +2956,13 @@ static int TreeviewIdentifyCommand(
* Query or configure item options.
*/
static int TreeviewItemCommand(
- void *recordPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
+ void *recordPtr, Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *const objv[])
{
Treeview *tv = (Treeview *)recordPtr;
TreeItem *item;
if (objc < 3) {
- Tcl_WrongNumArgs(interp, 2, objv, "item ?option ?value??...");
+ Tcl_WrongNumArgs(interp, 2, objv, "item ?-option ?value??...");
return TCL_ERROR;
}
if (!(item = FindItem(interp, tv, objv[2]))) {
@@ -2414,7 +2984,7 @@ static int TreeviewItemCommand(
* Column data accessor
*/
static int TreeviewColumnCommand(
- void *recordPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
+ void *recordPtr, Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *const objv[])
{
Treeview *tv = (Treeview *)recordPtr;
TreeColumn *column;
@@ -2442,7 +3012,7 @@ static int TreeviewColumnCommand(
* Heading data accessor
*/
static int TreeviewHeadingCommand(
- void *recordPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
+ void *recordPtr, Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *const objv[])
{
Treeview *tv = (Treeview *)recordPtr;
Tk_OptionTable optionTable = tv->tree.headingOptionTable;
@@ -2472,12 +3042,12 @@ static int TreeviewHeadingCommand(
* Query or configure cell values
*/
static int TreeviewSetCommand(
- void *recordPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
+ void *recordPtr, Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *const objv[])
{
Treeview *tv = (Treeview *)recordPtr;
TreeItem *item;
TreeColumn *column;
- int columnNumber;
+ Tcl_Size columnNumber;
if (objc < 3 || objc > 5) {
Tcl_WrongNumArgs(interp, 2, objv, "item ?column ?value??");
@@ -2537,7 +3107,7 @@ static int TreeviewSetCommand(
Tcl_SetObjResult(interp, result);
return TCL_OK;
} else { /* set column */
- int length;
+ Tcl_Size length;
item->valuesObj = unshareObj(item->valuesObj);
@@ -2566,7 +3136,7 @@ static int TreeviewSetCommand(
* Insert a new item.
*/
static int TreeviewInsertCommand(
- void *recordPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
+ void *recordPtr, Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *const objv[])
{
Treeview *tv = (Treeview *)recordPtr;
TreeItem *parent, *sibling, *newItem;
@@ -2624,7 +3194,7 @@ static int TreeviewInsertCommand(
*/
newItem = NewItem();
Tk_InitOptions(
- interp, (void *)newItem, tv->tree.itemOptionTable, tv->core.tkwin);
+ interp, newItem, tv->tree.itemOptionTable, tv->core.tkwin);
newItem->tagset = Ttk_GetTagSetFromObj(NULL, tv->tree.tagTable, NULL);
if (ConfigureItem(interp, tv, newItem, objc, objv) != TCL_OK) {
Tcl_DeleteHashEntry(entryPtr);
@@ -2637,6 +3207,7 @@ static int TreeviewInsertCommand(
Tcl_SetHashValue(entryPtr, newItem);
newItem->entryPtr = entryPtr;
InsertItem(parent, sibling, newItem);
+ tv->tree.rowPosNeedsUpdate = 1;
TtkRedisplayWidget(&tv->core);
Tcl_SetObjResult(interp, ItemID(tv, newItem));
@@ -2647,11 +3218,11 @@ static int TreeviewInsertCommand(
* Unlink each item in $items from the tree.
*/
static int TreeviewDetachCommand(
- void *recordPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
+ void *recordPtr, Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *const objv[])
{
Treeview *tv = (Treeview *)recordPtr;
TreeItem **items;
- int i;
+ Tcl_Size i;
if (objc != 3) {
Tcl_WrongNumArgs(interp, 2, objv, "item");
@@ -2676,6 +3247,7 @@ static int TreeviewDetachCommand(
DetachItem(items[i]);
}
+ tv->tree.rowPosNeedsUpdate = 1;
TtkRedisplayWidget(&tv->core);
ckfree(items);
return TCL_OK;
@@ -2694,11 +3266,11 @@ static int TreeviewDetachCommand(
*/
static int TreeviewDeleteCommand(
- void *recordPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
+ void *recordPtr, Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *const objv[])
{
Treeview *tv = (Treeview *)recordPtr;
TreeItem **items, *delq;
- int i;
+ Tcl_Size i;
int selChange = 0;
if (objc != 3) {
@@ -2726,9 +3298,15 @@ static int TreeviewDeleteCommand(
*/
delq = 0;
for (i = 0; items[i]; ++i) {
- if (items[i]->state & TTK_STATE_SELECTED) {
- selChange = 1;
- }
+ if (items[i]->state & TTK_STATE_SELECTED) {
+ selChange = 1;
+ } else if (items[i]->selObj != NULL) {
+ Tcl_Size length;
+ Tcl_ListObjLength(interp, items[i]->selObj, &length);
+ if (length > 0) {
+ selChange = 1;
+ }
+ }
delq = DeleteItems(items[i], delq);
}
@@ -2746,8 +3324,9 @@ static int TreeviewDeleteCommand(
ckfree(items);
if (selChange) {
- TtkSendVirtualEvent(tv->core.tkwin, "TreeviewSelect");
+ Tk_SendVirtualEvent(tv->core.tkwin, "TreeviewSelect", NULL);
}
+ tv->tree.rowPosNeedsUpdate = 1;
TtkRedisplayWidget(&tv->core);
return TCL_OK;
}
@@ -2756,7 +3335,7 @@ static int TreeviewDeleteCommand(
* Move $item to the specified $index in $parent's child list.
*/
static int TreeviewMoveCommand(
- void *recordPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
+ void *recordPtr, Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *const objv[])
{
Treeview *tv = (Treeview *)recordPtr;
TreeItem *item, *parent;
@@ -2809,6 +3388,7 @@ static int TreeviewMoveCommand(
DetachItem(item);
InsertItem(parent, sibling, item);
+ tv->tree.rowPosNeedsUpdate = 1;
TtkRedisplayWidget(&tv->core);
return TCL_OK;
}
@@ -2818,14 +3398,14 @@ static int TreeviewMoveCommand(
*/
static int TreeviewXViewCommand(
- void *recordPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
+ void *recordPtr, Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *const objv[])
{
Treeview *tv = (Treeview *)recordPtr;
return TtkScrollviewCommand(interp, objc, objv, tv->tree.xscrollHandle);
}
static int TreeviewYViewCommand(
- void *recordPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
+ void *recordPtr, Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *const objv[])
{
Treeview *tv = (Treeview *)recordPtr;
return TtkScrollviewCommand(interp, objc, objv, tv->tree.yscrollHandle);
@@ -2835,11 +3415,11 @@ static int TreeviewYViewCommand(
* Ensure that $item is visible.
*/
static int TreeviewSeeCommand(
- void *recordPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
+ void *recordPtr, Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *const objv[])
{
Treeview *tv = (Treeview *)recordPtr;
TreeItem *item, *parent;
- int rowNumber;
+ int scrollRow1, scrollRow2, visibleRows;
if (objc != 3) {
Tcl_WrongNumArgs(interp, 2, objv, "item");
@@ -2856,18 +3436,28 @@ static int TreeviewSeeCommand(
parent->openObj = unshareObj(parent->openObj);
Tcl_SetBooleanObj(parent->openObj, 1);
parent->state |= TTK_STATE_OPEN;
+ tv->tree.rowPosNeedsUpdate = 1;
TtkRedisplayWidget(&tv->core);
}
}
+ if (tv->tree.rowPosNeedsUpdate) {
+ UpdatePositionTree(tv);
+ }
/* Make sure item is visible:
*/
- rowNumber = RowNumber(tv, item);
- if (rowNumber < tv->tree.yscroll.first) {
- TtkScrollTo(tv->tree.yscrollHandle, rowNumber, 1);
- } else if (rowNumber >= tv->tree.yscroll.last) {
- TtkScrollTo(tv->tree.yscrollHandle,
- tv->tree.yscroll.first + (1+rowNumber - tv->tree.yscroll.last), 1);
+ if (item->rowPos < tv->tree.titleRows) {
+ return TCL_OK;
+ }
+ visibleRows = tv->tree.treeArea.height / tv->tree.rowHeight
+ - tv->tree.titleRows;
+ scrollRow1 = item->rowPos - tv->tree.titleRows;
+ scrollRow2 = scrollRow1 + item->height - 1;
+ if (scrollRow1 < tv->tree.yscroll.first || item->height > visibleRows) {
+ TtkScrollTo(tv->tree.yscrollHandle, scrollRow1, 1);
+ } else if (scrollRow2 >= tv->tree.yscroll.first + visibleRows) {
+ scrollRow1 = 1 + scrollRow2 - visibleRows;
+ TtkScrollTo(tv->tree.yscrollHandle, scrollRow1, 1);
}
return TCL_OK;
@@ -2881,11 +3471,11 @@ static int TreeviewSeeCommand(
* Set right edge of display column $column to x position $X
*/
static int TreeviewDragCommand(
- void *recordPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
+ void *recordPtr, Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *const objv[])
{
Treeview *tv = (Treeview *)recordPtr;
int left = tv->tree.treeArea.x - tv->tree.xscroll.first;
- int i = FirstColumn(tv);
+ Tcl_Size i = FirstColumn(tv);
TreeColumn *column;
int newx;
@@ -2903,6 +3493,10 @@ static int TreeviewDragCommand(
TreeColumn *c = tv->tree.displayColumns[i];
int right = left + c->width;
if (c == column) {
+ if (i < tv->tree.nTitleColumns) {
+ /* Unscrollable column, remove scroll shift */
+ right += tv->tree.xscroll.first;
+ }
DragColumn(tv, i, newx - right);
TtkRedisplayWidget(&tv->core);
return TCL_OK;
@@ -2917,7 +3511,7 @@ static int TreeviewDragCommand(
}
static int TreeviewDropCommand(
- void *recordPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
+ void *recordPtr, Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *const objv[])
{
Treeview *tv = (Treeview *)recordPtr;
@@ -2937,7 +3531,7 @@ static int TreeviewDropCommand(
/* + $tree focus ?item?
*/
static int TreeviewFocusCommand(
- void *recordPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
+ void *recordPtr, Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *const objv[])
{
Treeview *tv = (Treeview *)recordPtr;
@@ -2962,7 +3556,7 @@ static int TreeviewFocusCommand(
/* + $tree selection ?add|remove|set|toggle $items?
*/
static int TreeviewSelectionCommand(
- void *recordPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
+ void *recordPtr, Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *const objv[])
{
enum {
SELECTION_SET, SELECTION_ADD, SELECTION_REMOVE, SELECTION_TOGGLE
@@ -3041,7 +3635,252 @@ static int TreeviewSelectionCommand(
ckfree(items);
if (selChange) {
- TtkSendVirtualEvent(tv->core.tkwin, "TreeviewSelect");
+ Tk_SendVirtualEvent(tv->core.tkwin, "TreeviewSelect", NULL);
+ }
+ TtkRedisplayWidget(&tv->core);
+
+ return TCL_OK;
+}
+
+/* + SelObjChangeElement --
+ * Change an element in a cell selection list.
+ */
+static int SelObjChangeElement(
+ Treeview *tv, Tcl_Obj *listPtr, Tcl_Obj *elemPtr,
+ int add,
+ TCL_UNUSED(int) /*remove*/,
+ int toggle)
+{
+ Tcl_Size i, nElements;
+ int anyChange = 0;
+ TreeColumn *column, *elemColumn;
+ Tcl_Obj **elements;
+
+ elemColumn = FindColumn(NULL, tv, elemPtr);
+ Tcl_ListObjGetElements(NULL, listPtr, &nElements, &elements);
+ for (i = 0; i < nElements; i++) {
+ column = FindColumn(NULL, tv, elements[i]);
+ if (column == elemColumn) {
+ if (add) {
+ return anyChange;
+ }
+ Tcl_ListObjReplace(NULL, listPtr, i, 1, 0, NULL);
+ anyChange = 1;
+ return anyChange;
+ }
+ }
+ if (add || toggle) {
+ Tcl_ListObjAppendElement(NULL, listPtr, elemColumn->idObj);
+ anyChange = 1;
+ }
+ return anyChange;
+}
+
+/* + $tree cellselection ?add|remove|set|toggle $items?
+ */
+static int CellSelectionRange(
+ Tcl_Interp *interp, Treeview *tv, Tcl_Obj *fromCell, Tcl_Obj *toCell,
+ int add, int remove, int toggle)
+{
+ TreeCell cellFrom, cellTo;
+ TreeItem *item;
+ Tcl_Obj *columns, **elements;
+ int colno, fromNo, toNo, anyChange = 0;
+ Tcl_Size i, nElements;
+ int set = !(add || remove || toggle);
+
+ if (GetCellFromObj(interp, tv, fromCell, 1, &fromNo, &cellFrom)
+ != TCL_OK) {
+ return TCL_ERROR;
+ }
+ if (GetCellFromObj(interp, tv, toCell, 1, &toNo, &cellTo)
+ != TCL_OK) {
+ return TCL_ERROR;
+ }
+
+ /* Correct order.
+ */
+ if (fromNo > toNo) {
+ colno = fromNo;
+ fromNo = toNo;
+ toNo = colno;
+ }
+
+ /* Make a list of columns in this rectangle.
+ */
+ columns = Tcl_NewListObj(0, 0);
+ Tcl_IncrRefCount(columns);
+ for (colno = fromNo; colno <= toNo; colno++) {
+ Tcl_ListObjAppendElement(NULL, columns,
+ tv->tree.displayColumns[colno]->idObj);
+ }
+
+ /* Set is the only operation that affects items outside its rectangle.
+ * Start with clearing out.
+ */
+ if (set) {
+ anyChange = CellSelectionClear(tv);
+ }
+
+ /* Correct order.
+ */
+ if (tv->tree.rowPosNeedsUpdate) {
+ UpdatePositionTree(tv);
+ }
+ if (cellFrom.item->itemPos > cellTo.item->itemPos) {
+ item = cellFrom.item;
+ cellFrom.item = cellTo.item;
+ cellTo.item = item;
+ }
+
+ /* Go through all items in this rectangle.
+ */
+ for (item = cellFrom.item; item; item = NextPreorder(item)) {
+ if (item->selObj != NULL) {
+ item->selObj = unshareObj(item->selObj);
+
+ Tcl_ListObjGetElements(NULL, columns, &nElements, &elements);
+ for (i = 0; i < nElements; ++i) {
+ anyChange |= SelObjChangeElement(tv, item->selObj, elements[i],
+ add, remove, toggle);
+ }
+ } else {
+ /* Set, add and toggle do the same thing when empty before.
+ */
+ if (!remove) {
+ item->selObj = columns;
+ Tcl_IncrRefCount(item->selObj);
+ anyChange = 1;
+ }
+ }
+ if (item == cellTo.item) {
+ break;
+ }
+ }
+
+ Tcl_DecrRefCount(columns);
+
+ if (anyChange) {
+ Tk_SendVirtualEvent(tv->core.tkwin, "TreeviewSelect", NULL);
+ }
+ TtkRedisplayWidget(&tv->core);
+ return TCL_OK;
+}
+
+/* + $tree cellselection ?add|remove|set|toggle $items?
+ */
+static int TreeviewCellSelectionCommand(
+ void *recordPtr, Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *const objv[])
+{
+ enum {
+ SELECTION_SET, SELECTION_ADD, SELECTION_REMOVE, SELECTION_TOGGLE
+ };
+ static const char *const selopStrings[] = {
+ "set", "add", "remove", "toggle", NULL
+ };
+
+ Treeview *tv = (Treeview *)recordPtr;
+ int selop, anyChange = 0;
+ Tcl_Size i, nCells;
+ TreeCell *cells;
+ TreeItem *item;
+
+ if (objc == 2) {
+ Tcl_Obj *result = Tcl_NewListObj(0,0);
+ for (item = tv->tree.root->children; item; item = NextPreorder(item)) {
+ if (item->selObj != NULL) {
+ Tcl_Size n, elemc;
+ Tcl_Obj **elemv;
+
+ Tcl_ListObjGetElements(interp, item->selObj, &n, &elemv);
+ elemc = n;
+ for (i = 0; i < elemc; ++i) {
+ Tcl_Obj *elem[2];
+ elem[0] = ItemID(tv, item);
+ elem[1] = elemv[i];
+ Tcl_ListObjAppendElement(NULL, result,
+ Tcl_NewListObj(2, elem));
+ }
+ }
+ }
+ Tcl_SetObjResult(interp, result);
+ return TCL_OK;
+ }
+
+ if (objc < 4 || objc > 5) {
+ Tcl_WrongNumArgs(interp, 2, objv, "?add|remove|set|toggle arg...?");
+ return TCL_ERROR;
+ }
+
+ if (Tcl_GetIndexFromObjStruct(interp, objv[2], selopStrings,
+ sizeof(char *), "cellselection operation", 0, &selop) != TCL_OK) {
+ return TCL_ERROR;
+ }
+
+ if (objc == 5) {
+ switch (selop)
+ {
+ case SELECTION_SET:
+ return CellSelectionRange(interp, tv, objv[3], objv[4], 0, 0, 0);
+ case SELECTION_ADD:
+ return CellSelectionRange(interp, tv, objv[3], objv[4], 1, 0, 0);
+ case SELECTION_REMOVE:
+ return CellSelectionRange(interp, tv, objv[3], objv[4], 0, 1, 0);
+ case SELECTION_TOGGLE:
+ return CellSelectionRange(interp, tv, objv[3], objv[4], 0, 0, 1);
+ }
+ }
+
+ cells = GetCellListFromObj(interp, tv, objv[3], &nCells);
+ if (cells == NULL) {
+ return TCL_ERROR;
+ }
+
+ switch (selop)
+ {
+ case SELECTION_SET:
+ anyChange = CellSelectionClear(tv);
+ /*FALLTHRU*/
+ case SELECTION_ADD:
+ for (i = 0; i < nCells; i++) {
+ item = cells[i].item;
+ if (item->selObj == NULL) {
+ item->selObj = Tcl_NewListObj(0, 0);
+ Tcl_IncrRefCount(item->selObj);
+ }
+ item->selObj = unshareObj(item->selObj);
+ anyChange |= SelObjChangeElement(tv, item->selObj,
+ cells[i].colObj, 1, 0, 0);
+ }
+ break;
+ case SELECTION_REMOVE:
+ for (i = 0; i < nCells; i++) {
+ item = cells[i].item;
+ if (item->selObj == NULL) {
+ continue;
+ }
+ item->selObj = unshareObj(item->selObj);
+ anyChange |= SelObjChangeElement(tv, item->selObj,
+ cells[i].colObj, 0, 1, 0);
+ }
+ break;
+ case SELECTION_TOGGLE:
+ for (i = 0; i < nCells; i++) {
+ item = cells[i].item;
+ if (item->selObj == NULL) {
+ item->selObj = Tcl_NewListObj(0, 0);
+ Tcl_IncrRefCount(item->selObj);
+ }
+ item->selObj = unshareObj(item->selObj);
+ anyChange = SelObjChangeElement(tv, item->selObj,
+ cells[i].colObj, 0, 0, 1);
+ }
+ break;
+ }
+
+ ckfree(cells);
+ if (anyChange) {
+ Tk_SendVirtualEvent(tv->core.tkwin, "TreeviewSelect", NULL);
}
TtkRedisplayWidget(&tv->core);
@@ -3055,7 +3894,7 @@ static int TreeviewSelectionCommand(
/* + $tv tag bind $tag ?$sequence ?$script??
*/
static int TreeviewTagBindCommand(
- void *recordPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
+ void *recordPtr, Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *const objv[])
{
Treeview *tv = (Treeview *)recordPtr;
Ttk_TagTable tagTable = tv->tree.tagTable;
@@ -3108,7 +3947,7 @@ static int TreeviewTagBindCommand(
/* + $tv tag configure $tag ?-option ?value -option value...??
*/
static int TreeviewTagConfigureCommand(
- void *recordPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
+ void *recordPtr, Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *const objv[])
{
Treeview *tv = (Treeview *)recordPtr;
Ttk_TagTable tagTable = tv->tree.tagTable;
@@ -3136,10 +3975,40 @@ static int TreeviewTagConfigureCommand(
return Ttk_ConfigureTag(interp, tagTable, tag, objc - 4, objv + 4);
}
+/* + $tv tag delete $tag
+ */
+static int TreeviewTagDeleteCommand(
+ void *recordPtr, Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *const objv[])
+{
+ Treeview *tv = (Treeview *)recordPtr;
+ Ttk_TagTable tagTable = tv->tree.tagTable;
+ TreeItem *item = tv->tree.root;
+ Ttk_Tag tag;
+
+ if (objc != 4) {
+ Tcl_WrongNumArgs(interp, 3, objv, "tagName");
+ return TCL_ERROR;
+ }
+
+ tag = Ttk_GetTagFromObj(tagTable, objv[3]);
+ /* remove the tag from all cells and items */
+ while (item) {
+ RemoveTagFromCellsAtItem(item, tag);
+ RemoveTag(item, tag);
+ item = NextPreorder(item);
+ }
+ /* then remove the tag from the tag table */
+ Tk_DeleteAllBindings(tv->tree.bindingTable, tag);
+ Ttk_DeleteTagFromTable(tagTable, tag);
+ TtkRedisplayWidget(&tv->core);
+
+ return TCL_OK;
+}
+
/* + $tv tag has $tag ?$item?
*/
static int TreeviewTagHasCommand(
- void *recordPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
+ void *recordPtr, Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *const objv[])
{
Treeview *tv = (Treeview *)recordPtr;
@@ -3172,10 +4041,72 @@ static int TreeviewTagHasCommand(
}
}
+/* + $tv tag cell has $tag ?$cell?
+ */
+static int TreeviewCtagHasCommand(
+ void *recordPtr, Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *const objv[])
+{
+ Treeview *tv = (Treeview *)recordPtr;
+ TreeCell cell;
+ Tcl_Size i, columnNumber;
+
+ if (objc == 5) { /* Return list of all cells with tag */
+ Ttk_Tag tag = Ttk_GetTagFromObj(tv->tree.tagTable, objv[4]);
+ TreeItem *item = tv->tree.root;
+ Tcl_Obj *result = Tcl_NewListObj(0,0);
+
+ while (item) {
+ for (i = 0; i < item->nTagSets && i <= tv->tree.nColumns; ++i) {
+ if (item->cellTagSets[i] != NULL) {
+ if (Ttk_TagSetContains(item->cellTagSets[i], tag)) {
+ Tcl_Obj *elem[2];
+ elem[0] = ItemID(tv, item);
+ if (i == 0) {
+ elem[1] = tv->tree.column0.idObj;
+ } else {
+ elem[1] = tv->tree.columns[i-1].idObj;
+ }
+ Tcl_ListObjAppendElement(NULL, result,
+ Tcl_NewListObj(2, elem));
+ }
+ }
+ }
+ item = NextPreorder(item);
+ }
+
+ Tcl_SetObjResult(interp, result);
+ return TCL_OK;
+ } else if (objc == 6) { /* Test if cell has specified tag */
+ Ttk_Tag tag = Ttk_GetTagFromObj(tv->tree.tagTable, objv[4]);
+ int result = 0;
+ if (GetCellFromObj(interp, tv, objv[5], 0, NULL, &cell) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ if (cell.column == &tv->tree.column0) {
+ columnNumber = 0;
+ } else {
+ columnNumber = cell.column - tv->tree.columns + 1;
+ }
+ if (columnNumber < cell.item->nTagSets) {
+ if (cell.item->cellTagSets[columnNumber] != NULL) {
+ result = Ttk_TagSetContains(
+ cell.item->cellTagSets[columnNumber],
+ tag);
+ }
+ }
+
+ Tcl_SetObjResult(interp, Tcl_NewWideIntObj(result));
+ return TCL_OK;
+ } else {
+ Tcl_WrongNumArgs(interp, 4, objv, "tagName ?cell?");
+ return TCL_ERROR;
+ }
+}
+
/* + $tv tag names
*/
static int TreeviewTagNamesCommand(
- void *recordPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
+ void *recordPtr, Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *const objv[])
{
Treeview *tv = (Treeview *)recordPtr;
@@ -3199,12 +4130,12 @@ static void AddTag(TreeItem *item, Ttk_Tag tag)
}
static int TreeviewTagAddCommand(
- void *recordPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
+ void *recordPtr, Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *const objv[])
{
Treeview *tv = (Treeview *)recordPtr;
Ttk_Tag tag;
TreeItem **items;
- int i;
+ Tcl_Size i;
if (objc != 5) {
Tcl_WrongNumArgs(interp, 3, objv, "tagName items");
@@ -3221,12 +4152,77 @@ static int TreeviewTagAddCommand(
for (i = 0; items[i]; ++i) {
AddTag(items[i], tag);
}
+ ckfree(items);
TtkRedisplayWidget(&tv->core);
return TCL_OK;
}
+/* Make sure tagset at column is allocated and initialised */
+static void AllocCellTagSets(Treeview *tv, TreeItem *item, Tcl_Size columnNumber)
+{
+ Tcl_Size i, newSize = MAX(columnNumber + 1, tv->tree.nColumns + 1);
+ if (item->nTagSets < newSize) {
+ if (item->cellTagSets == NULL) {
+ item->cellTagSets = (Ttk_TagSet *)
+ ckalloc(sizeof(Ttk_TagSet)*newSize);
+ } else {
+ item->cellTagSets = (Ttk_TagSet *)
+ ckrealloc(item->cellTagSets, sizeof(Ttk_TagSet) * newSize);
+ }
+ for (i = item->nTagSets; i < newSize; i++) {
+ item->cellTagSets[i] = NULL;
+ }
+ item->nTagSets = newSize;
+ }
+
+ if (item->cellTagSets[columnNumber] == NULL) {
+ item->cellTagSets[columnNumber] =
+ Ttk_GetTagSetFromObj(NULL, tv->tree.tagTable, NULL);
+ }
+}
+
+/* + $tv tag cell add $tag $cells
+ */
+static int TreeviewCtagAddCommand(
+ void *recordPtr, Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *const objv[])
+{
+ Treeview *tv = (Treeview *)recordPtr;
+ Ttk_Tag tag;
+ TreeCell *cells;
+ TreeItem *item;
+ Tcl_Size i, nCells, columnNumber;
+
+ if (objc != 6) {
+ Tcl_WrongNumArgs(interp, 4, objv, "tagName cells");
+ return TCL_ERROR;
+ }
+
+ cells = GetCellListFromObj(interp, tv, objv[5], &nCells);
+ if (cells == NULL) {
+ return TCL_ERROR;
+ }
+
+ tag = Ttk_GetTagFromObj(tv->tree.tagTable, objv[4]);
+
+ for (i = 0; i < nCells; i++) {
+ if (cells[i].column == &tv->tree.column0) {
+ columnNumber = 0;
+ } else {
+ columnNumber = cells[i].column - tv->tree.columns + 1;
+ }
+ item = cells[i].item;
+ AllocCellTagSets(tv, item, columnNumber);
+ Ttk_TagSetAdd(item->cellTagSets[columnNumber], tag);
+ }
+
+ ckfree(cells);
+ TtkRedisplayWidget(&tv->core);
+
+ return TCL_OK;
+}
+
/* + $tv tag remove $tag ?$items?
*/
static void RemoveTag(TreeItem *item, Ttk_Tag tag)
@@ -3238,14 +4234,27 @@ static void RemoveTag(TreeItem *item, Ttk_Tag tag)
}
}
+/* Remove tag from all cells at row 'item'
+ */
+static void RemoveTagFromCellsAtItem(TreeItem *item, Ttk_Tag tag)
+{
+ Tcl_Size i;
+
+ for (i = 0; i < item->nTagSets; i++) {
+ if (item->cellTagSets[i] != NULL) {
+ Ttk_TagSetRemove(item->cellTagSets[i], tag);
+ }
+ }
+}
+
static int TreeviewTagRemoveCommand(
- void *recordPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
+ void *recordPtr, Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *const objv[])
{
Treeview *tv = (Treeview *)recordPtr;
Ttk_Tag tag;
- if (objc < 4) {
- Tcl_WrongNumArgs(interp, 3, objv, "tagName items");
+ if (objc < 4 || objc > 5) {
+ Tcl_WrongNumArgs(interp, 3, objv, "tagName ?items?");
return TCL_ERROR;
}
@@ -3261,6 +4270,7 @@ static int TreeviewTagRemoveCommand(
for (i = 0; items[i]; ++i) {
RemoveTag(items[i], tag);
}
+ ckfree(items);
} else if (objc == 4) {
TreeItem *item = tv->tree.root;
while (item) {
@@ -3274,10 +4284,67 @@ static int TreeviewTagRemoveCommand(
return TCL_OK;
}
+/* + $tv tag cell remove $tag ?$cells?
+ */
+static int TreeviewCtagRemoveCommand(
+ void *recordPtr, Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *const objv[])
+{
+ Treeview *tv = (Treeview *)recordPtr;
+ Ttk_Tag tag;
+ TreeCell *cells;
+ TreeItem *item;
+ Tcl_Size i, nCells, columnNumber;
+
+ if (objc < 5 || objc > 6) {
+ Tcl_WrongNumArgs(interp, 4, objv, "tagName ?cells?");
+ return TCL_ERROR;
+ }
+
+ tag = Ttk_GetTagFromObj(tv->tree.tagTable, objv[4]);
+
+ if (objc == 6) {
+ cells = GetCellListFromObj(interp, tv, objv[5], &nCells);
+ if (cells == NULL) {
+ return TCL_ERROR;
+ }
+
+ for (i = 0; i < nCells; i++) {
+ if (cells[i].column == &tv->tree.column0) {
+ columnNumber = 0;
+ } else {
+ columnNumber = cells[i].column - tv->tree.columns + 1;
+ }
+ item = cells[i].item;
+ AllocCellTagSets(tv, item, columnNumber);
+ Ttk_TagSetRemove(item->cellTagSets[columnNumber], tag);
+ }
+ ckfree(cells);
+ } else {
+ item = tv->tree.root;
+ while (item) {
+ RemoveTagFromCellsAtItem(item, tag);
+ item = NextPreorder(item);
+ }
+ }
+
+ TtkRedisplayWidget(&tv->core);
+
+ return TCL_OK;
+}
+
+static const Ttk_Ensemble TreeviewCtagCommands[] = {
+ { "add", TreeviewCtagAddCommand,0 },
+ { "has", TreeviewCtagHasCommand,0 },
+ { "remove", TreeviewCtagRemoveCommand,0 },
+ { 0,0,0 }
+};
+
static const Ttk_Ensemble TreeviewTagCommands[] = {
{ "add", TreeviewTagAddCommand,0 },
{ "bind", TreeviewTagBindCommand,0 },
+ { "cell", 0,TreeviewCtagCommands },
{ "configure", TreeviewTagConfigureCommand,0 },
+ { "delete", TreeviewTagDeleteCommand,0 },
{ "has", TreeviewTagHasCommand,0 },
{ "names", TreeviewTagNamesCommand,0 },
{ "remove", TreeviewTagRemoveCommand,0 },
@@ -3289,6 +4356,7 @@ static const Ttk_Ensemble TreeviewTagCommands[] = {
*/
static const Ttk_Ensemble TreeviewCommands[] = {
{ "bbox", TreeviewBBoxCommand,0 },
+ { "cellselection", TreeviewCellSelectionCommand,0 },
{ "children", TreeviewChildrenCommand,0 },
{ "cget", TtkWidgetCgetCommand,0 },
{ "column", TreeviewColumnCommand,0 },
@@ -3302,17 +4370,18 @@ static const Ttk_Ensemble TreeviewCommands[] = {
{ "heading", TreeviewHeadingCommand,0 },
{ "identify", TreeviewIdentifyCommand,0 },
{ "index", TreeviewIndexCommand,0 },
- { "instate", TtkWidgetInstateCommand,0 },
{ "insert", TreeviewInsertCommand,0 },
+ { "instate", TtkWidgetInstateCommand,0 },
{ "item", TreeviewItemCommand,0 },
{ "move", TreeviewMoveCommand,0 },
{ "next", TreeviewNextCommand,0 },
{ "parent", TreeviewParentCommand,0 },
{ "prev", TreeviewPrevCommand,0 },
{ "see", TreeviewSeeCommand,0 },
- { "selection" , TreeviewSelectionCommand,0 },
+ { "selection", TreeviewSelectionCommand,0 },
{ "set", TreeviewSetCommand,0 },
{ "state", TtkWidgetStateCommand,0 },
+ { "style", TtkWidgetStyleCommand,0 },
{ "tag", 0,TreeviewTagCommands },
{ "xview", TreeviewXViewCommand,0 },
{ "yview", TreeviewYViewCommand,0 },
@@ -3323,7 +4392,7 @@ static const Ttk_Ensemble TreeviewCommands[] = {
* +++ Widget definition.
*/
-static WidgetSpec TreeviewWidgetSpec = {
+static const WidgetSpec TreeviewWidgetSpec = {
"Treeview", /* className */
sizeof(Treeview), /* recordSize */
TreeviewOptionSpecs, /* optionSpecs */
@@ -3357,6 +4426,7 @@ TTK_LAYOUT("Item",
TTK_LAYOUT("Cell",
TTK_GROUP("Treedata.padding", TTK_FILL_BOTH,
+ TTK_NODE("Treeitem.image", TTK_PACK_LEFT)
TTK_NODE("Treeitem.text", TTK_FILL_BOTH)))
TTK_LAYOUT("Heading",
@@ -3369,6 +4439,9 @@ TTK_LAYOUT("Heading",
TTK_LAYOUT("Row",
TTK_NODE("Treeitem.row", TTK_FILL_BOTH))
+TTK_LAYOUT("Separator",
+ TTK_NODE("Treeitem.separator", TTK_FILL_BOTH))
+
TTK_END_LAYOUT_TABLE
/*------------------------------------------------------------------------
@@ -3381,13 +4454,13 @@ typedef struct {
Tcl_Obj *marginsObj;
} TreeitemIndicator;
-static Ttk_ElementOptionSpec TreeitemIndicatorOptions[] = {
+static const Ttk_ElementOptionSpec TreeitemIndicatorOptions[] = {
{ "-foreground", TK_OPTION_COLOR,
- Tk_Offset(TreeitemIndicator,colorObj), DEFAULT_FOREGROUND },
+ offsetof(TreeitemIndicator,colorObj), DEFAULT_FOREGROUND },
{ "-indicatorsize", TK_OPTION_PIXELS,
- Tk_Offset(TreeitemIndicator,sizeObj), "12" },
+ offsetof(TreeitemIndicator,sizeObj), "12" },
{ "-indicatormargins", TK_OPTION_STRING,
- Tk_Offset(TreeitemIndicator,marginsObj), "2 2 4 2" },
+ offsetof(TreeitemIndicator,marginsObj), "2 2 4 2" },
{ NULL, TK_OPTION_BOOLEAN, 0, NULL }
};
@@ -3441,7 +4514,7 @@ static void TreeitemIndicatorDraw(
Tk_FreeGC(Tk_Display(tkwin), gc);
}
-static Ttk_ElementSpec TreeitemIndicatorElementSpec = {
+static const Ttk_ElementSpec TreeitemIndicatorElementSpec = {
TK_STYLE_VERSION_2,
sizeof(TreeitemIndicator),
TreeitemIndicatorOptions,
@@ -3458,11 +4531,11 @@ typedef struct {
Tcl_Obj *rowNumberObj;
} RowElement;
-static Ttk_ElementOptionSpec RowElementOptions[] = {
+static const Ttk_ElementOptionSpec RowElementOptions[] = {
{ "-background", TK_OPTION_COLOR,
- Tk_Offset(RowElement,backgroundObj), DEFAULT_BACKGROUND },
+ offsetof(RowElement,backgroundObj), DEFAULT_BACKGROUND },
{ "-rownumber", TK_OPTION_INT,
- Tk_Offset(RowElement,rowNumberObj), "0" },
+ offsetof(RowElement,rowNumberObj), "0" },
{ NULL, TK_OPTION_BOOLEAN, 0, NULL }
};
@@ -3482,7 +4555,7 @@ static void RowElementDraw(
b.x, b.y, b.width, b.height);
}
-static Ttk_ElementSpec RowElementSpec = {
+static const Ttk_ElementSpec RowElementSpec = {
TK_STYLE_VERSION_2,
sizeof(RowElement),
RowElementOptions,
@@ -3504,6 +4577,7 @@ TtkTreeview_Init(Tcl_Interp *interp)
Ttk_RegisterElement(interp, theme, "Treeitem.indicator",
&TreeitemIndicatorElementSpec, 0);
Ttk_RegisterElement(interp, theme, "Treeitem.row", &RowElementSpec, 0);
+ Ttk_RegisterElement(interp, theme, "Treeitem.separator", &RowElementSpec, 0);
Ttk_RegisterElement(interp, theme, "Treeheading.cell", &RowElementSpec, 0);
Ttk_RegisterElement(interp, theme, "treearea", &ttkNullElementSpec, 0);