summaryrefslogtreecommitdiffstats
path: root/generic/ttk
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
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')
-rw-r--r--generic/ttk/ttkLayout.c23
-rw-r--r--generic/ttk/ttkTagSet.c191
-rw-r--r--generic/ttk/ttkTheme.c53
-rw-r--r--generic/ttk/ttkTheme.h7
-rw-r--r--generic/ttk/ttkThemeInt.h3
-rw-r--r--generic/ttk/ttkTreeview.c591
-rw-r--r--generic/ttk/ttkWidget.h33
7 files changed, 567 insertions, 334 deletions
diff --git a/generic/ttk/ttkLayout.c b/generic/ttk/ttkLayout.c
index bfa10c4..c1e239a 100644
--- a/generic/ttk/ttkLayout.c
+++ b/generic/ttk/ttkLayout.c
@@ -5,7 +5,7 @@
*
* Copyright (c) 2003 Joe English. Freely redistributable.
*
- * $Id: ttkLayout.c,v 1.11 2007/12/13 15:26:26 dgp Exp $
+ * $Id: ttkLayout.c,v 1.12 2008/05/23 20:20:05 jenglish Exp $
*/
#include <string.h>
@@ -47,8 +47,6 @@ Ttk_NewBoxObj(Ttk_Box box)
return Tcl_NewListObj(4, result);
}
-
-
/*
* packTop, packBottom, packLeft, packRight --
* Carve out a parcel of the specified height (resp width)
@@ -768,7 +766,7 @@ void Ttk_RegisterLayouts(Ttk_Theme theme, Ttk_LayoutSpec spec)
}
}
-Tcl_Obj *Ttk_UnparseLayoutTemplate(Ttk_TemplateNode *node)
+Tcl_Obj *Ttk_UnparseLayoutTemplate(Ttk_TemplateNode *node)
{
Tcl_Obj *result = Tcl_NewListObj(0,0);
@@ -785,14 +783,14 @@ Tcl_Obj *Ttk_UnparseLayoutTemplate(Ttk_TemplateNode *node)
*/
if (flags & TTK_EXPAND) {
APPENDSTR("-expand");
- APPENDSTR("1");
+ APPENDSTR("1");
} else {
if (flags & _TTK_MASK_PACK) {
int side = 0;
unsigned sideFlags = flags & _TTK_MASK_PACK;
while ((sideFlags & TTK_PACK_LEFT) == 0) {
- ++side;
+ ++side;
sideFlags >>= 1;
}
APPENDSTR("-side");
@@ -891,7 +889,7 @@ Ttk_Layout Ttk_CreateLayout(
* Creates a new sublayout.
*
* Sublayouts are used to draw subparts of a compound widget.
- * They use the same Tk_Window, but a different option table
+ * They use the same Tk_Window, but a different option table
* and data record.
*/
Ttk_Layout
@@ -924,7 +922,7 @@ Ttk_CreateSublayout(
Tcl_DStringFree(&buf);
return TTKNewLayout(
- style, 0, optionTable, parentLayout->tkwin,
+ style, 0, optionTable, parentLayout->tkwin,
Ttk_InstantiateLayout(themePtr, layoutTemplate));
}
@@ -947,6 +945,15 @@ Tcl_Obj *Ttk_QueryOption(
layout->style,layout->recordPtr,layout->optionTable,optionName,state);
}
+/*
+ * Ttk_LayoutStyle --
+ * Extract Ttk_Style from Ttk_Layout.
+ */
+Ttk_Style Ttk_LayoutStyle(Ttk_Layout layout)
+{
+ return layout->style;
+}
+
/*------------------------------------------------------------------------
* +++ Size computation.
*/
diff --git a/generic/ttk/ttkTagSet.c b/generic/ttk/ttkTagSet.c
index 85624a2..d925a78 100644
--- a/generic/ttk/ttkTagSet.c
+++ b/generic/ttk/ttkTagSet.c
@@ -1,6 +1,6 @@
-/* $Id: ttkTagSet.c,v 1.3 2007/01/11 19:59:26 jenglish Exp $
+/* $Id: ttkTagSet.c,v 1.4 2008/05/23 20:20:05 jenglish Exp $
*
- * Ttk widget set: tag tables. Half-baked, work in progress.
+ * Tag tables. 3/4-baked, work in progress.
*
* Copyright (C) 2005, Joe English. Freely redistributable.
*/
@@ -16,12 +16,16 @@
* +++ Internal data structures.
*/
struct TtkTag {
- Tcl_Obj **tagRecord; /* ... hrmph. */
+ int priority; /* 1=>highest */
+ void *tagRecord;
};
struct TtkTagTable {
- Tk_OptionTable tagOptionTable; /* ... */
- int tagRecordSize; /* size of tag record */
+ Tk_Window tkwin; /* owner window */
+ Tk_OptionSpec *optionSpecs; /* ... */
+ Tk_OptionTable optionTable; /* ... */
+ int recordSize; /* size of tag record */
+ int nTags; /* #tags defined so far */
Tcl_HashTable tags; /* defined tags */
};
@@ -31,38 +35,34 @@ struct TtkTagTable {
static Ttk_Tag NewTag(Ttk_TagTable tagTable)
{
Ttk_Tag tag = (Ttk_Tag)ckalloc(sizeof(*tag));
- tag->tagRecord = (Tcl_Obj **)ckalloc(tagTable->tagRecordSize);
- memset(tag->tagRecord, 0, tagTable->tagRecordSize);
+ tag->tagRecord = ckalloc(tagTable->recordSize);
+ memset(tag->tagRecord, 0, tagTable->recordSize);
+ /* Don't need Tk_InitOptions() here, all defaults should be NULL. */
+ tag->priority = ++tagTable->nTags;
return tag;
}
-static void DeleteTag(Ttk_Tag tag, int nOptions)
+static void DeleteTag(Ttk_TagTable tagTable, Ttk_Tag tag)
{
- int i;
- for (i = 0; i < nOptions; ++i) {
- if (tag->tagRecord[i]) {
- Tcl_DecrRefCount(tag->tagRecord[i]);
- }
- }
- ckfree((void*)tag->tagRecord);
+ Tk_FreeConfigOptions(tag->tagRecord,tagTable->optionTable,tagTable->tkwin);
+ ckfree(tag->tagRecord);
ckfree((void*)tag);
}
-Tcl_Obj **Ttk_TagRecord(Ttk_Tag tag)
-{
- return tag->tagRecord;
-}
-
/*------------------------------------------------------------------------
* +++ Tag tables.
*/
Ttk_TagTable Ttk_CreateTagTable(
- Tk_OptionTable tagOptionTable, int tagRecordSize)
+ Tcl_Interp *interp, Tk_Window tkwin,
+ Tk_OptionSpec optionSpecs[], int recordSize)
{
Ttk_TagTable tagTable = (Ttk_TagTable)ckalloc(sizeof(*tagTable));
- tagTable->tagOptionTable = tagOptionTable;
- tagTable->tagRecordSize = tagRecordSize;
+ tagTable->tkwin = tkwin;
+ tagTable->optionSpecs = optionSpecs;
+ tagTable->optionTable = Tk_CreateOptionTable(interp, optionSpecs);
+ tagTable->recordSize = recordSize;
+ tagTable->nTags = 0;
Tcl_InitHashTable(&tagTable->tags, TCL_STRING_KEYS);
return tagTable;
}
@@ -71,11 +71,10 @@ void Ttk_DeleteTagTable(Ttk_TagTable tagTable)
{
Tcl_HashSearch search;
Tcl_HashEntry *entryPtr;
- int nOptions = tagTable->tagRecordSize / sizeof(Tcl_Obj *);
entryPtr = Tcl_FirstHashEntry(&tagTable->tags, &search);
while (entryPtr != NULL) {
- DeleteTag(Tcl_GetHashValue(entryPtr), nOptions);
+ DeleteTag(tagTable, Tcl_GetHashValue(entryPtr));
entryPtr = Tcl_NextHashEntry(&search);
}
@@ -100,48 +99,144 @@ Ttk_Tag Ttk_GetTagFromObj(Ttk_TagTable tagTable, Tcl_Obj *objPtr)
return Ttk_GetTag(tagTable, Tcl_GetString(objPtr));
}
-/* Ttk_GetTagListFromObj --
+/*------------------------------------------------------------------------
+ * +++ Tag sets.
+ */
+
+/* Ttk_GetTagSetFromObj --
* Extract an array of pointers to Ttk_Tags from a Tcl_Obj.
- * (suitable for passing to Tk_BindEvent).
+ * objPtr may be NULL, in which case a new empty tag set is returned.
*
- * Result must be passed to Ttk_FreeTagList().
+ * Returns NULL and leaves an error message in interp->result on error.
+ *
+ * Non-NULL results must be passed to Ttk_FreeTagSet().
*/
-extern int Ttk_GetTagListFromObj(
- Tcl_Interp *interp,
- Ttk_TagTable tagTable,
- Tcl_Obj *objPtr,
- int *nTags_rtn,
- void **taglist_rtn)
+Ttk_TagSet Ttk_GetTagSetFromObj(
+ Tcl_Interp *interp, Ttk_TagTable tagTable, Tcl_Obj *objPtr)
{
+ Ttk_TagSet tagset = (Ttk_TagSet)(ckalloc(sizeof *tagset));
Tcl_Obj **objv;
int i, objc;
- void **tags;
-
- *taglist_rtn = NULL; *nTags_rtn = 0;
if (objPtr == NULL) {
- return TCL_OK;
+ tagset->tags = NULL;
+ tagset->nTags = 0;
+ return tagset;
}
if (Tcl_ListObjGetElements(interp, objPtr, &objc, &objv) != TCL_OK) {
- return TCL_ERROR;
+ ckfree((ClientData)tagset);
+ return NULL;
}
- tags = (void**)ckalloc((objc+1) * sizeof(void*));
+ tagset->tags = (Ttk_Tag*)ckalloc((objc+1) * sizeof(Ttk_Tag));
for (i=0; i<objc; ++i) {
- tags[i] = Ttk_GetTagFromObj(tagTable, objv[i]);
+ tagset->tags[i] = Ttk_GetTagFromObj(tagTable, objv[i]);
}
- tags[i] = NULL;
+ tagset->tags[i] = NULL;
+ tagset->nTags = objc;
+
+ return tagset;
+}
+
+void Ttk_FreeTagSet(Ttk_TagSet tagset)
+{
+ ckfree((ClientData)tagset->tags);
+ ckfree((ClientData)tagset);
+}
+
+/* Ttk_TagSetContains -- test if tag set contains a tag.
+ */
+int Ttk_TagSetContains(Ttk_TagSet tagset, Ttk_Tag tag)
+{
+ int i;
+ for (i = 0; i < tagset->nTags; ++i) {
+ if (tagset->tags[i] == tag) {
+ return 1;
+ }
+ }
+ return 0;
+}
- *taglist_rtn = tags;
- *nTags_rtn = objc;
+/*------------------------------------------------------------------------
+ * +++ Utilities for widget commands.
+ */
+
+/* Ttk_EnumerateTagOptions -- implements [$w tag configure $tag]
+ */
+int Ttk_EnumerateTagOptions(
+ Tcl_Interp *interp, Ttk_TagTable tagTable, Ttk_Tag tag)
+{
+ return TtkEnumerateOptions(interp, tag->tagRecord,
+ tagTable->optionSpecs, tagTable->optionTable, tagTable->tkwin);
+}
+
+Tcl_Obj *Ttk_TagOptionValue(
+ Tcl_Interp *interp,
+ Ttk_TagTable tagTable,
+ Ttk_Tag tag,
+ Tcl_Obj *optionName)
+{
+ return Tk_GetOptionValue(interp,
+ tag->tagRecord, tagTable->optionTable, optionName, tagTable->tkwin);
+}
+
+/* Ttk_ConfigureTag -- implements [$w tag configure $tag -option value...]
+ */
+int Ttk_ConfigureTag(
+ Tcl_Interp *interp,
+ Ttk_TagTable tagTable,
+ Ttk_Tag tag,
+ int objc, Tcl_Obj *const objv[])
+{
+ return Tk_SetOptions(
+ interp, tag->tagRecord, tagTable->optionTable,
+ objc, objv, tagTable->tkwin, NULL/*savedOptions*/, NULL/*mask*/);
+}
+
+/*------------------------------------------------------------------------
+ * +++ Tag values.
+ */
- return TCL_OK;
+#define OBJ_AT(record, offset) (*(Tcl_Obj**)(((char*)record)+offset))
+
+void Ttk_TagSetValues(Ttk_TagTable tagTable, Ttk_TagSet tagSet, void *record)
+{
+ const int LOWEST_PRIORITY = 0x7FFFFFFF;
+ int i, j;
+
+ memset(record, 0, tagTable->recordSize);
+
+ for (i = 0; tagTable->optionSpecs[i].type != TK_OPTION_END; ++i) {
+ Tk_OptionSpec *optionSpec = tagTable->optionSpecs + i;
+ int offset = optionSpec->objOffset;
+ int prio = LOWEST_PRIORITY;
+
+ for (j = 0; j < tagSet->nTags; ++j) {
+ Ttk_Tag tag = tagSet->tags[j];
+ if (OBJ_AT(tag->tagRecord, offset) != 0 && tag->priority < prio) {
+ OBJ_AT(record, offset) = OBJ_AT(tag->tagRecord, offset);
+ prio = tag->priority;
+ }
+ }
+ }
}
-void Ttk_FreeTagList(void **taglist)
+void Ttk_TagSetApplyStyle(
+ Ttk_TagTable tagTable, Ttk_Style style, Ttk_State state, void *record)
{
- if (taglist)
- ckfree((ClientData)taglist);
+ Tk_OptionSpec *optionSpec = tagTable->optionSpecs;
+
+ while (optionSpec->type != TK_OPTION_END) {
+ int offset = optionSpec->objOffset;
+ const char *optionName = optionSpec->optionName;
+ Tcl_Obj *val = Ttk_StyleMap(style, optionName, state);
+ if (val) {
+ OBJ_AT(record, offset) = val;
+ } else if (OBJ_AT(record, offset) == 0) {
+ OBJ_AT(record, offset) = Ttk_StyleDefault(style, optionName);
+ }
+ ++optionSpec;
+ }
}
diff --git a/generic/ttk/ttkTheme.c b/generic/ttk/ttkTheme.c
index 3439ef0..45049b6 100644
--- a/generic/ttk/ttkTheme.c
+++ b/generic/ttk/ttkTheme.c
@@ -9,7 +9,7 @@
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * $Id: ttkTheme.c,v 1.12 2008/04/27 22:41:12 dkf Exp $
+ * $Id: ttkTheme.c,v 1.13 2008/05/23 20:20:05 jenglish Exp $
*/
#include <stdlib.h>
@@ -85,34 +85,35 @@ static void FreeStyle(Style *stylePtr)
}
/*
- * LookupStateMap --
- * Look up dynamic resource settings in the in the specified style.
+ * Ttk_StyleMap --
+ * Look up state-specific option value from specified style.
*/
-
-static Ttk_StateMap LookupStateMap(Ttk_Style stylePtr, const char *optionName)
+Tcl_Obj *Ttk_StyleMap(Ttk_Style style, const char *optionName, Ttk_State state)
{
- while (stylePtr) {
+ while (style) {
Tcl_HashEntry *entryPtr =
- Tcl_FindHashEntry(&stylePtr->settingsTable, optionName);
- if (entryPtr)
- return (Ttk_StateMap)Tcl_GetHashValue(entryPtr);
- stylePtr = stylePtr->parentStyle;
+ Tcl_FindHashEntry(&style->settingsTable, optionName);
+ if (entryPtr) {
+ Ttk_StateMap stateMap = Tcl_GetHashValue(entryPtr);
+ return Ttk_StateMapLookup(NULL, stateMap, state);
+ }
+ style = style->parentStyle;
}
return 0;
}
/*
- * LookupDefault --
+ * Ttk_StyleDefault --
* Look up default resource setting the in the specified style.
*/
-static Tcl_Obj *LookupDefault(Ttk_Style stylePtr, const char *optionName)
+Tcl_Obj *Ttk_StyleDefault(Ttk_Style style, const char *optionName)
{
- while (stylePtr) {
+ while (style) {
Tcl_HashEntry *entryPtr =
- Tcl_FindHashEntry(&stylePtr->defaultsTable, optionName);
+ Tcl_FindHashEntry(&style->defaultsTable, optionName);
if (entryPtr)
return (Tcl_Obj *)Tcl_GetHashValue(entryPtr);
- stylePtr = stylePtr->parentStyle;
+ style= style->parentStyle;
}
return 0;
}
@@ -296,7 +297,6 @@ static void FreeElementImpl(ElementImpl *elementImpl)
ckfree((ClientData)elementImpl);
}
-
/*------------------------------------------------------------------------
* +++ Themes.
*/
@@ -993,15 +993,10 @@ int InitializeElementRecord(
Tcl_Obj **dest = (Tcl_Obj **)
(elementRecord + elementOption->offset);
const char *optionName = elementOption->optionName;
- Tcl_Obj *stateMap = LookupStateMap(style, optionName);
- Tcl_Obj *dynamicSetting = 0;
+ Tcl_Obj *dynamicSetting = Ttk_StyleMap(style, optionName, state);
Tcl_Obj *widgetValue = 0;
Tcl_Obj *elementDefault = element->defaultValues[i];
- if (stateMap) {
- dynamicSetting = Ttk_StateMapLookup(NULL, stateMap, state);
- }
-
if (optionMap[i]) {
widgetValue = *(Tcl_Obj **)
(widgetRecord + optionMap[i]->objOffset);
@@ -1012,7 +1007,7 @@ int InitializeElementRecord(
} else if (dynamicSetting) {
*dest = dynamicSetting;
} else {
- Tcl_Obj *styleDefault = LookupDefault(style, optionName);
+ Tcl_Obj *styleDefault = Ttk_StyleDefault(style, optionName);
*dest = styleDefault ? styleDefault : elementDefault;
}
@@ -1039,7 +1034,6 @@ Tcl_Obj *Ttk_QueryStyle(
const char *optionName, /* Option name */
Ttk_State state) /* Current state */
{
- Tcl_Obj *stateMap;
const Tk_OptionSpec *optionSpec;
Tcl_Obj *result;
@@ -1057,18 +1051,15 @@ Tcl_Obj *Ttk_QueryStyle(
/*
* Check dynamic settings:
*/
- stateMap = LookupStateMap(style, optionName);
- if (stateMap) {
- result = Ttk_StateMapLookup(NULL, stateMap, state);
- if (result) {
- return result;
- }
+ result = Ttk_StyleMap(style, optionName, state);
+ if (result) {
+ return result;
}
/*
* Use style default:
*/
- return LookupDefault(style, optionName);
+ return Ttk_StyleDefault(style, optionName);
}
/*
diff --git a/generic/ttk/ttkTheme.h b/generic/ttk/ttkTheme.h
index 5e7dc88..c5de39b 100644
--- a/generic/ttk/ttkTheme.h
+++ b/generic/ttk/ttkTheme.h
@@ -1,4 +1,4 @@
-/* $Id: ttkTheme.h,v 1.13 2007/12/13 15:26:26 dgp Exp $
+/* $Id: ttkTheme.h,v 1.14 2008/05/23 20:20:05 jenglish Exp $
* Copyright (c) 2003 Joe English. Freely redistributable.
*
* Declarations for Tk theme engine.
@@ -205,6 +205,7 @@ typedef struct Ttk_Theme_ *Ttk_Theme;
typedef struct Ttk_ElementImpl_ *Ttk_ElementImpl;
typedef struct Ttk_Layout_ *Ttk_Layout;
typedef struct Ttk_LayoutNode_ Ttk_LayoutNode;
+typedef struct Ttk_Style_ *Ttk_Style;
TTKAPI Ttk_Theme Ttk_GetTheme(Tcl_Interp *interp, const char *name);
TTKAPI Ttk_Theme Ttk_GetDefaultTheme(Tcl_Interp *interp);
@@ -341,6 +342,10 @@ MODULE_SCOPE void Ttk_ChangeElementState(Ttk_LayoutNode *,unsigned set,unsigned
MODULE_SCOPE Tcl_Obj *Ttk_QueryOption(Ttk_Layout, const char *, Ttk_State);
+TTKAPI Ttk_Style Ttk_LayoutStyle(Ttk_Layout);
+TTKAPI Tcl_Obj *Ttk_StyleDefault(Ttk_Style, const char *optionName);
+TTKAPI Tcl_Obj *Ttk_StyleMap(Ttk_Style, const char *optionName, Ttk_State);
+
/*------------------------------------------------------------------------
* +++ Resource cache.
* See resource.c for explanation.
diff --git a/generic/ttk/ttkThemeInt.h b/generic/ttk/ttkThemeInt.h
index a7c19aa..1f61b73 100644
--- a/generic/ttk/ttkThemeInt.h
+++ b/generic/ttk/ttkThemeInt.h
@@ -1,5 +1,5 @@
/*
- * $Id: ttkThemeInt.h,v 1.5 2007/12/13 15:26:26 dgp Exp $
+ * $Id: ttkThemeInt.h,v 1.6 2008/05/23 20:20:05 jenglish Exp $
*
* Theme engine: private definitions.
*
@@ -11,7 +11,6 @@
#include "ttkTheme.h"
-typedef struct Ttk_Style_ *Ttk_Style;
typedef struct Ttk_TemplateNode_ Ttk_TemplateNode, *Ttk_LayoutTemplate;
MODULE_SCOPE Ttk_ElementImpl Ttk_GetElement(Ttk_Theme theme, const char *name);
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,
diff --git a/generic/ttk/ttkWidget.h b/generic/ttk/ttkWidget.h
index 21cb1b3..c74711d 100644
--- a/generic/ttk/ttkWidget.h
+++ b/generic/ttk/ttkWidget.h
@@ -1,4 +1,4 @@
-/* $Id: ttkWidget.h,v 1.9 2008/01/06 22:33:14 jenglish Exp $
+/* $Id: ttkWidget.h,v 1.10 2008/05/23 20:20:05 jenglish Exp $
* Copyright (c) 2003, Joe English
* Helper routines for widget implementations.
*/
@@ -211,20 +211,39 @@ MODULE_SCOPE void TtkScrollbarUpdateRequired(ScrollHandle);
typedef struct TtkTag *Ttk_Tag;
typedef struct TtkTagTable *Ttk_TagTable;
+typedef struct TtkTagSet { /* TODO: make opaque */
+ Ttk_Tag *tags;
+ int nTags;
+} *Ttk_TagSet;
-MODULE_SCOPE Ttk_TagTable Ttk_CreateTagTable(Tk_OptionTable, int tagRecSize);
+MODULE_SCOPE Ttk_TagTable Ttk_CreateTagTable(
+ Tcl_Interp *, Tk_Window tkwin, Tk_OptionSpec[], int recordSize);
MODULE_SCOPE void Ttk_DeleteTagTable(Ttk_TagTable);
MODULE_SCOPE Ttk_Tag Ttk_GetTag(Ttk_TagTable, const char *tagName);
MODULE_SCOPE Ttk_Tag Ttk_GetTagFromObj(Ttk_TagTable, Tcl_Obj *);
-MODULE_SCOPE Tcl_Obj **Ttk_TagRecord(Ttk_Tag);
+MODULE_SCOPE Tcl_Obj *Ttk_TagOptionValue(
+ Tcl_Interp *, Ttk_TagTable, Ttk_Tag, Tcl_Obj *optionName);
-MODULE_SCOPE int Ttk_GetTagListFromObj(
- Tcl_Interp *interp, Ttk_TagTable, Tcl_Obj *objPtr,
- int *nTags_rtn, void **taglist_rtn);
+MODULE_SCOPE int Ttk_EnumerateTagOptions(
+ Tcl_Interp *, Ttk_TagTable, Ttk_Tag);
-MODULE_SCOPE void Ttk_FreeTagList(void **taglist);
+MODULE_SCOPE int Ttk_ConfigureTag(
+ Tcl_Interp *interp, Ttk_TagTable tagTable, Ttk_Tag tag,
+ int objc, Tcl_Obj *const objv[]);
+
+MODULE_SCOPE Ttk_TagSet Ttk_GetTagSetFromObj(
+ Tcl_Interp *interp, Ttk_TagTable, Tcl_Obj *objPtr);
+
+MODULE_SCOPE void Ttk_FreeTagSet(Ttk_TagSet);
+
+MODULE_SCOPE int Ttk_TagSetContains(Ttk_TagSet, Ttk_Tag tag);
+MODULE_SCOPE void Ttk_TagSetAdd(Ttk_TagSet, Ttk_Tag tag);
+MODULE_SCOPE void Ttk_TagSetRemove(Ttk_TagSet, Ttk_Tag tag);
+
+MODULE_SCOPE void Ttk_TagSetValues(Ttk_TagTable, Ttk_TagSet, void *record);
+MODULE_SCOPE void Ttk_TagSetApplyStyle(Ttk_TagTable,Ttk_Style,Ttk_State,void*);
/*
* Useful widget base classes: