summaryrefslogtreecommitdiffstats
path: root/generic/ttk/ttkTagSet.c
diff options
context:
space:
mode:
authorhobbs <hobbs>2010-08-26 02:06:08 (GMT)
committerhobbs <hobbs>2010-08-26 02:06:08 (GMT)
commitb29adcfbfc2e03e058536524f1aa3378b948e7ed (patch)
treefa90e1e6d32590addfbb0a1599a40b1f7f99ea3b /generic/ttk/ttkTagSet.c
parent7dec1714e5d5efd6b7d095657c1434fa68af0f87 (diff)
downloadtk-b29adcfbfc2e03e058536524f1aa3378b948e7ed.zip
tk-b29adcfbfc2e03e058536524f1aa3378b948e7ed.tar.gz
tk-b29adcfbfc2e03e058536524f1aa3378b948e7ed.tar.bz2
Major backport of 8.6 Ttk for 8.5.9. Most changes were only being
committed to head (8.6), although they could apply for 8.5 as well. This re-sync makes future work easier to maintain and adds some useful work for 8.5 users. Notable changes: - Lots of code cleanup - Some bug fixes never backported - Addition of ttk::spinbox - minor color changes - Improved Vista/7 styling - Move to tile version 0.8.6 (pseudo-package) - ABI and API compatible (even $w identify) - minor new features (extended $w identify)
Diffstat (limited to 'generic/ttk/ttkTagSet.c')
-rw-r--r--generic/ttk/ttkTagSet.c260
1 files changed, 210 insertions, 50 deletions
diff --git a/generic/ttk/ttkTagSet.c b/generic/ttk/ttkTagSet.c
index 85624a2..fd4c538 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.3.4.1 2010/08/26 02:06:09 hobbs 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,53 +16,55 @@
* +++ Internal data structures.
*/
struct TtkTag {
- Tcl_Obj **tagRecord; /* ... hrmph. */
+ int priority; /* 1=>highest */
+ const char *tagName; /* Back-pointer to hash table entry */
+ void *tagRecord; /* User data */
};
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 */
};
/*------------------------------------------------------------------------
* +++ Tags.
*/
-static Ttk_Tag NewTag(Ttk_TagTable tagTable)
+static Ttk_Tag NewTag(Ttk_TagTable tagTable, const char *tagName)
{
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;
+ tag->tagName = tagName;
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 +73,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);
}
@@ -90,7 +91,8 @@ Ttk_Tag Ttk_GetTag(Ttk_TagTable tagTable, const char *tagName)
&tagTable->tags, tagName, &isNew);
if (isNew) {
- Tcl_SetHashValue(entryPtr, NewTag(tagTable));
+ tagName = Tcl_GetHashKey(&tagTable->tags, entryPtr);
+ Tcl_SetHashValue(entryPtr, NewTag(tagTable,tagName));
}
return Tcl_GetHashValue(entryPtr);
}
@@ -100,48 +102,206 @@ 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.
+ *
+ * Returns NULL and leaves an error message in interp->result on error.
*
- * Result must be passed to Ttk_FreeTagList().
+ * 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]);
+ }
+ tagset->tags[i] = NULL;
+ tagset->nTags = objc;
+
+ return tagset;
+}
+
+/* Ttk_NewTagSetObj --
+ * Construct a fresh Tcl_Obj * from a tag set.
+ */
+Tcl_Obj *Ttk_NewTagSetObj(Ttk_TagSet tagset)
+{
+ Tcl_Obj *result = Tcl_NewListObj(0,0);
+ int i;
+
+ for (i = 0; i < tagset->nTags; ++i) {
+ Tcl_ListObjAppendElement(
+ NULL, result, Tcl_NewStringObj(tagset->tags[i]->tagName, -1));
}
- tags[i] = NULL;
+ return result;
+}
- *taglist_rtn = tags;
- *nTags_rtn = objc;
+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;
+}
- return TCL_OK;
+/* Ttk_TagSetAdd -- add a tag to a tag set.
+ *
+ * Returns: 0 if tagset already contained tag,
+ * 1 if tagset was modified.
+ */
+int Ttk_TagSetAdd(Ttk_TagSet tagset, Ttk_Tag tag)
+{
+ int i;
+ for (i = 0; i < tagset->nTags; ++i) {
+ if (tagset->tags[i] == tag) {
+ return 0;
+ }
+ }
+ tagset->tags = (void*)ckrealloc((void*)tagset->tags,
+ (tagset->nTags+1)*sizeof(tagset->tags[0]));
+ tagset->tags[tagset->nTags++] = tag;
+ return 1;
}
-void Ttk_FreeTagList(void **taglist)
+/* Ttk_TagSetRemove -- remove a tag from a tag set.
+ *
+ * Returns: 0 if tagset did not contain tag,
+ * 1 if tagset was modified.
+ */
+int Ttk_TagSetRemove(Ttk_TagSet tagset, Ttk_Tag tag)
{
- if (taglist)
- ckfree((ClientData)taglist);
+ int i = 0, j = 0;
+ while (i < tagset->nTags) {
+ if ((tagset->tags[j] = tagset->tags[i]) != tag) {
+ ++j;
+ }
+ ++i;
+ }
+ tagset->nTags = j;
+ return j != i;
+}
+
+/*------------------------------------------------------------------------
+ * +++ Utilities for widget commands.
+ */
+
+/* Ttk_EnumerateTags -- implements [$w tag names]
+ */
+int Ttk_EnumerateTags(
+ Tcl_Interp *interp, Ttk_TagTable tagTable)
+{
+ return TtkEnumerateHashTable(interp, &tagTable->tags);
+}
+
+/* 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);
+}
+
+/* Ttk_TagOptionValue -- implements [$w tag configure $tag -option]
+ */
+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.
+ */
+
+#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_TagSetApplyStyle(
+ Ttk_TagTable tagTable, Ttk_Style style, Ttk_State state, void *record)
+{
+ 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;
+ }
}