diff options
author | jenglish <jenglish@flightlab.com> | 2008-05-23 20:20:05 (GMT) |
---|---|---|
committer | jenglish <jenglish@flightlab.com> | 2008-05-23 20:20:05 (GMT) |
commit | ee1814c0cdbcfe9807b18e2b2732c299789897a3 (patch) | |
tree | 38468a3e3f80fe6a337d7e5bef1503a0780d1797 /generic/ttk | |
parent | c2ee900569916fac1b939549e153c9344dca8c0a (diff) | |
download | tk-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.c | 23 | ||||
-rw-r--r-- | generic/ttk/ttkTagSet.c | 191 | ||||
-rw-r--r-- | generic/ttk/ttkTheme.c | 53 | ||||
-rw-r--r-- | generic/ttk/ttkTheme.h | 7 | ||||
-rw-r--r-- | generic/ttk/ttkThemeInt.h | 3 | ||||
-rw-r--r-- | generic/ttk/ttkTreeview.c | 591 | ||||
-rw-r--r-- | generic/ttk/ttkWidget.h | 33 |
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: |