summaryrefslogtreecommitdiffstats
path: root/generic/ttk/ttkTreeview.c
diff options
context:
space:
mode:
authorjenglish <jenglish@flightlab.com>2008-05-23 20:20:05 (GMT)
committerjenglish <jenglish@flightlab.com>2008-05-23 20:20:05 (GMT)
commitee1814c0cdbcfe9807b18e2b2732c299789897a3 (patch)
tree38468a3e3f80fe6a337d7e5bef1503a0780d1797 /generic/ttk/ttkTreeview.c
parentc2ee900569916fac1b939549e153c9344dca8c0a (diff)
downloadtk-ee1814c0cdbcfe9807b18e2b2732c299789897a3.zip
tk-ee1814c0cdbcfe9807b18e2b2732c299789897a3.tar.gz
tk-ee1814c0cdbcfe9807b18e2b2732c299789897a3.tar.bz2
Batch of ttk::treeview enhancements:
+ Added [$tv identify region], [$tv identify element], and [$tv identify item] subcommands. + Simplified bindings. + Added [$tv tag has] subcommand. + Tag-related display improvements: setting a tag -background or -foreground no longer overrides selection feedback. + Don't need separate 'Item', 'Cell', and 'Row' style settings anymore, only the base "Treeview" style is used.
Diffstat (limited to 'generic/ttk/ttkTreeview.c')
-rw-r--r--generic/ttk/ttkTreeview.c591
1 files changed, 354 insertions, 237 deletions
diff --git a/generic/ttk/ttkTreeview.c b/generic/ttk/ttkTreeview.c
index 95c9a99..ffe1351 100644
--- a/generic/ttk/ttkTreeview.c
+++ b/generic/ttk/ttkTreeview.c
@@ -1,4 +1,4 @@
-/* $Id: ttkTreeview.c,v 1.24 2008/04/27 22:41:12 dkf Exp $
+/* $Id: ttkTreeview.c,v 1.25 2008/05/23 20:20:05 jenglish Exp $
* Copyright (c) 2004, Joe English
*
* ttk::treeview widget implementation.
@@ -33,8 +33,7 @@ static const int HALO = 4; /* separator */
*/
typedef struct TreeItemRec TreeItem;
-struct TreeItemRec
-{
+struct TreeItemRec {
Tcl_HashEntry *entryPtr; /* Back-pointer to hash table entry */
TreeItem *parent; /* Parent item */
TreeItem *children; /* Linked list of child items */
@@ -50,16 +49,24 @@ struct TreeItemRec
Tcl_Obj *valuesObj;
Tcl_Obj *openObj;
Tcl_Obj *tagsObj;
+
+ /*
+ * Derived resources:
+ */
+ Ttk_TagSet tagset;
+ Ttk_ImageSpec *imagespec;
};
-static Tk_OptionSpec ItemOptionSpecs[] =
-{
+#define ITEM_OPTION_TAGS_CHANGED 0x100
+#define ITEM_OPTION_IMAGE_CHANGED 0x200
+
+static Tk_OptionSpec ItemOptionSpecs[] = {
{TK_OPTION_STRING, "-text", "text", "Text",
"", Tk_Offset(TreeItem,textObj), -1,
0,0,0 },
{TK_OPTION_STRING, "-image", "image", "Image",
NULL, Tk_Offset(TreeItem,imageObj), -1,
- TK_OPTION_NULL_OK,0,0 },
+ TK_OPTION_NULL_OK,0,ITEM_OPTION_IMAGE_CHANGED },
{TK_OPTION_STRING, "-values", "values", "Values",
NULL, Tk_Offset(TreeItem,valuesObj), -1,
TK_OPTION_NULL_OK,0,0 },
@@ -68,7 +75,7 @@ static Tk_OptionSpec ItemOptionSpecs[] =
0,0,0 },
{TK_OPTION_STRING, "-tags", "tags", "Tags",
NULL, Tk_Offset(TreeItem,tagsObj), -1,
- TK_OPTION_NULL_OK,0,0 },
+ TK_OPTION_NULL_OK,0,ITEM_OPTION_TAGS_CHANGED },
{TK_OPTION_END, 0,0,0, NULL, -1,-1, 0,0,0}
};
@@ -90,6 +97,9 @@ static TreeItem *NewItem(void)
item->openObj = NULL;
item->tagsObj = NULL;
+ item->tagset = NULL;
+ item->imagespec = NULL;
+
return item;
}
@@ -103,6 +113,10 @@ static void FreeItem(TreeItem *item)
if (item->valuesObj) { Tcl_DecrRefCount(item->valuesObj); }
if (item->openObj) { Tcl_DecrRefCount(item->openObj); }
if (item->tagsObj) { Tcl_DecrRefCount(item->tagsObj); }
+
+ if (item->tagset) { Ttk_FreeTagSet(item->tagset); }
+ if (item->imagespec) { TtkFreeImageSpec(item->imagespec); }
+
ckfree((ClientData)item);
}
@@ -168,14 +182,13 @@ static TreeItem *NextPreorder(TreeItem *item)
typedef struct {
Tcl_Obj *textObj; /* taken from item / data cell */
Tcl_Obj *imageObj; /* taken from item */
- Tcl_Obj *anchorObj; /* from column */
+ Tcl_Obj *anchorObj; /* from column <<NOTE-ANCHOR>> */
Tcl_Obj *backgroundObj; /* remainder from tag */
Tcl_Obj *foregroundObj;
Tcl_Obj *fontObj;
} DisplayItem;
-static Tk_OptionSpec TagOptionSpecs[] =
-{
+static Tk_OptionSpec TagOptionSpecs[] = {
{TK_OPTION_STRING, "-text", "text", "Text",
NULL, Tk_Offset(DisplayItem,textObj), -1,
TK_OPTION_NULL_OK,0,0 },
@@ -184,14 +197,14 @@ static Tk_OptionSpec TagOptionSpecs[] =
TK_OPTION_NULL_OK,0,0 },
{TK_OPTION_ANCHOR, "-anchor", "anchor", "Anchor",
NULL, Tk_Offset(DisplayItem,anchorObj), -1,
- TK_OPTION_NULL_OK, 0, GEOMETRY_CHANGED},
- {TK_OPTION_STRING, "-background", "windowColor", "WindowColor", /*SB:COLOR*/
+ TK_OPTION_NULL_OK, 0, GEOMETRY_CHANGED}, /* <<NOTE-ANCHOR>> */
+ {TK_OPTION_COLOR, "-background", "windowColor", "WindowColor",
NULL, Tk_Offset(DisplayItem,backgroundObj), -1,
TK_OPTION_NULL_OK,0,0 },
- {TK_OPTION_STRING, "-foreground", "textColor", "TextColor", /*SB:COLOR*/
+ {TK_OPTION_COLOR, "-foreground", "textColor", "TextColor",
NULL, Tk_Offset(DisplayItem,foregroundObj), -1,
TK_OPTION_NULL_OK,0,0 },
- {TK_OPTION_STRING, "-font", "font", "Font", /* SB:FONT */
+ {TK_OPTION_FONT, "-font", "font", "Font",
NULL, Tk_Offset(DisplayItem,fontObj), -1,
TK_OPTION_NULL_OK,0,GEOMETRY_CHANGED },
@@ -211,7 +224,7 @@ typedef struct {
int stretch; /* Should column stretch while resizing? */
Tcl_Obj *idObj; /* Column identifier, from -columns option */
- Tcl_Obj *anchorObj; /* -anchor for cell data */
+ Tcl_Obj *anchorObj; /* -anchor for cell data <<NOTE-ANCHOR>> */
/* Column heading data:
*/
@@ -259,8 +272,7 @@ static void FreeColumn(TreeColumn *column)
/* Don't touch column->data, it's scratch storage */
}
-static Tk_OptionSpec ColumnOptionSpecs[] =
-{
+static Tk_OptionSpec ColumnOptionSpecs[] = {
{TK_OPTION_INT, "-width", "width", "Width",
DEF_COLWIDTH, -1, Tk_Offset(TreeColumn,width),
0,0,GEOMETRY_CHANGED },
@@ -271,7 +283,7 @@ static Tk_OptionSpec ColumnOptionSpecs[] =
"1", -1, Tk_Offset(TreeColumn,stretch),
0,0,0 },
{TK_OPTION_ANCHOR, "-anchor", "anchor", "Anchor",
- "w", Tk_Offset(TreeColumn,anchorObj), -1,
+ "w", Tk_Offset(TreeColumn,anchorObj), -1, /* <<NOTE-ANCHOR>> */
0,0,0 },
{TK_OPTION_STRING, "-id", "id", "ID",
NULL, Tk_Offset(TreeColumn,idObj), -1,
@@ -279,8 +291,7 @@ static Tk_OptionSpec ColumnOptionSpecs[] =
{TK_OPTION_END, 0,0,0, NULL, -1,-1, 0,0,0}
};
-static Tk_OptionSpec HeadingOptionSpecs[] =
-{
+static Tk_OptionSpec HeadingOptionSpecs[] = {
{TK_OPTION_STRING, "-text", "text", "Text",
"", Tk_Offset(TreeColumn,headingObj), -1,
0,0,0 },
@@ -349,8 +360,7 @@ static int GetEnumSetFromObj(
* headingHeight: [layout]
* rowHeight, indent: style
*/
-typedef struct
-{
+typedef struct {
/* Resources acquired at initialization-time:
*/
Tk_OptionTable itemOptionTable;
@@ -425,8 +435,7 @@ typedef struct {
static const char *SelectModeStrings[] = { "none", "browse", "extended", NULL };
-static Tk_OptionSpec TreeviewOptionSpecs[] =
-{
+static Tk_OptionSpec TreeviewOptionSpecs[] = {
WIDGET_TAKES_FOCUS,
{TK_OPTION_STRING, "-columns", "columns", "Columns",
@@ -887,14 +896,14 @@ static int DistributeWidth(Treeview *tv, int n)
/* + ResizeColumns --
* Recompute column widths based on available width.
- * Pick up slack first;
+ * Pick up slack first;
* Distribute the remainder evenly across stretchable columns;
* If any is still left over due to minwidth constraints, shove left.
*/
static void ResizeColumns(Treeview *tv, int newWidth)
{
int delta = newWidth - (TreeWidth(tv) + tv->tree.slack);
- DepositSlack(tv,
+ DepositSlack(tv,
ShoveLeft(tv, tv->tree.nDisplayColumns - 1,
DistributeWidth(tv, PickupSlack(tv, delta))));
}
@@ -915,7 +924,7 @@ static void DragColumn(Treeview *tv, int i, int delta)
* +++ Event handlers.
*/
-static TreeItem *IdentifyItem(Treeview *tv,int y,Ttk_Box *itemPos); /*forward*/
+static TreeItem *IdentifyItem(Treeview *tv, int y); /*forward*/
static const unsigned int TreeviewBindEventMask =
KeyPressMask|KeyReleaseMask
@@ -928,14 +937,11 @@ static void TreeviewBindEventProc(void *clientData, XEvent *event)
{
Treeview *tv = clientData;
TreeItem *item = NULL;
- Ttk_Box unused;
- void *taglist;
- int nTags;
+ Ttk_TagSet tagset;
/*
* Figure out where to deliver the event.
*/
-
switch (event->type)
{
case KeyPress:
@@ -945,10 +951,10 @@ static void TreeviewBindEventProc(void *clientData, XEvent *event)
break;
case ButtonPress:
case ButtonRelease:
- item = IdentifyItem(tv, event->xbutton.y, &unused);
+ item = IdentifyItem(tv, event->xbutton.y);
break;
case MotionNotify:
- item = IdentifyItem(tv, event->xmotion.y, &unused);
+ item = IdentifyItem(tv, event->xmotion.y);
break;
default:
break;
@@ -958,18 +964,21 @@ static void TreeviewBindEventProc(void *clientData, XEvent *event)
return;
}
- /* ASSERT: Ttk_GetTagListFromObj returns TCL_OK. */
- Ttk_GetTagListFromObj(NULL, tv->tree.tagTable, item->tagsObj,
- &nTags, &taglist);
+ /* ASSERT: Ttk_GetTagSetFromObj succeeds.
+ * NB: must use a local copy of the tagset,
+ * in case a binding script stomps on -tags.
+ */
+ tagset = Ttk_GetTagSetFromObj(NULL, tv->tree.tagTable, item->tagsObj);
/*
* Fire binding:
*/
Tcl_Preserve(clientData);
- Tk_BindEvent(tv->tree.bindingTable, event, tv->core.tkwin, nTags, taglist);
+ Tk_BindEvent(tv->tree.bindingTable, event, tv->core.tkwin,
+ tagset->nTags, (void **)tagset->tags);
Tcl_Release(clientData);
- Ttk_FreeTagList(taglist);
+ Ttk_FreeTagSet(tagset);
}
/*------------------------------------------------------------------------
@@ -991,7 +1000,7 @@ static int TreeviewInitialize(Tcl_Interp *interp, void *recordPtr)
Tk_CreateOptionTable(interp, TagOptionSpecs);
tv->tree.tagTable = Ttk_CreateTagTable(
- tv->tree.tagOptionTable, sizeof(DisplayItem));
+ interp, tv->core.tkwin, TagOptionSpecs, sizeof(DisplayItem));
tv->tree.bindingTable = Tk_CreateBindingTable(interp);
Tk_CreateEventHandler(tv->core.tkwin,
TreeviewBindEventMask, TreeviewBindEventProc, tv);
@@ -1028,6 +1037,7 @@ static int TreeviewInitialize(Tcl_Interp *interp, void *recordPtr)
tv->tree.root = NewItem();
Tk_InitOptions(interp, (ClientData)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);
Tcl_SetHashValue(tv->tree.root->entryPtr, tv->tree.root);
@@ -1122,9 +1132,12 @@ static int ConfigureItem(
int objc, Tcl_Obj *const objv[])
{
Tk_SavedOptions savedOptions;
+ unsigned mask;
+ Ttk_ImageSpec *newImageSpec = NULL;
+ Ttk_TagSet newTagSet = NULL;
if (Tk_SetOptions(interp, (ClientData)item, tv->tree.itemOptionTable,
- objc, objv, tv->core.tkwin,&savedOptions,0) != TCL_OK)
+ objc, objv, tv->core.tkwin,&savedOptions,&mask) != TCL_OK)
{
return TCL_ERROR;
}
@@ -1137,15 +1150,24 @@ static int ConfigureItem(
goto error;
}
- /* Validate -image option.
+ /* Check -image.
*/
- if (item->imageObj) {
- Ttk_ImageSpec *imageSpec =
- TtkGetImageSpec(interp, tv->core.tkwin, item->imageObj);
- if (!imageSpec) {
+ if ((mask & ITEM_OPTION_IMAGE_CHANGED) && item->imageObj) {
+ newImageSpec = TtkGetImageSpec(interp, tv->core.tkwin, item->imageObj);
+ if (!newImageSpec) {
+ goto error;
+ }
+ }
+
+ /* Check -tags.
+ * Side effect: may create new tags.
+ */
+ if (mask & ITEM_OPTION_TAGS_CHANGED) {
+ newTagSet = Ttk_GetTagSetFromObj(
+ interp, tv->tree.tagTable, item->tagsObj);
+ if (!newTagSet) {
goto error;
}
- TtkFreeImageSpec(imageSpec); /* @@@TODO: Keep this around */
}
/* Keep TTK_STATE_OPEN flag in sync with item->openObj.
@@ -1162,28 +1184,24 @@ static int ConfigureItem(
item->state &= ~TTK_STATE_OPEN;
}
- /* Make sure -tags is a valid list
- * (side effect: may create new tags)
- */
- if (item->tagsObj) {
- void *taglist;
- int nTags;
- if (Ttk_GetTagListFromObj(interp, tv->tree.tagTable, item->tagsObj,
- &nTags, &taglist) != TCL_OK)
- {
- goto error;
- }
- Ttk_FreeTagList(taglist);
- }
-
/* All OK.
*/
Tk_FreeSavedOptions(&savedOptions);
+ if (mask & ITEM_OPTION_TAGS_CHANGED) {
+ if (item->tagset) { Ttk_FreeTagSet(item->tagset); }
+ item->tagset = newTagSet;
+ }
+ if (mask & ITEM_OPTION_IMAGE_CHANGED) {
+ if (item->imagespec) { TtkFreeImageSpec(item->imagespec); }
+ item->imagespec = newImageSpec;
+ }
TtkRedisplayWidget(&tv->core);
return TCL_OK;
error:
Tk_RestoreSavedOptions(&savedOptions);
+ if (newTagSet) { Ttk_FreeTagSet(newTagSet); }
+ if (newImageSpec) { TtkFreeImageSpec(newImageSpec); }
return TCL_ERROR;
}
@@ -1300,21 +1318,18 @@ static int CountRows(TreeItem *item)
static TreeItem *IdentifyRow(
Treeview *tv, /* Widget record */
TreeItem *item, /* Where to start search */
- Ttk_Box *bp, /* Scan position */
+ int *ypos, /* Scan position */
int y) /* Target y coordinate */
{
while (item) {
- int next_ypos = bp->y + tv->tree.rowHeight;
- if (bp->y <= y && y <= next_ypos) {
- bp->height = tv->tree.rowHeight;
+ int next_ypos = *ypos + tv->tree.rowHeight;
+ if (*ypos <= y && y <= next_ypos) {
return item;
}
- bp->y = next_ypos;
+ *ypos = next_ypos;
if (item->state & TTK_STATE_OPEN) {
- TreeItem *subitem = IdentifyRow(tv, item->children, bp, y);
+ TreeItem *subitem = IdentifyRow(tv, item->children, ypos, y);
if (subitem) {
- bp->x += tv->tree.indent;
- bp->width -= tv->tree.indent;
return subitem;
}
}
@@ -1325,17 +1340,12 @@ static TreeItem *IdentifyRow(
/* + IdentifyItem --
* Locate the item at the specified y position, if any.
- * On return, *itemPos holds the parcel of the tree item.
*/
-static TreeItem *IdentifyItem(Treeview *tv, int y, Ttk_Box *itemPos)
+static TreeItem *IdentifyItem(Treeview *tv, int y)
{
int rowHeight = tv->tree.rowHeight;
- *itemPos = Ttk_MakeBox(
- tv->tree.treeArea.x,
- tv->tree.treeArea.y - tv->tree.yscroll.first * rowHeight,
- tv->tree.column0.width,
- rowHeight);
- return IdentifyRow(tv, tv->tree.root->children, itemPos, y);
+ int ypos = tv->tree.treeArea.y - tv->tree.yscroll.first * rowHeight;
+ return IdentifyRow(tv, tv->tree.root->children, &ypos, y);
}
/* + IdentifyDisplayColumn --
@@ -1361,6 +1371,51 @@ static int IdentifyDisplayColumn(Treeview *tv, int x, int *x1)
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;
+ }
+ }
+
+ return -1;
+}
+
+/* + ItemDepth -- return the depth of a tree item.
+ * The depth of an item is equal to the number of proper ancestors,
+ * not counting the root node.
+ */
+static int ItemDepth(TreeItem *item)
+{
+ int depth = 0;
+ while (item->parent) {
+ ++depth;
+ item = item->parent;
+ }
+ return depth-1;
+}
+
/* + ItemRow --
* Returns row number of specified item relative to root,
* -1 if item is not viewable.
@@ -1388,6 +1443,93 @@ static int ItemRow(Treeview *tv, TreeItem *p)
}
}
+/* + BoundingBox --
+ * Compute the parcel of the specified column of the specified item,
+ * (or the entire item if column is NULL)
+ * Returns: 0 if item or column is not viewable, 1 otherwise.
+ */
+static int BoundingBox(
+ Treeview *tv, /* treeview widget */
+ TreeItem *item, /* desired item */
+ TreeColumn *column, /* desired column */
+ Ttk_Box *bbox_rtn) /* bounding box of item */
+{
+ int row = ItemRow(tv, item);
+ Ttk_Box bbox = tv->tree.treeArea;
+
+ if (row < tv->tree.yscroll.first || row > tv->tree.yscroll.last) {
+ /* not viewable, or off-screen */
+ return 0;
+ }
+
+ bbox.y += (row - tv->tree.yscroll.first) * tv->tree.rowHeight;
+ bbox.height = tv->tree.rowHeight;
+
+ if (column) {
+ int xpos = 0, i = FirstColumn(tv);
+ while (i < tv->tree.nDisplayColumns) {
+ if (tv->tree.displayColumns[i] == column) {
+ break;
+ }
+ xpos += tv->tree.displayColumns[i]->width;
+ ++i;
+ }
+ if (i == tv->tree.nDisplayColumns) { /* specified column unviewable */
+ return 0;
+ }
+ bbox.x += xpos;
+ bbox.width = column->width;
+
+ /* Account for indentation in tree column:
+ */
+ if (column == &tv->tree.column0) {
+ int indent = tv->tree.indent * ItemDepth(item);
+ bbox.x += indent;
+ bbox.width -= indent;
+ }
+ }
+ *bbox_rtn = bbox;
+ return 1;
+}
+
+/* + IdentifyRegion --
+ */
+
+typedef enum {
+ REGION_NOTHING = 0,
+ REGION_HEADING,
+ REGION_SEPARATOR,
+ REGION_TREE,
+ REGION_CELL
+} TreeRegion;
+
+static const char *regionStrings[] = {
+ "nothing", "heading", "separator", "tree", "cell", 0
+};
+
+static TreeRegion IdentifyRegion(Treeview *tv, int x, int y)
+{
+ int x1, colno = IdentifyDisplayColumn(tv, x, &x1);
+
+ if (Ttk_BoxContains(tv->tree.headingArea, x, y)) {
+ if (colno < 0) {
+ return REGION_NOTHING;
+ } else if (-HALO <= x1 - x && x1 - x <= HALO) {
+ return REGION_SEPARATOR;
+ } else {
+ return REGION_HEADING;
+ }
+ } else if (Ttk_BoxContains(tv->tree.treeArea,x,y)) {
+ TreeItem *item = IdentifyItem(tv, y);
+ if (item && colno > 0) {
+ return REGION_CELL;
+ } else if (item) {
+ return REGION_TREE;
+ }
+ }
+ return REGION_NOTHING;
+}
+
/*------------------------------------------------------------------------
* +++ Display routines.
*/
@@ -1560,34 +1702,16 @@ static void DrawHeadings(Treeview *tv, Drawable d, Ttk_Box b)
}
/* + PrepareItem --
- * Fill in a displayItem record from tag settings.
+ * Fill in a displayItem record.
*/
-static void PrepareItem(Treeview *tv, TreeItem *item, DisplayItem *displayItem)
+static void PrepareItem(
+ Treeview *tv, TreeItem *item, DisplayItem *displayItem)
{
- const int nOptions = sizeof(*displayItem)/sizeof(Tcl_Obj*);
- Tcl_Obj **dest = (Tcl_Obj**)displayItem;
- Tcl_Obj **objv = NULL;
- int objc = 0;
-
- memset(displayItem, 0, sizeof(*displayItem));
+ Ttk_Style style = Ttk_LayoutStyle(tv->core.layout);
+ Ttk_State state = ItemState(tv, item);
- if ( item->tagsObj
- && Tcl_ListObjGetElements(NULL, item->tagsObj, &objc, &objv) == TCL_OK)
- {
- int i, j;
- for (i=0; i<objc; ++i) {
- Ttk_Tag tag = Ttk_GetTagFromObj(tv->tree.tagTable, objv[i]);
- Tcl_Obj **tagRecord = Ttk_TagRecord(tag);
-
- if (tagRecord) {
- for (j=0; j<nOptions; ++j) {
- if (tagRecord[j] != 0) {
- dest[j] = tagRecord[j];
- }
- }
- }
- }
- }
+ Ttk_TagSetValues(tv->tree.tagTable, item->tagset, displayItem);
+ Ttk_TagSetApplyStyle(tv->tree.tagTable, style, state, displayItem);
}
/* + DrawCells --
@@ -1620,7 +1744,7 @@ static void DrawCells(
Ttk_MakeBox(b.x+x, b.y+y, column->width, rowHeight), cellPadding);
displayItem->textObj = column->data;
- displayItem->anchorObj = column->anchorObj;
+ displayItem->anchorObj = column->anchorObj; /* <<NOTE-ANCHOR>> */
DisplayLayout(layout, displayItem, state, parcel, d);
x += column->width;
@@ -1655,9 +1779,9 @@ static void DrawItem(
if (tv->tree.showFlags & SHOW_TREE) {
int colwidth = tv->tree.column0.width;
Ttk_Box parcel = Ttk_MakeBox(b.x + x, b.y + y, colwidth - x, rowHeight);
- displayItem.textObj = item->textObj;
- displayItem.imageObj = item->imageObj;
- displayItem.anchorObj = 0;
+ if (item->textObj) { displayItem.textObj = item->textObj; }
+ if (item->imageObj) { displayItem.imageObj = item->imageObj; }
+ /* ??? displayItem.anchorObj = 0; <<NOTE-ANCHOR>> */
DisplayLayout(tv->tree.itemLayout, &displayItem, state, parcel, d);
x = colwidth;
} else {
@@ -1802,51 +1926,6 @@ static TreeItem *DeleteItems(TreeItem *item, TreeItem *delq)
return delq;
}
-/* + 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;
- }
- }
-
- return -1;
-}
-
-/* + ItemDepth -- return the depth of a tree item.
- * The depth of an item is equal to the number of proper ancestors,
- * not counting the root node.
- */
-static int ItemDepth(TreeItem *item)
-{
- int depth = 0;
- while (item->parent) {
- ++depth;
- item = item->parent;
- }
- return depth-1;
-}
-
/*------------------------------------------------------------------------
* +++ Widget commands -- item inquiry.
*/
@@ -2065,7 +2144,6 @@ static int TreeviewBBoxCommand(
Treeview *tv = recordPtr;
TreeItem *item = 0;
TreeColumn *column = 0;
- int row;
Ttk_Box bbox;
if (objc < 3 || objc > 4) {
@@ -2081,47 +2159,10 @@ static int TreeviewBBoxCommand(
return TCL_ERROR;
}
- /* Compute bounding box of item:
- */
- row = ItemRow(tv, item);
- if (row < tv->tree.yscroll.first || row > tv->tree.yscroll.last) {
- /* not viewable, or off-screen */
- return TCL_OK;
- }
-
- bbox = tv->tree.treeArea;
- bbox.y += (row - tv->tree.yscroll.first) * tv->tree.rowHeight;
- bbox.height = tv->tree.rowHeight;
-
- /* If column has been specified, compute bounding box of cell
- */
- if (column) {
- int xpos = 0, i = FirstColumn(tv);
- while (i < tv->tree.nDisplayColumns) {
- if (tv->tree.displayColumns[i] == column) {
- break;
- }
- xpos += tv->tree.displayColumns[i]->width;
- ++i;
- }
- if (i == tv->tree.nDisplayColumns) { /* specified column unviewable */
- return TCL_OK;
- }
- bbox.x += xpos;
- bbox.width = column->width;
-
- /* Special case for tree column -- account for indentation:
- * (@@@ NOTE: doesn't account for tree indicator or image;
- * @@@ this may or may not be the right thing.)
- */
- if (column == &tv->tree.column0) {
- int indent = tv->tree.indent * ItemDepth(item);
- bbox.x += indent;
- bbox.width -= indent;
- }
+ if (BoundingBox(tv, item, column, &bbox)) {
+ Tcl_SetObjResult(interp, Ttk_NewBoxObj(bbox));
}
- Tcl_SetObjResult(interp, Ttk_NewBoxObj(bbox));
return TCL_OK;
}
@@ -2166,16 +2207,17 @@ static int TreeviewHorribleIdentify(
}
detail = dcolbuf;
} else if (Ttk_BoxContains(tv->tree.treeArea,x,y)) {
- Ttk_Box itemBox;
- item = IdentifyItem(tv, y, &itemBox);
+ item = IdentifyItem(tv, y);
if (item && dColumnNumber > 0) {
what = "cell";
detail = dcolbuf;
} else if (item) {
Ttk_Layout layout = tv->tree.itemLayout;
+ Ttk_Box itemBox;
DisplayItem displayItem;
Ttk_LayoutNode *element;
+ BoundingBox(tv, item, NULL, &itemBox);
PrepareItem(tv, item, &displayItem); /*@@@ FIX: -text, etc*/
Ttk_RebindSublayout(layout, &displayItem);
Ttk_PlaceLayout(layout, ItemState(tv,item), itemBox);
@@ -2209,51 +2251,97 @@ done:
static int TreeviewIdentifyCommand(
Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], void *recordPtr)
{
- static const char *componentStrings[] =
- { "row", "column", NULL };
- enum { I_ROW, I_COLUMN };
+ static const char *submethodStrings[] =
+ { "region", "item", "column", "row", "element", NULL };
+ enum { I_REGION, I_ITEM, I_COLUMN, I_ROW, I_ELEMENT };
Treeview *tv = recordPtr;
- int component, x, y;
+ int submethod;
+ int x, y;
+
+ TreeRegion region;
+ Ttk_Box bbox;
+ TreeItem *item;
+ TreeColumn *column = 0;
+ int colno, x1;
if (objc == 4) { /* Old form */
return TreeviewHorribleIdentify(interp, objc, objv, tv);
} else if (objc != 5) {
- Tcl_WrongNumArgs(interp, 2, objv, "component x y");
+ Tcl_WrongNumArgs(interp, 2, objv, "command x y");
return TCL_ERROR;
}
if ( Tcl_GetIndexFromObj(interp, objv[2],
- componentStrings, "component", TCL_EXACT, &component) != TCL_OK
+ submethodStrings, "command", TCL_EXACT, &submethod) != TCL_OK
|| Tcl_GetIntFromObj(interp, objv[3], &x) != TCL_OK
|| Tcl_GetIntFromObj(interp, objv[4], &y) != TCL_OK
) {
return TCL_ERROR;
}
- switch (component)
+ region = IdentifyRegion(tv, x, y);
+ item = IdentifyItem(tv, y);
+ colno = IdentifyDisplayColumn(tv, x, &x1);
+ column = (colno >= 0) ? tv->tree.displayColumns[colno] : NULL;
+
+ switch (submethod)
{
+ case I_REGION :
+ Tcl_SetObjResult(interp,Tcl_NewStringObj(regionStrings[region],-1));
+ break;
+
+ case I_ITEM :
case I_ROW :
- {
- Ttk_Box itemBox;
- TreeItem *item = IdentifyItem(tv, y, &itemBox);
if (item) {
Tcl_SetObjResult(interp, ItemID(tv, item));
}
break;
- }
case I_COLUMN :
- {
- int x1;
- int column = IdentifyDisplayColumn(tv, x, &x1);
-
- if (column >= 0) {
+ if (colno >= 0) {
char dcolbuf[16];
- sprintf(dcolbuf, "#%d", column);
+ sprintf(dcolbuf, "#%d", colno);
Tcl_SetObjResult(interp, Tcl_NewStringObj(dcolbuf, -1));
}
break;
+
+ case I_ELEMENT :
+ {
+ Ttk_Layout layout = 0;
+ DisplayItem displayItem;
+ Ttk_LayoutNode *element;
+
+ switch (region) {
+ case REGION_NOTHING:
+ layout = tv->core.layout;
+ return TCL_OK; /* @@@ NYI */
+ case REGION_HEADING:
+ case REGION_SEPARATOR:
+ layout = tv->tree.headingLayout;
+ return TCL_OK; /* @@@ NYI */
+ case REGION_TREE:
+ layout = tv->tree.itemLayout;
+ break;
+ case REGION_CELL:
+ layout = tv->tree.cellLayout;
+ break;
+ }
+
+ if (!BoundingBox(tv, item, column, &bbox)) {
+ return TCL_OK;
+ }
+
+ PrepareItem(tv, item, &displayItem); /*@@@ FIX: fill in -text,etc */
+ Ttk_RebindSublayout(layout, &displayItem);
+ Ttk_PlaceLayout(layout, ItemState(tv,item), bbox);
+ element = Ttk_LayoutIdentify(layout, x, y);
+
+ if (element) {
+ const char *elementName = Ttk_LayoutNodeName(element);
+ Tcl_SetObjResult(interp, Tcl_NewStringObj(elementName, -1));
+ }
+ break;
}
}
return TCL_OK;
@@ -2501,6 +2589,7 @@ static int TreeviewInsertCommand(
newItem = NewItem();
Tk_InitOptions(
interp, (ClientData)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);
FreeItem(newItem);
@@ -2651,7 +2740,7 @@ static int TreeviewMoveCommand(
if (p != item) {
--index;
} /* else -- moving node forward, count index+1 nodes */
- sibling = p;
+ sibling = p;
}
}
@@ -2942,7 +3031,7 @@ static int TreeviewTagConfigureCommand(
Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], void *recordPtr)
{
Treeview *tv = recordPtr;
- void *tagRecord;
+ Ttk_TagTable tagTable = tv->tree.tagTable;
Ttk_Tag tag;
if (objc < 4) {
@@ -2950,22 +3039,57 @@ static int TreeviewTagConfigureCommand(
return TCL_ERROR;
}
- tag = Ttk_GetTagFromObj(tv->tree.tagTable, objv[3]);
- tagRecord = Ttk_TagRecord(tag);
+ tag = Ttk_GetTagFromObj(tagTable, objv[3]);
if (objc == 4) {
- return TtkEnumerateOptions(interp, tagRecord, TagOptionSpecs,
- tv->tree.tagOptionTable, tv->core.tkwin);
+ return Ttk_EnumerateTagOptions(interp, tagTable, tag);
} else if (objc == 5) {
- return TtkGetOptionValue(interp, tagRecord, objv[4],
- tv->tree.tagOptionTable, tv->core.tkwin);
+ Tcl_Obj *result = Ttk_TagOptionValue(interp, tagTable, tag, objv[4]);
+ if (result) {
+ Tcl_SetObjResult(interp, result);
+ return TCL_OK;
+ } /* else */
+ return TCL_ERROR;
}
/* else */
TtkRedisplayWidget(&tv->core);
- return Tk_SetOptions(
- interp, tagRecord, tv->tree.tagOptionTable,
- objc - 4, objv + 4, tv->core.tkwin,
- NULL/*savedOptions*/, NULL/*mask*/);
+ return Ttk_ConfigureTag(interp, tagTable, tag, objc - 4, objv + 4);
+}
+
+/* + $tv tag has $tag ?$item?
+ */
+static int TreeviewTagHasCommand(
+ Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], void *recordPtr)
+{
+ Treeview *tv = recordPtr;
+
+ if (objc == 4) { /* Return list of all items with tag */
+ Ttk_Tag tag = Ttk_GetTagFromObj(tv->tree.tagTable, objv[3]);
+ TreeItem *item = tv->tree.root;
+ Tcl_Obj *result = Tcl_NewListObj(0,0);
+
+ while (item) {
+ if (Ttk_TagSetContains(item->tagset, tag)) {
+ Tcl_ListObjAppendElement(NULL, result, ItemID(tv, item));
+ }
+ item = NextPreorder(item);
+ }
+
+ Tcl_SetObjResult(interp, result);
+ return TCL_OK;
+ } else if (objc == 5) { /* Test if item has specified tag */
+ Ttk_Tag tag = Ttk_GetTagFromObj(tv->tree.tagTable, objv[3]);
+ TreeItem *item = FindItem(interp, tv, objv[4]);
+ if (!item) {
+ return TCL_ERROR;
+ }
+ Tcl_SetObjResult(interp,
+ Tcl_NewBooleanObj(Ttk_TagSetContains(item->tagset, tag)));
+ return TCL_OK;
+ } else {
+ Tcl_WrongNumArgs(interp, 3, objv, "tagName ?item?");
+ return TCL_ERROR;
+ }
}
/* + $tv tag option args...
@@ -2976,6 +3100,7 @@ static int TreeviewTagCommand(
static WidgetCommandSpec TreeviewTagCommands[] = {
{ "bind", TreeviewTagBindCommand },
{ "configure", TreeviewTagConfigureCommand },
+ { "has", TreeviewTagHasCommand },
{0,0}
};
return TtkWidgetEnsembleCommand(
@@ -2985,8 +3110,7 @@ static int TreeviewTagCommand(
/*------------------------------------------------------------------------
* +++ Widget commands record.
*/
-static WidgetCommandSpec TreeviewCommands[] =
-{
+static WidgetCommandSpec TreeviewCommands[] = {
{ "bbox", TreeviewBBoxCommand },
{ "children", TreeviewChildrenCommand },
{ "cget", TtkWidgetCgetCommand },
@@ -3021,8 +3145,7 @@ static WidgetCommandSpec TreeviewCommands[] =
* +++ Widget definition.
*/
-static WidgetSpec TreeviewWidgetSpec =
-{
+static WidgetSpec TreeviewWidgetSpec = {
"Treeview", /* className */
sizeof(Treeview), /* recordSize */
TreeviewOptionSpecs, /* optionSpecs */
@@ -3075,15 +3198,13 @@ TTK_END_LAYOUT_TABLE
* +++ Tree indicator element.
*/
-typedef struct
-{
+typedef struct {
Tcl_Obj *colorObj;
Tcl_Obj *sizeObj;
Tcl_Obj *marginsObj;
} TreeitemIndicator;
-static Ttk_ElementOptionSpec TreeitemIndicatorOptions[] =
-{
+static Ttk_ElementOptionSpec TreeitemIndicatorOptions[] = {
{ "-foreground", TK_OPTION_COLOR,
Tk_Offset(TreeitemIndicator,colorObj), DEFAULT_FOREGROUND },
{ "-indicatorsize", TK_OPTION_PIXELS,
@@ -3135,8 +3256,7 @@ static void TreeitemIndicatorDraw(
Tk_FreeGC(Tk_Display(tkwin), gc);
}
-static Ttk_ElementSpec TreeitemIndicatorElementSpec =
-{
+static Ttk_ElementSpec TreeitemIndicatorElementSpec = {
TK_STYLE_VERSION_2,
sizeof(TreeitemIndicator),
TreeitemIndicatorOptions,
@@ -3148,14 +3268,12 @@ static Ttk_ElementSpec TreeitemIndicatorElementSpec =
* +++ Row element.
*/
-typedef struct
-{
+typedef struct {
Tcl_Obj *backgroundObj;
Tcl_Obj *rowNumberObj;
} RowElement;
-static Ttk_ElementOptionSpec RowElementOptions[] =
-{
+static Ttk_ElementOptionSpec RowElementOptions[] = {
{ "-background", TK_OPTION_COLOR,
Tk_Offset(RowElement,backgroundObj), DEFAULT_BACKGROUND },
{ "-rownumber", TK_OPTION_INT,
@@ -3174,8 +3292,7 @@ static void RowElementDraw(
b.x, b.y, b.width, b.height);
}
-static Ttk_ElementSpec RowElementSpec =
-{
+static Ttk_ElementSpec RowElementSpec = {
TK_STYLE_VERSION_2,
sizeof(RowElement),
RowElementOptions,