summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog6
-rw-r--r--doc/ttk_vsapi.n83
-rw-r--r--win/ttkWinXPTheme.c161
3 files changed, 247 insertions, 3 deletions
diff --git a/ChangeLog b/ChangeLog
index 0c6a696..6d5578c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2008-04-08 Pat Thoyts <patthoyts@users.sourceforge.net>
+
+ * win/ttkWinXpTheme.c: Provide a visual-styles API element engine
+ * tests/ttk/vsapi.test: to permit scripts to create any available
+ * doc/ttk_vsapi.n: windows xp/vista element. Plus basic tests.
+
2008-04-08 Daniel Steffen <das@users.sourceforge.net>
* generic/tkDecls.h: make genstubs (genStubs.tcl changes).
diff --git a/doc/ttk_vsapi.n b/doc/ttk_vsapi.n
new file mode 100644
index 0000000..8bd40d1
--- /dev/null
+++ b/doc/ttk_vsapi.n
@@ -0,0 +1,83 @@
+'\" -*- nroff -*-
+'\" Copyright (c) 2008 Pat Thoyts
+'\"
+'\" See the file "license.terms" for information on usage and redistribution
+'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+'\"
+'\" RCS: @(#) $Id: ttk_vsapi.n,v 1.1 2008/04/08 23:30:45 patthoyts Exp $
+'\"
+.so man.macros
+.TH ttk::vsapi n 8.5 Tk "Tk Themed Widget"
+.BS
+.SH NAME
+ttk::vsapi \- Define a Microsoft Visual Styles element
+.SH SYNOPSIS
+\fBttk::style element create \fIname\fR \fBvsapi\fR \fIclassName\fR
+\fIpartId\fR ?\fIstateMap\fR? ?\fIoptions\fR?
+.BE
+.SH DESCRIPTION
+The \fIvsapi\fR element factory creates a new element
+in the current theme whose visual appearance is drawn using the
+Microsoft Visual Styles API which is reponsible for the themed styles
+on Windows XP and Vista. This factory permits any of the Visual
+Styles parts to be declared as ttk elements that can then be
+included in a style layout to modify the appearance of ttk widgets.
+.PP
+\fIclassName\fR and \fIpartId\fR are required parameters and specify
+the Visual Styles class and part as given in the Microsoft
+documentation. The \fIstateMap\fR may be provided to map ttk states to
+Visual Styles API states (see \fBSTATE MAP\fR).
+.SH "OPTIONS"
+Valid \fIoptions\fR are:
+.TP
+\fB\-padding\fR \fIpadding\fR
+Specify the element's interior padding.
+\fIpadding\fR is a list of up to four integers specifying
+the left, top, right and bottom borders respectively. This option
+cannot be mixed with any other options.
+.TP
+\fB\-margins\fR \fIpadding\fR
+Specifies the elements exterior padding. The \fIpadding\fR is as
+described for the \fI-padding\fR option. This option may not be mixed
+with any other options.
+.TP
+\fB\-width\fR \fIwidth\fR
+Specifies the height for the element. If this option is set then
+the Visual Styles API will not be queried for the recommended
+size. If this option is set then \fI-height\fR should also be set.
+The \fI-width\fR and \fI-height\fR options cannot be mixed with
+the \fI-padding\fR or \fI-margins\fR options.
+.TP
+\fB\-height\fR \fIheight\fR
+Specifies the height of the element. See the comments for \fI-width\fR.
+.SH "STATE MAP"
+The \fIstateMap\fR parameter is a list of ttk states and the
+corresponding Visual Styles API state value.
+This permits the element appearence to respond to changes in the
+widget state such as becoming active or being pressed. The list should
+be as described for the \fBttk::style map\fR command but note that the
+last pair in the list should be the default state and is typically and
+empty list and 1.
+.PP
+If no \fIstateMap\fR parameter is given there is an implicit default
+\fIstateMap\fR of {{} 1}
+.SH "EXAMPLE"
+Change the appearence of a ttk::checkbutton to use the Explorer pin
+part.
+.CS
+# EXPLORERBAR EBP_HEADERPIN
+ttk::style element create pin vsapi EXPLORERBAR 3 {
+ {pressed !selected} 3
+ {active !selected} 2
+ {pressed selected} 6
+ {active selected} 5
+ {selected} 4
+ {} 1
+}
+ttk::style layout Explorer.Pin {Explorer.Pin.pin -sticky news}
+pack [ttk::checkbutton .pin -style Explorer.Pin]
+.CE
+.SH "SEE ALSO"
+ttk::intro(n), ttk::widget(n), ttk::style(n), ttk::image(n)
+.SH "KEYWORDS"
+style, theme, appearance, windows
diff --git a/win/ttkWinXPTheme.c b/win/ttkWinXPTheme.c
index 11a8269..a0a485c 100644
--- a/win/ttkWinXPTheme.c
+++ b/win/ttkWinXPTheme.c
@@ -1,5 +1,5 @@
/*
- * $Id: ttkWinXPTheme.c,v 1.18 2007/12/13 15:28:56 dgp Exp $
+ * $Id: ttkWinXPTheme.c,v 1.19 2008/04/08 23:30:46 patthoyts Exp $
*
* Tk theme engine which uses the Windows XP "Visual Styles" API
* Adapted from Georgios Petasis' XP theme patch.
@@ -372,6 +372,7 @@ typedef struct /* XP element specifications */
int flags;
# define IGNORE_THEMESIZE 0x80000000 /* See NOTE-GetThemePartSize */
# define PAD_MARGINS 0x40000000 /* See NOTE-GetThemeMargins */
+# define HEAP_ELEMENT 0x20000000 /* ElementInfo is on heap */
} ElementInfo;
typedef struct
@@ -406,9 +407,21 @@ NewElementData(XPThemeProcs *procs, ElementInfo *info)
return elementData;
}
-static void DestroyElementData(void *elementData)
+/*
+ * Destroy elements. If the element was created by the element factory
+ * then the info member is dynamically allocated. Otherwise it was
+ * static data from the C object and only the ElementData needs freeing.
+ */
+static void DestroyElementData(void *clientData)
{
- ckfree(elementData);
+ ElementData *elementData = clientData;
+ if (elementData->info->flags & HEAP_ELEMENT) {
+ ckfree((char *)elementData->info->statemap);
+ ckfree((char *)elementData->info->className);
+ ckfree((char *)elementData->info->elementName);
+ ckfree((char *)elementData->info);
+ }
+ ckfree(clientData);
}
/*
@@ -962,6 +975,147 @@ static ElementInfo ElementInfoTable[] = {
#undef PAD
/*----------------------------------------------------------------------
+ * Windows Visual Styles API Element Factory
+ *
+ * The Vista release has shown that the Windows Visual Styles can be
+ * extended with additional elements. This element factory can permit
+ * the programmer to create elements for use with script-defined layouts
+ *
+ * eg: to create the small close button:
+ * style element create smallclose vsapi \
+ * WINDOW 19 {disabled 4 pressed 3 active 2 {} 1}
+ */
+
+static int
+Ttk_CreateVsapiElement(
+ Tcl_Interp *interp,
+ void *clientData,
+ Ttk_Theme theme,
+ const char *elementName,
+ int objc, Tcl_Obj *CONST objv[])
+{
+ XPThemeData *themeData = clientData;
+ ElementInfo *elementPtr = NULL;
+ ClientData elementData;
+ Tcl_UniChar *className;
+ int partId = 0;
+ Ttk_StateTable *stateTable;
+ Ttk_Padding pad = {0, 0, 0, 0};
+ int flags = 0;
+ int length = 0;
+ char *name;
+ LPWSTR wname;
+
+ const char *optionStrings[] =
+ { "-padding","-width","-height","-margins",NULL };
+ enum { O_PADDING, O_WIDTH, O_HEIGHT, O_MARGINS };
+
+ if (objc < 2) {
+ Tcl_AppendResult(interp,
+ "missing required arguments 'class' and/or 'partId'", NULL);
+ return TCL_ERROR;
+ }
+
+ if (Tcl_GetIntFromObj(interp, objv[1], &partId) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ className = Tcl_GetUnicodeFromObj(objv[0], &length);
+
+ /* flags or padding */
+ if (objc > 3) {
+ int i = 3, option = 0;
+ for (i = 3; i < objc; i += 2) {
+ int tmp = 0;
+ if (i == objc -1) {
+ Tcl_AppendResult(interp, "Missing value for \"",
+ Tcl_GetString(objv[i]), "\".", NULL);
+ return TCL_ERROR;
+ }
+ if (Tcl_GetIndexFromObj(interp, objv[i], optionStrings,
+ "option", 0, &option) != TCL_OK)
+ return TCL_ERROR;
+ switch (option) {
+ case O_PADDING:
+ if (Ttk_GetBorderFromObj(interp, objv[i+1], &pad) != TCL_OK)
+ return TCL_ERROR;
+ break;
+ case O_MARGINS:
+ if (Ttk_GetBorderFromObj(interp, objv[i+1], &pad) != TCL_OK)
+ return TCL_ERROR;
+ flags |= PAD_MARGINS;
+ break;
+ case O_WIDTH:
+ if (Tcl_GetIntFromObj(interp, objv[i+1], &tmp) != TCL_OK)
+ return TCL_ERROR;
+ pad.left = pad.right = tmp;
+ flags |= IGNORE_THEMESIZE;
+ break;
+ case O_HEIGHT:
+ if (Tcl_GetIntFromObj(interp, objv[i+1], &tmp) != TCL_OK)
+ return TCL_ERROR;
+ pad.top = pad.bottom = tmp;
+ flags |= IGNORE_THEMESIZE;
+ break;
+ }
+ }
+ }
+
+ /* convert a statemap into a state table */
+ if (objc > 2) {
+ Tcl_Obj **specs;
+ int n,j,count, status = TCL_OK;
+ if (Tcl_ListObjGetElements(interp, objv[2], &count, &specs) != TCL_OK)
+ return TCL_ERROR;
+ /* we over-allocate to ensure there is a terminating entry */
+ stateTable = (Ttk_StateTable *)
+ ckalloc(sizeof(Ttk_StateTable) * (count + 1));
+ memset(stateTable, 0, sizeof(Ttk_StateTable) * (count + 1));
+ for (n = 0, j = 0; status == TCL_OK && n < count; n += 2, ++j) {
+ Ttk_StateSpec spec = {0,0};
+ status = Ttk_GetStateSpecFromObj(interp, specs[n], &spec);
+ if (status == TCL_OK) {
+ stateTable[j].onBits = spec.onbits;
+ stateTable[j].offBits = spec.offbits;
+ status = Tcl_GetIntFromObj(interp, specs[n+1],
+ &stateTable[j].index);
+ }
+ }
+ if (status != TCL_OK) {
+ ckfree((char *)stateTable);
+ return status;
+ }
+ } else {
+ stateTable = (Ttk_StateTable *)ckalloc(sizeof(Ttk_StateTable));
+ memset(stateTable, 0, sizeof(Ttk_StateTable));
+ }
+
+ elementPtr = (ElementInfo *)ckalloc(sizeof(ElementInfo));
+ elementPtr->elementSpec = &GenericElementSpec;
+ elementPtr->partId = partId;
+ elementPtr->statemap = stateTable;
+ elementPtr->padding = pad;
+ elementPtr->flags = HEAP_ELEMENT | flags;
+
+ /* set the element name to an allocated copy */
+ name = ckalloc(strlen(elementName) + 1);
+ strcpy(name, elementName);
+ elementPtr->elementName = name;
+
+ /* set the class name to an allocated copy */
+ wname = (LPWSTR)ckalloc(sizeof(WCHAR) * (length + 1));
+ wcscpy(wname, className);
+ elementPtr->className = wname;
+
+ elementData = NewElementData(themeData->procs, elementPtr);
+ Ttk_RegisterElementSpec(
+ theme, elementName, elementPtr->elementSpec, elementData);
+
+ Ttk_RegisterCleanup(interp, elementData, DestroyElementData);
+ Tcl_SetObjResult(interp, Tcl_NewStringObj(elementName, -1));
+ return TCL_OK;
+}
+
+/*----------------------------------------------------------------------
* +++ Initialization routine:
*/
@@ -997,6 +1151,7 @@ MODULE_SCOPE int TtkXPTheme_Init(Tcl_Interp *interp, HWND hwnd)
Ttk_SetThemeEnabledProc(themePtr, XPThemeEnabled, themeData);
Ttk_RegisterCleanup(interp, themeData, XPThemeDeleteProc);
+ Ttk_RegisterElementFactory(interp, "vsapi", Ttk_CreateVsapiElement, themeData);
/*
* New elements: