summaryrefslogtreecommitdiffstats
path: root/generic/ttk/ttkTagSet.c
blob: dd4d3a4072d5192718f912235e0083967b112a5b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
/* $Id: ttkTagSet.c,v 1.1 2006/10/31 01:42:26 hobbs Exp $
 *
 * Ttk widget set: tag tables.  Half-baked, work in progress.
 *
 * Copyright (C) 2005, Joe English.  Freely redistributable.
 */

#include <string.h>	/* for memset() */
#include <tcl.h>
#include <tk.h>

#include "ttkTheme.h"
#include "ttkWidget.h"

/*------------------------------------------------------------------------
 * +++ Internal data structures.
 */
struct TtkTag {
    Tcl_Obj **tagRecord;	/* ... hrmph. */
};

struct TtkTagTable {
    Tk_OptionTable	tagOptionTable;	/* ... */
    int         	tagRecordSize;	/* size of tag record */
    Tcl_HashTable	tags;		/* defined tags */
};

/*------------------------------------------------------------------------
 * +++ Tags.
 */
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);
    return tag;
}

static void DeleteTag(Ttk_Tag tag, int nOptions) 
{
    int i;
    for (i = 0; i < nOptions; ++i) {
	if (tag->tagRecord[i]) {
	    Tcl_DecrRefCount(tag->tagRecord[i]);
	}
    }
    ckfree((void*)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)
{
    Ttk_TagTable tagTable = (Ttk_TagTable)ckalloc(sizeof(*tagTable));
    tagTable->tagOptionTable = tagOptionTable;
    tagTable->tagRecordSize = tagRecordSize;
    Tcl_InitHashTable(&tagTable->tags, TCL_STRING_KEYS);
    return tagTable;
}

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);
	entryPtr = Tcl_NextHashEntry(&search);
    }

    Tcl_DeleteHashTable(&tagTable->tags);
    ckfree((void*)tagTable);
}

Ttk_Tag Ttk_GetTag(Ttk_TagTable tagTable, const char *tagName)
{
    int isNew = 0;
    Tcl_HashEntry *entryPtr = Tcl_CreateHashEntry(
	&tagTable->tags, tagName, &isNew);

    if (isNew) {
	Tcl_SetHashValue(entryPtr, NewTag(tagTable));
    }
    return Tcl_GetHashValue(entryPtr);
}

Ttk_Tag Ttk_GetTagFromObj(Ttk_TagTable tagTable, Tcl_Obj *objPtr)
{
    return Ttk_GetTag(tagTable, Tcl_GetString(objPtr));
}

/* Ttk_GetTagListFromObj --
 * 	Extract an array of pointers to Ttk_Tags from a Tcl_Obj.
 * 	(suitable for passing to Tk_BindEvent).
 *
 * Result must be passed to Ttk_FreeTagList().
 */
extern int Ttk_GetTagListFromObj(
    Tcl_Interp *interp, 
    Ttk_TagTable tagTable,
    Tcl_Obj *objPtr,
    int *nTags_rtn,
    void **taglist_rtn)
{
    Tcl_Obj **objv;
    int i, objc;
    void **tags;

    *taglist_rtn = NULL; *nTags_rtn = 0;

    if (objPtr == NULL) {
	return TCL_OK;
    }

    if (Tcl_ListObjGetElements(interp, objPtr, &objc, &objv) != TCL_OK) {
    	return TCL_ERROR;
    }

    tags = (void**)ckalloc((objc+1) * sizeof(void*));
    for (i=0; i<objc; ++i) {
	tags[i] = Ttk_GetTagFromObj(tagTable, objv[i]);
    }
    tags[i] = NULL;

    *taglist_rtn = tags;
    *nTags_rtn = objc;

    return TCL_OK;
}

void Ttk_FreeTagList(void **taglist)
{
    if (taglist) 
	ckfree((ClientData)taglist);
}