diff options
-rw-r--r-- | ChangeLog | 6 | ||||
-rw-r--r-- | doc/ttk_vsapi.n | 83 | ||||
-rw-r--r-- | win/ttkWinXPTheme.c | 161 |
3 files changed, 247 insertions, 3 deletions
@@ -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: |